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