sc, out of order undo: allow multiple actions from other view
this is the calc equivalent of
commit c88c2d40d1a4aebc46b25368b80c02bc2f136658
Date: Fri Nov 12 08:39:35 2021 +0100
sw, out of order undo: allow multiple actions from other views
Change-Id: I5acbd1e1cacef7c2e2a549f4d2270e961f576a65
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137652
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/sc/qa/unit/tiledrendering/tiledrendering.cxx b/sc/qa/unit/tiledrendering/tiledrendering.cxx
index 9ed5cf4..559769c 100644
--- a/sc/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sc/qa/unit/tiledrendering/tiledrendering.cxx
@@ -130,6 +130,7 @@ public:
void testInvalidEntrySave();
void testUndoReordering();
void testUndoReorderingRedo();
void testUndoReorderingMulti();
CPPUNIT_TEST_SUITE(ScTiledRenderingTest);
CPPUNIT_TEST(testRowColumnHeaders);
@@ -189,6 +190,7 @@ public:
CPPUNIT_TEST(testInvalidEntrySave);
CPPUNIT_TEST(testUndoReordering);
CPPUNIT_TEST(testUndoReorderingRedo);
CPPUNIT_TEST(testUndoReorderingMulti);
CPPUNIT_TEST_SUITE_END();
private:
@@ -3127,6 +3129,76 @@ void ScTiledRenderingTest::testUndoReorderingRedo()
CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc->GetString(ScAddress(0, 2, 0)));
}
void ScTiledRenderingTest::testUndoReorderingMulti()
{
ScModelObj* pModelObj = createDoc("empty.ods");
CPPUNIT_ASSERT(pModelObj);
ScDocument* pDoc = pModelObj->GetDocument();
CPPUNIT_ASSERT(pDoc);
ScUndoManager* pUndoManager = pDoc->GetUndoManager();
CPPUNIT_ASSERT(pUndoManager);
CPPUNIT_ASSERT_EQUAL(std::size_t(0), pUndoManager->GetUndoActionCount());
// view #1
int nView1 = SfxLokHelper::getView();
ViewCallback aView1;
// view #2
SfxLokHelper::createView();
int nView2 = SfxLokHelper::getView();
pModelObj->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
ViewCallback aView2;
// text edit a cell in view #1
SfxLokHelper::setView(nView1);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::RETURN);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::RETURN);
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT_EQUAL(std::size_t(1), pUndoManager->GetUndoActionCount());
// text edit a different cell in view #2
SfxLokHelper::setView(nView2);
ScTabViewShell* pView2 = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
pView2->SetCursor(0, 2);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'C', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'C', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'C', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'C', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::RETURN);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::RETURN);
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager->GetUndoActionCount());
CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc->GetString(ScAddress(0, 0, 0)));
CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc->GetString(ScAddress(0, 2, 0)));
// and another cell in view #2
pView2->SetCursor(0, 3);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'D', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'D', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'D', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'D', 0);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::RETURN);
pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::RETURN);
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT_EQUAL(std::size_t(3), pUndoManager->GetUndoActionCount());
CPPUNIT_ASSERT_EQUAL(OUString("xx"), pDoc->GetString(ScAddress(0, 0, 0)));
CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc->GetString(ScAddress(0, 2, 0)));
CPPUNIT_ASSERT_EQUAL(OUString("DD"), pDoc->GetString(ScAddress(0, 3, 0)));
// View 1 presses undo
SfxLokHelper::setView(nView1);
dispatchCommand(mxComponent, ".uno:Undo", {});
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT_EQUAL(std::size_t(2), pUndoManager->GetUndoActionCount());
CPPUNIT_ASSERT_EQUAL(OUString(""), pDoc->GetString(ScAddress(0, 0, 0)));
CPPUNIT_ASSERT_EQUAL(OUString("CC"), pDoc->GetString(ScAddress(0, 2, 0)));
CPPUNIT_ASSERT_EQUAL(OUString("DD"), pDoc->GetString(ScAddress(0, 3, 0)));
}
}
CPPUNIT_TEST_SUITE_REGISTRATION(ScTiledRenderingTest);
diff --git a/sc/source/ui/inc/undomanager.hxx b/sc/source/ui/inc/undomanager.hxx
index da254a0..7ec3db6 100644
--- a/sc/source/ui/inc/undomanager.hxx
+++ b/sc/source/ui/inc/undomanager.hxx
@@ -20,9 +20,9 @@ public:
/**
* Checks if the topmost undo action owned by pView is independent from the topmost action undo
* action.
* action. Sets rOffset to the offset of that independent undo action on success.
*/
bool IsViewUndoActionIndependent(const SfxViewShell* pView) const;
bool IsViewUndoActionIndependent(const SfxViewShell* pView, sal_uInt16& rOffset) const;
/// Make these public
using SdrUndoManager::UndoWithContext;
diff --git a/sc/source/ui/undo/undobase.cxx b/sc/source/ui/undo/undobase.cxx
index 250c786..31f1e41 100644
--- a/sc/source/ui/undo/undobase.cxx
+++ b/sc/source/ui/undo/undobase.cxx
@@ -621,7 +621,7 @@ 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
bool ScUndoManager::IsViewUndoActionIndependent(const SfxViewShell* pView, sal_uInt16& rOffset) const
{
if (GetUndoActionCount() <= 1)
{
@@ -641,10 +641,16 @@ bool ScUndoManager::IsViewUndoActionIndependent(const SfxViewShell* pView) const
// 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)
size_t nOffset = 0;
for (size_t i = 0; i < GetUndoActionCount(); ++i)
{
pViewAction = pAction;
const SfxUndoAction* pAction = GetUndoAction(i);
if (pAction->GetViewShellId() == nViewId)
{
pViewAction = pAction;
nOffset = i;
break;
}
}
if (!pViewAction)
@@ -679,6 +685,7 @@ bool ScUndoManager::IsViewUndoActionIndependent(const SfxViewShell* pView) const
}
}
rOffset = nOffset;
return true;
}
diff --git a/sc/source/ui/view/tabvwshb.cxx b/sc/source/ui/view/tabvwshb.cxx
index 02ea57f..7052820 100644
--- a/sc/source/ui/view/tabvwshb.cxx
+++ b/sc/source/ui/view/tabvwshb.cxx
@@ -756,11 +756,12 @@ void ScTabViewShell::ExecuteUndo(SfxRequest& rReq)
ViewShellId nViewShellId = GetViewShellId();
if (pAction->GetViewShellId() != nViewShellId)
{
if (pUndoManager->IsViewUndoActionIndependent(this))
sal_uInt16 nOffset = 0;
if (pUndoManager->IsViewUndoActionIndependent(this, nOffset))
{
// 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;
nUndoOffset += nOffset;
}
else
{