LibreOffice Module sc (master) 1
column3.cxx
Go to the documentation of this file.
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>
30#include <formula/token.hxx>
31#include <brdcst.hxx>
32#include <docoptio.hxx>
33#include <subtotal.hxx>
34#include <markdata.hxx>
35#include <stringutil.hxx>
36#include <docpool.hxx>
37#include <cellvalue.hxx>
38#include <tokenarray.hxx>
39#include <clipcontext.hxx>
40#include <columnspanset.hxx>
41#include <mtvcellfunc.hxx>
42#include <scopetools.hxx>
43#include <editutil.hxx>
44#include <sharedformula.hxx>
45#include <listenercontext.hxx>
46#include <filterentries.hxx>
47#include <conditio.hxx>
48#include <colorscale.hxx>
49#include <table.hxx>
50#include <editeng/brushitem.hxx>
51#include <editeng/colritem.hxx>
52
53#include <com/sun/star/i18n/LocaleDataItem2.hpp>
54#include <com/sun/star/lang/IllegalArgumentException.hpp>
55
56#include <memory>
57
58#include <o3tl/deleter.hxx>
59
60#include <rtl/tencinfo.h>
61
62#include <svl/numformat.hxx>
63#include <svl/zforlist.hxx>
64#include <svl/zformat.hxx>
66#include <osl/diagnose.h>
67
68#include <cstdio>
69#include <refdata.hxx>
70
71using ::com::sun::star::i18n::LocaleDataItem2;
72
73using namespace formula;
74
76{
77 ScHint aHint(SfxHintId::ScDataChanged, ScAddress(nCol, nRow, nTab));
78 GetDoc().Broadcast(aHint);
79}
80
81void ScColumn::BroadcastCells( const std::vector<SCROW>& rRows, SfxHintId nHint )
82{
83 if (rRows.empty())
84 return;
85
86 // Broadcast the changes.
87 ScDocument& rDocument = GetDoc();
88 ScHint aHint(nHint, ScAddress(nCol, 0, nTab));
89 for (const auto& rRow : rRows)
90 {
91 aHint.SetAddressRow(rRow);
92 rDocument.Broadcast(aHint);
93 }
94}
95
96void ScColumn::BroadcastRows( SCROW nStartRow, SCROW nEndRow, SfxHintId nHint )
97{
98 if( nStartRow > GetLastDataPos())
99 return;
100 sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
101 aSpanSet.scan(*this, nStartRow, nEndRow);
102 std::vector<SCROW> aRows;
103 aSpanSet.getRows(aRows);
104 BroadcastCells(aRows, nHint);
105}
106
107namespace {
108
109class CellInterpreterBase
110{
111protected:
112 void Interpret(ScFormulaCell* p)
113 {
114 // Interpret() takes a range in a formula group, so group those together.
115 if( !groupCells.empty() && p->GetCellGroup() == groupCells.back()->GetCellGroup()
116 && p->aPos.Row() == groupCells.back()->aPos.Row() + 1 )
117 {
118 assert( p->aPos.Tab() == groupCells.back()->aPos.Tab()
119 && p->aPos.Col() == groupCells.back()->aPos.Col());
120 groupCells.push_back(p); // Extend range.
121 return;
122 }
123 flushPending();
124 if( !p->GetCellGroup())
125 {
126 p->Interpret();
127 return;
128 }
129 groupCells.push_back(p);
130
131 }
132 ~CellInterpreterBase()
133 {
134 suppress_fun_call_w_exception(flushPending());
135 }
136private:
137 void flushPending()
138 {
139 if(groupCells.empty())
140 return;
141 SCROW firstRow = groupCells.front()->GetCellGroup()->mpTopCell->aPos.Row();
142 if(!groupCells.front()->Interpret(
143 groupCells.front()->aPos.Row() - firstRow, groupCells.back()->aPos.Row() - firstRow))
144 {
145 // Interpret() will try to group-interpret the given cell range if possible, but if that
146 // is not possible, it will interpret just the given cell. So if group-interpreting
147 // wasn't possible, interpret them one by one.
148 for(ScFormulaCell* cell : groupCells)
149 cell->Interpret();
150 }
151 groupCells.clear();
152 }
153 std::vector<ScFormulaCell*> groupCells;
154};
155
156class DirtyCellInterpreter : public CellInterpreterBase
157{
158public:
159 void operator() (size_t, ScFormulaCell* p)
160 {
161 if(p->GetDirty())
162 Interpret(p);
163 }
164};
165
166class NeedsInterpretCellInterpreter : public CellInterpreterBase
167{
168public:
169 void operator() (size_t, ScFormulaCell* p)
170 {
171 if(p->NeedsInterpret())
172 {
173 Interpret(p);
174 // In some cases such as circular dependencies Interpret()
175 // will not reset the dirty flag, check that in order to tell
176 // the caller that the cell range may trigger Interpret() again.
177 if(p->NeedsInterpret())
178 allInterpreted = false;
179 }
180 }
181 bool allInterpreted = true;
182};
183
184}
185
187{
188 if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
189 return;
190
191 DirtyCellInterpreter aFunc;
192 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
193}
194
196{
197 if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
198 return false;
199
200 NeedsInterpretCellInterpreter aFunc;
201 sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
202 return aFunc.allInterpreted;
203}
204
205void ScColumn::DeleteContent( SCROW nRow, bool bBroadcast )
206{
207 sc::CellStoreType::position_type aPos = maCells.position(nRow);
208 sc::CellStoreType::iterator it = aPos.first;
209 if (it == maCells.end())
210 return;
211
212 if (it->type == sc::element_type_formula)
213 {
214 ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
215 p->EndListeningTo(GetDoc());
217 }
218 maCells.set_empty(nRow, nRow);
219
220 if (bBroadcast)
221 {
222 Broadcast(nRow);
224 }
225}
226
228{
229 DeleteContent(nRow, false);
230 maCellTextAttrs.set_empty(nRow, nRow);
231 maCellNotes.set_empty(nRow, nRow);
232 maSparklines.set_empty(nRow, nRow);
233
234 Broadcast(nRow);
236}
237
239{
240 maCells.event_handler().stop();
241
242 auto maxRowCount = GetDoc().GetMaxRowCount();
243 // Keep a logical empty range of 0-rDoc.MaxRow() at all times.
244 maCells.clear();
245 maCells.resize(maxRowCount);
246 maCellTextAttrs.clear();
247 maCellTextAttrs.resize(maxRowCount);
248 maCellNotes.clear();
249 maCellNotes.resize(maxRowCount);
250 maSparklines.clear();
251 maSparklines.resize(maxRowCount);
253}
254
256{
257 maCellNotes.clear();
258 maCellNotes.resize(GetDoc().GetMaxRowCount());
259}
260
261namespace {
262
263class ShiftFormulaPosHandler
264{
265public:
266
267 void operator() (size_t nRow, ScFormulaCell* pCell)
268 {
269 pCell->aPos.SetRow(nRow);
270 }
271};
272
273}
274
275void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize, std::vector<ScAddress>* pGroupPos )
276{
277 pAttrArray->DeleteRow( nStartRow, nSize );
278
279 SCROW nEndRow = nStartRow + nSize - 1;
280
281 maBroadcasters.erase(nStartRow, nEndRow);
282 maBroadcasters.resize(GetDoc().GetMaxRowCount());
283
284 CellNotesDeleting(nStartRow, nEndRow, false);
285 maCellNotes.erase(nStartRow, nEndRow);
286 maCellNotes.resize(GetDoc().GetMaxRowCount());
287
288 // See if we have any cells that would get deleted or shifted by deletion.
289 sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
290 sc::CellStoreType::iterator itCell = aPos.first;
291 if (itCell->type == sc::element_type_empty)
292 {
293 // This is an empty block. If this is the last block, then there is no cells to delete or shift.
294 sc::CellStoreType::iterator itTest = itCell;
295 ++itTest;
296 if (itTest == maCells.end())
297 {
298 // No cells are affected by this deletion. Bail out.
299 CellStorageModified(); // broadcast array has been modified.
300 return;
301 }
302 }
303
304 // Check if there are any cells below the end row that will get shifted.
305 bool bShiftCells = false;
306 if (nEndRow < GetDoc().MaxRow()) //only makes sense to do this if there *is* a row after the end row
307 {
308 aPos = maCells.position(itCell, nEndRow+1);
309 itCell = aPos.first;
310 if (itCell->type == sc::element_type_empty)
311 {
312 // This block is empty. See if there is any block that follows.
313 sc::CellStoreType::iterator itTest = itCell;
314 ++itTest;
315 if (itTest != maCells.end())
316 // Non-empty block follows -> cells that will get shifted.
317 bShiftCells = true;
318 }
319 else
320 bShiftCells = true;
321 }
322
323 sc::SingleColumnSpanSet aNonEmptySpans(GetDoc().GetSheetLimits());
324 if (bShiftCells)
325 {
326 // Mark all non-empty cell positions below the end row.
328 aBlockPos.miCellPos = itCell;
329 aNonEmptySpans.scan(aBlockPos, *this, nEndRow+1, GetDoc().MaxRow());
330 }
331
332 sc::AutoCalcSwitch aACSwitch(GetDoc(), false);
333
334 // Remove the cells.
335 maCells.erase(nStartRow, nEndRow);
336 maCells.resize(GetDoc().GetMaxRowCount());
337
338 // Get the position again after the container change.
339 aPos = maCells.position(nStartRow);
340
341 // Shift the formula cell positions below the start row.
342 ShiftFormulaPosHandler aShiftFormulaFunc;
343 sc::ProcessFormula(aPos.first, maCells, nStartRow, GetDoc().MaxRow(), aShiftFormulaFunc);
344
346 if (bJoined && pGroupPos)
347 pGroupPos->push_back(ScAddress(nCol, nStartRow, nTab));
348
349 // Shift the text attribute array too (before the broadcast).
350 maCellTextAttrs.erase(nStartRow, nEndRow);
351 maCellTextAttrs.resize(GetDoc().GetMaxRowCount());
352
354}
355
356sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow, std::vector<SCROW>& rNewSharedRows,
357 bool bInsertFormula )
358{
359 return GetPositionToInsert(maCells.begin(), nRow, rNewSharedRows, bInsertFormula);
360}
361
363 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell )
364{
365 // Check the previous row position for possible grouping.
366 if (aPos.first->type == sc::element_type_formula && aPos.second > 0)
367 {
368 ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
369 sc::CellStoreType::position_type aPosPrev = aPos;
370 --aPosPrev.second;
371 sc::SharedFormulaUtil::joinFormulaCells(aPosPrev, rPrev, rCell);
372 }
373
374 // Check the next row position for possible grouping.
375 if (aPos.first->type == sc::element_type_formula && aPos.second+1 < aPos.first->size)
376 {
377 ScFormulaCell& rNext = *sc::formula_block::at(*aPos.first->data, aPos.second+1);
378 sc::SharedFormulaUtil::joinFormulaCells(aPos, rCell, rNext);
379 }
380}
381
383 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, std::vector<SCROW>& rNewSharedRows )
384{
385 if (!GetDoc().IsClipOrUndo())
386 {
387#if USE_FORMULA_GROUP_LISTENER
388 if (rCell.IsShared() && rCell.GetSharedLength() > 1)
389 {
390 // Record new spans (shared or remaining single) that will result
391 // from unsharing to reestablish listeners.
392 // Same cases as in unshareFormulaCell().
393 // XXX NOTE: this is not part of unshareFormulaCell() because that
394 // is called in other contexts as well, for which passing and
395 // determining the rows vector would be superfluous. If that was
396 // needed, move it there.
397 const SCROW nSharedTopRow = rCell.GetSharedTopRow();
398 const SCROW nSharedLength = rCell.GetSharedLength();
399 if (rCell.aPos.Row() == nSharedTopRow)
400 {
401 // Top cell.
402 // Next row will be new shared top or single cell.
403 rNewSharedRows.push_back( nSharedTopRow + 1);
404 rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
405 }
406 else if (rCell.aPos.Row() == nSharedTopRow + nSharedLength - 1)
407 {
408 // Bottom cell.
409 // Current shared top row will be new shared top again or
410 // single cell.
411 rNewSharedRows.push_back( nSharedTopRow);
412 rNewSharedRows.push_back( rCell.aPos.Row() - 1);
413 }
414 else
415 {
416 // Some mid cell.
417 // Current shared top row will be new shared top again or
418 // single cell, plus a new shared top below or single cell.
419 rNewSharedRows.push_back( nSharedTopRow);
420 rNewSharedRows.push_back( rCell.aPos.Row() - 1);
421 rNewSharedRows.push_back( rCell.aPos.Row() + 1);
422 rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
423 }
424 }
425#endif
426
427 // Have the dying formula cell stop listening.
428 // If in a shared formula group this ends the group listening.
429 rCell.EndListeningTo(GetDoc());
430 }
431
433}
434
435void ScColumn::StartListeningUnshared( const std::vector<SCROW>& rNewSharedRows )
436{
437 assert(rNewSharedRows.empty() || rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4);
438 ScDocument& rDoc = GetDoc();
439 if (rNewSharedRows.empty() || rDoc.IsDelayedFormulaGrouping())
440 return;
441
442 auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(rDoc);
443 sc::StartListeningContext aStartCxt(rDoc, pPosSet);
444 sc::EndListeningContext aEndCxt(rDoc, pPosSet);
445 if (rNewSharedRows.size() >= 2)
446 {
447 if(!rDoc.CanDelayStartListeningFormulaCells( this, rNewSharedRows[0], rNewSharedRows[1]))
448 StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[0], rNewSharedRows[1]);
449 }
450 if (rNewSharedRows.size() >= 4)
451 {
452 if(!rDoc.CanDelayStartListeningFormulaCells( this, rNewSharedRows[2], rNewSharedRows[3]))
453 StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[2], rNewSharedRows[3]);
454 }
455}
456
457namespace {
458
459class AttachFormulaCellsHandler
460{
462
463public:
464 explicit AttachFormulaCellsHandler(sc::StartListeningContext& rCxt)
465 : mrCxt(rCxt) {}
466
467 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
468 {
469 pCell->StartListeningTo(mrCxt);
470 }
471};
472
473class DetachFormulaCellsHandler
474{
475 ScDocument& mrDoc;
477
478public:
479 DetachFormulaCellsHandler( ScDocument& rDoc, sc::EndListeningContext* pCxt ) :
480 mrDoc(rDoc), mpCxt(pCxt) {}
481
482 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
483 {
484 if (mpCxt)
485 pCell->EndListeningTo(*mpCxt);
486 else
487 pCell->EndListeningTo(mrDoc);
488 }
489};
490
491}
492
494 const sc::CellStoreType::position_type& aPos, size_t nLength, std::vector<SCROW>* pNewSharedRows )
495{
496 const size_t nRow = aPos.first->position + aPos.second;
497 const size_t nNextTopRow = nRow + nLength; // start row of next formula group.
498
499 bool bLowerSplitOff = false;
500 if (pNewSharedRows && !GetDoc().IsClipOrUndo())
501 {
503 if (pFC)
504 {
505 const SCROW nTopRow = pFC->GetSharedTopRow();
506 const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
507 // nTopRow <= nRow <= nBotRow, because otherwise pFC would not exist.
508 if (nTopRow < static_cast<SCROW>(nRow))
509 {
510 // Upper part will be split off.
511 pNewSharedRows->push_back(nTopRow);
512 pNewSharedRows->push_back(nRow - 1);
513 }
514 if (static_cast<SCROW>(nNextTopRow) <= nBotRow)
515 {
516 // Lower part will be split off.
517 pNewSharedRows->push_back(nNextTopRow);
518 pNewSharedRows->push_back(nBotRow);
519 bLowerSplitOff = true;
520 }
521 }
522 }
523
524 // Split formula grouping at the top and bottom boundaries.
526
527 if (nLength > 0 && GetDoc().ValidRow(nNextTopRow))
528 {
529 if (pNewSharedRows && !bLowerSplitOff && !GetDoc().IsClipOrUndo())
530 {
531 sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow-1);
533 if (pFC)
534 {
535 const SCROW nTopRow = pFC->GetSharedTopRow();
536 const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
537 // nRow < nTopRow < nNextTopRow <= nBotRow
538 if (static_cast<SCROW>(nNextTopRow) <= nBotRow)
539 {
540 // Lower part will be split off.
541 pNewSharedRows->push_back(nNextTopRow);
542 pNewSharedRows->push_back(nBotRow);
543 }
544 }
545 }
546
547 sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow);
549 }
550
551 if (GetDoc().IsClipOrUndo())
552 return;
553
554 DetachFormulaCellsHandler aFunc(GetDoc(), nullptr);
555 sc::ProcessFormula(aPos.first, maCells, nRow, nNextTopRow-1, aFunc);
556}
557
559{
560 sc::CellStoreType::position_type aPos = maCells.position(nRow1);
561 sc::CellStoreType::iterator it = aPos.first;
562
564 if (GetDoc().ValidRow(nRow2+1))
565 {
566 aPos = maCells.position(it, nRow2+1);
568 }
569
570 if (GetDoc().IsClipOrUndo())
571 return;
572
573 // Need to process (start listening) entire shared formula groups, not just
574 // a slice thereof.
575 bool bEnlargedDown = false;
576 aPos = maCells.position(nRow1);
577 it = aPos.first;
578 if (it->type == sc::element_type_formula)
579 {
580 ScFormulaCell& rCell = *sc::formula_block::at(*it->data, aPos.second);
581 if (rCell.IsShared())
582 {
583 nRow1 = std::min( nRow1, rCell.GetSharedTopRow());
584 if (nRow2 < rCell.GetSharedTopRow() + rCell.GetSharedLength())
585 {
586 nRow2 = rCell.GetSharedTopRow() + rCell.GetSharedLength() - 1;
587 bEnlargedDown = true;
588 // Same end row is also enlarged, i.e. doesn't need to be
589 // checked for another group.
590 }
591 }
592 }
593 if (!bEnlargedDown)
594 {
595 aPos = maCells.position(it, nRow2);
596 it = aPos.first;
597 if (it->type == sc::element_type_formula)
598 {
599 ScFormulaCell& rCell = *sc::formula_block::at(*it->data, aPos.second);
600 if (rCell.IsShared())
601 {
602 nRow2 = std::max( nRow2, rCell.GetSharedTopRow() + rCell.GetSharedLength() - 1);
603 }
604 }
605 }
606
607 AttachFormulaCellsHandler aFunc(rCxt);
608 sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
609}
610
612{
613 sc::CellStoreType::position_type aPos = maCells.position(nRow1);
614 sc::CellStoreType::iterator it = aPos.first;
615
616 // Split formula grouping at the top and bottom boundaries.
618 if (GetDoc().ValidRow(nRow2+1))
619 {
620 aPos = maCells.position(it, nRow2+1);
622 }
623
624 if (GetDoc().IsClipOrUndo())
625 return;
626
627 DetachFormulaCellsHandler aFunc(GetDoc(), &rCxt);
628 sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
629}
630
631static void lcl_AddFormulaGroupBoundaries(const sc::CellStoreType::position_type& rPos,
632 std::vector<SCROW>& rNewSharedRows )
633{
634 sc::CellStoreType::iterator itRet = rPos.first;
635 if (itRet->type != sc::element_type_formula)
636 return;
637
638 ScFormulaCell& rFC = *sc::formula_block::at(*itRet->data, rPos.second);
639 if ( rFC.IsShared() )
640 {
641 const SCROW nSharedTopRow = rFC.GetSharedTopRow();
642 const SCROW nSharedLength = rFC.GetSharedLength();
643 rNewSharedRows.push_back( nSharedTopRow);
644 rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
645 }
646 else
647 {
648 const SCROW nRow = rFC.aPos.Row();
649 rNewSharedRows.push_back( nRow);
650 rNewSharedRows.push_back( nRow);
651 }
652}
653
654sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow,
655 std::vector<SCROW>& rNewSharedRows, bool bInsertFormula )
656{
657 // See if we are overwriting an existing formula cell.
658 sc::CellStoreType::position_type aPos = maCells.position(it, nRow);
659 sc::CellStoreType::iterator itRet = aPos.first;
660
661 if (itRet->type == sc::element_type_formula)
662 {
663 ScFormulaCell& rCell = *sc::formula_block::at(*itRet->data, aPos.second);
664 DetachFormulaCell(aPos, rCell, rNewSharedRows);
665 }
666 else if (bInsertFormula && !GetDoc().IsClipOrUndo())
667 {
668 if (nRow > 0)
669 {
670 sc::CellStoreType::position_type aPosBefore = maCells.position(maCells.begin(), nRow-1);
671 lcl_AddFormulaGroupBoundaries(aPosBefore, rNewSharedRows);
672 }
673 if (nRow < GetDoc().MaxRow())
674 {
675 sc::CellStoreType::position_type aPosAfter = maCells.position(maCells.begin(), nRow+1);
676 lcl_AddFormulaGroupBoundaries(aPosAfter, rNewSharedRows);
677 }
678 }
679
680 return itRet;
681}
682
684 const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell,
685 const std::vector<SCROW>& rNewSharedRows,
686 bool bJoin, sc::StartListeningType eListenType )
687{
688 AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, rNewSharedRows, bJoin, eListenType);
689}
690
692 const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell,
693 const std::vector<SCROW>& rNewSharedRows,
694 bool bJoin, sc::StartListeningType eListenType )
695{
696 if (bJoin)
697 // See if this new formula cell can join an existing shared formula group.
698 JoinNewFormulaCell(aPos, rCell);
699
700 // When we insert from the Clipboard we still have wrong (old) References!
701 // First they are rewired in CopyBlockFromClip via UpdateReference and the
702 // we call StartListeningFromClip and BroadcastFromClip.
703 // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
704 // After Import we call CalcAfterLoad and in there Listening.
705 ScDocument& rDocument = GetDoc();
706 if (rDocument.IsClipOrUndo() || rDocument.IsInsertingFromOtherDoc())
707 return;
708
709 switch (eListenType)
710 {
712 {
713 auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(rDocument);
714 sc::StartListeningContext aStartCxt(rDocument, pPosSet);
715 sc::EndListeningContext aEndCxt(rDocument, pPosSet);
716 SCROW nStartRow, nEndRow;
717 nStartRow = nEndRow = aPos.first->position + aPos.second;
718 for (const SCROW nR : rNewSharedRows)
719 {
720 if (nStartRow > nR)
721 nStartRow = nR;
722 if (nEndRow < nR)
723 nEndRow = nR;
724 }
725 StartListeningFormulaCells(aStartCxt, aEndCxt, nStartRow, nEndRow);
726 }
727 break;
729 rCell.StartListeningTo(rDocument);
730 StartListeningUnshared( rNewSharedRows);
731 break;
732 case sc::NoListening:
733 default:
734 if (!rNewSharedRows.empty())
735 {
736 assert(rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4);
737 // Calling SetNeedsListeningGroup() with a top row sets it to
738 // all affected formula cells of that group.
739 const ScFormulaCell* pFC = GetFormulaCell( rNewSharedRows[0]);
740 assert(pFC); // that *is* supposed to be a top row
741 if (pFC && !pFC->NeedsListening())
742 SetNeedsListeningGroup( rNewSharedRows[0]);
743 if (rNewSharedRows.size() > 2)
744 {
745 pFC = GetFormulaCell( rNewSharedRows[2]);
746 assert(pFC); // that *is* supposed to be a top row
747 if (pFC && !pFC->NeedsListening())
748 SetNeedsListeningGroup( rNewSharedRows[2]);
749 }
750 }
751 break;
752 }
753
754 if (!rDocument.IsCalcingAfterLoad())
755 rCell.SetDirty();
756}
757
758void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength,
759 std::vector<SCROW>& rNewSharedRows )
760{
761 // Make sure the whole length consists of formula cells.
762 if (aPos.first->type != sc::element_type_formula)
763 return;
764
765 if (aPos.first->size < aPos.second + nLength)
766 // Block is shorter than specified length.
767 return;
768
769 // Join the top and bottom cells only.
770 ScFormulaCell* pCell1 = sc::formula_block::at(*aPos.first->data, aPos.second);
771 JoinNewFormulaCell(aPos, *pCell1);
772
773 sc::CellStoreType::position_type aPosLast = aPos;
774 aPosLast.second += nLength - 1;
775 ScFormulaCell* pCell2 = sc::formula_block::at(*aPosLast.first->data, aPosLast.second);
776 JoinNewFormulaCell(aPosLast, *pCell2);
777
778 ScDocument& rDocument = GetDoc();
779 if (rDocument.IsClipOrUndo() || rDocument.IsInsertingFromOtherDoc())
780 return;
781
782 const bool bShared = pCell1->IsShared() || pCell2->IsShared();
783 if (bShared)
784 {
785 const SCROW nTopRow = (pCell1->IsShared() ? pCell1->GetSharedTopRow() : pCell1->aPos.Row());
786 const SCROW nBotRow = (pCell2->IsShared() ?
787 pCell2->GetSharedTopRow() + pCell2->GetSharedLength() - 1 : pCell2->aPos.Row());
788 if (rNewSharedRows.empty())
789 {
790 rNewSharedRows.push_back( nTopRow);
791 rNewSharedRows.push_back( nBotRow);
792 }
793 else if (rNewSharedRows.size() == 2)
794 {
795 // Combine into one span.
796 if (rNewSharedRows[0] > nTopRow)
797 rNewSharedRows[0] = nTopRow;
798 if (rNewSharedRows[1] < nBotRow)
799 rNewSharedRows[1] = nBotRow;
800 }
801 else if (rNewSharedRows.size() == 4)
802 {
803 // Merge into one span.
804 // The original two spans are ordered from top to bottom.
805 std::vector<SCROW> aRows { std::min( rNewSharedRows[0], nTopRow), std::max( rNewSharedRows[3], nBotRow) };
806 rNewSharedRows.swap( aRows);
807 }
808 else
809 {
810 assert(!"rNewSharedRows?");
811 }
812 }
813 StartListeningUnshared( rNewSharedRows);
814
815 sc::StartListeningContext aCxt(rDocument);
816 ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second);
817 ScFormulaCell** ppEnd = pp + nLength;
818 for (; pp != ppEnd; ++pp)
819 {
820 if (!bShared)
821 (*pp)->StartListeningTo(aCxt);
822 if (!rDocument.IsCalcingAfterLoad())
823 (*pp)->SetDirty();
824 }
825}
826
828{
829 // When we insert from the Clipboard we still have wrong (old) References!
830 // First they are rewired in CopyBlockFromClip via UpdateReference and the
831 // we call StartListeningFromClip and BroadcastFromClip.
832 // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
833 // After Import we call CalcAfterLoad and in there Listening.
834 if (GetDoc().IsClipOrUndo() || GetDoc().IsInsertingFromOtherDoc() || GetDoc().IsCalcingAfterLoad())
835 return;
836
837 Broadcast(nRow);
838}
839
840bool ScColumn::UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow, sc::CellStoreType::iterator& itr )
841{
842 if (rAttr.mnScriptType != SvtScriptType::UNKNOWN)
843 // Already updated. Nothing to do.
844 return false;
845
846 // Script type not yet determined. Determine the real script
847 // type, and store it.
848 const ScPatternAttr* pPattern = GetPattern(nRow);
849 if (!pPattern)
850 return false;
851
852 sc::CellStoreType::position_type pos = maCells.position(itr, nRow);
853 itr = pos.first;
854 size_t nOffset = pos.second;
855 ScRefCellValue aCell = GetCellValue( itr, nOffset );
856 ScAddress aPos(nCol, nRow, nTab);
857
858 ScDocument& rDocument = GetDoc();
859 const SfxItemSet* pCondSet = nullptr;
860 ScConditionalFormatList* pCFList = rDocument.GetCondFormList(nTab);
861 if (pCFList)
862 {
863 const ScCondFormatItem& rItem =
864 pPattern->GetItem(ATTR_CONDITIONAL);
865 const ScCondFormatIndexes& rData = rItem.GetCondFormatData();
866 pCondSet = rDocument.GetCondResult(aCell, aPos, *pCFList, rData);
867 }
868
869 SvNumberFormatter* pFormatter = rDocument.GetFormatTable();
870
871 // fetch the pattern again, it might have changed under us
872 pPattern = GetPattern(nRow);
873 const Color* pColor;
874 sal_uInt32 nFormat = pPattern->GetNumberFormat(pFormatter, pCondSet);
875 OUString aStr = ScCellFormat::GetString(aCell, nFormat, &pColor, *pFormatter, rDocument);
876
877 // Store the real script type to the array.
878 rAttr.mnScriptType = rDocument.GetStringScriptType(aStr);
879 return true;
880}
881
882namespace {
883
884class DeleteAreaHandler
885{
886 ScDocument& mrDoc;
887 std::vector<ScFormulaCell*> maFormulaCells;
888 sc::SingleColumnSpanSet maDeleteRanges;
889
890 bool mbNumeric:1;
891 bool mbString:1;
892 bool mbFormula:1;
893 bool mbDateTime:1;
894 ScColumn& mrCol;
895
896public:
897 DeleteAreaHandler(ScDocument& rDoc, InsertDeleteFlags nDelFlag, ScColumn& rCol) :
898 mrDoc(rDoc),
899 maDeleteRanges(rDoc.GetSheetLimits()),
900 mbNumeric(nDelFlag & InsertDeleteFlags::VALUE),
901 mbString(nDelFlag & InsertDeleteFlags::STRING),
902 mbFormula(nDelFlag & InsertDeleteFlags::FORMULA),
903 mbDateTime(nDelFlag & InsertDeleteFlags::DATETIME),
904 mrCol(rCol) {}
905
906 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
907 {
908 switch (node.type)
909 {
911 // Numeric type target datetime and number, thus we have a dedicated function
912 if (!mbNumeric && !mbDateTime)
913 return;
914
915 // If numeric and datetime selected, delete full range
916 if (mbNumeric && mbDateTime)
917 break;
918
919 deleteNumeric(node, nOffset, nDataSize);
920 return;
923 if (!mbString)
924 return;
925 break;
927 {
928 if (!mbFormula)
929 return;
930
931 sc::formula_block::iterator it = sc::formula_block::begin(*node.data) + nOffset;
932 sc::formula_block::iterator itEnd = it + nDataSize;
933 maFormulaCells.insert(maFormulaCells.end(), it, itEnd);
934 }
935 break;
937 default:
938 return;
939 }
940
941 // Tag these cells for deletion.
942 SCROW nRow1 = node.position + nOffset;
943 SCROW nRow2 = nRow1 + nDataSize - 1;
944 maDeleteRanges.set(nRow1, nRow2, true);
945 }
946
947 void deleteNumeric(const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
948 {
949 size_t nStart = node.position + nOffset;
950 size_t nElements = 1;
951 bool bLastTypeDateTime = isDateTime(nStart); // true = datetime, false = numeric
952 size_t nCount = nStart + nDataSize;
953
954 for (size_t i = nStart + 1; i < nCount; i++)
955 {
956 bool bIsDateTime = isDateTime(i);
957
958 // same type as previous
959 if (bIsDateTime == bLastTypeDateTime)
960 {
961 nElements++;
962 }
963 // type switching
964 else
965 {
966 deleteNumberOrDateTime(nStart, nStart + nElements - 1, bLastTypeDateTime);
967 nStart += nElements;
968 nElements = 1;
969 }
970
971 bLastTypeDateTime = bIsDateTime;
972 }
973
974 // delete last cells
975 deleteNumberOrDateTime(nStart, nStart + nElements - 1, bLastTypeDateTime);
976 }
977
978 void deleteNumberOrDateTime(SCROW nRow1, SCROW nRow2, bool dateTime)
979 {
980 if (!dateTime && !mbNumeric) // numeric flag must be selected
981 return;
982 if (dateTime && !mbDateTime) // datetime flag must be selected
983 return;
984 maDeleteRanges.set(nRow1, nRow2, true);
985 }
986
987 bool isDateTime(size_t position)
988 {
990 mrCol.GetAttr(position, ATTR_VALUE_FORMAT).GetValue());
991
992 return (nType == SvNumFormatType::DATE) || (nType == SvNumFormatType::TIME) ||
993 (nType == SvNumFormatType::DATETIME);
994 }
995
1000 std::vector<std::pair<SCROW, SCROW>> getFormulaRanges()
1001 {
1002 std::vector<std::pair<SCROW, SCROW>> aRet;
1003
1004 for (const ScFormulaCell* pFC : maFormulaCells)
1005 {
1006 SCROW nTopRow = pFC->aPos.Row();
1007 SCROW nBottomRow = pFC->aPos.Row();
1008
1009 auto xGroup = pFC->GetCellGroup();
1010 if (xGroup)
1011 {
1012 pFC = xGroup->mpTopCell;
1013 nTopRow = pFC->aPos.Row();
1014 nBottomRow = nTopRow + xGroup->mnLength - 1;
1015 }
1016
1017 aRet.emplace_back(nTopRow, nBottomRow);
1018 }
1019
1020 return aRet;
1021 }
1022
1023 void endFormulas()
1024 {
1025 mrDoc.EndListeningFormulaCells(maFormulaCells);
1026 }
1027
1028 sc::SingleColumnSpanSet& getSpans()
1029 {
1030 return maDeleteRanges;
1031 }
1032};
1033
1034class EmptyCells
1035{
1036 ScColumn& mrColumn;
1038
1039 static void splitFormulaGrouping(const sc::CellStoreType::position_type& rPos)
1040 {
1041 if (rPos.first->type == sc::element_type_formula)
1042 {
1043 ScFormulaCell& rCell = *sc::formula_block::at(*rPos.first->data, rPos.second);
1045 }
1046 }
1047
1048public:
1049 EmptyCells( sc::ColumnBlockPosition& rPos, ScColumn& rColumn ) :
1050 mrColumn(rColumn), mrPos(rPos) {}
1051
1052 void operator() (const sc::RowSpan& rSpan)
1053 {
1054 sc::CellStoreType& rCells = mrColumn.GetCellStore();
1055
1056 // First, split formula grouping at the top and bottom boundaries
1057 // before emptying the cells.
1058 sc::CellStoreType::position_type aPos = rCells.position(mrPos.miCellPos, rSpan.mnRow1);
1059 splitFormulaGrouping(aPos);
1060 aPos = rCells.position(aPos.first, rSpan.mnRow2);
1061 splitFormulaGrouping(aPos);
1062
1063 mrPos.miCellPos = rCells.set_empty(mrPos.miCellPos, rSpan.mnRow1, rSpan.mnRow2);
1064 mrPos.miCellTextAttrPos = mrColumn.GetCellAttrStore().set_empty(mrPos.miCellTextAttrPos, rSpan.mnRow1, rSpan.mnRow2);
1065 }
1066};
1067
1068}
1069
1071 aDeletedRows( rDoc.GetSheetLimits() )
1072{
1073}
1074
1075std::unique_ptr<ScColumn::DeleteCellsResult> ScColumn::DeleteCells(
1076 sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag )
1077{
1078 std::unique_ptr<DeleteCellsResult> xResult = std::make_unique<DeleteCellsResult>(GetDoc());
1079
1080 // Determine which cells to delete based on the deletion flags.
1081 DeleteAreaHandler aFunc(GetDoc(), nDelFlag, *this);
1082 sc::CellStoreType::iterator itPos = maCells.position(rBlockPos.miCellPos, nRow1).first;
1083 sc::ProcessBlock(itPos, maCells, aFunc, nRow1, nRow2);
1084 xResult->aFormulaRanges = aFunc.getFormulaRanges();
1085 aFunc.endFormulas(); // Have the formula cells stop listening.
1086
1087 // Get the deletion spans.
1089 aFunc.getSpans().getSpans(aSpans);
1090
1091 // Delete the cells for real.
1092 // tdf#139820: Deleting in reverse order is more efficient.
1093 std::for_each(aSpans.rbegin(), aSpans.rend(), EmptyCells(rBlockPos, *this));
1095
1096 aFunc.getSpans().swap(xResult->aDeletedRows);
1097
1098 return xResult;
1099}
1100
1102 SCROW nStartRow, SCROW nEndRow, InsertDeleteFlags nDelFlag, bool bBroadcast,
1103 sc::ColumnSpanSet* pBroadcastSpans )
1104{
1106 // InsertDeleteFlags::NOCAPTIONS needs to be passed too, if InsertDeleteFlags::NOTE is set
1107 if( nDelFlag & InsertDeleteFlags::NOTE )
1108 nContMask |= InsertDeleteFlags::NOCAPTIONS;
1109 InsertDeleteFlags nContFlag = nDelFlag & nContMask;
1110
1111 sc::ColumnBlockPosition aBlockPos;
1112 InitBlockPosition(aBlockPos);
1113 std::unique_ptr<DeleteCellsResult> xResult;
1114
1115 if (!IsEmptyData() && nContFlag != InsertDeleteFlags::NONE)
1116 {
1117 xResult = DeleteCells(aBlockPos, nStartRow, nEndRow, nDelFlag);
1118 if (pBroadcastSpans)
1119 {
1121 xResult->aDeletedRows.getSpans(aSpans);
1122 for (const auto& rSpan : aSpans)
1123 pBroadcastSpans->set(GetDoc(), nTab, nCol, rSpan.mnRow1, rSpan.mnRow2, true);
1124 }
1125 }
1126
1127 if (nDelFlag & InsertDeleteFlags::NOTE)
1128 {
1129 bool bForgetCaptionOwnership = ((nDelFlag & InsertDeleteFlags::FORGETCAPTIONS) != InsertDeleteFlags::NONE);
1130 DeleteCellNotes(aBlockPos, nStartRow, nEndRow, bForgetCaptionOwnership);
1131 }
1132
1133 if (nDelFlag & InsertDeleteFlags::SPARKLINES)
1134 {
1135 DeleteSparklineCells(aBlockPos, nStartRow, nEndRow);
1136 }
1137
1138 if ( nDelFlag & InsertDeleteFlags::EDITATTR )
1139 {
1140 RemoveEditAttribs(aBlockPos, nStartRow, nEndRow);
1141 }
1142
1143 // Delete attributes just now
1145 pAttrArray->DeleteArea( nStartRow, nEndRow );
1147 pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
1148
1149 if (xResult && bBroadcast)
1150 {
1151 // Broadcast on only cells that were deleted; no point broadcasting on
1152 // cells that were already empty before the deletion.
1153 std::vector<SCROW> aRows;
1154 xResult->aDeletedRows.getRows(aRows);
1155 BroadcastCells(aRows, SfxHintId::ScDataChanged);
1156 }
1157}
1158
1160{
1161 rBlockPos.miBroadcasterPos = maBroadcasters.begin();
1162 rBlockPos.miCellNotePos = maCellNotes.begin();
1163 rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
1164 rBlockPos.miCellPos = maCells.begin();
1165 rBlockPos.miSparklinePos = maSparklines.begin();
1166}
1167
1169{
1170 rBlockPos.miCellNotePos = maCellNotes.begin();
1171 rBlockPos.miCellTextAttrPos = maCellTextAttrs.begin();
1172 rBlockPos.miCellPos = maCells.begin();
1173}
1174
1175namespace {
1176
1177class CopyAttrArrayByRange
1178{
1179 ScAttrArray& mrDestAttrArray;
1180 ScAttrArray& mrSrcAttrArray;
1181 tools::Long mnRowOffset;
1182public:
1183 CopyAttrArrayByRange(ScAttrArray& rDestAttrArray, ScAttrArray& rSrcAttrArray, tools::Long nRowOffset) :
1184 mrDestAttrArray(rDestAttrArray), mrSrcAttrArray(rSrcAttrArray), mnRowOffset(nRowOffset) {}
1185
1186 void operator() (const sc::RowSpan& rSpan)
1187 {
1188 mrDestAttrArray.CopyAreaSafe(
1189 rSpan.mnRow1+mnRowOffset, rSpan.mnRow2+mnRowOffset, mnRowOffset, mrSrcAttrArray);
1190 }
1191};
1192
1193class CopyCellsFromClipHandler
1194{
1196 ScColumn& mrSrcCol;
1197 ScColumn& mrDestCol;
1198 SCTAB mnTab;
1199 SCCOL mnCol;
1200 SCTAB mnSrcTab;
1201 SCCOL mnSrcCol;
1202 tools::Long mnRowOffset;
1203 sc::ColumnBlockPosition maDestBlockPos;
1204 sc::ColumnBlockPosition* mpDestBlockPos; // to save it for next iteration.
1205 svl::SharedStringPool* mpSharedStringPool;
1206
1207 void insertRefCell(SCROW nSrcRow, SCROW nDestRow)
1208 {
1209 ScAddress aSrcPos(mnSrcCol, nSrcRow, mnSrcTab);
1210 ScAddress aDestPos(mnCol, nDestRow, mnTab);
1211 ScSingleRefData aRef;
1212 aRef.InitAddress(aSrcPos);
1213 aRef.SetFlag3D(true);
1214
1215 ScTokenArray aArr(*mrCxt.getDestDoc());
1216 aArr.AddSingleReference(aRef);
1217
1218 mrDestCol.SetFormulaCell(
1219 maDestBlockPos, nDestRow, new ScFormulaCell(mrDestCol.GetDoc(), aDestPos, aArr));
1220 }
1221
1222 void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
1223 {
1224 mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestBlockPos, bCloneCaption, mnRowOffset);
1225 }
1226
1227 void duplicateSparklines(SCROW nStartRow, size_t nDataSize)
1228 {
1229 mrSrcCol.DuplicateSparklines(nStartRow, nDataSize, mrDestCol, maDestBlockPos, mnRowOffset);
1230 }
1231
1232public:
1233 CopyCellsFromClipHandler(sc::CopyFromClipContext& rCxt, ScColumn& rSrcCol, ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, tools::Long nRowOffset, svl::SharedStringPool* pSharedStringPool) :
1234 mrCxt(rCxt),
1235 mrSrcCol(rSrcCol),
1236 mrDestCol(rDestCol),
1237 mnTab(nDestTab),
1238 mnCol(nDestCol),
1239 mnSrcTab(rSrcCol.GetTab()),
1240 mnSrcCol(rSrcCol.GetCol()),
1241 mnRowOffset(nRowOffset),
1242 mpDestBlockPos(mrCxt.getBlockPosition(nDestTab, nDestCol)),
1243 mpSharedStringPool(pSharedStringPool)
1244 {
1245 if (mpDestBlockPos)
1246 {
1247 {
1248 // Re-initialize the broadcaster position hint, which may have
1249 // become invalid by the time it gets here...
1250 sc::ColumnBlockPosition aTempPos;
1251 mrDestCol.InitBlockPosition(aTempPos);
1252 mpDestBlockPos->miBroadcasterPos = aTempPos.miBroadcasterPos;
1253 }
1254 maDestBlockPos = *mpDestBlockPos;
1255 }
1256 else
1257 mrDestCol.InitBlockPosition(maDestBlockPos);
1258 }
1259
1260 ~CopyCellsFromClipHandler()
1261 {
1262 if (mpDestBlockPos)
1263 // Don't forget to save this to the context!
1264 *mpDestBlockPos = maDestBlockPos;
1265 }
1266
1267 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
1268 {
1269 SCROW nSrcRow1 = node.position + nOffset;
1270 bool bCopyCellNotes = mrCxt.isCloneNotes();
1271 bool bCopySparklines = mrCxt.isCloneSparklines();
1272
1273 InsertDeleteFlags nFlags = mrCxt.getInsertFlag();
1274
1275 if (node.type == sc::element_type_empty)
1276 {
1277 if (bCopyCellNotes && !mrCxt.isSkipEmptyCells())
1278 {
1279 bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
1280 duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
1281 }
1282 if (bCopySparklines) // If there is a sparkline is it empty?
1283 {
1284 duplicateSparklines(nSrcRow1, nDataSize);
1285 }
1286 return;
1287 }
1288
1289 bool bNumeric = (nFlags & InsertDeleteFlags::VALUE) != InsertDeleteFlags::NONE;
1290 bool bDateTime = (nFlags & InsertDeleteFlags::DATETIME) != InsertDeleteFlags::NONE;
1291 bool bString = (nFlags & InsertDeleteFlags::STRING) != InsertDeleteFlags::NONE;
1292 bool bBoolean = (nFlags & InsertDeleteFlags::SPECIAL_BOOLEAN) != InsertDeleteFlags::NONE;
1293 bool bFormula = (nFlags & InsertDeleteFlags::FORMULA) != InsertDeleteFlags::NONE;
1294
1295 bool bAsLink = mrCxt.isAsLink();
1296
1297 switch (node.type)
1298 {
1300 {
1301 // We need to copy numeric cells individually because of date type check.
1302 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*node.data);
1303 std::advance(it, nOffset);
1304 sc::numeric_block::const_iterator itEnd = it;
1305 std::advance(itEnd, nDataSize);
1306 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
1307 {
1308 bool bCopy = mrCxt.isDateCell(mrSrcCol, nSrcRow) ? bDateTime : bNumeric;
1309 if (!bCopy)
1310 continue;
1311
1312 if (bAsLink)
1313 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1314 else
1315 mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, *it);
1316 }
1317 }
1318 break;
1320 {
1321 if (!bString)
1322 break;
1323
1324 sc::string_block::const_iterator it = sc::string_block::begin(*node.data);
1325 std::advance(it, nOffset);
1326 sc::string_block::const_iterator itEnd = it;
1327 std::advance(itEnd, nDataSize);
1328 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
1329 {
1330 if (bAsLink)
1331 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1332 else if (mpSharedStringPool)
1333 {
1334 // Re-intern the string if source is a different document.
1335 svl::SharedString aInterned = mpSharedStringPool->intern( (*it).getString());
1336 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aInterned);
1337 }
1338 else
1339 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, *it);
1340 }
1341 }
1342 break;
1344 {
1345 if (!bString)
1346 break;
1347
1348 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
1349 std::advance(it, nOffset);
1350 sc::edittext_block::const_iterator itEnd = it;
1351 std::advance(itEnd, nDataSize);
1352 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
1353 {
1354
1355 if (bAsLink)
1356 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1357 else
1358 mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, **it);
1359 }
1360 }
1361 break;
1363 {
1364 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
1365 std::advance(it, nOffset);
1366 sc::formula_block::const_iterator itEnd = it;
1367 std::advance(itEnd, nDataSize);
1368 for (SCROW nSrcRow = nSrcRow1; it != itEnd; ++it, ++nSrcRow)
1369 {
1370 ScFormulaCell& rSrcCell = **it;
1371 bool bForceFormula = false;
1372 if (bBoolean)
1373 {
1374 // See if the formula consists of =TRUE() or =FALSE().
1375 const ScTokenArray* pCode = rSrcCell.GetCode();
1376 if (pCode && pCode->GetLen() == 1)
1377 {
1378 const formula::FormulaToken* p = pCode->FirstToken();
1379 if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
1380 // This is a boolean formula.
1381 bForceFormula = true;
1382 }
1383 }
1384
1385 ScAddress aDestPos(mnCol, nSrcRow + mnRowOffset, mnTab);
1386 if (bFormula || bForceFormula)
1387 {
1388 if (bAsLink)
1389 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1390 else
1391 {
1392 mrDestCol.SetFormulaCell(
1393 maDestBlockPos, nSrcRow + mnRowOffset,
1394 new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos),
1396 rSrcCell.NeedsNumberFormat());
1397 }
1398 }
1399 else if (bNumeric || bDateTime || bString)
1400 {
1401 // Always just copy the original row to the Undo Document;
1402 // do not create Value/string cells from formulas
1403
1404 FormulaError nErr = rSrcCell.GetErrCode();
1405 if (nErr != FormulaError::NONE)
1406 {
1407 // error codes are cloned with values
1408 if (bNumeric)
1409 {
1410 if (bAsLink)
1411 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1412 else
1413 {
1414 ScFormulaCell* pErrCell = new ScFormulaCell(mrDestCol.GetDoc(), aDestPos);
1415 pErrCell->SetErrCode(nErr);
1416 mrDestCol.SetFormulaCell(
1417 maDestBlockPos, nSrcRow + mnRowOffset, pErrCell);
1418 }
1419 }
1420 }
1421 else if (rSrcCell.IsEmptyDisplayedAsString())
1422 {
1423 // Empty stays empty and doesn't become 0.
1424 continue;
1425 }
1426 else if (rSrcCell.IsValue())
1427 {
1428 bool bCopy = mrCxt.isDateCell(mrSrcCol, nSrcRow) ? bDateTime : bNumeric;
1429 if (!bCopy)
1430 continue;
1431
1432 if (bAsLink)
1433 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1434 else
1435 mrDestCol.SetValue(maDestBlockPos, nSrcRow + mnRowOffset, rSrcCell.GetValue());
1436 }
1437 else if (bString)
1438 {
1439 svl::SharedString aStr = rSrcCell.GetString();
1440 if (aStr.isEmpty())
1441 // do not clone empty string
1442 continue;
1443
1444 if (bAsLink)
1445 insertRefCell(nSrcRow, nSrcRow + mnRowOffset);
1446 else if (rSrcCell.IsMultilineResult())
1447 {
1448 // Clone as an edit text object.
1449 ScFieldEditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
1450 rEngine.SetTextCurrentDefaults(aStr.getString());
1451 mrDestCol.SetEditText(maDestBlockPos, nSrcRow + mnRowOffset, rEngine.CreateTextObject());
1452 }
1453 else if (mpSharedStringPool)
1454 {
1455 // Re-intern the string if source is a different document.
1456 svl::SharedString aInterned = mpSharedStringPool->intern( aStr.getString());
1457 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aInterned);
1458 }
1459 else
1460 {
1461 mrDestCol.SetRawString(maDestBlockPos, nSrcRow + mnRowOffset, aStr);
1462 }
1463 }
1464 }
1465 }
1466 }
1467 break;
1468 default:
1469 ;
1470 }
1471 if (bCopyCellNotes)
1472 {
1473 bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
1474 duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
1475 }
1476 if (bCopySparklines)
1477 {
1478 duplicateSparklines(nSrcRow1, nDataSize);
1479 }
1480 }
1481};
1482
1483class CopyTextAttrsFromClipHandler
1484{
1486 size_t mnDelta;
1487 sc::ColumnBlockPosition maDestBlockPos;
1488 sc::ColumnBlockPosition* mpDestBlockPos; // to save it for next iteration.
1489
1490public:
1491 CopyTextAttrsFromClipHandler( sc::CopyFromClipContext& rCxt, sc::CellTextAttrStoreType& rAttrs,
1492 ScColumn& rDestCol, SCTAB nDestTab, SCCOL nDestCol, size_t nDelta ) :
1493 mrAttrs(rAttrs),
1494 mnDelta(nDelta),
1495 mpDestBlockPos(rCxt.getBlockPosition(nDestTab, nDestCol))
1496 {
1497 if (mpDestBlockPos)
1498 maDestBlockPos.miCellTextAttrPos = mpDestBlockPos->miCellTextAttrPos;
1499 else
1500 rDestCol.InitBlockPosition(maDestBlockPos);
1501 }
1502
1503 ~CopyTextAttrsFromClipHandler()
1504 {
1505 if (mpDestBlockPos)
1506 // Don't forget to save this to the context!
1507 mpDestBlockPos->miCellTextAttrPos = maDestBlockPos.miCellTextAttrPos;
1508 }
1509
1510 void operator() ( const sc::CellTextAttrStoreType::value_type& aNode, size_t nOffset, size_t nDataSize )
1511 {
1512 if (aNode.type != sc::element_type_celltextattr)
1513 return;
1514
1515 sc::celltextattr_block::const_iterator it = sc::celltextattr_block::begin(*aNode.data);
1516 std::advance(it, nOffset);
1517 sc::celltextattr_block::const_iterator itEnd = it;
1518 std::advance(itEnd, nDataSize);
1519
1520 size_t nPos = aNode.position + nOffset + mnDelta;
1521 maDestBlockPos.miCellTextAttrPos = mrAttrs.set(maDestBlockPos.miCellTextAttrPos, nPos, it, itEnd);
1522 }
1523};
1524
1525}
1526
1527// rColumn = source
1528// nRow1, nRow2 = target position
1529
1531 sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, tools::Long nDy, ScColumn& rColumn )
1532{
1534 if (!pBlockPos)
1535 return;
1536
1538 {
1539 if (rCxt.isSkipEmptyCells())
1540 {
1541 // copy only attributes for non-empty cells between nRow1-nDy and nRow2-nDy.
1542 sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
1543 aSpanSet.scan(rColumn, nRow1-nDy, nRow2-nDy);
1545 aSpanSet.getSpans(aSpans);
1546 std::for_each(
1547 aSpans.begin(), aSpans.end(), CopyAttrArrayByRange(*rColumn.pAttrArray, *pAttrArray, nDy));
1548 }
1549 else
1550 rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray );
1551 }
1553 return;
1554
1555 ScDocument& rDocument = GetDoc();
1556 if (rCxt.isAsLink() && rCxt.getInsertFlag() == InsertDeleteFlags::ALL)
1557 {
1558 // We also reference empty cells for "ALL"
1559 // InsertDeleteFlags::ALL must always contain more flags when compared to "Insert contents" as
1560 // contents can be selected one by one!
1561
1562 ScAddress aDestPos( nCol, 0, nTab ); // Adapt Row
1563
1564 // Create reference (Source Position)
1565 ScSingleRefData aRef;
1566 aRef.InitFlags(); // -> All absolute
1567 aRef.SetAbsCol(rColumn.nCol);
1568 aRef.SetAbsTab(rColumn.nTab);
1569 aRef.SetFlag3D(true);
1570
1571 for (SCROW nDestRow = nRow1; nDestRow <= nRow2; nDestRow++)
1572 {
1573 aRef.SetAbsRow(nDestRow - nDy); // Source row
1574 aDestPos.SetRow( nDestRow );
1575
1577 aArr.AddSingleReference( aRef );
1578 SetFormulaCell(*pBlockPos, nDestRow, new ScFormulaCell(rDocument, aDestPos, aArr));
1579 }
1580
1581 // Don't forget to copy the cell text attributes.
1582 CopyTextAttrsFromClipHandler aFunc(rCxt, maCellTextAttrs, *this, nTab, nCol, nDy);
1583 sc::ParseBlock(rColumn.maCellTextAttrs.begin(), rColumn.maCellTextAttrs, aFunc, nRow1-nDy, nRow2-nDy);
1584
1585 return;
1586 }
1587
1588 // Compare the ScDocumentPool* to determine if we are copying within the
1589 // same document. If not, re-intern shared strings.
1590 svl::SharedStringPool* pSharedStringPool = (rColumn.GetDoc().GetPool() != rDocument.GetPool()) ?
1591 &rDocument.GetSharedStringPool() : nullptr;
1592
1593 // nRow1 to nRow2 is for destination (this) column. Subtract nDy to get the source range.
1594 // Copy all cells in the source column (rColumn) from nRow1-nDy to nRow2-nDy to this column.
1595 {
1596 CopyCellsFromClipHandler aFunc(rCxt, rColumn, *this, nTab, nCol, nDy, pSharedStringPool);
1597 sc::ParseBlock(rColumn.maCells.begin(), rColumn.maCells, aFunc, nRow1-nDy, nRow2-nDy);
1598 }
1599
1600 {
1601 // Don't forget to copy the cell text attributes.
1602 CopyTextAttrsFromClipHandler aFunc(rCxt, maCellTextAttrs, *this, nTab, nCol, nDy);
1603 sc::ParseBlock(rColumn.maCellTextAttrs.begin(), rColumn.maCellTextAttrs, aFunc, nRow1-nDy, nRow2-nDy);
1604 }
1605}
1606
1608 sc::MixDocContext& rCxt, const ScMarkData& rMark, ScPasteFunc nFunction,
1609 bool bSkipEmpty, const ScColumn& rSrcCol )
1610{
1611 SCROW nRow1, nRow2;
1612
1613 if (rMark.IsMultiMarked())
1614 {
1615 ScMultiSelIter aIter( rMark.GetMultiSelData(), nCol );
1616 while (aIter.Next( nRow1, nRow2 ))
1617 MixData(rCxt, nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol);
1618 }
1619}
1620
1621namespace {
1622
1623// Result in rVal1
1624bool lcl_DoFunction( double& rVal1, double nVal2, ScPasteFunc nFunction )
1625{
1626 bool bOk = false;
1627 switch (nFunction)
1628 {
1629 case ScPasteFunc::ADD:
1630 bOk = SubTotal::SafePlus( rVal1, nVal2 );
1631 break;
1632 case ScPasteFunc::SUB:
1633 nVal2 = -nVal2; // FIXME: Can we do this always without error?
1634 bOk = SubTotal::SafePlus( rVal1, nVal2 );
1635 break;
1636 case ScPasteFunc::MUL:
1637 bOk = SubTotal::SafeMult( rVal1, nVal2 );
1638 break;
1639 case ScPasteFunc::DIV:
1640 bOk = SubTotal::SafeDiv( rVal1, nVal2 );
1641 break;
1642 default: break;
1643 }
1644 return bOk;
1645}
1646
1647void lcl_AddCode( ScTokenArray& rArr, const ScFormulaCell* pCell )
1648{
1649 rArr.AddOpCode(ocOpen);
1650
1651 const ScTokenArray* pCode = pCell->GetCode();
1652 if (pCode)
1653 {
1654 FormulaTokenArrayPlainIterator aIter(*pCode);
1655 const formula::FormulaToken* pToken = aIter.First();
1656 while (pToken)
1657 {
1658 rArr.AddToken( *pToken );
1659 pToken = aIter.Next();
1660 }
1661 }
1662
1663 rArr.AddOpCode(ocClose);
1664}
1665
1666class MixDataHandler
1667{
1668 ScColumn& mrDestColumn;
1669 sc::ColumnBlockPosition& mrBlockPos;
1670
1671 sc::CellStoreType maNewCells;
1672 sc::CellStoreType::iterator miNewCellsPos;
1673
1674 size_t mnRowOffset;
1675 ScPasteFunc mnFunction;
1676
1677 bool mbSkipEmpty;
1678
1679 void doFunction( size_t nDestRow, double fVal1, double fVal2 )
1680 {
1681 bool bOk = lcl_DoFunction(fVal1, fVal2, mnFunction);
1682
1683 if (bOk)
1684 miNewCellsPos = maNewCells.set(miNewCellsPos, nDestRow-mnRowOffset, fVal1);
1685 else
1686 {
1687 ScAddress aPos(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab());
1688
1689 ScFormulaCell* pFC = new ScFormulaCell(mrDestColumn.GetDoc(), aPos);
1690 pFC->SetErrCode(FormulaError::NoValue);
1691
1692 miNewCellsPos = maNewCells.set(miNewCellsPos, nDestRow-mnRowOffset, pFC);
1693 }
1694 }
1695
1696public:
1697 MixDataHandler(
1698 sc::ColumnBlockPosition& rBlockPos,
1699 ScColumn& rDestColumn,
1700 SCROW nRow1, SCROW nRow2,
1701 ScPasteFunc nFunction, bool bSkipEmpty) :
1702 mrDestColumn(rDestColumn),
1703 mrBlockPos(rBlockPos),
1704 maNewCells(nRow2 - nRow1 + 1),
1705 miNewCellsPos(maNewCells.begin()),
1706 mnRowOffset(nRow1),
1707 mnFunction(nFunction),
1708 mbSkipEmpty(bSkipEmpty)
1709 {
1710 }
1711
1712 void operator() (size_t nRow, double f)
1713 {
1714 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow);
1715 mrBlockPos.miCellPos = aPos.first;
1716 switch (aPos.first->type)
1717 {
1720 {
1721 double fSrcVal = 0.0;
1722 if (aPos.first->type == sc::element_type_numeric)
1723 fSrcVal = sc::numeric_block::at(*aPos.first->data, aPos.second);
1724
1725 // Both src and dest are of numeric type.
1726 doFunction(nRow, f, fSrcVal);
1727 }
1728 break;
1730 {
1731 // Combination of value and at least one formula -> Create formula
1732 ScTokenArray aArr(mrDestColumn.GetDoc());
1733
1734 // First row
1735 aArr.AddDouble(f);
1736
1737 // Operator
1738 OpCode eOp = ocAdd;
1739 switch (mnFunction)
1740 {
1741 case ScPasteFunc::ADD: eOp = ocAdd; break;
1742 case ScPasteFunc::SUB: eOp = ocSub; break;
1743 case ScPasteFunc::MUL: eOp = ocMul; break;
1744 case ScPasteFunc::DIV: eOp = ocDiv; break;
1745 default: break;
1746 }
1747 aArr.AddOpCode(eOp); // Function
1748
1749 // Second row
1750 ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second);
1751 lcl_AddCode(aArr, pDest);
1752
1753 miNewCellsPos = maNewCells.set(
1754 miNewCellsPos, nRow-mnRowOffset,
1755 new ScFormulaCell(
1756 mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1757 }
1758 break;
1761 {
1762 // Destination cell is not a number. Just take the source cell.
1763 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f);
1764 }
1765 break;
1766 default:
1767 ;
1768 }
1769 }
1770
1771 void operator() (size_t nRow, const svl::SharedString& rStr)
1772 {
1773 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, rStr);
1774 }
1775
1776 void operator() (size_t nRow, const EditTextObject* p)
1777 {
1778 miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, p->Clone().release());
1779 }
1780
1781 void operator() (size_t nRow, const ScFormulaCell* p)
1782 {
1783 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow);
1784 mrBlockPos.miCellPos = aPos.first;
1785 switch (aPos.first->type)
1786 {
1788 {
1789 // Source is formula, and dest is value.
1790 ScTokenArray aArr(mrDestColumn.GetDoc());
1791
1792 // First row
1793 lcl_AddCode(aArr, p);
1794
1795 // Operator
1796 OpCode eOp = ocAdd;
1797 switch (mnFunction)
1798 {
1799 case ScPasteFunc::ADD: eOp = ocAdd; break;
1800 case ScPasteFunc::SUB: eOp = ocSub; break;
1801 case ScPasteFunc::MUL: eOp = ocMul; break;
1802 case ScPasteFunc::DIV: eOp = ocDiv; break;
1803 default: break;
1804 }
1805 aArr.AddOpCode(eOp); // Function
1806
1807 // Second row
1808 aArr.AddDouble(sc::numeric_block::at(*aPos.first->data, aPos.second));
1809
1810 miNewCellsPos = maNewCells.set(
1811 miNewCellsPos, nRow-mnRowOffset,
1812 new ScFormulaCell(
1813 mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1814 }
1815 break;
1817 {
1818 // Both are formulas.
1819 ScTokenArray aArr(mrDestColumn.GetDoc());
1820
1821 // First row
1822 lcl_AddCode(aArr, p);
1823
1824 // Operator
1825 OpCode eOp = ocAdd;
1826 switch (mnFunction)
1827 {
1828 case ScPasteFunc::ADD: eOp = ocAdd; break;
1829 case ScPasteFunc::SUB: eOp = ocSub; break;
1830 case ScPasteFunc::MUL: eOp = ocMul; break;
1831 case ScPasteFunc::DIV: eOp = ocDiv; break;
1832 default: break;
1833 }
1834 aArr.AddOpCode(eOp); // Function
1835
1836 // Second row
1837 ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second);
1838 lcl_AddCode(aArr, pDest);
1839
1840 miNewCellsPos = maNewCells.set(
1841 miNewCellsPos, nRow-mnRowOffset,
1842 new ScFormulaCell(
1843 mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab()), aArr));
1844 }
1845 break;
1849 {
1850 // Destination cell is not a number. Just take the source cell.
1851 ScAddress aDestPos(mrDestColumn.GetCol(), nRow, mrDestColumn.GetTab());
1852 miNewCellsPos = maNewCells.set(
1853 miNewCellsPos, nRow-mnRowOffset, new ScFormulaCell(*p, mrDestColumn.GetDoc(), aDestPos));
1854 }
1855 break;
1856 default:
1857 ;
1858 }
1859 }
1860
1864 void operator() (mdds::mtv::element_t, size_t nTopRow, size_t nDataSize)
1865 {
1866 if (mbSkipEmpty)
1867 return;
1868
1869 // Source cells are empty. Treat them as if they have a value of 0.0.
1870 for (size_t i = 0; i < nDataSize; ++i)
1871 {
1872 size_t nDestRow = nTopRow + i;
1873 sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nDestRow);
1874 mrBlockPos.miCellPos = aPos.first;
1875 switch (aPos.first->type)
1876 {
1878 {
1879 double fVal2 = sc::numeric_block::at(*aPos.first->data, aPos.second);
1880 doFunction(nDestRow, 0.0, fVal2);
1881 }
1882 break;
1884 {
1885 const svl::SharedString& aVal = sc::string_block::at(*aPos.first->data, aPos.second);
1886 miNewCellsPos = maNewCells.set(
1887 miNewCellsPos, nDestRow-mnRowOffset, aVal);
1888 }
1889 break;
1891 {
1892 EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
1893 miNewCellsPos = maNewCells.set(
1894 miNewCellsPos, nDestRow-mnRowOffset, pObj->Clone().release());
1895 }
1896 break;
1898 {
1899 ScTokenArray aArr(mrDestColumn.GetDoc());
1900
1901 // First row
1902 ScFormulaCell* pSrc = sc::formula_block::at(*aPos.first->data, aPos.second);
1903 lcl_AddCode( aArr, pSrc);
1904
1905 // Operator
1906 OpCode eOp = ocAdd;
1907 switch (mnFunction)
1908 {
1909 case ScPasteFunc::ADD: eOp = ocAdd; break;
1910 case ScPasteFunc::SUB: eOp = ocSub; break;
1911 case ScPasteFunc::MUL: eOp = ocMul; break;
1912 case ScPasteFunc::DIV: eOp = ocDiv; break;
1913 default: break;
1914 }
1915
1916 aArr.AddOpCode(eOp); // Function
1917 aArr.AddDouble(0.0);
1918
1919 miNewCellsPos = maNewCells.set(
1920 miNewCellsPos, nDestRow-mnRowOffset,
1921 new ScFormulaCell(
1922 mrDestColumn.GetDoc(), ScAddress(mrDestColumn.GetCol(), nDestRow, mrDestColumn.GetTab()), aArr));
1923 }
1924 break;
1925 default:
1926 ;
1927 }
1928 }
1929 }
1930
1934 void commit()
1935 {
1936 sc::CellStoreType& rDestCells = mrDestColumn.GetCellStore();
1937
1938 // Stop all formula cells in the destination range first.
1939 sc::CellStoreType::position_type aPos = rDestCells.position(mrBlockPos.miCellPos, mnRowOffset);
1940 mrDestColumn.DetachFormulaCells(aPos, maNewCells.size(), nullptr);
1941
1942 // Move the new cells to the destination range.
1943 sc::CellStoreType::iterator& itDestPos = mrBlockPos.miCellPos;
1944 sc::CellTextAttrStoreType::iterator& itDestAttrPos = mrBlockPos.miCellTextAttrPos;
1945
1946 for (const auto& rNewCell : maNewCells)
1947 {
1948 bool bHasContent = true;
1949 size_t nDestRow = mnRowOffset + rNewCell.position;
1950
1951 switch (rNewCell.type)
1952 {
1954 {
1955 sc::numeric_block::iterator itData = sc::numeric_block::begin(*rNewCell.data);
1956 sc::numeric_block::iterator itDataEnd = sc::numeric_block::end(*rNewCell.data);
1957 itDestPos = mrDestColumn.GetCellStore().set(itDestPos, nDestRow, itData, itDataEnd);
1958 }
1959 break;
1961 {
1962 sc::string_block::iterator itData = sc::string_block::begin(*rNewCell.data);
1963 sc::string_block::iterator itDataEnd = sc::string_block::end(*rNewCell.data);
1964 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1965 }
1966 break;
1968 {
1969 sc::edittext_block::iterator itData = sc::edittext_block::begin(*rNewCell.data);
1970 sc::edittext_block::iterator itDataEnd = sc::edittext_block::end(*rNewCell.data);
1971 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1972 }
1973 break;
1975 {
1976 sc::formula_block::iterator itData = sc::formula_block::begin(*rNewCell.data);
1977 sc::formula_block::iterator itDataEnd = sc::formula_block::end(*rNewCell.data);
1978
1979 // Group new formula cells before inserting them.
1981
1982 // Insert the formula cells to the column.
1983 itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
1984
1985 // Merge with the previous formula group (if any).
1986 aPos = rDestCells.position(itDestPos, nDestRow);
1988
1989 // Merge with the next formula group (if any).
1990 size_t nNextRow = nDestRow + rNewCell.size;
1991 if (mrDestColumn.GetDoc().ValidRow(nNextRow))
1992 {
1993 aPos = rDestCells.position(aPos.first, nNextRow);
1995 }
1996
1997 // Start listening on cells to get them updated by changes of referenced cells
1998 std::vector<SCROW> aNewSharedRows;
1999 aPos = rDestCells.position(itDestPos, nDestRow);
2000 size_t nFormulaCells = std::distance(itData, itDataEnd);
2001 mrDestColumn.AttachNewFormulaCells(aPos, nFormulaCells, aNewSharedRows);
2002 }
2003 break;
2005 {
2006 itDestPos = rDestCells.set_empty(itDestPos, nDestRow, nDestRow+rNewCell.size-1);
2007 bHasContent = false;
2008 }
2009 break;
2010 default:
2011 ;
2012 }
2013
2014 sc::CellTextAttrStoreType& rDestAttrs = mrDestColumn.GetCellAttrStore();
2015 if (bHasContent)
2016 {
2017 std::vector<sc::CellTextAttr> aAttrs(rNewCell.size, sc::CellTextAttr());
2018 itDestAttrPos = rDestAttrs.set(itDestAttrPos, nDestRow, aAttrs.begin(), aAttrs.end());
2019 }
2020 else
2021 itDestAttrPos = rDestAttrs.set_empty(itDestAttrPos, nDestRow, nDestRow+rNewCell.size-1);
2022 }
2023
2024 maNewCells.release();
2025 }
2026};
2027
2028}
2029
2031 sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, ScPasteFunc nFunction,
2032 bool bSkipEmpty, const ScColumn& rSrcCol )
2033{
2034 // destination (this column) block position.
2035
2037 if (!p)
2038 return;
2039
2040 MixDataHandler aFunc(*p, *this, nRow1, nRow2, nFunction, bSkipEmpty);
2041 sc::ParseAll(rSrcCol.maCells.begin(), rSrcCol.maCells, nRow1, nRow2, aFunc, aFunc);
2042
2043 aFunc.commit();
2045}
2046
2047std::unique_ptr<ScAttrIterator> ScColumnData::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
2048{
2049 return std::make_unique<ScAttrIterator>( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() );
2050}
2051
2052namespace {
2053
2054class StartListenersHandler
2055{
2057 bool mbAllListeners;
2058
2059public:
2060 StartListenersHandler( sc::StartListeningContext& rCxt, bool bAllListeners ) :
2061 mpCxt(&rCxt), mbAllListeners(bAllListeners) {}
2062
2063 void operator() ( sc::CellStoreType::value_type& aBlk )
2064 {
2065 if (aBlk.type != sc::element_type_formula)
2066 return;
2067
2068 ScFormulaCell** pp = &sc::formula_block::at(*aBlk.data, 0);
2069 ScFormulaCell** ppEnd = pp + aBlk.size;
2070
2071 for (; pp != ppEnd; ++pp)
2072 {
2073 ScFormulaCell& rFC = **pp;
2074 if (!mbAllListeners && !rFC.NeedsListening())
2075 continue;
2076
2077 if (rFC.IsSharedTop())
2078 {
2080 pp += rFC.GetSharedLength() - 1; // Move to the last cell in the group.
2081 }
2082 else
2083 rFC.StartListeningTo(*mpCxt);
2084 }
2085 }
2086};
2087
2088}
2089
2091{
2092 std::for_each(maCells.begin(), maCells.end(), StartListenersHandler(rCxt, bAll));
2093}
2094
2095namespace {
2096
2097void applyTextNumFormat( ScColumn& rCol, SCROW nRow, SvNumberFormatter* pFormatter )
2098{
2099 sal_uInt32 nFormat = pFormatter->GetStandardFormat(SvNumFormatType::TEXT);
2100 ScPatternAttr aNewAttrs(rCol.GetDoc().GetPool());
2101 SfxItemSet& rSet = aNewAttrs.GetItemSet();
2103 rCol.ApplyPattern(nRow, aNewAttrs);
2104}
2105
2106}
2107
2109 ScCellValue& rCell, SCROW nRow, SCTAB nTabP, const OUString& rString,
2111 const ScSetStringParam* pParam )
2112{
2113 if (rString.isEmpty())
2114 return false;
2115
2116 bool bNumFmtSet = false;
2117
2118 ScSetStringParam aParam;
2119
2120 if (pParam)
2121 aParam = *pParam;
2122
2123 sal_uInt32 nIndex = 0;
2124 sal_uInt32 nOldIndex = 0;
2125 SvNumFormatType eNumFormatType = SvNumFormatType::ALL;
2126 if (!aParam.mpNumFormatter)
2128
2129 sal_Unicode cFirstChar = 0; // Text
2130 nIndex = nOldIndex = GetNumberFormat( GetDoc().GetNonThreadedContext(), nRow );
2131 if ( rString.getLength() > 1 )
2132 {
2133 eNumFormatType = aParam.mpNumFormatter->GetType(nIndex);
2134 if ( eNumFormatType != SvNumFormatType::TEXT )
2135 cFirstChar = rString[0];
2136 }
2137
2139
2140 if ( cFirstChar == '=' )
2141 {
2142 if ( rString.getLength() == 1 ) // = Text
2143 {
2144 rCell.set(rPool.intern(rString));
2145 }
2147 {
2148 // Set the cell format type to Text.
2149 applyTextNumFormat(*this, nRow, aParam.mpNumFormatter);
2150 rCell.set(rPool.intern(rString));
2151 }
2152 else // = Formula
2153 {
2154 ScFormulaCell* pFormulaCell = new ScFormulaCell(
2155 GetDoc(), ScAddress(nCol, nRow, nTabP), rString,
2158 if (aParam.mbCheckLinkFormula)
2159 GetDoc().CheckLinkFormulaNeedingCheck( *pFormulaCell->GetCode());
2160 rCell.set( pFormulaCell);
2161 }
2162 }
2163 else if ( cFirstChar == '\'') // 'Text
2164 {
2165 if (aParam.mbHandleApostrophe)
2166 {
2167 // Cell format is not 'Text', and the first char is an apostrophe.
2168 // Strip it and set text content.
2169 // NOTE: this corresponds with sc/source/ui/view/tabvwsha.cxx
2170 // ScTabViewShell::UpdateInputHandler() prepending an apostrophe if
2171 // necessary.
2172 rCell.set(rPool.intern(rString.copy(1)));
2173 }
2174 else
2175 {
2176 // This is normal text. Take it as-is.
2177 rCell.set(rPool.intern(rString));
2178 }
2179 }
2180 else
2181 {
2182 double nVal;
2183
2184 do
2185 {
2186 if (aParam.mbDetectNumberFormat)
2187 {
2188 // Editing a date prefers the format's locale's edit date
2189 // format's date acceptance patterns and YMD order.
2190 /* TODO: this could be determined already far above when
2191 * starting to edit a date "cell" and passed down. A problem
2192 * could also be if a new date was typed over or written by a
2193 * macro assuming the current locale if that conflicts somehow.
2194 * You can't have everything. See tdf#116579 and tdf#125109. */
2195 if (eNumFormatType == SvNumFormatType::ALL)
2196 eNumFormatType = aParam.mpNumFormatter->GetType(nIndex);
2197 bool bForceFormatDate = (eNumFormatType == SvNumFormatType::DATE
2198 || eNumFormatType == SvNumFormatType::DATETIME);
2199 const SvNumberformat* pOldFormat = nullptr;
2201 if (bForceFormatDate)
2202 {
2203 ScRefCellValue aCell = GetCellValue(nRow);
2204 if (aCell.getType() == CELLTYPE_VALUE)
2205 {
2206 // Only for an actual date (serial number), not an
2207 // arbitrary string or formula or empty cell.
2208 // Also ensure the edit date format's pattern is used,
2209 // not the display format's.
2210 pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex);
2211 if (!pOldFormat)
2212 bForceFormatDate = false;
2213 else
2214 {
2216 aCell.getValue(), nOldIndex, eNumFormatType, pOldFormat);
2217 eEvalDateFormat = aParam.mpNumFormatter->GetEvalDateFormat();
2219 }
2220 }
2221 else
2222 {
2223 bForceFormatDate = false;
2224 }
2225 }
2226
2227 const bool bIsNumberFormat = aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal);
2228
2229 if (bForceFormatDate)
2230 aParam.mpNumFormatter->SetEvalDateFormat( eEvalDateFormat);
2231
2232 if (!bIsNumberFormat)
2233 break;
2234
2235 // If we have bForceFormatDate, the pOldFormat was/is of
2236 // nOldIndex date(+time) type already, if detected type is
2237 // compatible keep the original format.
2238 if (bForceFormatDate && SvNumberFormatter::IsCompatible(
2239 eNumFormatType, aParam.mpNumFormatter->GetType( nIndex)))
2240 {
2241 nIndex = nOldIndex;
2242 }
2243 else
2244 {
2245 // convert back to the original language if a built-in format was detected
2246 if (!pOldFormat)
2247 pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex );
2248 if (pOldFormat)
2250 nIndex, pOldFormat->GetLanguage());
2251 }
2252
2253 rCell.set(nVal);
2254 if ( nIndex != nOldIndex)
2255 {
2256 // #i22345# New behavior: Apply the detected number format only if
2257 // the old one was the default number, date, time or boolean format.
2258 // Exception: If the new format is boolean, always apply it.
2259
2260 bool bOverwrite = false;
2261 if ( pOldFormat )
2262 {
2263 SvNumFormatType nOldType = pOldFormat->GetMaskedType();
2264 if ( nOldType == SvNumFormatType::NUMBER || nOldType == SvNumFormatType::DATE ||
2265 nOldType == SvNumFormatType::TIME || nOldType == SvNumFormatType::LOGICAL )
2266 {
2267 if ( nOldIndex == aParam.mpNumFormatter->GetStandardFormat(
2268 nOldType, pOldFormat->GetLanguage() ) )
2269 {
2270 bOverwrite = true; // default of these types can be overwritten
2271 }
2272 }
2273 }
2274 if ( !bOverwrite && aParam.mpNumFormatter->GetType( nIndex ) == SvNumFormatType::LOGICAL )
2275 {
2276 bOverwrite = true; // overwrite anything if boolean was detected
2277 }
2278
2279 if ( bOverwrite )
2280 {
2282 nIndex) );
2283 bNumFmtSet = true;
2284 }
2285 }
2286 }
2287 else if (aParam.meSetTextNumFormat == ScSetStringParam::Never ||
2289 {
2290 // Only check if the string is a regular number.
2292 if (!pLocale)
2293 break;
2294
2295 const LocaleDataItem2& aLocaleItem = pLocale->getLocaleItem();
2296 const OUString& rDecSep = aLocaleItem.decimalSeparator;
2297 const OUString& rGroupSep = aLocaleItem.thousandSeparator;
2298 const OUString& rDecSepAlt = aLocaleItem.decimalSeparatorAlternative;
2299 if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1 || rDecSepAlt.getLength() > 1)
2300 break;
2301
2302 sal_Unicode dsep = rDecSep[0];
2303 sal_Unicode gsep = rGroupSep[0];
2304 sal_Unicode dsepa = rDecSepAlt.toChar();
2305
2306 if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, dsepa, nVal, aParam.mbDetectScientificNumberFormat))
2307 break;
2308
2309 rCell.set(nVal);
2310 }
2311 }
2312 while (false);
2313
2314 if (rCell.getType() == CELLTYPE_NONE)
2315 {
2316 // If we reach here with ScSetStringParam::SpecialNumberOnly it
2317 // means a simple number was not detected above, so test for
2318 // special numbers. In any case ScSetStringParam::Always does not
2319 // mean always, but only always for content that could be any
2320 // numeric.
2323 aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
2324 {
2325 // Set the cell format type to Text.
2326 applyTextNumFormat(*this, nRow, aParam.mpNumFormatter);
2327 }
2328
2329 rCell.set(rPool.intern(rString));
2330 }
2331 }
2332
2333 return bNumFmtSet;
2334}
2335
2339bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString,
2341 const ScSetStringParam* pParam )
2342{
2343 if (!GetDoc().ValidRow(nRow))
2344 return false;
2345
2346 ScCellValue aNewCell;
2347 bool bNumFmtSet = ParseString(aNewCell, nRow, nTabP, rString, eConv, pParam);
2348 if (pParam)
2349 aNewCell.release(*this, nRow, pParam->meStartListening);
2350 else
2351 aNewCell.release(*this, nRow);
2352
2353 // Do not set Formats and Formulas here anymore!
2354 // These are queried during output
2355
2356 return bNumFmtSet;
2357}
2358
2359void ScColumn::SetEditText( SCROW nRow, std::unique_ptr<EditTextObject> pEditText )
2360{
2361 pEditText->NormalizeString(GetDoc().GetSharedStringPool());
2362 std::vector<SCROW> aNewSharedRows;
2363 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false);
2364 maCells.set(it, nRow, pEditText.release());
2365 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2367
2368 StartListeningUnshared( aNewSharedRows);
2369
2370 BroadcastNewCell(nRow);
2371}
2372
2373void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, std::unique_ptr<EditTextObject> pEditText )
2374{
2375 pEditText->NormalizeString(GetDoc().GetSharedStringPool());
2376 std::vector<SCROW> aNewSharedRows;
2377 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false);
2378 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText.release());
2379 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2380 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2381
2383
2384 StartListeningUnshared( aNewSharedRows);
2385
2386 BroadcastNewCell(nRow);
2387}
2388
2389void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const EditTextObject& rEditText )
2390{
2391 if (GetDoc().GetEditPool() == rEditText.GetPool())
2392 {
2393 SetEditText(rBlockPos, nRow, rEditText.Clone());
2394 return;
2395 }
2396
2397 // rats, yet another "spool"
2398 // Sadly there is no other way to change the Pool than to
2399 // "spool" the Object through a corresponding Engine
2400 EditEngine& rEngine = GetDoc().GetEditEngine();
2401 rEngine.SetText(rEditText);
2402 SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
2403}
2404
2405void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
2406{
2407 if (pEditPool && GetDoc().GetEditPool() == pEditPool)
2408 {
2409 SetEditText(nRow, rEditText.Clone());
2410 return;
2411 }
2412
2413 // rats, yet another "spool"
2414 // Sadly there is no other way to change the Pool than to
2415 // "spool" the Object through a corresponding Engine
2416 EditEngine& rEngine = GetDoc().GetEditEngine();
2417 rEngine.SetText(rEditText);
2418 SetEditText(nRow, rEngine.CreateTextObject());
2419}
2420
2422{
2423 ScAddress aPos(nCol, nRow, nTab);
2424
2425 std::vector<SCROW> aNewSharedRows;
2426 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2427 ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rArray, eGram);
2428 sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2429 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
2430 pCell->SetNeedNumberFormat(true);
2431 it = maCells.set(it, nRow, pCell);
2432 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2433
2435
2436 AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
2437}
2438
2439void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
2440{
2441 ScAddress aPos(nCol, nRow, nTab);
2442
2443 std::vector<SCROW> aNewSharedRows;
2444 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2445 ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rFormula, eGram);
2446 sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2447 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
2448 pCell->SetNeedNumberFormat(true);
2449 it = maCells.set(it, nRow, pCell);
2450 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2451
2453
2454 AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
2455}
2456
2458 SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType,
2459 bool bInheritNumFormatIfNeeded )
2460{
2461 std::vector<SCROW> aNewSharedRows;
2462 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2463 sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2464 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded )
2465 pCell->SetNeedNumberFormat(true);
2466 it = maCells.set(it, nRow, pCell);
2467 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2468
2470
2471 AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows, true, eListenType);
2472
2473 return pCell;
2474}
2475
2477 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell,
2478 sc::StartListeningType eListenType,
2479 bool bInheritNumFormatIfNeeded )
2480{
2481 std::vector<SCROW> aNewSharedRows;
2482 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, true);
2483 sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2484 if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded )
2485 pCell->SetNeedNumberFormat(true);
2486 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pCell);
2487 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2488 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2489
2491
2492 AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, aNewSharedRows, true, eListenType);
2493}
2494
2495bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells )
2496{
2497 if (!GetDoc().ValidRow(nRow))
2498 return false;
2499
2500 SCROW nEndRow = nRow + rCells.size() - 1;
2501 if (!GetDoc().ValidRow(nEndRow))
2502 return false;
2503
2504 sc::CellStoreType::position_type aPos = maCells.position(nRow);
2505
2506 // Detach all formula cells that will be overwritten.
2507 std::vector<SCROW> aNewSharedRows;
2508 DetachFormulaCells(aPos, rCells.size(), &aNewSharedRows);
2509
2510 if (!GetDoc().IsClipOrUndo())
2511 {
2512 for (size_t i = 0, n = rCells.size(); i < n; ++i)
2513 {
2514 SCROW nThisRow = nRow + i;
2515 sal_uInt32 nFmt = GetNumberFormat(GetDoc().GetNonThreadedContext(), nThisRow);
2516 if ((nFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
2517 rCells[i]->SetNeedNumberFormat(true);
2518 }
2519 }
2520
2521 std::vector<sc::CellTextAttr> aDefaults(rCells.size(), sc::CellTextAttr());
2522 maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end());
2523
2524 maCells.set(aPos.first, nRow, rCells.begin(), rCells.end());
2525
2527
2528 // Reget position_type as the type may have changed to formula, block and
2529 // block size changed, ...
2530 aPos = maCells.position(nRow);
2531 AttachNewFormulaCells(aPos, rCells.size(), aNewSharedRows);
2532
2533 return true;
2534}
2535
2537{
2538 sc::CellStoreType::const_position_type aPos = maCells.position(nRow);
2539 switch (aPos.first->type)
2540 {
2542 return sc::string_block::at(*aPos.first->data, aPos.second);
2544 {
2545 const EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
2546 std::vector<svl::SharedString> aSSs = pObj->GetSharedStrings();
2547 if (aSSs.size() != 1)
2548 // We don't handle multiline content for now.
2549 return svl::SharedString();
2550
2551 return aSSs[0];
2552 }
2553 break;
2554 default:
2555 ;
2556 }
2557 return svl::SharedString();
2558}
2559
2560namespace {
2561
2562class FilterEntriesHandler
2563{
2564 ScColumn& mrColumn;
2565 ScFilterEntries& mrFilterEntries;
2566 bool mbFiltering;
2567 bool mbFilteredRow;
2568
2569 void processCell(const ScColumn& rColumn, SCROW nRow, ScRefCellValue& rCell, bool bIsEmptyCell=false)
2570 {
2571 SvNumberFormatter* pFormatter = mrColumn.GetDoc().GetFormatTable();
2572 sal_uLong nFormat = mrColumn.GetNumberFormat(mrColumn.GetDoc().GetNonThreadedContext(), nRow);
2573 OUString aStr = ScCellFormat::GetInputString(rCell, nFormat, *pFormatter, mrColumn.GetDoc(), mbFiltering);
2574
2575 // Colors
2576 ScAddress aPos(rColumn.GetCol(), nRow, rColumn.GetTab());
2577 if (ScTable* pTable = rColumn.GetDoc().FetchTable(rColumn.GetTab()))
2578 {
2579 mrFilterEntries.addTextColor(pTable->GetCellTextColor(aPos));
2580 mrFilterEntries.addBackgroundColor(pTable->GetCellBackgroundColor(aPos));
2581 }
2582
2583 if (bIsEmptyCell)
2584 {
2585 if (!mrFilterEntries.mbHasEmpties)
2586 {
2587 mrFilterEntries.push_back(ScTypedStrData(OUString()));
2588 mrFilterEntries.mbHasEmpties = true;
2589 }
2590 return;
2591 }
2592
2593 if (rCell.hasString())
2594 {
2595 mrFilterEntries.push_back(ScTypedStrData(std::move(aStr), 0.0, 0.0, ScTypedStrData::Standard, false, mbFilteredRow));
2596 return;
2597 }
2598
2599 double fVal = 0.0;
2600
2601 switch (rCell.getType())
2602 {
2603 case CELLTYPE_VALUE:
2604 fVal = rCell.getDouble();
2605 break;
2606
2607 case CELLTYPE_FORMULA:
2608 {
2609 ScFormulaCell* pFC = rCell.getFormula();
2610 FormulaError nErr = pFC->GetErrCode();
2611 if (nErr != FormulaError::NONE)
2612 {
2613 // Error cell is evaluated as string (for now).
2614 OUString aErr = ScGlobal::GetErrorString(nErr);
2615 if (!aErr.isEmpty())
2616 {
2617 mrFilterEntries.push_back(ScTypedStrData(std::move(aErr)));
2618 return;
2619 }
2620 }
2621 else
2622 fVal = pFC->GetValue();
2623 }
2624 break;
2625 default:
2626 ;
2627 }
2628
2629 SvNumFormatType nType = pFormatter->GetType(nFormat);
2630 bool bDate = false;
2631 if ((nType & SvNumFormatType::DATE) && !(nType & SvNumFormatType::TIME))
2632 {
2633 // special case for date values. Disregard the time
2634 // element if the number format is of date type.
2635 fVal = rtl::math::approxFloor(fVal);
2636 mrFilterEntries.mbHasDates = true;
2637 bDate = true;
2638 // Convert string representation to ISO 8601 date to eliminate
2639 // locale dependent behaviour later when filtering for dates.
2640 sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_YYYYMMDD);
2641 pFormatter->GetInputLineString( fVal, nIndex, aStr);
2642 }
2643 else if (nType == SvNumFormatType::DATETIME)
2644 {
2645 // special case for datetime values.
2646 // Convert string representation to ISO 8601 (with blank instead of T) datetime
2647 // to eliminate locale dependent behaviour later when filtering for datetimes.
2648 sal_uInt32 nIndex = pFormatter->GetFormatIndex(NF_DATETIME_ISO_YYYYMMDD_HHMMSS);
2649 pFormatter->GetInputLineString(fVal, nIndex, aStr);
2650 }
2651 // store the formatted/rounded value for filtering
2652 if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0 && !bDate)
2653 mrFilterEntries.push_back(ScTypedStrData(std::move(aStr), fVal, rColumn.GetDoc().RoundValueAsShown(fVal, nFormat), ScTypedStrData::Value, bDate, mbFilteredRow));
2654 else
2655 mrFilterEntries.push_back(ScTypedStrData(std::move(aStr), fVal, fVal, ScTypedStrData::Value, bDate, mbFilteredRow));
2656 }
2657
2658public:
2659 FilterEntriesHandler(ScColumn& rColumn, ScFilterEntries& rFilterEntries, bool bFiltering, bool bFilteredRow) :
2660 mrColumn(rColumn), mrFilterEntries(rFilterEntries), mbFiltering(bFiltering), mbFilteredRow(bFilteredRow) {}
2661
2662 void operator() (size_t nRow, double fVal)
2663 {
2664 ScRefCellValue aCell(fVal);
2665 processCell(mrColumn, nRow, aCell);
2666 }
2667
2668 void operator() (size_t nRow, const svl::SharedString& rStr)
2669 {
2670 ScRefCellValue aCell(&rStr);
2671 processCell(mrColumn, nRow, aCell);
2672 }
2673
2674 void operator() (size_t nRow, const EditTextObject* p)
2675 {
2676 ScRefCellValue aCell(p);
2677 processCell(mrColumn, nRow, aCell);
2678 }
2679
2680 void operator() (size_t nRow, const ScFormulaCell* p)
2681 {
2682 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
2683 processCell(mrColumn, nRow, aCell);
2684 }
2685
2686 void operator() (const int nElemType, size_t nRow, size_t /* nDataSize */)
2687 {
2688 ScRefCellValue aCell = mrColumn.GetCellValue(nRow);
2689 processCell(mrColumn, nRow, aCell, nElemType == sc::element_type_empty);
2690 }
2691};
2692
2693}
2694
2696 sc::ColumnBlockConstPosition& rBlockPos, SCROW nStartRow, SCROW nEndRow,
2697 ScFilterEntries& rFilterEntries, bool bFiltering, bool bFilteredRow )
2698{
2699 FilterEntriesHandler aFunc(*this, rFilterEntries, bFiltering, bFilteredRow);
2700 rBlockPos.miCellPos =
2701 sc::ParseAll(rBlockPos.miCellPos, maCells, nStartRow, nEndRow, aFunc, aFunc);
2702}
2703
2704namespace {
2705
2709class StrCellIterator
2710{
2711 typedef std::pair<sc::CellStoreType::const_iterator,size_t> PosType;
2712 PosType maPos;
2713 sc::CellStoreType::const_iterator miBeg;
2714 sc::CellStoreType::const_iterator miEnd;
2715 const ScDocument* mpDoc;
2716public:
2717 StrCellIterator(const sc::CellStoreType& rCells, SCROW nStart, const ScDocument* pDoc) :
2718 miBeg(rCells.begin()), miEnd(rCells.end()), mpDoc(pDoc)
2719 {
2720 if (pDoc->ValidRow(nStart))
2721 maPos = rCells.position(nStart);
2722 else
2723 // Make this iterator invalid.
2724 maPos.first = miEnd;
2725 }
2726
2727 bool valid() const { return (maPos.first != miEnd); }
2728
2729 bool has() const
2730 {
2731 return (maPos.first->type == sc::element_type_string || maPos.first->type == sc::element_type_edittext);
2732 }
2733
2734 bool prev()
2735 {
2736 if (!has())
2737 {
2738 // Not in a string block. Move back until we hit a string block.
2739 while (!has())
2740 {
2741 if (maPos.first == miBeg)
2742 return false;
2743
2744 --maPos.first; // move to the preceding block.
2745 maPos.second = maPos.first->size - 1; // last cell in the block.
2746 }
2747 return true;
2748 }
2749
2750 // We are in a string block.
2751 if (maPos.second > 0)
2752 {
2753 // Move back one cell in the same block.
2754 --maPos.second;
2755 }
2756 else
2757 {
2758 // Move back to the preceding string block.
2759 while (true)
2760 {
2761 if (maPos.first == miBeg)
2762 return false;
2763
2764 // Move to the last cell of the previous block.
2765 --maPos.first;
2766 maPos.second = maPos.first->size - 1;
2767 if (has())
2768 break;
2769 }
2770 }
2771 return true;
2772 }
2773
2774 bool next()
2775 {
2776 if (!has())
2777 {
2778 // Not in a string block. Move forward until we hit a string block.
2779 while (!has())
2780 {
2781 ++maPos.first;
2782 if (maPos.first == miEnd)
2783 return false;
2784
2785 maPos.second = 0; // First cell in this block.
2786 }
2787 return true;
2788 }
2789
2790 // We are in a string block.
2791 ++maPos.second;
2792 if (maPos.second >= maPos.first->size)
2793 {
2794 // Move to the next string block.
2795 while (true)
2796 {
2797 ++maPos.first;
2798 if (maPos.first == miEnd)
2799 return false;
2800
2801 maPos.second = 0;
2802 if (has())
2803 break;
2804 }
2805 }
2806 return true;
2807 }
2808
2809 OUString get() const
2810 {
2811 switch (maPos.first->type)
2812 {
2814 return sc::string_block::at(*maPos.first->data, maPos.second).getString();
2816 {
2817 const EditTextObject* p = sc::edittext_block::at(*maPos.first->data, maPos.second);
2818 return ScEditUtil::GetString(*p, mpDoc);
2819 }
2820 default:
2821 ;
2822 }
2823 return OUString();
2824 }
2825};
2826
2827}
2828
2829// GetDataEntries - Strings from continuous Section around nRow
2831 SCROW nStartRow, std::set<ScTypedStrData>& rStrings) const
2832{
2833 // Start at the specified row position, and collect all string values
2834 // going upward and downward directions in parallel. The start position
2835 // cell must be skipped.
2836
2837 StrCellIterator aItrUp(maCells, nStartRow, &GetDoc());
2838 StrCellIterator aItrDown(maCells, nStartRow+1, &GetDoc());
2839
2840 bool bMoveUp = aItrUp.valid();
2841 if (!bMoveUp)
2842 // Current cell is invalid.
2843 return false;
2844
2845 // Skip the start position cell.
2846 bMoveUp = aItrUp.prev(); // Find the previous string cell position.
2847
2848 bool bMoveDown = aItrDown.valid();
2849 if (bMoveDown && !aItrDown.has())
2850 bMoveDown = aItrDown.next(); // Find the next string cell position.
2851
2852 bool bFound = false;
2853 while (bMoveUp)
2854 {
2855 // Get the current string and move up.
2856 OUString aStr = aItrUp.get();
2857 if (!aStr.isEmpty())
2858 {
2859 if (rStrings.insert(ScTypedStrData(std::move(aStr))).second)
2860 bFound = true;
2861 }
2862
2863 bMoveUp = aItrUp.prev();
2864 }
2865
2866 while (bMoveDown)
2867 {
2868 // Get the current string and move down.
2869 OUString aStr = aItrDown.get();
2870 if (!aStr.isEmpty())
2871 {
2872 if (rStrings.insert(ScTypedStrData(std::move(aStr))).second)
2873 bFound = true;
2874 }
2875
2876 bMoveDown = aItrDown.next();
2877 }
2878
2879 return bFound;
2880}
2881
2882namespace {
2883
2884class FormulaToValueHandler
2885{
2886 struct Entry
2887 {
2888 SCROW mnRow;
2890
2891 Entry(SCROW nRow, double f) : mnRow(nRow), maValue(f) {}
2892 Entry(SCROW nRow, const svl::SharedString& rStr) : mnRow(nRow), maValue(rStr) {}
2893 };
2894
2895 typedef std::vector<Entry> EntriesType;
2896 EntriesType maEntries;
2897
2898public:
2899
2900 void operator() (size_t nRow, const ScFormulaCell* p)
2901 {
2902 ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
2903 if (p2->IsValue())
2904 maEntries.emplace_back(nRow, p2->GetValue());
2905 else
2906 maEntries.emplace_back(nRow, p2->GetString());
2907 }
2908
2909 void commitCells(ScColumn& rColumn)
2910 {
2911 sc::ColumnBlockPosition aBlockPos;
2912 rColumn.InitBlockPosition(aBlockPos);
2913
2914 for (const Entry& r : maEntries)
2915 {
2916 switch (r.maValue.getType())
2917 {
2918 case CELLTYPE_VALUE:
2919 rColumn.SetValue(aBlockPos, r.mnRow, r.maValue.getDouble(), false);
2920 break;
2921 case CELLTYPE_STRING:
2922 rColumn.SetRawString(aBlockPos, r.mnRow, *r.maValue.getSharedString(), false);
2923 break;
2924 default:
2925 ;
2926 }
2927 }
2928 }
2929};
2930
2931}
2932
2933void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
2934{
2935 FormulaToValueHandler aFunc;
2936 sc::CellStoreType::const_iterator itPos = maCells.begin();
2937
2938 ScAttrIterator aAttrIter( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() );
2939 SCROW nTop = -1;
2940 SCROW nBottom = -1;
2941 const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
2942 while (pPattern)
2943 {
2944 const ScProtectionAttr* pAttr = &pPattern->GetItem(ATTR_PROTECTION);
2945 if ( pAttr->GetHideCell() )
2946 DeleteArea( nTop, nBottom, InsertDeleteFlags::CONTENTS );
2947 else if ( pAttr->GetHideFormula() )
2948 {
2949 // Replace all formula cells between nTop and nBottom with raw value cells.
2950 itPos = sc::ParseFormula(itPos, maCells, nTop, nBottom, aFunc);
2951 }
2952
2953 pPattern = aAttrIter.Next( nTop, nBottom );
2954 }
2955
2956 aFunc.commitCells(*this);
2957}
2958
2959void ScColumn::SetError( SCROW nRow, const FormulaError nError)
2960{
2961 if (!GetDoc().ValidRow(nRow))
2962 return;
2963
2964 ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), ScAddress(nCol, nRow, nTab));
2965 pCell->SetErrCode(nError);
2966
2967 std::vector<SCROW> aNewSharedRows;
2968 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2969 it = maCells.set(it, nRow, pCell);
2970 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2971
2973
2974 AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
2975}
2976
2977void ScColumn::SetRawString( SCROW nRow, const OUString& rStr )
2978{
2979 if (!GetDoc().ValidRow(nRow))
2980 return;
2981
2983 if (!aSS.getData())
2984 return;
2985
2986 SetRawString(nRow, aSS);
2987}
2988
2990{
2991 if (!GetDoc().ValidRow(nRow))
2992 return;
2993
2994 std::vector<SCROW> aNewSharedRows;
2995 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false);
2996 maCells.set(it, nRow, rStr);
2997 maCellTextAttrs.set(nRow, sc::CellTextAttr());
2998
3000
3001 StartListeningUnshared( aNewSharedRows);
3002
3003 BroadcastNewCell(nRow);
3004}
3005
3007 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const svl::SharedString& rStr, bool bBroadcast )
3008{
3009 if (!GetDoc().ValidRow(nRow))
3010 return;
3011
3012 std::vector<SCROW> aNewSharedRows;
3013 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false);
3014 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr);
3015 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
3016 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
3017
3019
3020 StartListeningUnshared( aNewSharedRows);
3021
3022 if (bBroadcast)
3023 BroadcastNewCell(nRow);
3024}
3025
3026void ScColumn::SetValue( SCROW nRow, double fVal )
3027{
3028 if (!GetDoc().ValidRow(nRow))
3029 return;
3030
3031 std::vector<SCROW> aNewSharedRows;
3032 sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false);
3033 maCells.set(it, nRow, fVal);
3034 maCellTextAttrs.set(nRow, sc::CellTextAttr());
3035
3037
3038 StartListeningUnshared( aNewSharedRows);
3039
3040 BroadcastNewCell(nRow);
3041}
3042
3044 sc::ColumnBlockPosition& rBlockPos, SCROW nRow, double fVal, bool bBroadcast )
3045{
3046 if (!GetDoc().ValidRow(nRow))
3047 return;
3048
3049 std::vector<SCROW> aNewSharedRows;
3050 rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false);
3051 rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal);
3052 rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
3053 rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
3054
3056
3057 StartListeningUnshared( aNewSharedRows);
3058
3059 if (bBroadcast)
3060 BroadcastNewCell(nRow);
3061}
3062
3063OUString ScColumn::GetString( const ScRefCellValue& aCell, SCROW nRow, const ScInterpreterContext* pContext ) const
3064{
3065 // ugly hack for ordering problem with GetNumberFormat and missing inherited formats
3066 if (aCell.getType() == CELLTYPE_FORMULA)
3067 aCell.getFormula()->MaybeInterpret();
3068
3069 sal_uInt32 nFormat = GetNumberFormat( pContext ? *pContext : GetDoc().GetNonThreadedContext(), nRow);
3070 const Color* pColor = nullptr;
3071 return ScCellFormat::GetString(aCell, nFormat, &pColor,
3072 pContext ? *(pContext->GetFormatTable()) : *(GetDoc().GetFormatTable()), GetDoc());
3073}
3074
3076{
3077 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
3078 sc::CellStoreType::iterator it = aPos.first;
3079 if (it == maCells.end())
3080 return nullptr;
3081
3082 if (it->type != sc::element_type_numeric)
3083 return nullptr;
3084
3085 return &sc::numeric_block::at(*it->data, aPos.second);
3086}
3087
3088OUString ScColumn::GetInputString( const ScRefCellValue& aCell, SCROW nRow, bool bForceSystemLocale ) const
3089{
3090 sal_uLong nFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
3091 return ScCellFormat::GetInputString(aCell, nFormat, *(GetDoc().GetFormatTable()), GetDoc(), nullptr, false, bForceSystemLocale);
3092}
3093
3094double ScColumn::GetValue( SCROW nRow ) const
3095{
3096 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3097 sc::CellStoreType::const_iterator it = aPos.first;
3098 switch (it->type)
3099 {
3101 return sc::numeric_block::at(*it->data, aPos.second);
3103 {
3104 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
3105 ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
3106 return p2->IsValue() ? p2->GetValue() : 0.0;
3107 }
3108 default:
3109 ;
3110 }
3111
3112 return 0.0;
3113}
3114
3116{
3117 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3118 sc::CellStoreType::const_iterator it = aPos.first;
3119 if (it == maCells.end())
3120 return nullptr;
3121
3122 if (it->type != sc::element_type_edittext)
3123 return nullptr;
3124
3125 return sc::edittext_block::at(*it->data, aPos.second);
3126}
3127
3129{
3130 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
3131 sc::CellStoreType::iterator it = aPos.first;
3132 if (it == maCells.end())
3133 return;
3134
3135 if (it->type != sc::element_type_edittext)
3136 return;
3137
3138 EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
3140}
3141
3142OUString ScColumn::GetFormula( SCROW nRow ) const
3143{
3144 const ScFormulaCell* p = FetchFormulaCell(nRow);
3145 if (p)
3146 return p->GetFormula();
3147 return OUString();
3148}
3149
3151{
3152 return FetchFormulaCell(nRow);
3153}
3154
3156{
3157 return const_cast<ScFormulaCell*>(FetchFormulaCell(nRow));
3158}
3159
3161{
3162 switch (maCells.get_type(nRow))
3163 {
3165 return CELLTYPE_VALUE;
3167 return CELLTYPE_STRING;
3169 return CELLTYPE_EDIT;
3171 return CELLTYPE_FORMULA;
3172 default:
3173 ;
3174 }
3175 return CELLTYPE_NONE;
3176}
3177
3178namespace {
3179
3183class CellCounter
3184{
3185 size_t mnCount;
3186public:
3187 CellCounter() : mnCount(0) {}
3188
3189 void operator() (const sc::CellStoreType::value_type& node)
3190 {
3191 if (node.type == sc::element_type_empty)
3192 return;
3193
3194 mnCount += node.size;
3195 }
3196
3197 size_t getCount() const { return mnCount; }
3198};
3199
3200}
3201
3203{
3204 CellCounter aFunc;
3205 aFunc = std::for_each(maCells.begin(), maCells.end(), aFunc);
3206 return aFunc.getCount();
3207}
3208
3210{
3211 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3212 sc::CellStoreType::const_iterator it = aPos.first;
3213 if (it == maCells.end())
3214 return FormulaError::NONE;
3215
3216 if (it->type != sc::element_type_formula)
3217 return FormulaError::NONE;
3218
3219 const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
3220 return const_cast<ScFormulaCell*>(p)->GetErrCode();
3221}
3222
3224{
3225 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3226 switch (aPos.first->type)
3227 {
3230 return true;
3232 {
3233 const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
3234 return !const_cast<ScFormulaCell*>(p)->IsValue();
3235 }
3236 default:
3237 ;
3238 }
3239
3240 return false;
3241}
3242
3244{
3245 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3246 switch (aPos.first->type)
3247 {
3249 return true;
3251 {
3252 const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
3253 return const_cast<ScFormulaCell*>(p)->IsValue();
3254 }
3255 default:
3256 ;
3257 }
3258
3259 return false;
3260}
3261
3265bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
3266{
3267 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
3268 sc::CellStoreType::const_iterator it = aPos.first;
3269 size_t nOffset = aPos.second;
3270 SCROW nRow = nStartRow;
3271 for (; it != maCells.end() && nRow <= nEndRow; ++it)
3272 {
3273 if (it->type == sc::element_type_string || it->type == sc::element_type_edittext)
3274 return true;
3275
3276 nRow += it->size - nOffset;
3277 nOffset = 0;
3278 }
3279
3280 return false;
3281}
3282
3283namespace {
3284
3285class MaxStringLenHandler
3286{
3287 sal_Int32 mnMaxLen;
3288 const ScColumn& mrColumn;
3289 SvNumberFormatter* mpFormatter;
3290 rtl_TextEncoding meCharSet;
3291 bool mbOctetEncoding;
3292
3293 void processCell(size_t nRow, const ScRefCellValue& rCell)
3294 {
3295 const Color* pColor;
3296 sal_uInt32 nFormat = mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
3297 OUString aString = ScCellFormat::GetString(rCell, nFormat, &pColor, *mpFormatter, mrColumn.GetDoc());
3298 sal_Int32 nLen = 0;
3299 if (mbOctetEncoding)
3300 {
3301 OString aOString;
3302 if (!aString.convertToString(&aOString, meCharSet,
3303 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
3304 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
3305 {
3306 // TODO: anything? this is used by the dBase export filter
3307 // that throws an error anyway, but in case of another
3308 // context we might want to indicate a conversion error
3309 // early.
3310 }
3311 nLen = aOString.getLength();
3312 }
3313 else
3314 nLen = aString.getLength() * sizeof(sal_Unicode);
3315
3316 if (mnMaxLen < nLen)
3317 mnMaxLen = nLen;
3318 }
3319
3320public:
3321 MaxStringLenHandler(const ScColumn& rColumn, rtl_TextEncoding eCharSet) :
3322 mnMaxLen(0),
3323 mrColumn(rColumn),
3324 mpFormatter(rColumn.GetDoc().GetFormatTable()),
3325 meCharSet(eCharSet),
3326 mbOctetEncoding(rtl_isOctetTextEncoding(eCharSet))
3327 {
3328 }
3329
3330 void operator() (size_t nRow, double fVal)
3331 {
3332 ScRefCellValue aCell(fVal);
3333 processCell(nRow, aCell);
3334 }
3335
3336 void operator() (size_t nRow, const svl::SharedString& rStr)
3337 {
3338 ScRefCellValue aCell(&rStr);
3339 processCell(nRow, aCell);
3340 }
3341
3342 void operator() (size_t nRow, const EditTextObject* p)
3343 {
3344 ScRefCellValue aCell(p);
3345 processCell(nRow, aCell);
3346 }
3347
3348 void operator() (size_t nRow, const ScFormulaCell* p)
3349 {
3350 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
3351 processCell(nRow, aCell);
3352 }
3353
3354 sal_Int32 getMaxLen() const { return mnMaxLen; }
3355};
3356
3357}
3358
3359sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
3360{
3361 MaxStringLenHandler aFunc(*this, eCharSet);
3362 sc::ParseAllNonEmpty(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
3363 return aFunc.getMaxLen();
3364}
3365
3366namespace {
3367
3368class MaxNumStringLenHandler
3369{
3370 const ScColumn& mrColumn;
3371 SvNumberFormatter* mpFormatter;
3372 sal_Int32 mnMaxLen;
3373 sal_uInt16 mnPrecision;
3374 sal_uInt16 mnMaxGeneralPrecision;
3375 bool mbHaveSigned;
3376
3377 void processCell(size_t nRow, ScRefCellValue& rCell)
3378 {
3379 sal_uInt16 nCellPrecision = mnMaxGeneralPrecision;
3380 if (rCell.getType() == CELLTYPE_FORMULA)
3381 {
3382 if (!rCell.getFormula()->IsValue())
3383 return;
3384
3385 // Limit unformatted formula cell precision to precision
3386 // encountered so far, if any, otherwise we'd end up with 15 just
3387 // because of =1/3 ... If no precision yet then arbitrarily limit
3388 // to a maximum of 4 unless a maximum general precision is set.
3389 if (mnPrecision)
3390 nCellPrecision = mnPrecision;
3391 else
3392 nCellPrecision = (mnMaxGeneralPrecision >= 15) ? 4 : mnMaxGeneralPrecision;
3393 }
3394
3395 double fVal = rCell.getValue();
3396 if (!mbHaveSigned && fVal < 0.0)
3397 mbHaveSigned = true;
3398
3399 OUString aString;
3400 OUString aSep;
3401 sal_uInt16 nPrec;
3402 sal_uInt32 nFormat =
3403 mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
3404 if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
3405 {
3406 aSep = mpFormatter->GetFormatDecimalSep(nFormat);
3407 aString = ScCellFormat::GetInputString(rCell, nFormat, *mpFormatter, mrColumn.GetDoc());
3408 const SvNumberformat* pEntry = mpFormatter->GetEntry(nFormat);
3409 if (pEntry)
3410 {
3411 bool bThousand, bNegRed;
3412 sal_uInt16 nLeading;
3413 pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading);
3414 }
3415 else
3416 nPrec = mpFormatter->GetFormatPrecision(nFormat);
3417 }
3418 else
3419 {
3420 if (mnPrecision >= mnMaxGeneralPrecision)
3421 return; // early bail out for nothing changes here
3422
3423 if (!fVal)
3424 {
3425 // 0 doesn't change precision, but set a maximum length if none yet.
3426 if (!mnMaxLen)
3427 mnMaxLen = 1;
3428 return;
3429 }
3430
3431 // Simple number string with at most 15 decimals and trailing
3432 // decimal zeros eliminated.
3433 aSep = ".";
3434 aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true);
3436 }
3437
3438 sal_Int32 nLen = aString.getLength();
3439 if (nLen <= 0)
3440 // Ignore empty string.
3441 return;
3442
3443 if (nPrec == SvNumberFormatter::UNLIMITED_PRECISION && mnPrecision < mnMaxGeneralPrecision)
3444 {
3445 if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
3446 {
3447 // For some reason we couldn't obtain a precision from the
3448 // format, retry with simple number string.
3449 aSep = ".";
3450 aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true);
3451 nLen = aString.getLength();
3452 }
3453 sal_Int32 nSep = aString.indexOf( aSep);
3454 if (nSep != -1)
3455 nPrec = aString.getLength() - nSep - 1;
3456
3457 }
3458
3459 if (nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > mnPrecision)
3460 mnPrecision = nPrec;
3461
3462 if (mnPrecision)
3463 { // less than mnPrecision in string => widen it
3464 // more => shorten it
3465 sal_Int32 nTmp = aString.indexOf(aSep);
3466 if ( nTmp == -1 )
3467 nLen += mnPrecision + aSep.getLength();
3468 else
3469 {
3470 nTmp = aString.getLength() - (nTmp + aSep.getLength());
3471 if (nTmp != mnPrecision)
3472 nLen += mnPrecision - nTmp;
3473 // nPrecision > nTmp : nLen + Diff
3474 // nPrecision < nTmp : nLen - Diff
3475 }
3476 }
3477
3478 // Enlarge for sign if necessary. Bear in mind that
3479 // GetMaxNumberStringLen() is for determining dBase decimal field width
3480 // and precision where the overall field width must include the sign.
3481 // Fitting -1 into "#.##" (width 4, 2 decimals) does not work.
3482 if (mbHaveSigned && fVal >= 0.0)
3483 ++nLen;
3484
3485 if (mnMaxLen < nLen)
3486 mnMaxLen = nLen;
3487 }
3488
3489public:
3490 MaxNumStringLenHandler(const ScColumn& rColumn, sal_uInt16 nMaxGeneralPrecision) :
3491 mrColumn(rColumn), mpFormatter(rColumn.GetDoc().GetFormatTable()),
3492 mnMaxLen(0), mnPrecision(0), mnMaxGeneralPrecision(nMaxGeneralPrecision),
3493 mbHaveSigned(false)
3494 {
3495 // Limit the decimals passed to doubleToUString().
3496 // Also, the dBaseIII maximum precision is 15.
3497 if (mnMaxGeneralPrecision > 15)
3498 mnMaxGeneralPrecision = 15;
3499 }
3500
3501 void operator() (size_t nRow, double fVal)
3502 {
3503 ScRefCellValue aCell(fVal);
3504 processCell(nRow, aCell);
3505 }
3506
3507 void operator() (size_t nRow, const ScFormulaCell* p)
3508 {
3509 ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
3510 processCell(nRow, aCell);
3511 }
3512
3513 sal_Int32 getMaxLen() const { return mnMaxLen; }
3514
3515 sal_uInt16 getPrecision() const { return mnPrecision; }
3516};
3517
3518}
3519
3521 sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
3522{
3523 sal_uInt16 nMaxGeneralPrecision = GetDoc().GetDocOptions().GetStdPrecision();
3524 MaxNumStringLenHandler aFunc(*this, nMaxGeneralPrecision);
3525 sc::ParseFormulaNumeric(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
3526 nPrecision = aFunc.getPrecision();
3527 return aFunc.getMaxLen();
3528}
3529
3530namespace {
3531
3532class GroupFormulaCells
3533{
3534 std::vector<ScAddress>* mpGroupPos;
3535
3536public:
3537 explicit GroupFormulaCells(std::vector<ScAddress>* pGroupPos)
3538 : mpGroupPos(pGroupPos) {}
3539
3540 void operator() (sc::CellStoreType::value_type& node)
3541 {
3542 if (node.type != sc::element_type_formula)
3543 // We are only interested in formula cells.
3544 return;
3545
3546 size_t nRow = node.position; // start row position.
3547
3548 sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
3549 sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
3550
3551 // This block should never be empty.
3552
3553 ScFormulaCell* pPrev = *it;
3554 ScFormulaCellGroupRef xPrevGrp = pPrev->GetCellGroup();
3555 if (xPrevGrp)
3556 {
3557 // Move to the cell after the last cell of the current group.
3558 std::advance(it, xPrevGrp->mnLength);
3559 nRow += xPrevGrp->mnLength;
3560 }
3561 else
3562 {
3563 ++it;
3564 ++nRow;
3565 }
3566
3567 ScFormulaCell* pCur = nullptr;
3568 ScFormulaCellGroupRef xCurGrp;
3569 for (; it != itEnd; pPrev = pCur, xPrevGrp = xCurGrp)
3570 {
3571 pCur = *it;
3572 xCurGrp = pCur->GetCellGroup();
3573
3574 ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(*pCur);
3575 if (eCompState == ScFormulaCell::NotEqual)
3576 {
3577 // different formula tokens.
3578 if (xCurGrp)
3579 {
3580 // Move to the cell after the last cell of the current group.
3581 if (xCurGrp->mnLength > std::distance(it, itEnd))
3582 throw css::lang::IllegalArgumentException();
3583 std::advance(it, xCurGrp->mnLength);
3584 nRow += xCurGrp->mnLength;
3585 }
3586 else
3587 {
3588 ++it;
3589 ++nRow;
3590 }
3591
3592 continue;
3593 }
3594
3595 // Formula tokens equal those of the previous formula cell or cell group.
3596 if (xPrevGrp)
3597 {
3598 // Previous cell is a group.
3599 if (xCurGrp)
3600 {
3601 // The current cell is a group. Merge these two groups.
3602 xPrevGrp->mnLength += xCurGrp->mnLength;
3603 pCur->SetCellGroup(xPrevGrp);
3604 sc::formula_block::iterator itGrpEnd = it;
3605 if (xCurGrp->mnLength > std::distance(itGrpEnd, itEnd))
3606 throw css::lang::IllegalArgumentException();
3607 std::advance(itGrpEnd, xCurGrp->mnLength);
3608 for (++it; it != itGrpEnd; ++it)
3609 {
3610 ScFormulaCell* pCell = *it;
3611 pCell->SetCellGroup(xPrevGrp);
3612 }
3613 nRow += xCurGrp->mnLength;
3614 }
3615 else
3616 {
3617 // Add this cell to the previous group.
3618 pCur->SetCellGroup(xPrevGrp);
3619 ++xPrevGrp->mnLength;
3620 ++nRow;
3621 ++it;
3622 }
3623
3624 }
3625 else if (xCurGrp)
3626 {
3627 // Previous cell is a regular cell and current cell is a group.
3628 nRow += xCurGrp->mnLength;
3629 if (xCurGrp->mnLength > std::distance(it, itEnd))
3630 throw css::lang::IllegalArgumentException();
3631 std::advance(it, xCurGrp->mnLength);
3632 pPrev->SetCellGroup(xCurGrp);
3633 xCurGrp->mpTopCell = pPrev;
3634 ++xCurGrp->mnLength;
3635 xPrevGrp = xCurGrp;
3636 }
3637 else
3638 {
3639 // Both previous and current cells are regular cells.
3640 assert(pPrev->aPos.Row() == static_cast<SCROW>(nRow - 1));
3641 xPrevGrp = pPrev->CreateCellGroup(2, eCompState == ScFormulaCell::EqualInvariant);
3642 pCur->SetCellGroup(xPrevGrp);
3643 ++nRow;
3644 ++it;
3645 }
3646
3647 if (mpGroupPos)
3648 mpGroupPos->push_back(pCur->aPos);
3649
3650 pCur = pPrev;
3651 xCurGrp = xPrevGrp;
3652 }
3653 }
3654};
3655
3656}
3657
3658void ScColumn::RegroupFormulaCells( std::vector<ScAddress>* pGroupPos )
3659{
3660 // re-build formula groups.
3661 std::for_each(maCells.begin(), maCells.end(), GroupFormulaCells(pGroupPos));
3662}
3663
3664/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
bool ValidRow(SCROW nRow, SCROW nMaxRow)
Definition: address.hxx:105
std::unique_ptr< EditTextObject > CreateTextObject()
void SetText(const OUString &rStr)
virtual std::vector< svl::SharedString > GetSharedStrings() const=0
virtual const SfxItemPool * GetPool() const=0
virtual std::unique_ptr< EditTextObject > Clone() const=0
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
void CopyAreaSafe(SCROW nStartRow, SCROW nEndRow, tools::Long nDy, ScAttrArray &rAttrArray)
Leave flags summarized with CopyArea.
Definition: attarray.cxx:2493
const ScPatternAttr * Next(SCROW &rTop, SCROW &rBottom)
Definition: attarray.hxx:268
static OUString GetInputString(const ScRefCellValue &rCell, sal_uInt32 nFormat, SvNumberFormatter &rFormatter, const ScDocument &rDoc, const svl::SharedString **pShared=nullptr, bool bFiltering=false, bool bForceSystemLocale=false)
Definition: cellform.cxx:129
static OUString GetString(const ScRefCellValue &rCell, sal_uInt32 nFormat, const Color **ppColor, SvNumberFormatter &rFormatter, const ScDocument &rDoc, bool bNullVals=true, bool bFormula=false, bool bUseStarFormat=false)
Definition: cellform.cxx:31
std::unique_ptr< ScAttrArray > pAttrArray
Definition: column.hxx:118
std::unique_ptr< ScAttrIterator > CreateAttrIterator(SCROW nStartRow, SCROW nEndRow) const
Definition: column3.cxx:2047
void DeleteCellNotes(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
Definition: column2.cxx:2260
SCTAB GetTab() const
Definition: column.hxx:255
svl::SharedString GetSharedString(SCROW nRow) const
Definition: column3.cxx:2536
void CellStorageModified()
Called whenever the state of cell array gets modified i.e.
Definition: column2.cxx:1680
bool HasStringData(SCROW nRow) const
Definition: column3.cxx:3223
void ApplyPattern(SCROW nRow, const ScPatternAttr &rPatAttr)
Definition: column.cxx:467
FormulaError GetErrCode(SCROW nRow) const
Definition: column3.cxx:3209
SCCOL nCol
Definition: column.hxx:204
void SetValue(SCROW nRow, double fVal)
Definition: column3.cxx:3026
sc::CellTextAttrStoreType maCellTextAttrs
Definition: column.hxx:188
void SetFormula(SCROW nRow, const ScTokenArray &rArray, formula::FormulaGrammar::Grammar eGram)
Definition: column3.cxx:2421
bool HasValueData(SCROW nRow) const
Definition: column3.cxx:3243
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: column.hxx:965
void DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn &rDestCol, sc::ColumnBlockPosition &rDestBlockPos, bool bCloneCaption, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:1972
SCTAB nTab
Definition: column.hxx:205
const SfxPoolItem & GetAttr(SCROW nRow, sal_uInt16 nWhich) const
Definition: column.hxx:970
void RegroupFormulaCells(std::vector< ScAddress > *pGroupPos=nullptr)
Regroup formula cells for the entire column.
Definition: column3.cxx:3658
void SetError(SCROW nRow, const FormulaError nError)
Definition: column3.cxx:2959
ScFormulaCell * SetFormulaCell(SCROW nRow, ScFormulaCell *pCell, sc::StartListeningType eListenType=sc::SingleCellListening, bool bInheritNumFormatIfNeeded=true)
Takes ownership of pCell.
Definition: column3.cxx:2457
void BroadcastCells(const std::vector< SCROW > &rRows, SfxHintId nHint)
Definition: column3.cxx:81
bool SetFormulaCells(SCROW nRow, std::vector< ScFormulaCell * > &rCells)
Definition: column3.cxx:2495
void InterpretDirtyCells(SCROW nRow1, SCROW nRow2)
Definition: column3.cxx:186
void InitBlockPosition(sc::ColumnBlockPosition &rBlockPos)
Definition: column3.cxx:1159
void StartListeners(sc::StartListeningContext &rCxt, bool bAll)
Definition: column3.cxx:2090
sal_Int32 GetMaxNumberStringLen(sal_uInt16 &nPrecision, SCROW nRowStart, SCROW nRowEnd) const
Definition: column3.cxx:3520
void DetachFormulaCell(const sc::CellStoreType::position_type &aPos, ScFormulaCell &rCell, std::vector< SCROW > &rNewSharedRows)
Detach a formula cell that's about to be deleted, or removed from document storage (if that ever happ...
Definition: column3.cxx:382
OUString GetFormula(SCROW nRow) const
Definition: column3.cxx:3142
void RemoveProtected(SCROW nStartRow, SCROW nEndRow)
Definition: column3.cxx:2933
void FreeNotes()
Definition: column3.cxx:255
bool ParseString(ScCellValue &rCell, SCROW nRow, SCTAB nTab, const OUString &rString, formula::FormulaGrammar::AddressConvention eConv, const ScSetStringParam *pParam)
Definition: column3.cxx:2108
void DuplicateSparklines(SCROW nStartRow, size_t nDataSize, ScColumn &rDestCol, sc::ColumnBlockPosition &rDestBlockPos, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:2154
std::unique_ptr< DeleteCellsResult > DeleteCells(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag)
Definition: column3.cxx:1075
void GetFilterEntries(sc::ColumnBlockConstPosition &rBlockPos, SCROW nStartRow, SCROW nEndRow, ScFilterEntries &rFilterEntries, bool bFiltering, bool bFilteredRow)
Definition: column3.cxx:2695
void RemoveEditAttribs(sc::ColumnBlockPosition &rBlockPos, SCROW nStartRow, SCROW nEndRow)
Definition: column2.cxx:1267
bool HasStringCells(SCROW nStartRow, SCROW nEndRow) const
Return true if there is a string or editcell in the range.
Definition: column3.cxx:3265
sc::CellNoteStoreType maCellNotes
Definition: column.hxx:191
void AttachNewFormulaCell(const sc::CellStoreType::iterator &itPos, SCROW nRow, ScFormulaCell &rCell, const std::vector< SCROW > &rNewSharedRows, bool bJoin=true, sc::StartListeningType eListenType=sc::SingleCellListening)
Definition: column3.cxx:683
const ScFormulaCell * GetFormulaCell(SCROW nRow) const
Definition: column3.cxx:3150
void DeleteRow(SCROW nStartRow, SCSIZE nSize, std::vector< ScAddress > *pGroupPos)
Definition: column3.cxx:275
const EditTextObject * GetEditText(SCROW nRow) const
Definition: column3.cxx:3115
void MixMarked(sc::MixDocContext &rCxt, const ScMarkData &rMark, ScPasteFunc nFunction, bool bSkipEmpty, const ScColumn &rSrcCol)
Definition: column3.cxx:1607
void FreeAll()
Definition: column3.cxx:238
void CellNotesDeleting(SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
Definition: column2.cxx:2253
SCCOL GetCol() const
Definition: column.hxx:256
bool InterpretCellsIfNeeded(SCROW nRow1, SCROW nRow2)
Definition: column3.cxx:195
void CopyFromClip(sc::CopyFromClipContext &rCxt, SCROW nRow1, SCROW nRow2, tools::Long nDy, ScColumn &rColumn)
Definition: column3.cxx:1530
sal_Int32 GetMaxStringLen(SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet) const
Definition: column3.cxx:3359
void ApplyAttr(SCROW nRow, const SfxPoolItem &rAttr)
Definition: column.cxx:620
void Delete(SCROW nRow)
Definition: column3.cxx:227
void MixData(sc::MixDocContext &rCxt, SCROW nRow1, SCROW nRow2, ScPasteFunc nFunction, bool bSkipEmpty, const ScColumn &rSrcCol)
Definition: column3.cxx:2030
bool IsEmptyData() const
Definition: column2.cxx:1284
void BroadcastNewCell(SCROW nRow)
Definition: column3.cxx:827
void SetNeedsListeningGroup(SCROW nRow)
Definition: column4.cxx:1743
OUString GetInputString(SCROW nRow, bool bForceSystemLocale=false) const
Definition: column.hxx:448
bool GetDataEntries(SCROW nRow, std::set< ScTypedStrData > &rStrings) const
Definition: column3.cxx:2830
sc::CellStoreType maCells
Definition: column.hxx:197
ScRefCellValue GetCellValue(SCROW nRow) const
Definition: column.cxx:638
void DetachFormulaCells(const sc::CellStoreType::position_type &aPos, size_t nLength, std::vector< SCROW > *pNewSharedRows)
Definition: column3.cxx:493
bool UpdateScriptType(sc::CellTextAttr &rAttr, SCROW nRow, sc::CellStoreType::iterator &itr)
Definition: column3.cxx:840
SCSIZE GetCellCount() const
Definition: column3.cxx:3202
void StartListeningUnshared(const std::vector< SCROW > &rNewSharedRows)
Re-establish listeners on unshared formula groups.
Definition: column3.cxx:435
void StartListeningFormulaCells(sc::StartListeningContext &rStartCxt, sc::EndListeningContext &rEndCxt, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1606
void BroadcastRows(SCROW nStartRow, SCROW nEndRow, SfxHintId nHint)
Definition: column3.cxx:96
void Broadcast(SCROW nRow)
Definition: column3.cxx:75
sc::CellTextAttrStoreType & GetCellAttrStore()
Definition: column.hxx:259
double * GetValueCell(SCROW nRow)
Definition: column3.cxx:3075
void DeleteSparklineCells(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2)
Definition: column2.cxx:2068
void SetEditText(SCROW nRow, std::unique_ptr< EditTextObject > pEditText)
Definition: column3.cxx:2359
void DeleteContent(SCROW nRow, bool bBroadcast=true)
Definition: column3.cxx:205
sc::CellStoreType & GetCellStore()
Definition: column.hxx:257
bool SetString(SCROW nRow, SCTAB nTab, const OUString &rString, formula::FormulaGrammar::AddressConvention eConv, const ScSetStringParam *pParam=nullptr)
Returns true if the cell format was set as well.
Definition: column3.cxx:2339
void DeleteArea(SCROW nStartRow, SCROW nEndRow, InsertDeleteFlags nDelFlag, bool bBroadcast=true, sc::ColumnSpanSet *pBroadcastSpans=nullptr)
Definition: column3.cxx:1101
double GetValue(SCROW nRow) const
Definition: column3.cxx:3094
static void JoinNewFormulaCell(const sc::CellStoreType::position_type &aPos, ScFormulaCell &rCell)
Definition: column3.cxx:362
sc::BroadcasterStoreType maBroadcasters
Definition: column.hxx:194
OUString GetString(SCROW nRow, const ScInterpreterContext *pContext=nullptr) const
Definition: column.hxx:441
void SetRawString(SCROW nRow, const OUString &rStr)
Definition: column3.cxx:2977
void RemoveEditTextCharAttribs(SCROW nRow, const ScPatternAttr &rAttr)
Definition: column3.cxx:3128
SCROW GetLastDataPos() const
Definition: column2.cxx:1417
CellType GetCellType(SCROW nRow) const
Definition: column3.cxx:3160
const ScFormulaCell * FetchFormulaCell(SCROW nRow) const
Definition: column2.cxx:3321
ScDocument & GetDoc() const
Definition: column.hxx:127
sal_uInt32 GetNumberFormat(const ScInterpreterContext &rContext, SCROW nRow) const
Definition: column.hxx:980
sc::SparklineStoreType maSparklines
Definition: column.hxx:200
void AttachFormulaCells(sc::StartListeningContext &rCxt, SCROW nRow1, SCROW nRow2)
Definition: column3.cxx:558
sc::CellStoreType::iterator GetPositionToInsert(SCROW nRow, std::vector< SCROW > &rNewSharedRows, bool bInsertFormula)
Definition: column3.cxx:356
void AttachNewFormulaCells(const sc::CellStoreType::position_type &aPos, size_t nLength, std::vector< SCROW > &rNewSharedRows)
Definition: column3.cxx:758
const ScCondFormatIndexes & GetCondFormatData() const
Definition: attrib.hxx:287
sal_uInt16 GetStdPrecision() const
Definition: docoptio.hxx:78
bool IsCalcingAfterLoad() const
Definition: document.hxx:2228
bool ValidRow(SCROW nRow) const
Definition: document.hxx:900
SC_DLLPUBLIC ScTable * FetchTable(SCTAB nTab)
Definition: document.cxx:2509
SC_DLLPUBLIC SCROW GetMaxRowCount() const
Definition: document.hxx:895
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6050
SC_DLLPUBLIC void CheckLinkFormulaNeedingCheck(const ScTokenArray &rCode)
Check token array and set link check if ocDde/ocWebservice is contained.
Definition: documen8.cxx:1149
SC_DLLPUBLIC ScFieldEditEngine & GetEditEngine()
Definition: documen2.cxx:483
SC_DLLPUBLIC double RoundValueAsShown(double fVal, sal_uInt32 nFormat, const ScInterpreterContext *pContext=nullptr) const
Definition: documen4.cxx:627
ScInterpreterContext & GetNonThreadedContext() const
Definition: document.hxx:617
SC_DLLPUBLIC SvtScriptType GetStringScriptType(const OUString &rString)
Definition: documen6.cxx:76
bool IsDelayedFormulaGrouping() const
Definition: document.hxx:1425
void Broadcast(const ScHint &rHint)
Broadcast wrapper, calls rHint.GetCell()->Broadcast() and AreaBroadcast() and TrackFormulas() Preferr...
Definition: documen7.cxx:117
void EndListeningFormulaCells(std::vector< ScFormulaCell * > &rCells)
Definition: documen7.cxx:253
bool IsClipOrUndo() const
Definition: document.hxx:1592
bool IsInsertingFromOtherDoc() const
Definition: document.hxx:2224
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:601
SC_DLLPUBLIC ScConditionalFormatList * GetCondFormList(SCTAB nTab) const
Definition: documen4.cxx:860
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:467
bool CanDelayStartListeningFormulaCells(ScColumn *column, SCROW row1, SCROW row2)
If true is returned, ScColumn::StartListeningFormulaCells() for the given cells will be performed lat...
Definition: document10.cxx:430
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:791
SC_DLLPUBLIC const ScDocOptions & GetDocOptions() const
Definition: documen3.cxx:1936
void SetTextCurrentDefaults(const EditTextObject &rTextObject)
SetText and apply defaults already set.
Definition: editutil.cxx:619
static void RemoveCharAttribs(EditTextObject &rEditText, const ScPatternAttr &rAttr)
Definition: editutil.cxx:155
static SC_DLLPUBLIC OUString GetString(const EditTextObject &rEditText, const ScDocument *pDoc)
Retrieves string with paragraphs delimited by new lines (' ').
Definition: editutil.cxx:119
bool IsShared() const
SCROW GetSharedLength() const
void SetErrCode(FormulaError n)
void SetNeedNumberFormat(bool bVal)
void SetCellGroup(const ScFormulaCellGroupRef &xRef)
const ScFormulaCellGroupRef & GetCellGroup() const
SCROW GetSharedTopRow() const
bool IsEmptyDisplayedAsString()
bool IsSharedTop() const
double GetValue()
const svl::SharedString & GetString()
FormulaError GetErrCode()
void EndListeningTo(ScDocument &rDoc, ScTokenArray *pArr=nullptr, ScAddress aPos=ScAddress())
bool NeedsNumberFormat() const
void StartListeningTo(ScDocument &rDoc)
bool NeedsListening() const
void MaybeInterpret()
void SetDirty(bool bDirtyFlag=true)
ScFormulaCellGroupRef CreateCellGroup(SCROW nLen, bool bInvariant)
Turn a non-grouped cell into the top of a grouped cell.
CompareState CompareByTokenArray(const ScFormulaCell &rOther) const
ScTokenArray * GetCode()
bool IsMultilineResult()
Determines whether or not the result string contains more than one paragraph.
ScAddress aPos
static OUString GetErrorString(FormulaError nErrNumber)
Definition: global.cxx:315
void SetAddressRow(SCROW nRow)
Definition: brdcst.hxx:37
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
bool IsMultiMarked() const
Definition: markdata.hxx:81
const ScMultiSel & GetMultiSelData() const
Definition: markdata.hxx:106
bool Next(SCROW &rTop, SCROW &rBottom)
Definition: markmulti.cxx:455
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1398
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:73
bool GetHideFormula() const
Definition: attrib.hxx:150
bool GetHideCell() const
Definition: attrib.hxx:152
static bool parseSimpleNumber(const OUString &rStr, sal_Unicode dsep, sal_Unicode gsep, sal_Unicode dsepa, double &rVal, bool bDetectScientificNumber=true)
Check if a given string is a simple decimal number (e.g.
Definition: stringutil.cxx:55
virtual formula::FormulaToken * AddOpCode(OpCode eCode) override
Definition: token.cxx:2265
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
static bool SafePlus(double &fVal1, double fVal2)
Definition: subtotal.cxx:24
static bool SafeMult(double &fVal1, double fVal2)
Definition: subtotal.cxx:40
static bool SafeDiv(double &fVal1, double fVal2)
Definition: subtotal.cxx:53
sal_uInt32 GetStandardFormat(SvNumFormatType eType, LanguageType eLnge=LANGUAGE_DONTKNOW)
sal_uInt32 GetEditFormat(double fNumber, sal_uInt32 nFIndex, SvNumFormatType eType, SvNumberformat const *pFormat, LanguageType eForLocale=LANGUAGE_DONTKNOW)
void GetInputLineString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &rOutString, bool bFiltering=false, bool bForceSystemLocale=false)
sal_uInt16 GetFormatPrecision(sal_uInt32 nFormat) const
static const sal_uInt16 UNLIMITED_PRECISION
SvNumFormatType GetType(sal_uInt32 nFIndex) const
sal_uInt32 GetFormatIndex(NfIndexTableOffset, LanguageType eLnge=LANGUAGE_DONTKNOW)
OUString GetFormatDecimalSep(sal_uInt32 nFormat) const
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
static bool IsCompatible(SvNumFormatType eOldType, SvNumFormatType eNewType)
sal_uInt32 GetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType eLnge=LANGUAGE_DONTKNOW)
void SetEvalDateFormat(NfEvalDateFormat eEDF)
const LocaleDataWrapper * GetLocaleData() const
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
NfEvalDateFormat GetEvalDateFormat() const
SvNumFormatType GetMaskedType() const
LanguageType GetLanguage() const
void GetFormatSpecialInfo(bool &bThousand, bool &IsRed, sal_uInt16 &nPrecision, sal_uInt16 &nLeadingCnt) const
static Grammar mergeToGrammar(const Grammar eGrammar, const AddressConvention eConv)
FormulaToken * AddToken(const FormulaToken &)
sal_uInt16 GetLen() const
FormulaToken * FirstToken() const
Temporarily switch on/off auto calculation mode.
Definition: scopetools.hxx:27
ColumnBlockPosition * getBlockPosition(SCTAB nTab, SCCOL nCol)
Definition: clipcontext.cxx:33
Structure that stores segments of boolean flags per column, and perform custom action on those segmen...
void set(const ScDocument &rDoc, SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal)
bool isCloneSparklines() const
bool isSkipEmptyCells() const
Get the flag that indicates whether the "skip empty cells" paste option is selected.
InsertDeleteFlags getInsertFlag() const
bool isDateCell(const ScColumn &rCol, SCROW nRow) const
ScDocument * getDestDoc()
static void groupFormulaCells(const Iter &itBeg, const Iter &itEnd)
Group formula cells stored in the passed container.
static void startListeningAsGroup(StartListeningContext &rCxt, ScFormulaCell **ppSharedTop)
Have all formula cells belonging to a group start listening to their references.
static bool joinFormulaCells(const CellStoreType::position_type &rPos, ScFormulaCell &rCell1, ScFormulaCell &rCell2)
See if two specified adjacent formula cells can be merged, and if they can, merge them into the same ...
static void unshareFormulaCell(const CellStoreType::position_type &aPos, ScFormulaCell &rCell)
Turn a shared formula cell into a non-shared one, and split it off from the adjacent formula cell gro...
static bool joinFormulaCellAbove(const CellStoreType::position_type &aPos)
Merge with an existing formula group (if any) located immediately above if the cell at specified posi...
static bool splitFormulaCellGroup(const CellStoreType::position_type &aPos, sc::EndListeningContext *pCxt)
Split existing shared formula range at specified position.
static const ScFormulaCell * getSharedTopFormulaCell(const CellStoreType::position_type &aPos)
Get shared formula top cell from position, if any, else nullptr.
Keep track of spans in a single column only.
void scan(const ScColumn &rColumn)
Scan an entire column and tag all non-empty cell positions.
std::vector< RowSpan > SpansType
void getSpans(SpansType &rSpans) const
void getRows(std::vector< SCROW > &rRows) const
void set(SCROW nRow1, SCROW nRow2, bool bVal)
SharedString intern(const OUString &rStr)
rtl_uString * getData()
static void lcl_AddFormulaGroupBoundaries(const sc::CellStoreType::position_type &rPos, std::vector< SCROW > &rNewSharedRows)
Definition: column3.cxx:631
sal_Int32 nElements
int nCount
#define suppress_fun_call_w_exception(expr)
sal_Int32 mnRow
sal_Int32 mnCol
std::size_t mnCount
FormulaError
double maValue
CellType
Definition: global.hxx:272
@ CELLTYPE_EDIT
Definition: global.hxx:277
@ CELLTYPE_STRING
Definition: global.hxx:275
@ CELLTYPE_FORMULA
Definition: global.hxx:276
@ CELLTYPE_NONE
Definition: global.hxx:273
@ CELLTYPE_VALUE
Definition: global.hxx:274
ScPasteFunc
Definition: global.hxx:181
InsertDeleteFlags
Definition: global.hxx:149
@ SPARKLINES
Sheet / outlining (grouping) information.
@ NOTE
Strings (and string results if InsertDeleteFlags::FORMULA is not set).
@ NOCAPTIONS
Sparklines in a cell.
@ SPECIAL_BOOLEAN
Internal use only (copy from clip): do not delete existing cell contents when pasting notes.
@ EDITATTR
Drawing objects.
@ STRING
Dates, times, datetime values.
@ DATETIME
Numeric values (and numeric results if InsertDeleteFlags::FORMULA is not set).
@ ATTRIB
Internal use only (d&d undo): do not delete caption objects of cell notes.
@ FORMULA
Cell notes.
@ HARDATTR
Formula cells.
STRING
SfxHintId
sal_Int32 nIndex
void * p
sal_Int64 n
sal_uInt16 nPos
const char * pLocale
aStr
int i
enumrange< T >::Iterator begin(enumrange< T >)
end
CellStoreType::const_iterator ParseAllNonEmpty(const typename CellStoreType::const_iterator &itPos, const CellStoreType &rCells, SCROW nRow1, SCROW nRow2, Func &rFunc)
Definition: mtvcellfunc.hxx:95
StoreT::const_iterator ParseBlock(const typename StoreT::const_iterator &itPos, const StoreT &rStore, Func &rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
Generic algorithm to parse blocks of multi_type_vector either partially or fully.
const mdds::mtv::element_t element_type_celltextattr
Definition: mtvelements.hxx:45
const mdds::mtv::element_t element_type_edittext
Definition: mtvelements.hxx:48
CellStoreType::iterator ProcessFormula(const CellStoreType::iterator &it, CellStoreType &rStore, SCROW nRow1, SCROW nRow2, std::function< void(size_t, ScFormulaCell *)> aFuncElem)
Process formula cells found within specified row range.
Definition: mtvcellfunc.cxx:12
const mdds::mtv::element_t element_type_formula
Definition: mtvelements.hxx:49
StoreT::iterator ProcessBlock(const typename StoreT::iterator &itPos, StoreT &rStore, Func &rFunc, typename StoreT::size_type nStart, typename StoreT::size_type nEnd)
Non-const variant of the above function.
void ParseFormula(const CellStoreType &rStore, Func &rFunc)
Definition: mtvcellfunc.hxx:63
mdds::mtv::soa::multi_type_vector< CellStoreTraits > CellStoreType
Cell container.
const mdds::mtv::element_t element_type_numeric
Mapped standard element types (for convenience).
Definition: mtvelements.hxx:55
CellStoreType::const_iterator ParseFormulaNumeric(const CellStoreType::const_iterator &itPos, const CellStoreType &rCells, SCROW nRow1, SCROW nRow2, Func &rFunc)
CellStoreType::const_iterator ParseAll(const typename CellStoreType::const_iterator &itPos, const CellStoreType &rCells, SCROW nRow1, SCROW nRow2, FuncElem &rFuncElem, FuncElse &rFuncElse)
Definition: mtvcellfunc.hxx:83
StartListeningType
Definition: types.hxx:124
@ ConvertToGroupListening
Definition: types.hxx:125
@ SingleCellListening
Definition: types.hxx:126
@ NoListening
Definition: types.hxx:127
mdds::mtv::soa::multi_type_vector< CellTextAttrTraits > CellTextAttrStoreType
Cell text attribute container.
const mdds::mtv::element_t element_type_string
Definition: mtvelements.hxx:47
const mdds::mtv::element_t element_type_empty
Definition: mtvelements.hxx:56
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
const SvxPageUsage aArr[]
long Long
OpCode
ocDiv
ocAdd
ocSub
ocMul
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
ScAddress & mrPos
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALUE_FORMAT(146)
constexpr TypedWhichId< ScProtectionAttr > ATTR_PROTECTION(149)
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
static SfxItemSet & rSet
sal_uIntPtr sal_uLong
Store arbitrary cell value of any kind.
Definition: cellvalue.hxx:32
void set(double fValue)
Definition: cellvalue.cxx:329
CellType getType() const
Definition: cellvalue.cxx:296
void release(ScDocument &rDoc, const ScAddress &rPos)
Set cell value at specified position in specified document.
Definition: cellvalue.cxx:456
DeleteCellsResult(const ScDocument &rDoc)
Definition: column3.cxx:1070
void addBackgroundColor(const Color &aBackgroundColor)
void addTextColor(const Color &aTextColor)
void push_back(const ScTypedStrData &r)
SvNumberFormatter * GetFormatTable() const
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
ScFormulaCell * getFormula() const
Definition: cellvalue.hxx:137
double getDouble() const
Definition: cellvalue.hxx:134
double getValue()
Definition: cellvalue.cxx:629
bool hasString() const
Definition: cellvalue.cxx:614
CellType getType() const
Definition: cellvalue.hxx:133
Store parameters used in the ScDocument::SetString() method.
Definition: stringutil.hxx:35
bool mbHandleApostrophe
When true, treat input with a leading apostrophe as an escape character for all content,...
Definition: stringutil.hxx:94
bool mbCheckLinkFormula
When true and the string results in a compiled formula, check the formula tokens for presence of func...
Definition: stringutil.hxx:103
bool mbDetectScientificNumberFormat
Definition: stringutil.hxx:80
bool mbDetectNumberFormat
Specify which number formats are detected: mbDetectNumberFormat=true && mbDetectScientificNumberForma...
Definition: stringutil.hxx:79
SvNumberFormatter * mpNumFormatter
Stores the pointer to the number formatter instance to be used during number format detection.
Definition: stringutil.hxx:70
@ Always
Set Text number format if the input string can be parsed as a number or formula text.
Definition: stringutil.hxx:45
@ Never
Never set Text number format.
Definition: stringutil.hxx:62
@ SpecialNumberOnly
Set Text number format only when the input string is considered a special number but we only want to ...
Definition: stringutil.hxx:51
TextFormatPolicy meSetTextNumFormat
Determine when to set the 'Text' number format to the cell where the input string is being set.
Definition: stringutil.hxx:86
sc::StartListeningType meStartListening
Definition: stringutil.hxx:96
Single reference (one address) into the sheet.
Definition: refdata.hxx:30
void SetAbsCol(SCCOL nVal)
Definition: refdata.cxx:59
void SetAbsTab(SCTAB nVal)
Definition: refdata.cxx:93
void InitAddress(const ScAddress &rAdr)
InitAddress: InitFlags and set address.
Definition: refdata.cxx:27
void SetAbsRow(SCROW nVal)
Definition: refdata.cxx:76
void SetFlag3D(bool bVal)
Definition: refdata.hxx:89
void InitFlags()
No default ctor, because used in ScRawToken union, set InitFlags!
Definition: refdata.hxx:54
SvtScriptType mnScriptType
CellNoteStoreType::const_iterator miCellNotePos
CellTextAttrStoreType::const_iterator miCellTextAttrPos
CellStoreType::const_iterator miCellPos
Store position data for column array storage.
SparklineStoreType::iterator miSparklinePos
CellTextAttrStoreType::iterator miCellTextAttrPos
BroadcasterStoreType::iterator miBroadcasterPos
CellStoreType::iterator miCellPos
CellNoteStoreType::iterator miCellNotePos
sal_uInt16 sal_Unicode
sal_Int16 SCTAB
Definition: types.hxx:22
::boost::intrusive_ptr< ScFormulaCellGroup > ScFormulaCellGroupRef
Definition: types.hxx:43
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17
size_t pos
sal_Int32 nLength
SvNumFormatType
NfEvalDateFormat
NF_EVALDATEFORMAT_INTL_FORMAT
NF_EVALDATEFORMAT_FORMAT_INTL
#define SV_COUNTRY_LANGUAGE_OFFSET