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 <clipcontext.hxx>
12 : #include <clipparam.hxx>
13 : #include <cellvalue.hxx>
14 : #include <attarray.hxx>
15 : #include <document.hxx>
16 : #include <cellvalues.hxx>
17 : #include <columnspanset.hxx>
18 : #include <listenercontext.hxx>
19 : #include <tokenstringcontext.hxx>
20 : #include <mtvcellfunc.hxx>
21 : #include <clipcontext.hxx>
22 : #include <attrib.hxx>
23 : #include <patattr.hxx>
24 : #include <docpool.hxx>
25 : #include <conditio.hxx>
26 : #include <formulagroup.hxx>
27 : #include <tokenarray.hxx>
28 :
29 : #include <svl/sharedstringpool.hxx>
30 :
31 : #include <vector>
32 : #include <cassert>
33 :
34 : #include <boost/shared_ptr.hpp>
35 :
36 0 : bool ScColumn::IsMerged( SCROW nRow ) const
37 : {
38 0 : return pAttrArray->IsMerged(nRow);
39 : }
40 :
41 0 : void ScColumn::DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScColumn& rClipCol )
42 : {
43 0 : sc::CopyFromClipContext::Range aRange = rCxt.getDestRange();
44 0 : if (!ValidRow(aRange.mnRow1) || !ValidRow(aRange.mnRow2))
45 0 : return;
46 :
47 0 : ScRange aClipRange = rCxt.getClipDoc()->GetClipParam().getWholeRange();
48 0 : SCROW nClipRow1 = aClipRange.aStart.Row();
49 0 : SCROW nClipRow2 = aClipRange.aEnd.Row();
50 0 : SCROW nClipRowLen = nClipRow2 - nClipRow1 + 1;
51 :
52 : // Check for non-empty cell ranges in the clip column.
53 0 : sc::SingleColumnSpanSet aSpanSet;
54 0 : aSpanSet.scan(rClipCol, nClipRow1, nClipRow2);
55 0 : sc::SingleColumnSpanSet::SpansType aSpans;
56 0 : aSpanSet.getSpans(aSpans);
57 :
58 : // Translate the clip column spans into the destination column, and repeat as needed.
59 0 : std::vector<sc::RowSpan> aDestSpans;
60 0 : SCROW nDestOffset = aRange.mnRow1 - nClipRow1;
61 0 : bool bContinue = true;
62 0 : while (bContinue)
63 : {
64 0 : sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
65 0 : for (; it != itEnd && bContinue; ++it)
66 : {
67 0 : const sc::RowSpan& r = *it;
68 0 : SCROW nDestRow1 = r.mnRow1 + nDestOffset;
69 0 : SCROW nDestRow2 = r.mnRow2 + nDestOffset;
70 :
71 0 : if (nDestRow1 > aRange.mnRow2)
72 : {
73 : // We're done.
74 0 : bContinue = false;
75 0 : continue;
76 : }
77 :
78 0 : if (nDestRow2 > aRange.mnRow2)
79 : {
80 : // Truncate this range, and set it as the last span.
81 0 : nDestRow2 = aRange.mnRow2;
82 0 : bContinue = false;
83 : }
84 :
85 0 : aDestSpans.push_back(sc::RowSpan(nDestRow1, nDestRow2));
86 : }
87 :
88 0 : nDestOffset += nClipRowLen;
89 : }
90 :
91 0 : std::vector<SCROW> aDeletedRows;
92 0 : sal_uInt16 nDelFlag = rCxt.getDeleteFlag();
93 0 : sc::ColumnBlockPosition aBlockPos;
94 0 : InitBlockPosition(aBlockPos);
95 :
96 0 : std::vector<sc::RowSpan>::const_iterator it = aDestSpans.begin(), itEnd = aDestSpans.end();
97 0 : for (; it != itEnd; ++it)
98 : {
99 0 : SCROW nRow1 = it->mnRow1;
100 0 : SCROW nRow2 = it->mnRow2;
101 :
102 0 : if (nDelFlag & IDF_CONTENTS)
103 0 : DeleteCells(aBlockPos, nRow1, nRow2, nDelFlag, aDeletedRows);
104 :
105 0 : if (nDelFlag & IDF_NOTE)
106 0 : DeleteCellNotes(aBlockPos, nRow1, nRow2);
107 :
108 0 : if (nDelFlag & IDF_EDITATTR)
109 0 : RemoveEditAttribs(nRow1, nRow2);
110 :
111 : // Delete attributes just now
112 0 : if (nDelFlag & IDF_ATTRIB)
113 : {
114 0 : pAttrArray->DeleteArea(nRow1, nRow2);
115 :
116 0 : if (rCxt.isTableProtected())
117 : {
118 0 : ScPatternAttr aPattern(pDocument->GetPool());
119 0 : aPattern.GetItemSet().Put(ScProtectionAttr(false));
120 0 : ApplyPatternArea(nRow1, nRow2, aPattern);
121 : }
122 :
123 0 : ScConditionalFormatList* pCondList = rCxt.getCondFormatList();
124 0 : if (pCondList)
125 0 : pCondList->DeleteArea(nCol, nRow1, nCol, nRow2);
126 : }
127 0 : else if ((nDelFlag & IDF_HARDATTR) == IDF_HARDATTR)
128 0 : pAttrArray->DeleteHardAttr(nRow1, nRow2);
129 : }
130 :
131 0 : BroadcastCells(aDeletedRows, SC_HINT_DATACHANGED);
132 : }
133 :
134 0 : void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2 )
135 : {
136 : assert(nRow1 <= nRow2);
137 :
138 0 : size_t nDestSize = nRow2 - nRow1 + 1;
139 0 : sc::ColumnBlockPosition* pBlockPos = rCxt.getBlockPosition(nTab, nCol);
140 0 : if (!pBlockPos)
141 0 : return;
142 :
143 0 : ScCellValue& rSrcCell = rCxt.getSingleCell();
144 :
145 0 : sal_uInt16 nFlags = rCxt.getInsertFlag();
146 :
147 0 : if ((nFlags & IDF_ATTRIB) != 0)
148 : {
149 0 : if (!rCxt.isSkipAttrForEmptyCells() || rSrcCell.meType != CELLTYPE_NONE)
150 : {
151 0 : const ScPatternAttr* pAttr = rCxt.getSingleCellPattern();
152 0 : pAttrArray->SetPatternArea(nRow1, nRow2, pAttr, true);
153 : }
154 : }
155 :
156 0 : if ((nFlags & IDF_CONTENTS) != 0)
157 : {
158 0 : std::vector<sc::CellTextAttr> aTextAttrs(nDestSize);
159 :
160 0 : switch (rSrcCell.meType)
161 : {
162 : case CELLTYPE_VALUE:
163 : {
164 0 : std::vector<double> aVals(nDestSize, rSrcCell.mfValue);
165 0 : pBlockPos->miCellPos =
166 0 : maCells.set(pBlockPos->miCellPos, nRow1, aVals.begin(), aVals.end());
167 0 : pBlockPos->miCellTextAttrPos =
168 0 : maCellTextAttrs.set(pBlockPos->miCellTextAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
169 0 : CellStorageModified();
170 : }
171 0 : break;
172 : case CELLTYPE_STRING:
173 : {
174 : // Compare the ScDocumentPool* to determine if we are copying within the
175 : // same document. If not, re-intern shared strings.
176 0 : svl::SharedStringPool* pSharedStringPool = (rCxt.getClipDoc()->GetPool() != pDocument->GetPool()) ?
177 0 : &pDocument->GetSharedStringPool() : NULL;
178 : svl::SharedString aStr = (pSharedStringPool ?
179 : pSharedStringPool->intern( rSrcCell.mpString->getString()) :
180 0 : *rSrcCell.mpString);
181 :
182 0 : std::vector<svl::SharedString> aStrs(nDestSize, aStr);
183 0 : pBlockPos->miCellPos =
184 0 : maCells.set(pBlockPos->miCellPos, nRow1, aStrs.begin(), aStrs.end());
185 0 : pBlockPos->miCellTextAttrPos =
186 0 : maCellTextAttrs.set(pBlockPos->miCellTextAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
187 0 : CellStorageModified();
188 : }
189 0 : break;
190 : case CELLTYPE_EDIT:
191 : {
192 0 : std::vector<EditTextObject*> aStrs;
193 0 : aStrs.reserve(nDestSize);
194 0 : for (size_t i = 0; i < nDestSize; ++i)
195 0 : aStrs.push_back(rSrcCell.mpEditText->Clone());
196 :
197 0 : pBlockPos->miCellPos =
198 0 : maCells.set(pBlockPos->miCellPos, nRow1, aStrs.begin(), aStrs.end());
199 0 : pBlockPos->miCellTextAttrPos =
200 0 : maCellTextAttrs.set(pBlockPos->miCellTextAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
201 0 : CellStorageModified();
202 : }
203 0 : break;
204 : case CELLTYPE_FORMULA:
205 : {
206 0 : std::vector<sc::RowSpan> aRanges;
207 0 : aRanges.reserve(1);
208 0 : aRanges.push_back(sc::RowSpan(nRow1, nRow2));
209 0 : CloneFormulaCell(*rSrcCell.mpFormula, aRanges);
210 : }
211 0 : break;
212 : default:
213 : ;
214 0 : }
215 : }
216 :
217 0 : const ScPostIt* pNote = rCxt.getSingleCellNote();
218 0 : if (pNote && (nFlags & (IDF_NOTE | IDF_ADDNOTES)) != 0)
219 : {
220 : // Duplicate the cell note over the whole pasted range.
221 :
222 0 : ScDocument* pClipDoc = rCxt.getClipDoc();
223 0 : const ScAddress& rSrcPos = pClipDoc->GetClipParam().getWholeRange().aStart;
224 0 : std::vector<ScPostIt*> aNotes;
225 0 : ScAddress aDestPos(nCol, nRow1, nTab);
226 0 : aNotes.reserve(nDestSize);
227 0 : for (size_t i = 0; i < nDestSize; ++i)
228 : {
229 0 : bool bCloneCaption = (nFlags & IDF_NOCAPTIONS) == 0;
230 0 : aNotes.push_back(pNote->Clone(rSrcPos, *pDocument, aDestPos, bCloneCaption));
231 0 : aDestPos.IncRow();
232 : }
233 :
234 0 : pBlockPos->miCellNotePos =
235 : maCellNotes.set(
236 0 : pBlockPos->miCellNotePos, nRow1, aNotes.begin(), aNotes.end());
237 : }
238 : }
239 :
240 0 : void ScColumn::SetValues( SCROW nRow, const std::vector<double>& rVals )
241 : {
242 0 : if (!ValidRow(nRow))
243 0 : return;
244 :
245 0 : SCROW nLastRow = nRow + rVals.size() - 1;
246 0 : if (nLastRow > MAXROW)
247 : // Out of bound. Do nothing.
248 0 : return;
249 :
250 0 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
251 0 : DetachFormulaCells(aPos, rVals.size());
252 :
253 0 : maCells.set(nRow, rVals.begin(), rVals.end());
254 0 : std::vector<sc::CellTextAttr> aDefaults(rVals.size());
255 0 : maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end());
256 :
257 0 : CellStorageModified();
258 :
259 0 : std::vector<SCROW> aRows;
260 0 : aRows.reserve(rVals.size());
261 0 : for (SCROW i = nRow; i <= nLastRow; ++i)
262 0 : aRows.push_back(i);
263 :
264 0 : BroadcastCells(aRows, SC_HINT_DATACHANGED);
265 : }
266 :
267 0 : void ScColumn::TransferCellValuesTo( SCROW nRow, size_t nLen, sc::CellValues& rDest )
268 : {
269 0 : if (!ValidRow(nRow))
270 0 : return;
271 :
272 0 : SCROW nLastRow = nRow + nLen - 1;
273 0 : if (nLastRow > MAXROW)
274 : // Out of bound. Do nothing.
275 0 : return;
276 :
277 0 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
278 0 : DetachFormulaCells(aPos, nLen);
279 :
280 0 : rDest.transferFrom(*this, nRow, nLen);
281 :
282 0 : std::vector<sc::CellTextAttr> aDefaults(nLen);
283 0 : maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end());
284 :
285 0 : CellStorageModified();
286 :
287 0 : std::vector<SCROW> aRows;
288 0 : aRows.reserve(nLen);
289 0 : for (SCROW i = nRow; i <= nLastRow; ++i)
290 0 : aRows.push_back(i);
291 :
292 0 : BroadcastCells(aRows, SC_HINT_DATACHANGED);
293 : }
294 :
295 0 : void ScColumn::CopyCellValuesFrom( SCROW nRow, const sc::CellValues& rSrc )
296 : {
297 0 : if (!ValidRow(nRow))
298 0 : return;
299 :
300 0 : SCROW nLastRow = nRow + rSrc.size() - 1;
301 0 : if (nLastRow > MAXROW)
302 : // Out of bound. Do nothing
303 0 : return;
304 :
305 0 : sc::CellStoreType::position_type aPos = maCells.position(nRow);
306 0 : DetachFormulaCells(aPos, rSrc.size());
307 :
308 0 : rSrc.copyTo(*this, nRow);
309 :
310 0 : std::vector<sc::CellTextAttr> aDefaults(rSrc.size());
311 0 : maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end());
312 :
313 0 : CellStorageModified();
314 :
315 0 : std::vector<SCROW> aRows;
316 0 : aRows.reserve(rSrc.size());
317 0 : for (SCROW i = nRow; i <= nLastRow; ++i)
318 0 : aRows.push_back(i);
319 :
320 0 : BroadcastCells(aRows, SC_HINT_DATACHANGED);
321 : }
322 :
323 0 : void ScColumn::DeleteRanges( const std::vector<sc::RowSpan>& rRanges, sal_uInt16 nDelFlag, bool bBroadcast )
324 : {
325 0 : std::vector<sc::RowSpan>::const_iterator itSpan = rRanges.begin(), itSpanEnd = rRanges.end();
326 0 : for (; itSpan != itSpanEnd; ++itSpan)
327 0 : DeleteArea(itSpan->mnRow1, itSpan->mnRow2, nDelFlag, bBroadcast);
328 0 : }
329 :
330 0 : void ScColumn::CloneFormulaCell( const ScFormulaCell& rSrc, const std::vector<sc::RowSpan>& rRanges )
331 : {
332 0 : sc::CellStoreType::iterator itPos = maCells.begin();
333 0 : sc::CellTextAttrStoreType::iterator itAttrPos = maCellTextAttrs.begin();
334 0 : sc::StartListeningContext aCxt(*pDocument);
335 :
336 0 : std::vector<ScFormulaCell*> aFormulas;
337 0 : std::vector<sc::RowSpan>::const_iterator itSpan = rRanges.begin(), itSpanEnd = rRanges.end();
338 0 : for (; itSpan != itSpanEnd; ++itSpan)
339 : {
340 0 : SCROW nRow1 = itSpan->mnRow1, nRow2 = itSpan->mnRow2;
341 0 : size_t nLen = nRow2 - nRow1 + 1;
342 : assert(nLen > 0);
343 0 : aFormulas.clear();
344 0 : aFormulas.reserve(nLen);
345 :
346 0 : ScAddress aPos(nCol, nRow1, nTab);
347 :
348 0 : if (nLen == 1)
349 : {
350 : // Single, ungrouped formula cell.
351 : ScFormulaCell* pCell =
352 0 : new ScFormulaCell(rSrc, *pDocument, aPos, pDocument->GetGrammar());
353 0 : pCell->StartListeningTo(aCxt);
354 0 : pCell->SetDirty();
355 0 : aFormulas.push_back(pCell);
356 : }
357 : else
358 : {
359 : // Create a group of formula cells.
360 0 : ScFormulaCellGroupRef xGroup(new ScFormulaCellGroup);
361 0 : xGroup->setCode(*rSrc.GetCode());
362 0 : xGroup->compileCode(*pDocument, aPos, pDocument->GetGrammar());
363 0 : for (size_t i = 0; i < nLen; ++i, aPos.IncRow())
364 : {
365 0 : ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, xGroup);
366 0 : if (i == 0)
367 : {
368 0 : xGroup->mpTopCell = pCell;
369 0 : xGroup->mnLength = nLen;
370 : }
371 0 : pCell->StartListeningTo(aCxt);
372 0 : pCell->SetDirty();
373 0 : aFormulas.push_back(pCell);
374 0 : }
375 : }
376 :
377 0 : itPos = maCells.set(itPos, nRow1, aFormulas.begin(), aFormulas.end());
378 :
379 : // Join the top and bottom of the pasted formula cells as needed.
380 0 : sc::CellStoreType::position_type aPosObj = maCells.position(itPos, nRow1);
381 :
382 : assert(aPosObj.first->type == sc::element_type_formula);
383 0 : ScFormulaCell* pCell = sc::formula_block::at(*aPosObj.first->data, aPosObj.second);
384 0 : JoinNewFormulaCell(aPosObj, *pCell);
385 :
386 0 : aPosObj = maCells.position(aPosObj.first, nRow2);
387 : assert(aPosObj.first->type == sc::element_type_formula);
388 0 : pCell = sc::formula_block::at(*aPosObj.first->data, aPosObj.second);
389 0 : JoinNewFormulaCell(aPosObj, *pCell);
390 :
391 0 : std::vector<sc::CellTextAttr> aTextAttrs(nLen);
392 0 : itAttrPos = maCellTextAttrs.set(itAttrPos, nRow1, aTextAttrs.begin(), aTextAttrs.end());
393 0 : }
394 :
395 0 : CellStorageModified();
396 0 : }
397 :
398 0 : ScPostIt* ScColumn::ReleaseNote( SCROW nRow )
399 : {
400 0 : if (!ValidRow(nRow))
401 0 : return NULL;
402 :
403 0 : ScPostIt* p = NULL;
404 0 : maCellNotes.release(nRow, p);
405 0 : return p;
406 : }
407 :
408 0 : size_t ScColumn::GetNoteCount() const
409 : {
410 0 : size_t nCount = 0;
411 0 : sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
412 0 : for (; it != itEnd; ++it)
413 : {
414 0 : if (it->type != sc::element_type_cellnote)
415 0 : continue;
416 :
417 0 : nCount += it->size;
418 : }
419 :
420 0 : return nCount;
421 : }
422 :
423 : namespace {
424 :
425 : class NoteCaptionCreator
426 : {
427 : ScAddress maPos;
428 : public:
429 0 : NoteCaptionCreator( SCTAB nTab, SCCOL nCol ) : maPos(nCol,0,nTab) {}
430 :
431 0 : void operator() ( size_t nRow, ScPostIt* p )
432 : {
433 0 : maPos.SetRow(nRow);
434 0 : p->GetOrCreateCaption(maPos);
435 0 : }
436 : };
437 :
438 : struct NoteCaptionCleaner
439 : {
440 0 : void operator() ( size_t /*nRow*/, ScPostIt* p )
441 : {
442 0 : p->ForgetCaption();
443 0 : }
444 : };
445 :
446 : }
447 :
448 0 : void ScColumn::CreateAllNoteCaptions()
449 : {
450 0 : NoteCaptionCreator aFunc(nTab, nCol);
451 0 : sc::ProcessNote(maCellNotes, aFunc);
452 0 : }
453 :
454 0 : void ScColumn::ForgetNoteCaptions( SCROW nRow1, SCROW nRow2 )
455 : {
456 0 : if (!ValidRow(nRow1) || !ValidRow(nRow2))
457 0 : return;
458 :
459 : NoteCaptionCleaner aFunc;
460 0 : sc::CellNoteStoreType::iterator it = maCellNotes.begin();
461 0 : sc::ProcessNote(it, maCellNotes, nRow1, nRow2, aFunc);
462 : }
463 :
464 0 : SCROW ScColumn::GetNotePosition( size_t nIndex ) const
465 : {
466 : // Return the row position of the nth note in the column.
467 :
468 0 : sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
469 :
470 0 : size_t nCount = 0; // Number of notes encountered so far.
471 0 : for (; it != itEnd; ++it)
472 : {
473 0 : if (it->type != sc::element_type_cellnote)
474 : // Skip the empty blocks.
475 0 : continue;
476 :
477 0 : if (nIndex < nCount + it->size)
478 : {
479 : // Index falls within this block.
480 0 : size_t nOffset = nIndex - nCount;
481 0 : return it->position + nOffset;
482 : }
483 :
484 0 : nCount += it->size;
485 : }
486 :
487 0 : return -1;
488 : }
489 :
490 : namespace {
491 :
492 : class NoteEntryCollector
493 : {
494 : std::vector<sc::NoteEntry>& mrNotes;
495 : SCTAB mnTab;
496 : SCCOL mnCol;
497 : SCROW mnStartRow;
498 : SCROW mnEndRow;
499 : public:
500 0 : NoteEntryCollector( std::vector<sc::NoteEntry>& rNotes, SCTAB nTab, SCCOL nCol,
501 : SCROW nStartRow = 0, SCROW nEndRow = MAXROW) :
502 : mrNotes(rNotes), mnTab(nTab), mnCol(nCol),
503 0 : mnStartRow(nStartRow), mnEndRow(nEndRow) {}
504 :
505 0 : void operator() (const sc::CellNoteStoreType::value_type& node) const
506 : {
507 0 : if (node.type != sc::element_type_cellnote)
508 0 : return;
509 :
510 0 : size_t nTopRow = node.position;
511 0 : sc::cellnote_block::const_iterator it = sc::cellnote_block::begin(*node.data);
512 0 : sc::cellnote_block::const_iterator itEnd = sc::cellnote_block::end(*node.data);
513 0 : size_t nOffset = 0;
514 0 : if(nTopRow < size_t(mnStartRow))
515 : {
516 0 : std::advance(it, mnStartRow - nTopRow);
517 0 : nOffset = mnStartRow - nTopRow;
518 : }
519 :
520 0 : for (; it != itEnd && nTopRow + nOffset <= size_t(mnEndRow);
521 : ++it, ++nOffset)
522 : {
523 0 : ScAddress aPos(mnCol, nTopRow + nOffset, mnTab);
524 0 : mrNotes.push_back(sc::NoteEntry(aPos, *it));
525 : }
526 : }
527 : };
528 :
529 : }
530 :
531 0 : void ScColumn::GetAllNoteEntries( std::vector<sc::NoteEntry>& rNotes ) const
532 : {
533 0 : std::for_each(maCellNotes.begin(), maCellNotes.end(), NoteEntryCollector(rNotes, nTab, nCol));
534 0 : }
535 :
536 0 : void ScColumn::GetNotesInRange(SCROW nStartRow, SCROW nEndRow,
537 : std::vector<sc::NoteEntry>& rNotes ) const
538 : {
539 0 : std::pair<sc::CellNoteStoreType::const_iterator,size_t> aPos = maCellNotes.position(nStartRow);
540 0 : sc::CellNoteStoreType::const_iterator it = aPos.first;
541 0 : if (it == maCellNotes.end())
542 : // Invalid row number.
543 0 : return;
544 :
545 : std::pair<sc::CellNoteStoreType::const_iterator,size_t> aEndPos =
546 0 : maCellNotes.position(nEndRow);
547 0 : sc::CellNoteStoreType::const_iterator itEnd = aEndPos.first;
548 :
549 0 : std::for_each(it, itEnd, NoteEntryCollector(rNotes, nTab, nCol, nStartRow, nEndRow));
550 : }
551 :
552 : namespace {
553 :
554 : class PreRangeNameUpdateHandler
555 : {
556 : ScDocument* mpDoc;
557 : sc::EndListeningContext& mrEndListenCxt;
558 : sc::CompileFormulaContext& mrCompileFormulaCxt;
559 :
560 : public:
561 0 : PreRangeNameUpdateHandler( ScDocument* pDoc, sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt ) :
562 : mpDoc(pDoc),
563 : mrEndListenCxt(rEndListenCxt),
564 0 : mrCompileFormulaCxt(rCompileCxt) {}
565 :
566 0 : void operator() ( sc::FormulaGroupEntry& rEntry )
567 : {
568 : // Perform end listening, remove from formula tree, and set them up
569 : // for re-compilation.
570 :
571 0 : ScFormulaCell* pTop = NULL;
572 :
573 0 : if (rEntry.mbShared)
574 : {
575 : // Only inspect the code from the top cell.
576 0 : pTop = *rEntry.mpCells;
577 : }
578 : else
579 0 : pTop = rEntry.mpCell;
580 :
581 0 : ScTokenArray* pCode = pTop->GetCode();
582 :
583 0 : boost::unordered_set<OpCode> aOps;
584 0 : aOps.insert(ocBad);
585 0 : aOps.insert(ocColRowName);
586 0 : aOps.insert(ocName);
587 0 : bool bRecompile = pCode->HasOpCodes(aOps);
588 :
589 0 : if (bRecompile)
590 : {
591 : // Get the formula string.
592 0 : OUString aFormula = pTop->GetFormula(mrCompileFormulaCxt);
593 0 : sal_Int32 n = aFormula.getLength();
594 0 : if (pTop->GetMatrixFlag() != MM_NONE && n > 0)
595 : {
596 0 : if (aFormula[0] == '{' && aFormula[n-1] == '}')
597 0 : aFormula = aFormula.copy(1, n-2);
598 : }
599 :
600 0 : if (rEntry.mbShared)
601 : {
602 0 : ScFormulaCell** pp = rEntry.mpCells;
603 0 : ScFormulaCell** ppEnd = pp + rEntry.mnLength;
604 0 : for (; pp != ppEnd; ++pp)
605 : {
606 0 : ScFormulaCell* p = *pp;
607 0 : p->EndListeningTo(mrEndListenCxt);
608 0 : mpDoc->RemoveFromFormulaTree(p);
609 : }
610 : }
611 : else
612 : {
613 0 : rEntry.mpCell->EndListeningTo(mrEndListenCxt);
614 0 : mpDoc->RemoveFromFormulaTree(rEntry.mpCell);
615 : }
616 :
617 0 : pCode->Clear();
618 0 : pTop->SetHybridFormula(aFormula, mpDoc->GetGrammar());
619 0 : }
620 0 : }
621 : };
622 :
623 : class PostRangeNameUpdateHandler
624 : {
625 : ScDocument* mpDoc;
626 : sc::CompileFormulaContext& mrCompileFormulaCxt;
627 :
628 : public:
629 0 : PostRangeNameUpdateHandler( ScDocument* pDoc, sc::CompileFormulaContext& rCompileCxt ) :
630 : mpDoc(pDoc),
631 0 : mrCompileFormulaCxt(rCompileCxt) {}
632 :
633 0 : void operator() ( sc::FormulaGroupEntry& rEntry )
634 : {
635 0 : if (rEntry.mbShared)
636 : {
637 0 : ScFormulaCell* pTop = *rEntry.mpCells;
638 0 : OUString aFormula = pTop->GetHybridFormula();
639 :
640 0 : if (!aFormula.isEmpty())
641 : {
642 : // Create a new token array from the hybrid formula string, and
643 : // set it to the group.
644 0 : ScCompiler aComp(mrCompileFormulaCxt, pTop->aPos);
645 0 : ScTokenArray* pNewCode = aComp.CompileString(aFormula);
646 0 : ScFormulaCellGroupRef xGroup = pTop->GetCellGroup();
647 : assert(xGroup);
648 0 : xGroup->setCode(pNewCode);
649 0 : xGroup->compileCode(*mpDoc, pTop->aPos, mpDoc->GetGrammar());
650 :
651 : // Propagate the new token array to all formula cells in the group.
652 0 : ScFormulaCell** pp = rEntry.mpCells;
653 0 : ScFormulaCell** ppEnd = pp + rEntry.mnLength;
654 0 : for (; pp != ppEnd; ++pp)
655 : {
656 0 : ScFormulaCell* p = *pp;
657 0 : p->SyncSharedCode();
658 0 : p->SetDirty();
659 0 : }
660 0 : }
661 : }
662 : else
663 : {
664 0 : ScFormulaCell* pCell = rEntry.mpCell;
665 0 : OUString aFormula = pCell->GetHybridFormula();
666 :
667 0 : if (!aFormula.isEmpty())
668 : {
669 : // Create token array from formula string.
670 0 : ScCompiler aComp(mrCompileFormulaCxt, pCell->aPos);
671 0 : ScTokenArray* pNewCode = aComp.CompileString(aFormula);
672 :
673 : // Generate RPN tokens.
674 0 : ScCompiler aComp2(mpDoc, pCell->aPos, *pNewCode);
675 0 : aComp2.CompileTokenArray();
676 :
677 0 : pCell->SetCode(pNewCode);
678 0 : pCell->SetDirty();
679 0 : }
680 : }
681 0 : }
682 : };
683 :
684 : }
685 :
686 0 : void ScColumn::PreprocessRangeNameUpdate(
687 : sc::EndListeningContext& rEndListenCxt, sc::CompileFormulaContext& rCompileCxt )
688 : {
689 : // Collect all formula groups.
690 0 : std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
691 :
692 0 : PreRangeNameUpdateHandler aFunc(pDocument, rEndListenCxt, rCompileCxt);
693 0 : std::for_each(aGroups.begin(), aGroups.end(), aFunc);
694 0 : }
695 :
696 0 : void ScColumn::PostprocessRangeNameUpdate( sc::CompileFormulaContext& rCompileCxt )
697 : {
698 : // Collect all formula groups.
699 0 : std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
700 :
701 0 : PostRangeNameUpdateHandler aFunc(pDocument, rCompileCxt);
702 0 : std::for_each(aGroups.begin(), aGroups.end(), aFunc);
703 0 : }
704 :
705 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|