diff options
Diffstat (limited to 'sw/source/core/undo/docundo.cxx')
-rw-r--r-- | sw/source/core/undo/docundo.cxx | 123 |
1 files changed, 109 insertions, 14 deletions
diff --git a/sw/source/core/undo/docundo.cxx b/sw/source/core/undo/docundo.cxx index 6e350836fc20..57202fe3632a 100644 --- a/sw/source/core/undo/docundo.cxx +++ b/sw/source/core/undo/docundo.cxx @@ -23,12 +23,14 @@ #include <doc.hxx> #include <docsh.hxx> +#include <utility> #include <view.hxx> #include <drawdoc.hxx> #include <ndarr.hxx> #include <pam.hxx> #include <swundo.hxx> #include <UndoCore.hxx> +#include <wrtsh.hxx> #include <editsh.hxx> #include <unobaseclass.hxx> #include <IDocumentDrawModelAccess.hxx> @@ -39,6 +41,10 @@ #include <sfx2/viewfrm.hxx> #include <sfx2/bindings.hxx> +#include <osl/diagnose.h> +#include <o3tl/temporary.hxx> + +#include <UndoInsert.hxx> using namespace ::com::sun::star; @@ -47,14 +53,14 @@ using namespace ::com::sun::star; namespace sw { -UndoManager::UndoManager(std::shared_ptr<SwNodes> const & xUndoNodes, +UndoManager::UndoManager(std::shared_ptr<SwNodes> xUndoNodes, IDocumentDrawModelAccess & rDrawModelAccess, IDocumentRedlineAccess & rRedlineAccess, IDocumentState & rState) : m_rDrawModelAccess(rDrawModelAccess) , m_rRedlineAccess(rRedlineAccess) , m_rState(rState) - , m_xUndoNodes(xUndoNodes) + , m_xUndoNodes(std::move(xUndoNodes)) , m_bGroupUndo(true) , m_bDrawUndo(true) , m_bRepair(false) @@ -351,6 +357,88 @@ UndoManager::EndUndo(SwUndoId eUndoId, SwRewriter const*const pRewriter) return eUndoId; } +/** + * Checks if the topmost undo action owned by pView is independent from the topmost action undo + * action. + */ +bool UndoManager::IsViewUndoActionIndependent(const SwView* pView, sal_uInt16& rOffset) const +{ + if (GetUndoActionCount() <= 1) + { + // Single or less undo, owned by another view. + 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; + size_t nOffset = 0; + for (size_t i = 0; i < GetUndoActionCount(); ++i) + { + const SfxUndoAction* pAction = GetUndoAction(i); + if (pAction->GetViewShellId() == nViewId) + { + pViewAction = pAction; + nOffset = i; + break; + } + } + + if (!pViewAction) + { + // Found no earlier undo action that belongs to the view. + return false; + } + + auto pTopSwAction = dynamic_cast<const SwUndo*>(pTopAction); + if (!pTopSwAction || pTopSwAction->GetId() != SwUndoId::TYPING) + { + return false; + } + + auto pViewSwAction = dynamic_cast<const SwUndo*>(pViewAction); + if (!pViewSwAction || pViewSwAction->GetId() != SwUndoId::TYPING) + { + return false; + } + + const auto& rTopInsert = *static_cast<const SwUndoInsert*>(pTopSwAction); + const auto& rViewInsert = *static_cast<const SwUndoInsert*>(pViewSwAction); + + for (size_t i = 0; i < GetRedoActionCount(); ++i) + { + auto pRedoAction = dynamic_cast<const SwUndo*>(GetRedoAction(i)); + if (!pRedoAction || pRedoAction->GetId() != SwUndoId::TYPING) + { + return false; + } + + const auto& rRedoInsert = *static_cast<const SwUndoInsert*>(pRedoAction); + if (!rViewInsert.IsIndependent(rRedoInsert) && rRedoInsert.GetViewShellId() != nViewId) + { + // Dependent redo action and owned by another view. + return false; + } + } + + if (!rViewInsert.IsIndependent(rTopInsert)) + { + return false; + } + + rOffset = nOffset; + return true; +} + bool UndoManager::GetLastUndoInfo( OUString *const o_pStr, SwUndoId *const o_pId, const SwView* pView) const @@ -368,7 +456,9 @@ UndoManager::GetLastUndoInfo( { // If another view created the undo action, prevent undoing it from this view. ViewShellId nViewShellId = pView ? pView->GetViewShellId() : m_pDocShell->GetView()->GetViewShellId(); - if (pAction->GetViewShellId() != nViewShellId) + // Unless we know that the other view's undo action is independent from us. + if (pAction->GetViewShellId() != nViewShellId + && !IsViewUndoActionIndependent(pView, o3tl::temporary(sal_uInt16()))) { if (o_pId) { @@ -537,7 +627,7 @@ void UndoManager::AddUndoAction(std::unique_ptr<SfxUndoAction> pAction, bool bTr } // if the undo nodes array is too large, delete some actions - while (UNDO_ACTION_LIMIT < GetUndoNodes().Count()) + while (UNDO_ACTION_LIMIT < sal_Int32(GetUndoNodes().Count())) { RemoveOldestUndoAction(); } @@ -571,14 +661,16 @@ private: } -bool UndoManager::impl_DoUndoRedo(UndoOrRedoType undoOrRedo) +bool UndoManager::impl_DoUndoRedo(UndoOrRedoType undoOrRedo, size_t nUndoOffset) { SwDoc & rDoc(GetUndoNodes().GetDoc()); UnoActionContext c(& rDoc); // exception-safe StartAllAction/EndAllAction - SwEditShell *const pEditShell( rDoc.GetEditShell() ); - + SwView* pViewShell = dynamic_cast<SwView*>(SfxViewShell::Current()); + SwEditShell *const pEditShell( + comphelper::LibreOfficeKit::isActive() && pViewShell ? pViewShell->GetWrtShellPtr() + : rDoc.GetEditShell()); OSL_ENSURE(pEditShell, "sw::UndoManager needs a SwEditShell!"); if (!pEditShell) { @@ -600,6 +692,7 @@ bool UndoManager::impl_DoUndoRedo(UndoOrRedoType undoOrRedo) bool bRet(false); ::sw::UndoRedoContext context(rDoc, *pEditShell); + context.SetUndoOffset(nUndoOffset); // N.B. these may throw! if (UndoOrRedoType::Undo == undoOrRedo) @@ -629,7 +722,9 @@ bool UndoManager::impl_DoUndoRedo(UndoOrRedoType undoOrRedo) return bRet; } -bool UndoManager::Undo() +bool UndoManager::Undo() { return UndoWithOffset(0); } + +bool UndoManager::UndoWithOffset(size_t nUndoOffset) { if(isTextEditActive()) { @@ -637,7 +732,7 @@ bool UndoManager::Undo() } else { - return impl_DoUndoRedo(UndoOrRedoType::Undo); + return impl_DoUndoRedo(UndoOrRedoType::Undo, nUndoOffset); } } @@ -649,20 +744,20 @@ bool UndoManager::Redo() } else { - return impl_DoUndoRedo(UndoOrRedoType::Redo); + return impl_DoUndoRedo(UndoOrRedoType::Redo, /*nUndoOffset=*/0); } } void UndoManager::dumpAsXml(xmlTextWriterPtr pWriter) const { - xmlTextWriterStartElement(pWriter, BAD_CAST("swUndoManager")); + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("swUndoManager")); SdrUndoManager::dumpAsXml(pWriter); - xmlTextWriterStartElement(pWriter, BAD_CAST("m_xUndoNodes")); + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("m_xUndoNodes")); m_xUndoNodes->dumpAsXml(pWriter); - xmlTextWriterEndElement(pWriter); + (void)xmlTextWriterEndElement(pWriter); - xmlTextWriterEndElement(pWriter); + (void)xmlTextWriterEndElement(pWriter); } void UndoManager::EmptyActionsChanged() |