PropertyExpressionEngine: convert to link type property
PropertyExpressionEngine is changed to derived from a new class PropertyExpressionContainer, which is in turn derives from PropertyXLinkContainer. This makes PropertyExpressionEngine a link type property that is capable of external linking. It now uses the unified link property APIs for dependency management and tracking of object life time, re-labeling, etc. ObjectIdentifier is modified to support sub-object reference, but is not exposed to end-user, because expression syntax is kept mostly unchanged, which will be submitted in future PR. There is, however, one small change in expression syntax (ExpressionParser.y) to introduce local property reference to avoid ambiguity mentioned in FreeCAD/FreeCAD#1619 Modified Expression/ExpressionModifier interface to support various link property API for link modification.
This commit is contained in:
@@ -1671,6 +1671,7 @@ void Application::initTypes(void)
|
||||
App ::FunctionExpression ::init();
|
||||
App ::BooleanExpression ::init();
|
||||
App ::RangeExpression ::init();
|
||||
App ::PyObjectExpression ::init();
|
||||
|
||||
// register transaction type
|
||||
new App::TransactionProducer<TransactionDocumentObject>
|
||||
|
||||
@@ -372,7 +372,7 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
|
||||
void addExpressionSubgraphIfNeeded(DocumentObject * obj, bool CSsubgraphs) {
|
||||
|
||||
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo> expressions = obj->ExpressionEngine.getExpressions();
|
||||
auto expressions = obj->ExpressionEngine.getExpressions();
|
||||
|
||||
if (!expressions.empty()) {
|
||||
|
||||
@@ -394,11 +394,11 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
}
|
||||
|
||||
// Create subgraphs for all documentobjects that it depends on; it will depend on some property there
|
||||
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo>::const_iterator i = expressions.begin();
|
||||
auto i = expressions.begin();
|
||||
while (i != expressions.end()) {
|
||||
std::set<ObjectIdentifier> deps;
|
||||
|
||||
i->second.expression->getDeps(deps);
|
||||
i->second->getIdentifiers(deps);
|
||||
|
||||
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
|
||||
while (j != deps.end()) {
|
||||
@@ -486,8 +486,8 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
}
|
||||
|
||||
// Add expressions and its dependencies
|
||||
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo> expressions = docObj->ExpressionEngine.getExpressions();
|
||||
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo>::const_iterator i = expressions.begin();
|
||||
auto expressions = docObj->ExpressionEngine.getExpressions();
|
||||
auto i = expressions.begin();
|
||||
|
||||
// Add nodes for each property that has an expression attached to it
|
||||
while (i != expressions.end()) {
|
||||
@@ -507,7 +507,7 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
|
||||
// Get dependencies
|
||||
std::set<ObjectIdentifier> deps;
|
||||
i->second.expression->getDeps(deps);
|
||||
i->second->getIdentifiers(deps);
|
||||
|
||||
// Create subgraphs for all documentobjects that it depends on; it will depend on some property there
|
||||
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
|
||||
@@ -648,12 +648,12 @@ void Document::exportGraphviz(std::ostream& out) const
|
||||
const DocumentObject * docObj = *j;
|
||||
|
||||
// Add expressions and its dependencies
|
||||
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo> expressions = docObj->ExpressionEngine.getExpressions();
|
||||
boost::unordered_map<const App::ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo>::const_iterator i = expressions.begin();
|
||||
auto expressions = docObj->ExpressionEngine.getExpressions();
|
||||
auto i = expressions.begin();
|
||||
|
||||
while (i != expressions.end()) {
|
||||
std::set<ObjectIdentifier> deps;
|
||||
i->second.expression->getDeps(deps);
|
||||
i->second->getIdentifiers(deps);
|
||||
|
||||
// Create subgraphs for all documentobjects that it depends on; it will depend on some property there
|
||||
std::set<ObjectIdentifier>::const_iterator k = deps.begin();
|
||||
|
||||
@@ -762,13 +762,11 @@ void DocumentObject::Save (Base::Writer &writer) const
|
||||
* @brief Associate the expression \expr with the object identifier \a path in this document object.
|
||||
* @param path Target object identifier for the result of the expression
|
||||
* @param expr Expression tree
|
||||
* @param comment Optional comment describing the expression
|
||||
*/
|
||||
|
||||
void DocumentObject::setExpression(const ObjectIdentifier &path, boost::shared_ptr<Expression> expr, const char * comment)
|
||||
void DocumentObject::setExpression(const ObjectIdentifier &path, boost::shared_ptr<Expression> expr)
|
||||
{
|
||||
ExpressionEngine.setValue(path, expr, comment);
|
||||
connectRelabelSignals();
|
||||
ExpressionEngine.setValue(path, expr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -799,46 +797,6 @@ void DocumentObject::renameObjectIdentifiers(const std::map<ObjectIdentifier, Ob
|
||||
ExpressionEngine.renameObjectIdentifiers(paths);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function that sets up a signal to track document object renames.
|
||||
*/
|
||||
|
||||
void DocumentObject::connectRelabelSignals()
|
||||
{
|
||||
// Only keep signal if the ExpressionEngine has at least one expression
|
||||
if (ExpressionEngine.numExpressions() > 0) {
|
||||
|
||||
// Not already connected?
|
||||
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();
|
||||
}
|
||||
catch (...) {
|
||||
// Ignore any error
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Disconnect signals; nothing to track now
|
||||
onRelabledObjectConnection.disconnect();
|
||||
onRelabledDocumentConnection.disconnect();
|
||||
onDeletedObjectConnection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentObject::onDocumentRestored()
|
||||
{
|
||||
//call all extensions
|
||||
|
||||
@@ -351,14 +351,12 @@ public:
|
||||
|
||||
/* Expression support */
|
||||
|
||||
virtual void setExpression(const ObjectIdentifier & path, boost::shared_ptr<App::Expression> expr, const char *comment = 0);
|
||||
virtual void setExpression(const ObjectIdentifier & path, boost::shared_ptr<App::Expression> expr);
|
||||
|
||||
virtual const PropertyExpressionEngine::ExpressionInfo getExpression(const ObjectIdentifier &path) const;
|
||||
|
||||
virtual void renameObjectIdentifiers(const std::map<App::ObjectIdentifier, App::ObjectIdentifier> & paths);
|
||||
|
||||
virtual void connectRelabelSignals();
|
||||
|
||||
const std::string & getOldLabel() const { return oldLabel; }
|
||||
|
||||
const char *getViewProviderNameStored() const {
|
||||
@@ -531,11 +529,6 @@ protected: // attributes
|
||||
/// pointer to the document this object belongs to
|
||||
App::Document* _pDoc;
|
||||
|
||||
// Connections to track relabeling of document and document objects
|
||||
boost::signals2::scoped_connection onRelabledDocumentConnection;
|
||||
boost::signals2::scoped_connection onRelabledObjectConnection;
|
||||
boost::signals2::scoped_connection onDeletedObjectConnection;
|
||||
|
||||
/// Old label; used for renaming expressions
|
||||
std::string oldLabel;
|
||||
|
||||
|
||||
@@ -176,6 +176,19 @@ non-object sub-element name if any.
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="resolveSubElement" Const="true">
|
||||
<Documentation>
|
||||
<UserDocu>
|
||||
resolveSubElement(subname,append,type) -- resolve both new and old style sub element
|
||||
|
||||
subname: subname reference contianing object hierarchy
|
||||
append: Whether to append object hierarchy prefix inside subname to returned element name
|
||||
type: 0: normal, 1: for import, 2: for export
|
||||
|
||||
Return tuple(obj,newElementName,oldElementName)
|
||||
</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="adjustRelativeLinks">
|
||||
<Documentation>
|
||||
<UserDocu>adjustRelativeLinks(parent,recursive=True) -- auto correct potential cyclic dependencies</UserDocu>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "DocumentObject.h"
|
||||
#include "Document.h"
|
||||
#include "Expression.h"
|
||||
#include "GeoFeature.h"
|
||||
#include "GroupExtension.h"
|
||||
#include "GeoFeatureGroupExtension.h"
|
||||
|
||||
@@ -327,9 +328,11 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args)
|
||||
else if (PyString_Check(expr)) {
|
||||
const char * exprStr = PyString_AsString(expr);
|
||||
#endif
|
||||
boost::shared_ptr<Expression> shared_expr(ExpressionParser::parse(getDocumentObjectPtr(), exprStr));
|
||||
boost::shared_ptr<Expression> shared_expr(Expression::parse(getDocumentObjectPtr(), exprStr));
|
||||
if(shared_expr && comment)
|
||||
shared_expr->comment = comment;
|
||||
|
||||
getDocumentObjectPtr()->setExpression(p, shared_expr, comment);
|
||||
getDocumentObjectPtr()->setExpression(p, shared_expr);
|
||||
}
|
||||
else if (PyUnicode_Check(expr)) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
@@ -341,7 +344,9 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args)
|
||||
Py_DECREF(unicode);
|
||||
boost::shared_ptr<Expression> shared_expr(ExpressionParser::parse(getDocumentObjectPtr(), exprStr.c_str()));
|
||||
|
||||
getDocumentObjectPtr()->setExpression(p, shared_expr, comment);
|
||||
if(shared_expr && comment)
|
||||
shared_expr->comment = comment;
|
||||
getDocumentObjectPtr()->setExpression(p, shared_expr);
|
||||
}
|
||||
else {
|
||||
// utf-8 encoding failed
|
||||
@@ -785,6 +790,28 @@ PyObject *DocumentObjectPy::resolve(PyObject *args)
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
PyObject *DocumentObjectPy::resolveSubElement(PyObject *args)
|
||||
{
|
||||
const char *subname;
|
||||
PyObject *append = Py_False;
|
||||
int type = 0;
|
||||
if (!PyArg_ParseTuple(args, "s|Oi",&subname,&append,&type))
|
||||
return NULL; // NULL triggers exception
|
||||
|
||||
PY_TRY {
|
||||
std::pair<std::string,std::string> elementName;
|
||||
auto obj = GeoFeature::resolveElement(getDocumentObjectPtr(), subname,elementName,
|
||||
PyObject_IsTrue(append),(GeoFeature::ElementNameType)type);
|
||||
Py::Tuple ret(3);
|
||||
ret.setItem(0,obj?Py::Object(obj->getPyObject(),true):Py::None());
|
||||
ret.setItem(1,Py::String(elementName.first));
|
||||
ret.setItem(2,Py::String(elementName.second));
|
||||
return Py::new_reference_to(ret);
|
||||
} PY_CATCH;
|
||||
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
Py::List DocumentObjectPy::getParents() const {
|
||||
Py::List ret;
|
||||
for(auto &v : getDocumentObjectPtr()->getParents())
|
||||
|
||||
+1131
-154
File diff suppressed because it is too large
Load Diff
+190
-58
@@ -27,7 +27,7 @@
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Unit.h>
|
||||
#include <App/Property.h>
|
||||
#include <App/PropertyLinks.h>
|
||||
#include <App/ObjectIdentifier.h>
|
||||
#include <Base/BaseClass.h>
|
||||
#include <Base/Quantity.h>
|
||||
@@ -41,29 +41,66 @@ class DocumentObject;
|
||||
class Expression;
|
||||
class Document;
|
||||
|
||||
typedef std::unique_ptr<Expression> ExpressionPtr;
|
||||
|
||||
AppExport bool isAnyEqual(const App::any &v1, const App::any &v2);
|
||||
AppExport Base::Quantity anyToQuantity(const App::any &value, const char *errmsg = 0);
|
||||
|
||||
typedef std::map<App::DocumentObject*, std::map<std::string, std::vector<ObjectIdentifier> > > ExpressionDeps;
|
||||
class AppExport ExpressionVisitor {
|
||||
public:
|
||||
virtual ~ExpressionVisitor() {}
|
||||
virtual void visit(Expression * e) = 0;
|
||||
virtual void visit(Expression &e) = 0;
|
||||
virtual void aboutToChange() {}
|
||||
virtual int changed() const { return 0;}
|
||||
virtual void reset() {}
|
||||
virtual App::PropertyLinkBase* getPropertyLink() {return 0;}
|
||||
|
||||
protected:
|
||||
void getIdentifiers(Expression &e, std::set<App::ObjectIdentifier> &);
|
||||
void getDeps(Expression &e, ExpressionDeps &);
|
||||
void getDepObjects(Expression &e, std::set<App::DocumentObject*> &, std::vector<std::string> *);
|
||||
bool adjustLinks(Expression &e, const std::set<App::DocumentObject*> &inList);
|
||||
bool relabeledDocument(Expression &e, const std::string &oldName, const std::string &newName);
|
||||
bool renameObjectIdentifier(Expression &e,
|
||||
const std::map<ObjectIdentifier,ObjectIdentifier> &, const ObjectIdentifier &);
|
||||
void collectReplacement(Expression &e, std::map<ObjectIdentifier,ObjectIdentifier> &,
|
||||
const App::DocumentObject *parent, App::DocumentObject *oldObj, App::DocumentObject *newObj) const;
|
||||
bool updateElementReference(Expression &e, App::DocumentObject *feature,bool reverse);
|
||||
void importSubNames(Expression &e, const ObjectIdentifier::SubNameMap &subNameMap);
|
||||
void updateLabelReference(Expression &e, App::DocumentObject *obj,
|
||||
const std::string &ref, const char *newLabel);
|
||||
void moveCells(Expression &e, const CellAddress &address, int rowCount, int colCount);
|
||||
void offsetCells(Expression &e, int rowOffset, int colOffset);
|
||||
};
|
||||
|
||||
template<class P> class ExpressionModifier : public ExpressionVisitor {
|
||||
public:
|
||||
ExpressionModifier(P & _prop)
|
||||
: prop(_prop) { }
|
||||
: prop(_prop)
|
||||
, propLink(Base::freecad_dynamic_cast<App::PropertyLinkBase>(&prop))
|
||||
, signaller(_prop,false)
|
||||
, _changed(0)
|
||||
{}
|
||||
|
||||
virtual ~ExpressionModifier() { }
|
||||
|
||||
void setExpressionChanged() {
|
||||
if (!signaller)
|
||||
signaller = boost::shared_ptr<typename AtomicPropertyChangeInterface<P>::AtomicPropertyChange>(AtomicPropertyChangeInterface<P>::getAtomicPropertyChange(prop));
|
||||
virtual void aboutToChange() override{
|
||||
++_changed;
|
||||
signaller.aboutToChange();
|
||||
}
|
||||
|
||||
bool getChanged() const { return signaller != 0; }
|
||||
virtual int changed() const override { return _changed; }
|
||||
|
||||
virtual void reset() override {_changed = 0;}
|
||||
|
||||
virtual App::PropertyLinkBase* getPropertyLink() override {return propLink;}
|
||||
|
||||
protected:
|
||||
P & prop;
|
||||
boost::shared_ptr<typename AtomicPropertyChangeInterface<P>::AtomicPropertyChange> signaller;
|
||||
App::PropertyLinkBase *propLink;
|
||||
typename AtomicPropertyChangeInterface<P>::AtomicPropertyChange signaller;
|
||||
int _changed;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -84,31 +121,78 @@ public:
|
||||
|
||||
virtual Expression * eval() const = 0;
|
||||
|
||||
virtual std::string toString() const = 0;
|
||||
virtual std::string toString(bool persistent=false) const = 0;
|
||||
|
||||
static Expression * parse(const App::DocumentObject * owner, const std::string& buffer);
|
||||
|
||||
virtual Expression * copy() const = 0;
|
||||
Expression * copy() const;
|
||||
|
||||
virtual int priority() const { return 0; }
|
||||
|
||||
virtual void getDeps(std::set<ObjectIdentifier> &/*props*/) const { }
|
||||
void getIdentifiers(std::set<App::ObjectIdentifier> &) const;
|
||||
std::set<App::ObjectIdentifier> getIdentifiers() const;
|
||||
|
||||
void getDeps(ExpressionDeps &deps) const;
|
||||
ExpressionDeps getDeps() const;
|
||||
|
||||
std::set<App::DocumentObject*> getDepObjects(std::vector<std::string> *labels=0) const;
|
||||
void getDepObjects(std::set<App::DocumentObject*> &, std::vector<std::string> *labels=0) const;
|
||||
|
||||
ExpressionPtr importSubNames(const std::map<std::string,std::string> &nameMap) const;
|
||||
|
||||
ExpressionPtr updateLabelReference(App::DocumentObject *obj,
|
||||
const std::string &ref, const char *newLabel) const;
|
||||
|
||||
ExpressionPtr replaceObject(const App::DocumentObject *parent,
|
||||
App::DocumentObject *oldObj, App::DocumentObject *newObj) const;
|
||||
|
||||
bool adjustLinks(const std::set<App::DocumentObject*> &inList);
|
||||
|
||||
virtual Expression * simplify() const = 0;
|
||||
|
||||
virtual void visit(ExpressionVisitor & v) { v.visit(this); }
|
||||
void visit(ExpressionVisitor & v);
|
||||
|
||||
class Exception : public Base::Exception {
|
||||
public:
|
||||
Exception(const char *sMessage) : Base::Exception(sMessage) { }
|
||||
};
|
||||
|
||||
const App::DocumentObject * getOwner() const { return owner; }
|
||||
App::DocumentObject * getOwner() const { return owner; }
|
||||
|
||||
virtual boost::any getValueAsAny() const { static boost::any empty; return empty; }
|
||||
|
||||
bool isSame(const Expression &other) const;
|
||||
|
||||
friend ExpressionVisitor;
|
||||
|
||||
protected:
|
||||
const App::DocumentObject * owner; /**< The document object used to access unqualified variables (i.e local scope) */
|
||||
virtual Expression *_copy() const = 0;
|
||||
virtual void _getDeps(ExpressionDeps &) const {}
|
||||
virtual void _getDepObjects(std::set<App::DocumentObject*> &, std::vector<std::string> *) const {}
|
||||
virtual void _getIdentifiers(std::set<App::ObjectIdentifier> &) const {}
|
||||
virtual bool _adjustLinks(const std::set<App::DocumentObject*> &, ExpressionVisitor &) {return false;}
|
||||
virtual bool _updateElementReference(App::DocumentObject *,bool,ExpressionVisitor &) {return false;}
|
||||
virtual bool _relabeledDocument(const std::string &, const std::string &, ExpressionVisitor &) {return false;}
|
||||
virtual void _importSubNames(const ObjectIdentifier::SubNameMap &) {}
|
||||
virtual void _updateLabelReference(App::DocumentObject *, const std::string &, const char *) {}
|
||||
virtual bool _renameObjectIdentifier(const std::map<ObjectIdentifier,ObjectIdentifier> &,
|
||||
const ObjectIdentifier &, ExpressionVisitor &) {return false;}
|
||||
virtual void _collectReplacement(std::map<ObjectIdentifier,ObjectIdentifier> &,
|
||||
const App::DocumentObject *parent, App::DocumentObject *oldObj, App::DocumentObject *newObj) const
|
||||
{
|
||||
(void)parent;
|
||||
(void)oldObj;
|
||||
(void)newObj;
|
||||
}
|
||||
virtual void _moveCells(const CellAddress &, int, int, ExpressionVisitor &) {}
|
||||
virtual void _offsetCells(int, int, ExpressionVisitor &) {}
|
||||
virtual void _visit(ExpressionVisitor &) {}
|
||||
|
||||
protected:
|
||||
App::DocumentObject * owner; /**< The document object used to access unqualified variables (i.e local scope) */
|
||||
|
||||
public:
|
||||
std::string comment;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -125,9 +209,9 @@ public:
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
virtual std::string toString(bool persistent=false) const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
virtual Expression * _copy() const;
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
@@ -163,13 +247,15 @@ public:
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
virtual Expression * _copy() const;
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
void negate();
|
||||
|
||||
virtual std::string toString() const;
|
||||
virtual std::string toString(bool persistent=false) const;
|
||||
|
||||
bool isInteger(long *v=0) const;
|
||||
|
||||
protected:
|
||||
};
|
||||
@@ -179,9 +265,9 @@ class AppExport ConstantExpression : public NumberExpression {
|
||||
public:
|
||||
ConstantExpression(const App::DocumentObject *_owner = 0, std::string _name = "", const Base::Quantity &_quantity = Base::Quantity());
|
||||
|
||||
virtual std::string toString() const;
|
||||
virtual std::string toString(bool persistent=false) const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
virtual Expression * _copy() const;
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
@@ -196,7 +282,7 @@ class AppExport BooleanExpression : public NumberExpression {
|
||||
public:
|
||||
BooleanExpression(const App::DocumentObject *_owner = 0, bool _value = false);
|
||||
|
||||
virtual Expression * copy() const;
|
||||
virtual Expression * _copy() const;
|
||||
|
||||
};
|
||||
|
||||
@@ -236,15 +322,13 @@ public:
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
virtual std::string toString(bool persistent=false) const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
virtual Expression * _copy() const;
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
|
||||
|
||||
virtual void visit(ExpressionVisitor & v);
|
||||
virtual void _visit(ExpressionVisitor & v);
|
||||
|
||||
Operator getOperator() const { return op; }
|
||||
|
||||
@@ -278,15 +362,13 @@ public:
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
virtual std::string toString(bool persistent=false) const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
virtual Expression * _copy() const;
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
|
||||
|
||||
virtual void visit(ExpressionVisitor & v);
|
||||
virtual void _visit(ExpressionVisitor & v);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -355,15 +437,13 @@ public:
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
virtual std::string toString(bool persistent=false) const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
virtual Expression * _copy() const;
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
|
||||
|
||||
virtual void visit(ExpressionVisitor & v);
|
||||
virtual void _visit(ExpressionVisitor & v);
|
||||
|
||||
protected:
|
||||
Expression *evalAggregate() const;
|
||||
@@ -393,35 +473,73 @@ public:
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const { return var.toString(); }
|
||||
virtual std::string toString(bool persistent=false) const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
virtual Expression * _copy() const;
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
|
||||
|
||||
std::string name() const { return var.getPropertyName(); }
|
||||
|
||||
ObjectIdentifier getPath() const { return var; }
|
||||
|
||||
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;
|
||||
|
||||
protected:
|
||||
virtual void _getDeps(ExpressionDeps &) const;
|
||||
virtual void _getDepObjects(std::set<App::DocumentObject*> &, std::vector<std::string> *) const;
|
||||
virtual void _getIdentifiers(std::set<App::ObjectIdentifier> &) const;
|
||||
virtual bool _adjustLinks(const std::set<App::DocumentObject*> &, ExpressionVisitor &);
|
||||
virtual void _importSubNames(const ObjectIdentifier::SubNameMap &);
|
||||
virtual void _updateLabelReference(App::DocumentObject *, const std::string &, const char *);
|
||||
virtual bool _updateElementReference(App::DocumentObject *,bool,ExpressionVisitor &);
|
||||
virtual bool _relabeledDocument(const std::string &, const std::string &, ExpressionVisitor &);
|
||||
virtual bool _renameObjectIdentifier(const std::map<ObjectIdentifier,ObjectIdentifier> &,
|
||||
const ObjectIdentifier &, ExpressionVisitor &);
|
||||
virtual void _collectReplacement(std::map<ObjectIdentifier,ObjectIdentifier> &,
|
||||
const App::DocumentObject *parent, App::DocumentObject *oldObj,
|
||||
App::DocumentObject *newObj) const;
|
||||
virtual void _moveCells(const CellAddress &, int, int, ExpressionVisitor &);
|
||||
virtual void _offsetCells(int, int, ExpressionVisitor &);
|
||||
|
||||
protected:
|
||||
|
||||
ObjectIdentifier var; /**< Variable name */
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AppExport PyObjectExpression : public Expression {
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
PyObjectExpression(const App::DocumentObject *_owner=0, PyObject *pyobj=0, bool owned=false)
|
||||
:Expression(_owner)
|
||||
{
|
||||
setPyObject(pyobj,owned);
|
||||
}
|
||||
|
||||
virtual ~PyObjectExpression();
|
||||
|
||||
Py::Object getPyObject() const;
|
||||
|
||||
void setPyObject(Py::Object pyobj);
|
||||
void setPyObject(PyObject *pyobj, bool owned=false);
|
||||
|
||||
virtual std::string toString(bool) const;
|
||||
|
||||
virtual Expression * eval() const { return copy(); }
|
||||
virtual Expression * simplify() const { return copy(); }
|
||||
|
||||
protected:
|
||||
virtual Expression* _copy() const;
|
||||
|
||||
protected:
|
||||
PyObject *pyObj = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class implementing a string. Used to signal either a genuine string or
|
||||
* a failed evaluation of an expression.
|
||||
@@ -436,13 +554,13 @@ public:
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
virtual std::string toString(bool persistent=false) const;
|
||||
|
||||
virtual std::string getText() const { return text; }
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
virtual Expression * _copy() const;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -460,22 +578,26 @@ public:
|
||||
|
||||
virtual Expression * eval() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
virtual std::string toString(bool persistent=false) const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
virtual Expression * _copy() const;
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
virtual void getDeps(std::set<App::ObjectIdentifier> &props) const;
|
||||
|
||||
virtual App::Expression * simplify() const;
|
||||
|
||||
Range getRange() const { return range; }
|
||||
|
||||
void setRange(const Range & r);
|
||||
Range getRange() const;
|
||||
|
||||
protected:
|
||||
Range range;
|
||||
virtual void _getDeps(ExpressionDeps &) const;
|
||||
virtual bool _renameObjectIdentifier(const std::map<ObjectIdentifier,ObjectIdentifier> &,
|
||||
const ObjectIdentifier &, ExpressionVisitor &);
|
||||
virtual void _moveCells(const CellAddress &, int, int, ExpressionVisitor &);
|
||||
virtual void _offsetCells(int, int, ExpressionVisitor &);
|
||||
|
||||
protected:
|
||||
std::string begin;
|
||||
std::string end;
|
||||
};
|
||||
|
||||
namespace ExpressionParser {
|
||||
@@ -486,6 +608,16 @@ AppExport bool isTokenAnIndentifier(const std::string & str);
|
||||
AppExport bool isTokenAUnit(const std::string & str);
|
||||
AppExport std::vector<boost::tuple<int, int, std::string> > tokenize(const std::string & str);
|
||||
|
||||
/// Convenient class to mark begin of importing
|
||||
class AppExport ExpressionImporter {
|
||||
public:
|
||||
ExpressionImporter(Base::XMLReader &reader);
|
||||
~ExpressionImporter();
|
||||
static Base::XMLReader *reader();
|
||||
};
|
||||
|
||||
AppExport bool isModuleImported(PyObject *);
|
||||
|
||||
/**
|
||||
* @brief The semantic_type class encapsulates the value in the parse tree during parsing.
|
||||
*/
|
||||
|
||||
+258
-234
@@ -382,18 +382,18 @@ union yyalloc
|
||||
#endif /* !YYCOPY_NEEDED */
|
||||
|
||||
/* YYFINAL -- State number of the termination state. */
|
||||
#define YYFINAL 34
|
||||
#define YYFINAL 38
|
||||
/* YYLAST -- Last index in YYTABLE. */
|
||||
#define YYLAST 188
|
||||
#define YYLAST 196
|
||||
|
||||
/* YYNTOKENS -- Number of terminals. */
|
||||
#define YYNTOKENS 40
|
||||
/* YYNNTS -- Number of nonterminals. */
|
||||
#define YYNNTS 14
|
||||
/* YYNRULES -- Number of rules. */
|
||||
#define YYNRULES 73
|
||||
#define YYNRULES 74
|
||||
/* YYNSTATES -- Number of states. */
|
||||
#define YYNSTATES 130
|
||||
#define YYNSTATES 132
|
||||
|
||||
/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
|
||||
by yylex, with out-of-bounds checking. */
|
||||
@@ -446,10 +446,10 @@ static const yytype_uint8 yyrline[] =
|
||||
76, 77, 78, 79, 80, 81, 82, 83, 84, 87,
|
||||
88, 89, 90, 92, 93, 94, 95, 96, 97, 100,
|
||||
101, 102, 103, 106, 107, 108, 109, 110, 111, 114,
|
||||
115, 116, 117, 118, 119, 122, 126, 131, 136, 144,
|
||||
145, 149, 150, 151, 152, 153, 154, 155, 156, 157,
|
||||
160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
|
||||
172, 173, 176, 177
|
||||
115, 116, 117, 118, 119, 122, 126, 131, 136, 141,
|
||||
149, 150, 154, 155, 156, 157, 158, 159, 160, 161,
|
||||
162, 165, 166, 167, 168, 169, 170, 171, 172, 173,
|
||||
174, 177, 178, 181, 182
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -481,12 +481,12 @@ static const yytype_uint16 yytoknum[] =
|
||||
};
|
||||
# endif
|
||||
|
||||
#define YYPACT_NINF -100
|
||||
#define YYPACT_NINF -102
|
||||
|
||||
#define yypact_value_is_default(Yystate) \
|
||||
(!!((Yystate) == (-100)))
|
||||
(!!((Yystate) == (-102)))
|
||||
|
||||
#define YYTABLE_NINF -74
|
||||
#define YYTABLE_NINF -75
|
||||
|
||||
#define yytable_value_is_error(Yytable_value) \
|
||||
0
|
||||
@@ -495,19 +495,20 @@ static const yytype_uint16 yytoknum[] =
|
||||
STATE-NUM. */
|
||||
static const yytype_int16 yypact[] =
|
||||
{
|
||||
61, 79, -100, -100, 137, -100, -100, -100, -28, 106,
|
||||
104, 104, 61, 18, 154, -1, 27, 89, -100, -100,
|
||||
16, 26, -15, -17, 104, 154, 143, -100, 7, 86,
|
||||
-100, -100, 112, 47, -100, 104, 104, 104, 104, 104,
|
||||
104, 104, 104, 104, 61, 104, -1, 31, 104, -1,
|
||||
-1, 43, 146, 22, 23, 24, -100, 79, 79, 39,
|
||||
-100, -100, -100, -100, 33, -100, 42, 56, -100, -100,
|
||||
154, 154, 154, 154, 154, 154, 128, 128, 72, 72,
|
||||
31, -100, 135, 31, 31, 48, -100, 81, -100, -100,
|
||||
69, -100, -100, -100, -100, -100, -100, 154, -100, 154,
|
||||
-100, 7, 127, 84, 96, 98, 104, -100, 22, -100,
|
||||
101, 119, 132, 7, 7, 7, 73, -100, 148, 149,
|
||||
152, -100, -100, -100, 7, 7, 7, -100, -100, -100
|
||||
67, 92, -102, -102, 131, -102, -102, -102, -32, -2,
|
||||
117, 117, 67, 3, 24, 167, -4, 15, 86, -102,
|
||||
-102, 23, 45, -7, -18, 117, 167, 153, -102, 73,
|
||||
74, -102, -102, 125, 60, 19, -102, -102, -102, 117,
|
||||
117, 117, 117, 117, 117, 117, 117, 117, 67, 117,
|
||||
-4, 59, 117, -4, -4, 4, 101, 3, 13, 26,
|
||||
-102, 92, 92, 30, -102, -102, -102, -102, 55, -102,
|
||||
75, 77, -102, -102, 167, 167, 167, 167, 167, 167,
|
||||
103, 103, 90, 90, 59, -102, 148, 59, 59, 29,
|
||||
-102, -102, -102, 95, -102, -102, -102, -102, -102, 167,
|
||||
-102, 167, -102, 73, 140, 97, 109, 111, 117, -102,
|
||||
3, -102, 116, 126, 132, 73, 73, 73, 38, -102,
|
||||
120, 134, 154, -102, -102, -102, 73, 73, 73, -102,
|
||||
-102, -102
|
||||
};
|
||||
|
||||
/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
|
||||
@@ -515,33 +516,34 @@ static const yytype_int16 yypact[] =
|
||||
means the default is an error. */
|
||||
static const yytype_uint8 yydefact[] =
|
||||
{
|
||||
0, 0, 19, 20, 51, 39, 21, 22, 52, 6,
|
||||
0, 0, 0, 0, 2, 4, 0, 3, 7, 45,
|
||||
0, 0, 51, 52, 0, 23, 0, 24, 0, 0,
|
||||
8, 9, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 5, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 17, 0, 0, 60,
|
||||
62, 61, 59, 50, 0, 49, 0, 0, 16, 44,
|
||||
33, 34, 35, 36, 37, 38, 11, 10, 12, 13,
|
||||
14, 15, 0, 41, 40, 0, 42, 51, 72, 47,
|
||||
0, 52, 46, 32, 31, 30, 29, 25, 27, 26,
|
||||
28, 0, 0, 56, 55, 53, 0, 43, 0, 69,
|
||||
0, 0, 0, 0, 0, 0, 18, 48, 66, 65,
|
||||
63, 58, 57, 54, 0, 0, 0, 68, 67, 64
|
||||
0, 0, 19, 20, 52, 39, 21, 22, 53, 6,
|
||||
0, 0, 0, 0, 0, 2, 4, 0, 3, 7,
|
||||
45, 0, 0, 52, 53, 0, 23, 0, 24, 0,
|
||||
0, 8, 9, 0, 0, 52, 53, 46, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 5, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
17, 0, 0, 61, 63, 62, 60, 51, 0, 50,
|
||||
0, 0, 16, 44, 33, 34, 35, 36, 37, 38,
|
||||
11, 10, 12, 13, 14, 15, 0, 41, 40, 0,
|
||||
42, 73, 48, 0, 47, 32, 31, 30, 29, 25,
|
||||
27, 26, 28, 0, 0, 57, 56, 54, 0, 43,
|
||||
0, 70, 0, 0, 0, 0, 0, 0, 18, 49,
|
||||
67, 66, 64, 59, 58, 55, 0, 0, 0, 69,
|
||||
68, 65
|
||||
};
|
||||
|
||||
/* YYPGOTO[NTERM-NUM]. */
|
||||
static const yytype_int16 yypgoto[] =
|
||||
{
|
||||
-100, -100, 0, -100, -100, 129, -100, 5, -100, -39,
|
||||
-49, -99, -100, 130
|
||||
-102, -102, 0, -102, -102, 44, -102, 5, -102, -35,
|
||||
-6, -101, -102, 128
|
||||
};
|
||||
|
||||
/* YYDEFGOTO[NTERM-NUM]. */
|
||||
static const yytype_int8 yydefgoto[] =
|
||||
{
|
||||
-1, 13, 32, 15, 26, 27, 16, 33, 18, 67,
|
||||
19, 62, 20, 21
|
||||
-1, 14, 33, 16, 27, 28, 17, 34, 19, 71,
|
||||
20, 66, 21, 22
|
||||
};
|
||||
|
||||
/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
|
||||
@@ -549,48 +551,50 @@ static const yytype_int8 yydefgoto[] =
|
||||
number is the opposite. If YYTABLE_NINF, syntax error. */
|
||||
static const yytype_int16 yytable[] =
|
||||
{
|
||||
14, 25, 109, 89, 92, 17, 5, 55, -73, 54,
|
||||
30, 31, 86, 59, 121, 122, 123, 60, 34, -73,
|
||||
47, 28, -71, 29, 61, 127, 128, 129, 87, 93,
|
||||
95, 46, 91, 94, 96, 70, 71, 72, 73, 74,
|
||||
75, 76, 77, 78, 79, 81, 107, 63, 82, 80,
|
||||
48, 65, 63, 52, 83, 84, 65, 97, 99, 117,
|
||||
51, 85, 53, 112, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 103, 49, 50, 101, 51, 102, 9, 10,
|
||||
69, 104, 1, 2, 3, 22, 11, 6, 7, 23,
|
||||
63, 41, 64, 12, 65, 105, 9, 10, 42, 43,
|
||||
44, 45, 45, 66, 11, 108, 116, 1, 2, 3,
|
||||
4, 24, 6, 7, 8, 49, 50, 28, 51, 29,
|
||||
113, 9, 10, 35, 36, 37, 38, 39, 40, 11,
|
||||
41, 63, 114, 110, 115, 65, 24, 42, 43, 44,
|
||||
118, 45, -72, -70, 111, 68, 35, 36, 37, 38,
|
||||
39, 40, 87, 41, 43, 44, 8, 45, 119, 106,
|
||||
42, 43, 44, 88, 45, 35, 36, 37, 38, 39,
|
||||
40, 120, 41, 28, -71, 29, 56, 57, 58, 42,
|
||||
43, 44, 90, 45, 124, 125, 98, 100, 126
|
||||
15, 26, 111, 5, -74, 18, 59, 37, 67, 35,
|
||||
31, 32, 69, 36, 123, 124, 125, 58, -74, 95,
|
||||
90, 51, 89, 96, 38, 129, 130, 131, 50, 29,
|
||||
-72, 30, 97, 67, -73, -71, 98, 69, 52, 74,
|
||||
75, 76, 77, 78, 79, 80, 81, 82, 83, 85,
|
||||
92, 94, 86, 84, 109, 29, 45, 30, 87, 88,
|
||||
56, 99, 101, 46, 47, 48, 103, 49, 104, 114,
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 67, 63,
|
||||
68, 57, 69, 64, 9, 10, 53, 54, 55, 55,
|
||||
65, 70, 11, 73, 105, 1, 2, 3, 23, 12,
|
||||
6, 7, 24, 13, 119, 100, 102, 35, 118, 9,
|
||||
10, 8, 53, 54, 106, 55, 107, 11, 91, 49,
|
||||
1, 2, 3, 4, 25, 6, 7, 8, 13, 47,
|
||||
48, 110, 49, 115, 9, 10, 39, 40, 41, 42,
|
||||
43, 44, 11, 45, 67, 116, 112, 117, 69, 25,
|
||||
46, 47, 48, 13, 49, 120, 126, 113, 72, 39,
|
||||
40, 41, 42, 43, 44, 121, 45, 29, -72, 30,
|
||||
127, 122, 108, 46, 47, 48, 0, 49, 39, 40,
|
||||
41, 42, 43, 44, 93, 45, 60, 61, 62, 0,
|
||||
128, 0, 46, 47, 48, 0, 49
|
||||
};
|
||||
|
||||
static const yytype_uint8 yycheck[] =
|
||||
static const yytype_int16 yycheck[] =
|
||||
{
|
||||
0, 1, 101, 52, 53, 0, 7, 24, 36, 24,
|
||||
10, 11, 51, 6, 113, 114, 115, 10, 0, 36,
|
||||
15, 36, 37, 38, 17, 124, 125, 126, 6, 6,
|
||||
6, 32, 10, 10, 10, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 44, 45, 85, 4, 48, 44,
|
||||
23, 8, 4, 37, 49, 50, 8, 57, 58, 108,
|
||||
29, 18, 36, 102, 3, 4, 5, 6, 7, 8,
|
||||
9, 10, 39, 26, 27, 36, 29, 38, 17, 18,
|
||||
33, 39, 3, 4, 5, 6, 25, 8, 9, 10,
|
||||
4, 18, 6, 32, 8, 39, 17, 18, 25, 26,
|
||||
27, 29, 29, 17, 25, 36, 106, 3, 4, 5,
|
||||
6, 32, 8, 9, 10, 26, 27, 36, 29, 38,
|
||||
36, 17, 18, 11, 12, 13, 14, 15, 16, 25,
|
||||
18, 4, 36, 6, 36, 8, 32, 25, 26, 27,
|
||||
39, 29, 36, 37, 17, 33, 11, 12, 13, 14,
|
||||
15, 16, 6, 18, 26, 27, 10, 29, 39, 24,
|
||||
25, 26, 27, 17, 29, 11, 12, 13, 14, 15,
|
||||
16, 39, 18, 36, 37, 38, 33, 34, 35, 25,
|
||||
26, 27, 52, 29, 36, 36, 57, 58, 36
|
||||
0, 1, 103, 7, 36, 0, 24, 13, 4, 6,
|
||||
10, 11, 8, 10, 115, 116, 117, 24, 36, 6,
|
||||
55, 16, 18, 10, 0, 126, 127, 128, 32, 36,
|
||||
37, 38, 6, 4, 36, 37, 10, 8, 23, 39,
|
||||
40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
|
||||
56, 57, 52, 48, 89, 36, 18, 38, 53, 54,
|
||||
37, 61, 62, 25, 26, 27, 36, 29, 38, 104,
|
||||
3, 4, 5, 6, 7, 8, 9, 10, 4, 6,
|
||||
6, 36, 8, 10, 17, 18, 26, 27, 29, 29,
|
||||
17, 17, 25, 33, 39, 3, 4, 5, 6, 32,
|
||||
8, 9, 10, 36, 110, 61, 62, 6, 108, 17,
|
||||
18, 10, 26, 27, 39, 29, 39, 25, 17, 29,
|
||||
3, 4, 5, 6, 32, 8, 9, 10, 36, 26,
|
||||
27, 36, 29, 36, 17, 18, 11, 12, 13, 14,
|
||||
15, 16, 25, 18, 4, 36, 6, 36, 8, 32,
|
||||
25, 26, 27, 36, 29, 39, 36, 17, 33, 11,
|
||||
12, 13, 14, 15, 16, 39, 18, 36, 37, 38,
|
||||
36, 39, 24, 25, 26, 27, -1, 29, 11, 12,
|
||||
13, 14, 15, 16, 56, 18, 33, 34, 35, -1,
|
||||
36, -1, 25, 26, 27, -1, 29
|
||||
};
|
||||
|
||||
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
|
||||
@@ -598,18 +602,19 @@ static const yytype_uint8 yycheck[] =
|
||||
static const yytype_uint8 yystos[] =
|
||||
{
|
||||
0, 3, 4, 5, 6, 7, 8, 9, 10, 17,
|
||||
18, 25, 32, 41, 42, 43, 46, 47, 48, 50,
|
||||
52, 53, 6, 10, 32, 42, 44, 45, 36, 38,
|
||||
42, 42, 42, 47, 0, 11, 12, 13, 14, 15,
|
||||
16, 18, 25, 26, 27, 29, 32, 47, 23, 26,
|
||||
27, 29, 37, 36, 24, 24, 33, 34, 35, 6,
|
||||
10, 17, 51, 4, 6, 8, 17, 49, 33, 33,
|
||||
42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
|
||||
47, 42, 42, 47, 47, 18, 49, 6, 17, 50,
|
||||
53, 10, 50, 6, 10, 6, 10, 42, 45, 42,
|
||||
45, 36, 38, 39, 39, 39, 24, 49, 36, 51,
|
||||
6, 17, 49, 36, 36, 36, 42, 50, 39, 39,
|
||||
39, 51, 51, 51, 36, 36, 36, 51, 51, 51
|
||||
18, 25, 32, 36, 41, 42, 43, 46, 47, 48,
|
||||
50, 52, 53, 6, 10, 32, 42, 44, 45, 36,
|
||||
38, 42, 42, 42, 47, 6, 10, 50, 0, 11,
|
||||
12, 13, 14, 15, 16, 18, 25, 26, 27, 29,
|
||||
32, 47, 23, 26, 27, 29, 37, 36, 24, 24,
|
||||
33, 34, 35, 6, 10, 17, 51, 4, 6, 8,
|
||||
17, 49, 33, 33, 42, 42, 42, 42, 42, 42,
|
||||
42, 42, 42, 42, 47, 42, 42, 47, 47, 18,
|
||||
49, 17, 50, 53, 50, 6, 10, 6, 10, 42,
|
||||
45, 42, 45, 36, 38, 39, 39, 39, 24, 49,
|
||||
36, 51, 6, 17, 49, 36, 36, 36, 42, 50,
|
||||
39, 39, 39, 51, 51, 51, 36, 36, 36, 51,
|
||||
51, 51
|
||||
};
|
||||
|
||||
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
|
||||
@@ -619,10 +624,10 @@ static const yytype_uint8 yyr1[] =
|
||||
42, 42, 42, 42, 42, 42, 42, 42, 42, 43,
|
||||
43, 43, 43, 44, 44, 44, 44, 44, 44, 45,
|
||||
45, 45, 45, 46, 46, 46, 46, 46, 46, 47,
|
||||
47, 47, 47, 47, 47, 48, 48, 48, 48, 49,
|
||||
49, 50, 50, 50, 50, 50, 50, 50, 50, 50,
|
||||
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||
52, 52, 53, 53
|
||||
47, 47, 47, 47, 47, 48, 48, 48, 48, 48,
|
||||
49, 49, 50, 50, 50, 50, 50, 50, 50, 50,
|
||||
50, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||
51, 52, 52, 53, 53
|
||||
};
|
||||
|
||||
/* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
|
||||
@@ -632,10 +637,10 @@ static const yytype_uint8 yyr2[] =
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 5, 1,
|
||||
1, 1, 1, 1, 1, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
|
||||
3, 3, 3, 4, 3, 1, 3, 3, 5, 1,
|
||||
1, 1, 1, 4, 6, 4, 4, 6, 6, 3,
|
||||
1, 1, 1, 4, 6, 4, 4, 6, 6, 3,
|
||||
1, 1, 1, 1
|
||||
3, 3, 3, 4, 3, 1, 2, 3, 3, 5,
|
||||
1, 1, 1, 1, 4, 6, 4, 4, 6, 6,
|
||||
3, 1, 1, 1, 4, 6, 4, 4, 6, 6,
|
||||
3, 1, 1, 1, 1
|
||||
};
|
||||
|
||||
|
||||
@@ -1061,25 +1066,25 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
|
||||
case 42: /* exp */
|
||||
#line 59 "ExpressionParser.y" /* yacc.c:1257 */
|
||||
{ delete ((*yyvaluep).expr); }
|
||||
#line 1065 "ExpressionParser.tab.c" /* yacc.c:1257 */
|
||||
#line 1070 "ExpressionParser.tab.c" /* yacc.c:1257 */
|
||||
break;
|
||||
|
||||
case 44: /* args */
|
||||
#line 60 "ExpressionParser.y" /* yacc.c:1257 */
|
||||
{ std::vector<Expression*>::const_iterator i = ((*yyvaluep).arguments).begin(); while (i != ((*yyvaluep).arguments).end()) { delete *i; ++i; } }
|
||||
#line 1071 "ExpressionParser.tab.c" /* yacc.c:1257 */
|
||||
#line 1076 "ExpressionParser.tab.c" /* yacc.c:1257 */
|
||||
break;
|
||||
|
||||
case 46: /* cond */
|
||||
#line 59 "ExpressionParser.y" /* yacc.c:1257 */
|
||||
{ delete ((*yyvaluep).expr); }
|
||||
#line 1077 "ExpressionParser.tab.c" /* yacc.c:1257 */
|
||||
#line 1082 "ExpressionParser.tab.c" /* yacc.c:1257 */
|
||||
break;
|
||||
|
||||
case 47: /* unit_exp */
|
||||
#line 59 "ExpressionParser.y" /* yacc.c:1257 */
|
||||
{ delete ((*yyvaluep).expr); }
|
||||
#line 1083 "ExpressionParser.tab.c" /* yacc.c:1257 */
|
||||
#line 1088 "ExpressionParser.tab.c" /* yacc.c:1257 */
|
||||
break;
|
||||
|
||||
|
||||
@@ -1343,259 +1348,259 @@ yyreduce:
|
||||
case 2:
|
||||
#line 66 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ ScanResult = (yyvsp[0].expr); valueExpression = true; }
|
||||
#line 1347 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1352 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 3:
|
||||
#line 67 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ ScanResult = (yyvsp[0].expr); unitExpression = true; }
|
||||
#line 1353 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1358 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 4:
|
||||
#line 70 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = (yyvsp[0].expr); }
|
||||
#line 1359 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1364 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 5:
|
||||
#line 71 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-1].expr), OperatorExpression::UNIT, (yyvsp[0].expr)); }
|
||||
#line 1365 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1370 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 6:
|
||||
#line 72 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new StringExpression(DocumentObject, (yyvsp[0].string)); }
|
||||
#line 1371 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1376 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 7:
|
||||
#line 73 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new VariableExpression(DocumentObject, (yyvsp[0].path)); }
|
||||
#line 1377 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1382 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 8:
|
||||
#line 74 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[0].expr), OperatorExpression::NEG, new NumberExpression(DocumentObject, Quantity(-1))); }
|
||||
#line 1383 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1388 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 9:
|
||||
#line 75 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[0].expr), OperatorExpression::POS, new NumberExpression(DocumentObject, Quantity(1))); }
|
||||
#line 1389 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1394 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 10:
|
||||
#line 76 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::ADD, (yyvsp[0].expr)); }
|
||||
#line 1395 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1400 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 11:
|
||||
#line 77 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::SUB, (yyvsp[0].expr)); }
|
||||
#line 1401 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1406 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 12:
|
||||
#line 78 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::MUL, (yyvsp[0].expr)); }
|
||||
#line 1407 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1412 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 13:
|
||||
#line 79 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); }
|
||||
#line 1413 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1418 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 14:
|
||||
#line 80 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); }
|
||||
#line 1419 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1424 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 15:
|
||||
#line 81 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::POW, (yyvsp[0].expr)); }
|
||||
#line 1425 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1430 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 16:
|
||||
#line 82 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = (yyvsp[-1].expr); }
|
||||
#line 1431 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1436 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 17:
|
||||
#line 83 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new FunctionExpression(DocumentObject, (yyvsp[-2].func), (yyvsp[-1].arguments)); }
|
||||
#line 1437 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1442 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 18:
|
||||
#line 84 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new ConditionalExpression(DocumentObject, (yyvsp[-4].expr), (yyvsp[-2].expr), (yyvsp[0].expr)); }
|
||||
#line 1443 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1448 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 19:
|
||||
#line 87 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new NumberExpression(DocumentObject, Quantity((yyvsp[0].fvalue))); }
|
||||
#line 1449 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1454 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 20:
|
||||
#line 88 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new NumberExpression(DocumentObject, Quantity((yyvsp[0].fvalue))); }
|
||||
#line 1455 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1460 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 21:
|
||||
#line 89 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue))); }
|
||||
#line 1461 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1466 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 22:
|
||||
#line 90 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new ConstantExpression(DocumentObject, (yyvsp[0].constant).name, Quantity((yyvsp[0].constant).fvalue)); }
|
||||
#line 1467 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1472 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 23:
|
||||
#line 92 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.arguments).push_back((yyvsp[0].expr)); }
|
||||
#line 1473 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1478 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 24:
|
||||
#line 93 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.arguments).push_back((yyvsp[0].expr)); }
|
||||
#line 1479 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1484 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 25:
|
||||
#line 94 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
|
||||
#line 1485 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1490 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 26:
|
||||
#line 95 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
|
||||
#line 1491 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1496 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 27:
|
||||
#line 96 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
|
||||
#line 1497 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1502 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 28:
|
||||
#line 97 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[-2].arguments).push_back((yyvsp[0].expr)); (yyval.arguments) = (yyvsp[-2].arguments); }
|
||||
#line 1503 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1508 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 29:
|
||||
#line 100 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); }
|
||||
#line 1509 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1514 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 30:
|
||||
#line 101 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); }
|
||||
#line 1515 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1520 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 31:
|
||||
#line 102 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); }
|
||||
#line 1521 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1526 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 32:
|
||||
#line 103 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new RangeExpression(DocumentObject, (yyvsp[-2].string), (yyvsp[0].string)); }
|
||||
#line 1527 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1532 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 33:
|
||||
#line 106 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::EQ, (yyvsp[0].expr)); }
|
||||
#line 1533 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1538 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 34:
|
||||
#line 107 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::NEQ, (yyvsp[0].expr)); }
|
||||
#line 1539 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1544 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 35:
|
||||
#line 108 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::LT, (yyvsp[0].expr)); }
|
||||
#line 1545 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1550 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 36:
|
||||
#line 109 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::GT, (yyvsp[0].expr)); }
|
||||
#line 1551 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1556 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 37:
|
||||
#line 110 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::GTE, (yyvsp[0].expr)); }
|
||||
#line 1557 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1562 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 38:
|
||||
#line 111 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::LTE, (yyvsp[0].expr)); }
|
||||
#line 1563 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1568 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 39:
|
||||
#line 114 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new UnitExpression(DocumentObject, (yyvsp[0].quantity).scaler, (yyvsp[0].quantity).unitStr ); }
|
||||
#line 1569 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1574 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 40:
|
||||
#line 115 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::DIV, (yyvsp[0].expr)); }
|
||||
#line 1575 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1580 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 41:
|
||||
#line 116 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::MUL, (yyvsp[0].expr)); }
|
||||
#line 1581 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1586 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 42:
|
||||
#line 117 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-2].expr), OperatorExpression::POW, new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue)))); }
|
||||
#line 1587 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1592 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 43:
|
||||
#line 118 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = new OperatorExpression(DocumentObject, (yyvsp[-3].expr), OperatorExpression::POW, new OperatorExpression(DocumentObject, new NumberExpression(DocumentObject, Quantity((double)(yyvsp[0].ivalue))), OperatorExpression::NEG, new NumberExpression(DocumentObject, Quantity(-1)))); }
|
||||
#line 1593 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1598 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 44:
|
||||
#line 119 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.expr) = (yyvsp[-1].expr); }
|
||||
#line 1599 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1604 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 45:
|
||||
@@ -1603,193 +1608,212 @@ yyreduce:
|
||||
{ /* Path to property within document object */
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject);
|
||||
(yyval.path).addComponents((yyvsp[0].components));
|
||||
(yyval.path).resolveAmbiguity();
|
||||
}
|
||||
#line 1608 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1613 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 46:
|
||||
#line 126 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ /* Path to property within document object */
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject);
|
||||
(yyval.path).setDocumentObjectName((yyvsp[-2].string_or_identifier), true);
|
||||
{ /* Path to property of the current document object */
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject,true);
|
||||
(yyval.path).setDocumentObjectName(DocumentObject);
|
||||
(yyval.path).addComponents((yyvsp[0].components));
|
||||
}
|
||||
#line 1618 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1623 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 47:
|
||||
#line 131 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ /* Path to property from an external document, within a named document object */
|
||||
{ /* Path to property within document object */
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject);
|
||||
(yyval.path).setDocumentName((yyvsp[-2].string_or_identifier), true);
|
||||
(yyvsp[-2].string_or_identifier).checkImport(DocumentObject);
|
||||
(yyval.path).addComponent(ObjectIdentifier::SimpleComponent((yyvsp[-2].string_or_identifier)));
|
||||
(yyval.path).addComponents((yyvsp[0].components));
|
||||
(yyval.path).resolveAmbiguity();
|
||||
}
|
||||
#line 1628 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1633 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 48:
|
||||
#line 136 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ /* Path to property from an external document, within a named document object */
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject);
|
||||
(yyval.path).setDocumentName((yyvsp[-4].string_or_identifier), true);
|
||||
(yyval.path).setDocumentObjectName((yyvsp[-2].string_or_identifier), true);
|
||||
(yyval.path).setDocumentName(std::move(yyvsp[-2].string_or_identifier), true);
|
||||
if((yyvsp[0].components).size()) {
|
||||
(yyval.path).setDocumentObjectName(ObjectIdentifier::String((yyvsp[0].components).front().getName(),false,true), true);
|
||||
(yyvsp[0].components).pop_front();
|
||||
}
|
||||
(yyval.path).addComponents((yyvsp[0].components));
|
||||
(yyval.path).resolveAmbiguity();
|
||||
}
|
||||
#line 1639 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1643 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 49:
|
||||
#line 144 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.ivalue) = (yyvsp[0].ivalue); }
|
||||
#line 1645 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 141 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ /* Path to property from an external document, within a named document object */
|
||||
(yyval.path) = ObjectIdentifier(DocumentObject);
|
||||
(yyval.path).setDocumentName(std::move(yyvsp[-4].string_or_identifier), true);
|
||||
(yyval.path).setDocumentObjectName(std::move(yyvsp[-2].string_or_identifier), true);
|
||||
(yyval.path).addComponents((yyvsp[0].components));
|
||||
(yyval.path).resolveAmbiguity();
|
||||
}
|
||||
#line 1654 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 50:
|
||||
#line 145 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.ivalue) = (yyvsp[0].fvalue); }
|
||||
#line 1651 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 149 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.ivalue) = (yyvsp[0].ivalue); }
|
||||
#line 1660 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 51:
|
||||
#line 149 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1657 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 150 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.ivalue) = (yyvsp[0].fvalue); }
|
||||
#line 1666 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 52:
|
||||
#line 150 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1663 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 154 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1672 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 53:
|
||||
#line 151 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::ArrayComponent((yyvsp[-3].string), (yyvsp[-1].ivalue))); }
|
||||
#line 1669 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 155 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1678 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 54:
|
||||
#line 152 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::ArrayComponent((yyvsp[-5].string), (yyvsp[-3].ivalue))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1675 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 156 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::ArrayComponent((yyvsp[-1].ivalue))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
|
||||
#line 1684 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 55:
|
||||
#line 153 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-3].string), ObjectIdentifier::String((yyvsp[-1].string), true))); }
|
||||
#line 1681 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 157 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::ArrayComponent((yyvsp[-3].ivalue))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1690 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 56:
|
||||
#line 154 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-3].string), (yyvsp[-1].string))); }
|
||||
#line 1687 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 158 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String((yyvsp[-1].string), true))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
|
||||
#line 1696 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 57:
|
||||
#line 155 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-5].string), ObjectIdentifier::String((yyvsp[-3].string), true))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1693 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 159 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::MapComponent((yyvsp[-1].string))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
|
||||
#line 1702 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 58:
|
||||
#line 156 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-5].string), (yyvsp[-3].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1699 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 160 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String((yyvsp[-3].string), true))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1708 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 59:
|
||||
#line 157 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[-2].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1705 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 161 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::MapComponent((yyvsp[-3].string))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1714 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 60:
|
||||
#line 160 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1711 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 162 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-2].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1720 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 61:
|
||||
#line 161 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1717 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 165 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1726 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 62:
|
||||
#line 162 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1723 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 166 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1732 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 63:
|
||||
#line 163 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::ArrayComponent((yyvsp[-3].string), (yyvsp[-1].ivalue))); }
|
||||
#line 1729 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 167 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[0].string))); }
|
||||
#line 1738 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 64:
|
||||
#line 164 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::ArrayComponent((yyvsp[-5].string), (yyvsp[-3].ivalue))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1735 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 168 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::ArrayComponent((yyvsp[-1].ivalue))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
|
||||
#line 1744 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 65:
|
||||
#line 165 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-3].string), ObjectIdentifier::String((yyvsp[-1].string), true))); }
|
||||
#line 1741 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 169 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::ArrayComponent((yyvsp[-3].ivalue))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1750 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 66:
|
||||
#line 166 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-3].string), (yyvsp[-1].string))); }
|
||||
#line 1747 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 170 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String((yyvsp[-1].string), true))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
|
||||
#line 1756 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 67:
|
||||
#line 167 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-5].string), ObjectIdentifier::String((yyvsp[-3].string), true))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1753 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 171 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.components).push_front(ObjectIdentifier::MapComponent((yyvsp[-1].string))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-3].string))); }
|
||||
#line 1762 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 68:
|
||||
#line 168 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::MapComponent((yyvsp[-5].string), (yyvsp[-3].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1759 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 172 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String((yyvsp[-3].string), true))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1768 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 69:
|
||||
#line 169 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::Component::SimpleComponent((yyvsp[-2].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1765 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 173 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::MapComponent((yyvsp[-3].string))); (yyval.components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-5].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1774 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 70:
|
||||
#line 172 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string), true); }
|
||||
#line 1771 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 174 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyvsp[0].components).push_front(ObjectIdentifier::SimpleComponent((yyvsp[-2].string))); (yyval.components) = (yyvsp[0].components); }
|
||||
#line 1780 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 71:
|
||||
#line 173 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string)); }
|
||||
#line 1777 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 177 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string), true); }
|
||||
#line 1786 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 72:
|
||||
#line 176 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string), true); }
|
||||
#line 1783 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 178 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string)); }
|
||||
#line 1792 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 73:
|
||||
#line 177 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
#line 181 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string), true); }
|
||||
#line 1789 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1798 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
case 74:
|
||||
#line 182 "ExpressionParser.y" /* yacc.c:1646 */
|
||||
{ (yyval.string_or_identifier) = ObjectIdentifier::String((yyvsp[0].string), true); }
|
||||
#line 1804 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
break;
|
||||
|
||||
|
||||
#line 1793 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
#line 1808 "ExpressionParser.tab.c" /* yacc.c:1646 */
|
||||
default: break;
|
||||
}
|
||||
/* User semantic actions sometimes alter yychar, and that requires
|
||||
@@ -2017,5 +2041,5 @@ yyreturn:
|
||||
#endif
|
||||
return yyresult;
|
||||
}
|
||||
#line 180 "ExpressionParser.y" /* yacc.c:1906 */
|
||||
#line 185 "ExpressionParser.y" /* yacc.c:1906 */
|
||||
|
||||
|
||||
+33
-23
@@ -122,22 +122,32 @@ unit_exp: UNIT { $$ = new UnitExpression(Docume
|
||||
identifier: path { /* Path to property within document object */
|
||||
$$ = ObjectIdentifier(DocumentObject);
|
||||
$$.addComponents($1);
|
||||
$$.resolveAmbiguity();
|
||||
}
|
||||
| '.' path { /* Path to property of the current document object */
|
||||
$$ = ObjectIdentifier(DocumentObject,true);
|
||||
$$.setDocumentObjectName(DocumentObject);
|
||||
$$.addComponents($2);
|
||||
}
|
||||
| object '.' path { /* Path to property within document object */
|
||||
$$ = ObjectIdentifier(DocumentObject);
|
||||
$$.setDocumentObjectName($1, true);
|
||||
$1.checkImport(DocumentObject);
|
||||
$$.addComponent(ObjectIdentifier::SimpleComponent($1));
|
||||
$$.addComponents($3);
|
||||
$$.resolveAmbiguity();
|
||||
}
|
||||
| document '#' path { /* Path to property from an external document, within a named document object */
|
||||
$$ = ObjectIdentifier(DocumentObject);
|
||||
$$.setDocumentName($1, true);
|
||||
$$.setDocumentName(std::move($1), true);
|
||||
$$.addComponents($3);
|
||||
$$.resolveAmbiguity();
|
||||
}
|
||||
| document '#' object '.' path { /* Path to property from an external document, within a named document object */
|
||||
$$ = ObjectIdentifier(DocumentObject);
|
||||
$$.setDocumentName($1, true);
|
||||
$$.setDocumentObjectName($3, true);
|
||||
$$.setDocumentName(std::move($1), true);
|
||||
$$.setDocumentObjectName(std::move($3), true);
|
||||
$$.addComponents($5);
|
||||
$$.resolveAmbiguity();
|
||||
}
|
||||
;
|
||||
|
||||
@@ -146,27 +156,27 @@ integer: INTEGER { $$ = $1; }
|
||||
;
|
||||
|
||||
|
||||
path: IDENTIFIER { $$.push_front(ObjectIdentifier::Component::SimpleComponent($1)); }
|
||||
| CELLADDRESS { $$.push_front(ObjectIdentifier::Component::SimpleComponent($1)); }
|
||||
| IDENTIFIER '[' integer ']' { $$.push_front(ObjectIdentifier::Component::ArrayComponent($1, $3)); }
|
||||
| IDENTIFIER '[' integer ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::ArrayComponent($1, $3)); $$ = $6; }
|
||||
| IDENTIFIER '[' STRING ']' { $$.push_front(ObjectIdentifier::Component::MapComponent($1, ObjectIdentifier::String($3, true))); }
|
||||
| IDENTIFIER '[' IDENTIFIER ']' { $$.push_front(ObjectIdentifier::Component::MapComponent($1, $3)); }
|
||||
| IDENTIFIER '[' STRING ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::MapComponent($1, ObjectIdentifier::String($3, true))); $$ = $6; }
|
||||
| IDENTIFIER '[' IDENTIFIER ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::MapComponent($1, $3)); $$ = $6; }
|
||||
| IDENTIFIER '.' subpath { $3.push_front(ObjectIdentifier::Component::SimpleComponent($1)); $$ = $3; }
|
||||
path: IDENTIFIER { $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
|
||||
| CELLADDRESS { $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
|
||||
| IDENTIFIER '[' integer ']' { $$.push_front(ObjectIdentifier::ArrayComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1); }
|
||||
| IDENTIFIER '[' integer ']' '.' subpath { $6.push_front(ObjectIdentifier::ArrayComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1); $$ = $6; }
|
||||
| IDENTIFIER '[' STRING ']' { $$.push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String($3, true))); }
|
||||
| IDENTIFIER '[' IDENTIFIER ']' { $$.push_front(ObjectIdentifier::MapComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1); }
|
||||
| IDENTIFIER '[' STRING ']' '.' subpath { $6.push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String($3, true))); $$.push_front(ObjectIdentifier::SimpleComponent($1); $$ = $6; }
|
||||
| IDENTIFIER '[' IDENTIFIER ']' '.' subpath { $6.push_front(ObjectIdentifier::MapComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1); $$ = $6; }
|
||||
| IDENTIFIER '.' subpath { $3.push_front(ObjectIdentifier::SimpleComponent($1)); $$ = $3; }
|
||||
;
|
||||
|
||||
subpath: IDENTIFIER { $$.push_front(ObjectIdentifier::Component::SimpleComponent($1)); }
|
||||
| STRING { $$.push_front(ObjectIdentifier::Component::SimpleComponent($1)); }
|
||||
| CELLADDRESS { $$.push_front(ObjectIdentifier::Component::SimpleComponent($1)); }
|
||||
| IDENTIFIER '[' integer ']' { $$.push_front(ObjectIdentifier::Component::ArrayComponent($1, $3)); }
|
||||
| IDENTIFIER '[' integer ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::ArrayComponent($1, $3)); $$ = $6; }
|
||||
| IDENTIFIER '[' STRING ']' { $$.push_front(ObjectIdentifier::Component::MapComponent($1, ObjectIdentifier::String($3, true))); }
|
||||
| IDENTIFIER '[' IDENTIFIER ']' { $$.push_front(ObjectIdentifier::Component::MapComponent($1, $3)); }
|
||||
| IDENTIFIER '[' STRING ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::MapComponent($1, ObjectIdentifier::String($3, true))); $$ = $6; }
|
||||
| IDENTIFIER '[' IDENTIFIER ']' '.' subpath { $6.push_front(ObjectIdentifier::Component::MapComponent($1, $3)); $$ = $6; }
|
||||
| IDENTIFIER '.' subpath { $3.push_front(ObjectIdentifier::Component::SimpleComponent($1)); $$ = $3; }
|
||||
subpath: IDENTIFIER { $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
|
||||
| STRING { $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
|
||||
| CELLADDRESS { $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
|
||||
| IDENTIFIER '[' integer ']' { $$.push_front(ObjectIdentifier::ArrayComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
|
||||
| IDENTIFIER '[' integer ']' '.' subpath { $6.push_front(ObjectIdentifier::ArrayComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1));$$ = $6; }
|
||||
| IDENTIFIER '[' STRING ']' { $$.push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String($3, true))); $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
|
||||
| IDENTIFIER '[' IDENTIFIER ']' { $$.push_front(ObjectIdentifier::MapComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1)); }
|
||||
| IDENTIFIER '[' STRING ']' '.' subpath { $6.push_front(ObjectIdentifier::MapComponent(ObjectIdentifier::String($3, true))); $$.push_front(ObjectIdentifier::SimpleComponent($1));$$ = $6; }
|
||||
| IDENTIFIER '[' IDENTIFIER ']' '.' subpath { $6.push_front(ObjectIdentifier::MapComponent($3)); $$.push_front(ObjectIdentifier::SimpleComponent($1));$$ = $6; }
|
||||
| IDENTIFIER '.' subpath { $3.push_front(ObjectIdentifier::SimpleComponent($1)); $$ = $3; }
|
||||
;
|
||||
|
||||
document: STRING { $$ = ObjectIdentifier::String($1, true); }
|
||||
|
||||
@@ -43,18 +43,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
void visit(Expression &node) {
|
||||
this->renameObjectIdentifier(node,paths,owner);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,64 +53,72 @@ private:
|
||||
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> {
|
||||
template<class P> class UpdateElementReferenceExpressionVisitor : public ExpressionModifier<P> {
|
||||
public:
|
||||
|
||||
RelabelDocumentObjectExpressionVisitor(P & _prop, const std::string & _oldName, const std::string & _newName)
|
||||
: ExpressionModifier<P>(_prop)
|
||||
, oldName(_oldName)
|
||||
, newName(_newName)
|
||||
UpdateElementReferenceExpressionVisitor(P & _prop, App::DocumentObject *feature=0, bool reverse=false)
|
||||
: ExpressionModifier<P>(_prop),feature(feature),reverse(reverse)
|
||||
{
|
||||
}
|
||||
|
||||
~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);
|
||||
}
|
||||
void visit(Expression &node) {
|
||||
this->updateElementReference(node,feature,reverse);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string oldName; /**< Document object name to replace */
|
||||
std::string newName; /**< New document object name */
|
||||
App::DocumentObject *feature;
|
||||
bool reverse;
|
||||
};
|
||||
|
||||
template<class P> class RelabelDocumentExpressionVisitor : public ExpressionModifier<P> {
|
||||
// Document relabel is not undoable, so we don't derive from
|
||||
// ExpressionModifier, hence not calling aboutToSetValue/hasSetValue().
|
||||
// By right, modification of document label should not change evaluation result
|
||||
// of any expression.
|
||||
class RelabelDocumentExpressionVisitor : public ExpressionVisitor {
|
||||
public:
|
||||
|
||||
RelabelDocumentExpressionVisitor(P & prop, const std::string & _oldName, const std::string & _newName)
|
||||
: ExpressionModifier<P>(prop)
|
||||
, oldName(_oldName)
|
||||
, newName(_newName)
|
||||
RelabelDocumentExpressionVisitor(const App::Document &doc)
|
||||
: doc(doc)
|
||||
{
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
void visit(Expression &node) {
|
||||
this->relabeledDocument(node,doc.getOldLabel(),doc.Label.getStrValue());
|
||||
}
|
||||
|
||||
private:
|
||||
std::string oldName;
|
||||
std::string newName;
|
||||
const App::Document &doc;
|
||||
};
|
||||
|
||||
template<class P> class MoveCellsExpressionVisitor : public ExpressionModifier<P> {
|
||||
public:
|
||||
MoveCellsExpressionVisitor(P &prop, const CellAddress &address, int rowCount, int colCount)
|
||||
: ExpressionModifier<P>(prop),address(address),rowCount(rowCount),colCount(colCount)
|
||||
{}
|
||||
|
||||
void visit(Expression &node) {
|
||||
this->moveCells(node,address,rowCount,colCount);
|
||||
}
|
||||
|
||||
private:
|
||||
CellAddress address;
|
||||
int rowCount;
|
||||
int colCount;
|
||||
};
|
||||
|
||||
template<class P> class OffsetCellsExpressionVisitor : public ExpressionModifier<P> {
|
||||
public:
|
||||
OffsetCellsExpressionVisitor(P &prop, int rowOffset, int colOffset)
|
||||
: ExpressionModifier<P>(prop),rowOffset(rowOffset),colOffset(colOffset)
|
||||
{}
|
||||
|
||||
void visit(Expression &node) {
|
||||
this->offsetCells(node,rowOffset,colOffset);
|
||||
}
|
||||
|
||||
private:
|
||||
int rowOffset;
|
||||
int colOffset;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+1173
-428
File diff suppressed because it is too large
Load Diff
+246
-44
@@ -24,39 +24,86 @@
|
||||
#ifndef APP_PATH_H
|
||||
#define APP_PATH_H
|
||||
|
||||
#include <climits>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <bitset>
|
||||
#ifndef BOOST_105400
|
||||
#include <boost/any.hpp>
|
||||
#else
|
||||
#include <boost_any_1_55.hpp>
|
||||
#endif
|
||||
#include <CXX/Objects.hxx>
|
||||
|
||||
namespace App
|
||||
{
|
||||
|
||||
using any = boost::any;
|
||||
|
||||
template<class T>
|
||||
inline const T &any_cast(const boost::any &value) {
|
||||
return boost::any_cast<const T&>(value);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T &any_cast(boost::any &value) {
|
||||
return boost::any_cast<T&>(value);
|
||||
}
|
||||
|
||||
class Property;
|
||||
class Document;
|
||||
class PropertyContainer;
|
||||
class DocumentObject;
|
||||
class ExpressionVisitor;
|
||||
|
||||
AppExport std::string quote(const std::string &input);
|
||||
AppExport std::string quote(const std::string &input, bool toPython=false);
|
||||
|
||||
// Unfortunately VS2013 does not support default move constructor, so we have
|
||||
// to implement them manually
|
||||
#define FC_DEFAULT_CTORS(_t) \
|
||||
_t(const _t &) = default;\
|
||||
_t &operator=(const _t &) = default;\
|
||||
_t(_t &&other) { *this = std::move(other); }\
|
||||
_t &operator=(_t &&other)
|
||||
|
||||
class AppExport ObjectIdentifier {
|
||||
|
||||
public:
|
||||
|
||||
class AppExport DocumentMapper {
|
||||
public:
|
||||
DocumentMapper(const std::map<std::string,std::string> &);
|
||||
~DocumentMapper();
|
||||
};
|
||||
|
||||
class String {
|
||||
friend class ObjectIdentifier;
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
String(const std::string & s = "", bool _isRealString = false, bool _forceIdentifier = false) : str(s), isString(_isRealString), forceIdentifier(_forceIdentifier) { }
|
||||
String(const std::string & s = "", bool _isRealString = false, bool _forceIdentifier = false)
|
||||
: str(s), isString(_isRealString), forceIdentifier(_forceIdentifier)
|
||||
{ }
|
||||
|
||||
String(std::string &&s, bool _isRealString = false, bool _forceIdentifier = false)
|
||||
: str(std::move(s)), isString(_isRealString), forceIdentifier(_forceIdentifier)
|
||||
{ }
|
||||
|
||||
FC_DEFAULT_CTORS(String) {
|
||||
str = std::move(other.str);
|
||||
isString = other.isString;
|
||||
forceIdentifier = other.forceIdentifier;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
/** Returns the string */
|
||||
std::string getString() const { return str; }
|
||||
const std::string &getString() const { return str; }
|
||||
|
||||
/** Return true is string need to be quoted */
|
||||
bool isRealString() const { return isString; }
|
||||
@@ -64,7 +111,7 @@ public:
|
||||
bool isForceIdentifier() const { return forceIdentifier; }
|
||||
|
||||
/** Returns a possibly quoted string */
|
||||
std::string toString() const;
|
||||
std::string toString(bool toPython=false) const;
|
||||
|
||||
// Operators
|
||||
|
||||
@@ -82,6 +129,8 @@ public:
|
||||
|
||||
bool operator>(const String & other) const { return str > other.str; }
|
||||
|
||||
void checkImport(const App::DocumentObject *owner,
|
||||
const App::DocumentObject *obj=0, String *objName=0);
|
||||
private:
|
||||
|
||||
std::string str;
|
||||
@@ -103,22 +152,38 @@ public:
|
||||
enum typeEnum {
|
||||
SIMPLE,
|
||||
MAP,
|
||||
ARRAY
|
||||
ARRAY,
|
||||
RANGE,
|
||||
} ;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
FC_DEFAULT_CTORS(Component) {
|
||||
name = std::move(other.name);
|
||||
type = other.type;
|
||||
begin = other.begin;
|
||||
end = other.end;
|
||||
step = other.step;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Component(const String &_component, typeEnum _type = SIMPLE, int _index = -1, String _key = String());
|
||||
Component(const String &_name = String(), typeEnum _type=SIMPLE,
|
||||
int begin=INT_MAX, int end=INT_MAX, int step=1);
|
||||
Component(String &&_name, typeEnum _type=SIMPLE,
|
||||
int begin=INT_MAX, int end=INT_MAX, int step=1);
|
||||
|
||||
static Component SimpleComponent(const char * _component);
|
||||
|
||||
static Component SimpleComponent(const String & _component);
|
||||
static Component SimpleComponent(String &&_component);
|
||||
|
||||
static Component ArrayComponent(const String &_component, int _index);
|
||||
static Component ArrayComponent(int _index);
|
||||
|
||||
static Component MapComponent(const String &_component, const String &_key);
|
||||
static Component RangeComponent(int _begin, int _end = INT_MAX, int _step=1);
|
||||
|
||||
static Component MapComponent(const String &_key);
|
||||
static Component MapComponent(String &&_key);
|
||||
|
||||
// Type queries
|
||||
|
||||
@@ -128,93 +193,175 @@ public:
|
||||
|
||||
bool isArray() const { return type == ARRAY; }
|
||||
|
||||
bool isRange() const { return type == RANGE; }
|
||||
|
||||
// Accessors
|
||||
|
||||
std::string toString() const;
|
||||
void toString(std::ostream &ss, bool toPython=false) const;
|
||||
|
||||
std::string getName() const { return name.getString(); }
|
||||
const std::string &getName() const { return name.getString(); }
|
||||
|
||||
std::size_t getIndex() const { return static_cast<std::size_t>(index); }
|
||||
int getIndex() const {return begin;}
|
||||
size_t getIndex(size_t count) const;
|
||||
|
||||
String getKey() const { return key; }
|
||||
|
||||
bool getKeyIsString() const { return keyIsString; }
|
||||
int getBegin() const { return begin; }
|
||||
int getEnd() const { return end; }
|
||||
int getStep() const { return step; }
|
||||
|
||||
// Operators
|
||||
|
||||
bool operator==(const Component & other) const;
|
||||
bool operator<(const Component & other) const;
|
||||
|
||||
Py::Object get(const Py::Object &pyobj) const;
|
||||
void set(Py::Object &pyobj, const Py::Object &value) const;
|
||||
void del(Py::Object &pyobj) const;
|
||||
|
||||
private:
|
||||
|
||||
String name;
|
||||
typeEnum type;
|
||||
int index;
|
||||
String key;
|
||||
bool keyIsString;
|
||||
|
||||
int begin;
|
||||
int end;
|
||||
int step;
|
||||
friend class ObjectIdentifier;
|
||||
|
||||
};
|
||||
|
||||
ObjectIdentifier(const App::PropertyContainer * _owner = 0, const std::string & property = std::string());
|
||||
static Component SimpleComponent(const char * _component)
|
||||
{return Component::SimpleComponent(_component);}
|
||||
|
||||
ObjectIdentifier(const App::Property & prop);
|
||||
static Component SimpleComponent(const String & _component)
|
||||
{return Component::SimpleComponent(_component);}
|
||||
|
||||
static Component SimpleComponent(String &&_component)
|
||||
{return Component::SimpleComponent(std::move(_component));}
|
||||
|
||||
static Component ArrayComponent(int _index)
|
||||
{return Component::ArrayComponent(_index); }
|
||||
|
||||
static Component RangeComponent(int _begin, int _end = INT_MAX, int _step=1)
|
||||
{return Component::RangeComponent(_begin,_end,_step);}
|
||||
|
||||
static Component MapComponent(const String &_key)
|
||||
{return Component::MapComponent(_key);}
|
||||
|
||||
static Component MapComponent(String &&_key)
|
||||
{return Component::MapComponent(_key);}
|
||||
|
||||
ObjectIdentifier(const App::PropertyContainer * _owner = 0,
|
||||
const std::string & property = std::string(), int index=INT_MAX);
|
||||
|
||||
ObjectIdentifier(const App::PropertyContainer * _owner, bool localProperty);
|
||||
|
||||
ObjectIdentifier(const App::Property & prop, int index=INT_MAX);
|
||||
|
||||
FC_DEFAULT_CTORS(ObjectIdentifier) {
|
||||
owner = other.owner;
|
||||
documentName = std::move(other.documentName);
|
||||
documentObjectName = std::move(other.documentObjectName);
|
||||
subObjectName = std::move(other.subObjectName);
|
||||
shadowSub = std::move(other.shadowSub);
|
||||
components = std::move(other.components);
|
||||
documentNameSet = other.documentNameSet;
|
||||
documentObjectNameSet = other.documentObjectNameSet;
|
||||
localProperty = other.localProperty;
|
||||
_cache = std::move(other._cache);
|
||||
_hash = std::move(other._hash);
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~ObjectIdentifier() {}
|
||||
|
||||
App::DocumentObject *getOwner() const { return owner; }
|
||||
|
||||
// Components
|
||||
void addComponent(const Component &c) { components.push_back(c); }
|
||||
void addComponent(const Component &c) {
|
||||
components.push_back(c);
|
||||
_cache.clear();
|
||||
}
|
||||
|
||||
// Components
|
||||
void addComponent(Component &&c) {
|
||||
components.push_back(std::move(c));
|
||||
_cache.clear();
|
||||
}
|
||||
|
||||
std::string getPropertyName() const;
|
||||
|
||||
template<typename C>
|
||||
void addComponents(const C &cs) { components.insert(components.end(), cs.begin(), cs.end()); }
|
||||
|
||||
const std::string getPropertyName() const;
|
||||
|
||||
const Component & getPropertyComponent(int i) const;
|
||||
|
||||
std::string getSubPathStr() const;
|
||||
Component & getPropertyComponent(int i);
|
||||
|
||||
std::vector<Component> getPropertyComponents() const;
|
||||
const std::vector<Component> &getComponents() const { return components; }
|
||||
|
||||
std::string getSubPathStr(bool toPython=false) const;
|
||||
|
||||
int numComponents() const;
|
||||
|
||||
int numSubComponents() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
const std::string &toString() const;
|
||||
|
||||
std::string toPersistentString() const;
|
||||
|
||||
std::string toEscapedString() const;
|
||||
|
||||
App::Property *getProperty() const;
|
||||
bool isTouched() const;
|
||||
|
||||
App::Property *getProperty(int *ptype=0) const;
|
||||
|
||||
App::ObjectIdentifier canonicalPath() const;
|
||||
|
||||
// Document-centric functions
|
||||
|
||||
void setDocumentName(const String & name, bool force = false);
|
||||
void setDocumentName(String &&name, bool force = false);
|
||||
|
||||
const String getDocumentName() const;
|
||||
String getDocumentName() const;
|
||||
|
||||
void setDocumentObjectName(const String & name, bool force = false);
|
||||
void setDocumentObjectName(String &&name, bool force = false,
|
||||
String &&subname = String(), bool checkImport=false);
|
||||
|
||||
const String getDocumentObjectName() const;
|
||||
void setDocumentObjectName(const App::DocumentObject *obj, bool force = false,
|
||||
String &&subname = String(), bool checkImport=false);
|
||||
|
||||
bool validDocumentObjectRename(const std::string &oldName, const std::string &newName);
|
||||
bool hasDocumentObjectName(bool forced=false) const;
|
||||
|
||||
bool renameDocumentObject(const std::string & oldName, const std::string & newName);
|
||||
bool isLocalProperty() const { return localProperty; }
|
||||
|
||||
bool validDocumentRename(const std::string &oldName, const std::string &newName);
|
||||
String getDocumentObjectName() const;
|
||||
|
||||
bool renameDocument(const std::string &oldName, const std::string &newName);
|
||||
const std::string &getSubObjectName(bool newStyle) const;
|
||||
const std::string &getSubObjectName() const;
|
||||
|
||||
App::Document *getDocument(String name = String()) const;
|
||||
typedef std::map<std::pair<App::DocumentObject*,std::string>,std::string> SubNameMap;
|
||||
void importSubNames(const SubNameMap &subNameMap);
|
||||
|
||||
bool updateLabelReference(App::DocumentObject *, const std::string &, const char *);
|
||||
|
||||
bool relabeledDocument(ExpressionVisitor &v, const std::string &oldLabel, const std::string &newLabel);
|
||||
|
||||
std::pair<App::DocumentObject*,std::string> getDep(std::vector<std::string> *labels=0) const;
|
||||
|
||||
App::Document *getDocument(String name = String(), bool *ambiguous=0) const;
|
||||
|
||||
App::DocumentObject *getDocumentObject() const;
|
||||
|
||||
|
||||
std::vector<std::string> getStringList() const;
|
||||
|
||||
App::ObjectIdentifier relativeTo(const App::ObjectIdentifier & other) const;
|
||||
|
||||
bool replaceObject(ObjectIdentifier &res, const App::DocumentObject *parent,
|
||||
App::DocumentObject *oldObj, App::DocumentObject *newObj) const;
|
||||
|
||||
// Operators
|
||||
|
||||
App::ObjectIdentifier & operator<<(const Component & value);
|
||||
App::ObjectIdentifier & operator<<(Component &&value);
|
||||
|
||||
bool operator==(const ObjectIdentifier & other) const;
|
||||
|
||||
@@ -224,12 +371,14 @@ public:
|
||||
|
||||
// Getter
|
||||
|
||||
boost::any getValue() const;
|
||||
App::any getValue(bool pathValue=false, bool *isPseudoProperty=0) const;
|
||||
|
||||
Py::Object getPyValue(bool pathValue=false, bool *isPseudoProperty=0) const;
|
||||
|
||||
// Setter; is const because it does not alter the object state,
|
||||
// but does have a aide effect.
|
||||
|
||||
void setValue(const boost::any & value) const;
|
||||
void setValue(const App::any & value) const;
|
||||
|
||||
// Static functions
|
||||
|
||||
@@ -237,6 +386,16 @@ public:
|
||||
|
||||
std::string resolveErrorString() const;
|
||||
|
||||
bool adjustLinks(ExpressionVisitor &v, const std::set<App::DocumentObject *> &inList);
|
||||
|
||||
bool updateElementReference(ExpressionVisitor &v, App::DocumentObject *feature=0, bool reverse=false);
|
||||
|
||||
void resolveAmbiguity();
|
||||
|
||||
bool verify(const App::Property &prop, bool silent=false) const;
|
||||
|
||||
std::size_t hash() const;
|
||||
|
||||
protected:
|
||||
|
||||
struct ResolveResults {
|
||||
@@ -248,29 +407,72 @@ protected:
|
||||
String resolvedDocumentName;
|
||||
App::DocumentObject * resolvedDocumentObject;
|
||||
String resolvedDocumentObjectName;
|
||||
String subObjectName;
|
||||
App::DocumentObject * resolvedSubObject;
|
||||
App::Property * resolvedProperty;
|
||||
std::string propertyName;
|
||||
int propertyType;
|
||||
std::bitset<32> flags;
|
||||
|
||||
std::string resolveErrorString() const;
|
||||
void getProperty(const ObjectIdentifier &oi);
|
||||
};
|
||||
|
||||
std::string getPythonAccessor() const;
|
||||
friend struct ResolveResults;
|
||||
|
||||
App::Property *resolveProperty(const App::DocumentObject *obj,
|
||||
const char *propertyName, App::DocumentObject *&sobj,int &ptype) const;
|
||||
|
||||
void getSubPathStr(std::ostream &ss, const ResolveResults &result, bool toPython=false) const;
|
||||
|
||||
Py::Object access(const ResolveResults &rs, Py::Object *value=0) const;
|
||||
|
||||
void resolve(ResolveResults & results) const;
|
||||
void resolveAmbiguity(ResolveResults &results);
|
||||
|
||||
App::DocumentObject *getDocumentObject(const App::Document *doc, const String &name, bool &byIdentifier) const;
|
||||
static App::DocumentObject *getDocumentObject(
|
||||
const App::Document *doc, const String &name, std::bitset<32> &flags);
|
||||
|
||||
const App::PropertyContainer * owner;
|
||||
App::DocumentObject * owner;
|
||||
String documentName;
|
||||
bool documentNameSet;
|
||||
String documentObjectName;
|
||||
bool documentObjectNameSet;
|
||||
String subObjectName;
|
||||
std::pair<std::string,std::string> shadowSub;
|
||||
std::vector<Component> components;
|
||||
bool documentNameSet;
|
||||
bool documentObjectNameSet;
|
||||
bool localProperty;
|
||||
|
||||
private:
|
||||
std::string _cache; // Cached string represstation of this identifier
|
||||
std::size_t _hash; // Cached hash of this string
|
||||
};
|
||||
|
||||
std::size_t AppExport hash_value(const App::ObjectIdentifier & path);
|
||||
inline std::size_t hash_value(const App::ObjectIdentifier & path) {
|
||||
return path.hash();
|
||||
}
|
||||
|
||||
/** Helper function to convert Python object to/from App::any
|
||||
*
|
||||
* WARNING! Must hold Python global interpreter lock before calling these
|
||||
* functions
|
||||
*/
|
||||
//@{
|
||||
App::any AppExport pyObjectToAny(Py::Object pyobj, bool check=true);
|
||||
Py::Object AppExport pyObjectFromAny(const App::any &value);
|
||||
//@}
|
||||
}
|
||||
|
||||
namespace std {
|
||||
|
||||
template<>
|
||||
struct hash<App::ObjectIdentifier> {
|
||||
typedef App::ObjectIdentifier argument_type;
|
||||
typedef std::size_t result_type;
|
||||
inline result_type operator()(argument_type const& s) const {
|
||||
return s.hash();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
// Std. configurations
|
||||
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Persistence.h>
|
||||
#ifndef BOOST_105400
|
||||
#include <boost/any.hpp>
|
||||
@@ -35,6 +36,9 @@
|
||||
#include <string>
|
||||
#include <bitset>
|
||||
|
||||
namespace Py {
|
||||
class Object;
|
||||
}
|
||||
|
||||
namespace App
|
||||
{
|
||||
@@ -140,6 +144,11 @@ public:
|
||||
/// Get value of property
|
||||
virtual const boost::any getPathValue(const App::ObjectIdentifier & path) const;
|
||||
|
||||
/// Get Python value of property
|
||||
virtual bool getPyPathValue(const App::ObjectIdentifier &, Py::Object &) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Convert p to a canonical representation of it
|
||||
virtual App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier & p) const;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/Writer.h>
|
||||
#include <Base/Reader.h>
|
||||
#include <Base/Tools.h>
|
||||
#include "Expression.h"
|
||||
#include "ExpressionVisitors.h"
|
||||
#include "PropertyExpressionEngine.h"
|
||||
@@ -42,44 +43,44 @@ using namespace App;
|
||||
using namespace Base;
|
||||
using namespace boost;
|
||||
|
||||
class ObjectDeletedExpressionVisitor : public ExpressionVisitor {
|
||||
public:
|
||||
TYPESYSTEM_SOURCE_ABSTRACT(App::PropertyExpressionContainer , App::PropertyXLinkContainer);
|
||||
|
||||
ObjectDeletedExpressionVisitor(const App::DocumentObject * _obj)
|
||||
: obj(_obj)
|
||||
, found(false)
|
||||
{
|
||||
static std::set<PropertyExpressionContainer*> _ExprContainers;
|
||||
|
||||
PropertyExpressionContainer::PropertyExpressionContainer() {
|
||||
static bool inited;
|
||||
if(!inited) {
|
||||
inited = true;
|
||||
GetApplication().signalRelabelDocument.connect(PropertyExpressionContainer::slotRelabelDocument);
|
||||
}
|
||||
_ExprContainers.insert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Visit each node in the expression, and if it is a VariableExpression object check if it references obj
|
||||
* @param node Node to visit
|
||||
*/
|
||||
PropertyExpressionContainer::~PropertyExpressionContainer() {
|
||||
_ExprContainers.erase(this);
|
||||
}
|
||||
|
||||
void visit(Expression * node) {
|
||||
VariableExpression *expr = freecad_dynamic_cast<VariableExpression>(node);
|
||||
|
||||
if (expr && expr->getPath().getDocumentObject() == obj)
|
||||
found = true;
|
||||
void PropertyExpressionContainer::slotRelabelDocument(const App::Document &doc) {
|
||||
// For use a private _ExprContainers to track all living
|
||||
// PropertyExpressionContainer including those inside undo/redo stack,
|
||||
// because document relabel is not undoable/redoable.
|
||||
|
||||
if(doc.getOldLabel() != doc.Label.getValue()) {
|
||||
for(auto prop : _ExprContainers)
|
||||
prop->onRelabeledDocument(doc);
|
||||
}
|
||||
}
|
||||
|
||||
bool isFound() const { return found; }
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
const App::DocumentObject * obj;
|
||||
bool found;
|
||||
};
|
||||
|
||||
TYPESYSTEM_SOURCE(App::PropertyExpressionEngine , App::Property);
|
||||
TYPESYSTEM_SOURCE(App::PropertyExpressionEngine , App::PropertyExpressionContainer);
|
||||
|
||||
/**
|
||||
* @brief Construct a new PropertyExpressionEngine object.
|
||||
*/
|
||||
|
||||
PropertyExpressionEngine::PropertyExpressionEngine()
|
||||
: Property()
|
||||
, AtomicPropertyChangeInterface()
|
||||
, running(false)
|
||||
: running(false)
|
||||
, validator(0)
|
||||
{
|
||||
}
|
||||
@@ -110,81 +111,74 @@ Property *PropertyExpressionEngine::Copy() const
|
||||
PropertyExpressionEngine * engine = new PropertyExpressionEngine();
|
||||
|
||||
for (ExpressionMap::const_iterator it = expressions.begin(); it != expressions.end(); ++it)
|
||||
engine->expressions[it->first] = ExpressionInfo(boost::shared_ptr<Expression>(it->second.expression->copy()), it->second.comment.c_str());
|
||||
engine->expressions[it->first] = ExpressionInfo(boost::shared_ptr<Expression>(it->second.expression->copy()));
|
||||
|
||||
engine->validator = validator;
|
||||
|
||||
return engine;
|
||||
}
|
||||
|
||||
void PropertyExpressionEngine::hasSetValue()
|
||||
{
|
||||
App::DocumentObject *owner = dynamic_cast<App::DocumentObject*>(getContainer());
|
||||
if(!owner || !owner->getNameInDocument() || owner->isRestoring() || testFlag(LinkDetached)) {
|
||||
PropertyExpressionContainer::hasSetValue();
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<App::DocumentObject*> deps;
|
||||
std::vector<std::string> labels;
|
||||
unregisterElementReference();
|
||||
UpdateElementReferenceExpressionVisitor<PropertyExpressionEngine> v(*this);
|
||||
for(auto &e : expressions) {
|
||||
auto expr = e.second.expression;
|
||||
if(expr) {
|
||||
expr->getDepObjects(deps,&labels);
|
||||
if(!restoring)
|
||||
expr->visit(v);
|
||||
}
|
||||
}
|
||||
registerLabelReferences(std::move(labels));
|
||||
|
||||
updateDeps(std::move(deps));
|
||||
|
||||
PropertyExpressionContainer::hasSetValue();
|
||||
}
|
||||
|
||||
void PropertyExpressionEngine::Paste(const Property &from)
|
||||
{
|
||||
const PropertyExpressionEngine * fromee = static_cast<const PropertyExpressionEngine*>(&from);
|
||||
|
||||
AtomicPropertyChange signaller(*this);
|
||||
|
||||
#ifndef USE_OLD_DAG
|
||||
//maintain backlinks, verify that this property is owned by a DocumentObject
|
||||
App::DocumentObject* parent = dynamic_cast<App::DocumentObject*>(getContainer());
|
||||
if (parent) {
|
||||
ExpressionMap::const_iterator i = expressions.begin();
|
||||
while (i != expressions.end()) {
|
||||
std::set<ObjectIdentifier> deps;
|
||||
i->second.expression->getDeps(deps);
|
||||
|
||||
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
|
||||
while (j != deps.end()) {
|
||||
const ObjectIdentifier & p = *j;
|
||||
DocumentObject* docObj = p.getDocumentObject();
|
||||
|
||||
if (docObj && (docObj != parent))
|
||||
docObj->_removeBackLink(parent);
|
||||
|
||||
++j;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
expressions.clear();
|
||||
|
||||
for (ExpressionMap::const_iterator it = fromee->expressions.begin(); it != fromee->expressions.end(); ++it) {
|
||||
expressions[it->first] = ExpressionInfo(boost::shared_ptr<Expression>(it->second.expression->copy()), it->second.comment.c_str());
|
||||
|
||||
#ifndef USE_OLD_DAG
|
||||
if (parent) {
|
||||
//maintain backlinks
|
||||
std::set<ObjectIdentifier> deps;
|
||||
it->second.expression->getDeps(deps);
|
||||
|
||||
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
|
||||
while (j != deps.end()) {
|
||||
const ObjectIdentifier & p = *j;
|
||||
DocumentObject* docObj = p.getDocumentObject();
|
||||
|
||||
if (docObj && (docObj != parent))
|
||||
docObj->_addBackLink(parent);
|
||||
|
||||
++j;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
expressionChanged(it->first);
|
||||
for(auto &e : fromee->expressions) {
|
||||
expressions[e.first] = ExpressionInfo(
|
||||
boost::shared_ptr<Expression>(e.second.expression->copy()));
|
||||
expressionChanged(e.first);
|
||||
}
|
||||
|
||||
validator = fromee->validator;
|
||||
signaller.tryInvoke();
|
||||
}
|
||||
|
||||
void PropertyExpressionEngine::Save(Base::Writer &writer) const
|
||||
{
|
||||
writer.Stream() << writer.ind() << "<ExpressionEngine count=\"" << expressions.size() <<"\">" << std::endl;
|
||||
writer.incInd();
|
||||
writer.Stream() << writer.ind() << "<ExpressionEngine count=\"" << expressions.size();
|
||||
if(PropertyExpressionContainer::_XLinks.empty()) {
|
||||
writer.Stream() << "\">" << std::endl;
|
||||
writer.incInd();
|
||||
} else {
|
||||
writer.Stream() << "\" xlink=\"1\">" << std::endl;
|
||||
writer.incInd();
|
||||
PropertyExpressionContainer::Save(writer);
|
||||
}
|
||||
for (ExpressionMap::const_iterator it = expressions.begin(); it != expressions.end(); ++it) {
|
||||
writer.Stream() << writer.ind() << "<Expression path=\"" << Property::encodeAttribute(it->first.toString()) <<"\"" <<
|
||||
" expression=\"" << Property::encodeAttribute(it->second.expression->toString()) << "\"";
|
||||
if (it->second.comment.size() > 0)
|
||||
writer.Stream() << " comment=\"" << Property::encodeAttribute(it->second.comment) << "\"";
|
||||
writer.Stream() << writer.ind() << "<Expression path=\""
|
||||
<< Property::encodeAttribute(it->first.toString()) <<"\" expression=\""
|
||||
<< Property::encodeAttribute(it->second.expression->toString(true)) << "\"";
|
||||
if (it->second.expression->comment.size() > 0)
|
||||
writer.Stream() << " comment=\""
|
||||
<< Property::encodeAttribute(it->second.expression->comment) << "\"";
|
||||
writer.Stream() << "/>" << std::endl;
|
||||
}
|
||||
writer.decInd();
|
||||
@@ -194,19 +188,22 @@ void PropertyExpressionEngine::Save(Base::Writer &writer) const
|
||||
void PropertyExpressionEngine::Restore(Base::XMLReader &reader)
|
||||
{
|
||||
reader.readElement("ExpressionEngine");
|
||||
|
||||
int count = reader.getAttributeAsFloat("count");
|
||||
|
||||
restoredExpressions.clear();
|
||||
if(reader.hasAttribute("xlink") && reader.getAttributeAsInteger("xlink"))
|
||||
PropertyExpressionContainer::Restore(reader);
|
||||
|
||||
restoredExpressions.reset(new std::vector<RestoredExpression>);
|
||||
restoredExpressions->reserve(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());
|
||||
|
||||
reader.readElement("Expression");
|
||||
ObjectIdentifier path = ObjectIdentifier::parse(docObj, reader.getAttribute("path"));
|
||||
boost::shared_ptr<Expression> expression(ExpressionParser::parse(docObj, reader.getAttribute("expression")));
|
||||
const char * comment = reader.hasAttribute("comment") ? reader.getAttribute("comment") : 0;
|
||||
|
||||
restoredExpressions[path] = ExpressionInfo(expression, comment);
|
||||
restoredExpressions->emplace_back();
|
||||
auto &info = restoredExpressions->back();
|
||||
info.path = reader.getAttribute("path");
|
||||
info.expr = reader.getAttribute("expression");
|
||||
if(reader.hasAttribute("comment"))
|
||||
info.comment = reader.getAttribute("comment");
|
||||
}
|
||||
|
||||
reader.readEndElement("ExpressionEngine");
|
||||
@@ -227,8 +224,6 @@ void PropertyExpressionEngine::buildGraphStructures(const ObjectIdentifier & pat
|
||||
boost::unordered_map<int, ObjectIdentifier> & revNodes,
|
||||
std::vector<Edge> & edges) const
|
||||
{
|
||||
std::set<ObjectIdentifier> deps;
|
||||
|
||||
/* Insert target property into nodes structure */
|
||||
if (nodes.find(path) == nodes.end()) {
|
||||
int s = nodes.size();
|
||||
@@ -239,26 +234,20 @@ void PropertyExpressionEngine::buildGraphStructures(const ObjectIdentifier & pat
|
||||
else
|
||||
revNodes[nodes[path]] = path;
|
||||
|
||||
/* Get the dependencies for this expression */
|
||||
expression->getDeps(deps);
|
||||
|
||||
/* Insert dependencies into nodes structure */
|
||||
std::set<ObjectIdentifier>::const_iterator di = deps.begin();
|
||||
while (di != deps.end()) {
|
||||
Property * prop = di->getProperty();
|
||||
|
||||
if (prop) {
|
||||
ObjectIdentifier cPath(di->canonicalPath());
|
||||
|
||||
if (nodes.find(cPath) == nodes.end()) {
|
||||
int s = nodes.size();
|
||||
|
||||
nodes[cPath] = s;
|
||||
for(auto &dep : expression->getDeps()) {
|
||||
for(auto &info : dep.second) {
|
||||
if(info.first.empty())
|
||||
continue;
|
||||
for(auto &oid : info.second) {
|
||||
ObjectIdentifier cPath(oid.canonicalPath());
|
||||
if (nodes.find(cPath) == nodes.end()) {
|
||||
int s = nodes.size();
|
||||
nodes[cPath] = s;
|
||||
}
|
||||
edges.push_back(std::make_pair(nodes[path], nodes[cPath]));
|
||||
}
|
||||
|
||||
edges.push_back(std::make_pair(nodes[path], nodes[cPath]));
|
||||
}
|
||||
++di;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +257,7 @@ void PropertyExpressionEngine::buildGraphStructures(const ObjectIdentifier & pat
|
||||
* @return New ObjectIdentifier
|
||||
*/
|
||||
|
||||
const ObjectIdentifier PropertyExpressionEngine::canonicalPath(const ObjectIdentifier &p) const
|
||||
ObjectIdentifier PropertyExpressionEngine::canonicalPath(const ObjectIdentifier &p) const
|
||||
{
|
||||
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());
|
||||
|
||||
@@ -276,15 +265,15 @@ const ObjectIdentifier PropertyExpressionEngine::canonicalPath(const ObjectIdent
|
||||
if (!docObj)
|
||||
throw Base::RuntimeError("PropertyExpressionEngine must be owned by a DocumentObject.");
|
||||
|
||||
Property * prop = p.getProperty();
|
||||
int ptype;
|
||||
Property * prop = p.getProperty(&ptype);
|
||||
|
||||
// p pointing to a property...?
|
||||
if (!prop)
|
||||
throw Base::RuntimeError("Property not found");
|
||||
throw Base::RuntimeError(p.resolveErrorString().c_str());
|
||||
|
||||
// ... in the same container as I?
|
||||
if (prop->getContainer() != getContainer())
|
||||
throw Base::RuntimeError("Property does not belong to same container as PropertyExpressionEngine");
|
||||
if(ptype || prop->getContainer()!=getContainer())
|
||||
return p;
|
||||
|
||||
// In case someone calls this with p pointing to a PropertyExpressionEngine for some reason
|
||||
if (prop->isDerivedFrom(PropertyExpressionEngine::classTypeId))
|
||||
@@ -304,61 +293,37 @@ size_t PropertyExpressionEngine::numExpressions() const
|
||||
return expressions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Slot called when a document object is renamed.
|
||||
* @param obj Renamed object
|
||||
*/
|
||||
|
||||
void PropertyExpressionEngine::slotObjectRenamed(const DocumentObject &obj)
|
||||
{
|
||||
#ifdef FC_PROPERTYEXPRESSIONENGINE_LOG
|
||||
std::clog << "Object " << obj.getOldLabel() << " renamed to " << obj.Label.getValue() << std::endl;
|
||||
#endif
|
||||
|
||||
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());
|
||||
|
||||
/* In a document object, and on undo stack? */
|
||||
if (!docObj || docObj->getNameInDocument() == 0)
|
||||
return;
|
||||
|
||||
RelabelDocumentObjectExpressionVisitor<PropertyExpressionEngine> v(*this, obj.getOldLabel(), obj.Label.getStrValue());
|
||||
|
||||
for (ExpressionMap::iterator it = expressions.begin(); it != expressions.end(); ++it) {
|
||||
bool changed = v.getChanged();
|
||||
|
||||
it->second.expression->visit(v);
|
||||
|
||||
if (changed != v.getChanged())
|
||||
expressionChanged(it->first);
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyExpressionEngine::slotObjectDeleted(const DocumentObject &obj)
|
||||
void PropertyExpressionEngine::afterRestore()
|
||||
{
|
||||
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());
|
||||
if(restoredExpressions && docObj) {
|
||||
Base::FlagToggler<bool> flag(restoring);
|
||||
AtomicPropertyChange signaller(*this);
|
||||
|
||||
/* In a document object, and on undo stack? */
|
||||
if (!docObj || docObj->getNameInDocument() == 0)
|
||||
return;
|
||||
PropertyExpressionContainer::afterRestore();
|
||||
ObjectIdentifier::DocumentMapper mapper(this->_DocMap);
|
||||
|
||||
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;
|
||||
for(auto &info : *restoredExpressions) {
|
||||
ObjectIdentifier path = ObjectIdentifier::parse(docObj, info.path);
|
||||
boost::shared_ptr<Expression> expression(Expression::parse(docObj, info.expr.c_str()));
|
||||
if(expression)
|
||||
expression->comment = std::move(info.comment);
|
||||
setValue(path, expression);
|
||||
}
|
||||
signaller.tryInvoke();
|
||||
}
|
||||
restoredExpressions.reset();
|
||||
}
|
||||
|
||||
void PropertyExpressionEngine::onDocumentRestored()
|
||||
{
|
||||
AtomicPropertyChange signaller(*this);
|
||||
|
||||
for (ExpressionMap::iterator it = restoredExpressions.begin(); it != restoredExpressions.end(); ++it)
|
||||
setValue(it->first, it->second.expression, it->second.comment.size() > 0 ? it->second.comment.c_str() : 0);
|
||||
void PropertyExpressionEngine::onContainerRestored() {
|
||||
Base::FlagToggler<bool> flag(restoring);
|
||||
unregisterElementReference();
|
||||
UpdateElementReferenceExpressionVisitor<PropertyExpressionEngine> v(*this);
|
||||
for(auto &e : expressions) {
|
||||
auto expr = e.second.expression;
|
||||
if(expr)
|
||||
expr->visit(v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,7 +352,7 @@ const boost::any PropertyExpressionEngine::getPathValue(const App::ObjectIdentif
|
||||
* @param comment Optional comment.
|
||||
*/
|
||||
|
||||
void PropertyExpressionEngine::setValue(const ObjectIdentifier & path, boost::shared_ptr<Expression> expr, const char *comment)
|
||||
void PropertyExpressionEngine::setValue(const ObjectIdentifier & path, boost::shared_ptr<Expression> expr)
|
||||
{
|
||||
ObjectIdentifier usePath(canonicalPath(path));
|
||||
const Property * prop = usePath.getProperty();
|
||||
@@ -402,83 +367,17 @@ void PropertyExpressionEngine::setValue(const ObjectIdentifier & path, boost::sh
|
||||
|
||||
if (expr) {
|
||||
std::string error = validateExpression(usePath, expr);
|
||||
|
||||
if (error.size() > 0)
|
||||
throw Base::RuntimeError(error.c_str());
|
||||
|
||||
AtomicPropertyChange signaller(*this);
|
||||
#ifndef USE_OLD_DAG
|
||||
// When overriding an ObjectIdentifier key then first remove
|
||||
// the dependency caused by the expression as otherwise it happens
|
||||
// that the same object dependency is added twice for the same
|
||||
// identifier. This makes it impossible to properly clear dependencies
|
||||
// and thus leads to topological errors on recompute.
|
||||
//
|
||||
// Verify that this property is owned by a DocumentObject
|
||||
App::DocumentObject* parent = dynamic_cast<App::DocumentObject*>(getContainer());
|
||||
if (parent) {
|
||||
if (it != expressions.end() && it->second.expression) {
|
||||
std::set<ObjectIdentifier> deps;
|
||||
it->second.expression->getDeps(deps);
|
||||
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
|
||||
while (j != deps.end()) {
|
||||
const ObjectIdentifier & p = *j;
|
||||
DocumentObject* docObj = p.getDocumentObject();
|
||||
if (docObj && (docObj != parent))
|
||||
docObj->_removeBackLink(parent);
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
expressions[usePath] = ExpressionInfo(expr, comment);
|
||||
|
||||
#ifndef USE_OLD_DAG
|
||||
//maintain the backlinks in the documentobject graph datastructure
|
||||
if (parent) {
|
||||
std::set<ObjectIdentifier> deps;
|
||||
expr->getDeps(deps);
|
||||
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
|
||||
while (j != deps.end()) {
|
||||
const ObjectIdentifier & p = *j;
|
||||
DocumentObject* docObj = p.getDocumentObject();
|
||||
if (docObj && (docObj != parent))
|
||||
docObj->_addBackLink(parent);
|
||||
|
||||
++j;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
expressions[usePath] = ExpressionInfo(expr);
|
||||
expressionChanged(usePath);
|
||||
}
|
||||
else {
|
||||
signaller.tryInvoke();
|
||||
} else {
|
||||
AtomicPropertyChange signaller(*this);
|
||||
|
||||
#ifndef USE_OLD_DAG
|
||||
//verify that this property is owned by a DocumentObject
|
||||
//verify that the ObjectIdentifier usePath is part of the expression map and
|
||||
//that the expression is not null
|
||||
App::DocumentObject* parent = dynamic_cast<App::DocumentObject*>(getContainer());
|
||||
if (parent && it != expressions.end() && it->second.expression) {
|
||||
//maintain the backlinks in the documentobject graph datastructure
|
||||
std::set<ObjectIdentifier> deps;
|
||||
it->second.expression->getDeps(deps);
|
||||
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
|
||||
while (j != deps.end()) {
|
||||
const ObjectIdentifier & p = *j;
|
||||
DocumentObject* docObj = p.getDocumentObject();
|
||||
if (docObj && (docObj != parent))
|
||||
docObj->_removeBackLink(parent);
|
||||
|
||||
++j;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
expressions.erase(usePath);
|
||||
expressionChanged(usePath);
|
||||
signaller.tryInvoke();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,14 +408,29 @@ struct cycle_detector : public boost::dfs_visitor<> {
|
||||
*/
|
||||
|
||||
void PropertyExpressionEngine::buildGraph(const ExpressionMap & exprs,
|
||||
boost::unordered_map<int, ObjectIdentifier> & revNodes, DiGraph & g) const
|
||||
boost::unordered_map<int, ObjectIdentifier> & revNodes,
|
||||
DiGraph & g, ExecuteOption option) const
|
||||
{
|
||||
boost::unordered_map<ObjectIdentifier, int> nodes;
|
||||
std::vector<Edge> edges;
|
||||
|
||||
// Build data structure for graph
|
||||
for (ExpressionMap::const_iterator it = exprs.begin(); it != exprs.end(); ++it)
|
||||
for (ExpressionMap::const_iterator it = exprs.begin(); it != exprs.end(); ++it) {
|
||||
if(option!=ExecuteAll) {
|
||||
auto prop = it->first.getProperty();
|
||||
if(!prop)
|
||||
throw Base::RuntimeError("Path does not resolve to a property.");
|
||||
bool is_output = prop->testStatus(App::Property::Output)||(prop->getType()&App::Prop_Output);
|
||||
if((is_output && option==ExecuteNonOutput) || (!is_output && option==ExecuteOutput))
|
||||
continue;
|
||||
if(option == ExecuteOnRestore
|
||||
&& !prop->testStatus(Property::Transient)
|
||||
&& !(prop->getType() & Prop_Transient)
|
||||
&& !prop->testStatus(Property::EvalOnRestore))
|
||||
continue;
|
||||
}
|
||||
buildGraphStructures(it->first, it->second.expression, nodes, revNodes, edges);
|
||||
}
|
||||
|
||||
// Create graph
|
||||
g = DiGraph(revNodes.size());
|
||||
@@ -544,13 +458,13 @@ void PropertyExpressionEngine::buildGraph(const ExpressionMap & exprs,
|
||||
* order, in case properties depends on each other.
|
||||
*/
|
||||
|
||||
std::vector<App::ObjectIdentifier> PropertyExpressionEngine::computeEvaluationOrder()
|
||||
std::vector<App::ObjectIdentifier> PropertyExpressionEngine::computeEvaluationOrder(ExecuteOption option)
|
||||
{
|
||||
std::vector<App::ObjectIdentifier> evaluationOrder;
|
||||
boost::unordered_map<int, ObjectIdentifier> revNodes;
|
||||
DiGraph g;
|
||||
|
||||
buildGraph(expressions, revNodes, g);
|
||||
buildGraph(expressions, revNodes, g, option);
|
||||
|
||||
/* Compute evaluation order for expressions */
|
||||
std::vector<int> c;
|
||||
@@ -569,7 +483,7 @@ std::vector<App::ObjectIdentifier> PropertyExpressionEngine::computeEvaluationOr
|
||||
* @return StdReturn on success.
|
||||
*/
|
||||
|
||||
DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
|
||||
DocumentObjectExecReturn *App::PropertyExpressionEngine::execute(ExecuteOption option, bool *touched)
|
||||
{
|
||||
DocumentObject * docObj = freecad_dynamic_cast<DocumentObject>(getContainer());
|
||||
|
||||
@@ -579,6 +493,24 @@ DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
|
||||
if (running)
|
||||
return DocumentObject::StdReturn;
|
||||
|
||||
if(option == ExecuteOnRestore) {
|
||||
bool found = false;
|
||||
for(auto &e : expressions) {
|
||||
auto prop = e.first.getProperty();
|
||||
if(!prop)
|
||||
continue;
|
||||
if(prop->testStatus(App::Property::Transient)
|
||||
|| (prop->getType()&App::Prop_Transient)
|
||||
|| prop->testStatus(App::Property::EvalOnRestore))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
return DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
/* Resetter class, to ensure that the "running" variable gets set to false, even if
|
||||
* an exception is thrown.
|
||||
*/
|
||||
@@ -595,7 +527,7 @@ DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
|
||||
resetter r(running);
|
||||
|
||||
// Compute evaluation order
|
||||
std::vector<App::ObjectIdentifier> evaluationOrder = computeEvaluationOrder();
|
||||
std::vector<App::ObjectIdentifier> evaluationOrder = computeEvaluationOrder(option);
|
||||
std::vector<ObjectIdentifier>::const_iterator it = evaluationOrder.begin();
|
||||
|
||||
#ifdef FC_PROPERTYEXPRESSIONENGINE_LOG
|
||||
@@ -603,7 +535,7 @@ DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
|
||||
#endif
|
||||
|
||||
/* Evaluate the expressions, and update properties */
|
||||
while (it != evaluationOrder.end()) {
|
||||
for (;it != evaluationOrder.end();++it) {
|
||||
|
||||
// Get property to update
|
||||
Property * prop = it->getProperty();
|
||||
@@ -617,69 +549,28 @@ DocumentObjectExecReturn *App::PropertyExpressionEngine::execute()
|
||||
if (parent != docObj)
|
||||
throw Base::RuntimeError("Invalid property owner.");
|
||||
|
||||
// Evaluate expression
|
||||
std::unique_ptr<Expression> e(expressions[*it].expression->eval());
|
||||
|
||||
#ifdef FC_PROPERTYEXPRESSIONENGINE_LOG
|
||||
{
|
||||
Base::Quantity q;
|
||||
boost::any value = e->getValueAsAny();
|
||||
|
||||
if (value.type() == typeid(Base::Quantity))
|
||||
q = boost::any_cast<Base::Quantity>(value);
|
||||
else if (value.type() == typeid(double))
|
||||
q = boost::any_cast<double>(value);
|
||||
else {
|
||||
std::clog << "Unknown return value for expression.";
|
||||
q = 0;
|
||||
}
|
||||
|
||||
std::clog << "Assigning value " << q.getValue() << " to " << (*it).toString().c_str() << " (" << prop->getName() << ")" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Set value of property */
|
||||
prop->setPathValue(*it, e->getValueAsAny());
|
||||
|
||||
++it;
|
||||
try {
|
||||
// Evaluate expression
|
||||
std::unique_ptr<Expression> e(expressions[*it].expression->eval());
|
||||
auto value = e->getValueAsAny();
|
||||
if(option == ExecuteOnRestore && prop->testStatus(Property::EvalOnRestore)) {
|
||||
if(isAnyEqual(value, prop->getPathValue(*it)))
|
||||
continue;
|
||||
if(touched)
|
||||
*touched = true;
|
||||
}
|
||||
prop->setPathValue(*it, value);
|
||||
}catch(Base::Exception &e) {
|
||||
std::ostringstream ss;
|
||||
ss << e.what() << std::endl << "in property binding '" << prop->getName() << "'";
|
||||
e.setMessage(ss.str());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return DocumentObject::StdReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find document objects that the expressions depend on.
|
||||
* @param docObjs Dependencies
|
||||
*/
|
||||
|
||||
void PropertyExpressionEngine::getDocumentObjectDeps(std::vector<DocumentObject *> &docObjs) const
|
||||
{
|
||||
DocumentObject * owner = freecad_dynamic_cast<DocumentObject>(getContainer());
|
||||
|
||||
if (owner == 0)
|
||||
return;
|
||||
|
||||
ExpressionMap::const_iterator i = expressions.begin();
|
||||
|
||||
while (i != expressions.end()) {
|
||||
std::set<ObjectIdentifier> deps;
|
||||
|
||||
i->second.expression->getDeps(deps);
|
||||
|
||||
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
|
||||
|
||||
while (j != deps.end()) {
|
||||
const ObjectIdentifier & p = *j;
|
||||
DocumentObject* docObj = p.getDocumentObject();
|
||||
|
||||
if (docObj && docObj != owner)
|
||||
docObjs.push_back(docObj);
|
||||
|
||||
++j;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find paths to document object.
|
||||
* @param obj Document object
|
||||
@@ -691,30 +582,16 @@ void PropertyExpressionEngine::getPathsToDocumentObject(DocumentObject* obj,
|
||||
{
|
||||
DocumentObject * owner = freecad_dynamic_cast<DocumentObject>(getContainer());
|
||||
|
||||
if (owner == 0)
|
||||
if (owner == 0 || owner==obj)
|
||||
return;
|
||||
|
||||
ExpressionMap::const_iterator i = expressions.begin();
|
||||
|
||||
while (i != expressions.end()) {
|
||||
std::set<ObjectIdentifier> deps;
|
||||
|
||||
i->second.expression->getDeps(deps);
|
||||
|
||||
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
|
||||
|
||||
while (j != deps.end()) {
|
||||
const ObjectIdentifier & p = *j;
|
||||
DocumentObject* docObj = p.getDocumentObject();
|
||||
|
||||
if (docObj == obj && docObj != owner) {
|
||||
paths.push_back(i->first);
|
||||
break;
|
||||
}
|
||||
|
||||
++j;
|
||||
}
|
||||
++i;
|
||||
for(auto &v : expressions) {
|
||||
const auto &deps = v.second.expression->getDeps();
|
||||
auto it = deps.find(obj);
|
||||
if(it==deps.end())
|
||||
continue;
|
||||
for(auto &dep : it->second)
|
||||
paths.insert(paths.end(),dep.second.begin(),dep.second.end());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -725,48 +602,12 @@ void PropertyExpressionEngine::getPathsToDocumentObject(DocumentObject* obj,
|
||||
|
||||
bool PropertyExpressionEngine::depsAreTouched() const
|
||||
{
|
||||
ExpressionMap::const_iterator i = expressions.begin();
|
||||
|
||||
while (i != expressions.end()) {
|
||||
std::set<ObjectIdentifier> deps;
|
||||
|
||||
i->second.expression->getDeps(deps);
|
||||
|
||||
std::set<ObjectIdentifier>::const_iterator j = deps.begin();
|
||||
|
||||
while (j != deps.end()) {
|
||||
const ObjectIdentifier & p = *j;
|
||||
Property* prop = p.getProperty();
|
||||
|
||||
if (prop && prop->isTouched())
|
||||
return true;
|
||||
|
||||
++j;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
for(auto obj : _Deps)
|
||||
if(obj->isTouched())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a map of all registered expressions.
|
||||
* @return Map of expressions.
|
||||
*/
|
||||
|
||||
boost::unordered_map<const ObjectIdentifier, const PropertyExpressionEngine::ExpressionInfo> PropertyExpressionEngine::getExpressions() const
|
||||
{
|
||||
boost::unordered_map<const ObjectIdentifier, const ExpressionInfo> result;
|
||||
|
||||
ExpressionMap::const_iterator i = expressions.begin();
|
||||
while (i != expressions.end()) {
|
||||
result.insert(std::make_pair(i->first, i->second));
|
||||
++i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Validate the given path and expression.
|
||||
* @param path Object Identifier for expression.
|
||||
@@ -785,33 +626,16 @@ std::string PropertyExpressionEngine::validateExpression(const ObjectIdentifier
|
||||
return error;
|
||||
}
|
||||
|
||||
// Get dependencies from expression
|
||||
std::set<App::ObjectIdentifier> exprDeps;
|
||||
expr->getDeps(exprDeps);
|
||||
|
||||
// Get document object
|
||||
DocumentObject * pathDocObj = usePath.getDocumentObject();
|
||||
assert(pathDocObj);
|
||||
|
||||
// Check for document object dependencies
|
||||
for (std::set<App::ObjectIdentifier>::const_iterator j = exprDeps.begin(); j != exprDeps.end(); ++j) {
|
||||
DocumentObject * docObj = (*j).getDocumentObject();
|
||||
|
||||
// Skip internal dependencies;
|
||||
if (docObj == pathDocObj)
|
||||
continue;
|
||||
|
||||
// Get dependencies for the document object pointed to be *j
|
||||
std::vector<DocumentObject*> targets;
|
||||
targets.push_back(docObj);
|
||||
|
||||
// Does the dependency resolve to a document? If not, ignore it
|
||||
if ((*j).getDocument()) {
|
||||
std::vector<DocumentObject*> deps = (*j).getDocument()->getDependencyList(targets);
|
||||
|
||||
for (std::vector<DocumentObject*>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
|
||||
if (*i == pathDocObj)
|
||||
return (*j).toString() + " reference creates a cyclic dependency.";
|
||||
}
|
||||
auto inList = pathDocObj->getInListEx(true);
|
||||
for(auto docObj : expr->getDepObjects()) {
|
||||
if(inList.count(docObj)) {
|
||||
std::stringstream ss;
|
||||
ss << "cyclic reference to " << docObj->getFullName();
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,3 +723,181 @@ void PropertyExpressionEngine::setPyObject(PyObject *)
|
||||
{
|
||||
throw Base::RuntimeError("Property is read-only");
|
||||
}
|
||||
|
||||
/* The policy implemented in the following function is to auto erase binding in
|
||||
* case linked object is gone. I think it is better to cause error and get
|
||||
* user's attension
|
||||
*
|
||||
void PropertyExpressionEngine::breakLink(App::DocumentObject *obj, bool clear) {
|
||||
auto owner = dynamic_cast<App::DocumentObject*>(getContainer());
|
||||
if(!owner)
|
||||
return;
|
||||
if(_Deps.count(obj)==0 && (!clear || obj!=owner || _Deps.empty()))
|
||||
return;
|
||||
AtomicPropertyChange signaler(*this);
|
||||
for(auto it=expressions.begin(),itNext=it;it!=expressions.end();it=itNext) {
|
||||
++itNext;
|
||||
const auto &deps = it->second.expression->getDepObjects();
|
||||
if(clear) {
|
||||
// here means we are breaking all expression, except those that has
|
||||
// no depdenecy or self dependency
|
||||
if(deps.empty() || (deps.size()==1 && *deps.begin()==owner))
|
||||
continue;
|
||||
}else if(!deps.count(obj))
|
||||
continue;
|
||||
auto path = it->first;
|
||||
expressions.erase(it);
|
||||
expressionChanged(path);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
bool PropertyExpressionEngine::adjustLink(const std::set<DocumentObject*> &inList) {
|
||||
auto owner = dynamic_cast<App::DocumentObject*>(getContainer());
|
||||
if(!owner)
|
||||
return false;
|
||||
bool found = false;
|
||||
for(auto obj : _Deps) {
|
||||
if(inList.count(obj)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
return false;
|
||||
|
||||
AtomicPropertyChange signaler(*this);
|
||||
for(auto &v : expressions) {
|
||||
try {
|
||||
if(v.second.expression->adjustLinks(inList))
|
||||
expressionChanged(v.first);
|
||||
}catch(Base::Exception &e) {
|
||||
std::ostringstream ss;
|
||||
ss << "Failed to adjust link for " << owner->getFullName() << " in expression "
|
||||
<< v.second.expression->toString() << ": " << e.what();
|
||||
throw Base::RuntimeError(ss.str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PropertyExpressionEngine::updateElementReference(DocumentObject *feature, bool reverse, bool notify)
|
||||
{
|
||||
(void)notify;
|
||||
if(!feature)
|
||||
unregisterElementReference();
|
||||
UpdateElementReferenceExpressionVisitor<PropertyExpressionEngine> v(*this,feature,reverse);
|
||||
for(auto &e : expressions) {
|
||||
e.second.expression->visit(v);
|
||||
if(v.changed()) {
|
||||
expressionChanged(e.first);
|
||||
v.reset();
|
||||
}
|
||||
}
|
||||
if(feature && v.changed()) {
|
||||
auto owner = dynamic_cast<App::DocumentObject*>(getContainer());
|
||||
if(owner)
|
||||
owner->onUpdateElementReference(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertyExpressionEngine::referenceChanged() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
Property *PropertyExpressionEngine::CopyOnImportExternal(
|
||||
const std::map<std::string,std::string> &nameMap) const
|
||||
{
|
||||
std::unique_ptr<PropertyExpressionEngine> engine;
|
||||
for(auto it=expressions.begin();it!=expressions.end();++it) {
|
||||
boost::shared_ptr<Expression> expr(it->second.expression->importSubNames(nameMap));
|
||||
if(!expr && !engine)
|
||||
continue;
|
||||
if(!engine) {
|
||||
engine.reset(new PropertyExpressionEngine);
|
||||
for(auto it2=expressions.begin();it2!=it;++it2) {
|
||||
engine->expressions[it2->first] = ExpressionInfo(
|
||||
boost::shared_ptr<Expression>(it2->second.expression->copy()));
|
||||
}
|
||||
}else if(!expr)
|
||||
expr = it->second.expression;
|
||||
engine->expressions[it->first] = ExpressionInfo(expr);
|
||||
}
|
||||
if(!engine)
|
||||
return 0;
|
||||
engine->validator = validator;
|
||||
return engine.release();
|
||||
}
|
||||
|
||||
Property *PropertyExpressionEngine::CopyOnLabelChange(App::DocumentObject *obj,
|
||||
const std::string &ref, const char *newLabel) const
|
||||
{
|
||||
std::unique_ptr<PropertyExpressionEngine> engine;
|
||||
for(auto it=expressions.begin();it!=expressions.end();++it) {
|
||||
boost::shared_ptr<Expression> expr(it->second.expression->updateLabelReference(obj,ref,newLabel));
|
||||
if(!expr && !engine)
|
||||
continue;
|
||||
if(!engine) {
|
||||
engine.reset(new PropertyExpressionEngine);
|
||||
for(auto it2=expressions.begin();it2!=it;++it2) {
|
||||
engine->expressions[it2->first] = ExpressionInfo(
|
||||
boost::shared_ptr<Expression>(it2->second.expression->copy()));
|
||||
}
|
||||
}else if(!expr)
|
||||
expr = it->second.expression;
|
||||
engine->expressions[it->first] = ExpressionInfo(expr);
|
||||
}
|
||||
if(!engine)
|
||||
return 0;
|
||||
engine->validator = validator;
|
||||
return engine.release();
|
||||
}
|
||||
|
||||
Property *PropertyExpressionEngine::CopyOnLinkReplace(const App::DocumentObject *parent,
|
||||
App::DocumentObject *oldObj, App::DocumentObject *newObj) const
|
||||
{
|
||||
std::unique_ptr<PropertyExpressionEngine> engine;
|
||||
for(auto it=expressions.begin();it!=expressions.end();++it) {
|
||||
boost::shared_ptr<Expression> expr(
|
||||
it->second.expression->replaceObject(parent,oldObj,newObj));
|
||||
if(!expr && !engine)
|
||||
continue;
|
||||
if(!engine) {
|
||||
engine.reset(new PropertyExpressionEngine);
|
||||
for(auto it2=expressions.begin();it2!=it;++it2) {
|
||||
engine->expressions[it2->first] = ExpressionInfo(
|
||||
boost::shared_ptr<Expression>(it2->second.expression->copy()));
|
||||
}
|
||||
}else if(!expr)
|
||||
expr = it->second.expression;
|
||||
engine->expressions[it->first] = ExpressionInfo(expr);
|
||||
}
|
||||
if(!engine)
|
||||
return 0;
|
||||
engine->validator = validator;
|
||||
return engine.release();
|
||||
}
|
||||
|
||||
std::map<App::ObjectIdentifier, const App::Expression*>
|
||||
PropertyExpressionEngine::getExpressions() const
|
||||
{
|
||||
std::map<App::ObjectIdentifier, const Expression*> res;
|
||||
for(auto &v : expressions)
|
||||
res[v.first] = v.second.expression.get();
|
||||
return res;
|
||||
}
|
||||
|
||||
void PropertyExpressionEngine::setExpressions(
|
||||
std::map<App::ObjectIdentifier, App::ExpressionPtr> &&exprs)
|
||||
{
|
||||
AtomicPropertyChange signaller(*this);
|
||||
for(auto &v : exprs)
|
||||
setValue(v.first,std::move(v.second));
|
||||
}
|
||||
|
||||
void PropertyExpressionEngine::onRelabeledDocument(const App::Document &doc)
|
||||
{
|
||||
RelabelDocumentExpressionVisitor v(doc);
|
||||
for(auto &e : expressions)
|
||||
e.second.expression->visit(v);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <boost/signals2.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/topological_sort.hpp>
|
||||
#include <App/Property.h>
|
||||
#include <App/PropertyLinks.h>
|
||||
#include <App/Expression.h>
|
||||
#include <set>
|
||||
|
||||
@@ -44,11 +44,38 @@ class DocumentObjectExecReturn;
|
||||
class ObjectIdentifier;
|
||||
class Expression;
|
||||
|
||||
|
||||
class AppExport PropertyExpressionEngine : public App::Property, private App::AtomicPropertyChangeInterface<PropertyExpressionEngine>
|
||||
class AppExport PropertyExpressionContainer : public App::PropertyXLinkContainer
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
PropertyExpressionContainer();
|
||||
virtual ~PropertyExpressionContainer();
|
||||
|
||||
virtual std::map<App::ObjectIdentifier, const App::Expression*> getExpressions() const = 0;
|
||||
virtual void setExpressions(std::map<App::ObjectIdentifier, App::ExpressionPtr> &&exprs) = 0;
|
||||
|
||||
protected:
|
||||
virtual void onRelabeledDocument(const App::Document &doc) = 0;
|
||||
|
||||
private:
|
||||
static void slotRelabelDocument(const App::Document &doc);
|
||||
};
|
||||
|
||||
class AppExport PropertyExpressionEngine : public App::PropertyExpressionContainer,
|
||||
private App::AtomicPropertyChangeInterface<PropertyExpressionEngine>
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
|
||||
virtual void updateElementReference(
|
||||
App::DocumentObject *feature, bool reverse=false, bool notify=false) override;
|
||||
virtual bool referenceChanged() const override;
|
||||
virtual bool adjustLink(const std::set<App::DocumentObject *> &inList) override;
|
||||
virtual Property *CopyOnImportExternal(const std::map<std::string,std::string> &nameMap) const override;
|
||||
virtual Property *CopyOnLabelChange(App::DocumentObject *obj,
|
||||
const std::string &ref, const char *newLabel) const override;
|
||||
virtual Property *CopyOnLinkReplace(const App::DocumentObject *parent,
|
||||
App::DocumentObject *oldObj, App::DocumentObject *newObj) const override;
|
||||
|
||||
typedef boost::function<std::string (const App::ObjectIdentifier & path, boost::shared_ptr<const App::Expression> expr)> ValidatorFunc;
|
||||
|
||||
@@ -58,22 +85,17 @@ public:
|
||||
|
||||
struct ExpressionInfo {
|
||||
boost::shared_ptr<App::Expression> expression; /**< The actual expression tree */
|
||||
std::string comment; /**< Optional comment for this expression */
|
||||
|
||||
ExpressionInfo(boost::shared_ptr<App::Expression> expression = boost::shared_ptr<App::Expression>(), const char * comment = 0) {
|
||||
ExpressionInfo(boost::shared_ptr<App::Expression> expression = boost::shared_ptr<App::Expression>()) {
|
||||
this->expression = expression;
|
||||
if (comment)
|
||||
this->comment = comment;
|
||||
}
|
||||
|
||||
ExpressionInfo(const ExpressionInfo & other) {
|
||||
expression = other.expression;
|
||||
comment = other.comment;
|
||||
}
|
||||
|
||||
ExpressionInfo & operator=(const ExpressionInfo & other) {
|
||||
expression = other.expression;
|
||||
comment = other.comment;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
@@ -83,6 +105,10 @@ public:
|
||||
|
||||
unsigned int getMemSize (void) const;
|
||||
|
||||
virtual std::map<App::ObjectIdentifier, const App::Expression*> getExpressions() const override;
|
||||
virtual void setExpressions(std::map<App::ObjectIdentifier, App::ExpressionPtr> &&exprs) override;
|
||||
virtual void onRelabeledDocument(const App::Document &doc) override;
|
||||
|
||||
void setValue() { } // Dummy
|
||||
|
||||
Property *Copy(void) const;
|
||||
@@ -93,20 +119,31 @@ public:
|
||||
|
||||
void Restore(Base::XMLReader &reader);
|
||||
|
||||
void setValue(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr, const char * comment = 0);
|
||||
void setValue(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr);
|
||||
|
||||
const boost::any getPathValue(const App::ObjectIdentifier & path) const;
|
||||
|
||||
DocumentObjectExecReturn * execute();
|
||||
|
||||
void getDocumentObjectDeps(std::vector<DocumentObject*> & docObjs) const;
|
||||
/// Execute options
|
||||
enum ExecuteOption {
|
||||
/// Execute all expression
|
||||
ExecuteAll,
|
||||
/// Execute only output property bindings
|
||||
ExecuteOutput,
|
||||
/// Execute only non-output property bindings
|
||||
ExecuteNonOutput,
|
||||
/// Execute on document restore
|
||||
ExecuteOnRestore,
|
||||
};
|
||||
/** Evaluate the expressions
|
||||
*
|
||||
* @param option: execution option, see ExecuteOption.
|
||||
*/
|
||||
DocumentObjectExecReturn * execute(ExecuteOption option=ExecuteAll, bool *touched=0);
|
||||
|
||||
void getPathsToDocumentObject(DocumentObject*, std::vector<App::ObjectIdentifier> & paths) const;
|
||||
|
||||
bool depsAreTouched() const;
|
||||
|
||||
boost::unordered_map<const App::ObjectIdentifier, const ExpressionInfo> getExpressions() const;
|
||||
|
||||
/* Expression validator */
|
||||
void setValidator(ValidatorFunc f) { validator = f; }
|
||||
|
||||
@@ -116,45 +153,53 @@ public:
|
||||
|
||||
void renameObjectIdentifiers(const std::map<App::ObjectIdentifier, App::ObjectIdentifier> & paths);
|
||||
|
||||
const App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier &p) const;
|
||||
App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier &p) const;
|
||||
|
||||
size_t numExpressions() const;
|
||||
|
||||
void slotObjectRenamed(const App::DocumentObject & obj);
|
||||
|
||||
void slotObjectDeleted(const DocumentObject &obj);
|
||||
|
||||
///signal called when an expression was changed
|
||||
boost::signals2::signal<void (const App::ObjectIdentifier &)> expressionChanged;
|
||||
|
||||
void onDocumentRestored();
|
||||
virtual void afterRestore() override;
|
||||
virtual void onContainerRestored() override;
|
||||
|
||||
/* Python interface */
|
||||
PyObject *getPyObject(void);
|
||||
void setPyObject(PyObject *);
|
||||
|
||||
protected:
|
||||
virtual void hasSetValue() override;
|
||||
|
||||
private:
|
||||
|
||||
typedef boost::adjacency_list< boost::listS, boost::vecS, boost::directedS > DiGraph;
|
||||
typedef std::pair<int, int> Edge;
|
||||
typedef boost::unordered_map<const App::ObjectIdentifier, ExpressionInfo> ExpressionMap;
|
||||
|
||||
std::vector<App::ObjectIdentifier> computeEvaluationOrder();
|
||||
std::vector<App::ObjectIdentifier> computeEvaluationOrder(ExecuteOption option);
|
||||
|
||||
void buildGraphStructures(const App::ObjectIdentifier &path,
|
||||
const boost::shared_ptr<Expression> expression, boost::unordered_map<App::ObjectIdentifier, int> &nodes,
|
||||
boost::unordered_map<int, App::ObjectIdentifier> &revNodes, std::vector<Edge> &edges) const;
|
||||
|
||||
void buildGraph(const ExpressionMap &exprs,
|
||||
boost::unordered_map<int, App::ObjectIdentifier> &revNodes, DiGraph &g) const;
|
||||
boost::unordered_map<int, App::ObjectIdentifier> &revNodes,
|
||||
DiGraph &g, ExecuteOption option=ExecuteAll) const;
|
||||
|
||||
bool running; /**< Boolean used to avoid loops */
|
||||
bool restoring = false;
|
||||
|
||||
ExpressionMap expressions; /**< Stored expressions */
|
||||
|
||||
ValidatorFunc validator; /**< Valdiator functor */
|
||||
|
||||
ExpressionMap restoredExpressions; /**< Expressions are read from file to this map first before they are validated and inserted into the actual map */
|
||||
struct RestoredExpression {
|
||||
std::string path;
|
||||
std::string expr;
|
||||
std::string comment;
|
||||
};
|
||||
/**< Expressions are read from file to this map first before they are validated and inserted into the actual map */
|
||||
std::unique_ptr<std::vector<RestoredExpression> > restoredExpressions;
|
||||
|
||||
friend class AtomicPropertyChange;
|
||||
|
||||
|
||||
+83
-66
@@ -39,7 +39,10 @@
|
||||
#include <Base/VectorPy.h>
|
||||
#include <Base/MatrixPy.h>
|
||||
#include <Base/PlacementPy.h>
|
||||
#include <Base/QuantityPy.h>
|
||||
|
||||
#include "Document.h"
|
||||
#include "DocumentObject.h"
|
||||
#include "Placement.h"
|
||||
#include "PropertyGeo.h"
|
||||
#include "ObjectIdentifier.h"
|
||||
@@ -193,14 +196,46 @@ void PropertyVector::Paste(const Property &from)
|
||||
|
||||
void PropertyVector::getPaths(std::vector<ObjectIdentifier> &paths) const
|
||||
{
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("x")));
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("y")));
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("z")));
|
||||
paths.push_back(ObjectIdentifier(*this)
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("x")));
|
||||
paths.push_back(ObjectIdentifier(*this)
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("y")));
|
||||
paths.push_back(ObjectIdentifier(*this)
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("z")));
|
||||
}
|
||||
|
||||
const boost::any PropertyVector::getPathValue(const ObjectIdentifier &path) const
|
||||
{
|
||||
Base::Unit unit = getUnit();
|
||||
if(!unit.isEmpty()) {
|
||||
std::string p = path.getSubPathStr();
|
||||
if (p == ".x" || p == ".y" || p == ".z") {
|
||||
// Convert double to quantity
|
||||
return Base::Quantity(boost::any_cast<double>(Property::getPathValue(path)), unit);
|
||||
}
|
||||
}
|
||||
return Property::getPathValue(path);
|
||||
}
|
||||
|
||||
bool PropertyVector::getPyPathValue(const ObjectIdentifier &path, Py::Object &res) const
|
||||
{
|
||||
Base::Unit unit = getUnit();
|
||||
if(unit.isEmpty())
|
||||
return false;
|
||||
|
||||
std::string p = path.getSubPathStr();
|
||||
if (p == ".x") {
|
||||
res = new QuantityPy(new Quantity(getValue().x,unit));
|
||||
} else if(p == ".y") {
|
||||
res = new QuantityPy(new Quantity(getValue().y,unit));
|
||||
} else if(p == ".z") {
|
||||
res = new QuantityPy(new Quantity(getValue().z,unit));
|
||||
} else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// PropertyVectorDistance
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@@ -216,18 +251,6 @@ PropertyVectorDistance::PropertyVectorDistance()
|
||||
|
||||
}
|
||||
|
||||
const boost::any PropertyVectorDistance::getPathValue(const ObjectIdentifier &path) const
|
||||
{
|
||||
std::string p = path.getSubPathStr();
|
||||
|
||||
if (p == ".x" || p == ".y" || p == ".z") {
|
||||
// Convert double to quantity
|
||||
return Base::Quantity(boost::any_cast<double>(Property::getPathValue(path)), Unit::Length);
|
||||
}
|
||||
else
|
||||
return Property::getPathValue(path);
|
||||
}
|
||||
|
||||
PropertyVectorDistance::~PropertyVectorDistance()
|
||||
{
|
||||
|
||||
@@ -253,18 +276,6 @@ PropertyPosition::~PropertyPosition()
|
||||
|
||||
}
|
||||
|
||||
const boost::any PropertyPosition::getPathValue(const ObjectIdentifier &path) const
|
||||
{
|
||||
std::string p = path.getSubPathStr();
|
||||
|
||||
if (p == ".x" || p == ".y" || p == ".z") {
|
||||
// Convert double to quantity
|
||||
return Base::Quantity(boost::any_cast<double>(Property::getPathValue(path)), Unit::Length);
|
||||
}
|
||||
else
|
||||
return Property::getPathValue(path);
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// PropertyPosition
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@@ -285,18 +296,6 @@ PropertyDirection::~PropertyDirection()
|
||||
|
||||
}
|
||||
|
||||
const boost::any PropertyDirection::getPathValue(const ObjectIdentifier &path) const
|
||||
{
|
||||
std::string p = path.getSubPathStr();
|
||||
|
||||
if (p == ".x" || p == ".y" || p == ".z") {
|
||||
// Convert double to quantity
|
||||
return Base::Quantity(boost::any_cast<double>(Property::getPathValue(path)), Unit::Length);
|
||||
}
|
||||
else
|
||||
return Property::getPathValue(path);
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// PropertyVectorList
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
@@ -601,30 +600,30 @@ const Base::Placement & PropertyPlacement::getValue(void)const
|
||||
|
||||
void PropertyPlacement::getPaths(std::vector<ObjectIdentifier> &paths) const
|
||||
{
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Base"))
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("x")));
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Base"))
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("y")));
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Base"))
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("z")));
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Rotation"))
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Angle")));
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Rotation"))
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Axis"))
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("x")));
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Rotation"))
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Axis"))
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("y")));
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Rotation"))
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("Axis"))
|
||||
<< ObjectIdentifier::Component::SimpleComponent(ObjectIdentifier::String("z")));
|
||||
paths.push_back(ObjectIdentifier(*this)
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Base"))
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("x")));
|
||||
paths.push_back(ObjectIdentifier(*this)
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Base"))
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("y")));
|
||||
paths.push_back(ObjectIdentifier(*this)
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Base"))
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("z")));
|
||||
paths.push_back(ObjectIdentifier(*this)
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Angle")));
|
||||
paths.push_back(ObjectIdentifier(*this)
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("x")));
|
||||
paths.push_back(ObjectIdentifier(*this)
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("y")));
|
||||
paths.push_back(ObjectIdentifier(*this)
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Rotation"))
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("Axis"))
|
||||
<< ObjectIdentifier::SimpleComponent(ObjectIdentifier::String("z")));
|
||||
}
|
||||
|
||||
void PropertyPlacement::setPathValue(const ObjectIdentifier &path, const boost::any &value)
|
||||
@@ -669,6 +668,24 @@ const boost::any PropertyPlacement::getPathValue(const ObjectIdentifier &path) c
|
||||
return Property::getPathValue(path);
|
||||
}
|
||||
|
||||
bool PropertyPlacement::getPyPathValue(const ObjectIdentifier &path, Py::Object &res) const
|
||||
{
|
||||
std::string p = path.getSubPathStr();
|
||||
if (p == ".Rotation.Angle") {
|
||||
Base::Vector3d axis; double angle;
|
||||
_cPos.getRotation().getValue(axis,angle);
|
||||
res = new QuantityPy(new Quantity(Base::toDegrees(angle),Unit::Angle));
|
||||
} else if (p == ".Base.x") {
|
||||
res = new QuantityPy(new Quantity(_cPos.getPosition().x,Unit::Length));
|
||||
} else if (p == ".Base.y") {
|
||||
res = new QuantityPy(new Quantity(_cPos.getPosition().y,Unit::Length));
|
||||
} else if (p == ".Base.z") {
|
||||
res = new QuantityPy(new Quantity(_cPos.getPosition().z,Unit::Length));
|
||||
} else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
PyObject *PropertyPlacement::getPyObject(void)
|
||||
{
|
||||
return new Base::PlacementPy(new Base::Placement(_cPos));
|
||||
|
||||
+21
-4
@@ -30,6 +30,7 @@
|
||||
#include <Base/Matrix.h>
|
||||
#include <Base/BoundBox.h>
|
||||
#include <Base/Placement.h>
|
||||
#include <Base/Unit.h>
|
||||
|
||||
#include "Property.h"
|
||||
#include "PropertyLinks.h"
|
||||
@@ -98,6 +99,14 @@ public:
|
||||
return sizeof(Base::Vector3d);
|
||||
}
|
||||
|
||||
virtual const boost::any getPathValue(const ObjectIdentifier &path) const override;
|
||||
|
||||
virtual bool getPyPathValue(const ObjectIdentifier &path, Py::Object &res) const override;
|
||||
|
||||
virtual Base::Unit getUnit() const {
|
||||
return Base::Unit();
|
||||
}
|
||||
|
||||
private:
|
||||
Base::Vector3d _cVec;
|
||||
};
|
||||
@@ -120,7 +129,9 @@ public:
|
||||
*/
|
||||
virtual ~PropertyVectorDistance();
|
||||
|
||||
const boost::any getPathValue(const ObjectIdentifier &path) const;
|
||||
virtual Base::Unit getUnit() const {
|
||||
return Base::Unit::Length;
|
||||
}
|
||||
|
||||
const char* getEditorName(void) const {
|
||||
return "Gui::PropertyEditor::PropertyVectorDistanceItem";
|
||||
@@ -144,7 +155,9 @@ public:
|
||||
*/
|
||||
virtual ~PropertyPosition();
|
||||
|
||||
const boost::any getPathValue(const ObjectIdentifier &path) const;
|
||||
virtual Base::Unit getUnit() const {
|
||||
return Base::Unit::Length;
|
||||
}
|
||||
|
||||
const char* getEditorName(void) const {
|
||||
return "Gui::PropertyEditor::PropertyPositionItem";
|
||||
@@ -168,7 +181,9 @@ public:
|
||||
*/
|
||||
virtual ~PropertyDirection();
|
||||
|
||||
const boost::any getPathValue(const ObjectIdentifier &path) const;
|
||||
virtual Base::Unit getUnit() const {
|
||||
return Base::Unit::Length;
|
||||
}
|
||||
|
||||
const char* getEditorName(void) const {
|
||||
return "Gui::PropertyEditor::PropertyDirectionItem";
|
||||
@@ -304,7 +319,9 @@ public:
|
||||
|
||||
void setPathValue(const ObjectIdentifier &path, const boost::any &value);
|
||||
|
||||
const boost::any getPathValue(const ObjectIdentifier &path) const;
|
||||
virtual const boost::any getPathValue(const ObjectIdentifier &path) const override;
|
||||
|
||||
virtual bool getPyPathValue(const ObjectIdentifier &path, Py::Object &res) const override;
|
||||
|
||||
const char* getEditorName(void) const {
|
||||
return "Gui::PropertyEditor::PropertyPlacementItem";
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <Base/PyObjectBase.h>
|
||||
#include <Base/QuantityPy.h>
|
||||
#include <Base/UnitPy.h>
|
||||
#include "Expression.h"
|
||||
|
||||
using namespace App;
|
||||
using namespace Base;
|
||||
@@ -120,7 +121,9 @@ void PropertyQuantity::setPyObject(PyObject *value)
|
||||
if (PyObject_TypeCheck(value, &(UnitPy::Type))) {
|
||||
Base::UnitPy *pcObject = static_cast<Base::UnitPy*>(value);
|
||||
Base::Unit unit = *(pcObject->getUnitPtr());
|
||||
aboutToSetValue();
|
||||
_Unit = unit;
|
||||
hasSetValue();
|
||||
}
|
||||
else {
|
||||
Base::Quantity quant= createQuantityFromPy(value);
|
||||
@@ -140,12 +143,12 @@ void PropertyQuantity::setPyObject(PyObject *value)
|
||||
|
||||
void PropertyQuantity::setPathValue(const ObjectIdentifier & /*path*/, const boost::any &value)
|
||||
{
|
||||
if (value.type() == typeid(double))
|
||||
setValue(boost::any_cast<double>(value));
|
||||
else if (value.type() == typeid(Base::Quantity))
|
||||
setValue((boost::any_cast<Quantity>(value)).getValue());
|
||||
else
|
||||
throw bad_cast();
|
||||
auto q = App::anyToQuantity(value);
|
||||
aboutToSetValue();
|
||||
if(!q.getUnit().isEmpty())
|
||||
_Unit = q.getUnit();
|
||||
_dValue=q.getValue();
|
||||
setValue(q.getValue());
|
||||
}
|
||||
|
||||
const boost::any PropertyQuantity::getPathValue(const ObjectIdentifier & /*path*/) const
|
||||
|
||||
+39
-13
@@ -107,11 +107,11 @@ bool Range::next()
|
||||
* @returns The row.
|
||||
*/
|
||||
|
||||
int App::decodeRow(const std::string &rowstr)
|
||||
int App::decodeRow(const std::string &rowstr, bool silent)
|
||||
{
|
||||
int row = validRow(rowstr);
|
||||
|
||||
if (row >= 0)
|
||||
if (silent || row >= 0)
|
||||
return row;
|
||||
else
|
||||
throw Base::IndexError("Invalid row specification.");
|
||||
@@ -126,11 +126,11 @@ int App::decodeRow(const std::string &rowstr)
|
||||
*
|
||||
*/
|
||||
|
||||
int App::decodeColumn(const std::string &colstr)
|
||||
int App::decodeColumn(const std::string &colstr, bool silent)
|
||||
{
|
||||
int col = validColumn(colstr);
|
||||
|
||||
if (col >= 0)
|
||||
if (silent || col >= 0)
|
||||
return col;
|
||||
else
|
||||
throw Base::IndexError("Invalid column specification");
|
||||
@@ -201,19 +201,29 @@ int App::validColumn(const std::string &colstr)
|
||||
*
|
||||
*/
|
||||
|
||||
App::CellAddress App::stringToAddress(const char * strAddress)
|
||||
App::CellAddress App::stringToAddress(const char * strAddress, bool silent)
|
||||
{
|
||||
static const boost::regex e("\\${0,1}([A-Z]{1,2})\\${0,1}([0-9]{1,5})");
|
||||
boost::cmatch cm;
|
||||
|
||||
assert(strAddress != 0);
|
||||
|
||||
if (boost::regex_match(strAddress, cm, e)) {
|
||||
const boost::sub_match<const char *> colstr = cm[1];
|
||||
const boost::sub_match<const char *> rowstr = cm[2];
|
||||
static boost::regex e("(\\$?[A-Z]{1,2})(\\$?[0-9]{1,5})");
|
||||
boost::cmatch cm;
|
||||
|
||||
return CellAddress(decodeRow(rowstr.str()), decodeColumn(colstr.str()));
|
||||
if (boost::regex_match(strAddress, cm, e)) {
|
||||
bool absCol = (cm[1].first[0]=='$');
|
||||
std::string r,c;
|
||||
if(absCol)
|
||||
c = std::string(cm[1].first+1,cm[1].second);
|
||||
else
|
||||
c = std::string(cm[1].first,cm[1].second);
|
||||
bool absRow = (cm[2].first[0]=='$');
|
||||
if(absRow)
|
||||
r = std::string(cm[2].first+1,cm[2].second);
|
||||
else
|
||||
r = std::string(cm[2].first,cm[2].second);
|
||||
return CellAddress(decodeRow(r,silent), decodeColumn(c,silent), absRow, absCol);
|
||||
}
|
||||
else if(silent)
|
||||
return CellAddress();
|
||||
else
|
||||
throw Base::RuntimeError("Invalid cell specifier.");
|
||||
}
|
||||
@@ -224,10 +234,12 @@ App::CellAddress App::stringToAddress(const char * strAddress)
|
||||
* @returns Address given as a string.
|
||||
*/
|
||||
|
||||
std::string App::CellAddress::toString() const
|
||||
std::string App::CellAddress::toString(bool noAbsolute) const
|
||||
{
|
||||
std::stringstream s;
|
||||
|
||||
if(_absCol && !noAbsolute)
|
||||
s << '$';
|
||||
if (col() < 26)
|
||||
s << (char)('A' + col());
|
||||
else {
|
||||
@@ -237,7 +249,21 @@ std::string App::CellAddress::toString() const
|
||||
s << (char)('A' + (colnum % 26));
|
||||
}
|
||||
|
||||
if(_absRow && !noAbsolute)
|
||||
s << '$';
|
||||
s << (row() + 1);
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
bool App::CellAddress::parseAbsoluteAddress(const char *txt) {
|
||||
if(txt[0]=='$' || (txt[0] && txt[1] && (txt[1]=='$' || txt[2]=='$'))) {
|
||||
CellAddress addr = stringToAddress(txt,true);
|
||||
if(addr.isValid()) {
|
||||
*this = addr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+19
-5
@@ -29,15 +29,17 @@ namespace App {
|
||||
|
||||
struct CellAddress;
|
||||
|
||||
AppExport CellAddress stringToAddress(const char *strAddress);
|
||||
AppExport int decodeColumn(const std::string &colstr);
|
||||
AppExport int decodeRow(const std::string &rowstr);
|
||||
AppExport CellAddress stringToAddress(const char *strAddress, bool silent=false);
|
||||
AppExport int decodeColumn(const std::string &colstr, bool silent=false);
|
||||
AppExport int decodeRow(const std::string &rowstr, bool silent=false);
|
||||
AppExport int validColumn(const std::string &colstr);
|
||||
AppExport int validRow(const std::string &rowstr);
|
||||
|
||||
struct AppExport CellAddress {
|
||||
|
||||
CellAddress(int row = -1, int col = -1) : _row(row), _col(col) { }
|
||||
CellAddress(int row = -1, int col = -1, bool absRow=false, bool absCol=false)
|
||||
: _row(row), _col(col), _absRow(absRow), _absCol(absCol)
|
||||
{ }
|
||||
|
||||
CellAddress(const char * address) {
|
||||
*this = stringToAddress(address);
|
||||
@@ -47,10 +49,16 @@ struct AppExport CellAddress {
|
||||
*this = stringToAddress(address.c_str());
|
||||
}
|
||||
|
||||
bool parseAbsoluteAddress(const char *txt);
|
||||
|
||||
inline int row() const { return _row; }
|
||||
|
||||
inline int col() const { return _col; }
|
||||
|
||||
void setRow(int r) { _row = r; }
|
||||
|
||||
void setCol(int c) { _col = c; }
|
||||
|
||||
inline bool operator<(const CellAddress & other) const { return asInt() < other.asInt(); }
|
||||
|
||||
inline bool operator==(const CellAddress & other) const { return asInt() == other.asInt(); }
|
||||
@@ -59,7 +67,11 @@ struct AppExport CellAddress {
|
||||
|
||||
inline bool isValid() { return (row() >=0 && row() < MAX_ROWS && col() >= 0 && col() < MAX_COLUMNS); }
|
||||
|
||||
std::string toString() const;
|
||||
inline bool isAbsoluteRow() const { return _absRow; }
|
||||
|
||||
inline bool isAbsoluteCol() const { return _absCol; }
|
||||
|
||||
std::string toString(bool noAbsolute=false) const;
|
||||
|
||||
// Static members
|
||||
|
||||
@@ -73,6 +85,8 @@ protected:
|
||||
|
||||
short _row;
|
||||
short _col;
|
||||
bool _absRow;
|
||||
bool _absCol;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <Base/Reader.h>
|
||||
#include <Base/Writer.h>
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/QuantityPy.h>
|
||||
#include <App/ObjectIdentifier.h>
|
||||
#include <App/DocumentObject.h>
|
||||
|
||||
@@ -68,13 +69,13 @@ PropertyConstraintList::~PropertyConstraintList()
|
||||
|
||||
App::ObjectIdentifier PropertyConstraintList::makeArrayPath(int idx)
|
||||
{
|
||||
return App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::ArrayComponent(ObjectIdentifier::String(getName()), idx);
|
||||
return App::ObjectIdentifier(*this,idx);
|
||||
}
|
||||
|
||||
App::ObjectIdentifier PropertyConstraintList::makeSimplePath(const Constraint * c)
|
||||
{
|
||||
return App::ObjectIdentifier(getContainer()) << App::ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< App::ObjectIdentifier::Component::SimpleComponent(App::ObjectIdentifier::String(c->Name, !ExpressionParser::isTokenAnIndentifier(c->Name)));
|
||||
return App::ObjectIdentifier(*this) << App::ObjectIdentifier::SimpleComponent(
|
||||
App::ObjectIdentifier::String(c->Name, !ExpressionParser::isTokenAnIndentifier(c->Name)));
|
||||
}
|
||||
|
||||
App::ObjectIdentifier PropertyConstraintList::makePath(int idx, const Constraint * c)
|
||||
@@ -175,43 +176,52 @@ void PropertyConstraintList::setValue(const Constraint* lValue)
|
||||
|
||||
void PropertyConstraintList::setValues(const std::vector<Constraint*>& lValue)
|
||||
{
|
||||
auto copy = lValue;
|
||||
for(auto &cstr : copy)
|
||||
cstr = cstr->clone();
|
||||
aboutToSetValue();
|
||||
applyValues(lValue);
|
||||
applyValues(std::move(copy));
|
||||
hasSetValue();
|
||||
}
|
||||
|
||||
void PropertyConstraintList::applyValues(const std::vector<Constraint*>& lValue)
|
||||
void PropertyConstraintList::setValues(std::vector<Constraint*>&& lValue) {
|
||||
aboutToSetValue();
|
||||
applyValues(std::move(lValue));
|
||||
hasSetValue();
|
||||
}
|
||||
|
||||
void PropertyConstraintList::applyValues(std::vector<Constraint*>&& lValue)
|
||||
{
|
||||
std::vector<Constraint*> oldVals(_lValueList);
|
||||
std::set<Constraint*> oldVals(_lValueList.begin(),_lValueList.end());
|
||||
std::map<App::ObjectIdentifier, App::ObjectIdentifier> renamed;
|
||||
std::set<App::ObjectIdentifier> removed;
|
||||
boost::unordered_map<boost::uuids::uuid, std::size_t> newValueMap;
|
||||
|
||||
/* Check for renames */
|
||||
for (unsigned int i = 0; i < lValue.size(); i++) {
|
||||
boost::unordered_map<boost::uuids::uuid, std::size_t>::const_iterator j = valueMap.find(lValue[i]->tag);
|
||||
|
||||
if (j != valueMap.end() && (i != j->second || _lValueList[j->second]->Name != lValue[i]->Name) ) {
|
||||
App::ObjectIdentifier old_oid(makePath(j->second, _lValueList[j->second] ));
|
||||
App::ObjectIdentifier new_oid(makePath(i, lValue[i]));
|
||||
|
||||
renamed[old_oid] = new_oid;
|
||||
if (j != valueMap.end()) {
|
||||
if(i != j->second || _lValueList[j->second]->Name != lValue[i]->Name) {
|
||||
App::ObjectIdentifier old_oid(makePath(j->second, _lValueList[j->second] ));
|
||||
App::ObjectIdentifier new_oid(makePath(i, lValue[i]));
|
||||
renamed[old_oid] = new_oid;
|
||||
}
|
||||
valueMap.erase(j);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update value map with new tags from new array */
|
||||
valueMap.clear();
|
||||
for (std::size_t i = 0; i < lValue.size(); i++)
|
||||
valueMap[lValue[i]->tag] = i;
|
||||
newValueMap[lValue[i]->tag] = i;
|
||||
|
||||
// safety insurance in case new new values contain some pointers of the old values
|
||||
oldVals.erase(lValue[i]);
|
||||
}
|
||||
|
||||
/* Collect info about removed elements */
|
||||
for (std::size_t i = 0; i < oldVals.size(); i++) {
|
||||
boost::unordered_map<boost::uuids::uuid, std::size_t>::const_iterator j = valueMap.find(oldVals[i]->tag);
|
||||
App::ObjectIdentifier oid(makePath(i, oldVals[i]));
|
||||
for(auto &v : valueMap)
|
||||
removed.insert(makePath(v.second,_lValueList[v.second]));
|
||||
|
||||
/* If not found in new values, place it in the set to be removed */
|
||||
if (j == valueMap.end())
|
||||
removed.insert(oid);
|
||||
}
|
||||
/* Update value map with new tags from new array */
|
||||
valueMap = std::move(newValueMap);
|
||||
|
||||
/* Signal removes first, in case renamed values below have the same names as some of the removed ones. */
|
||||
if (removed.size() > 0)
|
||||
@@ -221,16 +231,11 @@ void PropertyConstraintList::applyValues(const std::vector<Constraint*>& lValue)
|
||||
if (renamed.size() > 0)
|
||||
signalConstraintsRenamed(renamed);
|
||||
|
||||
/* Resize array to new size */
|
||||
_lValueList.resize(lValue.size());
|
||||
|
||||
/* copy all objects */
|
||||
for (unsigned int i = 0; i < lValue.size(); i++)
|
||||
_lValueList[i] = lValue[i]->clone();
|
||||
_lValueList = std::move(lValue);
|
||||
|
||||
/* Clean-up; remove old values */
|
||||
for (unsigned int i = 0; i < oldVals.size(); i++)
|
||||
delete oldVals[i];
|
||||
for(auto &v : oldVals)
|
||||
delete v;
|
||||
}
|
||||
|
||||
PyObject *PropertyConstraintList::getPyObject(void)
|
||||
@@ -241,6 +246,32 @@ PyObject *PropertyConstraintList::getPyObject(void)
|
||||
return list;
|
||||
}
|
||||
|
||||
bool PropertyConstraintList::getPyPathValue(const App::ObjectIdentifier &path, Py::Object &res) const {
|
||||
if(path.numSubComponents()!=2 || path.getPropertyComponent(0).getName()!=getName())
|
||||
return false;
|
||||
|
||||
const ObjectIdentifier::Component & c1 = path.getPropertyComponent(1);
|
||||
|
||||
const Constraint *cstr = 0;
|
||||
|
||||
if (c1.isArray())
|
||||
cstr = _lValueList[c1.getIndex(_lValueList.size())];
|
||||
else if (c1.isSimple()) {
|
||||
ObjectIdentifier::Component c1 = path.getPropertyComponent(1);
|
||||
for(auto c : _lValueList) {
|
||||
if(c->Name == c1.getName()) {
|
||||
cstr = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!cstr)
|
||||
return false;
|
||||
Quantity q = cstr->getPresentationValue();
|
||||
res = new Base::QuantityPy(new Base::Quantity(q));
|
||||
return true;
|
||||
}
|
||||
|
||||
void PropertyConstraintList::setPyObject(PyObject *value)
|
||||
{
|
||||
if (PyList_Check(value)) {
|
||||
@@ -307,26 +338,21 @@ void PropertyConstraintList::Restore(Base::XMLReader &reader)
|
||||
reader.readEndElement("ConstraintList");
|
||||
|
||||
// assignment
|
||||
setValues(values);
|
||||
for (Constraint* it : values)
|
||||
delete it;
|
||||
setValues(std::move(values));
|
||||
}
|
||||
|
||||
Property *PropertyConstraintList::Copy(void) const
|
||||
{
|
||||
PropertyConstraintList *p = new PropertyConstraintList();
|
||||
p->applyValidGeometryKeys(validGeometryKeys);
|
||||
p->applyValues(_lValueList);
|
||||
p->setValues(_lValueList);
|
||||
return p;
|
||||
}
|
||||
|
||||
void PropertyConstraintList::Paste(const Property &from)
|
||||
{
|
||||
const PropertyConstraintList& FromList = dynamic_cast<const PropertyConstraintList&>(from);
|
||||
aboutToSetValue();
|
||||
applyValues(FromList._lValueList);
|
||||
applyValidGeometryKeys(FromList.validGeometryKeys);
|
||||
hasSetValue();
|
||||
setValues(FromList._lValueList);
|
||||
}
|
||||
|
||||
unsigned int PropertyConstraintList::getMemSize(void) const
|
||||
@@ -414,8 +440,7 @@ bool PropertyConstraintList::validConstraintName(const std::string & name)
|
||||
|
||||
ObjectIdentifier PropertyConstraintList::createPath(int ConstrNbr) const
|
||||
{
|
||||
return App::ObjectIdentifier(getContainer())
|
||||
<< App::ObjectIdentifier::Component::ArrayComponent(App::ObjectIdentifier::String(getName()), ConstrNbr);
|
||||
return App::ObjectIdentifier(*this,ConstrNbr);
|
||||
}
|
||||
|
||||
int PropertyConstraintList::getIndexFromConstraintName(const string &name)
|
||||
@@ -425,21 +450,27 @@ int PropertyConstraintList::getIndexFromConstraintName(const string &name)
|
||||
|
||||
void PropertyConstraintList::setPathValue(const ObjectIdentifier &path, const boost::any &value)
|
||||
{
|
||||
const ObjectIdentifier::Component & c0 = path.getPropertyComponent(0);
|
||||
if(path.numSubComponents()!=2 || path.getPropertyComponent(0).getName()!=getName())
|
||||
FC_THROWM(Base::ValueError,"invalid constraint path " << path.toString());
|
||||
|
||||
const ObjectIdentifier::Component & c1 = path.getPropertyComponent(1);
|
||||
double dvalue;
|
||||
|
||||
if (value.type() == typeid(double))
|
||||
dvalue = boost::any_cast<double>(value);
|
||||
else if (value.type() == typeid(float))
|
||||
dvalue = App::any_cast<float>(value);
|
||||
else if (value.type() == typeid(long))
|
||||
dvalue = App::any_cast<long>(value);
|
||||
else if (value.type() == typeid(int))
|
||||
dvalue = App::any_cast<int>(value);
|
||||
else if (value.type() == typeid(Quantity))
|
||||
dvalue = (boost::any_cast<Quantity>(value)).getValue();
|
||||
dvalue = (App::any_cast<const Quantity &>(value)).getValue();
|
||||
else
|
||||
throw std::bad_cast();
|
||||
|
||||
if (c0.isArray() && path.numSubComponents() == 1) {
|
||||
int index = c0.getIndex();
|
||||
|
||||
if (c0.getIndex() >= _lValueList.size())
|
||||
throw Base::IndexError("Array out of bounds");
|
||||
if (c1.isArray()) {
|
||||
size_t index = c1.getIndex(_lValueList.size());
|
||||
switch (_lValueList[index]->Type) {
|
||||
case Angle:
|
||||
dvalue = Base::toRadians<double>(dvalue);
|
||||
@@ -452,9 +483,7 @@ void PropertyConstraintList::setPathValue(const ObjectIdentifier &path, const bo
|
||||
hasSetValue();
|
||||
return;
|
||||
}
|
||||
else if (c0.isSimple() && path.numSubComponents() == 2) {
|
||||
ObjectIdentifier::Component c1 = path.getPropertyComponent(1);
|
||||
|
||||
else if (c1.isSimple()) {
|
||||
for (std::vector<Constraint *>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
|
||||
int index = it - _lValueList.begin();
|
||||
|
||||
@@ -473,20 +502,20 @@ void PropertyConstraintList::setPathValue(const ObjectIdentifier &path, const bo
|
||||
}
|
||||
}
|
||||
}
|
||||
throw Base::ValueError("Invalid constraint");
|
||||
FC_THROWM(Base::ValueError,"invalid constraint path " << path.toString());
|
||||
}
|
||||
|
||||
const Constraint * PropertyConstraintList::getConstraint(const ObjectIdentifier &path) const
|
||||
{
|
||||
const ObjectIdentifier::Component & c0 = path.getPropertyComponent(0);
|
||||
if(path.numSubComponents()!=2 || path.getPropertyComponent(0).getName()!=getName())
|
||||
FC_THROWM(Base::ValueError,"Invalid constraint path " << path.toString());
|
||||
|
||||
if (c0.isArray() && path.numSubComponents() == 1) {
|
||||
if (c0.getIndex() >= _lValueList.size())
|
||||
throw Base::IndexError("Array out of bounds");
|
||||
const ObjectIdentifier::Component & c1 = path.getPropertyComponent(1);
|
||||
|
||||
return _lValueList[c0.getIndex()];
|
||||
if (c1.isArray()) {
|
||||
return _lValueList[c1.getIndex(_lValueList.size())];
|
||||
}
|
||||
else if (c0.isSimple() && path.numSubComponents() == 2) {
|
||||
else if (c1.isSimple()) {
|
||||
ObjectIdentifier::Component c1 = path.getPropertyComponent(1);
|
||||
|
||||
for (std::vector<Constraint *>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
|
||||
@@ -494,7 +523,7 @@ const Constraint * PropertyConstraintList::getConstraint(const ObjectIdentifier
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
throw Base::ValueError("Invalid constraint");
|
||||
FC_THROWM(Base::ValueError,"Invalid constraint path " << path.toString());
|
||||
}
|
||||
|
||||
const boost::any PropertyConstraintList::getPathValue(const ObjectIdentifier &path) const
|
||||
@@ -502,31 +531,30 @@ const boost::any PropertyConstraintList::getPathValue(const ObjectIdentifier &pa
|
||||
return boost::any(getConstraint(path)->getPresentationValue());
|
||||
}
|
||||
|
||||
const ObjectIdentifier PropertyConstraintList::canonicalPath(const ObjectIdentifier &p) const
|
||||
ObjectIdentifier PropertyConstraintList::canonicalPath(const ObjectIdentifier &p) const
|
||||
{
|
||||
const ObjectIdentifier::Component & c0 = p.getPropertyComponent(0);
|
||||
if(p.numSubComponents()!=2 || p.getPropertyComponent(0).getName()!=getName())
|
||||
FC_THROWM(Base::ValueError,"Invalid constraint path " << p.toString());
|
||||
|
||||
if (c0.isArray() && p.numSubComponents() == 1) {
|
||||
if (c0.getIndex() < _lValueList.size() && _lValueList[c0.getIndex()]->Name.size() > 0)
|
||||
return ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent(_lValueList[c0.getIndex()]->Name);
|
||||
const ObjectIdentifier::Component & c1 = p.getPropertyComponent(1);
|
||||
|
||||
if (c1.isArray()) {
|
||||
size_t idx = c1.getIndex();
|
||||
if (idx < _lValueList.size() && _lValueList[idx]->Name.size() > 0)
|
||||
return ObjectIdentifier(*this) << ObjectIdentifier::SimpleComponent(_lValueList[idx]->Name);
|
||||
return p;
|
||||
}
|
||||
else if (c0.isSimple() && p.numSubComponents() == 2) {
|
||||
ObjectIdentifier::Component c1 = p.getPropertyComponent(1);
|
||||
|
||||
if (c1.isSimple())
|
||||
return p;
|
||||
else if (c1.isSimple()) {
|
||||
return p;
|
||||
}
|
||||
throw Base::ValueError("Invalid constraint");
|
||||
FC_THROWM(Base::ValueError,"Invalid constraint path " << p.toString());
|
||||
}
|
||||
|
||||
void PropertyConstraintList::getPaths(std::vector<ObjectIdentifier> &paths) const
|
||||
{
|
||||
for (std::vector<Constraint *>::const_iterator it = _lValueList.begin(); it != _lValueList.end(); ++it) {
|
||||
if ((*it)->Name.size() > 0)
|
||||
paths.push_back(ObjectIdentifier(getContainer()) << ObjectIdentifier::Component::SimpleComponent(getName())
|
||||
<< ObjectIdentifier::Component::SimpleComponent((*it)->Name));
|
||||
paths.push_back(ObjectIdentifier(*this) << ObjectIdentifier::SimpleComponent((*it)->Name));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,13 @@ public:
|
||||
*/
|
||||
void setValues(const std::vector<Constraint*>&);
|
||||
|
||||
/*!
|
||||
Sets a vector of constraint to the property.
|
||||
The values of the array are moved, and the ownership of constraints
|
||||
inside are taken by this property
|
||||
*/
|
||||
void setValues(std::vector<Constraint*>&&);
|
||||
|
||||
/*!
|
||||
Index operator
|
||||
\note If the geometry is invalid then the index operator
|
||||
@@ -124,9 +131,11 @@ public:
|
||||
const Constraint *getConstraint(const App::ObjectIdentifier &path) const;
|
||||
virtual void setPathValue(const App::ObjectIdentifier & path, const boost::any & value);
|
||||
virtual const boost::any getPathValue(const App::ObjectIdentifier & path) const;
|
||||
virtual const App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier & p) const;
|
||||
virtual App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier & p) const;
|
||||
virtual void getPaths(std::vector<App::ObjectIdentifier> & paths) const;
|
||||
|
||||
virtual bool getPyPathValue(const App::ObjectIdentifier &path, Py::Object &res) const override;
|
||||
|
||||
typedef std::pair<int, const Constraint*> ConstraintInfo ;
|
||||
|
||||
boost::signals2::signal<void (const std::map<App::ObjectIdentifier, App::ObjectIdentifier> &)> signalConstraintsRenamed;
|
||||
@@ -153,7 +162,7 @@ private:
|
||||
std::vector<unsigned int> validGeometryKeys;
|
||||
bool invalidGeometry;
|
||||
|
||||
void applyValues(const std::vector<Constraint*>&);
|
||||
void applyValues(std::vector<Constraint*>&&);
|
||||
void applyValidGeometryKeys(const std::vector<unsigned int> &keys);
|
||||
|
||||
static std::vector<Constraint *> _emptyValueList;
|
||||
|
||||
@@ -6393,17 +6393,17 @@ std::string SketchObject::validateExpression(const App::ObjectIdentifier &path,
|
||||
return "Reference constraints cannot be set!";
|
||||
}
|
||||
|
||||
std::set<App::ObjectIdentifier> deps;
|
||||
expr->getDeps(deps);
|
||||
auto deps = expr->getDeps();
|
||||
auto it = deps.find(this);
|
||||
if(it!=deps.end()) {
|
||||
auto it2 = it->second.find("Constraints");
|
||||
if(it2 != it->second.end()) {
|
||||
for(auto &oid : it2->second) {
|
||||
const Constraint * constraint = Constraints.getConstraint(oid);
|
||||
|
||||
for (std::set<App::ObjectIdentifier>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
|
||||
const App::Property * prop = (*i).getProperty();
|
||||
|
||||
if (prop == &Constraints) {
|
||||
const Constraint * constraint = Constraints.getConstraint(*i);
|
||||
|
||||
if (!constraint->isDriving)
|
||||
return "Reference constraint from this sketch cannot be used in this expression.";
|
||||
if (!constraint->isDriving)
|
||||
return "Reference constraint from this sketch cannot be used in this expression.";
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
@@ -6468,7 +6468,7 @@ void SketchObject::constraintsRemoved(const std::set<App::ObjectIdentifier> &rem
|
||||
std::set<App::ObjectIdentifier>::const_iterator i = removed.begin();
|
||||
|
||||
while (i != removed.end()) {
|
||||
ExpressionEngine.setValue(*i, boost::shared_ptr<App::Expression>(), 0);
|
||||
ExpressionEngine.setValue(*i, boost::shared_ptr<App::Expression>());
|
||||
++i;
|
||||
}
|
||||
}
|
||||
@@ -6860,9 +6860,9 @@ bool SketchObject::AutoLockTangencyAndPerpty(Constraint *cstr, bool bForce, bool
|
||||
return true;
|
||||
}
|
||||
|
||||
void SketchObject::setExpression(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr, const char * comment)
|
||||
void SketchObject::setExpression(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr)
|
||||
{
|
||||
DocumentObject::setExpression(path, expr, comment);
|
||||
DocumentObject::setExpression(path, expr);
|
||||
|
||||
if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver, constraints and UI
|
||||
solve();
|
||||
|
||||
@@ -414,7 +414,7 @@ protected:
|
||||
virtual void onDocumentRestored();
|
||||
virtual void restoreFinished();
|
||||
|
||||
virtual void setExpression(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr, const char * comment = 0);
|
||||
virtual void setExpression(const App::ObjectIdentifier &path, boost::shared_ptr<App::Expression> expr);
|
||||
|
||||
std::string validateExpression(const App::ObjectIdentifier &path, boost::shared_ptr<const App::Expression> expr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user