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 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "column.hxx"
21 :
22 : #include "scitems.hxx"
23 : #include "formulacell.hxx"
24 : #include "document.hxx"
25 : #include "attarray.hxx"
26 : #include "patattr.hxx"
27 : #include "cellform.hxx"
28 : #include "typedstrdata.hxx"
29 : #include "formula/errorcodes.hxx"
30 : #include "formula/token.hxx"
31 : #include "brdcst.hxx"
32 : #include "docoptio.hxx" // GetStdPrecision for GetMaxNumberStringLen
33 : #include "subtotal.hxx"
34 : #include "markdata.hxx"
35 : #include "detfunc.hxx" // For Notes for DeleteRange
36 : #include "postit.hxx"
37 : #include "stringutil.hxx"
38 : #include "docpool.hxx"
39 : #include "globalnames.hxx"
40 : #include "cellvalue.hxx"
41 : #include "tokenarray.hxx"
42 : #include "stlalgorithm.hxx"
43 : #include "clipcontext.hxx"
44 : #include "columnspanset.hxx"
45 : #include "mtvcellfunc.hxx"
46 : #include "scopetools.hxx"
47 : #include "editutil.hxx"
48 :
49 : #include <com/sun/star/i18n/LocaleDataItem.hpp>
50 :
51 : #include <boost/scoped_ptr.hpp>
52 :
53 : #include <mdds/flat_segment_tree.hpp>
54 :
55 : #include <sfx2/objsh.hxx>
56 : #include <svl/zforlist.hxx>
57 : #include <svl/zformat.hxx>
58 : #include <svl/broadcast.hxx>
59 : #include "editeng/editstat.hxx"
60 :
61 : #include <cstdio>
62 :
63 : using ::com::sun::star::i18n::LocaleDataItem;
64 :
65 : // Err527 Workaroand
66 : extern const ScFormulaCell* pLastFormulaTreeTop; // in cellform.cxx
67 : using namespace formula;
68 : // STATIC DATA -----------------------------------------------------------
69 :
70 : namespace {
71 :
72 17987 : void broadcastCells(ScDocument& rDoc, SCCOL nCol, SCROW nTab, const std::vector<SCROW>& rRows)
73 : {
74 17987 : if (rRows.empty())
75 35332 : return;
76 :
77 : // Broadcast the changes.
78 642 : ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab));
79 642 : std::vector<SCROW>::const_iterator itRow = rRows.begin(), itRowEnd = rRows.end();
80 2809 : for (; itRow != itRowEnd; ++itRow)
81 : {
82 2167 : aHint.GetAddress().SetRow(*itRow);
83 2167 : rDoc.Broadcast(aHint);
84 642 : }
85 : }
86 :
87 : }
88 :
89 17987 : void ScColumn::BroadcastCells( const std::vector<SCROW>& rRows )
90 : {
91 17987 : broadcastCells(*pDocument, nCol, nTab, rRows);
92 17987 : }
93 :
94 : namespace {
95 :
96 : class EndListeningHandler
97 : {
98 : ScDocument* mpDoc;
99 : public:
100 0 : EndListeningHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
101 :
102 0 : void operator() (size_t, ScFormulaCell* p)
103 : {
104 0 : p->EndListeningTo(mpDoc);
105 0 : }
106 : };
107 :
108 : }
109 :
110 0 : void ScColumn::EndFormulaListening( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
111 : {
112 0 : EndListeningHandler aFunc(pDocument);
113 0 : rBlockPos.miCellPos =
114 0 : sc::ProcessFormula(rBlockPos.miCellPos, maCells, nRow1, nRow2, aFunc);
115 0 : }
116 :
117 : struct DirtyCellInterpreter
118 : {
119 181 : void operator() (size_t, ScFormulaCell* p)
120 : {
121 181 : if (p->GetDirty())
122 57 : p->Interpret();
123 181 : }
124 : };
125 :
126 9679 : void ScColumn::InterpretDirtyCells( SCROW nRow1, SCROW nRow2 )
127 : {
128 : DirtyCellInterpreter aFunc;
129 9679 : sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
130 9679 : }
131 :
132 1714 : void ScColumn::Delete( SCROW nRow )
133 : {
134 1714 : std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
135 1714 : sc::CellStoreType::iterator it = aPos.first;
136 1714 : if (it == maCells.end())
137 1714 : return;
138 :
139 1714 : bool bFormulaCell = it->type == sc::element_type_formula;
140 1714 : if (bFormulaCell)
141 : {
142 1 : ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
143 1 : p->EndListeningTo(pDocument);
144 : }
145 1714 : maCells.set_empty(nRow, nRow);
146 1714 : maCellTextAttrs.set_empty(nRow, nRow);
147 :
148 : pDocument->Broadcast(
149 1714 : ScHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab)));
150 :
151 1714 : if (bFormulaCell)
152 1 : RegroupFormulaCells(nRow);
153 :
154 1714 : CellStorageModified();
155 : }
156 :
157 1554432 : void ScColumn::FreeAll()
158 : {
159 : // Keep a logical empty range of 0-MAXROW at all times.
160 1554432 : maCells.clear();
161 1554432 : maCells.resize(MAXROWCOUNT);
162 1554432 : maCellTextAttrs.clear();
163 1554432 : maCellTextAttrs.resize(MAXROWCOUNT);
164 1554432 : CellStorageModified();
165 1554432 : }
166 :
167 : namespace {
168 :
169 : /**
170 : * Collect all formula cells for later mass-unregistration. Also tag row
171 : * positions of all non-empty cells in the range.
172 : */
173 6 : class DeleteRowsHandler
174 : {
175 : ScDocument& mrDoc;
176 : std::vector<SCROW> maRows;
177 : std::vector<ScFormulaCell*> maFormulaCells;
178 : public:
179 6 : DeleteRowsHandler(ScDocument& rDoc) : mrDoc(rDoc) {}
180 :
181 3 : void operator() (size_t nRow, ScFormulaCell* pCell)
182 : {
183 3 : maFormulaCells.push_back(pCell);
184 3 : maRows.push_back(nRow);
185 3 : }
186 :
187 3 : void operator() (mdds::mtv::element_t nType, size_t nTopRow, size_t nDataSize)
188 : {
189 3 : if (nType == sc::element_type_empty)
190 : // Ignore empty cells.
191 4 : return;
192 :
193 4 : for (size_t i = 0; i < nDataSize; ++i)
194 : // Tag all non-empty cells.
195 2 : maRows.push_back(i + nTopRow);
196 : }
197 :
198 6 : void endFormulas()
199 : {
200 6 : mrDoc.EndListeningFormulaCells(maFormulaCells);
201 6 : }
202 :
203 6 : const std::vector<SCROW>& getNonEmptyRows() const
204 : {
205 6 : return maRows;
206 : }
207 : };
208 :
209 : class ShiftFormulaPosHandler
210 : {
211 : public:
212 :
213 0 : void operator() (size_t nRow, ScFormulaCell* pCell)
214 : {
215 0 : pCell->aPos.SetRow(nRow);
216 0 : }
217 : };
218 :
219 9 : class RangeBroadcaster
220 : {
221 : ScDocument& mrDoc;
222 : ScHint maHint;
223 : public:
224 3 : RangeBroadcaster(ScDocument& rDoc, SCTAB nTab, SCCOL nCol) :
225 : mrDoc(rDoc),
226 3 : maHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab)) {}
227 :
228 3 : void operator() (const sc::SingleColumnSpanSet::Span& rSpan)
229 : {
230 3 : SCROW nRow1 = rSpan.mnRow1, nRow2 = rSpan.mnRow2;
231 3 : maHint.GetAddress().SetRow(nRow1);
232 3 : ScRange aRange(maHint.GetAddress());
233 3 : aRange.aEnd.SetRow(nRow2);
234 3 : mrDoc.AreaBroadcastInRange(aRange, maHint);
235 3 : }
236 : };
237 :
238 : }
239 :
240 8199 : void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
241 : {
242 8199 : pAttrArray->DeleteRow( nStartRow, nSize );
243 :
244 8199 : SCROW nEndRow = nStartRow + nSize - 1;
245 :
246 8199 : maBroadcasters.erase(nStartRow, nEndRow);
247 8199 : maBroadcasters.resize(MAXROWCOUNT);
248 :
249 : // See if we have any cells that would get deleted or shifted by deletion.
250 8199 : sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
251 8199 : sc::CellStoreType::iterator itCell = aPos.first;
252 8199 : if (itCell->type == sc::element_type_empty)
253 : {
254 : // This is an empty block. If this is the last block, then there is no cells to delete or shift.
255 8194 : sc::CellStoreType::iterator itTest = itCell;
256 8194 : ++itTest;
257 8194 : if (itTest == maCells.end())
258 : {
259 : // No cells are affected by this deletion. Bail out.
260 8193 : CellStorageModified(); // broadcast array has been modified.
261 8193 : return;
262 : }
263 : }
264 :
265 : // Check if there are any cells below the end row that will get shifted.
266 6 : bool bShiftCells = false;
267 6 : aPos = maCells.position(itCell, nEndRow+1);
268 6 : itCell = aPos.first;
269 6 : if (itCell->type == sc::element_type_empty)
270 : {
271 : // This block is empty. See if there is any block that follows.
272 5 : sc::CellStoreType::iterator itTest = itCell;
273 5 : ++itTest;
274 5 : if (itTest != maCells.end())
275 : // Non-empty block follows -> cells that will get shifted.
276 2 : bShiftCells = true;
277 : }
278 : else
279 1 : bShiftCells = true;
280 :
281 6 : sc::SingleColumnSpanSet aNonEmptySpans;
282 6 : if (bShiftCells)
283 : {
284 : // Mark all non-empty cell positions below the end row.
285 3 : sc::ColumnBlockConstPosition aBlockPos;
286 3 : aBlockPos.miCellPos = itCell;
287 3 : aNonEmptySpans.scan(aBlockPos, *this, nEndRow+1, MAXROW);
288 : }
289 :
290 9 : sc::AutoCalcSwitch aACSwitch(*pDocument, false);
291 :
292 : // Parse all non-empty cells in the range to pick up their row positions,
293 : // and end all formula cells.
294 9 : DeleteRowsHandler aDeleteRowsFunc(*pDocument);
295 6 : sc::ProcessFormula(itCell, maCells, nStartRow, nEndRow, aDeleteRowsFunc, aDeleteRowsFunc);
296 6 : aDeleteRowsFunc.endFormulas();
297 :
298 : // Remove the cells.
299 6 : maCells.erase(nStartRow, nEndRow);
300 6 : maCells.resize(MAXROWCOUNT);
301 :
302 : // Shift the formula cell positions below the start row.
303 : ShiftFormulaPosHandler aShiftFormulaFunc;
304 6 : sc::ProcessFormula(maCells.begin(), maCells, nStartRow, MAXROW, aShiftFormulaFunc);
305 :
306 : // Single cell broadcasts on deleted cells.
307 6 : BroadcastCells(aDeleteRowsFunc.getNonEmptyRows());
308 :
309 : // Shift the text attribute array too (before the broadcast).
310 6 : maCellTextAttrs.erase(nStartRow, nEndRow);
311 6 : maCellTextAttrs.resize(MAXROWCOUNT);
312 :
313 6 : RegroupFormulaCells(nStartRow);
314 6 : CellStorageModified();
315 :
316 6 : if (!bShiftCells)
317 3 : return;
318 :
319 : // Do area broadcast on the old non-empty cell ranges prior to the shift.
320 6 : sc::SingleColumnSpanSet::SpansType aSpans;
321 3 : aNonEmptySpans.getSpans(aSpans);
322 6 : std::for_each(aSpans.begin(), aSpans.end(), RangeBroadcaster(*pDocument, nTab, nCol));
323 : }
324 :
325 65269 : sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow )
326 : {
327 65269 : return GetPositionToInsert(maCells.begin(), nRow);
328 : }
329 :
330 : namespace {
331 :
332 2469 : void joinFormulaCells(SCROW nRow, ScFormulaCell& rCell1, ScFormulaCell& rCell2)
333 : {
334 2469 : ScFormulaCell::CompareState eState = rCell1.CompareByTokenArray(rCell2);
335 2469 : if (eState == ScFormulaCell::NotEqual)
336 3608 : return;
337 :
338 : // Formula tokens equal those of the previous formula cell.
339 1330 : ScFormulaCellGroupRef xGroup1 = rCell1.GetCellGroup();
340 2660 : ScFormulaCellGroupRef xGroup2 = rCell2.GetCellGroup();
341 1330 : if (xGroup1)
342 : {
343 831 : if (xGroup2)
344 : {
345 : // Both cell1 and cell2 are shared. Merge them together.
346 1 : xGroup1->mnLength += xGroup2->mnLength;
347 1 : rCell2.SetCellGroup(xGroup1);
348 : }
349 : else
350 : {
351 : // cell1 is shared but cell2 is not.
352 830 : rCell2.SetCellGroup(xGroup1);
353 830 : ++xGroup1->mnLength;
354 : }
355 : }
356 : else
357 : {
358 499 : if (xGroup2)
359 : {
360 : // cell1 is not shared, but cell2 is already shared.
361 1 : rCell1.SetCellGroup(xGroup2);
362 1 : xGroup2->mnStart = nRow;
363 1 : ++xGroup2->mnLength;
364 : }
365 : else
366 : {
367 : // neither cells are shared.
368 498 : xGroup1.reset(new ScFormulaCellGroup);
369 498 : xGroup1->mnStart = nRow;
370 498 : xGroup1->mbInvariant = (eState == ScFormulaCell::EqualInvariant);
371 498 : xGroup1->mnLength = 2;
372 :
373 498 : rCell1.SetCellGroup(xGroup1);
374 498 : rCell2.SetCellGroup(xGroup1);
375 : }
376 1330 : }
377 : }
378 :
379 : }
380 :
381 3704 : void ScColumn::JoinNewFormulaCell(
382 : const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const
383 : {
384 3704 : SCROW nRow = aPos.first->position + aPos.second;
385 :
386 : // Check the previous row position for possible grouping.
387 3704 : if (aPos.first->type == sc::element_type_formula && aPos.second > 0)
388 : {
389 2427 : ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
390 2427 : joinFormulaCells(nRow-1, rPrev, rCell);
391 : }
392 :
393 : // Check the next row position for possible grouping.
394 3704 : if (aPos.first->type == sc::element_type_formula && aPos.second+1 < aPos.first->size)
395 : {
396 42 : ScFormulaCell& rNext = *sc::formula_block::at(*aPos.first->data, aPos.second+1);
397 42 : joinFormulaCells(nRow, rCell, rNext);
398 : }
399 3704 : }
400 :
401 195 : void ScColumn::DetouchFormulaCell(
402 : const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const
403 : {
404 195 : if (!pDocument->IsClipOrUndo())
405 : // Have the dying formula cell stop listening.
406 195 : rCell.EndListeningTo(pDocument);
407 :
408 195 : if (rCell.IsShared())
409 78 : UnshareFormulaCell(aPos, rCell);
410 195 : }
411 :
412 78 : void ScColumn::UnshareFormulaCell(
413 : const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const
414 : {
415 78 : if (!rCell.IsShared())
416 78 : return;
417 :
418 78 : ScFormulaCellGroupRef xNone;
419 78 : sc::CellStoreType::iterator it = aPos.first;
420 :
421 : // This formula cell is shared. Adjust the shared group.
422 78 : if (rCell.aPos.Row() == rCell.GetSharedTopRow())
423 : {
424 : // Top of the shared range.
425 12 : ScFormulaCellGroupRef xGroup = rCell.GetCellGroup();
426 12 : if (xGroup->mnLength == 2)
427 : {
428 : // Group consists only only two cells. Mark the second one non-shared.
429 : #if DEBUG_COLUMN_STORAGE
430 : if (aPos.second+1 >= aPos.first->size)
431 : {
432 : cerr << "ScColumn::UnshareFormulaCell: There is no next formula cell but there should be!" << endl;
433 : cerr.flush();
434 : abort();
435 : }
436 : #endif
437 6 : ScFormulaCell& rNext = *sc::formula_block::at(*it->data, aPos.second+1);
438 6 : rNext.SetCellGroup(xNone);
439 : }
440 : else
441 : {
442 : // Move the top cell to the next formula cell down.
443 6 : --xGroup->mnLength;
444 6 : ++xGroup->mnStart;
445 12 : }
446 : }
447 66 : else if (rCell.aPos.Row() == rCell.GetSharedTopRow() + rCell.GetSharedLength() - 1)
448 : {
449 : // Bottom of the shared range.
450 65 : ScFormulaCellGroupRef xGroup = rCell.GetCellGroup();
451 65 : if (xGroup->mnLength == 2)
452 : {
453 : // Mark the top cell non-shared.
454 : #if DEBUG_COLUMN_STORAGE
455 : if (aPos.second == 0)
456 : {
457 : cerr << "ScColumn::UnshareFormulaCell: There is no previous formula cell but there should be!" << endl;
458 : cerr.flush();
459 : abort();
460 : }
461 : #endif
462 16 : ScFormulaCell& rPrev = *sc::formula_block::at(*it->data, aPos.second-1);
463 16 : rPrev.SetCellGroup(xNone);
464 : }
465 : else
466 : {
467 : // Just shortern the shared range length by one.
468 49 : --xGroup->mnLength;
469 65 : }
470 : }
471 : else
472 : {
473 : // In the middle of the shared range. Split it into two groups.
474 1 : ScFormulaCellGroupRef xGroup = rCell.GetCellGroup();
475 1 : SCROW nEndRow = xGroup->mnStart + xGroup->mnLength - 1;
476 1 : xGroup->mnLength = rCell.aPos.Row() - xGroup->mnStart; // Shorten the top group.
477 :
478 2 : ScFormulaCellGroupRef xGroup2(new ScFormulaCellGroup);
479 1 : xGroup2->mnStart = rCell.aPos.Row() + 1;
480 1 : xGroup2->mnLength = nEndRow - rCell.aPos.Row();
481 1 : xGroup2->mbInvariant = xGroup->mbInvariant;
482 : #if DEBUG_COLUMN_STORAGE
483 : if (xGroup2->mnStart + xGroup2->mnLength > it->position + it->size)
484 : {
485 : cerr << "ScColumn::UnshareFormulaCell: Shared formula region goes beyond the formula block. Not good." << endl;
486 : cerr.flush();
487 : abort();
488 : }
489 : #endif
490 1 : sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
491 1 : std::advance(itCell, aPos.second+1);
492 1 : sc::formula_block::iterator itCellEnd = itCell;
493 1 : std::advance(itCellEnd, xGroup2->mnLength);
494 5 : for (; itCell != itCellEnd; ++itCell)
495 : {
496 4 : ScFormulaCell& rCell2 = **itCell;
497 4 : rCell2.SetCellGroup(xGroup2);
498 1 : }
499 : }
500 :
501 78 : rCell.SetCellGroup(xNone);
502 : }
503 :
504 0 : void ScColumn::SplitFormulaCellGroup( const sc::CellStoreType::position_type& aPos ) const
505 : {
506 0 : SCROW nRow = aPos.first->position + aPos.second;
507 :
508 0 : if (aPos.first->type != sc::element_type_formula)
509 : // Not a formula cell block.
510 0 : return;
511 :
512 0 : if (aPos.second == 0)
513 : // Split position coincides with the block border. Nothing to do.
514 0 : return;
515 :
516 0 : sc::formula_block::iterator it = sc::formula_block::begin(*aPos.first->data);
517 0 : std::advance(it, aPos.second);
518 0 : ScFormulaCell& rTop = **it;
519 0 : if (!rTop.IsShared())
520 : // Not a shared formula.
521 0 : return;
522 :
523 0 : if (nRow == rTop.GetSharedTopRow())
524 : // Already the top cell of a shared group.
525 0 : return;
526 :
527 0 : ScFormulaCellGroupRef xGroup = rTop.GetCellGroup();
528 :
529 0 : ScFormulaCellGroupRef xGroup2(new ScFormulaCellGroup);
530 0 : xGroup2->mbInvariant = xGroup->mbInvariant;
531 0 : xGroup2->mnStart = nRow;
532 0 : xGroup2->mnLength = xGroup->mnStart + xGroup->mnLength - nRow;
533 :
534 0 : xGroup->mnLength = nRow - xGroup->mnStart;
535 :
536 : // Apply the lower group object to the lower cells.
537 : #if DEBUG_COLUMN_STORAGE
538 : if (xGroup2->mnStart + xGroup2->mnLength > aPos.first->position + aPos.first->size)
539 : {
540 : cerr << "ScColumn::SplitFormulaCellGroup: Shared formula region goes beyond the formula block. Not good." << endl;
541 : cerr.flush();
542 : abort();
543 : }
544 : #endif
545 0 : sc::formula_block::iterator itEnd = it;
546 0 : std::advance(itEnd, xGroup2->mnLength);
547 0 : for (; it != itEnd; ++it)
548 : {
549 0 : ScFormulaCell& rCell = **it;
550 0 : rCell.SetCellGroup(xGroup2);
551 0 : }
552 : }
553 :
554 65472 : sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow )
555 : {
556 : // See if we are overwriting an existing formula cell.
557 65472 : sc::CellStoreType::position_type aPos = maCells.position(it, nRow);
558 65472 : sc::CellStoreType::iterator itRet = aPos.first;
559 65472 : if (itRet->type == sc::element_type_formula)
560 : {
561 195 : ScFormulaCell& rCell = *sc::formula_block::at(*itRet->data, aPos.second);
562 195 : DetouchFormulaCell(aPos, rCell);
563 : }
564 :
565 65472 : return itRet;
566 : }
567 :
568 3704 : void ScColumn::ActivateNewFormulaCell(
569 : const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell )
570 : {
571 3704 : ActivateNewFormulaCell(maCells.position(itPos, nRow), rCell);
572 3704 : }
573 :
574 3704 : void ScColumn::ActivateNewFormulaCell(
575 : const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell )
576 : {
577 : // See if this new formula cell can join an existing shared formula group.
578 3704 : JoinNewFormulaCell(aPos, rCell);
579 :
580 : // When we insert from the Clipboard we still have wrong (old) References!
581 : // First they are rewired in CopyBlockFromClip via UpdateReference and the
582 : // we call StartListeningFromClip and BroadcastFromClip.
583 : // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
584 : // After Import we call CalcAfterLoad and in there Listening.
585 3704 : if (!pDocument->IsClipOrUndo() && !pDocument->IsInsertingFromOtherDoc())
586 : {
587 717 : rCell.StartListeningTo(pDocument);
588 717 : if (!pDocument->IsCalcingAfterLoad())
589 717 : rCell.SetDirty();
590 : }
591 3704 : }
592 :
593 61768 : void ScColumn::BroadcastNewCell( SCROW nRow )
594 : {
595 : // When we insert from the Clipboard we still have wrong (old) References!
596 : // First they are rewired in CopyBlockFromClip via UpdateReference and the
597 : // we call StartListeningFromClip and BroadcastFromClip.
598 : // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
599 : // After Import we call CalcAfterLoad and in there Listening.
600 61768 : if (pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc() || pDocument->IsCalcingAfterLoad())
601 94923 : return;
602 :
603 28613 : ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, nRow, nTab));
604 28613 : pDocument->Broadcast(aHint);
605 : }
606 :
607 59538 : bool ScColumn::UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow )
608 : {
609 59538 : if (rAttr.mnScriptType != SC_SCRIPTTYPE_UNKNOWN)
610 : // Already updated. Nothing to do.
611 36237 : return false;
612 :
613 : // Script type not yet determined. Determine the real script
614 : // type, and store it.
615 23301 : const ScPatternAttr* pPattern = GetPattern(nRow);
616 23301 : if (!pPattern)
617 0 : return false;
618 :
619 23301 : ScRefCellValue aCell;
620 23301 : ScAddress aPos(nCol, nRow, nTab);
621 23301 : aCell.assign(*pDocument, aPos);
622 :
623 23301 : const SfxItemSet* pCondSet = NULL;
624 23301 : ScConditionalFormatList* pCFList = pDocument->GetCondFormList(nTab);
625 23301 : if (pCFList)
626 : {
627 : const ScCondFormatItem& rItem =
628 23301 : static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL));
629 23301 : const std::vector<sal_uInt32>& rData = rItem.GetCondFormatData();
630 23301 : pCondSet = pDocument->GetCondResult(aCell, aPos, *pCFList, rData);
631 : }
632 :
633 23301 : SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
634 :
635 46602 : OUString aStr;
636 : Color* pColor;
637 23301 : sal_uLong nFormat = pPattern->GetNumberFormat(pFormatter, pCondSet);
638 23301 : ScCellFormat::GetString(aCell, nFormat, aStr, &pColor, *pFormatter);
639 :
640 : // Store the real script type to the array.
641 23301 : rAttr.mnScriptType = pDocument->GetStringScriptType(aStr);
642 46602 : return true;
643 : }
644 :
645 : namespace {
646 :
647 4208 : class DeleteAreaHandler
648 : {
649 : ScDocument& mrDoc;
650 : std::vector<ScFormulaCell*> maFormulaCells;
651 : sc::SingleColumnSpanSet maDeleteRanges;
652 :
653 : bool mbNumeric:1;
654 : bool mbString:1;
655 : bool mbFormula:1;
656 :
657 : public:
658 4208 : DeleteAreaHandler(ScDocument& rDoc, sal_uInt16 nDelFlag) :
659 : mrDoc(rDoc),
660 4208 : mbNumeric(nDelFlag & IDF_VALUE),
661 4208 : mbString(nDelFlag & IDF_STRING),
662 12624 : mbFormula(nDelFlag & IDF_FORMULA) {}
663 :
664 5022 : void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
665 : {
666 5022 : switch (node.type)
667 : {
668 : case sc::element_type_numeric:
669 391 : if (!mbNumeric)
670 1 : return;
671 390 : break;
672 : case sc::element_type_string:
673 : case sc::element_type_edittext:
674 288 : if (!mbString)
675 7 : return;
676 281 : break;
677 : case sc::element_type_formula:
678 : {
679 38 : if (!mbFormula)
680 0 : return;
681 :
682 38 : sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
683 38 : std::advance(it, nOffset);
684 38 : sc::formula_block::iterator itEnd = it;
685 38 : std::advance(itEnd, nDataSize);
686 :
687 152 : for (; it != itEnd; ++it)
688 114 : maFormulaCells.push_back(*it);
689 : }
690 38 : break;
691 : case sc::element_type_empty:
692 : default:
693 4305 : return;
694 : }
695 :
696 : // Tag these cells for deletion.
697 709 : SCROW nRow1 = node.position + nOffset;
698 709 : SCROW nRow2 = nRow1 + nDataSize - 1;
699 709 : maDeleteRanges.set(nRow1, nRow2, true);
700 : }
701 :
702 4208 : void endFormulas()
703 : {
704 4208 : mrDoc.EndListeningFormulaCells(maFormulaCells);
705 4208 : }
706 :
707 8416 : const sc::SingleColumnSpanSet& getSpans() const
708 : {
709 8416 : return maDeleteRanges;
710 : }
711 : };
712 :
713 4208 : class EmptyCells
714 : {
715 : ScColumn& mrColumn;
716 : sc::ColumnBlockPosition& mrPos;
717 : sc::CellStoreType::iterator miPos;
718 : sc::CellStoreType& mrCells;
719 : sc::CellTextAttrStoreType& mrAttrs;
720 : public:
721 4208 : EmptyCells(sc::ColumnBlockPosition& rPos, ScColumn& rColumn, sc::CellStoreType& rCells, sc::CellTextAttrStoreType& rAttrs) :
722 4208 : mrColumn(rColumn), mrPos(rPos), mrCells(rCells), mrAttrs(rAttrs) {}
723 :
724 600 : void operator() (const sc::SingleColumnSpanSet::Span& rSpan)
725 : {
726 600 : mrPos.miCellPos = mrCells.set_empty(mrPos.miCellPos, rSpan.mnRow1, rSpan.mnRow2);
727 600 : mrPos.miCellTextAttrPos = mrAttrs.set_empty(mrPos.miCellTextAttrPos, rSpan.mnRow1, rSpan.mnRow2);
728 600 : mrColumn.RegroupFormulaCells(rSpan.mnRow1, rSpan.mnRow2);
729 600 : }
730 : };
731 :
732 : }
733 :
734 14599 : void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag)
735 : {
736 14599 : sal_uInt16 nContMask = IDF_CONTENTS;
737 : // IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set
738 14599 : if( nDelFlag & IDF_NOTE )
739 12230 : nContMask |= IDF_NOCAPTIONS;
740 14599 : sal_uInt16 nContFlag = nDelFlag & nContMask;
741 :
742 14599 : std::vector<SCROW> aDeletedRows;
743 :
744 14599 : if (!IsEmptyData() && nContFlag)
745 : {
746 : // There are cells to delete. Determine which cells to delete based on the deletion flags.
747 4208 : DeleteAreaHandler aFunc(*pDocument, nDelFlag);
748 4208 : sc::CellStoreType::iterator itPos = maCells.position(nStartRow).first;
749 4208 : sc::ProcessBlock(itPos, maCells, aFunc, nStartRow, nEndRow);
750 4208 : aFunc.endFormulas(); // Have the formula cells stop listening.
751 4208 : aFunc.getSpans().getRows(aDeletedRows);
752 :
753 : // Get the deletion spans.
754 8416 : sc::SingleColumnSpanSet::SpansType aSpans;
755 4208 : aFunc.getSpans().getSpans(aSpans);
756 :
757 4208 : sc::ColumnBlockPosition aBlockPos;
758 4208 : aBlockPos.miCellPos = itPos;
759 4208 : aBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
760 :
761 : // Delete the cells for real.
762 4208 : std::for_each(aSpans.begin(), aSpans.end(), EmptyCells(aBlockPos, *this, maCells, maCellTextAttrs));
763 8416 : CellStorageModified();
764 : }
765 :
766 14599 : if ( nDelFlag & IDF_EDITATTR )
767 : {
768 : OSL_ENSURE( nContFlag == 0, "DeleteArea: Wrong Flags" );
769 8 : RemoveEditAttribs( nStartRow, nEndRow );
770 : }
771 :
772 : // Delete attributes just now
773 14599 : if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB)
774 3848 : pAttrArray->DeleteArea( nStartRow, nEndRow );
775 10751 : else if ((nDelFlag & IDF_ATTRIB) != 0)
776 94 : pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
777 :
778 : // Broadcast on only cells that were deleted; no point broadcasting on
779 : // cells that were already empty before the deletion.
780 14599 : BroadcastCells(aDeletedRows);
781 14599 : }
782 :
783 80167 : bool ScColumn::InitBlockPosition( sc::ColumnBlockPosition& rBlockPos )
784 : {
785 80167 : rBlockPos.miBroadcasterPos = maBroadcasters.begin();
786 80167 : rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
787 80167 : rBlockPos.miCellPos = maCells.begin();
788 80167 : return true;
789 : }
790 :
791 967 : bool ScColumn::InitBlockPosition( sc::ColumnBlockConstPosition& rBlockPos ) const
792 : {
793 967 : rBlockPos.miBroadcasterPos = maBroadcasters.begin();
794 967 : rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
795 967 : rBlockPos.miCellPos = maCells.begin();
796 967 : return true;
797 : }
798 :
799 : namespace {
800 :
801 : class CopyAttrArrayByRange : std::unary_function<sc::SingleColumnSpanSet::Span, void>
802 : {
803 : ScAttrArray& mrDestAttrArray;
804 : ScAttrArray& mrSrcAttrArray;
805 : long mnRowOffset;
806 : public:
807 0 : CopyAttrArrayByRange(ScAttrArray& rDestAttrArray, ScAttrArray& rSrcAttrArray, long nRowOffset) :
808 0 : mrDestAttrArray(rDestAttrArray), mrSrcAttrArray(rSrcAttrArray), mnRowOffset(nRowOffset) {}
809 :
810 0 : void operator() (const sc::SingleColumnSpanSet::Span& rSpan)
811 : {
812 : mrDestAttrArray.CopyAreaSafe(
813 0 : rSpan.mnRow1+mnRowOffset, rSpan.mnRow2+mnRowOffset, mnRowOffset, mrSrcAttrArray);
814 0 : }
815 : };
816 :
817 : class CopyCellsFromClipHandler
818 : {
819 : sc::CopyFromClipContext& mrCxt;
820 : ScColumn& mrSrcCol;
821 : ScColumn& mrDestCol;
822 : SCTAB mnTab;
823 : SCCOL mnCol;
824 : long mnRowOffset;
825 : sc::ColumnBlockPosition maDestBlockPos;
826 :
827 101 : bool isDateCell(SCROW nSrcRow) const
828 : {
829 101 : ScDocument* pSrcDoc = mrCxt.getClipDoc(); // clip document is the source.
830 101 : sal_uLong nNumIndex = static_cast<const SfxUInt32Item*>(mrSrcCol.GetAttr(nSrcRow, ATTR_VALUE_FORMAT))->GetValue();
831 101 : short nType = pSrcDoc->GetFormatTable()->GetType(nNumIndex);
832 101 : return (nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME);
833 : }
834 :
835 0 : void insertRefCell(SCROW nSrcRow, SCROW nDestRow)
836 : {
837 0 : ScAddress aSrcPos(mnCol, nSrcRow, mnTab);
838 0 : ScAddress aDestPos(mnCol, nDestRow, mnTab);
839 : ScSingleRefData aRef;
840 0 : aRef.InitAddress(aSrcPos);
841 0 : aRef.SetFlag3D(true);
842 :
843 0 : ScTokenArray aArr;
844 0 : aArr.AddSingleReference(aRef);
845 :
846 : mrDestCol.SetFormulaCell(
847 0 : maDestBlockPos, nDestRow, new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos, &aArr));
848 0 : }
849 :
850 : public:
851 90 : CopyCellsFromClipHandler(sc::CopyFromClipContext& rCxt, ScColumn& rSrcCol, ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, long nRowOffset) :
852 : mrCxt(rCxt),
853 : mrSrcCol(rSrcCol),
854 : mrDestCol(rDestCol),
855 : mnTab(nDestTab),
856 : mnCol(nDestCol),
857 90 : mnRowOffset(nRowOffset)
858 : {
859 90 : sc::ColumnBlockPosition* p = mrCxt.getBlockPosition(nDestTab, nDestCol);
860 90 : if (p)
861 90 : maDestBlockPos = *p;
862 : else
863 0 : mrDestCol.InitBlockPosition(maDestBlockPos);
864 90 : }
865 :
866 170 : void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
867 : {
868 170 : if (node.type == sc::element_type_empty)
869 0 : return;
870 :
871 170 : SCROW nSrcRow1 = node.position + nOffset;
872 :
873 170 : sal_uInt16 nFlags = mrCxt.getInsertFlag();
874 170 : bool bNumeric = (nFlags & IDF_VALUE) != 0;
875 170 : bool bDateTime = (nFlags & IDF_DATETIME) != 0;
876 170 : bool bString = (nFlags & IDF_STRING) != 0;
877 170 : bool bBoolean = (nFlags & IDF_SPECIAL_BOOLEAN) != 0;
878 170 : bool bFormula = (nFlags & IDF_FORMULA) != 0;
879 :
880 170 : bool bAsLink = mrCxt.isAsLink();
881 :
882 170 : switch (node.type)
883 : {
884 : case sc::element_type_numeric:
885 : {
886 : // We need to copy numeric cells individually because of date type check.
887 81 : sc::numeric_block::const_iterator it = sc::numeric_block::begin(*node.data);
888 81 : std::advance(it, nOffset);
889 81 : sc::numeric_block::const_iterator itEnd = it;
890 81 : std::advance(itEnd, nDataSize);
891 182 : for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
892 : {
893 101 : bool bCopy = isDateCell(nSrcRow) ? bDateTime : bNumeric;
894 101 : if (!bCopy)
895 0 : continue;
896 :
897 101 : if (bAsLink)
898 0 : insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
899 : else
900 101 : mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, *it);
901 : }
902 : }
903 81 : break;
904 : case sc::element_type_string:
905 : {
906 86 : if (!bString)
907 0 : return;
908 :
909 86 : sc::string_block::const_iterator it = sc::string_block::begin(*node.data);
910 86 : std::advance(it, nOffset);
911 86 : sc::string_block::const_iterator itEnd = it;
912 86 : std::advance(itEnd, nDataSize);
913 176 : for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
914 : {
915 90 : if (bAsLink)
916 0 : insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
917 : else
918 90 : mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, *it);
919 : }
920 : }
921 86 : break;
922 : case sc::element_type_edittext:
923 : {
924 0 : if (!bString)
925 0 : return;
926 :
927 0 : sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
928 0 : std::advance(it, nOffset);
929 0 : sc::edittext_block::const_iterator itEnd = it;
930 0 : std::advance(itEnd, nDataSize);
931 0 : for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
932 : {
933 :
934 0 : if (bAsLink)
935 0 : insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
936 : else
937 0 : mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, **it);
938 : }
939 : }
940 0 : break;
941 : case sc::element_type_formula:
942 : {
943 3 : sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
944 3 : std::advance(it, nOffset);
945 3 : sc::formula_block::const_iterator itEnd = it;
946 3 : std::advance(itEnd, nDataSize);
947 15 : for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
948 : {
949 12 : ScFormulaCell& rSrcCell = const_cast<ScFormulaCell&>(**it);
950 12 : bool bForceFormula = false;
951 12 : if (bBoolean)
952 : {
953 : // See if the formula consists of =TRUE() or =FALSE().
954 0 : ScTokenArray* pCode = rSrcCell.GetCode();
955 0 : if (pCode && pCode->GetLen() == 1)
956 : {
957 0 : const formula::FormulaToken* p = pCode->First();
958 0 : if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
959 : // This is a boolean formula.
960 0 : bForceFormula = true;
961 : }
962 : }
963 :
964 12 : ScAddress aDestPos(mnCol, nSrcRow + mnRowOffset, mnTab);
965 12 : if (bFormula || bForceFormula)
966 : {
967 24 : if (bAsLink)
968 0 : insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
969 : else
970 : {
971 : mrDestCol.SetFormulaCell(
972 : maDestBlockPos, nSrcRow + mnRowOffset,
973 12 : new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos));
974 : }
975 : }
976 0 : else if (bNumeric || bDateTime || bString)
977 : {
978 : // Always just copy the original row to the Undo Documen;
979 : // do not create Value/string cells from formulas
980 :
981 0 : sal_uInt16 nErr = rSrcCell.GetErrCode();
982 0 : if (nErr)
983 : {
984 : // error codes are cloned with values
985 0 : if (bNumeric)
986 : {
987 0 : if (bAsLink)
988 0 : insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
989 : else
990 : {
991 0 : ScFormulaCell* pErrCell = new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos);
992 0 : pErrCell->SetErrCode(nErr);
993 : mrDestCol.SetFormulaCell(
994 0 : maDestBlockPos, nSrcRow + mnRowOffset, pErrCell);
995 : }
996 : }
997 : }
998 0 : else if (rSrcCell.IsValue())
999 : {
1000 0 : bool bCopy = isDateCell(nSrcRow) ? bDateTime : bNumeric;
1001 0 : if (!bCopy)
1002 0 : continue;
1003 :
1004 0 : if (bAsLink)
1005 0 : insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1006 : else
1007 0 : mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, rSrcCell.GetValue());
1008 : }
1009 0 : else if (bString)
1010 : {
1011 0 : OUString aStr = rSrcCell.GetString();
1012 0 : if (aStr.isEmpty())
1013 : // do not clone empty string
1014 0 : continue;
1015 :
1016 0 : if (bAsLink)
1017 0 : insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1018 0 : else if (rSrcCell.IsMultilineResult())
1019 : {
1020 : // Clone as an edit text object.
1021 0 : ScFieldEditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
1022 0 : rEngine.SetText(aStr);
1023 0 : mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, rEngine.CreateTextObject());
1024 : }
1025 : else
1026 0 : mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aStr);
1027 : }
1028 : }
1029 : }
1030 : }
1031 3 : break;
1032 : default:
1033 : ;
1034 : }
1035 : }
1036 : };
1037 :
1038 : }
1039 :
1040 : // rColumn = source
1041 : // nRow1, nRow2 = target position
1042 :
1043 170 : void ScColumn::CopyFromClip(
1044 : sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn )
1045 : {
1046 170 : if ((rCxt.getInsertFlag() & IDF_ATTRIB) != 0)
1047 : {
1048 90 : if (rCxt.isSkipAttrForEmptyCells())
1049 : {
1050 : // copy only attributes for non-empty cells between nRow1-nDy and nRow2-nDy.
1051 0 : sc::SingleColumnSpanSet aSpanSet;
1052 0 : aSpanSet.scan(rColumn, nRow1-nDy, nRow2-nDy);
1053 0 : sc::SingleColumnSpanSet::SpansType aSpans;
1054 0 : aSpanSet.getSpans(aSpans);
1055 : std::for_each(
1056 0 : aSpans.begin(), aSpans.end(), CopyAttrArrayByRange(*rColumn.pAttrArray, *pAttrArray, nDy));
1057 : }
1058 : else
1059 90 : rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray );
1060 : }
1061 170 : if ((rCxt.getInsertFlag() & IDF_CONTENTS) == 0)
1062 160 : return;
1063 :
1064 90 : if (rCxt.isAsLink() && rCxt.getInsertFlag() == IDF_ALL)
1065 : {
1066 : // We also reference empty cells for "ALL"
1067 : // IDF_ALL must always contain more flags when compared to "Insert contents" as
1068 : // contents can be selected one by one!
1069 :
1070 0 : ScAddress aDestPos( nCol, 0, nTab ); // Adapt Row
1071 :
1072 : // Create reference (Source Position)
1073 : ScSingleRefData aRef;
1074 0 : aRef.nCol = rColumn.nCol;
1075 : // Adapt nRow
1076 0 : aRef.nTab = rColumn.nTab;
1077 0 : aRef.InitFlags(); // -> All absolute
1078 0 : aRef.SetFlag3D(true);
1079 :
1080 0 : for (SCROW nDestRow = nRow1; nDestRow <= nRow2; nDestRow++)
1081 : {
1082 0 : aRef.nRow = nDestRow - nDy; // Source row
1083 0 : aDestPos.SetRow( nDestRow );
1084 :
1085 0 : aRef.CalcRelFromAbs( aDestPos );
1086 0 : ScTokenArray aArr;
1087 0 : aArr.AddSingleReference( aRef );
1088 0 : SetFormulaCell(nDestRow, new ScFormulaCell(pDocument, aDestPos, &aArr));
1089 0 : }
1090 :
1091 0 : return;
1092 : }
1093 :
1094 : // nRow1 to nRow2 is for destination (this) column. Subtract nDy to get the source range.
1095 :
1096 : // Copy all cells in the source column (rColumn) from nRow1-nDy to nRow2-nDy to this column.
1097 90 : CopyCellsFromClipHandler aFunc(rCxt, rColumn, *this, nTab, nCol, nDy);
1098 90 : sc::ParseBlock(rColumn.maCells.begin(), rColumn.maCells, aFunc, nRow1-nDy, nRow2-nDy);
1099 : }
1100 :
1101 0 : void ScColumn::MixMarked(
1102 : sc::MixDocContext& rCxt, const ScMarkData& rMark, sal_uInt16 nFunction,
1103 : bool bSkipEmpty, const ScColumn& rSrcCol )
1104 : {
1105 : SCROW nRow1, nRow2;
1106 :
1107 0 : if (rMark.IsMultiMarked())
1108 : {
1109 0 : ScMarkArrayIter aIter( rMark.GetArray()+nCol );
1110 0 : while (aIter.Next( nRow1, nRow2 ))
1111 0 : MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol);
1112 : }
1113 0 : }
1114 :
1115 : namespace {
1116 :
1117 : // Result in rVal1
1118 0 : bool lcl_DoFunction( double& rVal1, double nVal2, sal_uInt16 nFunction )
1119 : {
1120 0 : bool bOk = false;
1121 0 : switch (nFunction)
1122 : {
1123 : case PASTE_ADD:
1124 0 : bOk = SubTotal::SafePlus( rVal1, nVal2 );
1125 0 : break;
1126 : case PASTE_SUB:
1127 0 : nVal2 = -nVal2; // FIXME: Can we do this alwyas without error?
1128 0 : bOk = SubTotal::SafePlus( rVal1, nVal2 );
1129 0 : break;
1130 : case PASTE_MUL:
1131 0 : bOk = SubTotal::SafeMult( rVal1, nVal2 );
1132 0 : break;
1133 : case PASTE_DIV:
1134 0 : bOk = SubTotal::SafeDiv( rVal1, nVal2 );
1135 0 : break;
1136 : }
1137 0 : return bOk;
1138 : }
1139 :
1140 0 : void lcl_AddCode( ScTokenArray& rArr, const ScFormulaCell* pCell )
1141 : {
1142 0 : rArr.AddOpCode(ocOpen);
1143 :
1144 0 : ScTokenArray* pCode = pCell->GetCode();
1145 0 : if (pCode)
1146 : {
1147 0 : const formula::FormulaToken* pToken = pCode->First();
1148 0 : while (pToken)
1149 : {
1150 0 : rArr.AddToken( *pToken );
1151 0 : pToken = pCode->Next();
1152 : }
1153 : }
1154 :
1155 0 : rArr.AddOpCode(ocClose);
1156 0 : }
1157 :
1158 0 : class MixDataHandler
1159 : {
1160 : ScColumn& mrDestColumn;
1161 :
1162 : sc::CellStoreType& mrDestCells;
1163 : sc::CellStoreType::iterator miDestPos;
1164 :
1165 : sc::CellTextAttrStoreType& mrDestAttrs;
1166 :
1167 : sc::CellStoreType maNewCells;
1168 : sc::CellStoreType::iterator miNewCellsPos;
1169 :
1170 : size_t mnRowOffset;
1171 : sal_uInt16 mnFunction;
1172 :
1173 : bool mbSkipEmpty;
1174 :
1175 : public:
1176 0 : MixDataHandler(
1177 : sc::ColumnBlockPosition* pBlockPos,
1178 : ScColumn& rDestColumn,
1179 : sc::CellStoreType& rDestCells,
1180 : sc::CellTextAttrStoreType& rDestAttrs,
1181 : SCROW nRow1, SCROW nRow2,
1182 : sal_uInt16 nFunction, bool bSkipEmpty) :
1183 : mrDestColumn(rDestColumn),
1184 : mrDestCells(rDestCells),
1185 : mrDestAttrs(rDestAttrs),
1186 0 : maNewCells(nRow2 - nRow1 + 1),
1187 : miNewCellsPos(maNewCells.begin()),
1188 : mnRowOffset(nRow1),
1189 : mnFunction(nFunction),
1190 0 : mbSkipEmpty(bSkipEmpty)
1191 : {
1192 0 : if (pBlockPos)
1193 0 : miDestPos = pBlockPos->miCellPos;
1194 : else
1195 0 : miDestPos = mrDestCells.begin();
1196 0 : }
1197 :
1198 0 : void operator() (size_t nRow, double f)
1199 : {
1200 0 : std::pair<sc::CellStoreType::iterator, size_t> aPos = mrDestCells.position(miDestPos, nRow);
1201 0 : miDestPos = aPos.first;
1202 0 : switch (miDestPos->type)
1203 : {
1204 : case sc::element_type_numeric:
1205 : {
1206 : // Both src and dest are of numeric type.
1207 0 : bool bOk = lcl_DoFunction(f, sc::numeric_block::at(*miDestPos->data, aPos.second), mnFunction);
1208 :
1209 0 : if (bOk)
1210 0 : miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f);
1211 : else
1212 : {
1213 : ScFormulaCell* pFC =
1214 : new ScFormulaCell(
1215 0 : &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()));
1216 :
1217 0 : pFC->SetErrCode(errNoValue);
1218 0 : miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, pFC);
1219 : }
1220 : }
1221 0 : break;
1222 : case sc::element_type_formula:
1223 : {
1224 : // Combination of value and at least one formula -> Create formula
1225 0 : ScTokenArray aArr;
1226 :
1227 : // First row
1228 0 : aArr.AddDouble(f);
1229 :
1230 : // Operator
1231 0 : OpCode eOp = ocAdd;
1232 0 : switch (mnFunction)
1233 : {
1234 0 : case PASTE_ADD: eOp = ocAdd; break;
1235 0 : case PASTE_SUB: eOp = ocSub; break;
1236 0 : case PASTE_MUL: eOp = ocMul; break;
1237 0 : case PASTE_DIV: eOp = ocDiv; break;
1238 : }
1239 0 : aArr.AddOpCode(eOp); // Function
1240 :
1241 : // Second row
1242 0 : ScFormulaCell* pDest = sc::formula_block::at(*miDestPos->data, aPos.second);
1243 0 : lcl_AddCode(aArr, pDest);
1244 :
1245 0 : miNewCellsPos = maNewCells.set(
1246 : miNewCellsPos, nRow-mnRowOffset,
1247 : new ScFormulaCell(
1248 0 : &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), &aArr));
1249 : }
1250 0 : break;
1251 : case sc::element_type_string:
1252 : case sc::element_type_edittext:
1253 : case sc::element_type_empty:
1254 : {
1255 : // Destination cell is not a number. Just take the source cell.
1256 0 : miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f);
1257 : }
1258 0 : break;
1259 : default:
1260 : ;
1261 : }
1262 0 : }
1263 :
1264 0 : void operator() (size_t nRow, const OUString& rStr)
1265 : {
1266 0 : miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, rStr);
1267 0 : }
1268 :
1269 0 : void operator() (size_t nRow, const EditTextObject* p)
1270 : {
1271 0 : miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, p->Clone());
1272 0 : }
1273 :
1274 0 : void operator() (size_t nRow, const ScFormulaCell* p)
1275 : {
1276 0 : std::pair<sc::CellStoreType::iterator, size_t> aPos = mrDestCells.position(miDestPos, nRow);
1277 0 : miDestPos = aPos.first;
1278 0 : switch (miDestPos->type)
1279 : {
1280 : case sc::element_type_numeric:
1281 : {
1282 : // Source is formula, and dest is value.
1283 0 : ScTokenArray aArr;
1284 :
1285 : // First row
1286 0 : lcl_AddCode(aArr, p);
1287 :
1288 : // Operator
1289 0 : OpCode eOp = ocAdd;
1290 0 : switch (mnFunction)
1291 : {
1292 0 : case PASTE_ADD: eOp = ocAdd; break;
1293 0 : case PASTE_SUB: eOp = ocSub; break;
1294 0 : case PASTE_MUL: eOp = ocMul; break;
1295 0 : case PASTE_DIV: eOp = ocDiv; break;
1296 : }
1297 0 : aArr.AddOpCode(eOp); // Function
1298 :
1299 : // Second row
1300 0 : aArr.AddDouble(sc::numeric_block::at(*miDestPos->data, aPos.second));
1301 :
1302 0 : miNewCellsPos = maNewCells.set(
1303 : miNewCellsPos, nRow-mnRowOffset,
1304 : new ScFormulaCell(
1305 0 : &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), &aArr));
1306 : }
1307 0 : break;
1308 : case sc::element_type_formula:
1309 : {
1310 : // Both are formulas.
1311 0 : ScTokenArray aArr;
1312 :
1313 : // First row
1314 0 : lcl_AddCode(aArr, p);
1315 :
1316 : // Operator
1317 0 : OpCode eOp = ocAdd;
1318 0 : switch (mnFunction)
1319 : {
1320 0 : case PASTE_ADD: eOp = ocAdd; break;
1321 0 : case PASTE_SUB: eOp = ocSub; break;
1322 0 : case PASTE_MUL: eOp = ocMul; break;
1323 0 : case PASTE_DIV: eOp = ocDiv; break;
1324 : }
1325 0 : aArr.AddOpCode(eOp); // Function
1326 :
1327 : // Second row
1328 0 : ScFormulaCell* pDest = sc::formula_block::at(*miDestPos->data, aPos.second);
1329 0 : lcl_AddCode(aArr, pDest);
1330 :
1331 0 : miNewCellsPos = maNewCells.set(
1332 : miNewCellsPos, nRow-mnRowOffset,
1333 : new ScFormulaCell(
1334 0 : &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), &aArr));
1335 : }
1336 0 : break;
1337 : case sc::element_type_string:
1338 : case sc::element_type_edittext:
1339 : case sc::element_type_empty:
1340 : {
1341 : // Destination cell is not a number. Just take the source cell.
1342 0 : ScAddress aDestPos(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab());
1343 0 : miNewCellsPos = maNewCells.set(
1344 0 : miNewCellsPos, nRow-mnRowOffset, new ScFormulaCell(*p, mrDestColumn.GetDoc(), aDestPos));
1345 : }
1346 0 : break;
1347 : default:
1348 : ;
1349 : }
1350 0 : }
1351 :
1352 : /**
1353 : * Empty cell series in the source (clip) document.
1354 : */
1355 0 : void operator() (mdds::mtv::element_t, size_t nTopRow, size_t nDataSize)
1356 : {
1357 0 : if (mbSkipEmpty)
1358 0 : return;
1359 :
1360 : // Source cells are empty. Treat them as if they have a value of 0.0.
1361 0 : for (size_t i = 0; i < nDataSize; ++i)
1362 : {
1363 0 : size_t nDestRow = nTopRow + i;
1364 0 : std::pair<sc::CellStoreType::iterator, size_t> aPos = mrDestCells.position(miDestPos, nDestRow);
1365 0 : miDestPos = aPos.first;
1366 0 : switch (miDestPos->type)
1367 : {
1368 : case sc::element_type_numeric:
1369 : case sc::element_type_string:
1370 : case sc::element_type_edittext:
1371 : // Dont' do anything.
1372 0 : break;
1373 : case sc::element_type_formula:
1374 : {
1375 0 : ScTokenArray aArr;
1376 :
1377 : // First row
1378 0 : ScFormulaCell* pSrc = sc::formula_block::at(*miDestPos->data, aPos.second);
1379 0 : lcl_AddCode( aArr, pSrc);
1380 :
1381 : // Operator
1382 0 : OpCode eOp = ocAdd;
1383 0 : switch (mnFunction)
1384 : {
1385 0 : case PASTE_ADD: eOp = ocAdd; break;
1386 0 : case PASTE_SUB: eOp = ocSub; break;
1387 0 : case PASTE_MUL: eOp = ocMul; break;
1388 0 : case PASTE_DIV: eOp = ocDiv; break;
1389 : }
1390 :
1391 0 : aArr.AddOpCode(eOp); // Function
1392 0 : aArr.AddDouble(0.0);
1393 :
1394 0 : miNewCellsPos = maNewCells.set(
1395 : miNewCellsPos, nDestRow-mnRowOffset,
1396 : new ScFormulaCell(
1397 0 : &mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab()), &aArr));
1398 : }
1399 0 : break;
1400 : default:
1401 : ;
1402 : }
1403 : }
1404 : }
1405 :
1406 : /**
1407 : * Set the new cells to the destination (this) column.
1408 : */
1409 0 : void commit(sc::ColumnBlockPosition* pDestBlockPos)
1410 : {
1411 0 : sc::ColumnBlockPosition aDestBlockPos;
1412 0 : if (pDestBlockPos)
1413 0 : aDestBlockPos = *pDestBlockPos;
1414 : else
1415 0 : mrDestColumn.InitBlockPosition(aDestBlockPos);
1416 :
1417 : // Stop all formula cells in the destination range first.
1418 0 : sc::ColumnBlockPosition aCopy = aDestBlockPos;
1419 0 : mrDestColumn.EndFormulaListening(aCopy, mnRowOffset, mnRowOffset + maNewCells.size() - 1);
1420 :
1421 : // Move the new cells to the destination range.
1422 0 : sc::CellStoreType::iterator& itDestPos = aDestBlockPos.miCellPos;
1423 0 : sc::CellTextAttrStoreType::iterator& itDestAttrPos = aDestBlockPos.miCellTextAttrPos;
1424 :
1425 0 : sc::CellStoreType::iterator it = maNewCells.begin(), itEnd = maNewCells.end();
1426 0 : for (; it != itEnd; ++it)
1427 : {
1428 0 : bool bHasContent = true;
1429 0 : size_t nDestRow = mnRowOffset + it->position;
1430 :
1431 0 : switch (it->type)
1432 : {
1433 : case sc::element_type_numeric:
1434 : {
1435 0 : sc::numeric_block::iterator itData = sc::numeric_block::begin(*it->data);
1436 0 : sc::numeric_block::iterator itDataEnd = sc::numeric_block::end(*it->data);
1437 0 : itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1438 : }
1439 0 : break;
1440 : case sc::element_type_string:
1441 : {
1442 0 : sc::string_block::iterator itData = sc::string_block::begin(*it->data);
1443 0 : sc::string_block::iterator itDataEnd = sc::string_block::end(*it->data);
1444 0 : itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1445 : }
1446 0 : break;
1447 : case sc::element_type_edittext:
1448 : {
1449 0 : sc::edittext_block::iterator itData = sc::edittext_block::begin(*it->data);
1450 0 : sc::edittext_block::iterator itDataEnd = sc::edittext_block::end(*it->data);
1451 0 : itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1452 : }
1453 0 : break;
1454 : case sc::element_type_formula:
1455 : {
1456 0 : sc::formula_block::iterator itData = sc::formula_block::begin(*it->data);
1457 0 : sc::formula_block::iterator itDataEnd = sc::formula_block::end(*it->data);
1458 0 : itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1459 : }
1460 0 : break;
1461 : case sc::element_type_empty:
1462 : {
1463 0 : itDestPos = mrDestCells.set_empty(itDestPos, nDestRow, nDestRow+it->size-1);
1464 0 : bHasContent = false;
1465 : }
1466 0 : break;
1467 : default:
1468 : ;
1469 : }
1470 :
1471 0 : if (bHasContent)
1472 : {
1473 0 : std::vector<sc::CellTextAttr> aAttrs(it->size, sc::CellTextAttr());
1474 0 : itDestAttrPos = mrDestAttrs.set(itDestAttrPos, nDestRow, aAttrs.begin(), aAttrs.end());
1475 : }
1476 : else
1477 0 : itDestAttrPos = mrDestAttrs.set_empty(itDestAttrPos, nDestRow, nDestRow+it->size-1);
1478 : }
1479 :
1480 0 : maNewCells.release();
1481 :
1482 0 : if (pDestBlockPos)
1483 0 : *pDestBlockPos = aDestBlockPos;
1484 0 : }
1485 : };
1486 :
1487 : }
1488 :
1489 0 : void ScColumn::MixData(
1490 : sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, sal_uInt16 nFunction,
1491 : bool bSkipEmpty, const ScColumn& rSrcCol )
1492 : {
1493 : // destination (this column) block position.
1494 :
1495 0 : sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
1496 0 : MixDataHandler aFunc(p, *this, maCells, maCellTextAttrs, nRow1, nRow2, nFunction, bSkipEmpty);
1497 0 : sc::ParseAll(rSrcCol.maCells.begin(), rSrcCol.maCells, nRow1, nRow2, aFunc, aFunc);
1498 :
1499 0 : aFunc.commit(p);
1500 0 : RegroupFormulaCells(nRow1, nRow2);
1501 0 : CellStorageModified();
1502 0 : }
1503 :
1504 :
1505 356442 : ScAttrIterator* ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
1506 : {
1507 356442 : return new ScAttrIterator( pAttrArray, nStartRow, nEndRow );
1508 : }
1509 :
1510 : namespace {
1511 :
1512 : class StartAllListenersHandler
1513 : {
1514 : ScDocument* mpDoc;
1515 : public:
1516 193536 : StartAllListenersHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
1517 :
1518 72 : void operator() (size_t, ScFormulaCell* p)
1519 : {
1520 72 : p->StartListeningTo(mpDoc);
1521 72 : }
1522 : };
1523 :
1524 : class StartNeededListenerHandler
1525 : {
1526 : ScDocument* mpDoc;
1527 : public:
1528 60416 : StartNeededListenerHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
1529 :
1530 29 : void operator() (size_t, ScFormulaCell* p)
1531 : {
1532 29 : if (p->NeedsListening())
1533 0 : p->StartListeningTo(mpDoc);
1534 29 : }
1535 : };
1536 :
1537 : }
1538 :
1539 193536 : void ScColumn::StartAllListeners()
1540 : {
1541 193536 : StartAllListenersHandler aFunc(pDocument);
1542 193536 : sc::ProcessFormula(maCells, aFunc);
1543 193536 : }
1544 :
1545 :
1546 60416 : void ScColumn::StartNeededListeners()
1547 : {
1548 60416 : StartNeededListenerHandler aFunc(pDocument);
1549 60416 : sc::ProcessFormula(maCells, aFunc);
1550 60416 : }
1551 :
1552 : namespace {
1553 :
1554 : class StartListeningInAreaHandler
1555 : {
1556 : sc::StartListeningContext& mrCxt;
1557 : public:
1558 90 : StartListeningInAreaHandler(sc::StartListeningContext& rCxt) : mrCxt(rCxt) {}
1559 :
1560 12 : void operator() (size_t /*nRow*/, ScFormulaCell* p)
1561 : {
1562 12 : p->StartListeningTo(mrCxt);
1563 12 : }
1564 : };
1565 :
1566 : }
1567 :
1568 90 : void ScColumn::StartListeningInArea( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 )
1569 : {
1570 90 : StartListeningInAreaHandler aFunc(rCxt);
1571 90 : sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
1572 90 : }
1573 :
1574 :
1575 : /**
1576 : * Returns true if the cell format was set as well
1577 : */
1578 18493 : bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
1579 : formula::FormulaGrammar::AddressConvention eConv,
1580 : ScSetStringParam* pParam )
1581 : {
1582 18493 : bool bNumFmtSet = false;
1583 18493 : if (!ValidRow(nRow))
1584 0 : return false;
1585 :
1586 18493 : ScCellValue aNewCell;
1587 18493 : if (rString.Len() > 0)
1588 : {
1589 17267 : ScSetStringParam aParam;
1590 17267 : if (pParam)
1591 14873 : aParam = *pParam;
1592 :
1593 17267 : sal_uInt32 nIndex = 0;
1594 17267 : sal_uInt32 nOldIndex = 0;
1595 : sal_Unicode cFirstChar;
1596 17267 : if (!aParam.mpNumFormatter)
1597 16990 : aParam.mpNumFormatter = pDocument->GetFormatTable();
1598 :
1599 17267 : nIndex = nOldIndex = GetNumberFormat( nRow );
1600 34534 : if ( rString.Len() > 1
1601 17267 : && aParam.mpNumFormatter->GetType(nIndex) != NUMBERFORMAT_TEXT )
1602 15603 : cFirstChar = rString.GetChar(0);
1603 : else
1604 1664 : cFirstChar = 0; // Text
1605 :
1606 17267 : if ( cFirstChar == '=' )
1607 : {
1608 511 : if ( rString.Len() == 1 ) // = Text
1609 0 : aNewCell.set(rString);
1610 : else // = Formula
1611 : aNewCell.set(
1612 : new ScFormulaCell(
1613 : pDocument, ScAddress(nCol, nRow, nTabP), rString,
1614 : formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_DEFAULT, eConv),
1615 511 : MM_NONE));
1616 : }
1617 16756 : else if ( cFirstChar == '\'') // 'Text
1618 : {
1619 4 : bool bNumeric = false;
1620 4 : if (aParam.mbHandleApostrophe)
1621 : {
1622 : // Cell format is not 'Text', and the first char
1623 : // is an apostrophe. Check if the input is considered a number.
1624 4 : String aTest = rString.Copy(1);
1625 : double fTest;
1626 4 : bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest);
1627 4 : if (bNumeric)
1628 : // This is a number. Strip out the first char.
1629 3 : aNewCell.set(aTest);
1630 : }
1631 4 : if (!bNumeric)
1632 : // This is normal text. Take it as-is.
1633 1 : aNewCell.set(rString);
1634 : }
1635 : else
1636 : {
1637 : double nVal;
1638 :
1639 : do
1640 : {
1641 16752 : if (aParam.mbDetectNumberFormat)
1642 : {
1643 2238 : if (!aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
1644 1540 : break;
1645 :
1646 698 : if ( aParam.mpNumFormatter )
1647 : {
1648 : // convert back to the original language if a built-in format was detected
1649 698 : const SvNumberformat* pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex );
1650 698 : if ( pOldFormat )
1651 698 : nIndex = aParam.mpNumFormatter->GetFormatForLanguageIfBuiltIn( nIndex, pOldFormat->GetLanguage() );
1652 : }
1653 :
1654 698 : aNewCell.set(nVal);
1655 698 : if ( nIndex != nOldIndex)
1656 : {
1657 : // #i22345# New behavior: Apply the detected number format only if
1658 : // the old one was the default number, date, time or boolean format.
1659 : // Exception: If the new format is boolean, always apply it.
1660 :
1661 98 : sal_Bool bOverwrite = false;
1662 98 : const SvNumberformat* pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex );
1663 98 : if ( pOldFormat )
1664 : {
1665 98 : short nOldType = pOldFormat->GetType() & ~NUMBERFORMAT_DEFINED;
1666 98 : if ( nOldType == NUMBERFORMAT_NUMBER || nOldType == NUMBERFORMAT_DATE ||
1667 0 : nOldType == NUMBERFORMAT_TIME || nOldType == NUMBERFORMAT_LOGICAL )
1668 : {
1669 98 : if ( nOldIndex == aParam.mpNumFormatter->GetStandardFormat(
1670 98 : nOldType, pOldFormat->GetLanguage() ) )
1671 : {
1672 98 : bOverwrite = true; // default of these types can be overwritten
1673 : }
1674 : }
1675 : }
1676 98 : if ( !bOverwrite && aParam.mpNumFormatter->GetType( nIndex ) == NUMBERFORMAT_LOGICAL )
1677 : {
1678 0 : bOverwrite = true; // overwrite anything if boolean was detected
1679 : }
1680 :
1681 98 : if ( bOverwrite )
1682 : {
1683 : ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT,
1684 98 : (sal_uInt32) nIndex) );
1685 98 : bNumFmtSet = true;
1686 : }
1687 : }
1688 : }
1689 14514 : else if (aParam.meSetTextNumFormat != ScSetStringParam::Always)
1690 : {
1691 : // Only check if the string is a regular number.
1692 282 : const LocaleDataWrapper* pLocale = aParam.mpNumFormatter->GetLocaleData();
1693 282 : if (!pLocale)
1694 179 : break;
1695 :
1696 282 : LocaleDataItem aLocaleItem = pLocale->getLocaleItem();
1697 282 : const OUString& rDecSep = aLocaleItem.decimalSeparator;
1698 282 : const OUString& rGroupSep = aLocaleItem.thousandSeparator;
1699 282 : if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1)
1700 0 : break;
1701 :
1702 282 : sal_Unicode dsep = rDecSep.getStr()[0];
1703 282 : sal_Unicode gsep = rGroupSep.getStr()[0];
1704 :
1705 282 : if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, nVal))
1706 179 : break;
1707 :
1708 103 : aNewCell.set(nVal);
1709 : }
1710 : }
1711 : while (false);
1712 :
1713 16752 : if (aNewCell.meType == CELLTYPE_NONE)
1714 : {
1715 15951 : if (aParam.meSetTextNumFormat != ScSetStringParam::Never && aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
1716 : {
1717 : // Set the cell format type to Text.
1718 179 : sal_uInt32 nFormat = aParam.mpNumFormatter->GetStandardFormat(NUMBERFORMAT_TEXT);
1719 179 : ScPatternAttr aNewAttrs(pDocument->GetPool());
1720 179 : SfxItemSet& rSet = aNewAttrs.GetItemSet();
1721 179 : rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat) );
1722 179 : ApplyPattern(nRow, aNewAttrs);
1723 : }
1724 :
1725 15951 : aNewCell.set(rString);
1726 : }
1727 : }
1728 : }
1729 :
1730 18493 : aNewCell.release(*this, nRow);
1731 :
1732 : // Do not set Formats and Formulas here anymore!
1733 : // These are queried during output
1734 :
1735 18493 : return bNumFmtSet;
1736 : }
1737 :
1738 417 : void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
1739 : {
1740 417 : sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1741 417 : maCells.set(it, nRow, pEditText);
1742 417 : maCellTextAttrs.set(nRow, sc::CellTextAttr());
1743 417 : RegroupFormulaCells(nRow);
1744 417 : CellStorageModified();
1745 :
1746 417 : BroadcastNewCell(nRow);
1747 417 : }
1748 :
1749 0 : void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, EditTextObject* pEditText )
1750 : {
1751 0 : rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
1752 0 : rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText);
1753 0 : rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
1754 0 : rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1755 0 : RegroupFormulaCells(nRow);
1756 0 : CellStorageModified();
1757 :
1758 0 : BroadcastNewCell(nRow);
1759 0 : }
1760 :
1761 0 : void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const EditTextObject& rEditText )
1762 : {
1763 0 : if (pDocument->GetEditPool() == rEditText.GetPool())
1764 : {
1765 0 : SetEditText(rBlockPos, nRow, rEditText.Clone());
1766 0 : return;
1767 : }
1768 :
1769 : //! another "spool"
1770 : // Sadly there is no other way to change the Pool than to
1771 : // "spool" the Object through a corresponding Engine
1772 0 : EditEngine& rEngine = pDocument->GetEditEngine();
1773 0 : if (!rEditText.HasOnlineSpellErrors())
1774 : {
1775 0 : rEngine.SetText(rEditText);
1776 0 : SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
1777 0 : return;
1778 : }
1779 :
1780 0 : sal_uLong nControl = rEngine.GetControlWord();
1781 0 : const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
1782 0 : bool bNewControl = (nControl & nSpellControl) != nSpellControl;
1783 0 : if (bNewControl)
1784 0 : rEngine.SetControlWord(nControl | nSpellControl);
1785 0 : rEngine.SetText(rEditText);
1786 0 : EditTextObject* pData = rEngine.CreateTextObject();
1787 0 : if (bNewControl)
1788 0 : rEngine.SetControlWord(nControl);
1789 :
1790 0 : SetEditText(rBlockPos, nRow, pData);
1791 : }
1792 :
1793 0 : void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
1794 : {
1795 0 : if (pEditPool && pDocument->GetEditPool() == pEditPool)
1796 : {
1797 0 : SetEditText(nRow, rEditText.Clone());
1798 0 : return;
1799 : }
1800 :
1801 : //! another "spool"
1802 : // Sadly there is no other way to change the Pool than to
1803 : // "spool" the Object through a corresponding Engine
1804 0 : EditEngine& rEngine = pDocument->GetEditEngine();
1805 0 : if (!rEditText.HasOnlineSpellErrors())
1806 : {
1807 0 : rEngine.SetText(rEditText);
1808 0 : SetEditText(nRow, rEngine.CreateTextObject());
1809 0 : return;
1810 : }
1811 :
1812 0 : sal_uLong nControl = rEngine.GetControlWord();
1813 0 : const sal_uLong nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
1814 0 : bool bNewControl = (nControl & nSpellControl) != nSpellControl;
1815 0 : if (bNewControl)
1816 0 : rEngine.SetControlWord(nControl | nSpellControl);
1817 0 : rEngine.SetText(rEditText);
1818 0 : EditTextObject* pData = rEngine.CreateTextObject();
1819 0 : if (bNewControl)
1820 0 : rEngine.SetControlWord(nControl);
1821 :
1822 0 : SetEditText(nRow, pData);
1823 : }
1824 :
1825 0 : void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::FormulaGrammar::Grammar eGram )
1826 : {
1827 0 : ScAddress aPos(nCol, nRow, nTab);
1828 :
1829 0 : sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1830 0 : ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, &rArray, eGram);
1831 0 : sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1832 0 : if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1833 0 : pCell->SetNeedNumberFormat(true);
1834 0 : it = maCells.set(it, nRow, pCell);
1835 0 : maCellTextAttrs.set(nRow, sc::CellTextAttr());
1836 0 : CellStorageModified();
1837 :
1838 0 : ActivateNewFormulaCell(it, nRow, *pCell);
1839 0 : }
1840 :
1841 0 : void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
1842 : {
1843 0 : ScAddress aPos(nCol, nRow, nTab);
1844 :
1845 0 : sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1846 0 : ScFormulaCell* pCell = new ScFormulaCell(pDocument, aPos, rFormula, eGram);
1847 0 : sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1848 0 : if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1849 0 : pCell->SetNeedNumberFormat(true);
1850 0 : it = maCells.set(it, nRow, pCell);
1851 0 : maCellTextAttrs.set(nRow, sc::CellTextAttr());
1852 0 : CellStorageModified();
1853 :
1854 0 : ActivateNewFormulaCell(it, nRow, *pCell);
1855 0 : }
1856 :
1857 3668 : ScFormulaCell* ScColumn::SetFormulaCell( SCROW nRow, ScFormulaCell* pCell )
1858 : {
1859 3668 : sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
1860 3668 : sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1861 3668 : if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1862 3667 : pCell->SetNeedNumberFormat(true);
1863 3668 : it = maCells.set(it, nRow, pCell);
1864 3668 : maCellTextAttrs.set(nRow, sc::CellTextAttr());
1865 3668 : CellStorageModified();
1866 :
1867 3668 : ActivateNewFormulaCell(it, nRow, *pCell);
1868 3668 : return pCell;
1869 : }
1870 :
1871 12 : ScFormulaCell* ScColumn::SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell )
1872 : {
1873 12 : rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
1874 12 : sal_uInt32 nCellFormat = GetNumberFormat(nRow);
1875 12 : if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1876 12 : pCell->SetNeedNumberFormat(true);
1877 12 : rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pCell);
1878 24 : rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
1879 12 : rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
1880 12 : CellStorageModified();
1881 :
1882 12 : ActivateNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell);
1883 12 : return pCell;
1884 : }
1885 :
1886 : namespace {
1887 :
1888 : class FilterEntriesHandler
1889 : {
1890 : ScColumn& mrColumn;
1891 : std::vector<ScTypedStrData>& mrStrings;
1892 : bool mbHasDates;
1893 :
1894 0 : void processCell(SCROW nRow, ScRefCellValue& rCell)
1895 : {
1896 0 : SvNumberFormatter* pFormatter = mrColumn.GetDoc().GetFormatTable();
1897 0 : OUString aStr;
1898 0 : sal_uLong nFormat = mrColumn.GetNumberFormat(nRow);
1899 0 : ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter);
1900 :
1901 0 : if (rCell.hasString())
1902 : {
1903 0 : mrStrings.push_back(ScTypedStrData(aStr));
1904 0 : return;
1905 : }
1906 :
1907 0 : double fVal = 0.0;
1908 :
1909 0 : switch (rCell.meType)
1910 : {
1911 : case CELLTYPE_VALUE:
1912 0 : fVal = rCell.mfValue;
1913 0 : break;
1914 :
1915 : case CELLTYPE_FORMULA:
1916 : {
1917 0 : ScFormulaCell* pFC = rCell.mpFormula;
1918 0 : sal_uInt16 nErr = pFC->GetErrCode();
1919 0 : if (nErr)
1920 : {
1921 : // Error cell is evaluated as string (for now).
1922 0 : OUString aErr = ScGlobal::GetErrorString(nErr);
1923 0 : if (!aErr.isEmpty())
1924 : {
1925 0 : mrStrings.push_back(ScTypedStrData(aErr));
1926 0 : return;
1927 0 : }
1928 : }
1929 : else
1930 0 : fVal = pFC->GetValue();
1931 : }
1932 0 : break;
1933 : default:
1934 : ;
1935 : }
1936 :
1937 0 : short nType = pFormatter->GetType(nFormat);
1938 0 : if ((nType & NUMBERFORMAT_DATE) && !(nType & NUMBERFORMAT_TIME))
1939 : {
1940 : // special case for date values. Disregard the time
1941 : // element if the number format is of date type.
1942 0 : fVal = rtl::math::approxFloor(fVal);
1943 0 : mbHasDates = true;
1944 : }
1945 :
1946 0 : mrStrings.push_back(ScTypedStrData(aStr, fVal, ScTypedStrData::Value));
1947 : }
1948 :
1949 : public:
1950 0 : FilterEntriesHandler(ScColumn& rColumn, std::vector<ScTypedStrData>& rStrings) :
1951 0 : mrColumn(rColumn), mrStrings(rStrings), mbHasDates(false) {}
1952 :
1953 0 : void operator() (size_t nRow, double fVal)
1954 : {
1955 0 : ScRefCellValue aCell(fVal);
1956 0 : processCell(nRow, aCell);
1957 0 : }
1958 :
1959 0 : void operator() (size_t nRow, const OUString& rStr)
1960 : {
1961 0 : ScRefCellValue aCell(&rStr);
1962 0 : processCell(nRow, aCell);
1963 0 : }
1964 :
1965 0 : void operator() (size_t nRow, const EditTextObject* p)
1966 : {
1967 0 : ScRefCellValue aCell(p);
1968 0 : processCell(nRow, aCell);
1969 0 : }
1970 :
1971 0 : void operator() (size_t nRow, const ScFormulaCell* p)
1972 : {
1973 0 : ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
1974 0 : processCell(nRow, aCell);
1975 0 : }
1976 :
1977 0 : bool hasDates() const { return mbHasDates; }
1978 : };
1979 :
1980 : }
1981 :
1982 0 : void ScColumn::GetFilterEntries(SCROW nStartRow, SCROW nEndRow, std::vector<ScTypedStrData>& rStrings, bool& rHasDates)
1983 : {
1984 0 : FilterEntriesHandler aFunc(*this, rStrings);
1985 0 : sc::ParseAllNonEmpty(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
1986 0 : rHasDates = aFunc.hasDates();
1987 0 : }
1988 :
1989 : namespace {
1990 :
1991 : /**
1992 : * Iterate over only string and edit-text cells.
1993 : */
1994 : class StrCellIterator
1995 : {
1996 : typedef std::pair<sc::CellStoreType::const_iterator,size_t> PosType;
1997 : PosType maPos;
1998 : sc::CellStoreType::const_iterator miBeg;
1999 : sc::CellStoreType::const_iterator miEnd;
2000 : public:
2001 0 : StrCellIterator(const sc::CellStoreType& rCells, SCROW nStart) :
2002 0 : maPos(rCells.position(nStart)), miBeg(rCells.begin()), miEnd(rCells.end()) {}
2003 :
2004 0 : bool valid() const { return (maPos.first != miEnd); }
2005 :
2006 0 : bool has() const
2007 : {
2008 0 : return (maPos.first->type == sc::element_type_string || maPos.first->type == sc::element_type_edittext);
2009 : }
2010 :
2011 0 : bool prev()
2012 : {
2013 0 : if (!has())
2014 : {
2015 : // Not in a string block. Move back until we hit a string block.
2016 0 : while (!has())
2017 : {
2018 0 : if (maPos.first == miBeg)
2019 0 : return false;
2020 :
2021 0 : --maPos.first; // move to the preceding block.
2022 0 : maPos.second = maPos.first->size - 1; // last cell in the block.
2023 : }
2024 0 : return true;
2025 : }
2026 :
2027 : // We are in a string block.
2028 0 : if (maPos.second > 0)
2029 : {
2030 : // Move back one cell in the same block.
2031 0 : --maPos.second;
2032 : }
2033 : else
2034 : {
2035 : // Move back to the preceding string block.
2036 : while (true)
2037 : {
2038 0 : if (maPos.first == miBeg)
2039 0 : return false;
2040 :
2041 : // Move to the last cell of the previous block.
2042 0 : --maPos.first;
2043 0 : maPos.second = maPos.first->size - 1;
2044 0 : if (has())
2045 0 : break;
2046 : }
2047 : }
2048 0 : return true;
2049 : }
2050 :
2051 0 : bool next()
2052 : {
2053 0 : if (!has())
2054 : {
2055 : // Not in a string block. Move forward until we hit a string block.
2056 0 : while (!has())
2057 : {
2058 0 : ++maPos.first;
2059 0 : if (maPos.first == miEnd)
2060 0 : return false;
2061 :
2062 0 : maPos.second = 0; // First cell in this block.
2063 : }
2064 0 : return true;
2065 : }
2066 :
2067 : // We are in a string block.
2068 0 : ++maPos.second;
2069 0 : if (maPos.second >= maPos.first->size)
2070 : {
2071 : // Move to the next string block.
2072 : while (true)
2073 : {
2074 0 : ++maPos.first;
2075 0 : if (maPos.first == miEnd)
2076 0 : return false;
2077 :
2078 0 : maPos.second = 0;
2079 0 : if (has())
2080 0 : break;
2081 : }
2082 : }
2083 0 : return true;
2084 : }
2085 :
2086 0 : OUString get() const
2087 : {
2088 0 : switch (maPos.first->type)
2089 : {
2090 : case sc::element_type_string:
2091 0 : return sc::string_block::at(*maPos.first->data, maPos.second);
2092 : case sc::element_type_edittext:
2093 : {
2094 0 : const EditTextObject* p = sc::edittext_block::at(*maPos.first->data, maPos.second);
2095 0 : return ScEditUtil::GetString(*p);
2096 : }
2097 : default:
2098 : ;
2099 : }
2100 0 : return OUString();
2101 : }
2102 : };
2103 :
2104 : }
2105 :
2106 : //
2107 : // GetDataEntries - Strings from continuous Section around nRow
2108 : //
2109 :
2110 : // DATENT_MAX - max. number of entries in list for auto entry
2111 : // DATENT_SEARCH - max. number of cells that get transparent - new: only count Strings
2112 : #define DATENT_MAX 200
2113 : #define DATENT_SEARCH 2000
2114 :
2115 0 : bool ScColumn::GetDataEntries(
2116 : SCROW nStartRow, std::set<ScTypedStrData>& rStrings, bool bLimit ) const
2117 : {
2118 : // Start at the specified row position, and collect all string values
2119 : // going upward and downward directions in parallel. The start position
2120 : // cell must be skipped.
2121 :
2122 0 : StrCellIterator aItrUp(maCells, nStartRow);
2123 0 : StrCellIterator aItrDown(maCells, nStartRow+1);
2124 :
2125 0 : bool bMoveUp = aItrUp.valid();
2126 0 : if (!bMoveUp)
2127 : // Current cell is invalid.
2128 0 : return false;
2129 :
2130 : // Skip the start position cell.
2131 0 : bMoveUp = aItrUp.prev(); // Find the previous string cell position.
2132 :
2133 0 : bool bMoveDown = aItrDown.valid();
2134 0 : if (bMoveDown && !aItrDown.has())
2135 0 : bMoveDown = aItrDown.next(); // Find the next string cell position.
2136 :
2137 0 : bool bFound = false;
2138 0 : size_t nCellsSearched = 0;
2139 0 : while (bMoveUp || bMoveDown)
2140 : {
2141 0 : if (bMoveUp)
2142 : {
2143 : // Get the current string and move up.
2144 0 : OUString aStr = aItrUp.get();
2145 0 : if (!aStr.isEmpty())
2146 : {
2147 0 : bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second;
2148 0 : if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
2149 0 : return true; // Maximum reached
2150 0 : bFound = true;
2151 : }
2152 :
2153 0 : if (bLimit && ++nCellsSearched >= DATENT_SEARCH)
2154 0 : return bFound; // max search cell count reached.
2155 :
2156 0 : bMoveUp = aItrUp.prev();
2157 : }
2158 :
2159 0 : if (bMoveDown)
2160 : {
2161 : // Get the current string and move down.
2162 0 : OUString aStr = aItrDown.get();
2163 0 : if (!aStr.isEmpty())
2164 : {
2165 0 : bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second;
2166 0 : if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
2167 0 : return true; // Maximum reached
2168 0 : bFound = true;
2169 : }
2170 :
2171 0 : if (bLimit && ++nCellsSearched >= DATENT_SEARCH)
2172 0 : return bFound; // max search cell count reached.
2173 :
2174 0 : bMoveDown = aItrDown.next();
2175 : }
2176 : }
2177 :
2178 0 : return bFound;
2179 : }
2180 :
2181 : namespace {
2182 :
2183 0 : class FormulaToValueHandler
2184 : {
2185 0 : struct Entry
2186 : {
2187 : SCROW mnRow;
2188 : ScCellValue maValue;
2189 :
2190 0 : Entry(SCROW nRow, double f) : mnRow(nRow), maValue(f) {}
2191 0 : Entry(SCROW nRow, const OUString& rStr) : mnRow(nRow), maValue(rStr) {}
2192 : };
2193 :
2194 : typedef std::vector<Entry> EntriesType;
2195 : EntriesType maEntries;
2196 :
2197 : public:
2198 :
2199 0 : void operator() (size_t nRow, const ScFormulaCell* p)
2200 : {
2201 0 : ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
2202 0 : if (p2->IsValue())
2203 0 : maEntries.push_back(Entry(nRow, p2->GetValue()));
2204 : else
2205 0 : maEntries.push_back(Entry(nRow, p2->GetString()));
2206 0 : }
2207 :
2208 0 : void commitCells(ScColumn& rColumn)
2209 : {
2210 0 : sc::ColumnBlockPosition aBlockPos;
2211 0 : rColumn.InitBlockPosition(aBlockPos);
2212 :
2213 0 : EntriesType::iterator it = maEntries.begin(), itEnd = maEntries.end();
2214 0 : for (; it != itEnd; ++it)
2215 : {
2216 0 : Entry& r = *it;
2217 0 : switch (r.maValue.meType)
2218 : {
2219 : case CELLTYPE_VALUE:
2220 0 : rColumn.SetValue(aBlockPos, r.mnRow, r.maValue.mfValue, false);
2221 0 : break;
2222 : case CELLTYPE_STRING:
2223 0 : rColumn.SetRawString(aBlockPos, r.mnRow, *r.maValue.mpString, false);
2224 : default:
2225 : ;
2226 : }
2227 : }
2228 0 : }
2229 : };
2230 :
2231 : }
2232 :
2233 0 : void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
2234 : {
2235 0 : FormulaToValueHandler aFunc;
2236 0 : sc::CellStoreType::const_iterator itPos = maCells.begin();
2237 :
2238 0 : ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
2239 0 : SCROW nTop = -1;
2240 0 : SCROW nBottom = -1;
2241 0 : const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
2242 0 : while (pPattern)
2243 : {
2244 0 : const ScProtectionAttr* pAttr = (const ScProtectionAttr*)&pPattern->GetItem(ATTR_PROTECTION);
2245 0 : if ( pAttr->GetHideCell() )
2246 0 : DeleteArea( nTop, nBottom, IDF_CONTENTS );
2247 0 : else if ( pAttr->GetHideFormula() )
2248 : {
2249 : // Replace all formula cells between nTop and nBottom with raw value cells.
2250 0 : itPos = sc::ParseFormula(itPos, maCells, nTop, nBottom, aFunc);
2251 : }
2252 :
2253 0 : pPattern = aAttrIter.Next( nTop, nBottom );
2254 : }
2255 :
2256 0 : aFunc.commitCells(*this);
2257 0 : }
2258 :
2259 :
2260 24 : void ScColumn::SetError( SCROW nRow, const sal_uInt16 nError)
2261 : {
2262 24 : if (!ValidRow(nRow))
2263 24 : return;
2264 :
2265 24 : ScFormulaCell* pCell = new ScFormulaCell(pDocument, ScAddress(nCol, nRow, nTab));
2266 24 : pCell->SetErrCode(nError);
2267 :
2268 24 : sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
2269 24 : it = maCells.set(it, nRow, pCell);
2270 24 : maCellTextAttrs.set(nRow, sc::CellTextAttr());
2271 24 : RegroupFormulaCells(nRow);
2272 24 : CellStorageModified();
2273 :
2274 24 : ActivateNewFormulaCell(it, nRow, *pCell);
2275 : }
2276 :
2277 16011 : void ScColumn::SetRawString( SCROW nRow, const OUString& rStr, bool bBroadcast )
2278 : {
2279 16011 : if (!ValidRow(nRow))
2280 16011 : return;
2281 :
2282 16011 : sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
2283 16011 : maCells.set(it, nRow, rStr);
2284 16011 : maCellTextAttrs.set(nRow, sc::CellTextAttr());
2285 16011 : RegroupFormulaCells(nRow);
2286 16011 : CellStorageModified();
2287 :
2288 16011 : if (bBroadcast)
2289 16011 : BroadcastNewCell(nRow);
2290 : }
2291 :
2292 90 : void ScColumn::SetRawString(
2293 : sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const OUString& rStr, bool bBroadcast )
2294 : {
2295 90 : if (!ValidRow(nRow))
2296 90 : return;
2297 :
2298 90 : rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
2299 90 : rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr);
2300 180 : rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2301 90 : rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2302 90 : RegroupFormulaCells(nRow);
2303 90 : CellStorageModified();
2304 :
2305 90 : if (bBroadcast)
2306 90 : BroadcastNewCell(nRow);
2307 : }
2308 :
2309 45149 : void ScColumn::SetValue( SCROW nRow, double fVal )
2310 : {
2311 45149 : if (!ValidRow(nRow))
2312 45149 : return;
2313 :
2314 45149 : sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
2315 45149 : maCells.set(it, nRow, fVal);
2316 45149 : maCellTextAttrs.set(nRow, sc::CellTextAttr());
2317 45149 : RegroupFormulaCells(nRow);
2318 45149 : CellStorageModified();
2319 :
2320 45149 : BroadcastNewCell(nRow);
2321 : }
2322 :
2323 101 : void ScColumn::SetValue(
2324 : sc::ColumnBlockPosition& rBlockPos, SCROW nRow, double fVal, bool bBroadcast )
2325 : {
2326 101 : if (!ValidRow(nRow))
2327 101 : return;
2328 :
2329 101 : rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
2330 101 : rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal);
2331 202 : rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2332 101 : rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2333 101 : RegroupFormulaCells(nRow);
2334 101 : CellStorageModified();
2335 :
2336 101 : if (bBroadcast)
2337 101 : BroadcastNewCell(nRow);
2338 : }
2339 :
2340 13386 : void ScColumn::GetString( SCROW nRow, OUString& rString ) const
2341 : {
2342 13386 : ScRefCellValue aCell = GetCellValue(nRow);
2343 :
2344 : // ugly hack for ordering problem with GetNumberFormat and missing inherited formats
2345 13386 : if (aCell.meType == CELLTYPE_FORMULA)
2346 764 : aCell.mpFormula->MaybeInterpret();
2347 :
2348 13386 : sal_uLong nFormat = GetNumberFormat(nRow);
2349 13386 : Color* pColor = NULL;
2350 13386 : ScCellFormat::GetString(aCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()));
2351 13386 : }
2352 :
2353 0 : const OUString* ScColumn::GetStringCell( SCROW nRow ) const
2354 : {
2355 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2356 0 : sc::CellStoreType::const_iterator it = aPos.first;
2357 0 : if (it == maCells.end())
2358 0 : return NULL;
2359 :
2360 0 : if (it->type != sc::element_type_string)
2361 0 : return NULL;
2362 :
2363 0 : return &sc::string_block::at(*it->data, aPos.second);
2364 : }
2365 :
2366 5 : double* ScColumn::GetValueCell( SCROW nRow )
2367 : {
2368 5 : std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2369 5 : sc::CellStoreType::iterator it = aPos.first;
2370 5 : if (it == maCells.end())
2371 0 : return NULL;
2372 :
2373 5 : if (it->type != sc::element_type_numeric)
2374 0 : return NULL;
2375 :
2376 5 : return &sc::numeric_block::at(*it->data, aPos.second);
2377 : }
2378 :
2379 2837 : void ScColumn::GetInputString( SCROW nRow, OUString& rString ) const
2380 : {
2381 2837 : ScRefCellValue aCell = GetCellValue(nRow);
2382 2837 : sal_uLong nFormat = GetNumberFormat(nRow);
2383 2837 : ScCellFormat::GetInputString(aCell, nFormat, rString, *(pDocument->GetFormatTable()));
2384 2837 : }
2385 :
2386 8252 : double ScColumn::GetValue( SCROW nRow ) const
2387 : {
2388 8252 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2389 8252 : sc::CellStoreType::const_iterator it = aPos.first;
2390 8252 : switch (it->type)
2391 : {
2392 : case sc::element_type_numeric:
2393 7771 : return sc::numeric_block::at(*it->data, aPos.second);
2394 : case sc::element_type_formula:
2395 : {
2396 468 : const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
2397 468 : ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
2398 468 : return p2->IsValue() ? p2->GetValue() : 0.0;
2399 : }
2400 : default:
2401 : ;
2402 : }
2403 :
2404 13 : return 0.0;
2405 : }
2406 :
2407 48 : const EditTextObject* ScColumn::GetEditText( SCROW nRow ) const
2408 : {
2409 48 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2410 48 : sc::CellStoreType::const_iterator it = aPos.first;
2411 48 : if (it == maCells.end())
2412 0 : return NULL;
2413 :
2414 48 : if (it->type != sc::element_type_edittext)
2415 8 : return NULL;
2416 :
2417 40 : return sc::edittext_block::at(*it->data, aPos.second);
2418 : }
2419 :
2420 0 : void ScColumn::RemoveEditTextCharAttribs( SCROW nRow, const ScPatternAttr& rAttr )
2421 : {
2422 0 : std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2423 0 : sc::CellStoreType::iterator it = aPos.first;
2424 0 : if (it == maCells.end())
2425 0 : return;
2426 :
2427 0 : if (it->type != sc::element_type_edittext)
2428 0 : return;
2429 :
2430 0 : EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
2431 0 : ScEditUtil::RemoveCharAttribs(*p, rAttr);
2432 : }
2433 :
2434 39 : void ScColumn::GetFormula( SCROW nRow, OUString& rFormula ) const
2435 : {
2436 39 : const ScFormulaCell* p = FetchFormulaCell(nRow);
2437 39 : if (p)
2438 39 : p->GetFormula(rFormula);
2439 : else
2440 0 : rFormula = EMPTY_OUSTRING;
2441 39 : }
2442 :
2443 0 : const ScTokenArray* ScColumn::GetFormulaTokens( SCROW nRow ) const
2444 : {
2445 0 : const ScFormulaCell* pCell = FetchFormulaCell(nRow);
2446 0 : if (!pCell)
2447 0 : return NULL;
2448 :
2449 0 : return pCell->GetCode();
2450 : }
2451 :
2452 0 : const ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow ) const
2453 : {
2454 0 : return FetchFormulaCell(nRow);
2455 : }
2456 :
2457 739 : ScFormulaCell* ScColumn::GetFormulaCell( SCROW nRow )
2458 : {
2459 739 : return const_cast<ScFormulaCell*>(FetchFormulaCell(nRow));
2460 : }
2461 :
2462 17720 : CellType ScColumn::GetCellType( SCROW nRow ) const
2463 : {
2464 17720 : switch (maCells.get_type(nRow))
2465 : {
2466 : case sc::element_type_numeric:
2467 8190 : return CELLTYPE_VALUE;
2468 : case sc::element_type_string:
2469 5173 : return CELLTYPE_STRING;
2470 : case sc::element_type_edittext:
2471 156 : return CELLTYPE_EDIT;
2472 : case sc::element_type_formula:
2473 615 : return CELLTYPE_FORMULA;
2474 : default:
2475 : ;
2476 : }
2477 3586 : return CELLTYPE_NONE;
2478 : }
2479 :
2480 : namespace {
2481 :
2482 : /**
2483 : * Count the number of all non-empty cells.
2484 : */
2485 : class CellCounter
2486 : {
2487 : size_t mnCount;
2488 : public:
2489 953344 : CellCounter() : mnCount(0) {}
2490 :
2491 967050 : void operator() (const sc::CellStoreType::value_type& node)
2492 : {
2493 967050 : if (node.type == sc::element_type_empty)
2494 1925521 : return;
2495 :
2496 8579 : mnCount += node.size;
2497 : }
2498 :
2499 953344 : size_t getCount() const { return mnCount; }
2500 : };
2501 :
2502 : }
2503 :
2504 953344 : SCSIZE ScColumn::GetCellCount() const
2505 : {
2506 953344 : CellCounter aFunc;
2507 953344 : std::for_each(maCells.begin(), maCells.end(), aFunc);
2508 953344 : return aFunc.getCount();
2509 : }
2510 :
2511 890 : sal_uInt16 ScColumn::GetErrCode( SCROW nRow ) const
2512 : {
2513 890 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2514 890 : sc::CellStoreType::const_iterator it = aPos.first;
2515 890 : if (it == maCells.end())
2516 0 : return 0;
2517 :
2518 890 : if (it->type != sc::element_type_formula)
2519 867 : return 0;
2520 :
2521 23 : const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
2522 23 : return const_cast<ScFormulaCell*>(p)->GetErrCode();
2523 : }
2524 :
2525 :
2526 6 : bool ScColumn::HasStringData( SCROW nRow ) const
2527 : {
2528 6 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2529 6 : switch (aPos.first->type)
2530 : {
2531 : case sc::element_type_string:
2532 : case sc::element_type_edittext:
2533 4 : return true;
2534 : case sc::element_type_formula:
2535 : {
2536 0 : const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
2537 0 : return !const_cast<ScFormulaCell*>(p)->IsValue();
2538 : }
2539 : default:
2540 : ;
2541 : }
2542 :
2543 2 : return false;
2544 : }
2545 :
2546 :
2547 1344 : bool ScColumn::HasValueData( SCROW nRow ) const
2548 : {
2549 1344 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2550 1344 : switch (aPos.first->type)
2551 : {
2552 : case sc::element_type_numeric:
2553 722 : return true;
2554 : case sc::element_type_formula:
2555 : {
2556 23 : const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
2557 23 : return const_cast<ScFormulaCell*>(p)->IsValue();
2558 : }
2559 : default:
2560 : ;
2561 : }
2562 :
2563 599 : return false;
2564 : }
2565 :
2566 : /**
2567 : * Return true if there is a string or editcell in the range
2568 : */
2569 0 : bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
2570 : {
2571 0 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
2572 0 : sc::CellStoreType::const_iterator it = aPos.first;
2573 0 : size_t nOffset = aPos.second;
2574 0 : SCROW nRow = nStartRow;
2575 0 : for (; it != maCells.end() && nRow <= nEndRow; ++it)
2576 : {
2577 0 : if (it->type == sc::element_type_string || it->type == sc::element_type_edittext)
2578 0 : return true;
2579 :
2580 0 : nRow += it->size - nOffset;
2581 0 : nOffset = 0;
2582 : }
2583 :
2584 0 : return false;
2585 : }
2586 :
2587 : namespace {
2588 :
2589 : class MaxStringLenHandler
2590 : {
2591 : sal_Int32 mnMaxLen;
2592 : const ScColumn& mrColumn;
2593 : SvNumberFormatter* mpFormatter;
2594 : CharSet meCharSet;
2595 : bool mbOctetEncoding;
2596 :
2597 0 : void processCell(size_t nRow, ScRefCellValue& rCell)
2598 : {
2599 : Color* pColor;
2600 0 : OUString aString;
2601 0 : sal_uInt32 nFormat = static_cast<const SfxUInt32Item*>(mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT))->GetValue();
2602 0 : ScCellFormat::GetString(rCell, nFormat, aString, &pColor, *mpFormatter);
2603 0 : sal_Int32 nLen = 0;
2604 0 : if (mbOctetEncoding)
2605 : {
2606 0 : OString aOString;
2607 0 : if (!aString.convertToString(&aOString, meCharSet,
2608 : RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
2609 0 : RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
2610 : {
2611 : // TODO: anything? this is used by the dBase export filter
2612 : // that throws an error anyway, but in case of another
2613 : // context we might want to indicate a conversion error
2614 : // early.
2615 : }
2616 0 : nLen = aOString.getLength();
2617 : }
2618 : else
2619 0 : nLen = aString.getLength() * sizeof(sal_Unicode);
2620 :
2621 0 : if (mnMaxLen < nLen)
2622 0 : mnMaxLen = nLen;
2623 0 : }
2624 :
2625 : public:
2626 0 : MaxStringLenHandler(const ScColumn& rColumn, CharSet eCharSet) :
2627 : mnMaxLen(0),
2628 : mrColumn(rColumn),
2629 0 : mpFormatter(rColumn.GetDoc().GetFormatTable()),
2630 : meCharSet(eCharSet),
2631 0 : mbOctetEncoding(rtl_isOctetTextEncoding(eCharSet))
2632 : {
2633 0 : }
2634 :
2635 0 : void operator() (size_t nRow, double fVal)
2636 : {
2637 0 : ScRefCellValue aCell(fVal);
2638 0 : processCell(nRow, aCell);
2639 0 : }
2640 :
2641 0 : void operator() (size_t nRow, const OUString& rStr)
2642 : {
2643 0 : ScRefCellValue aCell(&rStr);
2644 0 : processCell(nRow, aCell);
2645 0 : }
2646 :
2647 0 : void operator() (size_t nRow, const EditTextObject* p)
2648 : {
2649 0 : ScRefCellValue aCell(p);
2650 0 : processCell(nRow, aCell);
2651 0 : }
2652 :
2653 0 : void operator() (size_t nRow, const ScFormulaCell* p)
2654 : {
2655 0 : ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
2656 0 : processCell(nRow, aCell);
2657 0 : }
2658 :
2659 0 : sal_Int32 getMaxLen() const { return mnMaxLen; }
2660 : };
2661 :
2662 : }
2663 :
2664 0 : sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, CharSet eCharSet ) const
2665 : {
2666 0 : MaxStringLenHandler aFunc(*this, eCharSet);
2667 0 : sc::ParseAllNonEmpty(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
2668 0 : return aFunc.getMaxLen();
2669 : }
2670 :
2671 : namespace {
2672 :
2673 : class MaxNumStringLenHandler
2674 : {
2675 : const ScColumn& mrColumn;
2676 : SvNumberFormatter* mpFormatter;
2677 : sal_Int32 mnMaxLen;
2678 : sal_uInt16 mnPrecision;
2679 :
2680 0 : void processCell(size_t nRow, ScRefCellValue& rCell)
2681 : {
2682 0 : if (rCell.meType == CELLTYPE_FORMULA && !rCell.mpFormula->IsValue())
2683 0 : return;
2684 :
2685 0 : OUString aString;
2686 : sal_uInt32 nFormat = static_cast<const SfxUInt32Item*>(
2687 0 : mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT))->GetValue();
2688 0 : ScCellFormat::GetInputString(rCell, nFormat, aString, *mpFormatter);
2689 0 : sal_Int32 nLen = aString.getLength();
2690 0 : if (nLen <= 0)
2691 : // Ignore empty string.
2692 0 : return;
2693 :
2694 0 : if (nFormat)
2695 : {
2696 0 : const SvNumberformat* pEntry = mpFormatter->GetEntry(nFormat);
2697 : sal_uInt16 nPrec;
2698 0 : if (pEntry)
2699 : {
2700 : bool bThousand, bNegRed;
2701 : sal_uInt16 nLeading;
2702 0 : pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading);
2703 : }
2704 : else
2705 0 : nPrec = mpFormatter->GetFormatPrecision(nFormat);
2706 :
2707 0 : if (nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > mnPrecision)
2708 0 : mnPrecision = nPrec;
2709 : }
2710 :
2711 0 : if (mnPrecision)
2712 : { // less than mnPrecision in string => widen it
2713 : // more => shorten it
2714 0 : OUString aSep = mpFormatter->GetFormatDecimalSep(nFormat);
2715 0 : sal_Int32 nTmp = aString.indexOf(aSep);
2716 0 : if ( nTmp == -1 )
2717 0 : nLen += mnPrecision + aSep.getLength();
2718 : else
2719 : {
2720 0 : nTmp = aString.getLength() - (nTmp + aSep.getLength());
2721 0 : if (nTmp != mnPrecision)
2722 0 : nLen += mnPrecision - nTmp;
2723 : // nPrecision > nTmp : nLen + Diff
2724 : // nPrecision < nTmp : nLen - Diff
2725 0 : }
2726 : }
2727 :
2728 0 : if (mnMaxLen < nLen)
2729 0 : mnMaxLen = nLen;
2730 : }
2731 :
2732 : public:
2733 0 : MaxNumStringLenHandler(const ScColumn& rColumn, sal_uInt16 nPrecision) :
2734 0 : mrColumn(rColumn), mpFormatter(rColumn.GetDoc().GetFormatTable()),
2735 0 : mnMaxLen(0), mnPrecision(nPrecision)
2736 : {
2737 0 : }
2738 :
2739 0 : void operator() (size_t nRow, double fVal)
2740 : {
2741 0 : ScRefCellValue aCell(fVal);
2742 0 : processCell(nRow, aCell);
2743 0 : }
2744 :
2745 0 : void operator() (size_t nRow, const ScFormulaCell* p)
2746 : {
2747 0 : ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
2748 0 : processCell(nRow, aCell);
2749 0 : }
2750 :
2751 0 : sal_Int32 getMaxLen() const { return mnMaxLen; }
2752 :
2753 0 : sal_uInt16 getPrecision() const { return mnPrecision; }
2754 : };
2755 :
2756 : }
2757 :
2758 0 : xub_StrLen ScColumn::GetMaxNumberStringLen(
2759 : sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
2760 : {
2761 0 : nPrecision = pDocument->GetDocOptions().GetStdPrecision();
2762 0 : if ( nPrecision == SvNumberFormatter::UNLIMITED_PRECISION )
2763 : // In case of unlimited precision, use 2 instead.
2764 0 : nPrecision = 2;
2765 :
2766 0 : MaxNumStringLenHandler aFunc(*this, nPrecision);
2767 0 : sc::ParseFormulaNumeric(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
2768 0 : nPrecision = aFunc.getPrecision();
2769 0 : return aFunc.getMaxLen();
2770 : }
2771 :
2772 : namespace {
2773 :
2774 0 : class CellGroupSetter
2775 : {
2776 : ScFormulaCellGroupRef mxGroup;
2777 : public:
2778 0 : CellGroupSetter(const ScFormulaCellGroupRef& xGroup) : mxGroup(xGroup) {}
2779 :
2780 0 : void operator() (size_t, ScFormulaCell* pCell)
2781 : {
2782 0 : pCell->SetCellGroup(mxGroup);
2783 0 : }
2784 : };
2785 :
2786 0 : class GroupFormulaCells
2787 : {
2788 : ScFormulaCellGroupRef mxNone;
2789 :
2790 : public:
2791 :
2792 0 : void operator() (sc::CellStoreType::value_type& node)
2793 : {
2794 0 : if (node.type != sc::element_type_formula)
2795 : // We are only interested in formula cells.
2796 0 : return;
2797 :
2798 0 : ScFormulaCell* pPrev = NULL;
2799 0 : ScFormulaCell* pCur = NULL;
2800 0 : size_t nRow = node.position; // start row position.
2801 :
2802 0 : sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
2803 0 : sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
2804 0 : for (; it != itEnd; ++it, ++nRow, pPrev = pCur)
2805 : {
2806 0 : pCur = *it;
2807 0 : if (!pPrev)
2808 0 : continue;
2809 :
2810 0 : ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(*pCur);
2811 0 : if (eCompState == ScFormulaCell::NotEqual)
2812 : {
2813 : // different formula tokens.
2814 0 : pCur->SetCellGroup(mxNone);
2815 0 : continue;
2816 : }
2817 :
2818 : // Formula tokens equal those of the previous formula cell.
2819 0 : ScFormulaCellGroupRef xGroup = pPrev->GetCellGroup();
2820 0 : if (!xGroup)
2821 : {
2822 : // create a new group ...
2823 0 : xGroup.reset(new ScFormulaCellGroup);
2824 0 : xGroup->mnStart = nRow - 1;
2825 0 : xGroup->mbInvariant = (eCompState == ScFormulaCell::EqualInvariant);
2826 0 : xGroup->mnLength = 2;
2827 :
2828 0 : pCur->SetCellGroup(xGroup);
2829 0 : pPrev->SetCellGroup(xGroup);
2830 : }
2831 : else
2832 : {
2833 : // existing group. extend its length.
2834 0 : pCur->SetCellGroup(xGroup);
2835 0 : ++xGroup->mnLength;
2836 : }
2837 0 : }
2838 : }
2839 : };
2840 :
2841 : }
2842 :
2843 : // Very[!] slow way to look for and merge contiguous runs
2844 : // of similar formulae into a formulagroup
2845 0 : void ScColumn::RebuildFormulaGroups()
2846 : {
2847 0 : if (!mbDirtyGroups)
2848 0 : return;
2849 :
2850 : // clear previous formula groups.
2851 0 : ScFormulaCellGroupRef xNone;
2852 0 : CellGroupSetter aFunc(xNone);
2853 0 : sc::ProcessFormula(maCells, aFunc);
2854 :
2855 : // re-build formula groups.
2856 0 : std::for_each(maCells.begin(), maCells.end(), GroupFormulaCells());
2857 :
2858 0 : mbDirtyGroups = false;
2859 93 : }
2860 :
2861 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|