diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2021-10-07 16:48:46 +0200 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2021-10-20 16:25:16 +0200 |
commit | c175c1dc19d0edc8ca66e39f0b4b8af04e3d6c87 (patch) | |
tree | 04e074d7e034642a4e4025e106dc20db09ca9ee2 /sd | |
parent | 85d53dafd8332fc9c7bf71d6cc9da19ab9d8e252 (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.py | 13 | ||||
-rw-r--r-- | sd/qa/unit/misc-tests.cxx | 34 | ||||
-rw-r--r-- | sd/qa/unit/tiledrendering/data/TextBoxAndRect.odg | bin | 0 -> 10474 bytes | |||
-rw-r--r-- | sd/qa/unit/tiledrendering/tiledrendering.cxx | 341 | ||||
-rw-r--r-- | sd/source/ui/inc/View.hxx | 3 | ||||
-rw-r--r-- | sd/source/ui/view/drviews1.cxx | 4 | ||||
-rw-r--r-- | sd/source/ui/view/sdview.cxx | 10 |
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 Binary files differnew file mode 100644 index 000000000000..aa1a37b83147 --- /dev/null +++ b/sd/qa/unit/tiledrendering/data/TextBoxAndRect.odg 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, |