Extensions: Show up in the python interface

This commit is contained in:
Stefan Tröger
2016-06-01 08:37:28 +02:00
committed by wmayer
parent 6fa964c53f
commit 552fe52774
21 changed files with 435 additions and 258 deletions

View File

@@ -53,6 +53,9 @@ set(FreeCADApp_LIBS
generate_from_xml(DocumentPy)
generate_from_xml(DocumentObjectPy)
generate_from_xml(ExtensionPy)
generate_from_xml(ExtensionContainerPy)
generate_from_xml(GroupExtensionPy)
generate_from_xml(DocumentObjectGroupPy)
generate_from_xml(GeoFeaturePy)
#generate_from_xml(GeoFeatureGroupPy)
@@ -67,6 +70,9 @@ generate_from_py(FreeCADInit InitScript.h)
generate_from_py(FreeCADTest TestScript.h)
SET(FreeCADApp_XML_SRCS
ExtensionPy.xml
ExtensionContainerPy.xml
GroupExtensionPy.xml
DocumentObjectGroupPy.xml
DocumentObjectPy.xml
GeoFeaturePy.xml
@@ -86,6 +92,9 @@ SET(Document_CPP_SRCS
Document.cpp
DocumentObject.cpp
Extension.cpp
ExtensionPyImp.cpp
ExtensionContainerPyImp.cpp
GroupExtensionPyImp.cpp
DocumentObjectFileIncluded.cpp
DocumentObjectGroup.cpp
DocumentObjectGroupPyImp.cpp

View File

@@ -28,6 +28,7 @@
#include "DocumentObjectGroup.h"
#include "DocumentObjectGroupPy.h"
#include "GroupExtensionPy.h"
#include "Document.h"
#include "FeaturePythonPyImp.h"
@@ -37,7 +38,7 @@ PROPERTY_SOURCE(App::GroupExtension, App::Extension)
GroupExtension::GroupExtension()
{
m_extensionType = GroupExtension::getClassTypeId();
initExtension(GroupExtension::getClassTypeId());
ADD_PROPERTY_TYPE(Group,(0),"Base",(App::PropertyType)(Prop_Output),"List of referenced objects");
}
@@ -178,18 +179,37 @@ DocumentObject* GroupExtension::getGroupOfObject(const DocumentObject* obj)
return 0;
}
PyObject* GroupExtension::getExtensionPyObject(void) {
if (ExtensionPythonObject.is(Py::_None())){
// ref counter is set to 1
auto grp = new GroupExtensionPy(this);
ExtensionPythonObject = Py::Object(grp,true);
}
return Py::new_reference_to(ExtensionPythonObject);
}
PROPERTY_SOURCE(App::DocumentObjectGroup, App::DocumentObject)
PROPERTY_SOURCE_WITH_EXTENSIONS(App::DocumentObjectGroup, App::DocumentObject, (App::GroupExtension))
DocumentObjectGroup::DocumentObjectGroup(void): DocumentObject(), GroupExtension() {
setExtendedObject(this);
GroupExtension::initExtension(this);
}
DocumentObjectGroup::~DocumentObjectGroup() {
}
PyObject *DocumentObjectGroup::getPyObject()
{
if (PythonObject.is(Py::_None())){
// ref counter is set to 1
PythonObject = Py::Object(new DocumentObjectGroupPy(this),true);
}
return Py::new_reference_to(PythonObject);
}
// Python feature ---------------------------------------------------------

View File

@@ -89,6 +89,8 @@ public:
*/
static DocumentObject* getGroupOfObject(const DocumentObject* obj);
//@}
virtual PyObject* getExtensionPyObject(void);
/// Properties
PropertyLinkList Group;
@@ -102,7 +104,7 @@ typedef App::ExtensionPython<App::GroupExtension> GroupExtensionPython;
class DocumentObjectGroup : public DocumentObject, public GroupExtension {
PROPERTY_HEADER(App::DocumentObjectGroup);
PROPERTY_HEADER_WITH_EXTENSIONS(App::DocumentObjectGroup);
public:
/// Constructor
@@ -113,6 +115,8 @@ public:
virtual const char* getViewProviderName(void) const {
return "Gui::ViewProviderDocumentObjectGroup";
};
virtual PyObject *getPyObject(void);
};
typedef App::FeaturePythonT<DocumentObjectGroup> DocumentObjectGroupPython;

View File

@@ -13,40 +13,6 @@
<Author Licence="LGPL" Name="Werner Mayer" EMail="wmayer@users.sourceforge.net" />
<UserDocu>This class handles document objects in group</UserDocu>
</Documentation>
<Methode Name="newObject">
<Documentation>
<UserDocu>Create and add an object with given type and name to the group</UserDocu>
</Documentation>
</Methode>
<Methode Name="addObject">
<Documentation>
<UserDocu>Add an object to the group</UserDocu>
</Documentation>
</Methode>
<Methode Name="removeObject">
<Documentation>
<UserDocu>Remove an object from the group</UserDocu>
</Documentation>
</Methode>
<Methode Name="removeObjectsFromDocument">
<Documentation>
<UserDocu>Remove all child objects from the group and document</UserDocu>
</Documentation>
</Methode>
<Methode Name="getObject">
<Documentation>
<UserDocu>Return the object with the given name</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasObject">
<Documentation>
<UserDocu>hasObject(obj, recursive=false)
Checks if the group has a given object
@param obj the object to check for.
@param recursive if true check also if the obj is child of some sub group (default is false).
</UserDocu>
</Documentation>
</Methode>
<CustomAttributes />
</PythonExport>
</GenerateModel>

View File

@@ -39,166 +39,6 @@ std::string DocumentObjectGroupPy::representation(void) const
return std::string("<group object>");
}
PyObject* DocumentObjectGroupPy::newObject(PyObject *args)
{
char *sType,*sName=0;
if (!PyArg_ParseTuple(args, "s|s", &sType,&sName)) // convert args: Python->C
return NULL;
DocumentObject *object = getDocumentObjectGroupPtr()->addObject(sType, sName);
if ( object ) {
return object->getPyObject();
}
else {
PyErr_Format(Base::BaseExceptionFreeCADError, "Cannot create object of type '%s'", sType);
return NULL;
}
}
PyObject* DocumentObjectGroupPy::addObject(PyObject *args)
{
PyObject *object;
if (!PyArg_ParseTuple(args, "O!", &(DocumentObjectPy::Type), &object)) // convert args: Python->C
return NULL; // NULL triggers exception
DocumentObjectPy* docObj = static_cast<DocumentObjectPy*>(object);
if (!docObj->getDocumentObjectPtr() || !docObj->getDocumentObjectPtr()->getNameInDocument()) {
PyErr_SetString(Base::BaseExceptionFreeCADError, "Cannot add an invalid object");
return NULL;
}
if (docObj->getDocumentObjectPtr()->getDocument() != getDocumentObjectGroupPtr()->getDocument()) {
PyErr_SetString(Base::BaseExceptionFreeCADError, "Cannot add an object from another document to this group");
return NULL;
}
if (docObj->getDocumentObjectPtr() == this->getDocumentObjectGroupPtr()) {
PyErr_SetString(Base::BaseExceptionFreeCADError, "Cannot add a group object to itself");
return NULL;
}
if (docObj->getDocumentObjectPtr()->getTypeId().isDerivedFrom(DocumentObjectGroup::getClassTypeId())) {
App::DocumentObjectGroup* docGrp = static_cast<DocumentObjectGroup*>(docObj->getDocumentObjectPtr());
if (this->getDocumentObjectGroupPtr()->isChildOf(docGrp)) {
PyErr_SetString(Base::BaseExceptionFreeCADError, "Cannot add a group object to a child group");
return NULL;
}
}
DocumentObjectGroup* grp = getDocumentObjectGroupPtr();
if (grp->getTypeId().isDerivedFrom(App::DocumentObjectGroupPython::getClassTypeId())) {
DocumentObjectGroupPython* grppy = static_cast<DocumentObjectGroupPython*>(grp);
App::Property* proxy = grppy->getPropertyByName("Proxy");
if (proxy && proxy->getTypeId() == App::PropertyPythonObject::getClassTypeId()) {
Py::Object vp = static_cast<App::PropertyPythonObject*>(proxy)->getValue();
if (vp.hasAttr(std::string("addObject"))) {
Py::Callable method(vp.getAttr(std::string("addObject")));
// check which this method belongs to to avoid an infinite recursion
if (method.getAttr(std::string("__self__")) != Py::Object(this)) {
Py::Tuple args(1);
args[0] = Py::Object(object);
method.apply(args);
Py_Return;
}
}
}
}
grp->addObject(docObj->getDocumentObjectPtr());
Py_Return;
}
PyObject* DocumentObjectGroupPy::removeObject(PyObject *args)
{
PyObject *object;
if (!PyArg_ParseTuple(args, "O!", &(DocumentObjectPy::Type), &object)) // convert args: Python->C
return NULL; // NULL triggers exception
DocumentObjectPy* docObj = static_cast<DocumentObjectPy*>(object);
if (!docObj->getDocumentObjectPtr() || !docObj->getDocumentObjectPtr()->getNameInDocument()) {
PyErr_SetString(Base::BaseExceptionFreeCADError, "Cannot remove an invalid object");
return NULL;
}
if (docObj->getDocumentObjectPtr()->getDocument() != getDocumentObjectGroupPtr()->getDocument()) {
PyErr_SetString(Base::BaseExceptionFreeCADError, "Cannot remove an object from another document from this group");
return NULL;
}
DocumentObjectGroup* grp = getDocumentObjectGroupPtr();
if (grp->getTypeId().isDerivedFrom(App::DocumentObjectGroupPython::getClassTypeId())) {
DocumentObjectGroupPython* grppy = static_cast<DocumentObjectGroupPython*>(grp);
App::Property* proxy = grppy->getPropertyByName("Proxy");
if (proxy && proxy->getTypeId() == App::PropertyPythonObject::getClassTypeId()) {
Py::Object vp = static_cast<App::PropertyPythonObject*>(proxy)->getValue();
if (vp.hasAttr(std::string("removeObject"))) {
Py::Callable method(vp.getAttr(std::string("removeObject")));
// check which this method belongs to to avoid an infinite recursion
if (method.getAttr(std::string("__self__")) != Py::Object(this)) {
Py::Tuple args(1);
args[0] = Py::Object(object);
method.apply(args);
Py_Return;
}
}
}
}
grp->removeObject(docObj->getDocumentObjectPtr());
Py_Return;
}
PyObject* DocumentObjectGroupPy::removeObjectsFromDocument(PyObject *args)
{
if (!PyArg_ParseTuple(args, "")) // convert args: Python->C
return NULL; // NULL triggers exception
getDocumentObjectGroupPtr()->removeObjectsFromDocument();
Py_Return;
}
PyObject* DocumentObjectGroupPy::getObject(PyObject *args)
{
char* pcName;
if (!PyArg_ParseTuple(args, "s", &pcName)) // convert args: Python->C
return NULL; // NULL triggers exception
DocumentObject* obj = getDocumentObjectGroupPtr()->getObject(pcName);
if ( obj ) {
return obj->getPyObject();
} else {
Py_Return;
}
}
PyObject* DocumentObjectGroupPy::hasObject(PyObject *args)
{
PyObject *object;
PyObject *recursivePy = 0;
int recursive = 0;
if (!PyArg_ParseTuple(args, "O!|O", &(DocumentObjectPy::Type), &object, &recursivePy))
return NULL; // NULL triggers exception
DocumentObjectPy* docObj = static_cast<DocumentObjectPy*>(object);
if (!docObj->getDocumentObjectPtr() || !docObj->getDocumentObjectPtr()->getNameInDocument()) {
PyErr_SetString(Base::BaseExceptionFreeCADError, "Cannot check an invalid object");
return NULL;
}
if (docObj->getDocumentObjectPtr()->getDocument() != getDocumentObjectGroupPtr()->getDocument()) {
PyErr_SetString(Base::BaseExceptionFreeCADError, "Cannot check an object from another document with this group");
return NULL;
}
if (recursivePy) {
recursive = PyObject_IsTrue(recursivePy);
if ( recursive == -1) {
// Note: shouldn't happen
PyErr_SetString(PyExc_ValueError, "The recursive parameter should be of boolean type");
return 0;
}
}
bool v = getDocumentObjectGroupPtr()->hasObject(docObj->getDocumentObjectPtr(), recursive);
return PyBool_FromLong(v ? 1 : 0);
}
PyObject *DocumentObjectGroupPy::getCustomAttributes(const char* /*attr*/) const
{
return 0;

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="PropertyContainerPy"
Father="ExtensionContainerPy"
Name="DocumentObjectPy"
Twin="DocumentObject"
TwinPointer="DocumentObject"
Include="App/DocumentObject.h"
Namespace="App"
FatherInclude="App/PropertyContainerPy.h"
FatherInclude="App/ExtensionContainerPy.h"
FatherNamespace="App">
<Documentation>
<Author Licence="LGPL" Name="Juergen Riegel" EMail="FreeCAD@juergen-riegel.net" />

View File

@@ -31,29 +31,69 @@
#include "Extension.h"
#include "DocumentObject.h"
#include "Base/Exception.h"
#include <Base/Console.h>
TYPESYSTEM_SOURCE(App::Extension, App::PropertyContainer);
/* We do not use a standart property macro for type initiation. The reason is that we want to expose all property functions,
* to allow the derived classes to access the private property data, but we do not want to have our
* property data a reference to the parent data. That is because the extension is used in a multi
* inheritance way, and hence our propertydata partent data would point to the same property data
* as any other parent of the inherited class. It makes more sense to create a total unrelated line
* of property datas which are added as additional parent to the extended class.
*/
TYPESYSTEM_SOURCE_P(App::Extension);
const App::PropertyData * App::Extension::getPropertyDataPtr(void){return &propertyData;}
const App::PropertyData & App::Extension::getPropertyData(void) const{return propertyData;}
App::PropertyData App::Extension::propertyData;
void App::Extension::init(void){
initSubclass(App::Extension::classTypeId, "App::Extension" , "App::PropertyContainer", &(App::Extension::create) );
}
using namespace App;
//**************************************************************************
// Construction/Destruction
// here the implemataion! description should take place in the header file!
Extension::Extension() {}
Extension::Extension()
{
}
Extension::~Extension()
{
}
void Extension::setExtendedObject(DocumentObject* obj) {
void Extension::initExtension(Base::Type type) {
m_extensionType = type;
if(m_extensionType.isBad())
throw Base::Exception("Extension: Extension type not set");
}
void Extension::initExtension(DocumentObject* obj) {
if(m_extensionType.isBad())
throw Base::Exception("Extension: Extension type not set");
m_base = obj;
m_base->registerExtension( m_extensionType, this );
}
PyObject* Extension::getExtensionPyObject(void) {
return nullptr;
}
const char* Extension::name() {
if(m_extensionType.isBad())
throw Base::Exception("Extension::setExtendedObject: Extension type not set");
m_base = obj;
obj->registerExtension( m_extensionType, this );
std::string temp(m_extensionType.getName());
std::string::size_type pos = temp.find_last_of(":");
if(pos != std::string::npos)
return temp.substr(pos+1).c_str();
else
return std::string().c_str();
}
@@ -70,12 +110,19 @@ ExtensionContainer::~ExtensionContainer() {
void ExtensionContainer::registerExtension(Base::Type extension, Extension* ext) {
if(hasExtension(extension))
throw Base::Exception("ExtensionContainer::registerExtension: Such a extension is already registered");
if(ext->getExtendedObject() != this)
throw Base::Exception("ExtensionContainer::registerExtension: Extension has not this as base object");
//no duplicate extensions (including base classes)
if(hasExtension(extension)) {
for(auto entry : _extensions) {
if(entry.first == extension || entry.first.isDerivedFrom(extension)) {
_extensions.erase(entry.first);
break;
}
}
}
_extensions[extension] = ext;
}
@@ -94,6 +141,17 @@ bool ExtensionContainer::hasExtension(Base::Type t) const {
return true;
}
bool ExtensionContainer::hasExtension(const char* name) const {
//and for types derived from it, as they can be cast to the extension
for(auto entry : _extensions) {
if(strcmp(entry.second->name(), name) == 0)
return true;
}
return false;
}
Extension* ExtensionContainer::getExtension(Base::Type t) {
auto result = _extensions.find(t);
@@ -109,3 +167,13 @@ Extension* ExtensionContainer::getExtension(Base::Type t) {
return result->second;
}
Extension* ExtensionContainer::getExtension(const char* name) {
//and for types derived from it, as they can be cast to the extension
for(auto entry : _extensions) {
if(strcmp(entry.second->name(), name) == 0)
return entry.second;
}
return nullptr;
}

View File

@@ -28,6 +28,8 @@
#include "PropertyPythonObject.h"
#include <CXX/Objects.hxx>
#include <boost/preprocessor/seq/for_each.hpp>
namespace App {
/**
@@ -37,30 +39,53 @@ namespace App {
class AppExport Extension : public virtual App::PropertyContainer
{
TYPESYSTEM_HEADER();
//The cass does not have properties itself, but it is important to provide the property access
//functions. see cpp file for details
PROPERTY_HEADER(App::Extension);
public:
/**
* A constructor.
* A more elaborate description of the constructor.
*/
Extension();
/**
* A destructor.
* A more elaborate description of the destructor.
*/
Extension();
virtual ~Extension();
App::DocumentObject* getExtendedObject() {return m_base;};
const App::DocumentObject* getExtendedObject() const {return m_base;};
void setExtendedObject(App::DocumentObject* obj);
const char* name();
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;
App::DocumentObject* m_base = nullptr;
};
#define PROPERTY_HEADER_WITH_EXTENSIONS(_class_) \
PROPERTY_HEADER(_class)
//helper macro to add parent to property data
#define ADD_PARENT(r, data, elem)\
data::propertyData.parentPropertyData.push_back(elem::getPropertyDataPtr());
///
#define PROPERTY_SOURCE_WITH_EXTENSIONS(_class_, _parentclass_, _extensions_) \
TYPESYSTEM_SOURCE_P(_class_);\
const App::PropertyData * _class_::getPropertyDataPtr(void){return &propertyData;} \
const App::PropertyData & _class_::getPropertyData(void) const{return propertyData;} \
App::PropertyData _class_::propertyData; \
void _class_::init(void){\
initSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
ADD_PARENT(0, _class_, _parentclass_)\
BOOST_PP_SEQ_FOR_EACH(ADD_PARENT, _class_, _extensions_)\
}
template<typename ExtensionT>
class ExtensionPython : public ExtensionT {
@@ -83,26 +108,25 @@ class AppExport ExtensionContainer : public virtual App::PropertyContainer
TYPESYSTEM_HEADER();
public:
/**
* A constructor.
* A more elaborate description of the constructor.
*/
ExtensionContainer();
typedef std::map<Base::Type, App::Extension*>::iterator ExtensionIterator;
/**
* A destructor.
* A more elaborate description of the destructor.
*/
ExtensionContainer();
virtual ~ExtensionContainer();
void registerExtension(Base::Type extension, App::Extension* ext);
bool hasExtension(Base::Type) const;
bool hasExtension(const char* name) const; //this version does not check derived classes
App::Extension* getExtension(Base::Type);
App::Extension* getExtension(const char* name); //this version does not check derived classes
template<typename Extension>
Extension* getExtensionByType() {
return dynamic_cast<Extension*>(getExtension(Extension::getClassTypeId()));
};
ExtensionIterator extensionBegin() {return _extensions.begin();};
ExtensionIterator extensionEnd() {return _extensions.end();};
private:
//stored extensions
std::map<Base::Type, App::Extension*> _extensions;

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="PropertyContainerPy"
Name="ExtensionContainerPy"
TwinPointer="ExtensionContainer"
Twin="ExtensionContainer"
Include="App/Extension.h"
Namespace="App"
FatherInclude="App/PropertyContainerPy.h"
FatherNamespace="App"
Initialisation="true"
Constructor = "true">
<Documentation>
<Author Licence="LGPL" Name="Stefan Troeger" EMail="stefantroeger@gmx.net" />
<UserDocu>Base class for all objects which can be extended</UserDocu>
</Documentation>
<CustomAttributes />
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,93 @@
/***************************************************************************
* Copyright (c) Stefan Tröger (stefantroeger@gmx.net) 2016 *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <sstream>
#endif
#include "Application.h"
// inclution of the generated files (generated out of PropertyContainerPy.xml)
#include "ExtensionContainerPy.h"
#include "ExtensionContainerPy.cpp"
using namespace App;
// returns a string which represent the object e.g. when printed in python
std::string ExtensionContainerPy::representation(void) const
{
return std::string("<extension>");
}
int ExtensionContainerPy::initialisation() {
if (this->ob_type->tp_dict == NULL) {
if (PyType_Ready(this->ob_type) < 0)
return 0;
}
ExtensionContainer::ExtensionIterator it = this->getExtensionContainerPtr()->extensionBegin();
for(; it != this->getExtensionContainerPtr()->extensionEnd(); ++it) {
PyObject* obj = (*it).second->getExtensionPyObject();
PyMethodDef* tmpptr = (PyMethodDef*)obj->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,obj);
//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;
}
}
return 0;
}
PyObject* ExtensionContainerPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
{
// create a new instance of @self.export.Name@ and the Twin object
Base::Console().Message("Make\n");
return 0;
}
// constructor method
int ExtensionContainerPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
Base::Console().Message("Init\n");
return 0;
}
PyObject *ExtensionContainerPy::getCustomAttributes(const char* attr) const
{
return 0;
}
int ExtensionContainerPy::setCustomAttributes(const char* attr, PyObject *obj)
{
return 0;
}

18
src/App/ExtensionPy.xml Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="PyObjectBase"
Name="ExtensionPy"
TwinPointer="Extension"
Twin="Extension"
Include="App/Extension.h"
Namespace="App"
FatherInclude="Base/PyObjectBase.h"
FatherNamespace="Base">
<Documentation>
<Author Licence="LGPL" Name="Stefan Troeger" EMail="stefantroeger@gmx.net" />
<UserDocu>Base class for all document object extensions</UserDocu>
</Documentation>
<CustomAttributes />
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,52 @@
/***************************************************************************
* Copyright (c) Stefan Tröger (stefantroeger@gmx.net) 2016 *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <sstream>
#endif
#include "Application.h"
// inclution of the generated files (generated out of PropertyContainerPy.xml)
#include "ExtensionPy.h"
#include "ExtensionPy.cpp"
using namespace App;
// returns a string which represent the object e.g. when printed in python
std::string ExtensionPy::representation(void) const
{
return std::string("<extension>");
}
PyObject *ExtensionPy::getCustomAttributes(const char* attr) const
{
return 0;
}
int ExtensionPy::setCustomAttributes(const char* attr, PyObject *obj)
{
return 0;
}

View File

@@ -45,7 +45,7 @@ PROPERTY_SOURCE(App::GeoFeatureGroupExtension, App::GroupExtension)
GeoFeatureGroupExtension::GeoFeatureGroupExtension(void)
{
m_extensionType = GeoFeatureGroupExtension::getClassTypeId();
initExtension(GeoFeatureGroupExtension::getClassTypeId());
ADD_PROPERTY(Placement,(Base::Placement()));
}

View File

@@ -39,7 +39,7 @@ PROPERTY_SOURCE(App::OriginGroupExtension, App::GeoFeatureGroupExtension);
OriginGroupExtension::OriginGroupExtension () {
m_extensionType = OriginGroupExtension::getClassTypeId();
initExtension(OriginGroupExtension::getClassTypeId());
ADD_PROPERTY_TYPE ( Origin, (0), 0, App::Prop_Hidden, "Origin linked to the group" );
}

View File

@@ -35,7 +35,7 @@
using namespace App;
PROPERTY_SOURCE(App::Part, App::DocumentObject)
PROPERTY_SOURCE_WITH_EXTENSIONS(App::Part, App::DocumentObject, (App::OriginGroupExtension))
//===========================================================================
@@ -60,7 +60,7 @@ Part::Part(void)
// color and apperance
ADD_PROPERTY(Color, (1.0, 1.0, 1.0, 1.0)); // set transparent -> not used
setExtendedObject(this);
GroupExtension::initExtension(this);
}
Part::~Part(void)

View File

@@ -37,7 +37,7 @@ namespace App
*/
class AppExport Part : public App::DocumentObject, public App::OriginGroupExtension
{
PROPERTY_HEADER(App::Part);
PROPERTY_HEADER_WITH_EXTENSIONS(App::Part);
public:
/// type of the part

View File

@@ -51,7 +51,6 @@ TYPESYSTEM_SOURCE(App::PropertyContainer,Base::Persistence);
// here the implemataion! description should take place in the header file!
PropertyContainer::PropertyContainer()
{
propertyData.parentPropertyData = 0;
}
PropertyContainer::~PropertyContainer()
@@ -279,14 +278,24 @@ void PropertyData::addProperty(const PropertyContainer *container,const char* Pr
}
}
void PropertyData::addParentPropertyData(const PropertyData* data) {
if(data)
parentPropertyData.push_back(data);
}
const PropertyData::PropertySpec *PropertyData::findProperty(const PropertyContainer *container,const char* PropName) const
{
for (vector<PropertyData::PropertySpec>::const_iterator It = propertyData.begin(); It != propertyData.end(); ++It)
if(strcmp(It->Name,PropName)==0)
return &(*It);
if(parentPropertyData)
return parentPropertyData->findProperty(container,PropName);
for(auto data : parentPropertyData) {
auto res = data->findProperty(container,PropName);
if(res)
return res;
}
return 0;
}
@@ -299,9 +308,12 @@ const PropertyData::PropertySpec *PropertyData::findProperty(const PropertyConta
if(diff == It->Offset)
return &(*It);
if(parentPropertyData)
return parentPropertyData->findProperty(container,prop);
for(auto data : parentPropertyData) {
auto res = data->findProperty(container,prop);
if(res)
return res;
}
return 0;
}
@@ -450,9 +462,9 @@ void PropertyData::getPropertyMap(const PropertyContainer *container,std::map<st
}
*/
if(parentPropertyData)
parentPropertyData->getPropertyMap(container,Map);
for(auto data : parentPropertyData)
data->getPropertyMap(container,Map);
}
void PropertyData::getPropertyList(const PropertyContainer *container,std::vector<Property*> &List) const
@@ -466,8 +478,8 @@ void PropertyData::getPropertyList(const PropertyContainer *container,std::vecto
{
List.push_back((Property *) (pos->second.Offset + (char *)container) );
}*/
if(parentPropertyData)
parentPropertyData->getPropertyList(container,List);
for(auto data : parentPropertyData)
data->getPropertyList(container,List);
}

View File

@@ -57,11 +57,12 @@ struct AppExport PropertyData
short Offset,Type;
};
// vector of all properties
std::vector<PropertySpec> propertyData;
const PropertyData *parentPropertyData;
std::vector<PropertySpec> propertyData;
std::vector<const PropertyData*> parentPropertyData;
void addProperty(const PropertyContainer *container,const char* PropName, Property *Prop, const char* PropertyGroup= 0, PropertyType = Prop_None, const char* PropertyDocu= 0 );
void addParentPropertyData(const PropertyData* data);
const PropertySpec *findProperty(const PropertyContainer *container,const char* PropName) const;
const PropertySpec *findProperty(const PropertyContainer *container,const Property* prop) const;
@@ -218,7 +219,7 @@ const App::PropertyData & _class_::getPropertyData(void) const{return propertyDa
App::PropertyData _class_::propertyData; \
void _class_::init(void){\
initSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::getPropertyDataPtr();\
_class_::propertyData.addParentPropertyData(_parentclass_::getPropertyDataPtr());\
}
#define PROPERTY_SOURCE_ABSTRACT(_class_, _parentclass_) \
@@ -228,7 +229,7 @@ const App::PropertyData & _class_::getPropertyData(void) const{return propertyDa
App::PropertyData _class_::propertyData; \
void _class_::init(void){\
initSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::getPropertyDataPtr();\
_class_::propertyData.addParentPropertyData(_parentclass_::getPropertyDataPtr());\
}
#define TYPESYSTEM_SOURCE_TEMPLATE(_class_) \
@@ -246,7 +247,7 @@ template<> const App::PropertyData * _class_::getPropertyDataPtr(void){return &p
template<> const App::PropertyData & _class_::getPropertyData(void) const{return propertyData;} \
template<> void _class_::init(void){\
initSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
_class_::propertyData.parentPropertyData = _parentclass_::getPropertyDataPtr();\
_class_::propertyData.addParentPropertyData(_parentclass_::getPropertyDataPtr());\
}

View File

@@ -243,8 +243,10 @@ PyObject *PropertyContainerPy::getCustomAttributes(const char* attr) const
getPropertyContainerPtr()->getPropertyMap(Map);
PyObject *dict = PyDict_New();
if (dict) {
for ( std::map<std::string,App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it )
for ( std::map<std::string,App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it ){
Base::Console().Message("Dict add property: %s\n",it->first.c_str());
PyDict_SetItem(dict, PyString_FromString(it->first.c_str()), PyString_FromString(""));
}
if (PyErr_Occurred()) {
Py_DECREF(dict);
dict = NULL;

View File

@@ -216,7 +216,7 @@ class GenerateModel:
class PythonExport:
subclass = None
def __init__(self, FatherNamespace='', RichCompare=0, Name='', Reference=0, FatherInclude='', Father='', Namespace='', Twin='', Constructor=0, TwinPointer='', Include='', NumberProtocol=0, Delete=0, Documentation=None, Methode=None, Attribute=None, Sequence=None, CustomAttributes='', ClassDeclarations=''):
def __init__(self, FatherNamespace='', RichCompare=0, Name='', Reference=0, FatherInclude='', Father='', Namespace='', Twin='', Constructor=0, TwinPointer='', Include='', NumberProtocol=0, Delete=0, Documentation=None, Methode=None, Attribute=None, Sequence=None, CustomAttributes='', ClassDeclarations='', Initialisation=0):
self.FatherNamespace = FatherNamespace
self.RichCompare = RichCompare
self.Name = Name
@@ -231,6 +231,7 @@ class PythonExport:
self.NumberProtocol = NumberProtocol
self.Delete = Delete
self.Documentation = Documentation
self.Initialisation = Initialisation
if Methode is None:
self.Methode = []
else:
@@ -248,6 +249,8 @@ class PythonExport:
else:
return PythonExport(*args_, **kwargs_)
factory = staticmethod(factory)
def getInitialisation(self): return self.Initialisation
def setInitialisation(self, Initialisation): self.Initialisation = Initialisation
def getDocumentation(self): return self.Documentation
def setDocumentation(self, Documentation): self.Documentation = Documentation
def getMethode(self): return self.Methode
@@ -311,6 +314,8 @@ class PythonExport:
outfile.write(' Twin="%s"' % (self.getTwin(), ))
if self.getConstructor() is not None:
outfile.write(' Constructor="%s"' % (self.getConstructor(), ))
if self.getInitialisation() is not None:
outfile.write(' Initialisation="%s"' % (self.getInitialisation(), ))
outfile.write(' TwinPointer="%s"' % (self.getTwinpointer(), ))
outfile.write(' Include="%s"' % (self.getInclude(), ))
if self.getNumberprotocol() is not None:
@@ -354,6 +359,7 @@ class PythonExport:
showIndent(outfile, level)
outfile.write('Constructor = "%s",\n' % (self.getConstructor(),))
showIndent(outfile, level)
outfile.write('Initialisation = "%s",\n' % (self.getInitialisation(),))
outfile.write('TwinPointer = "%s",\n' % (self.getTwinpointer(),))
showIndent(outfile, level)
outfile.write('Include = "%s",\n' % (self.getInclude(),))
@@ -442,6 +448,13 @@ class PythonExport:
self.Constructor = 0
else:
raise ValueError('Bad boolean attribute (Constructor)')
if attrs.get('Initialisation'):
if attrs.get('Initialisation').value in ('true', '1'):
self.Initialisation = 1
elif attrs.get('Initialisation').value in ('false', '0'):
self.Initialisation = 0
else:
raise ValueError('Bad boolean attribute (Initialisation)')
if attrs.get('TwinPointer'):
self.TwinPointer = attrs.get('TwinPointer').value
if attrs.get('Include'):
@@ -493,6 +506,11 @@ class PythonExport:
for text__content_ in child_.childNodes:
ClassDeclarations_ += text__content_.nodeValue
self.ClassDeclarations = ClassDeclarations_
elif child_.nodeType == Node.ELEMENT_NODE and \
nodeName_ == 'Initialisation':
obj_ = Documentation.factory()
obj_.build(child_)
self.setDocumentation(obj_)
# end class PythonExport
@@ -1827,6 +1845,14 @@ class SaxGeneratemodelHandler(handler.ContentHandler):
obj.setConstructor(0)
else:
self.reportError('"Constructor" attribute must be boolean ("true", "1", "false", "0")')
val = attrs.get('Initialisation', None)
if val is not None:
if val in ('true', '1'):
obj.setInitialisation(1)
elif val in ('false', '0'):
obj.setInitialisation(0)
else:
self.reportError('"Initialisation" attribute must be boolean ("true", "1", "false", "0")')
val = attrs.get('TwinPointer', None)
if val is not None:
obj.setTwinpointer(val)

View File

@@ -67,6 +67,10 @@ public:
static PyObject *PyMake(struct _typeobject *, PyObject *, PyObject *);
virtual int PyInit(PyObject* args, PyObject*k);
~@self.export.Name@();
+ if (self.export.Initialisation):
int initialisation();
-
typedef @self.export.TwinPointer@* PointerType ;
@@ -606,6 +610,10 @@ int @self.export.Name@::staticCallback_set@i.Name@ (PyObject *self, PyObject *va
+ if (self.export.Reference):
pcObject->ref();
-
+ if (self.export.Initialisation):
initialisation();
-
}
+ if not (self.export.Constructor):
@@ -808,6 +816,13 @@ int @self.export.Name@::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
}
-
+ if (self.export.Initialisation):
int @self.export.Name@::initialisation()
{
return 0;
}
-
// returns a string which represents the object e.g. when printed in python
std::string @self.export.Name@::representation(void) const
{
@@ -1117,6 +1132,13 @@ int @self.export.Name@::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
return 0;
}
-
+ if (self.export.Initialisation):
int @self.export.Name@::initialisation()
{
PyErr_SetString(PyExc_NotImplementedError, "Not yet implemented");
return 0;
}
-
+ for i in self.export.Methode: