From 34c35f8eff8eceae600b0b9731ca86eb99a10072 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Wed, 1 Jan 2020 18:13:55 +0800 Subject: [PATCH] Gui: fix property editor crash on remove dynamic property The crash happens when the dynamic property is removed due changes of the very same property. --- src/Gui/propertyeditor/PropertyItem.cpp | 95 ++++++++++++------------- src/Gui/propertyeditor/PropertyItem.h | 1 - 2 files changed, 45 insertions(+), 51 deletions(-) diff --git a/src/Gui/propertyeditor/PropertyItem.cpp b/src/Gui/propertyeditor/PropertyItem.cpp index c9757b38e0..334aeccd32 100644 --- a/src/Gui/propertyeditor/PropertyItem.cpp +++ b/src/Gui/propertyeditor/PropertyItem.cpp @@ -395,38 +395,6 @@ void PropertyItem::setValue(const QVariant& /*value*/) { } -QString PropertyItem::pythonIdentifier(const App::Property* prop) const -{ - App::PropertyContainer* parent = prop->getContainer(); - QString propPrefix = QString::fromLatin1(parent->getPropertyPrefix()); - if (parent->getTypeId() == App::Document::getClassTypeId()) { - App::Document* doc = static_cast(parent); - QString docName = QString::fromLatin1(App::GetApplication().getDocumentName(doc)); - QString propName = QString::fromLatin1(prop->getName()); - return QString::fromLatin1("FreeCAD.getDocument(\"%1\").%3%2").arg(docName).arg(propName).arg(propPrefix); - } - if (parent->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId())) { - App::DocumentObject* obj = static_cast(parent); - App::Document* doc = obj->getDocument(); - QString docName = QString::fromLatin1(App::GetApplication().getDocumentName(doc)); - QString objName = QString::fromLatin1(obj->getNameInDocument()); - QString propName = QString::fromLatin1(prop->getName()); - return QString::fromLatin1("FreeCAD.getDocument(\"%1\").getObject(\"%2\").%4%3") - .arg(docName,objName,propName,propPrefix); - } - auto* vp = dynamic_cast(parent); - if (vp) { - App::DocumentObject* obj = vp->getObject(); - App::Document* doc = obj->getDocument(); - QString docName = QString::fromLatin1(App::GetApplication().getDocumentName(doc)); - QString objName = QString::fromLatin1(obj->getNameInDocument()); - QString propName = QString::fromLatin1(prop->getName()); - return QString::fromLatin1("FreeCADGui.getDocument(\"%1\").getObject(\"%2\").%4%3") - .arg(docName,objName,propName,propPrefix); - } - return QString(); -} - QWidget* PropertyItem::createEditor(QWidget* /*parent*/, const QObject* /*receiver*/, const char* /*method*/) const { return 0; @@ -502,25 +470,52 @@ void PropertyItem::setPropertyName(const QString& name) void PropertyItem::setPropertyValue(const QString& value) { + // Construct command for property assignment in one go, in case of any + // intermediate changes caused by property change that may potentially + // invalidate the current property array. + std::ostringstream ss; for (std::vector::const_iterator it = propertyItems.begin(); - it != propertyItems.end(); ++it) { - App::PropertyContainer* parent = (*it)->getContainer(); - if (parent && !parent->isReadOnly(*it) && !(*it)->testStatus(App::Property::ReadOnly)) { - QString cmd = QString::fromLatin1("%1 = %2").arg(pythonIdentifier(*it), value); - try { - Gui::Command::runCommand(Gui::Command::App, cmd.toUtf8()); - } - catch (Base::PyException &e) { - e.ReportException(); - Base::Console().Error("Stack Trace: %s\n",e.getStackTrace().c_str()); - } - catch (Base::Exception &e) { - e.ReportException(); - } - catch (...) { - Base::Console().Error("Unknown C++ exception in PropertyItem::setPropertyValue thrown\n"); - } - } + it != propertyItems.end(); ++it) + { + auto prop = *it; + App::PropertyContainer* parent = prop->getContainer(); + if (!parent || parent->isReadOnly(prop) || prop->testStatus(App::Property::ReadOnly)) + continue; + if (parent->isDerivedFrom(App::Document::getClassTypeId())) { + App::Document* doc = static_cast(parent); + ss << "FreeCAD.getDocument('" << doc->getName() << "')."; + } else if (parent->isDerivedFrom(App::DocumentObject::getClassTypeId())) { + App::DocumentObject* obj = static_cast(parent); + App::Document* doc = obj->getDocument(); + ss << "FreeCAD.getDocument('" << doc->getName() << "').getObject('" + << obj->getNameInDocument() << "')."; + } else if (parent->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) { + App::DocumentObject* obj = static_cast(parent)->getObject(); + App::Document* doc = obj->getDocument(); + ss << "FreeCADGui.getDocument('" << doc->getName() << "').getObject('" + << obj->getNameInDocument() << "')."; + } else + continue; + ss << parent->getPropertyPrefix() << prop->getName() + << " = " << value.toLatin1().constData() << '\n'; + } + + std::string cmd = ss.str(); + if(cmd.empty()) + return; + + try { + Gui::Command::runCommand(Gui::Command::App, cmd.c_str()); + } + catch (Base::PyException &e) { + e.ReportException(); + Base::Console().Error("Stack Trace: %s\n",e.getStackTrace().c_str()); + } + catch (Base::Exception &e) { + e.ReportException(); + } + catch (...) { + Base::Console().Error("Unknown C++ exception in PropertyItem::setPropertyValue thrown\n"); } } diff --git a/src/Gui/propertyeditor/PropertyItem.h b/src/Gui/propertyeditor/PropertyItem.h index 5027348908..95e69de707 100644 --- a/src/Gui/propertyeditor/PropertyItem.h +++ b/src/Gui/propertyeditor/PropertyItem.h @@ -182,7 +182,6 @@ protected: virtual QVariant value(const App::Property*) const; virtual void setValue(const QVariant&); virtual void initialize(); - QString pythonIdentifier(const App::Property*) const; //gets called when the bound expression is changed virtual void onChange();