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