QQmlListModel: handle nested list models during iteration

ListElement::getProperty returns in turn a list model
The ModelObjectOwnPropertyKeyIterator should however return the concrete
values, and not some proxy object. This would cause funny return values
in the best case, and a crash in case of QTBUG-79083.

We therefore convert the nested model to a JavaScript array in
ModelObjectOwnPropertyKeyIterator::next, which avoids beforementioned
issues.

Fixes: QTBUG-79083
Change-Id: If038598ff1c3c59090e994aaba5fba94a6964224
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Fabian Kosmale 2019-10-08 15:05:15 +02:00 committed by Simon Hausmann
parent 7ec1dba095
commit 8ea33db635
2 changed files with 38 additions and 1 deletions

View File

@ -1641,8 +1641,18 @@ PropertyKey ModelObjectOwnPropertyKeyIterator::next(const Object *o, Property *p
if (attrs)
*attrs = QV4::Attr_Data;
if (pd) {
QVariant value = that->d()->m_model->data(that->d()->elementIndex(), role.index);
pd->value = v4->fromVariant(value);
if (auto recursiveListModel = qvariant_cast<QQmlListModel*>(value)) {
auto size = recursiveListModel->count();
auto array = ScopedArrayObject{scope, v4->newArrayObject(size)};
for (auto i = 0; i < size; i++) {
array->arrayPut(i, QJSValuePrivate::convertedToValue(v4, recursiveListModel->get(i)));
}
pd->value = array;
} else {
pd->value = v4->fromVariant(value);
}
}
return roleName->toPropertyKey();
}

View File

@ -128,6 +128,7 @@ private slots:
void qobjectTrackerForDynamicModelObjects();
void crash_append_empty_array();
void dynamic_roles_crash_QTBUG_38907();
void nestedListModelIteration();
};
bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object)
@ -1667,6 +1668,32 @@ void tst_qqmllistmodel::dynamic_roles_crash_QTBUG_38907()
QVERIFY(retVal.toBool());
}
void tst_qqmllistmodel::nestedListModelIteration()
{
QQmlEngine engine;
QQmlComponent component(&engine);
QTest::ignoreMessage(QtMsgType::QtDebugMsg ,R"({"subItems":[{"a":1,"b":0,"c":0},{"a":0,"b":2,"c":0},{"a":0,"b":0,"c":3}]})");
component.setData(
R"(import QtQuick 2.5
Item {
visible: true
width: 640
height: 480
ListModel {
id : model
}
Component.onCompleted: {
var tempData = {
subItems: [{a: 1}, {b: 2}, {c: 3}]
}
model.insert(0, tempData)
console.log(JSON.stringify(model.get(0)))
}
})",
QUrl());
QScopedPointer<QObject>(component.create());
}
QTEST_MAIN(tst_qqmllistmodel)
#include "tst_qqmllistmodel.moc"