From e8a78e21b8f0d5c6cfe30707c6c565557eea2378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cie=C5=9Blak?= Date: Wed, 24 Apr 2024 10:28:33 +0200 Subject: [PATCH] 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 --- ui/StatusQ/src/submodelproxymodel.cpp | 8 ++-- ui/StatusQ/tests/tst_SubmodelProxyModel.cpp | 44 +++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/ui/StatusQ/src/submodelproxymodel.cpp b/ui/StatusQ/src/submodelproxymodel.cpp index 395878213e..d6676263fd 100644 --- a/ui/StatusQ/src/submodelproxymodel.cpp +++ b/ui/StatusQ/src/submodelproxymodel.cpp @@ -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); diff --git a/ui/StatusQ/tests/tst_SubmodelProxyModel.cpp b/ui/StatusQ/tests/tst_SubmodelProxyModel.cpp index 172b48f9c9..5ef5fff83f 100644 --- a/ui/StatusQ/tests/tst_SubmodelProxyModel.cpp +++ b/ui/StatusQ/tests/tst_SubmodelProxyModel.cpp @@ -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);