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