PropertyExpressionEngine: Refactored and moved visitor code to separate file.

This commit is contained in:
Eivind Kvedalen 2016-02-08 21:01:33 +01:00 committed by wmayer
parent 095c823fda
commit 810135fad4
7 changed files with 197 additions and 95 deletions

View File

@ -85,6 +85,7 @@ SET(Document_HPP_SRCS
DocumentObserver.h
DocumentObserverPython.h
Expression.h
ExpressionVisitors.h
FeatureCustom.h
FeaturePython.h
FeaturePythonPyImp.h

View File

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

View File

@ -46,7 +46,7 @@ public:
virtual void visit(Expression * e) = 0;
};
template<class P> class AppExport ExpressionModifier : public ExpressionVisitor {
template<class P> 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;

View File

@ -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 <Base/BaseClass.h>
#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 P> class RenameObjectIdentifierExpressionVisitor : public ExpressionModifier<P> {
public:
RenameObjectIdentifierExpressionVisitor(P & _prop,
const std::map<ObjectIdentifier, ObjectIdentifier> &_paths, const ObjectIdentifier & _owner)
: ExpressionModifier<P>(_prop)
, paths(_paths)
, owner(_owner)
{
}
void visit(Expression *node) {
VariableExpression *expr = Base::freecad_dynamic_cast<VariableExpression>(node);
if (expr) {
const App::ObjectIdentifier & oldPath = expr->getPath().canonicalPath();
const std::map<ObjectIdentifier, ObjectIdentifier>::const_iterator it = paths.find(oldPath);
if (it != paths.end()) {
ExpressionModifier<P>::setExpressionChanged();
expr->setPath(it->second.relativeTo(owner));
}
}
}
private:
const std::map<ObjectIdentifier, ObjectIdentifier> &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 P> class RelabelDocumentObjectExpressionVisitor : public ExpressionModifier<P> {
public:
RelabelDocumentObjectExpressionVisitor(P & _prop, const std::string & _oldName, const std::string & _newName)
: ExpressionModifier<P>(_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<VariableExpression>(node);
if (expr && expr->validDocumentObjectRename(oldName, newName)) {
ExpressionModifier<P>::setExpressionChanged();
expr->renameDocumentObject(oldName, newName);
}
}
private:
std::string oldName; /**< Document object name to replace */
std::string newName; /**< New document object name */
};
template<class P> class RelabelDocumentExpressionVisitor : public ExpressionModifier<P> {
public:
RelabelDocumentExpressionVisitor(P & prop, const std::string & _oldName, const std::string & _newName)
: ExpressionModifier<P>(prop)
, oldName(_oldName)
, newName(_newName)
{
}
void visit(Expression * node) {
VariableExpression *expr = Base::freecad_dynamic_cast<VariableExpression>(node);
if (expr && expr->validDocumentRename(oldName, newName)) {
ExpressionModifier<P>::setExpressionChanged();
expr->renameDocument(oldName, newName);
}
}
private:
std::string oldName;
std::string newName;
};
}
#endif // RENAMEOBJECTIDENTIFIEREXPRESSIONVISITOR_H

View File

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

View File

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

View File

@ -28,6 +28,7 @@
#include <Base/Writer.h>
#include <Base/Reader.h>
#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<void ()> aboutToSetValueFunc;
typedef boost::function<void ()> 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<VariableExpression>(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<PropertyExpressionEngine> 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<ObjectIdentifier
hasSetValue();
}
/**
* @brief The RenameObjectIdentifierExpressionVisitor class is a functor used to visit each node of an expression, and
* possibly rename VariableExpression nodes.
*/
class RenameObjectIdentifierExpressionVisitor : public ExpressionVisitor {
public:
RenameObjectIdentifierExpressionVisitor(const std::map<ObjectIdentifier, ObjectIdentifier> &_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<VariableExpression>(node);
if (expr) {
const App::ObjectIdentifier & oldPath = expr->getPath().canonicalPath();
const std::map<ObjectIdentifier, ObjectIdentifier>::const_iterator it = paths.find(oldPath);
if (it != paths.end())
expr->setPath(it->second.relativeTo(owner));
}
}
private:
const std::map<ObjectIdentifier, ObjectIdentifier> &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<ObjectIdentifier, ObjectIdentifier> &paths)
{
for (ExpressionMap::iterator it = expressions.begin(); it != expressions.end(); ++it) {
RenameObjectIdentifierExpressionVisitor v(paths, it->first);
RenameObjectIdentifierExpressionVisitor<PropertyExpressionEngine> v(*this, paths, it->first);
it->second.expression->visit(v);
}
}