fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / column4.cxx
blobac09eac472ce6592bef0d08c75fc92bc470b80fe
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <column.hxx>
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>
21 #include <attrib.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>
34 #include <vector>
35 #include <cassert>
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))
49 return;
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);
62 if (aSpans.empty())
63 // All cells in the range in the clip are empty. Nothing to delete.
64 return;
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;
70 while (bContinue)
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)
81 // We're done.
82 bContinue = false;
83 continue;
86 if (nDestRow2 > aRange.mnRow2)
88 // Truncate this range, and set it as the last span.
89 nDestRow2 = aRange.mnRow2;
90 bContinue = false;
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();
135 if (pCondList)
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);
149 if (!pBlockPos)
150 return;
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)
175 case CELLTYPE_VALUE:
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();
184 break;
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()) :
192 *rSrcCell.mpString);
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();
201 break;
202 case CELLTYPE_EDIT:
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();
215 break;
216 case CELLTYPE_FORMULA:
218 std::vector<sc::RowSpan> aRanges;
219 aRanges.reserve(1);
220 aRanges.push_back(sc::RowSpan(nRow1, nRow2));
221 CloneFormulaCell(*rSrcCell.mpFormula, rSrcAttr, aRanges, NULL);
223 break;
224 default:
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));
243 aDestPos.IncRow();
246 pBlockPos->miCellNotePos =
247 maCellNotes.set(
248 pBlockPos->miCellNotePos, nRow1, aNotes.begin(), aNotes.end());
252 void ScColumn::SetValues( SCROW nRow, const std::vector<double>& rVals )
254 if (!ValidRow(nRow))
255 return;
257 SCROW nLastRow = nRow + rVals.size() - 1;
258 if (nLastRow > MAXROW)
259 // Out of bound. Do nothing.
260 return;
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)
274 aRows.push_back(i);
276 BroadcastCells(aRows, SC_HINT_DATACHANGED);
279 void ScColumn::TransferCellValuesTo( SCROW nRow, size_t nLen, sc::CellValues& rDest )
281 if (!ValidRow(nRow))
282 return;
284 SCROW nLastRow = nRow + nLen - 1;
285 if (nLastRow > MAXROW)
286 // Out of bound. Do nothing.
287 return;
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;
297 aRows.reserve(nLen);
298 for (SCROW i = nRow; i <= nLastRow; ++i)
299 aRows.push_back(i);
301 BroadcastCells(aRows, SC_HINT_DATACHANGED);
304 void ScColumn::CopyCellValuesFrom( SCROW nRow, const sc::CellValues& rSrc )
306 if (!ValidRow(nRow))
307 return;
309 SCROW nLastRow = nRow + rSrc.size() - 1;
310 if (nLastRow > MAXROW)
311 // Out of bound. Do nothing
312 return;
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)
324 aRows.push_back(i);
326 BroadcastCells(aRows, SC_HINT_DATACHANGED);
329 namespace {
331 class ConvertFormulaToValueHandler
333 sc::CellValues maResValues;
334 bool mbModified;
336 public:
337 ConvertFormulaToValueHandler( SCTAB, SCCOL ) :
338 mbModified(false)
340 maResValues.reset(MAXROWCOUNT);
343 void operator() ( size_t nRow, const ScFormulaCell* pCell )
345 sc::FormulaResultValue aRes = pCell->GetResult();
346 switch (aRes.meType)
348 case sc::FormulaResultValue::Value:
349 maResValues.setValue(nRow, aRes.mfValue);
350 break;
351 case sc::FormulaResultValue::String:
352 maResValues.setValue(nRow, aRes.maString);
353 break;
354 case sc::FormulaResultValue::Error:
355 case sc::FormulaResultValue::Invalid:
356 default:
357 maResValues.setValue(nRow, svl::SharedString::getEmptyString());
360 mbModified = true;
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)
374 return;
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.
389 return;
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);
397 if (pUndo)
398 pUndo->swap(nTab, nCol, aUndoCells);
401 namespace {
403 class StartListeningHandler
405 sc::StartListeningContext& mrCxt;
407 public:
408 StartListeningHandler( sc::StartListeningContext& rCxt ) :
409 mrCxt(rCxt) {}
411 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
413 pCell->StartListeningTo(mrCxt);
417 class EndListeningHandler
419 sc::EndListeningContext& mrCxt;
421 public:
422 EndListeningHandler( sc::EndListeningContext& rCxt ) :
423 mrCxt(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);
462 it = aSpans.begin();
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;
494 assert(nLen > 0);
495 aFormulas.clear();
496 aFormulas.reserve(nLen);
498 ScAddress aPos(nCol, nRow1, nTab);
500 if (nLen == 1)
502 // Single, ungrouped formula cell.
503 ScFormulaCell* pCell = new ScFormulaCell(rSrc, *pDocument, aPos);
504 if (pCxt)
506 pCell->StartListeningTo(*pCxt);
507 pCell->SetDirty();
509 aFormulas.push_back(pCell);
511 else
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());
520 if (i == 0)
522 xGroup->mpTopCell = pCell;
523 xGroup->mnLength = nLen;
525 if (pCxt)
527 pCell->StartListeningTo(*pCxt);
528 pCell->SetDirty();
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 )
557 if (!ValidRow(nRow))
558 return NULL;
560 ScPostIt* p = NULL;
561 maCellNotes.release(nRow, p);
562 return p;
565 size_t ScColumn::GetNoteCount() const
567 size_t nCount = 0;
568 sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
569 for (; it != itEnd; ++it)
571 if (it->type != sc::element_type_cellnote)
572 continue;
574 nCount += it->size;
577 return nCount;
580 namespace {
582 class NoteCaptionCreator
584 ScAddress maPos;
585 public:
586 NoteCaptionCreator( SCTAB nTab, SCCOL nCol ) : maPos(nCol,0,nTab) {}
588 void operator() ( size_t nRow, ScPostIt* p )
590 maPos.SetRow(nRow);
591 p->GetOrCreateCaption(maPos);
595 struct NoteCaptionCleaner
597 void operator() ( size_t /*nRow*/, ScPostIt* p )
599 p->ForgetCaption();
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))
614 return;
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.
632 continue;
634 if (nIndex < nCount + it->size)
636 // Index falls within this block.
637 size_t nOffset = nIndex - nCount;
638 return it->position + nOffset;
641 nCount += it->size;
644 return -1;
647 namespace {
649 class NoteEntryCollector
651 std::vector<sc::NoteEntry>& mrNotes;
652 SCTAB mnTab;
653 SCCOL mnCol;
654 SCROW mnStartRow;
655 SCROW mnEndRow;
656 public:
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)
665 return;
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);
670 size_t nOffset = 0;
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);
678 ++it, ++nOffset)
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.
700 return;
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));
709 namespace {
711 class RecompileByOpcodeHandler
713 ScDocument* mpDoc;
714 const formula::unordered_opcode_set& mrOps;
715 sc::EndListeningContext& mrEndListenCxt;
716 sc::CompileFormulaContext& mrCompileFormulaCxt;
718 public:
719 RecompileByOpcodeHandler(
720 ScDocument* pDoc, const formula::unordered_opcode_set& rOps,
721 sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt ) :
722 mpDoc(pDoc),
723 mrOps(rOps),
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;
734 if (rEntry.mbShared)
736 // Only inspect the code from the top cell.
737 pTop = *rEntry.mpCells;
739 else
740 pTop = rEntry.mpCell;
742 ScTokenArray* pCode = pTop->GetCode();
743 bool bRecompile = pCode->HasOpCodes(mrOps);
745 if (bRecompile)
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);
756 if (rEntry.mbShared)
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);
767 else
769 rEntry.mpCell->EndListeningTo(mrEndListenCxt);
770 mpDoc->RemoveFromFormulaTree(rEntry.mpCell);
773 pCode->Clear();
774 pTop->SetHybridFormula(aFormula, mpDoc->GetGrammar());
779 class CompileHybridFormulaHandler
781 ScDocument* mpDoc;
782 sc::StartListeningContext& mrStartListenCxt;
783 sc::CompileFormulaContext& mrCompileFormulaCxt;
785 public:
786 CompileHybridFormulaHandler( ScDocument* pDoc, sc::StartListeningContext& rStartListenCxt, sc::CompileFormulaContext& rCompileCxt ) :
787 mpDoc(pDoc),
788 mrStartListenCxt(rStartListenCxt),
789 mrCompileFormulaCxt(rCompileCxt) {}
791 void operator() ( sc::FormulaGroupEntry& rEntry )
793 if (rEntry.mbShared)
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();
805 assert(xGroup);
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;
815 p->SyncSharedCode();
816 p->StartListeningTo(mrStartListenCxt);
817 p->SetDirty();
821 else
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);
838 pCell->SetDirty();
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;
853 aOps.insert(ocBad);
854 aOps.insert(ocColRowName);
855 aOps.insert(ocName);
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;
867 aOps.insert(ocBad);
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);
885 namespace {
887 class ScriptTypeUpdater
889 ScColumn& mrCol;
890 sc::CellTextAttrStoreType& mrTextAttrs;
891 sc::CellTextAttrStoreType::iterator miPosAttr;
892 ScConditionalFormatList* mpCFList;
893 SvNumberFormatter* mpFormatter;
894 ScAddress maPos;
895 bool mbUpdated;
897 private:
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)
904 return;
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.
909 return;
911 const ScPatternAttr* pPat = mrCol.GetPattern(nRow);
912 if (!pPat)
913 // In theory this should never return NULL. But let's be safe.
914 return;
916 const SfxItemSet* pCondSet = NULL;
917 if (mpCFList)
919 maPos.SetRow(nRow);
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);
926 OUString aStr;
927 Color* pColor;
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);
932 mbUpdated = true;
935 public:
936 ScriptTypeUpdater( ScColumn& rCol ) :
937 mrCol(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()),
943 mbUpdated(false)
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)
978 return;
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);
993 if (bPattern)
995 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
997 const ScPatternAttr* pPat1 = GetPattern(nRow);
998 const ScPatternAttr* pPat2 = rOther.GetPattern(nRow);
999 if (pPat1 != pPat2)
1001 SetPattern(nRow, *pPat2, true);
1002 rOther.SetPattern(nRow, *pPat1, true);
1007 CellStorageModified();
1008 rOther.CellStorageModified();
1011 namespace {
1013 class FormulaColPosSetter
1015 SCCOL mnCol;
1016 bool mbUpdateRefs;
1017 public:
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);
1029 if (mbUpdateRefs)
1030 pCell->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, pCell->aPos);
1031 else
1032 pCell->GetCode()->AdjustReferenceOnMovedOriginIfOtherSheet(aOldPos, pCell->aPos);
1034 else
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);
1050 namespace {
1052 class RelativeRefBoundChecker
1054 std::vector<SCROW> maBounds;
1055 ScRange maBoundRange;
1057 public:
1058 RelativeRefBoundChecker( const ScRange& rBoundRange ) :
1059 maBoundRange(rBoundRange) {}
1061 void operator() ( size_t /*nRow*/, ScFormulaCell* pCell )
1063 if (!pCell->IsSharedTop())
1064 return;
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.
1082 return;
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);
1093 sc::ProcessFormula(
1094 maCells.begin(), maCells, rBoundRange.aStart.Row(), rBoundRange.aEnd.Row(), aFunc);
1095 aFunc.swapBounds(aBounds);
1096 sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
1099 namespace {
1101 class ListenerCollector
1103 std::vector<SvtListener*>& mrListeners;
1104 public:
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;
1118 public:
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))
1132 return;
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))
1141 return;
1143 FormulaCellCollector aFunc(rCells);
1144 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
1147 namespace {
1149 struct FindAnyFormula
1151 bool operator() ( size_t /*nRow*/, const ScFormulaCell* /*pCell*/ ) const
1153 return true;
1159 bool ScColumn::HasFormulaCell( SCROW nRow1, SCROW nRow2 ) const
1161 if (nRow2 < nRow1 || !ValidRow(nRow1) || !ValidRow(nRow2))
1162 return false;
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();
1171 namespace {
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;
1186 SCROW mnStartRow;
1187 SCROW mnEndRow;
1189 public:
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.
1197 return;
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)
1218 --pp;
1219 endListening(mrEndCxt, pp, ppBeg);
1220 mnStartRow -= nBackTrackSize;
1224 for (; pp != ppEnd; ++pp)
1226 pFC = *pp;
1228 if (!pFC->IsSharedTop())
1230 assert(!pFC->IsShared());
1231 pFC->StartListeningTo(mrStartCxt);
1232 continue;
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.
1251 else
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
1262 return mnStartRow;
1265 SCROW getEndRow() const
1267 return mnEndRow;
1271 class EndListeningFormulaCellsHandler
1273 sc::EndListeningContext& mrEndCxt;
1274 SCROW mnStartRow;
1275 SCROW mnEndRow;
1277 public:
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.
1285 return;
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)
1305 --pp;
1306 mnStartRow -= nBackTrackSize;
1310 for (; pp != ppEnd; ++pp)
1312 pFC = *pp;
1314 if (!pFC->IsSharedTop())
1316 assert(!pFC->IsShared());
1317 pFC->EndListeningTo(mrEndCxt);
1318 continue;
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.
1331 pp = ppEnd - 1;
1333 else
1335 // Move to the last one in the group.
1336 pp += pFC->GetSharedLength() - 1;
1341 SCROW getStartRow() const
1343 return mnStartRow;
1346 SCROW getEndRow() const
1348 return mnEndRow;
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);
1361 if (pStartRow)
1362 // start row position may be smaller than nRow1 in case the formula
1363 // group starts before nRow1 position.
1364 *pStartRow = aFunc.getStartRow();
1366 if (pEndRow)
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);
1379 if (pStartRow)
1380 *pStartRow = aFunc.getStartRow();
1382 if (pEndRow)
1383 *pEndRow = aFunc.getEndRow();
1386 void ScColumn::EndListeningIntersectedGroup(
1387 sc::EndListeningContext& rCxt, SCROW nRow, std::vector<ScAddress>* pGroupPos )
1389 if (!ValidRow(nRow))
1390 return;
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.
1396 return;
1398 ScFormulaCell* pFC = sc::formula_block::at(*it->data, aPos.second);
1399 ScFormulaCellGroupRef xGroup = pFC->GetCellGroup();
1400 if (!xGroup)
1401 // Not a formula group.
1402 return;
1404 // End listening.
1405 pFC->EndListeningTo(rCxt);
1407 if (pGroupPos)
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())
1432 // End listening.
1433 pFC->EndListeningTo(rCxt);
1434 if (pGroupPos)
1435 // Record the position of the top cell of the group.
1436 pGroupPos->push_back(xGroup->mpTopCell->aPos);
1440 aPos = maCells.position(it, nRow2);
1441 it = aPos.first;
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())
1448 // End listening.
1449 pFC->EndListeningTo(rCxt);
1450 if (pGroupPos)
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.
1466 return;
1468 ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second);
1470 ScFormulaCellGroupRef xGroup = (*pp)->GetCellGroup();
1471 if (!xGroup)
1473 // not a formula group.
1474 (*pp)->EndListeningTo(rCxt);
1475 return;
1478 // Move back to the top cell.
1479 SCROW nTopDelta = (*pp)->aPos.Row() - xGroup->mpTopCell->aPos.Row();
1480 assert(nTopDelta >= 0);
1481 if (nTopDelta > 0)
1482 pp -= nTopDelta;
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.
1496 return;
1498 ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second);
1500 ScFormulaCellGroupRef xGroup = (*pp)->GetCellGroup();
1501 if (!xGroup)
1503 // not a formula group.
1504 (*pp)->SetNeedsListening(true);
1505 return;
1508 // Move back to the top cell.
1509 SCROW nTopDelta = (*pp)->aPos.Row() - xGroup->mpTopCell->aPos.Row();
1510 assert(nTopDelta >= 0);
1511 if (nTopDelta > 0)
1512 pp -= nTopDelta;
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: */