From 810135fad469d540ca67e8de2f422329b572dc0c Mon Sep 17 00:00:00 2001 From: Eivind Kvedalen Date: Mon, 8 Feb 2016 21:01:33 +0100 Subject: [PATCH] PropertyExpressionEngine: Refactored and moved visitor code to separate file. --- src/App/CMakeLists.txt | 1 + src/App/Expression.cpp | 10 +++ src/App/Expression.h | 6 +- src/App/ExpressionVisitors.h | 128 +++++++++++++++++++++++++++ src/App/ObjectIdentifier.cpp | 46 ++++++++++ src/App/ObjectIdentifier.h | 4 + src/App/PropertyExpressionEngine.cpp | 97 +------------------- 7 files changed, 197 insertions(+), 95 deletions(-) create mode 100644 src/App/ExpressionVisitors.h diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt index 64f0f5538..6efca1390 100644 --- a/src/App/CMakeLists.txt +++ b/src/App/CMakeLists.txt @@ -85,6 +85,7 @@ SET(Document_HPP_SRCS DocumentObserver.h DocumentObserverPython.h Expression.h + ExpressionVisitors.h FeatureCustom.h FeaturePython.h FeaturePythonPyImp.h diff --git a/src/App/Expression.cpp b/src/App/Expression.cpp index c915c4e64..f11d80e2e 100644 --- a/src/App/Expression.cpp +++ b/src/App/Expression.cpp @@ -1100,11 +1100,21 @@ void VariableExpression::setPath(const ObjectIdentifier &path) var = path; } +bool VariableExpression::validDocumentObjectRename(const std::string &oldName, const std::string &newName) +{ + return var.validDocumentObjectRename(oldName, newName); +} + bool VariableExpression::renameDocumentObject(const std::string &oldName, const std::string &newName) { return var.renameDocumentObject(oldName, newName); } +bool VariableExpression::validDocumentRename(const std::string &oldName, const std::string &newName) +{ + return var.validDocumentRename(oldName, newName); +} + bool VariableExpression::renameDocument(const std::string &oldName, const std::string &newName) { return var.renameDocument(oldName, newName); diff --git a/src/App/Expression.h b/src/App/Expression.h index 5f3f7fb44..e20ea4d9c 100644 --- a/src/App/Expression.h +++ b/src/App/Expression.h @@ -46,7 +46,7 @@ public: virtual void visit(Expression * e) = 0; }; -template class AppExport ExpressionModifier : public ExpressionVisitor { +template class ExpressionModifier : public ExpressionVisitor { public: ExpressionModifier(P & _prop) : prop(_prop) { } @@ -368,8 +368,12 @@ public: void setPath(const ObjectIdentifier & path); + bool validDocumentObjectRename(const std::string & oldName, const std::string & newName); + bool renameDocumentObject(const std::string & oldName, const std::string & newName); + bool validDocumentRename(const std::string &oldName, const std::string &newName); + bool renameDocument(const std::string &oldName, const std::string &newName); const App::Property *getProperty() const; diff --git a/src/App/ExpressionVisitors.h b/src/App/ExpressionVisitors.h new file mode 100644 index 000000000..00f2e9289 --- /dev/null +++ b/src/App/ExpressionVisitors.h @@ -0,0 +1,128 @@ +/*************************************************************************** + * Copyright (c) Eivind Kvedalen (eivind@kvedalen.name) 2016 * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + +#ifndef RENAMEOBJECTIDENTIFIEREXPRESSIONVISITOR_H +#define RENAMEOBJECTIDENTIFIEREXPRESSIONVISITOR_H + +#include +#include "Expression.h" + +namespace App { + +/** + * @brief The RenameObjectIdentifierExpressionVisitor class is a functor used to visit each node of an expression, and + * possibly rename VariableExpression nodes. + */ + +template class RenameObjectIdentifierExpressionVisitor : public ExpressionModifier

{ +public: + RenameObjectIdentifierExpressionVisitor(P & _prop, + const std::map &_paths, const ObjectIdentifier & _owner) + : ExpressionModifier

(_prop) + , paths(_paths) + , owner(_owner) + { + } + + void visit(Expression *node) { + VariableExpression *expr = Base::freecad_dynamic_cast(node); + + if (expr) { + const App::ObjectIdentifier & oldPath = expr->getPath().canonicalPath(); + const std::map::const_iterator it = paths.find(oldPath); + + if (it != paths.end()) { + ExpressionModifier

::setExpressionChanged(); + expr->setPath(it->second.relativeTo(owner)); + } + } + } + + +private: + const std::map &paths; /**< Map with current and new object identifiers */ + const ObjectIdentifier owner; /**< Owner of expression */ +}; + +/** + * @brief The RelabelDocumentObjectExpressionVisitor class is a functor class used to rename variables in an expression. + */ + +template class RelabelDocumentObjectExpressionVisitor : public ExpressionModifier

{ +public: + + RelabelDocumentObjectExpressionVisitor(P & _prop, const std::string & _oldName, const std::string & _newName) + : ExpressionModifier

(_prop) + , oldName(_oldName) + , newName(_newName) + { + } + + ~RelabelDocumentObjectExpressionVisitor() { + } + + /** + * @brief Visit each node in the expression, and if it is a VariableExpression object, incoke renameDocumentObject in it. + * @param node Node to visit + */ + + void visit(Expression * node) { + VariableExpression *expr = Base::freecad_dynamic_cast(node); + + if (expr && expr->validDocumentObjectRename(oldName, newName)) { + ExpressionModifier

::setExpressionChanged(); + expr->renameDocumentObject(oldName, newName); + } + } + +private: + std::string oldName; /**< Document object name to replace */ + std::string newName; /**< New document object name */ +}; + +template class RelabelDocumentExpressionVisitor : public ExpressionModifier

{ +public: + + RelabelDocumentExpressionVisitor(P & prop, const std::string & _oldName, const std::string & _newName) + : ExpressionModifier

(prop) + , oldName(_oldName) + , newName(_newName) + { + } + + void visit(Expression * node) { + VariableExpression *expr = Base::freecad_dynamic_cast(node); + + if (expr && expr->validDocumentRename(oldName, newName)) { + ExpressionModifier

::setExpressionChanged(); + expr->renameDocument(oldName, newName); + } + } + +private: + std::string oldName; + std::string newName; +}; + +} + +#endif // RENAMEOBJECTIDENTIFIEREXPRESSIONVISITOR_H diff --git a/src/App/ObjectIdentifier.cpp b/src/App/ObjectIdentifier.cpp index 1e4e59a32..586cbe6e2 100644 --- a/src/App/ObjectIdentifier.cpp +++ b/src/App/ObjectIdentifier.cpp @@ -365,6 +365,29 @@ bool ObjectIdentifier::renameDocumentObject(const std::string &oldName, const st return false; } + +/** + * @brief Check whether a rename call with the same arguments would actually cause a rename. + * @param oldName Name of current document object + * @param newName New name of document object + */ + +bool ObjectIdentifier::validDocumentObjectRename(const std::string &oldName, const std::string &newName) +{ + if (oldName == newName) + return false; + + if (documentObjectNameSet && documentObjectName == oldName) + return true; + else { + ResolveResults result(*this); + + if (result.propertyIndex == 1 && result.resolvedDocumentObjectName == oldName) + return true; + } + return false; +} + /** * @brief Modify object identifier given that the document \a oldName has changed name to \a newName. * @param oldName Name of current document @@ -392,6 +415,29 @@ bool ObjectIdentifier::renameDocument(const std::string &oldName, const std::str return false; } +/** + * @brief Check whether a rename call with the same arguments would actually cause a rename. + * @param oldName Name of current document + * @param newName New name of document + */ + +bool ObjectIdentifier::validDocumentRename(const std::string &oldName, const std::string &newName) +{ + if (oldName == newName) + return false; + + if (documentNameSet && documentName == oldName) + return true; + else { + ResolveResults result(*this); + + if (result.resolvedDocumentName == oldName) + return true; + } + + return false; +} + /** * @brief Get sub field part of a property as a string. * @return String representation of path. diff --git a/src/App/ObjectIdentifier.h b/src/App/ObjectIdentifier.h index b77e5abad..c838f3be4 100644 --- a/src/App/ObjectIdentifier.h +++ b/src/App/ObjectIdentifier.h @@ -190,8 +190,12 @@ public: const String getDocumentObjectName() const; + bool validDocumentObjectRename(const std::string &oldName, const std::string &newName); + bool renameDocumentObject(const std::string & oldName, const std::string & newName); + bool validDocumentRename(const std::string &oldName, const std::string &newName); + bool renameDocument(const std::string &oldName, const std::string &newName); App::Document *getDocument(String name = String()) const; diff --git a/src/App/PropertyExpressionEngine.cpp b/src/App/PropertyExpressionEngine.cpp index 6359dfdd7..00b02935f 100644 --- a/src/App/PropertyExpressionEngine.cpp +++ b/src/App/PropertyExpressionEngine.cpp @@ -28,6 +28,7 @@ #include #include #include "Expression.h" +#include "ExpressionVisitors.h" #include "PropertyExpressionEngine.h" #include "PropertyStandard.h" #include "PropertyUnits.h" @@ -41,59 +42,6 @@ using namespace App; using namespace Base; using namespace boost; -typedef boost::function aboutToSetValueFunc; -typedef boost::function hasSetValueFunc; - -/** - * @brief The RelabelDocumentObjectExpressionVisitor class is a functor class used to rename variables in an expression. - */ - -class RelabelDocumentObjectExpressionVisitor : public ExpressionVisitor { -public: - - RelabelDocumentObjectExpressionVisitor(aboutToSetValueFunc _aboutToSetValue, hasSetValueFunc _hasSetValue, const std::string & _oldName, const std::string & _newName) - : aboutToSetValue(_aboutToSetValue) - , hasSetValue(_hasSetValue) - , oldName(_oldName) - , newName(_newName) - , changed(0) - { - } - - ~RelabelDocumentObjectExpressionVisitor() { - if (changed > 0) - hasSetValue(); - } - - - /** - * @brief Visit each node in the expression, and if it is a VariableExpression object, incoke renameDocumentObject in it. - * @param node Node to visit - */ - - void visit(Expression * node) { - VariableExpression *expr = freecad_dynamic_cast(node); - - if (expr) { - if (expr->renameDocumentObject(oldName, newName)) { - if (!changed) { - aboutToSetValue(); - ++changed; - } - } - } - } - - int getChanged() const { return changed; } - -private: - aboutToSetValueFunc aboutToSetValue; - hasSetValueFunc hasSetValue; - std::string oldName; /**< Document object name to replace */ - std::string newName; /**< New document object name */ - int changed; -}; - class ObjectDeletedExpressionVisitor : public ExpressionVisitor { public: @@ -329,9 +277,7 @@ void PropertyExpressionEngine::slotObjectRenamed(const DocumentObject &obj) if (!docObj || docObj->getNameInDocument() == 0) return; - RelabelDocumentObjectExpressionVisitor v(boost::bind( &PropertyExpressionEngine::aboutToSetValue, this), - boost::bind( &PropertyExpressionEngine::hasSetValue, this), - obj.getOldLabel(), obj.Label.getStrValue()); + RelabelDocumentObjectExpressionVisitor v(*this, obj.getOldLabel(), obj.Label.getStrValue()); for (ExpressionMap::iterator it = expressions.begin(); it != expressions.end(); ++it) { int changed = v.getChanged(); @@ -773,42 +719,6 @@ void PropertyExpressionEngine::renameExpressions(const std::map &_paths, const ObjectIdentifier & _owner) - : paths(_paths) - , owner(_owner) - { - } - - /** - * @brief If node is a VariableExpression object, look it up in the paths map, and possibly rename it. - * @param node Node to visit. - */ - - void visit(Expression * node) { - VariableExpression *expr = freecad_dynamic_cast(node); - - if (expr) { - const App::ObjectIdentifier & oldPath = expr->getPath().canonicalPath(); - const std::map::const_iterator it = paths.find(oldPath); - - if (it != paths.end()) - expr->setPath(it->second.relativeTo(owner)); - } - } - -private: - const std::map &paths; /**< Map with current and new object identifiers */ - const ObjectIdentifier & owner; /**< Owner og expression */ -}; - /** * @brief Rename object identifiers in the registered expressions. * @param paths Map with current and new object identifiers. @@ -816,9 +726,8 @@ private: void PropertyExpressionEngine::renameObjectIdentifiers(const std::map &paths) { - for (ExpressionMap::iterator it = expressions.begin(); it != expressions.end(); ++it) { - RenameObjectIdentifierExpressionVisitor v(paths, it->first); + RenameObjectIdentifierExpressionVisitor v(*this, paths, it->first); it->second.expression->visit(v); } }