aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/qml/qqmlproperty.cpp20
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp120
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h25
-rw-r--r--tests/auto/qml/qqmlproperty/data/listAssignmentSignals.qml13
-rw-r--r--tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp16
5 files changed, 128 insertions, 66 deletions
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index c1f327cd5a..0e0d798537 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -1549,18 +1549,26 @@ bool QQmlPropertyPrivate::write(
if (valueMetaObject.isNull())
return false;
- QQmlListProperty<void> prop;
+ QQmlListProperty<QObject> prop;
property.readProperty(object, &prop);
- if (!prop.clear)
+ if (!prop.clear || !prop.append)
return false;
- prop.clear(&prop);
+ const bool useNonsignalingListOps = prop.clear == &QQmlVMEMetaObject::list_clear
+ && prop.append == &QQmlVMEMetaObject::list_append;
+
+ auto propClear =
+ useNonsignalingListOps ? &QQmlVMEMetaObject::list_clear_nosignal : prop.clear;
+ auto propAppend =
+ useNonsignalingListOps ? &QQmlVMEMetaObject::list_append_nosignal : prop.append;
+
+ propClear(&prop);
const auto doAppend = [&](QObject *o) {
if (o && !QQmlMetaObject::canConvert(o, valueMetaObject))
o = nullptr;
- prop.append(&prop, o);
+ propAppend(&prop, o);
};
if (variantMetaType == QMetaType::fromType<QQmlListReference>()) {
@@ -1574,6 +1582,10 @@ bool QQmlPropertyPrivate::write(
} else if (!iterateQObjectContainer(variantMetaType, value.data(), doAppend)) {
doAppend(QQmlMetaType::toQObject(value));
}
+ if (useNonsignalingListOps) {
+ Q_ASSERT(QQmlVMEMetaObject::get(object));
+ QQmlVMEResolvedList(&prop).activateSignal();
+ }
} else if (variantMetaType == propertyMetaType) {
QVariant v = value;
property.writeProperty(object, v.data(), flags);
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 41dfbf74f8..b8383b8679 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -25,100 +25,96 @@
QT_BEGIN_NAMESPACE
-class ResolvedList
+QQmlVMEResolvedList::QQmlVMEResolvedList(QQmlListProperty<QObject> *prop)
{
- Q_DISABLE_COPY_MOVE(ResolvedList)
-
-public:
- ResolvedList(QQmlListProperty<QObject> *prop)
- {
- // see QQmlVMEMetaObject::metaCall for how this was constructed
- auto encodedIndex = quintptr(prop->data);
- constexpr quintptr usableBits = sizeof(quintptr) * CHAR_BIT;
- quintptr inheritanceDepth = encodedIndex >> (usableBits / 2);
- m_id = encodedIndex & ((quintptr(1) << (usableBits / 2)) - 1);
-
- // walk up to the correct meta object if necessary
- auto mo = static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(prop->object)->metaObject);
- while (inheritanceDepth--)
- mo = mo->parentVMEMetaObject();
- m_metaObject = mo;
- Q_ASSERT(m_metaObject);
- Q_ASSERT(::strstr(m_metaObject->toDynamicMetaObject(prop->object)->property(
- m_metaObject->propOffset() + m_id).typeName(), "QQmlListProperty") );
- Q_ASSERT(m_metaObject->object == prop->object);
-
- // readPropertyAsList() with checks transformed into Q_ASSERT
- // and without allocation.
- if (m_metaObject->propertyAndMethodStorage.isUndefined() &&
- m_metaObject->propertyAndMethodStorage.valueRef()) {
- return;
- }
-
- if (auto *md = static_cast<QV4::MemberData *>(
- m_metaObject->propertyAndMethodStorage.asManaged())) {
- const auto *v = (md->data() + m_id)->as<QV4::VariantObject>();
- Q_ASSERT(v);
- Q_ASSERT(v->d());
- QVariant &data = v->d()->data();
- Q_ASSERT(data.userType() == qMetaTypeId<QVector<QQmlGuard<QObject>>>());
- m_list = static_cast<QVector<QQmlGuard<QObject>> *>(data.data());
- Q_ASSERT(m_list);
- }
+ // see QQmlVMEMetaObject::metaCall for how this was constructed
+ auto encodedIndex = quintptr(prop->data);
+ constexpr quintptr usableBits = sizeof(quintptr) * CHAR_BIT;
+ quintptr inheritanceDepth = encodedIndex >> (usableBits / 2);
+ m_id = encodedIndex & ((quintptr(1) << (usableBits / 2)) - 1);
+
+ // walk up to the correct meta object if necessary
+ auto mo = static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(prop->object)->metaObject);
+ while (inheritanceDepth--)
+ mo = mo->parentVMEMetaObject();
+ m_metaObject = mo;
+ Q_ASSERT(m_metaObject);
+ Q_ASSERT(::strstr(m_metaObject->toDynamicMetaObject(prop->object)
+ ->property(m_metaObject->propOffset() + m_id)
+ .typeName(),
+ "QQmlListProperty"));
+ Q_ASSERT(m_metaObject->object == prop->object);
+
+ // readPropertyAsList() with checks transformed into Q_ASSERT
+ // and without allocation.
+ if (m_metaObject->propertyAndMethodStorage.isUndefined()
+ && m_metaObject->propertyAndMethodStorage.valueRef()) {
+ return;
}
- ~ResolvedList() = default;
-
- QQmlVMEMetaObject *metaObject() const { return m_metaObject; }
- QVector<QQmlGuard<QObject>> *list() const { return m_list; }
- quintptr id() const { return m_id; }
-
- void activateSignal() const
- {
- m_metaObject->activate(m_metaObject->object, int(m_id + m_metaObject->methodOffset()),
- nullptr);
+ if (auto *md = static_cast<QV4::MemberData *>(
+ m_metaObject->propertyAndMethodStorage.asManaged())) {
+ const auto *v = (md->data() + m_id)->as<QV4::VariantObject>();
+ Q_ASSERT(v);
+ Q_ASSERT(v->d());
+ QVariant &data = v->d()->data();
+ Q_ASSERT(data.userType() == qMetaTypeId<QVector<QQmlGuard<QObject>>>());
+ m_list = static_cast<QVector<QQmlGuard<QObject>> *>(data.data());
+ Q_ASSERT(m_list);
}
+}
-private:
- QQmlVMEMetaObject *m_metaObject = nullptr;
- QVector<QQmlGuard<QObject>> *m_list = nullptr;
- quintptr m_id = 0;
-};
+QQmlVMEResolvedList::~QQmlVMEResolvedList() = default;
-static void list_append(QQmlListProperty<QObject> *prop, QObject *o)
+void QQmlVMEResolvedList::activateSignal() const
{
- const ResolvedList resolved(prop);
+ m_metaObject->activate(m_metaObject->object, int(m_id + m_metaObject->methodOffset()), nullptr);
+}
+
+void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *o)
+{
+ const QQmlVMEResolvedList resolved(prop);
resolved.list()->append(o);
resolved.activateSignal();
}
+void QQmlVMEMetaObject::list_append_nosignal(QQmlListProperty<QObject> *prop, QObject *o)
+{
+ QQmlVMEResolvedList(prop).list()->append(o);
+}
+
static qsizetype list_count(QQmlListProperty<QObject> *prop)
{
- return ResolvedList(prop).list()->size();
+ return QQmlVMEResolvedList(prop).list()->size();
}
static QObject *list_at(QQmlListProperty<QObject> *prop, qsizetype index)
{
- return ResolvedList(prop).list()->at(index);
+ return QQmlVMEResolvedList(prop).list()->at(index);
}
-static void list_clear(QQmlListProperty<QObject> *prop)
+void QQmlVMEMetaObject::list_clear(QQmlListProperty<QObject> *prop)
{
- const ResolvedList resolved(prop);
+ const QQmlVMEResolvedList resolved(prop);
resolved.list()->clear();
resolved.activateSignal();
}
+void QQmlVMEMetaObject::list_clear_nosignal(QQmlListProperty<QObject> *prop)
+{
+ QQmlVMEResolvedList(prop).list()->clear();
+}
+
static void list_replace(QQmlListProperty<QObject> *prop, qsizetype index, QObject *o)
{
- const ResolvedList resolved(prop);
+ const QQmlVMEResolvedList resolved(prop);
resolved.list()->replace(index, o);
resolved.activateSignal();
}
static void list_removeLast(QQmlListProperty<QObject> *prop)
{
- const ResolvedList resolved(prop);
+ const QQmlVMEResolvedList resolved(prop);
resolved.list()->removeLast();
resolved.activateSignal();
}
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 1b9a122b1f..f679a2483b 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -37,6 +37,26 @@
QT_BEGIN_NAMESPACE
class QQmlVMEMetaObject;
+class QQmlVMEResolvedList
+{
+ Q_DISABLE_COPY_MOVE(QQmlVMEResolvedList)
+
+public:
+ QQmlVMEResolvedList(QQmlListProperty<QObject> *prop);
+ ~QQmlVMEResolvedList();
+
+ QQmlVMEMetaObject *metaObject() const { return m_metaObject; }
+ QVector<QQmlGuard<QObject>> *list() const { return m_list; }
+ quintptr id() const { return m_id; }
+
+ void activateSignal() const;
+
+private:
+ QQmlVMEMetaObject *m_metaObject = nullptr;
+ QVector<QQmlGuard<QObject>> *m_list = nullptr;
+ quintptr m_id = 0;
+};
+
class QQmlVMEVariantQObjectPtr : public QQmlGuard<QObject>
{
public:
@@ -149,6 +169,11 @@ public:
static QQmlVMEMetaObject *getForMethod(QObject *o, int coreIndex);
static QQmlVMEMetaObject *getForSignal(QObject *o, int coreIndex);
+ static void list_append(QQmlListProperty<QObject> *prop, QObject *o);
+ static void list_clear(QQmlListProperty<QObject> *prop);
+ static void list_append_nosignal(QQmlListProperty<QObject> *prop, QObject *o);
+ static void list_clear_nosignal(QQmlListProperty<QObject> *prop);
+
protected:
int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
diff --git a/tests/auto/qml/qqmlproperty/data/listAssignmentSignals.qml b/tests/auto/qml/qqmlproperty/data/listAssignmentSignals.qml
new file mode 100644
index 0000000000..8a2c68ab5d
--- /dev/null
+++ b/tests/auto/qml/qqmlproperty/data/listAssignmentSignals.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.0
+
+Item {
+ property int signalCounter: 0
+ property list<QtObject> sourceList: [ QtObject{}, QtObject{}, QtObject{} ]
+ property list<QtObject> targetList1: sourceList
+
+ onTargetList1Changed: signalCounter++
+
+ function assignList() {
+ targetList1 = sourceList
+ }
+}
diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
index 88c34f0e22..a636fe2292 100644
--- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
+++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp
@@ -217,6 +217,9 @@ private slots:
void bindToNonQObjectTarget();
void assignVariantList();
+
+ void listAssignmentSignals();
+
private:
QQmlEngine engine;
};
@@ -2544,6 +2547,19 @@ void tst_qqmlproperty::assignVariantList()
QCOMPARE(holder->doubleList(), doubleList);
}
+void tst_qqmlproperty::listAssignmentSignals()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("listAssignmentSignals.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(!root.isNull());
+
+ QCOMPARE(root->property("signalCounter").toInt(), 1);
+ QMetaObject::invokeMethod(root.get(), "assignList");
+ QCOMPARE(root->property("signalCounter").toInt(), 2);
+}
+
QTEST_MAIN(tst_qqmlproperty)
#include "tst_qqmlproperty.moc"