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