fix(SubmodelProxyModel): Proxy model made non-intrusive
Now SubmodelProxyModel doesn't affect source model therefore it's possible to safely use multiple SubmodelProxyModels over the same source model. Closes: #14550
This commit is contained in:
parent
d9707091d3
commit
2dfb61fe1c
|
@ -6,6 +6,8 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include "modelsyncedcontainer.h"
|
||||||
|
|
||||||
class QQmlComponent;
|
class QQmlComponent;
|
||||||
class QQmlEngine;
|
class QQmlEngine;
|
||||||
|
|
||||||
|
@ -69,4 +71,6 @@ private:
|
||||||
QHash<int, QByteArray> m_roleNames;
|
QHash<int, QByteArray> m_roleNames;
|
||||||
QHash<QString, int> m_additionalRolesMap;
|
QHash<QString, int> m_additionalRolesMap;
|
||||||
int m_additionalRolesOffset = std::numeric_limits<int>::max();
|
int m_additionalRolesOffset = std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
mutable ModelSyncedContainer<std::unique_ptr<QObject>> m_container;
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,8 +26,6 @@ SubmodelProxyModel::SubmodelProxyModel(QObject* parent)
|
||||||
|
|
||||||
QVariant SubmodelProxyModel::data(const QModelIndex& index, int role) const
|
QVariant SubmodelProxyModel::data(const QModelIndex& index, int role) const
|
||||||
{
|
{
|
||||||
static constexpr auto attachementPropertyName = "_attachement";
|
|
||||||
|
|
||||||
if (!checkIndex(index, CheckIndexOption::IndexIsValid))
|
if (!checkIndex(index, CheckIndexOption::IndexIsValid))
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -41,31 +39,34 @@ QVariant SubmodelProxyModel::data(const QModelIndex& index, int role) const
|
||||||
return submodel;
|
return submodel;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant attachement = submodelObj->property(attachementPropertyName);
|
QVariant proxyVariant;
|
||||||
|
|
||||||
if (attachement.isValid())
|
auto& entry = m_container[index.row()];
|
||||||
return attachement;
|
|
||||||
|
|
||||||
// Make sure that wrapper is destroyed before it receives signal related
|
if (entry) {
|
||||||
// to submodel's destruction. Otherwise injected context property may
|
proxyVariant = QVariant::fromValue(entry.get());
|
||||||
// be cleared causing warnings related to accessing null from qml.
|
}
|
||||||
connect(submodelObj, &QObject::destroyed, this, [](auto obj) {
|
|
||||||
QVariant attachement = obj->property(attachementPropertyName);
|
|
||||||
|
|
||||||
if (attachement.isValid())
|
if (proxyVariant.isValid())
|
||||||
delete attachement.value<QObject*>();
|
return proxyVariant;
|
||||||
});
|
|
||||||
|
|
||||||
auto creationContext = m_delegateModel->creationContext();
|
auto creationContext = m_delegateModel->creationContext();
|
||||||
auto parentContext = creationContext
|
auto parentContext = creationContext
|
||||||
? creationContext : m_delegateModel->engine()->rootContext();
|
? creationContext : m_delegateModel->engine()->rootContext();
|
||||||
|
|
||||||
auto context = new QQmlContext(parentContext, submodelObj);
|
auto context = new QQmlContext(parentContext, submodelObj);
|
||||||
|
|
||||||
|
// Make sure that wrapper is destroyed before it receives signal related
|
||||||
|
// to submodel's destruction. Otherwise injected context property may
|
||||||
|
// be cleared causing warnings related to accessing null from qml.
|
||||||
|
connect(submodelObj, &QObject::destroyed, this,
|
||||||
|
[context = QPointer(context)](auto obj) {
|
||||||
|
delete context.data();
|
||||||
|
});
|
||||||
|
|
||||||
context->setContextProperty(QStringLiteral("submodel"), submodel);
|
context->setContextProperty(QStringLiteral("submodel"), submodel);
|
||||||
|
|
||||||
QObject* instance = m_delegateModel->create(context);
|
QObject* instance = m_delegateModel->create(context);
|
||||||
instance->setParent(submodelObj);
|
|
||||||
|
|
||||||
QVariant wrappedInstance = QVariant::fromValue(instance);
|
QVariant wrappedInstance = QVariant::fromValue(instance);
|
||||||
|
|
||||||
if (m_additionalRolesMap.size()) {
|
if (m_additionalRolesMap.size()) {
|
||||||
|
@ -77,8 +78,7 @@ QVariant SubmodelProxyModel::data(const QModelIndex& index, int role) const
|
||||||
this, SLOT(onCustomRoleChanged(QObject*,int)));
|
this, SLOT(onCustomRoleChanged(QObject*,int)));
|
||||||
}
|
}
|
||||||
|
|
||||||
submodelObj->setProperty(attachementPropertyName, wrappedInstance);
|
m_container[index.row()].reset(instance);
|
||||||
|
|
||||||
return wrappedInstance;
|
return wrappedInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,8 @@ void SubmodelProxyModel::setSourceModel(QAbstractItemModel* model)
|
||||||
if (sourceModel() == model)
|
if (sourceModel() == model)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_container.setModel(model);
|
||||||
|
|
||||||
// Workaround for QTBUG-57971
|
// Workaround for QTBUG-57971
|
||||||
if (model->roleNames().isEmpty())
|
if (model->roleNames().isEmpty())
|
||||||
connect(model, &QAbstractItemModel::rowsInserted,
|
connect(model, &QAbstractItemModel::rowsInserted,
|
||||||
|
|
|
@ -663,9 +663,6 @@ private slots:
|
||||||
}
|
}
|
||||||
|
|
||||||
void multipleProxiesTest() {
|
void multipleProxiesTest() {
|
||||||
QSKIP("Not implemented yet. The goal is to make the proxy fully "
|
|
||||||
"non-intrusive what will fix the isse pointed in this test.");
|
|
||||||
|
|
||||||
QQmlEngine engine;
|
QQmlEngine engine;
|
||||||
auto delegate1 = std::make_unique<QQmlComponent>(&engine);
|
auto delegate1 = std::make_unique<QQmlComponent>(&engine);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue