diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2016-09-01 16:46:29 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2016-11-18 11:06:31 +0000 |
commit | 1969991c4a4bd39ee224b0fa3c8cffa51f061757 (patch) | |
tree | 86a5dc6036725d7fc093a7ba937367e42d2d9438 /src/qml/types | |
parent | a3fe91ba463fcd27d6e0a69b66bc389bd6470c46 (diff) |
Fix binding re-evaluation when list model properties change
This is a regression from commit
4876ea6a18ccdfd72014582aa5d50ab9f6b6ec9e, which avoided returning an
expensive QObject when calling get() but also lost the ability to
perform binding captures when accessing the properties. This change
restores the captures by performing them by hand in get() and also
triggering the notifiers directly when the values change, without
creating the QObject.
Task-number: QTBUG-52356
Change-Id: Ia429ffafd4032b63d3e592aa63bb0864a24e0965
Reviewed-by: Michael Brasser <michael.brasser@live.com>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml/types')
-rw-r--r-- | src/qml/types/qqmllistmodel.cpp | 44 | ||||
-rw-r--r-- | src/qml/types/qqmllistmodel_p_p.h | 2 |
2 files changed, 43 insertions, 3 deletions
diff --git a/src/qml/types/qqmllistmodel.cpp b/src/qml/types/qqmllistmodel.cpp index 3d71621290..299097d0c0 100644 --- a/src/qml/types/qqmllistmodel.cpp +++ b/src/qml/types/qqmllistmodel.cpp @@ -40,10 +40,12 @@ #include <private/qqmlcustomparser_p.h> #include <private/qqmlengine_p.h> +#include <private/qqmlnotifier_p.h> #include <private/qv4object_p.h> #include <private/qv4dateobject_p.h> #include <private/qv4objectiterator_p.h> +#include <private/qv4alloca_p.h> #include <qqmlcontext.h> #include <qqmlinfo.h> @@ -52,6 +54,7 @@ #include <QtCore/qstack.h> #include <QXmlStreamReader> #include <QtCore/qdatetime.h> +#include <QScopedValueRollback> QT_BEGIN_NAMESPACE @@ -1259,9 +1262,14 @@ ModelNodeMetaObject *ModelNodeMetaObject::get(QObject *obj) void ModelNodeMetaObject::updateValues() { - if (!m_initialized) + const int roleCount = m_model->m_listModel->roleCount(); + if (!m_initialized) { + int *changedRoles = reinterpret_cast<int *>(alloca(roleCount * sizeof(int))); + for (int i = 0; i < roleCount; ++i) + changedRoles[i] = i; + emitDirectNotifies(changedRoles, roleCount); return; - int roleCount = m_model->m_listModel->roleCount(); + } for (int i=0 ; i < roleCount ; ++i) { const ListLayout::Role &role = m_model->m_listModel->getExistingRole(i); QByteArray name = role.name.toUtf8(); @@ -1272,8 +1280,10 @@ void ModelNodeMetaObject::updateValues() void ModelNodeMetaObject::updateValues(const QVector<int> &roles) { - if (!m_initialized) + if (!m_initialized) { + emitDirectNotifies(roles.constData(), roles.count()); return; + } int roleCount = roles.count(); for (int i=0 ; i < roleCount ; ++i) { int roleIndex = roles.at(i); @@ -1303,6 +1313,22 @@ void ModelNodeMetaObject::propertyWritten(int index) } } +// Does the emission of the notifiers when we haven't created the meta-object yet +void ModelNodeMetaObject::emitDirectNotifies(const int *changedRoles, int roleCount) +{ + Q_ASSERT(!m_initialized); + QQmlData *ddata = QQmlData::get(object(), /*create*/false); + if (!ddata) + return; + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine(m_model)); + if (!ep) + return; + for (int i = 0; i < roleCount; ++i) { + const int changedRole = changedRoles[i]; + QQmlNotifier::notify(ddata, changedRole); + } +} + namespace QV4 { void ModelObject::put(Managed *m, String *name, const Value &value) @@ -1332,6 +1358,18 @@ ReturnedValue ModelObject::get(const Managed *m, String *name, bool *hasProperty return QObjectWrapper::get(m, name, hasProperty); if (hasProperty) *hasProperty = true; + + if (QQmlEngine *qmlEngine = that->engine()->qmlEngine()) { + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(qmlEngine); + if (ep && ep->propertyCapture) { + QObjectPrivate *op = QObjectPrivate::get(that->object()); + // Temporarily hide the dynamic meta-object, to prevent it from being created when the capture + // triggers a QObject::connectNotify() by calling obj->metaObject(). + QScopedValueRollback<QDynamicMetaObjectData*> metaObjectBlocker(op->metaObject, 0); + ep->propertyCapture->captureProperty(that->object(), -1, role->index); + } + } + const int elementIndex = that->d()->m_elementIndex; QVariant value = that->d()->m_model->data(elementIndex, role->index); return that->engine()->fromVariant(value); diff --git a/src/qml/types/qqmllistmodel_p_p.h b/src/qml/types/qqmllistmodel_p_p.h index d7e0defaec..f23fec1e59 100644 --- a/src/qml/types/qqmllistmodel_p_p.h +++ b/src/qml/types/qqmllistmodel_p_p.h @@ -146,6 +146,8 @@ private: setValue(name, val); } + void emitDirectNotifies(const int *changedRoles, int roleCount); + void initialize(); bool m_initialized; }; |