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