diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-10-09 08:24:21 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2023-10-23 12:26:07 +0200 |
commit | 91bf9aa10faad14de557136664f58005c935d11c (patch) | |
tree | d5ff6278aca875c89ffad46cc36d68ba74a366c9 /sources/pyside6/libpysideqml | |
parent | 624e52a0114a966bd852aeb66b8a1b928d80343b (diff) |
QML registration code: Modernize
Use QQmlPrivate::RegisterTypeAndRevisions and information set as
QMetaClassInfo as recommended by QML team. The only remaining old code
path is for qmlRegisterSingletonType() for the hypothetical case of a
value type.
[ChangeLog][PySide6] QML type registration has been ported
to use RegisterTypeAndRevisions.
Fixes: PYSIDE-2484
Change-Id: I7134cbfe1fad1fb543a560cc13b68327b9bd9c2b
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'sources/pyside6/libpysideqml')
6 files changed, 235 insertions, 132 deletions
diff --git a/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp b/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp index 940847632..24b313d32 100644 --- a/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp +++ b/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp @@ -6,6 +6,7 @@ #include "pysideqmltypeinfo_p.h" #include "pysideqmlattached_p.h" #include "pysideqmlextended_p.h" +#include "pysideqmluncreatable.h" #include <limits> #include <optional> @@ -17,6 +18,7 @@ // pyside #include <pyside.h> #include <pysideqobject.h> +#include <pysideclassinfo.h> #include <pyside_p.h> #include <QtCore/QMutex> @@ -27,8 +29,12 @@ #include <QtQml/QQmlListProperty> #include <private/qqmlmetatype_p.h> +using namespace Qt::StringLiterals; + static PySide::Qml::QuickRegisterItemFunction quickRegisterItemFunction = nullptr; +static const auto qmlElementKey = "QML.Element"_ba; + static void createInto(void *memory, void *type) { QMutexLocker locker(&PySide::nextQObjectMemoryAddrMutex()); @@ -150,11 +156,41 @@ std::optional<ImportData> getGlobalImportData(const char *decoratorName) return result; } +static PyTypeObject *checkTypeObject(PyObject *pyObj, const char *what) +{ + if (PyType_Check(pyObj) == 0) { + PyErr_Format(PyExc_TypeError, "%s can only be used for classes.", what); + return nullptr; + } + return reinterpret_cast<PyTypeObject *>(pyObj); +} + +static bool setClassInfo(PyTypeObject *type, const QByteArray &key, const QByteArray &value) +{ + if (!PySide::ClassInfo::setClassInfo(type, key, value)) { + PyErr_Format(PyExc_TypeError, "Setting class info \"%s\" to \"%s\" on \"%s\" failed.", + key.constData(), value.constData(), type->tp_name); + return false; + } + return true; +} + +static inline bool setSingletonClassInfo(PyTypeObject *type) +{ + return setClassInfo(type, "QML.Singleton"_ba, "true"_ba); +} + +static QQmlCustomParser *defaultCustomParserFactory() +{ + return nullptr; +} + namespace PySide::Qml { -static int qmlRegisterType(PyObject *pyObj, const ImportData &importData, - const char *qmlName, const char *noCreationReason, - bool creatable) +// Modern (6.7) type registration using RegisterTypeAndRevisions +// and information set to QMetaClassInfo. +static int qmlRegisterType(PyObject *pyObj, PyObject *pyClassInfoObj, + const ImportData &importData) { using namespace Shiboken; @@ -164,6 +200,8 @@ static int qmlRegisterType(PyObject *pyObj, const ImportData &importData, const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType); Q_ASSERT(metaObject); + const QMetaObject *classInfoMetaObject = pyObj == pyClassInfoObj + ? metaObject : PySide::retrieveMetaObject(pyClassInfoObj); // Register as simple QObject rather than Qt Quick item. // Incref the type object, don't worry about decref'ing it because @@ -181,26 +219,27 @@ static int qmlRegisterType(PyObject *pyObj, const ImportData &importData, const auto attachedInfo = qmlAttachedInfo(pyObjType, typeInfo); const auto extendedInfo = qmlExtendedInfo(pyObj, typeInfo); - QQmlPrivate::RegisterType type { + QList<int> ids; + QQmlPrivate::RegisterTypeAndRevisions type { QQmlPrivate::RegisterType::StructVersion::Base, // structVersion typeId, listId, objectSize, - creatable ? createInto : nullptr, // create + createInto, // create pyObj, // userdata - QString::fromUtf8(noCreationReason), nullptr, // createValueType (Remove in Qt 7) importData.importName.constData(), importData.toTypeRevision(), // version - qmlName, // elementName metaObject, + classInfoMetaObject, attachedInfo.factory, // attachedPropertiesFunction attachedInfo.metaObject, // attachedPropertiesMetaObject 0, 0, 0, // parserStatusCast, valueSourceCast, valueInterceptorCast extendedInfo.factory, // extensionObjectCreate extendedInfo.metaObject, // extensionMetaObject - nullptr, // customParser - {}, // revision + defaultCustomParserFactory, // customParser + &ids, // qmlTypeIds 0, // finalizerCast - QQmlPrivate::ValueTypeCreationMethod::None // creationMethod + false, // forceAnonymous + {} // listMetaSequence }; // Allow registering Qt Quick items. @@ -220,47 +259,137 @@ static int qmlRegisterType(PyObject *pyObj, const ImportData &importData, QQmlPrivate::StaticCastSelector<QObject, QQmlPropertyValueInterceptor>::cast(); } - int qmlTypeId = QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); + QQmlPrivate::qmlregister(QQmlPrivate::TypeAndRevisionsRegistration, &type); + const int qmlTypeId = ids.value(0, -1); if (qmlTypeId == -1) { PyErr_Format(PyExc_TypeError, "QML meta type registration of \"%s\" failed.", - qmlName); + typeName.constData()); } return qmlTypeId; } +// Legacy (pre 6.7) compatibility helper for the free register functions. int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int versionMinor, const char *qmlName, const char *noCreationReason, bool creatable) { - return qmlRegisterType(pyObj, {uri, versionMajor, versionMinor}, qmlName, - noCreationReason, creatable); + auto *type = checkTypeObject(pyObj, "qmlRegisterType()"); + if (type == nullptr || !setClassInfo(type, qmlElementKey, qmlName)) + return -1; + if (!creatable) + setUncreatableClassInfo(type, noCreationReason); + return qmlRegisterType(pyObj, pyObj, {uri, versionMajor, versionMinor}); } -static int qmlRegisterSingletonType(PyObject *pyObj, const ImportData &importData, - const char *qmlName, PyObject *callback, - bool isQObject, bool hasCallback) +// Singleton helpers + +bool checkSingletonCallback(PyObject *callback) +{ + if (PyCallable_Check(callback) == 0) { + PyErr_Format(PyExc_TypeError, "Invalid callback specified."); + return false; + } + Shiboken::AutoDecRef funcCode(PyObject_GetAttrString(callback, "__code__")); + Shiboken::AutoDecRef argCount(PyObject_GetAttrString(funcCode, "co_argcount")); + if (PyLong_AsLong(argCount) != 1) { + PyErr_Format(PyExc_TypeError, "Callback has a bad parameter count."); + return false; + } + // Make sure the callback never gets deallocated + Py_INCREF(callback); + + return true; +} + +using SingletonQObjectCreation = std::function<QObject*(QQmlEngine *, QJSEngine *)>; + +static SingletonQObjectCreation + singletonQObjectCreation(PyObject *pyObj, PyObject *callback, bool hasCallback) { using namespace Shiboken; - if (hasCallback) { - if (!PyCallable_Check(callback)) { - PyErr_Format(PyExc_TypeError, "Invalid callback specified."); - return -1; - } + return [callback, pyObj, hasCallback](QQmlEngine *engine, QJSEngine *) -> QObject * { + Shiboken::GilState gil; + AutoDecRef args(PyTuple_New(hasCallback ? 1 : 0)); - AutoDecRef funcCode(PyObject_GetAttrString(callback, "__code__")); - AutoDecRef argCount(PyObject_GetAttrString(funcCode, "co_argcount")); + if (hasCallback) { + PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython( + qQmlEngineType(), engine)); + } - int count = PyLong_AsLong(argCount); + AutoDecRef retVal(PyObject_CallObject(hasCallback ? callback : pyObj, args)); - if (count != 1) { - PyErr_Format(PyExc_TypeError, "Callback has a bad parameter count."); - return -1; + // Make sure the callback returns something we can convert, else the entire application will crash. + if (retVal.isNull() || + Conversions::isPythonToCppPointerConvertible(qObjectType(), retVal) == nullptr) { + PyErr_Format(PyExc_TypeError, "Callback returns invalid value."); + return nullptr; } - // Make sure the callback never gets deallocated - Py_INCREF(callback); + QObject *obj = nullptr; + Conversions::pythonToCppPointer(qObjectType(), retVal, &obj); + + if (obj != nullptr) + Py_INCREF(retVal); + + return obj; + }; +} + +// Modern (6.7) singleton type registration using RegisterSingletonTypeAndRevisions +// and information set to QMetaClassInfo (QObject only pending QTBUG-110467). +static int qmlRegisterSingletonTypeV2(PyObject *pyObj, PyObject *pyClassInfoObj, + const ImportData &importData, + PyObject *callback, bool hasCallback) +{ + PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj); + if (!isQObjectDerived(pyObjType, true)) + return -1; + + if (hasCallback && !checkSingletonCallback(callback)) + return -1; + + const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType); + Q_ASSERT(metaObject); + const QMetaObject *classInfoMetaObject = pyObj == pyClassInfoObj + ? metaObject : PySide::retrieveMetaObject(pyClassInfoObj); + + // If we don't have a callback we'll need the pyObj to stay allocated indefinitely + if (!hasCallback) + Py_INCREF(pyObj); + + QList<int> ids; + QQmlPrivate::RegisterSingletonTypeAndRevisions type { + QQmlPrivate::RegisterType::StructVersion::Base, // structVersion + importData.importName.constData(), + importData.toTypeRevision(), // version + singletonQObjectCreation(pyObj, callback, hasCallback), // qObjectApi, + metaObject, + classInfoMetaObject, + QMetaType(QMetaType::QObjectStar), // typeId + nullptr, // extensionMetaObject + nullptr, // extensionObjectCreate + &ids + }; + + QQmlPrivate::qmlregister(QQmlPrivate::SingletonAndRevisionsRegistration, &type); + const int qmlTypeId = ids.value(0, -1); + if (qmlTypeId == -1) { + PyErr_Format(PyExc_TypeError, "Singleton QML meta type registration of \"%s\" failed.", + pyObjType->tp_name); } + return qmlTypeId; +} + +// Legacy (pre 6.7) singleton type registration using RegisterSingletonType +// for QObject and value types. Still used by qmlRegisterSingletonType() +// for the hypothetical case of a value type. +static int qmlRegisterSingletonType(PyObject *pyObj, const ImportData &importData, + const char *qmlName, PyObject *callback, + bool isQObject, bool hasCallback) +{ + if (hasCallback && !checkSingletonCallback(callback)) + return -1; const QMetaObject *metaObject = nullptr; @@ -296,36 +425,12 @@ static int qmlRegisterSingletonType(PyObject *pyObj, const ImportData &importDat // FIXME: Fix this to assign new type ids each time. type.typeId = QMetaType(QMetaType::QObjectStar); - type.qObjectApi = - [callback, pyObj, hasCallback](QQmlEngine *engine, QJSEngine *) -> QObject * { - Shiboken::GilState gil; - AutoDecRef args(PyTuple_New(hasCallback ? 1 : 0)); - - if (hasCallback) { - PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython( - qQmlEngineType(), engine)); - } - - AutoDecRef retVal(PyObject_CallObject(hasCallback ? callback : pyObj, args)); - - // Make sure the callback returns something we can convert, else the entire application will crash. - if (retVal.isNull() || - Conversions::isPythonToCppPointerConvertible(qObjectType(), retVal) == nullptr) { - PyErr_Format(PyExc_TypeError, "Callback returns invalid value."); - return nullptr; - } - - QObject *obj = nullptr; - Conversions::pythonToCppPointer(qObjectType(), retVal, &obj); - - if (obj != nullptr) - Py_INCREF(retVal); - - return obj; - }; + type.qObjectApi = singletonQObjectCreation(pyObj, callback, hasCallback); } else { type.scriptApi = [callback](QQmlEngine *engine, QJSEngine *) -> QJSValue { + using namespace Shiboken; + Shiboken::GilState gil; AutoDecRef args(PyTuple_New(1)); @@ -355,6 +460,7 @@ static int qmlRegisterSingletonType(PyObject *pyObj, const ImportData &importDat return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &type); } +// Legacy (pre 6.7) compatibility helper for the free register functions. int qmlRegisterSingletonType(PyObject *pyObj,const char *uri, int versionMajor, int versionMinor, const char *qmlName, PyObject *callback, bool isQObject, bool hasCallback) @@ -363,8 +469,10 @@ int qmlRegisterSingletonType(PyObject *pyObj,const char *uri, callback, isQObject, hasCallback); } +// Modern (6.7) singleton instance registration using RegisterSingletonTypeAndRevisions +// and information set to QMetaClassInfo (QObject only). static int qmlRegisterSingletonInstance(PyObject *pyObj, const ImportData &importData, - const char *qmlName, PyObject *instanceObject) + PyObject *instanceObject) { using namespace Shiboken; @@ -387,123 +495,105 @@ static int qmlRegisterSingletonInstance(PyObject *pyObj, const ImportData &impor const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType); Q_ASSERT(metaObject); - // FIXME: Fix this to assign new type ids each time. - const QMetaType typeId = QMetaType(QMetaType::QObjectStar); - - QQmlPrivate::RegisterSingletonType type { + QList<int> ids; + QQmlPrivate::RegisterSingletonTypeAndRevisions type { QQmlPrivate::RegisterType::StructVersion::Base, // structVersion importData.importName.constData(), importData.toTypeRevision(), // version - qmlName, // typeName - {}, // scriptApi - registrationFunctor, // qObjectApi - metaObject, // instanceMetaObject - typeId, + registrationFunctor, // qObjectApi, + metaObject, + metaObject, // classInfoMetaObject + QMetaType(QMetaType::QObjectStar), // typeId nullptr, // extensionMetaObject nullptr, // extensionObjectCreate - {} // revision + &ids }; - return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &type); + QQmlPrivate::qmlregister(QQmlPrivate::SingletonAndRevisionsRegistration, &type); + return ids.value(0, -1); } +// Legacy (pre 6.7) compatibility helper for the free register functions. int qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri, int versionMajor, int versionMinor, const char *qmlName, PyObject *instanceObject) { + auto *type = checkTypeObject(pyObj, "qmlRegisterSingletonInstance()"); + if (type == nullptr || !setClassInfo(type, qmlElementKey, qmlName) + || !setSingletonClassInfo(type)) { + return -1; + } return qmlRegisterSingletonInstance(pyObj, {uri, versionMajor, versionMinor}, - qmlName, instanceObject); + instanceObject); } } // namespace PySide::Qml enum class RegisterMode { Normal, - Anonymous, - Uncreatable, Singleton }; -static PyObject *qmlElementMacroHelper(PyObject *pyObj, - const char *decoratorName, - const char *typeName = nullptr, - RegisterMode mode = RegisterMode::Normal, - const char *noCreationReason = nullptr) +namespace PySide::Qml { + +PyObject *qmlElementMacro(PyObject *pyObj, const char *decoratorName, + const QByteArray &typeName) { - if (!PyType_Check(pyObj)) { - PyErr_Format(PyExc_TypeError, "This decorator can only be used on classes."); + auto *pyObjType = checkTypeObject(pyObj, decoratorName); + if (pyObjType == nullptr || !setClassInfo(pyObjType, qmlElementKey, typeName)) return nullptr; - } - PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj); - if (typeName == nullptr) - typeName = pyObjType->tp_name; if (!PySide::isQObjectDerived(pyObjType, false)) { - PyErr_Format(PyExc_TypeError, "This decorator can only be used with classes inherited from QObject, got %s.", - pyObjType->tp_name); + PyErr_Format(PyExc_TypeError, + "%s can only be used with classes inherited from QObject, got %s.", + decoratorName, pyObjType->tp_name); return nullptr; } + RegisterMode mode = RegisterMode::Normal; + const auto info = PySide::Qml::qmlTypeInfo(pyObj); + auto *registerObject = pyObj; + if (info) { + if (info->flags.testFlag(PySide::Qml::QmlTypeFlag::Singleton)) { + mode = RegisterMode::Singleton; + setSingletonClassInfo(pyObjType); + } + if (info->foreignType) + registerObject = reinterpret_cast<PyObject *>(info->foreignType); + } + const auto importDataO = getGlobalImportData(decoratorName); if (!importDataO.has_value()) return nullptr; const auto importData = importDataO.value(); const int result = mode == RegisterMode::Singleton - ? PySide::Qml::qmlRegisterSingletonType(pyObj, importData, - typeName, nullptr, - true /* is QObject */, - false) - : PySide::Qml::qmlRegisterType(pyObj, importData, - mode != RegisterMode::Anonymous ? typeName : nullptr, - noCreationReason, - mode == RegisterMode::Normal); + ? PySide::Qml::qmlRegisterSingletonTypeV2(registerObject, pyObj, importData, + nullptr, false) + : PySide::Qml::qmlRegisterType(registerObject, pyObj, importData); if (result == -1) { PyErr_Format(PyExc_TypeError, "%s: Failed to register type %s.", - decoratorName, typeName); + decoratorName, pyObjType->tp_name); + return nullptr; } return pyObj; } -namespace PySide::Qml { - -PyObject *qmlElementMacro(PyObject *pyObj, const char *decoratorName, - const char *typeName = nullptr) -{ - RegisterMode mode = RegisterMode::Normal; - const char *noCreationReason = nullptr; - const auto info = PySide::Qml::qmlTypeInfo(pyObj); - auto *registerObject = pyObj; - if (info) { - if (info->flags.testFlag(PySide::Qml::QmlTypeFlag::Singleton)) - mode = RegisterMode::Singleton; - else if (info->flags.testFlag(PySide::Qml::QmlTypeFlag::Uncreatable)) - mode = RegisterMode::Uncreatable; - noCreationReason = info->noCreationReason.constData(); - if (info->foreignType) - registerObject = reinterpret_cast<PyObject *>(info->foreignType); - } - if (!qmlElementMacroHelper(registerObject, decoratorName, typeName, mode, noCreationReason)) - return nullptr; - return pyObj; -} - PyObject *qmlElementMacro(PyObject *pyObj) { - return qmlElementMacro(pyObj, "QmlElement"); + return qmlElementMacro(pyObj, "QmlElement", "auto"_ba); } PyObject *qmlNamedElementMacro(PyObject *pyObj, const QByteArray &typeName) { - return qmlElementMacro(pyObj, "QmlNamedElement", qstrdup(typeName.constData())); + return qmlElementMacro(pyObj, "QmlNamedElement", typeName); } PyObject *qmlAnonymousMacro(PyObject *pyObj) { - return qmlElementMacroHelper(pyObj, "QmlAnonymous", nullptr, - RegisterMode::Anonymous); + return qmlElementMacro(pyObj, "QmlAnonymous", "anonymous"_ba); } PyObject *qmlSingletonMacro(PyObject *pyObj) diff --git a/sources/pyside6/libpysideqml/pysideqmlregistertype.h b/sources/pyside6/libpysideqml/pysideqmlregistertype.h index 1e6c7d28d..3524adaf4 100644 --- a/sources/pyside6/libpysideqml/pysideqmlregistertype.h +++ b/sources/pyside6/libpysideqml/pysideqmlregistertype.h @@ -19,6 +19,9 @@ namespace PySide::Qml /** * PySide implementation of qmlRegisterType<T> function. * + * This is a helper for the legacy free qmlRegisterType*() type functions. + * Decorators should be used instead. + * * \param pyObj Python type to be registered. * \param uri QML element uri. * \param versionMajor QML component major version. @@ -34,6 +37,9 @@ PYSIDEQML_API int qmlRegisterType(PyObject *pyObj, const char *uri, /** * PySide implementation of qmlRegisterSingletonType<T> function. * + * This is a helper for the legacy free qmlRegisterSingletonType<T> type function. + * Decorators should be used instead. + * * \param pyObj Python type to be registered. * \param uri QML element uri. * \param versionMajor QML component major version. @@ -80,7 +86,7 @@ PYSIDEQML_API PyObject *qmlSingletonMacro(PyObject *pyObj); // Used by QtQuick module to fill the QQmlPrivate::RegisterType::parserStatusCast, // valueSourceCast and valueInterceptorCast fields with the correct values. using QuickRegisterItemFunction = - bool (*)(PyObject *pyObj, QQmlPrivate::RegisterType *); + bool (*)(PyObject *pyObj, QQmlPrivate::RegisterTypeAndRevisions *); PYSIDEQML_API QuickRegisterItemFunction getQuickRegisterItemFunction(); PYSIDEQML_API void setQuickRegisterItemFunction(QuickRegisterItemFunction function); diff --git a/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp b/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp index 0dc5d64c8..f369f7400 100644 --- a/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp +++ b/sources/pyside6/libpysideqml/pysideqmltypeinfo.cpp @@ -42,8 +42,6 @@ QDebug operator<<(QDebug d, const QmlTypeInfo &i) d.noquote(); d.nospace(); d << "QmlTypeInfo(" << i.flags; - if (!i.noCreationReason.isEmpty()) - d << ", noCreationReason=\"" << i.noCreationReason << '"'; if (i.foreignType) d << ", foreignType=" << i.foreignType->tp_name; if (i.attachedType) diff --git a/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h b/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h index cf06bb304..112e127a7 100644 --- a/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h +++ b/sources/pyside6/libpysideqml/pysideqmltypeinfo_p.h @@ -19,8 +19,7 @@ namespace PySide::Qml { enum class QmlTypeFlag { - Singleton = 0x1, - Uncreatable = 0x2 + Singleton = 0x1 }; Q_DECLARE_FLAGS(QmlTypeFlags, QmlTypeFlag) @@ -30,7 +29,6 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QmlTypeFlags) struct QmlTypeInfo { QmlTypeFlags flags; - QByteArray noCreationReason; PyTypeObject *foreignType = nullptr; PyTypeObject *attachedType = nullptr; PyTypeObject *extensionType = nullptr; diff --git a/sources/pyside6/libpysideqml/pysideqmluncreatable.cpp b/sources/pyside6/libpysideqml/pysideqmluncreatable.cpp index 43c795cb0..dad13cf5f 100644 --- a/sources/pyside6/libpysideqml/pysideqmluncreatable.cpp +++ b/sources/pyside6/libpysideqml/pysideqmluncreatable.cpp @@ -2,8 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "pysideqmluncreatable.h" -#include "pysideqmltypeinfo_p.h" #include <pysideclassdecorator_p.h> +#include <pysideclassinfo.h> #include <shiboken.h> #include <signature.h> @@ -14,6 +14,8 @@ #include <QtCore/QtGlobal> +using namespace Qt::StringLiterals; + class PySideQmlUncreatablePrivate : public PySide::ClassDecorator::StringDecoratorPrivate { public: @@ -35,11 +37,9 @@ PyObject *PySideQmlUncreatablePrivate::tp_call(PyObject *self, PyObject *args, P if (klass== nullptr) return nullptr; + auto *type = reinterpret_cast<PyTypeObject *>(klass); auto *data = DecoratorPrivate::get<PySideQmlUncreatablePrivate>(self); - - const auto info = PySide::Qml::ensureQmlTypeInfo(klass); - info->flags.setFlag(PySide::Qml::QmlTypeFlag::Uncreatable); - info->noCreationReason = data->string(); + setUncreatableClassInfo(type, data->string()); Py_INCREF(klass); return klass; @@ -105,3 +105,10 @@ void initQmlUncreatable(PyObject *module) PyModule_AddObject(module, "QmlUncreatable", reinterpret_cast<PyObject *>(PySideQmlUncreatable_TypeF())); } + +void setUncreatableClassInfo(PyTypeObject *type, const QByteArray &reason) +{ + PySide::ClassInfo::setClassInfo(type, { + {"QML.Creatable"_ba, "false"_ba}, + {"QML.UncreatableReason"_ba, reason} }); +} diff --git a/sources/pyside6/libpysideqml/pysideqmluncreatable.h b/sources/pyside6/libpysideqml/pysideqmluncreatable.h index 7961634ca..772ad4ccb 100644 --- a/sources/pyside6/libpysideqml/pysideqmluncreatable.h +++ b/sources/pyside6/libpysideqml/pysideqmluncreatable.h @@ -6,6 +6,8 @@ #include <sbkpython.h> +#include <QtCore/QByteArray> + // The QmlUncreatable decorator modifies QmlElement to register an uncreatable // type. Due to the (reverse) execution order of decorators, it needs to follow // QmlElement. @@ -16,4 +18,6 @@ extern "C" void initQmlUncreatable(PyObject *module); +void setUncreatableClassInfo(PyTypeObject *type, const QByteArray &reason); + #endif // PYSIDEQMLUNCREATABLE_H |