File indexing completed on 2024-04-28 04:41:52
0001 /*************************************************************************** 0002 * Copyright (C) 2018 by Emmanuel Lepage Vallee * 0003 * Author : Emmanuel Lepage Vallee <emmanuel.lepage@kde.org> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 3 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0017 **************************************************************************/ 0018 #include "indexview.h" 0019 0020 // Qt 0021 #include <QQmlEngine> 0022 #include <QQmlContext> 0023 0024 // KQuickItemViews 0025 #include <contextadapterfactory.h> 0026 #include <adapters/contextadapter.h> 0027 #include <extensions/contextextension.h> 0028 #include <qmodelindexwatcher.h> 0029 #include <qmodelindexbinder.h> 0030 0031 /// Make QModelIndexBinder life easier 0032 class MIWContextExtension final : public ContextExtension 0033 { 0034 public: 0035 virtual ~MIWContextExtension() {} 0036 virtual QVector<QByteArray>& propertyNames() const override; 0037 virtual QVariant getProperty(AbstractItemAdapter* item, uint id, const QModelIndex& index) const override; 0038 0039 IndexViewPrivate *d_ptr; 0040 }; 0041 0042 class IndexViewPrivate : public QObject 0043 { 0044 Q_OBJECT 0045 public: 0046 QQmlComponent *m_pComponent {nullptr}; 0047 ContextAdapter *m_pCTX {nullptr}; 0048 ContextAdapterFactory *m_pFactory {nullptr}; 0049 QQuickItem *m_pItem {nullptr}; 0050 MIWContextExtension *m_pExt {nullptr}; 0051 QModelIndexWatcher *m_pWatcher {nullptr}; 0052 0053 // Helper 0054 void initDelegate(); 0055 void initContext(); 0056 0057 IndexView *q_ptr; 0058 0059 public Q_SLOTS: 0060 void slotDismiss(); 0061 void slotDataChanged(const QVector<int> &roles); 0062 }; 0063 0064 IndexView::IndexView(QQuickItem *parent) : QQuickItem(parent), 0065 d_ptr(new IndexViewPrivate()) 0066 { 0067 d_ptr->q_ptr = this; 0068 d_ptr->m_pWatcher = new QModelIndexWatcher(this); 0069 connect(d_ptr->m_pWatcher, &QModelIndexWatcher::removed, 0070 d_ptr, &IndexViewPrivate::slotDismiss); 0071 connect(d_ptr->m_pWatcher, &QModelIndexWatcher::dataChanged, 0072 d_ptr, &IndexViewPrivate::slotDataChanged); 0073 } 0074 0075 IndexView::~IndexView() 0076 { 0077 if (d_ptr->m_pItem) 0078 delete d_ptr->m_pItem; 0079 0080 if (d_ptr->m_pCTX) 0081 delete d_ptr->m_pCTX; 0082 0083 if (d_ptr->m_pFactory) 0084 delete d_ptr->m_pFactory; 0085 0086 if (d_ptr->m_pExt) 0087 delete d_ptr->m_pExt; 0088 0089 delete d_ptr->m_pWatcher; 0090 delete d_ptr; 0091 } 0092 0093 void IndexView::setDelegate(QQmlComponent* delegate) 0094 { 0095 if (delegate == d_ptr->m_pComponent) 0096 return; 0097 0098 if (d_ptr->m_pItem) 0099 delete d_ptr->m_pItem; 0100 0101 d_ptr->m_pComponent = delegate; 0102 emit delegateChanged(delegate); 0103 0104 d_ptr->initDelegate(); 0105 } 0106 0107 QQmlComponent* IndexView::delegate() const 0108 { 0109 return d_ptr->m_pComponent; 0110 } 0111 0112 QModelIndex IndexView::modelIndex() const 0113 { 0114 return d_ptr->m_pWatcher->modelIndex(); 0115 } 0116 0117 QAbstractItemModel *IndexView::model() const 0118 { 0119 return d_ptr->m_pWatcher->model(); 0120 } 0121 0122 void IndexView::setModelIndex(const QModelIndex &index) 0123 { 0124 if (index == modelIndex()) 0125 return; 0126 0127 // Disconnect old models 0128 if (model() && model() != index.model()) 0129 d_ptr->slotDismiss(); 0130 0131 0132 if (model() != index.model()) { 0133 if (!d_ptr->m_pFactory) { 0134 d_ptr->m_pExt = new MIWContextExtension (); 0135 d_ptr->m_pFactory = new ContextAdapterFactory(); 0136 d_ptr->m_pExt->d_ptr = d_ptr; 0137 d_ptr->m_pFactory->addContextExtension(d_ptr->m_pExt); 0138 } 0139 0140 d_ptr->m_pFactory->setModel(const_cast<QAbstractItemModel*>(index.model())); 0141 0142 if (d_ptr->m_pItem) { 0143 delete d_ptr->m_pItem; 0144 d_ptr->m_pItem = nullptr; 0145 } 0146 0147 d_ptr->m_pCTX = nullptr; 0148 } 0149 0150 d_ptr->m_pWatcher->setModelIndex(index); 0151 0152 d_ptr->initContext(); 0153 0154 d_ptr->m_pCTX->setModelIndex(index); 0155 0156 d_ptr->initDelegate(); 0157 emit indexChanged(); 0158 } 0159 0160 void IndexViewPrivate::initContext() 0161 { 0162 if (m_pCTX) 0163 return; 0164 0165 Q_ASSERT(m_pFactory); 0166 0167 const auto ctx = QQmlEngine::contextForObject(q_ptr); 0168 m_pCTX = m_pFactory->createAdapter(ctx); 0169 Q_ASSERT(m_pCTX && m_pCTX->context()->parentContext() == ctx); 0170 } 0171 0172 void IndexViewPrivate::slotDismiss() 0173 { 0174 if (m_pItem) { 0175 delete m_pItem; 0176 m_pItem = nullptr; 0177 } 0178 0179 if (m_pCTX) { 0180 delete m_pCTX; 0181 m_pCTX = nullptr; 0182 } 0183 0184 emit q_ptr->indexChanged(); 0185 } 0186 0187 void IndexViewPrivate::slotDataChanged(const QVector<int> &roles) 0188 { 0189 m_pCTX->updateRoles(roles); 0190 } 0191 0192 void IndexViewPrivate::initDelegate() 0193 { 0194 if (m_pItem || (!m_pComponent) || !q_ptr->modelIndex().isValid()) 0195 return; 0196 0197 initContext(); 0198 0199 m_pItem = qobject_cast<QQuickItem *>(m_pComponent->create(m_pCTX->context())); 0200 0201 // It will happen when the QML itself is invalid 0202 if (!m_pItem) 0203 return; 0204 0205 const auto ctx = QQmlEngine::contextForObject(q_ptr); 0206 Q_ASSERT(ctx); 0207 0208 ctx->engine()->setObjectOwnership(m_pItem, QQmlEngine::CppOwnership); 0209 m_pItem->setParentItem(q_ptr); 0210 } 0211 0212 QVector<QByteArray>& MIWContextExtension::propertyNames() const 0213 { 0214 static QVector<QByteArray> ret { "_modelIndexWatcher", "_contextAdapter" }; 0215 return ret; 0216 } 0217 0218 QVariant MIWContextExtension::getProperty(AbstractItemAdapter* item, uint id, const QModelIndex& index) const 0219 { 0220 Q_UNUSED(item) 0221 Q_UNUSED(index) 0222 return id ? QVariant::fromValue(d_ptr->m_pCTX) : QVariant::fromValue(d_ptr->m_pWatcher); 0223 } 0224 0225 #include <indexview.moc>