From 1e016920769ae524575e40b1ec317c700ba0daa3 Mon Sep 17 00:00:00 2001 From: "Armin Le Grand (Allotropia)" Date: Tue, 10 May 2022 15:59:29 +0200 Subject: Advanced Diagram support: UNDO/REDO support for Diagram DataModel Added support for UNDO/REDO for changes in Diagram ModelData. This is currenly applied/used in the DiagramDialog for it's Add/Remove actions (also supports Cancel of that dialog 1st time ever). But it is defined more general to add/support manipulating actions like clone/change_text etc. Also the UI/dialog at he end will not be/stay modal, so this is a test implemenation how to use it. It uses an extract/apply mechanism to get/set the Diagram ModelData at/for the UNDO action. That may be expanded as needed for additional data in he future. It may also be considered to modify the Connection/Point ModelData to shared_ptr internally completely to avoid copying these at all. OTOH it is not that much data to handle at all. Change-Id: I4702ed908b79a476177fe66c0e3284898c6adda5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134118 Tested-by: Jenkins Reviewed-by: Armin Le Grand --- cui/source/dialogs/DiagramDialog.cxx | 90 ++++++++++++++++++++++++++++++++---- cui/source/factory/dlgfact.cxx | 6 ++- cui/source/factory/dlgfact.hxx | 2 +- cui/source/inc/DiagramDialog.hxx | 9 ++-- 4 files changed, 93 insertions(+), 14 deletions(-) (limited to 'cui/source') diff --git a/cui/source/dialogs/DiagramDialog.cxx b/cui/source/dialogs/DiagramDialog.cxx index 9c5816cf4b2b..ea592767461d 100644 --- a/cui/source/dialogs/DiagramDialog.cxx +++ b/cui/source/dialogs/DiagramDialog.cxx @@ -11,12 +11,15 @@ #include #include +#include +#include #include +#include -DiagramDialog::DiagramDialog(weld::Window* pWindow, - const std::shared_ptr& pDiagramHelper) +DiagramDialog::DiagramDialog(weld::Window* pWindow, SdrObjGroup& rDiagram) : GenericDialogController(pWindow, "cui/ui/diagramdialog.ui", "DiagramDialog") - , mpDiagramHelper(pDiagramHelper) + , m_rDiagram(rDiagram) + , m_nUndos(0) , mpBtnOk(m_xBuilder->weld_button("btnOk")) , mpBtnCancel(m_xBuilder->weld_button("btnCancel")) , mpBtnAdd(m_xBuilder->weld_button("btnAdd")) @@ -24,6 +27,7 @@ DiagramDialog::DiagramDialog(weld::Window* pWindow, , mpTreeDiagram(m_xBuilder->weld_tree_view("treeDiagram")) , mpTextAdd(m_xBuilder->weld_text_view("textAdd")) { + mpBtnCancel->connect_clicked(LINK(this, DiagramDialog, OnAddCancel)); mpBtnAdd->connect_clicked(LINK(this, DiagramDialog, OnAddClick)); mpBtnRemove->connect_clicked(LINK(this, DiagramDialog, OnRemoveClick)); @@ -37,13 +41,51 @@ DiagramDialog::DiagramDialog(weld::Window* pWindow, }); } +IMPL_LINK_NOARG(DiagramDialog, OnAddCancel, weld::Button&, void) +{ + // If the user cancels the dialog, undo all changes done so far. It may + // even be feasible to then delete the redo-stack, since it stays + // available (?) - but it does no harm either... + while (0 != m_nUndos) + { + comphelper::dispatchCommand(".uno:Undo", {}); + m_nUndos--; + } + + m_xDialog->response(RET_CANCEL); +} + IMPL_LINK_NOARG(DiagramDialog, OnAddClick, weld::Button&, void) { + if (!m_rDiagram.isDiagram()) + return; + OUString sText = mpTextAdd->get_text(); + const std::shared_ptr& pDiagramHelper(m_rDiagram.getDiagramHelper()); - if (!sText.isEmpty()) + if (pDiagramHelper && !sText.isEmpty()) { - OUString sNodeId = mpDiagramHelper->addNode(sText); + SdrModel& rDrawModel(m_rDiagram.getSdrModelFromSdrObject()); + const bool bUndo(rDrawModel.IsUndoEnabled()); + svx::diagram::DiagramDataStatePtr aStartState; + + if (bUndo) + { + // rescue all start state Diagram-defining data + aStartState = pDiagramHelper->extractDiagramDataState(); + } + + OUString sNodeId = pDiagramHelper->addNode(sText); + + if (bUndo) + { + // create undo action. That will internally secure the + // current Diagram-defining data as end state + rDrawModel.AddUndo( + rDrawModel.GetSdrUndoFactory().CreateUndoDiagramModelData(m_rDiagram, aStartState)); + m_nUndos++; + } + std::unique_ptr pEntry(mpTreeDiagram->make_iterator()); mpTreeDiagram->insert(nullptr, -1, &sText, &sNodeId, nullptr, nullptr, false, pEntry.get()); mpTreeDiagram->select(*pEntry); @@ -53,11 +95,35 @@ IMPL_LINK_NOARG(DiagramDialog, OnAddClick, weld::Button&, void) IMPL_LINK_NOARG(DiagramDialog, OnRemoveClick, weld::Button&, void) { + if (!m_rDiagram.isDiagram()) + return; + std::unique_ptr pEntry(mpTreeDiagram->make_iterator()); - if (mpTreeDiagram->get_selected(pEntry.get())) + const std::shared_ptr& pDiagramHelper(m_rDiagram.getDiagramHelper()); + + if (pDiagramHelper && mpTreeDiagram->get_selected(pEntry.get())) { - if (mpDiagramHelper->removeNode(mpTreeDiagram->get_id(*pEntry))) + SdrModel& rDrawModel(m_rDiagram.getSdrModelFromSdrObject()); + const bool bUndo(rDrawModel.IsUndoEnabled()); + svx::diagram::DiagramDataStatePtr aStartState; + + if (bUndo) + { + // rescue all start state Diagram-defining data + aStartState = pDiagramHelper->extractDiagramDataState(); + } + + if (pDiagramHelper->removeNode(mpTreeDiagram->get_id(*pEntry))) { + if (bUndo) + { + // create undo action. That will internally secure the + // current Diagram-defining data as end state + rDrawModel.AddUndo(rDrawModel.GetSdrUndoFactory().CreateUndoDiagramModelData( + m_rDiagram, aStartState)); + m_nUndos++; + } + mpTreeDiagram->remove(*pEntry); comphelper::dispatchCommand(".uno:RegenerateDiagram", {}); } @@ -66,7 +132,15 @@ IMPL_LINK_NOARG(DiagramDialog, OnRemoveClick, weld::Button&, void) void DiagramDialog::populateTree(const weld::TreeIter* pParent, const OUString& rParentId) { - auto aItems = mpDiagramHelper->getChildren(rParentId); + if (!m_rDiagram.isDiagram()) + return; + + const std::shared_ptr& pDiagramHelper(m_rDiagram.getDiagramHelper()); + + if (!pDiagramHelper) + return; + + auto aItems = pDiagramHelper->getChildren(rParentId); for (auto& aItem : aItems) { std::unique_ptr pEntry(mpTreeDiagram->make_iterator()); diff --git a/cui/source/factory/dlgfact.cxx b/cui/source/factory/dlgfact.cxx index c7a8a204e075..28d473479ac7 100644 --- a/cui/source/factory/dlgfact.cxx +++ b/cui/source/factory/dlgfact.cxx @@ -1524,10 +1524,12 @@ AbstractDialogFactory_Impl::CreateToolbarmodeDialog(weld::Window* pParent) } VclPtr -AbstractDialogFactory_Impl::CreateDiagramDialog(weld::Window* pParent, const std::shared_ptr& pDiagramHelper) +AbstractDialogFactory_Impl::CreateDiagramDialog( + weld::Window* pParent, + SdrObjGroup& rDiagram) { return VclPtr::Create( - std::make_unique(pParent, pDiagramHelper)); + std::make_unique(pParent, rDiagram)); } #ifdef _WIN32 diff --git a/cui/source/factory/dlgfact.hxx b/cui/source/factory/dlgfact.hxx index 3ce135927f14..1b9c85f66841 100644 --- a/cui/source/factory/dlgfact.hxx +++ b/cui/source/factory/dlgfact.hxx @@ -608,7 +608,7 @@ public: virtual VclPtr CreateDiagramDialog( weld::Window* pParent, - const std::shared_ptr& pDiagramHelper) override; + SdrObjGroup& rDiagram) override; #ifdef _WIN32 virtual VclPtr CreateFileExtCheckDialog(weld::Window* pParent, diff --git a/cui/source/inc/DiagramDialog.hxx b/cui/source/inc/DiagramDialog.hxx index 397aab44f50f..71a5bd9b79c4 100644 --- a/cui/source/inc/DiagramDialog.hxx +++ b/cui/source/inc/DiagramDialog.hxx @@ -12,17 +12,19 @@ #include #include -class IDiagramHelper; +class SdrObjGroup; /** Edit Diagram dialog */ class DiagramDialog : public weld::GenericDialogController { public: - DiagramDialog(weld::Window* pWindow, const std::shared_ptr& pDiagramHelper); + DiagramDialog(weld::Window* pWindow, SdrObjGroup& rDiagram); virtual ~DiagramDialog() override; private: - const std::shared_ptr mpDiagramHelper; + SdrObjGroup& m_rDiagram; + sal_uInt32 m_nUndos; + std::unique_ptr mpBtnOk; std::unique_ptr mpBtnCancel; std::unique_ptr mpBtnAdd; @@ -30,6 +32,7 @@ private: std::unique_ptr mpTreeDiagram; std::unique_ptr mpTextAdd; + DECL_LINK(OnAddCancel, weld::Button&, void); DECL_LINK(OnAddClick, weld::Button&, void); DECL_LINK(OnRemoveClick, weld::Button&, void); -- cgit v1.2.3