aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp81
-rw-r--r--sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h7
-rw-r--r--sources/pyside2/PySide2/QtQml/typesystem_qml.xml4
-rw-r--r--sources/pyside2/PySide2/glue/qtqml.cpp4
-rw-r--r--sources/pyside2/doc/extras/QtQml.QmlElement.rst28
-rw-r--r--sources/pyside2/tests/QtQml/registertype.py10
6 files changed, 130 insertions, 4 deletions
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
index fd470cd71..3a3c0d27e 100644
--- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
+++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
@@ -39,6 +39,8 @@
#include "pysideqmlregistertype.h"
+#include <limits>
+
// shiboken
#include <shiboken.h>
#include <signature.h>
@@ -649,3 +651,82 @@ void PySide::initQmlSupport(PyObject *module)
PyModule_AddObject(module, PepType_GetNameStr(QtQml_VolatileBoolTypeF()),
reinterpret_cast<PyObject *>(QtQml_VolatileBoolTypeF()));
}
+
+static std::string getGlobalString(const char *name)
+{
+ using Shiboken::AutoDecRef;
+
+ PyObject *globals = PyEval_GetGlobals();
+
+ AutoDecRef pyName(Py_BuildValue("s", name));
+
+ PyObject *globalVar = PyDict_GetItem(globals, pyName);
+
+ if (globalVar == nullptr || !PyUnicode_Check(globalVar))
+ return "";
+
+ const char *stringValue = PyUnicode_AsUTF8(globalVar);
+ return stringValue != nullptr ? stringValue : "";
+}
+
+static int getGlobalInt(const char *name)
+{
+ using Shiboken::AutoDecRef;
+
+ PyObject *globals = PyEval_GetGlobals();
+
+ AutoDecRef pyName(Py_BuildValue("s", name));
+
+ PyObject *globalVar = PyDict_GetItem(globals, pyName);
+
+ if (globalVar == nullptr || !PyLong_Check(globalVar))
+ return -1;
+
+ long value = PyLong_AsLong(globalVar);
+
+ if (value > std::numeric_limits<int>::max() || value < std::numeric_limits<int>::min())
+ return -1;
+
+ return value;
+}
+
+PyObject *PySide::qmlElementMacro(PyObject *pyObj)
+{
+ if (!PyType_Check(pyObj)) {
+ PyErr_Format(PyExc_TypeError, "This decorator can only be used on classes.");
+ return nullptr;
+ }
+
+ static PyTypeObject *qobjectType = Shiboken::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, "This decorator can only be used with classes inherited from QObject, got %s.", pyObjType->tp_name);
+ return nullptr;
+ }
+
+ std::string importName = getGlobalString("QML_IMPORT_NAME");
+ int majorVersion = getGlobalInt("QML_IMPORT_MAJOR_VERSION");
+ int minorVersion = getGlobalInt("QML_IMPORT_MINOR_VERSION");
+
+ if (importName.empty()) {
+ PyErr_Format(PyExc_TypeError, "You need specify QML_IMPORT_NAME in order to use QmlElement.");
+ return nullptr;
+ }
+
+ if (majorVersion == -1) {
+ PyErr_Format(PyExc_TypeError, "You need specify QML_IMPORT_MAJOR_VERSION in order to use QmlElement.");
+ return nullptr;
+ }
+
+ // Specifying a minor version is optional
+ if (minorVersion == -1)
+ minorVersion = 0;
+
+ if (qmlRegisterType(pyObj, importName.c_str(), majorVersion, minorVersion, pyObjType->tp_name) == -1) {
+ PyErr_Format(PyExc_TypeError, "Failed to register type %s.", pyObjType->tp_name);
+ }
+
+ return pyObj;
+}
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h
index b147d9888..30c174e46 100644
--- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h
+++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.h
@@ -84,6 +84,13 @@ 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 the QML_ELEMENT macro
+ *
+ * \param pyObj Python type to be registered
+ */
+PyObject *qmlElementMacro(PyObject *pyObj);
}
PyAPI_FUNC(PyTypeObject *) QtQml_VolatileBoolTypeF(void);
diff --git a/sources/pyside2/PySide2/QtQml/typesystem_qml.xml b/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
index b2def633f..0d7adf9e8 100644
--- a/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
+++ b/sources/pyside2/PySide2/QtQml/typesystem_qml.xml
@@ -100,6 +100,10 @@
<inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlregisteruncreatabletype"/>
</add-function>
+ <add-function signature="QmlElement(PyObject*)" return-type="PyObject*">
+ <inject-code class="target" file="../glue/qtqml.cpp" snippet="qmlelement"/>
+ </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 5ff072e09..eab6eab95 100644
--- a/sources/pyside2/PySide2/glue/qtqml.cpp
+++ b/sources/pyside2/PySide2/glue/qtqml.cpp
@@ -70,3 +70,7 @@ PySide::initQmlSupport(module);
%RETURN_TYPE retval = %CPPSELF.%FUNCTION_NAME(%1);
return %CONVERTTOPYTHON[%RETURN_TYPE](retval);
// @snippet qjsengine-toscriptvalue
+
+// @snippet qmlelement
+%PYARG_0 = PySide::qmlElementMacro(%ARGUMENT_NAMES);
+// @snippet qmlelement
diff --git a/sources/pyside2/doc/extras/QtQml.QmlElement.rst b/sources/pyside2/doc/extras/QtQml.QmlElement.rst
new file mode 100644
index 000000000..90a5134c1
--- /dev/null
+++ b/sources/pyside2/doc/extras/QtQml.QmlElement.rst
@@ -0,0 +1,28 @@
+.. currentmodule:: PySide2.QtQml
+.. _QmlElement:
+
+QmlElement
+**********
+
+.. py:decorator:: QmlElement
+
+ This decorator registers a class it is attached to for use in QML, using
+ global variables to specify the import name and version.
+
+ ::
+ QML_IMPORT_NAME = "com.library.name"
+ QML_IMPORT_MAJOR_VERSION = 1
+ QML_IMPORT_MINOR_VERSION = 0 # Optional
+
+ @QmlElement
+ class ClassForQml(QObject):
+ # ...
+
+ Afterwards the class may be used in QML:
+
+ ::
+ import com.library.name 1.0
+
+ ClassForQml {
+ // ...
+ }
diff --git a/sources/pyside2/tests/QtQml/registertype.py b/sources/pyside2/tests/QtQml/registertype.py
index e4dcd36f9..2c0577fe3 100644
--- a/sources/pyside2/tests/QtQml/registertype.py
+++ b/sources/pyside2/tests/QtQml/registertype.py
@@ -38,9 +38,13 @@ from helper.helper import adjust_filename
from PySide2.QtCore import Property, QObject, QTimer, QUrl
from PySide2.QtGui import QGuiApplication, QPen, QColor, QPainter
-from PySide2.QtQml import qmlRegisterType, ListProperty
+from PySide2.QtQml import qmlRegisterType, ListProperty, QmlElement
from PySide2.QtQuick import QQuickView, QQuickItem, QQuickPaintedItem
+QML_IMPORT_NAME = "Charts"
+QML_IMPORT_MAJOR_VERSION = 1
+
+@QmlElement
class PieSlice (QQuickPaintedItem):
def __init__(self, parent = None):
QQuickPaintedItem.__init__(self, parent)
@@ -78,6 +82,7 @@ class PieSlice (QQuickPaintedItem):
painter.drawPie(self.boundingRect(), self._fromAngle * 16, self._angleSpan * 16);
paintCalled = True
+@QmlElement
class PieChart (QQuickItem):
def __init__(self, parent = None):
QQuickItem.__init__(self, parent)
@@ -108,9 +113,6 @@ class TestQmlSupport(unittest.TestCase):
def testIt(self):
app = QGuiApplication([])
- self.assertTrue(qmlRegisterType(PieChart, 'Charts', 1, 0, 'PieChart') != -1)
- self.assertTrue(qmlRegisterType(PieSlice, "Charts", 1, 0, "PieSlice") != -1)
-
view = QQuickView()
view.setSource(QUrl.fromLocalFile(adjust_filename('registertype.qml', __file__)))
view.show()