Added PropertyExpressionEngine to DocumentObject class.

This commit is contained in:
Eivind Kvedalen 2015-09-17 00:55:54 +02:00 committed by wmayer
parent 8259ec6764
commit fb2b1a6ec0
6 changed files with 166 additions and 4 deletions

View File

@ -1191,6 +1191,7 @@ void Document::restore (void)
// reset all touched
for (std::map<std::string,DocumentObject*>::iterator It= d->objectMap.begin();It!=d->objectMap.end();++It) {
It->second->connectRelabelSignals();
It->second->onDocumentRestored();
It->second->purgeTouched();
}
@ -1362,6 +1363,29 @@ Document::getDependencyList(const std::vector<App::DocumentObject*>& objs) const
return ary;
}
/**
* @brief Signal that object identifiers, typically a property or document object has been renamed.
*
* This function iterates through all document object in the document, and calls its
* renameObjectIdentifiers functions.
*
* @param paths Map with current and new names
*/
void Document::renameObjectIdentifiers(const std::map<App::ObjectIdentifier, App::ObjectIdentifier> &paths)
{
std::map<App::ObjectIdentifier, App::ObjectIdentifier> extendedPaths;
std::map<App::ObjectIdentifier, App::ObjectIdentifier>::const_iterator it = paths.begin();
while (it != paths.end()) {
extendedPaths[it->first.canonicalPath()] = it->second.canonicalPath();
++it;
}
for (std::vector<DocumentObject*>::iterator it = d->objectArray.begin(); it != d->objectArray.end(); ++it)
(*it)->renameObjectIdentifiers(extendedPaths);
}
void Document::_rebuildDependencyList(void)
{
d->VertexObjectList.clear();

View File

@ -279,6 +279,9 @@ public:
//void setChanged(DocumentObject* change);
//@}
/// Function called to signal that an object identifier has been renamed
void renameObjectIdentifiers(const std::map<App::ObjectIdentifier, App::ObjectIdentifier> & paths);
virtual PyObject *getPyObject(void);
friend class Application;

View File

@ -33,6 +33,9 @@
#include "DocumentObjectPy.h"
#include "DocumentObjectGroup.h"
#include "PropertyLinks.h"
#include "PropertyExpressionEngine.h"
#include <boost/signals/connection.hpp>
#include <boost/bind.hpp>
using namespace App;
@ -46,10 +49,11 @@ DocumentObjectExecReturn *DocumentObject::StdReturn = 0;
//===========================================================================
DocumentObject::DocumentObject(void)
: _pDoc(0),pcNameInDocument(0)
: ExpressionEngine(),_pDoc(0),pcNameInDocument(0)
{
// define Label of type 'Output' to avoid being marked as touched after relabeling
ADD_PROPERTY_TYPE(Label,("Unnamed"),"Base",Prop_Output,"User name of the object (UTF8)");
ADD_PROPERTY_TYPE(ExpressionEngine,(),"Base",Prop_Hidden,"Property expressions");
}
DocumentObject::~DocumentObject(void)
@ -88,7 +92,7 @@ App::DocumentObjectExecReturn *DocumentObject::recompute(void)
DocumentObjectExecReturn *DocumentObject::execute(void)
{
return DocumentObject::StdReturn;
return StdReturn;
}
short DocumentObject::mustExecute(void) const
@ -148,6 +152,10 @@ std::vector<DocumentObject*> DocumentObject::getOutList(void) const
ret.push_back(static_cast<PropertyLinkSub*>(*It)->getValue());
}
}
// Get document objects that this document object relies on
ExpressionEngine.getDocumentObjectDeps(ret);
return ret;
}
@ -227,8 +235,87 @@ void DocumentObject::touch(void)
StatusBits.set(0);
}
/**
* @brief Check whether the document object is touched or not.
* @return true if document object is touched, false if not.
*/
bool DocumentObject::isTouched() const
{
return ExpressionEngine.isTouched() || StatusBits.test(0);
}
void DocumentObject::Save (Base::Writer &writer) const
{
writer.ObjectName = this->getNameInDocument();
App::PropertyContainer::Save(writer);
}
/**
* @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)
{
ExpressionEngine.setValue(path, expr, comment);
connectRelabelSignals();
}
/**
* @brief Get expression information associated with \a path.
* @param path Object identifier
* @return Expression info, containing expression and optional comment.
*/
const PropertyExpressionEngine::ExpressionInfo DocumentObject::getExpression(const ObjectIdentifier &path) const
{
boost::any value = ExpressionEngine.getValue(path);
if (value.type() == typeid(PropertyExpressionEngine::ExpressionInfo))
return boost::any_cast<PropertyExpressionEngine::ExpressionInfo>(value);
else
return PropertyExpressionEngine::ExpressionInfo();
}
/**
* @brief Invoke ExpressionEngine's renameObjectIdentifier, to possibly rewrite expressions using
* the \a paths map with current and new identifiers.
*
* @param paths
*/
void DocumentObject::renameObjectIdentifiers(const std::map<ObjectIdentifier, ObjectIdentifier> &paths)
{
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()->signalRenamedObject.connect(boost::bind(&PropertyExpressionEngine::slotObjectRenamed, &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();
}
}

View File

@ -26,18 +26,20 @@
#include <App/PropertyContainer.h>
#include <App/PropertyStandard.h>
#include <App/PropertyExpressionEngine.h>
#include <Base/TimeInfo.h>
#include <CXX/Objects.hxx>
#include <bitset>
#include <boost/signals.hpp>
namespace App
{
class Document;
class DocumentObjectGroup;
class DocumentObjectPy;
class Expression;
enum ObjectStatus {
Touch = 0,
@ -79,6 +81,7 @@ class AppExport DocumentObject: public App::PropertyContainer
public:
PropertyString Label;
PropertyExpressionEngine ExpressionEngine;
/// returns the type name of the ViewProvider
virtual const char* getViewProviderName(void) const {
@ -99,7 +102,7 @@ public:
/// set this feature touched (cause recomputation on depndend features)
void touch(void);
/// test if this feature is touched
bool isTouched(void) const {return StatusBits.test(0);}
bool isTouched(void) const;
/// reset this feature touched
void purgeTouched(void){StatusBits.reset(0);setPropertyStatus(0,false);}
/// set this feature to error
@ -160,6 +163,16 @@ public:
virtual void Save (Base::Writer &writer) const;
/* Expression support */
virtual void setExpression(const ObjectIdentifier & path, boost::shared_ptr<App::Expression> expr, const char *comment = 0);
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; }
protected:
@ -207,6 +220,10 @@ protected: // attributes
/// pointer to the document this object belongs to
App::Document* _pDoc;
// Connections to track relabeling of document and document objects
boost::BOOST_SIGNALS_NAMESPACE::scoped_connection onRelabledDocumentConnection;
boost::BOOST_SIGNALS_NAMESPACE::scoped_connection onRelabledObjectConnection;
/// Old label; used for renaming expressions
std::string oldLabel;

View File

@ -23,6 +23,11 @@
<UserDocu>Mark the object as unchanged</UserDocu>
</Documentation>
</Methode>
<Methode Name="setExpression">
<Documentation>
<UserDocu>Register an expression for a property</UserDocu>
</Documentation>
</Methode>
<Attribute Name="OutList" ReadOnly="true">
<Documentation>
<UserDocu>A list of all objects this object links to.</UserDocu>

View File

@ -28,6 +28,7 @@
// inclusion of the generated files (generated out of DocumentObjectPy.xml)
#include "DocumentObjectPy.h"
#include "DocumentObjectPy.cpp"
#include "Expression.h"
using namespace App;
@ -152,6 +153,31 @@ Py::List DocumentObjectPy::getOutList(void) const
return ret;
}
PyObject* DocumentObjectPy::setExpression(PyObject * args)
{
char * path = NULL;
PyObject * expr;
char * comment = 0;
if (!PyArg_ParseTuple(args, "sO|s", &path, &expr, &comment)) // convert args: Python->C
return NULL; // NULL triggers exception
App::ObjectIdentifier p(ObjectIdentifier::parse(getDocumentObjectPtr(), path));
if (Py::Object(expr).isNone())
getDocumentObjectPtr()->setExpression(p, boost::shared_ptr<Expression>());
else if (PyString_Check(expr)) {
const char * exprStr = PyString_AsString(expr);
boost::shared_ptr<Expression> shared_expr(ExpressionParser::parse(getDocumentObjectPtr(), exprStr));
getDocumentObjectPtr()->setExpression(p, shared_expr, comment);
}
else
throw Py::TypeError("String or None expected.");
Py_Return;
}
PyObject *DocumentObjectPy::getCustomAttributes(const char* /*attr*/) const
{
return 0;