/*************************************************************************** * Copyright (c) 2015 Eivind Kvedalen * * * * 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 EXPRESSIONENGINE_H #define EXPRESSIONENGINE_H #include #include #include #include #include #include #include namespace Base { class Writer; class XMLReader; } namespace App { class DocumentObject; class DocumentObjectExecReturn; class ObjectIdentifier; class Expression; using ExpressionPtr = std::unique_ptr; class AppExport PropertyExpressionContainer : public App::PropertyXLinkContainer { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: PropertyExpressionContainer(); ~PropertyExpressionContainer() override; virtual std::map getExpressions() const = 0; virtual void setExpressions(std::map &&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 { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: void updateElementReference( App::DocumentObject *feature, bool reverse=false, bool notify=false) override; bool referenceChanged() const override; bool adjustLink(const std::set &inList) override; Property *CopyOnImportExternal(const std::map &nameMap) const override; Property *CopyOnLabelChange(App::DocumentObject *obj, const std::string &ref, const char *newLabel) const override; Property *CopyOnLinkReplace(const App::DocumentObject *parent, App::DocumentObject *oldObj, App::DocumentObject *newObj) const override; using ValidatorFunc = std::function expr)>; /** * @brief The ExpressionInfo struct encapsulates an expression. */ struct ExpressionInfo { std::shared_ptr expression; /**< The actual expression tree */ bool busy; explicit ExpressionInfo(std::shared_ptr expression = std::shared_ptr()) { this->expression = expression; this->busy = false; } ExpressionInfo(const ExpressionInfo &) = default; ExpressionInfo & operator=(const ExpressionInfo &) = default; }; PropertyExpressionEngine(); ~PropertyExpressionEngine() override; unsigned int getMemSize () const override; std::map getExpressions() const override; void setExpressions(std::map &&exprs) override; void onRelabeledDocument(const App::Document &doc) override; void setValue() { } // Dummy Property *Copy() const override; void Paste(const Property &from) override; void Save (Base::Writer & writer) const override; void Restore(Base::XMLReader &reader) override; void setValue(const App::ObjectIdentifier &path, std::shared_ptr expr); const boost::any getPathValue(const App::ObjectIdentifier & path) const override; /// 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=nullptr); void getPathsToDocumentObject(DocumentObject*, std::vector & paths) const; bool depsAreTouched() const; /* Expression validator */ void setValidator(ValidatorFunc f) { validator = f; } std::string validateExpression(const App::ObjectIdentifier & path, std::shared_ptr expr) const; void renameExpressions(const std::map &paths); void renameObjectIdentifiers(const std::map & paths); App::ObjectIdentifier canonicalPath(const App::ObjectIdentifier &p) const override; size_t numExpressions() const; ///signal called when an expression was changed boost::signals2::signal expressionChanged; void afterRestore() override; void onContainerRestored() override; /* Python interface */ PyObject *getPyObject() override; void setPyObject(PyObject *) override; protected: void hasSetValue() override; private: using DiGraph = boost::adjacency_list< boost::listS, boost::vecS, boost::directedS >; using Edge = std::pair; // Note: use std::map instead of unordered_map to keep the binding order stable #if defined(FC_OS_MACOSX) || defined(FC_OS_BSD) || defined(_LIBCPP_VERSION) using ExpressionMap = std::map; #else using ExpressionMap = std::map; #endif std::vector computeEvaluationOrder(ExecuteOption option); void buildGraphStructures(const App::ObjectIdentifier &path, const std::shared_ptr expression, boost::unordered_map &nodes, boost::unordered_map &revNodes, std::vector &edges) const; void buildGraph(const ExpressionMap &exprs, boost::unordered_map &revNodes, DiGraph &g, ExecuteOption option=ExecuteAll) const; void slotChangedObject(const App::DocumentObject &obj, const App::Property &prop); void slotChangedProperty(const App::DocumentObject &obj, const App::Property &prop); void updateHiddenReference(const std::string &key); bool running = false; /**< Boolean used to avoid loops */ bool restoring = false; ExpressionMap expressions; /**< Stored expressions */ ValidatorFunc validator; /**< Valdiator functor */ 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 > restoredExpressions; struct Private; std::unique_ptr pimpl; friend class AtomicPropertyChange; }; } #endif // EXPRESSIONENGINE_H