summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/svl/undo.hxx2
-rw-r--r--svl/source/undo/undo.cxx4
-rw-r--r--sw/qa/extras/tiledrendering/tiledrendering.cxx56
-rw-r--r--sw/source/core/undo/docundo.cxx21
4 files changed, 77 insertions, 6 deletions
diff --git a/include/svl/undo.hxx b/include/svl/undo.hxx
index e0d064b27987..eff352298a5c 100644
--- a/include/svl/undo.hxx
+++ b/include/svl/undo.hxx
@@ -206,7 +206,7 @@ public:
OUString GetUndoActionsInfo() const;
virtual size_t GetRedoActionCount( bool const i_currentLevel = CurrentLevel ) const;
OUString GetRedoActionComment( size_t nNo=0, bool const i_currentLevel = CurrentLevel ) const;
- SfxUndoAction* GetRedoAction() const;
+ SfxUndoAction* GetRedoAction(size_t nNo = 0) const;
/// Get info about all redo actions (comment, view shell id, etc.)
OUString GetRedoActionsInfo() const;
virtual bool Undo();
diff --git a/svl/source/undo/undo.cxx b/svl/source/undo/undo.cxx
index 0c081b152c3a..f84d2cda185a 100644
--- a/svl/source/undo/undo.cxx
+++ b/svl/source/undo/undo.cxx
@@ -747,7 +747,7 @@ size_t SfxUndoManager::ImplGetRedoActionCount_Lock( bool const i_currentLevel )
}
-SfxUndoAction* SfxUndoManager::GetRedoAction() const
+SfxUndoAction* SfxUndoManager::GetRedoAction(size_t nNo) const
{
UndoManagerGuard aGuard( *m_xData );
@@ -756,7 +756,7 @@ SfxUndoAction* SfxUndoManager::GetRedoAction() const
{
return nullptr;
}
- return pUndoArray->maUndoActions[ pUndoArray->nCurUndoAction ].pAction.get();
+ return pUndoArray->maUndoActions[pUndoArray->nCurUndoAction + nNo].pAction.get();
}
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 46f1c781be02..4f0c7e3c5c7b 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -109,6 +109,7 @@ public:
void testUndoInvalidations();
void testUndoLimiting();
void testUndoReordering();
+ void testUndoReorderingRedo();
void testUndoShapeLimiting();
void testUndoDispatch();
void testUndoRepairDispatch();
@@ -191,6 +192,7 @@ public:
CPPUNIT_TEST(testUndoInvalidations);
CPPUNIT_TEST(testUndoLimiting);
CPPUNIT_TEST(testUndoReordering);
+ CPPUNIT_TEST(testUndoReorderingRedo);
CPPUNIT_TEST(testUndoShapeLimiting);
CPPUNIT_TEST(testUndoDispatch);
CPPUNIT_TEST(testUndoRepairDispatch);
@@ -1352,6 +1354,60 @@ void SwTiledRenderingTest::testUndoReordering()
SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
}
+void SwTiledRenderingTest::testUndoReorderingRedo()
+{
+ // Create two views and a document of 2 paragraphs.
+ SwXTextDocument* pXTextDocument = createDoc();
+ SwWrtShell* pWrtShell1 = pXTextDocument->GetDocShell()->GetWrtShell();
+ int nView1 = SfxLokHelper::getView();
+ int nView2 = SfxLokHelper::createView();
+ pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+ SwWrtShell* pWrtShell2 = pXTextDocument->GetDocShell()->GetWrtShell();
+ pWrtShell2->SplitNode();
+ SfxLokHelper::setView(nView1);
+ pWrtShell1->SttEndDoc(/*bStt=*/true);
+ SwTextNode* pTextNode1 = pWrtShell1->GetCursor()->GetNode().GetTextNode();
+ // View 1 types into the first paragraph, twice.
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'f', 0);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'f', 0);
+ Scheduler::ProcessEventsToIdle();
+ // Go to the start of the paragraph, to avoid grouping.
+ pWrtShell1->SttEndDoc(/*bStt=*/true);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 's', 0);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 's', 0);
+ Scheduler::ProcessEventsToIdle();
+ SfxLokHelper::setView(nView2);
+ pWrtShell2->SttEndDoc(/*bStt=*/false);
+ SwTextNode* pTextNode2 = pWrtShell2->GetCursor()->GetNode().GetTextNode();
+ // View 2 types into the second paragraph.
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'z', 0);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'z', 0);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(OUString("sf"), pTextNode1->GetText());
+ CPPUNIT_ASSERT_EQUAL(OUString("z"), pTextNode2->GetText());
+
+ // When view 1 presses undo, twice:
+ SfxLokHelper::setView(nView1);
+ dispatchCommand(mxComponent, ".uno:Undo", {});
+ Scheduler::ProcessEventsToIdle();
+ // First just s(econd) is erased:
+ CPPUNIT_ASSERT_EQUAL(OUString("f"), pTextNode1->GetText());
+ dispatchCommand(mxComponent, ".uno:Undo", {});
+ Scheduler::ProcessEventsToIdle();
+
+ // Then make sure view 1's undo actions are invoked, out of order:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expression: pTextNode1->GetText().isEmpty()
+ // i.e. out of order undo was executed only once, not twice.
+ CPPUNIT_ASSERT(pTextNode1->GetText().isEmpty());
+ // The top undo action is not invoked, as it belongs to view 2.
+ CPPUNIT_ASSERT_EQUAL(OUString("z"), pTextNode2->GetText());
+ SfxLokHelper::setView(nView1);
+ SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
+ SfxLokHelper::setView(nView2);
+ SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
+}
+
void SwTiledRenderingTest::testUndoShapeLimiting()
{
// Load a document and create a view.
diff --git a/sw/source/core/undo/docundo.cxx b/sw/source/core/undo/docundo.cxx
index 0a2b145362f4..8a4f6450605c 100644
--- a/sw/source/core/undo/docundo.cxx
+++ b/sw/source/core/undo/docundo.cxx
@@ -360,10 +360,9 @@ UndoManager::EndUndo(SwUndoId eUndoId, SwRewriter const*const pRewriter)
*/
bool UndoManager::IsViewUndoActionIndependent(const SwView* pView) const
{
- if (GetUndoActionCount() <= 1 || SdrUndoManager::GetRedoActionCount() > 0)
+ if (GetUndoActionCount() <= 1)
{
- // Single or less undo, owned by another view; or redo actions that might depend on the
- // current undo order.
+ // Single or less undo, owned by another view.
return false;
}
@@ -406,6 +405,22 @@ bool UndoManager::IsViewUndoActionIndependent(const SwView* pView) const
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 || pViewSwAction->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 an other view.
+ return false;
+ }
+ }
+
return rViewInsert.IsIndependent(rTopInsert);
}