summaryrefslogtreecommitdiff
path: root/sw/source/core/undo/docundo.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/undo/docundo.cxx')
-rw-r--r--sw/source/core/undo/docundo.cxx123
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()