From 8165d126075f615488defbee2db0b8d19f90e852 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 21 Mar 2025 15:00:12 +0100 Subject: [PATCH] Measure: Fix TaskMeasure Made several fixes to TaskMeasure: * Move to correct namespace * Handle possible exception in update() method * Add null pointer checks for buttonBox * Cannot use 'Measure::MeasurePython' as template argument in addObject<> because the macro PROPERTY_HEADER_WITH_OVERRIDE determines the invalid string 'App::FeaturePythonT' so that an exception is raised Note: The changes might fix issue 20304 --- src/App/Document.cpp | 2 +- src/Mod/Measure/Gui/Command.cpp | 2 +- src/Mod/Measure/Gui/TaskMeasure.cpp | 38 ++++++++++++++++++++--------- src/Mod/Measure/Gui/TaskMeasure.h | 7 +++--- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 5c01df8069..246a76e388 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -3065,7 +3065,7 @@ DocumentObject* Document::addObject(const char* sType, Base::Type::getTypeIfDerivedFrom(sType, DocumentObject::getClassTypeId(), true); if (type.isBad()) { std::stringstream str; - str << "'" << sType << "' is not a document object type"; + str << "Document::addObject: '" << sType << "' is not a document object type"; throw Base::TypeError(str.str()); } diff --git a/src/Mod/Measure/Gui/Command.cpp b/src/Mod/Measure/Gui/Command.cpp index 5f78fd85eb..873059b9da 100644 --- a/src/Mod/Measure/Gui/Command.cpp +++ b/src/Mod/Measure/Gui/Command.cpp @@ -62,7 +62,7 @@ void StdCmdMeasure::activated(int iMsg) { Q_UNUSED(iMsg); - Gui::TaskMeasure* task = new Gui::TaskMeasure(); + MeasureGui::TaskMeasure* task = new MeasureGui::TaskMeasure(); task->setDocumentName(this->getDocument()->getName()); Gui::Control().showDialog(task); } diff --git a/src/Mod/Measure/Gui/TaskMeasure.cpp b/src/Mod/Measure/Gui/TaskMeasure.cpp index d36454690f..45c784f71d 100644 --- a/src/Mod/Measure/Gui/TaskMeasure.cpp +++ b/src/Mod/Measure/Gui/TaskMeasure.cpp @@ -48,7 +48,7 @@ #include #include -using namespace Gui; +using namespace MeasureGui; namespace { @@ -225,7 +225,9 @@ Measure::MeasureBase* TaskMeasure::createObject(const App::MeasureType* measureT auto pyMeasureClass = measureType->pythonClass; // Create a MeasurePython instance - // Measure::MeasurePython is an alias so we need to use the string based addObject for now. + // Note: writing addObject() is not yet supported because + // getClassName() will determine the string 'App::FeaturePythonT' instead + // of 'Measure::MeasurePython' auto featurePython = doc->addObject("Measure::MeasurePython", measureType->label.c_str()); _mMeasureObject = dynamic_cast(featurePython); @@ -245,8 +247,17 @@ Measure::MeasureBase* TaskMeasure::createObject(const App::MeasureType* measureT return _mMeasureObject; } - void TaskMeasure::update() +{ + try { + tryUpdate(); + } + catch (const Base::Exception& e) { + e.reportException(); + } +} + +void TaskMeasure::tryUpdate() { App::Document* doc = App::GetApplication().getActiveDocument(); @@ -274,7 +285,7 @@ void TaskMeasure::update() std::string mode = explicitMode ? modeSwitch->currentText().toStdString() : ""; App::MeasureSelection selection; - for (auto s : Gui::Selection().getSelection(doc->getName(), ResolveMode::NoResolve)) { + for (auto s : Gui::Selection().getSelection(doc->getName(), Gui::ResolveMode::NoResolve)) { App::SubObjectT sub(s.pObject, s.SubName); App::MeasureSelectionItem item = {sub, Base::Vector3d(s.x, s.y, s.z)}; @@ -358,7 +369,7 @@ void TaskMeasure::initViewObject() void TaskMeasure::close() { - Control().closeDialog(); + Gui::Control().closeDialog(); } @@ -460,9 +471,10 @@ void TaskMeasure::clearSelection() void TaskMeasure::onSelectionChanged(const Gui::SelectionChanges& msg) { // Skip non-relevant events - if (msg.Type != SelectionChanges::AddSelection && msg.Type != SelectionChanges::RmvSelection - && msg.Type != SelectionChanges::SetSelection - && msg.Type != SelectionChanges::ClrSelection) { + if (msg.Type != Gui::SelectionChanges::AddSelection + && msg.Type != Gui::SelectionChanges::RmvSelection + && msg.Type != Gui::SelectionChanges::SetSelection + && msg.Type != Gui::SelectionChanges::ClrSelection) { return; } @@ -476,9 +488,9 @@ void TaskMeasure::onSelectionChanged(const Gui::SelectionChanges& msg) const bool shift = (modifier & Qt::ShiftModifier) > 0; // shift inverts the current state temporarily const auto autosave = (mAutoSave && !shift) || (!mAutoSave && shift); - if ((!ctrl && Selection().getSelectionStyle() == SelectionStyle::NormalSelection) - || (ctrl && Selection().getSelectionStyle() == SelectionStyle::GreedySelection)) { - if (autosave && this->buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) { + if ((!ctrl && Gui::Selection().getSelectionStyle() == SelectionStyle::NormalSelection) + || (ctrl && Gui::Selection().getSelectionStyle() == SelectionStyle::GreedySelection)) { + if (autosave && buttonBox && buttonBox->button(QDialogButtonBox::Apply)->isEnabled()) { apply(false); } } @@ -506,7 +518,9 @@ bool TaskMeasure::eventFilter(QObject* obj, QEvent* event) if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { // Save object. Indirectly dependent on whether the apply button is enabled // enabled if valid measurement object. - this->buttonBox->button(QDialogButtonBox::Apply)->click(); + if (buttonBox) { + buttonBox->button(QDialogButtonBox::Apply)->click(); + } return true; } } diff --git a/src/Mod/Measure/Gui/TaskMeasure.h b/src/Mod/Measure/Gui/TaskMeasure.h index 399641d56c..e5e9694305 100644 --- a/src/Mod/Measure/Gui/TaskMeasure.h +++ b/src/Mod/Measure/Gui/TaskMeasure.h @@ -41,10 +41,10 @@ #include #include -namespace Gui +namespace MeasureGui { -class TaskMeasure: public TaskView::TaskDialog, public Gui::SelectionObserver +class TaskMeasure: public Gui::TaskView::TaskDialog, public Gui::SelectionObserver { public: @@ -70,6 +70,7 @@ public: bool eventFilter(QObject* obj, QEvent* event) override; private: + void tryUpdate(); void onSelectionChanged(const Gui::SelectionChanges& msg) override; Measure::MeasureBase* _mMeasureObject = nullptr; @@ -103,6 +104,6 @@ private: bool mAutoSave = false; }; -} // namespace Gui +} // namespace MeasureGui #endif // MEASURE_TASKMEASURE_H