Extensions: Allow them to be added dynamically
This commit is contained in:
parent
c47c34edff
commit
93222098f0
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue
Block a user