File indexing completed on 2024-04-28 04:41:48
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 "modeladapter.h" 0019 0020 // Qt 0021 #include <QtCore/QVariant> 0022 #include <QtCore/QAbstractItemModel> 0023 #include <QtCore/QSharedPointer> 0024 #include <QtCore/QDebug> 0025 0026 // KQuickItemViews 0027 #include "viewport.h" 0028 #include "viewbase.h" 0029 #include "selectionadapter.h" 0030 #include "contextadapterfactory.h" 0031 #include "private/selectionadapter_p.h" 0032 #include "private/statetracker/viewitem_p.h" 0033 #include "private/statetracker/content_p.h" 0034 #include "private/statetracker/model_p.h" 0035 #include "private/viewport_p.h" 0036 #include "abstractitemadapter.h" 0037 #include "proxies/sizehintproxymodel.h" 0038 0039 using QSharedItemModel = QSharedPointer<QAbstractItemModel>; 0040 0041 class ModelAdapterPrivate : public QObject 0042 { 0043 Q_OBJECT 0044 public: 0045 enum class Mode { 0046 NONE, 0047 SMART_POINTER, 0048 RAW 0049 } m_Mode {Mode::NONE}; 0050 0051 QSharedItemModel m_pModelPtr { }; 0052 QAbstractItemModel *m_pRawModel {nullptr}; 0053 QQmlComponent *m_pDelegate {nullptr}; 0054 Viewport *m_pViewport {nullptr}; 0055 SelectionAdapter *m_pSelectionManager {nullptr}; 0056 ViewBase *m_pView {nullptr}; 0057 ContextAdapterFactory *m_pRoleContextFactory {nullptr}; 0058 0059 bool m_Collapsable {true }; 0060 bool m_AutoExpand {false}; 0061 int m_MaxDepth { -1 }; 0062 int m_CacheBuffer { 10 }; 0063 int m_PoolSize { 10 }; 0064 0065 int m_ExpandedCount { 999 }; //TODO 0066 0067 ModelAdapter::RecyclingMode m_RecyclingMode { 0068 ModelAdapter::RecyclingMode::NoRecycling 0069 }; 0070 0071 // Helpers 0072 void setModelCommon(QAbstractItemModel* m, QAbstractItemModel* old); 0073 0074 ModelAdapter *q_ptr; 0075 0076 public Q_SLOTS: 0077 void slotContentChanged(); 0078 void slotDestroyed(); 0079 }; 0080 0081 ModelAdapter::ModelAdapter(ViewBase* parent) : QObject(parent), 0082 d_ptr(new ModelAdapterPrivate()) 0083 { 0084 Q_ASSERT(parent); 0085 d_ptr->q_ptr = this; 0086 d_ptr->m_pView = parent; 0087 d_ptr->m_pSelectionManager = new SelectionAdapter(this); 0088 0089 selectionAdapter()->s_ptr->setView(parent); 0090 contextAdapterFactory()->addContextExtension(selectionAdapter()->contextExtension()); 0091 0092 selectionAdapter()->s_ptr->setViewport(d_ptr->m_pViewport = new Viewport(this)); 0093 0094 connect(d_ptr->m_pViewport, &Viewport::contentChanged, 0095 d_ptr, &ModelAdapterPrivate::slotContentChanged); 0096 } 0097 0098 ModelAdapter::~ModelAdapter() 0099 { 0100 delete d_ptr; 0101 } 0102 0103 QVariant ModelAdapter::model() const 0104 { 0105 switch(d_ptr->m_Mode) { 0106 case ModelAdapterPrivate::Mode::SMART_POINTER: 0107 return QVariant::fromValue(d_ptr->m_pModelPtr); 0108 case ModelAdapterPrivate::Mode::RAW: 0109 return QVariant::fromValue(d_ptr->m_pRawModel); 0110 case ModelAdapterPrivate::Mode::NONE: 0111 default: 0112 return {}; 0113 } 0114 } 0115 0116 void ModelAdapterPrivate::setModelCommon(QAbstractItemModel* m, QAbstractItemModel* old) 0117 { 0118 if (old) 0119 disconnect(old, &QObject::destroyed, this, &ModelAdapterPrivate::slotDestroyed); 0120 0121 q_ptr->selectionAdapter()->s_ptr->setModel(m); 0122 0123 if (auto f = m_pRoleContextFactory) 0124 f->setModel(m); 0125 0126 if (m) 0127 connect(m, &QObject::destroyed, this, &ModelAdapterPrivate::slotDestroyed); 0128 } 0129 0130 void ModelAdapter::setModel(const QVariant& var) 0131 { 0132 QSharedItemModel oldPtr; 0133 QAbstractItemModel* oldM = oldPtr ? oldPtr.data() : d_ptr->m_pRawModel; 0134 0135 if (d_ptr->m_pModelPtr) 0136 oldPtr = d_ptr->m_pModelPtr; 0137 0138 if (var.isNull()) { 0139 if ((!d_ptr->m_pRawModel) && (!d_ptr->m_pModelPtr)) 0140 return; 0141 0142 emit modelAboutToChange(nullptr, oldM); 0143 d_ptr->m_Mode = ModelAdapterPrivate::Mode::NONE; 0144 d_ptr->m_pRawModel = nullptr; 0145 d_ptr->m_pModelPtr = nullptr; 0146 d_ptr->setModelCommon(nullptr, oldM); 0147 emit modelChanged(nullptr, oldM); 0148 } 0149 else if (auto m = var.value<QSharedItemModel >()) { 0150 if (m == d_ptr->m_pModelPtr) 0151 return; 0152 0153 // Use .data() is "safe", this call holds a reference, but the user 0154 // users should "not" store it. Obviously they all will, but at least 0155 // they have to watch the signal and replace it in time. If they don't, 0156 // then it may crash but the bug is on the consumer side. 0157 emit modelAboutToChange(m.data(), oldM); 0158 d_ptr->m_Mode = ModelAdapterPrivate::Mode::SMART_POINTER; 0159 d_ptr->m_pRawModel = nullptr; 0160 d_ptr->m_pModelPtr = m; 0161 d_ptr->setModelCommon(m.data(), oldM); 0162 emit modelChanged(m.data(), oldM); 0163 0164 } 0165 else if (auto m = var.value<QAbstractItemModel*>()) { 0166 if (m == d_ptr->m_pRawModel) 0167 return; 0168 0169 emit modelAboutToChange(m, oldM); 0170 d_ptr->m_Mode = ModelAdapterPrivate::Mode::RAW; 0171 d_ptr->m_pRawModel = m; 0172 d_ptr->m_pModelPtr = nullptr; 0173 d_ptr->setModelCommon(m, oldPtr ? oldPtr.data() : oldM); 0174 emit modelChanged(m, oldM); 0175 } 0176 else { 0177 Q_ASSERT(false); 0178 qWarning() << "Cannot convert" << var << "to a model"; 0179 setModel({}); 0180 } 0181 } 0182 0183 void ModelAdapter::setDelegate(QQmlComponent* delegate) 0184 { 0185 if (delegate == d_ptr->m_pDelegate) 0186 return; 0187 0188 d_ptr->m_pDelegate = delegate; 0189 emit delegateChanged(delegate); 0190 0191 if (d_ptr->m_Mode != ModelAdapterPrivate::Mode::NONE && d_ptr->m_pViewport) { 0192 //FIXME handle this properly 0193 auto content = d_ptr->m_pViewport->s_ptr->m_pReflector; 0194 0195 content->modelTracker() 0196 << StateTracker::Model::Action::POPULATE 0197 << StateTracker::Model::Action::ENABLE; 0198 } 0199 } 0200 0201 QQmlComponent* ModelAdapter::delegate() const 0202 { 0203 return d_ptr->m_pDelegate; 0204 } 0205 0206 bool ModelAdapter::isEmpty() const 0207 { 0208 switch(d_ptr->m_Mode) { 0209 case ModelAdapterPrivate::Mode::SMART_POINTER: 0210 return d_ptr->m_pModelPtr->rowCount() == 0; 0211 case ModelAdapterPrivate::Mode::RAW: 0212 return d_ptr->m_pRawModel->rowCount() == 0; 0213 case ModelAdapterPrivate::Mode::NONE: 0214 default: 0215 return true; 0216 } 0217 } 0218 0219 bool ModelAdapter::isCollapsable() const 0220 { 0221 return d_ptr->m_Collapsable; 0222 } 0223 0224 void ModelAdapter::setCollapsable(bool value) 0225 { 0226 d_ptr->m_Collapsable = value; 0227 } 0228 0229 bool ModelAdapter::isAutoExpand() const 0230 { 0231 return d_ptr->m_AutoExpand; 0232 } 0233 0234 void ModelAdapter::setAutoExpand(bool value) 0235 { 0236 d_ptr->m_AutoExpand = value; 0237 } 0238 0239 int ModelAdapter::maxDepth() const 0240 { 0241 return d_ptr->m_MaxDepth; 0242 } 0243 0244 void ModelAdapter::setMaxDepth(int depth) 0245 { 0246 d_ptr->m_MaxDepth = depth; 0247 } 0248 0249 int ModelAdapter::cacheBuffer() const 0250 { 0251 return d_ptr->m_CacheBuffer; 0252 } 0253 0254 void ModelAdapter::setCacheBuffer(int value) 0255 { 0256 d_ptr->m_CacheBuffer = std::min(1, value); 0257 } 0258 0259 int ModelAdapter::poolSize() const 0260 { 0261 return d_ptr->m_PoolSize; 0262 } 0263 0264 void ModelAdapter::setPoolSize(int value) 0265 { 0266 d_ptr->m_PoolSize = value; 0267 } 0268 0269 ModelAdapter::RecyclingMode ModelAdapter::recyclingMode() const 0270 { 0271 return d_ptr->m_RecyclingMode; 0272 } 0273 0274 void ModelAdapter::setRecyclingMode(ModelAdapter::RecyclingMode mode) 0275 { 0276 d_ptr->m_RecyclingMode = mode; 0277 } 0278 0279 void ModelAdapter::setSelectionAdapter(SelectionAdapter* v) 0280 { 0281 d_ptr->m_pSelectionManager = v; 0282 } 0283 0284 SelectionAdapter* ModelAdapter::selectionAdapter() const 0285 { 0286 return d_ptr->m_pSelectionManager; 0287 } 0288 0289 ContextAdapterFactory* ModelAdapter::contextAdapterFactory() const 0290 { 0291 if (!d_ptr->m_pRoleContextFactory) { 0292 d_ptr->m_pRoleContextFactory = new ContextAdapterFactory(); 0293 0294 if (auto m = rawModel()) 0295 d_ptr->m_pRoleContextFactory->setModel(m); 0296 } 0297 0298 return d_ptr->m_pRoleContextFactory; 0299 } 0300 0301 QVector<Viewport*> ModelAdapter::viewports() const 0302 { 0303 return {d_ptr->m_pViewport}; 0304 } 0305 0306 void ModelAdapterPrivate::slotContentChanged() 0307 { 0308 emit q_ptr->contentChanged(); 0309 } 0310 0311 void ModelAdapterPrivate::slotDestroyed() 0312 { 0313 q_ptr->setModel( 0314 QVariant::fromValue((QAbstractItemModel*)nullptr) 0315 ); 0316 } 0317 0318 QAbstractItemModel *ModelAdapter::rawModel() const 0319 { 0320 switch(d_ptr->m_Mode) { 0321 case ModelAdapterPrivate::Mode::SMART_POINTER: 0322 return d_ptr->m_pModelPtr.data(); 0323 case ModelAdapterPrivate::Mode::RAW: 0324 return d_ptr->m_pRawModel; 0325 case ModelAdapterPrivate::Mode::NONE: 0326 default: 0327 return nullptr; 0328 } 0329 } 0330 0331 ViewBase *ModelAdapter::view() const 0332 { 0333 return d_ptr->m_pView; 0334 } 0335 0336 bool ModelAdapter::isCollapsed() const 0337 { 0338 // Having no expanded elements allows some optimizations to kick-in such 0339 // as total size using multiplications when the size is uniform. 0340 return d_ptr->m_ExpandedCount == 0; 0341 } 0342 0343 #include <modeladapter.moc>