1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
31 #include <document.hxx>
33 #include <drwlayer.hxx>
34 #include <olinetab.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>
44 #include <tabprotection.hxx>
45 #include <sheetevents.hxx>
46 #include <segmenttree.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>
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.
80 return pOuterProgress
;
83 return new ScProgress(
84 pDoc
->GetDocumentShell(), ScResId(STR_PROGRESS_HEIGHTING
), nTotalCount
, true);
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;
109 auto aRangeData
= rHeights
.GetRangeData(nPos
-1);
110 if (aRangeData
.maValue
< nMinHeight
)
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
);
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
140 explicit SetRowHeightOnlyFunc(ScTable
* pTab
) :
144 virtual bool operator() (SCROW nStartRow
, SCROW nEndRow
, sal_uInt16 nHeight
, bool /* bApi */) override
146 mpTab
->SetRowHeightOnly(nStartRow
, nEndRow
, nHeight
);
151 struct SetRowHeightRangeFunc
: public OptimalHeightsFuncObjBase
156 SetRowHeightRangeFunc(ScTable
* pTab
, double 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
,
173 bool bChanged
= false;
176 sal_uInt16 nLast
= 0;
177 sal_uInt16 nExtraHeight
= rCxt
.getExtraHeight();
178 for (SCSIZE i
= nStartRow
; i
<= o3tl::make_unsigned(nEndRow
); i
++)
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())
193 pRowFlags
->SetValue( i
, nRegionEndRow
, nRowFlag
| CRFlags::ManualSize
);
196 pRowFlags
->SetValue( i
, nRegionEndRow
, nRowFlag
& ~CRFlags::ManualSize
);
198 for (SCSIZE nInner
= i
; nInner
<= i
+ nMoreRows
; ++nInner
)
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
;
212 bChanged
|= rFuncObj(nRngStart
, nRngEnd
, nLast
, bApi
);
218 nLast
= rCxt
.getHeightArray().GetValue(nInner
) + rCxt
.getExtraHeight();
227 bChanged
|= rFuncObj(nRngStart
, nRngEnd
, nLast
, bApi
);
230 i
+= nMoreRows
; // already handled - skip
233 bChanged
|= rFuncObj(nRngStart
, nRngEnd
, nLast
, bApi
);
240 ScTable::ScTable( ScDocument
& rDoc
, SCTAB nNewTab
, const OUString
& rNewName
,
241 bool bColInfo
, bool bRowInfo
) :
242 aCol( rDoc
.GetSheetLimits(), INITIALCOLCOUNT
),
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())),
260 nTableAreaVisibleX( 0 ),
261 nTableAreaVisibleY( 0 ),
264 pSortCollator( nullptr ),
266 aScenarioColor( COL_LIGHTGRAY
),
267 aTabBgColor( COL_AUTO
),
268 nScenarioFlags(ScScenarioFlags::NONE
),
269 mpCondFormatList( new ScConditionalFormatList() ),
270 maLOKFreezeCell(-1, -1, nNewTab
),
274 bPageSizeValid(false),
275 bTableAreaValid(false),
276 bTableAreaVisibleValid(false),
278 bPendingRowHeights(false),
279 bCalcNotification(false),
280 bGlobalKeepQuery(false),
281 bPrintEntireSheet(true),
282 bActiveScenario(false),
283 mbPageBreaksValid(false),
284 mbForceBreaks(false),
285 mbTotalsRowBelow(true),
288 aDefaultColData
.InitAttrArray(new ScAttrArray(static_cast<SCCOL
>(-1), nNewTab
, rDoc
, nullptr));
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
) );
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();
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();
339 pDrawLayer
->ScRemovePage( nTab
);
343 pSheetEvents
.reset();
344 pOutlineTable
.reset();
346 moRepeatColRange
.reset();
347 moRepeatRowRange
.reset();
348 pScenarioRanges
.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
)
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
);
374 void ScTable::SetVisible( bool bVis
)
376 if (bVisible
!= bVis
)
377 SetStreamValid(false);
382 void ScTable::SetStreamValid( bool bSet
, bool bIgnoreLock
)
384 if (!bStreamValid
&& !bSet
)
386 if ( bIgnoreLock
|| !rDocument
.IsStreamValidLocked() )
390 void ScTable::SetPendingRowHeights( bool bSet
)
392 bPendingRowHeights
= bSet
;
395 void ScTable::SetLayoutRTL( bool bSet
)
400 void ScTable::SetLoadingRTL( bool 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
)
420 void ScTable::SetLink( ScLinkMode nMode
,
421 const OUString
& rDoc
, const OUString
& rFlt
, const OUString
& rOpt
,
422 const OUString
& rTab
, sal_Int32 nRefreshDelay
)
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
,
449 double nPPTX
, double nPPTY
,
450 const Fraction
& rZoomX
, const Fraction
& rZoomY
,
451 bool bWidth
, bool bTotalSize
, bool bInPrintTwips
)
453 if ( nCol
>= aCol
.size() )
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() )
478 if (!rCxt
.isForceAutoSize())
480 // Optimize - exit early if all rows have defined height: super expensive GetOptimalHeight
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;
496 if (bAllRowsAreManualHeight
)
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
)
515 mpRowHeights
->enableTreeSearch(true);
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
);
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() )
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
)
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
573 for (SCCOL i
=0; i
<aCol
.size(); i
++)
575 if (!aCol
[i
].IsEmptyData())
579 SCROW nRow
= aCol
[i
].GetLastDataPos();
583 if ( aCol
[i
].HasCellNotes() )
585 SCROW maxNoteRow
= aCol
[i
].GetCellNotesMaxRow();
586 if (maxNoteRow
>= nMaxY
)
597 if (aCol
[i
].HasSparklines())
599 SCROW maxSparklineRow
= aCol
[i
].GetSparklinesMaxRow();
600 if (maxSparklineRow
>= nMaxY
)
603 nMaxY
= maxSparklineRow
;
618 bool ScTable::GetTableArea( SCCOL
& rEndCol
, SCROW
& rEndRow
, bool bCalcHiddens
) const
620 bool bRet
= true; //TODO: remember?
623 if (!bTableAreaValid
)
625 bRet
= GetPrintArea(nTableAreaX
, nTableAreaY
, true, bCalcHiddens
);
626 bTableAreaValid
= true;
628 rEndCol
= nTableAreaX
;
629 rEndRow
= nTableAreaY
;
633 if (!bTableAreaVisibleValid
)
635 bRet
= GetPrintArea(nTableAreaVisibleX
, nTableAreaVisibleY
, true, bCalcHiddens
);
636 bTableAreaVisibleValid
= true;
638 rEndCol
= nTableAreaVisibleX
;
639 rEndRow
= nTableAreaVisibleY
;
644 const SCCOL SC_COLUMNS_STOP
= 30;
646 bool ScTable::GetPrintArea( SCCOL
& rEndCol
, SCROW
& rEndRow
, bool bNotes
, bool bCalcHiddens
) const
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())
664 SCROW nColY
= aCol
[i
].GetLastDataPos();
668 if (bNotes
&& aCol
[i
].HasCellNotes() )
670 SCROW maxNoteRow
= aCol
[i
].GetCellNotesMaxRow();
671 if (maxNoteRow
>= nMaxY
)
682 if (aCol
[i
].HasSparklines())
684 SCROW maxSparklineRow
= aCol
[i
].GetSparklinesMaxRow();
685 if (maxSparklineRow
>= nMaxY
)
688 nMaxY
= maxSparklineRow
;
699 SCCOL nMaxDataX
= nMaxX
;
701 for (i
=0; i
<aCol
.size(); i
++) // Test attribute
703 if (bCalcHiddens
|| !rDocument
.ColHidden(i
, nTab
))
706 if (aCol
[i
].GetLastVisibleAttr( nLastRow
, bSkipEmpty
))
710 if (nLastRow
> nMaxY
)
716 if (nMaxX
== rDocument
.MaxCol()) // omit attribute at the right
719 while ( nMaxX
>0 && aCol
[nMaxX
].IsVisibleAttrEqual(aCol
[nMaxX
+1], 0, rDocument
.MaxRow()) )
723 if ( 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()) )
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
742 while ( nMaxX
> nMaxDataX
&& !aCol
[nMaxX
].GetLastVisibleAttr( nDummyRow
, bSkipEmpty
) )
746 nAttrStartX
= nAttrEndX
+ 1;
755 bool ScTable::GetPrintAreaHor( SCROW nStartRow
, SCROW nEndRow
,
756 SCCOL
& rEndCol
) const
762 for (i
=0; i
<aCol
.size(); i
++) // Test attribute
764 if (aCol
[i
].HasVisibleAttrIn( nStartRow
, nEndRow
))
771 if (nMaxX
== rDocument
.MaxCol()) // omit attribute at the right
774 while ( nMaxX
>0 && aCol
[nMaxX
].IsVisibleAttrEqual(aCol
[nMaxX
+1], nStartRow
, nEndRow
) )
778 for (i
=0; i
<aCol
.size(); i
++) // test the data
780 if (!aCol
[i
].IsEmptyData( nStartRow
, nEndRow
)) //TODO: bNotes ??????
786 else if (aCol
[i
].HasSparklines())
800 bool ScTable::GetPrintAreaVer( SCCOL nStartCol
, SCCOL nEndCol
,
801 SCROW
& rEndRow
, bool bNotes
) const
807 bool bSkipEmpty
= ScModule::get()->GetPrintOptions().GetSkipEmpty();
809 for (i
=nStartCol
; i
<=nEndCol
&& i
< aCol
.size(); i
++) // Test attribute
812 if (aCol
[i
].GetLastVisibleAttr( nLastRow
, bSkipEmpty
))
815 if (nLastRow
> nMaxY
)
820 for (i
=nStartCol
; i
<=nEndCol
&& i
< aCol
.size(); i
++) // Test data
822 if (!aCol
[i
].IsEmptyData())
825 SCROW nColY
= aCol
[i
].GetLastDataPos();
829 if (bNotes
&& aCol
[i
].HasCellNotes() )
831 SCROW maxNoteRow
=aCol
[i
].GetCellNotesMaxRow();
832 if (maxNoteRow
> nMaxY
)
838 if (aCol
[i
].HasSparklines())
840 SCROW maxNoteRow
= aCol
[i
].GetSparklinesMaxRow();
841 if (maxNoteRow
> nMaxY
)
853 bool ScTable::GetDataStart( SCCOL
& rStartCol
, SCROW
& rStartRow
) const
856 SCCOL nMinX
= aCol
.size()-1;
857 SCROW nMinY
= rDocument
.MaxRow();
860 for (i
=0; i
<aCol
.size(); i
++) // Test attribute
863 if (aCol
[i
].GetFirstVisibleAttr( nFirstRow
))
868 if (nFirstRow
< nMinY
)
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
878 while ( nMinX
<(aCol
.size()-1) && aCol
[nMinX
].IsVisibleAttrEqual(aCol
[nMinX
-1], 0, rDocument
.MaxRow()))
883 bool bDatFound
= false;
884 for (i
=0; i
<aCol
.size(); i
++) // Test data
886 if (!aCol
[i
].IsEmptyData())
888 if (!bDatFound
&& i
<nMinX
)
890 bFound
= bDatFound
= true;
891 SCROW nRow
= aCol
[i
].GetFirstDataPos();
895 if ( aCol
[i
].HasCellNotes() )
897 SCROW minNoteRow
= aCol
[i
].GetCellNotesMinRow();
898 if (minNoteRow
<= nMinY
)
909 if (aCol
[i
].HasSparklines())
911 SCROW minSparkline
= aCol
[i
].GetSparklinesMinRow();
912 if (minSparkline
<= nMinY
)
915 nMinY
= minSparkline
;
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 );
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
] );
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 );
970 blockPos
.resize( blockPos
.size() + 1 );
971 aCol
[ rEndCol
].InitBlockPosition( blockPos
[ rEndCol
] );
977 if (!aCol
[rStartCol
-1].IsEmptyData(nStart
,nEnd
))
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
))
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
))
1017 if ( !bIncludeOld
&& !bOnlyDown
)
1020 while ( rStartCol
< rEndCol
&& rStartCol
< (aCol
.size()-1) && aCol
[rStartCol
].IsEmptyData(rStartRow
,rEndRow
) )
1024 while ( rEndCol
> 0 && rStartCol
< rEndCol
&& aCol
[rEndCol
].IsEmptyData(rStartRow
,rEndRow
) )
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
))
1037 } while (bShrink
&& rStartRow
< rDocument
.MaxRow() && rStartRow
< rEndRow
);
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() )
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
);
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 )
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());
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.
1102 PutInOrder( rStartCol
, rEndCol
);
1103 PutInOrder( rStartRow
, rEndRow
);
1114 if (rEndCol
>= aCol
.size())
1116 rEndCol
= aCol
.size()-1;
1119 if (rEndRow
> rDocument
.MaxRow())
1121 rEndRow
= rDocument
.MaxRow();
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
;
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
;
1178 while (rStartRow
< rEndRow
)
1180 SCROW nLastDataRow
= GetLastDataRow(rStartCol
, rEndCol
, rEndRow
, pDataAreaExtras
);
1181 if (0 <= nLastDataRow
&& nLastDataRow
< rEndRow
)
1183 rEndRow
= std::max( rStartRow
, nLastDataRow
);
1192 while (rStartRow
< rEndRow
)
1194 bool bFound
= false;
1195 for (SCCOL i
=rStartCol
; i
<=rEndCol
&& !bFound
; i
++)
1197 if (aCol
[i
].HasDataAt(rStartRow
, pDataAreaExtras
))
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
) )
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
;
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
))
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
);
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
)
1270 while ((nCol
>= nStartCol
) &&
1271 aCol
[nCol
].IsEmptyData(nStartRow
, nEndRow
))
1276 nCount
+= nGapRight
;
1281 while ((nCol
<= nEndCol
) && aCol
[nCol
].IsEmptyData(nStartRow
, nEndRow
))
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
;
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() )
1301 nEndCol
= std::min
<SCCOL
>( nEndCol
, aCol
.size()-1 );
1303 for (SCCOL i
=nStartCol
; i
<=nEndCol
; i
++)
1304 if (aCol
[i
].HasDataAt(nRow
))
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
) )
1317 while ( rStartCol
<rEndCol
&& aCol
[rEndCol
].IsEmptyData(rStartRow
,rEndRow
) )
1320 while ( rStartRow
<rEndRow
&& IsEmptyLine(rStartRow
, rStartCol
, rEndCol
) )
1323 // Optimised loop for finding the bottom of the area, can be costly in large
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
1340 bool bHidden
= rDocument
.ColHidden(nCol
, nTab
, nullptr, &nEnd
);
1344 return std::min
<SCCOL
>(rDocument
.MaxCol(), nCol
);
1349 SCCOL nStart
= rDocument
.MaxCol();
1350 bool bHidden
= rDocument
.ColHidden(nCol
, nTab
, &nStart
);
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;
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();
1372 bool bHidden
= rDocument
.ColHidden( nCol
, nTab
, nullptr, &nEndCol
);
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().
1379 return rDocument
.MaxCol();
1382 if(aCol
[nCol
].HasVisibleDataAt(nRow
))
1385 while(nCol
< nLastCol
); // Stop search as soon as the last allocated column is searched.
1387 return rDocument
.MaxCol();
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;
1403 SCCOL nStartCol
= rDocument
.MaxCol();
1404 bool bHidden
= rDocument
.ColHidden( nCol
, nTab
, &nStartCol
);
1407 nCol
= nStartCol
-1;
1412 if(aCol
[nCol
].HasVisibleDataAt(nRow
))
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
);
1432 if(nNewCol
>= rDocument
.MaxCol() && eDirection
== SC_MOVE_RIGHT
)
1434 else if(nNewCol
== 0 && eDirection
== SC_MOVE_LEFT
)
1437 SCCOL nNextCol
= FindNextVisibleCol( nNewCol
, bRight
);
1439 if( nNextCol
<= nLastCol
&& aCol
[nNextCol
].HasVisibleDataAt(rRow
) )
1441 bool bFound
= false;
1445 nNextCol
= FindNextVisibleCol( nNewCol
, bRight
);
1446 if( nNextCol
<= nLastCol
&& aCol
[nNextCol
].HasVisibleDataAt(rRow
) )
1451 while(!bFound
&& nNextCol
> 0 && nNextCol
< rDocument
.MaxCol());
1455 nNewCol
= FindNextVisibleColWithContent(nNewCol
, bRight
, rRow
);
1460 nNewCol
= FindNextVisibleColWithContent(nNewCol
, bRight
, rRow
);
1465 if (nNewCol
>rDocument
.MaxCol())
1466 nNewCol
=rDocument
.MaxCol();
1471 if ( rCol
<= nLastCol
)
1472 aCol
[rCol
].FindDataAreaPos(rRow
,eDirection
== SC_MOVE_DOWN
);
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
))
1489 if (rDocument
.HasAttrib(nCol
, nRow
, nTab
, nCol
, nRow
, nTab
, HasAttrFlags::Overlapped
))
1490 // Skip an overlapped cell.
1493 if (bMarked
&& !rMark
.IsCellMarked(nCol
,nRow
))
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
))
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
))
1511 if (ColHidden(nCol
))
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
))
1526 if (bSheetProtected
&& rDocument
.HasAttrib( nCol
, rRow
, nTab
, nCol
, rRow
, nTab
, HasAttrFlags::Protected
))
1528 if ( rRow
> nUsedY
)
1529 rRow
= (bUp
? nUsedY
: rDocument
.MaxRow() + nMovY
);
1534 rRow
= rMark
.GetNextMarked( nCol
, rRow
, bUp
);
1540 bool bRowHidden
= RowHidden( rRow
);
1541 bool bOverlapped
= rDocument
.HasAttrib( nCol
, rRow
, nTab
, nCol
, rRow
, nTab
, HasAttrFlags::Overlapped
);
1543 if ( bRowHidden
|| bOverlapped
)
1547 rRow
= rMark
.GetNextMarked( nCol
, rRow
, bUp
);
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
;
1574 ScRange
aRange( ScAddress::UNINITIALIZED
);
1575 if (rMark
.IsMarked())
1576 aRange
= rMark
.GetMarkArea();
1577 else if (rMark
.IsMultiMarked())
1578 aRange
= rMark
.GetMultiMarkArea();
1581 // Covered by assert() above, but for NDEBUG build.
1582 if (ValidColRow(nCol
,nRow
))
1589 nStartCol
= aRange
.aStart
.Col();
1590 nStartRow
= aRange
.aStart
.Row();
1591 nEndCol
= aRange
.aEnd
.Col();
1592 nEndRow
= aRange
.aEnd
.Row();
1594 else if (bUnprotected
)
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());
1610 // Invalid values show up for instance for Tab, when nothing is
1611 // selected and not protected (left / right edge), then leave values
1613 if (ValidColRow(nCol
,nRow
))
1619 // Caller ensures actually moving nMovY to jump to prev/next row's
1621 if (nTabStartCol
!= SC_TABSTART_NONE
)
1622 rCol
= nTabStartCol
;
1627 if ( nMovY
&& (bMarked
|| bUnprotected
))
1631 const bool bUp
= (nMovY
< 0);
1632 const SCCOL nColAdd
= (bUp
? -1 : 1);
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.
1653 nCol
= nTabStartCol
;
1657 while ( SkipRow( nCol
, nRow
, nMovY
, rMark
, bUp
, nEndRow
, bMarked
, bSheetProtected
))
1660 sal_uInt16 nWrap
= 0;
1661 while ( nRow
< nStartRow
|| nRow
> nEndRow
)
1665 while (nStartCol
<= nCol
&& nCol
<= nEndCol
&& ValidCol(nCol
) && ColHidden(nCol
))
1666 nCol
+= nColAdd
; // skip hidden cols
1668 if (nCol
< nStartCol
)
1675 else if (nCol
> nEndCol
)
1682 if (nRow
< nStartRow
)
1684 else if (nRow
> nEndRow
)
1688 nRow
= rMark
.GetNextMarked( nCol
, nRow
, bUp
);
1690 while ( SkipRow( nCol
, nRow
, nMovY
, rMark
, bUp
, nEndRow
, bMarked
, bSheetProtected
))
1696 if ( nMovX
&& ( bMarked
|| bUnprotected
) )
1698 // wrap initial skip counting:
1699 if (nCol
< nStartCol
)
1703 if (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;
1725 for (SCCOL i
= 0; i
< nColCount
; ++i
)
1726 pNextRows
[i
] = (i
+ nStartCol
> nCol
) ? (nRow
+ nRowAdd
) : nRow
;
1730 for (SCCOL i
= 0; i
< nColCount
; ++i
)
1731 pNextRows
[i
] = (i
+ nStartCol
< nCol
) ? (nRow
+ nRowAdd
) : nRow
;
1735 SCROW nNextRow
= pNextRows
[nCol
- nStartCol
] + nRowAdd
;
1737 nNextRow
= rMark
.GetNextMarked( nCol
, nNextRow
, bUp
);
1739 nNextRow
= ( nCol
<= nLastCol
) ? aCol
[nCol
].GetNextUnprotected( nNextRow
, bUp
) :
1740 aDefaultColData
.GetNextUnprotected( nNextRow
, bUp
);
1741 pNextRows
[nCol
- nStartCol
] = nNextRow
;
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
;
1756 if ( nRow
< nStartRow
)
1762 for (SCCOL i
= 0; i
< nColCount
; ++i
)
1763 pNextRows
[i
] = nEndRow
; // do it all over again
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
;
1779 if ( nRow
> nEndRow
)
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
))
1801 bool ScTable::GetNextMarkedCell( SCCOL
& rCol
, SCROW
& rRow
, const ScMarkData
& rMark
) const
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
;
1824 if (it
== rCells
.end())
1826 // No more block. Move on to the next column.
1827 rRow
= rDocument
.MaxRow() + 1;
1832 if (nTestRow
<= nEnd
)
1839 rRow
= nEnd
+ 1; // Search for next selected range
1842 rRow
= rDocument
.MaxRow() + 1; // End of column
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
1860 ScDrawLayer
* pDrawLayer
= rDocument
.GetDrawLayer();
1861 if ( eUpdateRefMode
!= URM_COPY
&& pDrawLayer
)
1863 if ( eUpdateRefMode
== URM_MOVE
)
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.
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
);
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
1902 aDefaultColData
.DeleteRow(nRow1
+nDy
, -nDy
);
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
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
,
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
,
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
,
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
) );
1986 SetStreamValid(false);
1988 if(mpCondFormatList
)
1989 mpCondFormatList
->UpdateReference(rCxt
);
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
2014 mpRangeName
->UpdateInsertTab(rCxt
, nTab
);
2016 if (nTab
>= rCxt
.mnInsertPos
)
2018 nTab
+= rCxt
.mnSheets
;
2020 pDBDataNoName
->UpdateMoveTab(nTab
- 1 ,nTab
);
2023 if (mpCondFormatList
)
2024 mpCondFormatList
->UpdateInsertTab(rCxt
);
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
2043 mpRangeName
->UpdateDeleteTab(rCxt
, nTab
);
2045 if (nTab
> rCxt
.mnDeletePos
)
2047 nTab
-= rCxt
.mnSheets
;
2049 pDBDataNoName
->UpdateMoveTab(nTab
+ 1,nTab
);
2052 if (mpCondFormatList
)
2053 mpCondFormatList
->UpdateDeleteTab(rCxt
);
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
)
2071 mpRangeName
->UpdateMoveTab(rCxt
, nTab
);
2074 pDBDataNoName
->UpdateMoveTab(rCxt
.mnOldPos
, rCxt
.mnNewPos
);
2076 if(mpCondFormatList
)
2077 mpCondFormatList
->UpdateMoveTab(rCxt
);
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
);
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
)
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");
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
)
2136 if (ColHidden(i
, nullptr, &nLastCol
))
2138 // Columns are hidden in this range.
2139 aSkipCols
.setTrue(i
, nLastCol
);
2143 // These columns are visible. Check for empty columns.
2144 SCCOL nEmptyCount
= 0;
2146 for (; j
<= nLastCol
; ++j
)
2148 if ( j
>= aCol
.size() )
2150 if (aCol
[j
].IsCellCountZero()) // empty
2154 aSkipCols
.setTrue(i
,i
+nEmptyCount
);
2155 if ( j
>= aCol
.size() )
2156 aSkipCols
.setTrue( j
, rDocument
.MaxCol() );
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!
2168 if (aColData
.mbValue
)
2170 // Skip these columns.
2171 nCol
= aColData
.mnCol1
; // move toward 0.
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.
2185 while (!aCell
.isEmpty())
2187 SCCOL nNewCol
= nDataCol
;
2188 SCROW nRow
= aIter
.getRow();
2190 // Went past the last row position. Bail out.
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
2221 ScColumn
& rColumn
= aCol
[rCol
];
2222 ScRefCellValue aCell
= rColumn
.GetCellValue(nRow
);
2223 if (!aCell
.hasString())
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
;
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
2260 // STANDARD is LEFT (only text is handled here)
2261 bool bRight
= ( eHorJust
== SvxCellHorJustify::Right
);
2262 if ( IsLayoutRTL() )
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();
2281 // Cell content in a next column ends display of this string.
2285 nMissing
-= GetColWidth(++nNewCol
);
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
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() )
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
) :
2426 mrRowSegs(rRowSegs
),
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();
2450 // specified row is visible. Take it.
2452 mnUBound
= aData
.mnRow2
;
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.
2473 // Find a first visible cell below this row (if any).
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();
2496 // This row is invisible. Skip to the last invisible row and
2498 mnCurRow
= mnUBound
= aData
.mnRow2
;
2502 // This row is visible.
2503 mnUBound
= aData
.mnRow2
;
2506 maCell
= mrColumn
.GetCellValue(mnCurRow
);
2507 if (!maCell
.isEmpty())
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
));
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
))
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();
2578 if ( nCol2
>= aCol
.size() )
2579 nMaxCol
= aCol
.size() - 1;
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
)
2597 return formula::VectorRefArray();
2599 if ( !IsColValid( nCol
) || !ValidRow( nRow1
) || !ValidRow( nRow2
) )
2600 return formula::VectorRefArray();
2602 return aCol
[nCol
].FetchVectorRefArray(nRow1
, nRow2
);
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
);
2614 bool ScTable::HandleRefArrayForParallelism( SCCOL nCol
, SCROW nRow1
, SCROW nRow2
, const ScFormulaCellGroupRef
& mxGroup
, ScAddress
* pDirtiedAddress
)
2619 if ( !IsColValid( nCol
) || !ValidRow( nRow1
) || !ValidRow( nRow2
) )
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
) )
2651 return aCol
[nCol
].GetBroadcaster(nRow
);
2654 void ScTable::DeleteBroadcasters(
2655 sc::ColumnBlockPosition
& rBlockPos
, SCCOL nCol
, SCROW nRow1
, SCROW nRow2
)
2657 if ( !IsColValid( nCol
) )
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
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
))
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
))
2710 size_t nLen
= nRowEnd
- nRowStart
+ 1;
2712 for (SCCOL nCurrCol
= nColStart
; nCurrCol
<= nColEnd
; ++nCurrCol
)
2714 aCol
[nCurrCol
].CalculateInThread( rContext
, nRowStart
, nLen
, nOffset
, nThisThread
, nThreadsTotal
);
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
) )
2734 aCol
[nCol
].DumpColumnStorage();
2738 const SvtBroadcaster
* ScTable::GetBroadcaster( SCCOL nCol
, SCROW nRow
) const
2740 if ( !IsColRowValid( nCol
, nRow
) )
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: */