App::Extension Class Reference

Base class for all extension that can be added to a DocumentObject. More...

#include <Extension.h>

Public Member Functions

 Extension ()
 
App::ExtensionContainergetExtendedContainer ()
 
const App::ExtensionContainergetExtendedContainer () const
 
virtual PyObjectgetExtensionPyObject ()
 
virtual void initExtension (App::ExtensionContainer *obj)
 
bool isPythonExtension ()
 
std::string name () const
 
virtual ~Extension ()
 
Access properties
virtual PropertyextensionGetPropertyByName (const char *name) const
 find a property by its name More...
 
virtual const char * extensionGetPropertyName (const Property *prop) const
 get the name of a property More...
 
virtual void extensionGetPropertyMap (std::map< std::string, Property * > &Map) const
 get all properties of the class (including properties of the parent) More...
 
virtual void extensionGetPropertyList (std::vector< Property * > &List) const
 get all properties of the class (including properties of the parent) More...
 
virtual short extensionGetPropertyType (const Property *prop) const
 get the Type of a Property More...
 
virtual short extensionGetPropertyType (const char *name) const
 get the Type of a named Property More...
 
virtual const char * extensionGetPropertyGroup (const Property *prop) const
 get the Group of a Property More...
 
virtual const char * extensionGetPropertyGroup (const char *name) const
 get the Group of a named Property More...
 
virtual const char * extensionGetPropertyDocumentation (const Property *prop) const
 get the Group of a Property More...
 
virtual const char * extensionGetPropertyDocumentation (const char *name) const
 get the Group of a named Property More...
 
Persistence
virtual void extensionSave (Base::Writer &) const
 
virtual void extensionRestore (Base::XMLReader &)
 

TypeHandling

class App::ExtensionContainer
 
bool m_isPythonExtension = false
 
Py::SmartPtr ExtensionPythonObject
 
bool extensionIsDerivedFrom (const Base::Type type) const
 
static void initExtensionSubclass (Base::Type &toInit, const char *ClassName, const char *ParentName, Base::Type::instantiationMethod method=nullptr)
 
virtual void extensionOnChanged (const Property *p)
 
void initExtensionType (Base::Type type)
 

Detailed Description

Base class for all extension that can be added to a DocumentObject.

For general documentation on why extension system exists and how to use it see the ExtensionContainer documentation. Following is a description howto create custom extensions.

Extensions are like every other FreeCAD object and based on properties. All information storage and persistence should be achieved by use of those. Additional any number of methods can be added to provide functionality around the properties. There are 3 small difference to normal objects:

  1. They must be derived from Extension class
  2. Properties must be handled with special extension macros
  3. Extensions must be initialised This works as simple as
    class MyExtension : public Extension {
    EXTENSION_PROPERTY_HEADER(MyExtension);
    PropertyInt MyProp;
    virtual bool overridableMethod(DocumentObject* obj) {};
    };
    EXTENSION_PROPERTY_SOURCE(App::MyExtension, App::Extension)
    MyExtension::MyExtension() {
    EXTENSION_ADD_PROPERTY(MyProp, (0)) *
    initExtension(MyExtension::getExtensionClassTypeId());
    }
    typedef ExtensionPythonT<MyExtension> MyExtensionPython;

The special python extension type created above is important, as only those python extensions can be added to an object from python. It does not work to add the c++ version directly there.

Note that every method of the extension becomes part of the extended object when added from c++. This means one should carefully design the API and make only necessary methods public or protected. Every internal method should be private.

The automatic availability of methods in the class does not hold for the python interface, only for c++ classes. This is like every where else in FreeCAD, there is no automatic creation of python API from c++ classes. Hence the extension creator must also create a custom python object of its extension, which works exactly like the normal FreeCAD python object workflow. There is nothing special at all for extension python objects, the normal xml + imp.cpp approach is used. It must only be taken care that the objects father is the correct extension base class. Of course also make sure your extension returns the correct python object in its "getPyObject" call. Every method you create in the extensions python will be later added to an extended object. This happens automatically for both, c++ and python extension, if "getPyObject" returns the correct python object. No extra work needs to be done.

A special case that needs to be handled for extensions is the possibility of overridden methods. Often it is desired to customise extension behaviour by allowing the user to override methods provided by the extension. On c++ side this is trivial, such methods are simply marked as "virtual" and can than be overridden in any derived class. This is more involved for the python interface and here special care needs to be taken.

