Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / column3.cxx
blob850a904e6fa235642f7b08ebc738b6a17dd7d416
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"
50 #include <com/sun/star/i18n/LocaleDataItem.hpp>
52 #include <boost/scoped_ptr.hpp>
54 #include <mdds/flat_segment_tree.hpp>
56 #include <sfx2/objsh.hxx>
57 #include <svl/zforlist.hxx>
58 #include <svl/zformat.hxx>
59 #include <svl/broadcast.hxx>
60 #include "svl/sharedstringpool.hxx"
61 #include "editeng/editstat.hxx"
63 #include <cstdio>
65 using ::com::sun::star::i18n::LocaleDataItem;
67 // Err527 Workaroand
68 extern const ScFormulaCell* pLastFormulaTreeTop; // in cellform.cxx
69 using namespace formula;
71 void ScColumn::Broadcast( SCROW nRow )
73 ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab));
74 pDocument->Broadcast(aHint);
77 void ScColumn::BroadcastCells( const std::vector<SCROW>& rRows, sal_uLong nHint )
79 if (rRows.empty())
80 return;
82 // Broadcast the changes.
83 ScHint aHint(nHint, ScAddress(nCol, 0, nTab));
84 std::vector<SCROW>::const_iterator itRow = rRows.begin(), itRowEnd = rRows.end();
85 for (; itRow != itRowEnd; ++itRow)
87 aHint.GetAddress().SetRow(*itRow);
88 pDocument->Broadcast(aHint);
92 struct DirtyCellInterpreter
94 void operator() (size_t, ScFormulaCell* p)
96 if (p->GetDirty())
97 p->Interpret();
101 void ScColumn::InterpretDirtyCells( SCROW nRow1, SCROW nRow2 )
103 DirtyCellInterpreter aFunc;
104 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
107 void ScColumn::Delete( SCROW nRow )
109 sc::CellStoreType::position_type aPos = maCells.position(nRow);
110 sc::CellStoreType::iterator it = aPos.first;
111 if (it == maCells.end())
112 return;
114 if (it->type == sc::element_type_formula)
116 ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
117 p->EndListeningTo(pDocument);
118 sc::SharedFormulaUtil::unshareFormulaCell(aPos, *p);
120 maCells.set_empty(nRow, nRow);
121 maCellTextAttrs.set_empty(nRow, nRow);
122 maCellNotes.set_empty(nRow, nRow);
124 Broadcast(nRow);
125 CellStorageModified();
128 void ScColumn::FreeAll()
130 // Keep a logical empty range of 0-MAXROW at all times.
131 maCells.clear();
132 maCells.resize(MAXROWCOUNT);
133 maCellTextAttrs.clear();
134 maCellTextAttrs.resize(MAXROWCOUNT);
135 maCellNotes.clear();
136 maCellNotes.resize(MAXROWCOUNT);
137 CellStorageModified();
140 namespace {
143 * Collect all formula cells for later mass-unregistration. Also tag row
144 * positions of all non-empty cells in the range.
146 class DeleteRowsHandler
148 ScDocument& mrDoc;
149 std::vector<SCROW> maRows;
150 std::vector<ScFormulaCell*> maFormulaCells;
151 public:
152 DeleteRowsHandler(ScDocument& rDoc) : mrDoc(rDoc) {}
154 void operator() (size_t nRow, ScFormulaCell* pCell)
156 maFormulaCells.push_back(pCell);
157 maRows.push_back(nRow);
160 void operator() (mdds::mtv::element_t nType, size_t nTopRow, size_t nDataSize)
162 if (nType == sc::element_type_empty)
163 // Ignore empty cells.
164 return;
166 for (size_t i = 0; i < nDataSize; ++i)
167 // Tag all non-empty cells.
168 maRows.push_back(i + nTopRow);
171 void endFormulas()
173 mrDoc.EndListeningFormulaCells(maFormulaCells);
176 const std::vector<SCROW>& getNonEmptyRows() const
178 return maRows;
182 class ShiftFormulaPosHandler
184 public:
186 void operator() (size_t nRow, ScFormulaCell* pCell)
188 pCell->aPos.SetRow(nRow);
192 class RangeBroadcaster
194 ScDocument& mrDoc;
195 ScHint maHint;
196 public:
197 RangeBroadcaster(ScDocument& rDoc, SCTAB nTab, SCCOL nCol) :
198 mrDoc(rDoc),
199 maHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab)) {}
201 void operator() (const sc::SingleColumnSpanSet::Span& rSpan)
203 SCROW nRow1 = rSpan.mnRow1, nRow2 = rSpan.mnRow2;
204 maHint.GetAddress().SetRow(nRow1);
205 ScRange aRange(maHint.GetAddress());
206 aRange.aEnd.SetRow(nRow2);
207 mrDoc.AreaBroadcastInRange(aRange, maHint);
213 void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
215 pAttrArray->DeleteRow( nStartRow, nSize );
217 SCROW nEndRow = nStartRow + nSize - 1;
219 maBroadcasters.erase(nStartRow, nEndRow);
220 maBroadcasters.resize(MAXROWCOUNT);
222 maCellNotes.erase(nStartRow, nEndRow);
223 maCellNotes.resize(MAXROWCOUNT);
225 // See if we have any cells that would get deleted or shifted by deletion.
226 sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
227 sc::CellStoreType::iterator itCell = aPos.first;
228 if (itCell->type == sc::element_type_empty)
230 // This is an empty block. If this is the last block, then there is no cells to delete or shift.
231 sc::CellStoreType::iterator itTest = itCell;
232 ++itTest;
233 if (itTest == maCells.end())
235 // No cells are affected by this deletion. Bail out.
236 CellStorageModified(); // broadcast array has been modified.
237 return;
241 // Check if there are any cells below the end row that will get shifted.
242 bool bShiftCells = false;
243 aPos = maCells.position(itCell, nEndRow+1);
244 itCell = aPos.first;
245 if (itCell->type == sc::element_type_empty)
247 // This block is empty. See if there is any block that follows.
248 sc::CellStoreType::iterator itTest = itCell;
249 ++itTest;
250 if (itTest != maCells.end())
251 // Non-empty block follows -> cells that will get shifted.
252 bShiftCells = true;
254 else
255 bShiftCells = true;
257 sc::SingleColumnSpanSet aNonEmptySpans;
258 if (bShiftCells)
260 // Mark all non-empty cell positions below the end row.
261 sc::ColumnBlockConstPosition aBlockPos;
262 aBlockPos.miCellPos = itCell;
263 aNonEmptySpans.scan(aBlockPos, *this, nEndRow+1, MAXROW);
266 sc::AutoCalcSwitch aACSwitch(*pDocument, false);
268 // Parse all non-empty cells in the range to pick up their row positions,
269 // and end all formula cells.
270 DeleteRowsHandler aDeleteRowsFunc(*pDocument);
271 sc::ProcessFormula(itCell, maCells, nStartRow, nEndRow, aDeleteRowsFunc, aDeleteRowsFunc);
272 aDeleteRowsFunc.endFormulas();
274 // Remove the cells.
275 maCells.erase(nStartRow, nEndRow);
276 maCells.resize(MAXROWCOUNT);
278 // Get the position again after the container change.
279 aPos = maCells.position(nStartRow);
281 // Shift the formula cell positions below the start row.
282 ShiftFormulaPosHandler aShiftFormulaFunc;
283 sc::ProcessFormula(aPos.first, maCells, nStartRow, MAXROW, aShiftFormulaFunc);
285 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
287 // Single cell broadcasts on deleted cells.
288 BroadcastCells(aDeleteRowsFunc.getNonEmptyRows(), SC_HINT_DATACHANGED);
290 // Shift the text attribute array too (before the broadcast).
291 maCellTextAttrs.erase(nStartRow, nEndRow);
292 maCellTextAttrs.resize(MAXROWCOUNT);
294 // Shift the cell notes array too (before the broadcast).
295 maCellNotes.erase(nStartRow, nEndRow);
296 maCellNotes.resize(MAXROWCOUNT);
298 CellStorageModified();
300 if (!bShiftCells)
301 return;
303 // Do area broadcast on the old non-empty cell ranges prior to the shift.
304 sc::SingleColumnSpanSet::SpansType aSpans;
305 aNonEmptySpans.getSpans(aSpans);
306 std::for_each(aSpans.begin(), aSpans.end(), RangeBroadcaster(*pDocument, nTab, nCol));
309 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow )
311 return GetPositionToInsert(maCells.begin(), nRow);
314 void ScColumn::JoinNewFormulaCell(
315 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const
317 // Check the previous row position for possible grouping.
318 if (aPos.first->type == sc::element_type_formula && aPos.second > 0)
320 ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
321 sc::CellStoreType::position_type aPosPrev = aPos;
322 --aPosPrev.second;
323 sc::SharedFormulaUtil::joinFormulaCells(aPosPrev, rPrev, rCell);
326 // Check the next row position for possible grouping.
327 if (aPos.first->type == sc::element_type_formula && aPos.second+1 < aPos.first->size)
329 ScFormulaCell& rNext = *sc::formula_block::at(*aPos.first->data, aPos.second+1);
330 sc::SharedFormulaUtil::joinFormulaCells(aPos, rCell, rNext);
334 void ScColumn::DetachFormulaCell(
335 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell )
337 if (!pDocument->IsClipOrUndo())
338 // Have the dying formula cell stop listening.
339 rCell.EndListeningTo(pDocument);
341 sc::SharedFormulaUtil::unshareFormulaCell(aPos, rCell);
344 namespace {
346 class DetachFormulaCellsHandler
348 ScDocument* mpDoc;
349 public:
350 DetachFormulaCellsHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
352 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
354 pCell->EndListeningTo(mpDoc);
360 void ScColumn::DetachFormulaCells(
361 const sc::CellStoreType::position_type& aPos, size_t nLength )
363 // Split formula grouping at the top and bottom boundaries.
364 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
365 size_t nRow = aPos.first->position + aPos.second;
366 size_t nNextTopRow = nRow + nLength; // start row of next formula group.
367 if (ValidRow(nNextTopRow))
369 sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow);
370 sc::SharedFormulaUtil::splitFormulaCellGroup(aPos2);
373 if (pDocument->IsClipOrUndo())
374 return;
376 DetachFormulaCellsHandler aFunc(pDocument);
377 sc::ProcessFormula(aPos.first, maCells, nRow, nNextTopRow-1, aFunc);
380 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow )
382 // See if we are overwriting an existing formula cell.
383 sc::CellStoreType::position_type aPos = maCells.position(it, nRow);
384 sc::CellStoreType::iterator itRet = aPos.first;
385 if (itRet->type == sc::element_type_formula)
387 ScFormulaCell& rCell = *sc::formula_block::at(*itRet->data, aPos.second);
388 DetachFormulaCell(aPos, rCell);
391 return itRet;
394 void ScColumn::ActivateNewFormulaCell(
395 const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, bool bJoin )
397 ActivateNewFormulaCell(maCells.position(itPos, nRow), rCell, bJoin);
400 void ScColumn::ActivateNewFormulaCell(
401 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, bool bJoin )
403 if (bJoin)
404 // See if this new formula cell can join an existing shared formula group.
405 JoinNewFormulaCell(aPos, rCell);
407 // When we insert from the Clipboard we still have wrong (old) References!
408 // First they are rewired in CopyBlockFromClip via UpdateReference and the
409 // we call StartListeningFromClip and BroadcastFromClip.
410 // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
411 // After Import we call CalcAfterLoad and in there Listening.
412 if (!pDocument->IsClipOrUndo() && !pDocument->IsInsertingFromOtherDoc())
414 rCell.StartListeningTo(pDocument);
415 if (!pDocument->IsCalcingAfterLoad())
416 rCell.SetDirty();
420 void ScColumn::BroadcastNewCell( SCROW nRow )
422 // When we insert from the Clipboard we still have wrong (old) References!
423 // First they are rewired in CopyBlockFromClip via UpdateReference and the
424 // we call StartListeningFromClip and BroadcastFromClip.
425 // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
426 // After Import we call CalcAfterLoad and in there Listening.
427 if (pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc() || pDocument->IsCalcingAfterLoad())
428 return;
430 Broadcast(nRow);
433 bool ScColumn::UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow, sc::CellStoreType::iterator& itr )
435 if (rAttr.mnScriptType != SC_SCRIPTTYPE_UNKNOWN)
436 // Already updated. Nothing to do.
437 return false;
439 // Script type not yet determined. Determine the real script
440 // type, and store it.
441 const ScPatternAttr* pPattern = GetPattern(nRow);
442 if (!pPattern)
443 return false;
445 sc::CellStoreType::position_type pos = maCells.position(itr, nRow);
446 itr = pos.first;
447 size_t nOffset = pos.second;
448 ScRefCellValue aCell = GetCellValue( itr, nOffset );
449 ScAddress aPos(nCol, nRow, nTab);
451 const SfxItemSet* pCondSet = NULL;
452 ScConditionalFormatList* pCFList = pDocument->GetCondFormList(nTab);
453 if (pCFList)
455 const ScCondFormatItem& rItem =
456 static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL));
457 const std::vector<sal_uInt32>& rData = rItem.GetCondFormatData();
458 pCondSet = pDocument->GetCondResult(aCell, aPos, *pCFList, rData);
461 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
463 OUString aStr;
464 Color* pColor;
465 sal_uLong nFormat = pPattern->GetNumberFormat(pFormatter, pCondSet);
466 ScCellFormat::GetString(aCell, nFormat, aStr, &pColor, *pFormatter, pDocument);
468 // Store the real script type to the array.
469 rAttr.mnScriptType = pDocument->GetStringScriptType(aStr);
470 return true;
473 namespace {
475 class DeleteAreaHandler
477 ScDocument& mrDoc;
478 std::vector<ScFormulaCell*> maFormulaCells;
479 sc::SingleColumnSpanSet maDeleteRanges;
481 bool mbNumeric:1;
482 bool mbString:1;
483 bool mbFormula:1;
485 public:
486 DeleteAreaHandler(ScDocument& rDoc, sal_uInt16 nDelFlag) :
487 mrDoc(rDoc),
488 mbNumeric(nDelFlag & IDF_VALUE),
489 mbString(nDelFlag & IDF_STRING),
490 mbFormula(nDelFlag & IDF_FORMULA) {}
492 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
494 switch (node.type)
496 case sc::element_type_numeric:
497 if (!mbNumeric)
498 return;
499 break;
500 case sc::element_type_string:
501 case sc::element_type_edittext:
502 if (!mbString)
503 return;
504 break;
505 case sc::element_type_formula:
507 if (!mbFormula)
508 return;
510 sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
511 std::advance(it, nOffset);
512 sc::formula_block::iterator itEnd = it;
513 std::advance(itEnd, nDataSize);
515 for (; it != itEnd; ++it)
516 maFormulaCells.push_back(*it);
518 break;
519 case sc::element_type_empty:
520 default:
521 return;
524 // Tag these cells for deletion.
525 SCROW nRow1 = node.position + nOffset;
526 SCROW nRow2 = nRow1 + nDataSize - 1;
527 maDeleteRanges.set(nRow1, nRow2, true);
530 void endFormulas()
532 mrDoc.EndListeningFormulaCells(maFormulaCells);
535 const sc::SingleColumnSpanSet& getSpans() const
537 return maDeleteRanges;
541 class EmptyCells
543 ScColumn& mrColumn;
544 sc::ColumnBlockPosition& mrPos;
546 void splitFormulaGrouping(const sc::CellStoreType::position_type& rPos)
548 if (rPos.first->type == sc::element_type_formula)
550 ScFormulaCell& rCell = *sc::formula_block::at(*rPos.first->data, rPos.second);
551 sc::SharedFormulaUtil::unshareFormulaCell(rPos, rCell);
555 public:
556 EmptyCells(sc::ColumnBlockPosition& rPos, ScColumn& rColumn) :
557 mrColumn(rColumn), mrPos(rPos) {}
559 void operator() (const sc::SingleColumnSpanSet::Span& rSpan)
561 sc::CellStoreType& rCells = mrColumn.GetCellStore();
563 // First, split formula grouping at the top and bottom boundaries
564 // before emptying the cells.
565 sc::CellStoreType::position_type aPos = rCells.position(mrPos.miCellPos, rSpan.mnRow1);
566 splitFormulaGrouping(aPos);
567 aPos = rCells.position(aPos.first, rSpan.mnRow2);
568 splitFormulaGrouping(aPos);
570 mrPos.miCellPos = rCells.set_empty(mrPos.miCellPos, rSpan.mnRow1, rSpan.mnRow2);
571 mrPos.miCellTextAttrPos = mrColumn.GetCellAttrStore().set_empty(mrPos.miCellTextAttrPos, rSpan.mnRow1, rSpan.mnRow2);
577 void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
579 sal_uInt16 nContMask = IDF_CONTENTS;
580 // IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set
581 if( nDelFlag & IDF_NOTE )
582 nContMask |= IDF_NOCAPTIONS;
583 sal_uInt16 nContFlag = nDelFlag & nContMask;
585 std::vector<SCROW> aDeletedRows;
587 if (!IsEmptyData() && nContFlag)
589 // There are cells to delete. Determine which cells to delete based on the deletion flags.
590 DeleteAreaHandler aFunc(*pDocument, nDelFlag);
591 sc::CellStoreType::iterator itPos = maCells.position(nStartRow).first;
592 sc::ProcessBlock(itPos, maCells, aFunc, nStartRow, nEndRow);
593 aFunc.endFormulas(); // Have the formula cells stop listening.
594 aFunc.getSpans().getRows(aDeletedRows);
596 // Get the deletion spans.
597 sc::SingleColumnSpanSet::SpansType aSpans;
598 aFunc.getSpans().getSpans(aSpans);
600 sc::ColumnBlockPosition aBlockPos;
601 aBlockPos.miCellPos = itPos;
602 aBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
603 aBlockPos.miCellNotePos = maCellNotes.begin();
605 // Delete the cells for real.
606 std::for_each(aSpans.begin(), aSpans.end(), EmptyCells(aBlockPos, *this));
607 CellStorageModified();
610 if (nDelFlag & IDF_NOTE)
612 sc::ColumnBlockPosition aBlockPos;
613 aBlockPos.miCellNotePos = maCellNotes.begin();
614 DeleteCellNotes(aBlockPos, nStartRow, nEndRow);
617 if ( nDelFlag & IDF_EDITATTR )
619 OSL_ENSURE( nContFlag == 0, "DeleteArea: Wrong Flags" );
620 RemoveEditAttribs( nStartRow, nEndRow );
623 // Delete attributes just now
624 if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB)
625 pAttrArray->DeleteArea( nStartRow, nEndRow );
626 else if ((nDelFlag & IDF_HARDATTR) == IDF_HARDATTR)
627 pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
629 // Broadcast on only cells that were deleted; no point broadcasting on
630 // cells that were already empty before the deletion.
631 BroadcastCells(aDeletedRows, SC_HINT_DATACHANGED);
634 bool ScColumn::InitBlockPosition( sc::ColumnBlockPosition& rBlockPos )
636 rBlockPos.miBroadcasterPos = maBroadcasters.begin();
637 rBlockPos.miCellNotePos = maCellNotes.begin();
638 rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
639 rBlockPos.miCellPos = maCells.begin();
640 return true;
643 bool ScColumn::InitBlockPosition( sc::ColumnBlockConstPosition& rBlockPos ) const
645 rBlockPos.miBroadcasterPos = maBroadcasters.begin();
646 rBlockPos.miCellNotePos = maCellNotes.begin();
647 rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
648 rBlockPos.miCellPos = maCells.begin();
649 return true;
652 namespace {
654 class CopyAttrArrayByRange : std::unary_function<sc::SingleColumnSpanSet::Span, void>
656 ScAttrArray& mrDestAttrArray;
657 ScAttrArray& mrSrcAttrArray;
658 long mnRowOffset;
659 public:
660 CopyAttrArrayByRange(ScAttrArray& rDestAttrArray, ScAttrArray& rSrcAttrArray, long nRowOffset) :
661 mrDestAttrArray(rDestAttrArray), mrSrcAttrArray(rSrcAttrArray), mnRowOffset(nRowOffset) {}
663 void operator() (const sc::SingleColumnSpanSet::Span& rSpan)
665 mrDestAttrArray.CopyAreaSafe(
666 rSpan.mnRow1+mnRowOffset, rSpan.mnRow2+mnRowOffset, mnRowOffset, mrSrcAttrArray);
670 class CopyCellsFromClipHandler
672 sc::CopyFromClipContext& mrCxt;
673 ScColumn& mrSrcCol;
674 ScColumn& mrDestCol;
675 SCTAB mnTab;
676 SCCOL mnCol;
677 SCTAB mnSrcTab;
678 SCCOL mnSrcCol;
679 long mnRowOffset;
680 sc::ColumnBlockPosition maDestBlockPos;
681 sc::ColumnBlockPosition* mpDestBlockPos; // to save it for next iteration.
683 bool isDateCell(SCROW nSrcRow) const
685 ScDocument* pSrcDoc = mrCxt.getClipDoc(); // clip document is the source.
686 sal_uLong nNumIndex = static_cast<const SfxUInt32Item*>(mrSrcCol.GetAttr(nSrcRow, ATTR_VALUE_FORMAT))->GetValue();
687 short nType = pSrcDoc->GetFormatTable()->GetType(nNumIndex);
688 return (nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME);
691 void insertRefCell(SCROW nSrcRow, SCROW nDestRow)
693 ScAddress aSrcPos(mnSrcCol, nSrcRow, mnSrcTab);
694 ScAddress aDestPos(mnCol, nDestRow, mnTab);
695 ScSingleRefData aRef;
696 aRef.InitAddress(aSrcPos);
697 aRef.SetFlag3D(true);
699 ScTokenArray aArr;
700 aArr.AddSingleReference(aRef);
702 mrDestCol.SetFormulaCell(
703 maDestBlockPos, nDestRow, new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos, aArr));
706 void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
708 mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestBlockPos, bCloneCaption, mnRowOffset);
711 public:
712 CopyCellsFromClipHandler(sc::CopyFromClipContext& rCxt, ScColumn& rSrcCol, ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, long nRowOffset) :
713 mrCxt(rCxt),
714 mrSrcCol(rSrcCol),
715 mrDestCol(rDestCol),
716 mnTab(nDestTab),
717 mnCol(nDestCol),
718 mnSrcTab(rSrcCol.GetTab()),
719 mnSrcCol(rSrcCol.GetCol()),
720 mnRowOffset(nRowOffset),
721 mpDestBlockPos(mrCxt.getBlockPosition(nDestTab, nDestCol))
723 if (mpDestBlockPos)
724 maDestBlockPos = *mpDestBlockPos;
725 else
726 mrDestCol.InitBlockPosition(maDestBlockPos);
729 ~CopyCellsFromClipHandler()
731 if (mpDestBlockPos)
732 // Don't forget to save this to the context!
733 *mpDestBlockPos = maDestBlockPos;
736 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
739 SCROW nSrcRow1 = node.position + nOffset;
740 bool bCopyCellNotes = mrCxt.isCloneNotes();
742 sal_uInt16 nFlags = mrCxt.getInsertFlag();
744 if (node.type == sc::element_type_empty)
746 if (bCopyCellNotes)
748 bool bCloneCaption = (nFlags & IDF_NOCAPTIONS) == 0;
749 duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
751 return;
754 bool bNumeric = (nFlags & IDF_VALUE) != 0;
755 bool bDateTime = (nFlags & IDF_DATETIME) != 0;
756 bool bString = (nFlags & IDF_STRING) != 0;
757 bool bBoolean = (nFlags & IDF_SPECIAL_BOOLEAN) != 0;
758 bool bFormula = (nFlags & IDF_FORMULA) != 0;
760 bool bAsLink = mrCxt.isAsLink();
762 switch (node.type)
764 case sc::element_type_numeric:
766 // We need to copy numeric cells individually because of date type check.
767 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*node.data);
768 std::advance(it, nOffset);
769 sc::numeric_block::const_iterator itEnd = it;
770 std::advance(itEnd, nDataSize);
771 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
773 bool bCopy = isDateCell(nSrcRow) ? bDateTime : bNumeric;
774 if (!bCopy)
775 continue;
777 if (bAsLink)
778 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
779 else
780 mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, *it);
783 break;
784 case sc::element_type_string:
786 if (!bString)
787 return;
789 sc::string_block::const_iterator it = sc::string_block::begin(*node.data);
790 std::advance(it, nOffset);
791 sc::string_block::const_iterator itEnd = it;
792 std::advance(itEnd, nDataSize);
793 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
795 if (bAsLink)
796 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
797 else
798 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, *it);
801 break;
802 case sc::element_type_edittext:
804 if (!bString)
805 return;
807 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
808 std::advance(it, nOffset);
809 sc::edittext_block::const_iterator itEnd = it;
810 std::advance(itEnd, nDataSize);
811 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
814 if (bAsLink)
815 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
816 else
817 mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, **it);
820 break;
821 case sc::element_type_formula:
823 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
824 std::advance(it, nOffset);
825 sc::formula_block::const_iterator itEnd = it;
826 std::advance(itEnd, nDataSize);
827 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
829 ScFormulaCell& rSrcCell = const_cast<ScFormulaCell&>(**it);
830 bool bForceFormula = false;
831 if (bBoolean)
833 // See if the formula consists of =TRUE() or =FALSE().
834 ScTokenArray* pCode = rSrcCell.GetCode();
835 if (pCode && pCode->GetLen() == 1)
837 const formula::FormulaToken* p = pCode->First();
838 if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
839 // This is a boolean formula.
840 bForceFormula = true;
844 ScAddress aDestPos(mnCol, nSrcRow + mnRowOffset, mnTab);
845 if (bFormula || bForceFormula)
847 if (bAsLink)
848 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
849 else
851 mrDestCol.SetFormulaCell(
852 maDestBlockPos, nSrcRow + mnRowOffset,
853 new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos));
856 else if (bNumeric || bDateTime || bString)
858 // Always just copy the original row to the Undo Documen;
859 // do not create Value/string cells from formulas
861 sal_uInt16 nErr = rSrcCell.GetErrCode();
862 if (nErr)
864 // error codes are cloned with values
865 if (bNumeric)
867 if (bAsLink)
868 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
869 else
871 ScFormulaCell* pErrCell = new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos);
872 pErrCell->SetErrCode(nErr);
873 mrDestCol.SetFormulaCell(
874 maDestBlockPos, nSrcRow + mnRowOffset, pErrCell);
878 else if (rSrcCell.IsValue())
880 bool bCopy = isDateCell(nSrcRow) ? bDateTime : bNumeric;
881 if (!bCopy)
882 continue;
884 if (bAsLink)
885 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
886 else
887 mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, rSrcCell.GetValue());
889 else if (bString)
891 svl::SharedString aStr = rSrcCell.GetString();
892 if (aStr.isEmpty())
893 // do not clone empty string
894 continue;
896 if (bAsLink)
897 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
898 else if (rSrcCell.IsMultilineResult())
900 // Clone as an edit text object.
901 ScFieldEditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
902 rEngine.SetText(aStr.getString());
903 mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, rEngine.CreateTextObject());
905 else
906 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aStr);
911 break;
912 default:
915 if (bCopyCellNotes)
917 bool bCloneCaption = (nFlags & IDF_NOCAPTIONS) == 0;
918 duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
925 // rColumn = source
926 // nRow1, nRow2 = target position
928 void ScColumn::CopyFromClip(
929 sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn )
931 if ((rCxt.getInsertFlag() & IDF_ATTRIB) != 0)
933 if (rCxt.isSkipAttrForEmptyCells())
935 // copy only attributes for non-empty cells between nRow1-nDy and nRow2-nDy.
936 sc::SingleColumnSpanSet aSpanSet;
937 aSpanSet.scan(rColumn, nRow1-nDy, nRow2-nDy);
938 sc::SingleColumnSpanSet::SpansType aSpans;
939 aSpanSet.getSpans(aSpans);
940 std::for_each(
941 aSpans.begin(), aSpans.end(), CopyAttrArrayByRange(*rColumn.pAttrArray, *pAttrArray, nDy));
943 else
944 rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray );
946 if ((rCxt.getInsertFlag() & IDF_CONTENTS) == 0)
947 return;
949 if (rCxt.isAsLink() && rCxt.getInsertFlag() == IDF_ALL)
951 // We also reference empty cells for "ALL"
952 // IDF_ALL must always contain more flags when compared to "Insert contents" as
953 // contents can be selected one by one!
955 ScAddress aDestPos( nCol, 0, nTab ); // Adapt Row
957 // Create reference (Source Position)
958 ScSingleRefData aRef;
959 aRef.InitFlags(); // -> All absolute
960 aRef.SetAbsCol(rColumn.nCol);
961 aRef.SetAbsTab(rColumn.nTab);
962 aRef.SetFlag3D(true);
964 for (SCROW nDestRow = nRow1; nDestRow <= nRow2; nDestRow++)
966 aRef.SetAbsRow(nDestRow - nDy); // Source row
967 aDestPos.SetRow( nDestRow );
969 ScTokenArray aArr;
970 aArr.AddSingleReference( aRef );
971 SetFormulaCell(nDestRow, new ScFormulaCell(pDocument, aDestPos, aArr));
974 return;
977 // nRow1 to nRow2 is for destination (this) column. Subtract nDy to get the source range.
979 // Copy all cells in the source column (rColumn) from nRow1-nDy to nRow2-nDy to this column.
980 CopyCellsFromClipHandler aFunc(rCxt, rColumn, *this, nTab, nCol, nDy);
981 sc::ParseBlock(rColumn.maCells.begin(), rColumn.maCells, aFunc, nRow1-nDy, nRow2-nDy);
984 void ScColumn::MixMarked(
985 sc::MixDocContext& rCxt, const ScMarkData& rMark, sal_uInt16 nFunction,
986 bool bSkipEmpty, const ScColumn& rSrcCol )
988 SCROW nRow1, nRow2;
990 if (rMark.IsMultiMarked())
992 ScMarkArrayIter aIter( rMark.GetArray()+nCol );
993 while (aIter.Next( nRow1, nRow2 ))
994 MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol);
998 namespace {
1000 // Result in rVal1
1001 bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunction )
1003 bool bOk = false;
1004 switch (nFunction)
1006 case PASTE_ADD:
1007 bOk = SubTotal::SafePlus( rVal1, nVal2 );
1008 break;
1009 case PASTE_SUB:
1010 nVal2 = -nVal2; // FIXME: Can we do this alwyas without error?
1011 bOk = SubTotal::SafePlus( rVal1, nVal2 );
1012 break;
1013 case PASTE_MUL:
1014 bOk = SubTotal::SafeMult( rVal1, nVal2 );
1015 break;
1016 case PASTE_DIV:
1017 bOk = SubTotal::SafeDiv( rVal1, nVal2 );
1018 break;
1020 return bOk;
1023 void lcl_AddCode( ScTokenArray& rArr, const ScFormulaCell* pCell )
1025 rArr.AddOpCode(ocOpen);
1027 ScTokenArray* pCode = const_cast<ScFormulaCell*>(pCell)->GetCode();
1028 if (pCode)
1030 const formula::FormulaToken* pToken = pCode->First();
1031 while (pToken)
1033 rArr.AddToken( *pToken );
1034 pToken = pCode->Next();
1038 rArr.AddOpCode(ocClose);
1041 class MixDataHandler
1043 ScColumn& mrDestColumn;
1044 sc::ColumnBlockPosition& mrBlockPos;
1046 sc::CellStoreType maNewCells;
1047 sc::CellStoreType::iterator miNewCellsPos;
1049 size_t mnRowOffset;
1050 sal_uInt16 mnFunction;
1052 bool mbSkipEmpty;
1054 public:
1055 MixDataHandler(
1056 sc::ColumnBlockPosition& rBlockPos,
1057 ScColumn& rDestColumn,
1058 SCROW nRow1, SCROW nRow2,
1059 sal_uInt16 nFunction, bool bSkipEmpty) :
1060 mrDestColumn(rDestColumn),
1061 mrBlockPos(rBlockPos),
1062 maNewCells(nRow2 - nRow1 + 1),
1063 miNewCellsPos(maNewCells.begin()),
1064 mnRowOffset(nRow1),
1065 mnFunction(nFunction),
1066 mbSkipEmpty(bSkipEmpty)
1070 void operator() (size_t nRow, double f)
1072 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow);
1073 mrBlockPos.miCellPos = aPos.first;
1074 switch (aPos.first->type)
1076 case sc::element_type_numeric:
1078 // Both src and dest are of numeric type.
1079 bool bOk = lcl_DoFunction(f, sc::numeric_block::at(*aPos.first->data, aPos.second), mnFunction);
1081 if (bOk)
1082 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f);
1083 else
1085 ScFormulaCell* pFC =
1086 new ScFormulaCell(
1087 &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()));
1089 pFC->SetErrCode(errNoValue);
1090 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, pFC);
1093 break;
1094 case sc::element_type_formula:
1096 // Combination of value and at least one formula -> Create formula
1097 ScTokenArray aArr;
1099 // First row
1100 aArr.AddDouble(f);
1102 // Operator
1103 OpCode eOp = ocAdd;
1104 switch (mnFunction)
1106 case PASTE_ADD: eOp = ocAdd; break;
1107 case PASTE_SUB: eOp = ocSub; break;
1108 case PASTE_MUL: eOp = ocMul; break;
1109 case PASTE_DIV: eOp = ocDiv; break;
1111 aArr.AddOpCode(eOp); // Function
1113 // Second row
1114 ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second);
1115 lcl_AddCode(aArr, pDest);
1117 miNewCellsPos = maNewCells.set(
1118 miNewCellsPos, nRow-mnRowOffset,
1119 new ScFormulaCell(
1120 &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1122 break;
1123 case sc::element_type_string:
1124 case sc::element_type_edittext:
1125 case sc::element_type_empty:
1127 // Destination cell is not a number. Just take the source cell.
1128 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f);
1130 break;
1131 default:
1136 void operator() (size_t nRow, const svl::SharedString& rStr)
1138 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, rStr);
1141 void operator() (size_t nRow, const EditTextObject* p)
1143 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, p->Clone());
1146 void operator() (size_t nRow, const ScFormulaCell* p)
1148 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow);
1149 mrBlockPos.miCellPos = aPos.first;
1150 switch (aPos.first->type)
1152 case sc::element_type_numeric:
1154 // Source is formula, and dest is value.
1155 ScTokenArray aArr;
1157 // First row
1158 lcl_AddCode(aArr, p);
1160 // Operator
1161 OpCode eOp = ocAdd;
1162 switch (mnFunction)
1164 case PASTE_ADD: eOp = ocAdd; break;
1165 case PASTE_SUB: eOp = ocSub; break;
1166 case PASTE_MUL: eOp = ocMul; break;
1167 case PASTE_DIV: eOp = ocDiv; break;
1169 aArr.AddOpCode(eOp); // Function
1171 // Second row
1172 aArr.AddDouble(sc::numeric_block::at(*aPos.first->data, aPos.second));
1174 miNewCellsPos = maNewCells.set(
1175 miNewCellsPos, nRow-mnRowOffset,
1176 new ScFormulaCell(
1177 &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1179 break;
1180 case sc::element_type_formula:
1182 // Both are formulas.
1183 ScTokenArray aArr;
1185 // First row
1186 lcl_AddCode(aArr, p);
1188 // Operator
1189 OpCode eOp = ocAdd;
1190 switch (mnFunction)
1192 case PASTE_ADD: eOp = ocAdd; break;
1193 case PASTE_SUB: eOp = ocSub; break;
1194 case PASTE_MUL: eOp = ocMul; break;
1195 case PASTE_DIV: eOp = ocDiv; break;
1197 aArr.AddOpCode(eOp); // Function
1199 // Second row
1200 ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second);
1201 lcl_AddCode(aArr, pDest);
1203 miNewCellsPos = maNewCells.set(
1204 miNewCellsPos, nRow-mnRowOffset,
1205 new ScFormulaCell(
1206 &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1208 break;
1209 case sc::element_type_string:
1210 case sc::element_type_edittext:
1211 case sc::element_type_empty:
1213 // Destination cell is not a number. Just take the source cell.
1214 ScAddress aDestPos(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab());
1215 miNewCellsPos = maNewCells.set(
1216 miNewCellsPos, nRow-mnRowOffset, new ScFormulaCell(*p, mrDestColumn.GetDoc(), aDestPos));
1218 break;
1219 default:
1225 * Empty cell series in the source (clip) document.
1227 void operator() (mdds::mtv::element_t, size_t nTopRow, size_t nDataSize)
1229 if (mbSkipEmpty)
1230 return;
1232 // Source cells are empty. Treat them as if they have a value of 0.0.
1233 for (size_t i = 0; i < nDataSize; ++i)
1235 size_t nDestRow = nTopRow + i;
1236 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nDestRow);
1237 mrBlockPos.miCellPos = aPos.first;
1238 switch (aPos.first->type)
1240 case sc::element_type_numeric:
1242 double fVal = sc::numeric_block::at(*aPos.first->data, aPos.second);
1243 miNewCellsPos = maNewCells.set(
1244 miNewCellsPos, nDestRow-mnRowOffset, fVal);
1246 break;
1247 case sc::element_type_string:
1249 const svl::SharedString& aVal = sc::string_block::at(*aPos.first->data, aPos.second);
1250 miNewCellsPos = maNewCells.set(
1251 miNewCellsPos, nDestRow-mnRowOffset, aVal);
1253 break;
1254 case sc::element_type_edittext:
1256 EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
1257 miNewCellsPos = maNewCells.set(
1258 miNewCellsPos, nDestRow-mnRowOffset, pObj->Clone());
1260 break;
1261 case sc::element_type_formula:
1263 ScTokenArray aArr;
1265 // First row
1266 ScFormulaCell* pSrc = sc::formula_block::at(*aPos.first->data, aPos.second);
1267 lcl_AddCode( aArr, pSrc);
1269 // Operator
1270 OpCode eOp = ocAdd;
1271 switch (mnFunction)
1273 case PASTE_ADD: eOp = ocAdd; break;
1274 case PASTE_SUB: eOp = ocSub; break;
1275 case PASTE_MUL: eOp = ocMul; break;
1276 case PASTE_DIV: eOp = ocDiv; break;
1279 aArr.AddOpCode(eOp); // Function
1280 aArr.AddDouble(0.0);
1282 miNewCellsPos = maNewCells.set(
1283 miNewCellsPos, nDestRow-mnRowOffset,
1284 new ScFormulaCell(
1285 &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab()), aArr));
1287 break;
1288 default:
1295 * Set the new cells to the destination (this) column.
1297 void commit()
1299 sc::CellStoreType& rDestCells = mrDestColumn.GetCellStore();
1301 // Stop all formula cells in the destination range first.
1302 sc::CellStoreType::position_type aPos = rDestCells.position(mrBlockPos.miCellPos, mnRowOffset);
1303 mrDestColumn.DetachFormulaCells(aPos, maNewCells.size());
1305 // Move the new cells to the destination range.
1306 sc::CellStoreType::iterator& itDestPos = mrBlockPos.miCellPos;
1307 sc::CellTextAttrStoreType::iterator& itDestAttrPos = mrBlockPos.miCellTextAttrPos;
1309 sc::CellStoreType::iterator it = maNewCells.begin(), itEnd = maNewCells.end();
1310 for (; it != itEnd; ++it)
1312 bool bHasContent = true;
1313 size_t nDestRow = mnRowOffset + it->position;
1315 switch (it->type)
1317 case sc::element_type_numeric:
1319 sc::numeric_block::iterator itData = sc::numeric_block::begin(*it->data);
1320 sc::numeric_block::iterator itDataEnd = sc::numeric_block::end(*it->data);
1321 itDestPos = mrDestColumn.GetCellStore().set(itDestPos, nDestRow, itData, itDataEnd);
1323 break;
1324 case sc::element_type_string:
1326 sc::string_block::iterator itData = sc::string_block::begin(*it->data);
1327 sc::string_block::iterator itDataEnd = sc::string_block::end(*it->data);
1328 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1330 break;
1331 case sc::element_type_edittext:
1333 sc::edittext_block::iterator itData = sc::edittext_block::begin(*it->data);
1334 sc::edittext_block::iterator itDataEnd = sc::edittext_block::end(*it->data);
1335 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1337 break;
1338 case sc::element_type_formula:
1340 sc::formula_block::iterator itData = sc::formula_block::begin(*it->data);
1341 sc::formula_block::iterator itDataEnd = sc::formula_block::end(*it->data);
1343 // Group new formula cells before inserting them.
1344 sc::SharedFormulaUtil::groupFormulaCells(itData, itDataEnd);
1346 // Insert the formula cells to the column.
1347 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1349 // Merge with the previous formula group (if any).
1350 aPos = rDestCells.position(itDestPos, nDestRow);
1351 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1353 // Merge with the next formula group (if any).
1354 size_t nNextRow = nDestRow + it->size;
1355 if (ValidRow(nNextRow))
1357 aPos = rDestCells.position(aPos.first, nNextRow);
1358 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
1361 break;
1362 case sc::element_type_empty:
1364 itDestPos = rDestCells.set_empty(itDestPos, nDestRow, nDestRow+it->size-1);
1365 bHasContent = false;
1367 break;
1368 default:
1372 sc::CellTextAttrStoreType& rDestAttrs = mrDestColumn.GetCellAttrStore();
1373 if (bHasContent)
1375 std::vector<sc::CellTextAttr> aAttrs(it->size, sc::CellTextAttr());
1376 itDestAttrPos = rDestAttrs.set(itDestAttrPos, nDestRow, aAttrs.begin(), aAttrs.end());
1378 else
1379 itDestAttrPos = rDestAttrs.set_empty(itDestAttrPos, nDestRow, nDestRow+it->size-1);
1382 maNewCells.release();
1388 void ScColumn::MixData(
1389 sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, sal_uInt16 nFunction,
1390 bool bSkipEmpty, const ScColumn& rSrcCol )
1392 // destination (this column) block position.
1394 sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
1395 if (!p)
1396 return;
1398 MixDataHandler aFunc(*p, *this, nRow1, nRow2, nFunction, bSkipEmpty);
1399 sc::ParseAll(rSrcCol.maCells.begin(), rSrcCol.maCells, nRow1, nRow2, aFunc, aFunc);
1401 aFunc.commit();
1402 CellStorageModified();
1406 ScAttrIterator* ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
1408 return new ScAttrIterator( pAttrArray, nStartRow, nEndRow );
1411 namespace {
1413 class StartAllListenersHandler
1415 ScDocument* mpDoc;
1416 public:
1417 StartAllListenersHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
1419 void operator() (size_t, ScFormulaCell* p)
1421 p->StartListeningTo(mpDoc);
1425 class StartNeededListenerHandler
1427 ScDocument* mpDoc;
1428 public:
1429 StartNeededListenerHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
1431 void operator() (size_t, ScFormulaCell* p)
1433 if (p->NeedsListening())
1434 p->StartListeningTo(mpDoc);
1440 void ScColumn::StartAllListeners()
1442 StartAllListenersHandler aFunc(pDocument);
1443 sc::ProcessFormula(maCells, aFunc);
1447 void ScColumn::StartNeededListeners()
1449 StartNeededListenerHandler aFunc(pDocument);
1450 sc::ProcessFormula(maCells, aFunc);
1453 namespace {
1455 class StartListeningInAreaHandler
1457 sc::StartListeningContext& mrCxt;
1458 public:
1459 StartListeningInAreaHandler(sc::StartListeningContext& rCxt) : mrCxt(rCxt) {}
1461 void operator() (size_t /*nRow*/, ScFormulaCell* p)
1463 p->StartListeningTo(mrCxt);
1469 void ScColumn::StartListeningInArea( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 )
1471 StartListeningInAreaHandler aFunc(rCxt);
1472 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
1475 bool ScColumn::ParseString(
1476 ScCellValue& rCell, SCROW nRow, SCTAB nTabP, const OUString& rString,
1477 formula::FormulaGrammar::AddressConvention eConv,
1478 ScSetStringParam* pParam )
1480 if (rString.isEmpty())
1481 return false;
1483 bool bNumFmtSet = false;
1485 ScSetStringParam aParam;
1487 if (pParam)
1488 aParam = *pParam;
1490 sal_uInt32 nIndex = 0;
1491 sal_uInt32 nOldIndex = 0;
1492 sal_Unicode cFirstChar;
1493 if (!aParam.mpNumFormatter)
1494 aParam.mpNumFormatter = pDocument->GetFormatTable();
1496 nIndex = nOldIndex = GetNumberFormat( nRow );
1497 if ( rString.getLength() > 1
1498 && aParam.mpNumFormatter->GetType(nIndex) != NUMBERFORMAT_TEXT )
1499 cFirstChar = rString[0];
1500 else
1501 cFirstChar = 0; // Text
1503 svl::SharedStringPool& rPool = pDocument->GetSharedStringPool();
1505 if ( cFirstChar == '=' )
1507 if ( rString.getLength() == 1 ) // = Text
1509 rCell.set(rPool.intern(rString));
1511 else // = Formula
1512 rCell.set(
1513 new ScFormulaCell(
1514 pDocument, ScAddress(nCol, nRow, nTabP), rString,
1515 formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_DEFAULT, eConv),
1516 MM_NONE));
1518 else if ( cFirstChar == '\'') // 'Text
1520 bool bNumeric = false;
1521 if (aParam.mbHandleApostrophe)
1523 // Cell format is not 'Text', and the first char
1524 // is an apostrophe. Check if the input is considered a number.
1525 OUString aTest = rString.copy(1);
1526 double fTest;
1527 bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest);
1528 if (bNumeric)
1529 // This is a number. Strip out the first char.
1530 rCell.set(rPool.intern(aTest));
1532 if (!bNumeric)
1533 // This is normal text. Take it as-is.
1534 rCell.set(rPool.intern(rString));
1536 else
1538 double nVal;
1542 if (aParam.mbDetectNumberFormat)
1544 if (!aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
1545 break;
1547 // convert back to the original language if a built-in format was detected
1548 const SvNumberformat* pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex );
1549 if ( pOldFormat )
1550 nIndex = aParam.mpNumFormatter->GetFormatForLanguageIfBuiltIn( nIndex, pOldFormat->GetLanguage() );
1552 rCell.set(nVal);
1553 if ( nIndex != nOldIndex)
1555 // #i22345# New behavior: Apply the detected number format only if
1556 // the old one was the default number, date, time or boolean format.
1557 // Exception: If the new format is boolean, always apply it.
1559 bool bOverwrite = false;
1560 if ( pOldFormat )
1562 short nOldType = pOldFormat->GetType() & ~NUMBERFORMAT_DEFINED;
1563 if ( nOldType == NUMBERFORMAT_NUMBER || nOldType == NUMBERFORMAT_DATE ||
1564 nOldType == NUMBERFORMAT_TIME || nOldType == NUMBERFORMAT_LOGICAL )
1566 if ( nOldIndex == aParam.mpNumFormatter->GetStandardFormat(
1567 nOldType, pOldFormat->GetLanguage() ) )
1569 bOverwrite = true; // default of these types can be overwritten
1573 if ( !bOverwrite && aParam.mpNumFormatter->GetType( nIndex ) == NUMBERFORMAT_LOGICAL )
1575 bOverwrite = true; // overwrite anything if boolean was detected
1578 if ( bOverwrite )
1580 ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT,
1581 (sal_uInt32) nIndex) );
1582 bNumFmtSet = true;
1586 else if (aParam.meSetTextNumFormat != ScSetStringParam::Always)
1588 // Only check if the string is a regular number.
1589 const LocaleDataWrapper* pLocale = aParam.mpNumFormatter->GetLocaleData();
1590 if (!pLocale)
1591 break;
1593 LocaleDataItem aLocaleItem = pLocale->getLocaleItem();
1594 const OUString& rDecSep = aLocaleItem.decimalSeparator;
1595 const OUString& rGroupSep = aLocaleItem.thousandSeparator;
1596 if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1)
1597 break;
1599 sal_Unicode dsep = rDecSep[0];
1600 sal_Unicode gsep = rGroupSep[0];
1602 if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, nVal))
1603 break;
1605 rCell.set(nVal);
1608 while (false);
1610 if (rCell.meType == CELLTYPE_NONE)
1612 if (aParam.meSetTextNumFormat != ScSetStringParam::Never && aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
1614 // Set the cell format type to Text.
1615 sal_uInt32 nFormat = aParam.mpNumFormatter->GetStandardFormat(NUMBERFORMAT_TEXT);
1616 ScPatternAttr aNewAttrs(pDocument->GetPool());
1617 SfxItemSet& rSet = aNewAttrs.GetItemSet();
1618 rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat) );
1619 ApplyPattern(nRow, aNewAttrs);
1622 rCell.set(rPool.intern(rString));
1626 return bNumFmtSet;
1630 * Returns true if the cell format was set as well
1632 bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString,
1633 formula::FormulaGrammar::AddressConvention eConv,
1634 ScSetStringParam* pParam )
1636 if (!ValidRow(nRow))
1637 return false;
1639 ScCellValue aNewCell;
1640 bool bNumFmtSet = ParseString(aNewCell, nRow, nTabP, rString, eConv, pParam);
1641 aNewCell.release(*this, nRow);
1643 // Do not set Formats and Formulas here anymore!
1644 // These are queried during output
1646 return bNumFmtSet;
1649 void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
1651 pEditText->NormalizeString(pDocument->GetSharedStringPool());
1652 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1653 maCells.set(it, nRow, pEditText);
1654 maCellTextAttrs.set(nRow, sc::CellTextAttr());
1655 CellStorageModified();
1657 BroadcastNewCell(nRow);
1660 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, EditTextObject* pEditText )
1662 pEditText->NormalizeString(pDocument->GetSharedStringPool());
1663 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
1664 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText);
1665 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
1666 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1668 CellStorageModified();
1670 BroadcastNewCell(nRow);
1673 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const EditTextObject& rEditText )
1675 if (pDocument->GetEditPool() == rEditText.GetPool())
1677 SetEditText(rBlockPos, nRow, rEditText.Clone());
1678 return;
1681 //! another "spool"
1682 // Sadly there is no other way to change the Pool than to
1683 // "spool" the Object through a corresponding Engine
1684 EditEngine& rEngine = pDocument->GetEditEngine();
1685 rEngine.SetText(rEditText);
1686 SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
1687 return;
1690 void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
1692 if (pEditPool && pDocument->GetEditPool() == pEditPool)
1694 SetEditText(nRow, rEditText.Clone());
1695 return;
1698 //! another "spool"
1699 // Sadly there is no other way to change the Pool than to
1700 // "spool" the Object through a corresponding Engine
1701 EditEngine& rEngine = pDocument->GetEditEngine();
1702 rEngine.SetText(rEditText);
1703 SetEditText(nRow, rEngine.CreateTextObject());
1704 return;
1707 void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram )
1709 ScAddress aPos(nCol, nRow, nTab);
1711 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1712 ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rArray, eGram);
1713 sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1714 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1715 pCell->SetNeedNumberFormat(true);
1716 it = maCells.set(it, nRow, pCell);
1717 maCellTextAttrs.set(nRow, sc::CellTextAttr());
1719 CellStorageModified();
1721 ActivateNewFormulaCell(it, nRow, *pCell);
1724 void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
1726 ScAddress aPos(nCol, nRow, nTab);
1728 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1729 ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rFormula, eGram);
1730 sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1731 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1732 pCell->SetNeedNumberFormat(true);
1733 it = maCells.set(it, nRow, pCell);
1734 maCellTextAttrs.set(nRow, sc::CellTextAttr());
1736 CellStorageModified();
1738 ActivateNewFormulaCell(it, nRow, *pCell);
1741 ScFormulaCell* ScColumn::SetFormulaCell( SCROW nRow, ScFormulaCell* pCell )
1743 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1744 sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1745 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1746 pCell->SetNeedNumberFormat(true);
1747 it = maCells.set(it, nRow, pCell);
1748 maCellTextAttrs.set(nRow, sc::CellTextAttr());
1750 CellStorageModified();
1752 ActivateNewFormulaCell(it, nRow, *pCell);
1753 return pCell;
1756 ScFormulaCell* ScColumn::SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell )
1758 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
1759 sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1760 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1761 pCell->SetNeedNumberFormat(true);
1762 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pCell);
1763 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
1764 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1766 CellStorageModified();
1768 ActivateNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell);
1769 return pCell;
1772 svl::SharedString ScColumn::GetSharedString( SCROW nRow ) const
1774 sc::CellStoreType::const_position_type aPos = maCells.position(nRow);
1775 switch (aPos.first->type)
1777 case sc::element_type_string:
1778 return sc::string_block::at(*aPos.first->data, aPos.second);
1779 case sc::element_type_edittext:
1781 const EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
1782 std::vector<svl::SharedString> aSSs = pObj->GetSharedStrings();
1783 if (aSSs.size() != 1)
1784 // We don't handle multiline content for now.
1785 return svl::SharedString();
1787 return aSSs[0];
1789 break;
1790 default:
1793 return svl::SharedString();
1796 namespace {
1798 class FilterEntriesHandler
1800 ScColumn& mrColumn;
1801 std::vector<ScTypedStrData>& mrStrings;
1802 bool mbHasDates;
1804 void processCell(SCROW nRow, ScRefCellValue& rCell)
1806 SvNumberFormatter* pFormatter = mrColumn.GetDoc().GetFormatTable();
1807 OUString aStr;
1808 sal_uLong nFormat = mrColumn.GetNumberFormat(nRow);
1809 ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter, &mrColumn.GetDoc());
1811 if (rCell.hasString())
1813 mrStrings.push_back(ScTypedStrData(aStr));
1814 return;
1817 double fVal = 0.0;
1819 switch (rCell.meType)
1821 case CELLTYPE_VALUE:
1822 fVal = rCell.mfValue;
1823 break;
1825 case CELLTYPE_FORMULA:
1827 ScFormulaCell* pFC = rCell.mpFormula;
1828 sal_uInt16 nErr = pFC->GetErrCode();
1829 if (nErr)
1831 // Error cell is evaluated as string (for now).
1832 OUString aErr = ScGlobal::GetErrorString(nErr);
1833 if (!aErr.isEmpty())
1835 mrStrings.push_back(ScTypedStrData(aErr));
1836 return;
1839 else
1840 fVal = pFC->GetValue();
1842 break;
1843 default:
1847 short nType = pFormatter->GetType(nFormat);
1848 bool bDate = false;
1849 if ((nType & NUMBERFORMAT_DATE) && !(nType & NUMBERFORMAT_TIME))
1851 // special case for date values. Disregard the time
1852 // element if the number format is of date type.
1853 fVal = rtl::math::approxFloor(fVal);
1854 mbHasDates = true;
1855 bDate = true;
1857 // maybe extend ScTypedStrData enum is also an option here
1858 mrStrings.push_back(ScTypedStrData(aStr, fVal, ScTypedStrData::Value,bDate));
1861 public:
1862 FilterEntriesHandler(ScColumn& rColumn, std::vector<ScTypedStrData>& rStrings) :
1863 mrColumn(rColumn), mrStrings(rStrings), mbHasDates(false) {}
1865 void operator() (size_t nRow, double fVal)
1867 ScRefCellValue aCell(fVal);
1868 processCell(nRow, aCell);
1871 void operator() (size_t nRow, const svl::SharedString& rStr)
1873 ScRefCellValue aCell(&rStr);
1874 processCell(nRow, aCell);
1877 void operator() (size_t nRow, const EditTextObject* p)
1879 ScRefCellValue aCell(p);
1880 processCell(nRow, aCell);
1883 void operator() (size_t nRow, const ScFormulaCell* p)
1885 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
1886 processCell(nRow, aCell);
1889 bool hasDates() const { return mbHasDates; }
1894 void ScColumn::GetFilterEntries(SCROW nStartRow, SCROW nEndRow, std::vector<ScTypedStrData>& rStrings, bool& rHasDates)
1896 FilterEntriesHandler aFunc(*this, rStrings);
1897 sc::ParseAllNonEmpty(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
1898 rHasDates = aFunc.hasDates();
1901 namespace {
1904 * Iterate over only string and edit-text cells.
1906 class StrCellIterator
1908 typedef std::pair<sc::CellStoreType::const_iterator,size_t> PosType;
1909 PosType maPos;
1910 sc::CellStoreType::const_iterator miBeg;
1911 sc::CellStoreType::const_iterator miEnd;
1912 const ScDocument* mpDoc;
1913 public:
1914 StrCellIterator(const sc::CellStoreType& rCells, SCROW nStart, const ScDocument* pDoc) :
1915 miBeg(rCells.begin()), miEnd(rCells.end()), mpDoc(pDoc)
1917 if (ValidRow(nStart))
1918 maPos = rCells.position(nStart);
1919 else
1920 // Make this iterator invalid.
1921 maPos.first = miEnd;
1924 bool valid() const { return (maPos.first != miEnd); }
1926 bool has() const
1928 return (maPos.first->type == sc::element_type_string || maPos.first->type == sc::element_type_edittext);
1931 bool prev()
1933 if (!has())
1935 // Not in a string block. Move back until we hit a string block.
1936 while (!has())
1938 if (maPos.first == miBeg)
1939 return false;
1941 --maPos.first; // move to the preceding block.
1942 maPos.second = maPos.first->size - 1; // last cell in the block.
1944 return true;
1947 // We are in a string block.
1948 if (maPos.second > 0)
1950 // Move back one cell in the same block.
1951 --maPos.second;
1953 else
1955 // Move back to the preceding string block.
1956 while (true)
1958 if (maPos.first == miBeg)
1959 return false;
1961 // Move to the last cell of the previous block.
1962 --maPos.first;
1963 maPos.second = maPos.first->size - 1;
1964 if (has())
1965 break;
1968 return true;
1971 bool next()
1973 if (!has())
1975 // Not in a string block. Move forward until we hit a string block.
1976 while (!has())
1978 ++maPos.first;
1979 if (maPos.first == miEnd)
1980 return false;
1982 maPos.second = 0; // First cell in this block.
1984 return true;
1987 // We are in a string block.
1988 ++maPos.second;
1989 if (maPos.second >= maPos.first->size)
1991 // Move to the next string block.
1992 while (true)
1994 ++maPos.first;
1995 if (maPos.first == miEnd)
1996 return false;
1998 maPos.second = 0;
1999 if (has())
2000 break;
2003 return true;
2006 OUString get() const
2008 switch (maPos.first->type)
2010 case sc::element_type_string:
2011 return sc::string_block::at(*maPos.first->data, maPos.second).getString();
2012 case sc::element_type_edittext:
2014 const EditTextObject* p = sc::edittext_block::at(*maPos.first->data, maPos.second);
2015 return ScEditUtil::GetString(*p, mpDoc);
2017 default:
2020 return OUString();
2027 // GetDataEntries - Strings from continuous Section around nRow
2030 // DATENT_MAX - max. number of entries in list for auto entry
2031 // DATENT_SEARCH - max. number of cells that get transparent - new: only count Strings
2032 #define DATENT_MAX 200
2033 #define DATENT_SEARCH 2000
2035 bool ScColumn::GetDataEntries(
2036 SCROW nStartRow, std::set<ScTypedStrData>& rStrings, bool bLimit ) const
2038 // Start at the specified row position, and collect all string values
2039 // going upward and downward directions in parallel. The start position
2040 // cell must be skipped.
2042 StrCellIterator aItrUp(maCells, nStartRow, pDocument);
2043 StrCellIterator aItrDown(maCells, nStartRow+1, pDocument);
2045 bool bMoveUp = aItrUp.valid();
2046 if (!bMoveUp)
2047 // Current cell is invalid.
2048 return false;
2050 // Skip the start position cell.
2051 bMoveUp = aItrUp.prev(); // Find the previous string cell position.
2053 bool bMoveDown = aItrDown.valid();
2054 if (bMoveDown && !aItrDown.has())
2055 bMoveDown = aItrDown.next(); // Find the next string cell position.
2057 bool bFound = false;
2058 size_t nCellsSearched = 0;
2059 while (bMoveUp || bMoveDown)
2061 if (bMoveUp)
2063 // Get the current string and move up.
2064 OUString aStr = aItrUp.get();
2065 if (!aStr.isEmpty())
2067 bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second;
2068 if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
2069 return true; // Maximum reached
2070 bFound = true;
2073 if (bLimit && ++nCellsSearched >= DATENT_SEARCH)
2074 return bFound; // max search cell count reached.
2076 bMoveUp = aItrUp.prev();
2079 if (bMoveDown)
2081 // Get the current string and move down.
2082 OUString aStr = aItrDown.get();
2083 if (!aStr.isEmpty())
2085 bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second;
2086 if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
2087 return true; // Maximum reached
2088 bFound = true;
2091 if (bLimit && ++nCellsSearched >= DATENT_SEARCH)
2092 return bFound; // max search cell count reached.
2094 bMoveDown = aItrDown.next();
2098 return bFound;
2101 namespace {
2103 class FormulaToValueHandler
2105 struct Entry
2107 SCROW mnRow;
2108 ScCellValue maValue;
2110 Entry(SCROW nRow, double f) : mnRow(nRow), maValue(f) {}
2111 Entry(SCROW nRow, const svl::SharedString& rStr) : mnRow(nRow), maValue(rStr) {}
2114 typedef std::vector<Entry> EntriesType;
2115 EntriesType maEntries;
2117 public:
2119 void operator() (size_t nRow, const ScFormulaCell* p)
2121 ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
2122 if (p2->IsValue())
2123 maEntries.push_back(Entry(nRow, p2->GetValue()));
2124 else
2125 maEntries.push_back(Entry(nRow, p2->GetString()));
2128 void commitCells(ScColumn& rColumn)
2130 sc::ColumnBlockPosition aBlockPos;
2131 rColumn.InitBlockPosition(aBlockPos);
2133 EntriesType::iterator it = maEntries.begin(), itEnd = maEntries.end();
2134 for (; it != itEnd; ++it)
2136 Entry& r = *it;
2137 switch (r.maValue.meType)
2139 case CELLTYPE_VALUE:
2140 rColumn.SetValue(aBlockPos, r.mnRow, r.maValue.mfValue, false);
2141 break;
2142 case CELLTYPE_STRING:
2143 rColumn.SetRawString(aBlockPos, r.mnRow, *r.maValue.mpString, false);
2144 default:
2153 void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
2155 FormulaToValueHandler aFunc;
2156 sc::CellStoreType::const_iterator itPos = maCells.begin();
2158 ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
2159 SCROW nTop = -1;
2160 SCROW nBottom = -1;
2161 const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
2162 while (pPattern)
2164 const ScProtectionAttr* pAttr = (const ScProtectionAttr*)&pPattern->GetItem(ATTR_PROTECTION);
2165 if ( pAttr->GetHideCell() )
2166 DeleteArea( nTop, nBottom, IDF_CONTENTS );
2167 else if ( pAttr->GetHideFormula() )
2169 // Replace all formula cells between nTop and nBottom with raw value cells.
2170 itPos = sc::ParseFormula(itPos, maCells, nTop, nBottom, aFunc);
2173 pPattern = aAttrIter.Next( nTop, nBottom );
2176 aFunc.commitCells(*this);
2180 void ScColumn::SetError( SCROW nRow, const sal_uInt16 nError)
2182 if (!ValidRow(nRow))
2183 return;
2185 ScFormulaCell* pCell = new ScFormulaCell(pDocument, ScAddress(nCol, nRow, nTab));
2186 pCell->SetErrCode(nError);
2188 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
2189 it = maCells.set(it, nRow, pCell);
2190 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2192 CellStorageModified();
2194 ActivateNewFormulaCell(it, nRow, *pCell);
2197 void ScColumn::SetRawString( SCROW nRow, const OUString& rStr, bool bBroadcast )
2199 if (!ValidRow(nRow))
2200 return;
2202 svl::SharedString aSS = pDocument->GetSharedStringPool().intern(rStr);
2203 if (!aSS.getData())
2204 return;
2206 SetRawString(nRow, aSS, bBroadcast);
2209 void ScColumn::SetRawString( SCROW nRow, const svl::SharedString& rStr, bool bBroadcast )
2211 if (!ValidRow(nRow))
2212 return;
2214 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
2215 maCells.set(it, nRow, rStr);
2216 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2218 CellStorageModified();
2220 if (bBroadcast)
2221 BroadcastNewCell(nRow);
2224 void ScColumn::SetRawString(
2225 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const OUString& rStr, bool bBroadcast )
2227 svl::SharedString aSS = pDocument->GetSharedStringPool().intern(rStr);
2228 if (!aSS.getData())
2229 return;
2231 SetRawString(rBlockPos, nRow, aSS, bBroadcast);
2234 void ScColumn::SetRawString(
2235 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const svl::SharedString& rStr, bool bBroadcast )
2237 if (!ValidRow(nRow))
2238 return;
2240 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
2241 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr);
2242 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2243 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2245 CellStorageModified();
2247 if (bBroadcast)
2248 BroadcastNewCell(nRow);
2251 void ScColumn::SetValue( SCROW nRow, double fVal )
2253 if (!ValidRow(nRow))
2254 return;
2256 sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
2257 maCells.set(it, nRow, fVal);
2258 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2260 CellStorageModified();
2262 BroadcastNewCell(nRow);
2265 void ScColumn::SetValue(
2266 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, double fVal, bool bBroadcast )
2268 if (!ValidRow(nRow))
2269 return;
2271 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
2272 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal);
2273 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2274 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2276 CellStorageModified();
2278 if (bBroadcast)
2279 BroadcastNewCell(nRow);
2282 void ScColumn::GetString( SCROW nRow, OUString& rString ) const
2284 ScRefCellValue aCell = GetCellValue(nRow);
2286 // ugly hack for ordering problem with GetNumberFormat and missing inherited formats
2287 if (aCell.meType == CELLTYPE_FORMULA)
2288 aCell.mpFormula->MaybeInterpret();
2290 sal_uLong nFormat = GetNumberFormat(nRow);
2291 Color* pColor = NULL;
2292 ScCellFormat::GetString(aCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()), pDocument);
2295 double* ScColumn::GetValueCell( SCROW nRow )
2297 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2298 sc::CellStoreType::iterator it = aPos.first;
2299 if (it == maCells.end())
2300 return NULL;
2302 if (it->type != sc::element_type_numeric)
2303 return NULL;
2305 return &sc::numeric_block::at(*it->data, aPos.second);
2308 void ScColumn::GetInputString( SCROW nRow, OUString& rString ) const
2310 ScRefCellValue aCell = GetCellValue(nRow);
2311 sal_uLong nFormat = GetNumberFormat(nRow);
2312 ScCellFormat::GetInputString(aCell, nFormat, rString, *(pDocument->GetFormatTable()), pDocument);
2315 double ScColumn::GetValue( SCROW nRow ) const
2317 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2318 sc::CellStoreType::const_iterator it = aPos.first;
2319 switch (it->type)
2321 case sc::element_type_numeric:
2322 return sc::numeric_block::at(*it->data, aPos.second);
2323 case sc::element_type_formula:
2325 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
2326 ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
2327 return p2->IsValue() ? p2->GetValue() : 0.0;
2329 default:
2333 return 0.0;
2336 const EditTextObject* ScColumn::GetEditText( SCROW nRow ) const
2338 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2339 sc::CellStoreType::const_iterator it = aPos.first;
2340 if (it == maCells.end())
2341 return NULL;
2343 if (it->type != sc::element_type_edittext)
2344 return NULL;
2346 return sc::edittext_block::at(*it->data, aPos.second);
2349 void ScColumn::RemoveEditTextCharAttribs( SCROW nRow, const ScPatternAttr& rAttr )
2351 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2352 sc::CellStoreType::iterator it = aPos.first;
2353 if (it == maCells.end())
2354 return;
2356 if (it->type != sc::element_type_edittext)
2357 return;
2359 EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
2360 ScEditUtil::RemoveCharAttribs(*p, rAttr);
2363 void ScColumn::GetFormula( SCROW nRow, OUString& rFormula ) const
2365 const ScFormulaCell* p = FetchFormulaCell(nRow);
2366 if (p)
2367 p->GetFormula(rFormula);
2368 else
2369 rFormula = EMPTY_OUSTRING;
2372 const ScTokenArray* ScColumn::GetFormulaTokens( SCROW nRow ) const
2374 const ScFormulaCell* pCell = FetchFormulaCell(nRow);
2375 if (!pCell)
2376 return NULL;
2378 return pCell->GetCode();
2381 const ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow ) const
2383 return FetchFormulaCell(nRow);
2386 ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow )
2388 return const_cast<ScFormulaCell*>(FetchFormulaCell(nRow));
2391 CellType ScColumn::GetCellType( SCROW nRow ) const
2393 switch (maCells.get_type(nRow))
2395 case sc::element_type_numeric:
2396 return CELLTYPE_VALUE;
2397 case sc::element_type_string:
2398 return CELLTYPE_STRING;
2399 case sc::element_type_edittext:
2400 return CELLTYPE_EDIT;
2401 case sc::element_type_formula:
2402 return CELLTYPE_FORMULA;
2403 default:
2406 return CELLTYPE_NONE;
2409 namespace {
2412 * Count the number of all non-empty cells.
2414 class CellCounter
2416 size_t mnCount;
2417 public:
2418 CellCounter() : mnCount(0) {}
2420 void operator() (const sc::CellStoreType::value_type& node)
2422 if (node.type == sc::element_type_empty)
2423 return;
2425 mnCount += node.size;
2428 size_t getCount() const { return mnCount; }
2433 SCSIZE ScColumn::GetCellCount() const
2435 CellCounter aFunc;
2436 std::for_each(maCells.begin(), maCells.end(), aFunc);
2437 return aFunc.getCount();
2440 sal_uInt16 ScColumn::GetErrCode( SCROW nRow ) const
2442 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2443 sc::CellStoreType::const_iterator it = aPos.first;
2444 if (it == maCells.end())
2445 return 0;
2447 if (it->type != sc::element_type_formula)
2448 return 0;
2450 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
2451 return const_cast<ScFormulaCell*>(p)->GetErrCode();
2455 bool ScColumn::HasStringData( SCROW nRow ) const
2457 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2458 switch (aPos.first->type)
2460 case sc::element_type_string:
2461 case sc::element_type_edittext:
2462 return true;
2463 case sc::element_type_formula:
2465 const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
2466 return !const_cast<ScFormulaCell*>(p)->IsValue();
2468 default:
2472 return false;
2476 bool ScColumn::HasValueData( SCROW nRow ) const
2478 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2479 switch (aPos.first->type)
2481 case sc::element_type_numeric:
2482 return true;
2483 case sc::element_type_formula:
2485 const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
2486 return const_cast<ScFormulaCell*>(p)->IsValue();
2488 default:
2492 return false;
2496 * Return true if there is a string or editcell in the range
2498 bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
2500 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
2501 sc::CellStoreType::const_iterator it = aPos.first;
2502 size_t nOffset = aPos.second;
2503 SCROW nRow = nStartRow;
2504 for (; it != maCells.end() && nRow <= nEndRow; ++it)
2506 if (it->type == sc::element_type_string || it->type == sc::element_type_edittext)
2507 return true;
2509 nRow += it->size - nOffset;
2510 nOffset = 0;
2513 return false;
2516 namespace {
2518 class MaxStringLenHandler
2520 sal_Int32 mnMaxLen;
2521 const ScColumn& mrColumn;
2522 SvNumberFormatter* mpFormatter;
2523 rtl_TextEncoding meCharSet;
2524 bool mbOctetEncoding;
2526 void processCell(size_t nRow, ScRefCellValue& rCell)
2528 Color* pColor;
2529 OUString aString;
2530 sal_uInt32 nFormat = static_cast<const SfxUInt32Item*>(mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT))->GetValue();
2531 ScCellFormat::GetString(rCell, nFormat, aString, &pColor, *mpFormatter, &mrColumn.GetDoc());
2532 sal_Int32 nLen = 0;
2533 if (mbOctetEncoding)
2535 OString aOString;
2536 if (!aString.convertToString(&aOString, meCharSet,
2537 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
2538 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
2540 // TODO: anything? this is used by the dBase export filter
2541 // that throws an error anyway, but in case of another
2542 // context we might want to indicate a conversion error
2543 // early.
2545 nLen = aOString.getLength();
2547 else
2548 nLen = aString.getLength() * sizeof(sal_Unicode);
2550 if (mnMaxLen < nLen)
2551 mnMaxLen = nLen;
2554 public:
2555 MaxStringLenHandler(const ScColumn& rColumn, rtl_TextEncoding eCharSet) :
2556 mnMaxLen(0),
2557 mrColumn(rColumn),
2558 mpFormatter(rColumn.GetDoc().GetFormatTable()),
2559 meCharSet(eCharSet),
2560 mbOctetEncoding(rtl_isOctetTextEncoding(eCharSet))
2564 void operator() (size_t nRow, double fVal)
2566 ScRefCellValue aCell(fVal);
2567 processCell(nRow, aCell);
2570 void operator() (size_t nRow, const svl::SharedString& rStr)
2572 ScRefCellValue aCell(&rStr);
2573 processCell(nRow, aCell);
2576 void operator() (size_t nRow, const EditTextObject* p)
2578 ScRefCellValue aCell(p);
2579 processCell(nRow, aCell);
2582 void operator() (size_t nRow, const ScFormulaCell* p)
2584 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
2585 processCell(nRow, aCell);
2588 sal_Int32 getMaxLen() const { return mnMaxLen; }
2593 sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
2595 MaxStringLenHandler aFunc(*this, eCharSet);
2596 sc::ParseAllNonEmpty(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
2597 return aFunc.getMaxLen();
2600 namespace {
2602 class MaxNumStringLenHandler
2604 const ScColumn& mrColumn;
2605 SvNumberFormatter* mpFormatter;
2606 sal_Int32 mnMaxLen;
2607 sal_uInt16 mnPrecision;
2609 void processCell(size_t nRow, ScRefCellValue& rCell)
2611 if (rCell.meType == CELLTYPE_FORMULA && !rCell.mpFormula->IsValue())
2612 return;
2614 OUString aString;
2615 sal_uInt32 nFormat = static_cast<const SfxUInt32Item*>(
2616 mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT))->GetValue();
2617 ScCellFormat::GetInputString(rCell, nFormat, aString, *mpFormatter, &mrColumn.GetDoc());
2618 sal_Int32 nLen = aString.getLength();
2619 if (nLen <= 0)
2620 // Ignore empty string.
2621 return;
2623 if (nFormat)
2625 const SvNumberformat* pEntry = mpFormatter->GetEntry(nFormat);
2626 sal_uInt16 nPrec;
2627 if (pEntry)
2629 bool bThousand, bNegRed;
2630 sal_uInt16 nLeading;
2631 pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading);
2633 else
2634 nPrec = mpFormatter->GetFormatPrecision(nFormat);
2636 if (nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > mnPrecision)
2637 mnPrecision = nPrec;
2640 if (mnPrecision)
2641 { // less than mnPrecision in string => widen it
2642 // more => shorten it
2643 OUString aSep = mpFormatter->GetFormatDecimalSep(nFormat);
2644 sal_Int32 nTmp = aString.indexOf(aSep);
2645 if ( nTmp == -1 )
2646 nLen += mnPrecision + aSep.getLength();
2647 else
2649 nTmp = aString.getLength() - (nTmp + aSep.getLength());
2650 if (nTmp != mnPrecision)
2651 nLen += mnPrecision - nTmp;
2652 // nPrecision > nTmp : nLen + Diff
2653 // nPrecision < nTmp : nLen - Diff
2657 if (mnMaxLen < nLen)
2658 mnMaxLen = nLen;
2661 public:
2662 MaxNumStringLenHandler(const ScColumn& rColumn, sal_uInt16 nPrecision) :
2663 mrColumn(rColumn), mpFormatter(rColumn.GetDoc().GetFormatTable()),
2664 mnMaxLen(0), mnPrecision(nPrecision)
2668 void operator() (size_t nRow, double fVal)
2670 ScRefCellValue aCell(fVal);
2671 processCell(nRow, aCell);
2674 void operator() (size_t nRow, const ScFormulaCell* p)
2676 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
2677 processCell(nRow, aCell);
2680 sal_Int32 getMaxLen() const { return mnMaxLen; }
2682 sal_uInt16 getPrecision() const { return mnPrecision; }
2687 xub_StrLen ScColumn::GetMaxNumberStringLen(
2688 sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
2690 nPrecision = pDocument->GetDocOptions().GetStdPrecision();
2691 if ( nPrecision == SvNumberFormatter::UNLIMITED_PRECISION )
2692 // In case of unlimited precision, use 2 instead.
2693 nPrecision = 2;
2695 MaxNumStringLenHandler aFunc(*this, nPrecision);
2696 sc::ParseFormulaNumeric(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
2697 nPrecision = aFunc.getPrecision();
2698 return aFunc.getMaxLen();
2701 namespace {
2703 class GroupFormulaCells
2705 ScFormulaCellGroupRef mxNone;
2707 public:
2709 void operator() (sc::CellStoreType::value_type& node)
2711 if (node.type != sc::element_type_formula)
2712 // We are only interested in formula cells.
2713 return;
2715 size_t nRow = node.position; // start row position.
2717 sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
2718 sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
2720 // This block should never be empty.
2722 ScFormulaCell* pPrev = *it;
2723 ScFormulaCellGroupRef xPrevGrp = pPrev->GetCellGroup();
2724 if (xPrevGrp)
2726 // Move to the cell after the last cell of the current group.
2727 std::advance(it, xPrevGrp->mnLength);
2728 nRow += xPrevGrp->mnLength;
2730 else
2732 ++it;
2733 ++nRow;
2736 ScFormulaCell* pCur = NULL;
2737 ScFormulaCellGroupRef xCurGrp;
2738 for (; it != itEnd; pPrev = pCur, xPrevGrp = xCurGrp)
2740 pCur = *it;
2741 xCurGrp = pCur->GetCellGroup();
2743 ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(*pCur);
2744 if (eCompState == ScFormulaCell::NotEqual)
2746 // different formula tokens.
2747 if (xCurGrp)
2749 // Move to the cell after the last cell of the current group.
2750 std::advance(it, xCurGrp->mnLength);
2751 nRow += xCurGrp->mnLength;
2753 else
2755 ++it;
2756 ++nRow;
2759 continue;
2762 // Formula tokens equal those of the previous formula cell or cell group.
2763 if (xPrevGrp)
2765 // Previous cell is a group.
2766 if (xCurGrp)
2768 // The current cell is a group. Merge these two groups.
2769 xPrevGrp->mnLength += xCurGrp->mnLength;
2770 pCur->SetCellGroup(xPrevGrp);
2771 sc::formula_block::iterator itGrpEnd = it;
2772 std::advance(itGrpEnd, xCurGrp->mnLength);
2773 for (++it; it != itGrpEnd; ++it)
2775 ScFormulaCell* pCell = *it;
2776 pCell->SetCellGroup(xPrevGrp);
2778 nRow += xCurGrp->mnLength;
2780 else
2782 // Add this cell to the previous group.
2783 pCur->SetCellGroup(xPrevGrp);
2784 ++xPrevGrp->mnLength;
2785 ++nRow;
2786 ++it;
2790 else if (xCurGrp)
2792 // Previous cell is a regular cell and current cell is a group.
2793 nRow += xCurGrp->mnLength;
2794 std::advance(it, xCurGrp->mnLength);
2795 pPrev->SetCellGroup(xCurGrp);
2796 xCurGrp->mpTopCell = pPrev;
2797 ++xCurGrp->mnLength;
2798 xPrevGrp = xCurGrp;
2800 else
2802 // Both previous and current cells are regular cells.
2803 assert(pPrev->aPos.Row() == (SCROW)(nRow - 1));
2804 xPrevGrp = pPrev->CreateCellGroup(2, eCompState == ScFormulaCell::EqualInvariant);
2805 pCur->SetCellGroup(xPrevGrp);
2806 ++nRow;
2807 ++it;
2810 pCur = pPrev;
2811 xCurGrp = xPrevGrp;
2818 void ScColumn::RegroupFormulaCells()
2820 // re-build formula groups.
2821 std::for_each(maCells.begin(), maCells.end(), GroupFormulaCells());
2824 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */