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