summaryrefslogtreecommitdiff
path: root/sd
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2021-10-07 16:48:46 +0200
committerTomaž Vajngerl <quikee@gmail.com>2021-10-20 16:25:16 +0200
commitc175c1dc19d0edc8ca66e39f0b4b8af04e3d6c87 (patch)
tree04e074d7e034642a4e4025e106dc20db09ca9ee2 /sd
parent85d53dafd8332fc9c7bf71d6cc9da19ab9d8e252 (diff)
svx: Don't end text edit mode for all views
This allows multiple views to not disturb each other editing inside a impress document. With the ending of text edit for all views still enabled, one view can cancel other views text editing just by moving or resizing a unrelated shape in the document. To make this possible we also need a view-local undo manager for the text edit mode, which is independent of the document undo manager. When the text edit mode ends, all the changes will be added as one change to the document undo stack. This prevents any conflicts in the undo stack that could be made when 2 views are editing the same document at the same time. This also adds the test for the new use case and changes the existing tests to reflect the change. Change-Id: I04edb4f91d7e111a490c946f7121cbca75f818d7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/123220 Tested-by: Tomaž Vajngerl <quikee@gmail.com> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'sd')
-rw-r--r--sd/qa/uitest/impress_tests/tdf130440.py13
-rw-r--r--sd/qa/unit/misc-tests.cxx34
-rw-r--r--sd/qa/unit/tiledrendering/data/TextBoxAndRect.odgbin0 -> 10474 bytes
-rw-r--r--sd/qa/unit/tiledrendering/tiledrendering.cxx341
-rw-r--r--sd/source/ui/inc/View.hxx3
-rw-r--r--sd/source/ui/view/drviews1.cxx4
-rw-r--r--sd/source/ui/view/sdview.cxx10
7 files changed, 378 insertions, 27 deletions
diff --git a/sd/qa/uitest/impress_tests/tdf130440.py b/sd/qa/uitest/impress_tests/tdf130440.py
index ea6b398a2841..0672e14f2f59 100644
--- a/sd/qa/uitest/impress_tests/tdf130440.py
+++ b/sd/qa/uitest/impress_tests/tdf130440.py
@@ -24,24 +24,31 @@ class tdf129346(UITestCase):
xDoc = self.xUITest.getTopFocusWindow()
xEdit = xDoc.getChild("impress_win")
+ # Type "test" into the text box
xEdit.executeAction("TYPE", mkPropertyValues({"TEXT":"test"}))
-
- self.xUITest.executeCommand(".uno:Undo")
+ # Go to Page 1, which also forces to end edit box
+ xEdit.executeAction("GOTO", mkPropertyValues({"PAGE": "1"}))
xToolkit.processEventsToIdle()
- self.assertEqual(document.CurrentController.getCurrentPage().Number, 2)
+ # We should be at Page 1
+ self.assertEqual(document.CurrentController.getCurrentPage().Number, 1)
+
+ # Undo sends us to Page 2 and undo-es the text edit
self.xUITest.executeCommand(".uno:Undo")
xToolkit.processEventsToIdle()
self.assertEqual(document.CurrentController.getCurrentPage().Number, 2)
+ # Undo sends us to page 1 and undo-es command ".uno:DuplicatePage"
self.xUITest.executeCommand(".uno:Undo")
xToolkit.processEventsToIdle()
self.assertEqual(document.CurrentController.getCurrentPage().Number, 1)
+ # Redo ".uno:DuplicatePage" - we go to Page 2
self.xUITest.executeCommand(".uno:Redo")
xToolkit.processEventsToIdle()
self.assertEqual(document.CurrentController.getCurrentPage().Number, 2)
+ # Redo text edit
self.xUITest.executeCommand(".uno:Redo")
xDoc = self.xUITest.getTopFocusWindow()
diff --git a/sd/qa/unit/misc-tests.cxx b/sd/qa/unit/misc-tests.cxx
index ba888c280601..dc2f4324c240 100644
--- a/sd/qa/unit/misc-tests.cxx
+++ b/sd/qa/unit/misc-tests.cxx
@@ -70,7 +70,7 @@ public:
void testTdf96206();
void testTdf96708();
void testTdf99396();
- void testTdf99396TextEdit();
+ void testTableObjectUndoTest();
void testFillGradient();
void testTdf44774();
void testTdf38225();
@@ -93,7 +93,7 @@ public:
CPPUNIT_TEST(testTdf96206);
CPPUNIT_TEST(testTdf96708);
CPPUNIT_TEST(testTdf99396);
- CPPUNIT_TEST(testTdf99396TextEdit);
+ CPPUNIT_TEST(testTableObjectUndoTest);
CPPUNIT_TEST(testFillGradient);
CPPUNIT_TEST(testTdf44774);
CPPUNIT_TEST(testTdf38225);
@@ -251,8 +251,10 @@ void SdMiscTest::testTdf99396()
xDocSh->DoClose();
}
-void SdMiscTest::testTdf99396TextEdit()
+void SdMiscTest::testTableObjectUndoTest()
{
+ // See tdf#99396 for the issue
+
// Load the document and select the table.
sd::DrawDocShellRef xDocSh = Load(m_directories.getURLFromSrc(u"/sd/qa/unit/data/tdf99396.odp"), ODP);
sd::ViewShell* pViewShell = xDocSh->GetViewShell();
@@ -278,14 +280,26 @@ void SdMiscTest::testTdf99396TextEdit()
const SfxItemSet* pArgs = aRequest.GetArgs();
pView->SetAttributes(*pArgs);
}
+ const auto& pLocalUndoManager = pView->getViewLocalUndoManager();
+ CPPUNIT_ASSERT_EQUAL(size_t(1), pLocalUndoManager->GetUndoActionCount());
+ CPPUNIT_ASSERT_EQUAL(OUString("Apply attributes"), pLocalUndoManager->GetUndoActionComment());
{
auto pTableController = dynamic_cast<sdr::table::SvxTableController*>(pView->getSelectionController().get());
CPPUNIT_ASSERT(pTableController);
SfxRequest aRequest(pViewShell->GetViewFrame(), SID_TABLE_VERT_BOTTOM);
pTableController->Execute(aRequest);
}
+ // Global change "Format cell" is applied only - Change the vertical alignment to "Bottom"
+ CPPUNIT_ASSERT_EQUAL(size_t(1), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionCount());
+ CPPUNIT_ASSERT_EQUAL(OUString("Format cell"), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionComment());
+
pView->SdrEndTextEdit();
+ // End of text edit, so the text edit action is added to the undo stack
+ CPPUNIT_ASSERT_EQUAL(size_t(2), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionCount());
+ CPPUNIT_ASSERT_EQUAL(OUString("Edit text of Table"), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionComment(0));
+ CPPUNIT_ASSERT_EQUAL(OUString("Format cell"), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionComment(1));
+
// Check that the result is what we expect.
{
uno::Reference<table::XTable> xTable = pTableObject->getTable();
@@ -303,6 +317,10 @@ void SdMiscTest::testTdf99396TextEdit()
// Now undo.
xDocSh->GetUndoManager()->Undo();
+ // Undoing the last action - one left
+ CPPUNIT_ASSERT_EQUAL(size_t(1), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionCount());
+ CPPUNIT_ASSERT_EQUAL(OUString("Format cell"), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionComment(0));
+
// Check again that the result is what we expect.
{
uno::Reference<table::XTable> xTable = pTableObject->getTable();
@@ -318,6 +336,9 @@ void SdMiscTest::testTdf99396TextEdit()
CPPUNIT_ASSERT_EQUAL(SvxAdjust::Center, pAdjust->GetAdjust());
}
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(size_t(1), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionCount());
+ CPPUNIT_ASSERT_EQUAL(OUString("Format cell"), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionComment(0));
/*
* now test tdf#103950 - Undo does not revert bundled font size changes for table cells
@@ -328,8 +349,11 @@ void SdMiscTest::testTdf99396TextEdit()
SfxRequest aRequest(pViewShell->GetViewFrame(), SID_GROW_FONT_SIZE);
static_cast<sd::DrawViewShell*>(pViewShell)->ExecChar(aRequest);
}
- CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionCount());
-
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionCount());
+ CPPUNIT_ASSERT_EQUAL(OUString("Apply attributes to Table"), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionComment(0));
+ CPPUNIT_ASSERT_EQUAL(OUString("Grow font size"), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionComment(1));
+ CPPUNIT_ASSERT_EQUAL(OUString("Format cell"), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionComment(2));
xDocSh->DoClose();
}
diff --git a/sd/qa/unit/tiledrendering/data/TextBoxAndRect.odg b/sd/qa/unit/tiledrendering/data/TextBoxAndRect.odg
new file mode 100644
index 000000000000..aa1a37b83147
--- /dev/null
+++ b/sd/qa/unit/tiledrendering/data/TextBoxAndRect.odg
Binary files differ
diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx
index 89ab2d62b815..a41e050bac06 100644
--- a/sd/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx
@@ -139,6 +139,7 @@ public:
void testMoveShapeHandle();
void testDeleteTable();
void testPasteUndo();
+ void testShapeEditInMultipleViews();
CPPUNIT_TEST_SUITE(SdTiledRenderingTest);
CPPUNIT_TEST(testCreateDestroy);
@@ -197,7 +198,7 @@ public:
CPPUNIT_TEST(testMoveShapeHandle);
CPPUNIT_TEST(testDeleteTable);
CPPUNIT_TEST(testPasteUndo);
-
+ CPPUNIT_TEST(testShapeEditInMultipleViews);
CPPUNIT_TEST_SUITE_END();
virtual void libreOfficeKitViewCallback(int nType, const char* pPayload) override;
@@ -1325,6 +1326,38 @@ void SdTiledRenderingTest::testUndoLimiting()
Scheduler::ProcessEventsToIdle();
CPPUNIT_ASSERT(pViewShell1->GetView()->IsTextEdit());
+ // View2 UNDO stack should be empty
+ {
+ SfxRequest aReq2(SID_UNDO, SfxCallMode::SLOT, pXImpressDocument->GetDocShell()->GetDoc()->GetPool());
+ aReq2.AppendItem(SfxUInt16Item(SID_UNDO, 1));
+ pViewShell2->ExecuteSlot(aReq2);
+ const auto* pReturnValue = aReq2.GetReturnValue();
+ CPPUNIT_ASSERT(!pReturnValue);
+ }
+
+ // View1 can UNDO
+ {
+ SfxRequest aReq1(SID_UNDO, SfxCallMode::SLOT, pXImpressDocument->GetDocShell()->GetDoc()->GetPool());
+ aReq1.AppendItem(SfxUInt16Item(SID_UNDO, 1));
+ pViewShell1->ExecuteSlot(aReq1);
+ CPPUNIT_ASSERT(aReq1.IsDone());
+ }
+
+ // View1 can REDO
+ {
+ SfxRequest aReq1(SID_REDO, SfxCallMode::SLOT, pXImpressDocument->GetDocShell()->GetDoc()->GetPool());
+ aReq1.AppendItem(SfxUInt16Item(SID_REDO, 1));
+ pViewShell1->ExecuteSlot(aReq1);
+ CPPUNIT_ASSERT(aReq1.IsDone());
+ }
+
+ // Exit text edit mode
+ pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE);
+ pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE);
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT(!pViewShell1->GetView()->IsTextEdit());
+
// Now check view2 cannot undo actions.
{
SfxRequest aReq2(SID_UNDO, SfxCallMode::SLOT, pXImpressDocument->GetDocShell()->GetDoc()->GetPool());
@@ -2062,11 +2095,19 @@ void SdTiledRenderingTest::testDisableUndoRepair()
{
// Load the document.
SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp");
+
+ // Create View 1
SfxViewShell* pView1 = SfxViewShell::Current();
+ sd::ViewShell* pViewShell1 = pXImpressDocument->GetDocShell()->GetViewShell();
int nView1 = SfxLokHelper::getView();
+
+ // Create View 2
SfxLokHelper::createView();
SfxViewShell* pView2 = SfxViewShell::Current();
+ sd::ViewShell* pViewShell2 = pXImpressDocument->GetDocShell()->GetViewShell();
int nView2 = SfxLokHelper::getView();
+
+ // Check UNDO is disabled
{
std::unique_ptr<SfxPoolItem> pItem1;
std::unique_ptr<SfxPoolItem> pItem2;
@@ -2081,15 +2122,24 @@ void SdTiledRenderingTest::testDisableUndoRepair()
pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'h', 0);
pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'h', 0);
Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT(pViewShell1->GetView()->IsTextEdit());
+ pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE);
+ pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT(!pViewShell1->GetView()->IsTextEdit());
+
+ // Check
{
std::unique_ptr<SfxPoolItem> xItem1;
- std::unique_ptr<SfxPoolItem> xItem2;
pView1->GetViewFrame()->GetBindings().QueryState(SID_UNDO, xItem1);
+ const auto* pUInt32Item1 = dynamic_cast<const SfxUInt32Item*>(xItem1.get());
+ CPPUNIT_ASSERT(!pUInt32Item1);
+
+ std::unique_ptr<SfxPoolItem> xItem2;
pView2->GetViewFrame()->GetBindings().QueryState(SID_UNDO, xItem2);
- CPPUNIT_ASSERT(!dynamic_cast< const SfxUInt32Item* >(xItem1.get()));
- const SfxUInt32Item* pUInt32Item = dynamic_cast<const SfxUInt32Item*>(xItem2.get());
- CPPUNIT_ASSERT(pUInt32Item);
- CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(SID_REPAIRPACKAGE), pUInt32Item->GetValue());
+ const auto* pUInt32Item2 = dynamic_cast<const SfxUInt32Item*>(xItem2.get());
+ CPPUNIT_ASSERT(pUInt32Item2);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(SID_REPAIRPACKAGE), pUInt32Item2->GetValue());
}
// Insert a character in the second view.
@@ -2100,15 +2150,23 @@ void SdTiledRenderingTest::testDisableUndoRepair()
pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'c', 0);
pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'c', 0);
Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT(pViewShell2->GetView()->IsTextEdit());
+ pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE);
+ pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT(!pViewShell2->GetView()->IsTextEdit());
+
+ // Check
{
std::unique_ptr<SfxPoolItem> xItem1;
- std::unique_ptr<SfxPoolItem> xItem2;
pView1->GetViewFrame()->GetBindings().QueryState(SID_UNDO, xItem1);
- pView2->GetViewFrame()->GetBindings().QueryState(SID_UNDO, xItem2);
- CPPUNIT_ASSERT(!dynamic_cast< const SfxUInt32Item* >(xItem2.get()));
const SfxUInt32Item* pUInt32Item = dynamic_cast<const SfxUInt32Item*>(xItem1.get());
CPPUNIT_ASSERT(pUInt32Item);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(SID_REPAIRPACKAGE), pUInt32Item->GetValue());
+
+ std::unique_ptr<SfxPoolItem> xItem2;
+ pView2->GetViewFrame()->GetBindings().QueryState(SID_UNDO, xItem2);
+ CPPUNIT_ASSERT(!dynamic_cast< const SfxUInt32Item* >(xItem2.get()));
}
}
@@ -2125,17 +2183,20 @@ void SdTiledRenderingTest::testDocumentRepair()
SfxLokHelper::createView();
SfxViewShell* pView2 = SfxViewShell::Current();
int nView2 = SfxLokHelper::getView();
+ sd::ViewShell* pViewShell2 = pXImpressDocument->GetDocShell()->GetViewShell();
+
CPPUNIT_ASSERT(pView1 != pView2);
{
std::unique_ptr<SfxPoolItem> xItem1;
- std::unique_ptr<SfxPoolItem> xItem2;
pView1->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR, xItem1);
- pView2->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR, xItem2);
const SfxBoolItem* pItem1 = dynamic_cast<const SfxBoolItem*>(xItem1.get());
- const SfxBoolItem* pItem2 = dynamic_cast<const SfxBoolItem*>(xItem2.get());
CPPUNIT_ASSERT(pItem1);
- CPPUNIT_ASSERT(pItem2);
CPPUNIT_ASSERT_EQUAL(false, pItem1->GetValue());
+
+ std::unique_ptr<SfxPoolItem> xItem2;
+ pView2->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR, xItem2);
+ const SfxBoolItem* pItem2 = dynamic_cast<const SfxBoolItem*>(xItem2.get());
+ CPPUNIT_ASSERT(pItem2);
CPPUNIT_ASSERT_EQUAL(false, pItem2->GetValue());
}
@@ -2147,16 +2208,23 @@ void SdTiledRenderingTest::testDocumentRepair()
pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'c', 0);
pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'c', 0);
Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT(pViewShell2->GetView()->IsTextEdit());
+ pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::ESCAPE);
+ pXImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::ESCAPE);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT(!pViewShell2->GetView()->IsTextEdit());
+
{
std::unique_ptr<SfxPoolItem> xItem1;
- std::unique_ptr<SfxPoolItem> xItem2;
pView1->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR, xItem1);
- pView2->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR, xItem2);
const SfxBoolItem* pItem1 = dynamic_cast<const SfxBoolItem*>(xItem1.get());
- const SfxBoolItem* pItem2 = dynamic_cast<const SfxBoolItem*>(xItem2.get());
CPPUNIT_ASSERT(pItem1);
- CPPUNIT_ASSERT(pItem2);
CPPUNIT_ASSERT_EQUAL(true, pItem1->GetValue());
+
+ std::unique_ptr<SfxPoolItem> xItem2;
+ pView2->GetViewFrame()->GetBindings().QueryState(SID_DOC_REPAIR, xItem2);
+ const SfxBoolItem* pItem2 = dynamic_cast<const SfxBoolItem*>(xItem2.get());
+ CPPUNIT_ASSERT(pItem2);
CPPUNIT_ASSERT_EQUAL(true, pItem2->GetValue());
}
}
@@ -2681,7 +2749,6 @@ void SdTiledRenderingTest::testMoveShapeHandle()
CPPUNIT_ASSERT_EQUAL(x-1, oldX);
CPPUNIT_ASSERT_EQUAL(y-1, oldY);
}
-
}
void SdTiledRenderingTest::testPasteUndo()
@@ -2718,6 +2785,244 @@ void SdTiledRenderingTest::testPasteUndo()
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aSelection.nStartPos);
}
+void SdTiledRenderingTest::testShapeEditInMultipleViews()
+{
+ SdXImpressDocument* pXImpressDocument = createDoc("TextBoxAndRect.odg");
+ pXImpressDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+ SdDrawDocument* pDocument = pXImpressDocument->GetDoc();
+
+ // Create view 1
+ const int nView1 = SfxLokHelper::getView();
+ sd::ViewShell* pViewShell1 = pXImpressDocument->GetDocShell()->GetViewShell();
+ SdrView* pView1 = pViewShell1->GetView();
+ Scheduler::ProcessEventsToIdle();
+
+ // Create view 2
+ SfxLokHelper::createView();
+ const int nView2 = SfxLokHelper::getView();
+ CPPUNIT_ASSERT(nView1 != nView2);
+
+ sd::ViewShell* pViewShell2 = pXImpressDocument->GetDocShell()->GetViewShell();
+ SdrView* pView2 = pViewShell2->GetView();
+ Scheduler::ProcessEventsToIdle();
+
+ // Switch to view 1
+ SfxLokHelper::setView(nView1);
+
+ SdPage* pPage1 = pViewShell1->GetActualPage();
+
+ SdrObject* pTextBoxObject = pPage1->GetObj(0);
+ CPPUNIT_ASSERT_EQUAL(OUString("Text Box"), pTextBoxObject->GetName());
+
+ SdrObject* pRectangleObject = pPage1->GetObj(1);
+ CPPUNIT_ASSERT_EQUAL(OUString("Rect"), pRectangleObject->GetName());
+
+ SdrObject* pTableObject = pPage1->GetObj(2);
+ CPPUNIT_ASSERT_EQUAL(OUString("Table1"), pTableObject->GetName());
+
+ // Scenario 1
+ // 2 shapes - "Text Box" and "Rect"
+ // View1 - "Text Box" enters text edit mode, View 2 - moves the "Rect" around
+ {
+ sd::UndoManager* pUndoManager = pDocument->GetUndoManager();
+ CPPUNIT_ASSERT_EQUAL(size_t(0), pUndoManager->GetUndoActionCount());
+
+ pView1->SdrBeginTextEdit(pTextBoxObject);
+ CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+
+ // Local undo count for View1 is 0
+ CPPUNIT_ASSERT_EQUAL(size_t(0), pView1->getViewLocalUndoManager()->GetUndoActionCount());
+ // Write 'test' in View1
+ SfxStringItem aInputString(SID_ATTR_CHAR, "test");
+ pViewShell1->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, SfxCallMode::SYNCHRON, { &aInputString });
+ // Local undo count for View1 is now 1
+ CPPUNIT_ASSERT_EQUAL(size_t(1), pView1->getViewLocalUndoManager()->GetUndoActionCount());
+
+ // Mark rectangle object
+ pView2->MarkObj(pRectangleObject, pView2->GetSdrPageView());
+
+ // Check the initial position of the object
+ tools::Rectangle aRectangle = pRectangleObject->GetLogicRect();
+ CPPUNIT_ASSERT_EQUAL(6250L, aRectangle.TopLeft().X());
+ CPPUNIT_ASSERT_EQUAL(7000L, aRectangle.TopLeft().Y());
+ CPPUNIT_ASSERT_EQUAL(6501L, aRectangle.GetWidth());
+ CPPUNIT_ASSERT_EQUAL(4501L, aRectangle.GetHeight());
+
+ // On View2 - Move handle 0 on the shape to a new mosition - resize
+ Point aNewPosition = aRectangle.TopLeft() + Point(-1250, -1000);
+ pView2->MoveShapeHandle(0, aNewPosition, -1);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(size_t(1), pUndoManager->GetUndoActionCount());
+
+ // Check the object has a new size
+ aRectangle = pRectangleObject->GetLogicRect();
+ CPPUNIT_ASSERT_EQUAL(5000L, aRectangle.TopLeft().X());
+ CPPUNIT_ASSERT_EQUAL(6000L, aRectangle.TopLeft().Y());
+ CPPUNIT_ASSERT_EQUAL(7751L, aRectangle.GetWidth());
+ CPPUNIT_ASSERT_EQUAL(5501L, aRectangle.GetHeight());
+
+ // View1 is still in text edit mode...
+ CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+
+ // On View2 - relative move the shape to a different position
+ pView2->MoveMarkedObj(Size(1000, 2000), /*bCopy=*/false);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(size_t(2), pUndoManager->GetUndoActionCount());
+
+ // Check the object is at a different position
+ aRectangle = pRectangleObject->GetLogicRect();
+ CPPUNIT_ASSERT_EQUAL(6000L, aRectangle.TopLeft().X());
+ CPPUNIT_ASSERT_EQUAL(8000L, aRectangle.TopLeft().Y());
+ CPPUNIT_ASSERT_EQUAL(7751L, aRectangle.GetWidth());
+ CPPUNIT_ASSERT_EQUAL(5501L, aRectangle.GetHeight());
+
+ // View1 is still in text edit mode...
+ CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+
+ // End Text edit - check undo count increase from 2 -> 3
+ CPPUNIT_ASSERT_EQUAL(size_t(2), pUndoManager->GetUndoActionCount());
+ pView1->SdrEndTextEdit();
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(size_t(3), pUndoManager->GetUndoActionCount());
+
+ // Check that both views exited the text edit mode
+ CPPUNIT_ASSERT_EQUAL(false, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+ }
+
+ // Scenario 2
+ // 1 shapes - "Text Box"
+ // View1 - "Text Box" enters text edit mode, View 2 - moves the "Text Box" around
+ {
+ sd::UndoManager* pUndoManager = pDocument->GetUndoManager();
+ CPPUNIT_ASSERT_EQUAL(size_t(3), pUndoManager->GetUndoActionCount());
+
+ pView1->SdrBeginTextEdit(pTextBoxObject);
+ CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+
+ // Local undo count for View1 is 0
+ CPPUNIT_ASSERT_EQUAL(size_t(0), pView1->getViewLocalUndoManager()->GetUndoActionCount());
+ // Write 'test' in View1
+ SfxStringItem aInputString(SID_ATTR_CHAR, "test");
+ pViewShell1->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, SfxCallMode::SYNCHRON, { &aInputString });
+ // Local undo count for View1 is now 1
+ CPPUNIT_ASSERT_EQUAL(size_t(1), pView1->getViewLocalUndoManager()->GetUndoActionCount());
+
+ // Mark rectangle object
+ pView2->MarkObj(pTextBoxObject, pView2->GetSdrPageView());
+
+ // Check the initial position of the object
+ tools::Rectangle aRectangle = pTextBoxObject->GetLogicRect();
+ CPPUNIT_ASSERT_EQUAL(2250L, aRectangle.TopLeft().X());
+ CPPUNIT_ASSERT_EQUAL(2000L, aRectangle.TopLeft().Y());
+ CPPUNIT_ASSERT_EQUAL(4501L, aRectangle.GetWidth());
+ CPPUNIT_ASSERT_EQUAL(2001L, aRectangle.GetHeight());
+
+ // On View2 - Move handle 0 on the shape to a new mosition - resize
+ Point aNewPosition = aRectangle.TopLeft() + Point(-1250, -1000);
+ pView2->MoveShapeHandle(0, aNewPosition, -1);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(size_t(4), pUndoManager->GetUndoActionCount());
+
+ // Check the object has a new size
+ aRectangle = pTextBoxObject->GetLogicRect();
+ CPPUNIT_ASSERT_EQUAL(1000L, aRectangle.TopLeft().X());
+ CPPUNIT_ASSERT_EQUAL(1000L, aRectangle.TopLeft().Y());
+ CPPUNIT_ASSERT_EQUAL(4990L, aRectangle.GetWidth());
+ CPPUNIT_ASSERT_EQUAL(2175L, aRectangle.GetHeight());
+
+ // View1 is still in text edit mode...
+ CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+
+ // On View2 - relative move the shape to a different position
+ pView2->MoveMarkedObj(Size(1000, 2000), /*bCopy=*/false);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(size_t(5), pUndoManager->GetUndoActionCount());
+
+ // Check the object is at a different position
+ aRectangle = pTextBoxObject->GetLogicRect();
+ CPPUNIT_ASSERT_EQUAL(2000L, aRectangle.TopLeft().X());
+ CPPUNIT_ASSERT_EQUAL(3000L, aRectangle.TopLeft().Y());
+ CPPUNIT_ASSERT_EQUAL(4990L, aRectangle.GetWidth());
+ CPPUNIT_ASSERT_EQUAL(2175L, aRectangle.GetHeight());
+
+ // View1 is still in text edit mode...
+ CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+
+ // End Text edit - check undo count increase from 5 -> 6
+ CPPUNIT_ASSERT_EQUAL(size_t(5), pUndoManager->GetUndoActionCount());
+ pView1->SdrEndTextEdit();
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(size_t(6), pUndoManager->GetUndoActionCount());
+
+ // Check that both views exited the text edit mode
+ CPPUNIT_ASSERT_EQUAL(false, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+ }
+
+ // Scenario 3
+ // 1 shapes - "Table1"
+ // View1 - "Table1" enters text edit mode, View 2 - moves the "Table1" around
+ {
+ sd::UndoManager* pUndoManager = pDocument->GetUndoManager();
+ CPPUNIT_ASSERT_EQUAL(size_t(6), pUndoManager->GetUndoActionCount());
+
+ pView1->SdrBeginTextEdit(pTableObject);
+ CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+
+ // Local undo count for View1 is 0
+ CPPUNIT_ASSERT_EQUAL(size_t(0), pView1->getViewLocalUndoManager()->GetUndoActionCount());
+ // Write 'test' in View1
+ SfxStringItem aInputString(SID_ATTR_CHAR, "test");
+ pViewShell1->GetViewFrame()->GetDispatcher()->ExecuteList(SID_ATTR_CHAR, SfxCallMode::SYNCHRON, { &aInputString });
+ // Local undo count for View1 is now 1
+ CPPUNIT_ASSERT_EQUAL(size_t(1), pView1->getViewLocalUndoManager()->GetUndoActionCount());
+
+ // Mark rectangle object
+ pView2->MarkObj(pTableObject, pView2->GetSdrPageView());
+
+ // Check the initial position of the table
+ tools::Rectangle aRectangle = pTableObject->GetLogicRect();
+ CPPUNIT_ASSERT_EQUAL(2919L, aRectangle.TopLeft().X());
+ CPPUNIT_ASSERT_EQUAL(18063L, aRectangle.TopLeft().Y());
+ CPPUNIT_ASSERT_EQUAL(14099L, aRectangle.GetWidth());
+ CPPUNIT_ASSERT_EQUAL(5999L, aRectangle.GetHeight());
+
+ // On View2 - relative move the shape to a different position
+ pView2->MoveMarkedObj(Size(1000, 2000), /*bCopy=*/false);
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(size_t(7), pUndoManager->GetUndoActionCount());
+
+ // Check the object is at a different position
+ aRectangle = pTableObject->GetLogicRect();
+ CPPUNIT_ASSERT_EQUAL(3919L, aRectangle.TopLeft().X());
+ CPPUNIT_ASSERT_EQUAL(20063L, aRectangle.TopLeft().Y());
+ CPPUNIT_ASSERT_EQUAL(14099L, aRectangle.GetWidth());
+ CPPUNIT_ASSERT_EQUAL(5999L, aRectangle.GetHeight());
+
+ // View1 is still in text edit mode...
+ CPPUNIT_ASSERT_EQUAL(true, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+
+ // End Text edit - check undo count increase from 7 -> 8
+ CPPUNIT_ASSERT_EQUAL(size_t(7), pUndoManager->GetUndoActionCount());
+ pView1->SdrEndTextEdit();
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(size_t(8), pUndoManager->GetUndoActionCount());
+
+ // Check that both views exited the text edit mode
+ CPPUNIT_ASSERT_EQUAL(false, pView1->IsTextEdit());
+ CPPUNIT_ASSERT_EQUAL(false, pView2->IsTextEdit());
+ }
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SdTiledRenderingTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sd/source/ui/inc/View.hxx b/sd/source/ui/inc/View.hxx
index 744023acb573..b0ad4ca2ff87 100644
--- a/sd/source/ui/inc/View.hxx
+++ b/sd/source/ui/inc/View.hxx
@@ -142,6 +142,9 @@ public:
ViewShell* GetViewShell() const { return mpViewSh; }
SfxViewShell* GetSfxViewShell() const override;
+ // Create a local UndoManager
+ std::unique_ptr<SdrUndoManager> createLocalTextUndoManager() override;
+
virtual bool SdrBeginTextEdit(SdrObject* pObj, SdrPageView* pPV = nullptr, vcl::Window* pWin = nullptr, bool bIsNewObj = false,
SdrOutliner* pGivenOutliner = nullptr, OutlinerView* pGivenOutlinerView = nullptr,
bool bDontDeleteOutliner = false, bool bOnlyOneView = false, bool bGrabFocus = true) override;
diff --git a/sd/source/ui/view/drviews1.cxx b/sd/source/ui/view/drviews1.cxx
index 6c1df14a3961..4c3e446963a5 100644
--- a/sd/source/ui/view/drviews1.cxx
+++ b/sd/source/ui/view/drviews1.cxx
@@ -344,7 +344,9 @@ void DrawViewShell::ChangeEditMode(EditMode eEMode, bool bIsLayerModeActive)
if ( mpDrawView->IsTextEdit() )
{
- mpDrawView->SdrEndTextEdit();
+ // This exits the text edit mode when going in and out of window focus, which is not needed
+ // Let's keep this call as comment for now as it probably just needs a better conditional.
+ // mpDrawView->SdrEndTextEdit();
}
LayerTabBar* pLayerBar = GetLayerTabControl();
diff --git a/sd/source/ui/view/sdview.cxx b/sd/source/ui/view/sdview.cxx
index d977334013f1..fadd89b99033 100644
--- a/sd/source/ui/view/sdview.cxx
+++ b/sd/source/ui/view/sdview.cxx
@@ -82,6 +82,8 @@
#include <DrawController.hxx>
#include <svtools/optionsdrawinglayer.hxx>
+#include <undo/undomanager.hxx>
+
#include <memory>
#include <numeric>
@@ -624,6 +626,14 @@ SfxViewShell* View::GetSfxViewShell() const
return pRet;
}
+// Create a new view-local UndoManager manager for Impress/Draw
+std::unique_ptr<SdrUndoManager> View::createLocalTextUndoManager()
+{
+ std::unique_ptr<SdrUndoManager> pUndoManager(new sd::UndoManager);
+ pUndoManager->SetDocShell(mpDocSh);
+ return pUndoManager;
+}
+
bool View::SdrBeginTextEdit(
SdrObject* pObj, SdrPageView* pPV, vcl::Window* pWin,
bool bIsNewObj,