sc/qa/unit/tiledrendering/SheetViewTest.cxx | 86 +++++++++++++++++ sc/source/ui/inc/operation/Operation.hxx | 9 + sc/source/ui/operation/DeleteCellOperation.cxx | 108 ---------------------- sc/source/ui/operation/DeleteContentOperation.cxx | 9 + sc/source/ui/operation/Operation.cxx | 108 ++++++++++++++++++++++ 5 files changed, 209 insertions(+), 111 deletions(-)
New commits: commit c7ab242e6dd46c58e0265967aaa9aba172275c30 Author: Tomaž Vajngerl <[email protected]> AuthorDate: Fri Feb 6 14:41:51 2026 +0900 Commit: Miklos Vajna <[email protected]> CommitDate: Mon Feb 16 09:08:10 2026 +0100 sc: Implement sync in DeleteContentOperation Sync all sheet view scenarios for delete content operation. Move the convertMark and convertAddress to Operation class, so we can reuse it in all Oeprations. Fix wrong parameter order when calling IsCellMarked in convertMark. Change-Id: I2301f3a3d21c601d368c816dc7157e3f55e2f9f8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198960 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/sc/qa/unit/tiledrendering/SheetViewTest.cxx b/sc/qa/unit/tiledrendering/SheetViewTest.cxx index 5195601a964d..50a7c906cb5a 100644 --- a/sc/qa/unit/tiledrendering/SheetViewTest.cxx +++ b/sc/qa/unit/tiledrendering/SheetViewTest.cxx @@ -1121,6 +1121,92 @@ CPPUNIT_TEST_FIXTURE(SyncTest, testSync_SheetView_DeleteCellOperation) CPPUNIT_ASSERT_EQUAL(aExpectedSorted, getValues(pDocument, 0, 1, 4, 1)); } +CPPUNIT_TEST_FIXTURE(SyncTest, testSync_DefaultView_DeleteContentOperation) +{ + // Create two views, and leave the second one current. + ScModelObj* pModelObj = createDoc("SheetView_AutoFilter.ods"); + pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + ScDocument* pDocument = pModelObj->GetDocument(); + + setupViews(); + + CPPUNIT_ASSERT_EQUAL(expectedValues({ u"4", u"5", u"3", u"7" }), + getValues(pDocument, 0, 1, 4, 0)); + CPPUNIT_ASSERT_EQUAL(expectedValues({ u"", u"", u"", u"" }), getValues(pDocument, 0, 1, 4, 1)); + + // Switch to Sheet View and Create + { + switchToSheetView(); + dispatchCommand(mxComponent, u".uno:NewSheetView"_ustr, {}); + dispatchCommand(mxComponent, u".uno:SortDescending"_ustr, {}); + } + + CPPUNIT_ASSERT_EQUAL(expectedValues({ u"4", u"5", u"3", u"7" }), + getValues(pDocument, 0, 1, 4, 0)); + CPPUNIT_ASSERT_EQUAL(expectedValues({ u"7", u"5", u"4", u"3" }), + getValues(pDocument, 0, 1, 4, 1)); + + // Switch to Default View + { + switchToDefaultView(); + + dispatchCommand( + mxComponent, u".uno:GoToCell"_ustr, + comphelper::InitPropertySequence({ { "ToPoint", uno::Any(u"A3:A4"_ustr) } })); + + dispatchCommand(mxComponent, u".uno:ClearContents"_ustr, {}); + } + + OUString aExpected = expectedValues({ u"4", u"", u"", u"7" }); + CPPUNIT_ASSERT_EQUAL(aExpected, getValues(mpTabViewDefaultView, 0, 1, 4)); + CPPUNIT_ASSERT_EQUAL(aExpected, getValues(pDocument, 0, 1, 4, 0)); + + OUString aExpectedSorted = expectedValues({ u"7", u"4", u"", u"" }); + CPPUNIT_ASSERT_EQUAL(aExpectedSorted, getValues(mpTabViewSheetView, 0, 1, 4)); + CPPUNIT_ASSERT_EQUAL(aExpectedSorted, getValues(pDocument, 0, 1, 4, 1)); +} + +CPPUNIT_TEST_FIXTURE(SyncTest, testSync_SheetView_DeleteContentOperation) +{ + // Create two views, and leave the second one current. + ScModelObj* pModelObj = createDoc("SheetView_AutoFilter.ods"); + pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>()); + ScDocument* pDocument = pModelObj->GetDocument(); + + setupViews(); + + CPPUNIT_ASSERT_EQUAL(expectedValues({ u"4", u"5", u"3", u"7" }), + getValues(pDocument, 0, 1, 4, 0)); + CPPUNIT_ASSERT_EQUAL(expectedValues({ u"", u"", u"", u"" }), getValues(pDocument, 0, 1, 4, 1)); + + // Switch to Sheet View and Create + { + switchToSheetView(); + + dispatchCommand(mxComponent, u".uno:NewSheetView"_ustr, {}); + dispatchCommand(mxComponent, u".uno:SortDescending"_ustr, {}); + + CPPUNIT_ASSERT_EQUAL(expectedValues({ u"4", u"5", u"3", u"7" }), + getValues(pDocument, 0, 1, 4, 0)); + CPPUNIT_ASSERT_EQUAL(expectedValues({ u"7", u"5", u"4", u"3" }), + getValues(pDocument, 0, 1, 4, 1)); + + dispatchCommand( + mxComponent, u".uno:GoToCell"_ustr, + comphelper::InitPropertySequence({ { "ToPoint", uno::Any(u"A3:A4"_ustr) } })); + + dispatchCommand(mxComponent, u".uno:ClearContents"_ustr, {}); + } + + OUString aExpected = expectedValues({ u"", u"", u"3", u"7" }); + CPPUNIT_ASSERT_EQUAL(aExpected, getValues(mpTabViewDefaultView, 0, 1, 4)); + CPPUNIT_ASSERT_EQUAL(aExpected, getValues(pDocument, 0, 1, 4, 0)); + + OUString aExpectedSorted = expectedValues({ u"7", u"3", u"", u"" }); + CPPUNIT_ASSERT_EQUAL(aExpectedSorted, getValues(mpTabViewSheetView, 0, 1, 4)); + CPPUNIT_ASSERT_EQUAL(aExpectedSorted, getValues(pDocument, 0, 1, 4, 1)); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/inc/operation/Operation.hxx b/sc/source/ui/inc/operation/Operation.hxx index f330f1b13c9c..596a7dbf26c7 100644 --- a/sc/source/ui/inc/operation/Operation.hxx +++ b/sc/source/ui/inc/operation/Operation.hxx @@ -11,6 +11,9 @@ #include <SheetViewOperationsTester.hxx> +class ScMarkData; +class ScAddress; + namespace sc { /** Operation is one atomic coarse change to the document model that can be run from UI or API @@ -46,6 +49,12 @@ public: bool run() { return runImplementation(); } bool checkSheetViewProtection(); + /** Convert address from a sheet view to the address in default view, take sorting into account. */ + static ScAddress convertAddress(ScAddress const& rAddress); + + /** Convert a mark from a sheet view to the mark in default view, take sorting into account. */ + static ScMarkData convertMark(ScMarkData const& rMarkData); + virtual bool runImplementation() = 0; }; diff --git a/sc/source/ui/operation/DeleteCellOperation.cxx b/sc/source/ui/operation/DeleteCellOperation.cxx index 9d320e8e98df..fbd88156b078 100644 --- a/sc/source/ui/operation/DeleteCellOperation.cxx +++ b/sc/source/ui/operation/DeleteCellOperation.cxx @@ -14,9 +14,6 @@ #include <markdata.hxx> #include <editable.hxx> #include <address.hxx> -#include <viewdata.hxx> -#include <SheetViewManager.hxx> -#include <SheetView.hxx> #include <memory> @@ -34,111 +31,6 @@ DeleteCellOperation::DeleteCellOperation(ScDocFunc& rDocFunc, ScDocShell& rDocSh { } -namespace -{ -std::shared_ptr<SheetView> getCurrentSheetView(ScViewData* pViewData) -{ - if (!pViewData) - return nullptr; - - sc::SheetViewID nID = pViewData->GetSheetViewID(); - if (nID == sc::DefaultSheetViewID) - return nullptr; - - std::shared_ptr<sc::SheetViewManager> pSheetViewManager - = pViewData->GetCurrentSheetViewManager(); - if (!pSheetViewManager) - return nullptr; - - return pSheetViewManager->get(nID); -} - -/** Convert address from a sheet view to the address in default view, take sorting into account. */ -ScAddress convertAddress(ScAddress const& rAddress) -{ - ScViewData* pViewData = ScDocShell::GetViewData(); - - std::shared_ptr<SheetView> pSheetView = getCurrentSheetView(pViewData); - if (!pSheetView) - return rAddress; - - std::optional<SortOrderReverser> const& oSortOrder = pSheetView->getSortOrder(); - if (!oSortOrder) - return rAddress; - - SCTAB nTab = rAddress.Tab(); - SCCOL nColumn = rAddress.Col(); - SCROW nRow = rAddress.Row(); - - if (pViewData->GetTabNumber() != nTab) - return rAddress; - - SCROW nUnsortedRow = oSortOrder->unsort(nRow, nColumn); - if (nUnsortedRow != nRow) - { - return ScAddress(nColumn, nUnsortedRow, nTab); - } - return rAddress; -} - -/** Convert a mark from a sheet view to the mark in default view, take sorting into account. */ -ScMarkData convertMark(ScMarkData const& rMarkData) -{ - ScViewData* pViewData = ScDocShell::GetViewData(); - - std::shared_ptr<SheetView> pSheetView = getCurrentSheetView(pViewData); - if (!pSheetView) - return rMarkData; - - std::optional<SortOrderReverser> const& oSortOrder = pSheetView->getSortOrder(); - if (!oSortOrder) - return rMarkData; - - ScMarkData aNewMark(rMarkData); - aNewMark.MarkToMulti(); - bool bChanged = false; - - for (const SCTAB& nTab : aNewMark) - { - if (pViewData->GetTabNumber() != nTab) - continue; - - std::vector<std::pair<SCCOL, SCROW>> aMarkedCells; - SortOrderInfo const& rSortInfo = oSortOrder->maSortInfo; - for (SCROW nRow = rSortInfo.mnFirstRow; nRow <= rSortInfo.mnLastRow; ++nRow) - { - for (SCROW nColumn = rSortInfo.mnFirstColumn; nColumn <= rSortInfo.mnLastColumn; - ++nColumn) - { - if (aNewMark.IsCellMarked(nRow, nColumn)) - { - aNewMark.SetMultiMarkArea(ScRange(nColumn, nRow, nTab, nColumn, nRow, nTab), - false); - aMarkedCells.emplace_back(nColumn, nRow); - } - } - } - for (auto & [ nColumn, nRow ] : aMarkedCells) - { - SCROW nUnsortedRow = oSortOrder->unsort(nRow, nColumn); - aNewMark.SetMultiMarkArea( - ScRange(nColumn, nUnsortedRow, nTab, nColumn, nUnsortedRow, nTab), true); - bChanged = true; - } - } - - if (!bChanged) - return rMarkData; - - if (bChanged && !aNewMark.HasAnyMultiMarks()) - aNewMark.ResetMark(); - - aNewMark.MarkToSimple(); - - return aNewMark; -} -} - bool DeleteCellOperation::runImplementation() { ScDocShellModificator aModificator(mrDocShell); diff --git a/sc/source/ui/operation/DeleteContentOperation.cxx b/sc/source/ui/operation/DeleteContentOperation.cxx index c1e50436017e..f269d49d523a 100644 --- a/sc/source/ui/operation/DeleteContentOperation.cxx +++ b/sc/source/ui/operation/DeleteContentOperation.cxx @@ -40,13 +40,14 @@ bool DeleteContentOperation::runImplementation() return false; } + ScMarkData aMultiMark = convertMark(mrMark); + ScDocument& rDoc = mrDocShell.GetDocument(); if (mbRecord && !rDoc.IsUndoEnabled()) mbRecord = false; - if (!checkSheetViewProtection()) - return false; + sc::SheetViewOperationsTester aSheetViewTester(ScDocShell::GetViewData()); ScEditableTester aTester = ScEditableTester::CreateAndTestSelection(rDoc, mrMark); if (!aTester.IsEditable()) @@ -56,7 +57,6 @@ bool DeleteContentOperation::runImplementation() return false; } - ScMarkData aMultiMark = mrMark; aMultiMark.SetMarking(false); // for MarkToMulti ScDocumentUniquePtr pUndoDoc; @@ -114,6 +114,9 @@ bool DeleteContentOperation::runImplementation() pDataSpans, bMulti, bDrawUndo); } + if (sc::SheetViewOperationsTester::doesUnsync(meType)) + aSheetViewTester.sync(); + if (!mrDocFunc.AdjustRowHeight(aExtendedRange, true, mbApi)) mrDocShell.PostPaint(aExtendedRange, PaintPartFlags::Grid, nExtFlags); else if (nExtFlags & SC_PF_LINES) diff --git a/sc/source/ui/operation/Operation.cxx b/sc/source/ui/operation/Operation.cxx index d37fb3908c35..471182de8b84 100644 --- a/sc/source/ui/operation/Operation.cxx +++ b/sc/source/ui/operation/Operation.cxx @@ -10,9 +10,117 @@ #include <operation/Operation.hxx> #include <SheetViewOperationsTester.hxx> #include <docsh.hxx> +#include <markdata.hxx> +#include <address.hxx> +#include <viewdata.hxx> +#include <SheetViewManager.hxx> +#include <SheetView.hxx> namespace sc { +namespace +{ +std::shared_ptr<SheetView> getCurrentSheetView(ScViewData* pViewData) +{ + if (!pViewData) + return nullptr; + + sc::SheetViewID nID = pViewData->GetSheetViewID(); + if (nID == sc::DefaultSheetViewID) + return nullptr; + + std::shared_ptr<sc::SheetViewManager> pSheetViewManager + = pViewData->GetCurrentSheetViewManager(); + if (!pSheetViewManager) + return nullptr; + + return pSheetViewManager->get(nID); +} +} + +ScAddress Operation::convertAddress(ScAddress const& rAddress) +{ + ScViewData* pViewData = ScDocShell::GetViewData(); + + std::shared_ptr<SheetView> pSheetView = getCurrentSheetView(pViewData); + if (!pSheetView) + return rAddress; + + std::optional<SortOrderReverser> const& oSortOrder = pSheetView->getSortOrder(); + if (!oSortOrder) + return rAddress; + + SCTAB nTab = rAddress.Tab(); + SCCOL nColumn = rAddress.Col(); + SCROW nRow = rAddress.Row(); + + if (pViewData->GetTabNumber() != nTab) + return rAddress; + + SCROW nUnsortedRow = oSortOrder->unsort(nRow, nColumn); + if (nUnsortedRow != nRow) + { + return ScAddress(nColumn, nUnsortedRow, nTab); + } + return rAddress; +} + +ScMarkData Operation::convertMark(ScMarkData const& rMarkData) +{ + ScViewData* pViewData = ScDocShell::GetViewData(); + + std::shared_ptr<SheetView> pSheetView = getCurrentSheetView(pViewData); + if (!pSheetView) + return rMarkData; + + std::optional<SortOrderReverser> const& oSortOrder = pSheetView->getSortOrder(); + if (!oSortOrder) + return rMarkData; + + ScMarkData aNewMark(rMarkData); + aNewMark.MarkToMulti(); + bool bChanged = false; + + for (const SCTAB& nTab : aNewMark) + { + if (pViewData->GetTabNumber() != nTab) + continue; + + std::vector<std::pair<SCCOL, SCROW>> aMarkedCells; + SortOrderInfo const& rSortInfo = oSortOrder->maSortInfo; + for (SCROW nRow = rSortInfo.mnFirstRow; nRow <= rSortInfo.mnLastRow; ++nRow) + { + for (SCROW nColumn = rSortInfo.mnFirstColumn; nColumn <= rSortInfo.mnLastColumn; + ++nColumn) + { + if (aNewMark.IsCellMarked(nColumn, nRow)) + { + aNewMark.SetMultiMarkArea(ScRange(nColumn, nRow, nTab, nColumn, nRow, nTab), + false); + aMarkedCells.emplace_back(nColumn, nRow); + } + } + } + for (auto & [ nColumn, nRow ] : aMarkedCells) + { + SCROW nUnsortedRow = oSortOrder->unsort(nRow, nColumn); + aNewMark.SetMultiMarkArea( + ScRange(nColumn, nUnsortedRow, nTab, nColumn, nUnsortedRow, nTab), true); + bChanged = true; + } + } + + if (!bChanged) + return rMarkData; + + if (bChanged && !aNewMark.HasAnyMultiMarks()) + aNewMark.ResetMark(); + + aNewMark.MarkToSimple(); + + return aNewMark; +} + bool Operation::checkSheetViewProtection() { sc::SheetViewOperationsTester aSheetViewTester(ScDocShell::GetViewData());
