diff options
-rw-r--r-- | src/qml/qml/qqmlproperty.cpp | 20 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject.cpp | 120 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject_p.h | 25 | ||||
-rw-r--r-- | tests/auto/qml/qqmlproperty/data/listAssignmentSignals.qml | 13 | ||||
-rw-r--r-- | tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 16 |
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" |