diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index b6bdeb950f..bd3e7a8518 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -556,20 +556,41 @@ ViewProvider * Document::getAnnotationViewProvider(const char* name) const return ( (it != d->_ViewProviderMapAnnotation.end()) ? it->second : 0 ); } -void Document::removeAnnotationViewProvider(const char* name) +bool Document::isAnnotationViewProvider(const ViewProvider* vp) const { - std::map::iterator it = d->_ViewProviderMapAnnotation.find(name); - std::list::iterator vIt; + std::map::const_iterator it; + for (it = d->_ViewProviderMapAnnotation.begin(); it != d->_ViewProviderMapAnnotation.end(); ++it) { + if (it->second == vp) + return true; + } + return false; +} - // cycling to all views of the document - for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) { - auto activeView = dynamic_cast(*vIt); - if (activeView) - activeView->getViewer()->removeViewProvider(it->second); + +ViewProvider* Document::takeAnnotationViewProvider(const char* name) +{ + auto it = d->_ViewProviderMapAnnotation.find(name); + if (it == d->_ViewProviderMapAnnotation.end()) { + return nullptr; } - delete it->second; + ViewProvider* vp = it->second; d->_ViewProviderMapAnnotation.erase(it); + + // cycling to all views of the document + for (auto vIt : d->baseViews) { + if (auto activeView = dynamic_cast(vIt)) { + activeView->getViewer()->removeViewProvider(vp); + } + } + + return vp; +} + + +void Document::removeAnnotationViewProvider(const char* name) +{ + delete takeAnnotationViewProvider(name); } diff --git a/src/Gui/Document.h b/src/Gui/Document.h index 8d65a4b88f..4e2d8f59da 100644 --- a/src/Gui/Document.h +++ b/src/Gui/Document.h @@ -95,9 +95,9 @@ protected: void slotChangePropertyEditor(const App::Document&, const App::Property &); //@} +public: void addViewProvider(Gui::ViewProviderDocumentObject*); -public: /** @name Signals of the document */ //@{ /// signal on new Object @@ -227,7 +227,11 @@ public: void setAnnotationViewProvider(const char* name, ViewProvider *pcProvider); /// get an annotation view provider ViewProvider * getAnnotationViewProvider(const char* name) const; - /// remove an annotation view provider + /// return true if the view provider is added as an annotation view provider + bool isAnnotationViewProvider(const ViewProvider* vp) const; + /// remove an annotation view provider from the document and return it + ViewProvider* takeAnnotationViewProvider(const char* name); + /// remove and delete an annotation view provider void removeAnnotationViewProvider(const char* name); /// test if the feature is in show bool isShow(const char* name); diff --git a/src/Gui/ViewProviderDocumentObject.cpp b/src/Gui/ViewProviderDocumentObject.cpp index 96640c61c0..3aed6cf9b1 100644 --- a/src/Gui/ViewProviderDocumentObject.cpp +++ b/src/Gui/ViewProviderDocumentObject.cpp @@ -401,6 +401,18 @@ Gui::MDIView* ViewProviderDocumentObject::getActiveView() const { if(!pcObject) throw Base::RuntimeError("View provider detached"); + + if (!pcObject->isAttachedToDocument()) { + // Check if view provider is attached to a document as an annotation + for (auto doc : App::GetApplication().getDocuments()) { + auto guiDoc = Gui::Application::Instance->getDocument(doc); + if (guiDoc->isAnnotationViewProvider(this)) { + return guiDoc->getActiveView(); + } + } + return nullptr; + } + App::Document* pAppDoc = pcObject->getDocument(); Gui::Document* pGuiDoc = Gui::Application::Instance->getDocument(pAppDoc); return pGuiDoc->getActiveView(); diff --git a/src/Mod/Measure/Gui/TaskMeasure.cpp b/src/Mod/Measure/Gui/TaskMeasure.cpp index cf5f4bc59f..a3e0256916 100644 --- a/src/Mod/Measure/Gui/TaskMeasure.cpp +++ b/src/Mod/Measure/Gui/TaskMeasure.cpp @@ -30,13 +30,13 @@ #include "TaskMeasure.h" -#include #include #include #include #include #include #include +#include #include #include @@ -162,6 +162,81 @@ void TaskMeasure::setMeasureObject(Measure::MeasureBase* obj) } +App::DocumentObject* TaskMeasure::createObject(const App::MeasureType* measureType) +{ + auto measureClass = + measureType->isPython ? "Measure::MeasurePython" : measureType->measureObject; + auto type = Base::Type::getTypeIfDerivedFrom(measureClass.c_str(), + App::DocumentObject::getClassTypeId(), + true); + + if (type.isBad()) { + return nullptr; + } + + _mMeasureObject = static_cast(type.createInstance()); + + // Create an instance of the python measure class, the classe's + // initializer sets the object as proxy + if (measureType->isPython) { + Base::PyGILStateLocker lock; + Py::Tuple args(1); + args.setItem(0, Py::asObject(_mMeasureObject->getPyObject())); + PyObject* result = PyObject_CallObject(measureType->pythonClass, args.ptr()); + Py_XDECREF(result); + } + + return static_cast(_mMeasureObject); +} + + +Gui::ViewProviderDocumentObject* TaskMeasure::createViewObject(App::DocumentObject* measureObj) +{ + // Add view object + auto vpName = measureObj->getViewProviderName(); + if ((vpName == nullptr) || (vpName[0] == '\0')) { + return nullptr; + } + + auto vpType = + Base::Type::getTypeIfDerivedFrom(vpName, + Gui::ViewProviderDocumentObject::getClassTypeId(), + true); + if (vpType.isBad()) { + return nullptr; + } + + auto vp = static_cast(vpType.createInstance()); + + _mGuiDocument = Gui::Application::Instance->activeDocument(); + _mGuiDocument->setAnnotationViewProvider(vp->getTypeId().getName(), vp); + vp->attach(measureObj); + + // Init the position of the annotation + static_cast(vp)->positionAnno(_mMeasureObject); + + vp->updateView(); + vp->setActiveMode(); + + _mViewObject = vp; + return vp; +} + + +void TaskMeasure::saveObject() +{ + if (_mViewObject && _mGuiDocument) { + _mGuiDocument->addViewProvider(_mViewObject); + _mGuiDocument->takeAnnotationViewProvider(_mViewObject->getTypeId().getName()); + _mViewObject = nullptr; + } + + _mDocument = App::GetApplication().getActiveDocument(); + _mDocument->addObject(_mMeasureObject, _mMeasureType->label.c_str()); + _mMeasureObject = nullptr; +} + + void TaskMeasure::update() { App::Document* doc = App::GetApplication().getActiveDocument(); @@ -189,8 +264,6 @@ void TaskMeasure::update() valueResult->setText(QString::asprintf("-")); // Get valid measure type - App::MeasureType* measureType(nullptr); - std::string mode = explicitMode ? modeSwitch->currentText().toStdString() : ""; @@ -204,10 +277,11 @@ void TaskMeasure::update() auto measureTypes = App::MeasureManager::getValidMeasureTypes(selection, mode); if (measureTypes.size() > 0) { - measureType = measureTypes.front(); + _mMeasureType = measureTypes.front(); } - if (!measureType) { + + if (!_mMeasureType) { // Note: If there's no valid measure type we might just restart the selection, // however this requires enough coverage of measuretypes that we can access all of them @@ -226,34 +300,13 @@ void TaskMeasure::update() } // Update tool mode display - setModeSilent(measureType); + setModeSilent(_mMeasureType); - if (!_mMeasureObject || measureType->measureObject != _mMeasureObject->getTypeId().getName()) { + if (!_mMeasureObject + || _mMeasureType->measureObject != _mMeasureObject->getTypeId().getName()) { // we don't already have a measureobject or it isn't the same type as the new one removeObject(); - - if (measureType->isPython) { - Base::PyGILStateLocker lock; - auto pyMeasureClass = measureType->pythonClass; - - // Create a MeasurePython instance - auto featurePython = - doc->addObject("Measure::MeasurePython", measureType->label.c_str()); - setMeasureObject((Measure::MeasureBase*)featurePython); - - // Create an instance of the pyMeasureClass, the classe's initializer sets the object as - // proxy - Py::Tuple args(1); - args.setItem(0, Py::asObject(featurePython->getPyObject())); - PyObject* result = PyObject_CallObject(pyMeasureClass, args.ptr()); - Py_XDECREF(result); - } - else { - // Create measure object - setMeasureObject( - (Measure::MeasureBase*)doc->addObject(measureType->measureObject.c_str(), - measureType->label.c_str())); - } + createObject(_mMeasureType); } // we have a valid measure object so we can enable the annotate button @@ -262,14 +315,10 @@ void TaskMeasure::update() // Fill measure object's properties from selection _mMeasureObject->parseSelection(selection); - // Init the view object - Gui::ViewProvider* viewObj = Gui::Application::Instance->getViewProvider(_mMeasureObject); - if (viewObj) { - static_cast(viewObj)->positionAnno(_mMeasureObject); - } - // Get result valueResult->setText(_mMeasureObject->getResultString()); + + createViewObject(_mMeasureObject); } void TaskMeasure::close() @@ -278,7 +327,7 @@ void TaskMeasure::close() } -void ensureGroup(Measure::MeasureBase* measurement) +void TaskMeasure::ensureGroup(Measure::MeasureBase* measurement) { // Ensure measurement object is part of the measurements group @@ -287,7 +336,7 @@ void ensureGroup(Measure::MeasureBase* measurement) return; } - App::Document* doc = App::GetApplication().getActiveDocument(); + App::Document* doc = measurement->getDocument(); App::DocumentObject* obj = doc->getObject(measurementGroupName); if (!obj || !obj->isValid()) { obj = doc->addObject("App::DocumentObjectGroup", @@ -309,7 +358,9 @@ void TaskMeasure::invoke() bool TaskMeasure::apply() { + saveObject(); ensureGroup(_mMeasureObject); + _mMeasureType = nullptr; _mMeasureObject = nullptr; reset(); @@ -332,6 +383,7 @@ bool TaskMeasure::reject() void TaskMeasure::reset() { // Reset tool state + _mMeasureType = nullptr; this->clearSelection(); // Should the explicit mode also be reset? @@ -350,7 +402,13 @@ void TaskMeasure::removeObject() if (_mMeasureObject->isRemoving()) { return; } - _mMeasureObject->getDocument()->removeObject(_mMeasureObject->getNameInDocument()); + + if (_mViewObject && _mGuiDocument) { + _mGuiDocument->removeAnnotationViewProvider(_mViewObject->getTypeId().getName()); + _mViewObject = nullptr; + } + + delete _mMeasureObject; setMeasureObject(nullptr); } diff --git a/src/Mod/Measure/Gui/TaskMeasure.h b/src/Mod/Measure/Gui/TaskMeasure.h index 152489992f..13ab9833af 100644 --- a/src/Mod/Measure/Gui/TaskMeasure.h +++ b/src/Mod/Measure/Gui/TaskMeasure.h @@ -26,7 +26,9 @@ #include #include +#include #include +#include #include #include @@ -67,7 +69,11 @@ public: private: void onSelectionChanged(const Gui::SelectionChanges& msg) override; + App::Document* _mDocument = nullptr; + Gui::Document* _mGuiDocument = nullptr; + App::MeasureType* _mMeasureType = nullptr; Measure::MeasureBase* _mMeasureObject = nullptr; + Gui::ViewProviderDocumentObject* _mViewObject = nullptr; QLineEdit* valueResult {nullptr}; QComboBox* modeSwitch {nullptr}; @@ -77,6 +83,11 @@ private: void setModeSilent(App::MeasureType* mode); App::MeasureType* getMeasureType(); void enableAnnotateButton(bool state); + App::DocumentObject* createObject(const App::MeasureType* measureType); + Gui::ViewProviderDocumentObject* createViewObject(App::DocumentObject* measureObj); + void saveObject(); + void ensureGroup(Measure::MeasureBase* measurement); + // List of measure types std::vector measureObjects;