aboutsummaryrefslogtreecommitdiffstats
path: root/src/qmlmodels
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2019-09-17 14:00:42 +0200
committerFabian Kosmale <fabian.kosmale@qt.io>2019-09-18 11:16:39 +0200
commit39274b8f605cbedb86e55fc29fd4421e38c717a4 (patch)
tree42846fe234546762d47f2861dd7907efecb59cf2 /src/qmlmodels
parent258a175a801fc4e5d1a971f06a8c9b4d3ac67c80 (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.cpp36
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p_p.h3
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