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"