tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / data / table1.cxx
blobcf22133056cf11c4740ab1bbb3bf61f5c8ee5c57
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/types.h>
21 #include <scitems.hxx>
22 #include <editeng/justifyitem.hxx>
23 #include <o3tl/safeint.hxx>
24 #include <o3tl/unit_conversion.hxx>
25 #include <unotools/textsearch.hxx>
26 #include <unotools/charclass.hxx>
27 #include <osl/diagnose.h>
29 #include <patattr.hxx>
30 #include <table.hxx>
31 #include <document.hxx>
32 #include <docsh.hxx>
33 #include <drwlayer.hxx>
34 #include <olinetab.hxx>
35 #include <global.hxx>
36 #include <globstr.hrc>
37 #include <scresid.hxx>
38 #include <refupdat.hxx>
39 #include <markdata.hxx>
40 #include <progress.hxx>
41 #include <prnsave.hxx>
42 #include <printopt.hxx>
43 #include <scmod.hxx>
44 #include <tabprotection.hxx>
45 #include <sheetevents.hxx>
46 #include <segmenttree.hxx>
47 #include <dbdata.hxx>
48 #include <conditio.hxx>
49 #include <globalnames.hxx>
50 #include <cellvalue.hxx>
51 #include <scmatrix.hxx>
52 #include <refupdatecontext.hxx>
53 #include <rowheightcontext.hxx>
54 #include <compressedarray.hxx>
55 #include <tabvwsh.hxx>
56 #include <vcl/svapp.hxx>
58 #include <formula/vectortoken.hxx>
59 #include <token.hxx>
61 #include <vector>
62 #include <memory>
64 using ::std::vector;
66 namespace {
68 ScProgress* GetProgressBar(
69 SCSIZE nCount, SCSIZE nTotalCount, ScProgress* pOuterProgress, const ScDocument* pDoc)
71 if (nTotalCount < 1000)
73 // if the total number of rows is less than 1000, don't even bother
74 // with the progress bar because drawing progress bar can be very
75 // expensive especially in GTK.
76 return nullptr;
79 if (pOuterProgress)
80 return pOuterProgress;
82 if (nCount > 1)
83 return new ScProgress(
84 pDoc->GetDocumentShell(), ScResId(STR_PROGRESS_HEIGHTING), nTotalCount, true);
86 return nullptr;
89 void GetOptimalHeightsInColumn(
90 sc::RowHeightContext& rCxt, ScColContainer& rCol, SCROW nStartRow, SCROW nEndRow,
91 ScProgress* pProgress, sal_uLong nProgressStart )
93 assert(nStartRow <= nEndRow);
95 // first, one time over the whole range
96 // (with the last column in the hope that they most likely still are
97 // on standard format)
100 rCol.back().GetOptimalHeight(rCxt, nStartRow, nEndRow, 0, 0);
102 // from there search for the standard height that is in use in the lower part
104 RowHeightsArray& rHeights = rCxt.getHeightArray();
105 sal_uInt16 nMinHeight = rHeights.GetValue(nEndRow);
106 SCSIZE nPos = nEndRow - 1;
107 while ( nPos )
109 auto aRangeData = rHeights.GetRangeData(nPos-1);
110 if (aRangeData.maValue < nMinHeight)
111 break;
112 nPos = std::max<SCSIZE>(0, aRangeData.mnRow1);
115 const SCROW nMinStart = nPos;
117 sal_uInt64 nWeightedCount = nProgressStart + rCol.back().GetWeightedCount(nStartRow, nEndRow);
118 const SCCOL maxCol = rCol.size() - 1; // last col done already above
119 for (SCCOL nCol=0; nCol<maxCol; nCol++)
121 rCol[nCol].GetOptimalHeight(rCxt, nStartRow, nEndRow, nMinHeight, nMinStart);
123 if (pProgress)
125 nWeightedCount += rCol[nCol].GetWeightedCount(nStartRow, nEndRow);
126 pProgress->SetState( nWeightedCount );
131 struct OptimalHeightsFuncObjBase
133 virtual ~OptimalHeightsFuncObjBase() {}
134 virtual bool operator() (SCROW nStartRow, SCROW nEndRow, sal_uInt16 nHeight, bool bApi) = 0;
137 struct SetRowHeightOnlyFunc : public OptimalHeightsFuncObjBase
139 ScTable* mpTab;
140 explicit SetRowHeightOnlyFunc(ScTable* pTab) :
141 mpTab(pTab)
144 virtual bool operator() (SCROW nStartRow, SCROW nEndRow, sal_uInt16 nHeight, bool /* bApi */) override
146 mpTab->SetRowHeightOnly(nStartRow, nEndRow, nHeight);
147 return false;
151 struct SetRowHeightRangeFunc : public OptimalHeightsFuncObjBase
153 ScTable* mpTab;
154 double mnPPTY;
156 SetRowHeightRangeFunc(ScTable* pTab, double nPPTY) :
157 mpTab(pTab),
158 mnPPTY(nPPTY)
161 virtual bool operator() (SCROW nStartRow, SCROW nEndRow, sal_uInt16 nHeight, bool bApi) override
163 return mpTab->SetRowHeightRange(nStartRow, nEndRow, nHeight, mnPPTY, bApi);
167 bool SetOptimalHeightsToRows(
168 sc::RowHeightContext& rCxt,
169 OptimalHeightsFuncObjBase& rFuncObj,
170 ScBitMaskCompressedArray<SCROW, CRFlags>* pRowFlags, SCROW nStartRow, SCROW nEndRow,
171 bool bApi )
173 bool bChanged = false;
174 SCROW nRngStart = 0;
175 SCROW nRngEnd = 0;
176 sal_uInt16 nLast = 0;
177 sal_uInt16 nExtraHeight = rCxt.getExtraHeight();
178 for (SCSIZE i = nStartRow; i <= o3tl::make_unsigned(nEndRow); i++)
180 size_t nIndex;
181 SCROW nRegionEndRow;
182 CRFlags nRowFlag = pRowFlags->GetValue( i, nIndex, nRegionEndRow );
183 if ( nRegionEndRow > nEndRow )
184 nRegionEndRow = nEndRow;
185 SCSIZE nMoreRows = nRegionEndRow - i; // additional equal rows after first
187 bool bAutoSize = !(nRowFlag & CRFlags::ManualSize);
188 if (bAutoSize || rCxt.isForceAutoSize())
190 if (nExtraHeight)
192 if (bAutoSize)
193 pRowFlags->SetValue( i, nRegionEndRow, nRowFlag | CRFlags::ManualSize);
195 else if (!bAutoSize)
196 pRowFlags->SetValue( i, nRegionEndRow, nRowFlag & ~CRFlags::ManualSize);
198 for (SCSIZE nInner = i; nInner <= i + nMoreRows; ++nInner)
200 if (nLast)
202 SCROW nRangeRowEnd;
203 size_t nTmp;
204 sal_uInt16 nRangeValue = rCxt.getHeightArray().GetValue(nInner, nTmp, nRangeRowEnd);
205 if (nRangeValue + nExtraHeight == nLast)
207 nRngEnd = std::min<SCSIZE>(i + nMoreRows, nRangeRowEnd);
208 nInner = nRangeRowEnd;
210 else
212 bChanged |= rFuncObj(nRngStart, nRngEnd, nLast, bApi);
213 nLast = 0;
216 if (!nLast)
218 nLast = rCxt.getHeightArray().GetValue(nInner) + rCxt.getExtraHeight();
219 nRngStart = nInner;
220 nRngEnd = nInner;
224 else
226 if (nLast)
227 bChanged |= rFuncObj(nRngStart, nRngEnd, nLast, bApi);
228 nLast = 0;
230 i += nMoreRows; // already handled - skip
232 if (nLast)
233 bChanged |= rFuncObj(nRngStart, nRngEnd, nLast, bApi);
235 return bChanged;
240 ScTable::ScTable( ScDocument& rDoc, SCTAB nNewTab, const OUString& rNewName,
241 bool bColInfo, bool bRowInfo ) :
242 aCol( rDoc.GetSheetLimits(), INITIALCOLCOUNT ),
243 aName( rNewName ),
244 aCodeName( rNewName ),
245 nLinkRefreshDelay( 0 ),
246 nLinkMode( ScLinkMode::NONE ),
247 aPageStyle( ScResId(STR_STYLENAME_STANDARD) ),
248 nRepeatStartX( SCCOL_REPEAT_NONE ),
249 nRepeatEndX( SCCOL_REPEAT_NONE ),
250 nRepeatStartY( SCROW_REPEAT_NONE ),
251 nRepeatEndY( SCROW_REPEAT_NONE ),
252 mnOptimalMinRowHeight(0),
253 mpRowHeights( static_cast<ScFlatUInt16RowSegments*>(nullptr) ),
254 mpHiddenCols(new ScFlatBoolColSegments(rDoc.MaxCol())),
255 mpHiddenRows(new ScFlatBoolRowSegments(rDoc.MaxRow())),
256 mpFilteredCols(new ScFlatBoolColSegments(rDoc.MaxCol())),
257 mpFilteredRows(new ScFlatBoolRowSegments(rDoc.MaxRow())),
258 nTableAreaX( 0 ),
259 nTableAreaY( 0 ),
260 nTableAreaVisibleX( 0 ),
261 nTableAreaVisibleY( 0 ),
262 nTab( nNewTab ),
263 rDocument( rDoc ),
264 pSortCollator( nullptr ),
265 nLockCount( 0 ),
266 aScenarioColor( COL_LIGHTGRAY ),
267 aTabBgColor( COL_AUTO ),
268 nScenarioFlags(ScScenarioFlags::NONE),
269 mpCondFormatList( new ScConditionalFormatList() ),
270 maLOKFreezeCell(-1, -1, nNewTab),
271 bScenario(false),
272 bLayoutRTL(false),
273 bLoadingRTL(false),
274 bPageSizeValid(false),
275 bTableAreaValid(false),
276 bTableAreaVisibleValid(false),
277 bVisible(true),
278 bPendingRowHeights(false),
279 bCalcNotification(false),
280 bGlobalKeepQuery(false),
281 bPrintEntireSheet(true),
282 bActiveScenario(false),
283 mbPageBreaksValid(false),
284 mbForceBreaks(false),
285 mbTotalsRowBelow(true),
286 bStreamValid(false)
288 aDefaultColData.InitAttrArray(new ScAttrArray(static_cast<SCCOL>(-1), nNewTab, rDoc, nullptr));
289 if (bColInfo)
291 mpColWidth.reset( new ScCompressedArray<SCCOL, sal_uInt16>( rDocument.MaxCol()+1, STD_COL_WIDTH ) );
292 mpColFlags.reset( new ScBitMaskCompressedArray<SCCOL, CRFlags>( rDocument.MaxCol()+1, CRFlags::NONE ) );
295 if (bRowInfo)
297 mpRowHeights.reset(new ScFlatUInt16RowSegments(rDocument.MaxRow(), GetOptimalMinRowHeight()));
298 pRowFlags.reset(new ScBitMaskCompressedArray<SCROW, CRFlags>( rDocument.MaxRow(), CRFlags::NONE));
301 if ( rDocument.IsDocVisible() )
303 // when a sheet is added to a visible document,
304 // initialize its RTL flag from the system locale
305 bLayoutRTL = ScGlobal::IsSystemRTL();
308 ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
309 if (pDrawLayer)
311 if ( pDrawLayer->ScAddPage( nTab ) ) // sal_False (not inserted) during Undo
313 pDrawLayer->ScRenamePage( nTab, aName );
314 sal_uLong const nx = o3tl::convert((rDocument.MaxCol()+1) * STD_COL_WIDTH, o3tl::Length::twip, o3tl::Length::mm100);
315 sal_uLong ny = o3tl::convert((rDocument.MaxRow() + 1) * GetOptimalMinRowHeight(),
316 o3tl::Length::twip, o3tl::Length::mm10);
317 pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( nx, ny ), false );
321 for (SCCOL k=0; k < aCol.size(); k++)
322 aCol[k].Init( k, nTab, rDocument, true );
325 ScTable::~ScTable() COVERITY_NOEXCEPT_FALSE
327 if (!rDocument.IsInDtorClear())
329 for (SCCOL nCol = 0; nCol < aCol.size(); ++nCol)
331 aCol[nCol].FreeNotes();
333 // In the dtor, don't delete the pages in the wrong order.
334 // (or else nTab does not reflect the page number!)
335 // In ScDocument::Clear is afterwards used from Clear at the Draw Layer to delete everything.
337 ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
338 if (pDrawLayer)
339 pDrawLayer->ScRemovePage( nTab );
342 pRowFlags.reset();
343 pSheetEvents.reset();
344 pOutlineTable.reset();
345 pSearchText.reset();
346 moRepeatColRange.reset();
347 moRepeatRowRange.reset();
348 pScenarioRanges.reset();
349 mpRangeName.reset();
350 pDBDataNoName.reset();
351 DestroySortCollator();
354 sal_Int64 ScTable::GetHashCode() const
356 return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this));
359 void ScTable::SetName( const OUString& rNewName )
361 aName = rNewName;
362 aUpperName.clear(); // invalidated if the name is changed
364 // SetStreamValid is handled in ScDocument::RenameTab
367 const OUString& ScTable::GetUpperName() const
369 if (aUpperName.isEmpty() && !aName.isEmpty())
370 aUpperName = ScGlobal::getCharClass().uppercase(aName);
371 return aUpperName;
374 void ScTable::SetVisible( bool bVis )
376 if (bVisible != bVis)
377 SetStreamValid(false);
379 bVisible = bVis;
382 void ScTable::SetStreamValid( bool bSet, bool bIgnoreLock )
384 if (!bStreamValid && !bSet)
385 return; // shortcut
386 if ( bIgnoreLock || !rDocument.IsStreamValidLocked() )
387 bStreamValid = bSet;
390 void ScTable::SetPendingRowHeights( bool bSet )
392 bPendingRowHeights = bSet;
395 void ScTable::SetLayoutRTL( bool bSet )
397 bLayoutRTL = bSet;
400 void ScTable::SetLoadingRTL( bool bSet )
402 bLoadingRTL = bSet;
405 void ScTable::SetTabBgColor(const Color& rColor)
407 if (aTabBgColor != rColor)
409 // The tab color has changed. Set this table 'modified'.
410 aTabBgColor = rColor;
411 SetStreamValid(false);
415 void ScTable::SetScenario( bool bFlag )
417 bScenario = bFlag;
420 void ScTable::SetLink( ScLinkMode nMode,
421 const OUString& rDoc, const OUString& rFlt, const OUString& rOpt,
422 const OUString& rTab, sal_Int32 nRefreshDelay )
424 nLinkMode = nMode;
425 aLinkDoc = rDoc; // File
426 aLinkFlt = rFlt; // Filter
427 aLinkOpt = rOpt; // Filter options
428 aLinkTab = rTab; // Sheet name in source file
429 nLinkRefreshDelay = nRefreshDelay; // refresh delay in seconds, 0==off
431 SetStreamValid(false);
434 sal_uInt16 ScTable::GetOptimalColWidth( SCCOL nCol, OutputDevice* pDev,
435 double nPPTX, double nPPTY,
436 const Fraction& rZoomX, const Fraction& rZoomY,
437 bool bFormula, const ScMarkData* pMarkData,
438 const ScColWidthParam* pParam )
440 if ( nCol >= aCol.size() )
441 return ( STD_COL_WIDTH - STD_EXTRA_WIDTH );
443 return aCol[nCol].GetOptimalColWidth( pDev, nPPTX, nPPTY, rZoomX, rZoomY,
444 bFormula, STD_COL_WIDTH - STD_EXTRA_WIDTH, pMarkData, pParam );
447 tools::Long ScTable::GetNeededSize( SCCOL nCol, SCROW nRow,
448 OutputDevice* pDev,
449 double nPPTX, double nPPTY,
450 const Fraction& rZoomX, const Fraction& rZoomY,
451 bool bWidth, bool bTotalSize, bool bInPrintTwips )
453 if ( nCol >= aCol.size() )
454 return 0;
456 ScNeededSizeOptions aOptions;
457 aOptions.bSkipMerged = false; // count merged cells
458 aOptions.bTotalSize = bTotalSize;
460 return aCol[nCol].GetNeededSize
461 ( nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, aOptions, nullptr, bInPrintTwips );
464 bool ScTable::SetOptimalHeight(
465 sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, bool bApi,
466 ScProgress* pOuterProgress, sal_uInt64 nProgressStart )
468 assert(nStartRow <= nEndRow);
470 OSL_ENSURE( rCxt.getExtraHeight() == 0 || rCxt.isForceAutoSize(),
471 "automatic OptimalHeight with Extra" );
473 if ( rDocument.IsAdjustHeightLocked() )
475 return false;
478 if (!rCxt.isForceAutoSize())
480 // Optimize - exit early if all rows have defined height: super expensive GetOptimalHeight
481 size_t nIndex;
482 SCROW nRow;
483 CRFlags nRowFlags = pRowFlags->GetValue(nStartRow, nIndex, nRow); // changes nIndex, nRow
484 if (nRowFlags & CRFlags::ManualSize) // first block of rows is manual - are all the rest?
486 bool bAllRowsAreManualHeight = true;
487 while (nRow < nEndRow)
489 nRowFlags = pRowFlags->GetNextValue(nIndex, nRow);
490 if (!(nRowFlags & CRFlags::ManualSize))
492 bAllRowsAreManualHeight = false;
493 break;
496 if (bAllRowsAreManualHeight)
497 return false;
501 SCSIZE nCount = static_cast<SCSIZE>(nEndRow-nStartRow+1);
503 ScProgress* pProgress = GetProgressBar(nCount, GetWeightedCount(), pOuterProgress, &rDocument);
505 mpRowHeights->enableTreeSearch(false);
507 GetOptimalHeightsInColumn(rCxt, aCol, nStartRow, nEndRow, pProgress, nProgressStart);
509 SetRowHeightRangeFunc aFunc(this, rCxt.getPPTY());
510 bool bChanged = SetOptimalHeightsToRows(rCxt, aFunc, pRowFlags.get(), nStartRow, nEndRow, bApi);
512 if ( pProgress != pOuterProgress )
513 delete pProgress;
515 mpRowHeights->enableTreeSearch(true);
517 if (bChanged)
519 if (ScViewData* pViewData = ScDocShell::GetViewData())
521 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
522 pViewData->GetViewShell(),
523 false /* bColsAffected */, true /* bRowsAffected */,
524 true /* bSizes*/, false /* bHidden */, false /* bFiltered */,
525 false /* bGroups */, nTab);
529 return bChanged;
532 void ScTable::SetOptimalHeightOnly(
533 sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow,
534 ScProgress* pOuterProgress, sal_uInt64 nProgressStart )
536 OSL_ENSURE( rCxt.getExtraHeight() == 0 || rCxt.isForceAutoSize(),
537 "automatic OptimalHeight with Extra" );
539 if ( rDocument.IsAdjustHeightLocked() )
540 return;
542 SCSIZE nCount = static_cast<SCSIZE>(nEndRow-nStartRow+1);
544 ScProgress* pProgress = GetProgressBar(nCount, GetWeightedCount(), pOuterProgress, &rDocument);
546 GetOptimalHeightsInColumn(rCxt, aCol, nStartRow, nEndRow, pProgress, nProgressStart);
548 SetRowHeightOnlyFunc aFunc(this);
550 bool bChanged = SetOptimalHeightsToRows(rCxt, aFunc, pRowFlags.get(), nStartRow, nEndRow, true);
552 if ( pProgress != pOuterProgress )
553 delete pProgress;
555 if (bChanged)
557 if (ScViewData* pViewData = ScDocShell::GetViewData())
559 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
560 pViewData->GetViewShell(),
561 false /* bColsAffected */, true /* bRowsAffected */,
562 true /* bSizes*/, false /* bHidden */, false /* bFiltered */,
563 false /* bGroups */, nTab);
568 bool ScTable::GetCellArea( SCCOL& rEndCol, SCROW& rEndRow ) const
570 bool bFound = false;
571 SCCOL nMaxX = 0;
572 SCROW nMaxY = 0;
573 for (SCCOL i=0; i<aCol.size(); i++)
575 if (!aCol[i].IsEmptyData())
577 bFound = true;
578 nMaxX = i;
579 SCROW nRow = aCol[i].GetLastDataPos();
580 if (nRow > nMaxY)
581 nMaxY = nRow;
583 if ( aCol[i].HasCellNotes() )
585 SCROW maxNoteRow = aCol[i].GetCellNotesMaxRow();
586 if (maxNoteRow >= nMaxY)
588 bFound = true;
589 nMaxY = maxNoteRow;
591 if (i>nMaxX)
593 bFound = true;
594 nMaxX = i;
597 if (aCol[i].HasSparklines())
599 SCROW maxSparklineRow = aCol[i].GetSparklinesMaxRow();
600 if (maxSparklineRow >= nMaxY)
602 bFound = true;
603 nMaxY = maxSparklineRow;
605 if (i > nMaxX)
607 bFound = true;
608 nMaxX = i;
613 rEndCol = nMaxX;
614 rEndRow = nMaxY;
615 return bFound;
618 bool ScTable::GetTableArea( SCCOL& rEndCol, SCROW& rEndRow, bool bCalcHiddens) const
620 bool bRet = true; //TODO: remember?
621 if (bCalcHiddens)
623 if (!bTableAreaValid)
625 bRet = GetPrintArea(nTableAreaX, nTableAreaY, true, bCalcHiddens);
626 bTableAreaValid = true;
628 rEndCol = nTableAreaX;
629 rEndRow = nTableAreaY;
631 else
633 if (!bTableAreaVisibleValid)
635 bRet = GetPrintArea(nTableAreaVisibleX, nTableAreaVisibleY, true, bCalcHiddens);
636 bTableAreaVisibleValid = true;
638 rEndCol = nTableAreaVisibleX;
639 rEndRow = nTableAreaVisibleY;
641 return bRet;
644 const SCCOL SC_COLUMNS_STOP = 30;
646 bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, bool bNotes, bool bCalcHiddens ) const
648 bool bFound = false;
649 SCCOL nMaxX = 0;
650 SCROW nMaxY = 0;
651 SCCOL i;
653 bool bSkipEmpty = ScModule::get()->GetPrintOptions().GetSkipEmpty();
655 for (i=0; i<aCol.size(); i++) // Test data
657 if (bCalcHiddens || !rDocument.ColHidden(i, nTab))
659 if (!aCol[i].IsEmptyData())
661 bFound = true;
662 if (i>nMaxX)
663 nMaxX = i;
664 SCROW nColY = aCol[i].GetLastDataPos();
665 if (nColY > nMaxY)
666 nMaxY = nColY;
668 if (bNotes && aCol[i].HasCellNotes() )
670 SCROW maxNoteRow = aCol[i].GetCellNotesMaxRow();
671 if (maxNoteRow >= nMaxY)
673 bFound = true;
674 nMaxY = maxNoteRow;
676 if (i>nMaxX)
678 bFound = true;
679 nMaxX = i;
682 if (aCol[i].HasSparklines())
684 SCROW maxSparklineRow = aCol[i].GetSparklinesMaxRow();
685 if (maxSparklineRow >= nMaxY)
687 bFound = true;
688 nMaxY = maxSparklineRow;
690 if (i > nMaxX)
692 bFound = true;
693 nMaxX = i;
699 SCCOL nMaxDataX = nMaxX;
701 for (i=0; i<aCol.size(); i++) // Test attribute
703 if (bCalcHiddens || !rDocument.ColHidden(i, nTab))
705 SCROW nLastRow;
706 if (aCol[i].GetLastVisibleAttr( nLastRow, bSkipEmpty ))
708 bFound = true;
709 nMaxX = i;
710 if (nLastRow > nMaxY)
711 nMaxY = nLastRow;
716 if (nMaxX == rDocument.MaxCol()) // omit attribute at the right
718 --nMaxX;
719 while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1], 0, rDocument.MaxRow()) )
720 --nMaxX;
723 if ( nMaxX < nMaxDataX )
725 nMaxX = nMaxDataX;
727 else if ( nMaxX > nMaxDataX )
729 SCCOL nAttrStartX = nMaxDataX + 1;
730 while ( nAttrStartX < (aCol.size()-1) )
732 SCCOL nAttrEndX = nAttrStartX;
733 while ( nAttrEndX < (aCol.size()-1) && aCol[nAttrStartX].IsVisibleAttrEqual(aCol[nAttrEndX+1], 0, rDocument.MaxRow()) )
734 ++nAttrEndX;
735 if ( nAttrEndX + 1 - nAttrStartX >= SC_COLUMNS_STOP )
737 // found equally-formatted columns behind data -> stop before these columns
738 nMaxX = nAttrStartX - 1;
740 // also don't include default-formatted columns before that
741 SCROW nDummyRow;
742 while ( nMaxX > nMaxDataX && !aCol[nMaxX].GetLastVisibleAttr( nDummyRow, bSkipEmpty ) )
743 --nMaxX;
744 break;
746 nAttrStartX = nAttrEndX + 1;
750 rEndCol = nMaxX;
751 rEndRow = nMaxY;
752 return bFound;
755 bool ScTable::GetPrintAreaHor( SCROW nStartRow, SCROW nEndRow,
756 SCCOL& rEndCol ) const
758 bool bFound = false;
759 SCCOL nMaxX = 0;
760 SCCOL i;
762 for (i=0; i<aCol.size(); i++) // Test attribute
764 if (aCol[i].HasVisibleAttrIn( nStartRow, nEndRow ))
766 bFound = true;
767 nMaxX = i;
771 if (nMaxX == rDocument.MaxCol()) // omit attribute at the right
773 --nMaxX;
774 while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1], nStartRow, nEndRow) )
775 --nMaxX;
778 for (i=0; i<aCol.size(); i++) // test the data
780 if (!aCol[i].IsEmptyData( nStartRow, nEndRow )) //TODO: bNotes ??????
782 bFound = true;
783 if (i > nMaxX)
784 nMaxX = i;
786 else if (aCol[i].HasSparklines())
788 if (i > nMaxX)
790 bFound = true;
791 nMaxX = i;
796 rEndCol = nMaxX;
797 return bFound;
800 bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol,
801 SCROW& rEndRow, bool bNotes ) const
803 bool bFound = false;
804 SCROW nMaxY = 0;
805 SCCOL i;
807 bool bSkipEmpty = ScModule::get()->GetPrintOptions().GetSkipEmpty();
809 for (i=nStartCol; i<=nEndCol && i < aCol.size(); i++) // Test attribute
811 SCROW nLastRow;
812 if (aCol[i].GetLastVisibleAttr( nLastRow, bSkipEmpty ))
814 bFound = true;
815 if (nLastRow > nMaxY)
816 nMaxY = nLastRow;
820 for (i=nStartCol; i<=nEndCol && i < aCol.size(); i++) // Test data
822 if (!aCol[i].IsEmptyData())
824 bFound = true;
825 SCROW nColY = aCol[i].GetLastDataPos();
826 if (nColY > nMaxY)
827 nMaxY = nColY;
829 if (bNotes && aCol[i].HasCellNotes() )
831 SCROW maxNoteRow =aCol[i].GetCellNotesMaxRow();
832 if (maxNoteRow > nMaxY)
834 bFound = true;
835 nMaxY = maxNoteRow;
838 if (aCol[i].HasSparklines())
840 SCROW maxNoteRow = aCol[i].GetSparklinesMaxRow();
841 if (maxNoteRow > nMaxY)
843 bFound = true;
844 nMaxY = maxNoteRow;
849 rEndRow = nMaxY;
850 return bFound;
853 bool ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const
855 bool bFound = false;
856 SCCOL nMinX = aCol.size()-1;
857 SCROW nMinY = rDocument.MaxRow();
858 SCCOL i;
860 for (i=0; i<aCol.size(); i++) // Test attribute
862 SCROW nFirstRow;
863 if (aCol[i].GetFirstVisibleAttr( nFirstRow ))
865 if (!bFound)
866 nMinX = i;
867 bFound = true;
868 if (nFirstRow < nMinY)
869 nMinY = nFirstRow;
873 if (nMinX == 0) // omit attribute at the right
875 if ( aCol.size() > 1 && aCol[0].IsVisibleAttrEqual(aCol[1], 0, rDocument.MaxRow())) // no single ones
877 ++nMinX;
878 while ( nMinX<(aCol.size()-1) && aCol[nMinX].IsVisibleAttrEqual(aCol[nMinX-1], 0, rDocument.MaxRow()))
879 ++nMinX;
883 bool bDatFound = false;
884 for (i=0; i<aCol.size(); i++) // Test data
886 if (!aCol[i].IsEmptyData())
888 if (!bDatFound && i<nMinX)
889 nMinX = i;
890 bFound = bDatFound = true;
891 SCROW nRow = aCol[i].GetFirstDataPos();
892 if (nRow < nMinY)
893 nMinY = nRow;
895 if ( aCol[i].HasCellNotes() )
897 SCROW minNoteRow = aCol[i].GetCellNotesMinRow();
898 if (minNoteRow <= nMinY)
900 bFound = true;
901 nMinY = minNoteRow;
903 if (i<nMinX)
905 bFound = true;
906 nMinX = i;
909 if (aCol[i].HasSparklines())
911 SCROW minSparkline = aCol[i].GetSparklinesMinRow();
912 if (minSparkline <= nMinY)
914 bFound = true;
915 nMinY = minSparkline;
917 if (i < nMinX)
919 bFound = true;
920 nMinX = i;
924 rStartCol = nMinX;
925 rStartRow = nMinY;
926 return bFound;
929 void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow,
930 bool bIncludeOld, bool bOnlyDown ) const
932 // return the smallest area containing at least all contiguous cells having data. This area
933 // is a square containing also empty cells. It may shrink or extend the area given as input
934 // Flags as modifiers:
936 // bIncludeOld = true ensure that the returned area contains at least the initial area,
937 // independently of the emptiness of rows / columns (i.e. does not allow shrinking)
938 // bOnlyDown = true means extend / shrink the inputted area only down, i.e modify only rEndRow
940 rStartCol = std::min<SCCOL>( rStartCol, aCol.size()-1 );
941 rEndCol = std::min<SCCOL>( rEndCol, aCol.size()-1 );
943 bool bLeft = false;
944 bool bRight = false;
945 bool bTop = false;
946 bool bBottom = false;
947 bool bChanged = false;
949 // We need to cache sc::ColumnBlockConstPosition per each column.
950 std::vector< sc::ColumnBlockConstPosition > blockPos( rEndCol + 1 );
951 for( SCCOL i = 0; i <= rEndCol; ++i )
952 aCol[ i ].InitBlockPosition( blockPos[ i ] );
956 bChanged = false;
958 if (!bOnlyDown)
960 SCROW nStart = rStartRow;
961 SCROW nEnd = rEndRow;
962 if (nStart>0) --nStart;
963 if (nEnd<rDocument.MaxRow()) ++nEnd;
965 if (rEndCol < (aCol.size()-1))
966 if (!aCol[rEndCol+1].IsEmptyData(nStart,nEnd))
968 assert( int( blockPos.size()) == rEndCol + 1 );
969 ++rEndCol;
970 blockPos.resize( blockPos.size() + 1 );
971 aCol[ rEndCol ].InitBlockPosition( blockPos[ rEndCol ] );
972 bChanged = true;
973 bRight = true;
976 if (rStartCol > 0)
977 if (!aCol[rStartCol-1].IsEmptyData(nStart,nEnd))
979 --rStartCol;
980 bChanged = true;
981 bLeft = true;
984 if (rStartRow > 0)
986 SCROW nTest = rStartRow-1;
987 bool needExtend = false;
988 for ( SCCOL i = rStartCol; i<=rEndCol && !needExtend; i++)
989 if (aCol[i].HasDataAt(blockPos[i], nTest))
990 needExtend = true;
991 if (needExtend)
993 --rStartRow;
994 bChanged = true;
995 bTop = true;
1000 if (rEndRow < rDocument.MaxRow())
1002 SCROW nTest = rEndRow+1;
1003 bool needExtend = false;
1004 for ( SCCOL i = rStartCol; i<=rEndCol && !needExtend; i++)
1005 if (aCol[i].HasDataAt(blockPos[ i ], nTest))
1006 needExtend = true;
1007 if (needExtend)
1009 ++rEndRow;
1010 bChanged = true;
1011 bBottom = true;
1015 while( bChanged );
1017 if ( !bIncludeOld && !bOnlyDown )
1019 if ( !bLeft )
1020 while ( rStartCol < rEndCol && rStartCol < (aCol.size()-1) && aCol[rStartCol].IsEmptyData(rStartRow,rEndRow) )
1021 ++rStartCol;
1023 if ( !bRight )
1024 while ( rEndCol > 0 && rStartCol < rEndCol && aCol[rEndCol].IsEmptyData(rStartRow,rEndRow) )
1025 --rEndCol;
1027 if ( !bTop && rStartRow < rDocument.MaxRow() && rStartRow < rEndRow )
1029 bool bShrink = true;
1032 for ( SCCOL i = rStartCol; i<=rEndCol && bShrink; i++)
1033 if (aCol[i].HasDataAt(rStartRow))
1034 bShrink = false;
1035 if (bShrink)
1036 ++rStartRow;
1037 } while (bShrink && rStartRow < rDocument.MaxRow() && rStartRow < rEndRow);
1041 if ( !bIncludeOld )
1043 if ( !bBottom && rEndRow > 0 && rStartRow < rEndRow )
1045 SCROW nLastDataRow = GetLastDataRow( rStartCol, rEndCol, rEndRow);
1046 if (nLastDataRow < rEndRow)
1047 rEndRow = std::max( rStartRow, nLastDataRow);
1052 bool ScTable::GetDataAreaSubrange( ScRange& rRange ) const
1054 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
1056 if ( nCol1 >= aCol.size() )
1057 return false;
1059 nCol2 = std::min<SCCOL>( nCol2, aCol.size()-1 );
1061 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
1063 SCCOL nFirstNonEmptyCol = -1, nLastNonEmptyCol = -1;
1064 SCROW nRowStart = nRow2, nRowEnd = nRow1;
1066 for ( SCCOL nCol = nCol1; nCol <= nCol2; ++nCol )
1068 SCROW nRowStartThis = nRow1, nRowEndThis = nRow2;
1069 bool bTrimmed = aCol[nCol].TrimEmptyBlocks(nRowStartThis, nRowEndThis);
1070 if ( bTrimmed )
1072 if ( nFirstNonEmptyCol == -1 )
1073 nFirstNonEmptyCol = nCol;
1074 nLastNonEmptyCol = nCol;
1076 nRowStart = std::min<SCROW>(nRowStart, nRowStartThis);
1077 nRowEnd = std::max<SCROW>(nRowEnd, nRowEndThis);
1081 if ( nFirstNonEmptyCol == -1 )
1082 return false;
1084 assert(nFirstNonEmptyCol <= nLastNonEmptyCol);
1085 assert(nRowStart <= nRowEnd);
1087 rRange.aStart.Set(nFirstNonEmptyCol, nRowStart, rRange.aStart.Tab());
1088 rRange.aEnd.Set(nLastNonEmptyCol, nRowEnd, rRange.aEnd.Tab());
1090 return true;
1093 bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow,
1094 SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly, bool bStickyTopRow, bool bStickyLeftCol,
1095 ScDataAreaExtras* pDataAreaExtras ) const
1097 rStartCol = std::min<SCCOL>( rStartCol, aCol.size()-1 );
1098 // check for rEndCol is done below.
1100 o_bShrunk = false;
1102 PutInOrder( rStartCol, rEndCol);
1103 PutInOrder( rStartRow, rEndRow);
1104 if (rStartCol < 0)
1106 rStartCol = 0;
1107 o_bShrunk = true;
1109 if (rStartRow < 0)
1111 rStartRow = 0;
1112 o_bShrunk = true;
1114 if (rEndCol >= aCol.size())
1116 rEndCol = aCol.size()-1;
1117 o_bShrunk = true;
1119 if (rEndRow > rDocument.MaxRow())
1121 rEndRow = rDocument.MaxRow();
1122 o_bShrunk = true;
1125 while (rStartCol < rEndCol)
1127 if (aCol[rEndCol].IsEmptyData( rStartRow, rEndRow))
1129 if (pDataAreaExtras && pDataAreaExtras->mnEndCol < rEndCol)
1131 // Check in order of likeliness.
1132 if ( (pDataAreaExtras->mbCellFormats
1133 && aCol[rEndCol].GetPatternCount( rStartRow, rEndRow) > 1
1134 && aCol[rEndCol].HasVisibleAttrIn( rStartRow, rEndRow)) ||
1135 (pDataAreaExtras->mbCellNotes
1136 && !aCol[rEndCol].IsNotesEmptyBlock( rStartRow, rEndRow)) ||
1137 (pDataAreaExtras->mbCellDrawObjects
1138 && !aCol[rEndCol].IsDrawObjectsEmptyBlock( rStartRow, rEndRow)))
1139 pDataAreaExtras->mnEndCol = rEndCol;
1142 --rEndCol;
1143 o_bShrunk = true;
1145 else
1146 break; // while
1149 if (!bStickyLeftCol)
1151 while (rStartCol < rEndCol)
1153 if (aCol[rStartCol].IsEmptyData( rStartRow, rEndRow))
1155 if (pDataAreaExtras && pDataAreaExtras->mnStartCol > rStartCol)
1157 // Check in order of likeliness.
1158 if ( (pDataAreaExtras->mbCellFormats
1159 && aCol[rStartCol].GetPatternCount( rStartRow, rEndRow) > 1
1160 && aCol[rStartCol].HasVisibleAttrIn( rStartRow, rEndRow)) ||
1161 (pDataAreaExtras->mbCellNotes
1162 && !aCol[rStartCol].IsNotesEmptyBlock( rStartRow, rEndRow)) ||
1163 (pDataAreaExtras->mbCellDrawObjects
1164 && !aCol[rStartCol].IsDrawObjectsEmptyBlock( rStartRow, rEndRow)))
1165 pDataAreaExtras->mnStartCol = rStartCol;
1168 ++rStartCol;
1169 o_bShrunk = true;
1171 else
1172 break; // while
1176 if (!bColumnsOnly)
1178 while (rStartRow < rEndRow)
1180 SCROW nLastDataRow = GetLastDataRow(rStartCol, rEndCol, rEndRow, pDataAreaExtras);
1181 if (0 <= nLastDataRow && nLastDataRow < rEndRow)
1183 rEndRow = std::max( rStartRow, nLastDataRow);
1184 o_bShrunk = true;
1186 else
1187 break; // while
1190 if (!bStickyTopRow)
1192 while (rStartRow < rEndRow)
1194 bool bFound = false;
1195 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++)
1197 if (aCol[i].HasDataAt(rStartRow, pDataAreaExtras))
1198 bFound = true;
1200 if (!bFound)
1202 ++rStartRow;
1203 o_bShrunk = true;
1205 else
1206 break; // while
1211 return rStartCol != rEndCol || (bColumnsOnly ?
1212 !aCol[rStartCol].IsEmptyData( rStartRow, rEndRow) :
1213 (rStartRow != rEndRow ||
1214 aCol[rStartCol].HasDataAt( rStartRow, pDataAreaExtras)));
1217 SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2, SCROW nLastRow, ScDataAreaExtras* pDataAreaExtras ) const
1219 if ( !IsColValid( nCol1 ) || !ValidCol( nCol2 ) )
1220 return -1;
1222 nCol2 = std::min<SCCOL>( nCol2, aCol.size() - 1 );
1224 SCROW nNewLastRow = 0;
1225 for (SCCOL i = nCol1; i <= nCol2; ++i)
1227 SCROW nThis = aCol[i].GetLastDataPos(nLastRow, pDataAreaExtras);
1228 if (nNewLastRow < nThis)
1229 nNewLastRow = nThis;
1232 return nNewLastRow;
1235 bool ScTable::IsEmptyData( SCCOL nStartCol, SCROW nStartRow,
1236 SCCOL nEndCol, SCROW nEndRow ) const
1238 for( SCCOL col : GetAllocatedColumnsRange( nStartCol, nEndCol ))
1239 if( !aCol[col].IsEmptyData( nStartRow, nEndRow ))
1240 return false;
1241 return true;
1244 SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
1245 SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) const
1247 SCCOL nStartColOrig = nStartCol;
1248 SCCOL nEndColOrig = nEndCol;
1249 nStartCol = std::min<SCCOL>( nStartCol, aCol.size()-1 );
1250 nEndCol = std::min<SCCOL>( nEndCol, aCol.size()-1 );
1252 // The region is not allocated and does not contain any data.
1253 if ( nStartColOrig != nStartCol )
1254 return ( ((eDir == DIR_BOTTOM) || (eDir == DIR_TOP)) ?
1255 static_cast<SCSIZE>(nEndRow - nStartRow + 1) :
1256 static_cast<SCSIZE>(nEndColOrig - nStartColOrig + 1) );
1258 SCSIZE nGapRight = static_cast<SCSIZE>(nEndColOrig - nEndCol);
1259 SCSIZE nCount = 0;
1260 SCCOL nCol;
1261 if ((eDir == DIR_BOTTOM) || (eDir == DIR_TOP))
1263 nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
1264 for (nCol = nStartCol; nCol <= nEndCol; nCol++)
1265 nCount = std::min(nCount, aCol[nCol].GetEmptyLinesInBlock(nStartRow, nEndRow, eDir));
1267 else if (eDir == DIR_RIGHT)
1269 nCol = nEndCol;
1270 while ((nCol >= nStartCol) &&
1271 aCol[nCol].IsEmptyData(nStartRow, nEndRow))
1273 nCount++;
1274 nCol--;
1276 nCount += nGapRight;
1278 else
1280 nCol = nStartCol;
1281 while ((nCol <= nEndCol) && aCol[nCol].IsEmptyData(nStartRow, nEndRow))
1283 nCount++;
1284 nCol++;
1287 // If the area between nStartCol and nEndCol are empty,
1288 // add the count of unallocated columns on the right.
1289 if ( nCol > nEndCol )
1290 nCount += nGapRight;
1292 return nCount;
1295 bool ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, SCCOL nEndCol ) const
1297 // The range of columns are unallocated hence empty.
1298 if ( nStartCol >= aCol.size() )
1299 return true;
1301 nEndCol = std::min<SCCOL>( nEndCol, aCol.size()-1 );
1303 for (SCCOL i=nStartCol; i<=nEndCol; i++)
1304 if (aCol[i].HasDataAt(nRow))
1305 return false;
1306 return true;
1309 void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow ) const
1311 rStartCol = std::min<SCCOL>( rStartCol, aCol.size()-1 );
1312 rEndCol = std::min<SCCOL>( rEndCol, aCol.size()-1 );
1314 while ( rStartCol<rEndCol && aCol[rStartCol].IsEmptyData(rStartRow,rEndRow) )
1315 ++rStartCol;
1317 while ( rStartCol<rEndCol && aCol[rEndCol].IsEmptyData(rStartRow,rEndRow) )
1318 --rEndCol;
1320 while ( rStartRow<rEndRow && IsEmptyLine(rStartRow, rStartCol, rEndCol) )
1321 ++rStartRow;
1323 // Optimised loop for finding the bottom of the area, can be costly in large
1324 // spreadsheets.
1325 SCROW lastDataPos = 0;
1326 for (SCCOL i=rStartCol; i<=rEndCol; i++)
1327 lastDataPos = std::max(lastDataPos, aCol[i].GetLastDataPos());
1328 // reduce EndRow to the last row with data
1329 rEndRow = std::min(rEndRow, lastDataPos);
1330 // but make sure EndRow is >= StartRow
1331 rEndRow = std::max(rStartRow, rEndRow);
1334 SCCOL ScTable::FindNextVisibleCol( SCCOL nCol, bool bRight ) const
1336 if(bRight)
1338 nCol++;
1339 SCCOL nEnd = 0;
1340 bool bHidden = rDocument.ColHidden(nCol, nTab, nullptr, &nEnd);
1341 if(bHidden)
1342 nCol = nEnd +1;
1344 return std::min<SCCOL>(rDocument.MaxCol(), nCol);
1346 else
1348 nCol--;
1349 SCCOL nStart = rDocument.MaxCol();
1350 bool bHidden = rDocument.ColHidden(nCol, nTab, &nStart);
1351 if(bHidden)
1352 nCol = nStart - 1;
1354 return std::max<SCCOL>(0, nCol);
1358 SCCOL ScTable::FindNextVisibleColWithContent( SCCOL nCol, bool bRight, SCROW nRow ) const
1360 const SCCOL nLastCol = aCol.size() - 1;
1361 if(bRight)
1363 // If nCol is the last allocated column index, there won't be any content to its right.
1364 // To maintain the original return behaviour, return rDocument.MaxCol().
1365 if(nCol >= nLastCol)
1366 return rDocument.MaxCol();
1370 nCol++;
1371 SCCOL nEndCol = 0;
1372 bool bHidden = rDocument.ColHidden( nCol, nTab, nullptr, &nEndCol );
1373 if(bHidden)
1375 nCol = nEndCol +1;
1376 // Can end search early as there is no data after nLastCol.
1377 // For nCol == nLastCol, it may still have data so don't want to return rDocument.MaxCol().
1378 if(nCol > nLastCol)
1379 return rDocument.MaxCol();
1382 if(aCol[nCol].HasVisibleDataAt(nRow))
1383 return nCol;
1385 while(nCol < nLastCol); // Stop search as soon as the last allocated column is searched.
1387 return rDocument.MaxCol();
1389 else
1391 if(nCol == 0)
1392 return 0;
1394 // If nCol is in the unallocated range [nLastCol+1, rDocument.MaxCol()], then move it directly after nLastCol
1395 // as there is no data in the unallocated range. This also makes the search faster and avoids
1396 // the need for more range checks in the loop below.
1397 if ( nCol > nLastCol )
1398 nCol = nLastCol + 1;
1402 nCol--;
1403 SCCOL nStartCol = rDocument.MaxCol();
1404 bool bHidden = rDocument.ColHidden( nCol, nTab, &nStartCol );
1405 if(bHidden)
1407 nCol = nStartCol -1;
1408 if(nCol <= 0)
1409 return 0;
1412 if(aCol[nCol].HasVisibleDataAt(nRow))
1413 return nCol;
1415 while(nCol > 0);
1417 return 0;
1421 void ScTable::FindAreaPos( SCCOL& rCol, SCROW& rRow, ScMoveDirection eDirection ) const
1423 const SCCOL nLastCol = aCol.size() - 1;
1425 if (eDirection == SC_MOVE_LEFT || eDirection == SC_MOVE_RIGHT)
1427 SCCOL nNewCol = rCol;
1428 bool bThere = ( nNewCol <= nLastCol ) && aCol[nNewCol].HasVisibleDataAt(rRow);
1429 bool bRight = (eDirection == SC_MOVE_RIGHT);
1430 if (bThere)
1432 if(nNewCol >= rDocument.MaxCol() && eDirection == SC_MOVE_RIGHT)
1433 return;
1434 else if(nNewCol == 0 && eDirection == SC_MOVE_LEFT)
1435 return;
1437 SCCOL nNextCol = FindNextVisibleCol( nNewCol, bRight );
1439 if( nNextCol <= nLastCol && aCol[nNextCol].HasVisibleDataAt(rRow) )
1441 bool bFound = false;
1442 nNewCol = nNextCol;
1445 nNextCol = FindNextVisibleCol( nNewCol, bRight );
1446 if( nNextCol <= nLastCol && aCol[nNextCol].HasVisibleDataAt(rRow) )
1447 nNewCol = nNextCol;
1448 else
1449 bFound = true;
1451 while(!bFound && nNextCol > 0 && nNextCol < rDocument.MaxCol());
1453 else
1455 nNewCol = FindNextVisibleColWithContent(nNewCol, bRight, rRow);
1458 else
1460 nNewCol = FindNextVisibleColWithContent(nNewCol, bRight, rRow);
1463 if (nNewCol<0)
1464 nNewCol=0;
1465 if (nNewCol>rDocument.MaxCol())
1466 nNewCol=rDocument.MaxCol();
1467 rCol = nNewCol;
1469 else
1471 if ( rCol <= nLastCol )
1472 aCol[rCol].FindDataAreaPos(rRow,eDirection == SC_MOVE_DOWN);
1473 else
1475 // The cell (rCol, rRow) is equivalent to an empty cell (although not allocated).
1476 // Set rRow to 0 or rDocument.MaxRow() depending on eDirection to maintain the behaviour of
1477 // ScColumn::FindDataAreaPos() when the given column is empty.
1478 rRow = ( eDirection == SC_MOVE_DOWN ) ? rDocument.MaxRow() : 0;
1483 bool ScTable::ValidNextPos( SCCOL nCol, SCROW nRow, const ScMarkData& rMark,
1484 bool bMarked, bool bUnprotected ) const
1486 if (!ValidCol(nCol) || !ValidRow(nRow))
1487 return false;
1489 if (rDocument.HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HasAttrFlags::Overlapped))
1490 // Skip an overlapped cell.
1491 return false;
1493 if (bMarked && !rMark.IsCellMarked(nCol,nRow))
1494 return false;
1496 /* TODO: for cursor movement *only* this should even take the protection
1497 * options (select locked, select unlocked) into account, see
1498 * ScTabView::SkipCursorHorizontal() and ScTabView::SkipCursorVertical(). */
1499 if (bUnprotected && rDocument.HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HasAttrFlags::Protected))
1500 return false;
1502 if (bMarked || bUnprotected) //TODO: also in other case ???
1504 // Hidden cells must be skipped, as the cursor would end up on the next cell
1505 // even if it is protected or not marked.
1506 //TODO: control per Extra-Parameter, only for Cursor movement ???
1508 if (RowHidden(nRow))
1509 return false;
1511 if (ColHidden(nCol))
1512 return false;
1515 return true;
1518 // Skips the current cell if it is Hidden, Overlapped or Protected and Sheet is Protected
1519 bool ScTable::SkipRow( const SCCOL nCol, SCROW& rRow, const SCROW nMovY,
1520 const ScMarkData& rMark, const bool bUp, const SCROW nUsedY,
1521 const bool bMarked, const bool bSheetProtected ) const
1523 if ( !ValidRow( rRow ))
1524 return false;
1526 if (bSheetProtected && rDocument.HasAttrib( nCol, rRow, nTab, nCol, rRow, nTab, HasAttrFlags::Protected))
1528 if ( rRow > nUsedY )
1529 rRow = (bUp ? nUsedY : rDocument.MaxRow() + nMovY);
1530 else
1531 rRow += nMovY;
1533 if (bMarked)
1534 rRow = rMark.GetNextMarked( nCol, rRow, bUp );
1536 return true;
1538 else
1540 bool bRowHidden = RowHidden( rRow );
1541 bool bOverlapped = rDocument.HasAttrib( nCol, rRow, nTab, nCol, rRow, nTab, HasAttrFlags::Overlapped );
1543 if ( bRowHidden || bOverlapped )
1545 rRow += nMovY;
1546 if (bMarked)
1547 rRow = rMark.GetNextMarked( nCol, rRow, bUp );
1549 return true;
1553 return false;
1556 void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCCOL nMovX, SCROW nMovY,
1557 bool bMarked, bool bUnprotected, const ScMarkData& rMark, SCCOL nTabStartCol ) const
1559 // Ensure bMarked is set only if there is a mark.
1560 assert( !bMarked || rMark.IsMarked() || rMark.IsMultiMarked());
1562 const bool bSheetProtected = IsProtected();
1564 if ( bUnprotected && !bSheetProtected ) // Is sheet really protected?
1565 bUnprotected = false;
1567 SCCOL nCol = rCol + nMovX;
1568 SCROW nRow = rRow + nMovY;
1570 SCCOL nStartCol, nEndCol;
1571 SCROW nStartRow, nEndRow;
1572 if (bMarked)
1574 ScRange aRange( ScAddress::UNINITIALIZED);
1575 if (rMark.IsMarked())
1576 aRange = rMark.GetMarkArea();
1577 else if (rMark.IsMultiMarked())
1578 aRange = rMark.GetMultiMarkArea();
1579 else
1581 // Covered by assert() above, but for NDEBUG build.
1582 if (ValidColRow(nCol,nRow))
1584 rCol = nCol;
1585 rRow = nRow;
1587 return;
1589 nStartCol = aRange.aStart.Col();
1590 nStartRow = aRange.aStart.Row();
1591 nEndCol = aRange.aEnd.Col();
1592 nEndRow = aRange.aEnd.Row();
1594 else if (bUnprotected)
1596 nStartCol = 0;
1597 nStartRow = 0;
1598 nEndCol = rCol;
1599 nEndRow = rRow;
1600 rDocument.GetPrintArea( nTab, nEndCol, nEndRow, true );
1601 // Add some cols/rows to the print area (which is "content or
1602 // visually different from empty") to enable travelling through
1603 // protected forms with empty cells and no visual indicator.
1604 // 42 might be good enough and not too much...
1605 nEndCol = std::min<SCCOL>( nEndCol+42, rDocument.MaxCol());
1606 nEndRow = std::min<SCROW>( nEndRow+42, rDocument.MaxRow());
1608 else
1610 // Invalid values show up for instance for Tab, when nothing is
1611 // selected and not protected (left / right edge), then leave values
1612 // unchanged.
1613 if (ValidColRow(nCol,nRow))
1615 rCol = nCol;
1616 rRow = nRow;
1619 // Caller ensures actually moving nMovY to jump to prev/next row's
1620 // start col.
1621 if (nTabStartCol != SC_TABSTART_NONE)
1622 rCol = nTabStartCol;
1624 return;
1627 if ( nMovY && (bMarked || bUnprotected))
1631 const bool bUp = (nMovY < 0);
1632 const SCCOL nColAdd = (bUp ? -1 : 1);
1634 if (bMarked)
1635 nRow = rMark.GetNextMarked( nCol, nRow, bUp );
1637 if (nTabStartCol != SC_TABSTART_NONE)
1639 /* NOTE: If current rCol < nTabStartCol when going down, there
1640 * is no way to detect if the previous Tab wrapped around to
1641 * the next row or if it was a Shift+Tab going backwards. The
1642 * result after a wrap is an odd jump to the next row's
1643 * nTabStartCol, which is logical though and always has been
1644 * the case. Similar for rCol > nTabStartCol when going up.
1645 * Related, it would be nice to limit advancing the position
1646 * within bounds even if another wrap would occur, but again we
1647 * can't tell if previously Tab or Shift+Tab was used, so we
1648 * don't know if it would be nTabStartCol to nEndCol (for Tab)
1649 * or nStartCol to nTabStartCol (for Shift+Tab). */
1651 // Continue moving horizontally.
1652 nMovX = nColAdd;
1653 nCol = nTabStartCol;
1654 break; // do
1657 while ( SkipRow( nCol, nRow, nMovY, rMark, bUp, nEndRow, bMarked, bSheetProtected ))
1660 sal_uInt16 nWrap = 0;
1661 while ( nRow < nStartRow || nRow > nEndRow )
1663 nCol += nColAdd;
1665 while (nStartCol <= nCol && nCol <= nEndCol && ValidCol(nCol) && ColHidden(nCol))
1666 nCol += nColAdd; // skip hidden cols
1668 if (nCol < nStartCol)
1670 nCol = nEndCol;
1672 if (++nWrap >= 2)
1673 return;
1675 else if (nCol > nEndCol)
1677 nCol = nStartCol;
1679 if (++nWrap >= 2)
1680 return;
1682 if (nRow < nStartRow)
1683 nRow = nEndRow;
1684 else if (nRow > nEndRow)
1685 nRow = nStartRow;
1687 if (bMarked)
1688 nRow = rMark.GetNextMarked( nCol, nRow, bUp );
1690 while ( SkipRow( nCol, nRow, nMovY, rMark, bUp, nEndRow, bMarked, bSheetProtected ))
1693 } while (false);
1696 if ( nMovX && ( bMarked || bUnprotected ) )
1698 // wrap initial skip counting:
1699 if (nCol < nStartCol)
1701 nCol = nEndCol;
1702 --nRow;
1703 if (nRow < nStartRow)
1704 nRow = nEndRow;
1706 if (nCol > nEndCol)
1708 nCol = nStartCol;
1709 ++nRow;
1710 if (nRow > nEndRow)
1711 nRow = nStartRow;
1714 if ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) )
1716 const SCCOL nColCount = nEndCol - nStartCol + 1;
1717 std::unique_ptr<SCROW[]> pNextRows( new SCROW[nColCount]);
1718 const SCCOL nLastCol = aCol.size() - 1;
1719 const bool bUp = (nMovX < 0); // Moving left also means moving up in rows.
1720 const SCROW nRowAdd = (bUp ? -1 : 1);
1721 sal_uInt16 nWrap = 0;
1723 if (bUp)
1725 for (SCCOL i = 0; i < nColCount; ++i)
1726 pNextRows[i] = (i + nStartCol > nCol) ? (nRow + nRowAdd) : nRow;
1728 else
1730 for (SCCOL i = 0; i < nColCount; ++i)
1731 pNextRows[i] = (i + nStartCol < nCol) ? (nRow + nRowAdd) : nRow;
1735 SCROW nNextRow = pNextRows[nCol - nStartCol] + nRowAdd;
1736 if ( bMarked )
1737 nNextRow = rMark.GetNextMarked( nCol, nNextRow, bUp );
1738 if ( bUnprotected )
1739 nNextRow = ( nCol <= nLastCol ) ? aCol[nCol].GetNextUnprotected( nNextRow, bUp ) :
1740 aDefaultColData.GetNextUnprotected( nNextRow, bUp );
1741 pNextRows[nCol - nStartCol] = nNextRow;
1743 if (bUp)
1745 SCROW nMaxRow = nStartRow - 1;
1746 for (SCCOL i = 0; i < nColCount; ++i)
1748 if (pNextRows[i] >= nMaxRow) // when two equal the right one
1750 nMaxRow = pNextRows[i];
1751 nCol = i + nStartCol;
1754 nRow = nMaxRow;
1756 if ( nRow < nStartRow )
1758 if (++nWrap >= 2)
1759 return;
1760 nCol = nEndCol;
1761 nRow = nEndRow;
1762 for (SCCOL i = 0; i < nColCount; ++i)
1763 pNextRows[i] = nEndRow; // do it all over again
1766 else
1768 SCROW nMinRow = nEndRow + 1;
1769 for (SCCOL i = 0; i < nColCount; ++i)
1771 if (pNextRows[i] < nMinRow) // when two equal the left one
1773 nMinRow = pNextRows[i];
1774 nCol = i + nStartCol;
1777 nRow = nMinRow;
1779 if ( nRow > nEndRow )
1781 if (++nWrap >= 2)
1782 return;
1783 nCol = nStartCol;
1784 nRow = nStartRow;
1785 for (SCCOL i = 0; i < nColCount; ++i)
1786 pNextRows[i] = nStartRow; // do it all over again
1790 while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) );
1794 if (ValidColRow(nCol,nRow))
1796 rCol = nCol;
1797 rRow = nRow;
1801 bool ScTable::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark ) const
1803 ++rRow; // next row
1805 while ( rCol < aCol.size() )
1807 ScMarkArray aArray( rMark.GetMarkArray( rCol ) );
1808 while ( rRow <= rDocument.MaxRow() )
1810 SCROW nStart = aArray.GetNextMarked( rRow, false );
1811 if ( nStart <= rDocument.MaxRow() )
1813 SCROW nEnd = aArray.GetMarkEnd( nStart, false );
1815 const sc::CellStoreType& rCells = aCol[rCol].maCells;
1816 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = rCells.position(nStart);
1817 sc::CellStoreType::const_iterator it = aPos.first;
1818 SCROW nTestRow = nStart;
1819 if (it->type == sc::element_type_empty)
1821 // Skip the empty block.
1822 nTestRow += it->size - aPos.second;
1823 ++it;
1824 if (it == rCells.end())
1826 // No more block. Move on to the next column.
1827 rRow = rDocument.MaxRow() + 1;
1828 continue;
1832 if (nTestRow <= nEnd)
1834 // Cell found.
1835 rRow = nTestRow;
1836 return true;
1839 rRow = nEnd + 1; // Search for next selected range
1841 else
1842 rRow = rDocument.MaxRow() + 1; // End of column
1844 rRow = 0;
1845 ++rCol; // test next column
1848 // Though searched only the allocated columns, it is equivalent to a search till rDocument.MaxCol().
1849 rCol = rDocument.MaxCol() + 1;
1850 return false; // Through all columns
1853 void ScTable::UpdateDrawRef( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
1854 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
1855 SCCOL nDx, SCROW nDy, SCTAB nDz, bool bUpdateNoteCaptionPos )
1857 if ( !(nTab >= nTab1 && nTab <= nTab2 && nDz == 0) ) // only within the table
1858 return;
1860 ScDrawLayer* pDrawLayer = rDocument.GetDrawLayer();
1861 if ( eUpdateRefMode != URM_COPY && pDrawLayer )
1863 if ( eUpdateRefMode == URM_MOVE )
1864 { // source range
1865 nCol1 = sal::static_int_cast<SCCOL>( nCol1 - nDx );
1866 nRow1 = sal::static_int_cast<SCROW>( nRow1 - nDy );
1867 nCol2 = sal::static_int_cast<SCCOL>( nCol2 - nDx );
1868 nRow2 = sal::static_int_cast<SCROW>( nRow2 - nDy );
1870 pDrawLayer->MoveArea( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy,
1871 (eUpdateRefMode == URM_INSDEL), bUpdateNoteCaptionPos );
1875 void ScTable::UpdateReference(
1876 sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, bool bIncludeDraw, bool bUpdateNoteCaptionPos )
1878 bool bUpdated = false;
1879 UpdateRefMode eUpdateRefMode = rCxt.meMode;
1880 SCCOL nDx = rCxt.mnColDelta;
1881 SCROW nDy = rCxt.mnRowDelta;
1882 SCTAB nDz = rCxt.mnTabDelta;
1883 SCCOL nCol1 = rCxt.maRange.aStart.Col(), nCol2 = rCxt.maRange.aEnd.Col();
1884 SCROW nRow1 = rCxt.maRange.aStart.Row(), nRow2 = rCxt.maRange.aEnd.Row();
1885 SCTAB nTab1 = rCxt.maRange.aStart.Tab(), nTab2 = rCxt.maRange.aEnd.Tab();
1887 // Named expressions need to be updated before formulas accessing them.
1888 if (mpRangeName)
1889 mpRangeName->UpdateReference(rCxt, nTab);
1891 if (rCxt.meMode == URM_COPY )
1893 for( SCCOL col : GetAllocatedColumnsRange( rCxt.maRange.aStart.Col(), rCxt.maRange.aEnd.Col()))
1894 bUpdated |= aCol[col].UpdateReference(rCxt, pUndoDoc);
1896 else
1898 for (SCCOL col : GetAllocatedColumnsRange(0, rDocument.MaxCol()))
1899 bUpdated |= aCol[col].UpdateReference(rCxt, pUndoDoc);
1900 // When deleting row(s), delete same row from the default attribute
1901 if (nDy < 0)
1902 aDefaultColData.DeleteRow(nRow1+nDy, -nDy);
1905 if ( bIncludeDraw )
1906 UpdateDrawRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, bUpdateNoteCaptionPos );
1908 if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // print ranges: only within the table
1910 SCTAB nSTab = nTab;
1911 SCTAB nETab = nTab;
1912 SCCOL nSCol = 0;
1913 SCROW nSRow = 0;
1914 SCCOL nECol = 0;
1915 SCROW nERow = 0;
1916 bool bRecalcPages = false;
1918 for ( auto& rPrintRange : aPrintRanges )
1920 nSCol = rPrintRange.aStart.Col();
1921 nSRow = rPrintRange.aStart.Row();
1922 nECol = rPrintRange.aEnd.Col();
1923 nERow = rPrintRange.aEnd.Row();
1925 // do not try to modify sheet index of print range
1926 if ( ScRefUpdate::Update( &rDocument, eUpdateRefMode,
1927 nCol1,nRow1,nTab, nCol2,nRow2,nTab,
1928 nDx,nDy,0,
1929 nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
1931 rPrintRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
1932 bRecalcPages = true;
1936 if ( moRepeatColRange )
1938 nSCol = moRepeatColRange->aStart.Col();
1939 nSRow = moRepeatColRange->aStart.Row();
1940 nECol = moRepeatColRange->aEnd.Col();
1941 nERow = moRepeatColRange->aEnd.Row();
1943 // do not try to modify sheet index of repeat range
1944 if ( ScRefUpdate::Update( &rDocument, eUpdateRefMode,
1945 nCol1,nRow1,nTab, nCol2,nRow2,nTab,
1946 nDx,nDy,0,
1947 nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
1949 *moRepeatColRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
1950 bRecalcPages = true;
1951 nRepeatStartX = nSCol; // for UpdatePageBreaks
1952 nRepeatEndX = nECol;
1956 if ( moRepeatRowRange )
1958 nSCol = moRepeatRowRange->aStart.Col();
1959 nSRow = moRepeatRowRange->aStart.Row();
1960 nECol = moRepeatRowRange->aEnd.Col();
1961 nERow = moRepeatRowRange->aEnd.Row();
1963 // do not try to modify sheet index of repeat range
1964 if ( ScRefUpdate::Update( &rDocument, eUpdateRefMode,
1965 nCol1,nRow1,nTab, nCol2,nRow2,nTab,
1966 nDx,nDy,0,
1967 nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
1969 *moRepeatRowRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
1970 bRecalcPages = true;
1971 nRepeatStartY = nSRow; // for UpdatePageBreaks
1972 nRepeatEndY = nERow;
1976 // updating print ranges is not necessary with multiple print ranges
1977 if ( bRecalcPages && GetPrintRangeCount() <= 1 )
1979 UpdatePageBreaks(nullptr);
1981 rDocument.RepaintRange( ScRange(0,0,nTab,rDocument.MaxCol(),rDocument.MaxRow(),nTab) );
1985 if (bUpdated)
1986 SetStreamValid(false);
1988 if(mpCondFormatList)
1989 mpCondFormatList->UpdateReference(rCxt);
1991 if (pTabProtection)
1992 pTabProtection->updateReference( eUpdateRefMode, rDocument, rCxt.maRange, nDx, nDy, nDz);
1995 void ScTable::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
1996 ScDocument* pUndoDoc )
1998 for (auto const & rpCol : aCol)
1999 rpCol->UpdateTranspose( rSource, rDest, pUndoDoc );
2002 void ScTable::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
2004 for (auto const & rpCol : aCol)
2005 rpCol->UpdateGrow( rArea, nGrowX, nGrowY );
2008 void ScTable::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
2010 // Store the old tab number in sc::UpdatedRangeNames for
2011 // ScTokenArray::AdjustReferenceOnInsertedTab() to check with
2012 // isNameModified()
2013 if (mpRangeName)
2014 mpRangeName->UpdateInsertTab(rCxt, nTab);
2016 if (nTab >= rCxt.mnInsertPos)
2018 nTab += rCxt.mnSheets;
2019 if (pDBDataNoName)
2020 pDBDataNoName->UpdateMoveTab(nTab - 1 ,nTab);
2023 if (mpCondFormatList)
2024 mpCondFormatList->UpdateInsertTab(rCxt);
2026 if (pTabProtection)
2027 pTabProtection->updateReference( URM_INSDEL, rDocument,
2028 ScRange( 0, 0, rCxt.mnInsertPos, rDocument.MaxCol(), rDocument.MaxRow(), MAXTAB),
2029 0, 0, rCxt.mnSheets);
2031 for (SCCOL i=0; i < aCol.size(); i++)
2032 aCol[i].UpdateInsertTab(rCxt);
2034 SetStreamValid(false);
2037 void ScTable::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
2039 // Store the old tab number in sc::UpdatedRangeNames for
2040 // ScTokenArray::AdjustReferenceOnDeletedTab() to check with
2041 // isNameModified()
2042 if (mpRangeName)
2043 mpRangeName->UpdateDeleteTab(rCxt, nTab);
2045 if (nTab > rCxt.mnDeletePos)
2047 nTab -= rCxt.mnSheets;
2048 if (pDBDataNoName)
2049 pDBDataNoName->UpdateMoveTab(nTab + 1,nTab);
2052 if (mpCondFormatList)
2053 mpCondFormatList->UpdateDeleteTab(rCxt);
2055 if (pTabProtection)
2056 pTabProtection->updateReference( URM_INSDEL, rDocument,
2057 ScRange( 0, 0, rCxt.mnDeletePos, rDocument.MaxCol(), rDocument.MaxRow(), MAXTAB),
2058 0, 0, -rCxt.mnSheets);
2060 for (SCCOL i = 0; i < aCol.size(); ++i)
2061 aCol[i].UpdateDeleteTab(rCxt);
2063 SetStreamValid(false);
2066 void ScTable::UpdateMoveTab(
2067 sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo, ScProgress* pProgress )
2069 nTab = nTabNo;
2070 if (mpRangeName)
2071 mpRangeName->UpdateMoveTab(rCxt, nTab);
2073 if (pDBDataNoName)
2074 pDBDataNoName->UpdateMoveTab(rCxt.mnOldPos, rCxt.mnNewPos);
2076 if(mpCondFormatList)
2077 mpCondFormatList->UpdateMoveTab(rCxt);
2079 if (pTabProtection)
2080 pTabProtection->updateReference( URM_REORDER, rDocument,
2081 ScRange( 0, 0, rCxt.mnOldPos, rDocument.MaxCol(), rDocument.MaxRow(), MAXTAB),
2082 0, 0, rCxt.mnNewPos - rCxt.mnOldPos);
2084 for ( SCCOL i=0; i < aCol.size(); i++ )
2086 aCol[i].UpdateMoveTab(rCxt, nTabNo);
2087 if (pProgress)
2088 pProgress->SetState(pProgress->GetState() + aCol[i].GetCodeCount());
2091 SetStreamValid(false);
2094 void ScTable::UpdateCompile( bool bForceIfNameInUse )
2096 for (SCCOL i=0; i < aCol.size(); i++)
2098 aCol[i].UpdateCompile( bForceIfNameInUse );
2102 void ScTable::SetTabNo(SCTAB nNewTab)
2104 nTab = nNewTab;
2105 for (SCCOL i=0; i < aCol.size(); i++)
2106 aCol[i].SetTabNo(nNewTab);
2109 void ScTable::FindRangeNamesInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
2110 sc::UpdatedRangeNames& rIndexes) const
2112 for (SCCOL i = nCol1; i <= nCol2 && IsColValid( i ); i++)
2113 aCol[i].FindRangeNamesInUse(nRow1, nRow2, rIndexes);
2116 void ScTable::ExtendPrintArea( OutputDevice* pDev,
2117 SCCOL /* nStartCol */, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow )
2119 if ( !mpColFlags || !pRowFlags )
2121 OSL_FAIL("ExtendPrintArea: No ColInfo or RowInfo");
2122 return;
2125 Point aPix1000 = pDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
2126 double nPPTX = aPix1000.X() / 1000.0;
2127 double nPPTY = aPix1000.Y() / 1000.0;
2129 // First, mark those columns that we need to skip i.e. hidden and empty columns.
2131 ScFlatBoolColSegments aSkipCols(rDocument.MaxCol());
2132 aSkipCols.setFalse(0, rDocument.MaxCol());
2133 for (SCCOL i = 0; i <= rDocument.MaxCol(); ++i)
2135 SCCOL nLastCol = i;
2136 if (ColHidden(i, nullptr, &nLastCol))
2138 // Columns are hidden in this range.
2139 aSkipCols.setTrue(i, nLastCol);
2141 else
2143 // These columns are visible. Check for empty columns.
2144 SCCOL nEmptyCount = 0;
2145 SCCOL j = i;
2146 for (; j <= nLastCol; ++j)
2148 if ( j >= aCol.size() )
2149 break;
2150 if (aCol[j].IsCellCountZero()) // empty
2151 nEmptyCount++;
2153 if (nEmptyCount)
2154 aSkipCols.setTrue(i,i+nEmptyCount);
2155 if ( j >= aCol.size() )
2156 aSkipCols.setTrue( j, rDocument.MaxCol() );
2158 i = nLastCol;
2161 ScFlatBoolColSegments::RangeData aColData;
2162 for (SCCOL nCol = rEndCol; nCol >= 0; --nCol)
2164 if (!aSkipCols.getRangeData(nCol, aColData))
2165 // Failed to get the data. This should never happen!
2166 return;
2168 if (aColData.mbValue)
2170 // Skip these columns.
2171 nCol = aColData.mnCol1; // move toward 0.
2172 continue;
2175 // These are visible and non-empty columns.
2176 for (SCCOL nDataCol = nCol; 0 <= nDataCol && nDataCol >= aColData.mnCol1; --nDataCol)
2178 SCCOL nPrintCol = nDataCol;
2179 VisibleDataCellIterator aIter(rDocument, *mpHiddenRows, aCol[nDataCol]);
2180 ScRefCellValue aCell = aIter.reset(nStartRow);
2181 if (aCell.isEmpty())
2182 // No visible cells found in this column. Skip it.
2183 continue;
2185 while (!aCell.isEmpty())
2187 SCCOL nNewCol = nDataCol;
2188 SCROW nRow = aIter.getRow();
2189 if (nRow > nEndRow)
2190 // Went past the last row position. Bail out.
2191 break;
2193 MaybeAddExtraColumn(nNewCol, nRow, pDev, nPPTX, nPPTY);
2194 if (nNewCol > nPrintCol)
2195 nPrintCol = nNewCol;
2196 aCell = aIter.next();
2199 if (nPrintCol > rEndCol)
2200 // Make sure we don't shrink the print area.
2201 rEndCol = nPrintCol;
2203 nCol = aColData.mnCol1; // move toward 0.
2207 void ScTable::MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY)
2209 // tdf#128873 we do not need to calculate text width (heavy operation)
2210 // when we for sure know that an additional column will not be added
2211 if (GetAllocatedColumnsCount() > rCol + 1)
2213 ScRefCellValue aNextCell = aCol[rCol + 1].GetCellValue(nRow);
2214 if (!aNextCell.isEmpty())
2216 // return rCol as is
2217 return;
2221 ScColumn& rColumn = aCol[rCol];
2222 ScRefCellValue aCell = rColumn.GetCellValue(nRow);
2223 if (!aCell.hasString())
2224 return;
2226 tools::Long nPixel = rColumn.GetTextWidth(nRow);
2228 // Width already calculated in Idle-Handler ?
2229 if ( TEXTWIDTH_DIRTY == nPixel )
2231 ScNeededSizeOptions aOptions;
2232 aOptions.bTotalSize = true;
2233 aOptions.bFormula = false; //TODO: pass as parameter
2234 aOptions.bSkipMerged = false;
2236 Fraction aZoom(1,1);
2237 nPixel = rColumn.GetNeededSize(
2238 nRow, pDev, nPPTX, nPPTY, aZoom, aZoom, true, aOptions, nullptr );
2240 rColumn.SetTextWidth(nRow, static_cast<sal_uInt16>(nPixel));
2243 tools::Long nTwips = static_cast<tools::Long>(nPixel / nPPTX);
2244 tools::Long nDocW = GetColWidth( rCol );
2246 tools::Long nMissing = nTwips - nDocW;
2247 if ( nMissing > 0 )
2249 // look at alignment
2251 const ScPatternAttr* pPattern = GetPattern( rCol, nRow );
2252 const SfxItemSet* pCondSet = rDocument.GetCondResult( rCol, nRow, nTab );
2254 SvxCellHorJustify eHorJust =
2255 pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet ).GetValue();
2256 if ( eHorJust == SvxCellHorJustify::Center )
2257 nMissing /= 2; // distributed into both directions
2258 else
2260 // STANDARD is LEFT (only text is handled here)
2261 bool bRight = ( eHorJust == SvxCellHorJustify::Right );
2262 if ( IsLayoutRTL() )
2263 bRight = !bRight;
2264 if ( bRight )
2265 nMissing = 0; // extended only to the left (logical)
2269 SCCOL nNewCol = rCol;
2270 while (nMissing > 0 && nNewCol < rDocument.MaxCol())
2272 auto nNextCol = nNewCol + 1;
2273 bool bNextEmpty = true;
2274 if (GetAllocatedColumnsCount() > nNextCol)
2276 ScRefCellValue aNextCell = aCol[nNextCol].GetCellValue(nRow);
2277 bNextEmpty = aNextCell.isEmpty();
2279 if (!bNextEmpty)
2281 // Cell content in a next column ends display of this string.
2282 nMissing = 0;
2284 else
2285 nMissing -= GetColWidth(++nNewCol);
2287 rCol = nNewCol;
2290 namespace {
2292 class SetTableIndex
2294 SCTAB mnTab;
2295 public:
2296 explicit SetTableIndex(SCTAB nTab) : mnTab(nTab) {}
2298 void operator() (ScRange& rRange) const
2300 rRange.aStart.SetTab(mnTab);
2301 rRange.aEnd.SetTab(mnTab);
2307 void ScTable::CopyPrintRange(const ScTable& rTable)
2309 // The table index shouldn't be used when the print range is used, but
2310 // just in case set the correct table index.
2312 aPrintRanges = rTable.aPrintRanges;
2313 ::std::for_each(aPrintRanges.begin(), aPrintRanges.end(), SetTableIndex(nTab));
2315 bPrintEntireSheet = rTable.bPrintEntireSheet;
2317 moRepeatColRange.reset();
2318 if (rTable.moRepeatColRange)
2320 moRepeatColRange.emplace(*rTable.moRepeatColRange);
2321 moRepeatColRange->aStart.SetTab(nTab);
2322 moRepeatColRange->aEnd.SetTab(nTab);
2325 moRepeatRowRange.reset();
2326 if (rTable.moRepeatRowRange)
2328 moRepeatRowRange.emplace(*rTable.moRepeatRowRange);
2329 moRepeatRowRange->aStart.SetTab(nTab);
2330 moRepeatRowRange->aEnd.SetTab(nTab);
2334 void ScTable::SetRepeatColRange( std::optional<ScRange> oNew )
2336 moRepeatColRange = std::move(oNew);
2338 SetStreamValid(false);
2340 InvalidatePageBreaks();
2343 void ScTable::SetRepeatRowRange( std::optional<ScRange> oNew )
2345 moRepeatRowRange = std::move(oNew);
2347 SetStreamValid(false);
2349 InvalidatePageBreaks();
2352 void ScTable::ClearPrintRanges()
2354 aPrintRanges.clear();
2355 bPrintEntireSheet = false;
2357 SetStreamValid(false);
2359 InvalidatePageBreaks(); // #i117952# forget page breaks for an old print range
2362 void ScTable::ClearPrintNamedRanges()
2364 // tdf#100034 Clearing print ranges also requires to remove all print named ranges
2365 // Iterate over all named ranges to determine which are print areas to be removed
2366 if (mpRangeName)
2368 std::vector<ScRangeData*> aRangesToRemove;
2369 for (auto it = mpRangeName->begin(); it != mpRangeName->end(); it++)
2371 ScRangeData* pData = it->second.get();
2372 if (pData->HasType(ScRangeData::Type::PrintArea))
2373 aRangesToRemove.push_back(pData);
2376 // Effectively remove all named ranges that refer to print ranges
2377 for (auto pItem : aRangesToRemove)
2378 mpRangeName->erase(*pItem);
2382 void ScTable::AddPrintRange( const ScRange& rNew )
2384 bPrintEntireSheet = false;
2385 if( aPrintRanges.size() < 0xFFFF )
2386 aPrintRanges.push_back( rNew );
2388 SetStreamValid(false);
2390 InvalidatePageBreaks();
2393 void ScTable::SetPrintEntireSheet()
2395 if( !IsPrintEntireSheet() )
2397 ClearPrintRanges();
2398 bPrintEntireSheet = true;
2402 const ScRange* ScTable::GetPrintRange(sal_uInt16 nPos) const
2404 return (nPos < GetPrintRangeCount()) ? &aPrintRanges[ nPos ] : nullptr;
2407 void ScTable::FillPrintSaver( ScPrintSaverTab& rSaveTab ) const
2409 rSaveTab.SetAreas( std::vector(aPrintRanges), bPrintEntireSheet );
2410 rSaveTab.SetRepeat( moRepeatColRange, moRepeatRowRange );
2413 void ScTable::RestorePrintRanges( const ScPrintSaverTab& rSaveTab )
2415 aPrintRanges = rSaveTab.GetPrintRanges();
2416 bPrintEntireSheet = rSaveTab.IsEntireSheet();
2417 SetRepeatColRange( rSaveTab.GetRepeatCol() );
2418 SetRepeatRowRange( rSaveTab.GetRepeatRow() );
2420 InvalidatePageBreaks(); // #i117952# forget page breaks for an old print range
2421 UpdatePageBreaks(nullptr);
2424 ScTable::VisibleDataCellIterator::VisibleDataCellIterator(const ScDocument& rDoc, ScFlatBoolRowSegments& rRowSegs, ScColumn& rColumn) :
2425 mrDocument(rDoc),
2426 mrRowSegs(rRowSegs),
2427 mrColumn(rColumn),
2428 mnCurRow(ROW_NOT_FOUND),
2429 mnUBound(ROW_NOT_FOUND)
2433 ScRefCellValue ScTable::VisibleDataCellIterator::reset(SCROW nRow)
2435 if (nRow > mrDocument.MaxRow())
2437 mnCurRow = ROW_NOT_FOUND;
2438 return ScRefCellValue();
2441 ScFlatBoolRowSegments::RangeData aData;
2442 if (!mrRowSegs.getRangeData(nRow, aData))
2444 mnCurRow = ROW_NOT_FOUND;
2445 return ScRefCellValue();
2448 if (!aData.mbValue)
2450 // specified row is visible. Take it.
2451 mnCurRow = nRow;
2452 mnUBound = aData.mnRow2;
2454 else
2456 // specified row is not-visible. The first visible row is the start of
2457 // the next segment.
2458 mnCurRow = aData.mnRow2 + 1;
2459 mnUBound = mnCurRow; // get range data on the next iteration.
2460 if (mnCurRow > mrDocument.MaxRow())
2462 // Make sure the row doesn't exceed our current limit.
2463 mnCurRow = ROW_NOT_FOUND;
2464 return ScRefCellValue();
2468 maCell = mrColumn.GetCellValue(mnCurRow);
2469 if (!maCell.isEmpty())
2470 // First visible cell found.
2471 return maCell;
2473 // Find a first visible cell below this row (if any).
2474 return next();
2477 ScRefCellValue ScTable::VisibleDataCellIterator::next()
2479 if (mnCurRow == ROW_NOT_FOUND)
2480 return ScRefCellValue();
2482 while (mrColumn.GetNextDataPos(mnCurRow))
2484 if (mnCurRow > mnUBound)
2486 // We don't know the visibility of this row range. Query it.
2487 ScFlatBoolRowSegments::RangeData aData;
2488 if (!mrRowSegs.getRangeData(mnCurRow, aData))
2490 mnCurRow = ROW_NOT_FOUND;
2491 return ScRefCellValue();
2494 if (aData.mbValue)
2496 // This row is invisible. Skip to the last invisible row and
2497 // try again.
2498 mnCurRow = mnUBound = aData.mnRow2;
2499 continue;
2502 // This row is visible.
2503 mnUBound = aData.mnRow2;
2506 maCell = mrColumn.GetCellValue(mnCurRow);
2507 if (!maCell.isEmpty())
2508 return maCell;
2511 mnCurRow = ROW_NOT_FOUND;
2512 return ScRefCellValue();
2515 void ScTable::SetAnonymousDBData(std::unique_ptr<ScDBData> pDBData)
2517 pDBDataNoName = std::move(pDBData);
2520 sal_uInt32 ScTable::AddCondFormat( std::unique_ptr<ScConditionalFormat> pNew )
2522 if(!mpCondFormatList)
2523 mpCondFormatList.reset(new ScConditionalFormatList());
2525 sal_uInt32 nMax = mpCondFormatList->getMaxKey();
2527 pNew->SetKey(nMax+1);
2528 mpCondFormatList->InsertNew(std::move(pNew));
2530 return nMax + 1;
2533 SvtScriptType ScTable::GetScriptType( SCCOL nCol, SCROW nRow ) const
2535 if ( !IsColValid( nCol ) )
2536 return SvtScriptType::NONE;
2538 return aCol[nCol].GetScriptType(nRow);
2541 void ScTable::SetScriptType( SCCOL nCol, SCROW nRow, SvtScriptType nType )
2543 if (!ValidCol(nCol))
2544 return;
2546 aCol[nCol].SetScriptType(nRow, nType);
2549 SvtScriptType ScTable::GetRangeScriptType(
2550 sc::ColumnBlockPosition& rBlockPos, SCCOL nCol, SCROW nRow1, SCROW nRow2 )
2552 if ( !IsColValid( nCol ) )
2553 return SvtScriptType::NONE;
2555 sc::CellStoreType::iterator itr = aCol[nCol].maCells.begin();
2556 return aCol[nCol].GetRangeScriptType(rBlockPos.miCellTextAttrPos, nRow1, nRow2, itr);
2559 formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol, SCROW nRow )
2561 if ( !ValidCol( nCol ) || !ValidRow( nRow ) )
2562 return formula::FormulaTokenRef();
2563 if ( nCol >= aCol.size() )
2564 // Return a value of 0.0 if column not exists
2565 return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
2566 return aCol[nCol].ResolveStaticReference(nRow);
2569 formula::FormulaTokenRef ScTable::ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2571 if (nCol2 < nCol1 || nRow2 < nRow1)
2572 return formula::FormulaTokenRef();
2574 if ( !ValidCol( nCol1 ) || !ValidCol( nCol2 ) || !ValidRow( nRow1 ) || !ValidRow( nRow2 ) )
2575 return formula::FormulaTokenRef();
2577 SCCOL nMaxCol;
2578 if ( nCol2 >= aCol.size() )
2579 nMaxCol = aCol.size() - 1;
2580 else
2581 nMaxCol = nCol2;
2583 ScMatrixRef pMat(new ScMatrix(nCol2-nCol1+1, nRow2-nRow1+1, 0.0));
2584 for (SCCOL nCol = nCol1; nCol <= nMaxCol; ++nCol)
2586 if (!aCol[nCol].ResolveStaticReference(*pMat, nCol2-nCol1, nRow1, nRow2))
2587 // Column contains non-static cell. Failed.
2588 return formula::FormulaTokenRef();
2591 return formula::FormulaTokenRef(new ScMatrixToken(std::move(pMat)));
2594 formula::VectorRefArray ScTable::FetchVectorRefArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
2596 if (nRow2 < nRow1)
2597 return formula::VectorRefArray();
2599 if ( !IsColValid( nCol ) || !ValidRow( nRow1 ) || !ValidRow( nRow2 ) )
2600 return formula::VectorRefArray();
2602 return aCol[nCol].FetchVectorRefArray(nRow1, nRow2);
2605 #ifdef DBG_UTIL
2606 void ScTable::AssertNoInterpretNeeded( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
2608 assert( nRow2 >= nRow1 );
2609 assert( IsColValid( nCol ) && ValidRow( nRow1 ) && ValidRow( nRow2 ) );
2610 return aCol[nCol].AssertNoInterpretNeeded(nRow1, nRow2);
2612 #endif
2614 bool ScTable::HandleRefArrayForParallelism( SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef& mxGroup, ScAddress* pDirtiedAddress )
2616 if (nRow2 < nRow1)
2617 return false;
2619 if ( !IsColValid( nCol ) || !ValidRow( nRow1 ) || !ValidRow( nRow2 ) )
2620 return false;
2622 mpHiddenCols->makeReady();
2623 mpHiddenRows->makeReady();
2624 mpFilteredCols->makeReady();
2625 mpFilteredRows->makeReady();
2627 return aCol[nCol].HandleRefArrayForParallelism(nRow1, nRow2, mxGroup, pDirtiedAddress);
2630 ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow )
2632 if ( !IsColRowValid( nCol, nRow ) )
2633 return ScRefCellValue();
2635 return aCol[nCol].GetCellValue(nRow);
2638 ScRefCellValue ScTable::GetRefCellValue( SCCOL nCol, SCROW nRow, sc::ColumnBlockPosition& rBlockPos )
2640 if ( !IsColRowValid( nCol, nRow ) )
2641 return ScRefCellValue();
2643 return aCol[nCol].GetCellValue(rBlockPos, nRow);
2646 SvtBroadcaster* ScTable::GetBroadcaster( SCCOL nCol, SCROW nRow )
2648 if ( !IsColRowValid( nCol, nRow ) )
2649 return nullptr;
2651 return aCol[nCol].GetBroadcaster(nRow);
2654 void ScTable::DeleteBroadcasters(
2655 sc::ColumnBlockPosition& rBlockPos, SCCOL nCol, SCROW nRow1, SCROW nRow2 )
2657 if ( !IsColValid( nCol ) )
2658 return;
2660 aCol[nCol].DeleteBroadcasters(rBlockPos, nRow1, nRow2);
2663 void ScTable::DeleteEmptyBroadcasters()
2665 for( auto& col : aCol )
2666 col->DeleteEmptyBroadcasters();
2669 void ScTable::FillMatrix( ScMatrix& rMat, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, svl::SharedStringPool* pPool ) const
2671 size_t nMatCol = 0;
2672 nCol2 = ClampToAllocatedColumns(nCol2);
2673 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nMatCol)
2674 aCol[nCol].FillMatrix(rMat, nMatCol, nRow1, nRow2, pPool);
2677 void ScTable::InterpretDirtyCells( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2679 nCol2 = ClampToAllocatedColumns(nCol2);
2680 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
2681 aCol[nCol].InterpretDirtyCells(nRow1, nRow2);
2684 bool ScTable::InterpretCellsIfNeeded( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2686 nCol2 = ClampToAllocatedColumns(nCol2);
2687 bool allInterpreted = true;
2688 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
2689 if(!aCol[nCol].InterpretCellsIfNeeded(nRow1, nRow2))
2690 allInterpreted = false;
2691 return allInterpreted;
2694 void ScTable::SetFormulaResults( SCCOL nCol, SCROW nRow, const double* pResults, size_t nLen )
2696 if (!ValidCol(nCol))
2697 return;
2699 aCol[nCol].SetFormulaResults(nRow, pResults, nLen);
2702 void ScTable::CalculateInColumnInThread( ScInterpreterContext& rContext,
2703 SCCOL nColStart, SCCOL nColEnd,
2704 SCROW nRowStart, SCROW nRowEnd,
2705 unsigned nThisThread, unsigned nThreadsTotal)
2707 if (!ValidCol(nColStart) || !ValidCol(nColEnd))
2708 return;
2710 size_t nLen = nRowEnd - nRowStart + 1;
2711 size_t nOffset = 0;
2712 for (SCCOL nCurrCol = nColStart; nCurrCol <= nColEnd; ++nCurrCol)
2714 aCol[nCurrCol].CalculateInThread( rContext, nRowStart, nLen, nOffset, nThisThread, nThreadsTotal );
2715 nOffset += nLen;
2719 void ScTable::HandleStuffAfterParallelCalculation( SCCOL nColStart, SCCOL nColEnd, SCROW nRow, size_t nLen,
2720 ScInterpreter* pInterpreter)
2722 assert(ValidCol(nColStart) && ValidCol(nColEnd));
2724 for (SCCOL nCurrCol = nColStart; nCurrCol <= nColEnd; ++nCurrCol)
2725 aCol[nCurrCol].HandleStuffAfterParallelCalculation( nRow, nLen, pInterpreter );
2728 #if DUMP_COLUMN_STORAGE
2729 void ScTable::DumpColumnStorage( SCCOL nCol ) const
2731 if ( !IsColValid( nCol ) )
2732 return;
2734 aCol[nCol].DumpColumnStorage();
2736 #endif
2738 const SvtBroadcaster* ScTable::GetBroadcaster( SCCOL nCol, SCROW nRow ) const
2740 if ( !IsColRowValid( nCol, nRow ) )
2741 return nullptr;
2743 return aCol[nCol].GetBroadcaster(nRow);
2746 void ScTable::DeleteConditionalFormat( sal_uLong nIndex )
2748 mpCondFormatList->erase(nIndex);
2751 void ScTable::SetCondFormList( ScConditionalFormatList* pNew )
2753 mpCondFormatList.reset( pNew );
2756 ScConditionalFormatList* ScTable::GetCondFormList()
2758 if(!mpCondFormatList)
2759 mpCondFormatList.reset( new ScConditionalFormatList() );
2761 return mpCondFormatList.get();
2764 const ScConditionalFormatList* ScTable::GetCondFormList() const
2766 return mpCondFormatList.get();
2769 ScColumnsRange ScTable::GetWritableColumnsRange(SCCOL nColBegin, SCCOL nColEnd)
2771 // because the range is inclusive, some code will pass nColEnd<nColBegin to indicate an empty range
2772 if (nColEnd < nColBegin)
2773 return ScColumnsRange(-1, -1);
2774 assert( nColEnd >= 0 && nColEnd <= GetDoc().MaxCol());
2775 CreateColumnIfNotExists(nColEnd);
2776 return GetColumnsRange(nColBegin, nColEnd);
2779 ScColumnsRange ScTable::GetAllocatedColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const
2781 if (nColBegin >= aCol.size())
2782 return ScColumnsRange(-1, -1);
2783 // clamp end of range to available columns
2784 if (nColEnd >= aCol.size())
2785 nColEnd = aCol.size() - 1;
2786 return GetColumnsRange(nColBegin, nColEnd);
2789 ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const
2791 // because the range is inclusive, some code will pass nColEnd<nColBegin to indicate an empty range
2792 if (nColEnd < nColBegin)
2793 return ScColumnsRange(-1, -1);
2794 assert( nColBegin >= 0 && nColBegin <= GetDoc().MaxCol());
2795 assert( nColEnd >= 0 && nColEnd <= GetDoc().MaxCol());
2796 return ScColumnsRange(nColBegin, nColEnd + 1); // change inclusive end to past-end
2799 // out-of-line the cold part of the CreateColumnIfNotExists function
2800 void ScTable::CreateColumnIfNotExistsImpl( const SCCOL nScCol )
2802 // When doing multi-threaded load of, e.g. XLS files, we can hit this, which calls
2803 // into SfxItemPool::Put, in parallel with other code that calls into SfxItemPool::Put,
2804 // which is bad since that code is not thread-safe.
2805 SolarMutexGuard aGuard;
2806 const SCCOL aOldColSize = aCol.size();
2807 aCol.resize( rDocument.GetSheetLimits(), static_cast< size_t >( nScCol + 1 ) );
2808 for (SCCOL i = aOldColSize; i <= nScCol; i++)
2809 aCol[i].Init( i, nTab, rDocument, false );
2811 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */