Merge pull request #19142 from hyarion/refactor/add-template-addobject
Add new addObject<T>() function
This commit is contained in:
@@ -3544,7 +3544,7 @@ DocumentObject* Document::addObject(const char* sType,
|
||||
const char* viewType,
|
||||
bool isPartial)
|
||||
{
|
||||
Base::Type type =
|
||||
const Base::Type type =
|
||||
Base::Type::getTypeIfDerivedFrom(sType, App::DocumentObject::getClassTypeId(), true);
|
||||
if (type.isBad()) {
|
||||
std::stringstream str;
|
||||
@@ -3557,8 +3557,7 @@ DocumentObject* Document::addObject(const char* sType,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
App::DocumentObject* pcObject = static_cast<App::DocumentObject*>(typeInstance);
|
||||
|
||||
auto* pcObject = static_cast<App::DocumentObject*>(typeInstance);
|
||||
pcObject->setDocument(this);
|
||||
|
||||
// do no transactions if we do a rollback!
|
||||
@@ -3571,15 +3570,8 @@ DocumentObject* Document::addObject(const char* sType,
|
||||
}
|
||||
|
||||
// get Unique name
|
||||
string ObjectName;
|
||||
|
||||
if (pObjectName && pObjectName[0] != '\0') {
|
||||
ObjectName = getUniqueObjectName(pObjectName);
|
||||
}
|
||||
else {
|
||||
ObjectName = getUniqueObjectName(sType);
|
||||
}
|
||||
|
||||
const bool hasName = pObjectName && pObjectName[0] != '\0';
|
||||
const string ObjectName = getUniqueObjectName(hasName ? pObjectName : type.getName());
|
||||
|
||||
d->activeObject = pcObject;
|
||||
|
||||
|
||||
@@ -268,6 +268,21 @@ public:
|
||||
bool isNew = true,
|
||||
const char* viewType = nullptr,
|
||||
bool isPartial = false);
|
||||
//@{
|
||||
/** Add a feature of T type with sName (ASCII) to this document and set it active.
|
||||
* Unicode names are set through the Label property.
|
||||
* @param pObjectName if nonNULL use that name otherwise generate a new unique name based on the
|
||||
* \a sType
|
||||
* @param isNew if false don't call the \c DocumentObject::setupObject() callback (default
|
||||
* is true)
|
||||
* @param viewType override object's view provider name
|
||||
* @param isPartial indicate if this object is meant to be partially loaded
|
||||
*/
|
||||
template<typename T>
|
||||
T* addObject(const char* pObjectName = nullptr,
|
||||
bool isNew = true,
|
||||
const char* viewType = nullptr,
|
||||
bool isPartial = false);
|
||||
/** Add an array of features of the given types and names.
|
||||
* Unicode names are set through the Label property.
|
||||
* @param sType The type of created object
|
||||
@@ -662,6 +677,12 @@ inline int Document::countObjectsOfType() const
|
||||
return this->countObjectsOfType(T::getClassTypeId());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Document::addObject(const char* pObjectName, bool isNew, const char* viewType, bool isPartial)
|
||||
{
|
||||
static_assert(std::is_base_of<DocumentObject, T>::value, "T must be derived from DocumentObject");
|
||||
return static_cast<T*>(addObject(T::getClassName(), pObjectName, isNew, viewType, isPartial));
|
||||
}
|
||||
|
||||
} // namespace App
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ private:
|
||||
std::map<Base::Type, App::Extension*> _extensions;
|
||||
};
|
||||
|
||||
#define PROPERTY_HEADER_WITH_EXTENSIONS(_class_) PROPERTY_HEADER_WITH_OVERRIDE(_class)
|
||||
#define PROPERTY_HEADER_WITH_EXTENSIONS(_class_) PROPERTY_HEADER_WITH_OVERRIDE(_class_)
|
||||
|
||||
/// We make sure that the PropertyData of the container is not connected to the one of the extension
|
||||
#define PROPERTY_SOURCE_WITH_EXTENSIONS(_class_, _parentclass_) \
|
||||
|
||||
@@ -51,6 +51,11 @@ public:
|
||||
* append it to this group as well.
|
||||
*/
|
||||
virtual DocumentObject* addObject(const char* sType, const char* pObjectName);
|
||||
/** Adds an object of \a T with \a pObjectName to the document this group belongs to and
|
||||
* append it to this group as well.
|
||||
*/
|
||||
template<typename T>
|
||||
T* addObject(const char* pObjectName);
|
||||
/* Adds the object \a obj to this group. Returns all objects that have been added.
|
||||
*/
|
||||
virtual std::vector<DocumentObject*> addObject(DocumentObject* obj);
|
||||
@@ -151,6 +156,13 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
T* GroupExtension::addObject(const char* pObjectName)
|
||||
{
|
||||
static_assert(std::is_base_of<DocumentObject, T>::value, "T must be derived from DocumentObject");
|
||||
return static_cast<T*>(addObject(T::getClassName(), pObjectName));
|
||||
}
|
||||
|
||||
template<typename ExtensionT>
|
||||
class GroupExtensionPythonT: public ExtensionT
|
||||
{
|
||||
|
||||
@@ -158,7 +158,7 @@ App::DocumentObjectExecReturn* OriginGroupExtension::extensionExecute()
|
||||
|
||||
App::DocumentObject* OriginGroupExtension::getLocalizedOrigin(App::Document* doc)
|
||||
{
|
||||
App::DocumentObject* originObject = doc->addObject("App::Origin", "Origin");
|
||||
auto* originObject = doc->addObject<App::Origin>("Origin");
|
||||
QByteArray byteArray = tr("Origin").toUtf8();
|
||||
originObject->Label.setValue(byteArray.constData());
|
||||
return originObject;
|
||||
|
||||
@@ -305,6 +305,49 @@ private: \
|
||||
/// Like PROPERTY_HEADER, but with overridden methods declared as such
|
||||
#define PROPERTY_HEADER_WITH_OVERRIDE(_class_) \
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE(); \
|
||||
public: \
|
||||
static constexpr const char* getClassName() {\
|
||||
/*
|
||||
TODO: When c++20 is available \
|
||||
- Use consteval to ensure the function is evaluated at compile time \
|
||||
- Move bulk of the function to a template `validate<T, _class_, #_class>()` \
|
||||
- Use `starts_with` when checking namespace in path \
|
||||
*/ \
|
||||
\
|
||||
static_assert(sizeof(_class_) > 0, "Class is not complete"); \
|
||||
\
|
||||
constexpr const char* sClass = #_class_; \
|
||||
constexpr std::string_view vClass {sClass}; \
|
||||
static_assert(vClass[0] != '\0', "Class name must not be empty"); \
|
||||
static_assert(std::is_base_of<App::PropertyContainer, _class_>::value, \
|
||||
"Class must be derived from App::PropertyContainer"); \
|
||||
\
|
||||
constexpr bool isSubClassOfDocObj = std::is_base_of<App::DocumentObject, _class_>::value && \
|
||||
!std::is_same<App::DocumentObject, _class_>::value; \
|
||||
if constexpr (isSubClassOfDocObj) { \
|
||||
constexpr auto pos = vClass.find("::"); \
|
||||
static_assert(pos != std::string_view::npos, \
|
||||
"Class name must be fully qualified for document object derived classes"); \
|
||||
static_assert(pos != 0, "Namespace must not be empty"); \
|
||||
\
|
||||
constexpr auto vNamespace = vClass.substr(0, pos); \
|
||||
constexpr std::string_view filePath = __FILE__; \
|
||||
constexpr auto posAfterSrcMod = filePath.find("/src/Mod/"); \
|
||||
if constexpr (constexpr bool hasSrcModInPath = posAfterSrcMod != std::string_view::npos) { \
|
||||
constexpr auto pathAfterSrcMod = filePath.substr(posAfterSrcMod + 9); \
|
||||
/* some workarounds are needed, if CI is ok in the future, remove these: \
|
||||
- isSubClassOfDocObj shouldn't be needed, but it is for some compilers \
|
||||
- allowing `Path` until it's been properly renamed */ \
|
||||
constexpr bool workarounds = !isSubClassOfDocObj || vNamespace == "Path"; \
|
||||
/* TODO: use `starts_with` instead of `find` when c++20 is available */ \
|
||||
constexpr bool isPathOk = pathAfterSrcMod.find(vNamespace) != std::string_view::npos; \
|
||||
static_assert(workarounds || isPathOk, \
|
||||
"Classes in `src/Mod` needs to be in a directory with the same name as" \
|
||||
" the namespace in order to load correctly"); \
|
||||
} \
|
||||
} \
|
||||
return sClass; \
|
||||
} \
|
||||
protected: \
|
||||
static const App::PropertyData * getPropertyDataPtr(void); \
|
||||
const App::PropertyData &getPropertyData(void) const override; \
|
||||
|
||||
Reference in New Issue
Block a user