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