Extensions: Allow them to be added dynamically

This commit is contained in:
Stefan Tröger 2016-06-03 08:02:05 +02:00 committed by wmayer
parent c47c34edff
commit 93222098f0
5 changed files with 284 additions and 2 deletions

View File

@ -188,3 +188,157 @@ std::vector< Extension* > ExtensionContainer::getExtensionsDerivedFrom(Base::Typ
}
return vec;
}
void ExtensionContainer::getPropertyList(std::vector< Property* >& List) const {
App::PropertyContainer::getPropertyList(List);
for(auto entry : _extensions) {
if(entry.second->isPythonExtension())
entry.second->getPropertyList(List);
}
}
void ExtensionContainer::getPropertyMap(std::map< std::string, Property* >& Map) const {
App::PropertyContainer::getPropertyMap(Map);
for(auto entry : _extensions) {
if(entry.second->isPythonExtension())
entry.second->getPropertyMap(Map);
}
}
Property* ExtensionContainer::getPropertyByName(const char* name) const {
auto prop = App::PropertyContainer::getPropertyByName(name);
if(prop)
return prop;
for(auto entry : _extensions) {
if(entry.second->isPythonExtension()){
auto prop = entry.second->getPropertyByName(name);
if(prop)
return prop;
}
}
return nullptr;
}
short int ExtensionContainer::getPropertyType(const Property* prop) const {
short int res = App::PropertyContainer::getPropertyType(prop);
if(res != 0)
return res;
for(auto entry : _extensions) {
if(entry.second->isPythonExtension()) {
res = entry.second->getPropertyType(prop);
if(res != 0)
return res;
}
}
return 0;
}
short int ExtensionContainer::getPropertyType(const char* name) const {
short int res = App::PropertyContainer::getPropertyType(name);
if(res != 0)
return res;
for(auto entry : _extensions) {
if(entry.second->isPythonExtension()) {
res = entry.second->getPropertyType(name);
if(res != 0)
return res;
}
}
return 0;
}
const char* ExtensionContainer::getPropertyName(const Property* prop) const {
const char* res = App::PropertyContainer::getPropertyName(prop);
if(res != 0)
return res;
for(auto entry : _extensions) {
if(entry.second->isPythonExtension()) {
res = entry.second->getPropertyName(prop);
if(res != 0)
return res;
}
}
return 0;
}
const char* ExtensionContainer::getPropertyGroup(const Property* prop) const {
const char* res = App::PropertyContainer::getPropertyGroup(prop);
if(res != 0)
return res;
for(auto entry : _extensions) {
if(entry.second->isPythonExtension()) {
res = entry.second->getPropertyGroup(prop);
if(res != 0)
return res;
}
}
return 0;
}
const char* ExtensionContainer::getPropertyGroup(const char* name) const {
const char* res = App::PropertyContainer::getPropertyGroup(name);
if(res != 0)
return res;
for(auto entry : _extensions) {
if(entry.second->isPythonExtension()) {
res = entry.second->getPropertyGroup(name);
if(res != 0)
return res;
}
}
return 0;
}
const char* ExtensionContainer::getPropertyDocumentation(const Property* prop) const {
const char* res = App::PropertyContainer::getPropertyDocumentation(prop);
if(res != 0)
return res;
for(auto entry : _extensions) {
if(entry.second->isPythonExtension()) {
res = entry.second->getPropertyDocumentation(prop);
if(res != 0)
return res;
}
}
return 0;
}
const char* ExtensionContainer::getPropertyDocumentation(const char* name) const {
const char* res = App::PropertyContainer::getPropertyDocumentation(name);
if(res != 0)
return res;
for(auto entry : _extensions) {
if(entry.second->isPythonExtension()) {
res = entry.second->getPropertyDocumentation(name);
if(res != 0)
return res;
}
}
return 0;
}

View File

@ -26,6 +26,7 @@
#include "PropertyContainer.h"
#include "PropertyPythonObject.h"
#include "DynamicProperty.h"
#include <CXX/Objects.hxx>
#include <boost/preprocessor/seq/for_each.hpp>
@ -48,21 +49,27 @@ public:
Extension();
virtual ~Extension();
void initExtension(App::DocumentObject* obj);
App::DocumentObject* getExtendedObject() {return m_base;};
const App::DocumentObject* getExtendedObject() const {return m_base;};
//get extension name without namespace
const char* name();
//store if this extension is created from python or not (hence c++ multiple inheritance)
void setPythonExtension(bool val) {m_isPythonExtension = val;};
bool isPythonExtension() {return m_isPythonExtension;};
virtual PyObject* getExtensionPyObject(void);
protected:
void initExtension(Base::Type type);
void initExtension(App::DocumentObject* obj);
Py::Object ExtensionPythonObject;
private:
Base::Type m_extensionType;
App::DocumentObject* m_base = nullptr;
bool m_isPythonExtension = false;
};
@ -139,6 +146,32 @@ public:
ExtensionIterator extensionBegin() {return _extensions.begin();};
ExtensionIterator extensionEnd() {return _extensions.end();};
/** @name Access properties */
//@{
/// find a property by its name
virtual Property *getPropertyByName(const char* name) const override;
/// get the name of a property
virtual const char* getPropertyName(const Property* prop) const override;
/// get all properties of the class (including properties of the parent)
virtual void getPropertyMap(std::map<std::string,Property*> &Map) const override;
/// get all properties of the class (including properties of the parent)
virtual void getPropertyList(std::vector<Property*> &List) const override;
/// get the Type of a Property
virtual short getPropertyType(const Property* prop) const override;
/// get the Type of a named Property
virtual short getPropertyType(const char *name) const override;
/// get the Group of a Property
virtual const char* getPropertyGroup(const Property* prop) const override;
/// get the Group of a named Property
virtual const char* getPropertyGroup(const char *name) const override;
/// get the Group of a Property
virtual const char* getPropertyDocumentation(const Property* prop) const override;
/// get the Group of a named Property
virtual const char* getPropertyDocumentation(const char *name) const override;
//@}
private:
//stored extensions
std::map<Base::Type, App::Extension*> _extensions;

