diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2019-09-17 14:00:42 +0200 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2019-09-18 11:16:39 +0200 |
commit | 39274b8f605cbedb86e55fc29fd4421e38c717a4 (patch) | |
tree | 42846fe234546762d47f2861dd7907efecb59cf2 /src/qmlmodels | |
parent | 258a175a801fc4e5d1a971f06a8c9b4d3ac67c80 (diff) |
Required properties: Break binding to model on write
This mirrors the behavior in other parts of QML where writing to a
property in imperative code breaks the binding.
Change-Id: Id19eef17a3c5e77bc4c2772bd749b38c732606a8
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qmlmodels')
-rw-r--r-- | src/qmlmodels/qqmldelegatemodel.cpp | 36 | ||||
-rw-r--r-- | src/qmlmodels/qqmldelegatemodel_p_p.h | 3 |
2 files changed, 36 insertions, 3 deletions
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp index c37dc114a1..e2a750a43a 100644 --- a/src/qmlmodels/qqmldelegatemodel.cpp +++ b/src/qmlmodels/qqmldelegatemodel.cpp @@ -894,6 +894,7 @@ void PropertyUpdater::doUpdate() auto sender = QObject::sender(); auto mo = sender->metaObject(); auto signalIndex = QObject::senderSignalIndex(); + ++updateCount; // start at 0 instead of propertyOffset to handle properties from parent hierarchy for (auto i = 0; i < mo->propertyCount() + mo->propertyOffset(); ++i) { auto property = mo->property(i); @@ -907,6 +908,27 @@ void PropertyUpdater::doUpdate() } } +void PropertyUpdater::breakBinding() +{ + auto it = senderToConnection.find(QObject::senderSignalIndex()); + if (it == senderToConnection.end()) + return; + if (updateCount == 0) { + QObject::disconnect(*it); + QQmlError warning; + warning.setUrl(qmlContext(QObject::sender())->baseUrl()); + auto signalName = QString::fromLatin1(QObject::sender()->metaObject()->method(QObject::senderSignalIndex()).name()); + signalName.chop(sizeof("changed")-1); + QString propName = signalName; + propName[0] = propName[0].toLower(); + warning.setDescription(QString::fromUtf8("Writing to \"%1\" broke the binding to the underlying model").arg(propName)); + qmlWarning(this, warning); + senderToConnection.erase(it); + } else { + --updateCount; + } +} + void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *modelItemToIncubate, QObject *object) { auto incubatorPriv = QQmlIncubatorPrivate::get(this); @@ -947,10 +969,18 @@ void QQDMIncubationTask::initializeRequiredProperties(QQmlDelegateModelItem *mod // only write to property if it was actually requested by the component if (wasInRequired && prop.hasNotifySignal()) { QMetaMethod changeSignal = prop.notifySignal(); - QMetaMethod updateSlot = PropertyUpdater::staticMetaObject.method(PropertyUpdater::staticMetaObject.indexOfSlot("doUpdate()")); - QObject::connect(modelItemToIncubate, changeSignal, updater, updateSlot); + static QMetaMethod updateSlot = PropertyUpdater::staticMetaObject.method(PropertyUpdater::staticMetaObject.indexOfSlot("doUpdate()")); + QMetaObject::Connection conn = QObject::connect(modelItemToIncubate, changeSignal, updater, updateSlot); + auto propIdx = object->metaObject()->indexOfProperty(propName.toUtf8()); + QMetaMethod writeToPropSignal = object->metaObject()->property(propIdx).notifySignal(); + updater->senderToConnection[writeToPropSignal.methodIndex()] = conn; + static QMetaMethod breakBinding = PropertyUpdater::staticMetaObject.method(PropertyUpdater::staticMetaObject.indexOfSlot("breakBinding()")); + componentProp.write(prop.read(modelItemToIncubate)); + // the connection needs to established after the write, + // else the signal gets triggered by it and breakBinding will remove the connection + QObject::connect(object, writeToPropSignal, updater, breakBinding); } - if (wasInRequired) + else if (wasInRequired) // we still have to write, even if there is no change signal componentProp.write(prop.read(modelItemToIncubate)); } } diff --git a/src/qmlmodels/qqmldelegatemodel_p_p.h b/src/qmlmodels/qqmldelegatemodel_p_p.h index f9dbc61a94..06365a212f 100644 --- a/src/qmlmodels/qqmldelegatemodel_p_p.h +++ b/src/qmlmodels/qqmldelegatemodel_p_p.h @@ -454,8 +454,11 @@ class PropertyUpdater : public QObject public: PropertyUpdater(QObject *parent); + QHash<int, QMetaObject::Connection> senderToConnection; + int updateCount = 0; public Q_SLOTS: void doUpdate(); + void breakBinding(); }; QT_END_NAMESPACE |