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