Properly wire up DelegateModel's modelChanged signal
If the model contents change we need to notify. This enables the signal propagation for Instantiator, Repeater, ListView, and GridView. Pick-to: 6.10 Task-number: QTBUG-139941 Change-Id: I384dcd296068ca7abfd1cad9fe662ae6e8938338 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
8ae3765c3f
commit
6803e9c908
|
@ -388,6 +388,9 @@ void QQmlDelegateModel::setModel(const QVariant &model)
|
|||
{
|
||||
Q_D(QQmlDelegateModel);
|
||||
|
||||
if (d->m_adaptorModel.model() == model)
|
||||
return;
|
||||
|
||||
if (d->m_complete)
|
||||
_q_itemsRemoved(0, d->m_count);
|
||||
|
||||
|
@ -420,6 +423,8 @@ void QQmlDelegateModel::setModel(const QVariant &model)
|
|||
if (aimPrivate->resetting)
|
||||
QObject::connect(aim, &QAbstractItemModel::modelReset, this, &QQmlDelegateModel::handleModelReset, Qt::SingleShotConnection);
|
||||
}
|
||||
|
||||
emit modelChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -2006,8 +2011,10 @@ void QQmlDelegateModel::_q_modelAboutToBeReset()
|
|||
// to throw away all the setup that we did
|
||||
handleModelReset();
|
||||
} else {
|
||||
// If they did change, we give up and just start from scratch via setMode
|
||||
setModel(QVariant::fromValue(model()));
|
||||
// If they did change, we give up and just start from scratch via setModel
|
||||
QVariant m = model();
|
||||
setModel(QVariant());
|
||||
setModel(m);
|
||||
// but we still have to call handleModelReset, otherwise views will
|
||||
// not refresh
|
||||
handleModelReset();
|
||||
|
|
|
@ -39,7 +39,7 @@ class Q_QMLMODELS_EXPORT QQmlDelegateModel : public QQmlInstanceModel, public QQ
|
|||
Q_OBJECT
|
||||
Q_DECLARE_PRIVATE(QQmlDelegateModel)
|
||||
|
||||
Q_PROPERTY(QVariant model READ model WRITE setModel)
|
||||
Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
|
||||
Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
|
||||
Q_PROPERTY(QString filterOnGroup READ filterGroup WRITE setFilterGroup NOTIFY filterGroupChanged RESET resetFilterGroup)
|
||||
Q_PROPERTY(QQmlDelegateModelGroup *items READ items CONSTANT) //TODO : worth renaming?
|
||||
|
@ -154,6 +154,7 @@ Q_SIGNALS:
|
|||
void rootIndexChanged();
|
||||
void delegateChanged();
|
||||
Q_REVISION(6, 10) void delegateModelAccessChanged();
|
||||
Q_REVISION(6, 10) void modelChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void _q_itemsChanged(int index, int count, const QVector<int> &roles);
|
||||
|
|
|
@ -99,6 +99,8 @@ int VDMListDelegateDataType::metaCall(
|
|||
accessor->cachedDataClean = false;
|
||||
} else {
|
||||
model->list.set(accessor->index, data);
|
||||
if (QQmlDelegateModel *delegateModel = accessor->metaType->model)
|
||||
emit delegateModel->modelChanged();
|
||||
}
|
||||
QMetaObject::activate(accessor, this, id - propertyOffset, nullptr);
|
||||
emit accessor->modelDataChanged();
|
||||
|
|
|
@ -53,6 +53,10 @@ public:
|
|||
this, &QQmlInstantiatorPrivate::_q_modelUpdated);
|
||||
QObjectPrivate::connect(instanceModel, &QQmlInstanceModel::createdItem,
|
||||
this, &QQmlInstantiatorPrivate::_q_createdItem);
|
||||
if (ownModel) {
|
||||
QObject::connect(model->delegateModel(), &QQmlDelegateModel::modelChanged,
|
||||
q, &QQmlInstantiator::modelChanged);
|
||||
}
|
||||
|
||||
regenerate();
|
||||
}
|
||||
|
@ -67,6 +71,10 @@ public:
|
|||
this, &QQmlInstantiatorPrivate::_q_modelUpdated);
|
||||
QObjectPrivate::disconnect(instanceModel, &QQmlInstanceModel::createdItem,
|
||||
this, &QQmlInstantiatorPrivate::_q_createdItem);
|
||||
if (ownModel) {
|
||||
QObject::disconnect(model->delegateModel(), &QQmlDelegateModel::modelChanged,
|
||||
q, &QQmlInstantiator::modelChanged);
|
||||
}
|
||||
}
|
||||
|
||||
QPointer<QQmlInstanceModel> model;
|
||||
|
|
|
@ -1160,6 +1160,10 @@ void QQuickItemViewPrivate::connectModel(QQuickItemView *q, QQmlDelegateModelPoi
|
|||
QObjectPrivate::connect(
|
||||
dataModel, &QQmlDelegateModel::delegateModelAccessChanged,
|
||||
this, &QQuickItemViewPrivate::applyDelegateModelAccessChange);
|
||||
if (ownModel) {
|
||||
QObject::connect(dataModel, &QQmlDelegateModel::modelChanged,
|
||||
q, &QQuickItemView::modelChanged);
|
||||
}
|
||||
}
|
||||
|
||||
emitCountChanged();
|
||||
|
@ -1191,6 +1195,10 @@ void QQuickItemViewPrivate::disconnectModel(QQuickItemView *q, QQmlDelegateModel
|
|||
QObjectPrivate::disconnect(
|
||||
delegateModel, &QQmlDelegateModel::delegateModelAccessChanged,
|
||||
this, &QQuickItemViewPrivate::applyDelegateModelAccessChange);
|
||||
if (ownModel) {
|
||||
QObject::disconnect(delegateModel, &QQmlDelegateModel::modelChanged,
|
||||
q, &QQuickItemView::modelChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -470,6 +470,10 @@ void QQuickRepeaterPrivate::connectModel(QQuickRepeater *q, QQmlDelegateModelPoi
|
|||
QObjectPrivate::connect(
|
||||
dataModel, &QQmlDelegateModel::delegateModelAccessChanged,
|
||||
this, &QQuickRepeaterPrivate::applyDelegateModelAccessChange);
|
||||
if (ownModel) {
|
||||
QObject::connect(dataModel, &QQmlDelegateModel::modelChanged,
|
||||
q, &QQuickRepeater::modelChanged);
|
||||
}
|
||||
}
|
||||
q->regenerate();
|
||||
}
|
||||
|
@ -493,6 +497,10 @@ void QQuickRepeaterPrivate::disconnectModel(QQuickRepeater *q, QQmlDelegateModel
|
|||
QObjectPrivate::disconnect(
|
||||
delegateModel, &QQmlDelegateModel::delegateModelAccessChanged,
|
||||
this, &QQuickRepeaterPrivate::applyDelegateModelAccessChange);
|
||||
if (ownModel) {
|
||||
QObject::disconnect(delegateModel, &QQmlDelegateModel::modelChanged,
|
||||
q, &QQuickRepeater::modelChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -477,6 +477,8 @@ void tst_qqmlinstantiator::delegateModelAccess()
|
|||
QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator *>(object.data());
|
||||
QVERIFY(instantiator);
|
||||
|
||||
QSignalSpy modelChangedSpy(instantiator, &QQmlInstantiator::modelChanged);
|
||||
|
||||
if (delegateKind == Delegate::Untyped && modelKind == Model::Array)
|
||||
QSKIP("Properties of objects in arrays are not exposed as context properties");
|
||||
|
||||
|
@ -500,20 +502,34 @@ void tst_qqmlinstantiator::delegateModelAccess()
|
|||
? access != QQmlDelegateModel::ReadOnly
|
||||
: access == QQmlDelegateModel::ReadWrite;
|
||||
|
||||
// Only the array is actually updated itself. The other models are pointers
|
||||
const bool writeShouldSignal = modelKind == Model::Kind::Array;
|
||||
|
||||
double expected = 11;
|
||||
|
||||
// Initial setting of the model, signals one update
|
||||
int expectedModelUpdates = 1;
|
||||
QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
|
||||
|
||||
QCOMPARE(delegate->property("immediateX").toDouble(), expected);
|
||||
QCOMPARE(delegate->property("modelX").toDouble(), expected);
|
||||
|
||||
if (modelWritable)
|
||||
if (modelWritable) {
|
||||
expected = 3;
|
||||
if (writeShouldSignal)
|
||||
++expectedModelUpdates;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(delegate, "writeThroughModel");
|
||||
QCOMPARE(delegate->property("immediateX").toDouble(), expected);
|
||||
QCOMPARE(delegate->property("modelX").toDouble(), expected);
|
||||
QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
|
||||
|
||||
if (immediateWritable)
|
||||
if (immediateWritable) {
|
||||
expected = 1;
|
||||
if (writeShouldSignal)
|
||||
++expectedModelUpdates;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(delegate, "writeImmediate");
|
||||
|
||||
|
@ -522,6 +538,7 @@ void tst_qqmlinstantiator::delegateModelAccess()
|
|||
delegateKind == Delegate::Untyped ? expected : 1);
|
||||
|
||||
QCOMPARE(delegate->property("modelX").toDouble(), expected);
|
||||
QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qqmlinstantiator)
|
||||
|
|
|
@ -1435,6 +1435,8 @@ void tst_QQuickListView2::delegateModelAccess()
|
|||
QQuickListView *listView = qobject_cast<QQuickListView *>(object.data());
|
||||
QVERIFY(listView);
|
||||
|
||||
QSignalSpy modelChangedSpy(listView, &QQuickItemView::modelChanged);
|
||||
|
||||
if (delegateKind == Delegate::Untyped && modelKind == Model::Array)
|
||||
QSKIP("Properties of objects in arrays are not exposed as context properties");
|
||||
|
||||
|
@ -1459,20 +1461,34 @@ void tst_QQuickListView2::delegateModelAccess()
|
|||
? access != QQmlDelegateModel::ReadOnly
|
||||
: access == QQmlDelegateModel::ReadWrite;
|
||||
|
||||
// Only the array is actually updated itself. The other models are pointers
|
||||
const bool writeShouldSignal = modelKind == Model::Kind::Array;
|
||||
|
||||
double expected = 11;
|
||||
|
||||
// Initial setting of the model, signals one update
|
||||
int expectedModelUpdates = 1;
|
||||
QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
|
||||
|
||||
QCOMPARE(delegate->property("immediateX").toDouble(), expected);
|
||||
QCOMPARE(delegate->property("modelX").toDouble(), expected);
|
||||
|
||||
if (modelWritable)
|
||||
if (modelWritable) {
|
||||
expected = 3;
|
||||
if (writeShouldSignal)
|
||||
++expectedModelUpdates;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(delegate, "writeThroughModel");
|
||||
QCOMPARE(delegate->property("immediateX").toDouble(), expected);
|
||||
QCOMPARE(delegate->property("modelX").toDouble(), expected);
|
||||
QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
|
||||
|
||||
if (immediateWritable)
|
||||
if (immediateWritable) {
|
||||
expected = 1;
|
||||
if (writeShouldSignal)
|
||||
++expectedModelUpdates;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(delegate, "writeImmediate");
|
||||
|
||||
|
@ -1481,6 +1497,7 @@ void tst_QQuickListView2::delegateModelAccess()
|
|||
delegateKind == Delegate::Untyped ? expected : 1);
|
||||
|
||||
QCOMPARE(delegate->property("modelX").toDouble(), expected);
|
||||
QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
|
||||
}
|
||||
|
||||
enum RemovalPolicy {
|
||||
|
|
|
@ -1290,6 +1290,8 @@ void tst_QQuickRepeater::delegateModelAccess()
|
|||
QQuickRepeater *repeater = qvariant_cast<QQuickRepeater *>(object->property("repeater"));
|
||||
QVERIFY(repeater);
|
||||
|
||||
QSignalSpy modelChangedSpy(repeater, &QQuickRepeater::modelChanged);
|
||||
|
||||
if (delegateKind == Delegate::Untyped && modelKind == Model::Array)
|
||||
QSKIP("Properties of objects in arrays are not exposed as context properties");
|
||||
|
||||
|
@ -1314,20 +1316,34 @@ void tst_QQuickRepeater::delegateModelAccess()
|
|||
? access != QQmlDelegateModel::ReadOnly
|
||||
: access == QQmlDelegateModel::ReadWrite;
|
||||
|
||||
// Only the array is actually updated itself. The other models are pointers
|
||||
const bool writeShouldSignal = modelKind == Model::Kind::Array;
|
||||
|
||||
double expected = 11;
|
||||
|
||||
// Initial setting of the model, signals one update
|
||||
int expectedModelUpdates = 1;
|
||||
QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
|
||||
|
||||
QCOMPARE(delegate->property("immediateX").toDouble(), expected);
|
||||
QCOMPARE(delegate->property("modelX").toDouble(), expected);
|
||||
|
||||
if (modelWritable)
|
||||
if (modelWritable) {
|
||||
expected = 3;
|
||||
if (writeShouldSignal)
|
||||
++expectedModelUpdates;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(delegate, "writeThroughModel");
|
||||
QCOMPARE(delegate->property("immediateX").toDouble(), expected);
|
||||
QCOMPARE(delegate->property("modelX").toDouble(), expected);
|
||||
QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
|
||||
|
||||
if (immediateWritable)
|
||||
if (immediateWritable) {
|
||||
expected = 1;
|
||||
if (writeShouldSignal)
|
||||
++expectedModelUpdates;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(delegate, "writeImmediate");
|
||||
|
||||
|
@ -1336,6 +1352,7 @@ void tst_QQuickRepeater::delegateModelAccess()
|
|||
delegateKind == Delegate::Untyped ? expected : 1);
|
||||
|
||||
QCOMPARE(delegate->property("modelX").toDouble(), expected);
|
||||
QCOMPARE(modelChangedSpy.count(), expectedModelUpdates);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QQuickRepeater)
|
||||
|
|
Loading…
Reference in New Issue