diff --git a/src/App/DocumentObject.cpp b/src/App/DocumentObject.cpp index cde03faa4..ca44ceb90 100644 --- a/src/App/DocumentObject.cpp +++ b/src/App/DocumentObject.cpp @@ -305,6 +305,10 @@ void DocumentObject::connectRelabelSignals() if (!onRelabledObjectConnection.connected()) onRelabledObjectConnection = getDocument()->signalRelabelObject.connect(boost::bind(&PropertyExpressionEngine::slotObjectRenamed, &ExpressionEngine, _1)); + // Connect to signalDeletedObject, to properly track deletion of other objects that might be referenced in an expression + if (!onDeletedObjectConnection.connected()) + onDeletedObjectConnection = getDocument()->signalDeletedObject.connect(boost::bind(&PropertyExpressionEngine::slotObjectDeleted, &ExpressionEngine, _1)); + try { // Crude method to resolve all expression dependencies ExpressionEngine.execute(); @@ -317,5 +321,6 @@ void DocumentObject::connectRelabelSignals() // Disconnect signals; nothing to track now onRelabledObjectConnection.disconnect(); onRelabledDocumentConnection.disconnect(); + onDeletedObjectConnection.disconnect(); } } diff --git a/src/App/DocumentObject.h b/src/App/DocumentObject.h index 8a9406a98..8b32e7a5e 100644 --- a/src/App/DocumentObject.h +++ b/src/App/DocumentObject.h @@ -223,6 +223,7 @@ protected: // attributes // Connections to track relabeling of document and document objects boost::BOOST_SIGNALS_NAMESPACE::scoped_connection onRelabledDocumentConnection; boost::BOOST_SIGNALS_NAMESPACE::scoped_connection onRelabledObjectConnection; + boost::BOOST_SIGNALS_NAMESPACE::scoped_connection onDeletedObjectConnection; /// Old label; used for renaming expressions std::string oldLabel; diff --git a/src/App/PropertyExpressionEngine.cpp b/src/App/PropertyExpressionEngine.cpp index fdbcb7bda..141be9508 100644 --- a/src/App/PropertyExpressionEngine.cpp +++ b/src/App/PropertyExpressionEngine.cpp @@ -94,6 +94,34 @@ private: int changed; }; +class ObjectDeletedExpressionVisitor : public ExpressionVisitor { +public: + + ObjectDeletedExpressionVisitor(const App::DocumentObject * _obj) + : obj(_obj) + , found(false) + { + } + + /** + * @brief Visit each node in the expression, and if it is a VariableExpression object check if it references obj + * @param node Node to visit + */ + + void visit(Expression * node) { + VariableExpression *expr = freecad_dynamic_cast(node); + + if (expr && expr->getPath().getDocumentObject() == obj) + found = true; + } + + bool isFound() const { return found; } + +private: + const App::DocumentObject * obj; + bool found; +}; + TYPESYSTEM_SOURCE(App::PropertyExpressionEngine , App::Property); /** @@ -315,6 +343,26 @@ void PropertyExpressionEngine::slotObjectRenamed(const DocumentObject &obj) } } +void PropertyExpressionEngine::slotObjectDeleted(const DocumentObject &obj) +{ + DocumentObject * docObj = freecad_dynamic_cast(getContainer()); + + /* In a document object, and on undo stack? */ + if (!docObj || docObj->getNameInDocument() == 0) + return; + + ObjectDeletedExpressionVisitor v(&obj); + + for (ExpressionMap::iterator it = expressions.begin(); it != expressions.end(); ++it) { + it->second.expression->visit(v); + + if (v.isFound()) { + touch(); // Touch to force recompute; that will trigger a proper error + return; + } + } +} + /** * @brief Get expression for \a path. * @param path ObjectIndentifier to query for. diff --git a/src/App/PropertyExpressionEngine.h b/src/App/PropertyExpressionEngine.h index 406b3a0ca..a2d948abd 100644 --- a/src/App/PropertyExpressionEngine.h +++ b/src/App/PropertyExpressionEngine.h @@ -118,6 +118,8 @@ public: size_t numExpressions() const; void slotObjectRenamed(const App::DocumentObject & obj); + + void slotObjectDeleted(const DocumentObject &obj); ///signal called when a expression was changed boost::signal expressionChanged;