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/.
11 #include <clipparam.hxx>
12 #include <cellvalue.hxx>
13 #include <attarray.hxx>
14 #include <document.hxx>
15 #include <cellvalues.hxx>
16 #include <columnspanset.hxx>
17 #include <listenercontext.hxx>
18 #include <tokenstringcontext.hxx>
19 #include <mtvcellfunc.hxx>
20 #include <clipcontext.hxx>
22 #include <patattr.hxx>
23 #include <docpool.hxx>
24 #include <conditio.hxx>
25 #include <formulagroup.hxx>
26 #include <tokenarray.hxx>
27 #include <globalnames.hxx>
28 #include <scitems.hxx>
29 #include <cellform.hxx>
30 #include <sharedformula.hxx>
32 #include <svl/sharedstringpool.hxx>
37 #include <boost/shared_ptr.hpp>
39 bool ScColumn::IsMerged( SCROW nRow
) const
41 return pAttrArray
->IsMerged(nRow
);
44 void ScColumn::DeleteBeforeCopyFromClip(
45 sc::CopyFromClipContext
& rCxt
, const ScColumn
& rClipCol
, sc::ColumnSpanSet
& rBroadcastSpans
)
47 sc::CopyFromClipContext::Range aRange
= rCxt
.getDestRange();
48 if (!ValidRow(aRange
.mnRow1
) || !ValidRow(aRange
.mnRow2
))
51 ScRange aClipRange
= rCxt
.getClipDoc()->GetClipParam().getWholeRange();
52 SCROW nClipRow1
= aClipRange
.aStart
.Row();
53 SCROW nClipRow2
= aClipRange
.aEnd
.Row();
54 SCROW nClipRowLen
= nClipRow2
- nClipRow1
+ 1;
56 // Check for non-empty cell ranges in the clip column.
57 sc::SingleColumnSpanSet aSpanSet
;
58 aSpanSet
.scan(rClipCol
, nClipRow1
, nClipRow2
);
59 sc::SingleColumnSpanSet::SpansType aSpans
;
60 aSpanSet
.getSpans(aSpans
);
63 // All cells in the range in the clip are empty. Nothing to delete.
66 // Translate the clip column spans into the destination column, and repeat as needed.
67 std::vector
<sc::RowSpan
> aDestSpans
;
68 SCROW nDestOffset
= aRange
.mnRow1
- nClipRow1
;
69 bool bContinue
= true;
72 sc::SingleColumnSpanSet::SpansType::const_iterator it
= aSpans
.begin(), itEnd
= aSpans
.end();
73 for (; it
!= itEnd
&& bContinue
; ++it
)
75 const sc::RowSpan
& r
= *it
;
76 SCROW nDestRow1
= r
.mnRow1
+ nDestOffset
;
77 SCROW nDestRow2
= r
.mnRow2
+ nDestOffset
;
79 if (nDestRow1
> aRange
.mnRow2
)
86 if (nDestRow2
> aRange
.mnRow2
)
88 // Truncate this range, and set it as the last span.
89 nDestRow2
= aRange
.mnRow2
;
93 aDestSpans
.push_back(sc::RowSpan(nDestRow1
, nDestRow2
));
96 nDestOffset
+= nClipRowLen
;
99 InsertDeleteFlags nDelFlag
= rCxt
.getDeleteFlag();
100 sc::ColumnBlockPosition aBlockPos
;
101 InitBlockPosition(aBlockPos
);
103 std::vector
<sc::RowSpan
>::const_iterator it
= aDestSpans
.begin(), itEnd
= aDestSpans
.end();
104 for (; it
!= itEnd
; ++it
)
106 SCROW nRow1
= it
->mnRow1
;
107 SCROW nRow2
= it
->mnRow2
;
109 if (nDelFlag
& IDF_CONTENTS
)
111 sc::SingleColumnSpanSet aDeletedRows
;
112 DeleteCells(aBlockPos
, nRow1
, nRow2
, nDelFlag
, aDeletedRows
);
113 rBroadcastSpans
.set(nTab
, nCol
, aDeletedRows
, true);
116 if (nDelFlag
& IDF_NOTE
)
117 DeleteCellNotes(aBlockPos
, nRow1
, nRow2
, false);
119 if (nDelFlag
& IDF_EDITATTR
)
120 RemoveEditAttribs(nRow1
, nRow2
);
122 // Delete attributes just now
123 if (nDelFlag
& IDF_ATTRIB
)
125 pAttrArray
->DeleteArea(nRow1
, nRow2
);
127 if (rCxt
.isTableProtected())
129 ScPatternAttr
aPattern(pDocument
->GetPool());
130 aPattern
.GetItemSet().Put(ScProtectionAttr(false));
131 ApplyPatternArea(nRow1
, nRow2
, aPattern
);
134 ScConditionalFormatList
* pCondList
= rCxt
.getCondFormatList();
136 pCondList
->DeleteArea(nCol
, nRow1
, nCol
, nRow2
);
138 else if ((nDelFlag
& IDF_HARDATTR
) == IDF_HARDATTR
)
139 pAttrArray
->DeleteHardAttr(nRow1
, nRow2
);
143 void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext
& rCxt
, SCROW nRow1
, SCROW nRow2
, size_t nColOffset
)
145 assert(nRow1
<= nRow2
);
147 size_t nDestSize
= nRow2
- nRow1
+ 1;
148 sc::ColumnBlockPosition
* pBlockPos
= rCxt
.getBlockPosition(nTab
, nCol
);
152 bool bSameDocPool
= (rCxt
.getClipDoc()->GetPool() == pDocument
->GetPool());
154 ScCellValue
& rSrcCell
= rCxt
.getSingleCell(nColOffset
);
155 sc::CellTextAttr
& rSrcAttr
= rCxt
.getSingleCellAttr(nColOffset
);
157 InsertDeleteFlags nFlags
= rCxt
.getInsertFlag();
159 if ((nFlags
& IDF_ATTRIB
) != IDF_NONE
)
161 if (!rCxt
.isSkipAttrForEmptyCells() || rSrcCell
.meType
!= CELLTYPE_NONE
)
163 const ScPatternAttr
* pAttr
= (bSameDocPool
? rCxt
.getSingleCellPattern(nColOffset
) :
164 rCxt
.getSingleCellPattern(nColOffset
)->PutInPool( pDocument
, rCxt
.getClipDoc()));
165 pAttrArray
->SetPatternArea(nRow1
, nRow2
, pAttr
, true);
169 if ((nFlags
& IDF_CONTENTS
) != IDF_NONE
)
171 std::vector
<sc::CellTextAttr
> aTextAttrs(nDestSize
, rSrcAttr
);
173 switch (rSrcCell
.meType
)
177 std::vector
<double> aVals(nDestSize
, rSrcCell
.mfValue
);
178 pBlockPos
->miCellPos
=
179 maCells
.set(pBlockPos
->miCellPos
, nRow1
, aVals
.begin(), aVals
.end());
180 pBlockPos
->miCellTextAttrPos
=
181 maCellTextAttrs
.set(pBlockPos
->miCellTextAttrPos
, nRow1
, aTextAttrs
.begin(), aTextAttrs
.end());
182 CellStorageModified();
185 case CELLTYPE_STRING
:
187 // Compare the ScDocumentPool* to determine if we are copying within the
188 // same document. If not, re-intern shared strings.
189 svl::SharedStringPool
* pSharedStringPool
= (bSameDocPool
? NULL
: &pDocument
->GetSharedStringPool());
190 svl::SharedString aStr
= (pSharedStringPool
?
191 pSharedStringPool
->intern( rSrcCell
.mpString
->getString()) :
194 std::vector
<svl::SharedString
> aStrs(nDestSize
, aStr
);
195 pBlockPos
->miCellPos
=
196 maCells
.set(pBlockPos
->miCellPos
, nRow1
, aStrs
.begin(), aStrs
.end());
197 pBlockPos
->miCellTextAttrPos
=
198 maCellTextAttrs
.set(pBlockPos
->miCellTextAttrPos
, nRow1
, aTextAttrs
.begin(), aTextAttrs
.end());
199 CellStorageModified();
204 std::vector
<EditTextObject
*> aStrs
;
205 aStrs
.reserve(nDestSize
);
206 for (size_t i
= 0; i
< nDestSize
; ++i
)
207 aStrs
.push_back(rSrcCell
.mpEditText
->Clone());
209 pBlockPos
->miCellPos
=
210 maCells
.set(pBlockPos
->miCellPos
, nRow1
, aStrs
.begin(), aStrs
.end());
211 pBlockPos
->miCellTextAttrPos
=
212 maCellTextAttrs
.set(pBlockPos
->miCellTextAttrPos
, nRow1
, aTextAttrs
.begin(), aTextAttrs
.end());
213 CellStorageModified();
216 case CELLTYPE_FORMULA
:
218 std::vector
<sc::RowSpan
> aRanges
;
220 aRanges
.push_back(sc::RowSpan(nRow1
, nRow2
));
221 CloneFormulaCell(*rSrcCell
.mpFormula
, rSrcAttr
, aRanges
, NULL
);
229 const ScPostIt
* pNote
= rCxt
.getSingleCellNote(nColOffset
);
230 if (pNote
&& (nFlags
& (IDF_NOTE
| IDF_ADDNOTES
)) != IDF_NONE
)
232 // Duplicate the cell note over the whole pasted range.
234 ScDocument
* pClipDoc
= rCxt
.getClipDoc();
235 const ScAddress
& rSrcPos
= pClipDoc
->GetClipParam().getWholeRange().aStart
;
236 std::vector
<ScPostIt
*> aNotes
;
237 ScAddress
aDestPos(nCol
, nRow1
, nTab
);
238 aNotes
.reserve(nDestSize
);
239 for (size_t i
= 0; i
< nDestSize
; ++i
)
241 bool bCloneCaption
= (nFlags
& IDF_NOCAPTIONS
) == IDF_NONE
;
242 aNotes
.push_back(pNote
->Clone(rSrcPos
, *pDocument
, aDestPos
, bCloneCaption
));
246 pBlockPos
->miCellNotePos
=
248 pBlockPos
->miCellNotePos
, nRow1
, aNotes
.begin(), aNotes
.end());
252 void ScColumn::SetValues( SCROW nRow
, const std::vector
<double>& rVals
)
257 SCROW nLastRow
= nRow
+ rVals
.size() - 1;
258 if (nLastRow
> MAXROW
)
259 // Out of bound. Do nothing.
262 sc::CellStoreType::position_type aPos
= maCells
.position(nRow
);
263 DetachFormulaCells(aPos
, rVals
.size());
265 maCells
.set(nRow
, rVals
.begin(), rVals
.end());
266 std::vector
<sc::CellTextAttr
> aDefaults(rVals
.size());
267 maCellTextAttrs
.set(nRow
, aDefaults
.begin(), aDefaults
.end());
269 CellStorageModified();
271 std::vector
<SCROW
> aRows
;
272 aRows
.reserve(rVals
.size());
273 for (SCROW i
= nRow
; i
<= nLastRow
; ++i
)
276 BroadcastCells(aRows
, SC_HINT_DATACHANGED
);
279 void ScColumn::TransferCellValuesTo( SCROW nRow
, size_t nLen
, sc::CellValues
& rDest
)
284 SCROW nLastRow
= nRow
+ nLen
- 1;
285 if (nLastRow
> MAXROW
)
286 // Out of bound. Do nothing.
289 sc::CellStoreType::position_type aPos
= maCells
.position(nRow
);
290 DetachFormulaCells(aPos
, nLen
);
292 rDest
.transferFrom(*this, nRow
, nLen
);
294 CellStorageModified();
296 std::vector
<SCROW
> aRows
;
298 for (SCROW i
= nRow
; i
<= nLastRow
; ++i
)
301 BroadcastCells(aRows
, SC_HINT_DATACHANGED
);
304 void ScColumn::CopyCellValuesFrom( SCROW nRow
, const sc::CellValues
& rSrc
)
309 SCROW nLastRow
= nRow
+ rSrc
.size() - 1;
310 if (nLastRow
> MAXROW
)
311 // Out of bound. Do nothing
314 sc::CellStoreType::position_type aPos
= maCells
.position(nRow
);
315 DetachFormulaCells(aPos
, rSrc
.size());
317 rSrc
.copyTo(*this, nRow
);
319 CellStorageModified();
321 std::vector
<SCROW
> aRows
;
322 aRows
.reserve(rSrc
.size());
323 for (SCROW i
= nRow
; i
<= nLastRow
; ++i
)
326 BroadcastCells(aRows
, SC_HINT_DATACHANGED
);
331 class ConvertFormulaToValueHandler
333 sc::CellValues maResValues
;
337 ConvertFormulaToValueHandler( SCTAB
, SCCOL
) :
340 maResValues
.reset(MAXROWCOUNT
);
343 void operator() ( size_t nRow
, const ScFormulaCell
* pCell
)
345 sc::FormulaResultValue aRes
= pCell
->GetResult();
348 case sc::FormulaResultValue::Value
:
349 maResValues
.setValue(nRow
, aRes
.mfValue
);
351 case sc::FormulaResultValue::String
:
352 maResValues
.setValue(nRow
, aRes
.maString
);
354 case sc::FormulaResultValue::Error
:
355 case sc::FormulaResultValue::Invalid
:
357 maResValues
.setValue(nRow
, svl::SharedString::getEmptyString());
363 bool isModified() const { return mbModified
; }
365 sc::CellValues
& getResValues() { return maResValues
; }
370 void ScColumn::ConvertFormulaToValue(
371 sc::EndListeningContext
& rCxt
, SCROW nRow1
, SCROW nRow2
, sc::TableValues
* pUndo
)
373 if (!ValidRow(nRow1
) || !ValidRow(nRow2
) || nRow1
> nRow2
)
376 std::vector
<SCROW
> aBounds
;
377 aBounds
.push_back(nRow1
);
378 if (nRow2
< MAXROW
-1)
379 aBounds
.push_back(nRow2
+1);
381 // Split formula cell groups at top and bottom boundaries (if applicable).
382 sc::SharedFormulaUtil::splitFormulaCellGroups(maCells
, aBounds
);
384 // Parse all formulas within the range and store their results into temporary storage.
385 ConvertFormulaToValueHandler
aFunc(nTab
, nCol
);
386 sc::ParseFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aFunc
);
387 if (!aFunc
.isModified())
388 // No formula cells encountered.
391 DetachFormulaCells(rCxt
, nRow1
, nRow2
);
393 // Undo storage to hold static values which will get swapped to the cell storage later.
394 sc::CellValues aUndoCells
;
395 aFunc
.getResValues().swap(aUndoCells
);
396 aUndoCells
.swapNonEmpty(*this);
398 pUndo
->swap(nTab
, nCol
, aUndoCells
);
403 class StartListeningHandler
405 sc::StartListeningContext
& mrCxt
;
408 StartListeningHandler( sc::StartListeningContext
& rCxt
) :
411 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
413 pCell
->StartListeningTo(mrCxt
);
417 class EndListeningHandler
419 sc::EndListeningContext
& mrCxt
;
422 EndListeningHandler( sc::EndListeningContext
& rCxt
) :
425 void operator() (size_t /*nRow*/, ScFormulaCell
* pCell
)
427 pCell
->EndListeningTo(mrCxt
);
433 void ScColumn::SwapNonEmpty(
434 sc::TableValues
& rValues
, sc::StartListeningContext
& rStartCxt
, sc::EndListeningContext
& rEndCxt
)
436 const ScRange
& rRange
= rValues
.getRange();
437 std::vector
<SCROW
> aBounds
;
438 aBounds
.push_back(rRange
.aStart
.Row());
439 if (rRange
.aEnd
.Row() < MAXROW
-1)
440 aBounds
.push_back(rRange
.aEnd
.Row()+1);
442 // Split formula cell groups at top and bottom boundaries (if applicable).
443 sc::SharedFormulaUtil::splitFormulaCellGroups(maCells
, aBounds
);
444 std::vector
<sc::CellValueSpan
> aSpans
= rValues
.getNonEmptySpans(nTab
, nCol
);
446 // Detach formula cells within the spans (if any).
447 EndListeningHandler
aEndLisFunc(rEndCxt
);
448 std::vector
<sc::CellValueSpan
>::const_iterator it
= aSpans
.begin(), itEnd
= aSpans
.end();
449 sc::CellStoreType::iterator itPos
= maCells
.begin();
450 for (; it
!= itEnd
; ++it
)
452 SCROW nRow1
= it
->mnRow1
;
453 SCROW nRow2
= it
->mnRow2
;
454 itPos
= sc::ProcessFormula(itPos
, maCells
, nRow1
, nRow2
, aEndLisFunc
);
457 rValues
.swapNonEmpty(nTab
, nCol
, *this);
458 RegroupFormulaCells();
460 // Attach formula cells within the spans (if any).
461 StartListeningHandler
aStartLisFunc(rStartCxt
);
463 itPos
= maCells
.begin();
464 for (; it
!= itEnd
; ++it
)
466 SCROW nRow1
= it
->mnRow1
;
467 SCROW nRow2
= it
->mnRow2
;
468 itPos
= sc::ProcessFormula(itPos
, maCells
, nRow1
, nRow2
, aStartLisFunc
);
471 CellStorageModified();
474 void ScColumn::DeleteRanges( const std::vector
<sc::RowSpan
>& rRanges
, InsertDeleteFlags nDelFlag
, bool bBroadcast
)
476 std::vector
<sc::RowSpan
>::const_iterator itSpan
= rRanges
.begin(), itSpanEnd
= rRanges
.end();
477 for (; itSpan
!= itSpanEnd
; ++itSpan
)
478 DeleteArea(itSpan
->mnRow1
, itSpan
->mnRow2
, nDelFlag
, bBroadcast
);
481 void ScColumn::CloneFormulaCell(
482 const ScFormulaCell
& rSrc
, const sc::CellTextAttr
& rAttr
,
483 const std::vector
<sc::RowSpan
>& rRanges
, sc::StartListeningContext
* pCxt
)
485 sc::CellStoreType::iterator itPos
= maCells
.begin();
486 sc::CellTextAttrStoreType::iterator itAttrPos
= maCellTextAttrs
.begin();
488 std::vector
<ScFormulaCell
*> aFormulas
;
489 std::vector
<sc::RowSpan
>::const_iterator itSpan
= rRanges
.begin(), itSpanEnd
= rRanges
.end();
490 for (; itSpan
!= itSpanEnd
; ++itSpan
)
492 SCROW nRow1
= itSpan
->mnRow1
, nRow2
= itSpan
->mnRow2
;
493 size_t nLen
= nRow2
- nRow1
+ 1;
496 aFormulas
.reserve(nLen
);
498 ScAddress
aPos(nCol
, nRow1
, nTab
);
502 // Single, ungrouped formula cell.
503 ScFormulaCell
* pCell
= new ScFormulaCell(rSrc
, *pDocument
, aPos
);
506 pCell
->StartListeningTo(*pCxt
);
509 aFormulas
.push_back(pCell
);
513 // Create a group of formula cells.
514 ScFormulaCellGroupRef
xGroup(new ScFormulaCellGroup
);
515 xGroup
->setCode(*rSrc
.GetCode());
516 xGroup
->compileCode(*pDocument
, aPos
, pDocument
->GetGrammar());
517 for (size_t i
= 0; i
< nLen
; ++i
, aPos
.IncRow())
519 ScFormulaCell
* pCell
= new ScFormulaCell(pDocument
, aPos
, xGroup
, pDocument
->GetGrammar(), rSrc
.GetMatrixFlag());
522 xGroup
->mpTopCell
= pCell
;
523 xGroup
->mnLength
= nLen
;
527 pCell
->StartListeningTo(*pCxt
);
530 aFormulas
.push_back(pCell
);
534 itPos
= maCells
.set(itPos
, nRow1
, aFormulas
.begin(), aFormulas
.end());
536 // Join the top and bottom of the pasted formula cells as needed.
537 sc::CellStoreType::position_type aPosObj
= maCells
.position(itPos
, nRow1
);
539 assert(aPosObj
.first
->type
== sc::element_type_formula
);
540 ScFormulaCell
* pCell
= sc::formula_block::at(*aPosObj
.first
->data
, aPosObj
.second
);
541 JoinNewFormulaCell(aPosObj
, *pCell
);
543 aPosObj
= maCells
.position(aPosObj
.first
, nRow2
);
544 assert(aPosObj
.first
->type
== sc::element_type_formula
);
545 pCell
= sc::formula_block::at(*aPosObj
.first
->data
, aPosObj
.second
);
546 JoinNewFormulaCell(aPosObj
, *pCell
);
548 std::vector
<sc::CellTextAttr
> aTextAttrs(nLen
, rAttr
);
549 itAttrPos
= maCellTextAttrs
.set(itAttrPos
, nRow1
, aTextAttrs
.begin(), aTextAttrs
.end());
552 CellStorageModified();
555 ScPostIt
* ScColumn::ReleaseNote( SCROW nRow
)
561 maCellNotes
.release(nRow
, p
);
565 size_t ScColumn::GetNoteCount() const
568 sc::CellNoteStoreType::const_iterator it
= maCellNotes
.begin(), itEnd
= maCellNotes
.end();
569 for (; it
!= itEnd
; ++it
)
571 if (it
->type
!= sc::element_type_cellnote
)
582 class NoteCaptionCreator
586 NoteCaptionCreator( SCTAB nTab
, SCCOL nCol
) : maPos(nCol
,0,nTab
) {}
588 void operator() ( size_t nRow
, ScPostIt
* p
)
591 p
->GetOrCreateCaption(maPos
);
595 struct NoteCaptionCleaner
597 void operator() ( size_t /*nRow*/, ScPostIt
* p
)
605 void ScColumn::CreateAllNoteCaptions()
607 NoteCaptionCreator
aFunc(nTab
, nCol
);
608 sc::ProcessNote(maCellNotes
, aFunc
);
611 void ScColumn::ForgetNoteCaptions( SCROW nRow1
, SCROW nRow2
)
613 if (!ValidRow(nRow1
) || !ValidRow(nRow2
))
616 NoteCaptionCleaner aFunc
;
617 sc::CellNoteStoreType::iterator it
= maCellNotes
.begin();
618 sc::ProcessNote(it
, maCellNotes
, nRow1
, nRow2
, aFunc
);
621 SCROW
ScColumn::GetNotePosition( size_t nIndex
) const
623 // Return the row position of the nth note in the column.
625 sc::CellNoteStoreType::const_iterator it
= maCellNotes
.begin(), itEnd
= maCellNotes
.end();
627 size_t nCount
= 0; // Number of notes encountered so far.
628 for (; it
!= itEnd
; ++it
)
630 if (it
->type
!= sc::element_type_cellnote
)
631 // Skip the empty blocks.
634 if (nIndex
< nCount
+ it
->size
)
636 // Index falls within this block.
637 size_t nOffset
= nIndex
- nCount
;
638 return it
->position
+ nOffset
;
649 class NoteEntryCollector
651 std::vector
<sc::NoteEntry
>& mrNotes
;
657 NoteEntryCollector( std::vector
<sc::NoteEntry
>& rNotes
, SCTAB nTab
, SCCOL nCol
,
658 SCROW nStartRow
= 0, SCROW nEndRow
= MAXROW
) :
659 mrNotes(rNotes
), mnTab(nTab
), mnCol(nCol
),
660 mnStartRow(nStartRow
), mnEndRow(nEndRow
) {}
662 void operator() (const sc::CellNoteStoreType::value_type
& node
) const
664 if (node
.type
!= sc::element_type_cellnote
)
667 size_t nTopRow
= node
.position
;
668 sc::cellnote_block::const_iterator it
= sc::cellnote_block::begin(*node
.data
);
669 sc::cellnote_block::const_iterator itEnd
= sc::cellnote_block::end(*node
.data
);
671 if(nTopRow
< size_t(mnStartRow
))
673 std::advance(it
, mnStartRow
- nTopRow
);
674 nOffset
= mnStartRow
- nTopRow
;
677 for (; it
!= itEnd
&& nTopRow
+ nOffset
<= size_t(mnEndRow
);
680 ScAddress
aPos(mnCol
, nTopRow
+ nOffset
, mnTab
);
681 mrNotes
.push_back(sc::NoteEntry(aPos
, *it
));
688 void ScColumn::GetAllNoteEntries( std::vector
<sc::NoteEntry
>& rNotes
) const
690 std::for_each(maCellNotes
.begin(), maCellNotes
.end(), NoteEntryCollector(rNotes
, nTab
, nCol
));
693 void ScColumn::GetNotesInRange(SCROW nStartRow
, SCROW nEndRow
,
694 std::vector
<sc::NoteEntry
>& rNotes
) const
696 std::pair
<sc::CellNoteStoreType::const_iterator
,size_t> aPos
= maCellNotes
.position(nStartRow
);
697 sc::CellNoteStoreType::const_iterator it
= aPos
.first
;
698 if (it
== maCellNotes
.end())
699 // Invalid row number.
702 std::pair
<sc::CellNoteStoreType::const_iterator
,size_t> aEndPos
=
703 maCellNotes
.position(nEndRow
);
704 sc::CellNoteStoreType::const_iterator itEnd
= aEndPos
.first
;
706 std::for_each(it
, itEnd
, NoteEntryCollector(rNotes
, nTab
, nCol
, nStartRow
, nEndRow
));
711 class RecompileByOpcodeHandler
714 const formula::unordered_opcode_set
& mrOps
;
715 sc::EndListeningContext
& mrEndListenCxt
;
716 sc::CompileFormulaContext
& mrCompileFormulaCxt
;
719 RecompileByOpcodeHandler(
720 ScDocument
* pDoc
, const formula::unordered_opcode_set
& rOps
,
721 sc::EndListeningContext
& rEndListenCxt
, sc::CompileFormulaContext
& rCompileCxt
) :
724 mrEndListenCxt(rEndListenCxt
),
725 mrCompileFormulaCxt(rCompileCxt
) {}
727 void operator() ( sc::FormulaGroupEntry
& rEntry
)
729 // Perform end listening, remove from formula tree, and set them up
730 // for re-compilation.
732 ScFormulaCell
* pTop
= NULL
;
736 // Only inspect the code from the top cell.
737 pTop
= *rEntry
.mpCells
;
740 pTop
= rEntry
.mpCell
;
742 ScTokenArray
* pCode
= pTop
->GetCode();
743 bool bRecompile
= pCode
->HasOpCodes(mrOps
);
747 // Get the formula string.
748 OUString aFormula
= pTop
->GetFormula(mrCompileFormulaCxt
);
749 sal_Int32 n
= aFormula
.getLength();
750 if (pTop
->GetMatrixFlag() != MM_NONE
&& n
> 0)
752 if (aFormula
[0] == '{' && aFormula
[n
-1] == '}')
753 aFormula
= aFormula
.copy(1, n
-2);
758 ScFormulaCell
** pp
= rEntry
.mpCells
;
759 ScFormulaCell
** ppEnd
= pp
+ rEntry
.mnLength
;
760 for (; pp
!= ppEnd
; ++pp
)
762 ScFormulaCell
* p
= *pp
;
763 p
->EndListeningTo(mrEndListenCxt
);
764 mpDoc
->RemoveFromFormulaTree(p
);
769 rEntry
.mpCell
->EndListeningTo(mrEndListenCxt
);
770 mpDoc
->RemoveFromFormulaTree(rEntry
.mpCell
);
774 pTop
->SetHybridFormula(aFormula
, mpDoc
->GetGrammar());
779 class CompileHybridFormulaHandler
782 sc::StartListeningContext
& mrStartListenCxt
;
783 sc::CompileFormulaContext
& mrCompileFormulaCxt
;
786 CompileHybridFormulaHandler( ScDocument
* pDoc
, sc::StartListeningContext
& rStartListenCxt
, sc::CompileFormulaContext
& rCompileCxt
) :
788 mrStartListenCxt(rStartListenCxt
),
789 mrCompileFormulaCxt(rCompileCxt
) {}
791 void operator() ( sc::FormulaGroupEntry
& rEntry
)
795 ScFormulaCell
* pTop
= *rEntry
.mpCells
;
796 OUString aFormula
= pTop
->GetHybridFormula();
798 if (!aFormula
.isEmpty())
800 // Create a new token array from the hybrid formula string, and
801 // set it to the group.
802 ScCompiler
aComp(mrCompileFormulaCxt
, pTop
->aPos
);
803 ScTokenArray
* pNewCode
= aComp
.CompileString(aFormula
);
804 ScFormulaCellGroupRef xGroup
= pTop
->GetCellGroup();
806 xGroup
->setCode(pNewCode
);
807 xGroup
->compileCode(*mpDoc
, pTop
->aPos
, mpDoc
->GetGrammar());
809 // Propagate the new token array to all formula cells in the group.
810 ScFormulaCell
** pp
= rEntry
.mpCells
;
811 ScFormulaCell
** ppEnd
= pp
+ rEntry
.mnLength
;
812 for (; pp
!= ppEnd
; ++pp
)
814 ScFormulaCell
* p
= *pp
;
816 p
->StartListeningTo(mrStartListenCxt
);
823 ScFormulaCell
* pCell
= rEntry
.mpCell
;
824 OUString aFormula
= pCell
->GetHybridFormula();
826 if (!aFormula
.isEmpty())
828 // Create token array from formula string.
829 ScCompiler
aComp(mrCompileFormulaCxt
, pCell
->aPos
);
830 ScTokenArray
* pNewCode
= aComp
.CompileString(aFormula
);
832 // Generate RPN tokens.
833 ScCompiler
aComp2(mpDoc
, pCell
->aPos
, *pNewCode
);
834 aComp2
.CompileTokenArray();
836 pCell
->SetCode(pNewCode
);
837 pCell
->StartListeningTo(mrStartListenCxt
);
846 void ScColumn::PreprocessRangeNameUpdate(
847 sc::EndListeningContext
& rEndListenCxt
, sc::CompileFormulaContext
& rCompileCxt
)
849 // Collect all formula groups.
850 std::vector
<sc::FormulaGroupEntry
> aGroups
= GetFormulaGroupEntries();
852 formula::unordered_opcode_set aOps
;
854 aOps
.insert(ocColRowName
);
856 RecompileByOpcodeHandler
aFunc(pDocument
, aOps
, rEndListenCxt
, rCompileCxt
);
857 std::for_each(aGroups
.begin(), aGroups
.end(), aFunc
);
860 void ScColumn::PreprocessDBDataUpdate(
861 sc::EndListeningContext
& rEndListenCxt
, sc::CompileFormulaContext
& rCompileCxt
)
863 // Collect all formula groups.
864 std::vector
<sc::FormulaGroupEntry
> aGroups
= GetFormulaGroupEntries();
866 formula::unordered_opcode_set aOps
;
868 aOps
.insert(ocColRowName
);
869 aOps
.insert(ocDBArea
);
870 aOps
.insert(ocTableRef
);
871 RecompileByOpcodeHandler
aFunc(pDocument
, aOps
, rEndListenCxt
, rCompileCxt
);
872 std::for_each(aGroups
.begin(), aGroups
.end(), aFunc
);
875 void ScColumn::CompileHybridFormula(
876 sc::StartListeningContext
& rStartListenCxt
, sc::CompileFormulaContext
& rCompileCxt
)
878 // Collect all formula groups.
879 std::vector
<sc::FormulaGroupEntry
> aGroups
= GetFormulaGroupEntries();
881 CompileHybridFormulaHandler
aFunc(pDocument
, rStartListenCxt
, rCompileCxt
);
882 std::for_each(aGroups
.begin(), aGroups
.end(), aFunc
);
887 class ScriptTypeUpdater
890 sc::CellTextAttrStoreType
& mrTextAttrs
;
891 sc::CellTextAttrStoreType::iterator miPosAttr
;
892 ScConditionalFormatList
* mpCFList
;
893 SvNumberFormatter
* mpFormatter
;
898 void updateScriptType( size_t nRow
, ScRefCellValue
& rCell
)
900 sc::CellTextAttrStoreType::position_type aAttrPos
= mrTextAttrs
.position(miPosAttr
, nRow
);
901 miPosAttr
= aAttrPos
.first
;
903 if (aAttrPos
.first
->type
!= sc::element_type_celltextattr
)
906 sc::CellTextAttr
& rAttr
= sc::celltextattr_block::at(*aAttrPos
.first
->data
, aAttrPos
.second
);
907 if (rAttr
.mnScriptType
!= SvtScriptType::UNKNOWN
)
908 // Script type already deteremined. Skip it.
911 const ScPatternAttr
* pPat
= mrCol
.GetPattern(nRow
);
913 // In theory this should never return NULL. But let's be safe.
916 const SfxItemSet
* pCondSet
= NULL
;
920 const ScCondFormatItem
& rItem
=
921 static_cast<const ScCondFormatItem
&>(pPat
->GetItem(ATTR_CONDITIONAL
));
922 const std::vector
<sal_uInt32
>& rData
= rItem
.GetCondFormatData();
923 pCondSet
= mrCol
.GetDoc().GetCondResult(rCell
, maPos
, *mpCFList
, rData
);
928 sal_uLong nFormat
= pPat
->GetNumberFormat(mpFormatter
, pCondSet
);
929 ScCellFormat::GetString(rCell
, nFormat
, aStr
, &pColor
, *mpFormatter
, &mrCol
.GetDoc());
931 rAttr
.mnScriptType
= mrCol
.GetDoc().GetStringScriptType(aStr
);
936 ScriptTypeUpdater( ScColumn
& rCol
) :
938 mrTextAttrs(rCol
.GetCellAttrStore()),
939 miPosAttr(mrTextAttrs
.begin()),
940 mpCFList(rCol
.GetDoc().GetCondFormList(rCol
.GetTab())),
941 mpFormatter(rCol
.GetDoc().GetFormatTable()),
942 maPos(rCol
.GetCol(), 0, rCol
.GetTab()),
946 void operator() ( size_t nRow
, double fVal
)
948 ScRefCellValue
aCell(fVal
);
949 updateScriptType(nRow
, aCell
);
952 void operator() ( size_t nRow
, const svl::SharedString
& rStr
)
954 ScRefCellValue
aCell(&rStr
);
955 updateScriptType(nRow
, aCell
);
958 void operator() ( size_t nRow
, const EditTextObject
* pText
)
960 ScRefCellValue
aCell(pText
);
961 updateScriptType(nRow
, aCell
);
964 void operator() ( size_t nRow
, const ScFormulaCell
* pCell
)
966 ScRefCellValue
aCell(const_cast<ScFormulaCell
*>(pCell
));
967 updateScriptType(nRow
, aCell
);
970 bool isUpdated() const { return mbUpdated
; }
975 void ScColumn::UpdateScriptTypes( SCROW nRow1
, SCROW nRow2
)
977 if (!ValidRow(nRow1
) || !ValidRow(nRow2
) || nRow1
> nRow2
)
980 ScriptTypeUpdater
aFunc(*this);
981 sc::ParseAllNonEmpty(maCells
.begin(), maCells
, nRow1
, nRow2
, aFunc
);
982 if (aFunc
.isUpdated())
983 CellStorageModified();
986 void ScColumn::Swap( ScColumn
& rOther
, SCROW nRow1
, SCROW nRow2
, bool bPattern
)
988 maCells
.swap(nRow1
, nRow2
, rOther
.maCells
, nRow1
);
989 maCellTextAttrs
.swap(nRow1
, nRow2
, rOther
.maCellTextAttrs
, nRow1
);
990 maCellNotes
.swap(nRow1
, nRow2
, rOther
.maCellNotes
, nRow1
);
991 maBroadcasters
.swap(nRow1
, nRow2
, rOther
.maBroadcasters
, nRow1
);
995 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
997 const ScPatternAttr
* pPat1
= GetPattern(nRow
);
998 const ScPatternAttr
* pPat2
= rOther
.GetPattern(nRow
);
1001 SetPattern(nRow
, *pPat2
, true);
1002 rOther
.SetPattern(nRow
, *pPat1
, true);
1007 CellStorageModified();
1008 rOther
.CellStorageModified();
1013 class FormulaColPosSetter
1018 FormulaColPosSetter( SCCOL nCol
, bool bUpdateRefs
) : mnCol(nCol
), mbUpdateRefs(bUpdateRefs
) {}
1020 void operator() ( size_t nRow
, ScFormulaCell
* pCell
)
1022 if (!pCell
->IsShared() || pCell
->IsSharedTop())
1024 // Ensure that the references still point to the same locations
1025 // after the position change.
1026 ScAddress aOldPos
= pCell
->aPos
;
1027 pCell
->aPos
.SetCol(mnCol
);
1028 pCell
->aPos
.SetRow(nRow
);
1030 pCell
->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos
, pCell
->aPos
);
1032 pCell
->GetCode()->AdjustReferenceOnMovedOriginIfOtherSheet(aOldPos
, pCell
->aPos
);
1036 pCell
->aPos
.SetCol(mnCol
);
1037 pCell
->aPos
.SetRow(nRow
);
1044 void ScColumn::ResetFormulaCellPositions( SCROW nRow1
, SCROW nRow2
, bool bUpdateRefs
)
1046 FormulaColPosSetter
aFunc(nCol
, bUpdateRefs
);
1047 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aFunc
);
1052 class RelativeRefBoundChecker
1054 std::vector
<SCROW
> maBounds
;
1055 ScRange maBoundRange
;
1058 RelativeRefBoundChecker( const ScRange
& rBoundRange
) :
1059 maBoundRange(rBoundRange
) {}
1061 void operator() ( size_t /*nRow*/, ScFormulaCell
* pCell
)
1063 if (!pCell
->IsSharedTop())
1066 pCell
->GetCode()->CheckRelativeReferenceBounds(
1067 pCell
->aPos
, pCell
->GetSharedLength(), maBoundRange
, maBounds
);
1070 void swapBounds( std::vector
<SCROW
>& rBounds
)
1072 rBounds
.swap(maBounds
);
1078 void ScColumn::SplitFormulaGroupByRelativeRef( const ScRange
& rBoundRange
)
1080 if (rBoundRange
.aStart
.Row() >= MAXROW
)
1081 // Nothing to split.
1084 std::vector
<SCROW
> aBounds
;
1086 // Cut at row boundaries first.
1087 aBounds
.push_back(rBoundRange
.aStart
.Row());
1088 if (rBoundRange
.aEnd
.Row() < MAXROW
)
1089 aBounds
.push_back(rBoundRange
.aEnd
.Row()+1);
1090 sc::SharedFormulaUtil::splitFormulaCellGroups(maCells
, aBounds
);
1092 RelativeRefBoundChecker
aFunc(rBoundRange
);
1094 maCells
.begin(), maCells
, rBoundRange
.aStart
.Row(), rBoundRange
.aEnd
.Row(), aFunc
);
1095 aFunc
.swapBounds(aBounds
);
1096 sc::SharedFormulaUtil::splitFormulaCellGroups(maCells
, aBounds
);
1101 class ListenerCollector
1103 std::vector
<SvtListener
*>& mrListeners
;
1105 ListenerCollector( std::vector
<SvtListener
*>& rListener
) :
1106 mrListeners(rListener
) {}
1108 void operator() ( size_t /*nRow*/, SvtBroadcaster
* p
)
1110 SvtBroadcaster::ListenersType
& rLis
= p
->GetAllListeners();
1111 std::copy(rLis
.begin(), rLis
.end(), std::back_inserter(mrListeners
));
1115 class FormulaCellCollector
1117 std::vector
<ScFormulaCell
*>& mrCells
;
1119 FormulaCellCollector( std::vector
<ScFormulaCell
*>& rCells
) : mrCells(rCells
) {}
1121 void operator() ( size_t /*nRow*/, ScFormulaCell
* p
)
1123 mrCells
.push_back(p
);
1129 void ScColumn::CollectListeners( std::vector
<SvtListener
*>& rListeners
, SCROW nRow1
, SCROW nRow2
)
1131 if (nRow2
< nRow1
|| !ValidRow(nRow1
) || !ValidRow(nRow2
))
1134 ListenerCollector
aFunc(rListeners
);
1135 sc::ProcessBroadcaster(maBroadcasters
.begin(), maBroadcasters
, nRow1
, nRow2
, aFunc
);
1138 void ScColumn::CollectFormulaCells( std::vector
<ScFormulaCell
*>& rCells
, SCROW nRow1
, SCROW nRow2
)
1140 if (nRow2
< nRow1
|| !ValidRow(nRow1
) || !ValidRow(nRow2
))
1143 FormulaCellCollector
aFunc(rCells
);
1144 sc::ProcessFormula(maCells
.begin(), maCells
, nRow1
, nRow2
, aFunc
);
1149 struct FindAnyFormula
1151 bool operator() ( size_t /*nRow*/, const ScFormulaCell
* /*pCell*/ ) const
1159 bool ScColumn::HasFormulaCell( SCROW nRow1
, SCROW nRow2
) const
1161 if (nRow2
< nRow1
|| !ValidRow(nRow1
) || !ValidRow(nRow2
))
1164 FindAnyFormula aFunc
;
1165 std::pair
<sc::CellStoreType::const_iterator
, size_t> aRet
=
1166 sc::FindFormula(maCells
, nRow1
, nRow2
, aFunc
);
1168 return aRet
.first
!= maCells
.end();
1173 void endListening( sc::EndListeningContext
& rCxt
, ScFormulaCell
** pp
, ScFormulaCell
** ppEnd
)
1175 for (; pp
!= ppEnd
; ++pp
)
1177 ScFormulaCell
& rFC
= **pp
;
1178 rFC
.EndListeningTo(rCxt
);
1182 class StartListeningFormulaCellsHandler
1184 sc::StartListeningContext
& mrStartCxt
;
1185 sc::EndListeningContext
& mrEndCxt
;
1190 StartListeningFormulaCellsHandler( sc::StartListeningContext
& rStartCxt
, sc::EndListeningContext
& rEndCxt
) :
1191 mrStartCxt(rStartCxt
), mrEndCxt(rEndCxt
), mnStartRow(-1), mnEndRow(-1) {}
1193 void operator() ( const sc::CellStoreType::value_type
& node
, size_t nOffset
, size_t nDataSize
)
1195 if (node
.type
!= sc::element_type_formula
)
1196 // We are only interested in formulas.
1199 mnStartRow
= node
.position
+ nOffset
;
1201 ScFormulaCell
** ppBeg
= &sc::formula_block::at(*node
.data
, nOffset
);
1202 ScFormulaCell
** ppEnd
= ppBeg
+ nDataSize
;
1204 ScFormulaCell
** pp
= ppBeg
;
1206 // If the first formula cell belongs to a group and it's not the top
1207 // cell, move up to the top cell of the group, and have all the extra
1208 // formula cells stop listening.
1210 ScFormulaCell
* pFC
= *pp
;
1211 if (pFC
->IsShared() && !pFC
->IsSharedTop())
1213 SCROW nBackTrackSize
= pFC
->aPos
.Row() - pFC
->GetSharedTopRow();
1214 if (nBackTrackSize
> 0)
1216 assert(static_cast<size_t>(nBackTrackSize
) <= nOffset
);
1217 for (SCROW i
= 0; i
< nBackTrackSize
; ++i
)
1219 endListening(mrEndCxt
, pp
, ppBeg
);
1220 mnStartRow
-= nBackTrackSize
;
1224 for (; pp
!= ppEnd
; ++pp
)
1228 if (!pFC
->IsSharedTop())
1230 assert(!pFC
->IsShared());
1231 pFC
->StartListeningTo(mrStartCxt
);
1235 // If This is the last group in the range, see if the group
1236 // extends beyond the range, in which case have the excess
1237 // formula cells stop listening.
1238 size_t nEndGroupPos
= (pp
- ppBeg
) + pFC
->GetSharedLength();
1239 mnEndRow
= node
.position
+ nOffset
+ nEndGroupPos
- 1; // absolute row position of the last one in the group.
1240 if (nEndGroupPos
> nDataSize
)
1242 size_t nExcessSize
= nEndGroupPos
- nDataSize
;
1243 ScFormulaCell
** ppGrpEnd
= pp
+ pFC
->GetSharedLength();
1244 ScFormulaCell
** ppGrp
= ppGrpEnd
- nExcessSize
;
1245 endListening(mrEndCxt
, ppGrp
, ppGrpEnd
);
1247 // Register formula cells as a group.
1248 sc::SharedFormulaUtil::startListeningAsGroup(mrStartCxt
, pp
);
1249 pp
= ppEnd
- 1; // Move to the one before the end position.
1253 // Register formula cells as a group.
1254 sc::SharedFormulaUtil::startListeningAsGroup(mrStartCxt
, pp
);
1255 pp
+= pFC
->GetSharedLength() - 1; // Move to the last one in the group.
1260 SCROW
getStartRow() const
1265 SCROW
getEndRow() const
1271 class EndListeningFormulaCellsHandler
1273 sc::EndListeningContext
& mrEndCxt
;
1278 EndListeningFormulaCellsHandler( sc::EndListeningContext
& rEndCxt
) :
1279 mrEndCxt(rEndCxt
), mnStartRow(-1), mnEndRow(-1) {}
1281 void operator() ( const sc::CellStoreType::value_type
& node
, size_t nOffset
, size_t nDataSize
)
1283 if (node
.type
!= sc::element_type_formula
)
1284 // We are only interested in formulas.
1287 mnStartRow
= node
.position
+ nOffset
;
1289 ScFormulaCell
** ppBeg
= &sc::formula_block::at(*node
.data
, nOffset
);
1290 ScFormulaCell
** ppEnd
= ppBeg
+ nDataSize
;
1292 ScFormulaCell
** pp
= ppBeg
;
1294 // If the first formula cell belongs to a group and it's not the top
1295 // cell, move up to the top cell of the group.
1297 ScFormulaCell
* pFC
= *pp
;
1298 if (pFC
->IsShared() && !pFC
->IsSharedTop())
1300 SCROW nBackTrackSize
= pFC
->aPos
.Row() - pFC
->GetSharedTopRow();
1301 if (nBackTrackSize
> 0)
1303 assert(static_cast<size_t>(nBackTrackSize
) <= nOffset
);
1304 for (SCROW i
= 0; i
< nBackTrackSize
; ++i
)
1306 mnStartRow
-= nBackTrackSize
;
1310 for (; pp
!= ppEnd
; ++pp
)
1314 if (!pFC
->IsSharedTop())
1316 assert(!pFC
->IsShared());
1317 pFC
->EndListeningTo(mrEndCxt
);
1321 size_t nEndGroupPos
= (pp
- ppBeg
) + pFC
->GetSharedLength();
1322 mnEndRow
= node
.position
+ nOffset
+ nEndGroupPos
- 1; // absolute row position of the last one in the group.
1324 ScFormulaCell
** ppGrpEnd
= pp
+ pFC
->GetSharedLength();
1325 endListening(mrEndCxt
, pp
, ppGrpEnd
);
1327 if (nEndGroupPos
> nDataSize
)
1329 // The group goes beyond the specified end row. Move to the
1330 // one before the end position to finish the loop.
1335 // Move to the last one in the group.
1336 pp
+= pFC
->GetSharedLength() - 1;
1341 SCROW
getStartRow() const
1346 SCROW
getEndRow() const
1354 void ScColumn::StartListeningFormulaCells(
1355 sc::StartListeningContext
& rStartCxt
, sc::EndListeningContext
& rEndCxt
,
1356 SCROW nRow1
, SCROW nRow2
, SCROW
* pStartRow
, SCROW
* pEndRow
)
1358 StartListeningFormulaCellsHandler
aFunc(rStartCxt
, rEndCxt
);
1359 sc::ProcessBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
1362 // start row position may be smaller than nRow1 in case the formula
1363 // group starts before nRow1 position.
1364 *pStartRow
= aFunc
.getStartRow();
1367 // row position of the last cell that started listening, which may be
1368 // greater than nRow2 in case the formula group extends beyond nRow2.
1369 *pEndRow
= aFunc
.getEndRow();
1372 void ScColumn::EndListeningFormulaCells(
1373 sc::EndListeningContext
& rCxt
, SCROW nRow1
, SCROW nRow2
,
1374 SCROW
* pStartRow
, SCROW
* pEndRow
)
1376 EndListeningFormulaCellsHandler
aFunc(rCxt
);
1377 sc::ProcessBlock(maCells
.begin(), maCells
, aFunc
, nRow1
, nRow2
);
1380 *pStartRow
= aFunc
.getStartRow();
1383 *pEndRow
= aFunc
.getEndRow();
1386 void ScColumn::EndListeningIntersectedGroup(
1387 sc::EndListeningContext
& rCxt
, SCROW nRow
, std::vector
<ScAddress
>* pGroupPos
)
1389 if (!ValidRow(nRow
))
1392 sc::CellStoreType::position_type aPos
= maCells
.position(nRow
);
1393 sc::CellStoreType::iterator it
= aPos
.first
;
1394 if (it
->type
!= sc::element_type_formula
)
1395 // Only interested in a formula block.
1398 ScFormulaCell
* pFC
= sc::formula_block::at(*it
->data
, aPos
.second
);
1399 ScFormulaCellGroupRef xGroup
= pFC
->GetCellGroup();
1401 // Not a formula group.
1405 pFC
->EndListeningTo(rCxt
);
1409 if (!pFC
->IsSharedTop())
1410 // Record the position of the top cell of the group.
1411 pGroupPos
->push_back(xGroup
->mpTopCell
->aPos
);
1413 SCROW nGrpLastRow
= pFC
->GetSharedTopRow() + pFC
->GetSharedLength() - 1;
1414 if (nRow
< nGrpLastRow
)
1415 // Record the last position of the group.
1416 pGroupPos
->push_back(ScAddress(nCol
, nGrpLastRow
, nTab
));
1420 void ScColumn::EndListeningIntersectedGroups(
1421 sc::EndListeningContext
& rCxt
, SCROW nRow1
, SCROW nRow2
, std::vector
<ScAddress
>* pGroupPos
)
1423 // Only end the intersected group.
1424 sc::CellStoreType::position_type aPos
= maCells
.position(nRow1
);
1425 sc::CellStoreType::iterator it
= aPos
.first
;
1426 if (it
->type
== sc::element_type_formula
)
1428 ScFormulaCell
* pFC
= sc::formula_block::at(*it
->data
, aPos
.second
);
1429 ScFormulaCellGroupRef xGroup
= pFC
->GetCellGroup();
1430 if (xGroup
&& !pFC
->IsSharedTop())
1433 pFC
->EndListeningTo(rCxt
);
1435 // Record the position of the top cell of the group.
1436 pGroupPos
->push_back(xGroup
->mpTopCell
->aPos
);
1440 aPos
= maCells
.position(it
, nRow2
);
1442 if (it
->type
== sc::element_type_formula
)
1444 ScFormulaCell
* pFC
= sc::formula_block::at(*it
->data
, aPos
.second
);
1445 ScFormulaCellGroupRef xGroup
= pFC
->GetCellGroup();
1446 if (xGroup
&& !pFC
->IsSharedTop())
1449 pFC
->EndListeningTo(rCxt
);
1452 // Record the position of the bottom cell of the group.
1453 ScAddress aPosLast
= xGroup
->mpTopCell
->aPos
;
1454 aPosLast
.IncRow(xGroup
->mnLength
-1);
1455 pGroupPos
->push_back(aPosLast
);
1461 void ScColumn::EndListeningGroup( sc::EndListeningContext
& rCxt
, SCROW nRow
)
1463 sc::CellStoreType::position_type aPos
= maCells
.position(nRow
);
1464 if (aPos
.first
->type
!= sc::element_type_formula
)
1465 // not a formula cell.
1468 ScFormulaCell
** pp
= &sc::formula_block::at(*aPos
.first
->data
, aPos
.second
);
1470 ScFormulaCellGroupRef xGroup
= (*pp
)->GetCellGroup();
1473 // not a formula group.
1474 (*pp
)->EndListeningTo(rCxt
);
1478 // Move back to the top cell.
1479 SCROW nTopDelta
= (*pp
)->aPos
.Row() - xGroup
->mpTopCell
->aPos
.Row();
1480 assert(nTopDelta
>= 0);
1484 // Set the needs listening flag to all cells in the group.
1485 assert(*pp
== xGroup
->mpTopCell
);
1486 ScFormulaCell
** ppEnd
= pp
+ xGroup
->mnLength
;
1487 for (; pp
!= ppEnd
; ++pp
)
1488 (*pp
)->EndListeningTo(rCxt
);
1491 void ScColumn::SetNeedsListeningGroup( SCROW nRow
)
1493 sc::CellStoreType::position_type aPos
= maCells
.position(nRow
);
1494 if (aPos
.first
->type
!= sc::element_type_formula
)
1495 // not a formula cell.
1498 ScFormulaCell
** pp
= &sc::formula_block::at(*aPos
.first
->data
, aPos
.second
);
1500 ScFormulaCellGroupRef xGroup
= (*pp
)->GetCellGroup();
1503 // not a formula group.
1504 (*pp
)->SetNeedsListening(true);
1508 // Move back to the top cell.
1509 SCROW nTopDelta
= (*pp
)->aPos
.Row() - xGroup
->mpTopCell
->aPos
.Row();
1510 assert(nTopDelta
>= 0);
1514 // Set the needs listening flag to all cells in the group.
1515 assert(*pp
== xGroup
->mpTopCell
);
1516 ScFormulaCell
** ppEnd
= pp
+ xGroup
->mnLength
;
1517 for (; pp
!= ppEnd
; ++pp
)
1518 (*pp
)->SetNeedsListening(true);
1521 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */