File indexing completed on 2024-05-12 05:36:51

0001 /*
0002  * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #include "ComponentCacheProxyModel.h"
0008 
0009 #include <QTimer>
0010 
0011 ComponentCacheAttached::ComponentCacheAttached(QObject *parent)
0012     : QObject(parent)
0013 {
0014 }
0015 
0016 ComponentCacheProxyModel::ComponentCacheProxyModel(QObject *parent)
0017     : QIdentityProxyModel(parent)
0018 {
0019 }
0020 
0021 ComponentCacheProxyModel::~ComponentCacheProxyModel()
0022 {
0023 }
0024 
0025 QHash<int, QByteArray> ComponentCacheProxyModel::roleNames() const
0026 {
0027     auto names = QIdentityProxyModel::roleNames();
0028     names.insert(CachedComponentRole, "cachedComponent");
0029     return names;
0030 }
0031 
0032 QVariant ComponentCacheProxyModel::data(const QModelIndex &proxyIndex, int role) const
0033 {
0034     if (role == CachedComponentRole) {
0035         if (m_instances.contains(proxyIndex)) {
0036             return QVariant::fromValue(m_instances.value(proxyIndex));
0037         }
0038 
0039         // This bit of trickery is to get around the fact that we are in a const
0040         // method here but still want to create the instances only on demand.
0041         m_pendingInstances.append(proxyIndex);
0042         if (m_pendingInstances.size() == 1) {
0043             QTimer::singleShot(0, this, &ComponentCacheProxyModel::createPendingInstance);
0044         }
0045         return QVariant{};
0046     }
0047 
0048     return QIdentityProxyModel::data(proxyIndex, role);
0049 }
0050 
0051 void ComponentCacheProxyModel::setSourceModel(QAbstractItemModel *newSourceModel)
0052 {
0053     if (sourceModel()) {
0054         sourceModel()->disconnect(this);
0055     }
0056 
0057     QIdentityProxyModel::setSourceModel(newSourceModel);
0058 
0059     if (newSourceModel) {
0060         connect(newSourceModel, &QAbstractItemModel::rowsRemoved, this, &ComponentCacheProxyModel::onRowsRemoved);
0061         connect(newSourceModel, &QAbstractItemModel::columnsRemoved, this, &ComponentCacheProxyModel::onColumnsRemoved);
0062         connect(newSourceModel, &QAbstractItemModel::modelReset, this, &ComponentCacheProxyModel::clear);
0063     }
0064 }
0065 
0066 QQmlComponent *ComponentCacheProxyModel::component() const
0067 {
0068     return m_component;
0069 }
0070 
0071 void ComponentCacheProxyModel::setComponent(QQmlComponent *newComponent)
0072 {
0073     if (newComponent == m_component) {
0074         return;
0075     }
0076 
0077     m_component = newComponent;
0078     clear();
0079     Q_EMIT componentChanged();
0080 }
0081 
0082 void ComponentCacheProxyModel::clear()
0083 {
0084     qDeleteAll(m_instances);
0085     m_instances.clear();
0086 }
0087 
0088 void ComponentCacheProxyModel::onRowsRemoved(const QModelIndex &parent, int start, int end)
0089 {
0090     for (int row = start; row < end; ++row) {
0091         for (int column = 0; column < columnCount(); ++column) {
0092             m_instances.remove(index(row, column, parent));
0093         }
0094     }
0095 }
0096 
0097 void ComponentCacheProxyModel::onColumnsRemoved(const QModelIndex &parent, int start, int end)
0098 {
0099     for (int column = start; column < end; ++column) {
0100         for (int row = 0; row < rowCount(); ++row) {
0101             m_instances.remove(index(row, column, parent));
0102         }
0103     }
0104 }
0105 
0106 void ComponentCacheProxyModel::createPendingInstance()
0107 {
0108     if (!m_component) {
0109         return;
0110     }
0111 
0112     while (!m_pendingInstances.isEmpty()) {
0113         auto index = m_pendingInstances.takeFirst();
0114         if (!index.isValid()) {
0115             continue;
0116         }
0117 
0118         auto context = qmlContext(this);
0119 
0120         auto instance = m_component->beginCreate(context);
0121         instance->setParent(this);
0122         auto attached = static_cast<ComponentCacheAttached *>(qmlAttachedPropertiesObject<ComponentCacheProxyModel>(instance));
0123         attached->m_model = this;
0124         attached->m_row = index.row();
0125         attached->m_column = index.column();
0126         m_component->completeCreate();
0127 
0128         m_instances.insert(index, instance);
0129         Q_EMIT dataChanged(index, index, {CachedComponentRole});
0130     }
0131 }
0132 
0133 #include "moc_ComponentCacheProxyModel.cpp"