[MeasureGui] Use temporary measure object creation (#15122)
* MeasureGui: Store measure type in TaskMeasure * MeasureGui: Avoid adding measurement to document during command interaction * [Gui] Add check for document in VPDocumentObject::getActiveView * MeasureGui: Track the document when adding objects * MeasureGui: Cleanup python measurement creation * [Gui] Add isAnnotationViewProvider method * [Gui] Check if viewprovider is added as an annotation in getActiveView * [Gui] Add takeAnnotationViewprovider method to Gui::Document * [Gui] Make addViewProvider public * [MeasureGui] Add existing view provider to document when storing measurement * [MeasureGui] Fix invocation of initial label placement * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -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<std::string,ViewProvider*>::iterator it = d->_ViewProviderMapAnnotation.find(name);
|
||||
std::list<Gui::BaseView*>::iterator vIt;
|
||||
std::map<std::string,ViewProvider*>::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<View3DInventor *>(*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<View3DInventor *>(vIt)) {
|
||||
activeView->getViewer()->removeViewProvider(vp);
|
||||
}
|
||||
}
|
||||
|
||||
return vp;
|
||||
}
|
||||
|
||||
|
||||
void Document::removeAnnotationViewProvider(const char* name)
|
||||
{
|
||||
delete takeAnnotationViewProvider(name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -30,13 +30,13 @@
|
||||
|
||||
#include "TaskMeasure.h"
|
||||
|
||||
#include <App/Document.h>
|
||||
#include <App/DocumentObjectGroup.h>
|
||||
#include <App/Link.h>
|
||||
#include <Gui/MainWindow.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/BitmapFactory.h>
|
||||
#include <Gui/Control.h>
|
||||
#include <Gui/ViewProviderDocumentObject.h>
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QPushButton>
|
||||
@@ -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<Measure::MeasureBase*>(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<App::DocumentObject*>(_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<Gui::ViewProviderDocumentObject*>(vpType.createInstance());
|
||||
|
||||
_mGuiDocument = Gui::Application::Instance->activeDocument();
|
||||
_mGuiDocument->setAnnotationViewProvider(vp->getTypeId().getName(), vp);
|
||||
vp->attach(measureObj);
|
||||
|
||||
// Init the position of the annotation
|
||||
static_cast<MeasureGui::ViewProviderMeasureBase*>(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<MeasureGui::ViewProviderMeasureBase*>(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);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
#include <QLineEdit>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
#include <App/MeasureManager.h>
|
||||
#include <Gui/Document.h>
|
||||
|
||||
#include <Mod/Measure/App/MeasureBase.h>
|
||||
#include <Mod/Measure/Gui/ViewProviderMeasureBase.h>
|
||||
@@ -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<App::DocumentObject> measureObjects;
|
||||
|
||||
Reference in New Issue
Block a user