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 
48 #include <com/sun/star/i18n/LocaleDataItem2.hpp>
49 #include <com/sun/star/lang/IllegalArgumentException.hpp>
50 
51 #include <memory>
52 
53 #include <rtl/tencinfo.h>
54 
55 #include <svl/zforlist.hxx>
56 #include <svl/zformat.hxx>
57 #include <svl/sharedstringpool.hxx>
58 #include <osl/diagnose.h>
59 
60 #include <cstdio>
61 #include <refdata.hxx>
62 
63 using ::com::sun::star::i18n::LocaleDataItem2;
64 
65 using namespace formula;
66 
68 {
69  ScHint aHint(SfxHintId::ScDataChanged, ScAddress(nCol, nRow, nTab));
70  GetDoc().Broadcast(aHint);
71 }
72 
73 void ScColumn::BroadcastCells( const std::vector<SCROW>& rRows, SfxHintId nHint )
74 {
75  if (rRows.empty())
76  return;
77 
78  // Broadcast the changes.
79  ScDocument& rDocument = GetDoc();
80  ScHint aHint(nHint, ScAddress(nCol, 0, nTab));
81  for (const auto& rRow : rRows)
82  {
83  aHint.GetAddress().SetRow(rRow);
84  rDocument.Broadcast(aHint);
85  }
86 }
87 
88 void ScColumn::BroadcastRows( SCROW nStartRow, SCROW nEndRow, SfxHintId nHint )
89 {
90  sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
91  aSpanSet.scan(*this, nStartRow, nEndRow);
92  std::vector<SCROW> aRows;
93  aSpanSet.getRows(aRows);
94  BroadcastCells(aRows, nHint);
95 }
96 
97 namespace {
98 
99 struct DirtyCellInterpreter
100 {
101  void operator() (size_t, ScFormulaCell* p)
102  {
103  if (p->GetDirty())
104  p->Interpret();
105  }
106 };
107 
108 }
109 
111 {
112  if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
113  return;
114 
115  DirtyCellInterpreter aFunc;
116  sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
117 }
118 
119 void ScColumn::DeleteContent( SCROW nRow, bool bBroadcast )
120 {
121  sc::CellStoreType::position_type aPos = maCells.position(nRow);
122  sc::CellStoreType::iterator it = aPos.first;
123  if (it == maCells.end())
124  return;
125 
126  if (it->type == sc::element_type_formula)
127  {
128  ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
129  p->EndListeningTo(GetDoc());
131  }
132  maCells.set_empty(nRow, nRow);
133 
134  if (bBroadcast)
135  {
136  Broadcast(nRow);
137  CellStorageModified();
138  }
139 }
140 
142 {
143  DeleteContent(nRow, false);
144  maCellTextAttrs.set_empty(nRow, nRow);
145  maCellNotes.set_empty(nRow, nRow);
146 
147  Broadcast(nRow);
148  CellStorageModified();
149 }
150 
152 {
153  auto maxRowCount = GetDoc().GetSheetLimits().GetMaxRowCount();
154  // Keep a logical empty range of 0-rDoc.MaxRow() at all times.
155  maCells.clear();
156  maCells.resize(maxRowCount);
157  maCellTextAttrs.clear();
158  maCellTextAttrs.resize(maxRowCount);
159  maCellNotes.clear();
160  maCellNotes.resize(maxRowCount);
161  CellStorageModified();
162 }
163 
165 {
166  maCellNotes.clear();
167  maCellNotes.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
168 }
169 
170 namespace {
171 
172 class ShiftFormulaPosHandler
173 {
174 public:
175 
176  void operator() (size_t nRow, ScFormulaCell* pCell)
177  {
178  pCell->aPos.SetRow(nRow);
179  }
180 };
181 
182 }
183 
184 void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize, std::vector<ScAddress>* pGroupPos )
185 {
186  pAttrArray->DeleteRow( nStartRow, nSize );
187 
188  SCROW nEndRow = nStartRow + nSize - 1;
189 
190  maBroadcasters.erase(nStartRow, nEndRow);
191  maBroadcasters.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
192 
193  CellNotesDeleting(nStartRow, nEndRow, false);
194  maCellNotes.erase(nStartRow, nEndRow);
195  maCellNotes.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
196 
197  // See if we have any cells that would get deleted or shifted by deletion.
198  sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
199  sc::CellStoreType::iterator itCell = aPos.first;
200  if (itCell->type == sc::element_type_empty)
201  {
202  // This is an empty block. If this is the last block, then there is no cells to delete or shift.
203  sc::CellStoreType::iterator itTest = itCell;
204  ++itTest;
205  if (itTest == maCells.end())
206  {
207  // No cells are affected by this deletion. Bail out.
208  CellStorageModified(); // broadcast array has been modified.
209  return;
210  }
211  }
212 
213  // Check if there are any cells below the end row that will get shifted.
214  bool bShiftCells = false;
215  if (nEndRow < GetDoc().MaxRow()) //only makes sense to do this if there *is* a row after the end row
216  {
217  aPos = maCells.position(itCell, nEndRow+1);
218  itCell = aPos.first;
219  if (itCell->type == sc::element_type_empty)
220  {
221  // This block is empty. See if there is any block that follows.
222  sc::CellStoreType::iterator itTest = itCell;
223  ++itTest;
224  if (itTest != maCells.end())
225  // Non-empty block follows -> cells that will get shifted.
226  bShiftCells = true;
227  }
228  else
229  bShiftCells = true;
230  }
231 
232  sc::SingleColumnSpanSet aNonEmptySpans(GetDoc().GetSheetLimits());
233  if (bShiftCells)
234  {
235  // Mark all non-empty cell positions below the end row.
237  aBlockPos.miCellPos = itCell;
238  aNonEmptySpans.scan(aBlockPos, *this, nEndRow+1, GetDoc().MaxRow());
239  }
240 
241  sc::AutoCalcSwitch aACSwitch(GetDoc(), false);
242 
243  // Remove the cells.
244  maCells.erase(nStartRow, nEndRow);
245  maCells.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
246 
247  // Get the position again after the container change.
248  aPos = maCells.position(nStartRow);
249 
250  // Shift the formula cell positions below the start row.
251  ShiftFormulaPosHandler aShiftFormulaFunc;
252  sc::ProcessFormula(aPos.first, maCells, nStartRow, GetDoc().MaxRow(), aShiftFormulaFunc);
253 
254  bool bJoined = sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
255  if (bJoined && pGroupPos)
256  pGroupPos->push_back(ScAddress(nCol, nStartRow, nTab));
257 
258  // Shift the text attribute array too (before the broadcast).
259  maCellTextAttrs.erase(nStartRow, nEndRow);
260  maCellTextAttrs.resize(GetDoc().GetSheetLimits().GetMaxRowCount());
261 
262  CellStorageModified();
263 }
264 
265 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow, std::vector<SCROW>& rNewSharedRows,
266  bool bInsertFormula )
267 {
268  return GetPositionToInsert(maCells.begin(), nRow, rNewSharedRows, bInsertFormula);
269 }
270 
272  const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell )
273 {
274  // Check the previous row position for possible grouping.
275  if (aPos.first->type == sc::element_type_formula && aPos.second > 0)
276  {
277  ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
278  sc::CellStoreType::position_type aPosPrev = aPos;
279  --aPosPrev.second;
280  sc::SharedFormulaUtil::joinFormulaCells(aPosPrev, rPrev, rCell);
281  }
282 
283  // Check the next row position for possible grouping.
284  if (aPos.first->type == sc::element_type_formula && aPos.second+1 < aPos.first->size)
285  {
286  ScFormulaCell& rNext = *sc::formula_block::at(*aPos.first->data, aPos.second+1);
287  sc::SharedFormulaUtil::joinFormulaCells(aPos, rCell, rNext);
288  }
289 }
290 
292  const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, std::vector<SCROW>& rNewSharedRows )
293 {
294  if (!GetDoc().IsClipOrUndo())
295  {
296 #if USE_FORMULA_GROUP_LISTENER
297  if (rCell.IsShared() && rCell.GetSharedLength() > 1)
298  {
299  // Record new spans (shared or remaining single) that will result
300  // from unsharing to reestablish listeners.
301  // Same cases as in unshareFormulaCell().
302  // XXX NOTE: this is not part of unshareFormulaCell() because that
303  // is called in other contexts as well, for which passing and
304  // determining the rows vector would be superfluous. If that was
305  // needed, move it there.
306  const SCROW nSharedTopRow = rCell.GetSharedTopRow();
307  const SCROW nSharedLength = rCell.GetSharedLength();
308  if (rCell.aPos.Row() == nSharedTopRow)
309  {
310  // Top cell.
311  // Next row will be new shared top or single cell.
312  rNewSharedRows.push_back( nSharedTopRow + 1);
313  rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
314  }
315  else if (rCell.aPos.Row() == nSharedTopRow + nSharedLength - 1)
316  {
317  // Bottom cell.
318  // Current shared top row will be new shared top again or
319  // single cell.
320  rNewSharedRows.push_back( nSharedTopRow);
321  rNewSharedRows.push_back( rCell.aPos.Row() - 1);
322  }
323  else
324  {
325  // Some mid cell.
326  // Current shared top row will be new shared top again or
327  // single cell, plus a new shared top below or single cell.
328  rNewSharedRows.push_back( nSharedTopRow);
329  rNewSharedRows.push_back( rCell.aPos.Row() - 1);
330  rNewSharedRows.push_back( rCell.aPos.Row() + 1);
331  rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
332  }
333  }
334 #endif
335 
336  // Have the dying formula cell stop listening.
337  // If in a shared formula group this ends the group listening.
338  rCell.EndListeningTo(GetDoc());
339  }
340 
342 }
343 
344 void ScColumn::StartListeningUnshared( const std::vector<SCROW>& rNewSharedRows )
345 {
346  assert(rNewSharedRows.empty() || rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4);
347  ScDocument& rDoc = GetDoc();
348  if (rNewSharedRows.empty() || rDoc.IsDelayedFormulaGrouping())
349  return;
350 
351  auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(rDoc);
352  sc::StartListeningContext aStartCxt(rDoc, pPosSet);
353  sc::EndListeningContext aEndCxt(rDoc, pPosSet);
354  if (rNewSharedRows.size() >= 2)
355  {
356  if(!rDoc.CanDelayStartListeningFormulaCells( this, rNewSharedRows[0], rNewSharedRows[1]))
357  StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[0], rNewSharedRows[1]);
358  }
359  if (rNewSharedRows.size() >= 4)
360  {
361  if(!rDoc.CanDelayStartListeningFormulaCells( this, rNewSharedRows[2], rNewSharedRows[3]))
362  StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[2], rNewSharedRows[3]);
363  }
364 }
365 
366 namespace {
367 
368 class AttachFormulaCellsHandler
369 {
371 
372 public:
373  explicit AttachFormulaCellsHandler(sc::StartListeningContext& rCxt)
374  : mrCxt(rCxt) {}
375 
376  void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
377  {
378  pCell->StartListeningTo(mrCxt);
379  }
380 };
381 
382 class DetachFormulaCellsHandler
383 {
384  ScDocument& mrDoc;
386 
387 public:
388  DetachFormulaCellsHandler( ScDocument& rDoc, sc::EndListeningContext* pCxt ) :
389  mrDoc(rDoc), mpCxt(pCxt) {}
390 
391  void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
392  {
393  if (mpCxt)
394  pCell->EndListeningTo(*mpCxt);
395  else
396  pCell->EndListeningTo(mrDoc);
397  }
398 };
399 
400 }
401 
403  const sc::CellStoreType::position_type& aPos, size_t nLength, std::vector<SCROW>* pNewSharedRows )
404 {
405  const size_t nRow = aPos.first->position + aPos.second;
406  const size_t nNextTopRow = nRow + nLength; // start row of next formula group.
407 
408  bool bLowerSplitOff = false;
409  if (pNewSharedRows && !GetDoc().IsClipOrUndo())
410  {
412  if (pFC)
413  {
414  const SCROW nTopRow = pFC->GetSharedTopRow();
415  const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
416  // nTopRow <= nRow <= nBotRow, because otherwise pFC would not exist.
417  if (nTopRow < static_cast<SCROW>(nRow))
418  {
419  // Upper part will be split off.
420  pNewSharedRows->push_back(nTopRow);
421  pNewSharedRows->push_back(nRow - 1);
422  }
423  if (static_cast<SCROW>(nNextTopRow) <= nBotRow)
424  {
425  // Lower part will be split off.
426  pNewSharedRows->push_back(nNextTopRow);
427  pNewSharedRows->push_back(nBotRow);
428  bLowerSplitOff = true;
429  }
430  }
431  }
432 
433  // Split formula grouping at the top and bottom boundaries.
435 
436  if (nLength > 0 && GetDoc().ValidRow(nNextTopRow))
437  {
438  if (pNewSharedRows && !bLowerSplitOff && !GetDoc().IsClipOrUndo())
439  {
440  sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow-1);
442  if (pFC)
443  {
444  const SCROW nTopRow = pFC->GetSharedTopRow();
445  const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
446  // nRow < nTopRow < nNextTopRow <= nBotRow
447  if (static_cast<SCROW>(nNextTopRow) <= nBotRow)
448  {
449  // Lower part will be split off.
450  pNewSharedRows->push_back(nNextTopRow);
451  pNewSharedRows->push_back(nBotRow);
452  }
453  }
454  }
455 
456  sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow);
458  }
459 
460  if (GetDoc().IsClipOrUndo())
461  return;
462 
463  DetachFormulaCellsHandler aFunc(GetDoc(), nullptr);
464  sc::ProcessFormula(aPos.first, maCells, nRow, nNextTopRow-1, aFunc);
465 }
466 
468 {
469  sc::CellStoreType::position_type aPos = maCells.position(nRow1);
470  sc::CellStoreType::iterator it = aPos.first;
471 
473  if (GetDoc().ValidRow(nRow2+1))
474  {
475  aPos = maCells.position(it, nRow2+1);
477  }
478 
479  if (GetDoc().IsClipOrUndo())
480  return;
481 
482  AttachFormulaCellsHandler aFunc(rCxt);
483  sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
484 }
485 
487  std::vector<SCROW>* pNewSharedRows )
488 {
489  sc::CellStoreType::position_type aPos = maCells.position(nRow1);
490  sc::CellStoreType::iterator it = aPos.first;
491 
492  bool bLowerSplitOff = false;
493  if (pNewSharedRows && !GetDoc().IsClipOrUndo())
494  {
496  if (pFC)
497  {
498  const SCROW nTopRow = pFC->GetSharedTopRow();
499  const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
500  // nTopRow <= nRow1 <= nBotRow, because otherwise pFC would not exist.
501  if (nTopRow < nRow1)
502  {
503  // Upper part will be split off.
504  pNewSharedRows->push_back(nTopRow);
505  pNewSharedRows->push_back(nRow1 - 1);
506  }
507  if (nRow2 < nBotRow)
508  {
509  // Lower part will be split off.
510  pNewSharedRows->push_back(nRow2 + 1);
511  pNewSharedRows->push_back(nBotRow);
512  bLowerSplitOff = true;
513  }
514  }
515  }
516 
517  // Split formula grouping at the top and bottom boundaries.
519  if (GetDoc().ValidRow(nRow2+1))
520  {
521  if (pNewSharedRows && !bLowerSplitOff && !GetDoc().IsClipOrUndo())
522  {
523  sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nRow2);
525  if (pFC)
526  {
527  const SCROW nTopRow = pFC->GetSharedTopRow();
528  const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
529  // nRow1 < nTopRow <= nRow2 < nBotRow
530  if (nRow2 < nBotRow)
531  {
532  // Lower part will be split off.
533  pNewSharedRows->push_back(nRow2 + 1);
534  pNewSharedRows->push_back(nBotRow);
535  }
536  }
537  }
538 
539  aPos = maCells.position(it, nRow2+1);
541  }
542 
543  if (GetDoc().IsClipOrUndo())
544  return;
545 
546  DetachFormulaCellsHandler aFunc(GetDoc(), &rCxt);
547  sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
548 }
549 
550 static void lcl_AddFormulaGroupBoundaries(const sc::CellStoreType::position_type& rPos,
551  std::vector<SCROW>& rNewSharedRows )
552 {
553  sc::CellStoreType::iterator itRet = rPos.first;
554  if (itRet->type != sc::element_type_formula)
555  return;
556 
557  ScFormulaCell& rFC = *sc::formula_block::at(*itRet->data, rPos.second);
558  if ( rFC.IsShared() )
559  {
560  const SCROW nSharedTopRow = rFC.GetSharedTopRow();
561  const SCROW nSharedLength = rFC.GetSharedLength();
562  rNewSharedRows.push_back( nSharedTopRow);
563  rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
564  }
565  else
566  {
567  const SCROW nRow = rFC.aPos.Row();
568  rNewSharedRows.push_back( nRow);
569  rNewSharedRows.push_back( nRow);
570  }
571 }
572 
573 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow,
574  std::vector<SCROW>& rNewSharedRows, bool bInsertFormula )
575 {
576  // See if we are overwriting an existing formula cell.
577  sc::CellStoreType::position_type aPos = maCells.position(it, nRow);
578  sc::CellStoreType::iterator itRet = aPos.first;
579 
580  if (itRet->type == sc::element_type_formula)
581  {
582  ScFormulaCell& rCell = *sc::formula_block::at(*itRet->data, aPos.second);
583  DetachFormulaCell(aPos, rCell, rNewSharedRows);
584  }
585  else if (bInsertFormula && !GetDoc().IsClipOrUndo())
586  {
587  if (nRow > 0)
588  {
589  sc::CellStoreType::position_type aPosBefore = maCells.position(maCells.begin(), nRow-1);
590  lcl_AddFormulaGroupBoundaries(aPosBefore, rNewSharedRows);
591  }
592  if (nRow < GetDoc().MaxRow())
593  {
594  sc::CellStoreType::position_type aPosAfter = maCells.position(maCells.begin(), nRow+1);
595  lcl_AddFormulaGroupBoundaries(aPosAfter, rNewSharedRows);
596  }
597  }
598 
599  return itRet;
600 }
601 
603  const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell,
604  const std::vector<SCROW>& rNewSharedRows,
605  bool bJoin, sc::StartListeningType eListenType )
606 {
607  AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, rNewSharedRows, bJoin, eListenType);
608 }
609 
611  const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell,
612  const std::vector<SCROW>& rNewSharedRows,
613  bool bJoin, sc::StartListeningType eListenType )
614 {
615  if (bJoin)
616  // See if this new formula cell can join an existing shared formula group.
617  JoinNewFormulaCell(aPos, rCell);
618 
619  // When we insert from the Clipboard we still have wrong (old) References!
620  // First they are rewired in CopyBlockFromClip via UpdateReference and the
621  // we call StartListeningFromClip and BroadcastFromClip.
622  // If we insert into the Clipboard/andoDoc, we do not use a Broadcast.
623  // After Import we call CalcAfterLoad and in there Listening.
624  ScDocument& rDocument = GetDoc();
625  if (rDocument.IsClipOrUndo() || rDocument.IsInsertingFromOtherDoc())
626  return;
627 
628  switch (eListenType)
629  {
631  {
632  auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(rDocument);
633  sc::StartListeningContext aStartCxt(rDocument, pPosSet);
634  sc::EndListeningContext aEndCxt(rDocument, pPosSet);
635  SCROW nStartRow, nEndRow;
636  nStartRow = nEndRow = aPos.first->position + aPos.second;
637  for (const SCROW nR : rNewSharedRows)
638  {
639  if (nStartRow > nR)
640  nStartRow = nR;
641  if (nEndRow < nR)
642  nEndRow = nR;
643  }
644  StartListeningFormulaCells(aStartCxt, aEndCxt, nStartRow, nEndRow);
645  }
646  break;
648  rCell.StartListeningTo(rDocument);
649  StartListeningUnshared( rNewSharedRows);
650  break;
651  case sc::NoListening:
652  default:
653  if (!rNewSharedRows.empty())
654  {
655  assert(rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4);
656  // Calling SetNeedsListeningGroup() with a top row sets it to
657  // all affected formula cells of that group.
658  const ScFormulaCell* pFC = GetFormulaCell( rNewSharedRows[0]);
659  assert(pFC); // that *is* supposed to be a top row
660  if (pFC && !pFC->NeedsListening())
661  SetNeedsListeningGroup( rNewSharedRows[0]);
662  if (rNewSharedRows.size() > 2)
663  {
664  pFC = GetFormulaCell( rNewSharedRows[2]);
665  assert(pFC); // that *is* supposed to be a top row
666  if (pFC && !pFC->NeedsListening())
667  SetNeedsListeningGroup( rNewSharedRows[2]);
668  }
669  }
670  break;
671  }
672 
673  if (!rDocument.IsCalcingAfterLoad())
674  rCell.SetDirty();
675 }
676 
677 void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength,
678  std::vector<SCROW>& rNewSharedRows )
679 {
680  // Make sure the whole length consists of formula cells.
681  if (aPos.first->type != sc::element_type_formula)
682  return;
683 
684  if (aPos.first->size < aPos.second + nLength)
685  // Block is shorter than specified length.
686  return;
687 
688  // Join the top and bottom cells only.
689  ScFormulaCell* pCell1 = sc::formula_block::at(*aPos.first->data, aPos.second);
690  JoinNewFormulaCell(aPos, *pCell1);
691 
692  sc::CellStoreType::position_type aPosLast = aPos;
693  aPosLast.second += nLength - 1;
694  ScFormulaCell* pCell2 = sc::formula_block::at(*aPosLast.first->data, aPosLast.second);
695  JoinNewFormulaCell(aPosLast, *pCell2);
696 
697  ScDocument& rDocument = GetDoc();
698  if (rDocument.IsClipOrUndo() || rDocument.IsInsertingFromOtherDoc())
699  return;
700 
701  const bool bShared = pCell1->IsShared() || pCell2->IsShared();
702  if (bShared)
703  {
704  const SCROW nTopRow = (pCell1->IsShared() ? pCell1->GetSharedTopRow() : pCell1->aPos.Row());
705  const SCROW nBotRow = (pCell2->IsShared() ?
706  pCell2->GetSharedTopRow() + pCell2->GetSharedLength() - 1 : pCell2->aPos.Row());
707  if (rNewSharedRows.empty())
708  {
709  rNewSharedRows.push_back( nTopRow);
710  rNewSharedRows.push_back( nBotRow);
711  }
712  else if (rNewSharedRows.size() == 2)
713  {
714  // Combine into one span.
715  if (rNewSharedRows[0] > nTopRow)
716  rNewSharedRows[0] = nTopRow;
717  if (rNewSharedRows[1] < nBotRow)
718  rNewSharedRows[1] = nBotRow;
719  }
720  else if (rNewSharedRows.size() == 4)
721  {
722  // Merge into one span.
723  // The original two spans are ordered from top to bottom.
724  std::vector<SCROW> aRows(2);
725  aRows[0] = std::min( rNewSharedRows[0], nTopRow);
726  aRows[1] = 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  break;
1856  {
1857  itDestPos = rDestCells.set_empty(itDestPos, nDestRow, nDestRow+rNewCell.size-1);
1858  bHasContent = false;
1859  }
1860  break;
1861  default:
1862  ;
1863  }
1864 
1865  sc::CellTextAttrStoreType& rDestAttrs = mrDestColumn.GetCellAttrStore();
1866  if (bHasContent)
1867  {
1868  std::vector<sc::CellTextAttr> aAttrs(rNewCell.size, sc::CellTextAttr());
1869  itDestAttrPos = rDestAttrs.set(itDestAttrPos, nDestRow, aAttrs.begin(), aAttrs.end());
1870  }
1871  else
1872  itDestAttrPos = rDestAttrs.set_empty(itDestAttrPos, nDestRow, nDestRow+rNewCell.size-1);
1873  }
1874 
1875  maNewCells.release();
1876  }
1877 };
1878 
1879 }
1880 
1882  sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, ScPasteFunc nFunction,
1883  bool bSkipEmpty, const ScColumn& rSrcCol )
1884 {
1885  // destination (this column) block position.
1886 
1887  sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
1888  if (!p)
1889  return;
1890 
1891  MixDataHandler aFunc(*p, *this, nRow1, nRow2, nFunction, bSkipEmpty);
1892  sc::ParseAll(rSrcCol.maCells.begin(), rSrcCol.maCells, nRow1, nRow2, aFunc, aFunc);
1893 
1894  aFunc.commit();
1895  CellStorageModified();
1896 }
1897 
1898 std::unique_ptr<ScAttrIterator> ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
1899 {
1900  return std::make_unique<ScAttrIterator>( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() );
1901 }
1902 
1903 namespace {
1904 
1905 class StartListenersHandler
1906 {
1908  bool mbAllListeners;
1909 
1910 public:
1911  StartListenersHandler( sc::StartListeningContext& rCxt, bool bAllListeners ) :
1912  mpCxt(&rCxt), mbAllListeners(bAllListeners) {}
1913 
1914  void operator() ( sc::CellStoreType::value_type& aBlk )
1915  {
1916  if (aBlk.type != sc::element_type_formula)
1917  return;
1918 
1919  ScFormulaCell** pp = &sc::formula_block::at(*aBlk.data, 0);
1920  ScFormulaCell** ppEnd = pp + aBlk.size;
1921 
1922  for (; pp != ppEnd; ++pp)
1923  {
1924  ScFormulaCell& rFC = **pp;
1925  if (!mbAllListeners && !rFC.NeedsListening())
1926  continue;
1927 
1928  if (rFC.IsSharedTop())
1929  {
1931  pp += rFC.GetSharedLength() - 1; // Move to the last cell in the group.
1932  }
1933  else
1934  rFC.StartListeningTo(*mpCxt);
1935  }
1936  }
1937 };
1938 
1939 }
1940 
1942 {
1943  std::for_each(maCells.begin(), maCells.end(), StartListenersHandler(rCxt, bAll));
1944 }
1945 
1946 namespace {
1947 
1948 void applyTextNumFormat( ScColumn& rCol, SCROW nRow, SvNumberFormatter* pFormatter )
1949 {
1950  sal_uInt32 nFormat = pFormatter->GetStandardFormat(SvNumFormatType::TEXT);
1951  ScPatternAttr aNewAttrs(rCol.GetDoc().GetPool());
1952  SfxItemSet& rSet = aNewAttrs.GetItemSet();
1953  rSet.Put(SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat));
1954  rCol.ApplyPattern(nRow, aNewAttrs);
1955 }
1956 
1957 }
1958 
1960  ScCellValue& rCell, SCROW nRow, SCTAB nTabP, const OUString& rString,
1962  const ScSetStringParam* pParam )
1963 {
1964  if (rString.isEmpty())
1965  return false;
1966 
1967  bool bNumFmtSet = false;
1968 
1969  ScSetStringParam aParam;
1970 
1971  if (pParam)
1972  aParam = *pParam;
1973 
1974  sal_uInt32 nIndex = 0;
1975  sal_uInt32 nOldIndex = 0;
1976  SvNumFormatType eNumFormatType = SvNumFormatType::ALL;
1977  if (!aParam.mpNumFormatter)
1978  aParam.mpNumFormatter = GetDoc().GetFormatTable();
1979 
1980  sal_Unicode cFirstChar = 0; // Text
1981  nIndex = nOldIndex = GetNumberFormat( GetDoc().GetNonThreadedContext(), nRow );
1982  if ( rString.getLength() > 1 )
1983  {
1984  eNumFormatType = aParam.mpNumFormatter->GetType(nIndex);
1985  if ( eNumFormatType != SvNumFormatType::TEXT )
1986  cFirstChar = rString[0];
1987  }
1988 
1989  svl::SharedStringPool& rPool = GetDoc().GetSharedStringPool();
1990 
1991  if ( cFirstChar == '=' )
1992  {
1993  if ( rString.getLength() == 1 ) // = Text
1994  {
1995  rCell.set(rPool.intern(rString));
1996  }
1997  else if (aParam.meSetTextNumFormat == ScSetStringParam::Always)
1998  {
1999  // Set the cell format type to Text.
2000  applyTextNumFormat(*this, nRow, aParam.mpNumFormatter);
2001  rCell.set(rPool.intern(rString));
2002  }
2003  else // = Formula
2004  {
2005  ScFormulaCell* pFormulaCell = new ScFormulaCell(
2006  GetDoc(), ScAddress(nCol, nRow, nTabP), rString,
2009  if (aParam.mbCheckLinkFormula)
2010  GetDoc().CheckLinkFormulaNeedingCheck( *pFormulaCell->GetCode());
2011  rCell.set( pFormulaCell);
2012  }
2013  }
2014  else if ( cFirstChar == '\'') // 'Text
2015  {
2016  bool bNumeric = false;
2017  if (aParam.mbHandleApostrophe)
2018  {
2019  // Cell format is not 'Text', and the first char
2020  // is an apostrophe. Check if the input is considered a number.
2021  OUString aTest = rString.copy(1);
2022  double fTest;
2023  bNumeric = aParam.mpNumFormatter->IsNumberFormat(aTest, nIndex, fTest);
2024  if (bNumeric)
2025  // This is a number. Strip out the first char.
2026  rCell.set(rPool.intern(aTest));
2027  }
2028  if (!bNumeric)
2029  // This is normal text. Take it as-is.
2030  rCell.set(rPool.intern(rString));
2031  }
2032  else
2033  {
2034  double nVal;
2035 
2036  do
2037  {
2038  if (aParam.mbDetectNumberFormat)
2039  {
2040  // Editing a date prefers the format's locale's edit date
2041  // format's date acceptance patterns and YMD order.
2042  /* TODO: this could be determined already far above when
2043  * starting to edit a date "cell" and passed down. A problem
2044  * could also be if a new date was typed over or written by a
2045  * macro assuming the current locale if that conflicts somehow.
2046  * You can't have everything. See tdf#116579 and tdf#125109. */
2047  if (eNumFormatType == SvNumFormatType::ALL)
2048  eNumFormatType = aParam.mpNumFormatter->GetType(nIndex);
2049  bool bForceFormatDate = (eNumFormatType == SvNumFormatType::DATE
2050  || eNumFormatType == SvNumFormatType::DATETIME);
2051  const SvNumberformat* pOldFormat = nullptr;
2053  if (bForceFormatDate)
2054  {
2055  ScRefCellValue aCell = GetCellValue(nRow);
2056  if (aCell.meType == CELLTYPE_VALUE)
2057  {
2058  // Only for an actual date (serial number), not an
2059  // arbitrary string or formula or empty cell.
2060  // Also ensure the edit date format's pattern is used,
2061  // not the display format's.
2062  pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex);
2063  if (!pOldFormat)
2064  bForceFormatDate = false;
2065  else
2066  {
2067  nIndex = aParam.mpNumFormatter->GetEditFormat( aCell.getValue(), nOldIndex, eNumFormatType,
2068  pOldFormat->GetLanguage(), pOldFormat);
2069  eEvalDateFormat = aParam.mpNumFormatter->GetEvalDateFormat();
2071  }
2072  }
2073  else
2074  {
2075  bForceFormatDate = false;
2076  }
2077  }
2078 
2079  const bool bIsNumberFormat = aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal);
2080 
2081  if (bForceFormatDate)
2082  aParam.mpNumFormatter->SetEvalDateFormat( eEvalDateFormat);
2083 
2084  if (!bIsNumberFormat)
2085  break;
2086 
2087  // If we have bForceFormatDate, the pOldFormat was/is of
2088  // nOldIndex date(+time) type already, if detected type is
2089  // compatible keep the original format.
2090  if (bForceFormatDate && SvNumberFormatter::IsCompatible(
2091  eNumFormatType, aParam.mpNumFormatter->GetType( nIndex)))
2092  {
2093  nIndex = nOldIndex;
2094  }
2095  else
2096  {
2097  // convert back to the original language if a built-in format was detected
2098  if (!pOldFormat)
2099  pOldFormat = aParam.mpNumFormatter->GetEntry( nOldIndex );
2100  if (pOldFormat)
2102  nIndex, pOldFormat->GetLanguage());
2103  }
2104 
2105  rCell.set(nVal);
2106  if ( nIndex != nOldIndex)
2107  {
2108  // #i22345# New behavior: Apply the detected number format only if
2109  // the old one was the default number, date, time or boolean format.
2110  // Exception: If the new format is boolean, always apply it.
2111 
2112  bool bOverwrite = false;
2113  if ( pOldFormat )
2114  {
2115  SvNumFormatType nOldType = pOldFormat->GetMaskedType();
2116  if ( nOldType == SvNumFormatType::NUMBER || nOldType == SvNumFormatType::DATE ||
2117  nOldType == SvNumFormatType::TIME || nOldType == SvNumFormatType::LOGICAL )
2118  {
2119  if ( nOldIndex == aParam.mpNumFormatter->GetStandardFormat(
2120  nOldType, pOldFormat->GetLanguage() ) )
2121  {
2122  bOverwrite = true; // default of these types can be overwritten
2123  }
2124  }
2125  }
2126  if ( !bOverwrite && aParam.mpNumFormatter->GetType( nIndex ) == SvNumFormatType::LOGICAL )
2127  {
2128  bOverwrite = true; // overwrite anything if boolean was detected
2129  }
2130 
2131  if ( bOverwrite )
2132  {
2133  ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT,
2134  nIndex) );
2135  bNumFmtSet = true;
2136  }
2137  }
2138  }
2139  else if (aParam.meSetTextNumFormat == ScSetStringParam::Never ||
2141  {
2142  // Only check if the string is a regular number.
2144  if (!pLocale)
2145  break;
2146 
2147  const LocaleDataItem2& aLocaleItem = pLocale->getLocaleItem();
2148  const OUString& rDecSep = aLocaleItem.decimalSeparator;
2149  const OUString& rGroupSep = aLocaleItem.thousandSeparator;
2150  const OUString& rDecSepAlt = aLocaleItem.decimalSeparatorAlternative;
2151  if (rDecSep.getLength() != 1 || rGroupSep.getLength() != 1 || rDecSepAlt.getLength() > 1)
2152  break;
2153 
2154  sal_Unicode dsep = rDecSep[0];
2155  sal_Unicode gsep = rGroupSep[0];
2156  sal_Unicode dsepa = rDecSepAlt.toChar();
2157 
2158  if (!ScStringUtil::parseSimpleNumber(rString, dsep, gsep, dsepa, nVal))
2159  break;
2160 
2161  rCell.set(nVal);
2162  }
2163  }
2164  while (false);
2165 
2166  if (rCell.meType == CELLTYPE_NONE)
2167  {
2168  // If we reach here with ScSetStringParam::SpecialNumberOnly it
2169  // means a simple number was not detected above, so test for
2170  // special numbers. In any case ScSetStringParam::Always does not
2171  // mean always, but only always for content that could be any
2172  // numeric.
2175  aParam.mpNumFormatter->IsNumberFormat(rString, nIndex, nVal))
2176  {
2177  // Set the cell format type to Text.
2178  applyTextNumFormat(*this, nRow, aParam.mpNumFormatter);
2179  }
2180 
2181  rCell.set(rPool.intern(rString));
2182  }
2183  }
2184 
2185  return bNumFmtSet;
2186 }
2187 
2191 bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString,
2193  const ScSetStringParam* pParam )
2194 {
2195  if (!GetDoc().ValidRow(nRow))
2196  return false;
2197 
2198  ScCellValue aNewCell;
2199  bool bNumFmtSet = ParseString(aNewCell, nRow, nTabP, rString, eConv, pParam);
2200  if (pParam)
2201  aNewCell.release(*this, nRow, pParam->meStartListening);
2202  else
2203  aNewCell.release(*this, nRow);
2204 
2205  // Do not set Formats and Formulas here anymore!
2206  // These are queried during output
2207 
2208  return bNumFmtSet;
2209 }
2210 
2211 void ScColumn::SetEditText( SCROW nRow, std::unique_ptr<EditTextObject> pEditText )
2212 {
2213  pEditText->NormalizeString(GetDoc().GetSharedStringPool());
2214  std::vector<SCROW> aNewSharedRows;
2215  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false);
2216  maCells.set(it, nRow, pEditText.release());
2217  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2218  CellStorageModified();
2219 
2220  StartListeningUnshared( aNewSharedRows);
2221 
2222  BroadcastNewCell(nRow);
2223 }
2224 
2225 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, std::unique_ptr<EditTextObject> pEditText )
2226 {
2227  pEditText->NormalizeString(GetDoc().GetSharedStringPool());
2228  std::vector<SCROW> aNewSharedRows;
2229  rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false);
2230  rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText.release());
2231  rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2232  rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2233 
2234  CellStorageModified();
2235 
2236  StartListeningUnshared( aNewSharedRows);
2237 
2238  BroadcastNewCell(nRow);
2239 }
2240 
2241 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const EditTextObject& rEditText )
2242 {
2243  if (GetDoc().GetEditPool() == rEditText.GetPool())
2244  {
2245  SetEditText(rBlockPos, nRow, rEditText.Clone());
2246  return;
2247  }
2248 
2249  // rats, yet another "spool"
2250  // Sadly there is no other way to change the Pool than to
2251  // "spool" the Object through a corresponding Engine
2252  EditEngine& rEngine = GetDoc().GetEditEngine();
2253  rEngine.SetText(rEditText);
2254  SetEditText(rBlockPos, nRow, rEngine.CreateTextObject());
2255 }
2256 
2257 void ScColumn::SetEditText( SCROW nRow, const EditTextObject& rEditText, const SfxItemPool* pEditPool )
2258 {
2259  if (pEditPool && GetDoc().GetEditPool() == pEditPool)
2260  {
2261  SetEditText(nRow, rEditText.Clone());
2262  return;
2263  }
2264 
2265  // rats, yet another "spool"
2266  // Sadly there is no other way to change the Pool than to
2267  // "spool" the Object through a corresponding Engine
2268  EditEngine& rEngine = GetDoc().GetEditEngine();
2269  rEngine.SetText(rEditText);
2270  SetEditText(nRow, rEngine.CreateTextObject());
2271 }
2272 
2274 {
2275  ScAddress aPos(nCol, nRow, nTab);
2276 
2277  std::vector<SCROW> aNewSharedRows;
2278  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2279  ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rArray, eGram);
2280  sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2281  if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
2282  pCell->SetNeedNumberFormat(true);
2283  it = maCells.set(it, nRow, pCell);
2284  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2285 
2286  CellStorageModified();
2287 
2288  AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
2289 }
2290 
2291 void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
2292 {
2293  ScAddress aPos(nCol, nRow, nTab);
2294 
2295  std::vector<SCROW> aNewSharedRows;
2296  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2297  ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rFormula, eGram);
2298  sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2299  if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
2300  pCell->SetNeedNumberFormat(true);
2301  it = maCells.set(it, nRow, pCell);
2302  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2303 
2304  CellStorageModified();
2305 
2306  AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
2307 }
2308 
2310  SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType,
2311  bool bInheritNumFormatIfNeeded )
2312 {
2313  std::vector<SCROW> aNewSharedRows;
2314  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2315  sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2316  if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded )
2317  pCell->SetNeedNumberFormat(true);
2318  it = maCells.set(it, nRow, pCell);
2319  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2320 
2321  CellStorageModified();
2322 
2323  AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows, true, eListenType);
2324 
2325  return pCell;
2326 }
2327 
2329  sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell,
2330  sc::StartListeningType eListenType,
2331  bool bInheritNumFormatIfNeeded )
2332 {
2333  std::vector<SCROW> aNewSharedRows;
2334  rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, true);
2335  sal_uInt32 nCellFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2336  if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded )
2337  pCell->SetNeedNumberFormat(true);
2338  rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pCell);
2339  rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2340  rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2341 
2342  CellStorageModified();
2343 
2344  AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, aNewSharedRows, true, eListenType);
2345 }
2346 
2347 bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells )
2348 {
2349  if (!GetDoc().ValidRow(nRow))
2350  return false;
2351 
2352  SCROW nEndRow = nRow + rCells.size() - 1;
2353  if (!GetDoc().ValidRow(nEndRow))
2354  return false;
2355 
2356  sc::CellStoreType::position_type aPos = maCells.position(nRow);
2357 
2358  // Detach all formula cells that will be overwritten.
2359  std::vector<SCROW> aNewSharedRows;
2360  DetachFormulaCells(aPos, rCells.size(), &aNewSharedRows);
2361 
2362  if (!GetDoc().IsClipOrUndo())
2363  {
2364  for (size_t i = 0, n = rCells.size(); i < n; ++i)
2365  {
2366  SCROW nThisRow = nRow + i;
2367  sal_uInt32 nFmt = GetNumberFormat(GetDoc().GetNonThreadedContext(), nThisRow);
2368  if ((nFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
2369  rCells[i]->SetNeedNumberFormat(true);
2370  }
2371  }
2372 
2373  std::vector<sc::CellTextAttr> aDefaults(rCells.size(), sc::CellTextAttr());
2374  maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end());
2375 
2376  maCells.set(aPos.first, nRow, rCells.begin(), rCells.end());
2377 
2378  CellStorageModified();
2379 
2380  // Reget position_type as the type may have changed to formula, block and
2381  // block size changed, ...
2382  aPos = maCells.position(nRow);
2383  AttachNewFormulaCells(aPos, rCells.size(), aNewSharedRows);
2384 
2385  return true;
2386 }
2387 
2389 {
2390  sc::CellStoreType::const_position_type aPos = maCells.position(nRow);
2391  switch (aPos.first->type)
2392  {
2394  return sc::string_block::at(*aPos.first->data, aPos.second);
2396  {
2397  const EditTextObject* pObj = sc::edittext_block::at(*aPos.first->data, aPos.second);
2398  std::vector<svl::SharedString> aSSs = pObj->GetSharedStrings();
2399  if (aSSs.size() != 1)
2400  // We don't handle multiline content for now.
2401  return svl::SharedString();
2402 
2403  return aSSs[0];
2404  }
2405  break;
2406  default:
2407  ;
2408  }
2409  return svl::SharedString();
2410 }
2411 
2412 namespace {
2413 
2414 class FilterEntriesHandler
2415 {
2416  ScColumn& mrColumn;
2417  ScFilterEntries& mrFilterEntries;
2418 
2419  void processCell(SCROW nRow, ScRefCellValue& rCell)
2420  {
2421  SvNumberFormatter* pFormatter = mrColumn.GetDoc().GetFormatTable();
2422  OUString aStr;
2423  sal_uLong nFormat = mrColumn.GetNumberFormat(mrColumn.GetDoc().GetNonThreadedContext(), nRow);
2424  ScCellFormat::GetInputString(rCell, nFormat, aStr, *pFormatter, mrColumn.GetDoc(), mrColumn.HasFiltering());
2425 
2426  if (rCell.hasString())
2427  {
2428  mrFilterEntries.push_back(ScTypedStrData(aStr));
2429  return;
2430  }
2431 
2432  double fVal = 0.0;
2433 
2434  switch (rCell.meType)
2435  {
2436  case CELLTYPE_VALUE:
2437  fVal = rCell.mfValue;
2438  break;
2439 
2440  case CELLTYPE_FORMULA:
2441  {
2442  ScFormulaCell* pFC = rCell.mpFormula;
2443  FormulaError nErr = pFC->GetErrCode();
2444  if (nErr != FormulaError::NONE)
2445  {
2446  // Error cell is evaluated as string (for now).
2447  OUString aErr = ScGlobal::GetErrorString(nErr);
2448  if (!aErr.isEmpty())
2449  {
2450  mrFilterEntries.push_back(ScTypedStrData(aErr));
2451  return;
2452  }
2453  }
2454  else
2455  fVal = pFC->GetValue();
2456  }
2457  break;
2458  default:
2459  ;
2460  }
2461 
2462  SvNumFormatType nType = pFormatter->GetType(nFormat);
2463  bool bDate = false;
2464  if ((nType & SvNumFormatType::DATE) && !(nType & SvNumFormatType::TIME))
2465  {
2466  // special case for date values. Disregard the time
2467  // element if the number format is of date type.
2468  fVal = rtl::math::approxFloor(fVal);
2469  mrFilterEntries.mbHasDates = true;
2470  bDate = true;
2471  // Convert string representation to ISO 8601 date to eliminate
2472  // locale dependent behaviour later when filtering for dates.
2473  sal_uInt32 nIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_YYYYMMDD);
2474  pFormatter->GetInputLineString( fVal, nIndex, aStr);
2475  }
2476  else if (nType == SvNumFormatType::DATETIME)
2477  {
2478  // special case for datetime values.
2479  // Convert string representation to ISO 8601 (with blank instead of T) datetime
2480  // to eliminate locale dependent behaviour later when filtering for datetimes.
2481  sal_uInt32 nIndex = pFormatter->GetFormatIndex(NF_DATETIME_ISO_YYYYMMDD_HHMMSS);
2482  pFormatter->GetInputLineString(fVal, nIndex, aStr);
2483  }
2484  // maybe extend ScTypedStrData enum is also an option here
2485  mrFilterEntries.push_back(ScTypedStrData(aStr, fVal, ScTypedStrData::Value,bDate));
2486  }
2487 
2488 public:
2489  FilterEntriesHandler(ScColumn& rColumn, ScFilterEntries& rFilterEntries) :
2490  mrColumn(rColumn), mrFilterEntries(rFilterEntries) {}
2491 
2492  void operator() (size_t nRow, double fVal)
2493  {
2494  ScRefCellValue aCell(fVal);
2495  processCell(nRow, aCell);
2496  }
2497 
2498  void operator() (size_t nRow, const svl::SharedString& rStr)
2499  {
2500  ScRefCellValue aCell(&rStr);
2501  processCell(nRow, aCell);
2502  }
2503 
2504  void operator() (size_t nRow, const EditTextObject* p)
2505  {
2506  ScRefCellValue aCell(p);
2507  processCell(nRow, aCell);
2508  }
2509 
2510  void operator() (size_t nRow, const ScFormulaCell* p)
2511  {
2512  ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
2513  processCell(nRow, aCell);
2514  }
2515 
2516  void operator() (const int nElemType, size_t nRow, size_t /* nDataSize */)
2517  {
2518  if ( nElemType == sc::element_type_empty )
2519  {
2520  if (!mrFilterEntries.mbHasEmpties)
2521  {
2522  mrFilterEntries.push_back(ScTypedStrData(OUString()));
2523  mrFilterEntries.mbHasEmpties = true;
2524  }
2525  return;
2526  }
2527  ScRefCellValue aCell = mrColumn.GetCellValue(nRow);
2528  processCell(nRow, aCell);
2529  }
2530 };
2531 
2532 }
2533 
2535  sc::ColumnBlockConstPosition& rBlockPos, SCROW nStartRow, SCROW nEndRow,
2536  ScFilterEntries& rFilterEntries, bool bFiltering )
2537 {
2538  mbFiltering = bFiltering;
2539  FilterEntriesHandler aFunc(*this, rFilterEntries);
2540  rBlockPos.miCellPos =
2541  sc::ParseAll(rBlockPos.miCellPos, maCells, nStartRow, nEndRow, aFunc, aFunc);
2542 }
2543 
2544 namespace {
2545 
2549 class StrCellIterator
2550 {
2551  typedef std::pair<sc::CellStoreType::const_iterator,size_t> PosType;
2552  PosType maPos;
2553  sc::CellStoreType::const_iterator miBeg;
2554  sc::CellStoreType::const_iterator miEnd;
2555  const ScDocument* mpDoc;
2556 public:
2557  StrCellIterator(const sc::CellStoreType& rCells, SCROW nStart, const ScDocument* pDoc) :
2558  miBeg(rCells.begin()), miEnd(rCells.end()), mpDoc(pDoc)
2559  {
2560  if (pDoc->ValidRow(nStart))
2561  maPos = rCells.position(nStart);
2562  else
2563  // Make this iterator invalid.
2564  maPos.first = miEnd;
2565  }
2566 
2567  bool valid() const { return (maPos.first != miEnd); }
2568 
2569  bool has() const
2570  {
2571  return (maPos.first->type == sc::element_type_string || maPos.first->type == sc::element_type_edittext);
2572  }
2573 
2574  bool prev()
2575  {
2576  if (!has())
2577  {
2578  // Not in a string block. Move back until we hit a string block.
2579  while (!has())
2580  {
2581  if (maPos.first == miBeg)
2582  return false;
2583 
2584  --maPos.first; // move to the preceding block.
2585  maPos.second = maPos.first->size - 1; // last cell in the block.
2586  }
2587  return true;
2588  }
2589 
2590  // We are in a string block.
2591  if (maPos.second > 0)
2592  {
2593  // Move back one cell in the same block.
2594  --maPos.second;
2595  }
2596  else
2597  {
2598  // Move back to the preceding string block.
2599  while (true)
2600  {
2601  if (maPos.first == miBeg)
2602  return false;
2603 
2604  // Move to the last cell of the previous block.
2605  --maPos.first;
2606  maPos.second = maPos.first->size - 1;
2607  if (has())
2608  break;
2609  }
2610  }
2611  return true;
2612  }
2613 
2614  bool next()
2615  {
2616  if (!has())
2617  {
2618  // Not in a string block. Move forward until we hit a string block.
2619  while (!has())
2620  {
2621  ++maPos.first;
2622  if (maPos.first == miEnd)
2623  return false;
2624 
2625  maPos.second = 0; // First cell in this block.
2626  }
2627  return true;
2628  }
2629 
2630  // We are in a string block.
2631  ++maPos.second;
2632  if (maPos.second >= maPos.first->size)
2633  {
2634  // Move to the next string block.
2635  while (true)
2636  {
2637  ++maPos.first;
2638  if (maPos.first == miEnd)
2639  return false;
2640 
2641  maPos.second = 0;
2642  if (has())
2643  break;
2644  }
2645  }
2646  return true;
2647  }
2648 
2649  OUString get() const
2650  {
2651  switch (maPos.first->type)
2652  {
2654  return sc::string_block::at(*maPos.first->data, maPos.second).getString();
2656  {
2657  const EditTextObject* p = sc::edittext_block::at(*maPos.first->data, maPos.second);
2658  return ScEditUtil::GetString(*p, mpDoc);
2659  }
2660  default:
2661  ;
2662  }
2663  return OUString();
2664  }
2665 };
2666 
2667 }
2668 
2669 // GetDataEntries - Strings from continuous Section around nRow
2670 
2671 // DATENT_MAX - max. number of entries in list for auto entry
2672 // DATENT_SEARCH - max. number of cells that get transparent - new: only count Strings
2673 #define DATENT_MAX 200
2674 #define DATENT_SEARCH 2000
2675 
2677  SCROW nStartRow, std::set<ScTypedStrData>& rStrings, bool bLimit ) const
2678 {
2679  // Start at the specified row position, and collect all string values
2680  // going upward and downward directions in parallel. The start position
2681  // cell must be skipped.
2682 
2683  StrCellIterator aItrUp(maCells, nStartRow, &GetDoc());
2684  StrCellIterator aItrDown(maCells, nStartRow+1, &GetDoc());
2685 
2686  bool bMoveUp = aItrUp.valid();
2687  if (!bMoveUp)
2688  // Current cell is invalid.
2689  return false;
2690 
2691  // Skip the start position cell.
2692  bMoveUp = aItrUp.prev(); // Find the previous string cell position.
2693 
2694  bool bMoveDown = aItrDown.valid();
2695  if (bMoveDown && !aItrDown.has())
2696  bMoveDown = aItrDown.next(); // Find the next string cell position.
2697 
2698  bool bFound = false;
2699  size_t nCellsSearched = 0;
2700  while (bMoveUp || bMoveDown)
2701  {
2702  if (bMoveUp)
2703  {
2704  // Get the current string and move up.
2705  OUString aStr = aItrUp.get();
2706  if (!aStr.isEmpty())
2707  {
2708  bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second;
2709  if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
2710  return true; // Maximum reached
2711  bFound = true;
2712  }
2713 
2714  if (bLimit && ++nCellsSearched >= DATENT_SEARCH)
2715  return bFound; // max search cell count reached.
2716 
2717  bMoveUp = aItrUp.prev();
2718  }
2719 
2720  if (bMoveDown)
2721  {
2722  // Get the current string and move down.
2723  OUString aStr = aItrDown.get();
2724  if (!aStr.isEmpty())
2725  {
2726  bool bInserted = rStrings.insert(ScTypedStrData(aStr)).second;
2727  if (bInserted && bLimit && rStrings.size() >= DATENT_MAX)
2728  return true; // Maximum reached
2729  bFound = true;
2730  }
2731 
2732  if (bLimit && ++nCellsSearched >= DATENT_SEARCH)
2733  return bFound; // max search cell count reached.
2734 
2735  bMoveDown = aItrDown.next();
2736  }
2737  }
2738 
2739  return bFound;
2740 }
2741 
2742 namespace {
2743 
2744 class FormulaToValueHandler
2745 {
2746  struct Entry
2747  {
2748  SCROW mnRow;
2750 
2751  Entry(SCROW nRow, double f) : mnRow(nRow), maValue(f) {}
2752  Entry(SCROW nRow, const svl::SharedString& rStr) : mnRow(nRow), maValue(rStr) {}
2753  };
2754 
2755  typedef std::vector<Entry> EntriesType;
2756  EntriesType maEntries;
2757 
2758 public:
2759 
2760  void operator() (size_t nRow, const ScFormulaCell* p)
2761  {
2762  ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
2763  if (p2->IsValue())
2764  maEntries.emplace_back(nRow, p2->GetValue());
2765  else
2766  maEntries.emplace_back(nRow, p2->GetString());
2767  }
2768 
2769  void commitCells(ScColumn& rColumn)
2770  {
2771  sc::ColumnBlockPosition aBlockPos;
2772  rColumn.InitBlockPosition(aBlockPos);
2773 
2774  for (const Entry& r : maEntries)
2775  {
2776  switch (r.maValue.meType)
2777  {
2778  case CELLTYPE_VALUE:
2779  rColumn.SetValue(aBlockPos, r.mnRow, r.maValue.mfValue, false);
2780  break;
2781  case CELLTYPE_STRING:
2782  rColumn.SetRawString(aBlockPos, r.mnRow, *r.maValue.mpString, false);
2783  break;
2784  default:
2785  ;
2786  }
2787  }
2788  }
2789 };
2790 
2791 }
2792 
2793 void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
2794 {
2795  FormulaToValueHandler aFunc;
2796  sc::CellStoreType::const_iterator itPos = maCells.begin();
2797 
2798  ScAttrIterator aAttrIter( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() );
2799  SCROW nTop = -1;
2800  SCROW nBottom = -1;
2801  const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
2802  while (pPattern)
2803  {
2804  const ScProtectionAttr* pAttr = &pPattern->GetItem(ATTR_PROTECTION);
2805  if ( pAttr->GetHideCell() )
2806  DeleteArea( nTop, nBottom, InsertDeleteFlags::CONTENTS );
2807  else if ( pAttr->GetHideFormula() )
2808  {
2809  // Replace all formula cells between nTop and nBottom with raw value cells.
2810  itPos = sc::ParseFormula(itPos, maCells, nTop, nBottom, aFunc);
2811  }
2812 
2813  pPattern = aAttrIter.Next( nTop, nBottom );
2814  }
2815 
2816  aFunc.commitCells(*this);
2817 }
2818 
2819 void ScColumn::SetError( SCROW nRow, const FormulaError nError)
2820 {
2821  if (!GetDoc().ValidRow(nRow))
2822  return;
2823 
2824  ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), ScAddress(nCol, nRow, nTab));
2825  pCell->SetErrCode(nError);
2826 
2827  std::vector<SCROW> aNewSharedRows;
2828  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, true);
2829  it = maCells.set(it, nRow, pCell);
2830  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2831 
2832  CellStorageModified();
2833 
2834  AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
2835 }
2836 
2837 void ScColumn::SetRawString( SCROW nRow, const OUString& rStr )
2838 {
2839  if (!GetDoc().ValidRow(nRow))
2840  return;
2841 
2842  svl::SharedString aSS = GetDoc().GetSharedStringPool().intern(rStr);
2843  if (!aSS.getData())
2844  return;
2845 
2846  SetRawString(nRow, aSS);
2847 }
2848 
2850 {
2851  if (!GetDoc().ValidRow(nRow))
2852  return;
2853 
2854  std::vector<SCROW> aNewSharedRows;
2855  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false);
2856  maCells.set(it, nRow, rStr);
2857  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2858 
2859  CellStorageModified();
2860 
2861  StartListeningUnshared( aNewSharedRows);
2862 
2863  BroadcastNewCell(nRow);
2864 }
2865 
2867  sc::ColumnBlockPosition& rBlockPos, SCROW nRow, const svl::SharedString& rStr, bool bBroadcast )
2868 {
2869  if (!GetDoc().ValidRow(nRow))
2870  return;
2871 
2872  std::vector<SCROW> aNewSharedRows;
2873  rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false);
2874  rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr);
2875  rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2876  rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2877 
2878  CellStorageModified();
2879 
2880  StartListeningUnshared( aNewSharedRows);
2881 
2882  if (bBroadcast)
2883  BroadcastNewCell(nRow);
2884 }
2885 
2886 void ScColumn::SetValue( SCROW nRow, double fVal )
2887 {
2888  if (!GetDoc().ValidRow(nRow))
2889  return;
2890 
2891  std::vector<SCROW> aNewSharedRows;
2892  sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows, false);
2893  maCells.set(it, nRow, fVal);
2894  maCellTextAttrs.set(nRow, sc::CellTextAttr());
2895 
2896  CellStorageModified();
2897 
2898  StartListeningUnshared( aNewSharedRows);
2899 
2900  BroadcastNewCell(nRow);
2901 }
2902 
2904  sc::ColumnBlockPosition& rBlockPos, SCROW nRow, double fVal, bool bBroadcast )
2905 {
2906  if (!GetDoc().ValidRow(nRow))
2907  return;
2908 
2909  std::vector<SCROW> aNewSharedRows;
2910  rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows, false);
2911  rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal);
2912  rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
2913  rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
2914 
2915  CellStorageModified();
2916 
2917  StartListeningUnshared( aNewSharedRows);
2918 
2919  if (bBroadcast)
2920  BroadcastNewCell(nRow);
2921 }
2922 
2923 void ScColumn::GetString( const ScRefCellValue& aCell, SCROW nRow, OUString& rString, const ScInterpreterContext* pContext ) const
2924 {
2925  // ugly hack for ordering problem with GetNumberFormat and missing inherited formats
2926  if (aCell.meType == CELLTYPE_FORMULA)
2927  aCell.mpFormula->MaybeInterpret();
2928 
2929  sal_uInt32 nFormat = GetNumberFormat( pContext ? *pContext : GetDoc().GetNonThreadedContext(), nRow);
2930  const Color* pColor = nullptr;
2931  ScCellFormat::GetString(aCell, nFormat, rString, &pColor,
2932  pContext ? *(pContext->GetFormatTable()) : *(GetDoc().GetFormatTable()), GetDoc());
2933 }
2934 
2936 {
2937  std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2938  sc::CellStoreType::iterator it = aPos.first;
2939  if (it == maCells.end())
2940  return nullptr;
2941 
2942  if (it->type != sc::element_type_numeric)
2943  return nullptr;
2944 
2945  return &sc::numeric_block::at(*it->data, aPos.second);
2946 }
2947 
2948 void ScColumn::GetInputString( const ScRefCellValue& aCell, SCROW nRow, OUString& rString ) const
2949 {
2950  sal_uLong nFormat = GetNumberFormat(GetDoc().GetNonThreadedContext(), nRow);
2951  ScCellFormat::GetInputString(aCell, nFormat, rString, *(GetDoc().GetFormatTable()), GetDoc());
2952 }
2953 
2954 double ScColumn::GetValue( SCROW nRow ) const
2955 {
2956  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2957  sc::CellStoreType::const_iterator it = aPos.first;
2958  switch (it->type)
2959  {
2961  return sc::numeric_block::at(*it->data, aPos.second);
2963  {
2964  const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
2965  ScFormulaCell* p2 = const_cast<ScFormulaCell*>(p);
2966  return p2->IsValue() ? p2->GetValue() : 0.0;
2967  }
2968  default:
2969  ;
2970  }
2971 
2972  return 0.0;
2973 }
2974 
2976 {
2977  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
2978  sc::CellStoreType::const_iterator it = aPos.first;
2979  if (it == maCells.end())
2980  return nullptr;
2981 
2982  if (it->type != sc::element_type_edittext)
2983  return nullptr;
2984 
2985  return sc::edittext_block::at(*it->data, aPos.second);
2986 }
2987 
2989 {
2990  std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2991  sc::CellStoreType::iterator it = aPos.first;
2992  if (it == maCells.end())
2993  return;
2994 
2995  if (it->type != sc::element_type_edittext)
2996  return;
2997 
2998  EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
2999  ScEditUtil::RemoveCharAttribs(*p, rAttr);
3000 }
3001 
3002 void ScColumn::GetFormula( SCROW nRow, OUString& rFormula ) const
3003 {
3004  const ScFormulaCell* p = FetchFormulaCell(nRow);
3005  if (p)
3006  p->GetFormula(rFormula);
3007  else
3008  rFormula = EMPTY_OUSTRING;
3009 }
3010 
3012 {
3013  return FetchFormulaCell(nRow);
3014 }
3015 
3017 {
3018  return const_cast<ScFormulaCell*>(FetchFormulaCell(nRow));
3019 }
3020 
3022 {
3023  switch (maCells.get_type(nRow))
3024  {
3026  return CELLTYPE_VALUE;
3028  return CELLTYPE_STRING;
3030  return CELLTYPE_EDIT;
3032  return CELLTYPE_FORMULA;
3033  default:
3034  ;
3035  }
3036  return CELLTYPE_NONE;
3037 }
3038 
3039 namespace {
3040 
3044 class CellCounter
3045 {
3046  size_t mnCount;
3047 public:
3048  CellCounter() : mnCount(0) {}
3049 
3050  void operator() (const sc::CellStoreType::value_type& node)
3051  {
3052  if (node.type == sc::element_type_empty)
3053  return;
3054 
3055  mnCount += node.size;
3056  }
3057 
3058  size_t getCount() const { return mnCount; }
3059 };
3060 
3061 }
3062 
3064 {
3065  CellCounter aFunc;
3066  aFunc = std::for_each(maCells.begin(), maCells.end(), aFunc);
3067  return aFunc.getCount();
3068 }
3069 
3071 {
3072  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3073  sc::CellStoreType::const_iterator it = aPos.first;
3074  if (it == maCells.end())
3075  return FormulaError::NONE;
3076 
3077  if (it->type != sc::element_type_formula)
3078  return FormulaError::NONE;
3079 
3080  const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
3081  return const_cast<ScFormulaCell*>(p)->GetErrCode();
3082 }
3083 
3084 bool ScColumn::HasStringData( SCROW nRow ) const
3085 {
3086  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3087  switch (aPos.first->type)
3088  {
3091  return true;
3093  {
3094  const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
3095  return !const_cast<ScFormulaCell*>(p)->IsValue();
3096  }
3097  default:
3098  ;
3099  }
3100 
3101  return false;
3102 }
3103 
3104 bool ScColumn::HasValueData( SCROW nRow ) const
3105 {
3106  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3107  switch (aPos.first->type)
3108  {
3110  return true;
3112  {
3113  const ScFormulaCell* p = sc::formula_block::at(*aPos.first->data, aPos.second);
3114  return const_cast<ScFormulaCell*>(p)->IsValue();
3115  }
3116  default:
3117  ;
3118  }
3119 
3120  return false;
3121 }
3122 
3126 bool ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
3127 {
3128  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
3129  sc::CellStoreType::const_iterator it = aPos.first;
3130  size_t nOffset = aPos.second;
3131  SCROW nRow = nStartRow;
3132  for (; it != maCells.end() && nRow <= nEndRow; ++it)
3133  {
3134  if (it->type == sc::element_type_string || it->type == sc::element_type_edittext)
3135  return true;
3136 
3137  nRow += it->size - nOffset;
3138  nOffset = 0;
3139  }
3140 
3141  return false;
3142 }
3143 
3144 namespace {
3145 
3146 class MaxStringLenHandler
3147 {
3148  sal_Int32 mnMaxLen;
3149  const ScColumn& mrColumn;
3150  SvNumberFormatter* mpFormatter;
3151  rtl_TextEncoding meCharSet;
3152  bool mbOctetEncoding;
3153 
3154  void processCell(size_t nRow, const ScRefCellValue& rCell)
3155  {
3156  const Color* pColor;
3157  OUString aString;
3158  sal_uInt32 nFormat = mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
3159  ScCellFormat::GetString(rCell, nFormat, aString, &pColor, *mpFormatter, mrColumn.GetDoc());
3160  sal_Int32 nLen = 0;
3161  if (mbOctetEncoding)
3162  {
3163  OString aOString;
3164  if (!aString.convertToString(&aOString, meCharSet,
3165  RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
3166  RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
3167  {
3168  // TODO: anything? this is used by the dBase export filter
3169  // that throws an error anyway, but in case of another
3170  // context we might want to indicate a conversion error
3171  // early.
3172  }
3173  nLen = aOString.getLength();
3174  }
3175  else
3176  nLen = aString.getLength() * sizeof(sal_Unicode);
3177 
3178  if (mnMaxLen < nLen)
3179  mnMaxLen = nLen;
3180  }
3181 
3182 public:
3183  MaxStringLenHandler(const ScColumn& rColumn, rtl_TextEncoding eCharSet) :
3184  mnMaxLen(0),
3185  mrColumn(rColumn),
3186  mpFormatter(rColumn.GetDoc().GetFormatTable()),
3187  meCharSet(eCharSet),
3188  mbOctetEncoding(rtl_isOctetTextEncoding(eCharSet))
3189  {
3190  }
3191 
3192  void operator() (size_t nRow, double fVal)
3193  {
3194  ScRefCellValue aCell(fVal);
3195  processCell(nRow, aCell);
3196  }
3197 
3198  void operator() (size_t nRow, const svl::SharedString& rStr)
3199  {
3200  ScRefCellValue aCell(&rStr);
3201  processCell(nRow, aCell);
3202  }
3203 
3204  void operator() (size_t nRow, const EditTextObject* p)
3205  {
3206  ScRefCellValue aCell(p);
3207  processCell(nRow, aCell);
3208  }
3209 
3210  void operator() (size_t nRow, const ScFormulaCell* p)
3211  {
3212  ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
3213  processCell(nRow, aCell);
3214  }
3215 
3216  sal_Int32 getMaxLen() const { return mnMaxLen; }
3217 };
3218 
3219 }
3220 
3221 sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
3222 {
3223  MaxStringLenHandler aFunc(*this, eCharSet);
3224  sc::ParseAllNonEmpty(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
3225  return aFunc.getMaxLen();
3226 }
3227 
3228 namespace {
3229 
3230 class MaxNumStringLenHandler
3231 {
3232  const ScColumn& mrColumn;
3233  SvNumberFormatter* mpFormatter;
3234  sal_Int32 mnMaxLen;
3235  sal_uInt16 mnPrecision;
3236  sal_uInt16 mnMaxGeneralPrecision;
3237  bool mbHaveSigned;
3238 
3239  void processCell(size_t nRow, ScRefCellValue& rCell)
3240  {
3241  sal_uInt16 nCellPrecision = mnMaxGeneralPrecision;
3242  if (rCell.meType == CELLTYPE_FORMULA)
3243  {
3244  if (!rCell.mpFormula->IsValue())
3245  return;
3246 
3247  // Limit unformatted formula cell precision to precision
3248  // encountered so far, if any, otherwise we'd end up with 15 just
3249  // because of =1/3 ... If no precision yet then arbitrarily limit
3250  // to a maximum of 4 unless a maximum general precision is set.
3251  if (mnPrecision)
3252  nCellPrecision = mnPrecision;
3253  else
3254  nCellPrecision = (mnMaxGeneralPrecision >= 15) ? 4 : mnMaxGeneralPrecision;
3255  }
3256 
3257  double fVal = rCell.getValue();
3258  if (!mbHaveSigned && fVal < 0.0)
3259  mbHaveSigned = true;
3260 
3261  OUString aString;
3262  OUString aSep;
3263  sal_uInt16 nPrec;
3264  sal_uInt32 nFormat =
3265  mrColumn.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue();
3266  if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
3267  {
3268  aSep = mpFormatter->GetFormatDecimalSep(nFormat);
3269  ScCellFormat::GetInputString(rCell, nFormat, aString, *mpFormatter, mrColumn.GetDoc());
3270  const SvNumberformat* pEntry = mpFormatter->GetEntry(nFormat);
3271  if (pEntry)
3272  {
3273  bool bThousand, bNegRed;
3274  sal_uInt16 nLeading;
3275  pEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrec, nLeading);
3276  }
3277  else
3278  nPrec = mpFormatter->GetFormatPrecision(nFormat);
3279  }
3280  else
3281  {
3282  if (mnPrecision >= mnMaxGeneralPrecision)
3283  return; // early bail out for nothing changes here
3284 
3285  if (!fVal)
3286  {
3287  // 0 doesn't change precision, but set a maximum length if none yet.
3288  if (!mnMaxLen)
3289  mnMaxLen = 1;
3290  return;
3291  }
3292 
3293  // Simple number string with at most 15 decimals and trailing
3294  // decimal zeros eliminated.
3295  aSep = ".";
3296  aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true);
3298  }
3299 
3300  sal_Int32 nLen = aString.getLength();
3301  if (nLen <= 0)
3302  // Ignore empty string.
3303  return;
3304 
3305  if (nPrec == SvNumberFormatter::UNLIMITED_PRECISION && mnPrecision < mnMaxGeneralPrecision)
3306  {
3307  if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET)
3308  {
3309  // For some reason we couldn't obtain a precision from the
3310  // format, retry with simple number string.
3311  aSep = ".";
3312  aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true);
3313  nLen = aString.getLength();
3314  }
3315  sal_Int32 nSep = aString.indexOf( aSep);
3316  if (nSep != -1)
3317  nPrec = aString.getLength() - nSep - 1;
3318 
3319  }
3320 
3321  if (nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > mnPrecision)
3322  mnPrecision = nPrec;
3323 
3324  if (mnPrecision)
3325  { // less than mnPrecision in string => widen it
3326  // more => shorten it
3327  sal_Int32 nTmp = aString.indexOf(aSep);
3328  if ( nTmp == -1 )
3329  nLen += mnPrecision + aSep.getLength();
3330  else
3331  {
3332  nTmp = aString.getLength() - (nTmp + aSep.getLength());
3333  if (nTmp != mnPrecision)
3334  nLen += mnPrecision - nTmp;
3335  // nPrecision > nTmp : nLen + Diff
3336  // nPrecision < nTmp : nLen - Diff
3337  }
3338  }
3339 
3340  // Enlarge for sign if necessary. Bear in mind that
3341  // GetMaxNumberStringLen() is for determining dBase decimal field width
3342  // and precision where the overall field width must include the sign.
3343  // Fitting -1 into "#.##" (width 4, 2 decimals) does not work.
3344  if (mbHaveSigned && fVal >= 0.0)
3345  ++nLen;
3346 
3347  if (mnMaxLen < nLen)
3348  mnMaxLen = nLen;
3349  }
3350 
3351 public:
3352  MaxNumStringLenHandler(const ScColumn& rColumn, sal_uInt16 nMaxGeneralPrecision) :
3353  mrColumn(rColumn), mpFormatter(rColumn.GetDoc().GetFormatTable()),
3354  mnMaxLen(0), mnPrecision(0), mnMaxGeneralPrecision(nMaxGeneralPrecision),
3355  mbHaveSigned(false)
3356  {
3357  // Limit the decimals passed to doubleToUString().
3358  // Also, the dBaseIII maximum precision is 15.
3359  if (mnMaxGeneralPrecision > 15)
3360  mnMaxGeneralPrecision = 15;
3361  }
3362 
3363  void operator() (size_t nRow, double fVal)
3364  {
3365  ScRefCellValue aCell(fVal);
3366  processCell(nRow, aCell);
3367  }
3368 
3369  void operator() (size_t nRow, const ScFormulaCell* p)
3370  {
3371  ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
3372  processCell(nRow, aCell);
3373  }
3374 
3375  sal_Int32 getMaxLen() const { return mnMaxLen; }
3376 
3377  sal_uInt16 getPrecision() const { return mnPrecision; }
3378 };
3379 
3380 }
3381 
3383  sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const
3384 {
3385  sal_uInt16 nMaxGeneralPrecision = GetDoc().GetDocOptions().GetStdPrecision();
3386  MaxNumStringLenHandler aFunc(*this, nMaxGeneralPrecision);
3387  sc::ParseFormulaNumeric(maCells.begin(), maCells, nRowStart, nRowEnd, aFunc);
3388  nPrecision = aFunc.getPrecision();
3389  return aFunc.getMaxLen();
3390 }
3391 
3392 namespace {
3393 
3394 class GroupFormulaCells
3395 {
3396  std::vector<ScAddress>* mpGroupPos;
3397 
3398 public:
3399  explicit GroupFormulaCells(std::vector<ScAddress>* pGroupPos)
3400  : mpGroupPos(pGroupPos) {}
3401 
3402  void operator() (sc::CellStoreType::value_type& node)
3403  {
3404  if (node.type != sc::element_type_formula)
3405  // We are only interested in formula cells.
3406  return;
3407 
3408  size_t nRow = node.position; // start row position.
3409 
3410  sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
3411  sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
3412 
3413  // This block should never be empty.
3414 
3415  ScFormulaCell* pPrev = *it;
3416  ScFormulaCellGroupRef xPrevGrp = pPrev->GetCellGroup();
3417  if (xPrevGrp)
3418  {
3419  // Move to the cell after the last cell of the current group.
3420  std::advance(it, xPrevGrp->mnLength);
3421  nRow += xPrevGrp->mnLength;
3422  }
3423  else
3424  {
3425  ++it;
3426  ++nRow;
3427  }
3428 
3429  ScFormulaCell* pCur = nullptr;
3430  ScFormulaCellGroupRef xCurGrp;
3431  for (; it != itEnd; pPrev = pCur, xPrevGrp = xCurGrp)
3432  {
3433  pCur = *it;
3434  xCurGrp = pCur->GetCellGroup();
3435 
3436  ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(*pCur);
3437  if (eCompState == ScFormulaCell::NotEqual)
3438  {
3439  // different formula tokens.
3440  if (xCurGrp)
3441  {
3442  // Move to the cell after the last cell of the current group.
3443  if (xCurGrp->mnLength > std::distance(it, itEnd))
3444  throw css::lang::IllegalArgumentException();
3445  std::advance(it, xCurGrp->mnLength);
3446  nRow += xCurGrp->mnLength;
3447  }
3448  else
3449  {
3450  ++it;
3451  ++nRow;
3452  }
3453 
3454  continue;
3455  }
3456 
3457  // Formula tokens equal those of the previous formula cell or cell group.
3458  if (xPrevGrp)
3459  {
3460  // Previous cell is a group.
3461  if (xCurGrp)
3462  {
3463  // The current cell is a group. Merge these two groups.
3464  xPrevGrp->mnLength += xCurGrp->mnLength;
3465  pCur->SetCellGroup(xPrevGrp);
3466  sc::formula_block::iterator itGrpEnd = it;
3467  if (xCurGrp->mnLength > std::distance(itGrpEnd, itEnd))
3468  throw css::lang::IllegalArgumentException();
3469  std::advance(itGrpEnd, xCurGrp->mnLength);
3470  for (++it; it != itGrpEnd; ++it)
3471  {
3472  ScFormulaCell* pCell = *it;
3473  pCell->SetCellGroup(xPrevGrp);
3474  }
3475  nRow += xCurGrp->mnLength;
3476  }
3477  else
3478  {
3479  // Add this cell to the previous group.
3480  pCur->SetCellGroup(xPrevGrp);
3481  ++xPrevGrp->mnLength;
3482  ++nRow;
3483  ++it;
3484  }
3485 
3486  }
3487  else if (xCurGrp)
3488  {
3489  // Previous cell is a regular cell and current cell is a group.
3490  nRow += xCurGrp->mnLength;
3491  if (xCurGrp->mnLength > std::distance(it, itEnd))
3492  throw css::lang::IllegalArgumentException();
3493  std::advance(it, xCurGrp->mnLength);
3494  pPrev->SetCellGroup(xCurGrp);
3495  xCurGrp->mpTopCell = pPrev;
3496  ++xCurGrp->mnLength;
3497  xPrevGrp = xCurGrp;
3498  }
3499  else
3500  {
3501  // Both previous and current cells are regular cells.
3502  assert(pPrev->aPos.Row() == static_cast<SCROW>(nRow - 1));
3503  xPrevGrp = pPrev->CreateCellGroup(2, eCompState == ScFormulaCell::EqualInvariant);
3504  pCur->SetCellGroup(xPrevGrp);
3505  ++nRow;
3506  ++it;
3507  }
3508 
3509  if (mpGroupPos)
3510  mpGroupPos->push_back(pCur->aPos);
3511 
3512  pCur = pPrev;
3513  xCurGrp = xPrevGrp;
3514  }
3515  }
3516 };
3517 
3518 }
3519 
3520 void ScColumn::RegroupFormulaCells( std::vector<ScAddress>* pGroupPos )
3521 {
3522  // re-build formula groups.
3523  std::for_each(maCells.begin(), maCells.end(), GroupFormulaCells(pGroupPos));
3524 }
3525 
3526 /* 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:151
void InterpretDirtyCells(SCROW nRow1, SCROW nRow2)
Definition: column3.cxx:110
const SfxItemPool * GetPool() const
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:184
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:130
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:183
#define EMPTY_OUSTRING
Definition: global.hxx:213
void SetError(SCROW nRow, const FormulaError nError)
Definition: column3.cxx:2819
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:2534
static void lcl_AddFormulaGroupBoundaries(const sc::CellStoreType::position_type &rPos, std::vector< SCROW > &rNewSharedRows)
Definition: column3.cxx:550
const mdds::mtv::element_t element_type_celltextattr
Definition: mtvelements.hxx:45
SCROW GetSharedTopRow() const
FormulaError GetErrCode(SCROW nRow) const
Definition: column3.cxx:3070
bool mbCheckLinkFormula
When true and the string results in a compiled formula, check the formula tokens for presence of func...
Definition: stringutil.hxx:100
#define DATENT_SEARCH
Definition: column3.cxx:2674
void GetFormula(OUString &rFormula, const formula::FormulaGrammar::Grammar=formula::FormulaGrammar::GRAM_DEFAULT, const ScInterpreterContext *pContext=nullptr) const
SCTAB nTab
Definition: column.hxx:135
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:1906
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:2211
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:67
Store position data for column array storage.
const ContentProperties & rData
InsertDeleteFlags getInsertFlag() const
bool IsClipOrUndo() const
Definition: document.hxx:1530
bool isSkipAttrForEmptyCells() const
CellType GetCellType(SCROW nRow) const
Definition: column3.cxx:3021
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:88
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:2988
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:1941
void GetFormula(SCROW nRow, OUString &rFormula) const
Definition: column3.cxx:3002
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:6048
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:3221
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:2309
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:265
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
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
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:141
sc::CellStoreType maCells
Definition: column.hxx:128
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:2463
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:2347
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:119
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:677
void SetDirty(bool bDirtyFlag=true)
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:2191
double GetValue(SCROW nRow) const
Definition: column3.cxx:2954
bool GetHideCell() const
Definition: attrib.hxx:147
SCROW GetSharedLength() const
svl::SharedString GetSharedString(SCROW nRow) const
Definition: column3.cxx:2388
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:134
void getSpans(SpansType &rSpans) const
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:440
bool IsInsertingFromOtherDoc() const
Definition: document.hxx:2137
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:602
void SetTextCurrentDefaults(const EditTextObject &rTextObject)
SetText and apply defaults already set.
Definition: editutil.cxx:598
#define DATENT_MAX
Definition: column3.cxx:2673
int i
void SetRawString(SCROW nRow, const OUString &rStr)
Definition: column3.cxx:2837
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:3520
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:117
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:271
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:3104
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:3084
FormulaToken * FirstToken() const
double * GetValueCell(SCROW nRow)
Definition: column3.cxx:2935
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:402
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
rtl_uString * getData()
void FreeNotes()
Definition: column3.cxx:164
enumrange< T >::Iterator end(enumrange< T >)
const svl::SharedString & GetString()
FormulaError
OUString GetFormatDecimalSep(sal_uInt32 nFormat) const
CellStoreType::iterator miCellPos
ocFalse
void MixData(sc::MixDocContext &rCxt, SCROW nRow1, SCROW nRow2, ScPasteFunc nFunction, bool bSkipEmpty, const ScColumn &rSrcCol)
Definition: column3.cxx:1881
static bool SafePlus(double &fVal1, double fVal2)
Definition: subtotal.cxx:24
static const sal_uInt16 UNLIMITED_PRECISION
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
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:1959
bool HasFiltering() const
Definition: column.hxx:186
const EditTextObject * GetEditText(SCROW nRow) const
Definition: column3.cxx:2975
bool ValidRow(SCROW nRow) const
Definition: document.hxx:874
NfEvalDateFormat
void SetFormula(SCROW nRow, const ScTokenArray &rArray, formula::FormulaGrammar::Grammar eGram)
Definition: column3.cxx:2273
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:2793
void AttachFormulaCells(sc::StartListeningContext &rCxt, SCROW nRow1, SCROW nRow2)
Definition: column3.cxx:467
std::unique_ptr< ScAttrIterator > CreateAttrIterator(SCROW nStartRow, SCROW nEndRow) const
Definition: column3.cxx:1898
SCCOL GetCol() const
Definition: column.hxx:185
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:189
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:369
CellNoteStoreType::iterator miCellNotePos
void ApplyPattern(SCROW nRow, const ScPatternAttr &rPatAttr)
Definition: column.cxx:501
const ScFormulaCell * GetFormulaCell(SCROW nRow) const
Definition: column3.cxx:3011
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
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:3382
SCSIZE GetCellCount() const
Definition: column3.cxx:3063
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:73
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:603
void GetInputString(SCROW nRow, OUString &rString) const
Definition: column.hxx:375
bool ValidRow(SCROW nRow, SCROW nMaxRow)
Definition: address.hxx:98
SCTAB GetTab() const
Definition: column.hxx:184
void MaybeInterpret()
const ScMultiSel & GetMultiSelData() const
Definition: markdata.hxx:106
void SetValue(SCROW nRow, double fVal)
Definition: column3.cxx:2886
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 DeleteCells(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nDelFlag, sc::SingleColumnSpanSet &rDeleted)
Definition: column3.cxx:967
bool IsCalcingAfterLoad() const
Definition: document.hxx:2141
bool HasStringCells(SCROW nStartRow, SCROW nEndRow) const
Return true if there is a string or editcell in the range.
Definition: column3.cxx:3126
CellNoteStoreType::const_iterator miCellNotePos
NF_EVALDATEFORMAT_FORMAT_INTL
std::unique_ptr< EditTextObject > Clone() const
void SetErrCode(FormulaError n)
bool GetDataEntries(SCROW nRow, std::set< ScTypedStrData > &rStrings, bool bLimit) const
Definition: column3.cxx:2676
const mdds::mtv::element_t element_type_string
Definition: mtvelements.hxx:47
mdds::multi_type_vector< CTAttrFunc > CellTextAttrStoreType
sc::CellStoreType & GetCellStore()
Definition: column.hxx:187
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 ...
std::vector< svl::SharedString > GetSharedStrings() const
LanguageType GetLanguage() const
void StartListeningUnshared(const std::vector< SCROW > &rNewSharedRows)
Re-establish listeners on unshared formula groups.
Definition: column3.cxx:344
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:291
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