LibreOffice Module sc (master)  1
column2.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 #include <docsh.hxx>
22 #include <scitems.hxx>
23 #include <formulacell.hxx>
24 #include <document.hxx>
25 #include <drwlayer.hxx>
26 #include <attarray.hxx>
27 #include <patattr.hxx>
28 #include <cellform.hxx>
29 #include <editutil.hxx>
30 #include <subtotal.hxx>
31 #include <markdata.hxx>
32 #include <fillinfo.hxx>
33 #include <segmenttree.hxx>
34 #include <docparam.hxx>
35 #include <cellvalue.hxx>
36 #include <tokenarray.hxx>
37 #include <formulagroup.hxx>
38 #include <listenercontext.hxx>
39 #include <mtvcellfunc.hxx>
40 #include <progress.hxx>
41 #include <scmatrix.hxx>
42 #include <rowheightcontext.hxx>
43 #include <tokenstringcontext.hxx>
44 #include <sortparam.hxx>
45 #include <SparklineGroup.hxx>
46 #include <SparklineList.hxx>
47 
48 #include <editeng/eeitem.hxx>
49 #include <o3tl/safeint.hxx>
50 #include <o3tl/unit_conversion.hxx>
51 #include <svx/algitem.hxx>
52 #include <editeng/editobj.hxx>
53 #include <editeng/editstat.hxx>
55 #include <editeng/fhgtitem.hxx>
56 #include <svx/rotmodit.hxx>
57 #include <editeng/unolingu.hxx>
58 #include <editeng/justifyitem.hxx>
59 #include <svl/numformat.hxx>
60 #include <svl/zforlist.hxx>
61 #include <svl/broadcast.hxx>
62 #include <vcl/outdev.hxx>
63 #include <formula/errorcodes.hxx>
64 #include <formula/vectortoken.hxx>
65 
66 #include <algorithm>
67 #include <limits>
68 #include <memory>
69 #include <numeric>
70 
71 // factor from font size to optimal cell height (text width)
72 #define SC_ROT_BREAK_FACTOR 6
73 
74 static bool IsAmbiguousScript( SvtScriptType nScript )
75 {
76  //TODO: move to a header file
77  return ( nScript != SvtScriptType::LATIN &&
78  nScript != SvtScriptType::ASIAN &&
79  nScript != SvtScriptType::COMPLEX );
80 }
81 
82 // Data operations
83 
85  SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY,
86  const Fraction& rZoomX, const Fraction& rZoomY,
87  bool bWidth, const ScNeededSizeOptions& rOptions,
88  const ScPatternAttr** ppPatternChange, bool bInPrintTwips ) const
89 {
90  // If bInPrintTwips is set, the size calculated should be in print twips,
91  // else it should be in pixels.
92 
93  // Switch unit to MapTwip instead ? (temporarily and then revert before exit).
94  if (bInPrintTwips)
95  assert(pDev->GetMapMode().GetMapUnit() == MapUnit::MapTwip);
96 
97  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
98  sc::CellStoreType::const_iterator it = aPos.first;
99  if (it == maCells.end() || it->type == sc::element_type_empty)
100  // Empty cell, or invalid row.
101  return 0;
102 
103  tools::Long nValue = 0;
104  ScRefCellValue aCell = GetCellValue(it, aPos.second);
105  double nPPT = bWidth ? nPPTX : nPPTY;
106 
107  auto conditionalScaleFunc = [bInPrintTwips](tools::Long nMeasure, double fScale) {
108  return bInPrintTwips ? nMeasure : static_cast<tools::Long>(nMeasure * fScale);
109  };
110 
111  const ScPatternAttr* pPattern = rOptions.pPattern;
112  if (!pPattern)
113  pPattern = pAttrArray->GetPattern( nRow );
114 
115  // merged?
116  // Do not merge in conditional formatting
117 
118  const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE);
119  const ScMergeFlagAttr* pFlag = &pPattern->GetItem(ATTR_MERGE_FLAG);
120 
121  if ( bWidth )
122  {
123  if ( pFlag->IsHorOverlapped() )
124  return 0;
125  if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
126  return 0;
127  }
128  else
129  {
130  if ( pFlag->IsVerOverlapped() )
131  return 0;
132  if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
133  return 0;
134  }
135 
136  // conditional formatting
137  ScDocument& rDocument = GetDoc();
138  const SfxItemSet* pCondSet = rDocument.GetCondResult( nCol, nRow, nTab );
139 
140  //The pPattern may change in GetCondResult
141  if (aCell.meType == CELLTYPE_FORMULA)
142  {
143  pPattern = pAttrArray->GetPattern( nRow );
144  if (ppPatternChange)
145  *ppPatternChange = pPattern;
146  }
147  // line break?
148 
149  const SvxHorJustifyItem* pCondItem;
150  SvxCellHorJustify eHorJust;
151  if (pCondSet && (pCondItem = pCondSet->GetItemIfSet(ATTR_HOR_JUSTIFY)) )
152  eHorJust = pCondItem->GetValue();
153  else
154  eHorJust = pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue();
155  bool bBreak;
156  const ScLineBreakCell* pLineBreakCell;
157  if ( eHorJust == SvxCellHorJustify::Block )
158  bBreak = true;
159  else if ( pCondSet && (pLineBreakCell = pCondSet->GetItemIfSet(ATTR_LINEBREAK)) )
160  bBreak = pLineBreakCell->GetValue();
161  else
162  bBreak = pPattern->GetItem(ATTR_LINEBREAK).GetValue();
163 
164  SvNumberFormatter* pFormatter = rDocument.GetFormatTable();
165  sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
166 
167  // get "cell is value" flag
168  // Must be synchronized with ScOutputData::LayoutStrings()
169  bool bCellIsValue = (aCell.meType == CELLTYPE_VALUE);
170  if (aCell.meType == CELLTYPE_FORMULA)
171  {
172  ScFormulaCell* pFCell = aCell.mpFormula;
173  bCellIsValue = pFCell->IsRunning() || pFCell->IsValue();
174  }
175 
176  // #i111387#, tdf#121040: disable automatic line breaks for all number formats
177  if (bBreak && bCellIsValue && (pFormatter->GetType(nFormat) == SvNumFormatType::NUMBER))
178  {
179  // If a formula cell needs to be interpreted during aCell.hasNumeric()
180  // to determine the type, the pattern may get invalidated because the
181  // result may set a number format. In which case there's also the
182  // General format not set anymore...
183  bool bMayInvalidatePattern = (aCell.meType == CELLTYPE_FORMULA);
184  const ScPatternAttr* pOldPattern = pPattern;
185  bool bNumeric = aCell.hasNumeric();
186  if (bMayInvalidatePattern)
187  {
188  pPattern = pAttrArray->GetPattern( nRow );
189  if (ppPatternChange)
190  *ppPatternChange = pPattern; // XXX caller may have to check for change!
191  }
192  if (bNumeric)
193  {
194  if (!bMayInvalidatePattern || pPattern == pOldPattern)
195  bBreak = false;
196  else
197  {
198  nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
199  if (pFormatter->GetType(nFormat) == SvNumFormatType::NUMBER)
200  bBreak = false;
201  }
202  }
203  }
204 
205  // get other attributes from pattern and conditional formatting
206 
207  SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
208  bool bAsianVertical = ( eOrient == SvxCellOrientation::Stacked &&
209  pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet ).GetValue() );
210  if ( bAsianVertical )
211  bBreak = false;
212 
213  if ( bWidth && bBreak ) // after determining bAsianVertical (bBreak may be reset)
214  return 0;
215 
216  Degree100 nRotate(0);
218  if ( eOrient == SvxCellOrientation::Standard )
219  {
220  const ScRotateValueItem* pRotateValueItem;
221  if (pCondSet &&
222  (pRotateValueItem = pCondSet->GetItemIfSet(ATTR_ROTATE_VALUE)) )
223  nRotate = pRotateValueItem->GetValue();
224  else
225  nRotate = pPattern->GetItem(ATTR_ROTATE_VALUE).GetValue();
226  if ( nRotate )
227  {
228  const SvxRotateModeItem* pRotateModeItem;
229  if (pCondSet &&
230  (pRotateModeItem = pCondSet->GetItemIfSet(ATTR_ROTATE_MODE)) )
231  eRotMode = pRotateModeItem->GetValue();
232  else
233  eRotMode = pPattern->GetItem(ATTR_ROTATE_MODE).GetValue();
234 
235  if ( nRotate == 18000_deg100 )
236  eRotMode = SVX_ROTATE_MODE_STANDARD; // no overflow
237  }
238  }
239 
240  if ( eHorJust == SvxCellHorJustify::Repeat )
241  {
242  // ignore orientation/rotation if "repeat" is active
243  eOrient = SvxCellOrientation::Standard;
244  nRotate = 0_deg100;
245  bAsianVertical = false;
246  }
247 
248  const SvxMarginItem* pMargin;
249  if (pCondSet &&
250  (pMargin = pCondSet->GetItemIfSet(ATTR_MARGIN)) )
251  ;
252  else
253  pMargin = &pPattern->GetItem(ATTR_MARGIN);
254  sal_uInt16 nIndent = 0;
255  if ( eHorJust == SvxCellHorJustify::Left )
256  {
257  const ScIndentItem* pIndentItem;
258  if (pCondSet &&
259  (pIndentItem = pCondSet->GetItemIfSet(ATTR_INDENT)) )
260  nIndent = pIndentItem->GetValue();
261  else
262  nIndent = pPattern->GetItem(ATTR_INDENT).GetValue();
263  }
264 
265  SvtScriptType nScript = rDocument.GetScriptType(nCol, nRow, nTab);
266  if (nScript == SvtScriptType::NONE) nScript = ScGlobal::GetDefaultScriptType();
267 
268  // also call SetFont for edit cells, because bGetFont may be set only once
269  // bGetFont is set also if script type changes
270  if (rOptions.bGetFont)
271  {
272  Fraction aFontZoom = ( eOrient == SvxCellOrientation::Standard ) ? rZoomX : rZoomY;
273  vcl::Font aFont;
274  // font color doesn't matter here
275  pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
276  pDev->SetFont(aFont);
277  }
278 
279  bool bAddMargin = true;
280  CellType eCellType = aCell.meType;
281 
282  bool bEditEngine = (eCellType == CELLTYPE_EDIT ||
283  eOrient == SvxCellOrientation::Stacked ||
284  IsAmbiguousScript(nScript) ||
285  ((eCellType == CELLTYPE_FORMULA) && aCell.mpFormula->IsMultilineResult()));
286 
287  if (!bEditEngine) // direct output
288  {
289  const Color* pColor;
290  OUString aValStr = ScCellFormat::GetString(
291  aCell, nFormat, &pColor, *pFormatter, rDocument, true, rOptions.bFormula);
292 
293  if (!aValStr.isEmpty())
294  {
295  // SetFont is moved up
296 
297  Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
298  if ( eOrient != SvxCellOrientation::Standard )
299  {
300  tools::Long nTemp = aSize.Width();
301  aSize.setWidth( aSize.Height() );
302  aSize.setHeight( nTemp );
303  }
304  else if ( nRotate )
305  {
306  //TODO: take different X/Y scaling into consideration
307 
308  double nRealOrient = toRadians(nRotate);
309  double nCosAbs = fabs( cos( nRealOrient ) );
310  double nSinAbs = fabs( sin( nRealOrient ) );
311  tools::Long nHeight = static_cast<tools::Long>( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
312  tools::Long nWidth;
313  if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
314  nWidth = static_cast<tools::Long>( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
315  else if ( rOptions.bTotalSize )
316  {
317  nWidth = conditionalScaleFunc(rDocument.GetColWidth( nCol,nTab ), nPPT);
318  bAddMargin = false;
319  // only to the right:
320  //TODO: differ on direction up/down (only Text/whole height)
321  if ( pPattern->GetRotateDir( pCondSet ) == ScRotateDir::Right )
322  nWidth += static_cast<tools::Long>( rDocument.GetRowHeight( nRow,nTab ) *
323  (bInPrintTwips ? 1.0 : nPPT) * nCosAbs / nSinAbs );
324  }
325  else
326  nWidth = static_cast<tools::Long>( aSize.Height() / nSinAbs ); //TODO: limit?
327 
328  if ( bBreak && !rOptions.bTotalSize )
329  {
330  // limit size for line break
332  if ( nHeight > nCmp )
333  nHeight = nCmp;
334  }
335 
336  aSize = Size( nWidth, nHeight );
337  }
338  nValue = bWidth ? aSize.Width() : aSize.Height();
339 
340  if ( bAddMargin )
341  {
342  if (bWidth)
343  {
344  nValue += conditionalScaleFunc(pMargin->GetLeftMargin(), nPPT) +
345  conditionalScaleFunc(pMargin->GetRightMargin(), nPPT);
346  if ( nIndent )
347  nValue += conditionalScaleFunc(nIndent, nPPT);
348  }
349  else
350  nValue += conditionalScaleFunc(pMargin->GetTopMargin(), nPPT) +
351  conditionalScaleFunc(pMargin->GetBottomMargin(), nPPT);
352  }
353 
354  // linebreak done ?
355 
356  if ( bBreak && !bWidth )
357  {
358  // test with EditEngine the safety at 90%
359  // (due to rounding errors and because EditEngine formats partially differently)
360 
361  tools::Long nDocSize = conditionalScaleFunc((rDocument.GetColWidth( nCol,nTab ) -
362  pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
363  nIndent), nPPTX);
364  nDocSize = (nDocSize * 9) / 10; // for safety
365  if ( aSize.Width() > nDocSize )
366  bEditEngine = true;
367  }
368  }
369  }
370 
371  if (bEditEngine)
372  {
373  // the font is not reset each time with !bEditEngine
374  vcl::Font aOldFont = pDev->GetFont();
375 
376  MapMode aHMMMode( MapUnit::Map100thMM, Point(), rZoomX, rZoomY );
377 
378  // save in document ?
379  std::unique_ptr<ScFieldEditEngine> pEngine = rDocument.CreateFieldEditEngine();
380 
381  const bool bPrevUpdateLayout = pEngine->SetUpdateLayout( false );
382  bool bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
383  EEControlBits nCtrl = pEngine->GetControlWord();
384  if ( bTextWysiwyg )
385  nCtrl |= EEControlBits::FORMAT100;
386  else
387  nCtrl &= ~EEControlBits::FORMAT100;
388  pEngine->SetControlWord( nCtrl );
389  MapMode aOld = pDev->GetMapMode();
390  pDev->SetMapMode( aHMMMode );
391  pEngine->SetRefDevice( pDev );
392  rDocument.ApplyAsianEditSettings( *pEngine );
393  SfxItemSet aSet( pEngine->GetEmptyItemSet() );
394  if ( ScStyleSheet* pPreviewStyle = rDocument.GetPreviewCellStyle( nCol, nRow, nTab ) )
395  {
396  ScPatternAttr aPreviewPattern( *pPattern );
397  aPreviewPattern.SetStyleSheet(pPreviewStyle);
398  aPreviewPattern.FillEditItemSet( &aSet, pCondSet );
399  }
400  else
401  {
402  SfxItemSet* pFontSet = rDocument.GetPreviewFont( nCol, nRow, nTab );
403  pPattern->FillEditItemSet( &aSet, pFontSet ? pFontSet : pCondSet );
404  }
405 // no longer needed, are set with the text (is faster)
406 // pEngine->SetDefaults( pSet );
407 
408  if ( aSet.Get(EE_PARA_HYPHENATE).GetValue() ) {
409 
410  css::uno::Reference<css::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
411  pEngine->SetHyphenator( xXHyphenator );
412  }
413 
414  Size aPaper( 1000000, 1000000 );
415  if ( eOrient==SvxCellOrientation::Stacked && !bAsianVertical )
416  aPaper.setWidth( 1 );
417  else if (bBreak)
418  {
419  double fWidthFactor = bInPrintTwips ? 1.0 : nPPTX;
420  if ( bTextWysiwyg )
421  {
422  // if text is formatted for printer, don't use PixelToLogic,
423  // to ensure the exact same paper width (and same line breaks) as in
424  // ScEditUtil::GetEditArea, used for output.
425 
427  }
428 
429  // use original width for hidden columns:
430  tools::Long nDocWidth = static_cast<tools::Long>( rDocument.GetOriginalWidth(nCol,nTab) * fWidthFactor );
431  SCCOL nColMerge = pMerge->GetColMerge();
432  if (nColMerge > 1)
433  for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
434  nDocWidth += static_cast<tools::Long>( rDocument.GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
435  nDocWidth -= static_cast<tools::Long>( pMargin->GetLeftMargin() * fWidthFactor )
436  + static_cast<tools::Long>( pMargin->GetRightMargin() * fWidthFactor )
437  + 1; // output size is width-1 pixel (due to gridline)
438  if ( nIndent )
439  nDocWidth -= static_cast<tools::Long>( nIndent * fWidthFactor );
440 
441  // space for AutoFilter button: 20 * nZoom/100
442  constexpr tools::Long nFilterButtonWidthPix = 20; // Autofilter pixel width at 100% zoom.
443  if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
444  nDocWidth -= bInPrintTwips ? o3tl::convert(nFilterButtonWidthPix, o3tl::Length::px,
446  : tools::Long(rZoomX * nFilterButtonWidthPix);
447 
448  aPaper.setWidth( nDocWidth );
449 
450  if ( !bTextWysiwyg )
451  {
452  aPaper = bInPrintTwips ?
454  pDev->PixelToLogic(aPaper, aHMMMode);
455  }
456  }
457  pEngine->SetPaperSize(aPaper);
458 
459  if (aCell.meType == CELLTYPE_EDIT)
460  {
461  pEngine->SetTextNewDefaults(*aCell.mpEditText, std::move(aSet));
462  }
463  else
464  {
465  const Color* pColor;
466  OUString aString = ScCellFormat::GetString(
467  aCell, nFormat, &pColor, *pFormatter, rDocument, true,
468  rOptions.bFormula);
469 
470  if (!aString.isEmpty())
471  pEngine->SetTextNewDefaults(aString, std::move(aSet));
472  else
473  pEngine->SetDefaults(std::move(aSet));
474  }
475 
476  bool bEngineVertical = pEngine->IsEffectivelyVertical();
477  pEngine->SetVertical( bAsianVertical );
478  pEngine->SetUpdateLayout( bPrevUpdateLayout );
479 
480  bool bEdWidth = bWidth;
481  if ( eOrient != SvxCellOrientation::Standard && eOrient != SvxCellOrientation::Stacked )
482  bEdWidth = !bEdWidth;
483  if ( nRotate )
484  {
485  //TODO: take different X/Y scaling into consideration
486 
487  Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
488  double nRealOrient = toRadians(nRotate);
489  double nCosAbs = fabs( cos( nRealOrient ) );
490  double nSinAbs = fabs( sin( nRealOrient ) );
491  tools::Long nHeight = static_cast<tools::Long>( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
492  tools::Long nWidth;
493  if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
494  nWidth = static_cast<tools::Long>( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
495  else if ( rOptions.bTotalSize )
496  {
497  nWidth = conditionalScaleFunc(rDocument.GetColWidth( nCol,nTab ), nPPT);
498  bAddMargin = false;
499  if ( pPattern->GetRotateDir( pCondSet ) == ScRotateDir::Right )
500  nWidth += static_cast<tools::Long>( rDocument.GetRowHeight( nRow,nTab ) *
501  (bInPrintTwips ? 1.0 : nPPT) * nCosAbs / nSinAbs );
502  }
503  else
504  nWidth = static_cast<tools::Long>( aSize.Height() / nSinAbs ); //TODO: limit?
505  aSize = Size( nWidth, nHeight );
506 
507  Size aTextSize = bInPrintTwips ?
509  pDev->LogicToPixel(aSize, aHMMMode);
510 
511  if ( bEdWidth )
512  nValue = aTextSize.Width();
513  else
514  {
515  nValue = aTextSize.Height();
516 
517  if ( bBreak && !rOptions.bTotalSize )
518  {
519  // limit size for line break
520  tools::Long nCmp = aOldFont.GetFontSize().Height() * SC_ROT_BREAK_FACTOR;
521  if ( nValue > nCmp )
522  nValue = nCmp;
523  }
524  }
525  }
526  else if ( bEdWidth )
527  {
528  if (bBreak)
529  nValue = 0;
530  else
531  {
532  sal_uInt32 aTextSize(pEngine->CalcTextWidth());
533  nValue = bInPrintTwips ?
534  o3tl::toTwips(aTextSize, o3tl::Length::mm100) :
535  pDev->LogicToPixel(Size(aTextSize, 0), aHMMMode).Width();
536  }
537  }
538  else // height
539  {
540  sal_uInt32 aTextSize(pEngine->GetTextHeight());
541  nValue = bInPrintTwips ?
542  o3tl::toTwips(aTextSize, o3tl::Length::mm100) :
543  pDev->LogicToPixel(Size(0, aTextSize), aHMMMode).Height();
544 
545  // With non-100% zoom and several lines or paragraphs, don't shrink below the result with FORMAT100 set
546  if ( !bTextWysiwyg && ( rZoomY.GetNumerator() != 1 || rZoomY.GetDenominator() != 1 ) &&
547  ( pEngine->GetParagraphCount() > 1 || ( bBreak && pEngine->GetLineCount(0) > 1 ) ) )
548  {
549  pEngine->SetControlWord( nCtrl | EEControlBits::FORMAT100 );
550  pEngine->QuickFormatDoc( true );
551  aTextSize = pEngine->GetTextHeight();
552  tools::Long nSecondValue = bInPrintTwips ?
553  o3tl::toTwips(aTextSize, o3tl::Length::mm100) :
554  pDev->LogicToPixel(Size(0, aTextSize), aHMMMode).Height();
555  if ( nSecondValue > nValue )
556  nValue = nSecondValue;
557  }
558  }
559 
560  if ( nValue && bAddMargin )
561  {
562  if (bWidth)
563  {
564  nValue += conditionalScaleFunc(pMargin->GetLeftMargin(), nPPT) +
565  conditionalScaleFunc(pMargin->GetRightMargin(), nPPT);
566  if (nIndent)
567  nValue += conditionalScaleFunc(nIndent, nPPT);
568  }
569  else
570  {
571  nValue += conditionalScaleFunc(pMargin->GetTopMargin(), nPPT) +
572  conditionalScaleFunc(pMargin->GetBottomMargin(), nPPT);
573 
574  if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
575  {
576  // add 1pt extra (default margin value) for line breaks with SetVertical
577  constexpr tools::Long nDefaultMarginInPoints = 1;
578  nValue += conditionalScaleFunc(
579  o3tl::convert(nDefaultMarginInPoints, o3tl::Length::pt, o3tl::Length::twip),
580  nPPT);
581  }
582  }
583  }
584 
585  // EditEngine is cached and re-used, so the old vertical flag must be restored
586  pEngine->SetVertical( bEngineVertical );
587 
588  rDocument.DisposeFieldEditEngine(pEngine);
589 
590  pDev->SetMapMode( aOld );
591  pDev->SetFont( aOldFont );
592  }
593 
594  if (bWidth)
595  {
596  // place for Autofilter Button
597  // 20 * nZoom/100
598  // Conditional formatting is not interesting here
599  constexpr tools::Long nFilterButtonWidthPix = 20; // Autofilter pixel width at 100% zoom.
600  ScMF nFlags = pPattern->GetItem(ATTR_MERGE_FLAG).GetValue();
601  if (nFlags & ScMF::Auto)
602  nValue += bInPrintTwips ? o3tl::convert(nFilterButtonWidthPix, o3tl::Length::px,
604  : tools::Long(rZoomX * nFilterButtonWidthPix);
605  }
606 
607  return nValue;
608 }
609 
610 namespace {
611 
612 class MaxStrLenFinder
613 {
614  ScDocument& mrDoc;
615  sal_uInt32 mnFormat;
616  OUString maMaxLenStr;
617  sal_Int32 mnMaxLen;
618 
619  // tdf#59820 - search for the longest substring in a multiline string
620  void checkLineBreak(const OUString& aStrVal)
621  {
622  sal_Int32 nFromIndex = 0;
623  sal_Int32 nToIndex = aStrVal.indexOf('\n', nFromIndex);
624  // if there is no line break, just take the length of the entire string
625  if (nToIndex == -1)
626  {
627  mnMaxLen = aStrVal.getLength();
628  maMaxLenStr = aStrVal;
629  }
630  else
631  {
632  sal_Int32 nMaxLen = 0;
633  // search for the longest substring in the multiline string
634  while (nToIndex != -1)
635  {
636  if (nMaxLen < nToIndex - nFromIndex)
637  {
638  nMaxLen = nToIndex - nFromIndex;
639  }
640  nFromIndex = nToIndex + 1;
641  nToIndex = aStrVal.indexOf('\n', nFromIndex);
642  }
643  // take into consideration the last part of multiline string
644  nToIndex = aStrVal.getLength() - nFromIndex;
645  if (nMaxLen < nToIndex)
646  {
647  nMaxLen = nToIndex;
648  }
649  // assign new maximum including its substring
650  if (mnMaxLen < nMaxLen)
651  {
652  mnMaxLen = nMaxLen;
653  maMaxLenStr = aStrVal.subView(nFromIndex);
654  }
655  }
656  }
657 
658  void checkLength(const ScRefCellValue& rCell)
659  {
660  const Color* pColor;
661  OUString aValStr = ScCellFormat::GetString(
662  rCell, mnFormat, &pColor, *mrDoc.GetFormatTable(), mrDoc);
663 
664  if (aValStr.getLength() <= mnMaxLen)
665  return;
666 
667  switch (rCell.meType)
668  {
669  case CELLTYPE_NONE:
670  case CELLTYPE_VALUE:
671  mnMaxLen = aValStr.getLength();
672  maMaxLenStr = aValStr;
673  break;
674  case CELLTYPE_EDIT:
675  case CELLTYPE_STRING:
676  case CELLTYPE_FORMULA:
677  default:
678  checkLineBreak(aValStr);
679  }
680  }
681 
682 public:
683  MaxStrLenFinder(ScDocument& rDoc, sal_uInt32 nFormat) :
684  mrDoc(rDoc), mnFormat(nFormat), mnMaxLen(0) {}
685 
686  void operator() (size_t /*nRow*/, double f)
687  {
688  ScRefCellValue aCell(f);
689  checkLength(aCell);
690  }
691 
692  void operator() (size_t /*nRow*/, const svl::SharedString& rSS)
693  {
694  if (rSS.getLength() > mnMaxLen)
695  {
696  checkLineBreak(rSS.getString());
697  }
698  }
699 
700  void operator() (size_t /*nRow*/, const EditTextObject* p)
701  {
702  ScRefCellValue aCell(p);
703  checkLength(aCell);
704  }
705 
706  void operator() (size_t /*nRow*/, const ScFormulaCell* p)
707  {
708  ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
709  checkLength(aCell);
710  }
711 
712  const OUString& getMaxLenStr() const { return maMaxLenStr; }
713 };
714 
715 }
716 
718  OutputDevice* pDev, double nPPTX, double nPPTY, const Fraction& rZoomX, const Fraction& rZoomY,
719  bool bFormula, sal_uInt16 nOldWidth, const ScMarkData* pMarkData, const ScColWidthParam* pParam) const
720 {
721  if (maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty)
722  // All cells are empty.
723  return nOldWidth;
724 
725  sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
727  if (pMarkData && (pMarkData->IsMarked() || pMarkData->IsMultiMarked()))
728  {
729  aSpanSet.scan(*pMarkData, nTab, nCol);
730  aSpanSet.getSpans(aMarkedSpans);
731  }
732  else
733  // "Select" the entire column if no selection exists.
734  aMarkedSpans.emplace_back(0, GetDoc().MaxRow());
735 
736  sal_uInt16 nWidth = static_cast<sal_uInt16>(nOldWidth*nPPTX);
737  bool bFound = false;
738  ScDocument& rDocument = GetDoc();
739 
740  if ( pParam && pParam->mbSimpleText )
741  { // all the same except for number format
742  const ScPatternAttr* pPattern = GetPattern( 0 );
743  vcl::Font aFont;
744  // font color doesn't matter here
745  pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &rZoomX );
746  pDev->SetFont( aFont );
747  const SvxMarginItem* pMargin = &pPattern->GetItem(ATTR_MARGIN);
748  tools::Long nMargin = static_cast<tools::Long>( pMargin->GetLeftMargin() * nPPTX ) +
749  static_cast<tools::Long>( pMargin->GetRightMargin() * nPPTX );
750 
751  // Try to find the row that has the longest string, and measure the width of that string.
752  SvNumberFormatter* pFormatter = rDocument.GetFormatTable();
753  sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
754  OUString aLongStr;
755  const Color* pColor;
756  if (pParam->mnMaxTextRow >= 0)
757  {
758  ScRefCellValue aCell = GetCellValue(pParam->mnMaxTextRow);
759  aLongStr = ScCellFormat::GetString(
760  aCell, nFormat, &pColor, *pFormatter, rDocument);
761  }
762  else
763  {
764  // Go though all non-empty cells within selection.
765  MaxStrLenFinder aFunc(rDocument, nFormat);
766  sc::CellStoreType::const_iterator itPos = maCells.begin();
767  for (const auto& rMarkedSpan : aMarkedSpans)
768  itPos = sc::ParseAllNonEmpty(itPos, maCells, rMarkedSpan.mnRow1, rMarkedSpan.mnRow2, aFunc);
769 
770  aLongStr = aFunc.getMaxLenStr();
771  }
772 
773  if (!aLongStr.isEmpty())
774  {
775  nWidth = pDev->GetTextWidth(aLongStr) + static_cast<sal_uInt16>(nMargin);
776  bFound = true;
777  }
778  }
779  else
780  {
781  ScNeededSizeOptions aOptions;
782  aOptions.bFormula = bFormula;
783  const ScPatternAttr* pOldPattern = nullptr;
784 
785  // Go though all non-empty cells within selection.
786  sc::CellStoreType::const_iterator itPos = maCells.begin();
787  for (const auto& rMarkedSpan : aMarkedSpans)
788  {
789  SCROW nRow1 = rMarkedSpan.mnRow1, nRow2 = rMarkedSpan.mnRow2;
790  SCROW nRow = nRow1;
791  while (nRow <= nRow2)
792  {
793  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
794  itPos = aPos.first;
795  if (itPos->type == sc::element_type_empty)
796  {
797  // Skip empty cells.
798  nRow += itPos->size - aPos.second;
799  continue;
800  }
801 
802  for (size_t nOffset = aPos.second; nOffset < itPos->size; ++nOffset, ++nRow)
803  {
804  SvtScriptType nScript = rDocument.GetScriptType(nCol, nRow, nTab);
805  if (nScript == SvtScriptType::NONE)
806  nScript = ScGlobal::GetDefaultScriptType();
807 
808  const ScPatternAttr* pPattern = GetPattern(nRow);
809  aOptions.pPattern = pPattern;
810  aOptions.bGetFont = (pPattern != pOldPattern || nScript != SvtScriptType::NONE);
811  pOldPattern = pPattern;
812  sal_uInt16 nThis = static_cast<sal_uInt16>(GetNeededSize(
813  nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, true, aOptions, &pOldPattern));
814  if (nThis && (nThis > nWidth || !bFound))
815  {
816  nWidth = nThis;
817  bFound = true;
818  }
819  }
820  }
821  }
822  }
823 
824  if (bFound)
825  {
826  nWidth += 2;
827  sal_uInt16 nTwips = static_cast<sal_uInt16>(
828  std::min(nWidth / nPPTX, std::numeric_limits<sal_uInt16>::max() / 2.0));
829  return nTwips;
830  }
831  else
832  return nOldWidth;
833 }
834 
835 static sal_uInt16 lcl_GetAttribHeight( const ScPatternAttr& rPattern, sal_uInt16 nFontHeightId )
836 {
837  const SvxFontHeightItem& rFontHeight =
838  static_cast<const SvxFontHeightItem&>(rPattern.GetItem(nFontHeightId));
839 
840  sal_uInt16 nHeight = rFontHeight.GetHeight();
841  nHeight *= 1.18;
842 
843  if ( rPattern.GetItem(ATTR_FONT_EMPHASISMARK).GetEmphasisMark() != FontEmphasisMark::NONE )
844  {
845  // add height for emphasis marks
846  //TODO: font metrics should be used instead
847  nHeight += nHeight / 4;
848  }
849 
850  const SvxMarginItem& rMargin = rPattern.GetItem(ATTR_MARGIN);
851 
852  nHeight += rMargin.GetTopMargin() + rMargin.GetBottomMargin();
853 
854  if (nHeight > STD_ROWHEIGHT_DIFF)
855  nHeight -= STD_ROWHEIGHT_DIFF;
856 
857  if (nHeight < ScGlobal::nStdRowHeight)
858  nHeight = ScGlobal::nStdRowHeight;
859 
860  return nHeight;
861 }
862 
863 // pHeight in Twips
864 // optimize nMinHeight, nMinStart : with nRow >= nMinStart is at least nMinHeight
865 // (is only evaluated with bStdAllowed)
866 
868  sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, sal_uInt16 nMinHeight, SCROW nMinStart )
869 {
870  ScDocument& rDocument = GetDoc();
871  RowHeightsArray& rHeights = rCxt.getHeightArray();
872  ScAttrIterator aIter( pAttrArray.get(), nStartRow, nEndRow, rDocument.GetDefPattern() );
873 
874  SCROW nStart = -1;
875  SCROW nEnd = -1;
876  SCROW nEditPos = 0;
877  SCROW nNextEnd = 0;
878 
879  // with conditional formatting, always consider the individual cells
880 
881  const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
882  while ( pPattern )
883  {
884  const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE);
885  const ScMergeFlagAttr* pFlag = &pPattern->GetItem(ATTR_MERGE_FLAG);
886  if ( pMerge->GetRowMerge() > 1 || pFlag->IsOverlapped() )
887  {
888  // do nothing - vertically with merged and overlapping,
889  // horizontally only with overlapped (invisible) -
890  // only one horizontal merged is always considered
891  }
892  else
893  {
894  bool bStdAllowed = (pPattern->GetCellOrientation() == SvxCellOrientation::Standard);
895  bool bStdOnly = false;
896  if (bStdAllowed)
897  {
898  bool bBreak = pPattern->GetItem(ATTR_LINEBREAK).GetValue() ||
899  (pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() ==
900  SvxCellHorJustify::Block);
901  bStdOnly = !bBreak;
902 
903  // conditional formatting: loop all cells
904  if (bStdOnly &&
905  !pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
906  {
907  bStdOnly = false;
908  }
909 
910  // rotated text: loop all cells
911  if ( bStdOnly && pPattern->GetItem(ATTR_ROTATE_VALUE).GetValue() )
912  bStdOnly = false;
913  }
914 
915  if (bStdOnly)
916  {
917  bool bHasEditCells = HasEditCells(nStart,nEnd,nEditPos);
918  // Call to HasEditCells() may change pattern due to
919  // calculation, => sync always.
920  // We don't know which row changed first, but as pPattern
921  // covered nStart to nEnd we can pick nStart. Worst case we
922  // have to repeat that for every row in range if every row
923  // changed.
924  pPattern = aIter.Resync( nStart, nStart, nEnd);
925  if (bHasEditCells && nEnd < nEditPos)
926  bHasEditCells = false; // run into that again
927  if (bHasEditCells) // includes mixed script types
928  {
929  if (nEditPos == nStart)
930  {
931  bStdOnly = false;
932  if (nEnd > nEditPos)
933  nNextEnd = nEnd;
934  nEnd = nEditPos; // calculate single
935  bStdAllowed = false; // will be computed in any case per cell
936  }
937  else
938  {
939  nNextEnd = nEnd;
940  nEnd = nEditPos - 1; // standard - part
941  }
942  }
943  }
944 
945  sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
946  aSpanSet.scan(*this, nStart, nEnd);
948  aSpanSet.getSpans(aSpans);
949 
950  if (bStdAllowed)
951  {
952  sal_uInt16 nLatHeight = 0;
953  sal_uInt16 nCjkHeight = 0;
954  sal_uInt16 nCtlHeight = 0;
955  sal_uInt16 nDefHeight;
957  if ( nDefScript == SvtScriptType::ASIAN )
958  nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
959  else if ( nDefScript == SvtScriptType::COMPLEX )
960  nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
961  else
962  nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
963 
964  // if everything below is already larger, the loop doesn't have to
965  // be run again
966  SCROW nStdEnd = nEnd;
967  if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
968  nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
969 
970  if (nStart <= nStdEnd)
971  {
972  SCROW nRow = nStart;
973  for (;;)
974  {
975  size_t nIndex;
976  SCROW nRangeEnd;
977  sal_uInt16 nRangeHeight = rHeights.GetValue(nRow, nIndex, nRangeEnd);
978  if (nRangeHeight < nDefHeight)
979  rHeights.SetValue(nRow, std::min(nRangeEnd, nStdEnd), nDefHeight);
980  nRow = nRangeEnd + 1;
981  if (nRow > nStdEnd)
982  break;
983  }
984  }
985 
986  if ( bStdOnly )
987  {
988  // if cells are not handled individually below,
989  // check for cells with different script type
990  sc::CellTextAttrStoreType::iterator itAttr = maCellTextAttrs.begin();
991  sc::CellStoreType::iterator itCells = maCells.begin();
992  for (const auto& rSpan : aSpans)
993  {
994  for (SCROW nRow = rSpan.mnRow1; nRow <= rSpan.mnRow2; ++nRow)
995  {
996  SvtScriptType nScript = GetRangeScriptType(itAttr, nRow, nRow, itCells);
997  if (nScript == nDefScript)
998  continue;
999 
1000  if ( nScript == SvtScriptType::ASIAN )
1001  {
1002  if ( nCjkHeight == 0 )
1003  nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
1004  if (nCjkHeight > rHeights.GetValue(nRow))
1005  rHeights.SetValue(nRow, nRow, nCjkHeight);
1006  }
1007  else if ( nScript == SvtScriptType::COMPLEX )
1008  {
1009  if ( nCtlHeight == 0 )
1010  nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
1011  if (nCtlHeight > rHeights.GetValue(nRow))
1012  rHeights.SetValue(nRow, nRow, nCtlHeight);
1013  }
1014  else
1015  {
1016  if ( nLatHeight == 0 )
1017  nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
1018  if (nLatHeight > rHeights.GetValue(nRow))
1019  rHeights.SetValue(nRow, nRow, nLatHeight);
1020  }
1021  }
1022  }
1023  }
1024  }
1025 
1026  if (!bStdOnly) // search covered cells
1027  {
1028  ScNeededSizeOptions aOptions;
1029 
1030  for (const auto& rSpan : aSpans)
1031  {
1032  for (SCROW nRow = rSpan.mnRow1; nRow <= rSpan.mnRow2; ++nRow)
1033  {
1034  // only calculate the cell height when it's used later (#37928#)
1035 
1036  if (rCxt.isForceAutoSize() || !(rDocument.GetRowFlags(nRow, nTab) & CRFlags::ManualSize) )
1037  {
1038  aOptions.pPattern = pPattern;
1039  const ScPatternAttr* pOldPattern = pPattern;
1040  sal_uInt16 nHeight = static_cast<sal_uInt16>(
1041  std::min(
1042  GetNeededSize( nRow, rCxt.getOutputDevice(), rCxt.getPPTX(), rCxt.getPPTY(),
1043  rCxt.getZoomX(), rCxt.getZoomY(), false, aOptions,
1044  &pPattern) / rCxt.getPPTY(),
1045  double(std::numeric_limits<sal_uInt16>::max())));
1046  if (nHeight > rHeights.GetValue(nRow))
1047  rHeights.SetValue(nRow, nRow, nHeight);
1048  // Pattern changed due to calculation? => sync.
1049  if (pPattern != pOldPattern)
1050  {
1051  pPattern = aIter.Resync( nRow, nStart, nEnd);
1052  nNextEnd = 0;
1053  }
1054  }
1055  }
1056  }
1057  }
1058  }
1059 
1060  if (nNextEnd > 0)
1061  {
1062  nStart = nEnd + 1;
1063  nEnd = nNextEnd;
1064  nNextEnd = 0;
1065  }
1066  else
1067  pPattern = aIter.Next(nStart,nEnd);
1068  }
1069 }
1070 
1071 bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) const
1072 {
1073  ScDocument& rDocument = GetDoc();
1074  sc::CellStoreType::const_iterator it = maCells.position(nRow).first;
1075  mdds::mtv::element_t eType = it->type;
1076  if (!bInSel && it != maCells.end() && eType != sc::element_type_empty)
1077  {
1078  if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
1079  !(HasAttrib( nRow, nRow, HasAttrFlags::Protected) &&
1080  rDocument.IsTabProtected(nTab)) )
1081  return true;
1082  }
1083  if (bInSel)
1084  {
1085  SCROW lastDataPos = GetLastDataPos();
1086  for (;;)
1087  {
1088  nRow = rData.GetNextMarked(nCol, nRow, false);
1089  if (!rDocument.ValidRow(nRow) || nRow > lastDataPos )
1090  {
1091  nRow = GetDoc().MaxRow()+1;
1092  return false;
1093  }
1094  else
1095  {
1096  it = maCells.position(it, nRow).first;
1097  eType = it->type;
1098  if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
1099  !(HasAttrib( nRow, nRow, HasAttrFlags::Protected) &&
1100  rDocument.IsTabProtected(nTab)) )
1101  return true;
1102  else
1103  nRow++;
1104  }
1105  }
1106  }
1107  else
1108  {
1109  while (GetNextDataPos(nRow))
1110  {
1111  it = maCells.position(it, nRow).first;
1112  eType = it->type;
1113  if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
1114  !(HasAttrib( nRow, nRow, HasAttrFlags::Protected) &&
1115  rDocument.IsTabProtected(nTab)) )
1116  return true;
1117  else
1118  nRow++;
1119  }
1120  nRow = GetDoc().MaxRow()+1;
1121  return false;
1122  }
1123 }
1124 
1125 namespace {
1126 
1127 class StrEntries
1128 {
1130 
1131 protected:
1132  struct StrEntry
1133  {
1134  SCROW mnRow;
1135  OUString maStr;
1136 
1137  StrEntry(SCROW nRow, const OUString& rStr) : mnRow(nRow), maStr(rStr) {}
1138  };
1139 
1140  std::vector<StrEntry> maStrEntries;
1141  ScDocument* mpDoc;
1142 
1143  StrEntries(sc::CellStoreType& rCells, ScDocument* pDoc) : mrCells(rCells), mpDoc(pDoc) {}
1144 
1145 public:
1146  void commitStrings()
1147  {
1148  svl::SharedStringPool& rPool = mpDoc->GetSharedStringPool();
1149  sc::CellStoreType::iterator it = mrCells.begin();
1150  for (const auto& rStrEntry : maStrEntries)
1151  it = mrCells.set(it, rStrEntry.mnRow, rPool.intern(rStrEntry.maStr));
1152  }
1153 };
1154 
1155 class RemoveEditAttribsHandler : public StrEntries
1156 {
1157  std::unique_ptr<ScFieldEditEngine> mpEngine;
1158 
1159 public:
1160  RemoveEditAttribsHandler(sc::CellStoreType& rCells, ScDocument* pDoc) : StrEntries(rCells, pDoc) {}
1161 
1162  void operator() (size_t nRow, EditTextObject*& pObj)
1163  {
1164  // For the test on hard formatting (ScEditAttrTester), are the defaults in the
1165  // EditEngine of no importance. When the tester would later recognise the same
1166  // attributes in default and hard formatting and has to remove them, the correct
1167  // defaults must be set in the EditEngine for each cell.
1168 
1169  // test for attributes
1170  if (!mpEngine)
1171  {
1172  mpEngine.reset(new ScFieldEditEngine(mpDoc, mpDoc->GetEditPool()));
1173  // EEControlBits::ONLINESPELLING if there are errors already
1174  mpEngine->SetControlWord(mpEngine->GetControlWord() | EEControlBits::ONLINESPELLING);
1175  mpDoc->ApplyAsianEditSettings(*mpEngine);
1176  }
1177  mpEngine->SetTextCurrentDefaults(*pObj);
1178  sal_Int32 nParCount = mpEngine->GetParagraphCount();
1179  for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
1180  {
1181  mpEngine->RemoveCharAttribs(nPar);
1182  const SfxItemSet& rOld = mpEngine->GetParaAttribs(nPar);
1183  if ( rOld.Count() )
1184  {
1185  SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() ); // empty
1186  mpEngine->SetParaAttribs( nPar, aNew );
1187  }
1188  }
1189  // change URL field to text (not possible otherwise, thus pType=0)
1190  mpEngine->RemoveFields();
1191 
1192  bool bSpellErrors = mpEngine->HasOnlineSpellErrors();
1193  bool bNeedObject = bSpellErrors || nParCount>1; // keep errors/paragraphs
1194  // ScEditAttrTester is not needed anymore, arrays are gone
1195 
1196  if (bNeedObject) // remains edit cell
1197  {
1198  EEControlBits nCtrl = mpEngine->GetControlWord();
1199  EEControlBits nWantBig = bSpellErrors ? EEControlBits::ALLOWBIGOBJS : EEControlBits::NONE;
1200  if ( ( nCtrl & EEControlBits::ALLOWBIGOBJS ) != nWantBig )
1201  mpEngine->SetControlWord( (nCtrl & ~EEControlBits::ALLOWBIGOBJS) | nWantBig );
1202 
1203  // Overwrite the existing object.
1204  delete pObj;
1205  pObj = mpEngine->CreateTextObject().release();
1206  }
1207  else // create String
1208  {
1209  // Store the string replacement for later commits.
1210  OUString aText = ScEditUtil::GetSpaceDelimitedString(*mpEngine);
1211  maStrEntries.emplace_back(nRow, aText);
1212  }
1213  }
1214 };
1215 
1216 class TestTabRefAbsHandler
1217 {
1218  SCTAB mnTab;
1219  bool mbTestResult;
1220 public:
1221  explicit TestTabRefAbsHandler(SCTAB nTab) : mnTab(nTab), mbTestResult(false) {}
1222 
1223  void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
1224  {
1225  if (const_cast<ScFormulaCell*>(pCell)->TestTabRefAbs(mnTab))
1226  mbTestResult = true;
1227  }
1228 
1229  bool getTestResult() const { return mbTestResult; }
1230 };
1231 
1232 }
1233 
1234 void ScColumn::RemoveEditAttribs( sc::ColumnBlockPosition& rBlockPos, SCROW nStartRow, SCROW nEndRow )
1235 {
1236  RemoveEditAttribsHandler aFunc(maCells, &GetDoc());
1237 
1238  rBlockPos.miCellPos = sc::ProcessEditText(
1239  rBlockPos.miCellPos, maCells, nStartRow, nEndRow, aFunc);
1240 
1241  aFunc.commitStrings();
1242 }
1243 
1244 bool ScColumn::TestTabRefAbs(SCTAB nTable) const
1245 {
1246  TestTabRefAbsHandler aFunc(nTable);
1247  sc::ParseFormula(maCells, aFunc);
1248  return aFunc.getTestResult();
1249 }
1250 
1252 {
1253  return maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty;
1254 }
1255 
1256 namespace {
1257 
1258 class CellCounter
1259 {
1260  size_t mnCount;
1261 public:
1262  CellCounter() : mnCount(0) {}
1263 
1264  void operator() (
1265  const sc::CellStoreType::value_type& node, size_t /*nOffset*/, size_t nDataSize)
1266  {
1267  if (node.type == sc::element_type_empty)
1268  return;
1269 
1270  mnCount += nDataSize;
1271  }
1272 
1273  size_t getCount() const { return mnCount; }
1274 };
1275 
1276 }
1277 
1278 SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
1279 {
1280  CellCounter aFunc;
1281  sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
1282  return aFunc.getCount();
1283 }
1284 
1286 {
1287  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
1288  sc::CellStoreType::const_iterator it = aPos.first;
1289  if (it == maCells.end())
1290  // Likely invalid row number.
1291  return false;
1292 
1293  return it->type != sc::element_type_empty;
1294 }
1295 
1296 bool ScColumn::IsEmptyData(SCROW nStartRow, SCROW nEndRow) const
1297 {
1298  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1299  sc::CellStoreType::const_iterator it = aPos.first;
1300  if (it == maCells.end())
1301  // Invalid row number.
1302  return false;
1303 
1304  if (it->type != sc::element_type_empty)
1305  // Non-empty cell at the start position.
1306  return false;
1307 
1308  // start position of next block which is not empty.
1309  SCROW nNextRow = nStartRow + it->size - aPos.second;
1310  return nEndRow < nNextRow;
1311 }
1312 
1313 bool ScColumn::IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
1314 {
1315  std::pair<sc::CellNoteStoreType::const_iterator,size_t> aPos = maCellNotes.position(nStartRow);
1316  sc::CellNoteStoreType::const_iterator it = aPos.first;
1317  if (it == maCellNotes.end())
1318  // Invalid row number.
1319  return false;
1320 
1321  if (it->type != sc::element_type_empty)
1322  // Non-empty cell at the start position.
1323  return false;
1324 
1325  // start position of next block which is not empty.
1326  SCROW nNextRow = nStartRow + it->size - aPos.second;
1327  return nEndRow < nNextRow;
1328 }
1329 
1331 {
1332  // Given a range of rows, find a top or bottom empty segment.
1333  switch (eDir)
1334  {
1335  case DIR_TOP:
1336  {
1337  // Determine the length of empty head segment.
1338  size_t nLength = nEndRow - nStartRow + 1;
1339  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1340  sc::CellStoreType::const_iterator it = aPos.first;
1341  if (it->type != sc::element_type_empty)
1342  // First row is already not empty.
1343  return 0;
1344 
1345  // length of this empty block minus the offset.
1346  size_t nThisLen = it->size - aPos.second;
1347  return std::min(nThisLen, nLength);
1348  }
1349  break;
1350  case DIR_BOTTOM:
1351  {
1352  // Determine the length of empty tail segment.
1353  size_t nLength = nEndRow - nStartRow + 1;
1354  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nEndRow);
1355  sc::CellStoreType::const_iterator it = aPos.first;
1356  if (it->type != sc::element_type_empty)
1357  // end row is already not empty.
1358  return 0;
1359 
1360  // length of this empty block from the tip to the end row position.
1361  size_t nThisLen = aPos.second + 1;
1362  return std::min(nThisLen, nLength);
1363  }
1364  break;
1365  default:
1366  ;
1367  }
1368 
1369  return 0;
1370 }
1371 
1373 {
1374  if (IsEmptyData())
1375  return 0;
1376 
1377  sc::CellStoreType::const_iterator it = maCells.begin();
1378  if (it->type != sc::element_type_empty)
1379  return 0;
1380 
1381  return it->size;
1382 }
1383 
1385 {
1386  if (IsEmptyData())
1387  return 0;
1388 
1389  sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
1390  if (it->type != sc::element_type_empty)
1391  return GetDoc().MaxRow();
1392 
1393  return GetDoc().MaxRow() - static_cast<SCROW>(it->size);
1394 }
1395 
1396 SCROW ScColumn::GetLastDataPos( SCROW nLastRow, ScDataAreaExtras* pDataAreaExtras ) const
1397 {
1398  nLastRow = std::min( nLastRow, GetDoc().MaxRow());
1399 
1400  if (pDataAreaExtras && pDataAreaExtras->mnEndRow < nLastRow)
1401  {
1402  // Check in order of likeliness.
1403  if ( (pDataAreaExtras->mbCellFormats && HasVisibleAttrIn(nLastRow, nLastRow)) ||
1404  (pDataAreaExtras->mbCellNotes && !IsNotesEmptyBlock(nLastRow, nLastRow)) ||
1405  (pDataAreaExtras->mbCellDrawObjects && !IsDrawObjectsEmptyBlock(nLastRow, nLastRow)))
1406  pDataAreaExtras->mnEndRow = nLastRow;
1407  }
1408 
1409  sc::CellStoreType::const_position_type aPos = maCells.position(nLastRow);
1410 
1411  if (aPos.first->type != sc::element_type_empty)
1412  return nLastRow;
1413 
1414  if (aPos.first == maCells.begin())
1415  // This is the first block, and is empty.
1416  return 0;
1417 
1418  return static_cast<SCROW>(aPos.first->position - 1);
1419 }
1420 
1422 {
1423  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
1424  sc::CellStoreType::const_iterator it = aPos.first;
1425  if (it == maCells.end())
1426  return false;
1427 
1428  if (it->type == sc::element_type_empty)
1429  {
1430  if (it == maCells.begin())
1431  // No more previous non-empty cell.
1432  return false;
1433 
1434  rRow -= aPos.second + 1; // Last row position of the previous block.
1435  return true;
1436  }
1437 
1438  // This block is not empty.
1439  if (aPos.second)
1440  {
1441  // There are preceding cells in this block. Simply move back one cell.
1442  --rRow;
1443  return true;
1444  }
1445 
1446  // This is the first cell in a non-empty block. Move back to the previous block.
1447  if (it == maCells.begin())
1448  // No more preceding block.
1449  return false;
1450 
1451  --rRow; // Move to the last cell of the previous block.
1452  --it;
1453  if (it->type == sc::element_type_empty)
1454  {
1455  // This block is empty.
1456  if (it == maCells.begin())
1457  // No more preceding blocks.
1458  return false;
1459 
1460  // Skip the whole empty block segment.
1461  rRow -= it->size;
1462  }
1463 
1464  return true;
1465 }
1466 
1467 bool ScColumn::GetNextDataPos(SCROW& rRow) const // greater than rRow
1468 {
1469  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
1470  sc::CellStoreType::const_iterator it = aPos.first;
1471  if (it == maCells.end())
1472  return false;
1473 
1474  if (it->type == sc::element_type_empty)
1475  {
1476  // This block is empty. Skip ahead to the next block (if exists).
1477  rRow += it->size - aPos.second;
1478  ++it;
1479  if (it == maCells.end())
1480  // No more next block.
1481  return false;
1482 
1483  // Next block exists, and is non-empty.
1484  return true;
1485  }
1486 
1487  if (aPos.second < it->size - 1)
1488  {
1489  // There are still cells following the current position.
1490  ++rRow;
1491  return true;
1492  }
1493 
1494  // This is the last cell in the block. Move ahead to the next block.
1495  rRow += it->size - aPos.second; // First cell in the next block.
1496  ++it;
1497  if (it == maCells.end())
1498  // No more next block.
1499  return false;
1500 
1501  if (it->type == sc::element_type_empty)
1502  {
1503  // Next block is empty. Move to the next block.
1504  rRow += it->size;
1505  ++it;
1506  if (it == maCells.end())
1507  return false;
1508  }
1509 
1510  return true;
1511 }
1512 
1513 bool ScColumn::TrimEmptyBlocks(SCROW& rRowStart, SCROW& rRowEnd) const
1514 {
1515  assert(rRowStart <= rRowEnd);
1516  SCROW nRowStartNew = rRowStart, nRowEndNew = rRowEnd;
1517 
1518  // Trim down rRowStart first
1519  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRowStart);
1520  sc::CellStoreType::const_iterator it = aPos.first;
1521  if (it == maCells.end())
1522  return false;
1523 
1524  if (it->type == sc::element_type_empty)
1525  {
1526  // This block is empty. Skip ahead to the next block (if exists).
1527  nRowStartNew += it->size - aPos.second;
1528  if (nRowStartNew > rRowEnd)
1529  return false;
1530  ++it;
1531  if (it == maCells.end())
1532  // No more next block.
1533  return false;
1534  }
1535 
1536  // Trim up rRowEnd next
1537  aPos = maCells.position(rRowEnd);
1538  it = aPos.first;
1539  if (it == maCells.end())
1540  {
1541  rRowStart = nRowStartNew;
1542  return true; // Because trimming of rRowStart is ok
1543  }
1544 
1545  if (it->type == sc::element_type_empty)
1546  {
1547  // rRowEnd cannot be in the first block which is empty !
1548  assert(it != maCells.begin());
1549  // This block is empty. Skip to the previous block (it exists).
1550  nRowEndNew -= aPos.second + 1; // Last row position of the previous block.
1551  assert(nRowStartNew <= nRowEndNew);
1552  }
1553 
1554  rRowStart = nRowStartNew;
1555  rRowEnd = nRowEndNew;
1556  return true;
1557 }
1558 
1559 SCROW ScColumn::FindNextVisibleRow(SCROW nRow, bool bForward) const
1560 {
1561  if(bForward)
1562  {
1563  nRow++;
1564  SCROW nEndRow = 0;
1565  bool bHidden = GetDoc().RowHidden(nRow, nTab, nullptr, &nEndRow);
1566  if(bHidden)
1567  return std::min<SCROW>(GetDoc().MaxRow(), nEndRow + 1);
1568  else
1569  return nRow;
1570  }
1571  else
1572  {
1573  nRow--;
1574  SCROW nStartRow = GetDoc().MaxRow();
1575  bool bHidden = GetDoc().RowHidden(nRow, nTab, &nStartRow);
1576  if(bHidden)
1577  return std::max<SCROW>(0, nStartRow - 1);
1578  else
1579  return nRow;
1580  }
1581 }
1582 
1584  sc::CellStoreType::const_iterator& itPos, SCROW nRow, bool bForward) const
1585 {
1586  ScDocument& rDocument = GetDoc();
1587  if (bForward)
1588  {
1589  do
1590  {
1591  nRow++;
1592  SCROW nEndRow = 0;
1593  bool bHidden = rDocument.RowHidden(nRow, nTab, nullptr, &nEndRow);
1594  if (bHidden)
1595  {
1596  nRow = nEndRow + 1;
1597  if(nRow >= GetDoc().MaxRow())
1598  return GetDoc().MaxRow();
1599  }
1600 
1601  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
1602  itPos = aPos.first;
1603  if (itPos == maCells.end())
1604  // Invalid row.
1605  return GetDoc().MaxRow();
1606 
1607  if (itPos->type != sc::element_type_empty)
1608  return nRow;
1609 
1610  // Move to the last cell of the current empty block.
1611  nRow += itPos->size - aPos.second - 1;
1612  }
1613  while (nRow < GetDoc().MaxRow());
1614 
1615  return GetDoc().MaxRow();
1616  }
1617 
1618  do
1619  {
1620  nRow--;
1621  SCROW nStartRow = GetDoc().MaxRow();
1622  bool bHidden = rDocument.RowHidden(nRow, nTab, &nStartRow);
1623  if (bHidden)
1624  {
1625  nRow = nStartRow - 1;
1626  if(nRow <= 0)
1627  return 0;
1628  }
1629 
1630  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
1631  itPos = aPos.first;
1632  if (itPos == maCells.end())
1633  // Invalid row.
1634  return 0;
1635 
1636  if (itPos->type != sc::element_type_empty)
1637  return nRow;
1638 
1639  // Move to the first cell of the current empty block.
1640  nRow -= aPos.second;
1641  }
1642  while (nRow > 0);
1643 
1644  return 0;
1645 }
1646 
1648 {
1649  // Remove cached values. Given how often this function is called and how (not that) often
1650  // the cached values are used, it should be more efficient to just discard everything
1651  // instead of trying to figure out each time exactly what to discard.
1653 
1654  // TODO: Update column's "last updated" timestamp here.
1655 
1656  assert(sal::static_int_cast<SCROW>(maCells.size()) == GetDoc().GetMaxRowCount()
1657  && "Size of the cell array is incorrect." );
1658 
1659  assert(sal::static_int_cast<SCROW>(maCellTextAttrs.size()) == GetDoc().GetMaxRowCount()
1660  && "Size of the cell text attribute array is incorrect.");
1661 
1662  assert(sal::static_int_cast<SCROW>(maBroadcasters.size()) == GetDoc().GetMaxRowCount()
1663  && "Size of the broadcaster array is incorrect.");
1664 
1665 #if DEBUG_COLUMN_STORAGE
1666  // Make sure that these two containers are synchronized wrt empty segments.
1667  auto lIsEmptyType = [](const auto& rElement) { return rElement.type == sc::element_type_empty; };
1668  // Move to the first empty blocks.
1669  auto itCell = std::find_if(maCells.begin(), maCells.end(), lIsEmptyType);
1670  auto itAttr = std::find_if(maCellTextAttrs.begin(), maCellTextAttrs.end(), lIsEmptyType);
1671 
1672  while (itCell != maCells.end())
1673  {
1674  if (itCell->position != itAttr->position || itCell->size != itAttr->size)
1675  {
1676  cout << "ScColumn::CellStorageModified: Cell array and cell text attribute array are out of sync." << endl;
1677  cout << "-- cell array" << endl;
1678  maCells.dump_blocks(cout);
1679  cout << "-- attribute array" << endl;
1680  maCellTextAttrs.dump_blocks(cout);
1681  cout.flush();
1682  abort();
1683  }
1684 
1685  // Move to the next empty blocks.
1686  ++itCell;
1687  itCell = std::find_if(itCell, maCells.end(), lIsEmptyType);
1688 
1689  ++itAttr;
1690  itAttr = std::find_if(itAttr, maCellTextAttrs.end(), lIsEmptyType);
1691  }
1692 #endif
1693 }
1694 
1695 #if DUMP_COLUMN_STORAGE
1696 
1697 namespace {
1698 
1699 #define DUMP_FORMULA_RESULTS 0
1700 
1701 struct ColumnStorageDumper
1702 {
1703  const ScDocument& mrDoc;
1704 
1705  ColumnStorageDumper( const ScDocument& rDoc ) : mrDoc(rDoc) {}
1706 
1707  void operator() (const sc::CellStoreType::value_type& rNode) const
1708  {
1709  switch (rNode.type)
1710  {
1712  cout << " * numeric block (pos=" << rNode.position << ", length=" << rNode.size << ")" << endl;
1713  break;
1715  cout << " * string block (pos=" << rNode.position << ", length=" << rNode.size << ")" << endl;
1716  break;
1718  cout << " * edit-text block (pos=" << rNode.position << ", length=" << rNode.size << ")" << endl;
1719  break;
1721  dumpFormulaBlock(rNode);
1722  break;
1724  cout << " * empty block (pos=" << rNode.position << ", length=" << rNode.size << ")" << endl;
1725  break;
1726  default:
1727  cout << " * unknown block" << endl;
1728  }
1729  }
1730 
1731  void dumpFormulaBlock(const sc::CellStoreType::value_type& rNode) const
1732  {
1733  cout << " * formula block (pos=" << rNode.position << ", length=" << rNode.size << ")" << endl;
1734  sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
1735  sc::formula_block::const_iterator itEnd = sc::formula_block::end(*rNode.data);
1736 
1737  for (; it != itEnd; ++it)
1738  {
1739  const ScFormulaCell* pCell = *it;
1740  if (!pCell->IsShared())
1741  {
1742  cout << " * row " << pCell->aPos.Row() << " not shared" << endl;
1743  printFormula(pCell);
1744  printResult(pCell);
1745  continue;
1746  }
1747 
1748  if (pCell->GetSharedTopRow() != pCell->aPos.Row())
1749  {
1750  cout << " * row " << pCell->aPos.Row() << " shared with top row "
1751  << pCell->GetSharedTopRow() << " with length " << pCell->GetSharedLength()
1752  << endl;
1753  continue;
1754  }
1755 
1756  SCROW nLen = pCell->GetSharedLength();
1757  cout << " * group: start=" << pCell->aPos.Row() << ", length=" << nLen << endl;
1758  printFormula(pCell);
1759  printResult(pCell);
1760 
1761  if (nLen > 1)
1762  {
1763  for (SCROW i = 0; i < nLen-1; ++i, ++it)
1764  {
1765  pCell = *it;
1766  printResult(pCell);
1767  }
1768  }
1769  }
1770  }
1771 
1772  void printFormula(const ScFormulaCell* pCell) const
1773  {
1774  sc::TokenStringContext aCxt(mrDoc, mrDoc.GetGrammar());
1775  OUString aFormula = pCell->GetCode()->CreateString(aCxt, pCell->aPos);
1776  cout << " * formula: " << aFormula << endl;
1777  }
1778 
1779 #if DUMP_FORMULA_RESULTS
1780  void printResult(const ScFormulaCell* pCell) const
1781  {
1782  sc::FormulaResultValue aRes = pCell->GetResult();
1783  cout << " * result: ";
1784  switch (aRes.meType)
1785  {
1787  cout << aRes.mfValue << " (type: value)";
1788  break;
1790  cout << "'" << aRes.maString.getString() << "' (type: string)";
1791  break;
1793  cout << "error (" << static_cast<int>(aRes.mnError) << ")";
1794  break;
1796  cout << "invalid";
1797  break;
1798  }
1799 
1800  cout << endl;
1801  }
1802 #else
1803  void printResult(const ScFormulaCell*) const
1804  {
1805  (void) this; /* loplugin:staticmethods */
1806  }
1807 #endif
1808 };
1809 
1810 }
1811 
1812 void ScColumn::DumpColumnStorage() const
1813 {
1814  cout << "-- table: " << nTab << "; column: " << nCol << endl;
1815  std::for_each(maCells.begin(), maCells.end(), ColumnStorageDumper(GetDoc()));
1816  cout << "--" << endl;
1817 }
1818 #endif
1819 
1820 void ScColumn::CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol) const
1821 {
1822  rDestCol.maCellTextAttrs.set_empty(nRow1, nRow2); // Empty the destination range first.
1823 
1824  sc::CellTextAttrStoreType::const_iterator itBlk = maCellTextAttrs.begin(), itBlkEnd = maCellTextAttrs.end();
1825 
1826  // Locate the top row position.
1827  size_t nBlockStart = 0, nRowPos = static_cast<size_t>(nRow1);
1828  itBlk = std::find_if(itBlk, itBlkEnd, [&nRowPos, &nBlockStart](const auto& rAttr) {
1829  return nBlockStart <= nRowPos && nRowPos < nBlockStart + rAttr.size; });
1830 
1831  if (itBlk == itBlkEnd)
1832  // Specified range not found. Bail out.
1833  return;
1834 
1835  size_t nBlockEnd;
1836  size_t nOffsetInBlock = nRowPos - nBlockStart;
1837 
1838  nRowPos = static_cast<size_t>(nRow2); // End row position.
1839 
1840  // Keep copying until we hit the end row position.
1841  sc::celltextattr_block::const_iterator itData, itDataEnd;
1842  for (; itBlk != itBlkEnd; ++itBlk, nBlockStart = nBlockEnd, nOffsetInBlock = 0)
1843  {
1844  nBlockEnd = nBlockStart + itBlk->size;
1845  if (!itBlk->data)
1846  {
1847  // Empty block.
1848  if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1849  // This block contains the end row.
1850  rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nRowPos);
1851  else
1852  rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nBlockEnd-1);
1853 
1854  continue;
1855  }
1856 
1857  // Non-empty block.
1858  itData = sc::celltextattr_block::begin(*itBlk->data);
1859  itDataEnd = sc::celltextattr_block::end(*itBlk->data);
1860  std::advance(itData, nOffsetInBlock);
1861 
1862  if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1863  {
1864  // This block contains the end row. Only copy partially.
1865  size_t nOffset = nRowPos - nBlockStart + 1;
1866  itDataEnd = sc::celltextattr_block::begin(*itBlk->data);
1867  std::advance(itDataEnd, nOffset);
1868 
1869  rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
1870  break;
1871  }
1872 
1873  rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
1874  }
1875 }
1876 
1877 namespace {
1878 
1879 class CopyCellNotesHandler
1880 {
1881  ScColumn& mrDestCol;
1882  sc::CellNoteStoreType& mrDestNotes;
1883  sc::CellNoteStoreType::iterator miPos;
1884  SCTAB mnSrcTab;
1885  SCCOL mnSrcCol;
1886  SCTAB mnDestTab;
1887  SCCOL mnDestCol;
1888  SCROW mnDestOffset;
1889  bool mbCloneCaption;
1890 
1891 public:
1892  CopyCellNotesHandler( const ScColumn& rSrcCol, ScColumn& rDestCol, SCROW nDestOffset, bool bCloneCaption ) :
1893  mrDestCol(rDestCol),
1894  mrDestNotes(rDestCol.GetCellNoteStore()),
1895  miPos(mrDestNotes.begin()),
1896  mnSrcTab(rSrcCol.GetTab()),
1897  mnSrcCol(rSrcCol.GetCol()),
1898  mnDestTab(rDestCol.GetTab()),
1899  mnDestCol(rDestCol.GetCol()),
1900  mnDestOffset(nDestOffset),
1901  mbCloneCaption(bCloneCaption) {}
1902 
1903  void operator() ( size_t nRow, const ScPostIt* p )
1904  {
1905  SCROW nDestRow = nRow + mnDestOffset;
1906  ScAddress aSrcPos(mnSrcCol, nRow, mnSrcTab);
1907  ScAddress aDestPos(mnDestCol, nDestRow, mnDestTab);
1908  ScPostIt* pNew = p->Clone(aSrcPos, mrDestCol.GetDoc(), aDestPos, mbCloneCaption).release();
1909  miPos = mrDestNotes.set(miPos, nDestRow, pNew);
1910  // Notify our LOK clients also
1912  }
1913 };
1914 
1915 }
1916 
1918  SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, bool bCloneCaption, SCROW nRowOffsetDest ) const
1919 {
1920  if (IsNotesEmptyBlock(nRow1, nRow2))
1921  // The column has no cell notes to copy between specified rows.
1922  return;
1923 
1924  ScDrawLayer *pDrawLayer = rDestCol.GetDoc().GetDrawLayer();
1925  bool bWasLocked = bool();
1926  if (pDrawLayer)
1927  {
1928  // Avoid O(n^2) by temporary locking SdrModel which disables broadcasting.
1929  // Each cell note adds undo listener, and all of them would be woken up in ScPostIt::CreateCaption.
1930  bWasLocked = pDrawLayer->isLocked();
1931  pDrawLayer->setLock(true);
1932  }
1933  CopyCellNotesHandler aFunc(*this, rDestCol, nRowOffsetDest, bCloneCaption);
1934  sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
1935  if (pDrawLayer)
1936  pDrawLayer->setLock(bWasLocked);
1937 }
1938 
1939 void ScColumn::DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol, sc::ColumnBlockPosition& maDestBlockPos,
1940  bool bCloneCaption, SCROW nRowOffsetDest ) const
1941 {
1942  CopyCellNotesToDocument(nStartRow, nStartRow + nDataSize -1, rDestCol, bCloneCaption, nRowOffsetDest);
1943  maDestBlockPos.miCellNotePos = rDestCol.maCellNotes.begin();
1944 }
1945 
1947 {
1948  return maBroadcasters.get<SvtBroadcaster*>(nRow);
1949 }
1950 
1952 {
1953  return maBroadcasters.get<SvtBroadcaster*>(nRow);
1954 }
1955 
1957 {
1958  rBlockPos.miBroadcasterPos =
1959  maBroadcasters.set_empty(rBlockPos.miBroadcasterPos, nRow1, nRow2);
1960 }
1961 
1963 {
1964  for (auto& rBroadcaster : maBroadcasters)
1965  {
1966  if (rBroadcaster.type == sc::element_type_broadcaster)
1967  {
1968  sc::broadcaster_block::iterator it = sc::broadcaster_block::begin(*rBroadcaster.data);
1969  sc::broadcaster_block::iterator itEnd = sc::broadcaster_block::end(*rBroadcaster.data);
1970  for (; it != itEnd; ++it)
1971  (*it)->PrepareForDestruction();
1972  }
1973  }
1974 }
1975 
1976 namespace
1977 {
1978 struct BroadcasterNoListenersPredicate
1979 {
1980  bool operator()( size_t, const SvtBroadcaster* broadcaster )
1981  {
1982  return !broadcaster->HasListeners();
1983  }
1984 };
1985 
1986 }
1987 
1989 {
1991  return;
1992  // Clean up after ScDocument::EnableDelayDeletingBroadcasters().
1993  BroadcasterNoListenersPredicate predicate;
1994  sc::SetElementsToEmpty1<sc::broadcaster_block>( maBroadcasters, predicate );
1996 }
1997 
1998 // Sparklines
1999 
2000 namespace
2001 {
2002 
2003 class DeletingSparklinesHandler
2004 {
2005  ScDocument& m_rDocument;
2006  SCTAB m_nTab;
2007 
2008 public:
2009  DeletingSparklinesHandler(ScDocument& rDocument, SCTAB nTab)
2010  : m_rDocument(rDocument)
2011  , m_nTab(nTab)
2012  {}
2013 
2014  void operator() (size_t /*nRow*/, const sc::SparklineCell* pCell)
2015  {
2016  auto* pList = m_rDocument.GetSparklineList(m_nTab);
2017  pList->removeSparkline(pCell->getSparkline());
2018  }
2019 };
2020 
2021 } // end anonymous ns
2022 
2024 {
2025  return maSparklines.get<sc::SparklineCell*>(nRow);
2026 }
2027 
2028 void ScColumn::CreateSparklineCell(SCROW nRow, std::shared_ptr<sc::Sparkline> const& pSparkline)
2029 {
2030  auto* pList = GetDoc().GetSparklineList(GetTab());
2031  pList->addSparkline(pSparkline);
2032  maSparklines.set(nRow, new sc::SparklineCell(pSparkline));
2033 }
2034 
2036 {
2037  DeletingSparklinesHandler aFunction(GetDoc(), nTab);
2038  sc::ParseSparkline(maSparklines.begin(), maSparklines, nRow1, nRow2, aFunction);
2039 
2040  rBlockPos.miSparklinePos = maSparklines.set_empty(rBlockPos.miSparklinePos, nRow1, nRow2);
2041 }
2042 
2044 {
2045  if (!GetDoc().ValidRow(nRow))
2046  return false;
2047 
2048  DeletingSparklinesHandler aFunction(GetDoc(), nTab);
2049  sc::ParseSparkline(maSparklines.begin(), maSparklines, nRow, nRow, aFunction);
2050 
2051  maSparklines.set_empty(nRow, nRow);
2052  return true;
2053 }
2054 
2055 bool ScColumn::IsSparklinesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
2056 {
2057  std::pair<sc::SparklineStoreType::const_iterator,size_t> aPos = maSparklines.position(nStartRow);
2058  sc::SparklineStoreType::const_iterator it = aPos.first;
2059  if (it == maSparklines.end())
2060  return false;
2061 
2062  if (it->type != sc::element_type_empty)
2063  return false;
2064 
2065  // start position of next block which is not empty.
2066  SCROW nNextRow = nStartRow + it->size - aPos.second;
2067  return nEndRow < nNextRow;
2068 }
2069 
2070 namespace
2071 {
2072 
2073 class CopySparklinesHandler
2074 {
2075  ScColumn& mrDestColumn;
2076  sc::SparklineStoreType& mrDestSparkline;
2077  sc::SparklineStoreType::iterator miDestPosition;
2078  SCROW mnDestOffset;
2079 
2080 public:
2081  CopySparklinesHandler(ScColumn& rDestColumn, SCROW nDestOffset)
2082  : mrDestColumn(rDestColumn)
2083  , mrDestSparkline(mrDestColumn.GetSparklineStore())
2084  , miDestPosition(mrDestSparkline.begin())
2085  , mnDestOffset(nDestOffset)
2086  {}
2087 
2088  void operator() (size_t nRow, const sc::SparklineCell* pCell)
2089  {
2090  SCROW nDestRow = nRow + mnDestOffset;
2091 
2092  auto const& pSparkline = pCell->getSparkline();
2093  auto const& pGroup = pCell->getSparklineGroup();
2094 
2095  auto& rDestDoc = mrDestColumn.GetDoc();
2096  auto pDestinationGroup = rDestDoc.SearchSparklineGroup(pGroup->getID());
2097  if (!pDestinationGroup)
2098  pDestinationGroup = std::make_shared<sc::SparklineGroup>(*pGroup); // Copy the group
2099  auto pNewSparkline = std::make_shared<sc::Sparkline>(mrDestColumn.GetCol(), nDestRow, pDestinationGroup);
2100  pNewSparkline->setInputRange(pSparkline->getInputRange());
2101 
2102  auto* pList = rDestDoc.GetSparklineList(mrDestColumn.GetTab());
2103  pList->addSparkline(pNewSparkline);
2104 
2105  miDestPosition = mrDestSparkline.set(miDestPosition, nDestRow, new sc::SparklineCell(pNewSparkline));
2106  }
2107 };
2108 
2109 }
2110 
2111 void ScColumn::CopyCellSparklinesToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, SCROW nRowOffsetDest) const
2112 {
2113  if (IsSparklinesEmptyBlock(nRow1, nRow2))
2114  // The column has no cell sparklines to copy between specified rows.
2115  return;
2116 
2117  CopySparklinesHandler aFunctor(rDestCol, nRowOffsetDest);
2118  sc::ParseSparkline(maSparklines.begin(), maSparklines, nRow1, nRow2, aFunctor);
2119 }
2120 
2121 void ScColumn::DuplicateSparklines(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol,
2122  sc::ColumnBlockPosition& rDestBlockPos, SCROW nRowOffsetDest) const
2123 {
2124  CopyCellSparklinesToDocument(nStartRow, nStartRow + nDataSize - 1, rDestCol, nRowOffsetDest);
2125  rDestBlockPos.miSparklinePos = rDestCol.maSparklines.begin();
2126 }
2127 
2129 {
2130  if (maSparklines.block_size() == 1 && maSparklines.begin()->type == sc::element_type_empty)
2131  return false; // all elements are empty
2132  return true; // otherwise some must be sparklines
2133 }
2134 
2136 {
2137  SCROW maxRow = 0;
2138  for (const auto& rSparkline : maSparklines)
2139  {
2140  if (rSparkline.type == sc::element_type_sparkline)
2141  maxRow = rSparkline.position + rSparkline.size - 1;
2142  }
2143  return maxRow;
2144 }
2145 
2147 {
2148  SCROW minRow = 0;
2149  sc::SparklineStoreType::const_iterator it = std::find_if(maSparklines.begin(), maSparklines.end(),
2150  [](const auto& rSparkline)
2151  {
2152  return rSparkline.type == sc::element_type_sparkline;
2153  });
2154  if (it != maSparklines.end())
2155  minRow = it->position;
2156  return minRow;
2157 }
2158 
2159 // Notes
2160 
2162 {
2163  return maCellNotes.get<ScPostIt*>(nRow);
2164 }
2165 
2167 {
2168  return maCellNotes.get<ScPostIt*>(nRow);
2169 }
2170 
2172 {
2173  sc::CellNoteStoreType::const_position_type aPos = maCellNotes.position(rBlockPos.miCellNotePos, nRow);
2174  rBlockPos.miCellNotePos = aPos.first;
2175 
2176  if (aPos.first->type != sc::element_type_cellnote)
2177  return nullptr;
2178 
2179  return sc::cellnote_block::at(*aPos.first->data, aPos.second);
2180 }
2181 
2183 {
2184  return const_cast<ScPostIt*>(const_cast<const ScColumn*>(this)->GetCellNote( rBlockPos, nRow ));
2185 }
2186 
2187 void ScColumn::SetCellNote(SCROW nRow, std::unique_ptr<ScPostIt> pNote)
2188 {
2189  //pNote->UpdateCaptionPos(ScAddress(nCol, nRow, nTab)); // TODO notes useful ? slow import with many notes
2190  maCellNotes.set(nRow, pNote.release());
2191 }
2192 
2193 namespace {
2194  class CellNoteHandler
2195  {
2196  const ScDocument* m_pDocument;
2197  const ScAddress m_aAddress; // 'incomplete' address consisting of tab, column
2198  const bool m_bForgetCaptionOwnership;
2199 
2200  public:
2201  CellNoteHandler(const ScDocument* pDocument, const ScAddress& rPos, bool bForgetCaptionOwnership) :
2202  m_pDocument(pDocument),
2203  m_aAddress(rPos),
2204  m_bForgetCaptionOwnership(bForgetCaptionOwnership) {}
2205 
2206  void operator() ( size_t nRow, ScPostIt* p )
2207  {
2208  if (m_bForgetCaptionOwnership)
2209  p->ForgetCaption();
2210 
2211  // Create a 'complete' address object
2212  ScAddress aAddr(m_aAddress);
2213  aAddr.SetRow(nRow);
2214  // Notify our LOK clients
2216  }
2217  };
2218 } // anonymous namespace
2219 
2220 void ScColumn::CellNotesDeleting(SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
2221 {
2222  ScAddress aAddr(nCol, 0, nTab);
2223  CellNoteHandler aFunc(&GetDoc(), aAddr, bForgetCaptionOwnership);
2224  sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
2225 }
2226 
2227 void ScColumn::DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership )
2228 {
2229  CellNotesDeleting(nRow1, nRow2, bForgetCaptionOwnership);
2230 
2231  rBlockPos.miCellNotePos =
2232  maCellNotes.set_empty(rBlockPos.miCellNotePos, nRow1, nRow2);
2233 }
2234 
2236 {
2237  if (maCellNotes.block_size() == 1 && maCellNotes.begin()->type == sc::element_type_empty)
2238  return false; // all elements are empty
2239  return true; // otherwise some must be notes
2240 }
2241 
2243 {
2244  // hypothesis : the column has cell notes (should be checked before)
2245  SCROW maxRow = 0;
2246  for (const auto& rCellNote : maCellNotes)
2247  {
2248  if (rCellNote.type == sc::element_type_cellnote)
2249  maxRow = rCellNote.position + rCellNote.size -1;
2250  }
2251  return maxRow;
2252 }
2254 {
2255  // hypothesis : the column has cell notes (should be checked before)
2256  SCROW minRow = 0;
2257  sc::CellNoteStoreType::const_iterator it = std::find_if(maCellNotes.begin(), maCellNotes.end(),
2258  [](const auto& rCellNote) { return rCellNote.type == sc::element_type_cellnote; });
2259  if (it != maCellNotes.end())
2260  minRow = it->position;
2261  return minRow;
2262 }
2263 
2264 sal_uInt16 ScColumn::GetTextWidth(SCROW nRow) const
2265 {
2266  return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnTextWidth;
2267 }
2268 
2269 void ScColumn::SetTextWidth(SCROW nRow, sal_uInt16 nWidth)
2270 {
2271  sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
2272  if (aPos.first->type != sc::element_type_celltextattr)
2273  return;
2274 
2275  // Set new value only when the slot is not empty.
2276  sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnTextWidth = nWidth;
2278 }
2279 
2281 {
2282  if (!GetDoc().ValidRow(nRow) || maCellTextAttrs.is_empty(nRow))
2283  return SvtScriptType::NONE;
2284 
2285  return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnScriptType;
2286 }
2287 
2289  sc::CellTextAttrStoreType::iterator& itPos, SCROW nRow1, SCROW nRow2, const sc::CellStoreType::iterator& itrCells_ )
2290 {
2291  if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
2292  return SvtScriptType::NONE;
2293 
2294  SCROW nRow = nRow1;
2295  std::pair<sc::CellTextAttrStoreType::iterator,size_t> aRet =
2296  maCellTextAttrs.position(itPos, nRow1);
2297 
2298  itPos = aRet.first; // Track the position of cell text attribute array.
2299  sc::CellStoreType::iterator itrCells = itrCells_;
2300 
2301  SvtScriptType nScriptType = SvtScriptType::NONE;
2302  bool bUpdated = false;
2303  if (itPos->type == sc::element_type_celltextattr)
2304  {
2305  sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
2306  sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
2307  std::advance(it, aRet.second);
2308  for (; it != itEnd; ++it, ++nRow)
2309  {
2310  if (nRow > nRow2)
2311  return nScriptType;
2312 
2313  sc::CellTextAttr& rVal = *it;
2314  if (UpdateScriptType(rVal, nRow, itrCells))
2315  bUpdated = true;
2316  nScriptType |= rVal.mnScriptType;
2317  }
2318  }
2319  else
2320  {
2321  // Skip this whole block.
2322  nRow += itPos->size - aRet.second;
2323  }
2324 
2325  while (nRow <= nRow2)
2326  {
2327  ++itPos;
2328  if (itPos == maCellTextAttrs.end())
2329  return nScriptType;
2330 
2331  if (itPos->type != sc::element_type_celltextattr)
2332  {
2333  // Skip this whole block.
2334  nRow += itPos->size;
2335  continue;
2336  }
2337 
2338  sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
2339  sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
2340  for (; it != itEnd; ++it, ++nRow)
2341  {
2342  if (nRow > nRow2)
2343  return nScriptType;
2344 
2345  sc::CellTextAttr& rVal = *it;
2346  if (UpdateScriptType(rVal, nRow, itrCells))
2347  bUpdated = true;
2348 
2349  nScriptType |= rVal.mnScriptType;
2350  }
2351  }
2352 
2353  if (bUpdated)
2355 
2356  return nScriptType;
2357 }
2358 
2360 {
2361  if (!GetDoc().ValidRow(nRow))
2362  return;
2363 
2364  sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
2365  if (aPos.first->type != sc::element_type_celltextattr)
2366  // Set new value only when the slot is already set.
2367  return;
2368 
2369  sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnScriptType = nType;
2371 }
2372 
2374 {
2375  std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2376  sc::CellStoreType::iterator it = aPos.first;
2377  if (it == maCells.end())
2378  // Invalid row. Return a null token.
2379  return formula::FormulaTokenRef();
2380 
2381  switch (it->type)
2382  {
2384  {
2385  double fVal = sc::numeric_block::at(*it->data, aPos.second);
2387  }
2389  {
2390  ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
2391  if (p->IsValue())
2393 
2395  }
2397  {
2398  const svl::SharedString& rSS = sc::string_block::at(*it->data, aPos.second);
2400  }
2402  {
2403  const EditTextObject* pText = sc::edittext_block::at(*it->data, aPos.second);
2404  OUString aStr = ScEditUtil::GetString(*pText, &GetDoc());
2405  svl::SharedString aSS( GetDoc().GetSharedStringPool().intern(aStr));
2407  }
2409  default:
2410  // Return a value of 0.0 in all the other cases.
2412  }
2413 }
2414 
2415 namespace {
2416 
2417 class ToMatrixHandler
2418 {
2419  ScMatrix& mrMat;
2420  SCCOL mnMatCol;
2421  SCROW mnTopRow;
2422  ScDocument* mpDoc;
2423  svl::SharedStringPool& mrStrPool;
2424 public:
2425  ToMatrixHandler(ScMatrix& rMat, SCCOL nMatCol, SCROW nTopRow, ScDocument* pDoc) :
2426  mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow),
2427  mpDoc(pDoc), mrStrPool(pDoc->GetSharedStringPool()) {}
2428 
2429  void operator() (size_t nRow, double fVal)
2430  {
2431  mrMat.PutDouble(fVal, mnMatCol, nRow - mnTopRow);
2432  }
2433 
2434  void operator() (size_t nRow, const ScFormulaCell* p)
2435  {
2436  // Formula cell may need to re-calculate.
2437  ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*p);
2438  if (rCell.IsValue())
2439  mrMat.PutDouble(rCell.GetValue(), mnMatCol, nRow - mnTopRow);
2440  else
2441  mrMat.PutString(rCell.GetString(), mnMatCol, nRow - mnTopRow);
2442  }
2443 
2444  void operator() (size_t nRow, const svl::SharedString& rSS)
2445  {
2446  mrMat.PutString(rSS, mnMatCol, nRow - mnTopRow);
2447  }
2448 
2449  void operator() (size_t nRow, const EditTextObject* pStr)
2450  {
2451  mrMat.PutString(mrStrPool.intern(ScEditUtil::GetString(*pStr, mpDoc)), mnMatCol, nRow - mnTopRow);
2452  }
2453 };
2454 
2455 }
2456 
2457 bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
2458 {
2459  if (nRow1 > nRow2)
2460  return false;
2461 
2462  ToMatrixHandler aFunc(rMat, nMatCol, nRow1, &GetDoc());
2463  sc::ParseAllNonEmpty(maCells.begin(), maCells, nRow1, nRow2, aFunc);
2464  return true;
2465 }
2466 
2467 namespace {
2468 
2469 struct CellBucket
2470 {
2471  SCSIZE mnEmpValStart;
2472  SCSIZE mnNumValStart;
2473  SCSIZE mnStrValStart;
2474  SCSIZE mnEmpValCount;
2475  std::vector<double> maNumVals;
2476  std::vector<svl::SharedString> maStrVals;
2477 
2478  CellBucket() : mnEmpValStart(0), mnNumValStart(0), mnStrValStart(0), mnEmpValCount(0) {}
2479 
2480  void flush(ScMatrix& rMat, SCSIZE nCol)
2481  {
2482  if (mnEmpValCount)
2483  {
2484  rMat.PutEmptyResultVector(mnEmpValCount, nCol, mnEmpValStart);
2485  reset();
2486  }
2487  else if (!maNumVals.empty())
2488  {
2489  const double* p = maNumVals.data();
2490  rMat.PutDouble(p, maNumVals.size(), nCol, mnNumValStart);
2491  reset();
2492  }
2493  else if (!maStrVals.empty())
2494  {
2495  const svl::SharedString* p = maStrVals.data();
2496  rMat.PutString(p, maStrVals.size(), nCol, mnStrValStart);
2497  reset();
2498  }
2499  }
2500 
2501  void reset()
2502  {
2503  mnEmpValStart = mnNumValStart = mnStrValStart = 0;
2504  mnEmpValCount = 0;
2505  maNumVals.clear();
2506  maStrVals.clear();
2507  }
2508 };
2509 
2510 class FillMatrixHandler
2511 {
2512  ScMatrix& mrMat;
2513  size_t mnMatCol;
2514  size_t mnTopRow;
2515 
2516  ScDocument* mpDoc;
2517  svl::SharedStringPool& mrPool;
2518  svl::SharedStringPool* mpPool; // if matrix is not in the same document
2519 
2520 public:
2521  FillMatrixHandler(ScMatrix& rMat, size_t nMatCol, size_t nTopRow, ScDocument* pDoc, svl::SharedStringPool* pPool) :
2522  mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow),
2523  mpDoc(pDoc), mrPool(pDoc->GetSharedStringPool()), mpPool(pPool) {}
2524 
2525  void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2526  {
2527  size_t nMatRow = node.position + nOffset - mnTopRow;
2528 
2529  switch (node.type)
2530  {
2532  {
2533  const double* p = &sc::numeric_block::at(*node.data, nOffset);
2534  mrMat.PutDouble(p, nDataSize, mnMatCol, nMatRow);
2535  }
2536  break;
2538  {
2539  if (!mpPool)
2540  {
2541  const svl::SharedString* p = &sc::string_block::at(*node.data, nOffset);
2542  mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
2543  }
2544  else
2545  {
2546  std::vector<svl::SharedString> aStrings;
2547  aStrings.reserve(nDataSize);
2548  const svl::SharedString* p = &sc::string_block::at(*node.data, nOffset);
2549  for (size_t i = 0; i < nDataSize; ++i)
2550  {
2551  aStrings.push_back(mpPool->intern(p[i].getString()));
2552  }
2553  mrMat.PutString(aStrings.data(), aStrings.size(), mnMatCol, nMatRow);
2554  }
2555  }
2556  break;
2558  {
2559  std::vector<svl::SharedString> aSSs;
2560  aSSs.reserve(nDataSize);
2561  sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
2562  std::advance(it, nOffset);
2563  sc::edittext_block::const_iterator itEnd = it;
2564  std::advance(itEnd, nDataSize);
2565  for (; it != itEnd; ++it)
2566  {
2567  OUString aStr = ScEditUtil::GetString(**it, mpDoc);
2568  if (!mpPool)
2569  aSSs.push_back(mrPool.intern(aStr));
2570  else
2571  aSSs.push_back(mpPool->intern(aStr));
2572  }
2573 
2574  const svl::SharedString* p = aSSs.data();
2575  mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
2576  }
2577  break;
2579  {
2580  CellBucket aBucket;
2581  sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
2582  std::advance(it, nOffset);
2583  sc::formula_block::const_iterator itEnd = it;
2584  std::advance(itEnd, nDataSize);
2585 
2586  size_t nPrevRow = 0, nThisRow = node.position + nOffset;
2587  for (; it != itEnd; ++it, nPrevRow = nThisRow, ++nThisRow)
2588  {
2589  ScFormulaCell& rCell = **it;
2590 
2591  if (rCell.IsEmpty())
2592  {
2593  if (aBucket.mnEmpValCount && nThisRow == nPrevRow + 1)
2594  {
2595  // Secondary empty results.
2596  ++aBucket.mnEmpValCount;
2597  }
2598  else
2599  {
2600  // First empty result.
2601  aBucket.flush(mrMat, mnMatCol);
2602  aBucket.mnEmpValStart = nThisRow - mnTopRow;
2603  ++aBucket.mnEmpValCount;
2604  }
2605  continue;
2606  }
2607 
2608  FormulaError nErr;
2609  double fVal;
2610  if (rCell.GetErrorOrValue(nErr, fVal))
2611  {
2612  if (nErr != FormulaError::NONE)
2613  fVal = CreateDoubleError(nErr);
2614 
2615  if (!aBucket.maNumVals.empty() && nThisRow == nPrevRow + 1)
2616  {
2617  // Secondary numbers.
2618  aBucket.maNumVals.push_back(fVal);
2619  }
2620  else
2621  {
2622  // First number.
2623  aBucket.flush(mrMat, mnMatCol);
2624  aBucket.mnNumValStart = nThisRow - mnTopRow;
2625  aBucket.maNumVals.push_back(fVal);
2626  }
2627  continue;
2628  }
2629 
2630  svl::SharedString aStr = rCell.GetString();
2631  if (mpPool)
2632  aStr = mpPool->intern(aStr.getString());
2633  if (!aBucket.maStrVals.empty() && nThisRow == nPrevRow + 1)
2634  {
2635  // Secondary strings.
2636  aBucket.maStrVals.push_back(aStr);
2637  }
2638  else
2639  {
2640  // First string.
2641  aBucket.flush(mrMat, mnMatCol);
2642  aBucket.mnStrValStart = nThisRow - mnTopRow;
2643  aBucket.maStrVals.push_back(aStr);
2644  }
2645  }
2646 
2647  aBucket.flush(mrMat, mnMatCol);
2648  }
2649  break;
2650  default:
2651  ;
2652  }
2653  }
2654 };
2655 
2656 }
2657 
2658 void ScColumn::FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2, svl::SharedStringPool* pPool ) const
2659 {
2660  FillMatrixHandler aFunc(rMat, nMatCol, nRow1, &GetDoc(), pPool);
2661  sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
2662 }
2663 
2664 namespace {
2665 
2666 template<typename Blk>
2667 void getBlockIterators(
2668  const sc::CellStoreType::iterator& it, size_t& rLenRemain,
2669  typename Blk::iterator& rData, typename Blk::iterator& rDataEnd )
2670 {
2671  rData = Blk::begin(*it->data);
2672  if (rLenRemain >= it->size)
2673  {
2674  // Block is shorter than the remaining requested length.
2675  rDataEnd = Blk::end(*it->data);
2676  rLenRemain -= it->size;
2677  }
2678  else
2679  {
2680  rDataEnd = rData;
2681  std::advance(rDataEnd, rLenRemain);
2682  rLenRemain = 0;
2683  }
2684 }
2685 
2686 bool appendToBlock(
2688  size_t nPos, size_t nArrayLen, const sc::CellStoreType::iterator& _it, const sc::CellStoreType::iterator& itEnd )
2689 {
2690  svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
2691  size_t nLenRemain = nArrayLen - nPos;
2692 
2693  for (sc::CellStoreType::iterator it = _it; it != itEnd; ++it)
2694  {
2695  switch (it->type)
2696  {
2698  {
2699  sc::string_block::iterator itData, itDataEnd;
2700  getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
2701  rCxt.ensureStrArray(rColArray, nArrayLen);
2702 
2703  for (; itData != itDataEnd; ++itData, ++nPos)
2704  (*rColArray.mpStrArray)[nPos] = itData->getData();
2705  }
2706  break;
2708  {
2709  sc::edittext_block::iterator itData, itDataEnd;
2710  getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd);
2711  rCxt.ensureStrArray(rColArray, nArrayLen);
2712 
2713  for (; itData != itDataEnd; ++itData, ++nPos)
2714  {
2715  OUString aStr = ScEditUtil::GetString(**itData, pDoc);
2716  (*rColArray.mpStrArray)[nPos] = rPool.intern(aStr).getData();
2717  }
2718  }
2719  break;
2721  {
2722  sc::formula_block::iterator itData, itDataEnd;
2723  getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd);
2724 
2725  /* tdf#91416 setting progress in triggers a resize of the window
2726  and so ScTabView::DoResize and an InterpretVisible and
2727  InterpretDirtyCells which resets the mpFormulaGroupCxt that
2728  the current rCxt points to, which is bad, so disable progress
2729  during GetResult
2730  */
2732  bool bTempDisableProgress = pProgress && pProgress->Enabled();
2733  if (bTempDisableProgress)
2734  pProgress->Disable();
2735 
2736  for (; itData != itDataEnd; ++itData, ++nPos)
2737  {
2738  ScFormulaCell& rFC = **itData;
2739 
2740  sc::FormulaResultValue aRes = rFC.GetResult();
2741 
2742  if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError != FormulaError::NONE)
2743  {
2744  if (aRes.mnError == FormulaError::CircularReference)
2745  {
2746  // This cell needs to be recalculated on next visit.
2747  rFC.SetErrCode(FormulaError::NONE);
2748  rFC.SetDirtyVar();
2749  }
2750  return false;
2751  }
2752 
2754  {
2755  rCxt.ensureStrArray(rColArray, nArrayLen);
2756  (*rColArray.mpStrArray)[nPos] = aRes.maString.getData();
2757  }
2758  else
2759  {
2760  rCxt.ensureNumArray(rColArray, nArrayLen);
2761  (*rColArray.mpNumArray)[nPos] = aRes.mfValue;
2762  }
2763  }
2764 
2765  if (bTempDisableProgress)
2766  pProgress->Enable();
2767  }
2768  break;
2770  {
2771  if (nLenRemain > it->size)
2772  {
2773  nPos += it->size;
2774  nLenRemain -= it->size;
2775  }
2776  else
2777  {
2778  nPos = nArrayLen;
2779  nLenRemain = 0;
2780  }
2781  }
2782  break;
2784  {
2785  sc::numeric_block::iterator itData, itDataEnd;
2786  getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
2787  rCxt.ensureNumArray(rColArray, nArrayLen);
2788 
2789  for (; itData != itDataEnd; ++itData, ++nPos)
2790  (*rColArray.mpNumArray)[nPos] = *itData;
2791  }
2792  break;
2793  default:
2794  return false;
2795  }
2796 
2797  if (!nLenRemain)
2798  return true;
2799  }
2800 
2801  return false;
2802 }
2803 
2804 void copyFirstStringBlock(
2805  ScDocument& rDoc, sc::FormulaGroupContext::StrArrayType& rArray, size_t nLen, const sc::CellStoreType::iterator& itBlk )
2806 {
2807  sc::FormulaGroupContext::StrArrayType::iterator itArray = rArray.begin();
2808 
2809  switch (itBlk->type)
2810  {
2812  {
2813  sc::string_block::iterator it = sc::string_block::begin(*itBlk->data);
2814  sc::string_block::iterator itEnd = it;
2815  std::advance(itEnd, nLen);
2816  for (; it != itEnd; ++it, ++itArray)
2817  *itArray = it->getData();
2818  }
2819  break;
2821  {
2822  sc::edittext_block::iterator it = sc::edittext_block::begin(*itBlk->data);
2823  sc::edittext_block::iterator itEnd = it;
2824  std::advance(itEnd, nLen);
2825 
2827  for (; it != itEnd; ++it, ++itArray)
2828  {
2829  EditTextObject* pText = *it;
2830  OUString aStr = ScEditUtil::GetString(*pText, &rDoc);
2831  *itArray = rPool.intern(aStr).getData();
2832  }
2833  }
2834  break;
2835  default:
2836  ;
2837  }
2838 }
2839 
2841 copyFirstFormulaBlock(
2842  sc::FormulaGroupContext& rCxt, const sc::CellStoreType::iterator& itBlk, size_t nArrayLen,
2843  SCTAB nTab, SCCOL nCol )
2844 {
2845  size_t nLen = std::min(itBlk->size, nArrayLen);
2846 
2847  sc::formula_block::iterator it = sc::formula_block::begin(*itBlk->data);
2848  sc::formula_block::iterator itEnd;
2849 
2850  sc::FormulaGroupContext::NumArrayType* pNumArray = nullptr;
2851  sc::FormulaGroupContext::StrArrayType* pStrArray = nullptr;
2852 
2853  itEnd = it;
2854  std::advance(itEnd, nLen);
2855  size_t nPos = 0;
2856  for (; it != itEnd; ++it, ++nPos)
2857  {
2858  ScFormulaCell& rFC = **it;
2859  sc::FormulaResultValue aRes = rFC.GetResult();
2860  if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError != FormulaError::NONE)
2861  {
2862  if (aRes.mnError == FormulaError::CircularReference)
2863  {
2864  // This cell needs to be recalculated on next visit.
2865  rFC.SetErrCode(FormulaError::NONE);
2866  rFC.SetDirtyVar();
2867  }
2868  return nullptr;
2869  }
2870 
2872  {
2873  if (!pNumArray)
2874  {
2875  rCxt.m_NumArrays.push_back(
2876  std::make_unique<sc::FormulaGroupContext::NumArrayType>(nArrayLen,
2877  std::numeric_limits<double>::quiet_NaN()));
2878  pNumArray = rCxt.m_NumArrays.back().get();
2879  }
2880 
2881  (*pNumArray)[nPos] = aRes.mfValue;
2882  }
2883  else
2884  {
2885  if (!pStrArray)
2886  {
2887  rCxt.m_StrArrays.push_back(
2888  std::make_unique<sc::FormulaGroupContext::StrArrayType>(nArrayLen, nullptr));
2889  pStrArray = rCxt.m_StrArrays.back().get();
2890  }
2891 
2892  (*pStrArray)[nPos] = aRes.maString.getData();
2893  }
2894  }
2895 
2896  if (!pNumArray && !pStrArray)
2897  // At least one of these arrays should be allocated.
2898  return nullptr;
2899 
2900  return rCxt.setCachedColArray(nTab, nCol, pNumArray, pStrArray);
2901 }
2902 
2903 struct NonNullStringFinder
2904 {
2905  bool operator() (const rtl_uString* p) const { return p != nullptr; }
2906 };
2907 
2908 bool hasNonEmpty( const sc::FormulaGroupContext::StrArrayType& rArray, SCROW nRow1, SCROW nRow2 )
2909 {
2910  // The caller has to make sure the array is at least nRow2+1 long.
2911  sc::FormulaGroupContext::StrArrayType::const_iterator it = rArray.begin();
2912  std::advance(it, nRow1);
2913  sc::FormulaGroupContext::StrArrayType::const_iterator itEnd = it;
2914  std::advance(itEnd, nRow2-nRow1+1);
2915  return std::any_of(it, itEnd, NonNullStringFinder());
2916 }
2917 
2918 struct ProtectFormulaGroupContext
2919 {
2920  ProtectFormulaGroupContext( ScDocument* d )
2921  : doc( d ) { doc->BlockFormulaGroupContextDiscard( true ); }
2922  ~ProtectFormulaGroupContext()
2923  { doc->BlockFormulaGroupContextDiscard( false ); }
2924  ScDocument* doc;
2925 };
2926 
2927 }
2928 
2930 {
2931  if (nRow1 > nRow2)
2933 
2934  // See if the requested range is already cached.
2935  ScDocument& rDocument = GetDoc();
2936  sc::FormulaGroupContext& rCxt = *(rDocument.GetFormulaGroupContext());
2937  sc::FormulaGroupContext::ColArray* pColArray = rCxt.getCachedColArray(nTab, nCol, nRow2+1);
2938  if (pColArray)
2939  {
2940  const double* pNum = nullptr;
2941  if (pColArray->mpNumArray)
2942  pNum = &(*pColArray->mpNumArray)[nRow1];
2943 
2944  rtl_uString** pStr = nullptr;
2945  if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
2946  pStr = &(*pColArray->mpStrArray)[nRow1];
2947 
2948  return formula::VectorRefArray(pNum, pStr);
2949  }
2950 
2951  // ScColumn::CellStorageModified() simply discards the entire cache (FormulaGroupContext)
2952  // on any modification. However getting cell values may cause this to be called
2953  // if interpreting a cell results in a change to it (not just its result though).
2954  // So temporarily block the discarding.
2955  ProtectFormulaGroupContext protectContext(&GetDoc());
2956 
2957  // We need to fetch all cell values from row 0 to nRow2 for caching purposes.
2958  sc::CellStoreType::iterator itBlk = maCells.begin();
2959  switch (itBlk->type)
2960  {
2962  {
2963  if (o3tl::make_unsigned(nRow2) < itBlk->size)
2964  {
2965  // Requested range falls within the first block. No need to cache.
2966  const double* p = &sc::numeric_block::at(*itBlk->data, nRow1);
2967  return formula::VectorRefArray(p);
2968  }
2969 
2970  // Allocate a new array and copy the values to it.
2971  sc::numeric_block::const_iterator it = sc::numeric_block::begin(*itBlk->data);
2972  sc::numeric_block::const_iterator itEnd = sc::numeric_block::end(*itBlk->data);
2973  rCxt.m_NumArrays.push_back(
2974  std::make_unique<sc::FormulaGroupContext::NumArrayType>(it, itEnd));
2975  sc::FormulaGroupContext::NumArrayType& rArray = *rCxt.m_NumArrays.back();
2976  // allocate to the requested length.
2977  rArray.resize(nRow2+1, std::numeric_limits<double>::quiet_NaN());
2978 
2979  pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, nullptr);
2980  if (!pColArray)
2981  // Failed to insert a new cached column array.
2983 
2984  // Fill the remaining array with values from the following blocks.
2985  size_t nPos = itBlk->size;
2986  ++itBlk;
2987  if (!appendToBlock(&rDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
2988  {
2989  rCxt.discardCachedColArray(nTab, nCol);
2991  }
2992 
2993  rtl_uString** pStr = nullptr;
2994  if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
2995  pStr = &(*pColArray->mpStrArray)[nRow1];
2996 
2997  return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], pStr);
2998  }
2999  break;
3002  {
3003  rCxt.m_StrArrays.push_back(
3004  std::make_unique<sc::FormulaGroupContext::StrArrayType>(nRow2+1, nullptr));
3005  sc::FormulaGroupContext::StrArrayType& rArray = *rCxt.m_StrArrays.back();
3006  pColArray = rCxt.setCachedColArray(nTab, nCol, nullptr, &rArray);
3007  if (!pColArray)
3008  // Failed to insert a new cached column array.
3009  return formula::VectorRefArray();
3010 
3011  if (o3tl::make_unsigned(nRow2) < itBlk->size)
3012  {
3013  // Requested range falls within the first block.
3014  copyFirstStringBlock(rDocument, rArray, nRow2+1, itBlk);
3015  return formula::VectorRefArray(&rArray[nRow1]);
3016  }
3017 
3018  copyFirstStringBlock(rDocument, rArray, itBlk->size, itBlk);
3019 
3020  // Fill the remaining array with values from the following blocks.
3021  size_t nPos = itBlk->size;
3022  ++itBlk;
3023  if (!appendToBlock(&rDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
3024  {
3025  rCxt.discardCachedColArray(nTab, nCol);
3027  }
3028 
3029  assert(pColArray->mpStrArray);
3030 
3031  rtl_uString** pStr = nullptr;
3032  if (hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
3033  pStr = &(*pColArray->mpStrArray)[nRow1];
3034 
3035  if (pColArray->mpNumArray)
3036  return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], pStr);
3037  else
3038  return formula::VectorRefArray(pStr);
3039  }
3040  break;
3042  {
3043  if (o3tl::make_unsigned(nRow2) < itBlk->size)
3044  {
3045  // Requested length is within a single block, and the data is
3046  // not cached.
3047  pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
3048  if (!pColArray)
3049  // Failed to insert a new cached column array.
3051 
3052  const double* pNum = nullptr;
3053  rtl_uString** pStr = nullptr;
3054  if (pColArray->mpNumArray)
3055  pNum = &(*pColArray->mpNumArray)[nRow1];
3056  if (pColArray->mpStrArray)
3057  pStr = &(*pColArray->mpStrArray)[nRow1];
3058 
3059  return formula::VectorRefArray(pNum, pStr);
3060  }
3061 
3062  pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
3063  if (!pColArray)
3064  {
3065  // Failed to insert a new cached column array.
3067  }
3068 
3069  size_t nPos = itBlk->size;
3070  ++itBlk;
3071  if (!appendToBlock(&rDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
3072  {
3073  rCxt.discardCachedColArray(nTab, nCol);
3075  }
3076 
3077  const double* pNum = nullptr;
3078  rtl_uString** pStr = nullptr;
3079  if (pColArray->mpNumArray)
3080  pNum = &(*pColArray->mpNumArray)[nRow1];
3081  if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
3082  pStr = &(*pColArray->mpStrArray)[nRow1];
3083 
3084  return formula::VectorRefArray(pNum, pStr);
3085  }
3086  break;
3088  {
3089  // Fill the whole length with NaN's.
3090  rCxt.m_NumArrays.push_back(
3091  std::make_unique<sc::FormulaGroupContext::NumArrayType>(nRow2+1,
3092  std::numeric_limits<double>::quiet_NaN()));
3093  sc::FormulaGroupContext::NumArrayType& rArray = *rCxt.m_NumArrays.back();
3094  pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, nullptr);
3095  if (!pColArray)
3096  // Failed to insert a new cached column array.
3098 
3099  if (o3tl::make_unsigned(nRow2) < itBlk->size)
3100  return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
3101 
3102  // Fill the remaining array with values from the following blocks.
3103  size_t nPos = itBlk->size;
3104  ++itBlk;
3105  if (!appendToBlock(&rDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
3106  {
3107  rCxt.discardCachedColArray(nTab, nCol);
3109  }
3110 
3111  if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
3112  return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
3113  else
3114  return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
3115  }
3116  break;
3117  default:
3118  ;
3119  }
3120 
3122 }
3123 
3124 #ifdef DBG_UTIL
3125 static void assertNoInterpretNeededHelper( const sc::CellStoreType::value_type& node,
3126  size_t nOffset, size_t nDataSize )
3127 {
3128  switch (node.type)
3129  {
3131  {
3132  sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
3133  std::advance(it, nOffset);
3134  sc::formula_block::const_iterator itEnd = it;
3135  std::advance(itEnd, nDataSize);
3136  for (; it != itEnd; ++it)
3137  {
3138  const ScFormulaCell* pCell = *it;
3139  assert( !pCell->NeedsInterpret());
3140  }
3141  break;
3142  }
3143  }
3144 }
3146 {
3147  assert(nRow2 >= nRow1);
3149 }
3150 #endif
3151 
3152 void ScColumn::SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen )
3153 {
3154  sc::CellStoreType::position_type aPos = maCells.position(nRow);
3155  sc::CellStoreType::iterator it = aPos.first;
3156  if (it->type != sc::element_type_formula)
3157  {
3158  // This is not a formula block.
3159  assert( false );
3160  return;
3161  }
3162 
3163  size_t nBlockLen = it->size - aPos.second;
3164  if (nBlockLen < nLen)
3165  // Result array is longer than the length of formula cells. Not good.
3166  return;
3167 
3168  sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
3169  std::advance(itCell, aPos.second);
3170 
3171  const double* pResEnd = pResults + nLen;
3172  for (; pResults != pResEnd; ++pResults, ++itCell)
3173  {
3174  ScFormulaCell& rCell = **itCell;
3175  FormulaError nErr = GetDoubleErrorValue(*pResults);
3176  if (nErr != FormulaError::NONE)
3177  rCell.SetResultError(nErr);
3178  else
3179  rCell.SetResultDouble(*pResults);
3180  rCell.ResetDirty();
3181  rCell.SetChanged(true);
3182  }
3183 }
3184 
3185 void ScColumn::CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, size_t nLen, size_t nOffset,
3186  unsigned nThisThread, unsigned nThreadsTotal)
3187 {
3188  assert(GetDoc().IsThreadedGroupCalcInProgress());
3189 
3190  sc::CellStoreType::position_type aPos = maCells.position(nRow);
3191  sc::CellStoreType::iterator it = aPos.first;
3192  if (it->type != sc::element_type_formula)
3193  {
3194  // This is not a formula block.
3195  assert( false );
3196  return;
3197  }
3198 
3199  size_t nBlockLen = it->size - aPos.second;
3200  if (nBlockLen < nLen)
3201  // Length is longer than the length of formula cells. Not good.
3202  return;
3203 
3204  sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
3205  std::advance(itCell, aPos.second);
3206 
3207  for (size_t i = 0; i < nLen; ++i, ++itCell)
3208  {
3209  if (nThreadsTotal > 0 && ((i + nOffset) % nThreadsTotal) != nThisThread)
3210  continue;
3211 
3212  ScFormulaCell& rCell = **itCell;
3213  if (!rCell.NeedsInterpret())
3214  continue;
3215  // Here we don't call IncInterpretLevel() and DecInterpretLevel() as this call site is
3216  // always in a threaded calculation.
3217  rCell.InterpretTail(rContext, ScFormulaCell::SCITP_NORMAL);
3218  }
3219 }
3220 
3222 {
3223  sc::CellStoreType::position_type aPos = maCells.position(nRow);
3224  sc::CellStoreType::iterator it = aPos.first;
3225  if (it->type != sc::element_type_formula)
3226  {
3227  // This is not a formula block.
3228  assert( false );
3229  return;
3230  }
3231 
3232  size_t nBlockLen = it->size - aPos.second;
3233  if (nBlockLen < nLen)
3234  // Length is longer than the length of formula cells. Not good.
3235  return;
3236 
3237  sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
3238  std::advance(itCell, aPos.second);
3239 
3240  for (size_t i = 0; i < nLen; ++i, ++itCell)
3241  {
3242  ScFormulaCell& rCell = **itCell;
3243  rCell.HandleStuffAfterParallelCalculation(pInterpreter);
3244  }
3245 }
3246 
3247 void ScColumn::SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat )
3248 {
3249  ApplyAttr(nRow, SfxUInt32Item(ATTR_VALUE_FORMAT, nNumberFormat));
3250 }
3251 
3252 ScFormulaCell * const * ScColumn::GetFormulaCellBlockAddress( SCROW nRow, size_t& rBlockSize ) const
3253 {
3254  if (!GetDoc().ValidRow(nRow))
3255  {
3256  rBlockSize = 0;
3257  return nullptr;
3258  }
3259 
3260  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3261  sc::CellStoreType::const_iterator it = aPos.first;
3262  if (it == maCells.end())
3263  {
3264  rBlockSize = 0;
3265  return nullptr;
3266  }
3267 
3268  if (it->type != sc::element_type_formula)
3269  {
3270  // Not a formula cell.
3271  rBlockSize = 0;
3272  return nullptr;
3273  }
3274 
3275  rBlockSize = it->size;
3276  return &sc::formula_block::at(*it->data, aPos.second);
3277 }
3278 
3280 {
3281  size_t nBlockSize = 0;
3282  ScFormulaCell const * const * pp = GetFormulaCellBlockAddress( nRow, nBlockSize );
3283  return pp ? *pp : nullptr;
3284 }
3285 
3286 void ScColumn::FindDataAreaPos(SCROW& rRow, bool bDown) const
3287 {
3288  // If the cell is empty, find the next non-empty cell position. If the
3289  // cell is not empty, find the last non-empty cell position in the current
3290  // contiguous cell block.
3291 
3292  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
3293  sc::CellStoreType::const_iterator it = aPos.first;
3294  if (it == maCells.end())
3295  // Invalid row.
3296  return;
3297 
3298  if (it->type == sc::element_type_empty)
3299  {
3300  // Current cell is empty. Find the next non-empty cell.
3301  rRow = FindNextVisibleRowWithContent(it, rRow, bDown);
3302  return;
3303  }
3304 
3305  // Current cell is not empty.
3306  SCROW nNextRow = FindNextVisibleRow(rRow, bDown);
3307  aPos = maCells.position(it, nNextRow);
3308  it = aPos.first;
3309  if (it->type == sc::element_type_empty)
3310  {
3311  // Next visible cell is empty. Find the next non-empty cell.
3312  rRow = FindNextVisibleRowWithContent(it, nNextRow, bDown);
3313  return;
3314  }
3315 
3316  // Next visible cell is non-empty. Find the edge that's still visible.
3317  SCROW nLastRow = nNextRow;
3318  do
3319  {
3320  nNextRow = FindNextVisibleRow(nLastRow, bDown);
3321  if (nNextRow == nLastRow)
3322  break;
3323 
3324  aPos = maCells.position(it, nNextRow);
3325  it = aPos.first;
3326  if (it->type != sc::element_type_empty)
3327  nLastRow = nNextRow;
3328  }
3329  while (it->type != sc::element_type_empty);
3330 
3331  rRow = nLastRow;
3332 }
3333 
3334 bool ScColumn::HasDataAt(SCROW nRow, ScDataAreaExtras* pDataAreaExtras ) const
3335 {
3336  if (pDataAreaExtras)
3337  GetDataExtrasAt( nRow, *pDataAreaExtras);
3338 
3339  return maCells.get_type(nRow) != sc::element_type_empty;
3340 }
3341 
3343  ScDataAreaExtras* pDataAreaExtras ) const
3344 {
3345  if (pDataAreaExtras)
3346  GetDataExtrasAt( nRow, *pDataAreaExtras);
3347 
3348  std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
3349  if (aPos.first == maCells.end())
3350  return false;
3351  rBlockPos.miCellPos = aPos.first; // Store this for next call.
3352  return aPos.first->type != sc::element_type_empty;
3353 }
3354 
3356  ScDataAreaExtras* pDataAreaExtras )
3357 {
3358  if (pDataAreaExtras)
3359  GetDataExtrasAt( nRow, *pDataAreaExtras);
3360 
3361  std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
3362  if (aPos.first == maCells.end())
3363  return false;
3364  rBlockPos.miCellPos = aPos.first; // Store this for next call.
3365  return aPos.first->type != sc::element_type_empty;
3366 }
3367 
3368 void ScColumn::GetDataExtrasAt( SCROW nRow, ScDataAreaExtras& rDataAreaExtras ) const
3369 {
3370  if (rDataAreaExtras.mnStartRow <= nRow && nRow <= rDataAreaExtras.mnEndRow)
3371  return;
3372 
3373  // Check in order of likeliness.
3374  if ( (rDataAreaExtras.mbCellFormats && HasVisibleAttrIn(nRow, nRow)) ||
3375  (rDataAreaExtras.mbCellNotes && !IsNotesEmptyBlock(nRow, nRow)) ||
3376  (rDataAreaExtras.mbCellDrawObjects && !IsDrawObjectsEmptyBlock(nRow, nRow)))
3377  {
3378  if (rDataAreaExtras.mnStartRow > nRow)
3379  rDataAreaExtras.mnStartRow = nRow;
3380  if (rDataAreaExtras.mnEndRow < nRow)
3381  rDataAreaExtras.mnEndRow = nRow;
3382  }
3383 }
3384 
3385 namespace {
3386 
3387 class FindUsedRowsHandler
3388 {
3389  typedef mdds::flat_segment_tree<SCROW,bool> UsedRowsType;
3390  UsedRowsType& mrUsed;
3391  UsedRowsType::const_iterator miUsed;
3392 public:
3393  explicit FindUsedRowsHandler(UsedRowsType& rUsed) : mrUsed(rUsed), miUsed(rUsed.begin()) {}
3394 
3395  void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
3396  {
3397  if (node.type == sc::element_type_empty)
3398  return;
3399 
3400  SCROW nRow1 = node.position + nOffset;
3401  SCROW nRow2 = nRow1 + nDataSize - 1;
3402  miUsed = mrUsed.insert(miUsed, nRow1, nRow2+1, true).first;
3403  }
3404 };
3405 
3406 }
3407 
3408 void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, mdds::flat_segment_tree<SCROW,bool>& rUsed ) const
3409 {
3410  FindUsedRowsHandler aFunc(rUsed);
3411  sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
3412 }
3413 
3414 namespace {
3415 
3416 void startListening(
3417  sc::BroadcasterStoreType& rStore, sc::BroadcasterStoreType::iterator& itBlockPos, size_t nElemPos,
3418  SCROW nRow, SvtListener& rLst)
3419 {
3420  switch (itBlockPos->type)
3421  {
3423  {
3424  // Broadcaster already exists here.
3425  SvtBroadcaster* pBC = sc::broadcaster_block::at(*itBlockPos->data, nElemPos);
3426  rLst.StartListening(*pBC);
3427  }
3428  break;
3430  {
3431  // No broadcaster exists at this position yet.
3432  SvtBroadcaster* pBC = new SvtBroadcaster;
3433  rLst.StartListening(*pBC);
3434  itBlockPos = rStore.set(itBlockPos, nRow, pBC); // Store the block position for next iteration.
3435  }
3436  break;
3437  default:
3438  assert(false && "wrong block type encountered in the broadcaster storage.");
3439  }
3440 }
3441 
3442 }
3443 
3445 {
3446  std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(nRow);
3447  startListening(maBroadcasters, aPos.first, aPos.second, nRow, rLst);
3448 }
3449 
3451 {
3452  SvtBroadcaster* pBC = GetBroadcaster(nRow);
3453  if (!pBC)
3454  return;
3455 
3456  rLst.EndListening(*pBC);
3457  if (!pBC->HasListeners())
3458  { // There is no more listeners for this cell. Remove the broadcaster.
3461  else
3462  maBroadcasters.set_empty(nRow, nRow);
3463  }
3464 }
3465 
3467 {
3468  if (!GetDoc().ValidRow(rAddress.Row()))
3469  return;
3470 
3471  sc::ColumnBlockPosition* p = rCxt.getBlockPosition(rAddress.Tab(), rAddress.Col());
3472  if (!p)
3473  return;
3474 
3475  sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
3476  std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, rAddress.Row());
3477  it = aPos.first; // store the block position for next iteration.
3478  startListening(maBroadcasters, it, aPos.second, rAddress.Row(), rLst);
3479 }
3480 
3481 void ScColumn::EndListening( sc::EndListeningContext& rCxt, const ScAddress& rAddress, SvtListener& rListener )
3482 {
3483  sc::ColumnBlockPosition* p = rCxt.getBlockPosition(rAddress.Tab(), rAddress.Col());
3484  if (!p)
3485  return;
3486 
3487  sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
3488  std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, rAddress.Row());
3489  it = aPos.first; // store the block position for next iteration.
3490  if (it->type != sc::element_type_broadcaster)
3491  return;
3492 
3493  SvtBroadcaster* pBC = sc::broadcaster_block::at(*it->data, aPos.second);
3494  assert(pBC);
3495 
3496  rListener.EndListening(*pBC);
3497  if (!pBC->HasListeners())
3498  // There is no more listeners for this cell. Add it to the purge list for later purging.
3499  rCxt.addEmptyBroadcasterPosition(rAddress.Tab(), rAddress.Col(), rAddress.Row());
3500 }
3501 
3502 namespace {
3503 
3504 class CompileDBFormulaHandler
3505 {
3507 
3508 public:
3509  explicit CompileDBFormulaHandler( sc::CompileFormulaContext& rCxt ) :
3510  mrCxt(rCxt) {}
3511 
3512  void operator() (size_t, ScFormulaCell* p)
3513  {
3514  p->CompileDBFormula(mrCxt);
3515  }
3516 };
3517 
3518 struct CompileColRowNameFormulaHandler
3519 {
3521 public:
3522  explicit CompileColRowNameFormulaHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
3523 
3524  void operator() (size_t, ScFormulaCell* p)
3525  {
3526  p->CompileColRowNameFormula(mrCxt);
3527  }
3528 };
3529 
3530 }
3531 
3533 {
3534  CompileDBFormulaHandler aFunc(rCxt);
3535  sc::ProcessFormula(maCells, aFunc);
3537 }
3538 
3540 {
3541  CompileColRowNameFormulaHandler aFunc(rCxt);
3542  sc::ProcessFormula(maCells, aFunc);
3544 }
3545 
3546 namespace {
3547 
3548 class UpdateSubTotalHandler
3549 {
3551 
3552  void update(double fVal, bool bVal)
3553  {
3554  if (mrData.getError())
3555  return;
3556 
3557  switch (mrData.getFunc())
3558  {
3559  case SUBTOTAL_FUNC_CNT2: // everything
3560  mrData.update( fVal);
3561  break;
3562  default: // only numeric values
3563  if (bVal)
3564  mrData.update( fVal);
3565  }
3566  }
3567 
3568 public:
3569  explicit UpdateSubTotalHandler(ScFunctionData& rData) : mrData(rData) {}
3570 
3571  void operator() (size_t /*nRow*/, double fVal)
3572  {
3573  update(fVal, true);
3574  }
3575 
3576  void operator() (size_t /*nRow*/, const svl::SharedString&)
3577  {
3578  update(0.0, false);
3579  }
3580 
3581  void operator() (size_t /*nRow*/, const EditTextObject*)
3582  {
3583  update(0.0, false);
3584  }
3585 
3586  void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
3587  {
3588  double fVal = 0.0;
3589  bool bVal = false;
3590  if (mrData.getFunc() != SUBTOTAL_FUNC_CNT2) // it doesn't interest us
3591  {
3592 
3593  if (pCell->GetErrCode() != FormulaError::NONE)
3594  {
3595  if (mrData.getFunc() != SUBTOTAL_FUNC_CNT) // simply remove from count
3596  mrData.setError();
3597  }
3598  else if (pCell->IsValue())
3599  {
3600  fVal = pCell->GetValue();
3601  bVal = true;
3602  }
3603  // otherwise text
3604  }
3605 
3606  update(fVal, bVal);
3607  }
3608 };
3609 
3610 }
3611 
3612 // multiple selections:
3614  const ScRangeList& rRanges, ScFunctionData& rData, const ScFlatBoolRowSegments& rHiddenRows )
3615 {
3616  sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
3617  aSpanSet.scan(rRanges, nTab, nCol); // mark all selected rows.
3618 
3619  if (aSpanSet.empty())
3620  return; // nothing to do, bail out
3621 
3622  // Exclude all hidden rows.
3624  SCROW nRow = 0;
3625  while (nRow <= GetDoc().MaxRow())
3626  {
3627  if (!rHiddenRows.getRangeData(nRow, aRange))
3628  break;
3629 
3630  if (aRange.mbValue)
3631  // Hidden range detected.
3632  aSpanSet.set(nRow, aRange.mnRow2, false);
3633 
3634  nRow = aRange.mnRow2 + 1;
3635  }
3636 
3638  aSpanSet.getSpans(aSpans);
3639 
3640  switch (rData.getFunc())
3641  {
3643  {
3644  // Simply count selected rows regardless of cell contents.
3645  for (const auto& rSpan : aSpans)
3646  rData.update( rSpan.mnRow2 - rSpan.mnRow1 + 1);
3647  }
3648  break;
3649  case SUBTOTAL_FUNC_CNT2:
3650  {
3651  // We need to parse all non-empty cells.
3652  sc::CellStoreType::const_iterator itCellPos = maCells.begin();
3653  UpdateSubTotalHandler aFunc(rData);
3654  for (const auto& rSpan : aSpans)
3655  {
3656  itCellPos = sc::ParseAllNonEmpty(
3657  itCellPos, maCells, rSpan.mnRow1, rSpan.mnRow2, aFunc);
3658  }
3659  }
3660  break;
3661  default:
3662  {
3663  // We need to parse only numeric values.
3664  sc::CellStoreType::const_iterator itCellPos = maCells.begin();
3665  UpdateSubTotalHandler aFunc(rData);
3666  for (const auto& rSpan : aSpans)
3667  {
3668  itCellPos = sc::ParseFormulaNumeric(
3669  itCellPos, maCells, rSpan.mnRow1, rSpan.mnRow2, aFunc);
3670  }
3671  }
3672  }
3673 }
3674 
3675 namespace {
3676 
3677 class WeightedCounter
3678 {
3680 public:
3681  WeightedCounter() : mnCount(0) {}
3682 
3683  void operator() (const sc::CellStoreType::value_type& node)
3684  {
3685  mnCount += getWeight(node);
3686  }
3687 
3688  static sal_uLong getWeight(const sc::CellStoreType::value_type& node)
3689  {
3690  switch (node.type)
3691  {
3694  return node.size;
3696  {
3697  // Each formula cell is worth its code length plus 5.
3698  return std::accumulate(sc::formula_block::begin(*node.data), sc::formula_block::end(*node.data), size_t(0),
3699  [](const size_t& rCount, const ScFormulaCell* p) { return rCount + 5 + p->GetCode()->GetCodeLen(); });
3700  }
3702  // each edit-text cell is worth 50.
3703  return node.size * 50;
3704  default:
3705  return 0;
3706  }
3707  }
3708 
3709  sal_uLong getCount() const { return mnCount; }
3710 };
3711 
3712 class WeightedCounterWithRows
3713 {
3714  const SCROW mnStartRow;
3715  const SCROW mnEndRow;
3716  sal_uLong mnCount;
3717 
3718 public:
3719  WeightedCounterWithRows(SCROW nStartRow, SCROW nEndRow)
3720  : mnStartRow(nStartRow)
3721  , mnEndRow(nEndRow)
3722  , mnCount(0)
3723  {
3724  }
3725 
3726  void operator() (const sc::CellStoreType::value_type& node)
3727  {
3728  const SCROW nRow1 = node.position;
3729  const SCROW nRow2 = nRow1 + 1;
3730 
3731  if ((nRow2 >= mnStartRow) && (nRow1 <= mnEndRow))
3732  {
3733  mnCount += WeightedCounter::getWeight(node);
3734  }
3735  }
3736 
3737  sal_uLong getCount() const { return mnCount; }
3738 };
3739 
3740 }
3741 
3742 sal_uInt64 ScColumn::GetWeightedCount() const
3743 {
3744  const WeightedCounter aFunc = std::for_each(maCells.begin(), maCells.end(),
3745  WeightedCounter());
3746  return aFunc.getCount();
3747 }
3748 
3749 sal_uInt64 ScColumn::GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const
3750 {
3751  const WeightedCounterWithRows aFunc = std::for_each(maCells.begin(), maCells.end(),
3752  WeightedCounterWithRows(nStartRow, nEndRow));
3753  return aFunc.getCount();
3754 }
3755 
3756 namespace {
3757 
3758 class CodeCounter
3759 {
3760  sal_uInt64 mnCount;
3761 public:
3762  CodeCounter() : mnCount(0) {}
3763 
3764  void operator() (size_t, const ScFormulaCell* p)
3765  {
3766  mnCount += p->GetCode()->GetCodeLen();
3767  }
3768 
3769  sal_uInt64 getCount() const { return mnCount; }
3770 };
3771 
3772 }
3773 
3774 sal_uInt64 ScColumn::GetCodeCount() const
3775 {
3776  CodeCounter aFunc;
3777  sc::ParseFormula(maCells, aFunc);
3778  return aFunc.getCount();
3779 }
3780 
3781 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScSubTotalFunc getFunc() const
Definition: subtotal.hxx:70
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:112
bool GetValue() const
SCROW GetCellNotesMinRow() const
Definition: column2.cxx:2253
SCROW GetCellNotesMaxRow() const
Definition: column2.cxx:2242
void CellStorageModified()
Called whenever the state of cell array gets modified i.e.
Definition: column2.cxx:1647
OutDevType GetOutDevType() const
SCROW GetNextMarked(SCCOL nCol, SCROW nRow, bool bUp) const
May return -1.
Definition: markdata.cxx:609
constexpr double nPPTY
SCCOL GetColMerge() const
Definition: attrib.hxx:68
SvxCellHorJustify
void HandleStuffAfterParallelCalculation(ScInterpreter *pInterpreter)
SCSIZE GetEmptyLinesInBlock(SCROW nStartRow, SCROW nEndRow, ScDirection eDir) const
Definition: column2.cxx:1330
svl::SharedString maString
constexpr TypedWhichId< SvxEmphasisMarkItem > ATTR_FONT_EMPHASISMARK(121)
sal_Int32 nIndex
ScRotateDir GetRotateDir(const SfxItemSet *pCondSet) const
Definition: patattr.cxx:1371
mdds::mtv::soa::multi_type_vector< CNoteFunc > CellNoteStoreType
OUString getString() const
SfxItemSet * GetPreviewFont()
Definition: document.hxx:1385
CellStoreType::const_iterator miCellPos
static ScProgress * GetInterpretProgress()
Definition: progress.hxx:65
SharedString intern(const OUString &rStr)
void SetTextWidth(SCROW nRow, sal_uInt16 nWidth)
Definition: column2.cxx:2269
bool isForceAutoSize() const
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:584
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
SC_DLLPUBLIC bool IsTabProtected(SCTAB nTab) const
Definition: documen3.cxx:1913
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:42
void CellNotesDeleting(SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
Definition: column2.cxx:2220
SCSIZE VisibleCount(SCROW nStartRow, SCROW nEndRow) const
Definition: column2.cxx:1278
void DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn &rDestCol, sc::ColumnBlockPosition &rDestBlockPos, bool bCloneCaption, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:1939
const sc::CellStoreType & mrCells
Definition: queryiter.cxx:906
bool NeedsInterpret() const
constexpr auto toTwips(N number, Length from)
void PrepareBroadcastersForDestruction()
Definition: column2.cxx:1962
SCROW Row() const
Definition: address.hxx:274
void setWidth(tools::Long nWidth)
SvxRotateMode
void ForgetCaption(bool bPreserveData=false)
Forgets the pointer to the note caption object.
Definition: postit.cxx:959
SC_DLLPUBLIC SCROW GetMaxRowCount() const
Definition: document.hxx:893
void CalculateInThread(ScInterpreterContext &rContext, SCROW nRow, size_t nLen, size_t nOffset, unsigned nThisThread, unsigned nThreadsTotal)
Definition: column2.cxx:3185
ColArray * setCachedColArray(SCTAB nTab, SCCOL nCol, NumArrayType *pNumArray, StrArrayType *pStrArray)
bool update()
bool HasVisibleAttrIn(SCROW nStartRow, SCROW nEndRow) const
Definition: column.hxx:886
constexpr TypedWhichId< SfxBoolItem > ATTR_VERTICAL_ASIAN(137)
void CompileDBFormula(sc::CompileFormulaContext &rCxt)
Definition: column2.cxx:3532
const mdds::mtv::element_t element_type_celltextattr
Definition: mtvelements.hxx:46
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: column.hxx:951
void PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:2955
SCROW GetSharedTopRow() const
bool GetNextDataPos(SCROW &rRow) const
Definition: column2.cxx:1467
double getPPTX() const
SCTAB nTab
Definition: column.hxx:201
ScTokenArray * GetCode()
sal_uIntPtr sal_uLong
long Long
static void assertNoInterpretNeededHelper(const sc::CellStoreType::value_type &node, size_t nOffset, size_t nDataSize)
Definition: column2.cxx:3125
void SetCellNote(SCROW nRow, std::unique_ptr< ScPostIt > pNote)
Definition: column2.cxx:2187
OutputDevice * getOutputDevice()
bool IsOverlapped() const
Definition: attrib.hxx:101
#define STD_ROWHEIGHT_DIFF
Definition: global.hxx:95
constexpr TypedWhichId< SvxRotateModeItem > ATTR_ROTATE_MODE(136)
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
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. ...
std::shared_ptr< sc::FormulaGroupContext > & GetFormulaGroupContext()
Definition: document.cxx:3567
CellStoreType::const_iterator ParseFormulaNumeric(const CellStoreType::const_iterator &itPos, const CellStoreType &rCells, SCROW nRow1, SCROW nRow2, Func &rFunc)
const WhichRangesContainer & GetRanges() const
void removeSparkline(std::shared_ptr< Sparkline > const &pSparkline)
ColArray * getCachedColArray(SCTAB nTab, SCCOL nCol, size_t nSize)
keep track of longest array for each column.
sal_uInt64 GetWeightedCount() const
Definition: column2.cxx:3742
sal_uInt16 GetValue() const
SvNumFormatType GetType(sal_uInt32 nFIndex) const
SVX_ROTATE_MODE_STANDARD
Store position data for column array storage.
bool IsEmptyData() const
Definition: column2.cxx:1251
const MapMode & GetMapMode() const
sal_uInt16 GetCodeLen() const
CellStoreType::const_iterator ParseAllNonEmpty(const typename CellStoreType::const_iterator &itPos, const CellStoreType &rCells, SCROW nRow1, SCROW nRow2, Func &rFunc)
Definition: mtvcellfunc.hxx:95
bool HasVisibleDataAt(SCROW nRow) const
Definition: column2.cxx:1285
sal_Int16 GetRightMargin() const
void HandleStuffAfterParallelCalculation(SCROW nRow, size_t nLen, ScInterpreter *pInterpreter)
Definition: column2.cxx:3221
void addEmptyBroadcasterPosition(SCTAB nTab, SCCOL nCol, SCROW nRow)
constexpr TypedWhichId< ScLineBreakCell > ATTR_LINEBREAK(139)
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
formula::FormulaTokenRef ResolveStaticReference(SCROW nRow)
Definition: column2.cxx:2373
RowHeightsArray & getHeightArray()
mdds::mtv::soa::multi_type_vector< BCBlkFunc > BroadcasterStoreType
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1007
void ApplyAsianEditSettings(ScEditEngineDefaulter &rEngine)
Definition: documen9.cxx:674
bool empty() const
Whether there isn't any row tagged.
EEControlBits
void CompileColRowNameFormula(sc::CompileFormulaContext &rCxt)
Definition: column2.cxx:3539
void SetMapMode()
void PutString(const svl::SharedString &rStr, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:2970
bool IsMultilineResult()
Determines whether or not the result string contains more than one paragraph.
void ensureStrArray(ColArray &rColArray, size_t nArrayLen)
constexpr TypedWhichId< ScMergeAttr > ATTR_MERGE(144)
SC_DLLPUBLIC sal_uInt16 GetRowHeight(SCROW nRow, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4211
sal_uInt64 GetCodeCount() const
Definition: column2.cxx:3774
ColumnBlockPosition * getBlockPosition(SCTAB nTab, SCCOL nCol)
void GetDataExtrasAt(SCROW nRow, ScDataAreaExtras &rDataAreaExtras) const
Definition: column2.cxx:3368
constexpr TypedWhichId< ScIndentItem > ATTR_INDENT(131)
bool mbCellDrawObjects
If TRUE, consider the presence of draw objects anchored to the cell.
Definition: sortparam.hxx:48
const mdds::mtv::element_t element_type_cellnote
Definition: mtvelements.hxx:52
constexpr tools::Long Width() const
void ParseFormula(const CellStoreType &rStore, Func &rFunc)
Definition: mtvcellfunc.hxx:63
mdds::mtv::soa::multi_type_vector< CSparklineFunction > SparklineStoreType
SvtScriptType
BroadcasterStoreType::iterator miBroadcasterPos
constexpr TypedWhichId< ScRotateValueItem > ATTR_ROTATE_VALUE(135)
void CopyCellSparklinesToDocument(SCROW nRow1, SCROW nRow2, ScColumn &rDestCol, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:2111
void CompileDBFormula(sc::CompileFormulaContext &rCxt)
ObjectFormatterData & mrData
const mdds::mtv::element_t element_type_formula
Definition: mtvelements.hxx:50
const EditTextObject * mpEditText
Definition: cellvalue.hxx:109
void addSparkline(std::shared_ptr< Sparkline > const &pSparkline)
Keep track of spans in a single column only.
SC_DLLPUBLIC sal_uInt16 GetOriginalWidth(SCCOL nCol, SCTAB nTab) const
Definition: document.cxx:4187
const ScPatternAttr * pPattern
Definition: column.hxx:103
ScRefCellValue GetCellValue(SCROW nRow) const
Definition: column.cxx:639
enumrange< T >::Iterator begin(enumrange< T >)
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:891
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
const vcl::Font & GetFont() const
Additional class containing cell annotation data.
Definition: postit.hxx:160
double GetValue()
bool IsMultiMarked() const
Definition: markdata.hxx:81
FormulaError GetErrCode()
static void LOKCommentNotify(LOKCommentNotificationType nType, const ScDocument *pDocument, const ScAddress &rPos, const ScPostIt *pNote)
Definition: docsh4.cxx:2524
void SetNumberFormat(SCROW nRow, sal_uInt32 nNumberFormat)
Definition: column2.cxx:3247
sc::CellStoreType maCells
Definition: column.hxx:193
bool isLocked() const
ScFormulaCell * mpFormula
Definition: cellvalue.hxx:110
SCTAB Tab() const
Definition: address.hxx:283
void DiscardFormulaGroupContext()
Definition: document.cxx:3576
SCROW GetLastDataPos() const
Definition: column2.cxx:1384
void RemoveEditAttribs(sc::ColumnBlockPosition &rBlockPos, SCROW nStartRow, SCROW nEndRow)
Definition: column2.cxx:1234
std::vector< double, DoubleAllocType > NumArrayType
FormulaError GetDoubleErrorValue(double fVal)
static OUString GetString(const ScRefCellValue &rCell, sal_uInt32 nFormat, const Color **ppColor, SvNumberFormatter &rFormatter, const ScDocument &rDoc, bool bNullVals=true, bool bFormula=false, bool bUseStarFormat=false)
Definition: cellform.cxx:31
ScAddress aPos
void EndListening(SvtBroadcaster &rBroadcaster)
bool IsSparklinesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
Definition: column2.cxx:2055
SparklineStoreType::const_iterator ParseSparkline(const SparklineStoreType::const_iterator &itPos, const SparklineStoreType &rStore, SCROW nStart, SCROW nEnd, Functor &rFunctor)
bool HasSparklines() const
Definition: column2.cxx:2128
bool mbCellNotes
If TRUE, consider the presence of cell notes besides data.
Definition: sortparam.hxx:46
void DuplicateSparklines(SCROW nStartRow, size_t nDataSize, ScColumn &rDestCol, sc::ColumnBlockPosition &rDestBlockPos, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:2121
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:72
StrArrayStoreType m_StrArrays
manage life cycle of numeric arrays.
ScStyleSheet * GetPreviewCellStyle()
Definition: document.hxx:1389
static bool IsAmbiguousScript(SvtScriptType nScript)
Definition: column2.cxx:74
SvtBroadcaster * GetBroadcaster(SCROW nRow)
Definition: column2.cxx:1946
void discardCachedColArray(SCTAB nTab, SCCOL nCol)
DocumentType eType
constexpr double nPPTX
std::shared_ptr< SparklineGroup > const & getSparklineGroup() const
void PutEmptyResultVector(SCSIZE nCount, SCSIZE nC, SCSIZE nR)
Put a column vector of empty results, starting at row nR, must fit into dimensions.
Definition: scmatrix.cxx:3130
static SC_DLLPUBLIC sal_uInt16 nStdRowHeight
Definition: global.hxx:581
OUTDEV_PRINTER
SCROW GetSharedLength() const
bool IsShared() const
void DeleteSparklineCells(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2)
Definition: column2.cxx:2035
OUString CreateString(sc::TokenStringContext &rCxt, const ScAddress &rPos) const
Create a string representation of formula token array without modifying the internal state of the tok...
Definition: token.cxx:5217
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1081
ColumnBlockPosition * getBlockPosition(SCTAB nTab, SCCOL nCol)
SCCOL nCol
Definition: column.hxx:200
void getSpans(SpansType &rSpans) const
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:459
bool IsVerOverlapped() const
Definition: attrib.hxx:100
static void GetFont(vcl::Font &rFont, const SfxItemSet &rItemSet, ScAutoFontColorMode eAutoMode, const OutputDevice *pOutDev=nullptr, const Fraction *pScale=nullptr, const SfxItemSet *pCondSet=nullptr, SvtScriptType nScript=SvtScriptType::NONE, const Color *pBackConfigColor=nullptr, const Color *pTextConfigColor=nullptr)
Static helper function to fill a font object from the passed item set.
Definition: patattr.cxx:251
bool IsMarked() const
Definition: markdata.hxx:80
void FillMatrix(ScMatrix &rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2, svl::SharedStringPool *pPool) const
Definition: column2.cxx:2658
constexpr TypedWhichId< SvxFontHeightItem > ATTR_CJK_FONT_HEIGHT(112)
void EndListening(SvtListener &rLst, SCROW nRow)
Definition: column2.cxx:3450
int i
const Fraction & getZoomY() const
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
void FindDataAreaPos(SCROW &rRow, bool bDown) const
Definition: column2.cxx:3286
void StartListening(SvtListener &rLst, SCROW nRow)
Definition: column2.cxx:3444
void DeleteBroadcasters(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2)
Definition: column2.cxx:1956
sal_Int32 getLength() const
bool TrimEmptyBlocks(SCROW &rRowStart, SCROW &rRowEnd) const
Definition: column2.cxx:1513
sal_Int16 SCCOL
Definition: types.hxx:21
void RegroupFormulaCells(std::vector< ScAddress > *pGroupPos=nullptr)
Regroup formula cells for the entire column.
Definition: column3.cxx:3622
Struct to hold non-data extended area, used with ScDocument::ShrinkToUsedDataArea().
Definition: sortparam.hxx:43
SvtScriptType mnScriptType
sc::CellTextAttrStoreType maCellTextAttrs
Definition: column.hxx:184
std::unique_ptr< ScPostIt > Clone(const ScAddress &rOwnPos, ScDocument &rDestDoc, const ScAddress &rDestPos, bool bCloneCaption) const
Clones this note and its caption object, if specified.
Definition: postit.cxx:878
static css::uno::Reference< css::linguistic2::XHyphenator > GetHyphenator()
ScFormulaCell *const * GetFormulaCellBlockAddress(SCROW nRow, size_t &rBlockSize) const
Definition: column2.cxx:3252
sal_uInt16 Count() const
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
const mdds::mtv::element_t element_type_empty
Definition: mtvelements.hxx:57
::boost::intrusive_ptr< FormulaToken > FormulaTokenRef
void set(SCROW nRow1, SCROW nRow2, bool bVal)
ScDocument & GetDoc() const
Definition: column.hxx:127
SparklineStoreType::iterator miSparklinePos
Context for creating string from an array of formula tokens, used in ScTokenArray::CreateString().
bool GetErrorOrValue(FormulaError &rErr, double &rVal)
void UpdateSelectionFunction(const ScRangeList &rRanges, ScFunctionData &rData, const ScFlatBoolRowSegments &rHiddenRows)
Definition: column2.cxx:3613
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALUE_FORMAT(146)
const Size & GetFontSize() const
const mdds::mtv::element_t element_type_numeric
Mapped standard element types (for convenience).
Definition: mtvelements.hxx:56
void FindUsed(SCROW nStartRow, SCROW nEndRow, mdds::flat_segment_tree< SCROW, bool > &rUsed) const
Definition: column2.cxx:3408
size
SC_DLLPUBLIC std::shared_ptr< sc::SparklineGroup > SearchSparklineGroup(tools::Guid const &rGuid)
Definition: document.cxx:6695
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1301
void DeleteEmptyBroadcasters()
Definition: column2.cxx:1988
double toRadians(D x)
bool IsRunning() const
MapUnit GetMapUnit() const
tools::Long GetNeededSize(SCROW nRow, OutputDevice *pDev, double nPPTX, double nPPTY, const Fraction &rZoomX, const Fraction &rZoomY, bool bWidth, const ScNeededSizeOptions &rOptions, const ScPatternAttr **pPatternChange, bool bInPrintTwips=false) const
Definition: column2.cxx:84
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
bool hasNumeric() const
Definition: cellvalue.cxx:622
bool DeleteSparkline(SCROW nRow)
Definition: column2.cxx:2043
std::size_t mnCount
bool StartListening(SvtBroadcaster &rBroadcaster)
void SetValue(A nPos, const D &rValue)
bool IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
Definition: column2.cxx:1313
constexpr TypedWhichId< SvxFontHeightItem > ATTR_CTL_FONT_HEIGHT(117)
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:805
static SvxCellOrientation GetCellOrientation(const SfxItemSet &rItemSet, const SfxItemSet *pCondSet)
Definition: patattr.cxx:189
std::vector< rtl_uString * > StrArrayType
SfxItemPool * GetPool() const
double getPPTY() const
bool mbEmptyBroadcastersPending
Definition: column.hxx:204
rtl_uString * getData()
void ApplyAttr(SCROW nRow, const SfxPoolItem &rAttr)
Definition: column.cxx:621
void setError()
Definition: subtotal.hxx:71
sal_Int16 GetBottomMargin() const
SCROW mnMaxTextRow
Definition: docparam.hxx:19
void SetStyleSheet(ScStyleSheet *pNewStyle, bool bClearDirectFormat=true)
Definition: patattr.cxx:1212
const svl::SharedString & GetString()
FormulaError
SCCOL Col() const
Definition: address.hxx:279
CellStoreType::iterator miCellPos
SCROW GetSparklinesMaxRow() const
Definition: column2.cxx:2135
void InterpretTail(ScInterpreterContext &, ScInterpretTailParameter)
void CopyCellNotesToDocument(SCROW nRow1, SCROW nRow2, ScColumn &rDestCol, bool bCloneCaption=true, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:1917
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
bool TestTabRefAbs(SCTAB nTable) const
Definition: column2.cxx:1244
bool IsHorOverlapped() const
Definition: attrib.hxx:99
const D & GetValue(A nPos) const
CellType meType
Definition: cellvalue.hxx:105
void GetOptimalHeight(sc::RowHeightContext &rCxt, SCROW nStartRow, SCROW nEndRow, sal_uInt16 nMinHeight, SCROW nMinStart)
Definition: column2.cxx:867
const mdds::mtv::element_t element_type_sparkline
Definition: mtvelements.hxx:53
void DeleteCellNotes(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
Definition: column2.cxx:2227
void setLock(bool bLock)
NumArrayStoreType m_NumArrays
bool mbCellFormats
If TRUE, consider the presence of cell formats.
Definition: sortparam.hxx:50
constexpr TypedWhichId< ScMergeFlagAttr > ATTR_MERGE_FLAG(145)
bool HasAttrib(SCROW nRow1, SCROW nRow2, HasAttrFlags nMask) const
Definition: column.hxx:916
sal_Int32 SCROW
Definition: types.hxx:17
To calculate a single subtotal function.
Definition: subtotal.hxx:60
mdds::mtv::soa::multi_type_vector< CellFunc, CellStoreTrait > CellStoreType
ScPostIt * GetCellNote(SCROW nRow)
Definition: column2.cxx:2161
static SC_DLLPUBLIC SvtScriptType GetDefaultScriptType()
Definition: global.cxx:860
sc::BroadcasterStoreType maBroadcasters
Definition: column.hxx:190
double CreateDoubleError(FormulaError nErr)
bool ValidRow(SCROW nRow) const
Definition: document.hxx:898
sc::SparklineStoreType maSparklines
Definition: column.hxx:196
ScMF
Definition: attrib.hxx:34
sal_uInt32 GetHeight() const
void AssertNoInterpretNeeded(SCROW nRow1, SCROW nRow2)
Definition: column2.cxx:3145
void SetFormulaResults(SCROW nRow, const double *pResults, size_t nLen)
Definition: column2.cxx:3152
sal_Int32 GetDenominator() const
sc::CellNoteStoreType maCellNotes
Definition: column.hxx:187
sal_uInt16 GetOptimalColWidth(OutputDevice *pDev, double nPPTX, double nPPTY, const Fraction &rZoomX, const Fraction &rZoomY, bool bFormula, sal_uInt16 nOldWidth, const ScMarkData *pMarkData, const ScColWidthParam *pParam) const
Definition: column2.cxx:717
SCROW GetFirstDataPos() const
Definition: column2.cxx:1372
constexpr tools::Long Height() const
void DumpColumnStorage() const
SCCOL GetCol() const
Definition: column.hxx:253
static sal_uInt16 lcl_GetAttribHeight(const ScPatternAttr &rPattern, sal_uInt16 nFontHeightId)
Definition: column2.cxx:835
SCROW FindNextVisibleRowWithContent(sc::CellStoreType::const_iterator &itPos, SCROW nRow, bool bForward) const
Definition: column2.cxx:1583
bool HasCellNotes() const
Definition: column2.cxx:2235
SvtScriptType GetRangeScriptType(sc::CellTextAttrStoreType::iterator &itPos, SCROW nRow1, SCROW nRow2, const sc::CellStoreType::iterator &itr)
Get combined script types of the specified range.
Definition: column2.cxx:2288
void SetFont(const vcl::Font &rNewFont)
CellType
Definition: global.hxx:269
formula::VectorRefArray FetchVectorRefArray(SCROW nRow1, SCROW nRow2)
Definition: column2.cxx:2929
void CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn &rDestCol) const
Definition: column2.cxx:1820
std::shared_ptr< Sparkline > const & getSparkline() const
std::unique_ptr< ScFieldEditEngine > CreateFieldEditEngine()
Definition: documen2.cxx:1142
const mdds::mtv::element_t element_type_edittext
Definition: mtvelements.hxx:49
void SetResultDouble(double n)
For import only: set a double result.
SvStream & endl(SvStream &rStr)
const mdds::mtv::element_t element_type_broadcaster
Custom element type IDs for multi_type_vector.
Definition: mtvelements.hxx:45
tools::Long GetTextHeight() const
SvtScriptType GetScriptType(SCROW nRow) const
Definition: column2.cxx:2280
void DisposeFieldEditEngine(std::unique_ptr< ScFieldEditEngine > &rpEditEngine)
Definition: documen2.cxx:1164
const Fraction & getZoomX() const
sc::SparklineCell * GetSparklineCell(SCROW nRow)
Definition: column2.cxx:2023
CellNoteStoreType::iterator miCellNotePos
sal_Int16 GetLeftMargin() const
const ScFormulaCell * FetchFormulaCell(SCROW nRow) const
Definition: column2.cxx:3279
void update(double fNewVal)
Definition: subtotal.cxx:66
SC_DLLPUBLIC SvtScriptType GetScriptType(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScRefCellValue *pCell=nullptr)
Definition: documen6.cxx:132
constexpr TypedWhichId< SfxBoolItem > EE_PARA_HYPHENATE(EE_PARA_START+6)
constexpr TypedWhichId< SvxHorJustifyItem > ATTR_HOR_JUSTIFY(129)
Degree100 GetValue() const
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
std::vector< RowSpan > SpansType
sal_Int32 GetNumerator() const
SC_DLLPUBLIC ScPatternAttr * GetDefPattern() const
Definition: document.cxx:6151
void CreateSparklineCell(SCROW nRow, std::shared_ptr< sc::Sparkline > const &pSparkline)
Definition: column2.cxx:2028
sc::FormulaResultValue GetResult()
bool GetNextSpellingCell(SCROW &nRow, bool bInSel, const ScMarkData &rData) const
Definition: column2.cxx:1071
SC_DLLPUBLIC sc::SparklineList * GetSparklineList(SCTAB nTab)
Definition: document.cxx:6651
static OUString GetSpaceDelimitedString(const EditEngine &rEngine)
Retrieves string with paragraphs delimited by spaces.
Definition: editutil.cxx:105
CellNoteStoreType::const_iterator ParseNote(const CellNoteStoreType::const_iterator &itPos, const CellNoteStoreType &rStore, SCROW nStart, SCROW nEnd, Func &rFunc)
void SetResultError(FormulaError n)
bool HasListeners() const
SCROW FindNextVisibleRow(SCROW nRow, bool bForward) const
Definition: column2.cxx:1559
bool IsDrawObjectsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
Definition: column.cxx:1864
SC_DLLPUBLIC SfxItemPool * GetEditPool() const
Definition: documen2.cxx:465
SC_DLLPUBLIC bool RowHidden(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4479
void scan(const ScColumn &rColumn)
Scan an entire column and tag all non-empty cell positions.
void ensureNumArray(ColArray &rColArray, size_t nArrayLen)
void SetScriptType(SCROW nRow, SvtScriptType nType)
Definition: column2.cxx:2359
static SC_DLLPUBLIC OUString GetString(const EditTextObject &rEditText, const ScDocument *pDoc)
Retrieves string with paragraphs delimited by new lines (' ').
Definition: editutil.cxx:119
bool HasDataAt(SCROW nRow, ScDataAreaExtras *pDataAreaExtras=nullptr) const
Definition: column2.cxx:3334
bool ValidRow(SCROW nRow, SCROW nMaxRow)
Definition: address.hxx:105
SCTAB GetTab() const
Definition: column.hxx:252
bool getError() const
Definition: subtotal.hxx:69
ScDirection
Definition: global.hxx:340
SCROW GetRowMerge() const
Definition: attrib.hxx:69
sal_Int32 nLength
sal_Int32 mnRow
SCROW GetSparklinesMinRow() const
Definition: column2.cxx:2146
bool HasAutoFilter() const
Definition: attrib.hxx:103
bool GetPrevDataPos(SCROW &rRow) const
Definition: column2.cxx:1421
SvxCellOrientation
bool getRangeData(SCROW nRow, RangeData &rData) const
#define SC_ROT_BREAK_FACTOR
Definition: column2.cxx:72
SC_DLLPUBLIC sal_uInt16 GetColWidth(SCCOL nCol, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4170
CellNoteStoreType::const_iterator miCellNotePos
sal_uInt16 GetTextWidth(SCROW nRow) const
Definition: column2.cxx:2264
void SetChanged(bool b)
std::unique_ptr< ScAttrArray > pAttrArray
Definition: column.hxx:118
void SetErrCode(FormulaError n)
const mdds::mtv::element_t element_type_string
Definition: mtvelements.hxx:48
constexpr TypedWhichId< SvxFontHeightItem > ATTR_FONT_HEIGHT(101)
bool IsDelayedDeletingBroadcasters() const
Definition: document.hxx:1434
aStr
bool HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW &rFirst)
Definition: column.cxx:3338
CellStoreType::iterator ProcessEditText(const CellStoreType::iterator &itPos, CellStoreType &rStore, SCROW nRow1, SCROW nRow2, Func &rFunc)
Definition: mtvcellfunc.hxx:55
sal_Int16 SCTAB
Definition: types.hxx:22
SC_DLLPUBLIC CRFlags GetRowFlags(SCROW nRow, SCTAB nTab) const
Definition: document.cxx:4386
constexpr TypedWhichId< SvxMarginItem > ATTR_MARGIN(143)
sal_Int16 nValue
bool UpdateScriptType(sc::CellTextAttr &rAttr, SCROW nRow, sc::CellStoreType::iterator &itr)
Definition: column3.cxx:787
void CompileColRowNameFormula(sc::CompileFormulaContext &rCxt)
bool m_bDetectedRangeSegmentation false
void FillEditItemSet(SfxItemSet *pEditSet, const SfxItemSet *pCondSet=nullptr) const
Converts all Calc items contained in the own item set to edit engine items and puts them into pEditSe...
Definition: patattr.cxx:827
sal_Int16 GetTopMargin() const
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo