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