As already seen above one needs to create a special ExtensionPythonT<> object for extension from python. This is done exactly for the purpose of allowing to have overridable methods. The ExtensionPythonT wrapper adds a proxy property which holds a PyObject which itself will contain the implementations for the overridden methods. This design is equal to the ObjectPythonT<> design of normal document objects. As this wrapper inherits the c++ extension class it can also override the virtual functions the user designed to be overridden. What it should do at a call of the virtual method is to check if this method is implemented in the proxy object and if so call it, and if not call the normal c++ version. It is the extensions creators responsibility to implement this check and call behaviour for every overridable method. This is done by creating a custom wrapper just like ExtensionPythonT<> and overriding all virtual methods.

template<typename ExtensionT> class MyExtensionPythonT : public ExtensionT {
public:
MyExtensionPythonT() {}
virtual ~MyExtensionPythonT() {}
virtual bool overridableMethod(DocumentObject* obj) override {
Py::Object pyobj = Py::asObject(obj->getPyObject());
EXTENSION_PROXY_ONEARG(allowObject, pyobj);
if(result.isNone())
ExtensionT::allowObject(obj);
if(result.isBoolean())
return result.isTrue();
return false;
};
};

@Note As seen in the code there are multiple helper macros to ease the repetitive work of querying and calling methods of the proxy object. See the macro documentation for how to use them.

To ensure that your wrapper is used when a extension is created from python the extension type must be exposed as follows:

This boilerplate is absolutely necessary to allow overridable methods in python and it is the extension creator's responsibility to ensure full implementation.

Constructor & Destructor Documentation

◆ Extension()

Extension::Extension ( )

◆ ~Extension()

Extension::~Extension ( )
virtual

References ExtensionPythonObject.

Member Function Documentation

◆ extensionGetPropertyByName()

Property * Extension::extensionGetPropertyByName ( const char *  name) const
virtual

find a property by its name

Reimplemented in App::LinkBaseExtension.

Referenced by App::LinkBaseExtension::extensionGetPropertyByName().

◆ extensionGetPropertyDocumentation() [1/2]

const char * Extension::extensionGetPropertyDocumentation ( const char *  name) const
virtual

get the Group of a named Property

◆ extensionGetPropertyDocumentation() [2/2]

const char * Extension::extensionGetPropertyDocumentation ( const Property prop) const
virtual

get the Group of a Property

◆ extensionGetPropertyGroup() [1/2]

const char * Extension::extensionGetPropertyGroup ( const char *  name) const
virtual

get the Group of a named Property

◆ extensionGetPropertyGroup() [2/2]

const char * Extension::extensionGetPropertyGroup ( const Property prop) const
virtual

get the Group of a Property

◆ extensionGetPropertyList()

void Extension::extensionGetPropertyList ( std::vector< Property * > &  List) const
virtual

get all properties of the class (including properties of the parent)

◆ extensionGetPropertyMap()

void Extension::extensionGetPropertyMap ( std::map< std::string, Property * > &  Map) const
virtual

get all properties of the class (including properties of the parent)

◆ extensionGetPropertyName()

const char * Extension::extensionGetPropertyName ( const Property prop) const
virtual

get the name of a property

Referenced by App::LinkBaseExtension::setProperty().

◆ extensionGetPropertyType() [1/2]

short int Extension::extensionGetPropertyType ( const char *  name) const
virtual

get the Type of a named Property

◆ extensionGetPropertyType() [2/2]

short int Extension::extensionGetPropertyType ( const Property prop) const
virtual

get the Type of a Property

◆ extensionIsDerivedFrom()

bool App::Extension::extensionIsDerivedFrom ( const Base::Type  type) const

◆ extensionOnChanged()

◆ extensionRestore()

virtual void App::Extension::extensionRestore ( Base::XMLReader )
virtual

◆ extensionSave()

virtual void App::Extension::extensionSave ( Base::Writer ) const
virtual

◆ getExtendedContainer() [1/2]

◆ getExtendedContainer() [2/2]

const App::ExtensionContainer * App::Extension::getExtendedContainer ( ) const

◆ getExtensionPyObject()

◆ initExtension()

◆ initExtensionSubclass()

void Extension::initExtensionSubclass ( Base::Type toInit,
const char *  ClassName,
const char *  ParentName,
Base::Type::instantiationMethod  method = nullptr 
)
staticprotected

◆ initExtensionType()

void Extension::initExtensionType ( Base::Type  type)
protected

◆ isPythonExtension()

bool App::Extension::isPythonExtension ( )

◆ name()

Friends And Related Function Documentation

◆ App::ExtensionContainer

Member Data Documentation

◆ ExtensionPythonObject

◆ m_isPythonExtension

bool App::Extension::m_isPythonExtension = false
protected

The documentation for this class was generated from the following files: