372 lines
13 KiB
C++
372 lines
13 KiB
C++
// SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
/***************************************************************************
|
|
* Copyright (c) 2016 Stefan Tröger <stefantroeger@gmx.net> *
|
|
* *
|
|
* 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 *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifndef SRC_APP_EXTENSION_H_
|
|
#define SRC_APP_EXTENSION_H_
|
|
|
|
#include <map>
|
|
#include <string>
|
|
|
|
#include "PropertyContainer.h"
|
|
#include <Base/SmartPtrPy.h>
|
|
|
|
namespace App {
|
|
|
|
class ExtensionContainer;
|
|
|
|
// clang-format off
|
|
/// define Extension types
|
|
#define EXTENSION_TYPESYSTEM_HEADER() \
|
|
public: \
|
|
static Base::Type getExtensionClassTypeId(void); \
|
|
virtual Base::Type getExtensionTypeId(void) const; \
|
|
static void init(void);\
|
|
static void *create(void);\
|
|
private: \
|
|
static Base::Type classTypeId
|
|
|
|
/// Like EXTENSION_TYPESYSTEM_HEADER, with getExtensionTypeId declared override
|
|
#define EXTENSION_TYPESYSTEM_HEADER_WITH_OVERRIDE() \
|
|
public: \
|
|
static Base::Type getExtensionClassTypeId(void); \
|
|
Base::Type getExtensionTypeId(void) const override; \
|
|
static void init(void);\
|
|
static void *create(void);\
|
|
private: \
|
|
static Base::Type classTypeId
|
|
|
|
/// define to implement a subclass of Base::BaseClass
|
|
#define EXTENSION_TYPESYSTEM_SOURCE_P(_class_) \
|
|
Base::Type _class_::getExtensionClassTypeId(void) { return _class_::classTypeId; } \
|
|
Base::Type _class_::getExtensionTypeId(void) const { return _class_::classTypeId; } \
|
|
Base::Type _class_::classTypeId = Base::Type::BadType; \
|
|
void * _class_::create(void){\
|
|
return new _class_ ();\
|
|
}
|
|
|
|
/// define to implement a subclass of Base::BaseClass
|
|
#define EXTENSION_TYPESYSTEM_SOURCE_ABSTRACT_P(_class_) \
|
|
Base::Type _class_::getExtensionClassTypeId(void) { return _class_::classTypeId; } \
|
|
Base::Type _class_::getExtensionTypeId(void) const { return _class_::classTypeId; } \
|
|
Base::Type _class_::classTypeId = Base::Type::BadType; \
|
|
void * _class_::create(void){return 0;}
|
|
|
|
/// define to implement a subclass of Base::BaseClass
|
|
#define EXTENSION_TYPESYSTEM_SOURCE(_class_, _parentclass_) \
|
|
EXTENSION_TYPESYSTEM_SOURCE_P(_class_)\
|
|
void _class_::init(void){\
|
|
initExtensionSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
|
|
}
|
|
|
|
#define EXTENSION_TYPESYSTEM_SOURCE_TEMPLATE(_class_) \
|
|
template<> Base::Type _class_::classTypeId = Base::Type::BadType; \
|
|
template<> Base::Type _class_::getExtensionClassTypeId(void) { return _class_::classTypeId; } \
|
|
template<> Base::Type _class_::getExtensionTypeId(void) const { return _class_::classTypeId; } \
|
|
template<> void * _class_::create(void){\
|
|
return new _class_ ();\
|
|
}
|
|
|
|
// init property stuff
|
|
#define EXTENSION_PROPERTY_HEADER(_class_) \
|
|
EXTENSION_TYPESYSTEM_HEADER(); \
|
|
protected: \
|
|
static const App::PropertyData * extensionGetPropertyDataPtr(void); \
|
|
virtual const App::PropertyData &extensionGetPropertyData(void) const; \
|
|
private: \
|
|
static App::PropertyData propertyData
|
|
|
|
/// Like EXTENSION_PROPERTY_HEADER, but with override declarations.
|
|
#define EXTENSION_PROPERTY_HEADER_WITH_OVERRIDE(_class_) \
|
|
EXTENSION_TYPESYSTEM_HEADER_WITH_OVERRIDE(); \
|
|
protected: \
|
|
static const App::PropertyData * extensionGetPropertyDataPtr(void); \
|
|
const App::PropertyData &extensionGetPropertyData(void) const override; \
|
|
private: \
|
|
static App::PropertyData propertyData
|
|
|
|
#define EXTENSION_PROPERTY_SOURCE(_class_, _parentclass_) \
|
|
EXTENSION_TYPESYSTEM_SOURCE_P(_class_)\
|
|
const App::PropertyData * _class_::extensionGetPropertyDataPtr(void){return &propertyData;} \
|
|
const App::PropertyData & _class_::extensionGetPropertyData(void) const{return propertyData;} \
|
|
App::PropertyData _class_::propertyData; \
|
|
void _class_::init(void){\
|
|
initExtensionSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
|
|
_class_::propertyData.parentPropertyData = _parentclass_::extensionGetPropertyDataPtr();\
|
|
}
|
|
|
|
#define EXTENSION_PROPERTY_SOURCE_TEMPLATE(_class_, _parentclass_) \
|
|
EXTENSION_TYPESYSTEM_SOURCE_TEMPLATE(_class_)\
|
|
template<> App::PropertyData _class_::propertyData = App::PropertyData(); \
|
|
template<> const App::PropertyData * _class_::extensionGetPropertyDataPtr(void){return &propertyData;} \
|
|
template<> const App::PropertyData & _class_::extensionGetPropertyData(void) const{return propertyData;} \
|
|
template<> void _class_::init(void){\
|
|
initExtensionSubclass(_class_::classTypeId, #_class_ , #_parentclass_, &(_class_::create) ); \
|
|
_class_::propertyData.parentPropertyData = _parentclass_::extensionGetPropertyDataPtr();\
|
|
}
|
|
// clang-format on
|
|
|
|
/**
|
|
* @brief A base class for extensions for a DocumentObject.
|
|
* @ingroup ExtensionFramework
|
|
*
|
|
* This class provides a base class for extensions for a DocumentObject. It is
|
|
* used to hold extensions of a document object. For a more high-level
|
|
* discussion of extensions see the topic @ref ExtensionFramework "Extension Framework".
|
|
*/
|
|
class AppExport Extension
|
|
{
|
|
|
|
//The cass does not have properties itself, but it is important to provide the property access
|
|
//functions. see cpp file for details
|
|
EXTENSION_PROPERTY_HEADER(App::Extension);
|
|
|
|
public:
|
|
/// Construct an extension object.
|
|
Extension() = default;
|
|
/// Destruct an extension object.
|
|
virtual ~Extension();
|
|
|
|
/**
|
|
* @brief Initialize the extension.
|
|
*
|
|
* This function is called by the ExtensionContainer to initialize the
|
|
* extension.
|
|
*
|
|
* @param[in,out] obj The ExtensionContainer object to which this extension
|
|
* is attached.
|
|
*
|
|
* @throw Base::RuntimeError If the extension type is not set.
|
|
*/
|
|
virtual void initExtension(App::ExtensionContainer* obj);
|
|
|
|
/**
|
|
* @brief Get the container of the extension.
|
|
*
|
|
* @return The ExtensionContainer object to which this extension belongs.
|
|
*/
|
|
App::ExtensionContainer* getExtendedContainer() {return m_base;}
|
|
|
|
/**
|
|
* @brief Get the container of the extension.
|
|
*
|
|
* @return The ExtensionContainer object to which this extension belongs.
|
|
*/
|
|
const App::ExtensionContainer* getExtendedContainer() const {return m_base;}
|
|
|
|
/**
|
|
* @brief Get the name of the extension.
|
|
*
|
|
* The name is the class name of the extension without the namespace.
|
|
*
|
|
* @return The name of the extension.
|
|
*/
|
|
std::string name() const;
|
|
|
|
/**
|
|
* @brief Whether the extension is a Python extension.
|
|
*
|
|
* @return True if the extension is a Python extension, false otherwise.
|
|
*/
|
|
bool isPythonExtension() {return m_isPythonExtension;}
|
|
|
|
/**
|
|
* @brief Get the PyObject of the extension.
|
|
*
|
|
* @return The PyObject of the extension.
|
|
*/
|
|
virtual PyObject* getExtensionPyObject();
|
|
|
|
|
|
/** @name Access properties
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::getPropertyByName()
|
|
*/
|
|
virtual Property *extensionGetPropertyByName(const char* name) const;
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::getPropertyName()
|
|
*/
|
|
virtual const char* extensionGetPropertyName(const Property* prop) const;
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::getPropertyMap()
|
|
*/
|
|
virtual void extensionGetPropertyMap(std::map<std::string,Property*> &map) const;
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::visitProperties()
|
|
*/
|
|
virtual void extensionVisitProperties(const std::function<void(Property*)>& visitor) const;
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::getPropertyList()
|
|
*/
|
|
virtual void extensionGetPropertyList(std::vector<Property*> &List) const;
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::getPropertyType(const Property*) const
|
|
*/
|
|
virtual short extensionGetPropertyType(const Property* prop) const;
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::getPropertyType(const char*) const
|
|
*/
|
|
virtual short extensionGetPropertyType(const char *name) const;
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::getPropertyGroup(const Property*) const
|
|
*/
|
|
virtual const char* extensionGetPropertyGroup(const Property* prop) const;
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::getPropertyGroup(const char*) const
|
|
*/
|
|
virtual const char* extensionGetPropertyGroup(const char *name) const;
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::getPropertyDocumentation(const Property*) const
|
|
*/
|
|
virtual const char* extensionGetPropertyDocumentation(const Property* prop) const;
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::getPropertyDocumentation(const char*) const
|
|
*/
|
|
virtual const char* extensionGetPropertyDocumentation(const char *name) const;
|
|
/// @}
|
|
|
|
/** @name Persistence
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @copydoc Base::Persistence::Save
|
|
*/
|
|
virtual void extensionSave(Base::Writer&) const {}
|
|
|
|
/**
|
|
* @copydoc Base::Persistence::Restore
|
|
*/
|
|
virtual void extensionRestore(Base::XMLReader&) {}
|
|
/// @}
|
|
|
|
/**
|
|
* @copydoc Base::Type::isDerivedFrom()
|
|
*/
|
|
bool extensionIsDerivedFrom(const Base::Type type) const {return getExtensionTypeId().isDerivedFrom(type);}
|
|
|
|
protected:
|
|
/**
|
|
* @brief Helper function to register the parent.
|
|
*
|
|
* This is used in the macros. It creates a new type in @p toInit based on
|
|
* the parent. @p toInit should be an uninitialized type.
|
|
*
|
|
* @param[out] toInit The type to initialize.
|
|
* @param[in] ClassName The name of the class.
|
|
* @param[in] ParentName The name of the parent class.
|
|
* @param[in] method The instantiation method.
|
|
*/
|
|
static void initExtensionSubclass(Base::Type &toInit,const char* ClassName, const char *ParentName,
|
|
Base::Type::instantiationMethod method=nullptr);
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::onChanged()
|
|
*/
|
|
virtual void extensionOnChanged([[maybe_unused]] const Property* prop) {}
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::handleChangedPropertyName()
|
|
*
|
|
* @return True if the property name change was handled by the extension,
|
|
* false otherwise.
|
|
*/
|
|
virtual bool extensionHandleChangedPropertyName(Base::XMLReader &reader, const char * typeName, const char *propName);
|
|
|
|
/**
|
|
* @copydoc PropertyContainer::handleChangedPropertyType()
|
|
*
|
|
* @return True if the property type change was handled by the extension,
|
|
* false otherwise.
|
|
*/
|
|
virtual bool extensionHandleChangedPropertyType(Base::XMLReader &reader, const char * typeName, Property * prop);
|
|
|
|
/// Provide access to the ExtensionContainer.
|
|
friend class App::ExtensionContainer;
|
|
|
|
protected:
|
|
/**
|
|
* @brief Initialize the extension type.
|
|
*
|
|
* This function is to be called by the constructor to initialize the
|
|
* extension type.
|
|
*
|
|
* @param[in] type The type of the extension.
|
|
*
|
|
* @throw Base::RuntimeError If the extension type is not set.
|
|
*/
|
|
void initExtensionType(Base::Type type);
|
|
|
|
/// Whether the extension is a Python extension.
|
|
bool m_isPythonExtension = false;
|
|
|
|
/// The Python object of the extension.
|
|
Py::SmartPtr ExtensionPythonObject;
|
|
|
|
private:
|
|
Base::Type m_extensionType;
|
|
App::ExtensionContainer* m_base = nullptr;
|
|
};
|
|
|
|
// clang-format off
|
|
// Property define
|
|
#define _EXTENSION_ADD_PROPERTY(_name, _prop_, _defaultval_) \
|
|
do { \
|
|
this->_prop_.setValue _defaultval_;\
|
|
propertyData.addProperty(static_cast<App::Extension*>(this), _name, &this->_prop_); \
|
|
} while (0)
|
|
|
|
|
|
#define EXTENSION_ADD_PROPERTY(_prop_, _defaultval_) \
|
|
_EXTENSION_ADD_PROPERTY(#_prop_, _prop_, _defaultval_)
|
|
|
|
#define _EXTENSION_ADD_PROPERTY_TYPE(_name, _prop_, _defaultval_, _group_,_type_,_Docu_) \
|
|
do { \
|
|
this->_prop_.setValue _defaultval_;\
|
|
propertyData.addProperty(static_cast<App::Extension*>(this), _name, &this->_prop_, (_group_),(_type_),(_Docu_)); \
|
|
} while (0)
|
|
|
|
#define EXTENSION_ADD_PROPERTY_TYPE(_prop_, _defaultval_, _group_,_type_,_Docu_) \
|
|
_EXTENSION_ADD_PROPERTY_TYPE(#_prop_, _prop_, _defaultval_, _group_,_type_,_Docu_)
|
|
// clang-format on
|
|
|
|
|
|
} // namespace App
|
|
|
|
#endif // SRC_APP_EXTENSION_H_
|