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