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 | |
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>
-rw-r--r-- | include/svx/svdedtv.hxx | 1 | ||||
-rw-r--r-- | include/svx/svdedxv.hxx | 13 | ||||
-rw-r--r-- | sc/qa/unit/uicalc/uicalc.cxx | 3 | ||||
-rw-r--r-- | sc/source/ui/inc/drawview.hxx | 4 | ||||
-rw-r--r-- | sc/source/ui/view/drawview.cxx | 9 | ||||
-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 | ||||
-rw-r--r-- | svx/source/svdraw/svddrgmt.cxx | 2 | ||||
-rw-r--r-- | svx/source/svdraw/svdedtv.cxx | 12 | ||||
-rw-r--r-- | svx/source/svdraw/svdedtv1.cxx | 24 | ||||
-rw-r--r-- | svx/source/svdraw/svdedxv.cxx | 17 | ||||
-rw-r--r-- | sw/qa/extras/tiledrendering/data/shape.fodt | 20 | ||||
-rw-r--r-- | sw/qa/extras/tiledrendering/tiledrendering.cxx | 16 | ||||
-rw-r--r-- | sw/source/core/draw/dview.cxx | 10 | ||||
-rw-r--r-- | sw/source/core/inc/dview.hxx | 4 |
20 files changed, 471 insertions, 69 deletions
diff --git a/include/svx/svdedtv.hxx b/include/svx/svdedtv.hxx index a21eeb3e0a43..6f80c3aca0fa 100644 --- a/include/svx/svdedtv.hxx +++ b/include/svx/svdedtv.hxx @@ -188,6 +188,7 @@ public: * Checks if this or other views have an active text edit, if true, end them. */ void EndTextEditAllViews() const; + void EndTextEditCurrentView(); std::vector< std::unique_ptr<SdrUndoAction> > CreateConnectorUndo( const SdrObject& rO ); void AddUndoActions( std::vector< std::unique_ptr<SdrUndoAction> > ); diff --git a/include/svx/svdedxv.hxx b/include/svx/svdedxv.hxx index a4f457c9aeba..a05a61c36c8d 100644 --- a/include/svx/svdedxv.hxx +++ b/include/svx/svdedxv.hxx @@ -109,18 +109,15 @@ protected: private: SfxUndoManager* mpOldTextEditUndoManager; + std::unique_ptr<SdrUndoManager> mpLocalTextEditUndoManager; protected: - // central method to get an SdrUndoManager for enhanced TextEdit. Default will - // try to return a dynamic_casted GetModel()->GetSdrUndoManager(). Applications - // which want to use this feature will need to override this virtual method, - // provide their document UndoManager and derive it from SdrUndoManager. - virtual SdrUndoManager* getSdrUndoManagerForEnhancedTextEdit() const; + // Create a local UndoManager that is used for text editing. + virtual std::unique_ptr<SdrUndoManager> createLocalTextUndoManager(); void ImpMoveCursorAfterChainingEvent(TextChainCursorManager *pCursorManager); std::unique_ptr<TextChainCursorManager> ImpHandleMotionThroughBoxesKeyInput(const KeyEvent& rKEvt, bool *bOutHandled); - OutlinerView* ImpFindOutlinerView(vcl::Window const * pWin) const; // Create a new OutlinerView at the heap and initialize all required parameters. @@ -180,6 +177,10 @@ public: virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override; virtual void ModelHasChanged() override; + const std::unique_ptr<SdrUndoManager>& getViewLocalUndoManager() const + { + return mpLocalTextEditUndoManager; + } // TextEdit over an outliner diff --git a/sc/qa/unit/uicalc/uicalc.cxx b/sc/qa/unit/uicalc/uicalc.cxx index 3c3d15f1d399..46c430c7e087 100644 --- a/sc/qa/unit/uicalc/uicalc.cxx +++ b/sc/qa/unit/uicalc/uicalc.cxx @@ -951,6 +951,9 @@ CPPUNIT_TEST_FIXTURE(ScUiCalcTest, testTdf119793) pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0); pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0); Scheduler::ProcessEventsToIdle(); + pModelObj->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_ESCAPE); + pModelObj->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_ESCAPE); + Scheduler::ProcessEventsToIdle(); dispatchCommand(mxComponent, ".uno:Undo", {}); Scheduler::ProcessEventsToIdle(); diff --git a/sc/source/ui/inc/drawview.hxx b/sc/source/ui/inc/drawview.hxx index 7e0db5eb0a0d..816a3428aacf 100644 --- a/sc/source/ui/inc/drawview.hxx +++ b/sc/source/ui/inc/drawview.hxx @@ -51,8 +51,8 @@ class ScDrawView final : public FmFormView void ImplClearCalcDropMarker(); - // support enhanced text edit for draw objects - virtual SdrUndoManager* getSdrUndoManagerForEnhancedTextEdit() const override; + // Create a local UndoManager + std::unique_ptr<SdrUndoManager> createLocalTextUndoManager() override; public: ScDrawView( diff --git a/sc/source/ui/view/drawview.cxx b/sc/source/ui/view/drawview.cxx index ed0cf254ba10..0254e62fb2be 100644 --- a/sc/source/ui/view/drawview.cxx +++ b/sc/source/ui/view/drawview.cxx @@ -1107,10 +1107,13 @@ bool ScDrawView::calculateGridOffsetForB2DRange( return true; } -// support enhanced text edit for draw objects -SdrUndoManager* ScDrawView::getSdrUndoManagerForEnhancedTextEdit() const +// Create a new view-local UndoManager manager for Calc +std::unique_ptr<SdrUndoManager> ScDrawView::createLocalTextUndoManager() { - return dynamic_cast<SdrUndoManager*>(rDoc.GetUndoManager()); + std::unique_ptr<SdrUndoManager> pUndoManager(new SdrUndoManager); + ScDocShell* pDocShell = pViewData ? pViewData->GetDocShell() : nullptr; + pUndoManager->SetDocShell(pDocShell); + return pUndoManager; } // #i123922# helper to apply a Graphic to an existing SdrObject 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, diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx index 7d5fb61569b7..bdba8aa0d7f4 100644 --- a/svx/source/svdraw/svddrgmt.cxx +++ b/svx/source/svdraw/svddrgmt.cxx @@ -1345,7 +1345,7 @@ bool SdrDragObjOwn::EndSdrDrag(bool /*bCopy*/) if( bUndo ) { - getSdrDragView().EndTextEditAllViews(); + getSdrDragView().EndTextEditCurrentView(); if(!getSdrDragView().IsInsObjPoint() && pObj->IsInserted() ) { if (DragStat().IsEndDragChangesAttributes()) diff --git a/svx/source/svdraw/svdedtv.cxx b/svx/source/svdraw/svdedtv.cxx index 0d4bb55d09f5..47f5c971e543 100644 --- a/svx/source/svdraw/svdedtv.cxx +++ b/svx/source/svdraw/svdedtv.cxx @@ -1000,7 +1000,7 @@ bool SdrEditView::InsertObjectAtView(SdrObject* pObj, SdrPageView& rPV, SdrInser } if( IsUndoEnabled()) { - EndTextEditAllViews(); + EndTextEditCurrentView(); AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pObj)); } @@ -1080,4 +1080,14 @@ void SdrEditView::EndTextEditAllViews() const } } +void SdrEditView::EndTextEditCurrentView() +{ + if (IsTextEdit()) + { + SdrView* pSdrView = dynamic_cast<SdrView*>(this); + if (pSdrView) + pSdrView->SdrEndTextEdit(); + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/svdraw/svdedtv1.cxx b/svx/source/svdraw/svdedtv1.cxx index 81cf6e6f0b0b..852d160ccd98 100644 --- a/svx/source/svdraw/svdedtv1.cxx +++ b/svx/source/svdraw/svdedtv1.cxx @@ -95,7 +95,7 @@ void SdrEditView::SetMarkedObjRect(const tools::Rectangle& rRect) const bool bUndo = IsUndoEnabled(); if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); BegUndo(ImpGetDescriptionString(STR_EditPosSize)); } @@ -186,7 +186,7 @@ void SdrEditView::MoveMarkedObj(const Size& rSiz, bool bCopy) if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); OUString aStr(SvxResId(STR_EditMove)); if (bCopy) aStr += SvxResId(STR_EditWithCopy); @@ -219,7 +219,7 @@ void SdrEditView::ResizeMarkedObj(const Point& rRef, const Fraction& xFact, cons const bool bUndo = IsUndoEnabled(); if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); OUString aStr {ImpGetDescriptionString(STR_EditResize)}; if (bCopy) aStr+=SvxResId(STR_EditWithCopy); @@ -254,7 +254,7 @@ void SdrEditView::ResizeMultMarkedObj(const Point& rRef, const bool bUndo = IsUndoEnabled(); if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); BegUndo(ImpGetDescriptionString(STR_EditResize)); } @@ -301,7 +301,7 @@ void SdrEditView::RotateMarkedObj(const Point& rRef, Degree100 nAngle, bool bCop const bool bUndo = IsUndoEnabled(); if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); OUString aStr {ImpGetDescriptionString(STR_EditRotate)}; if (bCopy) aStr+=SvxResId(STR_EditWithCopy); BegUndo(aStr); @@ -358,7 +358,7 @@ void SdrEditView::MirrorMarkedObj(const Point& rRef1, const Point& rRef2, bool b if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); OUString aStr; Point aDif(rRef2-rRef1); if (aDif.X()==0) @@ -458,7 +458,7 @@ void SdrEditView::ShearMarkedObj(const Point& rRef, Degree100 nAngle, bool bVShe if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); OUString aStr {ImpGetDescriptionString(STR_EditShear)}; if (bCopy) aStr+=SvxResId(STR_EditWithCopy); @@ -574,7 +574,7 @@ void SdrEditView::CrookMarkedObj(const Point& rRef, const Point& rRad, SdrCrookM if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); OUString aStr {ImpGetDescriptionString(bNoContortion ? STR_EditCrook : STR_EditCrookContortion)}; if (bCopy) aStr+=SvxResId(STR_EditWithCopy); @@ -648,7 +648,7 @@ void SdrEditView::DistortMarkedObj(const tools::Rectangle& rRef, const XPolygon& if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); OUString aStr {ImpGetDescriptionString(STR_EditDistort)}; if (bCopy) aStr+=SvxResId(STR_EditWithCopy); @@ -1098,7 +1098,7 @@ void SdrEditView::SetAttrToMarked(const SfxItemSet& rAttr, bool bReplaceAll) const bool bUndo = IsUndoEnabled(); if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); BegUndo(ImpGetDescriptionString(STR_EditSetAttributes)); } @@ -1277,7 +1277,7 @@ void SdrEditView::SetStyleSheetToMarked(SfxStyleSheet* pStyleSheet, bool bDontRe if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); OUString aStr; if (pStyleSheet!=nullptr) aStr = ImpGetDescriptionString(STR_EditSetStylesheet); @@ -1844,7 +1844,7 @@ void SdrEditView::AlignMarkedObjects(SdrHorAlign eHor, SdrVertAlign eVert) const bool bUndo = IsUndoEnabled(); if( bUndo ) { - EndTextEditAllViews(); + EndTextEditCurrentView(); OUString aStr(GetDescriptionOfMarkedObjects()); if (eHor==SdrHorAlign::NONE) { diff --git a/svx/source/svdraw/svdedxv.cxx b/svx/source/svdraw/svdedxv.cxx index db0ccf6ea486..3717fdce2c08 100644 --- a/svx/source/svdraw/svdedxv.cxx +++ b/svx/source/svdraw/svdedxv.cxx @@ -1060,10 +1060,11 @@ IMPL_LINK(SdrObjEditView, ImpOutlinerCalcFieldValueHdl, EditFieldInfo*, pFI, voi IMPL_LINK_NOARG(SdrObjEditView, EndTextEditHdl, SdrUndoManager*, void) { SdrEndTextEdit(); } -SdrUndoManager* SdrObjEditView::getSdrUndoManagerForEnhancedTextEdit() const +// Default implementation - null UndoManager +std::unique_ptr<SdrUndoManager> SdrObjEditView::createLocalTextUndoManager() { - // default returns registered UndoManager - return GetModel() ? dynamic_cast<SdrUndoManager*>(GetModel()->GetSdrUndoManager()) : nullptr; + SAL_WARN("svx", "SdrObjEditView::createLocalTextUndoManager needs to be overridden"); + return std::unique_ptr<SdrUndoManager>(); } bool SdrObjEditView::SdrBeginTextEdit(SdrObject* pObj_, SdrPageView* pPV, vcl::Window* pWin, @@ -1360,7 +1361,11 @@ bool SdrObjEditView::SdrBeginTextEdit(SdrObject* pObj_, SdrPageView* pPV, vcl::W if (GetModel() && IsUndoEnabled() && !GetModel()->GetDisableTextEditUsesCommonUndoManager()) { - SdrUndoManager* pSdrUndoManager = getSdrUndoManagerForEnhancedTextEdit(); + SdrUndoManager* pSdrUndoManager = nullptr; + mpLocalTextEditUndoManager = createLocalTextUndoManager(); + + if (mpLocalTextEditUndoManager) + pSdrUndoManager = mpLocalTextEditUndoManager.get(); if (pSdrUndoManager) { @@ -1434,7 +1439,7 @@ SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally) if (pOriginal) { // check if we got back our document undo manager - SdrUndoManager* pSdrUndoManager = getSdrUndoManagerForEnhancedTextEdit(); + SdrUndoManager* pSdrUndoManager = mpLocalTextEditUndoManager.get(); if (pSdrUndoManager && dynamic_cast<SdrUndoManager*>(pOriginal) == pSdrUndoManager) { @@ -1467,6 +1472,8 @@ SdrEndTextEditKind SdrObjEditView::SdrEndTextEdit(bool bDontDeleteReally) "expected document UndoManager (!)"); delete pOriginal; } + + mpLocalTextEditUndoManager.reset(); } } else diff --git a/sw/qa/extras/tiledrendering/data/shape.fodt b/sw/qa/extras/tiledrendering/data/shape.fodt index feefe48bcde3..4e9a7f629ba4 100644 --- a/sw/qa/extras/tiledrendering/data/shape.fodt +++ b/sw/qa/extras/tiledrendering/data/shape.fodt @@ -1,5 +1,20 @@ <?xml version="1.0" encoding="UTF-8"?> -<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text"> + +<office:document xmlns:officeooo="http://openoffice.org/2009/office" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rpt="http://openoffice.org/2005/report" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:xforms="http://www.w3.org/2002/xforms" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="GB" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Droid Sans Devanagari1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + </office:styles> + <office:automatic-styles> + <style:style style:name="gr1" style:family="graphic"> + <style:graphic-properties draw:textarea-horizontal-align="justify" draw:textarea-vertical-align="middle" draw:auto-grow-height="false" fo:min-height="1.9cm" fo:min-width="3.471cm" style:run-through="foreground" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph"/> + </style:style> + </office:automatic-styles> <office:body> <office:text> <text:sequence-decls> @@ -7,8 +22,9 @@ <text:sequence-decl text:display-outline-level="0" text:name="Table"/> <text:sequence-decl text:display-outline-level="0" text:name="Text"/> <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> </text:sequence-decls> - <text:p><draw:custom-shape text:anchor-type="paragraph" draw:z-index="0" svg:width="4.883cm" svg:height="3.225cm" svg:x="2.602cm" svg:y="1.178cm"> + <text:p text:style-name="Standard"><draw:custom-shape text:anchor-type="paragraph" draw:z-index="0" draw:name="Shape1" draw:style-name="gr1" svg:width="4.908cm" svg:height="2.687cm" svg:x="1.575cm" svg:y="-0.132cm"> <text:p/> <draw:enhanced-geometry svg:viewBox="0 0 21600 21600" draw:glue-points="10800 0 3163 3163 0 10800 3163 18437 10800 21600 18437 18437 21600 10800 18437 3163" draw:text-areas="3163 3163 18437 18437" draw:type="ellipse" draw:enhanced-path="U 10800 10800 10800 10800 0 360 Z N"/> </draw:custom-shape>Hello.</text:p> diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx index 8f637753d1d4..9eaca7d123a7 100644 --- a/sw/qa/extras/tiledrendering/tiledrendering.cxx +++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx @@ -1311,6 +1311,7 @@ void SwTiledRenderingTest::testUndoShapeLimiting() pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0); pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0); Scheduler::ProcessEventsToIdle(); + pWrtShell2->EndTextEdit(); // Assert that the first view can't and the second view can undo the insertion. SwDoc* pDoc = pXTextDocument->GetDocShell()->GetDoc(); @@ -1321,7 +1322,6 @@ void SwTiledRenderingTest::testUndoShapeLimiting() rUndoManager.SetView(&pWrtShell2->GetView()); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rUndoManager.GetUndoActionCount()); - pWrtShell2->EndTextEdit(); rUndoManager.SetView(nullptr); SfxLokHelper::setView(nView1); @@ -1426,11 +1426,14 @@ void SwTiledRenderingTest::testShapeTextUndoShells() pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'x', 0); pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'x', 0); Scheduler::ProcessEventsToIdle(); + pWrtShell->EndTextEdit(); // Make sure that the undo item remembers who created it. SwDoc* pDoc = pXTextDocument->GetDocShell()->GetDoc(); sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rUndoManager.GetUndoActionCount()); + CPPUNIT_ASSERT_EQUAL(size_t(1), rUndoManager.GetUndoActionCount()); + CPPUNIT_ASSERT_EQUAL(OUString("Edit text of Shape 'Shape1'"), rUndoManager.GetUndoActionComment(0)); + // This was -1: the view shell id for the undo action wasn't known. CPPUNIT_ASSERT_EQUAL(ViewShellId(nView1), rUndoManager.GetUndoAction()->GetViewShellId()); } @@ -1457,7 +1460,14 @@ void SwTiledRenderingTest::testShapeTextUndoGroupShells() // Make sure that the undo item remembers who created it. SwDoc* pDoc = pXTextDocument->GetDocShell()->GetDoc(); sw::UndoManager& rUndoManager = pDoc->GetUndoManager(); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rUndoManager.GetUndoActionCount()); + CPPUNIT_ASSERT_EQUAL(size_t(0), rUndoManager.GetUndoActionCount()); + + pWrtShell->EndTextEdit(); + pWrtShell->GetView().BeginTextEdit(pObject, pView->GetSdrPageView(), pWrtShell->GetWin()); + + CPPUNIT_ASSERT_EQUAL(size_t(1), rUndoManager.GetUndoActionCount()); + CPPUNIT_ASSERT_EQUAL(OUString("Edit text of Shape 'Shape1'"), rUndoManager.GetUndoActionComment(0)); + // This was -1: the view shell id for the (top) undo list action wasn't known. CPPUNIT_ASSERT_EQUAL(ViewShellId(nView1), rUndoManager.GetUndoAction()->GetViewShellId()); diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx index 33d6a83fb1f8..510addf10a9c 100644 --- a/sw/source/core/draw/dview.cxx +++ b/sw/source/core/draw/dview.cxx @@ -998,12 +998,12 @@ void SwDrawView::DeleteMarked() pTmpRoot->EndAllAction(); } -// support enhanced text edit for draw objects -SdrUndoManager* SwDrawView::getSdrUndoManagerForEnhancedTextEdit() const +// Create a new view-local UndoManager manager for Writer +std::unique_ptr<SdrUndoManager> SwDrawView::createLocalTextUndoManager() { - SwDoc* pDoc = Imp().GetShell()->GetDoc(); - - return pDoc ? &(pDoc->GetUndoManager()) : nullptr; + std::unique_ptr<SdrUndoManager> pUndoManager(new SdrUndoManager); + pUndoManager->SetDocShell(SfxObjectShell::Current()); + return pUndoManager; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/dview.hxx b/sw/source/core/inc/dview.hxx index 3e9f4e6c9864..cdcf3f265985 100644 --- a/sw/source/core/inc/dview.hxx +++ b/sw/source/core/inc/dview.hxx @@ -75,8 +75,8 @@ class SwDrawView final : public FmFormView using FmFormView::CheckSingleSdrObjectHit; virtual SdrObject* CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const override; - // support enhanced text edit for draw objects - virtual SdrUndoManager* getSdrUndoManagerForEnhancedTextEdit() const override; + // Create a local UndoManager + std::unique_ptr<SdrUndoManager> createLocalTextUndoManager() override; public: SwDrawView( |