update emoji autocorrect entries from po-files
[LibreOffice.git] / sc / source / core / data / column3.cxx
blobc0376eab2d96c04ce1884650e9d85bb11ccabddd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "column.hxx"
22 #include "scitems.hxx"
23 #include "formulacell.hxx"
24 #include "document.hxx"
25 #include "attarray.hxx"
26 #include "patattr.hxx"
27 #include "cellform.hxx"
28 #include "typedstrdata.hxx"
29 #include <formula/errorcodes.hxx>
30 #include <formula/token.hxx>
31 #include "brdcst.hxx"
32 #include "docoptio.hxx"
33 #include "subtotal.hxx"
34 #include "markdata.hxx"
35 #include "detfunc.hxx"
36 #include "postit.hxx"
37 #include "stringutil.hxx"
38 #include "docpool.hxx"
39 #include "globalnames.hxx"
40 #include "cellvalue.hxx"
41 #include "tokenarray.hxx"
42 #include "stlalgorithm.hxx"
43 #include "clipcontext.hxx"
44 #include "columnspanset.hxx"
45 #include "mtvcellfunc.hxx"
46 #include "scopetools.hxx"
47 #include "editutil.hxx"
48 #include "sharedformula.hxx"
49 #include <listenercontext.hxx>
51 #include <com/sun/star/i18n/LocaleDataItem.hpp>
53 #include <boost/scoped_ptr.hpp>
55 #include <mdds/flat_segment_tree.hpp>
57 #include <sfx2/objsh.hxx>
58 #include <svl/zforlist.hxx>
59 #include <svl/zformat.hxx>
60 #include <svl/broadcast.hxx>
61 #include <svl/sharedstringpool.hxx>
62 #include <editeng/editstat.hxx>
64 #include <cstdio>
66 using ::com::sun::star::i18n::LocaleDataItem;
68 // Err527 Workaroand
69 extern const ScFormulaCell* pLastFormulaTreeTop; // in cellform.cxx
70 using namespace formula;
72 void ScColumn::Broadcast( SCROW nRow )
74 ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab));
75 pDocument->Broadcast(aHint);
78 void ScColumn::BroadcastCells( const std::vector<SCROW>& rRows, sal_uLong nHint )
80 if (rRows.empty())
81 return;
83 // Broadcast the changes.
84 ScHint aHint(nHint, ScAddress(nCol, 0, nTab));
85 std::vector<SCROW>::const_iterator itRow = rRows.begin(), itRowEnd = rRows.end();
86 for (; itRow != itRowEnd; ++itRow)
88 aHint.GetAddress().SetRow(*itRow);
89 pDocument->Broadcast(aHint);
93 struct DirtyCellInterpreter
95 void operator() (size_t, ScFormulaCell* p)
97 if (p->GetDirty())
98 p->Interpret();
102 void ScColumn::InterpretDirtyCells( SCROW nRow1, SCROW nRow2 )
104 if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
105 return;
107 DirtyCellInterpreter aFunc;
108 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
111 void ScColumn::DeleteContent( SCROW nRow, bool bBroadcast )
113 sc::CellStoreType::position_type aPos = maCells.position(nRow);
114 sc::CellStoreType::iterator it = aPos.first;
115 if (it == maCells.end())
116 return;
118 if (it->type == sc::element_type_formula)
120 ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
121 p->EndListeningTo(pDocument);
122 sc::SharedFormulaUtil::unshareFormulaCell(aPos, *p);
124 maCells.set_empty(nRow, nRow);
126 if (bBroadcast)
128 Broadcast(nRow);
129 CellStorageModified();
133 void ScColumn::Delete( SCROW nRow )
135 DeleteContent(nRow, false);
136 maCellTextAttrs.set_empty(nRow, nRow);
137 maCellNotes.set_empty(nRow, nRow);
139 Broadcast(nRow);
140 CellStorageModified();
143 void ScColumn::FreeAll()
145 // Keep a logical empty range of 0-MAXROW at all times.
146 maCells.clear();
147 maCells.resize(MAXROWCOUNT);
148 maCellTextAttrs.clear();
149 maCellTextAttrs.resize(MAXROWCOUNT);
150 maCellNotes.clear();
151 maCellNotes.resize(MAXROWCOUNT);
152 CellStorageModified();
155 void ScColumn::FreeNotes()
157 maCellNotes.clear();
158 maCellNotes.resize(MAXROWCOUNT);
161 namespace {
163 class ShiftFormulaPosHandler
165 public:
167 void operator() (size_t nRow, ScFormulaCell* pCell)
169 pCell->aPos.SetRow(nRow);
175 void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize, std::vector<ScAddress>* pGroupPos )
177 pAttrArray->DeleteRow( nStartRow, nSize );
179 SCROW nEndRow = nStartRow + nSize - 1;
181 maBroadcasters.erase(nStartRow, nEndRow);
182 maBroadcasters.resize(MAXROWCOUNT);
184 maCellNotes.erase(nStartRow, nEndRow);
185 maCellNotes.resize(MAXROWCOUNT);
187 // See if we have any cells that would get deleted or shifted by deletion.
188 sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
189 sc::CellStoreType::iterator itCell = aPos.first;
190 if (itCell->type == sc::element_type_empty)
192 // This is an empty block. If this is the last block, then there is no cells to delete or shift.
193 sc::CellStoreType::iterator itTest = itCell;
194 ++itTest;
195 if (itTest == maCells.end())
197 // No cells are affected by this deletion. Bail out.
198 CellStorageModified(); // broadcast array has been modified.
199 return;
203 // Check if there are any cells below the end row that will get shifted.
204 bool bShiftCells = false;
205 if (nEndRow < MAXROW) //only makes sense to do this if there *is* a row after the end row
207 aPos = maCells.position(itCell, nEndRow+1);
208 itCell = aPos.first;
209 if (itCell->type == sc::element_type_empty)
211 // This block is empty. See if there is any block that follows.
212 sc::CellStoreType::iterator itTest = itCell;
213 ++itTest;
214 if (itTest != maCells.end())
215 // Non-empty block follows -> cells that will get shifted.
216 bShiftCells = true;
218 else
219 bShiftCells = true;
222 sc::SingleColumnSpanSet aNonEmptySpans;
223 if (bShiftCells)
225 // Mark all non-empty cell positions below the end row.
226 sc::ColumnBlockConstPosition aBlockPos;
227 aBlockPos.miCellPos = itCell;
228 aNonEmptySpans.scan(aBlockPos, *this, nEndRow+1, MAXROW);
231 sc::AutoCalcSwitch aACSwitch(*pDocument, false);
233 // Remove the cells.
234 maCells.erase(nStartRow, nEndRow);
235 maCells.resize(MAXROWCOUNT);
237 // Get the position again after the container change.
238 aPos = maCells.position(nStartRow);
240 // Shift the formula cell positions below the start row.
241 ShiftFormulaPosHandler aShiftFormulaFunc;
242 sc::ProcessFormula(aPos.first, maCells, nStartRow, MAXROW, aShiftFormulaFunc);
244 bool bJoined = sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
245 if (bJoined && pGroupPos)
246 pGroupPos->push_back(ScAddress(nCol, nStartRow, nTab));
248 // Shift the text attribute array too (before the broadcast).
249 maCellTextAttrs.erase(nStartRow, nEndRow);
250 maCellTextAttrs.resize(MAXROWCOUNT);
252 CellStorageModified();
255 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow )
257 return GetPositionToInsert(maCells.begin(), nRow);
260 void ScColumn::JoinNewFormulaCell(
261 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell )
263 // Check the previous row position for possible grouping.
264 if (aPos.first->type == sc::element_type_formula && aPos.second > 0)
266 ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
267 sc::CellStoreType::position_type aPosPrev = aPos;
268 --aPosPrev.second;
269 sc::SharedFormulaUtil::joinFormulaCells(aPosPrev, rPrev, rCell);
272 // Check the next row position for possible grouping.
273 if (aPos.first->type == sc::element_type_formula && aPos.second+1 < aPos.first->size)
275 ScFormulaCell& rNext = *sc::formula_block::at(*aPos.first->data, aPos.second+1);
276 sc::SharedFormulaUtil::joinFormulaCells(aPos, rCell, rNext);
280 void ScColumn::DetachFormulaCell(
281 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell )
283 if (!pDocument->IsClipOrUndo())
284 // Have the dying formula cell stop listening.
285 rCell.EndListeningTo(pDocument);
287 sc::SharedFormulaUtil::unshareFormulaCell(aPos, rCell);
290 namespace {
292 class AttachFormulaCellsHandler
294 sc::StartListeningContext& mrCxt;
296 public:
297 AttachFormulaCellsHandler( sc::StartListeningContext& rCxt ) :
298 mrCxt(rCxt) {}
300 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
302 pCell->StartListeningTo(mrCxt);
306 class DetachFormulaCellsHandler
308 ScDocument* mpDoc;
309 sc::EndListeningContext* mpCxt;
311 public:
312 DetachFormulaCellsHandler( ScDocument* pDoc, sc::EndListeningContext* pCxt ) :
313 mpDoc(pDoc), mpCxt(pCxt) {}
315 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
317 if (mpCxt)
318 pCell->EndListeningTo(*mpCxt);
319 else
320 pCell->EndListeningTo(mpDoc);
326 void ScColumn::DetachFormulaCells(
327 const sc::CellStoreType::position_type& aPos, size_t nLength )
329 // Split formula grouping at the top and bottom boundaries.
330 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, nullptr);
331 size_t nRow = aPos.first->position + aPos.second;
332 size_t nNextTopRow = nRow + nLength; // start row of next formula group.
333 if (ValidRow(nNextTopRow))
335 sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow);
336 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos2, nullptr);
339 if (pDocument->IsClipOrUndo())
340 return;
342 DetachFormulaCellsHandler aFunc(pDocument, NULL);
343 sc::ProcessFormula(aPos.first, maCells, nRow, nNextTopRow-1, aFunc);
346 void ScColumn::AttachFormulaCells( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 )
348 sc::CellStoreType::position_type aPos = maCells.position(nRow1);
349 sc::CellStoreType::iterator it = aPos.first;
351 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
352 if (ValidRow(nRow2+1))
354 aPos = maCells.position(it, nRow2+1);
355 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
358 if (pDocument->IsClipOrUndo())
359 return;
361 AttachFormulaCellsHandler aFunc(rCxt);
362 sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
365 void ScColumn::DetachFormulaCells( sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2 )
367 sc::CellStoreType::position_type aPos = maCells.position(nRow1);
368 sc::CellStoreType::iterator it = aPos.first;
370 // Split formula grouping at the top and bottom boundaries.
371 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, &rCxt);
372 if (ValidRow(nRow2+1))
374 aPos = maCells.position(it, nRow2+1);
375 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, &rCxt);
378 if (pDocument->IsClipOrUndo())
379 return;
381 DetachFormulaCellsHandler aFunc(pDocument, &rCxt);
382 sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
385 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow )
387 // See if we are overwriting an existing formula cell.
388 sc::CellStoreType::position_type aPos = maCells.position(it, nRow);
389 sc::CellStoreType::iterator itRet = aPos.first;
390 if (itRet->type == sc::element_type_formula)
392 ScFormulaCell& rCell = *sc::formula_block::at(*itRet->data, aPos.second);
393 DetachFormulaCell(aPos, rCell);
396 return itRet;
399 void ScColumn::AttachNewFormulaCell(
400 const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell,
401 bool bJoin, sc::StartListeningType eListenType )
403 AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, bJoin, eListenType);
406 void ScColumn::AttachNewFormulaCell(
407 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell,
408 bool bJoin, sc::StartListeningType eListenType )
410 if (bJoin)
411 // See if this new formula cell can join an existing shared formula group.
412 JoinNewFormulaCell(aPos, rCell);
414 // When we insert from the Clipboard we still have wrong (old) References!
415 // First they are rewired in CopyBlockFromClip via UpdateReference and the
416 // we call StartListeningFromClip and BroadcastFromClip.
417 // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
418 // After Import we call CalcAfterLoad and in there Listening.
419 if (pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc())
420 return;
422 switch (eListenType)
424 case sc::ConvertToGroupListening:
426 boost::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(new sc::ColumnBlockPositionSet(*pDocument));
427 sc::StartListeningContext aStartCxt(*pDocument, pPosSet);
428 sc::EndListeningContext aEndCxt(*pDocument, pPosSet);
429 SCROW nRow = aPos.first->position + aPos.second;
430 StartListeningFormulaCells(aStartCxt, aEndCxt, nRow, nRow);
432 break;
433 case sc::SingleCellListening:
434 rCell.StartListeningTo(pDocument);
435 break;
436 case sc::NoListening:
437 default:
442 if (!pDocument->IsCalcingAfterLoad())
443 rCell.SetDirty();
446 void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength )
448 // Make sure the whole length consists of formula cells.
449 if (aPos.first->type != sc::element_type_formula)
450 return;
452 if (aPos.first->size < aPos.second + nLength)
453 // Block is shorter than specified length.
454 return;
456 // Join the top and bottom cells only.
457 ScFormulaCell* pCell = sc::formula_block::at(*aPos.first->data, aPos.second);
458 JoinNewFormulaCell(aPos, *pCell);
460 sc::CellStoreType::position_type aPosLast = aPos;
461 aPosLast.second += nLength - 1;
462 pCell = sc::formula_block::at(*aPosLast.first->data, aPosLast.second);
463 JoinNewFormulaCell(aPosLast, *pCell);
465 if (!pDocument->IsClipOrUndo() && !pDocument->IsInsertingFromOtherDoc())
467 sc::StartListeningContext aCxt(*pDocument);
468 ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second);
469 ScFormulaCell** ppEnd = pp + nLength;
470 for (; pp != ppEnd; ++pp)
472 pCell = *pp;
473 pCell->StartListeningTo(aCxt);
474 if (!pDocument->IsCalcingAfterLoad())
475 pCell->SetDirty();
480 void ScColumn::BroadcastNewCell( SCROW nRow )
482 // When we insert from the Clipboard we still have wrong (old) References!
483 // First they are rewired in CopyBlockFromClip via UpdateReference and the
484 // we call StartListeningFromClip and BroadcastFromClip.
485 // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
486 // After Import we call CalcAfterLoad and in there Listening.
487 if (pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc() || pDocument->IsCalcingAfterLoad())
488 return;
490 Broadcast(nRow);
493 bool ScColumn::UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow, const sc::CellStoreType::iterator& itr )
495 if (rAttr.mnScriptType != SvtScriptType::UNKNOWN)
496 // Already updated. Nothing to do.
497 return false;
499 // Script type not yet determined. Determine the real script
500 // type, and store it.
501 const ScPatternAttr* pPattern = GetPattern(nRow);
502 if (!pPattern)
503 return false;
505 sc::CellStoreType::position_type pos = maCells.position(itr, nRow);
506 sc::CellStoreType::iterator itr2 = pos.first;
507 size_t nOffset = pos.second;
508 ScRefCellValue aCell = GetCellValue( itr2, nOffset );
509 ScAddress aPos(nCol, nRow, nTab);
511 const SfxItemSet* pCondSet = NULL;
512 ScConditionalFormatList* pCFList = pDocument->GetCondFormList(nTab);
513 if (pCFList)
515 const ScCondFormatItem& rItem =
516 static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL));
517 const std::vector<sal_uInt32>& rData = rItem.GetCondFormatData();
518 pCondSet = pDocument->GetCondResult(aCell, aPos, *pCFList, rData);
521 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
523 OUString aStr;
524 Color* pColor;
525 sal_uLong nFormat = pPattern->GetNumberFormat(pFormatter, pCondSet);
526 ScCellFormat::GetString(aCell, nFormat, aStr, &pColor, *pFormatter, pDocument);
528 // Store the real script type to the array.
529 rAttr.mnScriptType = pDocument->GetStringScriptType(aStr);
530 return true;
533 namespace {
535 class DeleteAreaHandler
537 ScDocument& mrDoc;
538 std::vector<ScFormulaCell*> maFormulaCells;
539 sc::SingleColumnSpanSet maDeleteRanges;
541 bool mbNumeric:1;
542 bool mbString:1;
543 bool mbFormula:1;
545 public:
546 DeleteAreaHandler(ScDocument& rDoc, InsertDeleteFlags nDelFlag) :
547 mrDoc(rDoc),
548 mbNumeric(nDelFlag & IDF_VALUE),
549 mbString(nDelFlag & IDF_STRING),
550 mbFormula(nDelFlag & IDF_FORMULA) {}
552 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
554 switch (node.type)
556 case sc::element_type_numeric:
557 if (!mbNumeric)
558 return;
559 break;
560 case sc::element_type_string:
561 case sc::element_type_edittext:
562 if (!mbString)
563 return;
564 break;
565 case sc::element_type_formula:
567 if (!mbFormula)
568 return;
570 sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
571 std::advance(it, nOffset);
572 sc::formula_block::iterator itEnd = it;
573 std::advance(itEnd, nDataSize);
575 for (; it != itEnd; ++it)
576 maFormulaCells.push_back(*it);
578 break;
579 case sc::element_type_empty:
580 default:
581 return;
584 // Tag these cells for deletion.
585 SCROW nRow1 = node.position + nOffset;
586 SCROW nRow2 = nRow1 + nDataSize - 1;
587 maDeleteRanges.set(nRow1, nRow2, true);
590 void endFormulas()
592 mrDoc.EndListeningFormulaCells(maFormulaCells);
595 sc::SingleColumnSpanSet& getSpans()
597 return maDeleteRanges;
601 class EmptyCells
603 ScColumn& mrColumn;
604 sc::ColumnBlockPosition& mrPos;
606 static void splitFormulaGrouping(const sc::CellStoreType::position_type& rPos)
608 if (rPos.first->type == sc::element_type_formula)
610 ScFormulaCell& rCell = *sc::formula_block::at(*rPos.first->data, rPos.second);
611 sc::SharedFormulaUtil::unshareFormulaCell(rPos, rCell);
615 public:
616 EmptyCells( sc::ColumnBlockPosition& rPos, ScColumn& rColumn ) :
617 mrColumn(rColumn), mrPos(rPos) {}
619 void operator() (const sc::RowSpan& rSpan)
621 sc::CellStoreType& rCells = mrColumn.GetCellStore();
623 // First, split formula grouping at the top and bottom boundaries
624 // before emptying the cells.
625 sc::CellStoreType::position_type aPos = rCells.position(mrPos.miCellPos, rSpan.mnRow1);
626 splitFormulaGrouping(aPos);
627 aPos = rCells.position(aPos.first, rSpan.mnRow2);
628 splitFormulaGrouping(aPos);
630 mrPos.miCellPos = rCells.set_empty(mrPos.miCellPos, rSpan.mnRow1, rSpan.mnRow2);
631 mrPos.miCellTextAttrPos = mrColumn.GetCellAttrStore().set_empty(mrPos.miCellTextAttrPos, rSpan.mnRow1, rSpan.mnRow2);
637 void ScColumn::DeleteCells(
638 sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag,
639 sc::SingleColumnSpanSet& rDeleted )
641 // Determine which cells to delete based on the deletion flags.
642 DeleteAreaHandler aFunc(*pDocument, nDelFlag);
643 sc::CellStoreType::iterator itPos = maCells.position(rBlockPos.miCellPos, nRow1).first;
644 sc::ProcessBlock(itPos, maCells, aFunc, nRow1, nRow2);
645 aFunc.endFormulas(); // Have the formula cells stop listening.
647 // Get the deletion spans.
648 sc::SingleColumnSpanSet::SpansType aSpans;
649 aFunc.getSpans().getSpans(aSpans);
651 // Delete the cells for real.
652 std::for_each(aSpans.begin(), aSpans.end(), EmptyCells(rBlockPos, *this));
653 CellStorageModified();
655 aFunc.getSpans().swap(rDeleted);
658 void ScColumn::DeleteArea(
659 SCROW nStartRow, SCROW nEndRow, InsertDeleteFlags nDelFlag, bool bBroadcast,
660 sc::ColumnSpanSet* pBroadcastSpans )
662 InsertDeleteFlags nContMask = IDF_CONTENTS;
663 // IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set
664 if( nDelFlag & IDF_NOTE )
665 nContMask |= IDF_NOCAPTIONS;
666 InsertDeleteFlags nContFlag = nDelFlag & nContMask;
668 sc::SingleColumnSpanSet aDeletedRows;
670 sc::ColumnBlockPosition aBlockPos;
671 InitBlockPosition(aBlockPos);
673 if (!IsEmptyData() && nContFlag)
675 DeleteCells(aBlockPos, nStartRow, nEndRow, nDelFlag, aDeletedRows);
676 if (pBroadcastSpans)
678 sc::SingleColumnSpanSet::SpansType aSpans;
679 aDeletedRows.getSpans(aSpans);
680 sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
681 for (; it != itEnd; ++it)
682 pBroadcastSpans->set(nTab, nCol, it->mnRow1, it->mnRow2, true);
686 if (nDelFlag & IDF_NOTE)
688 bool bForgetCaptionOwnership = ((nDelFlag & IDF_FORGETCAPTIONS) != IDF_NONE);
689 DeleteCellNotes(aBlockPos, nStartRow, nEndRow, bForgetCaptionOwnership);
692 if ( nDelFlag & IDF_EDITATTR )
694 OSL_ENSURE( nContFlag == IDF_NONE, "DeleteArea: Wrong Flags" );
695 RemoveEditAttribs( nStartRow, nEndRow );
698 // Delete attributes just now
699 if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB)
700 pAttrArray->DeleteArea( nStartRow, nEndRow );
701 else if ((nDelFlag & IDF_HARDATTR) == IDF_HARDATTR)
702 pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
704 if (bBroadcast)
706 // Broadcast on only cells that were deleted; no point broadcasting on
707 // cells that were already empty before the deletion.
708 std::vector<SCROW> aRows;
709 aDeletedRows.getRows(aRows);
710 BroadcastCells(aRows, SC_HINT_DATACHANGED);
714 bool ScColumn::InitBlockPosition( sc::ColumnBlockPosition& rBlockPos )
716 rBlockPos.miBroadcasterPos = maBroadcasters.begin();
717 rBlockPos.miCellNotePos = maCellNotes.begin();
718 rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
719 rBlockPos.miCellPos = maCells.begin();
720 return true;
723 bool ScColumn::InitBlockPosition( sc::ColumnBlockConstPosition& rBlockPos ) const
725 rBlockPos.miBroadcasterPos = maBroadcasters.begin();
726 rBlockPos.miCellNotePos = maCellNotes.begin();
727 rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
728 rBlockPos.miCellPos = maCells.begin();
729 return true;
732 namespace {
734 class CopyAttrArrayByRange : std::unary_function<sc::RowSpan, void>
736 ScAttrArray& mrDestAttrArray;
737 ScAttrArray& mrSrcAttrArray;
738 long mnRowOffset;
739 public:
740 CopyAttrArrayByRange(ScAttrArray& rDestAttrArray, ScAttrArray& rSrcAttrArray, long nRowOffset) :
741 mrDestAttrArray(rDestAttrArray), mrSrcAttrArray(rSrcAttrArray), mnRowOffset(nRowOffset) {}
743 void operator() (const sc::RowSpan& rSpan)
745 mrDestAttrArray.CopyAreaSafe(
746 rSpan.mnRow1+mnRowOffset, rSpan.mnRow2+mnRowOffset, mnRowOffset, mrSrcAttrArray);
750 class CopyCellsFromClipHandler
752 sc::CopyFromClipContext& mrCxt;
753 ScColumn& mrSrcCol;
754 ScColumn& mrDestCol;
755 SCTAB mnTab;
756 SCCOL mnCol;
757 SCTAB mnSrcTab;
758 SCCOL mnSrcCol;
759 long mnRowOffset;
760 sc::ColumnBlockPosition maDestBlockPos;
761 sc::ColumnBlockPosition* mpDestBlockPos; // to save it for next iteration.
762 svl::SharedStringPool* mpSharedStringPool;
764 void insertRefCell(SCROW nSrcRow, SCROW nDestRow)
766 ScAddress aSrcPos(mnSrcCol, nSrcRow, mnSrcTab);
767 ScAddress aDestPos(mnCol, nDestRow, mnTab);
768 ScSingleRefData aRef;
769 aRef.InitAddress(aSrcPos);
770 aRef.SetFlag3D(true);
772 ScTokenArray aArr;
773 aArr.AddSingleReference(aRef);
775 mrDestCol.SetFormulaCell(
776 maDestBlockPos, nDestRow, new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos, aArr));
779 void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
781 mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestBlockPos, bCloneCaption, mnRowOffset);
784 public:
785 CopyCellsFromClipHandler(sc::CopyFromClipContext& rCxt, ScColumn& rSrcCol, ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, long nRowOffset, svl::SharedStringPool* pSharedStringPool) :
786 mrCxt(rCxt),
787 mrSrcCol(rSrcCol),
788 mrDestCol(rDestCol),
789 mnTab(nDestTab),
790 mnCol(nDestCol),
791 mnSrcTab(rSrcCol.GetTab()),
792 mnSrcCol(rSrcCol.GetCol()),
793 mnRowOffset(nRowOffset),
794 mpDestBlockPos(mrCxt.getBlockPosition(nDestTab, nDestCol)),
795 mpSharedStringPool(pSharedStringPool)
797 if (mpDestBlockPos)
798 maDestBlockPos = *mpDestBlockPos;
799 else
800 mrDestCol.InitBlockPosition(maDestBlockPos);
803 ~CopyCellsFromClipHandler()
805 if (mpDestBlockPos)
806 // Don't forget to save this to the context!
807 *mpDestBlockPos = maDestBlockPos;
810 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
812 SCROW nSrcRow1 = node.position + nOffset;
813 bool bCopyCellNotes = mrCxt.isCloneNotes();
815 InsertDeleteFlags nFlags = mrCxt.getInsertFlag();
817 if (node.type == sc::element_type_empty)
819 if (bCopyCellNotes && !mrCxt.isSkipAttrForEmptyCells())
821 bool bCloneCaption = (nFlags & IDF_NOCAPTIONS) == IDF_NONE;
822 duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
824 return;
827 bool bNumeric = (nFlags & IDF_VALUE) != IDF_NONE;
828 bool bDateTime = (nFlags & IDF_DATETIME) != IDF_NONE;
829 bool bString = (nFlags & IDF_STRING) != IDF_NONE;
830 bool bBoolean = (nFlags & IDF_SPECIAL_BOOLEAN) != IDF_NONE;
831 bool bFormula = (nFlags & IDF_FORMULA) != IDF_NONE;
833 bool bAsLink = mrCxt.isAsLink();
835 switch (node.type)
837 case sc::element_type_numeric:
839 // We need to copy numeric cells individually because of date type check.
840 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*node.data);
841 std::advance(it, nOffset);
842 sc::numeric_block::const_iterator itEnd = it;
843 std::advance(itEnd, nDataSize);
844 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
846 bool bCopy = mrCxt.isDateCell(mrSrcCol, nSrcRow) ? bDateTime : bNumeric;
847 if (!bCopy)
848 continue;
850 if (bAsLink)
851 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
852 else
853 mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, *it);
856 break;
857 case sc::element_type_string:
859 if (!bString)
860 break;
862 sc::string_block::const_iterator it = sc::string_block::begin(*node.data);
863 std::advance(it, nOffset);
864 sc::string_block::const_iterator itEnd = it;
865 std::advance(itEnd, nDataSize);
866 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
868 if (bAsLink)
869 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
870 else if (mpSharedStringPool)
872 // Re-intern the string if source is a different document.
873 svl::SharedString aInterned = mpSharedStringPool->intern( (*it).getString());
874 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aInterned);
876 else
877 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, *it);
880 break;
881 case sc::element_type_edittext:
883 if (!bString)
884 break;
886 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
887 std::advance(it, nOffset);
888 sc::edittext_block::const_iterator itEnd = it;
889 std::advance(itEnd, nDataSize);
890 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
893 if (bAsLink)
894 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
895 else
896 mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, **it);
899 break;
900 case sc::element_type_formula:
902 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
903 std::advance(it, nOffset);
904 sc::formula_block::const_iterator itEnd = it;
905 std::advance(itEnd, nDataSize);
906 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
908 ScFormulaCell& rSrcCell = const_cast<ScFormulaCell&>(**it);
909 bool bForceFormula = false;
910 if (bBoolean)
912 // See if the formula consists of =TRUE() or =FALSE().
913 ScTokenArray* pCode = rSrcCell.GetCode();
914 if (pCode && pCode->GetLen() == 1)
916 const formula::FormulaToken* p = pCode->First();
917 if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
918 // This is a boolean formula.
919 bForceFormula = true;
923 ScAddress aDestPos(mnCol, nSrcRow + mnRowOffset, mnTab);
924 if (bFormula || bForceFormula)
926 if (bAsLink)
927 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
928 else
930 mrDestCol.SetFormulaCell(
931 maDestBlockPos, nSrcRow + mnRowOffset,
932 new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos));
935 else if (bNumeric || bDateTime || bString)
937 // Always just copy the original row to the Undo Documen;
938 // do not create Value/string cells from formulas
940 sal_uInt16 nErr = rSrcCell.GetErrCode();
941 if (nErr)
943 // error codes are cloned with values
944 if (bNumeric)
946 if (bAsLink)
947 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
948 else
950 ScFormulaCell* pErrCell = new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos);
951 pErrCell->SetErrCode(nErr);
952 mrDestCol.SetFormulaCell(
953 maDestBlockPos, nSrcRow + mnRowOffset, pErrCell);
957 else if (rSrcCell.IsValue())
959 bool bCopy = mrCxt.isDateCell(mrSrcCol, nSrcRow) ? bDateTime : bNumeric;
960 if (!bCopy)
961 continue;
963 if (bAsLink)
964 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
965 else
966 mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, rSrcCell.GetValue());
968 else if (bString)
970 svl::SharedString aStr = rSrcCell.GetString();
971 if (aStr.isEmpty())
972 // do not clone empty string
973 continue;
975 if (bAsLink)
976 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
977 else if (rSrcCell.IsMultilineResult())
979 // Clone as an edit text object.
980 ScFieldEditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
981 rEngine.SetText(aStr.getString());
982 mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, rEngine.CreateTextObject());
984 else if (mpSharedStringPool)
986 // Re-intern the string if source is a different document.
987 svl::SharedString aInterned = mpSharedStringPool->intern( aStr.getString());
988 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aInterned);
990 else
992 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aStr);
998 break;
999 default:
1002 if (bCopyCellNotes)
1004 bool bCloneCaption = (nFlags & IDF_NOCAPTIONS) == IDF_NONE;
1005 duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
1010 class CopyTextAttrsFromClipHandler
1012 sc::CellTextAttrStoreType& mrAttrs;
1013 sc::CellTextAttrStoreType::iterator miPos;
1014 size_t mnDelta;
1016 public:
1017 CopyTextAttrsFromClipHandler( sc::CellTextAttrStoreType& rAttrs, size_t nDelta ) :
1018 mrAttrs(rAttrs), miPos(mrAttrs.begin()), mnDelta(nDelta) {}
1020 void operator() ( const sc::CellTextAttrStoreType::value_type& aNode, size_t nOffset, size_t nDataSize )
1022 if (aNode.type != sc::element_type_celltextattr)
1023 return;
1025 sc::celltextattr_block::const_iterator it = sc::celltextattr_block::begin(*aNode.data);
1026 std::advance(it, nOffset);
1027 sc::celltextattr_block::const_iterator itEnd = it;
1028 std::advance(itEnd, nDataSize);
1030 size_t nPos = aNode.position + nOffset + mnDelta;
1031 miPos = mrAttrs.set(miPos, nPos, it, itEnd);
1037 // rColumn = source
1038 // nRow1, nRow2 = target position
1040 void ScColumn::CopyFromClip(
1041 sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn )
1043 if ((rCxt.getInsertFlag() & IDF_ATTRIB) != IDF_NONE)
1045 if (rCxt.isSkipAttrForEmptyCells())
1047 // copy only attributes for non-empty cells between nRow1-nDy and nRow2-nDy.
1048 sc::SingleColumnSpanSet aSpanSet;
1049 aSpanSet.scan(rColumn, nRow1-nDy, nRow2-nDy);
1050 sc::SingleColumnSpanSet::SpansType aSpans;
1051 aSpanSet.getSpans(aSpans);
1052 std::for_each(
1053 aSpans.begin(), aSpans.end(), CopyAttrArrayByRange(*rColumn.pAttrArray, *pAttrArray, nDy));
1055 else
1056 rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray );
1058 if ((rCxt.getInsertFlag() & IDF_CONTENTS) == IDF_NONE)
1059 return;
1061 if (rCxt.isAsLink() && rCxt.getInsertFlag() == IDF_ALL)
1063 // We also reference empty cells for "ALL"
1064 // IDF_ALL must always contain more flags when compared to "Insert contents" as
1065 // contents can be selected one by one!
1067 ScAddress aDestPos( nCol, 0, nTab ); // Adapt Row
1069 // Create reference (Source Position)
1070 ScSingleRefData aRef;
1071 aRef.InitFlags(); // -> All absolute
1072 aRef.SetAbsCol(rColumn.nCol);
1073 aRef.SetAbsTab(rColumn.nTab);
1074 aRef.SetFlag3D(true);
1076 for (SCROW nDestRow = nRow1; nDestRow <= nRow2; nDestRow++)
1078 aRef.SetAbsRow(nDestRow - nDy); // Source row
1079 aDestPos.SetRow( nDestRow );
1081 ScTokenArray aArr;
1082 aArr.AddSingleReference( aRef );
1083 SetFormulaCell(nDestRow, new ScFormulaCell(pDocument, aDestPos, aArr));
1086 // Don't forget to copy the cell text attributes.
1087 CopyTextAttrsFromClipHandler aFunc(maCellTextAttrs, nDy);
1088 sc::ParseBlock(rColumn.maCellTextAttrs.begin(), rColumn.maCellTextAttrs, aFunc, nRow1-nDy, nRow2-nDy);
1090 return;
1093 // Compare the ScDocumentPool* to determine if we are copying within the
1094 // same document. If not, re-intern shared strings.
1095 svl::SharedStringPool* pSharedStringPool = (rColumn.pDocument->GetPool() != pDocument->GetPool()) ?
1096 &pDocument->GetSharedStringPool() : NULL;
1098 // nRow1 to nRow2 is for destination (this) column. Subtract nDy to get the source range.
1099 // Copy all cells in the source column (rColumn) from nRow1-nDy to nRow2-nDy to this column.
1101 CopyCellsFromClipHandler aFunc(rCxt, rColumn, *this, nTab, nCol, nDy, pSharedStringPool);
1102 sc::ParseBlock(rColumn.maCells.begin(), rColumn.maCells, aFunc, nRow1-nDy, nRow2-nDy);
1106 // Don't forget to copy the cell text attributes.
1107 CopyTextAttrsFromClipHandler aFunc(maCellTextAttrs, nDy);
1108 sc::ParseBlock(rColumn.maCellTextAttrs.begin(), rColumn.maCellTextAttrs, aFunc, nRow1-nDy, nRow2-nDy);
1112 void ScColumn::MixMarked(
1113 sc::MixDocContext& rCxt, const ScMarkData& rMark, sal_uInt16 nFunction,
1114 bool bSkipEmpty, const ScColumn& rSrcCol )
1116 SCROW nRow1, nRow2;
1118 if (rMark.IsMultiMarked())
1120 ScMarkArrayIter aIter( rMark.GetArray()+nCol );
1121 while (aIter.Next( nRow1, nRow2 ))
1122 MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol);
1126 namespace {
1128 // Result in rVal1
1129 bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunction )
1131 bool bOk = false;
1132 switch (nFunction)
1134 case PASTE_ADD:
1135 bOk = SubTotal::SafePlus( rVal1, nVal2 );
1136 break;
1137 case PASTE_SUB:
1138 nVal2 = -nVal2; // FIXME: Can we do this always without error?
1139 bOk = SubTotal::SafePlus( rVal1, nVal2 );
1140 break;
1141 case PASTE_MUL:
1142 bOk = SubTotal::SafeMult( rVal1, nVal2 );
1143 break;
1144 case PASTE_DIV:
1145 bOk = SubTotal::SafeDiv( rVal1, nVal2 );
1146 break;
1148 return bOk;
1151 void lcl_AddCode( ScTokenArray& rArr, const ScFormulaCell* pCell )
1153 rArr.AddOpCode(ocOpen);
1155 ScTokenArray* pCode = const_cast<ScFormulaCell*>(pCell)->GetCode();
1156 if (pCode)
1158 const formula::FormulaToken* pToken = pCode->First();
1159 while (pToken)
1161 rArr.AddToken( *pToken );
1162 pToken = pCode->Next();
1166 rArr.AddOpCode(ocClose);
1169 class MixDataHandler
1171 ScColumn& mrDestColumn;
1172 sc::ColumnBlockPosition& mrBlockPos;
1174 sc::CellStoreType maNewCells;
1175 sc::CellStoreType::iterator miNewCellsPos;
1177 size_t mnRowOffset;
1178 sal_uInt16 mnFunction;
1180 bool mbSkipEmpty;
1182 void doFunction( size_t nDestRow, double fVal1, double fVal2 )
1184 bool bOk = lcl_DoFunction(fVal1, fVal2, mnFunction);
1186 if (bOk)
1187 miNewCellsPos = maNewCells.set(miNewCellsPos, nDestRow-mnRowOffset, fVal1);
1188 else
1190 ScAddress aPos(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab());
1192 ScFormulaCell* pFC = new ScFormulaCell(&mrDestColumn.GetDoc(), aPos);
1193 pFC->SetErrCode(errNoValue);
1195 miNewCellsPos = maNewCells.set(miNewCellsPos, nDestRow-mnRowOffset, pFC);
1199 public:
1200 MixDataHandler(
1201 sc::ColumnBlockPosition& rBlockPos,
1202 ScColumn& rDestColumn,
1203 SCROW nRow1, SCROW nRow2,
1204 sal_uInt16 nFunction, bool bSkipEmpty) :
1205 mrDestColumn(rDestColumn),
1206 mrBlockPos(rBlockPos),
1207 maNewCells(nRow2 - nRow1 + 1),
1208 miNewCellsPos(maNewCells.begin()),
1209 mnRowOffset(nRow1),
1210 mnFunction(nFunction),
1211 mbSkipEmpty(bSkipEmpty)
1215 void operator() (size_t nRow, double f)
1217 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow);
1218 mrBlockPos.miCellPos = aPos.first;
1219 switch (aPos.first->type)
1221 case sc::element_type_empty:
1222 case sc::element_type_numeric:
1224 double fSrcVal = 0.0;
1225 if (aPos.first->type == sc::element_type_numeric)
1226 fSrcVal = sc::numeric_block::at(*aPos.first->data, aPos.second);
1228 // Both src and dest are of numeric type.
1229 doFunction(nRow, f, fSrcVal);
1231 break;
1232 case sc::element_type_formula:
1234 // Combination of value and at least one formula -> Create formula
1235 ScTokenArray aArr;
1237 // First row
1238 aArr.AddDouble(f);
1240 // Operator
1241 OpCode eOp = ocAdd;
1242 switch (mnFunction)
1244 case PASTE_ADD: eOp = ocAdd; break;
1245 case PASTE_SUB: eOp = ocSub; break;
1246 case PASTE_MUL: eOp = ocMul; break;
1247 case PASTE_DIV: eOp = ocDiv; break;
1249 aArr.AddOpCode(eOp); // Function
1251 // Second row
1252 ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second);
1253 lcl_AddCode(aArr, pDest);
1255 miNewCellsPos = maNewCells.set(
1256 miNewCellsPos, nRow-mnRowOffset,
1257 new ScFormulaCell(
1258 &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1260 break;
1261 case sc::element_type_string:
1262 case sc::element_type_edittext:
1264 // Destination cell is not a number. Just take the source cell.
1265 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f);
1267 break;
1268 default:
1273 void operator() (size_t nRow, const svl::SharedString& rStr)
1275 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, rStr);
1278 void operator() (size_t nRow, const EditTextObject* p)
1280 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, p->Clone());
1283 void operator() (size_t nRow, const ScFormulaCell* p)
1285 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow);
1286 mrBlockPos.miCellPos = aPos.first;
1287 switch (aPos.first->type)
1289 case sc::element_type_numeric:
1291 // Source is formula, and dest is value.
1292 ScTokenArray aArr;
1294 // First row
1295 lcl_AddCode(aArr, p);
1297 // Operator
1298 OpCode eOp = ocAdd;
1299 switch (mnFunction)
1301 case PASTE_ADD: eOp = ocAdd; break;
1302 case PASTE_SUB: eOp = ocSub; break;
1303 case PASTE_MUL: eOp = ocMul; break;
1304 case PASTE_DIV: eOp = ocDiv; break;
1306 aArr.AddOpCode(eOp); // Function
1308 // Second row
1309 aArr.AddDouble(sc::numeric_block::at(*aPos.first->data, aPos.second));
1311 miNewCellsPos = maNewCells.set(
1312 miNewCellsPos, nRow-mnRowOffset,
1313 new ScFormulaCell(
1314 &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1316 break;
1317 case sc::element_type_formula:
1319 // Both are formulas.
1320 ScTokenArray aArr;
1322 // First row
1323 lcl_AddCode(aArr, p);
1325 // Operator
1326 OpCode eOp = ocAdd;
1327 switch (mnFunction)
1329 case PASTE_ADD: eOp = ocAdd; break;
1330 case PASTE_SUB: eOp = ocSub; break;
1331 case PASTE_MUL: eOp = ocMul; break;
1332 case PASTE_DIV: eOp = ocDiv; break;
1334 aArr.AddOpCode(eOp); // Function
1336 // Second row
1337 ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second);
1338 lcl_AddCode(aArr, pDest);
1340 miNewCellsPos = maNewCells.set(
1341 miNewCellsPos, nRow-mnRowOffset,
1342 new ScFormulaCell(
1343 &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1345 break;
1346 case sc::element_type_string:
1347 case sc::element_type_edittext:
1348 case sc::element_type_empty:
1350 // Destination cell is not a number. Just take the source cell.
1351 ScAddress aDestPos(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab());
1352 miNewCellsPos = maNewCells.set(
1353 miNewCellsPos, nRow-mnRowOffset, new ScFormulaCell(*p, mrDestColumn.GetDoc(), aDestPos));
1355 break;
1356 default:
1362 * Empty cell series in the source (clip) document.
1364 void operator() (mdds::mtv::element_t, size_t nTopRow, size_t nDataSize)
1366 if (mbSkipEmpty)
1367 return;
1369 // Source cells are empty. Treat them as if they have a value of 0.0.
1370 for (size_t i = 0; i < nDataSize; ++i)
1372 size_t nDestRow = nTopRow + i;
1373 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nDestRow);
1374 mrBlockPos.miCellPos = aPos.first;
1375 switch (aPos.first->type)
1377 case sc::element_type_numeric:
1379 double fVal1 = 0.0;
1380 double fVal2 = sc::numeric_block::at(*aPos.first->data, aPos.second);
1381 doFunction(nDestRow, fVal1, fVal2);
1383 break;
1384 case sc::element_type_string:
1386 const svl::SharedString& aVal = sc::string_block::at(*aPos.first->data, aPos.second);
1387 miNewCellsPos = maNewCells.set(
1388 miNewCellsPos, nDestRow-mnRowOffset, aVal);
1390 break;
1391 case sc::element_type_edittext:
1393 EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
1394 miNewCellsPos = maNewCells.set(
1395 miNewCellsPos, nDestRow-mnRowOffset, pObj->Clone());
1397 break;
1398 case sc::element_type_formula:
1400 ScTokenArray aArr;
1402 // First row
1403 ScFormulaCell* pSrc = sc::formula_block::at(*aPos.first->data, aPos.second);
1404 lcl_AddCode( aArr, pSrc);
1406 // Operator
1407 OpCode eOp = ocAdd;
1408 switch (mnFunction)
1410 case PASTE_ADD: eOp = ocAdd; break;
1411 case PASTE_SUB: eOp = ocSub; break;
1412 case PASTE_MUL: eOp = ocMul; break;
1413 case PASTE_DIV: eOp = ocDiv; break;
1416 aArr.AddOpCode(eOp); // Function
1417 aArr.AddDouble(0.0);
1419 miNewCellsPos = maNewCells.set(
1420 miNewCellsPos, nDestRow-mnRowOffset,
1421 new ScFormulaCell(
1422 &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab()), aArr));
1424 break;
1425 default:
1432 * Set the new cells to the destination (this) column.
1434 void commit()
1436 sc::CellStoreType& rDestCells = mrDestColumn.GetCellStore();
1438 // Stop all formula cells in the destination range first.
1439 sc::CellStoreType::position_type aPos = rDestCells.position(mrBlockPos.miCellPos, mnRowOffset);
1440 mrDestColumn.DetachFormulaCells(aPos, maNewCells.size());
1442 // Move the new cells to the destination range.
1443 sc::CellStoreType::iterator& itDestPos = mrBlockPos.miCellPos;
1444 sc::CellTextAttrStoreType::iterator& itDestAttrPos = mrBlockPos.miCellTextAttrPos;
1446 sc::CellStoreType::iterator it = maNewCells.begin(), itEnd = maNewCells.end();
1447 for (; it != itEnd; ++it)
1449 bool bHasContent = true;
1450 size_t nDestRow = mnRowOffset + it->position;
1452 switch (it->type)
1454 case sc::element_type_numeric:
1456 sc::numeric_block::iterator itData = sc::numeric_block::begin(*it->data);
1457 sc::numeric_block::iterator itDataEnd = sc::numeric_block::end(*it->data);
1458 itDestPos = mrDestColumn.GetCellStore().set(itDestPos, nDestRow, itData, itDataEnd);
1460 break;
1461 case sc::element_type_string:
1463 sc::string_block::iterator itData = sc::string_block::begin(*it->data);
1464 sc::string_block::iterator itDataEnd = sc::string_block::end(*it->data);
1465 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1467 break;
1468 case sc::element_type_edittext:
1470 sc::edittext_block::iterator itData = sc::edittext_block::begin(*it->data);
1471 sc::edittext_block::iterator itDataEnd = sc::edittext_block::end(*it->data);
1472 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1474 break;
1475 case sc::element_type_formula:
1477 sc::formula_block::iterator itData = sc::formula_block::begin(*it->data);
1478 sc::formula_block::iterator itDataEnd = sc::formula_block::end(*it->data);
1480 // Group new formula cells before inserting them.
1481 sc::SharedFormulaUtil::groupFormulaCells(itData, itDataEnd);
1483 // Insert the formula cells to the column.
1484 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1486 // Merge with the previous formula group (if any).
1487 aPos = rDestCells.position(itDestPos, nDestRow);
1488 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1490 // Merge with the next formula group (if any).
1491 size_t nNextRow = nDestRow + it->size;
1492 if (ValidRow(nNextRow))
1494 aPos = rDestCells.position(aPos.first, nNextRow);
1495 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1498 break;
1499 case sc::element_type_empty:
1501 itDestPos = rDestCells.set_empty(itDestPos, nDestRow, nDestRow+it->size-1);
1502 bHasContent = false;
1504 break;
1505 default:
1509 sc::CellTextAttrStoreType& rDestAttrs = mrDestColumn.GetCellAttrStore();
1510 if (bHasContent)
1512 std::vector<sc::CellTextAttr> aAttrs(it->size, sc::CellTextAttr());
1513 itDestAttrPos = rDestAttrs.set(itDestAttrPos, nDestRow, aAttrs.begin(), aAttrs.end());
1515 else
1516 itDestAttrPos = rDestAttrs.set_empty(itDestAttrPos, nDestRow, nDestRow+it->size-1);
1519 maNewCells.release();
1525 void ScColumn::MixData(
1526 sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, sal_uInt16 nFunction,
1527 bool bSkipEmpty, const ScColumn& rSrcCol )
1529 // destination (this column) block position.
1531 sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
1532 if (!p)
1533 return;
1535 MixDataHandler aFunc(*p, *this, nRow1, nRow2, nFunction, bSkipEmpty);
1536 sc::ParseAll(rSrcCol.maCells.begin(), rSrcCol.maCells, nRow1, nRow2, aFunc, aFunc);
1538 aFunc.commit();
1539 CellStorageModified();
1542 ScAttrIterator* ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
1544 return new ScAttrIterator( pAttrArray, nStartRow, nEndRow );
1547 namespace {
1549 class StartListenersHandler
1551 sc::StartListeningContext* mpCxt;
1552 bool mbAllListeners;
1554 public:
1555 StartListenersHandler( sc::StartListeningContext& rCxt, bool bAllListeners ) :
1556 mpCxt(&rCxt), mbAllListeners(bAllListeners) {}
1558 void operator() ( sc::CellStoreType::value_type& aBlk )
1560 if (aBlk.type != sc::element_type_formula)
1561 return;
1563 ScFormulaCell** pp = &sc::formula_block::at(*aBlk.data, 0);
1564 ScFormulaCell** ppEnd = pp + aBlk.size;
1566 for (; pp != ppEnd; ++pp)
1568 ScFormulaCell& rFC = **pp;
1569 if (!mbAllListeners && !rFC.NeedsListening())
1570 continue;
1572 if (rFC.IsSharedTop())
1574 sc::SharedFormulaUtil::startListeningAsGroup(*mpCxt, pp);
1575 pp += rFC.GetSharedLength() - 1; // Move to the last cell in the group.
1577 else
1578 rFC.StartListeningTo(*mpCxt);
1585 void ScColumn::StartListeners( sc::StartListeningContext& rCxt, bool bAll )
1587 std::for_each(maCells.begin(), maCells.end(), StartListenersHandler(rCxt, bAll));
1590 namespace {
1592 void applyTextNumFormat( ScColumn& rCol, SCROW nRow, SvNumberFormatter* pFormatter )
1594 sal_uInt32 nFormat = pFormatter->GetStandardFormat(css::util::NumberFormat::TEXT);
1595 ScPatternAttr aNewAttrs(rCol.GetDoc().GetPool());
1596 SfxItemSet& rSet = aNewAttrs.GetItemSet();
1597 rSet.Put(SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat));
1598 rCol.ApplyPattern(nRow, aNewAttrs);
1603 bool ScColumn::ParseString(
1604 ScCellValue& rCell, SCROW nRow, SCTAB nTabP, const OUString& rString,
1605 formula::FormulaGrammar::AddressConvention eConv,
1606 ScSetStringParam* pParam )
1608 if (rString.isEmpty())
1609 return false;
1611 bool bNumFmtSet = false;
1613 ScSetStringParam aParam;
1615 if (pParam)
1616 aParam = *pParam;
1618 sal_uInt32 nIndex = 0;
1619 sal_uInt32 nOldIndex = 0;
1620 sal_Unicode cFirstChar;
1621 if (!aParam.mpNumFormatter)
1622 aParam.mpNumFormatter = pDocument->GetFormatTable();
1624 nIndex = nOldIndex = GetNumberFormat( nRow );
1625 if ( rString.getLength() > 1
1626 && aParam.mpNumFormatter->GetType(nIndex) != css::util::NumberFormat::TEXT )
1627 cFirstChar = rString[0];
1628 else
1629 cFirstChar = 0; // Text
1631 svl::SharedStringPool& rPool = pDocument->GetSharedStringPool();
1633 if ( cFirstChar == '=' )
1635 if ( rString.getLength() == 1 ) // = Text
1637 rCell.set(rPool.intern(rString));
1639 else if (aParam.meSetTextNumFormat == ScSetStringParam::Always)
1641 // Set the cell format type to Text.
1642 applyTextNumFormat(*this, nRow, aParam.mpNumFormatter);
1643 rCell.set(rPool.intern(rString));
1645 else // = Formula
1646 rCell.set(
1647 new ScFormulaCell(
1648 pDocument, ScAddress(nCol, nRow, nTabP), rString,
1649 formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_DEFAULT, eConv),
1650 MM_NONE));
1652 else if ( cFirstChar == '\'') // 'Text
1654 bool bNumeric = false;
1655 if (aParam.mbHandleApostrophe)
1657 // Cell format is not 'Text', and the first char
1658 // is an apostrophe. Check if the input is considered a number.
1659 OUString aTest = rString.copy(1);
1660 double fTest;
1661 bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest);
1662 if (bNumeric)
1663 // This is a number. Strip out the first char.
1664 rCell.set(rPool.intern(aTest));
1666 if (!bNumeric)
1667 // This is normal text. Take it as-is.
1668 rCell.set(rPool.intern(rString));
1670 else
1672 double nVal;
1676 if (aParam.mbDetectNumberFormat)
1678 if (!aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
1679 break;
1681 // convert back to the original language if a built-in format was detected
1682 const SvNumberformat* pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex );
1683 if ( pOldFormat )
1684 nIndex = aParam.mpNumFormatter->GetFormatForLanguageIfBuiltIn( nIndex, pOldFormat->GetLanguage() );
1686 rCell.set(nVal);
1687 if ( nIndex != nOldIndex)
1689 // #i22345# New behavior: Apply the detected number format only if
1690 // the old one was the default number, date, time or boolean format.
1691 // Exception: If the new format is boolean, always apply it.
1693 bool bOverwrite = false;
1694 if ( pOldFormat )
1696 short nOldType = pOldFormat->GetType() & ~css::util::NumberFormat::DEFINED;
1697 if ( nOldType == css::util::NumberFormat::NUMBER || nOldType == css::util::NumberFormat::DATE ||
1698 nOldType == css::util::NumberFormat::TIME || nOldType == css::util::NumberFormat::LOGICAL )
1700 if ( nOldIndex == aParam.mpNumFormatter->GetStandardFormat(
1701 nOldType, pOldFormat->GetLanguage() ) )
1703 bOverwrite = true; // default of these types can be overwritten
1707 if ( !bOverwrite && aParam.mpNumFormatter->GetType( nIndex ) == css::util::NumberFormat::LOGICAL )
1709 bOverwrite = true; // overwrite anything if boolean was detected
1712 if ( bOverwrite )
1714 ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT,
1715 (sal_uInt32) nIndex) );
1716 bNumFmtSet = true;
1720 else if (aParam.meSetTextNumFormat != ScSetStringParam::Always)
1722 // Only check if the string is a regular number.
1723 const LocaleDataWrapper* pLocale = aParam.mpNumFormatter->GetLocaleData();
1724 if (!pLocale)
1725 break;
1727 LocaleDataItem aLocaleItem = pLocale->getLocaleItem();
1728 const OUString& rDecSep = aLocaleItem.decimalSeparator;
1729 const OUString& rGroupSep = aLocaleItem.thousandSeparator;
1730 if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1)
1731 break;
1733 sal_Unicode dsep = rDecSep[0];
1734 sal_Unicode gsep = rGroupSep[0];
1736 if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, nVal))
1737 break;
1739 rCell.set(nVal);
1742 while (false);
1744 if (rCell.meType == CELLTYPE_NONE)
1746 if (aParam.meSetTextNumFormat != ScSetStringParam::Never && aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
1748 // Set the cell format type to Text.
1749 applyTextNumFormat(*this, nRow, aParam.mpNumFormatter);
1752 rCell.set(rPool.intern(rString));
1756 return bNumFmtSet;
1760 * Returns true if the cell format was set as well
1762 bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString,
1763 formula::FormulaGrammar::AddressConvention eConv,
1764 ScSetStringParam* pParam )
1766 if (!ValidRow(nRow))
1767 return false;
1769 ScCellValue aNewCell;
1770 bool bNumFmtSet = ParseString(aNewCell, nRow, nTabP, rString, eConv, pParam);
1771 if (pParam)
1772 aNewCell.release(*this, nRow, pParam->meStartListening);
1773 else
1774 aNewCell.release(*this, nRow);
1776 // Do not set Formats and Formulas here anymore!
1777 // These are queried during output
1779 return bNumFmtSet;
1782 void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
1784 pEditText->NormalizeString(pDocument->GetSharedStringPool());
1785 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1786 maCells.set(it, nRow, pEditText);
1787 maCellTextAttrs.set(nRow, sc::CellTextAttr());
1788 CellStorageModified();
1790 BroadcastNewCell(nRow);
1793 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, EditTextObject* pEditText )
1795 pEditText->NormalizeString(pDocument->GetSharedStringPool());
1796 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
1797 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText);
1798 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
1799 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1801 CellStorageModified();
1803 BroadcastNewCell(nRow);
1806 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const EditTextObject& rEditText )
1808 if (pDocument->GetEditPool() == rEditText.GetPool())
1810 SetEditText(rBlockPos, nRow, rEditText.Clone());
1811 return;
1814 // rats, yet another "spool"
1815 // Sadly there is no other way to change the Pool than to
1816 // "spool" the Object through a corresponding Engine
1817 EditEngine& rEngine = pDocument->GetEditEngine();
1818 rEngine.SetText(rEditText);
1819 SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
1820 return;
1823 void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
1825 if (pEditPool && pDocument->GetEditPool() == pEditPool)
1827 SetEditText(nRow, rEditText.Clone());
1828 return;
1831 // rats, yet another "spool"
1832 // Sadly there is no other way to change the Pool than to
1833 // "spool" the Object through a corresponding Engine
1834 EditEngine& rEngine = pDocument->GetEditEngine();
1835 rEngine.SetText(rEditText);
1836 SetEditText(nRow, rEngine.CreateTextObject());
1837 return;
1840 void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram )
1842 ScAddress aPos(nCol, nRow, nTab);
1844 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1845 ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rArray, eGram);
1846 sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1847 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1848 pCell->SetNeedNumberFormat(true);
1849 it = maCells.set(it, nRow, pCell);
1850 maCellTextAttrs.set(nRow, sc::CellTextAttr());
1852 CellStorageModified();
1854 AttachNewFormulaCell(it, nRow, *pCell);
1857 void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
1859 ScAddress aPos(nCol, nRow, nTab);
1861 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1862 ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rFormula, eGram);
1863 sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1864 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1865 pCell->SetNeedNumberFormat(true);
1866 it = maCells.set(it, nRow, pCell);
1867 maCellTextAttrs.set(nRow, sc::CellTextAttr());
1869 CellStorageModified();
1871 AttachNewFormulaCell(it, nRow, *pCell);
1874 ScFormulaCell* ScColumn::SetFormulaCell(
1875 SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType )
1877 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1878 sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1879 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1880 pCell->SetNeedNumberFormat(true);
1881 it = maCells.set(it, nRow, pCell);
1882 maCellTextAttrs.set(nRow, sc::CellTextAttr());
1884 CellStorageModified();
1886 AttachNewFormulaCell(it, nRow, *pCell, true, eListenType);
1887 return pCell;
1890 ScFormulaCell* ScColumn::SetFormulaCell(
1891 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell,
1892 sc::StartListeningType eListenType )
1894 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
1895 sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1896 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1897 pCell->SetNeedNumberFormat(true);
1898 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pCell);
1899 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
1900 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1902 CellStorageModified();
1904 AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, true, eListenType);
1905 return pCell;
1908 bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells )
1910 if (!ValidRow(nRow))
1911 return false;
1913 SCROW nEndRow = nRow + rCells.size() - 1;
1914 if (!ValidRow(nEndRow))
1915 return false;
1917 sc::CellStoreType::position_type aPos = maCells.position(nRow);
1919 // Detach all formula cells that will be overwritten.
1920 DetachFormulaCells(aPos, rCells.size());
1922 for (size_t i = 0, n = rCells.size(); i < n; ++i)
1924 SCROW nThisRow = nRow + i;
1925 sal_uInt32 nFmt = GetNumberFormat(nThisRow);
1926 if ((nFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1927 rCells[i]->SetNeedNumberFormat(true);
1930 std::vector<sc::CellTextAttr> aDefaults(rCells.size(), sc::CellTextAttr());
1931 maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end());
1933 maCells.set(aPos.first, nRow, rCells.begin(), rCells.end());
1935 CellStorageModified();
1937 AttachNewFormulaCells(aPos, rCells.size());
1939 return true;
1942 svl::SharedString ScColumn::GetSharedString( SCROW nRow ) const
1944 sc::CellStoreType::const_position_type aPos = maCells.position(nRow);
1945 switch (aPos.first->type)
1947 case sc::element_type_string:
1948 return sc::string_block::at(*aPos.first->data, aPos.second);
1949 case sc::element_type_edittext:
1951 const EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
1952 std::vector<svl::SharedString> aSSs = pObj->GetSharedStrings();
1953 if (aSSs.size() != 1)
1954 // We don't handle multiline content for now.
1955 return svl::SharedString();
1957 return aSSs[0];
1959 break;
1960 default:
1963 return svl::SharedString();
1966 namespace {
1968 class FilterEntriesHandler
1970 ScColumn& mrColumn;
1971 std::vector<ScTypedStrData>& mrStrings;
1972 bool mbHasDates;
1974 void processCell(SCROW nRow, ScRefCellValue& rCell)
1976 SvNumberFormatter* pFormatter = mrColumn.GetDoc().GetFormatTable();
1977 OUString aStr;
1978 sal_uLong nFormat = mrColumn.GetNumberFormat(nRow);
1979 ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter, &mrColumn.GetDoc());
1981 if (rCell.hasString())
1983 mrStrings.push_back(ScTypedStrData(aStr));
1984 return;
1987 double fVal = 0.0;
1989 switch (rCell.meType)
1991 case CELLTYPE_VALUE:
1992 fVal = rCell.mfValue;
1993 break;
1995 case CELLTYPE_FORMULA:
1997 ScFormulaCell* pFC = rCell.mpFormula;
1998 sal_uInt16 nErr = pFC->GetErrCode();
1999 if (nErr)
2001 // Error cell is evaluated as string (for now).
2002 OUString aErr = ScGlobal::GetErrorString(nErr);
2003 if (!aErr.isEmpty())
2005 mrStrings.push_back(ScTypedStrData(aErr));
2006 return;
2009 else
2010 fVal = pFC->GetValue();
2012 break;
2013 default:
2017 short nType = pFormatter->GetType(nFormat);
2018 bool bDate = false;
2019 if ((nType & css::util::NumberFormat::DATE) && !(nType & css::util::NumberFormat::TIME))
2021 // special case for date values. Disregard the time
2022 // element if the number format is of date type.
2023 fVal = rtl::math::approxFloor(fVal);
2024 mbHasDates = true;
2025 bDate = true;
2026 // Convert string representation to ISO 8601 date to eliminate
2027 // locale dependent behaviour later when filtering for dates.
2028 sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_YYYYMMDD);
2029 pFormatter->GetInputLineString( fVal, nIndex, aStr);
2031 // maybe extend ScTypedStrData enum is also an option here
2032 mrStrings.push_back(ScTypedStrData(aStr, fVal, ScTypedStrData::Value,bDate));
2035 public:
2036 FilterEntriesHandler(ScColumn& rColumn, std::vector<ScTypedStrData>& rStrings) :
2037 mrColumn(rColumn), mrStrings(rStrings), mbHasDates(false) {}
2039 void operator() (size_t nRow, double fVal)
2041 ScRefCellValue aCell(fVal);
2042 processCell(nRow, aCell);
2045 void operator() (size_t nRow, const svl::SharedString& rStr)
2047 ScRefCellValue aCell(&rStr);
2048 processCell(nRow, aCell);
2051 void operator() (size_t nRow, const EditTextObject* p)
2053 ScRefCellValue aCell(p);
2054 processCell(nRow, aCell);
2057 void operator() (size_t nRow, const ScFormulaCell* p)
2059 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
2060 processCell(nRow, aCell);
2063 void operator() (const int nElemType, size_t nRow, size_t /* nDataSize */)
2065 if ( nElemType == sc::element_type_empty ) {
2066 mrStrings.push_back(ScTypedStrData(OUString()));
2067 return;
2069 ScRefCellValue aCell = mrColumn.GetCellValue(nRow);
2070 processCell(nRow, aCell);
2073 bool hasDates() const { return mbHasDates; }
2078 void ScColumn::GetFilterEntries(
2079 sc::ColumnBlockConstPosition& rBlockPos, SCROW nStartRow, SCROW nEndRow,
2080 std::vector<ScTypedStrData>& rStrings, bool& rHasDates )
2082 FilterEntriesHandler aFunc(*this, rStrings);
2083 rBlockPos.miCellPos =
2084 sc::ParseAll(rBlockPos.miCellPos, maCells, nStartRow, nEndRow, aFunc, aFunc);
2085 rHasDates = aFunc.hasDates();
2088 namespace {
2091 * Iterate over only string and edit-text cells.
2093 class StrCellIterator
2095 typedef std::pair<sc::CellStoreType::const_iterator,size_t> PosType;
2096 PosType maPos;
2097 sc::CellStoreType::const_iterator miBeg;
2098 sc::CellStoreType::const_iterator miEnd;
2099 const ScDocument* mpDoc;
2100 public:
2101 StrCellIterator(const sc::CellStoreType& rCells, SCROW nStart, const ScDocument* pDoc) :
2102 miBeg(rCells.begin()), miEnd(rCells.end()), mpDoc(pDoc)
2104 if (ValidRow(nStart))
2105 maPos = rCells.position(nStart);
2106 else
2107 // Make this iterator invalid.
2108 maPos.first = miEnd;
2111 bool valid() const { return (maPos.first != miEnd); }
2113 bool has() const
2115 return (maPos.first->type == sc::element_type_string || maPos.first->type == sc::element_type_edittext);
2118 bool prev()
2120 if (!has())
2122 // Not in a string block. Move back until we hit a string block.
2123 while (!has())
2125 if (maPos.first == miBeg)
2126 return false;
2128 --maPos.first; // move to the preceding block.
2129 maPos.second = maPos.first->size - 1; // last cell in the block.
2131 return true;
2134 // We are in a string block.
2135 if (maPos.second > 0)
2137 // Move back one cell in the same block.
2138 --maPos.second;
2140 else
2142 // Move back to the preceding string block.
2143 while (true)
2145 if (maPos.first == miBeg)
2146 return false;
2148 // Move to the last cell of the previous block.
2149 --maPos.first;
2150 maPos.second = maPos.first->size - 1;
2151 if (has())
2152 break;
2155 return true;
2158 bool next()
2160 if (!has())
2162 // Not in a string block. Move forward until we hit a string block.
2163 while (!has())
2165 ++maPos.first;
2166 if (maPos.first == miEnd)
2167 return false;
2169 maPos.second = 0; // First cell in this block.
2171 return true;
2174 // We are in a string block.
2175 ++maPos.second;
2176 if (maPos.second >= maPos.first->size)
2178 // Move to the next string block.
2179 while (true)
2181 ++maPos.first;
2182 if (maPos.first == miEnd)
2183 return false;
2185 maPos.second = 0;
2186 if (has())
2187 break;
2190 return true;
2193 OUString get() const
2195 switch (maPos.first->type)
2197 case sc::element_type_string:
2198 return sc::string_block::at(*maPos.first->data, maPos.second).getString();
2199 case sc::element_type_edittext:
2201 const EditTextObject* p = sc::edittext_block::at(*maPos.first->data, maPos.second);
2202 return ScEditUtil::GetString(*p, mpDoc);
2204 default:
2207 return OUString();
2213 // GetDataEntries - Strings from continuous Section around nRow
2215 // DATENT_MAX - max. number of entries in list for auto entry
2216 // DATENT_SEARCH - max. number of cells that get transparent - new: only count Strings
2217 #define DATENT_MAX 200
2218 #define DATENT_SEARCH 2000
2220 bool ScColumn::GetDataEntries(
2221 SCROW nStartRow, std::set<ScTypedStrData>& rStrings, bool bLimit ) const
2223 // Start at the specified row position, and collect all string values
2224 // going upward and downward directions in parallel. The start position
2225 // cell must be skipped.
2227 StrCellIterator aItrUp(maCells, nStartRow, pDocument);
2228 StrCellIterator aItrDown(maCells, nStartRow+1, pDocument);
2230 bool bMoveUp = aItrUp.valid();
2231 if (!bMoveUp)
2232 // Current cell is invalid.
2233 return false;
2235 // Skip the start position cell.
2236 bMoveUp = aItrUp.prev(); // Find the previous string cell position.
2238 bool bMoveDown = aItrDown.valid();
2239 if (bMoveDown && !aItrDown.has())
2240 bMoveDown = aItrDown.next(); // Find the next string cell position.
2242 bool bFound = false;
2243 size_t nCellsSearched = 0;
2244 while (bMoveUp || bMoveDown)
2246 if (bMoveUp)
2248 // Get the current string and move up.
2249 OUString aStr = aItrUp.get();
2250 if (!aStr.isEmpty())
2252 bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second;
2253 if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
2254 return true; // Maximum reached
2255 bFound = true;
2258 if (bLimit && ++nCellsSearched >= DATENT_SEARCH)
2259 return bFound; // max search cell count reached.
2261 bMoveUp = aItrUp.prev();
2264 if (bMoveDown)
2266 // Get the current string and move down.
2267 OUString aStr = aItrDown.get();
2268 if (!aStr.isEmpty())
2270 bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second;
2271 if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
2272 return true; // Maximum reached
2273 bFound = true;
2276 if (bLimit && ++nCellsSearched >= DATENT_SEARCH)
2277 return bFound; // max search cell count reached.
2279 bMoveDown = aItrDown.next();
2283 return bFound;
2286 namespace {
2288 class FormulaToValueHandler
2290 struct Entry
2292 SCROW mnRow;
2293 ScCellValue maValue;
2295 Entry(SCROW nRow, double f) : mnRow(nRow), maValue(f) {}
2296 Entry(SCROW nRow, const svl::SharedString& rStr) : mnRow(nRow), maValue(rStr) {}
2299 typedef std::vector<Entry> EntriesType;
2300 EntriesType maEntries;
2302 public:
2304 void operator() (size_t nRow, const ScFormulaCell* p)
2306 ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
2307 if (p2->IsValue())
2308 maEntries.push_back(Entry(nRow, p2->GetValue()));
2309 else
2310 maEntries.push_back(Entry(nRow, p2->GetString()));
2313 void commitCells(ScColumn& rColumn)
2315 sc::ColumnBlockPosition aBlockPos;
2316 rColumn.InitBlockPosition(aBlockPos);
2318 EntriesType::iterator it = maEntries.begin(), itEnd = maEntries.end();
2319 for (; it != itEnd; ++it)
2321 Entry& r = *it;
2322 switch (r.maValue.meType)
2324 case CELLTYPE_VALUE:
2325 rColumn.SetValue(aBlockPos, r.mnRow, r.maValue.mfValue, false);
2326 break;
2327 case CELLTYPE_STRING:
2328 rColumn.SetRawString(aBlockPos, r.mnRow, *r.maValue.mpString, false);
2329 default:
2338 void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
2340 FormulaToValueHandler aFunc;
2341 sc::CellStoreType::const_iterator itPos = maCells.begin();
2343 ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
2344 SCROW nTop = -1;
2345 SCROW nBottom = -1;
2346 const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
2347 while (pPattern)
2349 const ScProtectionAttr* pAttr = static_cast<const ScProtectionAttr*>(&pPattern->GetItem(ATTR_PROTECTION));
2350 if ( pAttr->GetHideCell() )
2351 DeleteArea( nTop, nBottom, IDF_CONTENTS );
2352 else if ( pAttr->GetHideFormula() )
2354 // Replace all formula cells between nTop and nBottom with raw value cells.
2355 itPos = sc::ParseFormula(itPos, maCells, nTop, nBottom, aFunc);
2358 pPattern = aAttrIter.Next( nTop, nBottom );
2361 aFunc.commitCells(*this);
2364 void ScColumn::SetError( SCROW nRow, const sal_uInt16 nError)
2366 if (!ValidRow(nRow))
2367 return;
2369 ScFormulaCell* pCell = new ScFormulaCell(pDocument, ScAddress(nCol, nRow, nTab));
2370 pCell->SetErrCode(nError);
2372 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
2373 it = maCells.set(it, nRow, pCell);
2374 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2376 CellStorageModified();
2378 AttachNewFormulaCell(it, nRow, *pCell);
2381 void ScColumn::SetRawString( SCROW nRow, const OUString& rStr, bool bBroadcast )
2383 if (!ValidRow(nRow))
2384 return;
2386 svl::SharedString aSS = pDocument->GetSharedStringPool().intern(rStr);
2387 if (!aSS.getData())
2388 return;
2390 SetRawString(nRow, aSS, bBroadcast);
2393 void ScColumn::SetRawString( SCROW nRow, const svl::SharedString& rStr, bool bBroadcast )
2395 if (!ValidRow(nRow))
2396 return;
2398 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
2399 maCells.set(it, nRow, rStr);
2400 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2402 CellStorageModified();
2404 if (bBroadcast)
2405 BroadcastNewCell(nRow);
2408 void ScColumn::SetRawString(
2409 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const svl::SharedString& rStr, bool bBroadcast )
2411 if (!ValidRow(nRow))
2412 return;
2414 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
2415 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr);
2416 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2417 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2419 CellStorageModified();
2421 if (bBroadcast)
2422 BroadcastNewCell(nRow);
2425 void ScColumn::SetValue( SCROW nRow, double fVal )
2427 if (!ValidRow(nRow))
2428 return;
2430 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
2431 maCells.set(it, nRow, fVal);
2432 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2434 CellStorageModified();
2436 BroadcastNewCell(nRow);
2439 void ScColumn::SetValue(
2440 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, double fVal, bool bBroadcast )
2442 if (!ValidRow(nRow))
2443 return;
2445 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
2446 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal);
2447 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2448 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2450 CellStorageModified();
2452 if (bBroadcast)
2453 BroadcastNewCell(nRow);
2456 void ScColumn::GetString( SCROW nRow, OUString& rString ) const
2458 ScRefCellValue aCell = GetCellValue(nRow);
2460 // ugly hack for ordering problem with GetNumberFormat and missing inherited formats
2461 if (aCell.meType == CELLTYPE_FORMULA)
2462 aCell.mpFormula->MaybeInterpret();
2464 sal_uLong nFormat = GetNumberFormat(nRow);
2465 Color* pColor = NULL;
2466 ScCellFormat::GetString(aCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()), pDocument);
2469 double* ScColumn::GetValueCell( SCROW nRow )
2471 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2472 sc::CellStoreType::iterator it = aPos.first;
2473 if (it == maCells.end())
2474 return NULL;
2476 if (it->type != sc::element_type_numeric)
2477 return NULL;
2479 return &sc::numeric_block::at(*it->data, aPos.second);
2482 void ScColumn::GetInputString( SCROW nRow, OUString& rString ) const
2484 ScRefCellValue aCell = GetCellValue(nRow);
2485 sal_uLong nFormat = GetNumberFormat(nRow);
2486 ScCellFormat::GetInputString(aCell, nFormat, rString, *(pDocument->GetFormatTable()), pDocument);
2489 double ScColumn::GetValue( SCROW nRow ) const
2491 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2492 sc::CellStoreType::const_iterator it = aPos.first;
2493 switch (it->type)
2495 case sc::element_type_numeric:
2496 return sc::numeric_block::at(*it->data, aPos.second);
2497 case sc::element_type_formula:
2499 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
2500 ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
2501 return p2->IsValue() ? p2->GetValue() : 0.0;
2503 default:
2507 return 0.0;
2510 const EditTextObject* ScColumn::GetEditText( SCROW nRow ) const
2512 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2513 sc::CellStoreType::const_iterator it = aPos.first;
2514 if (it == maCells.end())
2515 return NULL;
2517 if (it->type != sc::element_type_edittext)
2518 return NULL;
2520 return sc::edittext_block::at(*it->data, aPos.second);
2523 void ScColumn::RemoveEditTextCharAttribs( SCROW nRow, const ScPatternAttr& rAttr )
2525 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2526 sc::CellStoreType::iterator it = aPos.first;
2527 if (it == maCells.end())
2528 return;
2530 if (it->type != sc::element_type_edittext)
2531 return;
2533 EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
2534 ScEditUtil::RemoveCharAttribs(*p, rAttr);
2537 void ScColumn::GetFormula( SCROW nRow, OUString& rFormula ) const
2539 const ScFormulaCell* p = FetchFormulaCell(nRow);
2540 if (p)
2541 p->GetFormula(rFormula);
2542 else
2543 rFormula = EMPTY_OUSTRING;
2546 const ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow ) const
2548 return FetchFormulaCell(nRow);
2551 ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow )
2553 return const_cast<ScFormulaCell*>(FetchFormulaCell(nRow));
2556 CellType ScColumn::GetCellType( SCROW nRow ) const
2558 switch (maCells.get_type(nRow))
2560 case sc::element_type_numeric:
2561 return CELLTYPE_VALUE;
2562 case sc::element_type_string:
2563 return CELLTYPE_STRING;
2564 case sc::element_type_edittext:
2565 return CELLTYPE_EDIT;
2566 case sc::element_type_formula:
2567 return CELLTYPE_FORMULA;
2568 default:
2571 return CELLTYPE_NONE;
2574 namespace {
2577 * Count the number of all non-empty cells.
2579 class CellCounter
2581 size_t mnCount;
2582 public:
2583 CellCounter() : mnCount(0) {}
2585 void operator() (const sc::CellStoreType::value_type& node)
2587 if (node.type == sc::element_type_empty)
2588 return;
2590 mnCount += node.size;
2593 size_t getCount() const { return mnCount; }
2598 SCSIZE ScColumn::GetCellCount() const
2600 CellCounter aFunc;
2601 aFunc = std::for_each(maCells.begin(), maCells.end(), aFunc);
2602 return aFunc.getCount();
2605 sal_uInt16 ScColumn::GetErrCode( SCROW nRow ) const
2607 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2608 sc::CellStoreType::const_iterator it = aPos.first;
2609 if (it == maCells.end())
2610 return 0;
2612 if (it->type != sc::element_type_formula)
2613 return 0;
2615 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
2616 return const_cast<ScFormulaCell*>(p)->GetErrCode();
2619 bool ScColumn::HasStringData( SCROW nRow ) const
2621 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2622 switch (aPos.first->type)
2624 case sc::element_type_string:
2625 case sc::element_type_edittext:
2626 return true;
2627 case sc::element_type_formula:
2629 const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
2630 return !const_cast<ScFormulaCell*>(p)->IsValue();
2632 default:
2636 return false;
2639 bool ScColumn::HasValueData( SCROW nRow ) const
2641 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2642 switch (aPos.first->type)
2644 case sc::element_type_numeric:
2645 return true;
2646 case sc::element_type_formula:
2648 const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
2649 return const_cast<ScFormulaCell*>(p)->IsValue();
2651 default:
2655 return false;
2659 * Return true if there is a string or editcell in the range
2661 bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
2663 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
2664 sc::CellStoreType::const_iterator it = aPos.first;
2665 size_t nOffset = aPos.second;
2666 SCROW nRow = nStartRow;
2667 for (; it != maCells.end() && nRow <= nEndRow; ++it)
2669 if (it->type == sc::element_type_string || it->type == sc::element_type_edittext)
2670 return true;
2672 nRow += it->size - nOffset;
2673 nOffset = 0;
2676 return false;
2679 namespace {
2681 class MaxStringLenHandler
2683 sal_Int32 mnMaxLen;
2684 const ScColumn& mrColumn;
2685 SvNumberFormatter* mpFormatter;
2686 rtl_TextEncoding meCharSet;
2687 bool mbOctetEncoding;
2689 void processCell(size_t nRow, ScRefCellValue& rCell)
2691 Color* pColor;
2692 OUString aString;
2693 sal_uInt32 nFormat = static_cast<const SfxUInt32Item*>(mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT))->GetValue();
2694 ScCellFormat::GetString(rCell, nFormat, aString, &pColor, *mpFormatter, &mrColumn.GetDoc());
2695 sal_Int32 nLen = 0;
2696 if (mbOctetEncoding)
2698 OString aOString;
2699 if (!aString.convertToString(&aOString, meCharSet,
2700 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
2701 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
2703 // TODO: anything? this is used by the dBase export filter
2704 // that throws an error anyway, but in case of another
2705 // context we might want to indicate a conversion error
2706 // early.
2708 nLen = aOString.getLength();
2710 else
2711 nLen = aString.getLength() * sizeof(sal_Unicode);
2713 if (mnMaxLen < nLen)
2714 mnMaxLen = nLen;
2717 public:
2718 MaxStringLenHandler(const ScColumn& rColumn, rtl_TextEncoding eCharSet) :
2719 mnMaxLen(0),
2720 mrColumn(rColumn),
2721 mpFormatter(rColumn.GetDoc().GetFormatTable()),
2722 meCharSet(eCharSet),
2723 mbOctetEncoding(rtl_isOctetTextEncoding(eCharSet))
2727 void operator() (size_t nRow, double fVal)
2729 ScRefCellValue aCell(fVal);
2730 processCell(nRow, aCell);
2733 void operator() (size_t nRow, const svl::SharedString& rStr)
2735 ScRefCellValue aCell(&rStr);
2736 processCell(nRow, aCell);
2739 void operator() (size_t nRow, const EditTextObject* p)
2741 ScRefCellValue aCell(p);
2742 processCell(nRow, aCell);
2745 void operator() (size_t nRow, const ScFormulaCell* p)
2747 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
2748 processCell(nRow, aCell);
2751 sal_Int32 getMaxLen() const { return mnMaxLen; }
2756 sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
2758 MaxStringLenHandler aFunc(*this, eCharSet);
2759 sc::ParseAllNonEmpty(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
2760 return aFunc.getMaxLen();
2763 namespace {
2765 class MaxNumStringLenHandler
2767 const ScColumn& mrColumn;
2768 SvNumberFormatter* mpFormatter;
2769 sal_Int32 mnMaxLen;
2770 sal_uInt16 mnPrecision;
2771 sal_uInt16 mnMaxGeneralPrecision;
2772 bool mbHaveSigned;
2774 void processCell(size_t nRow, ScRefCellValue& rCell)
2776 sal_uInt16 nCellPrecision = mnMaxGeneralPrecision;
2777 if (rCell.meType == CELLTYPE_FORMULA)
2779 if (!rCell.mpFormula->IsValue())
2780 return;
2782 // Limit unformatted formula cell precision to precision
2783 // encountered so far, if any, otherwise we'd end up with 15 just
2784 // because of =1/3 ... If no precision yet then arbitrarily limit
2785 // to a maximum of 4 unless a maximum general precision is set.
2786 if (mnPrecision)
2787 nCellPrecision = mnPrecision;
2788 else
2789 nCellPrecision = (mnMaxGeneralPrecision >= 15) ? 4 : mnMaxGeneralPrecision;
2792 double fVal = rCell.getValue();
2793 if (!mbHaveSigned && fVal < 0.0)
2794 mbHaveSigned = true;
2796 OUString aString;
2797 OUString aSep;
2798 sal_uInt16 nPrec;
2799 sal_uInt32 nFormat = static_cast<const SfxUInt32Item*>(
2800 mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT))->GetValue();
2801 if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
2803 aSep = mpFormatter->GetFormatDecimalSep(nFormat);
2804 ScCellFormat::GetInputString(rCell, nFormat, aString, *mpFormatter, &mrColumn.GetDoc());
2805 const SvNumberformat* pEntry = mpFormatter->GetEntry(nFormat);
2806 if (pEntry)
2808 bool bThousand, bNegRed;
2809 sal_uInt16 nLeading;
2810 pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading);
2812 else
2813 nPrec = mpFormatter->GetFormatPrecision(nFormat);
2815 else
2817 if (mnPrecision >= mnMaxGeneralPrecision)
2818 return; // early bail out for nothing changes here
2820 if (!fVal)
2822 // 0 doesn't change precision, but set a maximum length if none yet.
2823 if (!mnMaxLen)
2824 mnMaxLen = 1;
2825 return;
2828 // Simple number string with at most 15 decimals and trailing
2829 // decimal zeros eliminated.
2830 aSep = ".";
2831 aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true);
2832 nPrec = SvNumberFormatter::UNLIMITED_PRECISION;
2835 sal_Int32 nLen = aString.getLength();
2836 if (nLen <= 0)
2837 // Ignore empty string.
2838 return;
2840 if (nPrec == SvNumberFormatter::UNLIMITED_PRECISION && mnPrecision < mnMaxGeneralPrecision)
2842 if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
2844 // For some reason we couldn't obtain a precision from the
2845 // format, retry with simple number string.
2846 aSep = ".";
2847 aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true);
2848 nLen = aString.getLength();
2850 sal_Int32 nSep = aString.indexOf( aSep);
2851 if (nSep != -1)
2852 nPrec = aString.getLength() - nSep - 1;
2856 if (nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > mnPrecision)
2857 mnPrecision = nPrec;
2859 if (mnPrecision)
2860 { // less than mnPrecision in string => widen it
2861 // more => shorten it
2862 sal_Int32 nTmp = aString.indexOf(aSep);
2863 if ( nTmp == -1 )
2864 nLen += mnPrecision + aSep.getLength();
2865 else
2867 nTmp = aString.getLength() - (nTmp + aSep.getLength());
2868 if (nTmp != mnPrecision)
2869 nLen += mnPrecision - nTmp;
2870 // nPrecision > nTmp : nLen + Diff
2871 // nPrecision < nTmp : nLen - Diff
2875 // Enlarge for sign if necessary. Bear in mind that
2876 // GetMaxNumberStringLen() is for determining dBase decimal field width
2877 // and precision where the overall field width must include the sign.
2878 // Fitting -1 into "#.##" (width 4, 2 decimals) does not work.
2879 if (mbHaveSigned && fVal >= 0.0)
2880 ++nLen;
2882 if (mnMaxLen < nLen)
2883 mnMaxLen = nLen;
2886 public:
2887 MaxNumStringLenHandler(const ScColumn& rColumn, sal_uInt16 nMaxGeneralPrecision) :
2888 mrColumn(rColumn), mpFormatter(rColumn.GetDoc().GetFormatTable()),
2889 mnMaxLen(0), mnPrecision(0), mnMaxGeneralPrecision(nMaxGeneralPrecision),
2890 mbHaveSigned(false)
2892 // Limit the decimals passed to doubleToUString().
2893 // Also, the dBaseIII maximum precision is 15.
2894 if (mnMaxGeneralPrecision > 15)
2895 mnMaxGeneralPrecision = 15;
2898 void operator() (size_t nRow, double fVal)
2900 ScRefCellValue aCell(fVal);
2901 processCell(nRow, aCell);
2904 void operator() (size_t nRow, const ScFormulaCell* p)
2906 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
2907 processCell(nRow, aCell);
2910 sal_Int32 getMaxLen() const { return mnMaxLen; }
2912 sal_uInt16 getPrecision() const { return mnPrecision; }
2917 sal_Int32 ScColumn::GetMaxNumberStringLen(
2918 sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
2920 sal_uInt16 nMaxGeneralPrecision = pDocument->GetDocOptions().GetStdPrecision();
2921 MaxNumStringLenHandler aFunc(*this, nMaxGeneralPrecision);
2922 sc::ParseFormulaNumeric(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
2923 nPrecision = aFunc.getPrecision();
2924 return aFunc.getMaxLen();
2927 namespace {
2929 class GroupFormulaCells
2931 ScFormulaCellGroupRef mxNone;
2932 std::vector<ScAddress>* mpGroupPos;
2934 public:
2935 GroupFormulaCells( std::vector<ScAddress>* pGroupPos ) :
2936 mpGroupPos(pGroupPos) {}
2938 void operator() (sc::CellStoreType::value_type& node)
2940 if (node.type != sc::element_type_formula)
2941 // We are only interested in formula cells.
2942 return;
2944 size_t nRow = node.position; // start row position.
2946 sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
2947 sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
2949 // This block should never be empty.
2951 ScFormulaCell* pPrev = *it;
2952 ScFormulaCellGroupRef xPrevGrp = pPrev->GetCellGroup();
2953 if (xPrevGrp)
2955 // Move to the cell after the last cell of the current group.
2956 std::advance(it, xPrevGrp->mnLength);
2957 nRow += xPrevGrp->mnLength;
2959 else
2961 ++it;
2962 ++nRow;
2965 ScFormulaCell* pCur = NULL;
2966 ScFormulaCellGroupRef xCurGrp;
2967 for (; it != itEnd; pPrev = pCur, xPrevGrp = xCurGrp)
2969 pCur = *it;
2970 xCurGrp = pCur->GetCellGroup();
2972 ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(*pCur);
2973 if (eCompState == ScFormulaCell::NotEqual)
2975 // different formula tokens.
2976 if (xCurGrp)
2978 // Move to the cell after the last cell of the current group.
2979 std::advance(it, xCurGrp->mnLength);
2980 nRow += xCurGrp->mnLength;
2982 else
2984 ++it;
2985 ++nRow;
2988 continue;
2991 // Formula tokens equal those of the previous formula cell or cell group.
2992 if (xPrevGrp)
2994 // Previous cell is a group.
2995 if (xCurGrp)
2997 // The current cell is a group. Merge these two groups.
2998 xPrevGrp->mnLength += xCurGrp->mnLength;
2999 pCur->SetCellGroup(xPrevGrp);
3000 sc::formula_block::iterator itGrpEnd = it;
3001 std::advance(itGrpEnd, xCurGrp->mnLength);
3002 for (++it; it != itGrpEnd; ++it)
3004 ScFormulaCell* pCell = *it;
3005 pCell->SetCellGroup(xPrevGrp);
3007 nRow += xCurGrp->mnLength;
3009 else
3011 // Add this cell to the previous group.
3012 pCur->SetCellGroup(xPrevGrp);
3013 ++xPrevGrp->mnLength;
3014 ++nRow;
3015 ++it;
3019 else if (xCurGrp)
3021 // Previous cell is a regular cell and current cell is a group.
3022 nRow += xCurGrp->mnLength;
3023 std::advance(it, xCurGrp->mnLength);
3024 pPrev->SetCellGroup(xCurGrp);
3025 xCurGrp->mpTopCell = pPrev;
3026 ++xCurGrp->mnLength;
3027 xPrevGrp = xCurGrp;
3029 else
3031 // Both previous and current cells are regular cells.
3032 assert(pPrev->aPos.Row() == (SCROW)(nRow - 1));
3033 xPrevGrp = pPrev->CreateCellGroup(2, eCompState == ScFormulaCell::EqualInvariant);
3034 pCur->SetCellGroup(xPrevGrp);
3035 ++nRow;
3036 ++it;
3039 if (mpGroupPos)
3040 mpGroupPos->push_back(pCur->aPos);
3042 pCur = pPrev;
3043 xCurGrp = xPrevGrp;
3050 void ScColumn::RegroupFormulaCells( std::vector<ScAddress>* pGroupPos )
3052 // re-build formula groups.
3053 std::for_each(maCells.begin(), maCells.end(), GroupFormulaCells(pGroupPos));
3056 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */