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