diff --git a/src/App/Extension.cpp b/src/App/Extension.cpp index cf3ee329a..aff75fc80 100644 --- a/src/App/Extension.cpp +++ b/src/App/Extension.cpp @@ -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; +} + diff --git a/src/App/Extension.h b/src/App/Extension.h index 3237adb4e..359bcc643 100644 --- a/src/App/Extension.h +++ b/src/App/Extension.h @@ -26,6 +26,7 @@ #include "PropertyContainer.h" #include "PropertyPythonObject.h" +#include "DynamicProperty.h" #include #include @@ -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 &Map) const override; + /// get all properties of the class (including properties of the parent) + virtual void getPropertyList(std::vector &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 _extensions; diff --git a/src/App/ExtensionContainerPy.xml b/src/App/ExtensionContainerPy.xml index 209a7743a..5d460ce5e 100644 --- a/src/App/ExtensionContainerPy.xml +++ b/src/App/ExtensionContainerPy.xml @@ -15,6 +15,16 @@ Base class for all objects which can be extended + + + Adds an extension to the object + + + + + Returns if this object has the specified extension + + diff --git a/src/App/ExtensionContainerPyImp.cpp b/src/App/ExtensionContainerPyImp.cpp index dea412492..515de5946 100644 --- a/src/App/ExtensionContainerPyImp.cpp +++ b/src/App/ExtensionContainerPyImp.cpp @@ -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(extension.createInstance()); + ext->initExtension(dynamic_cast(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; +} \ No newline at end of file diff --git a/src/Tools/generateTemplates/templateClassPyExport.py b/src/Tools/generateTemplates/templateClassPyExport.py index e2240d134..9bfa844b3 100644 --- a/src/Tools/generateTemplates/templateClassPyExport.py +++ b/src/Tools/generateTemplates/templateClassPyExport.py @@ -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: