aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp122
-rw-r--r--sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h15
-rw-r--r--sources/pyside2/PySide2/QtQml/typesystem_qml.xml21
-rw-r--r--sources/pyside2/PySide2/glue/qtqml.cpp15
-rw-r--r--sources/pyside2/tests/QtQml/registersingletontype.py86
-rw-r--r--sources/pyside2/tests/QtQml/registersingletontype.qml36
6 files changed, 295 insertions, 0 deletions
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
index 046d62800..2381b3e73 100644
--- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
+++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
@@ -52,6 +52,8 @@
#include "pyside2_qtcore_python.h"
#include "pyside2_qtqml_python.h"
+#include <QtQml/QJSValue>
+
// Forward declarations.
static void propListMetaCall(PySideProperty *pp, PyObject *self, QMetaObject::Call call,
void **args);
@@ -144,6 +146,126 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
return qmlTypeId;
}
+int PySide::qmlRegisterSingletonType(PyObject *pyObj, const char *uri, int versionMajor,
+ int versionMinor, const char *qmlName, PyObject *callback,
+ bool isQObject, bool hasCallback)
+{
+ using namespace Shiboken;
+
+ if (hasCallback) {
+ if (!PyCallable_Check(callback)) {
+ PyErr_Format(PyExc_TypeError, "Invalid callback specified.");
+ return -1;
+ }
+
+ AutoDecRef funcCode(PyObject_GetAttrString(callback, "__code__"));
+ AutoDecRef argCount(PyObject_GetAttrString(funcCode, "co_argcount"));
+
+ int count = PyInt_AsLong(argCount);
+
+ if (count != 1) {
+ PyErr_Format(PyExc_TypeError, "Callback has a bad parameter count.");
+ return -1;
+ }
+
+ // Make sure the callback never gets deallocated
+ Py_INCREF(callback);
+ }
+
+ 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);
+ return -1;
+ }
+
+ // If we don't have a callback we'll need the pyObj to stay allocated indefinitely
+ if (!hasCallback)
+ Py_INCREF(pyObj);
+
+ 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;
+
+ if (isQObject) {
+ // FIXME: Fix this to assign new type ids each time.
+ type.typeId = QMetaType(QMetaType::QObjectStar);
+
+ type.qObjectApi =
+ [callback, pyObj, hasCallback](QQmlEngine *engine, QJSEngine *) -> QObject * {
+ AutoDecRef args(PyTuple_New(hasCallback ? 1 : 0));
+
+ if (hasCallback) {
+ PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython(
+ (SbkObjectType *)SbkPySide2_QtQmlTypes[SBK_QQMLENGINE_IDX],
+ engine));
+ }
+
+ AutoDecRef retVal(PyObject_CallObject(hasCallback ? callback : pyObj, args));
+
+ SbkObjectType *qobjectType = (SbkObjectType *)SbkPySide2_QtCoreTypes[SBK_QOBJECT_IDX];
+
+ // 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;
+ };
+ } else {
+ type.scriptApi =
+ [callback](QQmlEngine *engine, QJSEngine *) -> QJSValue {
+ AutoDecRef args(PyTuple_New(1));
+
+ PyTuple_SET_ITEM(args, 0, Conversions::pointerToPython(
+ (SbkObjectType *)SbkPySide2_QtQmlTypes[SBK_QQMLENGINE_IDX],
+ engine));
+
+ AutoDecRef retVal(PyObject_CallObject(callback, args));
+
+ SbkObjectType *qjsvalueType = (SbkObjectType *)SbkPySide2_QtQmlTypes[SBK_QJSVALUE_IDX];
+
+ // Make sure the callback returns something we can convert, else the entire application will crash.
+ if (retVal.isNull() ||
+ Conversions::isPythonToCppPointerConvertible(qjsvalueType, retVal) == nullptr) {
+ PyErr_Format(PyExc_TypeError, "Callback returns invalid value.");
+ return QJSValue(QJSValue::UndefinedValue);
+ }
+
+ QJSValue *val = nullptr;
+ Conversions::pythonToCppPointer(qjsvalueType, retVal, &val);
+
+ Py_INCREF(retVal);
+
+ return *val;
+ };
+ }
+
+ return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &type);
+}
+
extern "C"
{
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h
index 74690d937..52ef92608 100644
--- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h
+++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h
@@ -71,6 +71,21 @@ void initQmlSupport(PyObject *module);
*/
int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, int versionMinor,
const char *qmlName);
+
+/**
+ * PySide implementation of qmlRegisterType<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 callback Registration callback
+ * \return the metatype id of the registered type.
+ */
+int qmlRegisterSingletonType(PyObject *pyObj,const char *uri, int versionMajor, int versionMinor, const char *qmlName,
+ PyObject *callback, bool isQObject, bool hasCallback);
+
}
// Volatile Bool Ptr type definition for QQmlIncubationController::incubateWhile(std::atomic<bool> *, int)
diff --git a/sources/pyside2/PySide2/QtQml/typesystem_qml.xml b/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
index af6f75131..1b3dade86 100644
--- a/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
+++ b/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
@@ -90,6 +90,27 @@
<inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistertype"/>
</add-function>
+ <add-function signature="qmlRegisterSingletonType(PyTypeObject,const char*,int,int,const char*,PyObject*)" return-type="int">
+ <inject-documentation format="target" mode="append">
+ This function registers a Python type as a singleton in the QML system using the provided callback (which gets a QQmlEngine as a parameter) to generate the singleton.
+ </inject-documentation>
+ <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletontype_qobject_callback"/>
+ </add-function>
+
+ <add-function signature="qmlRegisterSingletonType(PyTypeObject,const char*,int,int,const char*)" return-type="int">
+ <inject-documentation format="target" mode="append">
+ This function registers a Python type as a singleton in the QML system.
+ </inject-documentation>
+ <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletontype_qobject_nocallback"/>
+ </add-function>
+
+ <add-function signature="qmlRegisterSingletonType(const char*,int,int,const char*,PyObject*)" return-type="int">
+ <inject-documentation format="target" mode="append">
+ This function registers a QJSValue as a singleton in the QML system using the provided callback (which gets a QQmlEngine as a parameter) to generate the singleton.
+ </inject-documentation>
+ <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregistersingletontype_qjsvalue"/>
+ </add-function>
+
<enum-type identified-by-value="QML_HAS_ATTACHED_PROPERTIES">
<extra-includes>
<include file-name="QtQml" location="global"/>
diff --git a/sources/pyside2/PySide2/glue/qtqml.cpp b/sources/pyside2/PySide2/glue/qtqml.cpp
index 1913204c3..b1d043cf8 100644
--- a/sources/pyside2/PySide2/glue/qtqml.cpp
+++ b/sources/pyside2/PySide2/glue/qtqml.cpp
@@ -42,6 +42,21 @@ int %0 = PySide::qmlRegisterType(%ARGUMENT_NAMES);
%PYARG_0 = %CONVERTTOPYTHON[int](%0);
// @snippet qmlregistertype
+// @snippet qmlregistersingletontype_qobject_callback
+int %0 = PySide::qmlRegisterSingletonType(%ARGUMENT_NAMES, true, true);
+%PYARG_0 = %CONVERTTOPYTHON[int](%0);
+// @snippet qmlregistersingletontype_qobject_callback
+
+// @snippet qmlregistersingletontype_qobject_nocallback
+int %0 = PySide::qmlRegisterSingletonType(%ARGUMENT_NAMES, nullptr, true, false);
+%PYARG_0 = %CONVERTTOPYTHON[int](%0);
+// @snippet qmlregistersingletontype_qobject_nocallback
+
+// @snippet qmlregistersingletontype_qjsvalue
+int %0 = PySide::qmlRegisterSingletonType(nullptr, %ARGUMENT_NAMES, false, true);
+%PYARG_0 = %CONVERTTOPYTHON[int](%0);
+// @snippet qmlregistersingletontype_qjsvalue
+
// @snippet init
PySide::initQmlSupport(module);
// @snippet init
diff --git a/sources/pyside2/tests/QtQml/registersingletontype.py b/sources/pyside2/tests/QtQml/registersingletontype.py
new file mode 100644
index 000000000..fe3f749f5
--- /dev/null
+++ b/sources/pyside2/tests/QtQml/registersingletontype.py
@@ -0,0 +1,86 @@
+#############################################################################
+##
+## Copyright (C) 2020 The Qt Company Ltd.
+## Contact: https://www.qt.io/licensing/
+##
+## This file is part of the test suite of Qt for Python.
+##
+## $QT_BEGIN_LICENSE:GPL-EXCEPT$
+## Commercial License Usage
+## Licensees holding valid commercial Qt licenses may use this file in
+## accordance with the commercial license agreement provided with the
+## Software or, alternatively, in accordance with the terms contained in
+## a written agreement between you and The Qt Company. For licensing terms
+## and conditions see https://www.qt.io/terms-conditions. For further
+## information use the contact form at https://www.qt.io/contact-us.
+##
+## GNU General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU
+## General Public License version 3 as published by the Free Software
+## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+## included in the packaging of this file. Please review the following
+## information to ensure the GNU General Public License requirements will
+## be met: https://www.gnu.org/licenses/gpl-3.0.html.
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
+
+import os
+import sys
+import unittest
+
+sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+from init_paths import init_test_paths
+init_test_paths(False)
+
+from helper.helper import adjust_filename
+
+from PySide2.QtCore import Property, Signal, QTimer, QUrl, QObject
+from PySide2.QtGui import QGuiApplication
+from PySide2.QtQml import qmlRegisterSingletonType
+from PySide2.QtQuick import QQuickView
+
+finalResult = 0
+
+class SingletonQObject(QObject):
+ def __init__(self, parent = None):
+ QObject.__init__(self, parent)
+ self._data = 100
+
+ def getData(self):
+ return self._data
+
+ def setData(self, data):
+ global finalResult
+ finalResult = self._data = data
+
+ data = Property(int, getData, setData)
+
+def singletonQObjectCallback(engine):
+ obj = SingletonQObject()
+ obj.setData(50)
+ return obj
+
+def singletonQJSValueCallback(engine):
+ return engine.evaluate("new Object({data: 50})")
+
+class TestQmlSupport(unittest.TestCase):
+ def testIt(self):
+ app = QGuiApplication([])
+
+ qmlRegisterSingletonType(SingletonQObject, 'Singletons', 1, 0, 'SingletonQObjectNoCallback')
+ qmlRegisterSingletonType(SingletonQObject, 'Singletons', 1, 0, 'SingletonQObjectCallback',
+ singletonQObjectCallback)
+
+ qmlRegisterSingletonType('Singletons', 1, 0, 'SingletonQJSValue', singletonQJSValueCallback)
+
+ view = QQuickView()
+ view.setSource(QUrl.fromLocalFile(adjust_filename('registersingletontype.qml', __file__)))
+ view.show()
+ QTimer.singleShot(250, view.close)
+ app.exec_()
+ self.assertEqual(finalResult, 200)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/sources/pyside2/tests/QtQml/registersingletontype.qml b/sources/pyside2/tests/QtQml/registersingletontype.qml
new file mode 100644
index 000000000..c8b34e69a
--- /dev/null
+++ b/sources/pyside2/tests/QtQml/registersingletontype.qml
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of Qt for Python.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import Singletons 1.0
+
+Item {
+ Component.onCompleted: {
+ SingletonQObjectCallback.data += SingletonQObjectNoCallback.data + SingletonQJSValue.data
+ }
+}