sc/inc/SheetView.hxx | 12 ++++ sc/qa/unit/tiledrendering/SheetViewTest.cxx | 63 +++++++++++++++++++++++ sc/source/core/data/SheetView.cxx | 38 +++++++++++++- sc/source/core/data/SheetViewManager.cxx | 2 sc/source/core/data/table3.cxx | 10 +++ sc/source/ui/view/viewfunc.cxx | 76 ++++++++++++++++++---------- 6 files changed, 172 insertions(+), 29 deletions(-)
New commits: commit 0bdd6e315ebe5620e627d584af76da69bb339545 Author: Tomaž Vajngerl <[email protected]> AuthorDate: Fri Sep 12 16:13:54 2025 +0200 Commit: Miklos Vajna <[email protected]> CommitDate: Fri Jan 23 10:28:41 2026 +0100 sc: unsort when synching a change from sheet view to default view If we sort in sheet view and change the value in sheet view, we need to reverse the sort when syncing the value with the default view. When a sheet view is sorted, we store the order inside SheetView. If we sort again, we need to combine the existing sort order with the new sort order (sort asc. and then sort desc). We also need sheet view info in ScTable of a sheet view, so we can properly set the sort order. This sent the information when we create the sheet view. Change-Id: I4d7f2c8add3f137025bcc9c6f29482795fa32ccb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190891 Reviewed-by: Tomaž Vajngerl <[email protected]> Tested-by: Jenkins Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197819 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/sc/inc/SheetView.hxx b/sc/inc/SheetView.hxx index bff043b55812..5c36ddf01fc8 100644 --- a/sc/inc/SheetView.hxx +++ b/sc/inc/SheetView.hxx @@ -12,6 +12,7 @@ #include "scdllapi.h" #include "types.hxx" #include <rtl/ustring.hxx> +#include "SheetViewTypes.hxx" class ScTable; @@ -29,11 +30,17 @@ private: bool mbSynced = true; OUString maName; + SCROW mnFirstRow; + SCROW mnLastRow; + std::vector<SCCOLROW> maOrder; + SheetViewID mnID; + public: - SheetView(ScTable* pTable, OUString const& rName); + SheetView(ScTable* pTable, OUString const& rName, SheetViewID nID); ScTable* getTablePointer() const; SCTAB getTableNumber() const; + SheetViewID getID() const { return mnID; } OUString const& GetName() { return maName; } @@ -45,6 +52,9 @@ public: /** Is the sheet view synced with its default view. */ bool isSynced() const { return mbSynced; } + + void addOrderIndices(std::vector<SCCOLROW> const& rOrder, SCROW firstRow, SCROW lastRow); + SCROW unsort(SCROW nRow) const; }; } diff --git a/sc/qa/unit/tiledrendering/SheetViewTest.cxx b/sc/qa/unit/tiledrendering/SheetViewTest.cxx index aae9dbb1f2ed..12fd8ddfa8be 100644 --- a/sc/qa/unit/tiledrendering/SheetViewTest.cxx +++ b/sc/qa/unit/tiledrendering/SheetViewTest.cxx @@ -807,6 +807,69 @@ CPPUNIT_TEST_FIXTURE(SheetViewTest, testSyncAfterSorting_DefaultViewSort) } } +CPPUNIT_TEST_FIXTURE(SheetViewTest, testSyncAfterSorting_SheetViewSort) +{ + // Two related scenarios tested: + // + // 1. Auto-filter is sorted in the sheet view, then the data is changed in a sheet view. + // In this case the default view is unsorted and the sheet view is sorted, so the data + // in the sheet view needs to be first unsorted so we get the correct position of the + // cell that needs to be changed. + // 2. Continuation of scenario 1, where the sheet view is sorted again (ascending then + // descending order). In this case the sort orders must be combined correctly. + + // Create two views, and leave the second one current. + ScModelObj* pModelObj = createDoc("SheetView_AutoFilter.ods"); + pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + + // Setup views + ScTestViewCallback aSheetView; + ScTabViewShell* pTabViewSheetView = aSheetView.getTabViewShell(); + + SfxLokHelper::createView(); + Scheduler::ProcessEventsToIdle(); + + ScTestViewCallback aDefaultView; + ScTabViewShell* pTabViewDefaultView = aDefaultView.getTabViewShell(); + + CPPUNIT_ASSERT(pTabViewSheetView != pTabViewDefaultView); + CPPUNIT_ASSERT(aSheetView.getViewID() != aDefaultView.getViewID()); + + // Switch to Sheet View and Create + { + SfxLokHelper::setView(aSheetView.getViewID()); + Scheduler::ProcessEventsToIdle(); + + // New Sheet view + dispatchCommand(mxComponent, u".uno:NewSheetView"_ustr, {}); + + // Sort AutoFilter + dispatchCommand(mxComponent, u".uno:SortAscending"_ustr, {}); + + // Check values - Sheet View + CPPUNIT_ASSERT(checkValues(pTabViewSheetView, 0, 1, 4, { u"3", u"4", u"5", u"7" })); + CPPUNIT_ASSERT(checkValues(pTabViewDefaultView, 0, 1, 4, { u"4", u"5", u"3", u"7" })); + + typeCharsInCell(std::string("9"), 0, 1, pTabViewSheetView, pModelObj); + + CPPUNIT_ASSERT(checkValues(pTabViewSheetView, 0, 1, 4, { u"9", u"4", u"5", u"7" })); + CPPUNIT_ASSERT(checkValues(pTabViewDefaultView, 0, 1, 4, { u"4", u"5", u"9", u"7" })); + + // Scenario 2 + + // Sort AutoFilter + dispatchCommand(mxComponent, u".uno:SortDescending"_ustr, {}); + + CPPUNIT_ASSERT(checkValues(pTabViewSheetView, 0, 1, 4, { u"9", u"7", u"5", u"4" })); + CPPUNIT_ASSERT(checkValues(pTabViewDefaultView, 0, 1, 4, { u"4", u"5", u"9", u"7" })); + + typeCharsInCell(std::string("6"), 0, 3, pTabViewSheetView, pModelObj); + + CPPUNIT_ASSERT(checkValues(pTabViewSheetView, 0, 1, 4, { u"9", u"7", u"6", u"4" })); + CPPUNIT_ASSERT(checkValues(pTabViewDefaultView, 0, 1, 4, { u"4", u"6", u"9", u"7" })); + } +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/SheetView.cxx b/sc/source/core/data/SheetView.cxx index 0c51d5ea6678..a7b103deeb7c 100644 --- a/sc/source/core/data/SheetView.cxx +++ b/sc/source/core/data/SheetView.cxx @@ -12,9 +12,10 @@ namespace sc { -SheetView::SheetView(ScTable* pTable, OUString const& rName) +SheetView::SheetView(ScTable* pTable, OUString const& rName, SheetViewID nID) : mpTable(pTable) , maName(rName) + , mnID(nID) { } @@ -25,6 +26,41 @@ SCTAB SheetView::getTableNumber() const assert(mpTable); return mpTable->GetTab(); } + +void SheetView::addOrderIndices(std::vector<SCCOLROW> const& rOrder, SCROW firstRow, SCROW lastRow) +{ + mnFirstRow = firstRow; + mnLastRow = lastRow; + if (maOrder.empty()) + { + maOrder = rOrder; + } + else + { + assert(maOrder.size() == rOrder.size()); + std::vector<SCCOLROW> newOrder(maOrder.size()); + for (size_t nIndex = 0; nIndex < maOrder.size(); ++nIndex) + { + size_t nSortedIndex = rOrder[nIndex]; + newOrder[nIndex] = maOrder[nSortedIndex - 1]; + } + maOrder = newOrder; + } +} + +SCROW SheetView::unsort(SCROW nRow) const +{ + if (maOrder.empty()) + return nRow; + + if (nRow >= mnFirstRow && nRow <= mnLastRow) + { + size_t index = nRow - mnFirstRow; + auto nUnsortedRow = mnFirstRow + maOrder[index] - 1; + return nUnsortedRow; + } + return nRow; +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/SheetViewManager.cxx b/sc/source/core/data/SheetViewManager.cxx index a7bd35f8545f..02a791dab158 100644 --- a/sc/source/core/data/SheetViewManager.cxx +++ b/sc/source/core/data/SheetViewManager.cxx @@ -19,7 +19,7 @@ SheetViewManager::SheetViewManager() {} SheetViewID SheetViewManager::create(ScTable* pSheetViewTable) { SheetViewID nID(maViews.size()); - maViews.emplace_back(std::make_shared<SheetView>(pSheetViewTable, generateName())); + maViews.emplace_back(std::make_shared<SheetView>(pSheetViewTable, generateName(), nID)); return nID; } diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx index ad928acd38a7..2341b6ea891e 100644 --- a/sc/source/core/data/table3.cxx +++ b/sc/source/core/data/table3.cxx @@ -1757,7 +1757,15 @@ void ScTable::Sort( bool bAutoFilter = GetDoc().HasAutoFilter(rSortParam.nCol1, nRow1, GetTab()); if (bAutoFilter) { - GetSheetViewManager()->addOrderIndices(pArray->GetOrderIndices(), nRow1, nLastRow); + if (IsSheetViewHolder()) + { + auto pSheetView = mpSheetViewFor->GetSheetViewManager()->get(mnSheetViewID); + pSheetView->addOrderIndices(pArray->GetOrderIndices(), nRow1, nLastRow); + } + else + { + GetSheetViewManager()->addOrderIndices(pArray->GetOrderIndices(), nRow1, nLastRow); + } } } } diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx index e927c114ef27..77b584dfbab7 100644 --- a/sc/source/ui/view/viewfunc.cxx +++ b/sc/source/ui/view/viewfunc.cxx @@ -810,47 +810,73 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, { SCTAB nSelectedTab = aMark.GetFirstSelected(); applyFormulaToCell(*this, nCol, nRow, nTab, rString, pData, xModificator, aMark, bMatrixExpand, bRecord, bNumFmtChanged); - if (!rDoc.IsSheetViewHolder(nSelectedTab)) - { - auto pManager = rDoc.GetSheetViewManager(nSelectedTab); + if (rDoc.IsSheetViewHolder(nSelectedTab)) + return; - for (auto const& pSheetView : pManager->getSheetViews()) - { - if (!pSheetView) - continue; + auto pManager = rDoc.GetSheetViewManager(nSelectedTab); - SCTAB nSheetViewTab = pSheetView->getTableNumber(); + for (auto const& pSheetView : pManager->getSheetViews()) + { + if (!pSheetView) + continue; - ScMarkData aSheetViewMark(rDoc.GetSheetLimits()); - aSheetViewMark.SelectTable(nSheetViewTab, false); - ScRange aSheetViewRange(aMark.GetMarkArea()); - aSheetViewRange.aStart.SetTab(nSheetViewTab); - aSheetViewRange.aEnd.SetTab(nSheetViewTab); - aSheetViewMark.SetMarkArea(aSheetViewRange); + SCTAB nSheetViewTab = pSheetView->getTableNumber(); - applyFormulaToCell(*this, nCol, nRow, nSheetViewTab, rString, pData, xModificator, aSheetViewMark, bMatrixExpand, bRecord, bNumFmtChanged); - } + ScMarkData aSheetViewMark(rDoc.GetSheetLimits()); + aSheetViewMark.SelectTable(nSheetViewTab, false); + ScRange aSheetViewRange(aMark.GetMarkArea()); + aSheetViewRange.aStart.SetTab(nSheetViewTab); + aSheetViewRange.aEnd.SetTab(nSheetViewTab); + aSheetViewMark.SetMarkArea(aSheetViewRange); + + applyFormulaToCell(*this, nCol, nRow, nSheetViewTab, rString, pData, xModificator, aSheetViewMark, bMatrixExpand, bRecord, bNumFmtChanged); } } else { + sc::SheetViewID nSheetViewID = GetViewData().GetSheetViewID(); for (const auto& rTab : aMark) { - if (!rDoc.IsSheetViewHolder(rTab)) + if (rDoc.IsSheetViewHolder(rTab)) + continue; + + auto pManager = rDoc.GetSheetViewManager(rTab); + + for (auto const& pSheetView : pManager->getSheetViews()) { - auto pManager = rDoc.GetSheetViewManager(rTab); - for (auto const& pSheetView : pManager->getSheetViews()) - { - if (!pSheetView) - continue; + if (!pSheetView) + continue; - SCTAB nSheetViewTab = pSheetView->getTableNumber(); - SCROW nUnsortedRow = pManager->unsort(nRow); + SCTAB nSheetViewTab = pSheetView->getTableNumber(); + + if (GetViewData().GetSheetViewID() == sc::DefaultSheetViewID) + { + SCROW nUnsortedRow = nRow; + nUnsortedRow = pManager->unsort(nUnsortedRow); applyText(*this, nCol, nUnsortedRow, nSheetViewTab, rString, bNumFmtChanged); } + else if (GetViewData().GetSheetViewID() == pSheetView->getID()) + { + applyText(*this, nCol, nRow, nSheetViewTab, rString, bNumFmtChanged); + } + else + { + // TODO - we need to update other sheet views as well, test case needed + } + } + + { + SCROW nUnsortedRow = nRow; + + if (nSheetViewID != sc::DefaultSheetViewID) + { + auto pSheetView = pManager->get(nSheetViewID); + nUnsortedRow = pSheetView->unsort(nUnsortedRow); + } + applyText(*this, nCol, nUnsortedRow, rTab, rString, bNumFmtChanged); } - applyText(*this, nCol, nRow, rTab, rString, bNumFmtChanged); } + performAutoFormatAndUpdate(rString, aMark, nCol, nRow, nTab, bNumFmtChanged, bRecord, xModificator, *this); } }
