Added PropertyExpressionEngine to DocumentObject class.
This commit is contained in:
parent
8259ec6764
commit
fb2b1a6ec0
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user