sc/inc/document.hxx | 9 +++++ sc/inc/table.hxx | 18 ++++++---- sc/source/core/data/column2.cxx | 6 +-- sc/source/core/data/documen4.cxx | 2 - sc/source/core/data/document.cxx | 31 ++++++++++++++---- sc/source/core/data/table1.cxx | 63 +++++++++++++++++++++---------------- sc/source/core/data/table2.cxx | 2 - sc/source/core/data/table3.cxx | 4 +- sc/source/core/data/table4.cxx | 14 ++++---- sc/source/core/data/table7.cxx | 2 - sc/source/filter/dif/difimp.cxx | 2 - sc/source/filter/html/htmlexp2.cxx | 4 -- sc/source/ui/unoobj/docuno.cxx | 2 - sc/source/ui/view/tabview2.cxx | 12 +++++-- 14 files changed, 110 insertions(+), 61 deletions(-)
New commits: commit fe703f245d4419861f7840c945183b4bed41cd81 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Wed Apr 27 18:36:56 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue May 3 19:57:24 2022 +0200 fix horizontal Calc cursor skipping UITest_calc_tests' columns.CalcColumns.test_column_hide_show fails with INITIALCOLCOUNT being 1 because column C was hidden, but searching only up to the first allocated column + 1 searched only up to column B. Whether an entire column is hidden is not part of ScColumn, it's stored in ScTable. Change-Id: Ib1befe5cd0db8d50a6196bc6621fb1b0967e6209 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133524 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/source/ui/view/tabview2.cxx b/sc/source/ui/view/tabview2.cxx index 49167895a182..1c2cbd1389e6 100644 --- a/sc/source/ui/view/tabview2.cxx +++ b/sc/source/ui/view/tabview2.cxx @@ -739,8 +739,16 @@ void ScTabView::SkipCursorHorizontal(SCCOL& rCurX, SCROW& rCurY, SCCOL nOldX, SC bool bSkipCell = false; bool bHFlip = false; - // search also the first unallocated column (all unallocated columns share a set of attrs) - SCCOL nMaxCol = std::min<SCCOL>( rDoc.GetAllocatedColumnsCount(nTab) + 1, rDoc.MaxCol()); + // If a number of last columns are hidden, search up to and including the first of them, + // because after it nothing changes. + SCCOL nMaxCol; + if(rDoc.ColHidden(rDoc.MaxCol(), nTab, &nMaxCol)) + ++nMaxCol; + else + nMaxCol = rDoc.MaxCol(); + // Search also at least up to and including the first unallocated column (all unallocated columns + // share a set of attrs). + nMaxCol = std::max( nMaxCol, std::min<SCCOL>( rDoc.GetAllocatedColumnsCount(nTab) + 1, rDoc.MaxCol())); do { bSkipCell = rDoc.ColHidden(rCurX, nTab) || rDoc.IsHorOverlapped(rCurX, rCurY, nTab); commit 6f0e08a8cd92caa8a2c01e82559ceddb451b6721 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Apr 22 10:03:47 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue May 3 19:57:24 2022 +0200 fix an off-by-one error in GetEmptyLinesInBlock() The function has been there since the initial commit and is not documented, but I think it counts the shortest amount of empty cells in the given area starting from the direction given. And AFAICT the off-by-one error was there since the initial commit, when it returned one less if the entire area was empty and the direction was vertical (horizontal was fine). And ScHTMLExport::FillGraphList() even was adjusted for this until my recent commit changing that code). But then ad2bc869bfe2d34bde added a shortcut for unallocated columns that didn't have the error. And the error even got corrected during the rewrite in c008dc483f8c6840803983e7e351cec6fdd32070, but then 01de94471c20a8b9c36d6080638d70e57eac55bf reverted that. Anyway, so fix this, I think all the relevant code should(?) now work properly. Change-Id: I194691f7276a1cea75945de05cb0dda2cdca859a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133319 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index e4b57138794a..fc96571c0b5d 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -1527,6 +1527,7 @@ public: SCCOL& rEndCol, SCROW nEndRow ) const; SC_DLLPUBLIC bool IsEmptyBlock(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab) const; + // I think this returns the number of empty cells starting from the given direction. SC_DLLPUBLIC SCSIZE GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir ); diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index aeb28bf2ae00..4cd91d93e771 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -1328,13 +1328,13 @@ bool ScColumn::IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const { - // Given a range of rows, find a top or bottom empty segment. Skip the start row. + // Given a range of rows, find a top or bottom empty segment. switch (eDir) { case DIR_TOP: { // Determine the length of empty head segment. - size_t nLength = nEndRow - nStartRow; + size_t nLength = nEndRow - nStartRow + 1; std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow); sc::CellStoreType::const_iterator it = aPos.first; if (it->type != sc::element_type_empty) @@ -1349,7 +1349,7 @@ SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirecti case DIR_BOTTOM: { // Determine the length of empty tail segment. - size_t nLength = nEndRow - nStartRow; + size_t nLength = nEndRow - nStartRow + 1; std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nEndRow); sc::CellStoreType::const_iterator it = aPos.first; if (it->type != sc::element_type_empty) commit fa487acd51833021802871213f8fd2f93bb2d882 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Thu Apr 21 21:56:32 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue May 3 19:57:24 2022 +0200 fix checking whether a block of cells is empty The GetEmptyLinesInBlock() call has unclear semantics and it appears that it has an off-by-one error. Use a simple clear function for the check. Change-Id: I45d9b73428aedababc1ad93c202daa1de945b5bf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133303 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 566c742e38a1..e4b57138794a 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -1525,6 +1525,8 @@ public: void ExtendPrintArea( OutputDevice* pDev, SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow ) const; + SC_DLLPUBLIC bool IsEmptyBlock(SCCOL nStartCol, SCROW nStartRow, + SCCOL nEndCol, SCROW nEndRow, SCTAB nTab) const; SC_DLLPUBLIC SCSIZE GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir ); diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 2340680ddbea..57a332d8708f 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -619,6 +619,7 @@ public: SCROW GetLastDataRow( SCCOL nCol1, SCCOL nCol2, SCROW nLastRow, ScDataAreaExtras* pDataAreaExtras = nullptr ) const; + bool IsEmptyBlock(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow) const; SCSIZE GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) const; diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 1bfc84ee9824..7cf852ecc9e4 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -6133,6 +6133,13 @@ ScStyleSheetPool* ScDocument::GetStyleSheetPool() const return mxPoolHelper->GetStylePool(); } +bool ScDocument::IsEmptyBlock(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab) const +{ + if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab]) + return maTabs[nTab]->IsEmptyBlock(nStartCol, nStartRow, nEndCol, nEndRow); + return true; +} + SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir ) { diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 489b8939bfdf..377dfa3d2114 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -1175,6 +1175,15 @@ SCROW ScTable::GetLastDataRow( SCCOL nCol1, SCCOL nCol2, SCROW nLastRow, ScDataA return nNewLastRow; } +bool ScTable::IsEmptyBlock( SCCOL nStartCol, SCROW nStartRow, + SCCOL nEndCol, SCROW nEndRow ) const +{ + for( SCCOL col : GetAllocatedColumnsRange( nStartCol, nEndCol )) + if( !aCol[col].IsEmptyBlock( nStartRow, nEndRow )) + return false; + return true; +} + SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) const { diff --git a/sc/source/filter/html/htmlexp2.cxx b/sc/source/filter/html/htmlexp2.cxx index 50ff33b6ffc8..acb2f1394167 100644 --- a/sc/source/filter/html/htmlexp2.cxx +++ b/sc/source/filter/html/htmlexp2.cxx @@ -89,9 +89,7 @@ void ScHTMLExport::FillGraphList( const SdrPage* pPage, SCTAB nTab, SCCOL nCol2 = aR.aEnd.Col(); SCROW nRow2 = aR.aEnd.Row(); // All cells empty under object? - bool bInCell = (pDoc->GetEmptyLinesInBlock( - nCol1, nRow1, nTab, nCol2, nRow2, nTab, DIR_TOP ) - == static_cast< SCSIZE >( nRow2 - nRow1 )); // rows-1 ! + bool bInCell = pDoc->IsEmptyBlock( nCol1, nRow1, nCol2, nRow2, nTab ); if ( bInCell ) { // Spacing in spanning cell tools::Rectangle aCellRect = pDoc->GetMMRect( commit 5b89dc537bff62926b1a6174097b873ebd6f351d Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Thu Apr 21 22:33:26 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue May 3 19:57:23 2022 +0200 use range-checked GetCellValue() Change-Id: Ie02b6be79d1be7481ebcfbc6862295a34e38f7db Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133304 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx index 93d38c9e3ec4..a0cf373fc95b 100644 --- a/sc/source/core/data/table4.cxx +++ b/sc/source/core/data/table4.cxx @@ -1867,7 +1867,7 @@ void ScTable::FillAutoSimple( { if (bVertical) // rInner&:=nRow, rOuter&:=nCol { - aSrcCell = aCol[rCol].GetCellValue(nSource); + aSrcCell = GetCellValue(rCol, nSource); if (nISrcStart == nISrcEnd && aSrcCell.meType == CELLTYPE_FORMULA) { FillFormulaVertical(*aSrcCell.mpFormula, rInner, rCol, nIStart, nIEnd, pProgress, rProgress); @@ -1881,7 +1881,7 @@ void ScTable::FillAutoSimple( } else // rInner&:=nCol, rOuter&:=nRow { - aSrcCell = aCol[nSource].GetCellValue(rRow); + aSrcCell = GetCellValue(nSource, rRow); const SvNumFormatType nFormatType = rDocument.GetFormatTable()->GetType( aCol[nSource].GetNumberFormat( rDocument.GetNonThreadedContext(), rRow)); bBooleanCell = (nFormatType == SvNumFormatType::LOGICAL); @@ -2207,9 +2207,9 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, // it is still a good upper estimation. ScCellValue aSrcCell; if (bVertical) - aSrcCell = aCol[static_cast<SCCOL>(nOStart)].GetCellValue(static_cast<SCROW>(nISource)); + aSrcCell = GetCellValue(static_cast<SCCOL>(nOStart), static_cast<SCROW>(nISource)); else - aSrcCell = aCol[static_cast<SCCOL>(nISource)].GetCellValue(static_cast<SCROW>(nOStart)); + aSrcCell = GetCellValue(static_cast<SCCOL>(nISource), static_cast<SCROW>(nOStart)); // Same logic as for the actual series. if (!aSrcCell.isEmpty() && (aSrcCell.meType == CELLTYPE_VALUE || aSrcCell.meType == CELLTYPE_FORMULA)) { @@ -2263,7 +2263,7 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, CreateColumnIfNotExists(nCol); // Source cell value. We need to clone the value since it may be inserted repeatedly. - ScCellValue aSrcCell = aCol[nCol].GetCellValue(static_cast<SCROW>(nRow)); + ScCellValue aSrcCell = GetCellValue(nCol, static_cast<SCROW>(nRow)); // Maybe another source cell need to be searched, if the fill is going through merged cells, // where overlapped parts does not contain any information, so they can be skipped. @@ -2288,9 +2288,9 @@ void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, //Set the real source cell if (bVertical) - aSrcCell = aCol[nOStart].GetCellValue(static_cast<SCROW>(nFirstValueIdx)); + aSrcCell = GetCellValue(nOStart, static_cast<SCROW>(nFirstValueIdx)); else - aSrcCell = aCol[nFirstValueIdx].GetCellValue(static_cast<SCROW>(nOStart)); + aSrcCell = GetCellValue(nFirstValueIdx, static_cast<SCROW>(nOStart)); } const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow)); commit 427c4aa9ec13ca07d61178ab2a449470392ac0a7 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Thu Apr 21 21:03:59 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue May 3 19:57:23 2022 +0200 simply return from a loop Change-Id: I4e10945f32dfb535663ea7392f19532e45ca9ee3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133301 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 37fce167410e..489b8939bfdf 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -1234,11 +1234,10 @@ bool ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, SCCOL nEndCol ) const nEndCol = std::min<SCCOL>( nEndCol, aCol.size()-1 ); - bool bFound = false; - for (SCCOL i=nStartCol; i<=nEndCol && !bFound; i++) + for (SCCOL i=nStartCol; i<=nEndCol; i++) if (aCol[i].HasDataAt(nRow)) - bFound = true; - return !bFound; + return false; + return true; } void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow ) const commit fd54ffec2defdd78ed7f203026b51c5a7034c291 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Thu Apr 21 19:54:53 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue May 3 19:57:23 2022 +0200 fix off-by-one error Change-Id: Ic58a896a7a2edf5ba602ab9cfc5a4578fd5d0a56 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133296 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 892555995e43..37fce167410e 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -318,7 +318,7 @@ ScTable::~ScTable() COVERITY_NOEXCEPT_FALSE { if (!rDocument.IsInDtorClear()) { - for (SCCOL nCol = 0; nCol < (aCol.size() - 1); ++nCol) + for (SCCOL nCol = 0; nCol < aCol.size(); ++nCol) { aCol[nCol].FreeNotes(); } commit df629d0a5c854589e5e1f133713a5efa8156ae8c Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Thu Apr 21 19:11:38 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue May 3 19:57:23 2022 +0200 rework GetColumnsRange() and ScColumnsRange The problem with GetColumnsRange() was that it was clamping the range to the number of allocated columns, but that's not always wanted, e.g. ScDocument::InsertMatrixFormula() needs to iterate over the whole range and allocate columns if necessary instead of ignoring them. From an API point of view it's also not very obvious that something called GetColumnsRange() actually does something more than just returning the given range. Handle this by making GetColumnsRange() return the actual given range, and add GetWriteableColumnsRange() and GetAllocatedColumnsRange() for the specific cases. This also required changing ScColumnsRange to work simply on SCCOL value instead of using std::vector iterator (since the vector may not have all the elements in the range). Change-Id: I9b645459461efe6b282e8ac5d7a29549830f46c1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133295 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index c2c597983cea..566c742e38a1 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -2600,6 +2600,12 @@ public: void finalizeOutlineImport(); bool TableExists( SCTAB nTab ) const; + // Returns the given column range, first allocating all the columns if necessary. + SC_DLLPUBLIC ScColumnsRange GetWritableColumnsRange(SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd); + // Returns a column range, clamped to the allocated columns. + SC_DLLPUBLIC ScColumnsRange GetAllocatedColumnsRange(SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const; + // Returns the given range, without any adjustments. One of the variants above may return + // a smaller range (better performance) if the use case is known. SC_DLLPUBLIC ScColumnsRange GetColumnsRange(SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const; bool IsInDocShellRecalc() const { return mbDocShellRecalc; } diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 8ec17616dc1f..2340680ddbea 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -123,7 +123,7 @@ class ScColumnsRange final public: class Iterator final { - std::vector<std::unique_ptr<ScColumn, o3tl::default_delete<ScColumn>>>::const_iterator maColIter; + SCCOL mCol; public: typedef std::input_iterator_tag iterator_category; typedef SCCOL value_type; @@ -131,17 +131,18 @@ class ScColumnsRange final typedef const SCCOL* pointer; typedef SCCOL reference; - explicit Iterator(const std::vector<std::unique_ptr<ScColumn, o3tl::default_delete<ScColumn>>>::const_iterator& colIter) : maColIter(colIter) {} + explicit Iterator(SCCOL nCol) : mCol(nCol) {} - Iterator& operator++() { ++maColIter; return *this;} - Iterator& operator--() { --maColIter; return *this;} + Iterator& operator++() { ++mCol; return *this;} + Iterator& operator--() { --mCol; return *this;} - bool operator==(const Iterator & rOther) const {return maColIter == rOther.maColIter;} + // Comparing iterators from different containers is undefined, so comparing mCol is enough. + bool operator==(const Iterator & rOther) const {return mCol == rOther.mCol;} bool operator!=(const Iterator & rOther) const {return !(*this == rOther);} - SCCOL operator*() const {return (*maColIter)->GetCol();} + SCCOL operator*() const {return mCol;} }; - ScColumnsRange(const Iterator & rBegin, const Iterator & rEnd) : maBegin(rBegin), maEnd(rEnd) {} + ScColumnsRange(SCCOL nBegin, SCCOL nEnd) : maBegin(nBegin), maEnd(nEnd) {} const Iterator & begin() { return maBegin; } const Iterator & end() { return maEnd; } std::reverse_iterator<Iterator> rbegin() { return std::reverse_iterator<Iterator>(maEnd); } @@ -1111,6 +1112,8 @@ public: */ static void UpdateSearchItemAddressForReplace( const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow ); + ScColumnsRange GetWritableColumnsRange(SCCOL begin, SCCOL end); + ScColumnsRange GetAllocatedColumnsRange(SCCOL begin, SCCOL end) const; ScColumnsRange GetColumnsRange(SCCOL begin, SCCOL end) const; SCCOL ClampToAllocatedColumns(SCCOL nCol) const { return std::min(nCol, static_cast<SCCOL>(aCol.size() - 1)); } SCCOL GetAllocatedColumnsCount() const { return aCol.size(); } diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx index de75f206b34e..cf9a2fbd0a83 100644 --- a/sc/source/core/data/documen4.cxx +++ b/sc/source/core/data/documen4.cxx @@ -332,7 +332,7 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1, *t->GetSingleRef() = aRefData; } - for (SCCOL nCol : GetColumnsRange(nTab1, nCol1, nCol2)) + for (SCCOL nCol : GetWritableColumnsRange(nTab1, nCol1, nCol2)) { for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) { diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 0ee24ea0ab8c..1bfc84ee9824 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -2541,15 +2541,27 @@ const ScTable* ScDocument::FetchTable( SCTAB nTab ) const return maTabs[nTab].get(); } -ScColumnsRange ScDocument::GetColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const +ScColumnsRange ScDocument::GetWritableColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) { if (!TableExists(nTab)) { - std::vector<std::unique_ptr<ScColumn, o3tl::default_delete<ScColumn>>> aEmptyVector; - return ScColumnsRange(ScColumnsRange::Iterator(aEmptyVector.begin()), - ScColumnsRange::Iterator(aEmptyVector.end())); + SAL_WARN("sc", "GetWritableColumnsRange() called for non-existent table"); + return ScColumnsRange(-1, -1); } + return maTabs[nTab]->GetWritableColumnsRange(nColBegin, nColEnd); +} +ScColumnsRange ScDocument::GetAllocatedColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const +{ + if (!TableExists(nTab)) + return ScColumnsRange(-1, -1); + return maTabs[nTab]->GetAllocatedColumnsRange(nColBegin, nColEnd); +} + +ScColumnsRange ScDocument::GetColumnsRange( SCTAB nTab, SCCOL nColBegin, SCCOL nColEnd) const +{ + if (!TableExists(nTab)) + return ScColumnsRange(-1, -1); return maTabs[nTab]->GetColumnsRange(nColBegin, nColEnd); } @@ -6860,7 +6872,7 @@ ScAddress ScDocument::GetNotePosition( size_t nIndex ) const { for (size_t nTab = 0; nTab < maTabs.size(); ++nTab) { - for (SCCOL nCol : GetColumnsRange(nTab, 0, MaxCol())) + for (SCCOL nCol : GetAllocatedColumnsRange(nTab, 0, MaxCol())) { size_t nColNoteCount = GetNoteCount(nTab, nCol); if (!nColNoteCount) @@ -6887,7 +6899,7 @@ ScAddress ScDocument::GetNotePosition( size_t nIndex ) const ScAddress ScDocument::GetNotePosition( size_t nIndex, SCTAB nTab ) const { - for (SCCOL nCol : GetColumnsRange(nTab, 0, MaxCol())) + for (SCCOL nCol : GetAllocatedColumnsRange(nTab, 0, MaxCol())) { size_t nColNoteCount = GetNoteCount(nTab, nCol); if (!nColNoteCount) diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 311a3756d817..892555995e43 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -2670,31 +2670,34 @@ const ScConditionalFormatList* ScTable::GetCondFormList() const return mpCondFormatList.get(); } -ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const +ScColumnsRange ScTable::GetWritableColumnsRange(SCCOL nColBegin, SCCOL nColEnd) +{ + // because the range is inclusive, some code will pass nColEnd<nColBegin to indicate an empty range + if (nColEnd < nColBegin) + return ScColumnsRange(-1, -1); + assert( nColEnd >= 0 && nColEnd <= GetDoc().MaxCol()); + CreateColumnIfNotExists(nColEnd); + return GetColumnsRange(nColBegin, nColEnd); +} + +ScColumnsRange ScTable::GetAllocatedColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const { - ScColContainer::ScColumnVector::const_iterator beginIter; - ScColContainer::ScColumnVector::const_iterator endIter; + if (nColBegin >= aCol.size()) + return ScColumnsRange(-1, -1); + // clamp end of range to available columns + if (nColEnd >= aCol.size()) + nColEnd = aCol.size() - 1; + return GetColumnsRange(nColBegin, nColEnd); +} +ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const +{ // because the range is inclusive, some code will pass nColEnd<nColBegin to indicate an empty range if (nColEnd < nColBegin) - { - beginIter = aCol.end(); - endIter = aCol.end(); - } - else if (nColBegin >= aCol.size()) - { - beginIter = aCol.end(); - endIter = aCol.end(); - } - else - { - // clamp end of range to available columns - if (nColEnd >= aCol.size()) - nColEnd = aCol.size() - 1; - beginIter = aCol.begin() + nColBegin; - endIter = aCol.begin() + nColEnd + 1; - } - return ScColumnsRange(ScColumnsRange::Iterator(beginIter), ScColumnsRange::Iterator(endIter)); + return ScColumnsRange(-1, -1); + assert( nColBegin >= 0 && nColBegin <= GetDoc().MaxCol()); + assert( nColEnd >= 0 && nColEnd <= GetDoc().MaxCol()); + return ScColumnsRange(nColBegin, nColEnd + 1); // change inclusive end to past-end } // out-of-line the cold part of the CreateColumnIfNotExists function diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 415507f313e1..19707dff4403 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -260,7 +260,7 @@ bool ScTable::TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize ) cons && ! pOutlineTable->TestInsertCol(nSize) ) return false; - auto range = GetColumnsRange( rDocument.MaxCol() - static_cast<SCCOL>(nSize) + 1, rDocument.MaxCol() ); + auto range = GetAllocatedColumnsRange( rDocument.MaxCol() - static_cast<SCCOL>(nSize) + 1, rDocument.MaxCol() ); for (auto it = range.rbegin(); it != range.rend(); ++it ) if (! aCol[*it].TestInsertCol(nStartRow, nEndRow)) return false; diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx index 3508c183e85f..c99bc9f8c7ce 100644 --- a/sc/source/core/data/table3.cxx +++ b/sc/source/core/data/table3.cxx @@ -1927,12 +1927,12 @@ public: SCCOL nStartCol = mrParam.nCol1; SCCOL nEndCol = mrParam.nCol2; - for (SCCOL nCol : mrTab.GetColumnsRange(0, nStartCol - 1)) + for (SCCOL nCol : mrTab.GetAllocatedColumnsRange(0, nStartCol - 1)) { if (mrTab.HasData(nCol, nRow)) return true; } - for (SCCOL nCol : mrTab.GetColumnsRange(nEndCol + 1, mrTab.GetDoc().MaxCol())) + for (SCCOL nCol : mrTab.GetAllocatedColumnsRange(nEndCol + 1, mrTab.GetDoc().MaxCol())) { if (mrTab.HasData(nCol, nRow)) return true; diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx index dc3a8c045dd9..30788b0daca7 100644 --- a/sc/source/core/data/table7.cxx +++ b/sc/source/core/data/table7.cxx @@ -321,7 +321,7 @@ void ScTable::EndListeningIntersectedGroups( if (nCol2 < nCol1 || !IsColValid(nCol1) || !ValidCol(nCol2)) return; - for (SCCOL nCol : GetColumnsRange(nCol1, nCol2)) + for (SCCOL nCol : GetAllocatedColumnsRange(nCol1, nCol2)) aCol[nCol].EndListeningIntersectedGroups(rCxt, nRow1, nRow2, pGroupPos); } diff --git a/sc/source/filter/dif/difimp.cxx b/sc/source/filter/dif/difimp.cxx index 5f7178b9fe8a..cf5953c81c99 100644 --- a/sc/source/filter/dif/difimp.cxx +++ b/sc/source/filter/dif/difimp.cxx @@ -683,7 +683,7 @@ void DifAttrCache::SetNumFormat( const ScDocument* pDoc, const SCCOL nCol, const void DifAttrCache::Apply( ScDocument& rDoc, SCTAB nTab ) { - for( SCCOL nCol : rDoc.GetColumnsRange(nTab, 0, rDoc.MaxCol()) ) + for( SCCOL nCol : rDoc.GetWritableColumnsRange(nTab, 0, rDoc.MaxCol()) ) { if( maColMap.count(nCol) ) maColMap[ nCol ]->Apply( rDoc, nCol, nTab ); diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx index 85dec63985b1..694ee5dc09e1 100644 --- a/sc/source/ui/unoobj/docuno.cxx +++ b/sc/source/ui/unoobj/docuno.cxx @@ -4627,7 +4627,7 @@ sal_Int32 SAL_CALL ScAnnotationsObj::getCount() if (pDocShell) { const ScDocument& rDoc = pDocShell->GetDocument(); - for (SCCOL nCol : rDoc.GetColumnsRange(nTab, 0, rDoc.MaxCol())) + for (SCCOL nCol : rDoc.GetAllocatedColumnsRange(nTab, 0, rDoc.MaxCol())) nCount += rDoc.GetNoteCount(nTab, nCol); } return nCount;