diff options
Diffstat (limited to 'sources/pyside6')
| -rw-r--r-- | sources/pyside6/libpyside/dynamicqmetaobject.cpp | 44 | ||||
| -rw-r--r-- | sources/pyside6/libpysideqml/pysideqmlregistertype.cpp | 13 | ||||
| -rw-r--r-- | sources/pyside6/tests/QtQml/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | sources/pyside6/tests/QtQml/groupedproperty.py | 137 | ||||
| -rw-r--r-- | sources/pyside6/tests/QtQml/groupedproperty.qml | 34 |
5 files changed, 219 insertions, 10 deletions
diff --git a/sources/pyside6/libpyside/dynamicqmetaobject.cpp b/sources/pyside6/libpyside/dynamicqmetaobject.cpp index 6b412de9a..6f1c9b40a 100644 --- a/sources/pyside6/libpyside/dynamicqmetaobject.cpp +++ b/sources/pyside6/libpyside/dynamicqmetaobject.cpp @@ -45,6 +45,7 @@ #include "pysideproperty_p.h" #include "pysideslot_p.h" #include "pysideqenum.h" +#include "pyside_p.h" #include <shiboken.h> @@ -102,6 +103,10 @@ public: const QMetaObject *m_baseObject = nullptr; MetaObjects m_cachedMetaObjects; bool m_dirty = true; + +private: + QMetaPropertyBuilder + createProperty(PySideProperty *property, const QByteArray &propertyName); }; QMetaObjectBuilder *MetaObjectBuilderPrivate::ensureBuilder() @@ -300,6 +305,35 @@ int MetaObjectBuilderPrivate::getPropertyNotifyId(PySideProperty *property) cons return notifyId; } +QMetaPropertyBuilder + MetaObjectBuilderPrivate::createProperty(PySideProperty *property, + const QByteArray &propertyName) +{ + int propertyNotifyId = getPropertyNotifyId(property); + if (propertyNotifyId >= 0) + propertyNotifyId -= m_baseObject->methodCount(); + + // For QObject-derived Python types, retrieve the meta type registered + // by name from the qmlRegisterType, if there is one. This is required for + // grouped QML properties to work. + auto *builder = ensureBuilder(); + auto *typeObject = Property::getTypeObject(property); + if (typeObject != nullptr && PyType_Check(typeObject)) { + auto *pyTypeObject = reinterpret_cast<PyTypeObject *>(typeObject); + if (qstrncmp(pyTypeObject->tp_name, "PySide", 6) != 0 + && PySide::isQObjectDerived(pyTypeObject, false)) { + const QByteArray pyType(pyTypeObject->tp_name); + const auto metaType = QMetaType::fromName(pyType + '*'); + if (metaType.isValid()) { + return builder->addProperty(propertyName, pyType, + metaType, propertyNotifyId); + } + } + } + return builder->addProperty(propertyName, property->d->typeName, + propertyNotifyId); +} + int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName, PyObject *data) { @@ -307,13 +341,9 @@ int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName, if (index != -1) return index; - PySideProperty *property = reinterpret_cast<PySideProperty *>(data); - int propertyNotifyId = getPropertyNotifyId(property); - if (propertyNotifyId >= 0) - propertyNotifyId -= m_baseObject->methodCount(); - auto newProperty = - ensureBuilder()->addProperty(propertyName, property->d->typeName, - propertyNotifyId); + auto *property = reinterpret_cast<PySideProperty *>(data); + auto newProperty = createProperty(property, propertyName); + // Adding property attributes newProperty.setReadable(PySide::Property::isReadable(property)); newProperty.setWritable(PySide::Property::isWritable(property)); diff --git a/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp b/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp index ad839ec96..05a7bbffb 100644 --- a/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp +++ b/sources/pyside6/libpysideqml/pysideqmlregistertype.cpp @@ -60,6 +60,7 @@ #include <QtQml/qqml.h> #include <QtQml/QJSValue> #include <QtQml/QQmlListProperty> +#include <private/qqmlmetatype_p.h> static PySide::Qml::QuickRegisterItemFunction quickRegisterItemFunction = nullptr; @@ -140,15 +141,21 @@ int qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor, // Register as simple QObject rather than Qt Quick item. if (!registered) { + using QObjectQmlList = QQmlListProperty<QObject>; // Incref the type object, don't worry about decref'ing it because // there's no way to unregister a QML type. Py_INCREF(pyObj); type.structVersion = 0; - // FIXME: Fix this to assign new type ids each time. - type.typeId = QMetaType(QMetaType::QObjectStar); - type.listId = QMetaType::fromType<QQmlListProperty<QObject> >(); + const QByteArray typeName(pyObjType->tp_name); + QByteArray ptrType = typeName + '*'; + QByteArray listType = QByteArrayLiteral("QQmlListProperty<") + typeName + '>'; + + type.typeId = QMetaType(new QQmlMetaTypeInterface(ptrType, static_cast<QObject **>(nullptr))); + type.listId = QMetaType(new QQmlListMetaTypeInterface(listType, + static_cast<QObjectQmlList*>(nullptr), + type.typeId.iface())); const auto typeInfo = qmlTypeInfo(pyObj); auto info = qmlAttachedInfo(pyObjType, typeInfo); type.attachedPropertiesFunction = info.factory; diff --git a/sources/pyside6/tests/QtQml/CMakeLists.txt b/sources/pyside6/tests/QtQml/CMakeLists.txt index f97e3eb43..0006accde 100644 --- a/sources/pyside6/tests/QtQml/CMakeLists.txt +++ b/sources/pyside6/tests/QtQml/CMakeLists.txt @@ -11,6 +11,7 @@ PYSIDE_TEST(bug_951.py) PYSIDE_TEST(bug_995.py) PYSIDE_TEST(bug_997.py) PYSIDE_TEST(bug_1029.py) +PYSIDE_TEST(groupedproperty.py) PYSIDE_TEST(listproperty.py) PYSIDE_TEST(qqmlapplicationengine_test.py) PYSIDE_TEST(qqmlnetwork_test.py) diff --git a/sources/pyside6/tests/QtQml/groupedproperty.py b/sources/pyside6/tests/QtQml/groupedproperty.py new file mode 100644 index 000000000..c3798300c --- /dev/null +++ b/sources/pyside6/tests/QtQml/groupedproperty.py @@ -0,0 +1,137 @@ +############################################################################# +## +## Copyright (C) 2022 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$ +## +############################################################################# + +"""Test grouped properties (PYSIDE-1836).""" + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from init_paths import init_test_paths +init_test_paths(False) + +from PySide6.QtCore import (QCoreApplication, QUrl, QObject, Property) +from PySide6.QtQml import (QQmlComponent, QQmlEngine, QmlAnonymous, QmlElement) + + +QML_IMPORT_NAME = "grouped" +QML_IMPORT_MAJOR_VERSION = 1 + + +@QmlAnonymous +class ShoeDescription(QObject): + def __init__(self, parent=None): + super().__init__(parent) + self._brand = "" + self._size = 0 + self._price = 0 + + @Property(str) + def brand(self): + return self._brand + + @brand.setter + def brand(self, b): + self._brand = b + + @Property(int) + def size(self): + return self._size + + @size.setter + def size(self, s): + self._size = s + + @Property(int) + def price(self): + return self._price + + @price.setter + def price(self, p): + self._price = p + + +@QmlElement +class Person(QObject): + def __init__(self, parent=None): + super().__init__(parent) + self._name = "" + self._shoe = ShoeDescription() + + @Property(str) + def name(self): + return self._name + + @name.setter + def name(self, n): + self._name = n + + @Property(ShoeDescription) + def shoe(self): + return self._shoe + + +def component_error(component): + result = "" + for e in component.errors(): + if result: + result += "\n" + result += str(e) + return result + + +class TestQmlGroupedProperties(unittest.TestCase): + def testIt(self): + app = QCoreApplication(sys.argv) + file = Path(__file__).resolve().parent / "groupedproperty.qml" + url = QUrl.fromLocalFile(file) + engine = QQmlEngine() + component = QQmlComponent(engine, url) + person = component.create() + self.assertTrue(person, component_error(component)) + + # Check the meta type of the property + meta_object = person.metaObject() + index = meta_object.indexOfProperty("shoe") + self.assertTrue(index > 0) + meta_property = meta_object.property(index) + meta_type = meta_property.metaType() + self.assertTrue(meta_type.isValid()) + + # Check the values + self.assertEqual(person.shoe.brand, "Bikey") + self.assertEqual(person.shoe.price, 90) + self.assertEqual(person.shoe.size, 12) + + del engine + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/pyside6/tests/QtQml/groupedproperty.qml b/sources/pyside6/tests/QtQml/groupedproperty.qml new file mode 100644 index 000000000..596c21f39 --- /dev/null +++ b/sources/pyside6/tests/QtQml/groupedproperty.qml @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 grouped + +Person { + name: "Bob Jones" + shoe { size: 12; brand: "Bikey"; price: 90 } +} |