View File

@ -15,6 +15,16 @@
<Author Licence="LGPL" Name="Stefan Troeger" EMail="stefantroeger@gmx.net" />
<UserDocu>Base class for all objects which can be extended</UserDocu>
</Documentation>
<Methode Name="addExtension">
<Documentation>
<UserDocu>Adds an extension to the object</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasExtension">
<Documentation>
<UserDocu>Returns if this object has the specified extension</UserDocu>
</Documentation>
</Methode>
<CustomAttributes />
</PythonExport>
</GenerateModel>

View File

@ -28,6 +28,7 @@
#endif
#include "Application.h"
#include "DocumentObject.h"
// inclution of the generated files (generated out of PropertyContainerPy.xml)
#include "ExtensionContainerPy.h"
@ -65,9 +66,20 @@ int ExtensionContainerPy::initialisation() {
++tmpptr;
}
}
return 0;
return 1;
}
int ExtensionContainerPy::deinitialisation() {
//we need to delete all added python extensions, as we are the owner!
ExtensionContainer::ExtensionIterator it = this->getExtensionContainerPtr()->extensionBegin();
for(; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
if((*it).second->isPythonExtension())
delete (*it).second;
}
return 1;
};
PyObject* ExtensionContainerPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
{
// create a new instance of @self.export.Name@ and the Twin object
@ -89,3 +101,63 @@ int ExtensionContainerPy::setCustomAttributes(const char* attr, PyObject *obj)
{
return 0;
}
PyObject* ExtensionContainerPy::hasExtension(PyObject *args) {
char *type;
if (!PyArg_ParseTuple(args, "s", &type))
return NULL; // NULL triggers exception
//get the extension type asked for
Base::Type extension = Base::Type::fromName(type);
if(extension.isBad() || !extension.isDerivedFrom(App::Extension::getClassTypeId())) {
std::stringstream str;
str << "No extension found of type '" << type << "'" << std::ends;
throw Py::Exception(Base::BaseExceptionFreeCADError,str.str());
}
if(getExtensionContainerPtr()->hasExtension(extension)) {
Py_INCREF(Py_True);
return Py_True;
}
Py_INCREF(Py_False);
return Py_False;
}
PyObject* ExtensionContainerPy::addExtension(PyObject *args) {
char *type;
if (!PyArg_ParseTuple(args, "s", &type))
return NULL; // NULL triggers exception
//get the extension type asked for
Base::Type extension = Base::Type::fromName(type);
if(extension.isBad() || !extension.isDerivedFrom(App::Extension::getClassTypeId())) {
std::stringstream str;
str << "No extension found of type '" << type << "'" << std::ends;
throw Py::Exception(Base::BaseExceptionFreeCADError,str.str());
}
//register the extension
App::Extension* ext = static_cast<App::Extension*>(extension.createInstance());
ext->initExtension(dynamic_cast<App::DocumentObject*>(getExtensionContainerPtr()));
//we are responsible for deleting the extension once done with it!
ext->setPythonExtension(true);
//make sure all functions of the extension are acessible through this object
PyMethodDef* tmpptr = (PyMethodDef*)ext->getExtensionPyObject()->ob_type->tp_methods;
while(tmpptr->ml_name) {
//Note: to add methods the call to PyMethod_New is required. However, than the PyObject
// self is added to the functions arguments list. FreeCAD py implementations are not
// made to handle this, the do not accept self as argument. Hence we only use function
PyObject *func = PyCFunction_New(tmpptr, ext->getExtensionPyObject());
//PyObject *method = PyMethod_New(func, (PyObject*)this, PyObject_Type((PyObject*)this));
PyDict_SetItem(this->ob_type->tp_dict, PyString_FromString(tmpptr->ml_name), func);
Py_DECREF(func);
//Py_DECREF(method);
++tmpptr;
}
Py_Return;
}

View File

@ -70,6 +70,7 @@ public:
+ if (self.export.Initialisation):
int initialisation();
int deinitialisation();
-
typedef @self.export.TwinPointer@* PointerType ;
@ -644,6 +645,9 @@ int @self.export.Name@::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
@self.export.Name@::PointerType ptr = static_cast<@self.export.Name@::PointerType>(_pcTwinPointer);
delete ptr;
-
+ if (self.export.Initialisation):
deinitialisation();
-
}
//--------------------------------------------------------------------------
@ -821,6 +825,10 @@ int @self.export.Name@::initialisation()
{
return 0;
}
int @self.export.Name@::deinitialisation()
{
return 0;
}
-
// returns a string which represents the object e.g. when printed in python
@ -1138,6 +1146,11 @@ int @self.export.Name@::initialisation()
PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
return 0;
}
int @self.export.Name@::deinitialisation()
{
PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
return 0;
}
-
+ for i in self.export.Methode: