File indexing completed on 2024-05-12 04:37:37

0001 /*
0002     SPDX-FileCopyrightText: 2008 Vladimir Prus <ghost@cs.msu.su>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "treemodel.h"
0008 
0009 #include <iostream>
0010 
0011 #include "treeitem.h"
0012 
0013 using namespace KDevelop;
0014 
0015 class KDevelop::TreeModelPrivate
0016 {
0017 public:
0018     explicit TreeModelPrivate(const QVector<QString>& headers)
0019         : headers(headers)
0020     {
0021     }
0022 
0023     QVector<QString> headers;
0024     TreeItem* root = nullptr;
0025 };
0026 
0027 TreeModel::TreeModel(const QVector<QString>& headers,
0028                      QObject *parent)
0029   : QAbstractItemModel(parent)
0030   , d_ptr(new TreeModelPrivate(headers))
0031 {
0032 }
0033 
0034 void TreeModel::setRootItem(TreeItem *item)
0035 {
0036     Q_D(TreeModel);
0037 
0038     d->root = item;
0039     d->root->fetchMoreChildren();
0040 }
0041 
0042 TreeModel::~TreeModel()
0043 {
0044     Q_D(TreeModel);
0045 
0046     delete d->root;
0047 }
0048 
0049 int TreeModel::columnCount(const QModelIndex &parent) const
0050 {
0051     Q_D(const TreeModel);
0052 
0053     Q_UNUSED(parent);
0054     return d->headers.size();
0055 }
0056 
0057 QVariant TreeModel::data(const QModelIndex &index, int role) const
0058 {
0059     if (!index.isValid())
0060         return QVariant();
0061 
0062     auto *item = static_cast<TreeItem*>(index.internalPointer());
0063     if (role == ItemRole)
0064         return QVariant::fromValue(item);
0065 
0066     return item->data(index.column(), role);
0067 }
0068 
0069 Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
0070 {
0071     if (!index.isValid())
0072         return Qt::NoItemFlags;
0073 
0074     return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
0075 }
0076 
0077 QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
0078                                int role) const
0079 {
0080     Q_D(const TreeModel);
0081 
0082     if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
0083         return d->headers.value(section);
0084 
0085     return QVariant();
0086 }
0087 
0088 QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent)
0089     const
0090 {
0091     Q_D(const TreeModel);
0092 
0093     if (!hasIndex(row, column, parent))
0094         return QModelIndex();
0095 
0096     TreeItem *parentItem;
0097 
0098     if (!parent.isValid())
0099         parentItem = d->root;
0100     else
0101         parentItem = static_cast<TreeItem*>(parent.internalPointer());
0102 
0103     TreeItem *childItem = parentItem->child(row);
0104     if (childItem)
0105         return createIndex(row, column, childItem);
0106     else
0107         return createIndex(row, column, nullptr);
0108 }
0109 
0110 QModelIndex TreeModel::parent(const QModelIndex &index) const
0111 {
0112     Q_D(const TreeModel);
0113 
0114     if (!index.isValid())
0115         return QModelIndex();
0116 
0117     auto *childItem = static_cast<TreeItem*>(index.internalPointer());
0118     TreeItem *parentItem = childItem->parent();
0119 
0120     if (parentItem == d->root)
0121         return QModelIndex();
0122 
0123     return createIndex(parentItem->row(), 0, parentItem);
0124 }
0125 
0126 int TreeModel::rowCount(const QModelIndex &parent) const
0127 {
0128     Q_D(const TreeModel);
0129 
0130     TreeItem *parentItem;
0131     if (parent.column() > 0)
0132         return 0;
0133 
0134     if (!parent.isValid())
0135         parentItem = d->root;
0136     else
0137         parentItem = static_cast<TreeItem*>(parent.internalPointer());
0138 
0139     if(parentItem)
0140         return parentItem->childCount();
0141     else
0142         return 0;
0143 }
0144 
0145 TreeItem* TreeModel::itemForIndex(const QModelIndex& index) const
0146 {
0147     Q_D(const TreeModel);
0148 
0149     if (!index.isValid())
0150         return d->root;
0151     else
0152         return static_cast<TreeItem*>(index.internalPointer());
0153 }
0154 
0155 QModelIndex TreeModel::indexForItem(TreeItem *item, int column) const
0156 {
0157     if (item->parent() == nullptr)
0158         return QModelIndex();
0159 
0160     if (TreeItem* parent = item->parent())
0161     {
0162         /* FIXME: we might store row directly in item.  */
0163         int row = parent->childItems.indexOf(item);
0164         Q_ASSERT(row != -1);
0165 
0166         return createIndex(row, column, item);
0167     }
0168     else
0169     {
0170         return QModelIndex();
0171     }
0172 }
0173 
0174 void TreeModel::expanded(const QModelIndex &index)
0175 {
0176     TreeItem* item = itemForIndex(index);
0177     QObject::connect(item, &TreeItem::allChildrenFetched, this, &TreeModel::itemChildrenReady);
0178     if (item->hasMore() && item->childCount() == 1)
0179         item->fetchMoreChildren();
0180     else
0181         emit itemChildrenReady();
0182     item->setExpanded(true);
0183 }
0184 
0185 void TreeModel::collapsed(const QModelIndex &index)
0186 {
0187     TreeItem* item = itemForIndex(index);
0188     item->setExpanded(false);
0189 }
0190 
0191 void TreeModel::clicked(const QModelIndex &index)
0192 {
0193     TreeItem* item = itemForIndex(index);
0194     item->clicked();
0195 }
0196 
0197 bool TreeModel::setData(const QModelIndex& index, const QVariant& value,
0198                         int role)
0199 {
0200     /* FIXME: CheckStateRole is dirty.  Should we pass the role to
0201        the item?  */
0202     if (index.isValid()
0203         && (role == Qt::EditRole || role == Qt::CheckStateRole))
0204     {
0205 
0206         auto *item = static_cast<TreeItem*>(index.internalPointer());
0207         item->setColumn(index.column(), value);
0208         return true;
0209     }
0210     return false;
0211 }
0212 
0213 KDevelop::TreeItem* KDevelop::TreeModel::root() const
0214 {
0215     Q_D(const TreeModel);
0216 
0217     return d->root;
0218 }
0219 
0220 #include "moc_treemodel.cpp"