Added Expression classes to App directory. Added Expression interface to Property base class.
This commit is contained in:
@@ -95,6 +95,7 @@
|
||||
#include "Placement.h"
|
||||
#include "Plane.h"
|
||||
#include "MaterialObject.h"
|
||||
#include "Expression.h"
|
||||
|
||||
// If you stumble here, run the target "BuildExtractRevision" on Windows systems
|
||||
// or the Python script "SubWCRev.py" on Linux based systems which builds
|
||||
@@ -1116,6 +1117,18 @@ void Application::initTypes(void)
|
||||
App ::MaterialObjectPython ::init();
|
||||
App ::Placement ::init();
|
||||
App ::Plane ::init();
|
||||
|
||||
// Expression classes
|
||||
App ::Expression ::init();
|
||||
App ::UnitExpression ::init();
|
||||
App ::NumberExpression ::init();
|
||||
App ::ConstantExpression ::init();
|
||||
App ::OperatorExpression ::init();
|
||||
App ::VariableExpression ::init();
|
||||
App ::ConditionalExpression ::init();
|
||||
App ::StringExpression ::init();
|
||||
App ::FunctionExpression ::init();
|
||||
|
||||
}
|
||||
|
||||
void Application::initConfig(int argc, char ** argv)
|
||||
|
||||
@@ -62,6 +62,7 @@ SET(Document_CPP_SRCS
|
||||
DocumentObserver.cpp
|
||||
DocumentObserverPython.cpp
|
||||
DocumentPyImp.cpp
|
||||
Expression.cpp
|
||||
FeaturePython.cpp
|
||||
FeatureTest.cpp
|
||||
GeoFeature.cpp
|
||||
@@ -83,6 +84,7 @@ SET(Document_HPP_SRCS
|
||||
DocumentObjectGroup.h
|
||||
DocumentObserver.h
|
||||
DocumentObserverPython.h
|
||||
Expression.h
|
||||
FeaturePython.h
|
||||
FeaturePythonPyImp.h
|
||||
FeaturePythonPyImp.inl
|
||||
@@ -106,6 +108,7 @@ SOURCE_GROUP("Document" FILES ${Document_SRCS})
|
||||
# The property stuff
|
||||
SET(Properties_CPP_SRCS
|
||||
DynamicProperty.cpp
|
||||
ObjectIdentifier.cpp
|
||||
Property.cpp
|
||||
PropertyContainer.cpp
|
||||
PropertyContainerPyImp.cpp
|
||||
@@ -118,6 +121,7 @@ SET(Properties_CPP_SRCS
|
||||
)
|
||||
SET(Properties_HPP_SRCS
|
||||
DynamicProperty.h
|
||||
ObjectIdentifier.h
|
||||
Property.h
|
||||
PropertyContainer.h
|
||||
PropertyFile.h
|
||||
|
||||
1448
src/App/Expression.cpp
Normal file
1448
src/App/Expression.cpp
Normal file
File diff suppressed because it is too large
Load Diff
433
src/App/Expression.h
Normal file
433
src/App/Expression.h
Normal file
@@ -0,0 +1,433 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) Eivind Kvedalen (eivind@kvedalen.name) 2015 *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef EXPRESSION_H
|
||||
#define EXPRESSION_H
|
||||
|
||||
#include <string>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <Base/Exception.h>
|
||||
#include <Base/Unit.h>
|
||||
#include <App/Property.h>
|
||||
#include <App/ObjectIdentifier.h>
|
||||
#include <Base/BaseClass.h>
|
||||
#include <Base/Quantity.h>
|
||||
#include <set>
|
||||
#include <deque>
|
||||
|
||||
namespace App {
|
||||
|
||||
class DocumentObject;
|
||||
class Expression;
|
||||
class Document;
|
||||
|
||||
class AppExport ExpressionVisitor {
|
||||
public:
|
||||
virtual ~ExpressionVisitor() {}
|
||||
virtual void visit(Expression * e) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for expressions.
|
||||
*
|
||||
*/
|
||||
|
||||
class AppExport Expression : public Base::BaseClass {
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
|
||||
Expression(const App::DocumentObject * _owner);
|
||||
|
||||
virtual ~Expression();
|
||||
|
||||
virtual bool isTouched() const { return false; }
|
||||
|
||||
virtual Expression * eval() const = 0;
|
||||
|
||||
virtual std::string toString() const = 0;
|
||||
|
||||
static Expression * parse(const App::DocumentObject * owner, const std::string& buffer);
|
||||
|
||||
virtual Expression * copy() const = 0;
|
||||
|
||||
virtual int priority() const { return 0; }
|
||||
|
||||
virtual void getDeps(std::set<ObjectIdentifier> &props) const { }
|
||||
|
||||
virtual Expression * simplify() const = 0;
|
||||
|
||||
virtual void visit(ExpressionVisitor & v) { v.visit(this); }
|
||||
|
||||
class Exception : public Base::Exception {
|
||||
public:
|
||||
Exception(const char *sMessage) : Base::Exception(sMessage) { }
|
||||
};
|
||||
|
||||
const App::DocumentObject * getOwner() const { return owner; }
|
||||
|
||||
virtual boost::any getValueAsAny() const { static boost::any empty; return empty; }
|
||||
|
||||
protected:
|
||||
const App::DocumentObject * owner; /**< The document object used to access unqualified variables (i.e local scope) */
|
||||
};
|
||||
|
||||
/**
|
||||
* Part of an expressions that contains a unit.
|
||||
*
|
||||
*/
|
||||
|
||||
class AppExport UnitExpression : public Expression {
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
UnitExpression(const App::DocumentObject *_owner = 0, const Base::Quantity & _quantity = Base::Quantity(), const std::string & _unitStr = std::string());
|
||||
|
||||
virtual Expression * eval() const;
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
|
||||
virtual int priority() const { return 20; }
|
||||
|
||||
void setUnit(const Base::Quantity &_quantity);
|
||||
|
||||
double getValue() const { return quantity.getValue(); }
|
||||
|
||||
const Base::Unit & getUnit() const { return quantity.getUnit(); }
|
||||
|
||||
const Base::Quantity & getQuantity() const { return quantity; }
|
||||
|
||||
const std::string getUnitString() const { return unitStr; }
|
||||
|
||||
double getScaler() const { return quantity.getValue(); }
|
||||
|
||||
boost::any getValueAsAny() const { return quantity.getUnit().isEmpty() ? boost::any(quantity.getValue()) : boost::any(quantity); }
|
||||
|
||||
protected:
|
||||
Base::Quantity quantity;
|
||||
std::string unitStr; /**< The unit string from the original parsed string */
|
||||
};
|
||||
|
||||
/**
|
||||
* Class implementing a number with an optional unit
|
||||
*/
|
||||
|
||||
class AppExport NumberExpression : public UnitExpression {
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
NumberExpression(const App::DocumentObject *_owner = 0, const Base::Quantity & quantity = Base::Quantity());
|
||||
|
||||
virtual Expression * eval() const;
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
|
||||
virtual int priority() const { return 20; }
|
||||
|
||||
void negate();
|
||||
|
||||
virtual std::string toString() const;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
class AppExport ConstantExpression : public NumberExpression {
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
ConstantExpression(const App::DocumentObject *_owner = 0, std::string _name = "", const Base::Quantity &_quantity = Base::Quantity());
|
||||
|
||||
virtual std::string toString() const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
|
||||
virtual int priority() const { return 20; }
|
||||
|
||||
std::string getName() const { return name; }
|
||||
|
||||
protected:
|
||||
std::string name; /**< Constant's name */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class implementing an infix expression.
|
||||
*
|
||||
*/
|
||||
|
||||
class AppExport OperatorExpression : public UnitExpression {
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
enum Operator {
|
||||
NONE,
|
||||
ADD,
|
||||
SUB,
|
||||
MUL,
|
||||
DIV,
|
||||
POW,
|
||||
EQ,
|
||||
NEQ,
|
||||
LT,
|
||||
GT,
|
||||
LTE,
|
||||
GTE,
|
||||
UNIT,
|
||||
NEG,
|
||||
POS
|
||||
};
|
||||
OperatorExpression(const App::DocumentObject *_owner = 0, Expression * _left = 0, Operator _op = NONE, Expression * _right = 0);
|
||||
|
||||
virtual ~OperatorExpression();
|
||||
|
||||
virtual bool isTouched() const;
|
||||
|
||||
virtual Expression * eval() const;
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
|
||||
|
||||
virtual void visit(ExpressionVisitor & v);
|
||||
|
||||
protected:
|
||||
Operator op; /**< Operator working on left and right */
|
||||
Expression * left; /**< Left operand */
|
||||
Expression * right; /**< Right operand */
|
||||
};
|
||||
|
||||
class AppExport ConditionalExpression : public Expression {
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
ConditionalExpression(const App::DocumentObject *_owner = 0, Expression * _condition = 0,Expression * _trueExpr = 0, Expression * _falseExpr = 0);
|
||||
|
||||
virtual ~ConditionalExpression();
|
||||
|
||||
virtual bool isTouched() const;
|
||||
|
||||
virtual Expression * eval() const;
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
|
||||
virtual int priority() const;
|
||||
|
||||
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
|
||||
|
||||
virtual void visit(ExpressionVisitor & v);
|
||||
|
||||
protected:
|
||||
|
||||
Expression * condition; /**< Condition */
|
||||
Expression * trueExpr; /**< Expression if abs(condition) is > 0.5 */
|
||||
Expression * falseExpr; /**< Expression if abs(condition) is < 0.5 */
|
||||
};
|
||||
|
||||
/**
|
||||
* Class implementing various functions, e.g sin, cos, etc.
|
||||
*
|
||||
*/
|
||||
|
||||
class AppExport FunctionExpression : public UnitExpression {
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
enum Function {
|
||||
NONE,
|
||||
|
||||
// Normal functions taking one or two arguments
|
||||
ACOS,
|
||||
ASIN,
|
||||
ATAN,
|
||||
ABS,
|
||||
EXP,
|
||||
LOG,
|
||||
LOG10,
|
||||
SIN,
|
||||
SINH,
|
||||
TAN,
|
||||
TANH,
|
||||
SQRT,
|
||||
COS,
|
||||
COSH,
|
||||
ATAN2,
|
||||
MOD,
|
||||
POW,
|
||||
ROUND,
|
||||
TRUNC,
|
||||
CEIL,
|
||||
FLOOR,
|
||||
LAST,
|
||||
};
|
||||
|
||||
FunctionExpression(const App::DocumentObject *_owner = 0, Function _f = NONE, std::vector<Expression *> _args = std::vector<Expression*>());
|
||||
|
||||
virtual ~FunctionExpression();
|
||||
|
||||
virtual bool isTouched() const;
|
||||
|
||||
virtual Expression * eval() const;
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
|
||||
virtual Expression * copy() const;
|
||||
|
||||
virtual int priority() const { return 20; }
|
||||
|
||||
virtual void getDeps(std::set<ObjectIdentifier> &props) const;
|
||||
|
||||
virtual void visit(ExpressionVisitor & v);
|
||||
|
||||
protected:
|
||||
Function f; /**< Function to execute */
|
||||
std::vector<Expression *> args; /** Arguments to function*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Class implementing a reference to a property. If the name is unqualified,
|
||||
* the owner of the expression is searched. If it is qualified, the document
|
||||
* that contains the owning document object is searched for other document
|
||||
* objects to search. Both labels and internal document names are searched.
|
||||
*
|
||||
*/
|
||||
|
||||
class AppExport VariableExpression : public UnitExpression {
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
VariableExpression(const App::DocumentObject *_owner = 0, ObjectIdentifier _var = ObjectIdentifier());
|
||||
|
||||
~VariableExpression();
|
||||
|
||||
virtual bool isTouched() const;
|
||||
|
||||
virtual Expression * eval() const;
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const { return var.toString(); }
|
||||
|
||||
virtual Expression * copy() const;
|
||||
|
||||
virtual int priority() const { return 20; }
|
||||
|
||||
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);
|
||||
|
||||
void setName(const std::string & name) { assert(0); }
|
||||
|
||||
void renameDocumentObject(const std::string & oldName, const std::string & newName);
|
||||
|
||||
void renameDocument(const std::string &oldName, const std::string &newName);
|
||||
|
||||
const App::Property *getProperty() const;
|
||||
|
||||
protected:
|
||||
|
||||
ObjectIdentifier var; /**< Variable name */
|
||||
};
|
||||
|
||||
/**
|
||||
* Class implementing a string. Used to signal either a genuine string or
|
||||
* a failed evaluation of an expression.
|
||||
*/
|
||||
|
||||
class AppExport StringExpression : public Expression {
|
||||
TYPESYSTEM_HEADER();
|
||||
public:
|
||||
StringExpression(const App::DocumentObject *_owner = 0, const std::string & _text = std::string());
|
||||
|
||||
virtual Expression * eval() const;
|
||||
|
||||
virtual Expression * simplify() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
|
||||
virtual std::string getText() const { return text; }
|
||||
|
||||
virtual int priority() const { return 20; }
|
||||
|
||||
virtual Expression * copy() const;
|
||||
|
||||
protected:
|
||||
|
||||
std::string text; /**< Text string */
|
||||
};
|
||||
|
||||
namespace ExpressionParser {
|
||||
AppExport Expression * parse(const App::DocumentObject *owner, const char *buffer);
|
||||
AppExport UnitExpression * parseUnit(const App::DocumentObject *owner, const char *buffer);
|
||||
AppExport ObjectIdentifier parsePath(const App::DocumentObject *owner, const char* buffer);
|
||||
AppExport bool isTokenAnIndentifier(const std::string & str);
|
||||
AppExport std::vector<boost::tuple<int, int, std::string> > tokenize(const std::string & str);
|
||||
|
||||
/**
|
||||
* @brief The semantic_type class encapsulates the value in the parse tree during parsing.
|
||||
*/
|
||||
|
||||
class semantic_type {
|
||||
public:
|
||||
struct {
|
||||
Base::Quantity scaler;
|
||||
std::string unitStr;
|
||||
} quantity;
|
||||
Expression * expr;
|
||||
ObjectIdentifier path;
|
||||
std::deque<ObjectIdentifier::Component> components;
|
||||
int ivalue;
|
||||
double fvalue;
|
||||
struct {
|
||||
std::string name;
|
||||
double fvalue;
|
||||
} constant;
|
||||
std::vector<Expression*> arguments;
|
||||
std::string string;
|
||||
FunctionExpression::Function func;
|
||||
ObjectIdentifier::String string_or_identifier;
|
||||
semantic_type() {}
|
||||
};
|
||||
|
||||
#define YYSTYPE semantic_type
|
||||
#include "ExpressionParser.tab.h"
|
||||
#undef YYTOKENTYPE
|
||||
#undef YYSTYPE
|
||||
#undef YYSTYPE_ISDECLARED
|
||||
}
|
||||
|
||||
}
|
||||
#endif // EXPRESSION_H
|
||||
274
src/App/ExpressionParser.l
Normal file
274
src/App/ExpressionParser.l
Normal file
File diff suppressed because one or more lines are too long
2252
src/App/ExpressionParser.tab.c
Normal file
2252
src/App/ExpressionParser.tab.c
Normal file
File diff suppressed because it is too large
Load Diff
75
src/App/ExpressionParser.tab.h
Normal file
75
src/App/ExpressionParser.tab.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* A Bison parser, made by GNU Bison 2.5. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
|
||||
/* Tokens. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
/* Put the tokens into the symbol table, so that GDB and other debuggers
|
||||
know about them. */
|
||||
enum yytokentype {
|
||||
FUNC = 258,
|
||||
ONE = 259,
|
||||
NUM = 260,
|
||||
IDENTIFIER = 261,
|
||||
UNIT = 262,
|
||||
INTEGER = 263,
|
||||
CONSTANT = 264,
|
||||
CELLADDRESS = 265,
|
||||
EQ = 266,
|
||||
NEQ = 267,
|
||||
LT = 268,
|
||||
GT = 269,
|
||||
GTE = 270,
|
||||
LTE = 271,
|
||||
STRING = 272,
|
||||
MINUSSIGN = 273,
|
||||
PROPERTY_REF = 274,
|
||||
DOCUMENT = 275,
|
||||
OBJECT = 276,
|
||||
EXPONENT = 277,
|
||||
NEG = 278,
|
||||
POS = 279
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
extern YYSTYPE yylval;
|
||||
|
||||
|
||||
178
src/App/ExpressionParser.y
Normal file
178
src/App/ExpressionParser.y
Normal file
@@ -0,0 +1,178 @@
|
||||
/* Parser for the FreeCAD Units language */
|
||||
/* (c) 2010 Juergen Riegel LGPL */
|
||||
/* (c) 2015 Eivind Kvedalen LGPL */
|
||||
|
||||
/* Represents the many different ways we can access our data */
|
||||
|
||||
%{
|
||||
|
||||
#define YYSTYPE semantic_type
|
||||
|
||||
std::stack<FunctionExpression::Function> functions; /**< Function identifier */
|
||||
|
||||
//#define YYSTYPE yystype
|
||||
#define yyparse ExpressionParser_yyparse
|
||||
#define yyerror ExpressionParser_yyerror
|
||||
%}
|
||||
|
||||
/* Bison declarations. */
|
||||
%token FUNC
|
||||
%token ONE
|
||||
%token NUM
|
||||
%token IDENTIFIER
|
||||
%token UNIT
|
||||
%token INTEGER
|
||||
%token CONSTANT
|
||||
%token CELLADDRESS
|
||||
%token EQ NEQ LT GT GTE LTE
|
||||
%token STRING MINUSSIGN PROPERTY_REF
|
||||
%token DOCUMENT OBJECT
|
||||
%token EXPONENT
|
||||
%type <arguments> args
|
||||
%type <expr> input exp unit_exp cond
|
||||
%type <quantity> UNIT
|
||||
%type <string> STRING IDENTIFIER CELLADDRESS
|
||||
%type <ivalue> INTEGER
|
||||
%type <string> PROPERTY_REF
|
||||
%type <fvalue> ONE
|
||||
%type <fvalue> NUM
|
||||
%type <constant> CONSTANT
|
||||
%type <expr> num
|
||||
%type <expr> basic_num
|
||||
%type <path> identifier
|
||||
%type <components> path subpath
|
||||
%type <func> FUNC
|
||||
%type <string_or_identifier> document
|
||||
%type <string_or_identifier> object
|
||||
%type <ivalue> integer
|
||||
%left ONE
|
||||
%left NUM
|
||||
%left INTEGER
|
||||
%left CONSTANT
|
||||
%left MINUSSIGN '+'
|
||||
%left '*' '/'
|
||||
%left '?' ':' EQ NEQ LT GT GTE LTE
|
||||
%left NEG /* negation--unary minus */
|
||||
%left POS /* unary plus */
|
||||
%right '^' /* exponentiation */
|
||||
%right EXPONENT
|
||||
|
||||
%destructor { delete $$; } exp cond unit_exp
|
||||
%destructor { std::vector<Expression*>::const_iterator i = $$.begin(); while (i != $$.end()) { delete *i; ++i; } } args
|
||||
|
||||
%start input
|
||||
|
||||
%%
|
||||
|
||||
input: exp { ScanResult = $1; valueExpression = true; }
|
||||
| unit_exp { ScanResult = $1; unitExpression = true; }
|
||||
;
|
||||
|
||||
exp: num { $$ = $1; }
|
||||
| STRING { $$ = new StringExpression(DocumentObject, $1); }
|
||||
| identifier { $$ = new VariableExpression(DocumentObject, $1); }
|
||||
| MINUSSIGN exp %prec NEG { $$ = new OperatorExpression(DocumentObject, $2, OperatorExpression::NEG, new NumberExpression(DocumentObject, -1)); }
|
||||
| '+' exp %prec POS { $$ = new OperatorExpression(DocumentObject, $2, OperatorExpression::POS, new NumberExpression(DocumentObject, 1)); }
|
||||
| exp '+' exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::ADD, $3); }
|
||||
| exp MINUSSIGN exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::SUB, $3); }
|
||||
| exp '*' exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::MUL, $3); }
|
||||
| exp '/' exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::DIV, $3); }
|
||||
| exp '/' unit_exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::DIV, $3); }
|
||||
| exp '^' exp %prec EXPONENT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, $3); }
|
||||
| '(' exp ')' { $$ = $2; }
|
||||
| FUNC args ')' { $$ = new FunctionExpression(DocumentObject, $1, $2); }
|
||||
| cond '?' exp ':' exp { $$ = new ConditionalExpression(DocumentObject, $1, $3, $5); }
|
||||
;
|
||||
|
||||
basic_num: ONE { $$ = new NumberExpression(DocumentObject, $1); }
|
||||
| NUM { $$ = new NumberExpression(DocumentObject, $1); }
|
||||
| INTEGER { $$ = new NumberExpression(DocumentObject, (double)$1); }
|
||||
;
|
||||
|
||||
num: basic_num { $$ = $1; }
|
||||
| CONSTANT { $$ = new ConstantExpression(DocumentObject, $1.name, $1.fvalue); }
|
||||
| basic_num unit_exp %prec EXPONENT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::UNIT, $2); }
|
||||
| CONSTANT unit_exp { $$ = new OperatorExpression(DocumentObject, new ConstantExpression(DocumentObject, $1.name, $1.fvalue), OperatorExpression::UNIT, $2); }
|
||||
;
|
||||
|
||||
args: exp { $$.push_back($1); }
|
||||
| args ',' exp { $1.push_back($3); $$ = $1; }
|
||||
| args ';' exp { $1.push_back($3); $$ = $1; }
|
||||
;
|
||||
|
||||
cond: exp EQ exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::EQ, $3); }
|
||||
| exp NEQ exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::NEQ, $3); }
|
||||
| exp LT exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::LT, $3); }
|
||||
| exp GT exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::GT, $3); }
|
||||
| exp GTE exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::GTE, $3); }
|
||||
| exp LTE exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::LTE, $3); }
|
||||
;
|
||||
|
||||
unit_exp: UNIT { $$ = new UnitExpression(DocumentObject, $1.scaler, $1.unitStr ); }
|
||||
| ONE '/' unit_exp { $$ = new OperatorExpression(DocumentObject, new NumberExpression(DocumentObject, $1), OperatorExpression::DIV, $3); }
|
||||
| unit_exp '/' unit_exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::DIV, $3); }
|
||||
| unit_exp '*' unit_exp { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::MUL, $3); }
|
||||
| unit_exp '^' basic_num %prec EXPONENT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, $3); }
|
||||
| unit_exp '^' MINUSSIGN basic_num %prec EXPONENT { $$ = new OperatorExpression(DocumentObject, $1, OperatorExpression::POW, new OperatorExpression(DocumentObject, $4, OperatorExpression::NEG, new NumberExpression(DocumentObject, -1))); }
|
||||
| '(' unit_exp ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
identifier: path { /* Path to property within document object */
|
||||
$$ = ObjectIdentifier(DocumentObject);
|
||||
$$.addComponents($1);
|
||||
}
|
||||
| object '.' path { /* Path to property within document object */
|
||||
$$ = ObjectIdentifier(DocumentObject);
|
||||
$$.setDocumentObjectName($1, true);
|
||||
$$.addComponents($3);
|
||||
}
|
||||
| document '#' path { /* Path to property from an external document, within a named document object */
|
||||
$$ = ObjectIdentifier(DocumentObject);
|
||||
$$.setDocumentName($1, true);
|
||||
$$.addComponents($3);
|
||||
}
|
||||
| document '#' object '.' path { /* Path to property from an external document, within a named document object */
|
||||
$$ = ObjectIdentifier(DocumentObject);
|
||||
$$.setDocumentName($1, true);
|
||||
$$.setDocumentObjectName($3, true);
|
||||
$$.addComponents($5);
|
||||
}
|
||||
;
|
||||
|
||||
integer: INTEGER { $$ = $1; }
|
||||
| ONE { $$ = $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; }
|
||||
;
|
||||
|
||||
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; }
|
||||
;
|
||||
|
||||
document: STRING { $$ = ObjectIdentifier::String($1, true); }
|
||||
| IDENTIFIER { $$ = ObjectIdentifier::String($1); }
|
||||
;
|
||||
|
||||
object: STRING { $$ = ObjectIdentifier::String($1, true); }
|
||||
| CELLADDRESS { $$ = ObjectIdentifier::String($1, true); }
|
||||
;
|
||||
|
||||
%%
|
||||
940
src/App/ObjectIdentifier.cpp
Normal file
940
src/App/ObjectIdentifier.cpp
Normal file
@@ -0,0 +1,940 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) Eivind Kvedalen (eivind@kvedalen.name) 2015 *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <cassert>
|
||||
#endif
|
||||
|
||||
/// Here the FreeCAD includes sorted by Base,App,Gui......
|
||||
#include "Property.h"
|
||||
#include "Application.h"
|
||||
#include "Document.h"
|
||||
#include "DocumentObject.h"
|
||||
#include "ObjectIdentifier.h"
|
||||
#include "Expression.h"
|
||||
#include <Base/Tools.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/QuantityPy.h>
|
||||
|
||||
using namespace App;
|
||||
using namespace Base;
|
||||
|
||||
/**
|
||||
* @brief Compute a hash value for the object identifier given by \a path.
|
||||
* @param path Inputn path
|
||||
* @return Hash value
|
||||
*/
|
||||
|
||||
std::size_t App::hash_value(const App::ObjectIdentifier & path)
|
||||
{
|
||||
return boost::hash_value(path.toString());
|
||||
}
|
||||
|
||||
// Path class
|
||||
|
||||
/**
|
||||
* @brief Quote input string according to quoting rules for an expression: because " and ' are
|
||||
* used to designate inch and foot units, strings are quoted as <<string>>.
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
|
||||
std::string App::quote(const std::string &input)
|
||||
{
|
||||
std::stringstream output;
|
||||
|
||||
std::string::const_iterator cur = input.begin();
|
||||
std::string::const_iterator end = input.end();
|
||||
|
||||
output << "<<";
|
||||
while (cur != end) {
|
||||
switch (*cur) {
|
||||
case '\t':
|
||||
output << "\\t";
|
||||
break;
|
||||
case '\n':
|
||||
output << "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
output << "\\r";
|
||||
break;
|
||||
case '\\':
|
||||
output << "\\\\";
|
||||
break;
|
||||
case '\'':
|
||||
output << "\\'";
|
||||
break;
|
||||
case '"':
|
||||
output << "\\\"";
|
||||
break;
|
||||
case '>':
|
||||
output << "\\>";
|
||||
break;
|
||||
default:
|
||||
output << *cur;
|
||||
}
|
||||
++cur;
|
||||
}
|
||||
output << ">>";
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct an ObjectIdentifier object, given an owner and a single-value property.
|
||||
* @param _owner Owner of property.
|
||||
* @param property Name of property.
|
||||
*/
|
||||
|
||||
ObjectIdentifier::ObjectIdentifier(const App::PropertyContainer * _owner, const std::string & property)
|
||||
: owner(_owner)
|
||||
, documentNameSet(false)
|
||||
, documentObjectNameSet(false)
|
||||
, propertyIndex(-1)
|
||||
{
|
||||
if (property.size() > 0)
|
||||
addComponent(Component::SimpleComponent(property));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct an ObjectIdentifier object given a property. The property is assumed to be single-valued.
|
||||
* @param prop Property to construct object idenfier for.
|
||||
*/
|
||||
|
||||
ObjectIdentifier::ObjectIdentifier(const Property &prop)
|
||||
: owner(prop.getContainer())
|
||||
, documentNameSet(false)
|
||||
, documentObjectNameSet(false)
|
||||
, propertyIndex(-1)
|
||||
{
|
||||
addComponent(Component::SimpleComponent(String(owner->getPropertyName(&prop))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the name of the property.
|
||||
* @return Name
|
||||
*/
|
||||
|
||||
const std::string App::ObjectIdentifier::getPropertyName() const
|
||||
{
|
||||
resolve();
|
||||
|
||||
assert(propertyIndex >=0 && static_cast<std::size_t>(propertyIndex) < components.size());
|
||||
|
||||
return components[propertyIndex].toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get Component at given index \a i.
|
||||
* @param i Index to get
|
||||
* @return A component.
|
||||
*/
|
||||
|
||||
const App::ObjectIdentifier::Component &App::ObjectIdentifier::getPropertyComponent(int i) const
|
||||
{
|
||||
resolve();
|
||||
|
||||
assert(propertyIndex + i >=0 && static_cast<std::size_t>(propertyIndex) + i < components.size());
|
||||
|
||||
return components[propertyIndex + i];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare object identifier with \a other.
|
||||
* @param other Other object identifier.
|
||||
* @return true if they are equal.
|
||||
*/
|
||||
|
||||
bool ObjectIdentifier::operator ==(const ObjectIdentifier &other) const
|
||||
{
|
||||
resolve();
|
||||
other.resolve();
|
||||
|
||||
if (owner != other.owner)
|
||||
return false;
|
||||
if (documentName != other.documentName)
|
||||
return false;
|
||||
if (documentObjectName != other.documentObjectName)
|
||||
return false;
|
||||
if (components != other.components)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare object identifier with \a other.
|
||||
* @param other Other object identifier
|
||||
* @return true if they differ from each other.
|
||||
*/
|
||||
|
||||
bool ObjectIdentifier::operator !=(const ObjectIdentifier &other) const
|
||||
{
|
||||
return !(operator==)(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare object identifier with other.
|
||||
* @param other Other object identifier.
|
||||
* @return true if this object is less than the other.
|
||||
*/
|
||||
|
||||
bool ObjectIdentifier::operator <(const ObjectIdentifier &other) const
|
||||
{
|
||||
resolve();
|
||||
other.resolve();
|
||||
|
||||
if (documentName < other.documentName)
|
||||
return true;
|
||||
|
||||
if (documentName > other.documentName)
|
||||
return false;
|
||||
|
||||
if (documentObjectName < other.documentObjectName)
|
||||
return true;
|
||||
|
||||
if (documentObjectName > other.documentObjectName)
|
||||
return false;
|
||||
|
||||
if (components.size() < other.components.size())
|
||||
return true;
|
||||
|
||||
if (components.size() > other.components.size())
|
||||
return false;
|
||||
|
||||
for (std::size_t i = 0; i < components.size(); ++i) {
|
||||
if (components[i].name < other.components[i].name)
|
||||
return true;
|
||||
if (components[i].name > other.components[i].name)
|
||||
return false;
|
||||
if (components[i].type < other.components[i].type)
|
||||
return true;
|
||||
if (components[i].type > other.components[i].type)
|
||||
return false;
|
||||
if (components[i].isArray()) {
|
||||
if (components[i].index < other.components[i].index)
|
||||
return true;
|
||||
if (components[i].index > other.components[i].index)
|
||||
return false;
|
||||
}
|
||||
else if (components[i].isMap()) {
|
||||
if (components[i].key < other.components[i].key)
|
||||
return true;
|
||||
if (components[i].key > other.components[i].key)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return number of components.
|
||||
* @return Number of components in this identifier.
|
||||
*/
|
||||
|
||||
int ObjectIdentifier::numComponents() const
|
||||
{
|
||||
return components.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute number of sub components, i.e excluding the property.
|
||||
* @return Number of components.
|
||||
*/
|
||||
|
||||
int ObjectIdentifier::numSubComponents() const
|
||||
{
|
||||
return components.size() - propertyIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of this object identifier.
|
||||
*
|
||||
* An identifier is written as document#documentobject.property.subproperty1...subpropertyN
|
||||
* document# may be dropped; it is assumed to be within owner's document. If documentobject is dropped,
|
||||
* the property is assumed to be owned by the owner specified in the object identifiers constructor.
|
||||
*
|
||||
* @return A string
|
||||
*/
|
||||
|
||||
std::string ObjectIdentifier::toString() const
|
||||
{
|
||||
std::stringstream s;
|
||||
|
||||
resolve();
|
||||
|
||||
if (documentNameSet)
|
||||
s << getDocumentName().toString() << "#";
|
||||
|
||||
if (documentObjectNameSet)
|
||||
s << getDocumentObjectName().toString() << ".";
|
||||
else if (propertyIndex > 0)
|
||||
s << components[0].toString() << ".";
|
||||
|
||||
s << getPropertyName() << getSubPathStr();
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Escape toString representation so it is suitable for being embeddded in a python command.
|
||||
* @return Escaped string.
|
||||
*/
|
||||
|
||||
std::string ObjectIdentifier::toEscapedString() const
|
||||
{
|
||||
return Base::Tools::escapedUnicodeFromUtf8(toString().c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Modifiy object identifier given that document object \a oldName gets the new name \a newName.
|
||||
* @param oldName Name of current document object
|
||||
* @param newName New name of document object
|
||||
*/
|
||||
|
||||
void ObjectIdentifier::renameDocumentObject(const std::string &oldName, const std::string &newName)
|
||||
{
|
||||
if (documentObjectNameSet && documentObjectName == oldName) {
|
||||
if (ExpressionParser::isTokenAnIndentifier(newName))
|
||||
documentObjectName = newName;
|
||||
else
|
||||
documentObjectName = ObjectIdentifier::String(newName, true);
|
||||
}
|
||||
else if (propertyIndex == 1 && documentObjectName == oldName) {
|
||||
if (ExpressionParser::isTokenAnIndentifier(newName))
|
||||
components[0].name = newName;
|
||||
else
|
||||
components[0].name = ObjectIdentifier::String(newName, true);
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Modify object identifier given that the document \a oldName has changed name to \a newName.
|
||||
* @param oldName Name of current document
|
||||
* @param newName New name of document
|
||||
*/
|
||||
|
||||
void ObjectIdentifier::renameDocument(const std::string &oldName, const std::string &newName)
|
||||
{
|
||||
if (documentName == oldName) {
|
||||
documentName = newName;
|
||||
}
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sub field part of a property as a string.
|
||||
* @return String representation of path.
|
||||
*/
|
||||
|
||||
std::string ObjectIdentifier::getSubPathStr() const
|
||||
{
|
||||
resolve();
|
||||
|
||||
std::stringstream s;
|
||||
std::vector<Component>::const_iterator i = components.begin() + propertyIndex + 1;
|
||||
while (i != components.end()) {
|
||||
s << "." << i->toString();
|
||||
++i;
|
||||
}
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a Component part
|
||||
* @param _component Name of component
|
||||
* @param _type Type; simple, array, or map
|
||||
* @param _index Array index, if type is array, or -1 if simple or map.
|
||||
* @param _key Key index, if type is map, ir empty if simple or array.
|
||||
*/
|
||||
|
||||
ObjectIdentifier::Component::Component(const String &_component, ObjectIdentifier::Component::typeEnum _type, int _index, String _key)
|
||||
: name(_component)
|
||||
, type(_type)
|
||||
, index(_index)
|
||||
, key(_key)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a simple component part with the given name
|
||||
* @param _component Name of component.
|
||||
* @return A new Component object.
|
||||
*/
|
||||
|
||||
ObjectIdentifier::Component ObjectIdentifier::Component::SimpleComponent(const char *_component)
|
||||
{
|
||||
return Component(String(_component));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a simple component part with the given name
|
||||
* @param _component Name of component.
|
||||
* @return A new Component object.
|
||||
*/
|
||||
|
||||
ObjectIdentifier::Component ObjectIdentifier::Component::SimpleComponent(const ObjectIdentifier::String &_component)
|
||||
{
|
||||
return Component(_component);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create an array component with given name and index.
|
||||
* @param _component Name of component
|
||||
* @param _index Index of component
|
||||
* @return A new Component object.
|
||||
*/
|
||||
|
||||
ObjectIdentifier::Component ObjectIdentifier::Component::ArrayComponent(const ObjectIdentifier::String &_component, int _index)
|
||||
{
|
||||
return Component(_component, ARRAY, _index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a map component with given name and key.
|
||||
* @param _component Name of component
|
||||
* @param _key Key of component
|
||||
* @return A new Component object.
|
||||
*/
|
||||
|
||||
ObjectIdentifier::Component ObjectIdentifier::Component::MapComponent(const ObjectIdentifier::String &_component, const String & _key)
|
||||
{
|
||||
return Component(_component, MAP, -1, _key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Comparison operator for Component objects.
|
||||
* @param other The object we want to compare to.
|
||||
* @return true if they are equal, false if not.
|
||||
*/
|
||||
|
||||
bool ObjectIdentifier::Component::operator ==(const ObjectIdentifier::Component &other) const
|
||||
{
|
||||
if (type != other.type)
|
||||
return false;
|
||||
|
||||
if (name != other.name)
|
||||
return false;
|
||||
|
||||
switch (type) {
|
||||
case SIMPLE:
|
||||
return true;
|
||||
case ARRAY:
|
||||
return index == other.index;
|
||||
case MAP:
|
||||
return key == other.key;
|
||||
default:
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a string representation of a component.
|
||||
* @return A string representing the component.
|
||||
*/
|
||||
|
||||
std::string ObjectIdentifier::Component::toString() const
|
||||
{
|
||||
std::stringstream s;
|
||||
|
||||
s << name.toString();
|
||||
switch (type) {
|
||||
case Component::SIMPLE:
|
||||
break;
|
||||
case Component::MAP:
|
||||
s << "[" << key.toString() << "]";
|
||||
break;
|
||||
case Component::ARRAY:
|
||||
s << "[" << index << "]";
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Search for the document object given by name in doc.
|
||||
*
|
||||
* Name might be the internal name or a label. In any case, it must uniquely define
|
||||
* the document object.
|
||||
*
|
||||
* @param doc Document to search
|
||||
* @param name Name to search for.
|
||||
* @return Pointer to document object if a unique pointer is found, 0 otherwise.
|
||||
*/
|
||||
|
||||
App::DocumentObject * ObjectIdentifier::getDocumentObject(const App::Document * doc, const std::string & name) const
|
||||
{
|
||||
DocumentObject * o1 = 0;
|
||||
DocumentObject * o2 = 0;
|
||||
std::vector<DocumentObject*> docObjects = doc->getObjects();
|
||||
|
||||
for (std::vector<DocumentObject*>::iterator j = docObjects.begin(); j != docObjects.end(); ++j) {
|
||||
if (strcmp((*j)->Label.getValue(), name.c_str()) == 0) {
|
||||
// Found object with matching label
|
||||
if (o1 != 0)
|
||||
return 0;
|
||||
o1 = *j;
|
||||
}
|
||||
}
|
||||
|
||||
// No object found with matching label, try using name directly
|
||||
o2 = doc->getObject(name.c_str());
|
||||
|
||||
if (o1 == 0 && o2 == 0) // Not found at all
|
||||
return 0;
|
||||
else if (o1 == 0) // Found by name
|
||||
return o2;
|
||||
else if (o2 == 0) // Found by label
|
||||
return o1;
|
||||
else if (o1 == o2) // Found by both name and label, same object
|
||||
return o1;
|
||||
else
|
||||
return 0; // Found by both name and label, two different objects
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resolve the object identifier to a concrete document, documentobject, and property.
|
||||
*
|
||||
* This method is a helper methos that updates mutable data in the object, to be used by
|
||||
* other public methods of this class.
|
||||
*
|
||||
*/
|
||||
|
||||
void ObjectIdentifier::resolve() const
|
||||
{
|
||||
const App::Document * doc;
|
||||
const App::DocumentObject * docObject;
|
||||
|
||||
if (freecad_dynamic_cast<DocumentObject>(owner) == 0)
|
||||
return;
|
||||
|
||||
/* Document name specified? */
|
||||
if (documentName.getString().size() > 0) {
|
||||
doc = getDocument(documentName);
|
||||
}
|
||||
else
|
||||
doc = freecad_dynamic_cast<DocumentObject>(owner)->getDocument();
|
||||
|
||||
propertyName = "";
|
||||
propertyIndex = 0;
|
||||
|
||||
// Assume document name and object name from owner if not found
|
||||
if (doc == 0) {
|
||||
doc = freecad_dynamic_cast<DocumentObject>(owner)->getDocument();
|
||||
if (doc == 0) {
|
||||
documentName = String();
|
||||
documentObjectName = String();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
documentName = String(doc->Label.getValue());
|
||||
|
||||
/* Document object name specified? */
|
||||
if (documentObjectNameSet) {
|
||||
docObject = getDocumentObject(doc, documentObjectName.getString());
|
||||
if (!docObject)
|
||||
return;
|
||||
if (components.size() > 0) {
|
||||
propertyName = components[0].name.getString();
|
||||
propertyIndex = 0;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
else {
|
||||
/* Document object name not specified, resolve from path */
|
||||
if (components.size() == 1) {
|
||||
documentObjectName = String(freecad_dynamic_cast<DocumentObject>(owner)->getNameInDocument());
|
||||
propertyName = components[0].name.getString();
|
||||
propertyIndex = 0;
|
||||
}
|
||||
else if (components.size() >= 2) {
|
||||
if (!components[0].isSimple())
|
||||
return;
|
||||
|
||||
docObject = getDocumentObject(doc, components[0].name);
|
||||
|
||||
if (docObject) {
|
||||
documentObjectName = components[0].name;
|
||||
propertyName = components[1].name.getString();
|
||||
propertyIndex = 1;
|
||||
}
|
||||
else {
|
||||
documentObjectName = String(freecad_dynamic_cast<DocumentObject>(owner)->getNameInDocument());
|
||||
propertyName = components[0].name.getString();
|
||||
propertyIndex = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find a document with the given name.
|
||||
* @param name Name of document
|
||||
* @return Pointer to document, or 0 if it is not found or not uniquely defined by name.
|
||||
*/
|
||||
|
||||
Document * ObjectIdentifier::getDocument(String name) const
|
||||
{
|
||||
App::Document * doc = 0;
|
||||
const std::vector<App::Document*> docs = App::GetApplication().getDocuments();
|
||||
|
||||
if (name.getString().size() == 0)
|
||||
name = getDocumentName();
|
||||
|
||||
for (std::vector<App::Document*>::const_iterator i = docs.begin(); i != docs.end(); ++i) {
|
||||
if ((*i)->Label.getValue() == name.getString()) {
|
||||
if (doc != 0)
|
||||
return 0;
|
||||
doc = *i;
|
||||
}
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the document object for the object identifier.
|
||||
* @return Pointer to document object, or 0 if not found or uniquely defined.
|
||||
*/
|
||||
|
||||
DocumentObject *ObjectIdentifier::getDocumentObject() const
|
||||
{
|
||||
const App::Document * doc = getDocument();
|
||||
|
||||
if (!doc)
|
||||
return 0;
|
||||
|
||||
return getDocumentObject(doc, documentObjectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get components as a string list.
|
||||
* @return List of strings.
|
||||
*/
|
||||
|
||||
std::vector<std::string> ObjectIdentifier::getStringList() const
|
||||
{
|
||||
std::vector<std::string> l;
|
||||
|
||||
if (documentNameSet)
|
||||
l.push_back(documentName.toString());
|
||||
if (documentObjectNameSet)
|
||||
l.push_back(documentObjectName.toString());
|
||||
|
||||
std::vector<Component>::const_iterator i = components.begin();
|
||||
while (i != components.end()) {
|
||||
l.push_back(i->toString());
|
||||
++i;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct the simplest possible object identifier relative to another.
|
||||
* @param other The other object identifier.
|
||||
* @return A new simplified object identifier.
|
||||
*/
|
||||
|
||||
ObjectIdentifier ObjectIdentifier::relativeTo(const ObjectIdentifier &other) const
|
||||
{
|
||||
ObjectIdentifier result(owner);
|
||||
|
||||
if (other.getDocument() != getDocument())
|
||||
result.setDocumentName(getDocumentName(), true);
|
||||
if (other.getDocumentObject() != getDocumentObject())
|
||||
result.setDocumentObjectName(getDocumentObjectName(), true);
|
||||
|
||||
for (std::size_t i = propertyIndex; i < components.size(); ++i)
|
||||
result << components[i];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse a string to create an object identifier.
|
||||
*
|
||||
* This method throws an exception if the string is invalid.
|
||||
*
|
||||
* @param docObj Document object that will own this object identifier.
|
||||
* @param str String to parse
|
||||
* @return A new object identifier.
|
||||
*/
|
||||
|
||||
ObjectIdentifier ObjectIdentifier::parse(const DocumentObject *docObj, const std::string &str)
|
||||
{
|
||||
std::auto_ptr<Expression> expr(ExpressionParser::parse(docObj, str.c_str()));
|
||||
VariableExpression * v = freecad_dynamic_cast<VariableExpression>(expr.get());
|
||||
|
||||
if (v)
|
||||
return v->getPath();
|
||||
else
|
||||
throw Base::Exception("Invalid property specification.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief << operator, used to add a component to the object identifier.
|
||||
* @param value Component object
|
||||
* @return Reference to itself.
|
||||
*/
|
||||
|
||||
ObjectIdentifier &ObjectIdentifier::operator <<(const ObjectIdentifier::Component &value)
|
||||
{
|
||||
components.push_back(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get pointer to property pointed to by this object identifier.
|
||||
* @return Point to property if it is uniquely defined, or 0 otherwise.
|
||||
*/
|
||||
|
||||
Property *ObjectIdentifier::getProperty() const
|
||||
{
|
||||
const App::Document * doc = getDocument();
|
||||
|
||||
if (!doc)
|
||||
return 0;
|
||||
|
||||
App::DocumentObject * docObj = getDocumentObject(doc, documentObjectName);
|
||||
|
||||
if (!docObj)
|
||||
return 0;
|
||||
|
||||
return docObj->getPropertyByName(getPropertyComponent(0).getName().c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a canonical representation of an object identifier.
|
||||
*
|
||||
* The main work is actually done by the property's virtual canonicalPath(...) method,
|
||||
* which is invoked by this call.
|
||||
*
|
||||
* @return A new object identifier.
|
||||
*/
|
||||
|
||||
ObjectIdentifier ObjectIdentifier::canonicalPath() const
|
||||
{
|
||||
// Simplify input path by ensuring that components array only has property + optional sub-properties first.
|
||||
ObjectIdentifier simplified(getDocumentObject());
|
||||
|
||||
for (std::size_t i = propertyIndex; i < components.size(); ++i)
|
||||
simplified << components[i];
|
||||
|
||||
Property * prop = getProperty();
|
||||
|
||||
// Invoke properties canonicalPath method, to let the property do the rest of the job.
|
||||
|
||||
return prop ? prop->canonicalPath(simplified) : simplified;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the document name for this object identifier.
|
||||
*
|
||||
* If force is true, the document name will always be included in the string representation.
|
||||
*
|
||||
* @param name Name of document object.
|
||||
* @param force Force name to be set
|
||||
*/
|
||||
|
||||
void ObjectIdentifier::setDocumentName(const ObjectIdentifier::String &name, bool force)
|
||||
{
|
||||
documentName = name;
|
||||
documentNameSet = force;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the document name from this object identifier
|
||||
*
|
||||
* @return Document name as a String object.
|
||||
*/
|
||||
|
||||
const ObjectIdentifier::String ObjectIdentifier::getDocumentName() const
|
||||
{
|
||||
resolve();
|
||||
return documentName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the document object name of this object identifier.
|
||||
*
|
||||
* If force is true, the document object will not be resolved dynamically from the
|
||||
* object identifier's components, but used as given by this method.
|
||||
*
|
||||
* @param name Name of document object.
|
||||
* @param force Force name to be set.
|
||||
*/
|
||||
|
||||
void ObjectIdentifier::setDocumentObjectName(const ObjectIdentifier::String &name, bool force)
|
||||
{
|
||||
documentObjectName = name;
|
||||
documentObjectNameSet = force;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the document object name
|
||||
* @return String with name of document object as resolved by object identifier.
|
||||
*/
|
||||
|
||||
const ObjectIdentifier::String ObjectIdentifier::getDocumentObjectName() const
|
||||
{
|
||||
resolve();
|
||||
return documentObjectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a string representation of this object identifier.
|
||||
* @return String representation.
|
||||
*/
|
||||
|
||||
std::string ObjectIdentifier::String::toString() const
|
||||
{
|
||||
if (isRealString())
|
||||
return quote(str);
|
||||
else
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return a string that can be used to access the property or field pointed to by
|
||||
* this object identifier.
|
||||
* @return Python code as a string
|
||||
*/
|
||||
|
||||
std::string ObjectIdentifier::getPythonAccessor() const
|
||||
{
|
||||
std::stringstream s;
|
||||
DocumentObject * docObj = getDocumentObject();
|
||||
|
||||
s << "App.getDocument('" << getDocumentName() << "')."
|
||||
<< "getObject('" << docObj->getNameInDocument() << "')."
|
||||
<< getPropertyName() << getSubPathStr();
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the value of the property or field pointed to by this object identifier.
|
||||
*
|
||||
* Only a limited number of types are supported: Int, Float, String, Unicode String, and Quantities.
|
||||
*
|
||||
* @return The value of the property or field.
|
||||
*/
|
||||
|
||||
boost::any ObjectIdentifier::getValue() const
|
||||
{
|
||||
std::string s = "_path_value_temp_ = " + getPythonAccessor();
|
||||
PyObject * pyvalue = Base::Interpreter().getValue(s.c_str(), "_path_value_temp_");
|
||||
|
||||
class destructor {
|
||||
public:
|
||||
destructor(PyObject * _p) : p(_p) { }
|
||||
~destructor() { Py_DECREF(p); }
|
||||
private:
|
||||
PyObject * p;
|
||||
};
|
||||
|
||||
destructor d1(pyvalue);
|
||||
|
||||
if (!pyvalue)
|
||||
throw Base::Exception("Failed to get property value.");
|
||||
|
||||
if (PyInt_Check(pyvalue))
|
||||
return boost::any(PyInt_AsLong(pyvalue));
|
||||
else if (PyFloat_Check(pyvalue))
|
||||
return boost::any(PyFloat_AsDouble(pyvalue));
|
||||
else if (PyString_Check(pyvalue))
|
||||
return boost::any(PyString_AsString(pyvalue));
|
||||
else if (PyUnicode_Check(pyvalue)) {
|
||||
PyObject * s = PyUnicode_AsUTF8String(pyvalue);
|
||||
destructor d2(s);
|
||||
|
||||
return boost::any(PyString_AsString(s));
|
||||
}
|
||||
else if (PyObject_TypeCheck(pyvalue, &Base::QuantityPy::Type)) {
|
||||
Base::QuantityPy * qp = static_cast<Base::QuantityPy*>(pyvalue);
|
||||
Base::Quantity * q = qp->getQuantityPtr();
|
||||
|
||||
return boost::any(*q);
|
||||
}
|
||||
else {
|
||||
throw Base::Exception("Invalid property type.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set value of a property or field pointed to by this object identifier.
|
||||
*
|
||||
* This method uses Python to do the actual work. and a limited set of types that
|
||||
* can be in the boost::any variable is supported: Base::Quantity, double,
|
||||
* char*, const char*, int, unsigned int, short, unsigned short, char, and unsigned char.
|
||||
*
|
||||
* @param value Value to set
|
||||
*/
|
||||
|
||||
void ObjectIdentifier::setValue(const boost::any &value) const
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << getPythonAccessor() + " = ";
|
||||
|
||||
if (value.type() == typeid(Base::Quantity))
|
||||
ss << boost::any_cast<Base::Quantity>(value).getValue();
|
||||
else if (value.type() == typeid(double))
|
||||
ss << boost::any_cast<double>(value);
|
||||
else if (value.type() == typeid(char*))
|
||||
ss << '\'' << Base::Tools::escapedUnicodeFromUtf8(boost::any_cast<char*>(value)) << '\'';
|
||||
else if (value.type() == typeid(const char*))
|
||||
ss << '\'' << Base::Tools::escapedUnicodeFromUtf8(boost::any_cast<const char*>(value)) << '\'';
|
||||
else if (value.type() == typeid(std::string))
|
||||
ss << '\'' << Base::Tools::escapedUnicodeFromUtf8(boost::any_cast<std::string>(value).c_str()) << '\'';
|
||||
else if (value.type() == typeid(int))
|
||||
ss << boost::any_cast<int>(value);
|
||||
else if (value.type() == typeid(unsigned int))
|
||||
ss << boost::any_cast<unsigned int >(value);
|
||||
else if (value.type() == typeid(short))
|
||||
ss << boost::any_cast<short>(value);
|
||||
else if (value.type() == typeid(unsigned short))
|
||||
ss << boost::any_cast<unsigned short>(value);
|
||||
else if (value.type() == typeid(char))
|
||||
ss << boost::any_cast<char>(value);
|
||||
else if (value.type() == typeid(unsigned char))
|
||||
ss << boost::any_cast<unsigned char>(value);
|
||||
else
|
||||
throw std::bad_cast();
|
||||
|
||||
Base::Interpreter().runString(ss.str().c_str());
|
||||
}
|
||||
249
src/App/ObjectIdentifier.h
Normal file
249
src/App/ObjectIdentifier.h
Normal file
@@ -0,0 +1,249 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) Eivind Kvedalen <eivind@kvedalen.name> 2015 *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef APP_PATH_H
|
||||
#define APP_PATH_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <boost/any.hpp>
|
||||
|
||||
namespace App
|
||||
{
|
||||
|
||||
class Property;
|
||||
class Document;
|
||||
class PropertyContainer;
|
||||
class DocumentObject;
|
||||
|
||||
AppExport std::string quote(const std::string &input);
|
||||
|
||||
class AppExport ObjectIdentifier {
|
||||
|
||||
public:
|
||||
|
||||
class String {
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
String(const std::string & s = "", bool _isRealString = false) : str(s), isString(_isRealString) { }
|
||||
|
||||
// Accessors
|
||||
|
||||
/** Returns the string */
|
||||
std::string getString() const { return str; }
|
||||
|
||||
/** Return true is string need to be quoted */
|
||||
bool isRealString() const { return isString; }
|
||||
|
||||
/** Returns a possibly quoted string */
|
||||
std::string toString() const;
|
||||
|
||||
// Operators
|
||||
|
||||
operator std::string() const { return str; }
|
||||
|
||||
operator const char *() const { return str.c_str(); }
|
||||
|
||||
bool operator==(const String & other) const { return str == other.str; }
|
||||
|
||||
bool operator!=(const String & other) const { return str != other.str; }
|
||||
|
||||
bool operator>=(const String & other) const { return str >= other.str; }
|
||||
|
||||
bool operator<(const String & other) const { return str < other.str; }
|
||||
|
||||
bool operator>(const String & other) const { return str > other.str; }
|
||||
|
||||
private:
|
||||
|
||||
std::string str;
|
||||
bool isString;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A component is a part of a Path object, and is used to either
|
||||
* name a property or a field within a property. A component can be either
|
||||
* a single entry, and array, or a map to other sub-fields.
|
||||
*/
|
||||
|
||||
class AppExport Component {
|
||||
|
||||
private:
|
||||
|
||||
enum typeEnum {
|
||||
SIMPLE,
|
||||
MAP,
|
||||
ARRAY
|
||||
} ;
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
Component(const String &_component, typeEnum _type = SIMPLE, int _index = -1, String _key = String());
|
||||
|
||||
static Component SimpleComponent(const char * _component);
|
||||
|
||||
static Component SimpleComponent(const String & _component);
|
||||
|
||||
static Component ArrayComponent(const String &_component, int _index);
|
||||
|
||||
static Component MapComponent(const String &_component, const String &_key);
|
||||
|
||||
// Type queries
|
||||
|
||||
bool isSimple() const { return type == SIMPLE; }
|
||||
|
||||
bool isMap() const { return type == MAP; }
|
||||
|
||||
bool isArray() const { return type == ARRAY; }
|
||||
|
||||
// Accessors
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
std::string getName() const { return name.getString(); }
|
||||
|
||||
std::size_t getIndex() const { return static_cast<std::size_t>(index); }
|
||||
|
||||
String getKey() const { return key; }
|
||||
|
||||
bool getKeyIsString() const { return keyIsString; }
|
||||
|
||||
// Operators
|
||||
|
||||
bool operator==(const Component & other) const;
|
||||
|
||||
private:
|
||||
|
||||
String name;
|
||||
typeEnum type;
|
||||
int index;
|
||||
String key;
|
||||
bool keyIsString;
|
||||
|
||||
friend class ObjectIdentifier;
|
||||
|
||||
};
|
||||
|
||||
ObjectIdentifier(const App::PropertyContainer * _owner = 0, const std::string & property = std::string());
|
||||
|
||||
ObjectIdentifier(const App::Property & prop);
|
||||
|
||||
// Components
|
||||
void addComponent(const Component &c) { components.push_back(c); }
|
||||
|
||||
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;
|
||||
|
||||
int numComponents() const;
|
||||
|
||||
int numSubComponents() const;
|
||||
|
||||
virtual std::string toString() const;
|
||||
|
||||
std::string toEscapedString() const;
|
||||
|
||||
App::Property *getProperty() const;
|
||||
|
||||
App::ObjectIdentifier canonicalPath() const;
|
||||
|
||||
// Document-centric functions
|
||||
|
||||
void setDocumentName(const String & name, bool force = false);
|
||||
|
||||
const String getDocumentName() const;
|
||||
|
||||
void setDocumentObjectName(const String & name, bool force = false);
|
||||
|
||||
const String getDocumentObjectName() const;
|
||||
|
||||
void renameDocumentObject(const std::string & oldName, const std::string & newName);
|
||||
|
||||
void renameDocument(const std::string &oldName, const std::string &newName);
|
||||
|
||||
App::Document *getDocument(String name = String()) const;
|
||||
|
||||
App::DocumentObject *getDocumentObject() const;
|
||||
|
||||
std::vector<std::string> getStringList() const;
|
||||
|
||||
App::ObjectIdentifier relativeTo(const App::ObjectIdentifier & other) const;
|
||||
|
||||
// Operators
|
||||
|
||||
App::ObjectIdentifier & operator<<(const Component & value);
|
||||
|
||||
bool operator==(const ObjectIdentifier & other) const;
|
||||
|
||||
bool operator!=(const ObjectIdentifier & other) const;
|
||||
|
||||
bool operator<(const ObjectIdentifier &other) const;
|
||||
|
||||
// Getter
|
||||
|
||||
boost::any getValue() 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;
|
||||
|
||||
// Static functions
|
||||
|
||||
static ObjectIdentifier parse(const App::DocumentObject *docObj, const std::string & str);
|
||||
|
||||
protected:
|
||||
|
||||
std::string getPythonAccessor() const;
|
||||
|
||||
void resolve() const;
|
||||
|
||||
App::DocumentObject *getDocumentObject(const App::Document *doc, const std::string &name) const;
|
||||
|
||||
const App::PropertyContainer * owner;
|
||||
bool documentNameSet;
|
||||
bool documentObjectNameSet;
|
||||
std::vector<Component> components;
|
||||
|
||||
/// Mutable elements, updated by resolve()
|
||||
mutable int propertyIndex;
|
||||
mutable String documentName;
|
||||
mutable String documentObjectName;
|
||||
mutable std::string propertyName;
|
||||
|
||||
};
|
||||
|
||||
std::size_t hash_value(const App::ObjectIdentifier & path);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 *
|
||||
* Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
@@ -29,7 +29,9 @@
|
||||
|
||||
/// Here the FreeCAD includes sorted by Base,App,Gui......
|
||||
#include "Property.h"
|
||||
#include "ObjectIdentifier.h"
|
||||
#include "PropertyContainer.h"
|
||||
#include <Base/Exception.h>
|
||||
|
||||
using namespace App;
|
||||
|
||||
@@ -81,6 +83,26 @@ void Property::setContainer(PropertyContainer *Father)
|
||||
father = Father;
|
||||
}
|
||||
|
||||
void Property::setValue(const ObjectIdentifier &path, const boost::any &value)
|
||||
{
|
||||
path.setValue(value);
|
||||
}
|
||||
|
||||
const boost::any Property::getValue(const ObjectIdentifier &path) const
|
||||
{
|
||||
return path.getValue();
|
||||
}
|
||||
|
||||
void Property::getPaths(std::vector<ObjectIdentifier> &paths) const
|
||||
{
|
||||
paths.push_back(App::ObjectIdentifier(getContainer(), getName()));
|
||||
}
|
||||
|
||||
const ObjectIdentifier Property::canonicalPath(const ObjectIdentifier &p) const
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
void Property::touch()
|
||||
{
|
||||
if (father)
|
||||
@@ -101,6 +123,16 @@ void Property::aboutToSetValue(void)
|
||||
father->onBeforeChange(this);
|
||||
}
|
||||
|
||||
void Property::verifyPath(const ObjectIdentifier &p) const
|
||||
{
|
||||
if (p.numSubComponents() != 1)
|
||||
throw Base::Exception("Invalid property path: single component expected");
|
||||
if (!p.getPropertyComponent(0).isSimple())
|
||||
throw Base::Exception("Invalid property path: simple component expected");
|
||||
if (p.getPropertyComponent(0).getName() != getName())
|
||||
throw Base::Exception("Invalid property path: name mismatch");
|
||||
}
|
||||
|
||||
Property *Property::Copy(void) const
|
||||
{
|
||||
// have to be reimplemented by a subclass!
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
// Std. configurations
|
||||
|
||||
#include <Base/Persistence.h>
|
||||
#include <boost/any.hpp>
|
||||
#include <string>
|
||||
#include <bitset>
|
||||
|
||||
@@ -35,6 +36,7 @@ namespace App
|
||||
{
|
||||
|
||||
class PropertyContainer;
|
||||
class ObjectIdentifier;
|
||||
|
||||
/** Base class of all properties
|
||||
* This is the father of all properties. Properties are objects which are used
|
||||
@@ -84,6 +86,19 @@ public:
|
||||
|
||||
/// Get a pointer to the PropertyContainer derived class the property belongs to
|
||||
PropertyContainer *getContainer(void) const {return father;}
|
||||
|
||||
/// Set value of property
|
||||
virtual void setValue(const App::ObjectIdentifier & path, const boost::any & value);
|
||||
|
||||
/// Get value of property
|
||||
virtual const boost::any getValue(const App::ObjectIdentifier & path) const;
|
||||
|
||||
/// Convert p to a canonical representation of it
|
||||
virtual const App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier & p) const;
|
||||
|
||||
/// Get valid paths for this property; used by auto completer
|
||||
virtual void getPaths(std::vector<App::ObjectIdentifier> & paths) const;
|
||||
|
||||
/// Set the property touched
|
||||
void touch();
|
||||
/// Test if this property is touched
|
||||
@@ -119,6 +134,9 @@ protected:
|
||||
/// Gets called by all setValue() methods before the value has changed
|
||||
void aboutToSetValue(void);
|
||||
|
||||
/// Verify a path for the current property
|
||||
virtual void verifyPath(const App::ObjectIdentifier & p) const;
|
||||
|
||||
private:
|
||||
// forbidden
|
||||
Property(const Property&);
|
||||
|
||||
7316
src/App/lex.ExpressionParser.c
Normal file
7316
src/App/lex.ExpressionParser.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user