StatusQ(SubmodelProxyModel): Submodel type fixed

There was inconsistency in qvariant type of submodels depending if it
was initial call for a given row (creating proxy) or further calls
(returning cached object). It led to subtle issues in views - view was
reporting type errors and failing assigning submodels properly when used
with submodel proxy with already initialized and cached proxy submodels.

Closes: #14507
This commit is contained in:
Michał Cieślak 2024-04-24 10:28:33 +02:00 committed by Khushboo-dev-cpp
parent bbd0e71fd6
commit e8a78e21b8
2 changed files with 48 additions and 4 deletions

View File

@ -50,13 +50,13 @@ QVariant SubmodelProxyModel::data(const QModelIndex &index, int role) const
context->setContextProperty(QStringLiteral("submodel"), submodel);
QObject* instance = m_delegateModel->create(context);
instance->setParent(submodelObj);
submodelObj->setProperty(attachementPropertyName,
QVariant::fromValue(QPointer(instance)));
QVariant wrappedInstance = QVariant::fromValue(instance);
return QVariant::fromValue(instance);
submodelObj->setProperty(attachementPropertyName, wrappedInstance);
return QVariant::fromValue(wrappedInstance);
}
return QIdentityProxyModel::data(index, role);

View File

@ -78,6 +78,50 @@ private slots:
QQmlEngine::CppOwnership);
}
void submodelTypeTest() {
QQmlEngine engine;
QQmlComponent delegate(&engine);
auto delegateData = R"(
import QtQml 2.15
QtObject {
property var count: submodel.count
}
)";
delegate.setData(delegateData, QUrl());
SubmodelProxyModel model;
auto source = R"([
{ balances: [ { balance: 4 } ], name: "name 1" }
])";
ListModelWrapper sourceModel(engine, source);
model.setSourceModel(sourceModel);
model.setDelegateModel(&delegate);
model.setSubmodelRoleName(QStringLiteral("balances"));
QCOMPARE(model.rowCount(), 1);
QVariant balances = model.data(model.index(0, 0),
sourceModel.role("balances"));
QVERIFY(balances.isValid());
QVariant balances2 = model.data(model.index(0, 0),
sourceModel.role("balances"));
// SubmodelProxyModel may create proxy objects on demand, then first
// call to data(...) returns freshly created object, the next calls
// related to the same row should return cached object. It's important
// to have QVariant type identical in both cases. E.g. returning raw
// pointer in first call and pointer wrapped into QPointer in the next
// one leads to problems in UI components in some scenarios even if
// those QVariant types are automatically convertible.
QCOMPARE(balances2.type(), balances.type());
}
void usingNonObjectSubmodelRoleTest() {
QQmlEngine engine;
QQmlComponent delegate(&engine);