[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:
hlorus
2024-09-02 17:54:05 +02:00
committed by GitHub
parent 7b0a23337c
commit 979ca3bbd1
5 changed files with 156 additions and 50 deletions

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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;