From 3bc7f1e85ec2d1c9612d693fd1ef200a12871afd Mon Sep 17 00:00:00 2001 From: PaddleStroke Date: Tue, 29 Oct 2024 15:58:11 +0100 Subject: [PATCH] Core: Enable TaskDialogs to associate view (#17373) * Core: Add possibility for task dialogs to associate a view and be able to close when associated view is closed. * TaskImage: Use task dialog view association. * Sketcher: Use task dialog view association. Preventing crash (https://github.com/FreeCAD/FreeCAD/issues/16702) * EditableDatumLabel: Use QPointer to prevent crash --- src/Gui/Application.cpp | 5 ++++ src/Gui/Application.h | 4 +++ src/Gui/EditableDatumLabel.h | 3 +- src/Gui/MDIView.cpp | 2 ++ src/Gui/TaskView/TaskDialog.cpp | 33 ++++++++++++++++++++++ src/Gui/TaskView/TaskDialog.h | 24 +++++++++++++++- src/Gui/TaskView/TaskImage.cpp | 4 +-- src/Gui/TaskView/TaskView.cpp | 27 ++++++++++++++++++ src/Gui/TaskView/TaskView.h | 3 ++ src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp | 8 ++++++ src/Mod/Sketcher/Gui/TaskDlgEditSketch.h | 1 + 11 files changed, 109 insertions(+), 5 deletions(-) diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index b93ca67131..32101ce3b0 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -1411,6 +1411,11 @@ void Application::viewActivated(MDIView* pcView) } } +/// Gets called if a view gets closed +void Application::viewClosed(MDIView* pcView) +{ + signalCloseView(pcView); +} void Application::updateActive() { diff --git a/src/Gui/Application.h b/src/Gui/Application.h index 9dc8dc9b69..423d7600a3 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -97,6 +97,8 @@ public: void detachView(Gui::BaseView* pcView); /// get called if a view gets activated, this manage the whole activation scheme void viewActivated(Gui::MDIView* pcView); + /// get called if a view gets closed + void viewClosed(Gui::MDIView* pcView); /// call update to all documents and all views (costly!) void onUpdate(); /// call update to all views of the active document @@ -137,6 +139,8 @@ public: boost::signals2::signal signalShowHidden; /// signal on activating view boost::signals2::signal signalActivateView; + /// signal on closing view + boost::signals2::signal signalCloseView; /// signal on entering in edit mode boost::signals2::signal signalInEdit; /// signal on leaving edit mode diff --git a/src/Gui/EditableDatumLabel.h b/src/Gui/EditableDatumLabel.h index d2a7acf6c4..80d6bffe06 100644 --- a/src/Gui/EditableDatumLabel.h +++ b/src/Gui/EditableDatumLabel.h @@ -25,6 +25,7 @@ #define GUI_EDITABLEDATUMLABEL_H #include +#include #include #include "SoDatumLabel.h" @@ -98,7 +99,7 @@ private: private: SoSeparator* root; SoTransform* transform; - View3DInventorViewer* viewer; + QPointer viewer; QuantitySpinBox* spinBox; SoNodeSensor* cameraSensor; SbVec3f midpos; diff --git a/src/Gui/MDIView.cpp b/src/Gui/MDIView.cpp index cc77ad6808..3b3554664f 100644 --- a/src/Gui/MDIView.cpp +++ b/src/Gui/MDIView.cpp @@ -209,6 +209,8 @@ void MDIView::closeEvent(QCloseEvent *e) { if (canClose()) { e->accept(); + Application::Instance->viewClosed(this); + if (!bIsPassive) { // must be detached so that the last view can get asked Document* doc = this->getGuiDocument(); diff --git a/src/Gui/TaskView/TaskDialog.cpp b/src/Gui/TaskView/TaskDialog.cpp index b90c3123cf..9c9e304f8c 100644 --- a/src/Gui/TaskView/TaskDialog.cpp +++ b/src/Gui/TaskView/TaskDialog.cpp @@ -27,6 +27,13 @@ # include #endif +#include +#include +#include +#include +#include + + #include "TaskDialog.h" #include "TaskView.h" @@ -42,6 +49,8 @@ TaskDialog::TaskDialog() : QObject(nullptr), pos(North) , escapeButton(true) , autoCloseTransaction(false) + , autoCloseDeletedDocument(false) + , autoCloseClosedView(false) { } @@ -96,6 +105,25 @@ bool TaskDialog::canClose() const return (ret == QMessageBox::Yes); } +void TaskDialog::associateToObject3dView(App::DocumentObject* obj) +{ + if (!obj) { + return; + } + + Gui::Document* guiDoc = Gui::Application::Instance->getDocument(obj->getDocument()); + auto* vp = Gui::Application::Instance->getViewProvider(obj); + auto* vpdo = static_cast(vp); + auto* view = guiDoc->openEditingView3D(vpdo); + + if (!view) { + return; + } + + setAssociatedView(view); + setAutoCloseOnClosedView(true); +} + //==== calls from the TaskView =============================================================== void TaskDialog::open() @@ -118,6 +146,11 @@ void TaskDialog::autoClosedOnDeletedDocument() } +void TaskDialog::autoClosedOnClosedView() +{ + +} + void TaskDialog::clicked(int) { diff --git a/src/Gui/TaskView/TaskDialog.h b/src/Gui/TaskView/TaskDialog.h index f291d334f3..41f6d6e54b 100644 --- a/src/Gui/TaskView/TaskDialog.h +++ b/src/Gui/TaskView/TaskDialog.h @@ -33,10 +33,11 @@ namespace App { - +class DocumentObject; } namespace Gui { +class MDIView; namespace TaskView { class TaskContent; @@ -104,6 +105,22 @@ public: { return documentName; } void setDocumentName(const std::string& doc) { documentName = doc; } + + /// Defines whether a task dialog must be closed if the associated view + /// is deleted. + void setAutoCloseOnClosedView(bool on) { + autoCloseClosedView = on; + } + bool isAutoCloseOnClosedView() const { + return autoCloseClosedView; + } + void associateToObject3dView(App::DocumentObject* obj); + + const Gui::MDIView* getAssociatedView() const + { return associatedView; } + void setAssociatedView(const Gui::MDIView* view) + { associatedView = view; } + /*! Indicates whether this task dialog allows other commands to modify the document while it is open. @@ -136,6 +153,9 @@ public: /// is called by the framework when the dialog is automatically closed due to /// deleting the document virtual void autoClosedOnDeletedDocument(); + /// is called by the framework when the dialog is automatically closed due to + /// closing of associated view + virtual void autoClosedOnClosedView(); /// is called by the framework if a button is clicked which has no accept or reject role virtual void clicked(int); /// is called by the framework if the dialog is accepted (Ok) @@ -160,9 +180,11 @@ protected: private: std::string documentName; + const Gui::MDIView* associatedView; bool escapeButton; bool autoCloseTransaction; bool autoCloseDeletedDocument; + bool autoCloseClosedView; friend class TaskDialogAttorney; }; diff --git a/src/Gui/TaskView/TaskImage.cpp b/src/Gui/TaskView/TaskImage.cpp index 69642bb011..357c97e353 100644 --- a/src/Gui/TaskView/TaskImage.cpp +++ b/src/Gui/TaskView/TaskImage.cpp @@ -679,9 +679,7 @@ TaskImageDialog::TaskImageDialog(Image::ImagePlane* obj) { addTaskBox(Gui::BitmapFactory().pixmap("image-plane"), widget); - auto doc = obj->getDocument(); - setDocumentName(doc->getName()); - setAutoCloseOnDeletedDocument(true); + associateToObject3dView(obj); } void TaskImageDialog::open() diff --git a/src/Gui/TaskView/TaskView.cpp b/src/Gui/TaskView/TaskView.cpp index 6993ad59fa..ad99f23ada 100644 --- a/src/Gui/TaskView/TaskView.cpp +++ b/src/Gui/TaskView/TaskView.cpp @@ -295,6 +295,9 @@ TaskView::TaskView(QWidget *parent) connectApplicationDeleteDocument = App::GetApplication().signalDeleteDocument.connect (std::bind(&Gui::TaskView::TaskView::slotDeletedDocument, this, sp::_1)); + connectApplicationClosedView = + Gui::Application::Instance->signalCloseView.connect + (std::bind(&Gui::TaskView::TaskView::slotViewClosed, this, sp::_1)); connectApplicationUndoDocument = App::GetApplication().signalUndoDocument.connect (std::bind(&Gui::TaskView::TaskView::slotUndoDocument, this, sp::_1)); @@ -310,6 +313,7 @@ TaskView::~TaskView() { connectApplicationActiveDocument.disconnect(); connectApplicationDeleteDocument.disconnect(); + connectApplicationClosedView.disconnect(); connectApplicationUndoDocument.disconnect(); connectApplicationRedoDocument.disconnect(); Gui::Selection().Detach(this); @@ -479,6 +483,29 @@ void TaskView::slotDeletedDocument(const App::Document& doc) } } +void TaskView::slotViewClosed(const Gui::MDIView* view) +{ + // It can happen that only a view is closed an not the document + if (ActiveDialog) { + if (ActiveDialog->isAutoCloseOnClosedView()) { + const Gui::MDIView* associatedView = ActiveDialog->getAssociatedView(); + if (!associatedView) { + Base::Console().Warning(std::string("TaskView::slotViewClosed"), + "No view associated\n"); + } + + if (associatedView == view) { + ActiveDialog->autoClosedOnClosedView(); + removeDialog(); + } + } + } + + if (!ActiveDialog) { + updateWatcher(); + } +} + void TaskView::transactionChangeOnDocument(const App::Document& doc) { if (ActiveDialog) { diff --git a/src/Gui/TaskView/TaskView.h b/src/Gui/TaskView/TaskView.h index 19b318a943..c15d3ab0a4 100644 --- a/src/Gui/TaskView/TaskView.h +++ b/src/Gui/TaskView/TaskView.h @@ -37,6 +37,7 @@ class Property; } namespace Gui { +class MDIView; class ControlSingleton; namespace DockWnd{ class ComboView; @@ -183,6 +184,7 @@ private: void tryRestoreWidth(); void slotActiveDocument(const App::Document&); void slotDeletedDocument(const App::Document&); + void slotViewClosed(const Gui::MDIView*); void slotUndoDocument(const App::Document&); void slotRedoDocument(const App::Document&); void transactionChangeOnDocument(const App::Document&); @@ -210,6 +212,7 @@ protected: Connection connectApplicationActiveDocument; Connection connectApplicationDeleteDocument; + Connection connectApplicationClosedView; Connection connectApplicationUndoDocument; Connection connectApplicationRedoDocument; }; diff --git a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp index fb84095d67..a3b15f0efc 100644 --- a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp +++ b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp @@ -79,6 +79,8 @@ TaskDlgEditSketch::TaskDlgEditSketch(ViewProviderSketch* sketchView) std::bind(&SketcherGui::TaskDlgEditSketch::slotToolChanged, this, sp::_1)); ToolSettings->setHidden(true); + + associateToObject3dView(sketchView->getObject()); } TaskDlgEditSketch::~TaskDlgEditSketch() @@ -145,4 +147,10 @@ bool TaskDlgEditSketch::reject() } +void TaskDlgEditSketch::autoClosedOnClosedView() +{ + // Make sure the edit mode is exited when the view is closed. + reject(); +} + #include "moc_TaskDlgEditSketch.cpp" diff --git a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h index 51b4c6701a..6492e630da 100644 --- a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h +++ b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h @@ -67,6 +67,7 @@ public: { return false; } + void autoClosedOnClosedView() override; /// returns for Close and Help button QDialogButtonBox::StandardButtons getStandardButtons() const override