compilerplugins/clang/redundantfcast.cxx | 3 include/svx/framelink.hxx | 11 ++ sal/cppunittester/cppunittester.cxx | 5 - sc/inc/attarray.hxx | 4 sc/inc/column.hxx | 17 ++- sc/inc/dociter.hxx | 4 sc/inc/document.hxx | 14 +-- sc/inc/documentimport.hxx | 9 +- sc/inc/fillinfo.hxx | 2 sc/inc/table.hxx | 14 +-- sc/qa/unit/data/xlsx/tdf58243.xlsx |binary sc/qa/unit/subsequent_export_test2.cxx | 44 +++++++++ sc/qa/unit/ucalc.cxx | 138 +++++++++++++++++++++++++++++-- sc/source/core/data/attarray.cxx | 9 ++ sc/source/core/data/column3.cxx | 2 sc/source/core/data/dociter.cxx | 82 ++++-------------- sc/source/core/data/document.cxx | 12 +- sc/source/core/data/documentimport.cxx | 17 +-- sc/source/core/data/table2.cxx | 82 ++++++++++-------- sc/source/filter/excel/xistyle.cxx | 17 +++ sc/source/filter/inc/sheetdatabuffer.hxx | 12 +- sc/source/filter/oox/sheetdatabuffer.cxx | 34 ++++++- sc/source/filter/xml/xmlcoli.cxx | 1 sc/source/filter/xml/xmlexprt.cxx | 8 - sc/source/ui/unoobj/cellsuno.cxx | 7 - sc/source/ui/view/output.cxx | 38 ++++---- sc/source/ui/view/tabview.cxx | 8 - svx/source/dialog/framelink.cxx | 5 - 28 files changed, 409 insertions(+), 190 deletions(-)
New commits: commit 033fe3f340a3d47bb87099e23aaa101781932262 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Tue Apr 12 14:33:55 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:18:24 2022 +0200 bail out of the loop when the item is found Change-Id: If0816f38eeeb3330738ab40bc8a72f1e14575c33 diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx index 532e675ad08b..ca77bae6c093 100644 --- a/sc/source/ui/unoobj/cellsuno.cxx +++ b/sc/source/ui/unoobj/cellsuno.cxx @@ -8819,7 +8819,6 @@ rtl::Reference<ScCellRangeObj> ScCellFormatsObj::GetObjectByIndex_Impl(tools::Lo { //! access the AttrArrays directly !!!! - rtl::Reference<ScCellRangeObj> pRet; if (pDocShell) { ScDocument& rDoc = pDocShell->GetDocument(); @@ -8837,14 +8836,14 @@ rtl::Reference<ScCellRangeObj> ScCellFormatsObj::GetObjectByIndex_Impl(tools::Lo ScRange aNext( nCol1, nRow1, nTab, nCol2, nRow2, nTab ); if ( aNext.aStart == aNext.aEnd ) - pRet = new ScCellObj( pDocShell, aNext.aStart ); + return new ScCellObj( pDocShell, aNext.aStart ); else - pRet = new ScCellRangeObj( pDocShell, aNext ); + return new ScCellRangeObj( pDocShell, aNext ); } ++nPos; } } - return pRet; + return {}; } // XIndexAccess commit 1de6fcb8e43a1bdac0b49b843172a634227e6303 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Mar 25 12:42:58 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:18:15 2022 +0200 fix ScTable::GetLastChangedCol() for unallocated columns Column flags and widths are stored separately from ScColumn data, and so don't depend on allocated columns count. Also rename the functions from the misleading generic name to what they actually do. Change-Id: If85ae80efda1d8b382fa3b559aa65be0292e25ba diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index d9e9b22be9f6..9bf190571f56 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -2027,17 +2027,17 @@ public: */ void SyncColRowFlags(); - /// @return the index of the last row with any set flags (auto-pagebreak is ignored). + /// @return the index of the last row with any set flags (auto-pagebreak is ignored). SC_DLLPUBLIC SCROW GetLastFlaggedRow( SCTAB nTab ) const; - /// @return the index of the last changed column (flags and column width, auto pagebreak is ignored). - SCCOL GetLastChangedCol( SCTAB nTab ) const; - /// @return the index of the last changed row (flags and row height, auto pagebreak is ignored). - SCROW GetLastChangedRow( SCTAB nTab ) const; + /// @return the index of the last changed column (flags and column width, auto pagebreak is ignored). + SCCOL GetLastChangedColFlagsWidth( SCTAB nTab ) const; + /// @return the index of the last changed row (flags and row height, auto pagebreak is ignored). + SCROW GetLastChangedRowFlagsWidth( SCTAB nTab ) const; - SCCOL GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const; + SCCOL GetNextDifferentChangedColFlagsWidth( SCTAB nTab, SCCOL nStart) const; - SCROW GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart) const; + SCROW GetNextDifferentChangedRowFlagsWidth( SCTAB nTab, SCROW nStart) const; // returns whether to export a Default style for this col or not // nDefault is set to one position in the current row where the Default style is diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 55321c6965ea..8ec17616dc1f 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -883,10 +883,10 @@ public: /// @return the index of the last row with any set flags (auto-pagebreak is ignored). SCROW GetLastFlaggedRow() const; - /// @return the index of the last changed column (flags and column width, auto pagebreak is ignored). - SCCOL GetLastChangedCol() const; - /// @return the index of the last changed row (flags and row height, auto pagebreak is ignored). - SCROW GetLastChangedRow() const; + /// @return the index of the last changed column (flags and column width, auto pagebreak is ignored). + SCCOL GetLastChangedColFlagsWidth() const; + /// @return the index of the last changed row (flags and row height, auto pagebreak is ignored). + SCROW GetLastChangedRowFlagsWidth() const; bool IsDataFiltered(SCCOL nColStart, SCROW nRowStart, SCCOL nColEnd, SCROW nRowEnd) const; bool IsDataFiltered(const ScRange& rRange) const; diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index 8323ca310298..3c9a3db2417c 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -148,6 +148,7 @@ public: void testHorizontalAttrIterator(); void testIteratorsUnallocatedColumnsAttributes(); void testIteratorsDefPattern(); + void testLastChangedColFlagsWidth(); /** * More direct test for cell broadcaster management, used to track formula @@ -280,6 +281,7 @@ public: CPPUNIT_TEST(testHorizontalAttrIterator); CPPUNIT_TEST(testIteratorsUnallocatedColumnsAttributes); CPPUNIT_TEST(testIteratorsDefPattern); + CPPUNIT_TEST(testLastChangedColFlagsWidth); CPPUNIT_TEST(testCellBroadcaster); CPPUNIT_TEST(testFuncParam); CPPUNIT_TEST(testNamedRange); @@ -1507,6 +1509,23 @@ void Test::testIteratorsDefPattern() m_pDoc->DeleteTab(0); } +void Test::testLastChangedColFlagsWidth() +{ + m_pDoc->InsertTab(0, "Tab1"); + + constexpr SCCOL firstChangedCol = 100; + assert( firstChangedCol > INITIALCOLCOUNT ); + for( SCCOL col = firstChangedCol; col <= m_pDoc->MaxCol(); ++col ) + m_pDoc->SetColWidth( col, 0, 10 ); + + // That shouldn't need allocating more columns, just changing column flags. + CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), m_pDoc->GetAllocatedColumnsCount(0)); + // But the flags are changed. + CPPUNIT_ASSERT_EQUAL(m_pDoc->MaxCol(), m_pDoc->GetLastChangedColFlagsWidth(0)); + + m_pDoc->DeleteTab(0); +} + namespace { bool broadcasterShifted(const ScDocument& rDoc, const ScAddress& rFrom, const ScAddress& rTo) diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 6765e8a5849e..941b8ade54ca 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -4589,21 +4589,21 @@ SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const return 0; } -SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const +SCCOL ScDocument::GetLastChangedColFlagsWidth( SCTAB nTab ) const { if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] ) - return maTabs[nTab]->GetLastChangedCol(); + return maTabs[nTab]->GetLastChangedColFlagsWidth(); return 0; } -SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const +SCROW ScDocument::GetLastChangedRowFlagsWidth( SCTAB nTab ) const { if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] ) - return maTabs[nTab]->GetLastChangedRow(); + return maTabs[nTab]->GetLastChangedRowFlagsWidth(); return 0; } -SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const +SCCOL ScDocument::GetNextDifferentChangedColFlagsWidth( SCTAB nTab, SCCOL nStart) const { if ( ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab] ) { @@ -4621,7 +4621,7 @@ SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const return 0; } -SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart) const +SCROW ScDocument::GetNextDifferentChangedRowFlagsWidth( SCTAB nTab, SCROW nStart) const { if (!ValidTab(nTab) || nTab >= static_cast<SCTAB>(maTabs.size()) || !maTabs[nTab]) return 0; diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 642b78f1c94d..023e853ecdc4 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -3918,22 +3918,21 @@ SCROW ScTable::GetLastFlaggedRow() const return nLastFound; } -SCCOL ScTable::GetLastChangedCol() const +SCCOL ScTable::GetLastChangedColFlagsWidth() const { if ( !mpColFlags ) return 0; SCCOL nLastFound = 0; - const auto nColSize = aCol.size(); auto colWidthIt = mpColWidth->begin() + 1; - for (SCCOL nCol = 1; nCol < nColSize; (++nCol < nColSize) ? ++colWidthIt : (void)false) + for (SCCOL nCol = 1; nCol <= GetDoc().MaxCol(); (++nCol <= GetDoc().MaxCol()) ? ++colWidthIt : (void)false) if ((mpColFlags->GetValue(nCol) & CRFlags::All) || (*colWidthIt != STD_COL_WIDTH)) nLastFound = nCol; return nLastFound; } -SCROW ScTable::GetLastChangedRow() const +SCROW ScTable::GetLastChangedRowFlagsWidth() const { if ( !pRowFlags ) return 0; diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx index 7be7bd4e72f0..8e9e03fca80c 100644 --- a/sc/source/filter/xml/xmlexprt.cxx +++ b/sc/source/filter/xml/xmlexprt.cxx @@ -2538,7 +2538,7 @@ void ScXMLExport::collectAutoStyles() uno::Reference<table::XTableColumns> xTableColumns(xColumnRowRange->getColumns()); if (xTableColumns.is()) { - sal_Int32 nColumns(pDoc->GetLastChangedCol(sal::static_int_cast<SCTAB>(nTable))); + sal_Int32 nColumns(pDoc->GetLastChangedColFlagsWidth(sal::static_int_cast<SCTAB>(nTable))); pSharedData->SetLastColumn(nTable, nColumns); table::CellRangeAddress aCellAddress(GetEndAddress(xTable)); if (aCellAddress.EndColumn > nColumns) @@ -2560,7 +2560,7 @@ void ScXMLExport::collectAutoStyles() pColumnStyles->AddFieldStyleName(nTable, nColumn, nIndex, bIsVisible); } sal_Int32 nOld(nColumn); - nColumn = pDoc->GetNextDifferentChangedCol(sal::static_int_cast<SCTAB>(nTable), static_cast<SCCOL>(nColumn)); + nColumn = pDoc->GetNextDifferentChangedColFlagsWidth(sal::static_int_cast<SCTAB>(nTable), static_cast<SCCOL>(nColumn)); for (sal_Int32 i = nOld + 1; i < nColumn; ++i) pColumnStyles->AddFieldStyleName(nTable, i, nIndex, bIsVisible); } @@ -2575,7 +2575,7 @@ void ScXMLExport::collectAutoStyles() uno::Reference<table::XTableRows> xTableRows(xColumnRowRange->getRows()); if (xTableRows.is()) { - sal_Int32 nRows(pDoc->GetLastChangedRow(sal::static_int_cast<SCTAB>(nTable))); + sal_Int32 nRows(pDoc->GetLastChangedRowFlagsWidth(sal::static_int_cast<SCTAB>(nTable))); pSharedData->SetLastRow(nTable, nRows); pRowStyles->AddNewTable(nTable, pDoc->MaxRow()); @@ -2590,7 +2590,7 @@ void ScXMLExport::collectAutoStyles() pRowStyles->AddFieldStyleName(nTable, nRow, nIndex); } sal_Int32 nOld(nRow); - nRow = pDoc->GetNextDifferentChangedRow(sal::static_int_cast<SCTAB>(nTable), static_cast<SCROW>(nRow)); + nRow = pDoc->GetNextDifferentChangedRowFlagsWidth(sal::static_int_cast<SCTAB>(nTable), static_cast<SCROW>(nRow)); if (nRow > nOld + 1) pRowStyles->AddFieldStyleName(nTable, nOld + 1, nIndex, nRow - 1); } commit 7fe6a3eebadd9b18e788bc6547fd58fcb25afd62 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Wed Mar 23 12:26:45 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:18:06 2022 +0200 forcepoint#81 fix array size A mistake from 694148a9898b47d749588f9a32173a9933262e29, the array is meant to be from column 0, so as if 'nStartCol == 0'. Change-Id: I7f2ecea6c7378d0d5530cb38314807a8f7c896c3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131972 Tested-by: Caolán McNamara <caol...@redhat.com> Reviewed-by: Caolán McNamara <caol...@redhat.com> diff --git a/sc/inc/fillinfo.hxx b/sc/inc/fillinfo.hxx index d6ab0bd537c6..ecd836f89ec9 100644 --- a/sc/inc/fillinfo.hxx +++ b/sc/inc/fillinfo.hxx @@ -221,7 +221,7 @@ struct RowInfo nEndCol = endCol; #endif pCellInfo = new CellInfo[ endCol - nStartCol + 1 + 2 ]; - pBasicCellInfo = new BasicCellInfo[ endCol + 2 ]; + pBasicCellInfo = new BasicCellInfo[ endCol + 1 + 2 ]; } void freeCellInfo() { commit f142fb374756fd6ab9cba62b957e950162e059ad Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Mar 18 17:20:47 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:17:19 2022 +0200 handle broken row ranges in excel import, #2 In ad1f6e62298612f4b277708b813a219ba390f1b0 I didn't add a second std::unique() pass, that seems to be necessary with some broken documents as well (sc_column3_regroupformulacells_heap_buffer_overflow.sample from crashtesting). Change-Id: I6865085a9b77fe51246180e519bf1a2309615144 diff --git a/sc/source/filter/oox/sheetdatabuffer.cxx b/sc/source/filter/oox/sheetdatabuffer.cxx index 82fc10f35069..63b9b4f11145 100644 --- a/sc/source/filter/oox/sheetdatabuffer.cxx +++ b/sc/source/filter/oox/sheetdatabuffer.cxx @@ -379,9 +379,15 @@ void SheetDataBuffer::addColXfStyles() // as operator< is somewhat specific (see StyleRowRangeComp). { return !StyleRowRangeComp()(lhs,rhs) && !StyleRowRangeComp()(rhs,lhs); } ), s.end()); - // Broken documents may have overlapping ranges that cause problems, re-sort again if needed. + // Broken documents may have overlapping ranges that cause problems, repeat once more. if(!std::is_sorted(s.begin(), s.end(), StyleRowRangeComp())) + { std::sort( s.begin(), s.end(), StyleRowRangeComp()); + s.erase( std::unique( s.begin(), s.end(), + [](const RowRangeStyle& lhs, const RowRangeStyle& rhs) + { return !StyleRowRangeComp()(lhs,rhs) && !StyleRowRangeComp()(rhs,lhs); } ), + s.end()); + } maStylesPerColumn[ rowStyles.first ].insert_sorted_unique_vector( std::move( s )); } } commit e7ca47af1e40d488813c48a3e425e4ad462ab891 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Tue Mar 15 21:48:34 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:17:10 2022 +0200 handle broken row ranges in excel import LIBREOFFICE-39G76603.xlsx from crashtesting has broken data cause assertion failures about the ranges being sorted (because the ranges overlap and StyleRowRangeComp needs and assumes that they do not). Changing the std::unique() call to remove ranges that compare equal (which is not the same as being equal, due to how StyleRowRangeComp compares) and sorting again seems to drop all problematic ranges. (I'm not adding the problematic file to tests as loading it takes a lot of time.) Change-Id: If6ac94959a649a641d02fd703d33edddbdf0fb85 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131637 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/source/filter/inc/sheetdatabuffer.hxx b/sc/source/filter/inc/sheetdatabuffer.hxx index 8eee9f7b79b0..940da26416fe 100644 --- a/sc/source/filter/inc/sheetdatabuffer.hxx +++ b/sc/source/filter/inc/sheetdatabuffer.hxx @@ -207,13 +207,6 @@ private: return lhs.mnEndRow<rhs.mnStartRow; } }; - struct StyleRowRangeCompEqual - { - bool operator() (const RowRangeStyle& lhs, const RowRangeStyle& rhs) const - { - return lhs.mnStartRow==rhs.mnStartRow && lhs.mnEndRow == rhs.mnEndRow; - } - }; typedef ::o3tl::sorted_vector< RowRangeStyle, StyleRowRangeComp > RowStyles; typedef ::std::map< sal_Int32, RowStyles > ColStyles; typedef ::std::vector< RowRangeStyle > TmpRowStyles; diff --git a/sc/source/filter/oox/sheetdatabuffer.cxx b/sc/source/filter/oox/sheetdatabuffer.cxx index 259e3190107b..82fc10f35069 100644 --- a/sc/source/filter/oox/sheetdatabuffer.cxx +++ b/sc/source/filter/oox/sheetdatabuffer.cxx @@ -373,7 +373,15 @@ void SheetDataBuffer::addColXfStyles() { TmpRowStyles& s = rowStyles.second; std::sort( s.begin(), s.end(), StyleRowRangeComp()); - s.erase( std::unique( s.begin(), s.end(), StyleRowRangeCompEqual()), s.end()); + s.erase( std::unique( s.begin(), s.end(), + [](const RowRangeStyle& lhs, const RowRangeStyle& rhs) + // Synthetize operator== from operator < . Do not create an actual operator== + // as operator< is somewhat specific (see StyleRowRangeComp). + { return !StyleRowRangeComp()(lhs,rhs) && !StyleRowRangeComp()(rhs,lhs); } ), + s.end()); + // Broken documents may have overlapping ranges that cause problems, re-sort again if needed. + if(!std::is_sorted(s.begin(), s.end(), StyleRowRangeComp())) + std::sort( s.begin(), s.end(), StyleRowRangeComp()); maStylesPerColumn[ rowStyles.first ].insert_sorted_unique_vector( std::move( s )); } } commit 6338a0a44d3c9eeac26419aecb866682a41eed52 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Tue Mar 15 20:03:50 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:17:02 2022 +0200 fix comparison operators in Excel export, #2 It turns out that the end-vs-start comparison was intentional and the file causing problems is broken, so more or less revert 83d599fd7c530d14f70ac60bd673b66640191bf7, and I'll handle the problematic file in another commit. Change-Id: I5c7538a7c3eeea9c5fd1661e1a9a2c3370b799c9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131636 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/qa/unit/data/xlsx/tdf58243.xlsx b/sc/qa/unit/data/xlsx/tdf58243.xlsx new file mode 100644 index 000000000000..f95e13b4b6db Binary files /dev/null and b/sc/qa/unit/data/xlsx/tdf58243.xlsx differ diff --git a/sc/qa/unit/subsequent_export_test2.cxx b/sc/qa/unit/subsequent_export_test2.cxx index ad3f125db7d9..9776b1629197 100644 --- a/sc/qa/unit/subsequent_export_test2.cxx +++ b/sc/qa/unit/subsequent_export_test2.cxx @@ -217,6 +217,7 @@ public: void testTdf145059(); void testTdf130104_XLSXIndent(); void testWholeRowBold(); + void testXlsxRowsOrder(); CPPUNIT_TEST_SUITE(ScExportTest2); @@ -333,6 +334,7 @@ public: CPPUNIT_TEST(testTdf145059); CPPUNIT_TEST(testTdf130104_XLSXIndent); CPPUNIT_TEST(testWholeRowBold); + CPPUNIT_TEST(testXlsxRowsOrder); CPPUNIT_TEST_SUITE_END(); @@ -3113,6 +3115,15 @@ void ScExportTest2::testWholeRowBold() xDocSh3->DoClose(); } +void ScExportTest2::testXlsxRowsOrder() +{ + ScDocShellRef xDocSh = loadDoc(u"tdf58243.", FORMAT_XLSX); + CPPUNIT_ASSERT(xDocSh.is()); + // Make sure code in SheetDataBuffer doesn't assert columns/rows sorting. + ScBootstrapFixture::exportTo(*xDocSh, FORMAT_XLSX); + xDocSh->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest2); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sc/source/core/data/attarray.cxx b/sc/source/core/data/attarray.cxx index 5af0e3b3609d..1b84ae4616a5 100644 --- a/sc/source/core/data/attarray.cxx +++ b/sc/source/core/data/attarray.cxx @@ -930,6 +930,15 @@ void ScAttrArray::SetAttrEntries(std::vector<ScAttrEntry> && vNewData) pDocPool->Remove(*rEntry.pPattern); mvData = std::move(vNewData); + +#ifdef DBG_UTIL + SCROW lastEndRow = -1; + for(const auto& entry : mvData) + { // Verify that the data is not corrupted. + assert(entry.nEndRow > lastEndRow); + lastEndRow = entry.nEndRow; + } +#endif } static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource ) diff --git a/sc/source/filter/inc/sheetdatabuffer.hxx b/sc/source/filter/inc/sheetdatabuffer.hxx index 33366fde9f9e..8eee9f7b79b0 100644 --- a/sc/source/filter/inc/sheetdatabuffer.hxx +++ b/sc/source/filter/inc/sheetdatabuffer.hxx @@ -199,14 +199,19 @@ private: { bool operator() (const RowRangeStyle& lhs, const RowRangeStyle& rhs) const { - return lhs.mnStartRow<rhs.mnStartRow; + // This end-vs-start comparison is needed by the lower_bound() use + // in SheetDataBuffer::addColXfStyleProcessRowRanges() that searches + // for partially overlapping ranges. In all other places the ranges + // should be non-overlapping, in which case this is the same as the "normal" + // comparison. + return lhs.mnEndRow<rhs.mnStartRow; } }; struct StyleRowRangeCompEqual { bool operator() (const RowRangeStyle& lhs, const RowRangeStyle& rhs) const { - return lhs.mnStartRow==rhs.mnStartRow; + return lhs.mnStartRow==rhs.mnStartRow && lhs.mnEndRow == rhs.mnEndRow; } }; typedef ::o3tl::sorted_vector< RowRangeStyle, StyleRowRangeComp > RowStyles; diff --git a/sc/source/filter/oox/sheetdatabuffer.cxx b/sc/source/filter/oox/sheetdatabuffer.cxx index 6dbec9e6bd9d..259e3190107b 100644 --- a/sc/source/filter/oox/sheetdatabuffer.cxx +++ b/sc/source/filter/oox/sheetdatabuffer.cxx @@ -409,8 +409,6 @@ void SheetDataBuffer::addColXfStyleProcessRowRanges() RowRangeStyle aStyleRows; aStyleRows.mnNumFmt.first = nXfId; aStyleRows.mnNumFmt.second = -1; - aStyleRows.mnStartRow = rRange.mnFirst; - aStyleRows.mnEndRow = rRange.mnLast; // Reset row range for each column aStyleRows.mnStartRow = rRange.mnFirst; commit e6abff6c96f5b429f8da5ff0db173cbda558c69b Author: Luboš Luňák <l.lu...@centrum.cz> AuthorDate: Mon Feb 28 04:02:14 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:16:54 2022 +0200 set LO_TESTNAME on startup on all platforms c0b1d1bf5701d5f94b618f70da8e863d32d97ab4 did this only for UNX for no apparent reason. Solves CppunitTest_sc_tablecolumnsobj asserting on it not being set. Change-Id: Ia9484e5c90bef18450addcf9429f9a27d575c3b4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131631 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sal/cppunittester/cppunittester.cxx b/sal/cppunittester/cppunittester.cxx index 5b886ea2189d..f75caccbc143 100644 --- a/sal/cppunittester/cppunittester.cxx +++ b/sal/cppunittester/cppunittester.cxx @@ -301,9 +301,12 @@ public: EyecatcherListener eye; result.addListener(&eye); -#ifdef UNX + // set this to track down files created before first test method std::string lib = testlib.substr(testlib.rfind('/')+1); +#ifdef WIN32 + _putenv_s("LO_TESTNAME", lib.c_str()); +#else setenv("LO_TESTNAME", lib.c_str(), true); #endif const char* pVal = getenv("CPPUNIT_TEST_NAME"); commit 52f7a58330296fa6b2cf678c7cf0e943d8214e49 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Mar 11 17:43:41 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:16:46 2022 +0200 allocate column in ScTable::SetPatternAreaCondFormat() (tdf#147894) Change-Id: Id14bb20ef5e49551cef5216b5149e3c281c04223 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131389 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 9142ae62aba7..642b78f1c94d 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -2967,7 +2967,7 @@ void ScTable::RemoveCondFormatData( const ScRangeList& rRangeList, sal_uInt32 nI void ScTable::SetPatternAreaCondFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rAttr, const ScCondFormatIndexes& rCondFormatIndexes ) { - aCol[nCol].SetPatternArea( nStartRow, nEndRow, rAttr); + CreateColumnIfNotExists(nCol).SetPatternArea( nStartRow, nEndRow, rAttr); for (const auto& rIndex : rCondFormatIndexes) { commit 754f7e8b234d91e69b3ffc39faf2aab31bc448ac Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Mar 11 09:56:20 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:16:37 2022 +0200 fix comparison operators It seems the ranges are always distinct, so the < comparison always worked in practice, but the == comparison added by my 6810aa937caca1 is obviously incorrect. Change-Id: Ib7fcd36b5956901265248b34a4dc69e587cebe41 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131340 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/source/filter/inc/sheetdatabuffer.hxx b/sc/source/filter/inc/sheetdatabuffer.hxx index 8002e6ee93f9..33366fde9f9e 100644 --- a/sc/source/filter/inc/sheetdatabuffer.hxx +++ b/sc/source/filter/inc/sheetdatabuffer.hxx @@ -199,14 +199,14 @@ private: { bool operator() (const RowRangeStyle& lhs, const RowRangeStyle& rhs) const { - return lhs.mnEndRow<rhs.mnStartRow; + return lhs.mnStartRow<rhs.mnStartRow; } }; struct StyleRowRangeCompEqual { bool operator() (const RowRangeStyle& lhs, const RowRangeStyle& rhs) const { - return lhs.mnEndRow==rhs.mnStartRow; + return lhs.mnStartRow==rhs.mnStartRow; } }; typedef ::o3tl::sorted_vector< RowRangeStyle, StyleRowRangeComp > RowStyles; commit f61c4b9eb55ecf7d354c58d2ca4753ee33d69f77 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Fri Mar 11 08:49:17 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:16:29 2022 +0200 make svx::frame::Style ctor inline ScDocument: :FillInfo() may result in calling it often. Change-Id: I05d0582befc57c4959c33fae6dec3d340b8a49ba Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131338 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx index 2ee2a6f556e0..ae35185a4eb6 100644 --- a/include/svx/framelink.hxx +++ b/include/svx/framelink.hxx @@ -167,6 +167,17 @@ public: inline bool operator>( const Style& rL, const Style& rR ) { return rR.operator<(rL); } +inline Style::Style() + : mfPrim(0) + , mfDist(0) + , mfSecn(0) + , mfPatternScale(1.0) + , meRefMode(RefMode::Centered) + , mnType(SvxBorderLineStyle::SOLID) + , mbWordTableCell(false) + , mbUseGapColor(false) +{} + } diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx index 6400eb33d8b0..77098bd3e80d 100644 --- a/svx/source/dialog/framelink.cxx +++ b/svx/source/dialog/framelink.cxx @@ -31,11 +31,6 @@ using namespace editeng; namespace svx::frame { -Style::Style() -{ - Clear(); -} - Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) { Clear(); commit 8113cc4aac983d0b04df765efa630d1f8c9dbace Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Thu Mar 10 15:03:25 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:16:21 2022 +0200 load ods/xlsx with full row attributes without allocating all columns If there's e.g. an entire row bold, it's enough to set default attribute for unallocated columns. This also reverts the workaround from commit 297ab561c6754, as it's no longer necessary. Change-Id: I0b208709aeaff1c0d59da2410926876715cfe642 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131320 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/compilerplugins/clang/redundantfcast.cxx b/compilerplugins/clang/redundantfcast.cxx index 67ff2c56edef..2cfe5183ed46 100644 --- a/compilerplugins/clang/redundantfcast.cxx +++ b/compilerplugins/clang/redundantfcast.cxx @@ -329,7 +329,8 @@ public: if (fn == SRCDIR "/bridges/source/jni_uno/jni_bridge.cxx") return false; // TODO constructing a temporary to pass to a && param - if (fn == SRCDIR "/sc/source/ui/view/viewfunc.cxx") + if (fn == SRCDIR "/sc/source/ui/view/viewfunc.cxx" + || fn == SRCDIR "/sc/source/core/data/table2.cxx") return false; // tdf#145203: FIREBIRD cannot create a table if (fn == SRCDIR "/connectivity/source/drivers/firebird/DatabaseMetaData.cxx") diff --git a/sc/inc/attarray.hxx b/sc/inc/attarray.hxx index 34d1403bcc91..f4028b844c62 100644 --- a/sc/inc/attarray.hxx +++ b/sc/inc/attarray.hxx @@ -82,6 +82,10 @@ struct ScAttrEntry { SCROW nEndRow; const ScPatternAttr* pPattern; + bool operator==( const ScAttrEntry& other ) const + { + return nEndRow == other.nEndRow && pPattern == other.pPattern; + } }; class ScAttrArray diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 3fafb4adedca..1361ba514f2e 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -140,6 +140,8 @@ public: return static_cast<const T&>(GetAttr(nRow, sal_uInt16(nWhich), nStartRow, nEndRow)); } + void SetAttrEntries(std::vector<ScAttrEntry> && vNewData); + const ScPatternAttr* GetPattern( SCROW nRow ) const; const ScPatternAttr* GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const; SCROW ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark, ScEditDataArray* pDataArray, bool* const pIsChanged, @@ -1020,4 +1022,9 @@ inline void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow, pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, true/*bPutToPool*/ ); } +inline void ScColumnData::SetAttrEntries(std::vector<ScAttrEntry> && vNewData) +{ + pAttrArray->SetAttrEntries( std::move( vNewData )); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/inc/documentimport.hxx b/sc/inc/documentimport.hxx index 0e49e073fd62..c5b8cf5d5a62 100644 --- a/sc/inc/documentimport.hxx +++ b/sc/inc/documentimport.hxx @@ -53,6 +53,11 @@ public: ~Attrs(); Attrs& operator=( Attrs const & ) = delete; // MSVC2015 workaround Attrs( Attrs const & ) = delete; // MSVC2015 workaround + bool operator==(const Attrs& other) const + { + return mvData == other.mvData && mbLatinNumFmtOnly == other.mbLatinNumFmtOnly; + } + Attrs& operator=( Attrs&& attrs ) = default; }; ScDocumentImport() = delete; @@ -115,11 +120,11 @@ public: void fillDownCells(const ScAddress& rPos, SCROW nFillSize); /** - * Set an array of cell attributes to specified column. This call + * Set an array of cell attributes to specified range of columns. This call * transfers the ownership of the ScAttrEntry array from the caller to the * column. */ - void setAttrEntries( SCTAB nTab, SCCOL nCol, Attrs&& rAttrs ); + void setAttrEntries( SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, Attrs&& rAttrs ); void setRowsVisible(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, bool bVisible); diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index d9479117bfee..55321c6965ea 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -749,6 +749,7 @@ public: void ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScPatternAttr& rAttr, ScEditDataArray* pDataArray = nullptr, bool* const pIsChanged = nullptr ); + void SetAttrEntries( SCCOL nStartCol, SCCOL nEndCol, std::vector<ScAttrEntry> && vNewData); void SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr ); const ScPatternAttr* SetPattern( SCCOL nCol, SCROW nRow, std::unique_ptr<ScPatternAttr> ); diff --git a/sc/qa/unit/subsequent_export_test2.cxx b/sc/qa/unit/subsequent_export_test2.cxx index 50ca9ddba05a..ad3f125db7d9 100644 --- a/sc/qa/unit/subsequent_export_test2.cxx +++ b/sc/qa/unit/subsequent_export_test2.cxx @@ -3096,7 +3096,7 @@ void ScExportTest2::testWholeRowBold() ScDocShellRef xDocSh2 = saveAndReload(*xDocSh1, FORMAT_ODS); CPPUNIT_ASSERT(xDocSh2.is()); pDoc = &xDocSh2->GetDocument(); - // TODO CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), pDoc->GetAllocatedColumnsCount(0)); + CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), pDoc->GetAllocatedColumnsCount(0)); vcl::Font aFont; pDoc->GetPattern(pDoc->MaxCol(), 1, 0)->GetFont(aFont, SC_AUTOCOL_RAW); CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD, aFont.GetWeight()); @@ -3104,7 +3104,7 @@ void ScExportTest2::testWholeRowBold() ScDocShellRef xDocSh3 = saveAndReload(*xDocSh2, FORMAT_XLSX); CPPUNIT_ASSERT(xDocSh3.is()); pDoc = &xDocSh3->GetDocument(); - // TODO CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), pDoc->GetAllocatedColumnsCount(0)); + CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), pDoc->GetAllocatedColumnsCount(0)); pDoc->GetPattern(pDoc->MaxCol(), 1, 0)->GetFont(aFont, SC_AUTOCOL_RAW); CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD, aFont.GetWeight()); diff --git a/sc/source/core/data/documentimport.cxx b/sc/source/core/data/documentimport.cxx index d47d50a4cb35..87a14416925b 100644 --- a/sc/source/core/data/documentimport.cxx +++ b/sc/source/core/data/documentimport.cxx @@ -593,21 +593,20 @@ void ScDocumentImport::fillDownCells(const ScAddress& rPos, SCROW nFillSize) } } -void ScDocumentImport::setAttrEntries( SCTAB nTab, SCCOL nCol, Attrs&& rAttrs ) +void ScDocumentImport::setAttrEntries( SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, Attrs&& rAttrs ) { ScTable* pTab = mpImpl->mrDoc.FetchTable(nTab); if (!pTab) return; - ScColumn* pCol = pTab->FetchColumn(nCol); - if (!pCol) - return; - - ColAttr* pColAttr = mpImpl->getColAttr(nTab, nCol); - if (pColAttr) - pColAttr->mbLatinNumFmtOnly = rAttrs.mbLatinNumFmtOnly; + for(SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol ) + { + ColAttr* pColAttr = mpImpl->getColAttr(nTab, nCol); + if (pColAttr) + pColAttr->mbLatinNumFmtOnly = rAttrs.mbLatinNumFmtOnly; + } - pCol->pAttrArray->SetAttrEntries(std::move(rAttrs.mvData)); + pTab->SetAttrEntries( nColStart, nColEnd, std::move( rAttrs.mvData )); } void ScDocumentImport::setRowsVisible(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, bool bVisible) diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index cada997f556a..9142ae62aba7 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -2889,6 +2889,37 @@ void ScTable::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, CreateColumnIfNotExists(i).ApplyPatternArea(nStartRow, nEndRow, rAttr, pDataArray, pIsChanged); } +void ScTable::SetAttrEntries( SCCOL nStartCol, SCCOL nEndCol, std::vector<ScAttrEntry> && vNewData) +{ + if (!ValidCol(nStartCol) || !ValidCol(nEndCol)) + return; + if ( nEndCol == rDocument.MaxCol() ) + { + if ( nStartCol < aCol.size() ) + { + // If we would like set all columns to same attrs, then change only attrs for not existing columns + nEndCol = aCol.size() - 1; + for (SCCOL i = nStartCol; i <= nEndCol; i++) + aCol[i].SetAttrEntries( std::vector<ScAttrEntry>(vNewData)); + aDefaultColData.SetAttrEntries(std::move(vNewData)); + } + else + { + CreateColumnIfNotExists( nStartCol - 1 ); + aDefaultColData.SetAttrEntries(std::move(vNewData)); + } + } + else + { + CreateColumnIfNotExists( nEndCol ); + for (SCCOL i = nStartCol; i < nEndCol; i++) // all but last need a copy + aCol[i].SetAttrEntries( std::vector<ScAttrEntry>(vNewData)); + aCol[nEndCol].SetAttrEntries( std::move(vNewData)); + } +} + + + void ScTable::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange, const ScPatternAttr& rPattern, SvNumFormatType nNewType ) { diff --git a/sc/source/filter/excel/xistyle.cxx b/sc/source/filter/excel/xistyle.cxx index 4161d47a94df..c556b51ec602 100644 --- a/sc/source/filter/excel/xistyle.cxx +++ b/sc/source/filter/excel/xistyle.cxx @@ -1989,6 +1989,9 @@ void XclImpXFRangeBuffer::Finalize() // apply patterns XclImpXFBuffer& rXFBuffer = GetXFBuffer(); + ScDocumentImport::Attrs aPendingAttrParam; + SCCOL pendingColStart = -1; + SCCOL pendingColEnd = -1; SCCOL nScCol = 0; for( const auto& rxColumn : maColumns ) { @@ -2026,10 +2029,22 @@ void XclImpXFRangeBuffer::Finalize() ScDocumentImport::Attrs aAttrParam; aAttrParam.mvData.swap(aAttrs); aAttrParam.mbLatinNumFmtOnly = false; // when unsure, set it to false. - rDocImport.setAttrEntries(nScTab, nScCol, std::move(aAttrParam)); + + // Compress setting the attributes, set the same set in one call. + if( pendingColStart != -1 && pendingColEnd == nScCol - 1 && aAttrParam == aPendingAttrParam ) + ++pendingColEnd; + else + { + if( pendingColStart != -1 ) + rDocImport.setAttrEntries(nScTab, pendingColStart, pendingColEnd, std::move(aPendingAttrParam)); + pendingColStart = pendingColEnd = nScCol; + aPendingAttrParam = std::move( aAttrParam ); + } } ++nScCol; } + if( pendingColStart != -1 ) + rDocImport.setAttrEntries(nScTab, pendingColStart, pendingColEnd, std::move(aPendingAttrParam)); // insert hyperlink cells for( const auto& [rXclRange, rUrl] : maHyperlinks ) diff --git a/sc/source/filter/oox/sheetdatabuffer.cxx b/sc/source/filter/oox/sheetdatabuffer.cxx index b4d6158f66fe..6dbec9e6bd9d 100644 --- a/sc/source/filter/oox/sheetdatabuffer.cxx +++ b/sc/source/filter/oox/sheetdatabuffer.cxx @@ -482,6 +482,9 @@ void SheetDataBuffer::finalizeImport() ScDocument& rDoc = rDocImport.getDoc(); StylesBuffer& rStyles = getStyles(); + ScDocumentImport::Attrs aPendingAttrParam; + SCCOL pendingColStart = -1; + SCCOL pendingColEnd = -1; for ( const auto& [rCol, rRowStyles] : maStylesPerColumn ) { SCCOL nScCol = static_cast< SCCOL >( rCol ); @@ -529,8 +532,19 @@ void SheetDataBuffer::finalizeImport() aAttrParam.mvData.swap(aAttrs.maAttrs); aAttrParam.mbLatinNumFmtOnly = aAttrs.mbLatinNumFmtOnly; - rDocImport.setAttrEntries(getSheetIndex(), nScCol, std::move(aAttrParam)); + // Compress setting the attributes, set the same set in one call. + if( pendingColStart != -1 && pendingColEnd == nScCol - 1 && aAttrParam == aPendingAttrParam ) + ++pendingColEnd; + else + { + if( pendingColStart != -1 ) + rDocImport.setAttrEntries(getSheetIndex(), pendingColStart, pendingColEnd, std::move(aPendingAttrParam)); + pendingColStart = pendingColEnd = nScCol; + aPendingAttrParam = std::move( aAttrParam ); + } } + if( pendingColStart != -1 ) + rDocImport.setAttrEntries(getSheetIndex(), pendingColStart, pendingColEnd, std::move(aPendingAttrParam)); // merge all cached merged ranges and update right/bottom cell borders for( const auto& rMergedRange : maMergedRanges ) diff --git a/sc/source/filter/xml/xmlcoli.cxx b/sc/source/filter/xml/xmlcoli.cxx index 00514f830305..502690fe2f03 100644 --- a/sc/source/filter/xml/xmlcoli.cxx +++ b/sc/source/filter/xml/xmlcoli.cxx @@ -93,7 +93,6 @@ void SAL_CALL ScXMLTableColContext::endFastElement( sal_Int32 /*nElement*/ ) nLastColumn = pDoc->MaxCol(); if (nCurrentColumn > pDoc->MaxCol()) nCurrentColumn = pDoc->MaxCol(); - pDoc->CreateColumnIfNotExists(nSheet, nLastColumn); uno::Reference<table::XColumnRowRange> xColumnRowRange (xSheet->getCellRangeByPosition(nCurrentColumn, 0, nLastColumn, 0), uno::UNO_QUERY); if (xColumnRowRange.is()) { commit 7252170e4e1ea7348b8c66022dcec8002541ea8e Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Thu Mar 10 18:00:28 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:16:12 2022 +0200 don't bother drawing zero-width cells If a document has most columns hidden, then they'd be "drawn" anyway, since ScGridWindow::Draw() calls ExtendHidden(), this appears to be needed in order to drawn properly background after the last cell. So at least try avoid zero-sized draw operations which may add up enough to be noticeable with 16k columns Change-Id: I631e3be7467f8ea2dbfb824e647f900a7573da61 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131326 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx index 279225079d79..82126f68fe1d 100644 --- a/sc/source/ui/view/output.cxx +++ b/sc/source/ui/view/output.cxx @@ -1093,6 +1093,27 @@ void ScOutputData::DrawBackground(vcl::RenderContext& rRenderContext) nOldMerged = nMergedCols; + tools::Long nNewPosX = nPosX; + // extend for all merged cells + nMergedCols = 1; + if (pInfo->bMerged && pInfo->pPatternAttr) + { + const ScMergeAttr* pMerge = + &pInfo->pPatternAttr->GetItem(ATTR_MERGE); + nMergedCols = std::max<SCCOL>(1, pMerge->GetColMerge()); + } + + for (SCCOL nMerged = 0; nMerged < nMergedCols; ++nMerged) + { + SCCOL nCol = nX+nOldMerged+nMerged; + if (nCol > nX2+2) + break; + nNewPosX += pRowInfo[0].basicCellInfo(nCol-1).nWidth * nLayoutSign; + } + + if (nNewPosX == nPosX) + continue; // Zero width, no need to draw. + if (bCellContrast) { // high contrast for cell borders and backgrounds -> empty background @@ -1136,22 +1157,7 @@ void ScOutputData::DrawBackground(vcl::RenderContext& rRenderContext) drawCells(rRenderContext, pColor, pBackground, pOldColor, pOldBackground, aRect, nPosXLogic, nLayoutSign, nOneXLogic, nOneYLogic, pDataBarInfo, pOldDataBarInfo, pIconSetInfo, pOldIconSetInfo, mpDoc->GetIconSetBitmapMap()); - // extend for all merged cells - nMergedCols = 1; - if (pInfo->bMerged && pInfo->pPatternAttr) - { - const ScMergeAttr* pMerge = - &pInfo->pPatternAttr->GetItem(ATTR_MERGE); - nMergedCols = std::max<SCCOL>(1, pMerge->GetColMerge()); - } - - for (SCCOL nMerged = 0; nMerged < nMergedCols; ++nMerged) - { - SCCOL nCol = nX+nOldMerged+nMerged; - if (nCol > nX2+2) - break; - nPosX += pRowInfo[0].basicCellInfo(nCol-1).nWidth * nLayoutSign; - } + nPosX = nNewPosX; } tools::Long nPosXLogic = nPosX; commit 76a5b2109a4638c9151af1b8462bea1548d61be6 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Thu Mar 10 16:40:26 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:16:04 2022 +0200 optimize searching for last visible row If all the remaining rows until the end of the sheet are hidden (which apparently some users do to make the sheet look "nicer"), don't search all the rows one by one. Change-Id: I5f7ef61ece62f7858d4d8cfdf53bb514daa5b504 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131323 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/source/ui/view/tabview.cxx b/sc/source/ui/view/tabview.cxx index 5862d87a8fa0..523044c7531a 100644 --- a/sc/source/ui/view/tabview.cxx +++ b/sc/source/ui/view/tabview.cxx @@ -1330,15 +1330,15 @@ namespace SCROW lcl_LastVisible( const ScViewData& rViewData ) { - // If many rows are hidden at end of the document (what kind of idiot does that?), + // If many rows are hidden at end of the document, // then there should not be a switch to wide row headers because of this - //! as a member to the document??? ScDocument& rDoc = rViewData.GetDocument(); SCTAB nTab = rViewData.GetTabNo(); SCROW nVis = rDoc.MaxRow(); - while ( nVis > 0 && rDoc.GetRowHeight( nVis, nTab ) == 0 ) - --nVis; + SCROW startRow; + while ( nVis > 0 && rDoc.GetRowHeight( nVis, nTab, &startRow, nullptr ) == 0 ) + nVis = std::max<SCROW>( startRow - 1, 0 ); return nVis; } commit c99a6bf0adb9390f2dd34bf5dee4b1a21e9ae067 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Tue Apr 12 15:19:38 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:15:56 2022 +0200 don't ignore GetDefPattern() in ScHorizontalAttrIterator As said in the previous commit, the default pattern is the default style that can be edited by the user, so it's principially incorrect to simply ignore it. If needed for performance, then it needs to be done explicitly. This change currently should not affect anything, as ScHorizontalAttrIterator is used only in tests. Change-Id: I31f153d427cdfd6e98a4d7a3584cfa89676d4c33 diff --git a/sc/inc/dociter.hxx b/sc/inc/dociter.hxx index 2aee6ac950c1..99ceb1e99972 100644 --- a/sc/inc/dociter.hxx +++ b/sc/inc/dociter.hxx @@ -499,8 +499,6 @@ public: bool GetNext( double& rValue, FormulaError& rErr ); }; -// returns all areas with non-default formatting (horizontal) - class ScHorizontalAttrIterator { private: @@ -518,11 +516,9 @@ private: ppPatterns; SCCOL nCol; SCROW nRow; - bool bRowEmpty; SCROW nMinNextEnd; void InitForNextRow(bool bInitialization); - bool InitForNextAttr(); public: ScHorizontalAttrIterator( ScDocument& rDocument, SCTAB nTable, diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index 814bc4b77d1b..8323ca310298 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -147,6 +147,7 @@ public: void testValueIterator(); void testHorizontalAttrIterator(); void testIteratorsUnallocatedColumnsAttributes(); + void testIteratorsDefPattern(); /** * More direct test for cell broadcaster management, used to track formula @@ -278,6 +279,7 @@ public: CPPUNIT_TEST(testValueIterator); CPPUNIT_TEST(testHorizontalAttrIterator); CPPUNIT_TEST(testIteratorsUnallocatedColumnsAttributes); + CPPUNIT_TEST(testIteratorsDefPattern); CPPUNIT_TEST(testCellBroadcaster); CPPUNIT_TEST(testFuncParam); CPPUNIT_TEST(testNamedRange); @@ -1388,12 +1390,15 @@ void Test::testHorizontalAttrIterator() SCCOL nCol1, nCol2; SCROW nRow; size_t nCheckPos = 0; - for (const ScPatternAttr* pAttr = aIter.GetNext(nCol1, nCol2, nRow); pAttr; pAttr = aIter.GetNext(nCol1, nCol2, nRow), ++nCheckPos) + for (const ScPatternAttr* pAttr = aIter.GetNext(nCol1, nCol2, nRow); pAttr; pAttr = aIter.GetNext(nCol1, nCol2, nRow)) { - CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos < nCheckLen); - CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][0], static_cast<int>(nCol1)); - CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][1], static_cast<int>(nCol2)); - CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][2], static_cast<int>(nRow)); + if( pAttr == m_pDoc->GetDefPattern()) + continue; + CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos < nCheckLen); + CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][0], static_cast<int>(nCol1)); + CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][1], static_cast<int>(nCol2)); + CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][2], static_cast<int>(nRow)); + ++nCheckPos; } } @@ -1452,6 +1457,56 @@ void Test::testIteratorsUnallocatedColumnsAttributes() m_pDoc->DeleteTab(0); } +void Test::testIteratorsDefPattern() +{ + m_pDoc->InsertTab(0, "Tab1"); + + // The default pattern is the default style, which can be edited by the user. + // As such iterators should not ignore it by default, because it might contain + // some attributes set. + + // Set cells as bold, default allocated, bold, default unallocated. + SCCOL firstCol = 100; + SCCOL lastCol = 103; + ScPatternAttr boldAttr(m_pDoc->GetPool()); + boldAttr.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD, ATTR_FONT_WEIGHT)); + m_pDoc->ApplyPattern(100, 0, 0, boldAttr); + m_pDoc->ApplyPattern(102, 0, 0, boldAttr); + + CPPUNIT_ASSERT_EQUAL(SCCOL(102 + 1), m_pDoc->GetAllocatedColumnsCount(0)); + const ScPatternAttr* pattern = m_pDoc->GetPattern(100, 0, 0); + CPPUNIT_ASSERT(pattern != m_pDoc->GetDefPattern()); + CPPUNIT_ASSERT(m_pDoc->GetPattern(102, 0, 0) == pattern); + CPPUNIT_ASSERT(m_pDoc->GetPattern(101, 0, 0) == m_pDoc->GetDefPattern()); + CPPUNIT_ASSERT(m_pDoc->GetPattern(103, 0, 0) == m_pDoc->GetDefPattern()); + + // Test iterators. + ScDocAttrIterator docit( *m_pDoc, 0, firstCol, 0, lastCol, 0 ); + SCCOL col1, col2; + SCROW row1, row2; + CPPUNIT_ASSERT( docit.GetNext( col1, row1, row2 ) == pattern); + CPPUNIT_ASSERT( docit.GetNext( col1, row1, row2 ) == m_pDoc->GetDefPattern()); + CPPUNIT_ASSERT( docit.GetNext( col1, row1, row2 ) == pattern); + CPPUNIT_ASSERT( docit.GetNext( col1, row1, row2 ) == m_pDoc->GetDefPattern()); + CPPUNIT_ASSERT( docit.GetNext( col1, row1, row2 ) == nullptr ); + + ScAttrRectIterator rectit( *m_pDoc, 0, firstCol, 0, lastCol, 0 ); + CPPUNIT_ASSERT( rectit.GetNext( col1, col2, row1, row2 ) == pattern); + CPPUNIT_ASSERT( rectit.GetNext( col1, col2, row1, row2 ) == m_pDoc->GetDefPattern()); + CPPUNIT_ASSERT( rectit.GetNext( col1, col2, row1, row2 ) == pattern); + CPPUNIT_ASSERT( rectit.GetNext( col1, col2, row1, row2 ) == m_pDoc->GetDefPattern()); + CPPUNIT_ASSERT( rectit.GetNext( col1, col2, row1, row2 ) == nullptr ); + + ScHorizontalAttrIterator horit( *m_pDoc, 0, firstCol, 0, lastCol, 0 ); + CPPUNIT_ASSERT( horit.GetNext( col1, col2, row1 ) == pattern); + CPPUNIT_ASSERT( horit.GetNext( col1, col2, row1 ) == m_pDoc->GetDefPattern()); + CPPUNIT_ASSERT( horit.GetNext( col1, col2, row1 ) == pattern); + CPPUNIT_ASSERT( horit.GetNext( col1, col2, row1 ) == m_pDoc->GetDefPattern()); + CPPUNIT_ASSERT( horit.GetNext( col1, col2, row1 ) == nullptr ); + + m_pDoc->DeleteTab(0); +} + namespace { bool broadcasterShifted(const ScDocument& rDoc, const ScAddress& rFrom, const ScAddress& rTo) diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx index 6bb47df2a9d8..01583d570d63 100644 --- a/sc/source/core/data/dociter.cxx +++ b/sc/source/core/data/dociter.cxx @@ -2396,7 +2396,6 @@ ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument& rDocument, SCTAB nRow = nStartRow; nCol = nStartCol; - bRowEmpty = false; pIndices.reset( new SCSIZE[nEndCol-nStartCol+1] ); pNextEnd.reset( new SCROW[nEndCol-nStartCol+1] ); @@ -2412,7 +2411,6 @@ ScHorizontalAttrIterator::~ScHorizontalAttrIterator() void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization) { - bool bEmpty = true; nMinNextEnd = rDoc.MaxRow(); SCCOL nThisHead = 0; @@ -2440,18 +2438,12 @@ void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization) { pNextEnd[nPos] = rDoc.MaxRow(); assert( pNextEnd[nPos] >= nRow && "Sequence out of order" ); - ppPatterns[nPos] = nullptr; + ppPatterns[nPos] = rDoc.GetDefPattern(); } else if ( nIndex < pArray.Count() ) { const ScPatternAttr* pPattern = pArray.mvData[nIndex].pPattern; SCROW nThisEnd = pArray.mvData[nIndex].nEndRow; - - if ( IsDefaultItem( pPattern ) ) - pPattern = nullptr; - else - bEmpty = false; // Found attributes - pNextEnd[nPos] = nThisEnd; assert( pNextEnd[nPos] >= nRow && "Sequence out of order" ); ppPatterns[nPos] = pPattern; @@ -2463,8 +2455,6 @@ void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization) ppPatterns[nPos] = nullptr; } } - else if ( ppPatterns[nPos] ) - bEmpty = false; // Area not at the end yet if ( nMinNextEnd > pNextEnd[nPos] ) nMinNextEnd = pNextEnd[nPos]; @@ -2477,24 +2467,7 @@ void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization) } } - if (bEmpty) - nRow = nMinNextEnd; // Skip until end of next section - else - pHorizEnd[nThisHead] = nEndCol; // set the end position of the last horizontal group, too - bRowEmpty = bEmpty; -} - -bool ScHorizontalAttrIterator::InitForNextAttr() -{ - if ( !ppPatterns[nCol-nStartCol] ) // Skip default items - { - assert( pHorizEnd[nCol-nStartCol] < rDoc.MaxCol()+1 && "missing stored data" ); - nCol = pHorizEnd[nCol-nStartCol] + 1; - if ( nCol > nEndCol ) - return false; - } - - return true; + pHorizEnd[nThisHead] = nEndCol; // set the end position of the last horizontal group, too } const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow ) @@ -2502,7 +2475,7 @@ const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCo assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT"); for (;;) { - if ( !bRowEmpty && nCol <= nEndCol && InitForNextAttr() ) + if ( nCol <= nEndCol ) { const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol]; rRow = nRow; @@ -2520,7 +2493,7 @@ const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCo return nullptr; // Found nothing nCol = nStartCol; // Start at the left again - if ( bRowEmpty || nRow > nMinNextEnd ) + if ( nRow > nMinNextEnd ) InitForNextRow(false); } } commit cb185c0a7f079ba4ce945c30e6823d377dc97954 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Tue Apr 12 14:58:33 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:15:49 2022 +0200 don't artificially clamp attribute iterators range Even ScDocument::GetDefPattern() can be modified by the user (it's the default style that can be edited), so it's conceptually incorrect to ignore it while iterating, and clamping to allocated columns is also no longer needed. If this makes some code slow, then that needs explicit handling in that code or some other way of speeding things up. Change-Id: I4a7c7fef0a8625b559bbce4580df19a5e9ed92a7 diff --git a/sc/inc/attarray.hxx b/sc/inc/attarray.hxx index c08da494c142..34d1403bcc91 100644 --- a/sc/inc/attarray.hxx +++ b/sc/inc/attarray.hxx @@ -221,7 +221,6 @@ public: bool Reserve( SCSIZE nReserve ); SCSIZE Count() const { return mvData.size(); } SCSIZE Count( SCROW nRow1, SCROW nRow2 ) const; - bool HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const; private: const ScPatternAttr* SetPatternAreaImpl( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr* pPattern, diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index e8a90cbd1f77..3fafb4adedca 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -164,7 +164,6 @@ public: std::unique_ptr<ScAttrIterator> CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const; bool IsAllAttrEqual( const ScColumnData& rCol, SCROW nStartRow, SCROW nEndRow ) const; - bool HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const; void ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark, SCCOL nCol ); void ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark, SCCOL nCol ); @@ -858,11 +857,6 @@ inline bool ScColumnData::IsAllAttrEqual( const ScColumnData& rCol, SCROW nStart return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow ); } -inline bool ScColumnData::HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const -{ - return pAttrArray->HasNonDefPattern( nStartRow, nEndRow ); -} - inline bool ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const { return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow ); diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index f2f0ab196fa7..d9e9b22be9f6 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -819,15 +819,6 @@ public: SC_DLLPUBLIC SCCOL ClampToAllocatedColumns(SCTAB nTab, SCCOL nCol) const; SC_DLLPUBLIC SCCOL GetAllocatedColumnsCount(SCTAB nTab) const; - // Limits nCol to the last column that can possibly have a non-default pattern. The purpose - // is to avoid checking unallocated columns if they don't have attributes set, so this is - // never less than ClampToAllocatedColumns(). - SCCOL ClampToMaxNonDefPatternColumn(SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2) const; - SCCOL ClampToMaxNonDefPatternColumn(SCTAB nTab, SCCOL nCol) const - { return ClampToMaxNonDefPatternColumn(nTab, nCol, 0, MaxRow()); } - SCCOL GetMaxNonDefPatternColumnsCount(SCTAB nTab, SCROW nRow1, SCROW nRow2) const; - SCCOL GetMaxNonDefPatternColumnsCount(SCTAB nTab) const - { return GetMaxNonDefPatternColumnsCount(nTab, 0, MaxRow()); } SC_DLLPUBLIC ScDBCollection* GetDBCollection() const { return pDBCollection.get();} void SetDBCollection( std::unique_ptr<ScDBCollection> pNewDBCollection, diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index e39a921a0926..d9479117bfee 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -1113,12 +1113,6 @@ public: 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(); } - SCCOL ClampToMaxNonDefPatternColumn(SCCOL nCol, SCROW nRow1, SCROW nRow2) const; - SCCOL ClampToMaxNonDefPatternColumn(SCCOL nCol) const - { return ClampToMaxNonDefPatternColumn(nCol, 0, rDocument.MaxRow()); } - SCCOL GetMaxNonDefPatternColumnsCount(SCROW nRow1, SCROW nRow2) const; - SCCOL GetMaxNonDefPatternColumnsCount() const - { return GetMaxNonDefPatternColumnsCount(0, rDocument.MaxRow()); } /** * Serializes the sheet's geometry data. diff --git a/sc/source/core/data/attarray.cxx b/sc/source/core/data/attarray.cxx index e74edd94a434..5af0e3b3609d 100644 --- a/sc/source/core/data/attarray.cxx +++ b/sc/source/core/data/attarray.cxx @@ -2689,24 +2689,4 @@ SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow ) const return nIndex2 - nIndex1 + 1; } -bool ScAttrArray::HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const -{ - if ( mvData.empty() ) - return false; - - SCSIZE nIndex1, nIndex2; - - if( !Search( nStartRow, nIndex1 ) ) - return false; - - if( !Search( nEndRow, nIndex2 ) ) - nIndex2 = mvData.size() - 1; - - const ScPatternAttr* defPattern = rDocument.GetDefPattern(); - for( SCSIZE index = nIndex1; index <= nIndex2; ++index ) - if( mvData[index].pPattern != defPattern ) - return true; - return false; -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx index 35148072f387..6bb47df2a9d8 100644 --- a/sc/source/core/data/dociter.cxx +++ b/sc/source/core/data/dociter.cxx @@ -2394,8 +2394,6 @@ ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument& rDocument, SCTAB assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT"); assert(rDoc.maTabs[nTab]); - nEndCol = rDoc.maTabs[nTab]->ClampToMaxNonDefPatternColumn(nEndCol); - nRow = nStartRow; nCol = nStartCol; bRowEmpty = false; @@ -2644,14 +2642,7 @@ ScDocAttrIterator::ScDocAttrIterator(ScDocument& rDocument, SCTAB nTable, nCol( nCol1 ) { if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab] ) - { - SCCOL attrColCount = rDoc.maTabs[nTab]->GetMaxNonDefPatternColumnsCount(nStartRow, nEndRow); - if( nCol < attrColCount ) - { - nEndCol = std::min<SCCOL>(nEndCol,attrColCount - 1); - pColIter = rDoc.maTabs[nTab]->ColumnData(nCol).CreateAttrIterator( nStartRow, nEndRow ); - } - } + pColIter = rDoc.maTabs[nTab]->ColumnData(nCol).CreateAttrIterator( nStartRow, nEndRow ); } ScDocAttrIterator::~ScDocAttrIterator() @@ -2780,16 +2771,11 @@ ScAttrRectIterator::ScAttrRectIterator(ScDocument& rDocument, SCTAB nTable, { if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab] ) { - SCCOL attrColCount = rDoc.maTabs[nTab]->GetMaxNonDefPatternColumnsCount(nStartRow, nEndRow); - if( nCol1 < attrColCount ) - { - nEndCol = std::min<SCCOL>(nEndCol,attrColCount - 1); - pColIter = rDoc.maTabs[nTab]->ColumnData(nIterStartCol).CreateAttrIterator( nStartRow, nEndRow ); - while ( nIterEndCol < nEndCol && - rDoc.maTabs[nTab]->ColumnData(nIterEndCol).IsAllAttrEqual( - rDoc.maTabs[nTab]->ColumnData(nIterEndCol+1), nStartRow, nEndRow ) ) - ++nIterEndCol; - } + pColIter = rDoc.maTabs[nTab]->ColumnData(nIterStartCol).CreateAttrIterator( nStartRow, nEndRow ); + while ( nIterEndCol < nEndCol && + rDoc.maTabs[nTab]->ColumnData(nIterEndCol).IsAllAttrEqual( + rDoc.maTabs[nTab]->ColumnData(nIterEndCol+1), nStartRow, nEndRow ) ) + ++nIterEndCol; } } diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index d07d82716404..311a3756d817 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -2697,21 +2697,6 @@ ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const return ScColumnsRange(ScColumnsRange::Iterator(beginIter), ScColumnsRange::Iterator(endIter)); } -SCCOL ScTable::ClampToMaxNonDefPatternColumn(SCCOL nCol, SCROW nRow1, SCROW nRow2) const -{ - // The purpose so to avoid unallocated columns if possible, so don't check allocated ones. - if( nCol < GetAllocatedColumnsCount()) - return nCol; - return std::min<SCCOL>(nCol, GetMaxNonDefPatternColumnsCount( nRow1, nRow2 ) - 1 ); -} - -SCCOL ScTable::GetMaxNonDefPatternColumnsCount(SCROW nRow1, SCROW nRow2) const -{ - if( aDefaultColData.HasNonDefPattern(nRow1, nRow2)) - return GetDoc().GetMaxColCount(); - return GetAllocatedColumnsCount(); -} - // out-of-line the cold part of the CreateColumnIfNotExists function void ScTable::CreateColumnIfNotExistsImpl( const SCCOL nScCol ) const { commit 89a7c69589cdd533a4e359ae3c05fb3c733aff97 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Wed Mar 9 15:12:43 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:15:38 2022 +0200 fix attr iterators to walk even unallocated columns if needed Things like applying bold to an entire row no longer allocates all rows after my recent changes, but the attribute change is done in ScTable to the default attribute of unallocated columns. That means that clamping column positions to the end of allocated columns is no longer valid when handling attributes. Add functions that clamp depending on whether unallocated columns have a non-default attribute set. Change-Id: I879d0a034c0b336064361d0f8cb12e5a8da22b9c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131265 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/inc/attarray.hxx b/sc/inc/attarray.hxx index 34d1403bcc91..c08da494c142 100644 --- a/sc/inc/attarray.hxx +++ b/sc/inc/attarray.hxx @@ -221,6 +221,7 @@ public: bool Reserve( SCSIZE nReserve ); SCSIZE Count() const { return mvData.size(); } SCSIZE Count( SCROW nRow1, SCROW nRow2 ) const; + bool HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const; private: const ScPatternAttr* SetPatternAreaImpl( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr* pPattern, diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 23f7df5201bc..e8a90cbd1f77 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -161,6 +161,11 @@ public: bool HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) const; bool HasAttrib( SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow = nullptr, SCROW* nEndRow = nullptr ) const; + std::unique_ptr<ScAttrIterator> CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const; + + bool IsAllAttrEqual( const ScColumnData& rCol, SCROW nStartRow, SCROW nEndRow ) const; + bool HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const; + void ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark, SCCOL nCol ); void ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark, SCCOL nCol ); }; @@ -206,7 +211,6 @@ friend class ScCountIfCellIterator; friend class ScFormulaGroupIterator; friend class ScCellIterator; friend class ScHorizontalCellIterator; -friend class ScHorizontalAttrIterator; friend class ScColumnTextWidthIterator; friend class ScDocumentImport; friend class sc::DocumentStreamAccess; @@ -303,7 +307,6 @@ public: bool GetLastVisibleAttr( SCROW& rLastRow ) const; bool HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const; bool IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const; - bool IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const; bool TestInsertCol( SCROW nStartRow, SCROW nEndRow) const; bool TestInsertRow( SCROW nStartRow, SCSIZE nSize ) const; @@ -352,8 +355,6 @@ public: sc::MixDocContext& rCxt, SCROW nRow1, SCROW nRow2, ScPasteFunc nFunction, bool bSkipEmpty, const ScColumn& rSrcCol ); - std::unique_ptr<ScAttrIterator> CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const; - void UpdateSelectionFunction( const ScRangeList& rRanges, ScFunctionData& rData, const ScFlatBoolRowSegments& rHiddenRows ); @@ -852,11 +853,16 @@ inline bool ScColumn::IsEmptyAttr() const return pAttrArray->IsEmpty(); } -inline bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const +inline bool ScColumnData::IsAllAttrEqual( const ScColumnData& rCol, SCROW nStartRow, SCROW nEndRow ) const { return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow ); } +inline bool ScColumnData::HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const +{ + return pAttrArray->HasNonDefPattern( nStartRow, nEndRow ); +} + inline bool ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const { return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow ); diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index d9e9b22be9f6..f2f0ab196fa7 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -819,6 +819,15 @@ public: SC_DLLPUBLIC SCCOL ClampToAllocatedColumns(SCTAB nTab, SCCOL nCol) const; SC_DLLPUBLIC SCCOL GetAllocatedColumnsCount(SCTAB nTab) const; + // Limits nCol to the last column that can possibly have a non-default pattern. The purpose + // is to avoid checking unallocated columns if they don't have attributes set, so this is + // never less than ClampToAllocatedColumns(). + SCCOL ClampToMaxNonDefPatternColumn(SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2) const; + SCCOL ClampToMaxNonDefPatternColumn(SCTAB nTab, SCCOL nCol) const + { return ClampToMaxNonDefPatternColumn(nTab, nCol, 0, MaxRow()); } + SCCOL GetMaxNonDefPatternColumnsCount(SCTAB nTab, SCROW nRow1, SCROW nRow2) const; + SCCOL GetMaxNonDefPatternColumnsCount(SCTAB nTab) const + { return GetMaxNonDefPatternColumnsCount(nTab, 0, MaxRow()); } SC_DLLPUBLIC ScDBCollection* GetDBCollection() const { return pDBCollection.get();} void SetDBCollection( std::unique_ptr<ScDBCollection> pNewDBCollection, diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 80117ccf5f42..e39a921a0926 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -262,9 +262,6 @@ friend class ScCellIterator; friend class ScQueryCellIterator; friend class ScCountIfCellIterator; friend class ScHorizontalCellIterator; -friend class ScHorizontalAttrIterator; -friend class ScDocAttrIterator; -friend class ScAttrRectIterator; friend class ScColumnTextWidthIterator; friend class ScDocumentImport; friend class sc::DocumentStreamAccess; @@ -1116,6 +1113,12 @@ public: 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(); } + SCCOL ClampToMaxNonDefPatternColumn(SCCOL nCol, SCROW nRow1, SCROW nRow2) const; + SCCOL ClampToMaxNonDefPatternColumn(SCCOL nCol) const + { return ClampToMaxNonDefPatternColumn(nCol, 0, rDocument.MaxRow()); } + SCCOL GetMaxNonDefPatternColumnsCount(SCROW nRow1, SCROW nRow2) const; + SCCOL GetMaxNonDefPatternColumnsCount() const + { return GetMaxNonDefPatternColumnsCount(0, rDocument.MaxRow()); } /** * Serializes the sheet's geometry data. diff --git a/sc/qa/unit/subsequent_export_test2.cxx b/sc/qa/unit/subsequent_export_test2.cxx index 769a7f77a60c..50ca9ddba05a 100644 --- a/sc/qa/unit/subsequent_export_test2.cxx +++ b/sc/qa/unit/subsequent_export_test2.cxx @@ -216,6 +216,7 @@ public: void testTdf142578(); void testTdf145059(); void testTdf130104_XLSXIndent(); + void testWholeRowBold(); CPPUNIT_TEST_SUITE(ScExportTest2); @@ -331,6 +332,7 @@ public: CPPUNIT_TEST(testTdf142578); CPPUNIT_TEST(testTdf145059); CPPUNIT_TEST(testTdf130104_XLSXIndent); + CPPUNIT_TEST(testWholeRowBold); CPPUNIT_TEST_SUITE_END(); @@ -3080,6 +3082,37 @@ void ScExportTest2::testTdf130104_XLSXIndent() xDocSh->DoClose(); } +void ScExportTest2::testWholeRowBold() +{ + ScDocShellRef xDocSh1 = loadDoc(u"blank.", FORMAT_ODS); + CPPUNIT_ASSERT_MESSAGE("Failed to open empty doc", xDocSh1.is()); + ScDocument* pDoc = &xDocSh1->GetDocument(); + + // Make entire second row row bold. + ScPatternAttr boldAttr(pDoc->GetPool()); + boldAttr.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD, ATTR_FONT_WEIGHT)); + pDoc->ApplyPatternAreaTab(0, 1, pDoc->MaxCol(), 1, 0, boldAttr); + + ScDocShellRef xDocSh2 = saveAndReload(*xDocSh1, FORMAT_ODS); + CPPUNIT_ASSERT(xDocSh2.is()); + pDoc = &xDocSh2->GetDocument(); + // TODO CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), pDoc->GetAllocatedColumnsCount(0)); + vcl::Font aFont; + pDoc->GetPattern(pDoc->MaxCol(), 1, 0)->GetFont(aFont, SC_AUTOCOL_RAW); + CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD, aFont.GetWeight()); + + ScDocShellRef xDocSh3 = saveAndReload(*xDocSh2, FORMAT_XLSX); + CPPUNIT_ASSERT(xDocSh3.is()); + pDoc = &xDocSh3->GetDocument(); + // TODO CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), pDoc->GetAllocatedColumnsCount(0)); + pDoc->GetPattern(pDoc->MaxCol(), 1, 0)->GetFont(aFont, SC_AUTOCOL_RAW); + CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD, aFont.GetWeight()); + + xDocSh1->DoClose(); + xDocSh2->DoClose(); + xDocSh3->DoClose(); +} + CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest2); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx index b51735bad5bd..814bc4b77d1b 100644 --- a/sc/qa/unit/ucalc.cxx +++ b/sc/qa/unit/ucalc.cxx @@ -146,6 +146,7 @@ public: void testHorizontalIterator(); void testValueIterator(); void testHorizontalAttrIterator(); + void testIteratorsUnallocatedColumnsAttributes(); /** * More direct test for cell broadcaster management, used to track formula @@ -276,6 +277,7 @@ public: CPPUNIT_TEST(testHorizontalIterator); CPPUNIT_TEST(testValueIterator); CPPUNIT_TEST(testHorizontalAttrIterator); + CPPUNIT_TEST(testIteratorsUnallocatedColumnsAttributes); CPPUNIT_TEST(testCellBroadcaster); CPPUNIT_TEST(testFuncParam); CPPUNIT_TEST(testNamedRange); @@ -1398,6 +1400,58 @@ void Test::testHorizontalAttrIterator() m_pDoc->DeleteTab(0); } +void Test::testIteratorsUnallocatedColumnsAttributes() +{ + m_pDoc->InsertTab(0, "Tab1"); + + // Make entire second row and third row bold. + ScPatternAttr boldAttr(m_pDoc->GetPool()); + boldAttr.GetItemSet().Put(SvxWeightItem(WEIGHT_BOLD, ATTR_FONT_WEIGHT)); + m_pDoc->ApplyPatternAreaTab(0, 1, m_pDoc->MaxCol(), 2, 0, boldAttr); + + // That shouldn't need allocating more columns, just changing the default attribute. + CPPUNIT_ASSERT_EQUAL(SCCOL(INITIALCOLCOUNT), m_pDoc->GetAllocatedColumnsCount(0)); + vcl::Font aFont; + const ScPatternAttr* pattern = m_pDoc->GetPattern(m_pDoc->MaxCol(), 1, 0); + pattern->GetFont(aFont, SC_AUTOCOL_RAW); + CPPUNIT_ASSERT_EQUAL_MESSAGE("font should be bold", WEIGHT_BOLD, aFont.GetWeight()); + + // Test iterators. + ScDocAttrIterator docit( *m_pDoc, 0, INITIALCOLCOUNT - 1, 1, INITIALCOLCOUNT, 2 ); + SCCOL col1, col2; + SCROW row1, row2; + CPPUNIT_ASSERT_EQUAL( pattern, docit.GetNext( col1, row1, row2 )); + CPPUNIT_ASSERT_EQUAL( SCCOL(INITIALCOLCOUNT - 1), col1 ); + CPPUNIT_ASSERT_EQUAL( SCROW(1), row1 ); + CPPUNIT_ASSERT_EQUAL( SCROW(2), row2 ); + CPPUNIT_ASSERT_EQUAL( pattern, docit.GetNext( col1, row1, row2 )); + CPPUNIT_ASSERT_EQUAL( INITIALCOLCOUNT, col1 ); + CPPUNIT_ASSERT_EQUAL( SCROW(1), row1 ); + CPPUNIT_ASSERT_EQUAL( SCROW(2), row2 ); + CPPUNIT_ASSERT( docit.GetNext( col1, row1, row2 ) == nullptr ); + + ScAttrRectIterator rectit( *m_pDoc, 0, INITIALCOLCOUNT - 1, 1, INITIALCOLCOUNT, 2 ); + CPPUNIT_ASSERT_EQUAL( pattern, rectit.GetNext( col1, col2, row1, row2 )); + CPPUNIT_ASSERT_EQUAL( SCCOL(INITIALCOLCOUNT - 1), col1 ); + CPPUNIT_ASSERT_EQUAL( INITIALCOLCOUNT, col2 ); + CPPUNIT_ASSERT_EQUAL( SCROW(1), row1 ); + CPPUNIT_ASSERT_EQUAL( SCROW(2), row2 ); + CPPUNIT_ASSERT( rectit.GetNext( col1, col2, row1, row2 ) == nullptr ); + + ScHorizontalAttrIterator horit( *m_pDoc, 0, INITIALCOLCOUNT - 1, 1, INITIALCOLCOUNT, 2 ); + CPPUNIT_ASSERT_EQUAL( pattern, horit.GetNext( col1, col2, row1 )); + CPPUNIT_ASSERT_EQUAL( SCCOL(INITIALCOLCOUNT - 1), col1 ); + CPPUNIT_ASSERT_EQUAL( INITIALCOLCOUNT, col2 ); + CPPUNIT_ASSERT_EQUAL( SCROW(1), row1 ); + CPPUNIT_ASSERT_EQUAL( pattern, horit.GetNext( col1, col2, row1 )); + CPPUNIT_ASSERT_EQUAL( SCCOL(INITIALCOLCOUNT - 1), col1 ); + CPPUNIT_ASSERT_EQUAL( INITIALCOLCOUNT, col2 ); + CPPUNIT_ASSERT_EQUAL( SCROW(2), row1 ); + CPPUNIT_ASSERT( horit.GetNext( col1, col2, row1 ) == nullptr ); + + m_pDoc->DeleteTab(0); +} + namespace { bool broadcasterShifted(const ScDocument& rDoc, const ScAddress& rFrom, const ScAddress& rTo) diff --git a/sc/source/core/data/attarray.cxx b/sc/source/core/data/attarray.cxx index 5af0e3b3609d..e74edd94a434 100644 --- a/sc/source/core/data/attarray.cxx +++ b/sc/source/core/data/attarray.cxx @@ -2689,4 +2689,24 @@ SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow ) const return nIndex2 - nIndex1 + 1; } +bool ScAttrArray::HasNonDefPattern( SCROW nStartRow, SCROW nEndRow ) const +{ + if ( mvData.empty() ) + return false; + + SCSIZE nIndex1, nIndex2; + + if( !Search( nStartRow, nIndex1 ) ) + return false; + + if( !Search( nEndRow, nIndex2 ) ) + nIndex2 = mvData.size() - 1; + + const ScPatternAttr* defPattern = rDocument.GetDefPattern(); + for( SCSIZE index = nIndex1; index <= nIndex2; ++index ) + if( mvData[index].pPattern != defPattern ) + return true; + return false; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 966a182cbf7c..84b68b76db39 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -1940,7 +1940,7 @@ void ScColumn::MixData( CellStorageModified(); } -std::unique_ptr<ScAttrIterator> ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const +std::unique_ptr<ScAttrIterator> ScColumnData::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const { return std::make_unique<ScAttrIterator>( pAttrArray.get(), nStartRow, nEndRow, GetDoc().GetDefPattern() ); } diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx index 28543f720c16..35148072f387 100644 --- a/sc/source/core/data/dociter.cxx +++ b/sc/source/core/data/dociter.cxx @@ -2394,7 +2394,7 @@ ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument& rDocument, SCTAB assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT"); assert(rDoc.maTabs[nTab]); - nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol); + nEndCol = rDoc.maTabs[nTab]->ClampToMaxNonDefPatternColumn(nEndCol); nRow = nStartRow; nCol = nStartCol; @@ -2423,14 +2423,13 @@ void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization) SCCOL nPos = i - nStartCol; if ( bInitialization || pNextEnd[nPos] < nRow ) { - const ScAttrArray* pArray = rDoc.maTabs[nTab]->aCol[i].pAttrArray.get(); - assert(pArray); + const ScAttrArray& pArray = rDoc.maTabs[nTab]->ColumnData(i).AttrArray(); SCSIZE nIndex; if (bInitialization) { - if ( pArray->Count() ) - pArray->Search( nStartRow, nIndex ); + if ( pArray.Count() ) + pArray.Search( nStartRow, nIndex ); else nIndex = 0; pIndices[nPos] = nIndex; @@ -2439,16 +2438,16 @@ void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization) else nIndex = ++pIndices[nPos]; - if ( !nIndex && !pArray->Count() ) + if ( !nIndex && !pArray.Count() ) { pNextEnd[nPos] = rDoc.MaxRow(); assert( pNextEnd[nPos] >= nRow && "Sequence out of order" ); ppPatterns[nPos] = nullptr; } - else if ( nIndex < pArray->Count() ) + else if ( nIndex < pArray.Count() ) { - const ScPatternAttr* pPattern = pArray->mvData[nIndex].pPattern; - SCROW nThisEnd = pArray->mvData[nIndex].nEndRow; + const ScPatternAttr* pPattern = pArray.mvData[nIndex].pPattern; + SCROW nThisEnd = pArray.mvData[nIndex].nEndRow; if ( IsDefaultItem( pPattern ) ) pPattern = nullptr; @@ -2644,11 +2643,14 @@ ScDocAttrIterator::ScDocAttrIterator(ScDocument& rDocument, SCTAB nTable, nEndRow( nRow2 ), nCol( nCol1 ) { - if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab] - && nCol < rDoc.maTabs[nTab]->GetAllocatedColumnsCount()) + if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab] ) { - nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol); - pColIter = rDoc.maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow ); + SCCOL attrColCount = rDoc.maTabs[nTab]->GetMaxNonDefPatternColumnsCount(nStartRow, nEndRow); + if( nCol < attrColCount ) + { + nEndCol = std::min<SCCOL>(nEndCol,attrColCount - 1); + pColIter = rDoc.maTabs[nTab]->ColumnData(nCol).CreateAttrIterator( nStartRow, nEndRow ); + } } } @@ -2669,7 +2671,7 @@ const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCRO ++nCol; if ( nCol <= nEndCol ) - pColIter = rDoc.maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow ); + pColIter = rDoc.maTabs[nTab]->ColumnData(nCol).CreateAttrIterator( nStartRow, nEndRow ); else pColIter.reset(); } @@ -2776,18 +2778,19 @@ ScAttrRectIterator::ScAttrRectIterator(ScDocument& rDocument, SCTAB nTable, nIterStartCol( nCol1 ), nIterEndCol( nCol1 ) { - if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab] - && nCol1 < rDoc.maTabs[nTab]->GetAllocatedColumnsCount()) + if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab] ) { - nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol); - pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow ); - while ( nIterEndCol < nEndCol && - rDoc.maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual( - rDoc.maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) ) - ++nIterEndCol; + SCCOL attrColCount = rDoc.maTabs[nTab]->GetMaxNonDefPatternColumnsCount(nStartRow, nEndRow); + if( nCol1 < attrColCount ) + { + nEndCol = std::min<SCCOL>(nEndCol,attrColCount - 1); + pColIter = rDoc.maTabs[nTab]->ColumnData(nIterStartCol).CreateAttrIterator( nStartRow, nEndRow ); + while ( nIterEndCol < nEndCol && + rDoc.maTabs[nTab]->ColumnData(nIterEndCol).IsAllAttrEqual( + rDoc.maTabs[nTab]->ColumnData(nIterEndCol+1), nStartRow, nEndRow ) ) + ++nIterEndCol; + } } - else - pColIter = nullptr; } ScAttrRectIterator::~ScAttrRectIterator() @@ -2799,7 +2802,7 @@ void ScAttrRectIterator::DataChanged() if (pColIter) { SCROW nNextRow = pColIter->GetNextRow(); - pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow ); + pColIter = rDoc.maTabs[nTab]->ColumnData(nIterStartCol).CreateAttrIterator( nNextRow, nEndRow ); } } @@ -2820,10 +2823,10 @@ const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, if ( nIterStartCol <= nEndCol ) { nIterEndCol = nIterStartCol; - pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow ); + pColIter = rDoc.maTabs[nTab]->ColumnData(nIterStartCol).CreateAttrIterator( nStartRow, nEndRow ); while ( nIterEndCol < nEndCol && - rDoc.maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual( - rDoc.maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) ) + rDoc.maTabs[nTab]->ColumnData(nIterEndCol).IsAllAttrEqual( + rDoc.maTabs[nTab]->ColumnData(nIterEndCol+1), nStartRow, nEndRow ) ) ++nIterEndCol; } else diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 311a3756d817..d07d82716404 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -2697,6 +2697,21 @@ ScColumnsRange ScTable::GetColumnsRange(SCCOL nColBegin, SCCOL nColEnd) const return ScColumnsRange(ScColumnsRange::Iterator(beginIter), ScColumnsRange::Iterator(endIter)); } +SCCOL ScTable::ClampToMaxNonDefPatternColumn(SCCOL nCol, SCROW nRow1, SCROW nRow2) const +{ + // The purpose so to avoid unallocated columns if possible, so don't check allocated ones. + if( nCol < GetAllocatedColumnsCount()) + return nCol; + return std::min<SCCOL>(nCol, GetMaxNonDefPatternColumnsCount( nRow1, nRow2 ) - 1 ); +} + +SCCOL ScTable::GetMaxNonDefPatternColumnsCount(SCROW nRow1, SCROW nRow2) const +{ + if( aDefaultColData.HasNonDefPattern(nRow1, nRow2)) + return GetDoc().GetMaxColCount(); + return GetAllocatedColumnsCount(); +} + // out-of-line the cold part of the CreateColumnIfNotExists function void ScTable::CreateColumnIfNotExistsImpl( const SCCOL nScCol ) const { commit a2f1d8ce529551c0212a492d36fda27f555ef547 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Wed Mar 9 11:45:34 2022 +0100 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Thu Apr 14 10:15:30 2022 +0200 add ColumnData() for simple handling of unallocated column data Move the decision whether to return a column or the default data for unallocated columns into a simple function. Change-Id: I369b8c815de96b61181f2483c6afac44a5c3bc2e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/131264 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lu...@collabora.com> diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 9362fee910dd..80117ccf5f42 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -1128,6 +1128,8 @@ public: std::set<SCCOL> QueryColumnsWithFormulaCells() const; + const ScColumnData& ColumnData( SCCOL nCol ) const { return nCol < aCol.size() ? aCol[ nCol ] : aDefaultColData; } + void CheckIntegrity() const; private: diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index c1e89152d3ae..cada997f556a 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -2230,28 +2230,20 @@ const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, sal_uInt16 nWhich ) { if (!ValidColRow(nCol, nRow)) return nullptr; - if (nCol < GetAllocatedColumnsCount()) - return &aCol[nCol].GetAttr( nRow, nWhich ); - return &aDefaultColData.GetAttr( nRow, nWhich ); + return &ColumnData(nCol).GetAttr( nRow, nWhich ); } const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, sal_uInt16 nWhich, SCROW& nStartRow, SCROW& nEndRow ) const { if (!ValidColRow(nCol, nRow)) return nullptr; - if (nCol < GetAllocatedColumnsCount()) - return &aCol[nCol].GetAttr( nRow, nWhich, nStartRow, nEndRow ); - return &aDefaultColData.GetAttr( nRow, nWhich, nStartRow, nEndRow ); + return &ColumnData(nCol).GetAttr( nRow, nWhich, nStartRow, nEndRow ); } sal_uInt32 ScTable::GetNumberFormat( const ScInterpreterContext& rContext, const ScAddress& rPos ) const { if (ValidColRow(rPos.Col(), rPos.Row())) - { - if (rPos.Col() < GetAllocatedColumnsCount()) - return aCol[rPos.Col()].GetNumberFormat(rContext, rPos.Row()); - return aDefaultColData.GetNumberFormat(rContext, rPos.Row()); - } + return ColumnData(rPos.Col()).GetNumberFormat(rContext, rPos.Row()); return 0; } @@ -2265,9 +2257,7 @@ sal_uInt32 ScTable::GetNumberFormat( SCCOL nCol, SCROW nStartRow, SCROW nEndRow if (!ValidCol(nCol) || !ValidRow(nStartRow) || !ValidRow(nEndRow)) return 0; - if (nCol < GetAllocatedColumnsCount()) - return aCol[nCol].GetNumberFormat(nStartRow, nEndRow); - return aDefaultColData.GetNumberFormat(nStartRow, nEndRow); + return ColumnData(nCol).GetNumberFormat(nStartRow, nEndRow); } void ScTable::SetNumberFormat( SCCOL nCol, SCROW nRow, sal_uInt32 nNumberFormat ) @@ -2280,19 +2270,16 @@ void ScTable::SetNumberFormat( SCCOL nCol, SCROW nRow, sal_uInt32 nNumberFormat const ScPatternAttr* ScTable::GetPattern( SCCOL nCol, SCROW nRow ) const { - if (ValidColRow(nCol,nRow) && nCol < GetAllocatedColumnsCount()) - return aCol[nCol].GetPattern( nRow ); - else - return aDefaultColData.GetPattern( nRow ); + if (!ValidColRow(nCol,nRow)) + return nullptr; + return ColumnData(nCol).GetPattern( nRow ); } const ScPatternAttr* ScTable::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const { - if ( ValidColRow( nCol, nStartRow ) && ValidRow( nEndRow ) && (nStartRow <= nEndRow) - && nCol < GetAllocatedColumnsCount()) - return aCol[nCol].GetMostUsedPattern( nStartRow, nEndRow ); - else - return aDefaultColData.GetMostUsedPattern( nStartRow, nEndRow ); + if ( ValidColRow( nCol, nStartRow ) && ValidRow( nEndRow ) && (nStartRow <= nEndRow)) + return ColumnData(nCol).GetMostUsedPattern( nStartRow, nEndRow ); + return nullptr; } bool ScTable::HasAttrib( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, HasAttrFlags nMask ) const @@ -2307,9 +2294,7 @@ bool ScTable::HasAttrib( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, Has bool ScTable::HasAttrib( SCCOL nCol, SCROW nRow, HasAttrFlags nMask, SCROW* nStartRow, SCROW* nEndRow ) const { - if( nCol < aCol.size()) - return aCol[nCol].HasAttrib( nRow, nMask, nStartRow, nEndRow ); - return aDefaultColData.HasAttrib( nRow, nMask, nStartRow, nEndRow ); + return ColumnData(nCol).HasAttrib( nRow, nMask, nStartRow, nEndRow ); } bool ScTable::HasAttribSelection( const ScMarkData& rMark, HasAttrFlags nMask ) const @@ -3023,10 +3008,7 @@ const ScStyleSheet* ScTable::GetStyle( SCCOL nCol, SCROW nRow ) const { if ( !ValidColRow( nCol, nRow ) ) return nullptr; - if ( nCol < aCol.size() ) - return aCol[nCol].GetStyle( nRow ); - else - return aDefaultColData.GetStyle( nRow ); + return ColumnData(nCol).GetStyle( nRow ); } const ScStyleSheet* ScTable::GetSelectionStyle( const ScMarkData& rMark, bool& rFound ) const