From 7c448f5c27a51a60e27a54b79e298b53312ef2a8 Mon Sep 17 00:00:00 2001 From: Maximilian Goldstein Date: Thu, 27 Aug 2020 15:45:56 +0200 Subject: QtQml: Implement QmlElement Equivalent to QML_ELEMENT in C++, this enables users to register classes for use in QML by using the QmlElement decorator. Change-Id: I697e486ef58b18cce4c310e4b556e28735a16d45 Reviewed-by: Cristian Maureira-Fredes --- .../PySide2/QtQml/pysideqmlregistertype.cpp | 81 ++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp') 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 + // shiboken #include #include @@ -649,3 +651,82 @@ void PySide::initQmlSupport(PyObject *module) PyModule_AddObject(module, PepType_GetNameStr(QtQml_VolatileBoolTypeF()), reinterpret_cast(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::max() || value < std::numeric_limits::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(pyObj); + if (!PySequence_Contains(pyObjType->tp_mro, reinterpret_cast(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; +} -- cgit v1.2.3