diff options
-rw-r--r-- | sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp | 58 | ||||
-rw-r--r-- | sources/pyside6/PySide6/QtQml/pysideqmlregistertype.h | 16 | ||||
-rw-r--r-- | sources/pyside6/PySide6/QtQml/typesystem_qml.xml | 4 | ||||
-rw-r--r-- | sources/pyside6/PySide6/glue/qtqml.cpp | 5 | ||||
-rw-r--r-- | sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst | 25 | ||||
-rw-r--r-- | sources/pyside6/libpyside/dynamicqmetaobject.cpp | 4 | ||||
-rw-r--r-- | sources/pyside6/libpyside/pyside.cpp | 11 | ||||
-rw-r--r-- | sources/pyside6/libpyside/pyside.h | 7 | ||||
-rw-r--r-- | sources/pyside6/tests/QtQml/registersingletontype.py | 14 | ||||
-rw-r--r-- | sources/pyside6/tests/QtQml/registersingletontype.qml | 4 |
10 files changed, 135 insertions, 13 deletions
diff --git a/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp b/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp index d2b9b689e..873ec53ce 100644 --- a/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp +++ b/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.cpp @@ -180,15 +180,10 @@ int PySide::qmlRegisterSingletonType(PyObject *pyObj, const char *uri, int versi const QMetaObject *metaObject = nullptr; if (isQObject) { - static PyTypeObject *qobjectType = Conversions::getPythonTypeObject("QObject*"); - assert(qobjectType); - PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj); - if (!PySequence_Contains(pyObjType->tp_mro, reinterpret_cast<PyObject *>(qobjectType))) { - PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.", - qobjectType->tp_name, pyObjType->tp_name); + + if (!isQObjectDerived(pyObjType, true)) return -1; - } // If we don't have a callback we'll need the pyObj to stay allocated indefinitely if (!hasCallback) @@ -273,6 +268,55 @@ int PySide::qmlRegisterSingletonType(PyObject *pyObj, const char *uri, int versi return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &type); } +int PySide::qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri, int versionMajor, + int versionMinor, const char *qmlName, + PyObject *instanceObject) +{ + using namespace Shiboken; + + static PyTypeObject *qobjectType = Conversions::getPythonTypeObject("QObject*"); + assert(qobjectType); + + // Check if the Python Type inherit from QObject + PyTypeObject *pyObjType = reinterpret_cast<PyTypeObject *>(pyObj); + + if (!isQObjectDerived(pyObjType, true)) + return -1; + + // Check if the instance object derives from QObject + PyTypeObject *typeInstanceObject = instanceObject->ob_type; + + if (!isQObjectDerived(typeInstanceObject, true)) + return -1; + + // Convert the instanceObject (PyObject) into a QObject + QObject *instanceQObject = reinterpret_cast<QObject*>( + Object::cppPointer(reinterpret_cast<SbkObject*>(instanceObject), qobjectType)); + + // Create Singleton Functor to pass the QObject to the Type registration step + // similarly to the case when we have a callback + QQmlPrivate::SingletonFunctor registrationFunctor; + registrationFunctor.m_object = instanceQObject; + + const QMetaObject *metaObject = PySide::retrieveMetaObject(pyObjType); + Q_ASSERT(metaObject); + + QQmlPrivate::RegisterSingletonType type; + type.structVersion = 0; + + type.uri = uri; + type.version = QTypeRevision::fromVersion(versionMajor, versionMinor); + type.typeName = qmlName; + type.instanceMetaObject = metaObject; + + // FIXME: Fix this to assign new type ids each time. + type.typeId = QMetaType(QMetaType::QObjectStar); + type.qObjectApi = registrationFunctor; + + + return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &type); +} + extern "C" { diff --git a/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.h b/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.h index 9cc7379e9..2a90a07e0 100644 --- a/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.h +++ b/sources/pyside6/PySide6/QtQml/pysideqmlregistertype.h @@ -71,7 +71,7 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int vers const char *qmlName, const char *noCreationReason = nullptr, bool creatable = true); /** - * PySide implementation of qmlRegisterType<T> function. + * PySide implementation of qmlRegisterSingletonType<T> function. * * \param pyObj Python type to be registered. * \param uri QML element uri. @@ -84,6 +84,20 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int vers int qmlRegisterSingletonType(PyObject *pyObj,const char *uri, int versionMajor, int versionMinor, const char *qmlName, PyObject *callback, bool isQObject, bool hasCallback); +/** + * PySide implementation of qmlRegisterSingletonInstance<T> function. + * + * \param pyObj Python type to be registered. + * \param uri QML element uri. + * \param versionMajor QML component major version. + * \param versionMinor QML component minor version. + * \param qmlName QML element name + * \param instanceObject singleton object to be registered. + * \return the metatype id of the registered type. + */ +int qmlRegisterSingletonInstance(PyObject *pyObj, const char *uri, int versionMajor, + int versionMinor, const char *qmlName, PyObject *instanceObject); + /** * PySide implementation of the QML_ELEMENT macro diff --git a/sources/pyside6/PySide6/QtQml/typesystem_qml.xml b/sources/pyside6/PySide6/QtQml/typesystem_qml.xml index 1b855a073..ad883f09d 100644 --- a/sources/pyside6/PySide6/QtQml/typesystem_qml.xml +++ b/sources/pyside6/PySide6/QtQml/typesystem_qml.xml @@ -92,6 +92,10 @@ <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletontype_qjsvalue"/> </add-function> + <add-function signature="qmlRegisterSingletonInstance(PyTypeObject,const char*,int,int,const char*,PyObject*)" return-type="int"> + <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletoninstance"/> + </add-function> + <add-function signature="qmlRegisterUncreatableType(PyTypeObject,const char*,int,int,const char*,const char*)" return-type="int"> <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregisteruncreatabletype"/> </add-function> diff --git a/sources/pyside6/PySide6/glue/qtqml.cpp b/sources/pyside6/PySide6/glue/qtqml.cpp index eab6eab95..99a1c441a 100644 --- a/sources/pyside6/PySide6/glue/qtqml.cpp +++ b/sources/pyside6/PySide6/glue/qtqml.cpp @@ -57,6 +57,11 @@ int %0 = PySide::qmlRegisterSingletonType(nullptr, %ARGUMENT_NAMES, false, true) %PYARG_0 = %CONVERTTOPYTHON[int](%0); // @snippet qmlregistersingletontype_qjsvalue +// @snippet qmlregistersingletoninstance +int %0 = PySide::qmlRegisterSingletonInstance(%ARGUMENT_NAMES); +%PYARG_0 = %CONVERTTOPYTHON[int](%0); +// @snippet qmlregistersingletoninstance + // @snippet qmlregisteruncreatabletype int %0 = PySide::qmlRegisterType(%ARGUMENT_NAMES, false); %PYARG_0 = %CONVERTTOPYTHON[int](%0); diff --git a/sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst b/sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst new file mode 100644 index 000000000..19d59893e --- /dev/null +++ b/sources/pyside6/doc/extras/QtQml.qmlRegisterSingletonInstance.rst @@ -0,0 +1,25 @@ +.. currentmodule:: PySide6.QtQml +.. _qmlRegisterSingletonInstance: + +qmlRegisterSingletonInstance +**************************** + +.. py:function:: qmlRegisterSingletonInstance(pytype: type,\ + uri: str,\ + versionMajor: int,\ + versionMinor: int,\ + typeName: str,\ + instanceObject: object) -> int + + :param type pytype: Python class + :param str uri: uri to use while importing the component in QML + :param int versionMajor: major version + :param int versionMinor: minor version + :param str typeName: name exposed to QML + :param object instanceObject: singleton object to be registered + :return: int (the QML type id) + + This function registers a singleton Python object *instanceObject*, with a particular *uri* and + *typeName*. Its version is a combination of *versionMajor* and *versionMinor*. + + Use this function to register an object of the given type *pytype* as a singleton type. diff --git a/sources/pyside6/libpyside/dynamicqmetaobject.cpp b/sources/pyside6/libpyside/dynamicqmetaobject.cpp index b7febf492..5269067e7 100644 --- a/sources/pyside6/libpyside/dynamicqmetaobject.cpp +++ b/sources/pyside6/libpyside/dynamicqmetaobject.cpp @@ -47,6 +47,7 @@ #include "pysideqenum.h" #include <shiboken.h> +#include <pyside.h> #include <QtCore/QByteArray> #include <QtCore/QObject> @@ -466,7 +467,6 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type) // existing connections. const PyObject *mro = type->tp_mro; const Py_ssize_t basesCount = PyTuple_GET_SIZE(mro); - PyTypeObject *qObjectType = Conversions::getPythonTypeObject("QObject*"); std::vector<PyTypeObject *> basesToCheck; // Prepend the actual type that we are parsing. @@ -478,7 +478,7 @@ void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type) for (Py_ssize_t i = 0; i < basesCount; ++i) { auto baseType = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i)); if (baseType != sbkObjTypeF && baseType != baseObjType - && PyType_IsSubtype(baseType, qObjectType) == 0) { + && !PySide::isQObjectDerived(baseType, false)) { basesToCheck.push_back(baseType); } } diff --git a/sources/pyside6/libpyside/pyside.cpp b/sources/pyside6/libpyside/pyside.cpp index 14b86f322..990b45694 100644 --- a/sources/pyside6/libpyside/pyside.cpp +++ b/sources/pyside6/libpyside/pyside.cpp @@ -656,6 +656,17 @@ bool registerInternalQtConf() return isRegistered; } +bool isQObjectDerived(PyTypeObject *pyType, bool raiseError) { + static PyTypeObject *qobjectType = Shiboken::Conversions::getPythonTypeObject("QObject*"); + + if (!PyType_IsSubtype(pyType, qobjectType)) { + if (raiseError) + PyErr_Format(PyExc_TypeError, "A type inherited from %s expected, got %s.", + qobjectType->tp_name, pyType->tp_name); + return false; + } + return true; +} } //namespace PySide diff --git a/sources/pyside6/libpyside/pyside.h b/sources/pyside6/libpyside/pyside.h index 1cb77b4c5..0c9ad92cf 100644 --- a/sources/pyside6/libpyside/pyside.h +++ b/sources/pyside6/libpyside/pyside.h @@ -105,6 +105,13 @@ PYSIDE_API void initQApp(); /// Return the size in bytes of a type that inherits QObject. PYSIDE_API std::size_t getSizeOfQObject(SbkObjectType *type); +/* Check if a PyTypeObject or its bases contains a QObject + * \param pyType is the PyTypeObject to check + * \param raiseError controls if a TypeError is raised when an object does not + * inherits from QObject + */ +PYSIDE_API bool isQObjectDerived(PyTypeObject *pyType, bool raiseError); + typedef void (*CleanupFunction)(void); /** diff --git a/sources/pyside6/tests/QtQml/registersingletontype.py b/sources/pyside6/tests/QtQml/registersingletontype.py index 30844ff8c..c22f3706e 100644 --- a/sources/pyside6/tests/QtQml/registersingletontype.py +++ b/sources/pyside6/tests/QtQml/registersingletontype.py @@ -39,7 +39,7 @@ from helper.helper import quickview_errorstring from PySide6.QtCore import Property, Signal, QTimer, QUrl, QObject from PySide6.QtGui import QGuiApplication -from PySide6.QtQml import qmlRegisterSingletonType +from PySide6.QtQml import qmlRegisterSingletonType, qmlRegisterSingletonInstance from PySide6.QtQuick import QQuickView finalResult = 0 @@ -80,6 +80,16 @@ class TestQmlSupport(unittest.TestCase): qmlRegisterSingletonType('Singletons', 1, 0, 'SingletonQJSValue', singletonQJSValueCallback) + # Accepts only QObject derived types + l = [1, 2] + with self.assertRaises(TypeError): + qmlRegisterSingletonInstance(SingletonQObject, 'Singletons', 1, 0, 'SingletonInstance', l) + + # Modify value on the instance + s = SingletonQObject() + s.setData(99) + qmlRegisterSingletonInstance(SingletonQObject, 'Singletons', 1, 0, 'SingletonInstance', s) + view = QQuickView() file = Path(__file__).resolve().parent / 'registersingletontype.qml' self.assertTrue(file.is_file()) @@ -88,7 +98,7 @@ class TestQmlSupport(unittest.TestCase): view.show() QTimer.singleShot(250, view.close) app.exec() - self.assertEqual(finalResult, 200) + self.assertEqual(finalResult, 299) if __name__ == '__main__': diff --git a/sources/pyside6/tests/QtQml/registersingletontype.qml b/sources/pyside6/tests/QtQml/registersingletontype.qml index c8b34e69a..2365cf201 100644 --- a/sources/pyside6/tests/QtQml/registersingletontype.qml +++ b/sources/pyside6/tests/QtQml/registersingletontype.qml @@ -31,6 +31,8 @@ import Singletons 1.0 Item { Component.onCompleted: { - SingletonQObjectCallback.data += SingletonQObjectNoCallback.data + SingletonQJSValue.data + SingletonQObjectCallback.data += SingletonQObjectNoCallback.data + + SingletonQJSValue.data + + SingletonInstance.data; } } |