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->GetFont( aFont, SC_AUTOCOL_BLACK, 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->GetFont( aFont, SC_AUTOCOL_BLACK, 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{
860 const SvxFontHeightItem& rFontHeight =
861 static_cast<const SvxFontHeightItem&>(rPattern.GetItem(nFontHeightId));
862
863 sal_uInt16 nHeight = rFontHeight.GetHeight();
864 nHeight *= 1.18;
865
866 if ( rPattern.GetItem(ATTR_FONT_EMPHASISMARK).GetEmphasisMark() != FontEmphasisMark::NONE )
867 {
868 // add height for emphasis marks
869 //TODO: font metrics should be used instead
870 nHeight += nHeight / 4;
871 }
872
873 const SvxMarginItem& rMargin = rPattern.GetItem(ATTR_MARGIN);
874
875 nHeight += rMargin.GetTopMargin() + rMargin.GetBottomMargin();
876
877 if (nHeight > STD_ROWHEIGHT_DIFF)
878 nHeight -= STD_ROWHEIGHT_DIFF;
879
880 if (nHeight < ScGlobal::nStdRowHeight)
881 nHeight = ScGlobal::nStdRowHeight;
882
883 return nHeight;
884}
885
886// pHeight in Twips
887// optimize nMinHeight, nMinStart : with nRow >= nMinStart is at least nMinHeight
888// (is only evaluated with bStdAllowed)
889
891 sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, sal_uInt16 nMinHeight, SCROW nMinStart )
892{
893 ScDocument& rDocument = GetDoc();
894 RowHeightsArray& rHeights = rCxt.getHeightArray();
895 ScAttrIterator aIter( pAttrArray.get(), nStartRow, nEndRow, rDocument.GetDefPattern() );
896
897 SCROW nStart = -1;
898 SCROW nEnd = -1;
899 SCROW nEditPos = 0;
900 SCROW nNextEnd = 0;
901
902 // with conditional formatting, always consider the individual cells
903
904 const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
905 while ( pPattern )
906 {
907 const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE);
908 const ScMergeFlagAttr* pFlag = &pPattern->GetItem(ATTR_MERGE_FLAG);
909 if ( pMerge->GetRowMerge() > 1 || pFlag->IsOverlapped() )
910 {
911 // do nothing - vertically with merged and overlapping,
912 // horizontally only with overlapped (invisible) -
913 // only one horizontal merged is always considered
914 }
915 else
916 {
917 bool bStdAllowed = (pPattern->GetCellOrientation() == SvxCellOrientation::Standard);
918 bool bStdOnly = false;
919 if (bStdAllowed)
920 {
921 bool bBreak = pPattern->GetItem(ATTR_LINEBREAK).GetValue() ||
922 (pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() ==
923 SvxCellHorJustify::Block);
924 bStdOnly = !bBreak;
925
926 // conditional formatting: loop all cells
927 if (bStdOnly &&
928 !pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty())
929 {
930 bStdOnly = false;
931 }
932
933 // rotated text: loop all cells
934 if ( bStdOnly && pPattern->GetItem(ATTR_ROTATE_VALUE).GetValue() )
935 bStdOnly = false;
936 }
937
938 if (bStdOnly)
939 {
940 bool bHasEditCells = HasEditCells(nStart,nEnd,nEditPos);
941 // Call to HasEditCells() may change pattern due to
942 // calculation, => sync always.
943 // We don't know which row changed first, but as pPattern
944 // covered nStart to nEnd we can pick nStart. Worst case we
945 // have to repeat that for every row in range if every row
946 // changed.
947 pPattern = aIter.Resync( nStart, nStart, nEnd);
948 if (bHasEditCells && nEnd < nEditPos)
949 bHasEditCells = false; // run into that again
950 if (bHasEditCells) // includes mixed script types
951 {
952 if (nEditPos == nStart)
953 {
954 bStdOnly = false;
955 if (nEnd > nEditPos)
956 nNextEnd = nEnd;
957 nEnd = nEditPos; // calculate single
958 bStdAllowed = false; // will be computed in any case per cell
959 }
960 else
961 {
962 nNextEnd = nEnd;
963 nEnd = nEditPos - 1; // standard - part
964 }
965 }
966 }
967
968 sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
969 aSpanSet.scan(*this, nStart, nEnd);
971 aSpanSet.getSpans(aSpans);
972
973 if (bStdAllowed)
974 {
975 sal_uInt16 nLatHeight = 0;
976 sal_uInt16 nCjkHeight = 0;
977 sal_uInt16 nCtlHeight = 0;
978 sal_uInt16 nDefHeight;
980 if ( nDefScript == SvtScriptType::ASIAN )
981 nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
982 else if ( nDefScript == SvtScriptType::COMPLEX )
983 nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
984 else
985 nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
986
987 // if everything below is already larger, the loop doesn't have to
988 // be run again
989 SCROW nStdEnd = nEnd;
990 if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
991 nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
992
993 if (nStart <= nStdEnd)
994 {
995 SCROW nRow = nStart;
996 for (;;)
997 {
998 size_t nIndex;
999 SCROW nRangeEnd;
1000 sal_uInt16 nRangeHeight = rHeights.GetValue(nRow, nIndex, nRangeEnd);
1001 if (nRangeHeight < nDefHeight)
1002 rHeights.SetValue(nRow, std::min(nRangeEnd, nStdEnd), nDefHeight);
1003 nRow = nRangeEnd + 1;
1004 if (nRow > nStdEnd)
1005 break;
1006 }
1007 }
1008
1009 if ( bStdOnly )
1010 {
1011 // if cells are not handled individually below,
1012 // check for cells with different script type
1013 sc::CellTextAttrStoreType::iterator itAttr = maCellTextAttrs.begin();
1014 sc::CellStoreType::iterator itCells = maCells.begin();
1015 for (const auto& rSpan : aSpans)
1016 {
1017 for (SCROW nRow = rSpan.mnRow1; nRow <= rSpan.mnRow2; ++nRow)
1018 {
1019 SvtScriptType nScript = GetRangeScriptType(itAttr, nRow, nRow, itCells);
1020 if (nScript == nDefScript)
1021 continue;
1022
1023 if ( nScript == SvtScriptType::ASIAN )
1024 {
1025 if ( nCjkHeight == 0 )
1026 nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
1027 if (nCjkHeight > rHeights.GetValue(nRow))
1028 rHeights.SetValue(nRow, nRow, nCjkHeight);
1029 }
1030 else if ( nScript == SvtScriptType::COMPLEX )
1031 {
1032 if ( nCtlHeight == 0 )
1033 nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
1034 if (nCtlHeight > rHeights.GetValue(nRow))
1035 rHeights.SetValue(nRow, nRow, nCtlHeight);
1036 }
1037 else
1038 {
1039 if ( nLatHeight == 0 )
1040 nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
1041 if (nLatHeight > rHeights.GetValue(nRow))
1042 rHeights.SetValue(nRow, nRow, nLatHeight);
1043 }
1044 }
1045 }
1046 }
1047 }
1048
1049 if (!bStdOnly) // search covered cells
1050 {
1051 ScNeededSizeOptions aOptions;
1052
1053 for (const auto& rSpan : aSpans)
1054 {
1055 for (SCROW nRow = rSpan.mnRow1; nRow <= rSpan.mnRow2; ++nRow)
1056 {
1057 // only calculate the cell height when it's used later (#37928#)
1058
1059 if (rCxt.isForceAutoSize() || !(rDocument.GetRowFlags(nRow, nTab) & CRFlags::ManualSize) )
1060 {
1061 aOptions.pPattern = pPattern;
1062 const ScPatternAttr* pOldPattern = pPattern;
1063 sal_uInt16 nHeight = static_cast<sal_uInt16>(
1064 std::min(
1065 GetNeededSize( nRow, rCxt.getOutputDevice(), rCxt.getPPTX(), rCxt.getPPTY(),
1066 rCxt.getZoomX(), rCxt.getZoomY(), false, aOptions,
1067 &pPattern) / rCxt.getPPTY(),
1068 double(std::numeric_limits<sal_uInt16>::max())));
1069 if (nHeight > rHeights.GetValue(nRow))
1070 rHeights.SetValue(nRow, nRow, nHeight);
1071 // Pattern changed due to calculation? => sync.
1072 if (pPattern != pOldPattern)
1073 {
1074 pPattern = aIter.Resync( nRow, nStart, nEnd);
1075 nNextEnd = 0;
1076 }
1077 }
1078 }
1079 }
1080 }
1081 }
1082
1083 if (nNextEnd > 0)
1084 {
1085 nStart = nEnd + 1;
1086 nEnd = nNextEnd;
1087 nNextEnd = 0;
1088 }
1089 else
1090 pPattern = aIter.Next(nStart,nEnd);
1091 }
1092}
1093
1094bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) const
1095{
1096 ScDocument& rDocument = GetDoc();
1097 sc::CellStoreType::const_iterator it = maCells.position(nRow).first;
1098 mdds::mtv::element_t eType = it->type;
1099 if (!bInSel && it != maCells.end() && eType != sc::element_type_empty)
1100 {
1102 !(HasAttrib( nRow, nRow, HasAttrFlags::Protected) &&
1103 rDocument.IsTabProtected(nTab)) )
1104 return true;
1105 }
1106 if (bInSel)
1107 {
1108 SCROW lastDataPos = GetLastDataPos();
1109 for (;;)
1110 {
1111 nRow = rData.GetNextMarked(nCol, nRow, false);
1112 if (!rDocument.ValidRow(nRow) || nRow > lastDataPos )
1113 {
1114 nRow = GetDoc().MaxRow()+1;
1115 return false;
1116 }
1117 else
1118 {
1119 it = maCells.position(it, nRow).first;
1120 eType = it->type;
1122 !(HasAttrib( nRow, nRow, HasAttrFlags::Protected) &&
1123 rDocument.IsTabProtected(nTab)) )
1124 return true;
1125 else
1126 nRow++;
1127 }
1128 }
1129 }
1130 else
1131 {
1132 while (GetNextDataPos(nRow))
1133 {
1134 it = maCells.position(it, nRow).first;
1135 eType = it->type;
1137 !(HasAttrib( nRow, nRow, HasAttrFlags::Protected) &&
1138 rDocument.IsTabProtected(nTab)) )
1139 return true;
1140 else
1141 nRow++;
1142 }
1143 nRow = GetDoc().MaxRow()+1;
1144 return false;
1145 }
1146}
1147
1148namespace {
1149
1150class StrEntries
1151{
1153
1154protected:
1155 struct StrEntry
1156 {
1157 SCROW mnRow;
1158 OUString maStr;
1159
1160 StrEntry(SCROW nRow, OUString aStr) : mnRow(nRow), maStr(std::move(aStr)) {}
1161 };
1162
1163 std::vector<StrEntry> maStrEntries;
1164 ScDocument* mpDoc;
1165
1166 StrEntries(sc::CellStoreType& rCells, ScDocument* pDoc) : mrCells(rCells), mpDoc(pDoc) {}
1167
1168public:
1169 void commitStrings()
1170 {
1172 sc::CellStoreType::iterator it = mrCells.begin();
1173 for (const auto& rStrEntry : maStrEntries)
1174 it = mrCells.set(it, rStrEntry.mnRow, rPool.intern(rStrEntry.maStr));
1175 }
1176};
1177
1178class RemoveEditAttribsHandler : public StrEntries
1179{
1180 std::unique_ptr<ScFieldEditEngine> mpEngine;
1181
1182public:
1183 RemoveEditAttribsHandler(sc::CellStoreType& rCells, ScDocument* pDoc) : StrEntries(rCells, pDoc) {}
1184
1185 void operator() (size_t nRow, EditTextObject*& pObj)
1186 {
1187 // For the test on hard formatting (ScEditAttrTester), are the defaults in the
1188 // EditEngine of no importance. When the tester would later recognise the same
1189 // attributes in default and hard formatting and has to remove them, the correct
1190 // defaults must be set in the EditEngine for each cell.
1191
1192 // test for attributes
1193 if (!mpEngine)
1194 {
1195 mpEngine.reset(new ScFieldEditEngine(mpDoc, mpDoc->GetEditPool()));
1196 // EEControlBits::ONLINESPELLING if there are errors already
1197 mpEngine->SetControlWord(mpEngine->GetControlWord() | EEControlBits::ONLINESPELLING);
1198 mpDoc->ApplyAsianEditSettings(*mpEngine);
1199 }
1200 mpEngine->SetTextCurrentDefaults(*pObj);
1201 sal_Int32 nParCount = mpEngine->GetParagraphCount();
1202 for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
1203 {
1204 mpEngine->RemoveCharAttribs(nPar);
1205 const SfxItemSet& rOld = mpEngine->GetParaAttribs(nPar);
1206 if ( rOld.Count() )
1207 {
1208 SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() ); // empty
1209 mpEngine->SetParaAttribs( nPar, aNew );
1210 }
1211 }
1212 // change URL field to text (not possible otherwise, thus pType=0)
1213 mpEngine->RemoveFields();
1214
1215 bool bSpellErrors = mpEngine->HasOnlineSpellErrors();
1216 bool bNeedObject = bSpellErrors || nParCount>1; // keep errors/paragraphs
1217 // ScEditAttrTester is not needed anymore, arrays are gone
1218
1219 if (bNeedObject) // remains edit cell
1220 {
1221 EEControlBits nCtrl = mpEngine->GetControlWord();
1222 EEControlBits nWantBig = bSpellErrors ? EEControlBits::ALLOWBIGOBJS : EEControlBits::NONE;
1223 if ( ( nCtrl & EEControlBits::ALLOWBIGOBJS ) != nWantBig )
1224 mpEngine->SetControlWord( (nCtrl & ~EEControlBits::ALLOWBIGOBJS) | nWantBig );
1225
1226 // Overwrite the existing object.
1227 delete pObj;
1228 pObj = mpEngine->CreateTextObject().release();
1229 }
1230 else // create String
1231 {
1232 // Store the string replacement for later commits.
1233 OUString aText = ScEditUtil::GetSpaceDelimitedString(*mpEngine);
1234 maStrEntries.emplace_back(nRow, aText);
1235 }
1236 }
1237};
1238
1239class TestTabRefAbsHandler
1240{
1241 SCTAB mnTab;
1242 bool mbTestResult;
1243public:
1244 explicit TestTabRefAbsHandler(SCTAB nTab) : mnTab(nTab), mbTestResult(false) {}
1245
1246 void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
1247 {
1248 if (const_cast<ScFormulaCell*>(pCell)->TestTabRefAbs(mnTab))
1249 mbTestResult = true;
1250 }
1251
1252 bool getTestResult() const { return mbTestResult; }
1253};
1254
1255}
1256
1258{
1259 RemoveEditAttribsHandler aFunc(maCells, &GetDoc());
1260
1261 rBlockPos.miCellPos = sc::ProcessEditText(
1262 rBlockPos.miCellPos, maCells, nStartRow, nEndRow, aFunc);
1263
1264 aFunc.commitStrings();
1265}
1266
1268{
1269 TestTabRefAbsHandler aFunc(nTable);
1270 sc::ParseFormula(maCells, aFunc);
1271 return aFunc.getTestResult();
1272}
1273
1275{
1276 return maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty;
1277}
1278
1279namespace {
1280
1281class CellCounter
1282{
1283 size_t mnCount;
1284public:
1285 CellCounter() : mnCount(0) {}
1286
1287 void operator() (
1288 const sc::CellStoreType::value_type& node, size_t /*nOffset*/, size_t nDataSize)
1289 {
1290 if (node.type == sc::element_type_empty)
1291 return;
1292
1293 mnCount += nDataSize;
1294 }
1295
1296 size_t getCount() const { return mnCount; }
1297};
1298
1299}
1300
1301SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
1302{
1303 CellCounter aFunc;
1304 sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
1305 return aFunc.getCount();
1306}
1307
1309{
1310 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
1311 sc::CellStoreType::const_iterator it = aPos.first;
1312 if (it == maCells.end())
1313 // Likely invalid row number.
1314 return false;
1315
1316 return it->type != sc::element_type_empty;
1317}
1318
1319bool ScColumn::IsEmptyData(SCROW nStartRow, SCROW nEndRow) const
1320{
1321 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1322 sc::CellStoreType::const_iterator it = aPos.first;
1323 if (it == maCells.end())
1324 // Invalid row number.
1325 return false;
1326
1327 if (it->type != sc::element_type_empty)
1328 // Non-empty cell at the start position.
1329 return false;
1330
1331 // start position of next block which is not empty.
1332 SCROW nNextRow = nStartRow + it->size - aPos.second;
1333 return nEndRow < nNextRow;
1334}
1335
1336bool ScColumn::IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
1337{
1338 std::pair<sc::CellNoteStoreType::const_iterator,size_t> aPos = maCellNotes.position(nStartRow);
1339 sc::CellNoteStoreType::const_iterator it = aPos.first;
1340 if (it == maCellNotes.end())
1341 // Invalid row number.
1342 return false;
1343
1344 if (it->type != sc::element_type_empty)
1345 // Non-empty cell at the start position.
1346 return false;
1347
1348 // start position of next block which is not empty.
1349 SCROW nNextRow = nStartRow + it->size - aPos.second;
1350 return nEndRow < nNextRow;
1351}
1352
1354{
1355 // Given a range of rows, find a top or bottom empty segment.
1356 switch (eDir)
1357 {
1358 case DIR_TOP:
1359 {
1360 // Determine the length of empty head segment.
1361 size_t nLength = nEndRow - nStartRow + 1;
1362 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
1363 sc::CellStoreType::const_iterator it = aPos.first;
1364 if (it->type != sc::element_type_empty)
1365 // First row is already not empty.
1366 return 0;
1367
1368 // length of this empty block minus the offset.
1369 size_t nThisLen = it->size - aPos.second;
1370 return std::min(nThisLen, nLength);
1371 }
1372 break;
1373 case DIR_BOTTOM:
1374 {
1375 // Determine the length of empty tail segment.
1376 size_t nLength = nEndRow - nStartRow + 1;
1377 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nEndRow);
1378 sc::CellStoreType::const_iterator it = aPos.first;
1379 if (it->type != sc::element_type_empty)
1380 // end row is already not empty.
1381 return 0;
1382
1383 // length of this empty block from the tip to the end row position.
1384 size_t nThisLen = aPos.second + 1;
1385 return std::min(nThisLen, nLength);
1386 }
1387 break;
1388 default:
1389 ;
1390 }
1391
1392 return 0;
1393}
1394
1396{
1397 if (IsEmptyData())
1398 return 0;
1399
1400 sc::CellStoreType::const_iterator it = maCells.begin();
1401 if (it->type != sc::element_type_empty)
1402 return 0;
1403
1404 return it->size;
1405}
1406
1408{
1409 if (IsEmptyData())
1410 return 0;
1411
1412 sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
1413 if (it->type != sc::element_type_empty)
1414 return GetDoc().MaxRow();
1415
1416 return GetDoc().MaxRow() - static_cast<SCROW>(it->size);
1417}
1418
1419SCROW ScColumn::GetLastDataPos( SCROW nLastRow, ScDataAreaExtras* pDataAreaExtras ) const
1420{
1421 nLastRow = std::min( nLastRow, GetDoc().MaxRow());
1422
1423 if (pDataAreaExtras && pDataAreaExtras->mnEndRow < nLastRow)
1424 {
1425 // Check in order of likeliness.
1426 if ( (pDataAreaExtras->mbCellFormats && HasVisibleAttrIn(nLastRow, nLastRow)) ||
1427 (pDataAreaExtras->mbCellNotes && !IsNotesEmptyBlock(nLastRow, nLastRow)) ||
1428 (pDataAreaExtras->mbCellDrawObjects && !IsDrawObjectsEmptyBlock(nLastRow, nLastRow)))
1429 pDataAreaExtras->mnEndRow = nLastRow;
1430 }
1431
1432 sc::CellStoreType::const_position_type aPos = maCells.position(nLastRow);
1433
1434 if (aPos.first->type != sc::element_type_empty)
1435 return nLastRow;
1436
1437 if (aPos.first == maCells.begin())
1438 // This is the first block, and is empty.
1439 return 0;
1440
1441 return static_cast<SCROW>(aPos.first->position - 1);
1442}
1443
1445{
1446 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
1447 sc::CellStoreType::const_iterator it = aPos.first;
1448 if (it == maCells.end())
1449 return false;
1450
1451 if (it->type == sc::element_type_empty)
1452 {
1453 if (it == maCells.begin())
1454 // No more previous non-empty cell.
1455 return false;
1456
1457 rRow -= aPos.second + 1; // Last row position of the previous block.
1458 return true;
1459 }
1460
1461 // This block is not empty.
1462 if (aPos.second)
1463 {
1464 // There are preceding cells in this block. Simply move back one cell.
1465 --rRow;
1466 return true;
1467 }
1468
1469 // This is the first cell in a non-empty block. Move back to the previous block.
1470 if (it == maCells.begin())
1471 // No more preceding block.
1472 return false;
1473
1474 --rRow; // Move to the last cell of the previous block.
1475 --it;
1476 if (it->type == sc::element_type_empty)
1477 {
1478 // This block is empty.
1479 if (it == maCells.begin())
1480 // No more preceding blocks.
1481 return false;
1482
1483 // Skip the whole empty block segment.
1484 rRow -= it->size;
1485 }
1486
1487 return true;
1488}
1489
1490bool ScColumn::GetNextDataPos(SCROW& rRow) const // greater than rRow
1491{
1492 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
1493 sc::CellStoreType::const_iterator it = aPos.first;
1494 if (it == maCells.end())
1495 return false;
1496
1497 if (it->type == sc::element_type_empty)
1498 {
1499 // This block is empty. Skip ahead to the next block (if exists).
1500 rRow += it->size - aPos.second;
1501 ++it;
1502 if (it == maCells.end())
1503 // No more next block.
1504 return false;
1505
1506 // Next block exists, and is non-empty.
1507 return true;
1508 }
1509
1510 if (aPos.second < it->size - 1)
1511 {
1512 // There are still cells following the current position.
1513 ++rRow;
1514 return true;
1515 }
1516
1517 // This is the last cell in the block. Move ahead to the next block.
1518 rRow += it->size - aPos.second; // First cell in the next block.
1519 ++it;
1520 if (it == maCells.end())
1521 // No more next block.
1522 return false;
1523
1524 if (it->type == sc::element_type_empty)
1525 {
1526 // Next block is empty. Move to the next block.
1527 rRow += it->size;
1528 ++it;
1529 if (it == maCells.end())
1530 return false;
1531 }
1532
1533 return true;
1534}
1535
1536bool ScColumn::TrimEmptyBlocks(SCROW& rRowStart, SCROW& rRowEnd) const
1537{
1538 assert(rRowStart <= rRowEnd);
1539 SCROW nRowStartNew = rRowStart, nRowEndNew = rRowEnd;
1540
1541 // Trim down rRowStart first
1542 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRowStart);
1543 sc::CellStoreType::const_iterator it = aPos.first;
1544 if (it == maCells.end())
1545 return false;
1546
1547 if (it->type == sc::element_type_empty)
1548 {
1549 // This block is empty. Skip ahead to the next block (if exists).
1550 nRowStartNew += it->size - aPos.second;
1551 if (nRowStartNew > rRowEnd)
1552 return false;
1553 ++it;
1554 if (it == maCells.end())
1555 // No more next block.
1556 return false;
1557 }
1558
1559 // Trim up rRowEnd next
1560 aPos = maCells.position(rRowEnd);
1561 it = aPos.first;
1562 if (it == maCells.end())
1563 {
1564 rRowStart = nRowStartNew;
1565 return true; // Because trimming of rRowStart is ok
1566 }
1567
1568 if (it->type == sc::element_type_empty)
1569 {
1570 // rRowEnd cannot be in the first block which is empty !
1571 assert(it != maCells.begin());
1572 // This block is empty. Skip to the previous block (it exists).
1573 nRowEndNew -= aPos.second + 1; // Last row position of the previous block.
1574 assert(nRowStartNew <= nRowEndNew);
1575 }
1576
1577 rRowStart = nRowStartNew;
1578 rRowEnd = nRowEndNew;
1579 return true;
1580}
1581
1582SCROW ScColumn::FindNextVisibleRow(SCROW nRow, bool bForward) const
1583{
1584 if(bForward)
1585 {
1586 nRow++;
1587 SCROW nEndRow = 0;
1588 bool bHidden = GetDoc().RowHidden(nRow, nTab, nullptr, &nEndRow);
1589 if(bHidden)
1590 return std::min<SCROW>(GetDoc().MaxRow(), nEndRow + 1);
1591 else
1592 return nRow;
1593 }
1594 else
1595 {
1596 nRow--;
1597 SCROW nStartRow = GetDoc().MaxRow();
1598 bool bHidden = GetDoc().RowHidden(nRow, nTab, &nStartRow);
1599 if(bHidden)
1600 return std::max<SCROW>(0, nStartRow - 1);
1601 else
1602 return nRow;
1603 }
1604}
1605
1607 sc::CellStoreType::const_iterator& itPos, SCROW nRow, bool bForward) const
1608{
1609 ScDocument& rDocument = GetDoc();
1610 if (bForward)
1611 {
1612 do
1613 {
1614 nRow++;
1615 SCROW nEndRow = 0;
1616 bool bHidden = rDocument.RowHidden(nRow, nTab, nullptr, &nEndRow);
1617 if (bHidden)
1618 {
1619 nRow = nEndRow + 1;
1620 if(nRow >= GetDoc().MaxRow())
1621 return GetDoc().MaxRow();
1622 }
1623
1624 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
1625 itPos = aPos.first;
1626 if (itPos == maCells.end())
1627 // Invalid row.
1628 return GetDoc().MaxRow();
1629
1630 if (itPos->type != sc::element_type_empty)
1631 return nRow;
1632
1633 // Move to the last cell of the current empty block.
1634 nRow += itPos->size - aPos.second - 1;
1635 }
1636 while (nRow < GetDoc().MaxRow());
1637
1638 return GetDoc().MaxRow();
1639 }
1640
1641 do
1642 {
1643 nRow--;
1644 SCROW nStartRow = GetDoc().MaxRow();
1645 bool bHidden = rDocument.RowHidden(nRow, nTab, &nStartRow);
1646 if (bHidden)
1647 {
1648 nRow = nStartRow - 1;
1649 if(nRow <= 0)
1650 return 0;
1651 }
1652
1653 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
1654 itPos = aPos.first;
1655 if (itPos == maCells.end())
1656 // Invalid row.
1657 return 0;
1658
1659 if (itPos->type != sc::element_type_empty)
1660 return nRow;
1661
1662 // Move to the first cell of the current empty block.
1663 nRow -= aPos.second;
1664 }
1665 while (nRow > 0);
1666
1667 return 0;
1668}
1669
1671{
1672 // Remove cached values. Given how often this function is called and how (not that) often
1673 // the cached values are used, it should be more efficient to just discard everything
1674 // instead of trying to figure out each time exactly what to discard.
1676
1677 // TODO: Update column's "last updated" timestamp here.
1678
1679 assert(sal::static_int_cast<SCROW>(maCells.size()) == GetDoc().GetMaxRowCount()
1680 && "Size of the cell array is incorrect." );
1681
1682 assert(sal::static_int_cast<SCROW>(maCellTextAttrs.size()) == GetDoc().GetMaxRowCount()
1683 && "Size of the cell text attribute array is incorrect.");
1684
1685 assert(sal::static_int_cast<SCROW>(maBroadcasters.size()) == GetDoc().GetMaxRowCount()
1686 && "Size of the broadcaster array is incorrect.");
1687
1688#if DEBUG_COLUMN_STORAGE
1689 // Make sure that these two containers are synchronized wrt empty segments.
1690 auto lIsEmptyType = [](const auto& rElement) { return rElement.type == sc::element_type_empty; };
1691 // Move to the first empty blocks.
1692 auto itCell = std::find_if(maCells.begin(), maCells.end(), lIsEmptyType);
1693 auto itAttr = std::find_if(maCellTextAttrs.begin(), maCellTextAttrs.end(), lIsEmptyType);
1694
1695 while (itCell != maCells.end())
1696 {
1697 if (itCell->position != itAttr->position || itCell->size != itAttr->size)
1698 {
1699 cout << "ScColumn::CellStorageModified: Cell array and cell text attribute array are out of sync." << endl;
1700 cout << "-- cell array" << endl;
1701 maCells.dump_blocks(cout);
1702 cout << "-- attribute array" << endl;
1703 maCellTextAttrs.dump_blocks(cout);
1704 cout.flush();
1705 abort();
1706 }
1707
1708 // Move to the next empty blocks.
1709 ++itCell;
1710 itCell = std::find_if(itCell, maCells.end(), lIsEmptyType);
1711
1712 ++itAttr;
1713 itAttr = std::find_if(itAttr, maCellTextAttrs.end(), lIsEmptyType);
1714 }
1715#endif
1716}
1717
1718#if DUMP_COLUMN_STORAGE
1719
1720namespace {
1721
1722#define DUMP_FORMULA_RESULTS 0
1723
1724struct ColumnStorageDumper
1725{
1726 const ScDocument& mrDoc;
1727
1728 ColumnStorageDumper( const ScDocument& rDoc ) : mrDoc(rDoc) {}
1729
1730 void operator() (const sc::CellStoreType::value_type& rNode) const
1731 {
1732 switch (rNode.type)
1733 {
1735 cout << " * numeric block (pos=" << rNode.position << ", length=" << rNode.size << ")" << endl;
1736 break;
1738 cout << " * string block (pos=" << rNode.position << ", length=" << rNode.size << ")" << endl;
1739 break;
1741 cout << " * edit-text block (pos=" << rNode.position << ", length=" << rNode.size << ")" << endl;
1742 break;
1744 dumpFormulaBlock(rNode);
1745 break;
1747 cout << " * empty block (pos=" << rNode.position << ", length=" << rNode.size << ")" << endl;
1748 break;
1749 default:
1750 cout << " * unknown block" << endl;
1751 }
1752 }
1753
1754 void dumpFormulaBlock(const sc::CellStoreType::value_type& rNode) const
1755 {
1756 cout << " * formula block (pos=" << rNode.position << ", length=" << rNode.size << ")" << endl;
1757 sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
1758 sc::formula_block::const_iterator itEnd = sc::formula_block::end(*rNode.data);
1759
1760 for (; it != itEnd; ++it)
1761 {
1762 const ScFormulaCell* pCell = *it;
1763 if (!pCell->IsShared())
1764 {
1765 cout << " * row " << pCell->aPos.Row() << " not shared" << endl;
1766 printFormula(pCell);
1767 printResult(pCell);
1768 continue;
1769 }
1770
1771 if (pCell->GetSharedTopRow() != pCell->aPos.Row())
1772 {
1773 cout << " * row " << pCell->aPos.Row() << " shared with top row "
1774 << pCell->GetSharedTopRow() << " with length " << pCell->GetSharedLength()
1775 << endl;
1776 continue;
1777 }
1778
1779 SCROW nLen = pCell->GetSharedLength();
1780 cout << " * group: start=" << pCell->aPos.Row() << ", length=" << nLen << endl;
1781 printFormula(pCell);
1782 printResult(pCell);
1783
1784 if (nLen > 1)
1785 {
1786 for (SCROW i = 0; i < nLen-1; ++i, ++it)
1787 {
1788 pCell = *it;
1789 printResult(pCell);
1790 }
1791 }
1792 }
1793 }
1794
1795 void printFormula(const ScFormulaCell* pCell) const
1796 {
1797 sc::TokenStringContext aCxt(mrDoc, mrDoc.GetGrammar());
1798 OUString aFormula = pCell->GetCode()->CreateString(aCxt, pCell->aPos);
1799 cout << " * formula: " << aFormula << endl;
1800 }
1801
1802#if DUMP_FORMULA_RESULTS
1803 void printResult(const ScFormulaCell* pCell) const
1804 {
1805 sc::FormulaResultValue aRes = pCell->GetResult();
1806 cout << " * result: ";
1807 switch (aRes.meType)
1808 {
1810 cout << aRes.mfValue << " (type: value)";
1811 break;
1813 cout << "'" << aRes.maString.getString() << "' (type: string)";
1814 break;
1816 cout << "error (" << static_cast<int>(aRes.mnError) << ")";
1817 break;
1819 cout << "invalid";
1820 break;
1821 }
1822
1823 cout << endl;
1824 }
1825#else
1826 void printResult(const ScFormulaCell*) const
1827 {
1828 (void) this; /* loplugin:staticmethods */
1829 }
1830#endif
1831};
1832
1833}
1834
1835void ScColumn::DumpColumnStorage() const
1836{
1837 cout << "-- table: " << nTab << "; column: " << nCol << endl;
1838 std::for_each(maCells.begin(), maCells.end(), ColumnStorageDumper(GetDoc()));
1839 cout << "--" << endl;
1840}
1841#endif
1842
1844{
1845 rDestCol.maCellTextAttrs.set_empty(nRow1, nRow2); // Empty the destination range first.
1846
1847 sc::CellTextAttrStoreType::const_iterator itBlk = maCellTextAttrs.begin(), itBlkEnd = maCellTextAttrs.end();
1848
1849 // Locate the top row position.
1850 size_t nBlockStart = 0, nRowPos = static_cast<size_t>(nRow1);
1851 itBlk = std::find_if(itBlk, itBlkEnd, [&nRowPos, &nBlockStart](const auto& rAttr) {
1852 return nBlockStart <= nRowPos && nRowPos < nBlockStart + rAttr.size; });
1853
1854 if (itBlk == itBlkEnd)
1855 // Specified range not found. Bail out.
1856 return;
1857
1858 size_t nBlockEnd;
1859 size_t nOffsetInBlock = nRowPos - nBlockStart;
1860
1861 nRowPos = static_cast<size_t>(nRow2); // End row position.
1862
1863 // Keep copying until we hit the end row position.
1864 sc::celltextattr_block::const_iterator itData, itDataEnd;
1865 for (; itBlk != itBlkEnd; ++itBlk, nBlockStart = nBlockEnd, nOffsetInBlock = 0)
1866 {
1867 nBlockEnd = nBlockStart + itBlk->size;
1868 if (!itBlk->data)
1869 {
1870 // Empty block.
1871 if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1872 // This block contains the end row.
1873 rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nRowPos);
1874 else
1875 rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nBlockEnd-1);
1876
1877 continue;
1878 }
1879
1880 // Non-empty block.
1881 itData = sc::celltextattr_block::begin(*itBlk->data);
1882 itDataEnd = sc::celltextattr_block::end(*itBlk->data);
1883 std::advance(itData, nOffsetInBlock);
1884
1885 if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
1886 {
1887 // This block contains the end row. Only copy partially.
1888 size_t nOffset = nRowPos - nBlockStart + 1;
1889 itDataEnd = sc::celltextattr_block::begin(*itBlk->data);
1890 std::advance(itDataEnd, nOffset);
1891
1892 rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
1893 break;
1894 }
1895
1896 rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
1897 }
1898}
1899
1900namespace {
1901
1902class CopyCellNotesHandler
1903{
1904 ScColumn& mrDestCol;
1905 sc::CellNoteStoreType& mrDestNotes;
1906 sc::CellNoteStoreType::iterator miPos;
1907 SCTAB mnSrcTab;
1908 SCCOL mnSrcCol;
1909 SCTAB mnDestTab;
1910 SCCOL mnDestCol;
1911 SCROW mnDestOffset;
1912 bool mbCloneCaption;
1913
1914public:
1915 CopyCellNotesHandler( const ScColumn& rSrcCol, ScColumn& rDestCol, SCROW nDestOffset, bool bCloneCaption ) :
1916 mrDestCol(rDestCol),
1917 mrDestNotes(rDestCol.GetCellNoteStore()),
1918 miPos(mrDestNotes.begin()),
1919 mnSrcTab(rSrcCol.GetTab()),
1920 mnSrcCol(rSrcCol.GetCol()),
1921 mnDestTab(rDestCol.GetTab()),
1922 mnDestCol(rDestCol.GetCol()),
1923 mnDestOffset(nDestOffset),
1924 mbCloneCaption(bCloneCaption) {}
1925
1926 void operator() ( size_t nRow, const ScPostIt* p )
1927 {
1928 SCROW nDestRow = nRow + mnDestOffset;
1929 ScAddress aSrcPos(mnSrcCol, nRow, mnSrcTab);
1930 ScAddress aDestPos(mnDestCol, nDestRow, mnDestTab);
1931 ScPostIt* pNew = p->Clone(aSrcPos, mrDestCol.GetDoc(), aDestPos, mbCloneCaption).release();
1932 miPos = mrDestNotes.set(miPos, nDestRow, pNew);
1933 // Notify our LOK clients also
1935 }
1936};
1937
1938}
1939
1941 SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, bool bCloneCaption, SCROW nRowOffsetDest ) const
1942{
1943 if (IsNotesEmptyBlock(nRow1, nRow2))
1944 // The column has no cell notes to copy between specified rows.
1945 return;
1946
1947 ScDrawLayer *pDrawLayer = rDestCol.GetDoc().GetDrawLayer();
1948 bool bWasLocked = bool();
1949 if (pDrawLayer)
1950 {
1951 // Avoid O(n^2) by temporary locking SdrModel which disables broadcasting.
1952 // Each cell note adds undo listener, and all of them would be woken up in ScPostIt::CreateCaption.
1953 bWasLocked = pDrawLayer->isLocked();
1954 pDrawLayer->setLock(true);
1955 }
1956 CopyCellNotesHandler aFunc(*this, rDestCol, nRowOffsetDest, bCloneCaption);
1957 sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
1958 if (pDrawLayer)
1959 pDrawLayer->setLock(bWasLocked);
1960}
1961
1962void ScColumn::DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol, sc::ColumnBlockPosition& maDestBlockPos,
1963 bool bCloneCaption, SCROW nRowOffsetDest ) const
1964{
1965 CopyCellNotesToDocument(nStartRow, nStartRow + nDataSize -1, rDestCol, bCloneCaption, nRowOffsetDest);
1966 maDestBlockPos.miCellNotePos = rDestCol.maCellNotes.begin();
1967}
1968
1970{
1971 return maBroadcasters.get<SvtBroadcaster*>(nRow);
1972}
1973
1975{
1976 return maBroadcasters.get<SvtBroadcaster*>(nRow);
1977}
1978
1980{
1981 rBlockPos.miBroadcasterPos =
1982 maBroadcasters.set_empty(rBlockPos.miBroadcasterPos, nRow1, nRow2);
1983}
1984
1986{
1987 for (auto& rBroadcaster : maBroadcasters)
1988 {
1989 if (rBroadcaster.type == sc::element_type_broadcaster)
1990 {
1991 sc::broadcaster_block::iterator it = sc::broadcaster_block::begin(*rBroadcaster.data);
1992 sc::broadcaster_block::iterator itEnd = sc::broadcaster_block::end(*rBroadcaster.data);
1993 for (; it != itEnd; ++it)
1994 (*it)->PrepareForDestruction();
1995 }
1996 }
1997}
1998
1999namespace
2000{
2001struct BroadcasterNoListenersPredicate
2002{
2003 bool operator()( size_t, const SvtBroadcaster* broadcaster )
2004 {
2005 return !broadcaster->HasListeners();
2006 }
2007};
2008
2009}
2010
2012{
2014 return;
2015 // Clean up after ScDocument::EnableDelayDeletingBroadcasters().
2016 BroadcasterNoListenersPredicate predicate;
2017 sc::SetElementsToEmpty1<sc::broadcaster_block>( maBroadcasters, predicate );
2019}
2020
2021// Sparklines
2022
2023namespace
2024{
2025
2026class DeletingSparklinesHandler
2027{
2028 ScDocument& m_rDocument;
2029 SCTAB m_nTab;
2030
2031public:
2032 DeletingSparklinesHandler(ScDocument& rDocument, SCTAB nTab)
2033 : m_rDocument(rDocument)
2034 , m_nTab(nTab)
2035 {}
2036
2037 void operator() (size_t /*nRow*/, const sc::SparklineCell* pCell)
2038 {
2039 auto* pList = m_rDocument.GetSparklineList(m_nTab);
2040 pList->removeSparkline(pCell->getSparkline());
2041 }
2042};
2043
2044} // end anonymous ns
2045
2047{
2048 return maSparklines.get<sc::SparklineCell*>(nRow);
2049}
2050
2051void ScColumn::CreateSparklineCell(SCROW nRow, std::shared_ptr<sc::Sparkline> const& pSparkline)
2052{
2053 auto* pList = GetDoc().GetSparklineList(GetTab());
2054 pList->addSparkline(pSparkline);
2055 maSparklines.set(nRow, new sc::SparklineCell(pSparkline));
2056}
2057
2059{
2060 DeletingSparklinesHandler aFunction(GetDoc(), nTab);
2061 sc::ParseSparkline(maSparklines.begin(), maSparklines, nRow1, nRow2, aFunction);
2062
2063 rBlockPos.miSparklinePos = maSparklines.set_empty(rBlockPos.miSparklinePos, nRow1, nRow2);
2064}
2065
2067{
2068 if (!GetDoc().ValidRow(nRow))
2069 return false;
2070
2071 DeletingSparklinesHandler aFunction(GetDoc(), nTab);
2072 sc::ParseSparkline(maSparklines.begin(), maSparklines, nRow, nRow, aFunction);
2073
2074 maSparklines.set_empty(nRow, nRow);
2075 return true;
2076}
2077
2078bool ScColumn::IsSparklinesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
2079{
2080 std::pair<sc::SparklineStoreType::const_iterator,size_t> aPos = maSparklines.position(nStartRow);
2081 sc::SparklineStoreType::const_iterator it = aPos.first;
2082 if (it == maSparklines.end())
2083 return false;
2084
2085 if (it->type != sc::element_type_empty)
2086 return false;
2087
2088 // start position of next block which is not empty.
2089 SCROW nNextRow = nStartRow + it->size - aPos.second;
2090 return nEndRow < nNextRow;
2091}
2092
2093namespace
2094{
2095
2096class CopySparklinesHandler
2097{
2098 ScColumn& mrDestColumn;
2099 sc::SparklineStoreType& mrDestSparkline;
2100 sc::SparklineStoreType::iterator miDestPosition;
2101 SCROW mnDestOffset;
2102
2103public:
2104 CopySparklinesHandler(ScColumn& rDestColumn, SCROW nDestOffset)
2105 : mrDestColumn(rDestColumn)
2106 , mrDestSparkline(mrDestColumn.GetSparklineStore())
2107 , miDestPosition(mrDestSparkline.begin())
2108 , mnDestOffset(nDestOffset)
2109 {}
2110
2111 void operator() (size_t nRow, const sc::SparklineCell* pCell)
2112 {
2113 SCROW nDestRow = nRow + mnDestOffset;
2114
2115 auto const& pSparkline = pCell->getSparkline();
2116 auto const& pGroup = pCell->getSparklineGroup();
2117
2118 auto& rDestDoc = mrDestColumn.GetDoc();
2119 auto pDestinationGroup = rDestDoc.SearchSparklineGroup(pGroup->getID());
2120 if (!pDestinationGroup)
2121 pDestinationGroup = std::make_shared<sc::SparklineGroup>(*pGroup); // Copy the group
2122 auto pNewSparkline = std::make_shared<sc::Sparkline>(mrDestColumn.GetCol(), nDestRow, pDestinationGroup);
2123 pNewSparkline->setInputRange(pSparkline->getInputRange());
2124
2125 auto* pList = rDestDoc.GetSparklineList(mrDestColumn.GetTab());
2126 pList->addSparkline(pNewSparkline);
2127
2128 miDestPosition = mrDestSparkline.set(miDestPosition, nDestRow, new sc::SparklineCell(pNewSparkline));
2129 }
2130};
2131
2132}
2133
2134void ScColumn::CopyCellSparklinesToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, SCROW nRowOffsetDest) const
2135{
2136 if (IsSparklinesEmptyBlock(nRow1, nRow2))
2137 // The column has no cell sparklines to copy between specified rows.
2138 return;
2139
2140 CopySparklinesHandler aFunctor(rDestCol, nRowOffsetDest);
2141 sc::ParseSparkline(maSparklines.begin(), maSparklines, nRow1, nRow2, aFunctor);
2142}
2143
2144void ScColumn::DuplicateSparklines(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol,
2145 sc::ColumnBlockPosition& rDestBlockPos, SCROW nRowOffsetDest) const
2146{
2147 CopyCellSparklinesToDocument(nStartRow, nStartRow + nDataSize - 1, rDestCol, nRowOffsetDest);
2148 rDestBlockPos.miSparklinePos = rDestCol.maSparklines.begin();
2149}
2150
2152{
2153 if (maSparklines.block_size() == 1 && maSparklines.begin()->type == sc::element_type_empty)
2154 return false; // all elements are empty
2155 return true; // otherwise some must be sparklines
2156}
2157
2159{
2160 SCROW maxRow = 0;
2161 for (const auto& rSparkline : maSparklines)
2162 {
2163 if (rSparkline.type == sc::element_type_sparkline)
2164 maxRow = rSparkline.position + rSparkline.size - 1;
2165 }
2166 return maxRow;
2167}
2168
2170{
2171 SCROW minRow = 0;
2172 sc::SparklineStoreType::const_iterator it = std::find_if(maSparklines.begin(), maSparklines.end(),
2173 [](const auto& rSparkline)
2174 {
2175 return rSparkline.type == sc::element_type_sparkline;
2176 });
2177 if (it != maSparklines.end())
2178 minRow = it->position;
2179 return minRow;
2180}
2181
2182// Notes
2183
2185{
2186 return maCellNotes.get<ScPostIt*>(nRow);
2187}
2188
2190{
2191 return maCellNotes.get<ScPostIt*>(nRow);
2192}
2193
2195{
2196 sc::CellNoteStoreType::const_position_type aPos = maCellNotes.position(rBlockPos.miCellNotePos, nRow);
2197 rBlockPos.miCellNotePos = aPos.first;
2198
2199 if (aPos.first->type != sc::element_type_cellnote)
2200 return nullptr;
2201
2202 return sc::cellnote_block::at(*aPos.first->data, aPos.second);
2203}
2204
2206{
2207 return const_cast<ScPostIt*>(const_cast<const ScColumn*>(this)->GetCellNote( rBlockPos, nRow ));
2208}
2209
2210void ScColumn::SetCellNote(SCROW nRow, std::unique_ptr<ScPostIt> pNote)
2211{
2212 //pNote->UpdateCaptionPos(ScAddress(nCol, nRow, nTab)); // TODO notes useful ? slow import with many notes
2213 maCellNotes.set(nRow, pNote.release());
2214}
2215
2216namespace {
2217 class CellNoteHandler
2218 {
2219 const ScDocument* m_pDocument;
2220 const ScAddress m_aAddress; // 'incomplete' address consisting of tab, column
2221 const bool m_bForgetCaptionOwnership;
2222
2223 public:
2224 CellNoteHandler(const ScDocument* pDocument, const ScAddress& rPos, bool bForgetCaptionOwnership) :
2225 m_pDocument(pDocument),
2226 m_aAddress(rPos),
2227 m_bForgetCaptionOwnership(bForgetCaptionOwnership) {}
2228
2229 void operator() ( size_t nRow, ScPostIt* p )
2230 {
2231 if (m_bForgetCaptionOwnership)
2232 p->ForgetCaption();
2233
2234 // Create a 'complete' address object
2235 ScAddress aAddr(m_aAddress);
2236 aAddr.SetRow(nRow);
2237 // Notify our LOK clients
2239 }
2240 };
2241} // anonymous namespace
2242
2243void ScColumn::CellNotesDeleting(SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
2244{
2245 ScAddress aAddr(nCol, 0, nTab);
2246 CellNoteHandler aFunc(&GetDoc(), aAddr, bForgetCaptionOwnership);
2247 sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
2248}
2249
2250void ScColumn::DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership )
2251{
2252 CellNotesDeleting(nRow1, nRow2, bForgetCaptionOwnership);
2253
2254 rBlockPos.miCellNotePos =
2255 maCellNotes.set_empty(rBlockPos.miCellNotePos, nRow1, nRow2);
2256}
2257
2259{
2260 if (maCellNotes.block_size() == 1 && maCellNotes.begin()->type == sc::element_type_empty)
2261 return false; // all elements are empty
2262 return true; // otherwise some must be notes
2263}
2264
2266{
2267 // hypothesis : the column has cell notes (should be checked before)
2268 SCROW maxRow = 0;
2269 for (const auto& rCellNote : maCellNotes)
2270 {
2271 if (rCellNote.type == sc::element_type_cellnote)
2272 maxRow = rCellNote.position + rCellNote.size -1;
2273 }
2274 return maxRow;
2275}
2277{
2278 // hypothesis : the column has cell notes (should be checked before)
2279 SCROW minRow = 0;
2280 sc::CellNoteStoreType::const_iterator it = std::find_if(maCellNotes.begin(), maCellNotes.end(),
2281 [](const auto& rCellNote) { return rCellNote.type == sc::element_type_cellnote; });
2282 if (it != maCellNotes.end())
2283 minRow = it->position;
2284 return minRow;
2285}
2286
2287sal_uInt16 ScColumn::GetTextWidth(SCROW nRow) const
2288{
2289 return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnTextWidth;
2290}
2291
2292void ScColumn::SetTextWidth(SCROW nRow, sal_uInt16 nWidth)
2293{
2294 sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
2295 if (aPos.first->type != sc::element_type_celltextattr)
2296 return;
2297
2298 // Set new value only when the slot is not empty.
2299 sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnTextWidth = nWidth;
2301}
2302
2304{
2305 if (!GetDoc().ValidRow(nRow) || maCellTextAttrs.is_empty(nRow))
2306 return SvtScriptType::NONE;
2307
2308 return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnScriptType;
2309}
2310
2312 sc::CellTextAttrStoreType::iterator& itPos, SCROW nRow1, SCROW nRow2, const sc::CellStoreType::iterator& itrCells_ )
2313{
2314 if (!GetDoc().ValidRow(nRow1) || !GetDoc().ValidRow(nRow2) || nRow1 > nRow2)
2315 return SvtScriptType::NONE;
2316
2317 SCROW nRow = nRow1;
2318 std::pair<sc::CellTextAttrStoreType::iterator,size_t> aRet =
2319 maCellTextAttrs.position(itPos, nRow1);
2320
2321 itPos = aRet.first; // Track the position of cell text attribute array.
2322 sc::CellStoreType::iterator itrCells = itrCells_;
2323
2324 SvtScriptType nScriptType = SvtScriptType::NONE;
2325 bool bUpdated = false;
2326 if (itPos->type == sc::element_type_celltextattr)
2327 {
2328 sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
2329 sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
2330 std::advance(it, aRet.second);
2331 for (; it != itEnd; ++it, ++nRow)
2332 {
2333 if (nRow > nRow2)
2334 return nScriptType;
2335
2336 sc::CellTextAttr& rVal = *it;
2337 if (UpdateScriptType(rVal, nRow, itrCells))
2338 bUpdated = true;
2339 nScriptType |= rVal.mnScriptType;
2340 }
2341 }
2342 else
2343 {
2344 // Skip this whole block.
2345 nRow += itPos->size - aRet.second;
2346 }
2347
2348 while (nRow <= nRow2)
2349 {
2350 ++itPos;
2351 if (itPos == maCellTextAttrs.end())
2352 return nScriptType;
2353
2354 if (itPos->type != sc::element_type_celltextattr)
2355 {
2356 // Skip this whole block.
2357 nRow += itPos->size;
2358 continue;
2359 }
2360
2361 sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
2362 sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
2363 for (; it != itEnd; ++it, ++nRow)
2364 {
2365 if (nRow > nRow2)
2366 return nScriptType;
2367
2368 sc::CellTextAttr& rVal = *it;
2369 if (UpdateScriptType(rVal, nRow, itrCells))
2370 bUpdated = true;
2371
2372 nScriptType |= rVal.mnScriptType;
2373 }
2374 }
2375
2376 if (bUpdated)
2378
2379 return nScriptType;
2380}
2381
2383{
2384 if (!GetDoc().ValidRow(nRow))
2385 return;
2386
2387 sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
2388 if (aPos.first->type != sc::element_type_celltextattr)
2389 // Set new value only when the slot is already set.
2390 return;
2391
2392 sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnScriptType = nType;
2394}
2395
2397{
2398 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
2399 sc::CellStoreType::iterator it = aPos.first;
2400 if (it == maCells.end())
2401 // Invalid row. Return a null token.
2402 return formula::FormulaTokenRef();
2403
2404 switch (it->type)
2405 {
2407 {
2408 double fVal = sc::numeric_block::at(*it->data, aPos.second);
2410 }
2412 {
2413 ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
2414 if (p->IsValue())
2416
2417 return formula::FormulaTokenRef(new formula::FormulaStringToken(p->GetString()));
2418 }
2420 {
2421 const svl::SharedString& rSS = sc::string_block::at(*it->data, aPos.second);
2423 }
2425 {
2426 const EditTextObject* pText = sc::edittext_block::at(*it->data, aPos.second);
2427 OUString aStr = ScEditUtil::GetString(*pText, &GetDoc());
2428 svl::SharedString aSS( GetDoc().GetSharedStringPool().intern(aStr));
2429 return formula::FormulaTokenRef(new formula::FormulaStringToken(std::move(aSS)));
2430 }
2432 default:
2433 // Return a value of 0.0 in all the other cases.
2435 }
2436}
2437
2438namespace {
2439
2440class ToMatrixHandler
2441{
2442 ScMatrix& mrMat;
2443 SCCOL mnMatCol;
2444 SCROW mnTopRow;
2445 ScDocument* mpDoc;
2446 svl::SharedStringPool& mrStrPool;
2447public:
2448 ToMatrixHandler(ScMatrix& rMat, SCCOL nMatCol, SCROW nTopRow, ScDocument* pDoc) :
2449 mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow),
2450 mpDoc(pDoc), mrStrPool(pDoc->GetSharedStringPool()) {}
2451
2452 void operator() (size_t nRow, double fVal)
2453 {
2454 mrMat.PutDouble(fVal, mnMatCol, nRow - mnTopRow);
2455 }
2456
2457 void operator() (size_t nRow, const ScFormulaCell* p)
2458 {
2459 // Formula cell may need to re-calculate.
2460 ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*p);
2461 if (rCell.IsValue())
2462 mrMat.PutDouble(rCell.GetValue(), mnMatCol, nRow - mnTopRow);
2463 else
2464 mrMat.PutString(rCell.GetString(), mnMatCol, nRow - mnTopRow);
2465 }
2466
2467 void operator() (size_t nRow, const svl::SharedString& rSS)
2468 {
2469 mrMat.PutString(rSS, mnMatCol, nRow - mnTopRow);
2470 }
2471
2472 void operator() (size_t nRow, const EditTextObject* pStr)
2473 {
2474 mrMat.PutString(mrStrPool.intern(ScEditUtil::GetString(*pStr, mpDoc)), mnMatCol, nRow - mnTopRow);
2475 }
2476};
2477
2478}
2479
2480bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
2481{
2482 if (nRow1 > nRow2)
2483 return false;
2484
2485 ToMatrixHandler aFunc(rMat, nMatCol, nRow1, &GetDoc());
2486 sc::ParseAllNonEmpty(maCells.begin(), maCells, nRow1, nRow2, aFunc);
2487 return true;
2488}
2489
2490namespace {
2491
2492struct CellBucket
2493{
2494 SCSIZE mnEmpValStart;
2495 SCSIZE mnNumValStart;
2496 SCSIZE mnStrValStart;
2497 SCSIZE mnEmpValCount;
2498 std::vector<double> maNumVals;
2499 std::vector<svl::SharedString> maStrVals;
2500
2501 CellBucket() : mnEmpValStart(0), mnNumValStart(0), mnStrValStart(0), mnEmpValCount(0) {}
2502
2503 void flush(ScMatrix& rMat, SCSIZE nCol)
2504 {
2505 if (mnEmpValCount)
2506 {
2507 rMat.PutEmptyResultVector(mnEmpValCount, nCol, mnEmpValStart);
2508 reset();
2509 }
2510 else if (!maNumVals.empty())
2511 {
2512 const double* p = maNumVals.data();
2513 rMat.PutDouble(p, maNumVals.size(), nCol, mnNumValStart);
2514 reset();
2515 }
2516 else if (!maStrVals.empty())
2517 {
2518 const svl::SharedString* p = maStrVals.data();
2519 rMat.PutString(p, maStrVals.size(), nCol, mnStrValStart);
2520 reset();
2521 }
2522 }
2523
2524 void reset()
2525 {
2526 mnEmpValStart = mnNumValStart = mnStrValStart = 0;
2527 mnEmpValCount = 0;
2528 maNumVals.clear();
2529 maStrVals.clear();
2530 }
2531};
2532
2533class FillMatrixHandler
2534{
2535 ScMatrix& mrMat;
2536 size_t mnMatCol;
2537 size_t mnTopRow;
2538
2539 ScDocument* mpDoc;
2540 svl::SharedStringPool& mrPool;
2541 svl::SharedStringPool* mpPool; // if matrix is not in the same document
2542
2543public:
2544 FillMatrixHandler(ScMatrix& rMat, size_t nMatCol, size_t nTopRow, ScDocument* pDoc, svl::SharedStringPool* pPool) :
2545 mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow),
2546 mpDoc(pDoc), mrPool(pDoc->GetSharedStringPool()), mpPool(pPool) {}
2547
2548 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
2549 {
2550 size_t nMatRow = node.position + nOffset - mnTopRow;
2551
2552 switch (node.type)
2553 {
2555 {
2556 const double* p = &sc::numeric_block::at(*node.data, nOffset);
2557 mrMat.PutDouble(p, nDataSize, mnMatCol, nMatRow);
2558 }
2559 break;
2561 {
2562 if (!mpPool)
2563 {
2564 const svl::SharedString* p = &sc::string_block::at(*node.data, nOffset);
2565 mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
2566 }
2567 else
2568 {
2569 std::vector<svl::SharedString> aStrings;
2570 aStrings.reserve(nDataSize);
2571 const svl::SharedString* p = &sc::string_block::at(*node.data, nOffset);
2572 for (size_t i = 0; i < nDataSize; ++i)
2573 {
2574 aStrings.push_back(mpPool->intern(p[i].getString()));
2575 }
2576 mrMat.PutString(aStrings.data(), aStrings.size(), mnMatCol, nMatRow);
2577 }
2578 }
2579 break;
2581 {
2582 std::vector<svl::SharedString> aSSs;
2583 aSSs.reserve(nDataSize);
2584 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
2585 std::advance(it, nOffset);
2586 sc::edittext_block::const_iterator itEnd = it;
2587 std::advance(itEnd, nDataSize);
2588 for (; it != itEnd; ++it)
2589 {
2590 OUString aStr = ScEditUtil::GetString(**it, mpDoc);
2591 if (!mpPool)
2592 aSSs.push_back(mrPool.intern(aStr));
2593 else
2594 aSSs.push_back(mpPool->intern(aStr));
2595 }
2596
2597 const svl::SharedString* p = aSSs.data();
2598 mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
2599 }
2600 break;
2602 {
2603 CellBucket aBucket;
2604 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
2605 std::advance(it, nOffset);
2606 sc::formula_block::const_iterator itEnd = it;
2607 std::advance(itEnd, nDataSize);
2608
2609 size_t nPrevRow = 0, nThisRow = node.position + nOffset;
2610 for (; it != itEnd; ++it, nPrevRow = nThisRow, ++nThisRow)
2611 {
2612 ScFormulaCell& rCell = **it;
2613
2614 if (rCell.IsEmpty())
2615 {
2616 if (aBucket.mnEmpValCount && nThisRow == nPrevRow + 1)
2617 {
2618 // Secondary empty results.
2619 ++aBucket.mnEmpValCount;
2620 }
2621 else
2622 {
2623 // First empty result.
2624 aBucket.flush(mrMat, mnMatCol);
2625 aBucket.mnEmpValStart = nThisRow - mnTopRow;
2626 ++aBucket.mnEmpValCount;
2627 }
2628 continue;
2629 }
2630
2631 FormulaError nErr;
2632 double fVal;
2633 if (rCell.GetErrorOrValue(nErr, fVal))
2634 {
2635 if (nErr != FormulaError::NONE)
2636 fVal = CreateDoubleError(nErr);
2637
2638 if (!aBucket.maNumVals.empty() && nThisRow == nPrevRow + 1)
2639 {
2640 // Secondary numbers.
2641 aBucket.maNumVals.push_back(fVal);
2642 }
2643 else
2644 {
2645 // First number.
2646 aBucket.flush(mrMat, mnMatCol);
2647 aBucket.mnNumValStart = nThisRow - mnTopRow;
2648 aBucket.maNumVals.push_back(fVal);
2649 }
2650 continue;
2651 }
2652
2654 if (mpPool)
2655 aStr = mpPool->intern(aStr.getString());
2656 if (!aBucket.maStrVals.empty() && nThisRow == nPrevRow + 1)
2657 {
2658 // Secondary strings.
2659 aBucket.maStrVals.push_back(aStr);
2660 }
2661 else
2662 {
2663 // First string.
2664 aBucket.flush(mrMat, mnMatCol);
2665 aBucket.mnStrValStart = nThisRow - mnTopRow;
2666 aBucket.maStrVals.push_back(aStr);
2667 }
2668 }
2669
2670 aBucket.flush(mrMat, mnMatCol);
2671 }
2672 break;
2673 default:
2674 ;
2675 }
2676 }
2677};
2678
2679}
2680
2681void ScColumn::FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2, svl::SharedStringPool* pPool ) const
2682{
2683 FillMatrixHandler aFunc(rMat, nMatCol, nRow1, &GetDoc(), pPool);
2684 sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
2685}
2686
2687namespace {
2688
2689template<typename Blk>
2690void getBlockIterators(
2691 const sc::CellStoreType::iterator& it, size_t& rLenRemain,
2692 typename Blk::iterator& rData, typename Blk::iterator& rDataEnd )
2693{
2694 rData = Blk::begin(*it->data);
2695 if (rLenRemain >= it->size)
2696 {
2697 // Block is shorter than the remaining requested length.
2698 rDataEnd = Blk::end(*it->data);
2699 rLenRemain -= it->size;
2700 }
2701 else
2702 {
2703 rDataEnd = rData;
2704 std::advance(rDataEnd, rLenRemain);
2705 rLenRemain = 0;
2706 }
2707}
2708
2709bool appendToBlock(
2711 size_t nPos, size_t nArrayLen, const sc::CellStoreType::iterator& _it, const sc::CellStoreType::iterator& itEnd )
2712{
2714 size_t nLenRemain = nArrayLen - nPos;
2715
2716 for (sc::CellStoreType::iterator it = _it; it != itEnd; ++it)
2717 {
2718 switch (it->type)
2719 {
2721 {
2722 sc::string_block::iterator itData, itDataEnd;
2723 getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
2724 rCxt.ensureStrArray(rColArray, nArrayLen);
2725
2726 for (; itData != itDataEnd; ++itData, ++nPos)
2727 (*rColArray.mpStrArray)[nPos] = itData->getData();
2728 }
2729 break;
2731 {
2732 sc::edittext_block::iterator itData, itDataEnd;
2733 getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd);
2734 rCxt.ensureStrArray(rColArray, nArrayLen);
2735
2736 for (; itData != itDataEnd; ++itData, ++nPos)
2737 {
2738 OUString aStr = ScEditUtil::GetString(**itData, pDoc);
2739 (*rColArray.mpStrArray)[nPos] = rPool.intern(aStr).getData();
2740 }
2741 }
2742 break;
2744 {
2745 sc::formula_block::iterator itData, itDataEnd;
2746 getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd);
2747
2748 /* tdf#91416 setting progress in triggers a resize of the window
2749 and so ScTabView::DoResize and an InterpretVisible and
2750 InterpretDirtyCells which resets the mpFormulaGroupCxt that
2751 the current rCxt points to, which is bad, so disable progress
2752 during GetResult
2753 */
2755 bool bTempDisableProgress = pProgress && pProgress->Enabled();
2756 if (bTempDisableProgress)
2757 pProgress->Disable();
2758
2759 for (; itData != itDataEnd; ++itData, ++nPos)
2760 {
2761 ScFormulaCell& rFC = **itData;
2762
2763 sc::FormulaResultValue aRes = rFC.GetResult();
2764
2765 if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError != FormulaError::NONE)
2766 {
2767 if (aRes.mnError == FormulaError::CircularReference)
2768 {
2769 // This cell needs to be recalculated on next visit.
2770 rFC.SetErrCode(FormulaError::NONE);
2771 rFC.SetDirtyVar();
2772 }
2773 return false;
2774 }
2775
2777 {
2778 rCxt.ensureStrArray(rColArray, nArrayLen);
2779 (*rColArray.mpStrArray)[nPos] = aRes.maString.getData();
2780 }
2781 else
2782 {
2783 rCxt.ensureNumArray(rColArray, nArrayLen);
2784 (*rColArray.mpNumArray)[nPos] = aRes.mfValue;
2785 }
2786 }
2787
2788 if (bTempDisableProgress)
2789 pProgress->Enable();
2790 }
2791 break;
2793 {
2794 if (nLenRemain > it->size)
2795 {
2796 nPos += it->size;
2797 nLenRemain -= it->size;
2798 }
2799 else
2800 {
2801 nPos = nArrayLen;
2802 nLenRemain = 0;
2803 }
2804 }
2805 break;
2807 {
2808 sc::numeric_block::iterator itData, itDataEnd;
2809 getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
2810 rCxt.ensureNumArray(rColArray, nArrayLen);
2811
2812 for (; itData != itDataEnd; ++itData, ++nPos)
2813 (*rColArray.mpNumArray)[nPos] = *itData;
2814 }
2815 break;
2816 default:
2817 return false;
2818 }
2819
2820 if (!nLenRemain)
2821 return true;
2822 }
2823
2824 return false;
2825}
2826
2827void copyFirstStringBlock(
2828 ScDocument& rDoc, sc::FormulaGroupContext::StrArrayType& rArray, size_t nLen, const sc::CellStoreType::iterator& itBlk )
2829{
2830 sc::FormulaGroupContext::StrArrayType::iterator itArray = rArray.begin();
2831
2832 switch (itBlk->type)
2833 {
2835 {
2836 sc::string_block::iterator it = sc::string_block::begin(*itBlk->data);
2837 sc::string_block::iterator itEnd = it;
2838 std::advance(itEnd, nLen);
2839 for (; it != itEnd; ++it, ++itArray)
2840 *itArray = it->getData();
2841 }
2842 break;
2844 {
2845 sc::edittext_block::iterator it = sc::edittext_block::begin(*itBlk->data);
2846 sc::edittext_block::iterator itEnd = it;
2847 std::advance(itEnd, nLen);
2848
2850 for (; it != itEnd; ++it, ++itArray)
2851 {
2852 EditTextObject* pText = *it;
2853 OUString aStr = ScEditUtil::GetString(*pText, &rDoc);
2854 *itArray = rPool.intern(aStr).getData();
2855 }
2856 }
2857 break;
2858 default:
2859 ;
2860 }
2861}
2862
2864copyFirstFormulaBlock(
2865 sc::FormulaGroupContext& rCxt, const sc::CellStoreType::iterator& itBlk, size_t nArrayLen,
2866 SCTAB nTab, SCCOL nCol )
2867{
2868 size_t nLen = std::min(itBlk->size, nArrayLen);
2869
2870 sc::formula_block::iterator it = sc::formula_block::begin(*itBlk->data);
2871 sc::formula_block::iterator itEnd;
2872
2873 sc::FormulaGroupContext::NumArrayType* pNumArray = nullptr;
2874 sc::FormulaGroupContext::StrArrayType* pStrArray = nullptr;
2875
2876 itEnd = it;
2877 std::advance(itEnd, nLen);
2878 size_t nPos = 0;
2879 for (; it != itEnd; ++it, ++nPos)
2880 {
2881 ScFormulaCell& rFC = **it;
2882 sc::FormulaResultValue aRes = rFC.GetResult();
2883 if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError != FormulaError::NONE)
2884 {
2885 if (aRes.mnError == FormulaError::CircularReference)
2886 {
2887 // This cell needs to be recalculated on next visit.
2888 rFC.SetErrCode(FormulaError::NONE);
2889 rFC.SetDirtyVar();
2890 }
2891 return nullptr;
2892 }
2893
2895 {
2896 if (!pNumArray)
2897 {
2898 rCxt.m_NumArrays.push_back(
2899 std::make_unique<sc::FormulaGroupContext::NumArrayType>(nArrayLen,
2900 std::numeric_limits<double>::quiet_NaN()));
2901 pNumArray = rCxt.m_NumArrays.back().get();
2902 }
2903
2904 (*pNumArray)[nPos] = aRes.mfValue;
2905 }
2906 else
2907 {
2908 if (!pStrArray)
2909 {
2910 rCxt.m_StrArrays.push_back(
2911 std::make_unique<sc::FormulaGroupContext::StrArrayType>(nArrayLen, nullptr));
2912 pStrArray = rCxt.m_StrArrays.back().get();
2913 }
2914
2915 (*pStrArray)[nPos] = aRes.maString.getData();
2916 }
2917 }
2918
2919 if (!pNumArray && !pStrArray)
2920 // At least one of these arrays should be allocated.
2921 return nullptr;
2922
2923 return rCxt.setCachedColArray(nTab, nCol, pNumArray, pStrArray);
2924}
2925
2926struct NonNullStringFinder
2927{
2928 bool operator() (const rtl_uString* p) const { return p != nullptr; }
2929};
2930
2931bool hasNonEmpty( const sc::FormulaGroupContext::StrArrayType& rArray, SCROW nRow1, SCROW nRow2 )
2932{
2933 // The caller has to make sure the array is at least nRow2+1 long.
2934 sc::FormulaGroupContext::StrArrayType::const_iterator it = rArray.begin();
2935 std::advance(it, nRow1);
2936 sc::FormulaGroupContext::StrArrayType::const_iterator itEnd = it;
2937 std::advance(itEnd, nRow2-nRow1+1);
2938 return std::any_of(it, itEnd, NonNullStringFinder());
2939}
2940
2941struct ProtectFormulaGroupContext
2942{
2943 ProtectFormulaGroupContext( ScDocument* d )
2944 : doc( d ) { doc->BlockFormulaGroupContextDiscard( true ); }
2945 ~ProtectFormulaGroupContext()
2946 { doc->BlockFormulaGroupContextDiscard( false ); }
2947 ScDocument* doc;
2948};
2949
2950}
2951
2953{
2954 if (nRow1 > nRow2)
2956
2957 // See if the requested range is already cached.
2958 ScDocument& rDocument = GetDoc();
2959 sc::FormulaGroupContext& rCxt = *(rDocument.GetFormulaGroupContext());
2960 sc::FormulaGroupContext::ColArray* pColArray = rCxt.getCachedColArray(nTab, nCol, nRow2+1);
2961 if (pColArray)
2962 {
2963 const double* pNum = nullptr;
2964 if (pColArray->mpNumArray)
2965 pNum = &(*pColArray->mpNumArray)[nRow1];
2966
2967 rtl_uString** pStr = nullptr;
2968 if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
2969 pStr = &(*pColArray->mpStrArray)[nRow1];
2970
2971 return formula::VectorRefArray(pNum, pStr);
2972 }
2973
2974 // ScColumn::CellStorageModified() simply discards the entire cache (FormulaGroupContext)
2975 // on any modification. However getting cell values may cause this to be called
2976 // if interpreting a cell results in a change to it (not just its result though).
2977 // So temporarily block the discarding.
2978 ProtectFormulaGroupContext protectContext(&GetDoc());
2979
2980 // We need to fetch all cell values from row 0 to nRow2 for caching purposes.
2981 sc::CellStoreType::iterator itBlk = maCells.begin();
2982 switch (itBlk->type)
2983 {
2985 {
2986 if (o3tl::make_unsigned(nRow2) < itBlk->size)
2987 {
2988 // Requested range falls within the first block. No need to cache.
2989 const double* p = &sc::numeric_block::at(*itBlk->data, nRow1);
2990 return formula::VectorRefArray(p);
2991 }
2992
2993 // Allocate a new array and copy the values to it.
2994 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*itBlk->data);
2995 sc::numeric_block::const_iterator itEnd = sc::numeric_block::end(*itBlk->data);
2996 rCxt.m_NumArrays.push_back(
2997 std::make_unique<sc::FormulaGroupContext::NumArrayType>(it, itEnd));
2999 // allocate to the requested length.
3000 rArray.resize(nRow2+1, std::numeric_limits<double>::quiet_NaN());
3001
3002 pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, nullptr);
3003 if (!pColArray)
3004 // Failed to insert a new cached column array.
3006
3007 // Fill the remaining array with values from the following blocks.
3008 size_t nPos = itBlk->size;
3009 ++itBlk;
3010 if (!appendToBlock(&rDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
3011 {
3014 }
3015
3016 rtl_uString** pStr = nullptr;
3017 if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
3018 pStr = &(*pColArray->mpStrArray)[nRow1];
3019
3020 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], pStr);
3021 }
3022 break;
3025 {
3026 rCxt.m_StrArrays.push_back(
3027 std::make_unique<sc::FormulaGroupContext::StrArrayType>(nRow2+1, nullptr));
3029 pColArray = rCxt.setCachedColArray(nTab, nCol, nullptr, &rArray);
3030 if (!pColArray)
3031 // Failed to insert a new cached column array.
3032 return formula::VectorRefArray();
3033
3034 if (o3tl::make_unsigned(nRow2) < itBlk->size)
3035 {
3036 // Requested range falls within the first block.
3037 copyFirstStringBlock(rDocument, rArray, nRow2+1, itBlk);
3038 return formula::VectorRefArray(&rArray[nRow1]);
3039 }
3040
3041 copyFirstStringBlock(rDocument, rArray, itBlk->size, itBlk);
3042
3043 // Fill the remaining array with values from the following blocks.
3044 size_t nPos = itBlk->size;
3045 ++itBlk;
3046 if (!appendToBlock(&rDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
3047 {
3050 }
3051
3052 assert(pColArray->mpStrArray);
3053
3054 rtl_uString** pStr = nullptr;
3055 if (hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
3056 pStr = &(*pColArray->mpStrArray)[nRow1];
3057
3058 if (pColArray->mpNumArray)
3059 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], pStr);
3060 else
3061 return formula::VectorRefArray(pStr);
3062 }
3063 break;
3065 {
3066 if (o3tl::make_unsigned(nRow2) < itBlk->size)
3067 {
3068 // Requested length is within a single block, and the data is
3069 // not cached.
3070 pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
3071 if (!pColArray)
3072 // Failed to insert a new cached column array.
3074
3075 const double* pNum = nullptr;
3076 rtl_uString** pStr = nullptr;
3077 if (pColArray->mpNumArray)
3078 pNum = &(*pColArray->mpNumArray)[nRow1];
3079 if (pColArray->mpStrArray)
3080 pStr = &(*pColArray->mpStrArray)[nRow1];
3081
3082 return formula::VectorRefArray(pNum, pStr);
3083 }
3084
3085 pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
3086 if (!pColArray)
3087 {
3088 // Failed to insert a new cached column array.
3090 }
3091
3092 size_t nPos = itBlk->size;
3093 ++itBlk;
3094 if (!appendToBlock(&rDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
3095 {
3098 }
3099
3100 const double* pNum = nullptr;
3101 rtl_uString** pStr = nullptr;
3102 if (pColArray->mpNumArray)
3103 pNum = &(*pColArray->mpNumArray)[nRow1];
3104 if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
3105 pStr = &(*pColArray->mpStrArray)[nRow1];
3106
3107 return formula::VectorRefArray(pNum, pStr);
3108 }
3109 break;
3111 {
3112 // Fill the whole length with NaN's.
3113 rCxt.m_NumArrays.push_back(
3114 std::make_unique<sc::FormulaGroupContext::NumArrayType>(nRow2+1,
3115 std::numeric_limits<double>::quiet_NaN()));
3117 pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, nullptr);
3118 if (!pColArray)
3119 // Failed to insert a new cached column array.
3121
3122 if (o3tl::make_unsigned(nRow2) < itBlk->size)
3123 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
3124
3125 // Fill the remaining array with values from the following blocks.
3126 size_t nPos = itBlk->size;
3127 ++itBlk;
3128 if (!appendToBlock(&rDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
3129 {
3132 }
3133
3134 if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
3135 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
3136 else
3137 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
3138 }
3139 break;
3140 default:
3141 ;
3142 }
3143
3145}
3146
3147#ifdef DBG_UTIL
3148static void assertNoInterpretNeededHelper( const sc::CellStoreType::value_type& node,
3149 size_t nOffset, size_t nDataSize )
3150{
3151 switch (node.type)
3152 {
3154 {
3155 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
3156 std::advance(it, nOffset);
3157 sc::formula_block::const_iterator itEnd = it;
3158 std::advance(itEnd, nDataSize);
3159 for (; it != itEnd; ++it)
3160 {
3161 const ScFormulaCell* pCell = *it;
3162 assert( !pCell->NeedsInterpret());
3163 }
3164 break;
3165 }
3166 }
3167}
3169{
3170 assert(nRow2 >= nRow1);
3172}
3173#endif
3174
3175void ScColumn::SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen )
3176{
3177 sc::CellStoreType::position_type aPos = maCells.position(nRow);
3178 sc::CellStoreType::iterator it = aPos.first;
3179 if (it->type != sc::element_type_formula)
3180 {
3181 // This is not a formula block.
3182 assert( false );
3183 return;
3184 }
3185
3186 size_t nBlockLen = it->size - aPos.second;
3187 if (nBlockLen < nLen)
3188 {
3189 // Result array is longer than the length of formula cells. Not good.
3190 assert( false );
3191 return;
3192 }
3193
3194 sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
3195 std::advance(itCell, aPos.second);
3196
3197 const double* pResEnd = pResults + nLen;
3198 for (; pResults != pResEnd; ++pResults, ++itCell)
3199 {
3200 ScFormulaCell& rCell = **itCell;
3201 FormulaError nErr = GetDoubleErrorValue(*pResults);
3202 if (nErr != FormulaError::NONE)
3203 rCell.SetResultError(nErr);
3204 else
3205 rCell.SetResultDouble(*pResults);
3206 rCell.ResetDirty();
3207 rCell.SetChanged(true);
3208 }
3209}
3210
3211void ScColumn::CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, size_t nLen, size_t nOffset,
3212 unsigned nThisThread, unsigned nThreadsTotal)
3213{
3214 assert(GetDoc().IsThreadedGroupCalcInProgress());
3215
3216 sc::CellStoreType::position_type aPos = maCells.position(nRow);
3217 sc::CellStoreType::iterator it = aPos.first;
3218 if (it->type != sc::element_type_formula)
3219 {
3220 // This is not a formula block.
3221 assert( false );
3222 return;
3223 }
3224
3225 size_t nBlockLen = it->size - aPos.second;
3226 if (nBlockLen < nLen)
3227 {
3228 // Length is longer than the length of formula cells. Not good.
3229 assert( false );
3230 return;
3231 }
3232
3233 sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
3234 std::advance(itCell, aPos.second);
3235
3236 for (size_t i = 0; i < nLen; ++i, ++itCell)
3237 {
3238 if (nThreadsTotal > 0 && ((i + nOffset) % nThreadsTotal) != nThisThread)
3239 continue;
3240
3241 ScFormulaCell& rCell = **itCell;
3242 if (!rCell.NeedsInterpret())
3243 continue;
3244 // Here we don't call IncInterpretLevel() and DecInterpretLevel() as this call site is
3245 // always in a threaded calculation.
3247 }
3248}
3249
3251{
3252 sc::CellStoreType::position_type aPos = maCells.position(nRow);
3253 sc::CellStoreType::iterator it = aPos.first;
3254 if (it->type != sc::element_type_formula)
3255 {
3256 // This is not a formula block.
3257 assert( false );
3258 return;
3259 }
3260
3261 size_t nBlockLen = it->size - aPos.second;
3262 if (nBlockLen < nLen)
3263 {
3264 // Length is longer than the length of formula cells. Not good.
3265 assert( false );
3266 return;
3267 }
3268
3269 sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
3270 std::advance(itCell, aPos.second);
3271
3272 for (size_t i = 0; i < nLen; ++i, ++itCell)
3273 {
3274 ScFormulaCell& rCell = **itCell;
3275 rCell.HandleStuffAfterParallelCalculation(pInterpreter);
3276 }
3277}
3278
3279void ScColumn::SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat )
3280{
3281 ApplyAttr(nRow, SfxUInt32Item(ATTR_VALUE_FORMAT, nNumberFormat));
3282}
3283
3284ScFormulaCell * const * ScColumn::GetFormulaCellBlockAddress( SCROW nRow, size_t& rBlockSize ) const
3285{
3286 if (!GetDoc().ValidRow(nRow))
3287 {
3288 rBlockSize = 0;
3289 return nullptr;
3290 }
3291
3292 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
3293 sc::CellStoreType::const_iterator it = aPos.first;
3294 if (it == maCells.end())
3295 {
3296 rBlockSize = 0;
3297 return nullptr;
3298 }
3299
3300 if (it->type != sc::element_type_formula)
3301 {
3302 // Not a formula cell.
3303 rBlockSize = 0;
3304 return nullptr;
3305 }
3306
3307 rBlockSize = it->size;
3308 return &sc::formula_block::at(*it->data, aPos.second);
3309}
3310
3312{
3313 size_t nBlockSize = 0;
3314 ScFormulaCell const * const * pp = GetFormulaCellBlockAddress( nRow, nBlockSize );
3315 return pp ? *pp : nullptr;
3316}
3317
3318void ScColumn::FindDataAreaPos(SCROW& rRow, bool bDown) const
3319{
3320 // If the cell is empty, find the next non-empty cell position. If the
3321 // cell is not empty, find the last non-empty cell position in the current
3322 // contiguous cell block.
3323
3324 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
3325 sc::CellStoreType::const_iterator it = aPos.first;
3326 if (it == maCells.end())
3327 // Invalid row.
3328 return;
3329
3330 if (it->type == sc::element_type_empty)
3331 {
3332 // Current cell is empty. Find the next non-empty cell.
3333 rRow = FindNextVisibleRowWithContent(it, rRow, bDown);
3334 return;
3335 }
3336
3337 // Current cell is not empty.
3338 SCROW nNextRow = FindNextVisibleRow(rRow, bDown);
3339 aPos = maCells.position(it, nNextRow);
3340 it = aPos.first;
3341 if (it->type == sc::element_type_empty)
3342 {
3343 // Next visible cell is empty. Find the next non-empty cell.
3344 rRow = FindNextVisibleRowWithContent(it, nNextRow, bDown);
3345 return;
3346 }
3347
3348 // Next visible cell is non-empty. Find the edge that's still visible.
3349 SCROW nLastRow = nNextRow;
3350 do
3351 {
3352 nNextRow = FindNextVisibleRow(nLastRow, bDown);
3353 if (nNextRow == nLastRow)
3354 break;
3355
3356 aPos = maCells.position(it, nNextRow);
3357 it = aPos.first;
3358 if (it->type != sc::element_type_empty)
3359 nLastRow = nNextRow;
3360 }
3361 while (it->type != sc::element_type_empty);
3362
3363 rRow = nLastRow;
3364}
3365
3366bool ScColumn::HasDataAt(SCROW nRow, ScDataAreaExtras* pDataAreaExtras ) const
3367{
3368 if (pDataAreaExtras)
3369 GetDataExtrasAt( nRow, *pDataAreaExtras);
3370
3371 return maCells.get_type(nRow) != sc::element_type_empty;
3372}
3373
3375 ScDataAreaExtras* pDataAreaExtras ) const
3376{
3377 if (pDataAreaExtras)
3378 GetDataExtrasAt( nRow, *pDataAreaExtras);
3379
3380 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
3381 if (aPos.first == maCells.end())
3382 return false;
3383 rBlockPos.miCellPos = aPos.first; // Store this for next call.
3384 return aPos.first->type != sc::element_type_empty;
3385}
3386
3388 ScDataAreaExtras* pDataAreaExtras )
3389{
3390 if (pDataAreaExtras)
3391 GetDataExtrasAt( nRow, *pDataAreaExtras);
3392
3393 std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
3394 if (aPos.first == maCells.end())
3395 return false;
3396 rBlockPos.miCellPos = aPos.first; // Store this for next call.
3397 return aPos.first->type != sc::element_type_empty;
3398}
3399
3400void ScColumn::GetDataExtrasAt( SCROW nRow, ScDataAreaExtras& rDataAreaExtras ) const
3401{
3402 if (rDataAreaExtras.mnStartRow <= nRow && nRow <= rDataAreaExtras.mnEndRow)
3403 return;
3404
3405 // Check in order of likeliness.
3406 if ( (rDataAreaExtras.mbCellFormats && HasVisibleAttrIn(nRow, nRow)) ||
3407 (rDataAreaExtras.mbCellNotes && !IsNotesEmptyBlock(nRow, nRow)) ||
3408 (rDataAreaExtras.mbCellDrawObjects && !IsDrawObjectsEmptyBlock(nRow, nRow)))
3409 {
3410 if (rDataAreaExtras.mnStartRow > nRow)
3411 rDataAreaExtras.mnStartRow = nRow;
3412 if (rDataAreaExtras.mnEndRow < nRow)
3413 rDataAreaExtras.mnEndRow = nRow;
3414 }
3415}
3416
3417namespace {
3418
3419class FindUsedRowsHandler
3420{
3421 typedef mdds::flat_segment_tree<SCROW,bool> UsedRowsType;
3422 UsedRowsType& mrUsed;
3423 UsedRowsType::const_iterator miUsed;
3424public:
3425 explicit FindUsedRowsHandler(UsedRowsType& rUsed) : mrUsed(rUsed), miUsed(rUsed.begin()) {}
3426
3427 void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
3428 {
3429 if (node.type == sc::element_type_empty)
3430 return;
3431
3432 SCROW nRow1 = node.position + nOffset;
3433 SCROW nRow2 = nRow1 + nDataSize - 1;
3434 miUsed = mrUsed.insert(miUsed, nRow1, nRow2+1, true).first;
3435 }
3436};
3437
3438}
3439
3440void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, mdds::flat_segment_tree<SCROW,bool>& rUsed ) const
3441{
3442 FindUsedRowsHandler aFunc(rUsed);
3443 sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
3444}
3445
3446namespace {
3447
3448void startListening(
3449 sc::BroadcasterStoreType& rStore, sc::BroadcasterStoreType::iterator& itBlockPos, size_t nElemPos,
3450 SCROW nRow, SvtListener& rLst)
3451{
3452 switch (itBlockPos->type)
3453 {
3455 {
3456 // Broadcaster already exists here.
3457 SvtBroadcaster* pBC = sc::broadcaster_block::at(*itBlockPos->data, nElemPos);
3458 rLst.StartListening(*pBC);
3459 }
3460 break;
3462 {
3463 // No broadcaster exists at this position yet.
3464 SvtBroadcaster* pBC = new SvtBroadcaster;
3465 rLst.StartListening(*pBC);
3466 itBlockPos = rStore.set(itBlockPos, nRow, pBC); // Store the block position for next iteration.
3467 }
3468 break;
3469 default:
3470 assert(false && "wrong block type encountered in the broadcaster storage.");
3471 }
3472}
3473
3474}
3475
3477{
3478 std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(nRow);
3479 startListening(maBroadcasters, aPos.first, aPos.second, nRow, rLst);
3480}
3481
3483{
3484 SvtBroadcaster* pBC = GetBroadcaster(nRow);
3485 if (!pBC)
3486 return;
3487
3488 rLst.EndListening(*pBC);
3489 if (!pBC->HasListeners())
3490 { // There is no more listeners for this cell. Remove the broadcaster.
3491 if(GetDoc().IsDelayedDeletingBroadcasters())
3493 else
3494 maBroadcasters.set_empty(nRow, nRow);
3495 }
3496}
3497
3499{
3500 if (!GetDoc().ValidRow(rAddress.Row()))
3501 return;
3502
3503 sc::ColumnBlockPosition* p = rCxt.getBlockPosition(rAddress.Tab(), rAddress.Col());
3504 if (!p)
3505 return;
3506
3507 sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
3508 std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, rAddress.Row());
3509 it = aPos.first; // store the block position for next iteration.
3510 startListening(maBroadcasters, it, aPos.second, rAddress.Row(), rLst);
3511}
3512
3514{
3515 sc::ColumnBlockPosition* p = rCxt.getBlockPosition(rAddress.Tab(), rAddress.Col());
3516 if (!p)
3517 return;
3518
3519 sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
3520 std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, rAddress.Row());
3521 it = aPos.first; // store the block position for next iteration.
3522 if (it->type != sc::element_type_broadcaster)
3523 return;
3524
3525 SvtBroadcaster* pBC = sc::broadcaster_block::at(*it->data, aPos.second);
3526 assert(pBC);
3527
3528 rListener.EndListening(*pBC);
3529 if (!pBC->HasListeners())
3530 // There is no more listeners for this cell. Add it to the purge list for later purging.
3531 rCxt.addEmptyBroadcasterPosition(rAddress.Tab(), rAddress.Col(), rAddress.Row());
3532}
3533
3534namespace {
3535
3536class CompileDBFormulaHandler
3537{
3539
3540public:
3541 explicit CompileDBFormulaHandler( sc::CompileFormulaContext& rCxt ) :
3542 mrCxt(rCxt) {}
3543
3544 void operator() (size_t, ScFormulaCell* p)
3545 {
3546 p->CompileDBFormula(mrCxt);
3547 }
3548};
3549
3550struct CompileColRowNameFormulaHandler
3551{
3553public:
3554 explicit CompileColRowNameFormulaHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
3555
3556 void operator() (size_t, ScFormulaCell* p)
3557 {
3558 p->CompileColRowNameFormula(mrCxt);
3559 }
3560};
3561
3562}
3563
3565{
3566 CompileDBFormulaHandler aFunc(rCxt);
3569}
3570
3572{
3573 CompileColRowNameFormulaHandler aFunc(rCxt);
3576}
3577
3578namespace {
3579
3580class UpdateSubTotalHandler
3581{
3583
3584 void update(double fVal, bool bVal)
3585 {
3586 if (mrData.getError())
3587 return;
3588
3589 switch (mrData.getFunc())
3590 {
3591 case SUBTOTAL_FUNC_CNT2: // everything
3592 mrData.update( fVal);
3593 break;
3594 default: // only numeric values
3595 if (bVal)
3596 mrData.update( fVal);
3597 }
3598 }
3599
3600public:
3601 explicit UpdateSubTotalHandler(ScFunctionData& rData) : mrData(rData) {}
3602
3603 void operator() (size_t /*nRow*/, double fVal)
3604 {
3605 update(fVal, true);
3606 }
3607
3608 void operator() (size_t /*nRow*/, const svl::SharedString&)
3609 {
3610 update(0.0, false);
3611 }
3612
3613 void operator() (size_t /*nRow*/, const EditTextObject*)
3614 {
3615 update(0.0, false);
3616 }
3617
3618 void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
3619 {
3620 double fVal = 0.0;
3621 bool bVal = false;
3622 if (mrData.getFunc() != SUBTOTAL_FUNC_CNT2) // it doesn't interest us
3623 {
3624
3625 if (pCell->GetErrCode() != FormulaError::NONE)
3626 {
3627 if (mrData.getFunc() != SUBTOTAL_FUNC_CNT) // simply remove from count
3628 mrData.setError();
3629 }
3630 else if (pCell->IsValue())
3631 {
3632 fVal = pCell->GetValue();
3633 bVal = true;
3634 }
3635 // otherwise text
3636 }
3637
3638 update(fVal, bVal);
3639 }
3640};
3641
3642}
3643
3644// multiple selections:
3646 const ScRangeList& rRanges, ScFunctionData& rData, const ScFlatBoolRowSegments& rHiddenRows )
3647{
3648 sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
3649 aSpanSet.scan(rRanges, nTab, nCol); // mark all selected rows.
3650
3651 if (aSpanSet.empty())
3652 return; // nothing to do, bail out
3653
3654 // Exclude all hidden rows.
3656 SCROW nRow = 0;
3657 while (nRow <= GetDoc().MaxRow())
3658 {
3659 if (!rHiddenRows.getRangeData(nRow, aRange))
3660 break;
3661
3662 if (aRange.mbValue)
3663 // Hidden range detected.
3664 aSpanSet.set(nRow, aRange.mnRow2, false);
3665
3666 nRow = aRange.mnRow2 + 1;
3667 }
3668
3670 aSpanSet.getSpans(aSpans);
3671
3672 switch (rData.getFunc())
3673 {
3675 {
3676 // Simply count selected rows regardless of cell contents.
3677 for (const auto& rSpan : aSpans)
3678 rData.update( rSpan.mnRow2 - rSpan.mnRow1 + 1);
3679 }
3680 break;
3681 case SUBTOTAL_FUNC_CNT2:
3682 {
3683 // We need to parse all non-empty cells.
3684 sc::CellStoreType::const_iterator itCellPos = maCells.begin();
3685 UpdateSubTotalHandler aFunc(rData);
3686 for (const auto& rSpan : aSpans)
3687 {
3688 itCellPos = sc::ParseAllNonEmpty(
3689 itCellPos, maCells, rSpan.mnRow1, rSpan.mnRow2, aFunc);
3690 }
3691 }
3692 break;
3693 default:
3694 {
3695 // We need to parse only numeric values.
3696 sc::CellStoreType::const_iterator itCellPos = maCells.begin();
3697 UpdateSubTotalHandler aFunc(rData);
3698 for (const auto& rSpan : aSpans)
3699 {
3700 itCellPos = sc::ParseFormulaNumeric(
3701 itCellPos, maCells, rSpan.mnRow1, rSpan.mnRow2, aFunc);
3702 }
3703 }
3704 }
3705}
3706
3707namespace {
3708
3709class WeightedCounter
3710{
3712public:
3713 WeightedCounter() : mnCount(0) {}
3714
3715 void operator() (const sc::CellStoreType::value_type& node)
3716 {
3717 mnCount += getWeight(node);
3718 }
3719
3720 static sal_uLong getWeight(const sc::CellStoreType::value_type& node)
3721 {
3722 switch (node.type)
3723 {
3726 return node.size;
3728 {
3729 // Each formula cell is worth its code length plus 5.
3730 return std::accumulate(sc::formula_block::begin(*node.data), sc::formula_block::end(*node.data), size_t(0),
3731 [](const size_t& rCount, const ScFormulaCell* p) { return rCount + 5 + p->GetCode()->GetCodeLen(); });
3732 }
3734 // each edit-text cell is worth 50.
3735 return node.size * 50;
3736 default:
3737 return 0;
3738 }
3739 }
3740
3741 sal_uLong getCount() const { return mnCount; }
3742};
3743
3744class WeightedCounterWithRows
3745{
3746 const SCROW mnStartRow;
3747 const SCROW mnEndRow;
3749
3750public:
3751 WeightedCounterWithRows(SCROW nStartRow, SCROW nEndRow)
3752 : mnStartRow(nStartRow)
3753 , mnEndRow(nEndRow)
3754 , mnCount(0)
3755 {
3756 }
3757
3758 void operator() (const sc::CellStoreType::value_type& node)
3759 {
3760 const SCROW nRow1 = node.position;
3761 const SCROW nRow2 = nRow1 + 1;
3762
3763 if ((nRow2 >= mnStartRow) && (nRow1 <= mnEndRow))
3764 {
3765 mnCount += WeightedCounter::getWeight(node);
3766 }
3767 }
3768
3769 sal_uLong getCount() const { return mnCount; }
3770};
3771
3772}
3773
3775{
3776 const WeightedCounter aFunc = std::for_each(maCells.begin(), maCells.end(),
3777 WeightedCounter());
3778 return aFunc.getCount();
3779}
3780
3781sal_uInt64 ScColumn::GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const
3782{
3783 const WeightedCounterWithRows aFunc = std::for_each(maCells.begin(), maCells.end(),
3784 WeightedCounterWithRows(nStartRow, nEndRow));
3785 return aFunc.getCount();
3786}
3787
3788namespace {
3789
3790class CodeCounter
3791{
3792 sal_uInt64 mnCount;
3793public:
3794 CodeCounter() : mnCount(0) {}
3795
3796 void operator() (size_t, const ScFormulaCell* p)
3797 {
3798 mnCount += p->GetCode()->GetCodeLen();
3799 }
3800
3801 sal_uInt64 getCount() const { return mnCount; }
3802};
3803
3804}
3805
3806sal_uInt64 ScColumn::GetCodeCount() const
3807{
3808 CodeCounter aFunc;
3809 sc::ParseFormula(maCells, aFunc);
3810 return aFunc.getCount();
3811}
3812
3813/* 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:929
void DeleteCellNotes(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
Definition: column2.cxx:2250
void DeleteBroadcasters(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2)
Definition: column2.cxx:1979
void CreateSparklineCell(SCROW nRow, std::shared_ptr< sc::Sparkline > const &pSparkline)
Definition: column2.cxx:2051
SCROW GetFirstDataPos() const
Definition: column2.cxx:1395
SCTAB GetTab() const
Definition: column.hxx:254
void CellStorageModified()
Called whenever the state of cell array gets modified i.e.
Definition: column2.cxx:1670
void CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn &rDestCol) const
Definition: column2.cxx:1843
void UpdateSelectionFunction(const ScRangeList &rRanges, ScFunctionData &rData, const ScFlatBoolRowSegments &rHiddenRows)
Definition: column2.cxx:3645
SCCOL nCol
Definition: column.hxx:203
bool IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
Definition: column2.cxx:1336
sc::CellTextAttrStoreType maCellTextAttrs
Definition: column.hxx:187
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: column.hxx:964
void DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn &rDestCol, sc::ColumnBlockPosition &rDestBlockPos, bool bCloneCaption, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:1962
SCTAB nTab
Definition: column.hxx:204
bool HasVisibleDataAt(SCROW nRow) const
Definition: column2.cxx:1308
bool mbEmptyBroadcastersPending
Definition: column.hxx:206
void RegroupFormulaCells(std::vector< ScAddress > *pGroupPos=nullptr)
Regroup formula cells for the entire column.
Definition: column3.cxx:3711
SCROW FindNextVisibleRowWithContent(sc::CellStoreType::const_iterator &itPos, SCROW nRow, bool bForward) const
Definition: column2.cxx:1606
ScPostIt * GetCellNote(SCROW nRow)
Definition: column2.cxx:2184
bool TestTabRefAbs(SCTAB nTable) const
Definition: column2.cxx:1267
void CompileColRowNameFormula(sc::CompileFormulaContext &rCxt)
Definition: column2.cxx:3571
SCROW GetSparklinesMinRow() const
Definition: column2.cxx:2169
SCSIZE VisibleCount(SCROW nStartRow, SCROW nEndRow) const
Definition: column2.cxx:1301
void DumpColumnStorage() const
void CopyCellSparklinesToDocument(SCROW nRow1, SCROW nRow2, ScColumn &rDestCol, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:2134
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:2311
void DuplicateSparklines(SCROW nStartRow, size_t nDataSize, ScColumn &rDestCol, sc::ColumnBlockPosition &rDestBlockPos, SCROW nRowOffsetDest=0) const
Definition: column2.cxx:2144
void RemoveEditAttribs(sc::ColumnBlockPosition &rBlockPos, SCROW nStartRow, SCROW nEndRow)
Definition: column2.cxx:1257
sc::CellNoteStoreType maCellNotes
Definition: column.hxx:190
SvtScriptType GetScriptType(SCROW nRow) const
Definition: column2.cxx:2303
void EndListening(SvtListener &rLst, SCROW nRow)
Definition: column2.cxx:3482
void FindDataAreaPos(SCROW &rRow, bool bDown) const
Definition: column2.cxx:3318
bool TrimEmptyBlocks(SCROW &rRowStart, SCROW &rRowEnd) const
Definition: column2.cxx:1536
void CellNotesDeleting(SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership)
Definition: column2.cxx:2243
SCCOL GetCol() const
Definition: column.hxx:255
void SetNumberFormat(SCROW nRow, sal_uInt32 nNumberFormat)
Definition: column2.cxx:3279
void AssertNoInterpretNeeded(SCROW nRow1, SCROW nRow2)
Definition: column2.cxx:3168
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:890
bool HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW &rFirst)
Definition: column.cxx:3331
sal_uInt64 GetWeightedCount() const
Definition: column2.cxx:3774
void SetFormulaResults(SCROW nRow, const double *pResults, size_t nLen)
Definition: column2.cxx:3175
void GetDataExtrasAt(SCROW nRow, ScDataAreaExtras &rDataAreaExtras) const
Definition: column2.cxx:3400
void CompileDBFormula(sc::CompileFormulaContext &rCxt)
Definition: column2.cxx:3564
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:2258
bool IsEmptyData() const
Definition: column2.cxx:1274
SCROW GetCellNotesMaxRow() const
Definition: column2.cxx:2265
bool HasSparklines() const
Definition: column2.cxx:2151
SCROW FindNextVisibleRow(SCROW nRow, bool bForward) const
Definition: column2.cxx:1582
void CalculateInThread(ScInterpreterContext &rContext, SCROW nRow, size_t nLen, size_t nOffset, unsigned nThisThread, unsigned nThreadsTotal)
Definition: column2.cxx:3211
bool GetNextDataPos(SCROW &rRow) const
Definition: column2.cxx:1490
sc::CellStoreType maCells
Definition: column.hxx:196
ScRefCellValue GetCellValue(SCROW nRow) const
Definition: column.cxx:638
formula::VectorRefArray FetchVectorRefArray(SCROW nRow1, SCROW nRow2)
Definition: column2.cxx:2952
bool UpdateScriptType(sc::CellTextAttr &rAttr, SCROW nRow, sc::CellStoreType::iterator &itr)
Definition: column3.cxx:839
bool DeleteSparkline(SCROW nRow)
Definition: column2.cxx:2066
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:1940
void FillMatrix(ScMatrix &rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2, svl::SharedStringPool *pPool) const
Definition: column2.cxx:2681
bool IsDrawObjectsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
Definition: column.cxx:1857
void SetCellNote(SCROW nRow, std::unique_ptr< ScPostIt > pNote)
Definition: column2.cxx:2210
bool GetNextSpellingCell(SCROW &nRow, bool bInSel, const ScMarkData &rData) const
Definition: column2.cxx:1094
sal_uInt64 GetCodeCount() const
Definition: column2.cxx:3806
void PrepareBroadcastersForDestruction()
Definition: column2.cxx:1985
SCROW GetCellNotesMinRow() const
Definition: column2.cxx:2276
void DeleteEmptyBroadcasters()
Definition: column2.cxx:2011
void FindUsed(SCROW nStartRow, SCROW nEndRow, mdds::flat_segment_tree< SCROW, bool > &rUsed) const
Definition: column2.cxx:3440
void DeleteSparklineCells(sc::ColumnBlockPosition &rBlockPos, SCROW nRow1, SCROW nRow2)
Definition: column2.cxx:2058
bool GetPrevDataPos(SCROW &rRow) const
Definition: column2.cxx:1444
bool HasVisibleAttrIn(SCROW nStartRow, SCROW nEndRow) const
Definition: column.hxx:899
sc::SparklineCell * GetSparklineCell(SCROW nRow)
Definition: column2.cxx:2046
formula::FormulaTokenRef ResolveStaticReference(SCROW nRow)
Definition: column2.cxx:2396
sc::BroadcasterStoreType maBroadcasters
Definition: column.hxx:193
SCROW GetLastDataPos() const
Definition: column2.cxx:1407
const ScFormulaCell * FetchFormulaCell(SCROW nRow) const
Definition: column2.cxx:3311
void SetScriptType(SCROW nRow, SvtScriptType nType)
Definition: column2.cxx:2382
SCROW GetSparklinesMaxRow() const
Definition: column2.cxx:2158
ScDocument & GetDoc() const
Definition: column.hxx:127
void HandleStuffAfterParallelCalculation(SCROW nRow, size_t nLen, ScInterpreter *pInterpreter)
Definition: column2.cxx:3250
ScFormulaCell *const * GetFormulaCellBlockAddress(SCROW nRow, size_t &rBlockSize) const
Definition: column2.cxx:3284
SvtBroadcaster * GetBroadcaster(SCROW nRow)
Definition: column2.cxx:1969
sc::SparklineStoreType maSparklines
Definition: column.hxx:199
bool HasDataAt(SCROW nRow, ScDataAreaExtras *pDataAreaExtras=nullptr) const
Definition: column2.cxx:3366
void SetTextWidth(SCROW nRow, sal_uInt16 nWidth)
Definition: column2.cxx:2292
bool IsSparklinesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
Definition: column2.cxx:2078
void StartListening(SvtListener &rLst, SCROW nRow)
Definition: column2.cxx:3476
sal_uInt16 GetTextWidth(SCROW nRow) const
Definition: column2.cxx:2287
SCSIZE GetEmptyLinesInBlock(SCROW nStartRow, SCROW nEndRow, ScDirection eDir) const
Definition: column2.cxx:1353
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:2525
SC_DLLPUBLIC sal_uInt16 GetRowHeight(SCROW nRow, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4226
SC_DLLPUBLIC sal_uInt16 GetColWidth(SCCOL nCol, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4185
SC_DLLPUBLIC ScPatternAttr * GetDefPattern() const
Definition: document.cxx:6182
bool ValidRow(SCROW nRow) const
Definition: document.hxx:900
SC_DLLPUBLIC bool IsTabProtected(SCTAB nTab) const
Definition: documen3.cxx:1919
void DiscardFormulaGroupContext()
Definition: document.cxx:3586
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:893
std::shared_ptr< sc::FormulaGroupContext > & GetFormulaGroupContext()
Definition: document.cxx:3577
SC_DLLPUBLIC SfxItemPool * GetEditPool() const
Definition: documen2.cxx:473
std::unique_ptr< ScFieldEditEngine > CreateFieldEditEngine()
Definition: documen2.cxx:1191
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1083
SC_DLLPUBLIC bool RowHidden(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4494
SC_DLLPUBLIC CRFlags GetRowFlags(SCROW nRow, SCTAB nTab) const
Definition: document.cxx:4401
SC_DLLPUBLIC std::shared_ptr< sc::SparklineGroup > SearchSparklineGroup(tools::Guid const &rGuid)
Definition: document.cxx:6726
void DisposeFieldEditEngine(std::unique_ptr< ScFieldEditEngine > &rpEditEngine)
Definition: documen2.cxx:1213
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1009
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:603
void ApplyAsianEditSettings(ScEditEngineDefaulter &rEngine)
Definition: documen9.cxx:664
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:6682
SfxItemSet * GetPreviewFont()
Definition: document.hxx:1389
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:467
SC_DLLPUBLIC sal_uInt16 GetOriginalWidth(SCCOL nCol, SCTAB nTab) const
Definition: document.cxx:4202
ScStyleSheet * GetPreviewCellStyle()
Definition: document.hxx:1393
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:797
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 sal_uInt16 nStdRowHeight
Definition: global.hxx:595
static SC_DLLPUBLIC SvtScriptType GetDefaultScriptType()
Definition: global.cxx:898
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:3169
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:3329
void PutDouble(double fVal, SCSIZE nC, SCSIZE nR)
Definition: scmatrix.cxx:3154
SCCOL GetColMerge() const
Definition: attrib.hxx:68
SCROW GetRowMerge() const
Definition: attrib.hxx:69
bool HasAutoFilter() const
Definition: attrib.hxx:103
bool IsHorOverlapped() const
Definition: attrib.hxx:99
bool IsOverlapped() const
Definition: attrib.hxx:101
bool IsVerOverlapped() const
Definition: attrib.hxx:100
void SetStyleSheet(ScStyleSheet *pNewStyle, bool bClearDirectFormat=true)
Definition: patattr.cxx:1212
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1301
ScRotateDir GetRotateDir(const SfxItemSet *pCondSet) const
Definition: patattr.cxx:1371
static void GetFont(vcl::Font &rFont, const SfxItemSet &rItemSet, ScAutoFontColorMode eAutoMode, const OutputDevice *pOutDev=nullptr, const Fraction *pScale=nullptr, const SfxItemSet *pCondSet=nullptr, SvtScriptType nScript=SvtScriptType::NONE, const Color *pBackConfigColor=nullptr, const Color *pTextConfigColor=nullptr)
Static helper function to fill a font object from the passed item set.
Definition: patattr.cxx:251
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:72
void FillEditItemSet(SfxItemSet *pEditSet, const SfxItemSet *pCondSet=nullptr) const
Converts all Calc items contained in the own item set to edit engine items and puts them into pEditSe...
Definition: patattr.cxx:827
static SvxCellOrientation GetCellOrientation(const SfxItemSet &rItemSet, const SfxItemSet *pCondSet)
Definition: patattr.cxx:189
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:5217
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:3148
static sal_uInt16 lcl_GetAttribHeight(const ScPatternAttr &rPattern, sal_uInt16 nFontHeightId)
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:271
@ CELLTYPE_EDIT
Definition: global.hxx:276
@ CELLTYPE_STRING
Definition: global.hxx:274
@ CELLTYPE_FORMULA
Definition: global.hxx:275
@ CELLTYPE_NONE
Definition: global.hxx:272
@ CELLTYPE_VALUE
Definition: global.hxx:273
@ SUBTOTAL_FUNC_CNT2
Definition: global.hxx:863
@ SUBTOTAL_FUNC_SELECTION_COUNT
Definition: global.hxx:873
@ SUBTOTAL_FUNC_CNT
Definition: global.hxx:862
ScDirection
Definition: global.hxx:342
@ DIR_TOP
Definition: global.hxx:345
@ DIR_BOTTOM
Definition: global.hxx:343
#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
@ SC_AUTOCOL_BLACK
always use black
Definition: patattr.hxx:45
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
const sc::CellStoreType & mrCells
Definition: queryiter.cxx:919
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:44
bool mbCellDrawObjects
If TRUE, consider the presence of draw objects anchored to the cell.
Definition: sortparam.hxx:48
bool mbCellFormats
If TRUE, consider the presence of cell formats.
Definition: sortparam.hxx:50
bool mbCellNotes
If TRUE, consider the presence of cell notes besides data.
Definition: sortparam.hxx:46
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