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