aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2019-10-01 14:26:44 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2019-10-21 14:38:32 +0200
commit1eed1b860534f481b89b411fc7e21a7daa22d5ee (patch)
treef5f0d2291c1dbbb4c5fd4a897fd08956c438075b
parent488a37c861a1724a935a8d7b925693a38918a71a (diff)
Fix interface handling in bindings
If a type had a property with an interface type, we did not support the case where the assigned binding value is convertible to the interface. This is now fixed by adding a last new check to QQmlPrivate::write Fixes: QTBUG-78721 Change-Id: I0b85fbfdf8561ba43610ac343001ae380287a674 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/qml/qml/qqmlproperty.cpp12
-rw-r--r--tests/auto/qml/qqmlproperty/data/interfaceBinding.qml27
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp79
3 files changed, 117 insertions, 1 deletions
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 5f57e0eca1..b6baa86bd7 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1373,8 +1373,9 @@ bool QQmlPropertyPrivate::write(QObject *object,
}
}
if (!ok) {
- // the only other option is that they are assigning a single value
+ // the only other options are that they are assigning a single value
// to a sequence type property (eg, an int to a QList<int> property).
+ // or that we encountered an interface type
// Note that we've already handled single-value assignment to QList<QUrl> properties.
if (variantType == QVariant::Int && propertyType == qMetaTypeId<QList<int> >()) {
QList<int> list;
@@ -1405,6 +1406,15 @@ bool QQmlPropertyPrivate::write(QObject *object,
}
}
+ if (!ok && QQmlMetaType::isInterface(propertyType)) {
+ auto valueAsQObject = qvariant_cast<QObject *>(value);
+ if (valueAsQObject && valueAsQObject->qt_metacast(QQmlMetaType::interfaceIId(propertyType))) {
+ // this case can occur when object has an interface type
+ // and the variant contains a type implementing the interface
+ return property.writeProperty(object, const_cast<void *>(value.constData()), flags);
+ }
+ }
+
if (ok) {
return property.writeProperty(object, const_cast<void *>(v.constData()), flags);
} else {
diff --git a/tests/auto/qml/qqmlproperty/data/interfaceBinding.qml b/tests/auto/qml/qqmlproperty/data/interfaceBinding.qml
new file mode 100644
index 0000000000..4e72a75f42
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/interfaceBinding.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.12
+import io.qt.bugreports 1.0
+Item {
+ InterfaceConsumer {
+ objectName: "a1"
+ i: A {
+ property int i: 42
+ }
+ }
+
+ InterfaceConsumer {
+ objectName: "a2"
+ property A a: A {
+ property int i: 43
+ }
+ i: a
+ }
+
+ InterfaceConsumer {
+ objectName: "a3"
+ property A a: A {
+ id : aa
+ property int i: 44
+ }
+ i: aa
+ }
+}
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index bc407e97a2..7ebe0bac52 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -40,6 +40,7 @@
#endif
#include <QtCore/private/qobject_p.h>
#include "../../shared/util.h"
+#include "qobject.h"
#include <QDebug>
class MyQmlObject : public QObject
@@ -148,6 +149,7 @@ private slots:
void readOnlyDynamicProperties();
void aliasToIdWithMatchingQmlFileNameOnCaseInsensitiveFileSystem();
void nullPropertyBinding();
+ void interfaceBinding();
void floatToStringPrecision_data();
void floatToStringPrecision();
@@ -2083,6 +2085,83 @@ void tst_qqmlproperty::nullPropertyBinding()
QMetaObject::invokeMethod(root.get(), "tog");
}
+struct Interface {
+};
+
+QT_BEGIN_NAMESPACE
+#define MyInterface_iid "io.qt.bugreports.Interface"
+Q_DECLARE_INTERFACE(Interface, MyInterface_iid);
+QT_END_NAMESPACE
+
+class A : public QObject, Interface {
+ Q_OBJECT
+ Q_INTERFACES(Interface)
+};
+
+class B : public QObject, Interface {
+ Q_OBJECT
+ Q_INTERFACES(Interface)
+};
+
+class C : public QObject {
+ Q_OBJECT
+};
+
+class InterfaceConsumer : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(Interface* i READ interface WRITE setInterface NOTIFY interfaceChanged)
+ Q_PROPERTY(int testValue READ testValue NOTIFY testValueChanged)
+
+
+public:
+
+ Interface* interface() const
+ {
+ return m_interface;
+ }
+ void setInterface(Interface* interface)
+ {
+ QObject* object = reinterpret_cast<QObject*>(interface);
+ m_testValue = object->property("i").toInt();
+ emit testValueChanged();
+ if (m_interface == interface)
+ return;
+
+ m_interface = interface;
+ emit interfaceChanged();
+ }
+
+ int testValue() {
+ return m_testValue;
+ }
+
+signals:
+ void interfaceChanged();
+ void testValueChanged();
+
+private:
+ Interface* m_interface = nullptr;
+ int m_testValue = 0;
+};
+void tst_qqmlproperty::interfaceBinding()
+{
+
+ qmlRegisterInterface<Interface>("Interface");
+ qmlRegisterType<A>("io.qt.bugreports", 1, 0, "A");
+ qmlRegisterType<B>("io.qt.bugreports", 1, 0, "B");
+ qmlRegisterType<C>("io.qt.bugreports", 1, 0, "C");
+ qmlRegisterType<InterfaceConsumer>("io.qt.bugreports", 1, 0, "InterfaceConsumer");
+
+ const QUrl url = testFileUrl("interfaceBinding.qml");
+ QQmlEngine engine;
+ QQmlComponent component(&engine, url);
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+ QCOMPARE(root->findChild<QObject*>("a1")->property("testValue").toInt(), 42);
+ QCOMPARE(root->findChild<QObject*>("a2")->property("testValue").toInt(), 43);
+ QCOMPARE(root->findChild<QObject*>("a3")->property("testValue").toInt(), 44);
+}
+
void tst_qqmlproperty::floatToStringPrecision_data()
{
QTest::addColumn<QString>("propertyName");