1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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"
32 #include "docoptio.hxx"
33 #include "subtotal.hxx"
34 #include "markdata.hxx"
35 #include "detfunc.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"
65 using ::com::sun::star::i18n::LocaleDataItem
;
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
)
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
)
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())
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
);
125 CellStorageModified();
128 void ScColumn::FreeAll()
130 // Keep a logical empty range of 0-MAXROW at all times.
132 maCells
.resize(MAXROWCOUNT
);
133 maCellTextAttrs
.clear();
134 maCellTextAttrs
.resize(MAXROWCOUNT
);
136 maCellNotes
.resize(MAXROWCOUNT
);
137 CellStorageModified();
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
149 std::vector
<SCROW
> maRows
;
150 std::vector
<ScFormulaCell
*> maFormulaCells
;
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.
166 for (size_t i
= 0; i
< nDataSize
; ++i
)
167 // Tag all non-empty cells.
168 maRows
.push_back(i
+ nTopRow
);
173 mrDoc
.EndListeningFormulaCells(maFormulaCells
);
176 const std::vector
<SCROW
>& getNonEmptyRows() const
182 class ShiftFormulaPosHandler
186 void operator() (size_t nRow
, ScFormulaCell
* pCell
)
188 pCell
->aPos
.SetRow(nRow
);
192 class RangeBroadcaster
197 RangeBroadcaster(ScDocument
& rDoc
, SCTAB nTab
, SCCOL nCol
) :
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
;
233 if (itTest
== maCells
.end())
235 // No cells are affected by this deletion. Bail out.
236 CellStorageModified(); // broadcast array has been modified.
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);
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
;
250 if (itTest
!= maCells
.end())
251 // Non-empty block follows -> cells that will get shifted.
257 sc::SingleColumnSpanSet aNonEmptySpans
;
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();
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();
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
;
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
);
346 class DetachFormulaCellsHandler
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())
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
);
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
)
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())
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())
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.
439 // Script type not yet determined. Determine the real script
440 // type, and store it.
441 const ScPatternAttr
* pPattern
= GetPattern(nRow
);
445 sc::CellStoreType::position_type pos
= maCells
.position(itr
, nRow
);
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
);
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();
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
);
475 class DeleteAreaHandler
478 std::vector
<ScFormulaCell
*> maFormulaCells
;
479 sc::SingleColumnSpanSet maDeleteRanges
;
486 DeleteAreaHandler(ScDocument
& rDoc
, sal_uInt16 nDelFlag
) :
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
)
496 case sc::element_type_numeric
:
500 case sc::element_type_string
:
501 case sc::element_type_edittext
:
505 case sc::element_type_formula
:
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
);
519 case sc::element_type_empty
:
524 // Tag these cells for deletion.
525 SCROW nRow1
= node
.position
+ nOffset
;
526 SCROW nRow2
= nRow1
+ nDataSize
- 1;
527 maDeleteRanges
.set(nRow1
, nRow2
, true);
532 mrDoc
.EndListeningFormulaCells(maFormulaCells
);
535 const sc::SingleColumnSpanSet
& getSpans() const
537 return maDeleteRanges
;
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
);
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();
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();
654 class CopyAttrArrayByRange
: std::unary_function
<sc::SingleColumnSpanSet::Span
, void>
656 ScAttrArray
& mrDestAttrArray
;
657 ScAttrArray
& mrSrcAttrArray
;
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
;
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);
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
);
712 CopyCellsFromClipHandler(sc::CopyFromClipContext
& rCxt
, ScColumn
& rSrcCol
, ScColumn
& rDestCol
, SCTAB nDestTab
, SCCOL nDestCol
, long nRowOffset
) :
718 mnSrcTab(rSrcCol
.GetTab()),
719 mnSrcCol(rSrcCol
.GetCol()),
720 mnRowOffset(nRowOffset
),
721 mpDestBlockPos(mrCxt
.getBlockPosition(nDestTab
, nDestCol
))
724 maDestBlockPos
= *mpDestBlockPos
;
726 mrDestCol
.InitBlockPosition(maDestBlockPos
);
729 ~CopyCellsFromClipHandler()
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
)
748 bool bCloneCaption
= (nFlags
& IDF_NOCAPTIONS
) == 0;
749 duplicateNotes(nSrcRow1
, nDataSize
, bCloneCaption
);
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();
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
;
778 insertRefCell(nSrcRow
, nSrcRow
+ mnRowOffset
);
780 mrDestCol
.SetValue(maDestBlockPos
, nSrcRow
+ mnRowOffset
, *it
);
784 case sc::element_type_string
:
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
)
796 insertRefCell(nSrcRow
, nSrcRow
+ mnRowOffset
);
798 mrDestCol
.SetRawString(maDestBlockPos
, nSrcRow
+ mnRowOffset
, *it
);
802 case sc::element_type_edittext
:
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
)
815 insertRefCell(nSrcRow
, nSrcRow
+ mnRowOffset
);
817 mrDestCol
.SetEditText(maDestBlockPos
, nSrcRow
+ mnRowOffset
, **it
);
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;
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
)
848 insertRefCell(nSrcRow
, nSrcRow
+ mnRowOffset
);
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();
864 // error codes are cloned with values
868 insertRefCell(nSrcRow
, nSrcRow
+ mnRowOffset
);
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
;
885 insertRefCell(nSrcRow
, nSrcRow
+ mnRowOffset
);
887 mrDestCol
.SetValue(maDestBlockPos
, nSrcRow
+ mnRowOffset
, rSrcCell
.GetValue());
891 svl::SharedString aStr
= rSrcCell
.GetString();
893 // do not clone empty string
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());
906 mrDestCol
.SetRawString(maDestBlockPos
, nSrcRow
+ mnRowOffset
, aStr
);
917 bool bCloneCaption
= (nFlags
& IDF_NOCAPTIONS
) == 0;
918 duplicateNotes(nSrcRow1
, nDataSize
, bCloneCaption
);
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
);
941 aSpans
.begin(), aSpans
.end(), CopyAttrArrayByRange(*rColumn
.pAttrArray
, *pAttrArray
, nDy
));
944 rColumn
.pAttrArray
->CopyAreaSafe( nRow1
, nRow2
, nDy
, *pAttrArray
);
946 if ((rCxt
.getInsertFlag() & IDF_CONTENTS
) == 0)
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
);
970 aArr
.AddSingleReference( aRef
);
971 SetFormulaCell(nDestRow
, new ScFormulaCell(pDocument
, aDestPos
, aArr
));
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
)
990 if (rMark
.IsMultiMarked())
992 ScMarkArrayIter
aIter( rMark
.GetArray()+nCol
);
993 while (aIter
.Next( nRow1
, nRow2
))
994 MixData(rCxt
, nRow1
, nRow2
, nFunction
, bSkipEmpty
, rSrcCol
);
1001 bool lcl_DoFunction( double& rVal1
, double nVal2
, sal_uInt16 nFunction
)
1007 bOk
= SubTotal::SafePlus( rVal1
, nVal2
);
1010 nVal2
= -nVal2
; // FIXME: Can we do this alwyas without error?
1011 bOk
= SubTotal::SafePlus( rVal1
, nVal2
);
1014 bOk
= SubTotal::SafeMult( rVal1
, nVal2
);
1017 bOk
= SubTotal::SafeDiv( rVal1
, nVal2
);
1023 void lcl_AddCode( ScTokenArray
& rArr
, const ScFormulaCell
* pCell
)
1025 rArr
.AddOpCode(ocOpen
);
1027 ScTokenArray
* pCode
= const_cast<ScFormulaCell
*>(pCell
)->GetCode();
1030 const formula::FormulaToken
* pToken
= pCode
->First();
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
;
1050 sal_uInt16 mnFunction
;
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()),
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
);
1082 miNewCellsPos
= maNewCells
.set(miNewCellsPos
, nRow
-mnRowOffset
, f
);
1085 ScFormulaCell
* pFC
=
1087 &mrDestColumn
.GetDoc(), ScAddress(mrDestColumn
.GetCol(), nRow
, mrDestColumn
.GetTab()));
1089 pFC
->SetErrCode(errNoValue
);
1090 miNewCellsPos
= maNewCells
.set(miNewCellsPos
, nRow
-mnRowOffset
, pFC
);
1094 case sc::element_type_formula
:
1096 // Combination of value and at least one formula -> Create formula
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
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
,
1120 &mrDestColumn
.GetDoc(), ScAddress(mrDestColumn
.GetCol(), nRow
, mrDestColumn
.GetTab()), aArr
));
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
);
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.
1158 lcl_AddCode(aArr
, p
);
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
1172 aArr
.AddDouble(sc::numeric_block::at(*aPos
.first
->data
, aPos
.second
));
1174 miNewCellsPos
= maNewCells
.set(
1175 miNewCellsPos
, nRow
-mnRowOffset
,
1177 &mrDestColumn
.GetDoc(), ScAddress(mrDestColumn
.GetCol(), nRow
, mrDestColumn
.GetTab()), aArr
));
1180 case sc::element_type_formula
:
1182 // Both are formulas.
1186 lcl_AddCode(aArr
, p
);
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
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
,
1206 &mrDestColumn
.GetDoc(), ScAddress(mrDestColumn
.GetCol(), nRow
, mrDestColumn
.GetTab()), aArr
));
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
));
1225 * Empty cell series in the source (clip) document.
1227 void operator() (mdds::mtv::element_t
, size_t nTopRow
, size_t nDataSize
)
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
);
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
);
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());
1261 case sc::element_type_formula
:
1266 ScFormulaCell
* pSrc
= sc::formula_block::at(*aPos
.first
->data
, aPos
.second
);
1267 lcl_AddCode( aArr
, pSrc
);
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
,
1285 &mrDestColumn
.GetDoc(), ScAddress(mrDestColumn
.GetCol(), nDestRow
, mrDestColumn
.GetTab()), aArr
));
1295 * Set the new cells to the destination (this) column.
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
;
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
);
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
);
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
);
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
);
1362 case sc::element_type_empty
:
1364 itDestPos
= rDestCells
.set_empty(itDestPos
, nDestRow
, nDestRow
+it
->size
-1);
1365 bHasContent
= false;
1372 sc::CellTextAttrStoreType
& rDestAttrs
= mrDestColumn
.GetCellAttrStore();
1375 std::vector
<sc::CellTextAttr
> aAttrs(it
->size
, sc::CellTextAttr());
1376 itDestAttrPos
= rDestAttrs
.set(itDestAttrPos
, nDestRow
, aAttrs
.begin(), aAttrs
.end());
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
);
1398 MixDataHandler
aFunc(*p
, *this, nRow1
, nRow2
, nFunction
, bSkipEmpty
);
1399 sc::ParseAll(rSrcCol
.maCells
.begin(), rSrcCol
.maCells
, nRow1
, nRow2
, aFunc
, aFunc
);
1402 CellStorageModified();
1406 ScAttrIterator
* ScColumn::CreateAttrIterator( SCROW nStartRow
, SCROW nEndRow
) const
1408 return new ScAttrIterator( pAttrArray
, nStartRow
, nEndRow
);
1413 class StartAllListenersHandler
1417 StartAllListenersHandler(ScDocument
* pDoc
) : mpDoc(pDoc
) {}
1419 void operator() (size_t, ScFormulaCell
* p
)
1421 p
->StartListeningTo(mpDoc
);
1425 class StartNeededListenerHandler
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
);
1455 class StartListeningInAreaHandler
1457 sc::StartListeningContext
& mrCxt
;
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())
1483 bool bNumFmtSet
= false;
1485 ScSetStringParam aParam
;
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];
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
));
1514 pDocument
, ScAddress(nCol
, nRow
, nTabP
), rString
,
1515 formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_DEFAULT
, eConv
),
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);
1527 bNumeric
= aParam
.mpNumFormatter
->IsNumberFormat(aTest
, nIndex
, fTest
);
1529 // This is a number. Strip out the first char.
1530 rCell
.set(rPool
.intern(aTest
));
1533 // This is normal text. Take it as-is.
1534 rCell
.set(rPool
.intern(rString
));
1542 if (aParam
.mbDetectNumberFormat
)
1544 if (!aParam
.mpNumFormatter
->IsNumberFormat(rString
, nIndex
, nVal
))
1547 // convert back to the original language if a built-in format was detected
1548 const SvNumberformat
* pOldFormat
= aParam
.mpNumFormatter
->GetEntry( nOldIndex
);
1550 nIndex
= aParam
.mpNumFormatter
->GetFormatForLanguageIfBuiltIn( nIndex
, pOldFormat
->GetLanguage() );
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;
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
1580 ApplyAttr( nRow
, SfxUInt32Item( ATTR_VALUE_FORMAT
,
1581 (sal_uInt32
) nIndex
) );
1586 else if (aParam
.meSetTextNumFormat
!= ScSetStringParam::Always
)
1588 // Only check if the string is a regular number.
1589 const LocaleDataWrapper
* pLocale
= aParam
.mpNumFormatter
->GetLocaleData();
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)
1599 sal_Unicode dsep
= rDecSep
[0];
1600 sal_Unicode gsep
= rGroupSep
[0];
1602 if (!ScStringUtil::parseSimpleNumber(rString
, dsep
, gsep
, nVal
))
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
));
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
))
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
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());
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());
1690 void ScColumn::SetEditText( SCROW nRow
, const EditTextObject
& rEditText
, const SfxItemPool
* pEditPool
)
1692 if (pEditPool
&& pDocument
->GetEditPool() == pEditPool
)
1694 SetEditText(nRow
, rEditText
.Clone());
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());
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
);
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
);
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();
1793 return svl::SharedString();
1798 class FilterEntriesHandler
1801 std::vector
<ScTypedStrData
>& mrStrings
;
1804 void processCell(SCROW nRow
, ScRefCellValue
& rCell
)
1806 SvNumberFormatter
* pFormatter
= mrColumn
.GetDoc().GetFormatTable();
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
));
1819 switch (rCell
.meType
)
1821 case CELLTYPE_VALUE
:
1822 fVal
= rCell
.mfValue
;
1825 case CELLTYPE_FORMULA
:
1827 ScFormulaCell
* pFC
= rCell
.mpFormula
;
1828 sal_uInt16 nErr
= pFC
->GetErrCode();
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
));
1840 fVal
= pFC
->GetValue();
1847 short nType
= pFormatter
->GetType(nFormat
);
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
);
1857 // maybe extend ScTypedStrData enum is also an option here
1858 mrStrings
.push_back(ScTypedStrData(aStr
, fVal
, ScTypedStrData::Value
,bDate
));
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();
1904 * Iterate over only string and edit-text cells.
1906 class StrCellIterator
1908 typedef std::pair
<sc::CellStoreType::const_iterator
,size_t> PosType
;
1910 sc::CellStoreType::const_iterator miBeg
;
1911 sc::CellStoreType::const_iterator miEnd
;
1912 const ScDocument
* mpDoc
;
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
);
1920 // Make this iterator invalid.
1921 maPos
.first
= miEnd
;
1924 bool valid() const { return (maPos
.first
!= miEnd
); }
1928 return (maPos
.first
->type
== sc::element_type_string
|| maPos
.first
->type
== sc::element_type_edittext
);
1935 // Not in a string block. Move back until we hit a string block.
1938 if (maPos
.first
== miBeg
)
1941 --maPos
.first
; // move to the preceding block.
1942 maPos
.second
= maPos
.first
->size
- 1; // last cell in the block.
1947 // We are in a string block.
1948 if (maPos
.second
> 0)
1950 // Move back one cell in the same block.
1955 // Move back to the preceding string block.
1958 if (maPos
.first
== miBeg
)
1961 // Move to the last cell of the previous block.
1963 maPos
.second
= maPos
.first
->size
- 1;
1975 // Not in a string block. Move forward until we hit a string block.
1979 if (maPos
.first
== miEnd
)
1982 maPos
.second
= 0; // First cell in this block.
1987 // We are in a string block.
1989 if (maPos
.second
>= maPos
.first
->size
)
1991 // Move to the next string block.
1995 if (maPos
.first
== miEnd
)
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
);
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();
2047 // Current cell is invalid.
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
)
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
2073 if (bLimit
&& ++nCellsSearched
>= DATENT_SEARCH
)
2074 return bFound
; // max search cell count reached.
2076 bMoveUp
= aItrUp
.prev();
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
2091 if (bLimit
&& ++nCellsSearched
>= DATENT_SEARCH
)
2092 return bFound
; // max search cell count reached.
2094 bMoveDown
= aItrDown
.next();
2103 class FormulaToValueHandler
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
;
2119 void operator() (size_t nRow
, const ScFormulaCell
* p
)
2121 ScFormulaCell
* p2
= const_cast<ScFormulaCell
*>(p
);
2123 maEntries
.push_back(Entry(nRow
, p2
->GetValue()));
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
)
2137 switch (r
.maValue
.meType
)
2139 case CELLTYPE_VALUE
:
2140 rColumn
.SetValue(aBlockPos
, r
.mnRow
, r
.maValue
.mfValue
, false);
2142 case CELLTYPE_STRING
:
2143 rColumn
.SetRawString(aBlockPos
, r
.mnRow
, *r
.maValue
.mpString
, false);
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
);
2161 const ScPatternAttr
* pPattern
= aAttrIter
.Next( nTop
, nBottom
);
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
))
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
))
2202 svl::SharedString aSS
= pDocument
->GetSharedStringPool().intern(rStr
);
2206 SetRawString(nRow
, aSS
, bBroadcast
);
2209 void ScColumn::SetRawString( SCROW nRow
, const svl::SharedString
& rStr
, bool bBroadcast
)
2211 if (!ValidRow(nRow
))
2214 sc::CellStoreType::iterator it
= GetPositionToInsert(nRow
);
2215 maCells
.set(it
, nRow
, rStr
);
2216 maCellTextAttrs
.set(nRow
, sc::CellTextAttr());
2218 CellStorageModified();
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
);
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
))
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();
2248 BroadcastNewCell(nRow
);
2251 void ScColumn::SetValue( SCROW nRow
, double fVal
)
2253 if (!ValidRow(nRow
))
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
))
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();
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())
2302 if (it
->type
!= sc::element_type_numeric
)
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
;
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;
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())
2343 if (it
->type
!= sc::element_type_edittext
)
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())
2356 if (it
->type
!= sc::element_type_edittext
)
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
);
2367 p
->GetFormula(rFormula
);
2369 rFormula
= EMPTY_OUSTRING
;
2372 const ScTokenArray
* ScColumn::GetFormulaTokens( SCROW nRow
) const
2374 const ScFormulaCell
* pCell
= FetchFormulaCell(nRow
);
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
;
2406 return CELLTYPE_NONE
;
2412 * Count the number of all non-empty cells.
2418 CellCounter() : mnCount(0) {}
2420 void operator() (const sc::CellStoreType::value_type
& node
)
2422 if (node
.type
== sc::element_type_empty
)
2425 mnCount
+= node
.size
;
2428 size_t getCount() const { return mnCount
; }
2433 SCSIZE
ScColumn::GetCellCount() const
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())
2447 if (it
->type
!= sc::element_type_formula
)
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
:
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();
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
:
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();
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
)
2509 nRow
+= it
->size
- nOffset
;
2518 class MaxStringLenHandler
2521 const ScColumn
& mrColumn
;
2522 SvNumberFormatter
* mpFormatter
;
2523 rtl_TextEncoding meCharSet
;
2524 bool mbOctetEncoding
;
2526 void processCell(size_t nRow
, ScRefCellValue
& rCell
)
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());
2533 if (mbOctetEncoding
)
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
2545 nLen
= aOString
.getLength();
2548 nLen
= aString
.getLength() * sizeof(sal_Unicode
);
2550 if (mnMaxLen
< nLen
)
2555 MaxStringLenHandler(const ScColumn
& rColumn
, rtl_TextEncoding eCharSet
) :
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();
2602 class MaxNumStringLenHandler
2604 const ScColumn
& mrColumn
;
2605 SvNumberFormatter
* mpFormatter
;
2607 sal_uInt16 mnPrecision
;
2609 void processCell(size_t nRow
, ScRefCellValue
& rCell
)
2611 if (rCell
.meType
== CELLTYPE_FORMULA
&& !rCell
.mpFormula
->IsValue())
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();
2620 // Ignore empty string.
2625 const SvNumberformat
* pEntry
= mpFormatter
->GetEntry(nFormat
);
2629 bool bThousand
, bNegRed
;
2630 sal_uInt16 nLeading
;
2631 pEntry
->GetFormatSpecialInfo(bThousand
, bNegRed
, nPrec
, nLeading
);
2634 nPrec
= mpFormatter
->GetFormatPrecision(nFormat
);
2636 if (nPrec
!= SvNumberFormatter::UNLIMITED_PRECISION
&& nPrec
> mnPrecision
)
2637 mnPrecision
= nPrec
;
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
);
2646 nLen
+= mnPrecision
+ aSep
.getLength();
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
)
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.
2695 MaxNumStringLenHandler
aFunc(*this, nPrecision
);
2696 sc::ParseFormulaNumeric(maCells
.begin(), maCells
, nRowStart
, nRowEnd
, aFunc
);
2697 nPrecision
= aFunc
.getPrecision();
2698 return aFunc
.getMaxLen();
2703 class GroupFormulaCells
2705 ScFormulaCellGroupRef mxNone
;
2709 void operator() (sc::CellStoreType::value_type
& node
)
2711 if (node
.type
!= sc::element_type_formula
)
2712 // We are only interested in formula cells.
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();
2726 // Move to the cell after the last cell of the current group.
2727 std::advance(it
, xPrevGrp
->mnLength
);
2728 nRow
+= xPrevGrp
->mnLength
;
2736 ScFormulaCell
* pCur
= NULL
;
2737 ScFormulaCellGroupRef xCurGrp
;
2738 for (; it
!= itEnd
; pPrev
= pCur
, xPrevGrp
= xCurGrp
)
2741 xCurGrp
= pCur
->GetCellGroup();
2743 ScFormulaCell::CompareState eCompState
= pPrev
->CompareByTokenArray(*pCur
);
2744 if (eCompState
== ScFormulaCell::NotEqual
)
2746 // different formula tokens.
2749 // Move to the cell after the last cell of the current group.
2750 std::advance(it
, xCurGrp
->mnLength
);
2751 nRow
+= xCurGrp
->mnLength
;
2762 // Formula tokens equal those of the previous formula cell or cell group.
2765 // Previous cell is a group.
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
;
2782 // Add this cell to the previous group.
2783 pCur
->SetCellGroup(xPrevGrp
);
2784 ++xPrevGrp
->mnLength
;
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
;
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
);
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: */