Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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 : */
9 :
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>
31 :
32 : #include <svl/sharedstringpool.hxx>
33 :
34 : #include <vector>
35 : #include <cassert>
36 :
37 : #include <boost/shared_ptr.hpp>
38 :
39 17 : bool ScColumn::IsMerged( SCROW nRow ) const
40 : {
41 17 : return pAttrArray->IsMerged(nRow);
42 : }
43 :
44 4 : void ScColumn::DeleteBeforeCopyFromClip(
45 : sc::CopyFromClipContext& rCxt, const ScColumn& rClipCol, sc::ColumnSpanSet& rBroadcastSpans )
46 : {
47 4 : sc::CopyFromClipContext::Range aRange = rCxt.getDestRange();
48 4 : if (!ValidRow(aRange.mnRow1) || !ValidRow(aRange.mnRow2))
49 1 : return;
50 :
51 4 : ScRange aClipRange = rCxt.getClipDoc()->GetClipParam().getWholeRange();
52 4 : SCROW nClipRow1 = aClipRange.aStart.Row();
53 4 : SCROW nClipRow2 = aClipRange.aEnd.Row();
54 4 : SCROW nClipRowLen = nClipRow2 - nClipRow1 + 1;
55 :
56 : // Check for non-empty cell ranges in the clip column.
57 4 : sc::SingleColumnSpanSet aSpanSet;
58 4 : aSpanSet.scan(rClipCol, nClipRow1, nClipRow2);
59 7 : sc::SingleColumnSpanSet::SpansType aSpans;
60 4 : aSpanSet.getSpans(aSpans);
61 :
62 4 : if (aSpans.empty())
63 : // All cells in the range in the clip are empty. Nothing to delete.
64 1 : return;
65 :
66 : // Translate the clip column spans into the destination column, and repeat as needed.
67 6 : std::vector<sc::RowSpan> aDestSpans;
68 3 : SCROW nDestOffset = aRange.mnRow1 - nClipRow1;
69 3 : bool bContinue = true;
70 12 : while (bContinue)
71 : {
72 6 : sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
73 14 : for (; it != itEnd && bContinue; ++it)
74 : {
75 8 : const sc::RowSpan& r = *it;
76 8 : SCROW nDestRow1 = r.mnRow1 + nDestOffset;
77 8 : SCROW nDestRow2 = r.mnRow2 + nDestOffset;
78 :
79 8 : if (nDestRow1 > aRange.mnRow2)
80 : {
81 : // We're done.
82 3 : bContinue = false;
83 3 : continue;
84 : }
85 :
86 5 : if (nDestRow2 > aRange.mnRow2)
87 : {
88 : // Truncate this range, and set it as the last span.
89 0 : nDestRow2 = aRange.mnRow2;
90 0 : bContinue = false;
91 : }
92 :
93 5 : aDestSpans.push_back(sc::RowSpan(nDestRow1, nDestRow2));
94 : }
95 :
96 6 : nDestOffset += nClipRowLen;
97 : }
98 :
99 3 : InsertDeleteFlags nDelFlag = rCxt.getDeleteFlag();
100 3 : sc::ColumnBlockPosition aBlockPos;
101 3 : InitBlockPosition(aBlockPos);
102 :
103 3 : std::vector<sc::RowSpan>::const_iterator it = aDestSpans.begin(), itEnd = aDestSpans.end();
104 8 : for (; it != itEnd; ++it)
105 : {
106 5 : SCROW nRow1 = it->mnRow1;
107 5 : SCROW nRow2 = it->mnRow2;
108 :
109 5 : if (nDelFlag & IDF_CONTENTS)
110 : {
111 5 : sc::SingleColumnSpanSet aDeletedRows;
112 5 : DeleteCells(aBlockPos, nRow1, nRow2, nDelFlag, aDeletedRows);
113 5 : rBroadcastSpans.set(nTab, nCol, aDeletedRows, true);
114 : }
115 :
116 5 : if (nDelFlag & IDF_NOTE)
117 5 : DeleteCellNotes(aBlockPos, nRow1, nRow2);
118 :
119 5 : if (nDelFlag & IDF_EDITATTR)
120 0 : RemoveEditAttribs(nRow1, nRow2);
121 :
122 : // Delete attributes just now
123 5 : if (nDelFlag & IDF_ATTRIB)
124 : {
125 5 : pAttrArray->DeleteArea(nRow1, nRow2);
126 :
127 5 : if (rCxt.isTableProtected())
128 : {
129 0 : ScPatternAttr aPattern(pDocument->GetPool());
130 0 : aPattern.GetItemSet().Put(ScProtectionAttr(false));
131 0 : ApplyPatternArea(nRow1, nRow2, aPattern);
132 : }
133 :
134 5 : ScConditionalFormatList* pCondList = rCxt.getCondFormatList();
135 5 : if (pCondList)
136 5 : pCondList->DeleteArea(nCol, nRow1, nCol, nRow2);
137 : }
138 0 : else if ((nDelFlag & IDF_HARDATTR) == IDF_HARDATTR)
139 0 : pAttrArray->DeleteHardAttr(nRow1, nRow2);
140 3 : }
141 : }
142 :
143 17 : void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, size_t nColOffset )
144 : {
145 : assert(nRow1 <= nRow2);
146 :
147 17 : size_t nDestSize = nRow2 - nRow1 + 1;
148 17 : sc::ColumnBlockPosition* pBlockPos = rCxt.getBlockPosition(nTab, nCol);
149 17 : if (!pBlockPos)
150 17 : return;
151 :
152 17 : bool bSameDocPool = (rCxt.getClipDoc()->GetPool() == pDocument->GetPool());
153 :
154 17 : ScCellValue& rSrcCell = rCxt.getSingleCell(nColOffset);
155 17 : sc::CellTextAttr& rSrcAttr = rCxt.getSingleCellAttr(nColOffset);
156 :
157 17 : InsertDeleteFlags nFlags = rCxt.getInsertFlag();
158 :
159 17 : if ((nFlags & IDF_ATTRIB) != IDF_NONE)
160 : {
161 16 : if (!rCxt.isSkipAttrForEmptyCells() || rSrcCell.meType != CELLTYPE_NONE)
162 : {
163 : const ScPatternAttr* pAttr = (bSameDocPool ? rCxt.getSingleCellPattern(nColOffset) :
164 15 : rCxt.getSingleCellPattern(nColOffset)->PutInPool( pDocument, rCxt.getClipDoc()));
165 15 : pAttrArray->SetPatternArea(nRow1, nRow2, pAttr, true);
166 : }
167 : }
168 :
169 17 : if ((nFlags & IDF_CONTENTS) != IDF_NONE)
170 : {
171 17 : std::vector<sc::CellTextAttr> aTextAttrs(nDestSize, rSrcAttr);
172 :
173 17 : switch (rSrcCell.meType)
174 : {
175 : case CELLTYPE_VALUE:
176 : {
177 2 : std::vector<double> aVals(nDestSize, rSrcCell.mfValue);
178 4 : pBlockPos->miCellPos =
179 2 : maCells.set(pBlockPos->miCellPos, nRow1, aVals.begin(), aVals.end());
180 4 : pBlockPos->miCellTextAttrPos =
181 2 : maCellTextAttrs.set(pBlockPos->miCellTextAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
182 2 : CellStorageModified();
183 : }
184 2 : break;
185 : case CELLTYPE_STRING:
186 : {
187 : // Compare the ScDocumentPool* to determine if we are copying within the
188 : // same document. If not, re-intern shared strings.
189 4 : svl::SharedStringPool* pSharedStringPool = (bSameDocPool ? NULL : &pDocument->GetSharedStringPool());
190 : svl::SharedString aStr = (pSharedStringPool ?
191 : pSharedStringPool->intern( rSrcCell.mpString->getString()) :
192 4 : *rSrcCell.mpString);
193 :
194 8 : std::vector<svl::SharedString> aStrs(nDestSize, aStr);
195 8 : pBlockPos->miCellPos =
196 4 : maCells.set(pBlockPos->miCellPos, nRow1, aStrs.begin(), aStrs.end());
197 8 : pBlockPos->miCellTextAttrPos =
198 4 : maCellTextAttrs.set(pBlockPos->miCellTextAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
199 8 : CellStorageModified();
200 : }
201 4 : break;
202 : case CELLTYPE_EDIT:
203 : {
204 0 : std::vector<EditTextObject*> aStrs;
205 0 : aStrs.reserve(nDestSize);
206 0 : for (size_t i = 0; i < nDestSize; ++i)
207 0 : aStrs.push_back(rSrcCell.mpEditText->Clone());
208 :
209 0 : pBlockPos->miCellPos =
210 0 : maCells.set(pBlockPos->miCellPos, nRow1, aStrs.begin(), aStrs.end());
211 0 : pBlockPos->miCellTextAttrPos =
212 0 : maCellTextAttrs.set(pBlockPos->miCellTextAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
213 0 : CellStorageModified();
214 : }
215 0 : break;
216 : case CELLTYPE_FORMULA:
217 : {
218 7 : std::vector<sc::RowSpan> aRanges;
219 7 : aRanges.reserve(1);
220 7 : aRanges.push_back(sc::RowSpan(nRow1, nRow2));
221 7 : CloneFormulaCell(*rSrcCell.mpFormula, rSrcAttr, aRanges, NULL);
222 : }
223 7 : break;
224 : default:
225 : ;
226 17 : }
227 : }
228 :
229 17 : const ScPostIt* pNote = rCxt.getSingleCellNote(nColOffset);
230 17 : if (pNote && (nFlags & (IDF_NOTE | IDF_ADDNOTES)) != IDF_NONE)
231 : {
232 : // Duplicate the cell note over the whole pasted range.
233 :
234 3 : ScDocument* pClipDoc = rCxt.getClipDoc();
235 3 : const ScAddress& rSrcPos = pClipDoc->GetClipParam().getWholeRange().aStart;
236 3 : std::vector<ScPostIt*> aNotes;
237 3 : ScAddress aDestPos(nCol, nRow1, nTab);
238 3 : aNotes.reserve(nDestSize);
239 6 : for (size_t i = 0; i < nDestSize; ++i)
240 : {
241 3 : bool bCloneCaption = (nFlags & IDF_NOCAPTIONS) == IDF_NONE;
242 3 : aNotes.push_back(pNote->Clone(rSrcPos, *pDocument, aDestPos, bCloneCaption));
243 3 : aDestPos.IncRow();
244 : }
245 :
246 6 : pBlockPos->miCellNotePos =
247 : maCellNotes.set(
248 6 : pBlockPos->miCellNotePos, nRow1, aNotes.begin(), aNotes.end());
249 : }
250 : }
251 :
252 0 : void ScColumn::SetValues( SCROW nRow, const std::vector<double>& rVals )
253 : {
254 0 : if (!ValidRow(nRow))
255 0 : return;
256 :
257 0 : SCROW nLastRow = nRow + rVals.size() - 1;
258 0 : if (nLastRow > MAXROW)
259 : // Out of bound. Do nothing.
260 0 : return;
261 :
262 0 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
263 0 : DetachFormulaCells(aPos, rVals.size());
264 :
265 0 : maCells.set(nRow, rVals.begin(), rVals.end());
266 0 : std::vector<sc::CellTextAttr> aDefaults(rVals.size());
267 0 : maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end());
268 :
269 0 : CellStorageModified();
270 :
271 0 : std::vector<SCROW> aRows;
272 0 : aRows.reserve(rVals.size());
273 0 : for (SCROW i = nRow; i <= nLastRow; ++i)
274 0 : aRows.push_back(i);
275 :
276 0 : BroadcastCells(aRows, SC_HINT_DATACHANGED);
277 : }
278 :
279 0 : void ScColumn::TransferCellValuesTo( SCROW nRow, size_t nLen, sc::CellValues& rDest )
280 : {
281 0 : if (!ValidRow(nRow))
282 0 : return;
283 :
284 0 : SCROW nLastRow = nRow + nLen - 1;
285 0 : if (nLastRow > MAXROW)
286 : // Out of bound. Do nothing.
287 0 : return;
288 :
289 0 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
290 0 : DetachFormulaCells(aPos, nLen);
291 :
292 0 : rDest.transferFrom(*this, nRow, nLen);
293 :
294 0 : CellStorageModified();
295 :
296 0 : std::vector<SCROW> aRows;
297 0 : aRows.reserve(nLen);
298 0 : for (SCROW i = nRow; i <= nLastRow; ++i)
299 0 : aRows.push_back(i);
300 :
301 0 : BroadcastCells(aRows, SC_HINT_DATACHANGED);
302 : }
303 :
304 0 : void ScColumn::CopyCellValuesFrom( SCROW nRow, const sc::CellValues& rSrc )
305 : {
306 0 : if (!ValidRow(nRow))
307 0 : return;
308 :
309 0 : SCROW nLastRow = nRow + rSrc.size() - 1;
310 0 : if (nLastRow > MAXROW)
311 : // Out of bound. Do nothing
312 0 : return;
313 :
314 0 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
315 0 : DetachFormulaCells(aPos, rSrc.size());
316 :
317 0 : rSrc.copyTo(*this, nRow);
318 :
319 0 : CellStorageModified();
320 :
321 0 : std::vector<SCROW> aRows;
322 0 : aRows.reserve(rSrc.size());
323 0 : for (SCROW i = nRow; i <= nLastRow; ++i)
324 0 : aRows.push_back(i);
325 :
326 0 : BroadcastCells(aRows, SC_HINT_DATACHANGED);
327 : }
328 :
329 : namespace {
330 :
331 3 : class ConvertFormulaToValueHandler
332 : {
333 : sc::CellValues maResValues;
334 : bool mbModified;
335 :
336 : public:
337 3 : ConvertFormulaToValueHandler( SCTAB, SCCOL ) :
338 3 : mbModified(false)
339 : {
340 3 : maResValues.reset(MAXROWCOUNT);
341 3 : }
342 :
343 6 : void operator() ( size_t nRow, const ScFormulaCell* pCell )
344 : {
345 6 : sc::FormulaResultValue aRes = pCell->GetResult();
346 6 : switch (aRes.meType)
347 : {
348 : case sc::FormulaResultValue::Value:
349 6 : maResValues.setValue(nRow, aRes.mfValue);
350 6 : break;
351 : case sc::FormulaResultValue::String:
352 0 : maResValues.setValue(nRow, aRes.maString);
353 0 : break;
354 : case sc::FormulaResultValue::Error:
355 : case sc::FormulaResultValue::Invalid:
356 : default:
357 0 : maResValues.setValue(nRow, svl::SharedString::getEmptyString());
358 : }
359 :
360 6 : mbModified = true;
361 6 : }
362 :
363 3 : bool isModified() const { return mbModified; }
364 :
365 3 : sc::CellValues& getResValues() { return maResValues; }
366 : };
367 :
368 : }
369 :
370 3 : void ScColumn::ConvertFormulaToValue(
371 : sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2, sc::TableValues* pUndo )
372 : {
373 3 : if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
374 0 : return;
375 :
376 3 : std::vector<SCROW> aBounds;
377 3 : aBounds.push_back(nRow1);
378 3 : if (nRow2 < MAXROW-1)
379 3 : aBounds.push_back(nRow2+1);
380 :
381 : // Split formula cell groups at top and bottom boundaries (if applicable).
382 3 : sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
383 :
384 : // Parse all formulas within the range and store their results into temporary storage.
385 6 : ConvertFormulaToValueHandler aFunc(nTab, nCol);
386 3 : sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
387 3 : if (!aFunc.isModified())
388 : // No formula cells encountered.
389 0 : return;
390 :
391 3 : DetachFormulaCells(rCxt, nRow1, nRow2);
392 :
393 : // Undo storage to hold static values which will get swapped to the cell storage later.
394 6 : sc::CellValues aUndoCells;
395 3 : aFunc.getResValues().swap(aUndoCells);
396 3 : aUndoCells.swapNonEmpty(*this);
397 3 : if (pUndo)
398 6 : pUndo->swap(nTab, nCol, aUndoCells);
399 : }
400 :
401 : namespace {
402 :
403 : class StartListeningHandler
404 : {
405 : sc::StartListeningContext& mrCxt;
406 :
407 : public:
408 7 : StartListeningHandler( sc::StartListeningContext& rCxt ) :
409 7 : mrCxt(rCxt) {}
410 :
411 10 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
412 : {
413 10 : pCell->StartListeningTo(mrCxt);
414 10 : }
415 : };
416 :
417 : class EndListeningHandler
418 : {
419 : sc::EndListeningContext& mrCxt;
420 :
421 : public:
422 7 : EndListeningHandler( sc::EndListeningContext& rCxt ) :
423 7 : mrCxt(rCxt) {}
424 :
425 4 : void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
426 : {
427 4 : pCell->EndListeningTo(mrCxt);
428 4 : }
429 : };
430 :
431 : }
432 :
433 7 : void ScColumn::SwapNonEmpty(
434 : sc::TableValues& rValues, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt )
435 : {
436 7 : const ScRange& rRange = rValues.getRange();
437 7 : std::vector<SCROW> aBounds;
438 7 : aBounds.push_back(rRange.aStart.Row());
439 7 : if (rRange.aEnd.Row() < MAXROW-1)
440 7 : aBounds.push_back(rRange.aEnd.Row()+1);
441 :
442 : // Split formula cell groups at top and bottom boundaries (if applicable).
443 7 : sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
444 14 : std::vector<sc::CellValueSpan> aSpans = rValues.getNonEmptySpans(nTab, nCol);
445 :
446 : // Detach formula cells within the spans (if any).
447 7 : EndListeningHandler aEndLisFunc(rEndCxt);
448 7 : std::vector<sc::CellValueSpan>::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
449 7 : sc::CellStoreType::iterator itPos = maCells.begin();
450 15 : for (; it != itEnd; ++it)
451 : {
452 8 : SCROW nRow1 = it->mnRow1;
453 8 : SCROW nRow2 = it->mnRow2;
454 8 : itPos = sc::ProcessFormula(itPos, maCells, nRow1, nRow2, aEndLisFunc);
455 : }
456 :
457 7 : rValues.swapNonEmpty(nTab, nCol, *this);
458 7 : RegroupFormulaCells();
459 :
460 : // Attach formula cells within the spans (if any).
461 7 : StartListeningHandler aStartLisFunc(rStartCxt);
462 7 : it = aSpans.begin();
463 7 : itPos = maCells.begin();
464 15 : for (; it != itEnd; ++it)
465 : {
466 8 : SCROW nRow1 = it->mnRow1;
467 8 : SCROW nRow2 = it->mnRow2;
468 8 : itPos = sc::ProcessFormula(itPos, maCells, nRow1, nRow2, aStartLisFunc);
469 : }
470 :
471 14 : CellStorageModified();
472 7 : }
473 :
474 1 : void ScColumn::DeleteRanges( const std::vector<sc::RowSpan>& rRanges, InsertDeleteFlags nDelFlag, bool bBroadcast )
475 : {
476 1 : std::vector<sc::RowSpan>::const_iterator itSpan = rRanges.begin(), itSpanEnd = rRanges.end();
477 2 : for (; itSpan != itSpanEnd; ++itSpan)
478 1 : DeleteArea(itSpan->mnRow1, itSpan->mnRow2, nDelFlag, bBroadcast);
479 1 : }
480 :
481 8 : void ScColumn::CloneFormulaCell(
482 : const ScFormulaCell& rSrc, const sc::CellTextAttr& rAttr,
483 : const std::vector<sc::RowSpan>& rRanges, sc::StartListeningContext* pCxt )
484 : {
485 8 : sc::CellStoreType::iterator itPos = maCells.begin();
486 8 : sc::CellTextAttrStoreType::iterator itAttrPos = maCellTextAttrs.begin();
487 :
488 8 : std::vector<ScFormulaCell*> aFormulas;
489 8 : std::vector<sc::RowSpan>::const_iterator itSpan = rRanges.begin(), itSpanEnd = rRanges.end();
490 16 : for (; itSpan != itSpanEnd; ++itSpan)
491 : {
492 8 : SCROW nRow1 = itSpan->mnRow1, nRow2 = itSpan->mnRow2;
493 8 : size_t nLen = nRow2 - nRow1 + 1;
494 : assert(nLen > 0);
495 8 : aFormulas.clear();
496 8 : aFormulas.reserve(nLen);
497 :
498 8 : ScAddress aPos(nCol, nRow1, nTab);
499 :
500 8 : if (nLen == 1)
501 : {
502 : // Single, ungrouped formula cell.
503 5 : ScFormulaCell* pCell = new ScFormulaCell(rSrc, *pDocument, aPos);
504 5 : if (pCxt)
505 : {
506 0 : pCell->StartListeningTo(*pCxt);
507 0 : pCell->SetDirty();
508 : }
509 5 : aFormulas.push_back(pCell);
510 : }
511 : else
512 : {
513 : // Create a group of formula cells.
514 3 : ScFormulaCellGroupRef xGroup(new ScFormulaCellGroup);
515 3 : xGroup->setCode(*rSrc.GetCode());
516 3 : xGroup->compileCode(*pDocument, aPos, pDocument->GetGrammar());
517 25 : for (size_t i = 0; i < nLen; ++i, aPos.IncRow())
518 : {
519 22 : ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, xGroup, pDocument->GetGrammar(), rSrc.GetMatrixFlag());
520 22 : if (i == 0)
521 : {
522 3 : xGroup->mpTopCell = pCell;
523 3 : xGroup->mnLength = nLen;
524 : }
525 22 : if (pCxt)
526 : {
527 0 : pCell->StartListeningTo(*pCxt);
528 0 : pCell->SetDirty();
529 : }
530 22 : aFormulas.push_back(pCell);
531 3 : }
532 : }
533 :
534 8 : itPos = maCells.set(itPos, nRow1, aFormulas.begin(), aFormulas.end());
535 :
536 : // Join the top and bottom of the pasted formula cells as needed.
537 8 : sc::CellStoreType::position_type aPosObj = maCells.position(itPos, nRow1);
538 :
539 : assert(aPosObj.first->type == sc::element_type_formula);
540 8 : ScFormulaCell* pCell = sc::formula_block::at(*aPosObj.first->data, aPosObj.second);
541 8 : JoinNewFormulaCell(aPosObj, *pCell);
542 :
543 8 : aPosObj = maCells.position(aPosObj.first, nRow2);
544 : assert(aPosObj.first->type == sc::element_type_formula);
545 8 : pCell = sc::formula_block::at(*aPosObj.first->data, aPosObj.second);
546 8 : JoinNewFormulaCell(aPosObj, *pCell);
547 :
548 8 : std::vector<sc::CellTextAttr> aTextAttrs(nLen, rAttr);
549 8 : itAttrPos = maCellTextAttrs.set(itAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
550 8 : }
551 :
552 8 : CellStorageModified();
553 8 : }
554 :
555 21 : ScPostIt* ScColumn::ReleaseNote( SCROW nRow )
556 : {
557 21 : if (!ValidRow(nRow))
558 0 : return NULL;
559 :
560 21 : ScPostIt* p = NULL;
561 21 : maCellNotes.release(nRow, p);
562 21 : return p;
563 : }
564 :
565 1056 : size_t ScColumn::GetNoteCount() const
566 : {
567 1056 : size_t nCount = 0;
568 1056 : sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
569 2146 : for (; it != itEnd; ++it)
570 : {
571 1090 : if (it->type != sc::element_type_cellnote)
572 1073 : continue;
573 :
574 17 : nCount += it->size;
575 : }
576 :
577 1056 : return nCount;
578 : }
579 :
580 : namespace {
581 :
582 : class NoteCaptionCreator
583 : {
584 : ScAddress maPos;
585 : public:
586 34816 : NoteCaptionCreator( SCTAB nTab, SCCOL nCol ) : maPos(nCol,0,nTab) {}
587 :
588 4 : void operator() ( size_t nRow, ScPostIt* p )
589 : {
590 4 : maPos.SetRow(nRow);
591 4 : p->GetOrCreateCaption(maPos);
592 4 : }
593 : };
594 :
595 : struct NoteCaptionCleaner
596 : {
597 10 : void operator() ( size_t /*nRow*/, ScPostIt* p )
598 : {
599 10 : p->ForgetCaption();
600 10 : }
601 : };
602 :
603 : }
604 :
605 34816 : void ScColumn::CreateAllNoteCaptions()
606 : {
607 34816 : NoteCaptionCreator aFunc(nTab, nCol);
608 34816 : sc::ProcessNote(maCellNotes, aFunc);
609 34816 : }
610 :
611 16 : void ScColumn::ForgetNoteCaptions( SCROW nRow1, SCROW nRow2 )
612 : {
613 16 : if (!ValidRow(nRow1) || !ValidRow(nRow2))
614 16 : return;
615 :
616 : NoteCaptionCleaner aFunc;
617 16 : sc::CellNoteStoreType::iterator it = maCellNotes.begin();
618 16 : sc::ProcessNote(it, maCellNotes, nRow1, nRow2, aFunc);
619 : }
620 :
621 6 : SCROW ScColumn::GetNotePosition( size_t nIndex ) const
622 : {
623 : // Return the row position of the nth note in the column.
624 :
625 6 : sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
626 :
627 6 : size_t nCount = 0; // Number of notes encountered so far.
628 12 : for (; it != itEnd; ++it)
629 : {
630 12 : if (it->type != sc::element_type_cellnote)
631 : // Skip the empty blocks.
632 6 : continue;
633 :
634 6 : if (nIndex < nCount + it->size)
635 : {
636 : // Index falls within this block.
637 6 : size_t nOffset = nIndex - nCount;
638 6 : return it->position + nOffset;
639 : }
640 :
641 0 : nCount += it->size;
642 : }
643 :
644 0 : return -1;
645 : }
646 :
647 : namespace {
648 :
649 : class NoteEntryCollector
650 : {
651 : std::vector<sc::NoteEntry>& mrNotes;
652 : SCTAB mnTab;
653 : SCCOL mnCol;
654 : SCROW mnStartRow;
655 : SCROW mnEndRow;
656 : public:
657 314368 : 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 314368 : mnStartRow(nStartRow), mnEndRow(nEndRow) {}
661 :
662 302145 : void operator() (const sc::CellNoteStoreType::value_type& node) const
663 : {
664 302145 : if (node.type != sc::element_type_cellnote)
665 604256 : return;
666 :
667 34 : size_t nTopRow = node.position;
668 34 : sc::cellnote_block::const_iterator it = sc::cellnote_block::begin(*node.data);
669 34 : sc::cellnote_block::const_iterator itEnd = sc::cellnote_block::end(*node.data);
670 34 : size_t nOffset = 0;
671 34 : if(nTopRow < size_t(mnStartRow))
672 : {
673 0 : std::advance(it, mnStartRow - nTopRow);
674 0 : nOffset = mnStartRow - nTopRow;
675 : }
676 :
677 68 : for (; it != itEnd && nTopRow + nOffset <= size_t(mnEndRow);
678 : ++it, ++nOffset)
679 : {
680 34 : ScAddress aPos(mnCol, nTopRow + nOffset, mnTab);
681 34 : mrNotes.push_back(sc::NoteEntry(aPos, *it));
682 : }
683 : }
684 : };
685 :
686 : }
687 :
688 302080 : void ScColumn::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
689 : {
690 302080 : std::for_each(maCellNotes.begin(), maCellNotes.end(), NoteEntryCollector(rNotes, nTab, nCol));
691 302080 : }
692 :
693 12288 : void ScColumn::GetNotesInRange(SCROW nStartRow, SCROW nEndRow,
694 : std::vector<sc::NoteEntry>& rNotes ) const
695 : {
696 12288 : std::pair<sc::CellNoteStoreType::const_iterator,size_t> aPos = maCellNotes.position(nStartRow);
697 12288 : sc::CellNoteStoreType::const_iterator it = aPos.first;
698 12288 : if (it == maCellNotes.end())
699 : // Invalid row number.
700 12288 : return;
701 :
702 : std::pair<sc::CellNoteStoreType::const_iterator,size_t> aEndPos =
703 12288 : maCellNotes.position(nEndRow);
704 12288 : sc::CellNoteStoreType::const_iterator itEnd = aEndPos.first;
705 :
706 12288 : std::for_each(it, itEnd, NoteEntryCollector(rNotes, nTab, nCol, nStartRow, nEndRow));
707 : }
708 :
709 : namespace {
710 :
711 : class RecompileByOpcodeHandler
712 : {
713 : ScDocument* mpDoc;
714 : const formula::unordered_opcode_set& mrOps;
715 : sc::EndListeningContext& mrEndListenCxt;
716 : sc::CompileFormulaContext& mrCompileFormulaCxt;
717 :
718 : public:
719 82944 : 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 82944 : mrCompileFormulaCxt(rCompileCxt) {}
726 :
727 14 : void operator() ( sc::FormulaGroupEntry& rEntry )
728 : {
729 : // Perform end listening, remove from formula tree, and set them up
730 : // for re-compilation.
731 :
732 14 : ScFormulaCell* pTop = NULL;
733 :
734 14 : if (rEntry.mbShared)
735 : {
736 : // Only inspect the code from the top cell.
737 5 : pTop = *rEntry.mpCells;
738 : }
739 : else
740 9 : pTop = rEntry.mpCell;
741 :
742 14 : ScTokenArray* pCode = pTop->GetCode();
743 14 : bool bRecompile = pCode->HasOpCodes(mrOps);
744 :
745 14 : if (bRecompile)
746 : {
747 : // Get the formula string.
748 5 : OUString aFormula = pTop->GetFormula(mrCompileFormulaCxt);
749 5 : sal_Int32 n = aFormula.getLength();
750 5 : if (pTop->GetMatrixFlag() != MM_NONE && n > 0)
751 : {
752 0 : if (aFormula[0] == '{' && aFormula[n-1] == '}')
753 0 : aFormula = aFormula.copy(1, n-2);
754 : }
755 :
756 5 : if (rEntry.mbShared)
757 : {
758 4 : ScFormulaCell** pp = rEntry.mpCells;
759 4 : ScFormulaCell** ppEnd = pp + rEntry.mnLength;
760 16 : for (; pp != ppEnd; ++pp)
761 : {
762 12 : ScFormulaCell* p = *pp;
763 12 : p->EndListeningTo(mrEndListenCxt);
764 12 : mpDoc->RemoveFromFormulaTree(p);
765 : }
766 : }
767 : else
768 : {
769 1 : rEntry.mpCell->EndListeningTo(mrEndListenCxt);
770 1 : mpDoc->RemoveFromFormulaTree(rEntry.mpCell);
771 : }
772 :
773 5 : pCode->Clear();
774 5 : pTop->SetHybridFormula(aFormula, mpDoc->GetGrammar());
775 : }
776 14 : }
777 : };
778 :
779 : class CompileHybridFormulaHandler
780 : {
781 : ScDocument* mpDoc;
782 : sc::StartListeningContext& mrStartListenCxt;
783 : sc::CompileFormulaContext& mrCompileFormulaCxt;
784 :
785 : public:
786 82944 : CompileHybridFormulaHandler( ScDocument* pDoc, sc::StartListeningContext& rStartListenCxt, sc::CompileFormulaContext& rCompileCxt ) :
787 : mpDoc(pDoc),
788 : mrStartListenCxt(rStartListenCxt),
789 82944 : mrCompileFormulaCxt(rCompileCxt) {}
790 :
791 14 : void operator() ( sc::FormulaGroupEntry& rEntry )
792 : {
793 14 : if (rEntry.mbShared)
794 : {
795 5 : ScFormulaCell* pTop = *rEntry.mpCells;
796 5 : OUString aFormula = pTop->GetHybridFormula();
797 :
798 5 : if (!aFormula.isEmpty())
799 : {
800 : // Create a new token array from the hybrid formula string, and
801 : // set it to the group.
802 4 : ScCompiler aComp(mrCompileFormulaCxt, pTop->aPos);
803 4 : ScTokenArray* pNewCode = aComp.CompileString(aFormula);
804 8 : ScFormulaCellGroupRef xGroup = pTop->GetCellGroup();
805 : assert(xGroup);
806 4 : xGroup->setCode(pNewCode);
807 4 : xGroup->compileCode(*mpDoc, pTop->aPos, mpDoc->GetGrammar());
808 :
809 : // Propagate the new token array to all formula cells in the group.
810 4 : ScFormulaCell** pp = rEntry.mpCells;
811 4 : ScFormulaCell** ppEnd = pp + rEntry.mnLength;
812 16 : for (; pp != ppEnd; ++pp)
813 : {
814 12 : ScFormulaCell* p = *pp;
815 12 : p->SyncSharedCode();
816 12 : p->StartListeningTo(mrStartListenCxt);
817 12 : p->SetDirty();
818 4 : }
819 5 : }
820 : }
821 : else
822 : {
823 9 : ScFormulaCell* pCell = rEntry.mpCell;
824 9 : OUString aFormula = pCell->GetHybridFormula();
825 :
826 9 : if (!aFormula.isEmpty())
827 : {
828 : // Create token array from formula string.
829 1 : ScCompiler aComp(mrCompileFormulaCxt, pCell->aPos);
830 1 : ScTokenArray* pNewCode = aComp.CompileString(aFormula);
831 :
832 : // Generate RPN tokens.
833 2 : ScCompiler aComp2(mpDoc, pCell->aPos, *pNewCode);
834 1 : aComp2.CompileTokenArray();
835 :
836 1 : pCell->SetCode(pNewCode);
837 1 : pCell->StartListeningTo(mrStartListenCxt);
838 2 : pCell->SetDirty();
839 9 : }
840 : }
841 14 : }
842 : };
843 :
844 : }
845 :
846 71680 : void ScColumn::PreprocessRangeNameUpdate(
847 : sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt )
848 : {
849 : // Collect all formula groups.
850 71680 : std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
851 :
852 143360 : formula::unordered_opcode_set aOps;
853 71680 : aOps.insert(ocBad);
854 71680 : aOps.insert(ocColRowName);
855 71680 : aOps.insert(ocName);
856 71680 : RecompileByOpcodeHandler aFunc(pDocument, aOps, rEndListenCxt, rCompileCxt);
857 143360 : std::for_each(aGroups.begin(), aGroups.end(), aFunc);
858 71680 : }
859 :
860 11264 : void ScColumn::PreprocessDBDataUpdate(
861 : sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt )
862 : {
863 : // Collect all formula groups.
864 11264 : std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
865 :
866 22528 : formula::unordered_opcode_set aOps;
867 11264 : aOps.insert(ocBad);
868 11264 : aOps.insert(ocColRowName);
869 11264 : aOps.insert(ocDBArea);
870 11264 : aOps.insert(ocTableRef);
871 11264 : RecompileByOpcodeHandler aFunc(pDocument, aOps, rEndListenCxt, rCompileCxt);
872 22528 : std::for_each(aGroups.begin(), aGroups.end(), aFunc);
873 11264 : }
874 :
875 82944 : void ScColumn::CompileHybridFormula(
876 : sc::StartListeningContext& rStartListenCxt, sc::CompileFormulaContext& rCompileCxt )
877 : {
878 : // Collect all formula groups.
879 82944 : std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
880 :
881 82944 : CompileHybridFormulaHandler aFunc(pDocument, rStartListenCxt, rCompileCxt);
882 82944 : std::for_each(aGroups.begin(), aGroups.end(), aFunc);
883 82944 : }
884 :
885 : namespace {
886 :
887 : class ScriptTypeUpdater
888 : {
889 : ScColumn& mrCol;
890 : sc::CellTextAttrStoreType& mrTextAttrs;
891 : sc::CellTextAttrStoreType::iterator miPosAttr;
892 : ScConditionalFormatList* mpCFList;
893 : SvNumberFormatter* mpFormatter;
894 : ScAddress maPos;
895 : bool mbUpdated;
896 :
897 : private:
898 560 : void updateScriptType( size_t nRow, ScRefCellValue& rCell )
899 : {
900 560 : sc::CellTextAttrStoreType::position_type aAttrPos = mrTextAttrs.position(miPosAttr, nRow);
901 560 : miPosAttr = aAttrPos.first;
902 :
903 560 : if (aAttrPos.first->type != sc::element_type_celltextattr)
904 180 : return;
905 :
906 560 : sc::CellTextAttr& rAttr = sc::celltextattr_block::at(*aAttrPos.first->data, aAttrPos.second);
907 560 : if (rAttr.mnScriptType != SvtScriptType::UNKNOWN)
908 : // Script type already deteremined. Skip it.
909 180 : return;
910 :
911 380 : const ScPatternAttr* pPat = mrCol.GetPattern(nRow);
912 380 : if (!pPat)
913 : // In theory this should never return NULL. But let's be safe.
914 0 : return;
915 :
916 380 : const SfxItemSet* pCondSet = NULL;
917 380 : if (mpCFList)
918 : {
919 380 : maPos.SetRow(nRow);
920 : const ScCondFormatItem& rItem =
921 380 : static_cast<const ScCondFormatItem&>(pPat->GetItem(ATTR_CONDITIONAL));
922 380 : const std::vector<sal_uInt32>& rData = rItem.GetCondFormatData();
923 380 : pCondSet = mrCol.GetDoc().GetCondResult(rCell, maPos, *mpCFList, rData);
924 : }
925 :
926 380 : OUString aStr;
927 : Color* pColor;
928 380 : sal_uLong nFormat = pPat->GetNumberFormat(mpFormatter, pCondSet);
929 380 : ScCellFormat::GetString(rCell, nFormat, aStr, &pColor, *mpFormatter, &mrCol.GetDoc());
930 :
931 380 : rAttr.mnScriptType = mrCol.GetDoc().GetStringScriptType(aStr);
932 380 : mbUpdated = true;
933 : }
934 :
935 : public:
936 17504 : ScriptTypeUpdater( ScColumn& rCol ) :
937 : mrCol(rCol),
938 17504 : mrTextAttrs(rCol.GetCellAttrStore()),
939 : miPosAttr(mrTextAttrs.begin()),
940 17504 : mpCFList(rCol.GetDoc().GetCondFormList(rCol.GetTab())),
941 17504 : mpFormatter(rCol.GetDoc().GetFormatTable()),
942 35008 : maPos(rCol.GetCol(), 0, rCol.GetTab()),
943 105024 : mbUpdated(false)
944 17504 : {}
945 :
946 250 : void operator() ( size_t nRow, double fVal )
947 : {
948 250 : ScRefCellValue aCell(fVal);
949 250 : updateScriptType(nRow, aCell);
950 250 : }
951 :
952 128 : void operator() ( size_t nRow, const svl::SharedString& rStr )
953 : {
954 128 : ScRefCellValue aCell(&rStr);
955 128 : updateScriptType(nRow, aCell);
956 128 : }
957 :
958 0 : void operator() ( size_t nRow, const EditTextObject* pText )
959 : {
960 0 : ScRefCellValue aCell(pText);
961 0 : updateScriptType(nRow, aCell);
962 0 : }
963 :
964 182 : void operator() ( size_t nRow, const ScFormulaCell* pCell )
965 : {
966 182 : ScRefCellValue aCell(const_cast<ScFormulaCell*>(pCell));
967 182 : updateScriptType(nRow, aCell);
968 182 : }
969 :
970 17504 : bool isUpdated() const { return mbUpdated; }
971 : };
972 :
973 : }
974 :
975 17504 : void ScColumn::UpdateScriptTypes( SCROW nRow1, SCROW nRow2 )
976 : {
977 17504 : if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
978 17504 : return;
979 :
980 17504 : ScriptTypeUpdater aFunc(*this);
981 17504 : sc::ParseAllNonEmpty(maCells.begin(), maCells, nRow1, nRow2, aFunc);
982 17504 : if (aFunc.isUpdated())
983 142 : CellStorageModified();
984 : }
985 :
986 18 : void ScColumn::Swap( ScColumn& rOther, SCROW nRow1, SCROW nRow2, bool bPattern )
987 : {
988 18 : maCells.swap(nRow1, nRow2, rOther.maCells, nRow1);
989 18 : maCellTextAttrs.swap(nRow1, nRow2, rOther.maCellTextAttrs, nRow1);
990 18 : maCellNotes.swap(nRow1, nRow2, rOther.maCellNotes, nRow1);
991 18 : maBroadcasters.swap(nRow1, nRow2, rOther.maBroadcasters, nRow1);
992 :
993 18 : if (bPattern)
994 : {
995 43 : for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
996 : {
997 25 : const ScPatternAttr* pPat1 = GetPattern(nRow);
998 25 : const ScPatternAttr* pPat2 = rOther.GetPattern(nRow);
999 25 : if (pPat1 != pPat2)
1000 : {
1001 0 : SetPattern(nRow, *pPat2, true);
1002 0 : rOther.SetPattern(nRow, *pPat1, true);
1003 : }
1004 : }
1005 : }
1006 :
1007 18 : CellStorageModified();
1008 18 : rOther.CellStorageModified();
1009 18 : }
1010 :
1011 : namespace {
1012 :
1013 : class FormulaColPosSetter
1014 : {
1015 : SCCOL mnCol;
1016 : bool mbUpdateRefs;
1017 : public:
1018 38 : FormulaColPosSetter( SCCOL nCol, bool bUpdateRefs ) : mnCol(nCol), mbUpdateRefs(bUpdateRefs) {}
1019 :
1020 3 : void operator() ( size_t nRow, ScFormulaCell* pCell )
1021 : {
1022 3 : if (!pCell->IsShared() || pCell->IsSharedTop())
1023 : {
1024 : // Ensure that the references still point to the same locations
1025 : // after the position change.
1026 1 : ScAddress aOldPos = pCell->aPos;
1027 1 : pCell->aPos.SetCol(mnCol);
1028 1 : pCell->aPos.SetRow(nRow);
1029 1 : if (mbUpdateRefs)
1030 1 : pCell->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, pCell->aPos);
1031 : else
1032 0 : pCell->GetCode()->AdjustReferenceOnMovedOriginIfOtherSheet(aOldPos, pCell->aPos);
1033 : }
1034 : else
1035 : {
1036 2 : pCell->aPos.SetCol(mnCol);
1037 2 : pCell->aPos.SetRow(nRow);
1038 : }
1039 3 : }
1040 : };
1041 :
1042 : }
1043 :
1044 38 : void ScColumn::ResetFormulaCellPositions( SCROW nRow1, SCROW nRow2, bool bUpdateRefs )
1045 : {
1046 38 : FormulaColPosSetter aFunc(nCol, bUpdateRefs);
1047 38 : sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
1048 38 : }
1049 :
1050 : namespace {
1051 :
1052 38 : class RelativeRefBoundChecker
1053 : {
1054 : std::vector<SCROW> maBounds;
1055 : ScRange maBoundRange;
1056 :
1057 : public:
1058 38 : RelativeRefBoundChecker( const ScRange& rBoundRange ) :
1059 38 : maBoundRange(rBoundRange) {}
1060 :
1061 3 : void operator() ( size_t /*nRow*/, ScFormulaCell* pCell )
1062 : {
1063 3 : if (!pCell->IsSharedTop())
1064 5 : return;
1065 :
1066 : pCell->GetCode()->CheckRelativeReferenceBounds(
1067 1 : pCell->aPos, pCell->GetSharedLength(), maBoundRange, maBounds);
1068 : }
1069 :
1070 38 : void swapBounds( std::vector<SCROW>& rBounds )
1071 : {
1072 38 : rBounds.swap(maBounds);
1073 38 : }
1074 : };
1075 :
1076 : }
1077 :
1078 38 : void ScColumn::SplitFormulaGroupByRelativeRef( const ScRange& rBoundRange )
1079 : {
1080 38 : if (rBoundRange.aStart.Row() >= MAXROW)
1081 : // Nothing to split.
1082 38 : return;
1083 :
1084 38 : std::vector<SCROW> aBounds;
1085 :
1086 : // Cut at row boundaries first.
1087 38 : aBounds.push_back(rBoundRange.aStart.Row());
1088 38 : if (rBoundRange.aEnd.Row() < MAXROW)
1089 38 : aBounds.push_back(rBoundRange.aEnd.Row()+1);
1090 38 : sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
1091 :
1092 76 : RelativeRefBoundChecker aFunc(rBoundRange);
1093 : sc::ProcessFormula(
1094 38 : maCells.begin(), maCells, rBoundRange.aStart.Row(), rBoundRange.aEnd.Row(), aFunc);
1095 38 : aFunc.swapBounds(aBounds);
1096 76 : sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
1097 : }
1098 :
1099 : namespace {
1100 :
1101 : class ListenerCollector
1102 : {
1103 : std::vector<SvtListener*>& mrListeners;
1104 : public:
1105 158 : ListenerCollector( std::vector<SvtListener*>& rListener ) :
1106 158 : mrListeners(rListener) {}
1107 :
1108 141 : void operator() ( size_t /*nRow*/, SvtBroadcaster* p )
1109 : {
1110 141 : SvtBroadcaster::ListenersType& rLis = p->GetAllListeners();
1111 141 : std::copy(rLis.begin(), rLis.end(), std::back_inserter(mrListeners));
1112 141 : }
1113 : };
1114 :
1115 : class FormulaCellCollector
1116 : {
1117 : std::vector<ScFormulaCell*>& mrCells;
1118 : public:
1119 4 : FormulaCellCollector( std::vector<ScFormulaCell*>& rCells ) : mrCells(rCells) {}
1120 :
1121 20 : void operator() ( size_t /*nRow*/, ScFormulaCell* p )
1122 : {
1123 20 : mrCells.push_back(p);
1124 20 : }
1125 : };
1126 :
1127 : }
1128 :
1129 158 : void ScColumn::CollectListeners( std::vector<SvtListener*>& rListeners, SCROW nRow1, SCROW nRow2 )
1130 : {
1131 158 : if (nRow2 < nRow1 || !ValidRow(nRow1) || !ValidRow(nRow2))
1132 158 : return;
1133 :
1134 158 : ListenerCollector aFunc(rListeners);
1135 158 : sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
1136 : }
1137 :
1138 4 : void ScColumn::CollectFormulaCells( std::vector<ScFormulaCell*>& rCells, SCROW nRow1, SCROW nRow2 )
1139 : {
1140 4 : if (nRow2 < nRow1 || !ValidRow(nRow1) || !ValidRow(nRow2))
1141 4 : return;
1142 :
1143 4 : FormulaCellCollector aFunc(rCells);
1144 4 : sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
1145 : }
1146 :
1147 : namespace {
1148 :
1149 : struct FindAnyFormula
1150 : {
1151 0 : bool operator() ( size_t /*nRow*/, const ScFormulaCell* /*pCell*/ ) const
1152 : {
1153 0 : return true;
1154 : }
1155 : };
1156 :
1157 : }
1158 :
1159 0 : bool ScColumn::HasFormulaCell( SCROW nRow1, SCROW nRow2 ) const
1160 : {
1161 0 : if (nRow2 < nRow1 || !ValidRow(nRow1) || !ValidRow(nRow2))
1162 0 : return false;
1163 :
1164 : FindAnyFormula aFunc;
1165 : std::pair<sc::CellStoreType::const_iterator, size_t> aRet =
1166 0 : sc::FindFormula(maCells, nRow1, nRow2, aFunc);
1167 :
1168 0 : return aRet.first != maCells.end();
1169 : }
1170 :
1171 : namespace {
1172 :
1173 79 : void endListening( sc::EndListeningContext& rCxt, ScFormulaCell** pp, ScFormulaCell** ppEnd )
1174 : {
1175 330 : for (; pp != ppEnd; ++pp)
1176 : {
1177 251 : ScFormulaCell& rFC = **pp;
1178 251 : rFC.EndListeningTo(rCxt);
1179 : }
1180 79 : }
1181 :
1182 : class StartListeningFormulaCellsHandler
1183 : {
1184 : sc::StartListeningContext& mrStartCxt;
1185 : sc::EndListeningContext& mrEndCxt;
1186 : SCROW mnStartRow;
1187 : SCROW mnEndRow;
1188 :
1189 : public:
1190 41778 : StartListeningFormulaCellsHandler( sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ) :
1191 41778 : mrStartCxt(rStartCxt), mrEndCxt(rEndCxt), mnStartRow(-1), mnEndRow(-1) {}
1192 :
1193 43018 : void operator() ( const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize )
1194 : {
1195 43018 : if (node.type != sc::element_type_formula)
1196 : // We are only interested in formulas.
1197 85701 : return;
1198 :
1199 335 : mnStartRow = node.position + nOffset;
1200 :
1201 335 : ScFormulaCell** ppBeg = &sc::formula_block::at(*node.data, nOffset);
1202 335 : ScFormulaCell** ppEnd = ppBeg + nDataSize;
1203 :
1204 335 : ScFormulaCell** pp = ppBeg;
1205 :
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.
1209 :
1210 335 : ScFormulaCell* pFC = *pp;
1211 335 : if (pFC->IsShared() && !pFC->IsSharedTop())
1212 : {
1213 78 : SCROW nBackTrackSize = pFC->aPos.Row() - pFC->GetSharedTopRow();
1214 78 : if (nBackTrackSize > 0)
1215 : {
1216 : assert(static_cast<size_t>(nBackTrackSize) <= nOffset);
1217 318 : for (SCROW i = 0; i < nBackTrackSize; ++i)
1218 240 : --pp;
1219 78 : endListening(mrEndCxt, pp, ppBeg);
1220 78 : mnStartRow -= nBackTrackSize;
1221 : }
1222 : }
1223 :
1224 717 : for (; pp != ppEnd; ++pp)
1225 : {
1226 382 : pFC = *pp;
1227 :
1228 382 : if (!pFC->IsSharedTop())
1229 : {
1230 : assert(!pFC->IsShared());
1231 229 : pFC->StartListeningTo(mrStartCxt);
1232 229 : continue;
1233 : }
1234 :
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 153 : size_t nEndGroupPos = (pp - ppBeg) + pFC->GetSharedLength();
1239 153 : mnEndRow = node.position + nOffset + nEndGroupPos - 1; // absolute row position of the last one in the group.
1240 153 : if (nEndGroupPos > nDataSize)
1241 : {
1242 0 : size_t nExcessSize = nEndGroupPos - nDataSize;
1243 0 : ScFormulaCell** ppGrpEnd = pp + pFC->GetSharedLength();
1244 0 : ScFormulaCell** ppGrp = ppGrpEnd - nExcessSize;
1245 0 : endListening(mrEndCxt, ppGrp, ppGrpEnd);
1246 :
1247 : // Register formula cells as a group.
1248 0 : sc::SharedFormulaUtil::startListeningAsGroup(mrStartCxt, pp);
1249 0 : pp = ppEnd - 1; // Move to the one before the end position.
1250 : }
1251 : else
1252 : {
1253 : // Register formula cells as a group.
1254 153 : sc::SharedFormulaUtil::startListeningAsGroup(mrStartCxt, pp);
1255 153 : pp += pFC->GetSharedLength() - 1; // Move to the last one in the group.
1256 : }
1257 : }
1258 : }
1259 :
1260 0 : SCROW getStartRow() const
1261 : {
1262 0 : return mnStartRow;
1263 : }
1264 :
1265 0 : SCROW getEndRow() const
1266 : {
1267 0 : return mnEndRow;
1268 : }
1269 : };
1270 :
1271 : class EndListeningFormulaCellsHandler
1272 : {
1273 : sc::EndListeningContext& mrEndCxt;
1274 : SCROW mnStartRow;
1275 : SCROW mnEndRow;
1276 :
1277 : public:
1278 1 : EndListeningFormulaCellsHandler( sc::EndListeningContext& rEndCxt ) :
1279 1 : mrEndCxt(rEndCxt), mnStartRow(-1), mnEndRow(-1) {}
1280 :
1281 1 : void operator() ( const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize )
1282 : {
1283 1 : if (node.type != sc::element_type_formula)
1284 : // We are only interested in formulas.
1285 1 : return;
1286 :
1287 1 : mnStartRow = node.position + nOffset;
1288 :
1289 1 : ScFormulaCell** ppBeg = &sc::formula_block::at(*node.data, nOffset);
1290 1 : ScFormulaCell** ppEnd = ppBeg + nDataSize;
1291 :
1292 1 : ScFormulaCell** pp = ppBeg;
1293 :
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.
1296 :
1297 1 : ScFormulaCell* pFC = *pp;
1298 1 : if (pFC->IsShared() && !pFC->IsSharedTop())
1299 : {
1300 0 : SCROW nBackTrackSize = pFC->aPos.Row() - pFC->GetSharedTopRow();
1301 0 : if (nBackTrackSize > 0)
1302 : {
1303 : assert(static_cast<size_t>(nBackTrackSize) <= nOffset);
1304 0 : for (SCROW i = 0; i < nBackTrackSize; ++i)
1305 0 : --pp;
1306 0 : mnStartRow -= nBackTrackSize;
1307 : }
1308 : }
1309 :
1310 2 : for (; pp != ppEnd; ++pp)
1311 : {
1312 1 : pFC = *pp;
1313 :
1314 1 : if (!pFC->IsSharedTop())
1315 : {
1316 : assert(!pFC->IsShared());
1317 0 : pFC->EndListeningTo(mrEndCxt);
1318 0 : continue;
1319 : }
1320 :
1321 1 : size_t nEndGroupPos = (pp - ppBeg) + pFC->GetSharedLength();
1322 1 : mnEndRow = node.position + nOffset + nEndGroupPos - 1; // absolute row position of the last one in the group.
1323 :
1324 1 : ScFormulaCell** ppGrpEnd = pp + pFC->GetSharedLength();
1325 1 : endListening(mrEndCxt, pp, ppGrpEnd);
1326 :
1327 1 : if (nEndGroupPos > nDataSize)
1328 : {
1329 : // The group goes beyond the specified end row. Move to the
1330 : // one before the end position to finish the loop.
1331 1 : pp = ppEnd - 1;
1332 : }
1333 : else
1334 : {
1335 : // Move to the last one in the group.
1336 0 : pp += pFC->GetSharedLength() - 1;
1337 : }
1338 : }
1339 : }
1340 :
1341 1 : SCROW getStartRow() const
1342 : {
1343 1 : return mnStartRow;
1344 : }
1345 :
1346 1 : SCROW getEndRow() const
1347 : {
1348 1 : return mnEndRow;
1349 : }
1350 : };
1351 :
1352 : }
1353 :
1354 41778 : void ScColumn::StartListeningFormulaCells(
1355 : sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt,
1356 : SCROW nRow1, SCROW nRow2, SCROW* pStartRow, SCROW* pEndRow )
1357 : {
1358 41778 : StartListeningFormulaCellsHandler aFunc(rStartCxt, rEndCxt);
1359 41778 : sc::ProcessBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1360 :
1361 41778 : if (pStartRow)
1362 : // start row position may be smaller than nRow1 in case the formula
1363 : // group starts before nRow1 position.
1364 0 : *pStartRow = aFunc.getStartRow();
1365 :
1366 41778 : 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 0 : *pEndRow = aFunc.getEndRow();
1370 41778 : }
1371 :
1372 1 : void ScColumn::EndListeningFormulaCells(
1373 : sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2,
1374 : SCROW* pStartRow, SCROW* pEndRow )
1375 : {
1376 1 : EndListeningFormulaCellsHandler aFunc(rCxt);
1377 1 : sc::ProcessBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
1378 :
1379 1 : if (pStartRow)
1380 1 : *pStartRow = aFunc.getStartRow();
1381 :
1382 1 : if (pEndRow)
1383 1 : *pEndRow = aFunc.getEndRow();
1384 1 : }
1385 :
1386 36 : void ScColumn::EndListeningIntersectedGroup(
1387 : sc::EndListeningContext& rCxt, SCROW nRow, std::vector<ScAddress>* pGroupPos )
1388 : {
1389 36 : if (!ValidRow(nRow))
1390 0 : return;
1391 :
1392 36 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
1393 36 : sc::CellStoreType::iterator it = aPos.first;
1394 36 : if (it->type != sc::element_type_formula)
1395 : // Only interested in a formula block.
1396 0 : return;
1397 :
1398 36 : ScFormulaCell* pFC = sc::formula_block::at(*it->data, aPos.second);
1399 36 : ScFormulaCellGroupRef xGroup = pFC->GetCellGroup();
1400 36 : if (!xGroup)
1401 : // Not a formula group.
1402 0 : return;
1403 :
1404 : // End listening.
1405 36 : pFC->EndListeningTo(rCxt);
1406 :
1407 36 : if (pGroupPos)
1408 : {
1409 36 : if (!pFC->IsSharedTop())
1410 : // Record the position of the top cell of the group.
1411 20 : pGroupPos->push_back(xGroup->mpTopCell->aPos);
1412 :
1413 36 : SCROW nGrpLastRow = pFC->GetSharedTopRow() + pFC->GetSharedLength() - 1;
1414 36 : if (nRow < nGrpLastRow)
1415 : // Record the last position of the group.
1416 33 : pGroupPos->push_back(ScAddress(nCol, nGrpLastRow, nTab));
1417 36 : }
1418 : }
1419 :
1420 72621 : void ScColumn::EndListeningIntersectedGroups(
1421 : sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2, std::vector<ScAddress>* pGroupPos )
1422 : {
1423 : // Only end the intersected group.
1424 72621 : sc::CellStoreType::position_type aPos = maCells.position(nRow1);
1425 72621 : sc::CellStoreType::iterator it = aPos.first;
1426 72621 : if (it->type == sc::element_type_formula)
1427 : {
1428 33 : ScFormulaCell* pFC = sc::formula_block::at(*it->data, aPos.second);
1429 33 : ScFormulaCellGroupRef xGroup = pFC->GetCellGroup();
1430 33 : if (xGroup && !pFC->IsSharedTop())
1431 : {
1432 : // End listening.
1433 7 : pFC->EndListeningTo(rCxt);
1434 7 : if (pGroupPos)
1435 : // Record the position of the top cell of the group.
1436 7 : pGroupPos->push_back(xGroup->mpTopCell->aPos);
1437 33 : }
1438 : }
1439 :
1440 72621 : aPos = maCells.position(it, nRow2);
1441 72621 : it = aPos.first;
1442 72621 : if (it->type == sc::element_type_formula)
1443 : {
1444 17 : ScFormulaCell* pFC = sc::formula_block::at(*it->data, aPos.second);
1445 17 : ScFormulaCellGroupRef xGroup = pFC->GetCellGroup();
1446 17 : if (xGroup && !pFC->IsSharedTop())
1447 : {
1448 : // End listening.
1449 6 : pFC->EndListeningTo(rCxt);
1450 6 : if (pGroupPos)
1451 : {
1452 : // Record the position of the bottom cell of the group.
1453 6 : ScAddress aPosLast = xGroup->mpTopCell->aPos;
1454 6 : aPosLast.IncRow(xGroup->mnLength-1);
1455 6 : pGroupPos->push_back(aPosLast);
1456 : }
1457 17 : }
1458 : }
1459 72621 : }
1460 :
1461 6 : void ScColumn::EndListeningGroup( sc::EndListeningContext& rCxt, SCROW nRow )
1462 : {
1463 6 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
1464 6 : if (aPos.first->type != sc::element_type_formula)
1465 : // not a formula cell.
1466 0 : return;
1467 :
1468 6 : ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second);
1469 :
1470 6 : ScFormulaCellGroupRef xGroup = (*pp)->GetCellGroup();
1471 6 : if (!xGroup)
1472 : {
1473 : // not a formula group.
1474 0 : (*pp)->EndListeningTo(rCxt);
1475 0 : return;
1476 : }
1477 :
1478 : // Move back to the top cell.
1479 6 : SCROW nTopDelta = (*pp)->aPos.Row() - xGroup->mpTopCell->aPos.Row();
1480 : assert(nTopDelta >= 0);
1481 6 : if (nTopDelta > 0)
1482 6 : pp -= nTopDelta;
1483 :
1484 : // Set the needs listening flag to all cells in the group.
1485 : assert(*pp == xGroup->mpTopCell);
1486 6 : ScFormulaCell** ppEnd = pp + xGroup->mnLength;
1487 34 : for (; pp != ppEnd; ++pp)
1488 34 : (*pp)->EndListeningTo(rCxt);
1489 : }
1490 :
1491 72 : void ScColumn::SetNeedsListeningGroup( SCROW nRow )
1492 : {
1493 72 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
1494 72 : if (aPos.first->type != sc::element_type_formula)
1495 : // not a formula cell.
1496 14 : return;
1497 :
1498 70 : ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second);
1499 :
1500 70 : ScFormulaCellGroupRef xGroup = (*pp)->GetCellGroup();
1501 70 : if (!xGroup)
1502 : {
1503 : // not a formula group.
1504 10 : (*pp)->SetNeedsListening(true);
1505 10 : return;
1506 : }
1507 :
1508 : // Move back to the top cell.
1509 60 : SCROW nTopDelta = (*pp)->aPos.Row() - xGroup->mpTopCell->aPos.Row();
1510 : assert(nTopDelta >= 0);
1511 60 : if (nTopDelta > 0)
1512 38 : pp -= nTopDelta;
1513 :
1514 : // Set the needs listening flag to all cells in the group.
1515 : assert(*pp == xGroup->mpTopCell);
1516 60 : ScFormulaCell** ppEnd = pp + xGroup->mnLength;
1517 462 : for (; pp != ppEnd; ++pp)
1518 462 : (*pp)->SetNeedsListening(true);
1519 156 : }
1520 :
1521 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|