fix(ObjectProxyModel): source data change handling improved
- source dataChanged rage is checked and skipped if malformed - dataChange is not propagated to delegate for rows not accessed so far
This commit is contained in:
parent
45863ad4c1
commit
4f24ee0422
|
@ -61,20 +61,25 @@ void ObjectProxyModel::setSourceModel(QAbstractItemModel* model)
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(model, &QAbstractItemModel::dataChanged, this,
|
connect(model, &QAbstractItemModel::dataChanged, this,
|
||||||
[this](const QModelIndex& topLeft, const QModelIndex& bottomRight,
|
[this, model](const QModelIndex& topLeft,
|
||||||
const QVector<int>& roles)
|
const QModelIndex& bottomRight, const QVector<int>& roles)
|
||||||
{
|
{
|
||||||
|
if (!topLeft.isValid() || !bottomRight.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
auto first = topLeft.row();
|
auto first = topLeft.row();
|
||||||
auto last = bottomRight.row();
|
auto last = bottomRight.row();
|
||||||
|
|
||||||
auto model = sourceModel();
|
|
||||||
|
|
||||||
for (auto idx = first; idx <= last; idx++) {
|
for (auto idx = first; idx <= last; idx++) {
|
||||||
auto rowData = m_container[idx].rowData;
|
auto rowData = m_container[idx].rowData;
|
||||||
|
|
||||||
|
if (rowData == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
QHashIterator i(m_expectedRoleNames);
|
QHashIterator i(m_expectedRoleNames);
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
i.next();
|
i.next();
|
||||||
|
|
||||||
rowData->insert(i.value(),
|
rowData->insert(i.value(),
|
||||||
model->data(model->index(idx, 0), i.key()));
|
model->data(model->index(idx, 0), i.key()));
|
||||||
}
|
}
|
||||||
|
@ -232,12 +237,12 @@ void ObjectProxyModel::emitAllDataChanged()
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (m_expectedRoles.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
QVector<int> roles(m_exposedRolesSet.cbegin(),
|
QVector<int> roles(m_exposedRolesSet.cbegin(),
|
||||||
m_exposedRolesSet.cend());
|
m_exposedRolesSet.cend());
|
||||||
|
|
||||||
if (roles.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
emit this->dataChanged(index(0, 0), index(count - 1, 0), roles);
|
emit this->dataChanged(index(0, 0), index(count - 1, 0), roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -313,7 +313,6 @@ private slots:
|
||||||
|
|
||||||
ModelSignalsSpy signalsSpy(&model);
|
ModelSignalsSpy signalsSpy(&model);
|
||||||
|
|
||||||
|
|
||||||
QObject* proxy = model.proxyObject(0);
|
QObject* proxy = model.proxyObject(0);
|
||||||
proxy->setProperty("extraValue", 42);
|
proxy->setProperty("extraValue", 42);
|
||||||
|
|
||||||
|
@ -376,7 +375,6 @@ private slots:
|
||||||
|
|
||||||
QObject* proxy = model.proxyObject(0);
|
QObject* proxy = model.proxyObject(0);
|
||||||
|
|
||||||
|
|
||||||
// dataChanged signal emission is scheduled to event loop, not called
|
// dataChanged signal emission is scheduled to event loop, not called
|
||||||
// immediately. In the meantime the source may be cleared and then no
|
// immediately. In the meantime the source may be cleared and then no
|
||||||
// dataChanged event should be emited.
|
// dataChanged event should be emited.
|
||||||
|
@ -681,6 +679,73 @@ private slots:
|
||||||
QCOMPARE(model.rowCount(), 0);
|
QCOMPARE(model.rowCount(), 0);
|
||||||
QCOMPARE(model.roleNames().size(), 0);
|
QCOMPARE(model.roleNames().size(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sourceModelDataChangeTest() {
|
||||||
|
QQmlEngine engine;
|
||||||
|
QQmlComponent delegate(&engine);
|
||||||
|
|
||||||
|
auto delegateData = R"(
|
||||||
|
import QtQml 2.15
|
||||||
|
QtObject {
|
||||||
|
readonly property int doubledBalance: model.balance * 2
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
delegate.setData(delegateData, QUrl());
|
||||||
|
|
||||||
|
ObjectProxyModel model;
|
||||||
|
|
||||||
|
auto source = R"([
|
||||||
|
{ balance: 4 },
|
||||||
|
{ balance: 10 }
|
||||||
|
])";
|
||||||
|
|
||||||
|
ListModelWrapper sourceModel(engine, source);
|
||||||
|
|
||||||
|
model.setSourceModel(sourceModel);
|
||||||
|
model.setDelegate(&delegate);
|
||||||
|
|
||||||
|
model.setExpectedRoles(QStringList({ QStringLiteral("balance") }));
|
||||||
|
model.setExposedRoles({ QStringLiteral("doubledBalance")});
|
||||||
|
|
||||||
|
ModelSignalsSpy signalsSpy(&model);
|
||||||
|
|
||||||
|
sourceModel.setProperty(0, "balance", 42);
|
||||||
|
sourceModel.setProperty(1, "balance", 0);
|
||||||
|
|
||||||
|
{
|
||||||
|
ListModelWrapper expected(engine, R"([
|
||||||
|
{ balance: 42, doubledBalance: 84 },
|
||||||
|
{ balance: 0, doubledBalance: 0 }
|
||||||
|
])");
|
||||||
|
|
||||||
|
QVERIFY(isSame(&model, expected));
|
||||||
|
QCOMPARE(signalsSpy.count(), 2);
|
||||||
|
QCOMPARE(signalsSpy.dataChangedSpy.count(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTest::qWait(100);
|
||||||
|
QCOMPARE(signalsSpy.count(), 2);
|
||||||
|
QCOMPARE(signalsSpy.dataChangedSpy.count(), 2);
|
||||||
|
|
||||||
|
sourceModel.setProperty(0, "balance", 1);
|
||||||
|
sourceModel.setProperty(1, "balance", 2);
|
||||||
|
|
||||||
|
{
|
||||||
|
ListModelWrapper expected(engine, R"([
|
||||||
|
{ balance: 1, doubledBalance: 2 },
|
||||||
|
{ balance: 2, doubledBalance: 4 }
|
||||||
|
])");
|
||||||
|
|
||||||
|
QVERIFY(isSame(&model, expected));
|
||||||
|
QCOMPARE(signalsSpy.count(), 4);
|
||||||
|
QCOMPARE(signalsSpy.dataChangedSpy.count(), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTest::qWait(100);
|
||||||
|
QCOMPARE(signalsSpy.count(), 5);
|
||||||
|
QCOMPARE(signalsSpy.dataChangedSpy.count(), 5);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QTEST_MAIN(TestObjectProxyModel)
|
QTEST_MAIN(TestObjectProxyModel)
|
||||||
|
|
Loading…
Reference in New Issue