aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6')
-rw-r--r--sources/pyside6/libpyside/dynamicqmetaobject.cpp44
-rw-r--r--sources/pyside6/libpysideqml/pysideqmlregistertype.cpp13
-rw-r--r--sources/pyside6/tests/QtQml/CMakeLists.txt1
-rw-r--r--sources/pyside6/tests/QtQml/groupedproperty.py137
-rw-r--r--sources/pyside6/tests/QtQml/groupedproperty.qml34
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 }
+}