diff options
author | Noel Grandin <noelgrandin@gmail.com> | 2022-07-28 19:06:59 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2022-07-30 09:02:07 +0200 |
commit | 640a6488a32e8f682788feb6cab01acfffca7fa7 (patch) | |
tree | 05c3d735e99a9afe6f94ef7b260ff420456f8006 /sc/source | |
parent | be32cb92103326da2c744bc85d82b9c788f4e98b (diff) |
sc: allow undo of typing in 2 views independent from each other
This commit follows the same pattern as
commit c72e500ccaf0ce2261c5233b80fba9342778f810
sw: allow undo of typing in 2 views independent from each other
with some changes since calc and writer have different undo/redo
infrastructure on top of SfxUndoManager.
Change-Id: Ib6e7e21caccb94752c01c529b5013553dba8b4f9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137579
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'sc/source')
-rw-r--r-- | sc/source/core/data/document.cxx | 5 | ||||
-rw-r--r-- | sc/source/ui/docshell/docsh.cxx | 1 | ||||
-rw-r--r-- | sc/source/ui/inc/undocell.hxx | 2 | ||||
-rw-r--r-- | sc/source/ui/inc/undomanager.hxx | 45 | ||||
-rw-r--r-- | sc/source/ui/undo/undobase.cxx | 66 | ||||
-rw-r--r-- | sc/source/ui/view/tabvwshb.cxx | 26 |
6 files changed, 138 insertions, 7 deletions
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 9c6f040961f1..53c9223ad5bd 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -88,6 +88,7 @@ #include <recursionhelper.hxx> #include <SparklineGroup.hxx> #include <SparklineList.hxx> +#include <undomanager.hxx> #include <formula/vectortoken.hxx> @@ -6482,14 +6483,14 @@ bool ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const return false; // otherwise not } -SfxUndoManager* ScDocument::GetUndoManager() +ScUndoManager* ScDocument::GetUndoManager() { if (!mpUndoManager) { // to support enhanced text edit for draw objects, use an SdrUndoManager ScMutationGuard aGuard(*this, ScMutationGuardFlags::CORE); - SdrUndoManager* pUndoManager = new SdrUndoManager; + ScUndoManager* pUndoManager = new ScUndoManager; pUndoManager->SetDocShell(GetDocumentShell()); mpUndoManager = pUndoManager; } diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx index 74b174479f72..3198b5a2325f 100644 --- a/sc/source/ui/docshell/docsh.cxx +++ b/sc/source/ui/docshell/docsh.cxx @@ -117,6 +117,7 @@ #include <docparam.hxx> #include "docshimp.hxx" #include <sizedev.hxx> +#include <undomanager.hxx> #include <refreshtimerprotector.hxx> #include <officecfg/Office/Calc.hxx> diff --git a/sc/source/ui/inc/undocell.hxx b/sc/source/ui/inc/undocell.hxx index b013e084fee5..f47aa6ca18bb 100644 --- a/sc/source/ui/inc/undocell.hxx +++ b/sc/source/ui/inc/undocell.hxx @@ -94,6 +94,8 @@ public: virtual OUString GetComment() const override; + const ScAddress& GetPositionAddress() const { return maPos; } + private: ValuesType maOldValues; diff --git a/sc/source/ui/inc/undomanager.hxx b/sc/source/ui/inc/undomanager.hxx new file mode 100644 index 000000000000..4f3ddc282fb4 --- /dev/null +++ b/sc/source/ui/inc/undomanager.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include <svx/sdrundomanager.hxx> + +class SfxViewShell; + +class SC_DLLPUBLIC ScUndoManager : public SdrUndoManager +{ +public: + ~ScUndoManager(); + + /** + * Checks if the topmost undo action owned by pView is independent from the topmost action undo + * action. + */ + bool IsViewUndoActionIndependent(const SfxViewShell* pView) const; + + /// Make these public + using SdrUndoManager::UndoWithContext; + using SdrUndoManager::RedoWithContext; + +private: + static std::optional<ScRange> getAffectedRangeFromUndo(const SfxUndoAction*); +}; + +class ScUndoRedoContext final : public SfxUndoContext +{ +public: + void SetUndoOffset(size_t nUndoOffset) { m_nUndoOffset = nUndoOffset; } + + size_t GetUndoOffset() override { return m_nUndoOffset; } + +private: + size_t m_nUndoOffset = 0; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sc/source/ui/undo/undobase.cxx b/sc/source/ui/undo/undobase.cxx index 8ce8bc9e82f0..b591b38aabc7 100644 --- a/sc/source/ui/undo/undobase.cxx +++ b/sc/source/ui/undo/undobase.cxx @@ -21,6 +21,7 @@ #include <svx/svdundo.hxx> #include <undobase.hxx> +#include <undocell.hxx> #include <refundo.hxx> #include <docsh.hxx> #include <tabvwsh.hxx> @@ -34,6 +35,7 @@ #include <column.hxx> #include <sortparam.hxx> #include <columnspanset.hxx> +#include <undomanager.hxx> ScSimpleUndo::ScSimpleUndo( ScDocShell* pDocSh ) : @@ -613,4 +615,68 @@ bool ScUndoWrapper::CanRepeat(SfxRepeatTarget& rTarget) const return false; } +ScUndoManager::~ScUndoManager() {} + +/** + * Checks if the topmost undo action owned by pView is independent from the topmost action undo + * action. + */ +bool ScUndoManager::IsViewUndoActionIndependent(const SfxViewShell* pView) const +{ + if (GetUndoActionCount() <= 1 || SdrUndoManager::GetRedoActionCount() > 0) + { + // Single or less undo, owned by another view; or redo actions that might depend on the + // current undo order. + return false; + } + + if (!pView) + { + return false; + } + + // Last undo action that doesn't belong to the view. + const SfxUndoAction* pTopAction = GetUndoAction(); + + ViewShellId nViewId = pView->GetViewShellId(); + + // Earlier undo action that belongs to the view, but is not the top one. + const SfxUndoAction* pViewAction = nullptr; + const SfxUndoAction* pAction = GetUndoAction(1); + if (pAction->GetViewShellId() == nViewId) + { + pViewAction = pAction; + } + + if (!pViewAction) + { + // Found no earlier undo action that belongs to the view. + return false; + } + + std::optional<ScRange> topRange = getAffectedRangeFromUndo(pTopAction); + if (!topRange) + return false; + + std::optional<ScRange> viewRange = getAffectedRangeFromUndo(pViewAction); + if (!viewRange) + return false; + + return !topRange->Intersects(*viewRange); +} + +std::optional<ScRange> ScUndoManager::getAffectedRangeFromUndo(const SfxUndoAction* pAction) +{ + auto pListAction = dynamic_cast<const SfxListUndoAction*>(pAction); + if (!pListAction) + return std::nullopt; + if (pListAction->maUndoActions.size() > 1) + return std::nullopt; + auto pTopScUndoEnterData = dynamic_cast<ScUndoEnterData*>(pListAction->maUndoActions[0].pAction.get()); + if (!pTopScUndoEnterData) + return std::nullopt; + return pTopScUndoEnterData->GetPositionAddress(); +} + + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/view/tabvwshb.cxx b/sc/source/ui/view/tabvwshb.cxx index c7265cab1e3b..02ea57f74a5e 100644 --- a/sc/source/ui/view/tabvwshb.cxx +++ b/sc/source/ui/view/tabvwshb.cxx @@ -59,6 +59,7 @@ #include <drawview.hxx> #include <ChartRangeSelectionListener.hxx> #include <gridwin.hxx> +#include <undomanager.hxx> #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> #include <svx/svdpagv.hxx> @@ -709,7 +710,7 @@ bool ScTabViewShell::IsSignatureLineSigned() void ScTabViewShell::ExecuteUndo(SfxRequest& rReq) { SfxShell* pSh = GetViewData().GetDispatcher().GetShell(0); - SfxUndoManager* pUndoManager = pSh->GetUndoManager(); + ScUndoManager* pUndoManager = static_cast<ScUndoManager*>(pSh->GetUndoManager()); const SfxItemSet* pReqArgs = rReq.GetArgs(); ScDocShell* pDocSh = GetViewData().GetDocShell(); @@ -734,6 +735,7 @@ void ScTabViewShell::ExecuteUndo(SfxRequest& rReq) if (pReqArgs && pReqArgs->GetItemState(SID_REPAIRPACKAGE, false, &pItem) == SfxItemState::SET) bRepair = static_cast<const SfxBoolItem*>(pItem)->GetValue(); + sal_uInt16 nUndoOffset = 0; if (comphelper::LibreOfficeKit::isActive() && !bRepair) { SfxUndoAction* pAction = nullptr; @@ -749,11 +751,22 @@ void ScTabViewShell::ExecuteUndo(SfxRequest& rReq) } if (pAction) { + // If another view created the undo action, prevent undoing it from this view. + // Unless we know that the other view's undo action is independent from us. ViewShellId nViewShellId = GetViewShellId(); if (pAction->GetViewShellId() != nViewShellId) { - rReq.SetReturnValue(SfxUInt32Item(SID_UNDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE))); - return; + if (pUndoManager->IsViewUndoActionIndependent(this)) + { + // Execute the undo with an offset: don't undo the top action, but an + // earlier one, since it's independent and that belongs to our view. + nUndoOffset = 1; + } + else + { + rReq.SetReturnValue(SfxUInt32Item(SID_UNDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE))); + return; + } } } } @@ -765,12 +778,15 @@ void ScTabViewShell::ExecuteUndo(SfxRequest& rReq) try { + ScUndoRedoContext aUndoRedoContext; + aUndoRedoContext.SetUndoOffset(nUndoOffset); + for (sal_uInt16 i=0; i<nCount; i++) { if ( bIsUndo ) - pUndoManager->Undo(); + pUndoManager->UndoWithContext(aUndoRedoContext); else - pUndoManager->Redo(); + pUndoManager->RedoWithContext(aUndoRedoContext); } } catch ( const uno::Exception& ) |