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