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

0001 /*
0002     SPDX-FileCopyrightText: 2007-2008 Hamish Rodda <rodda@kde.org>
0003     SPDX-FileCopyrightText: 2009 Lior Mualem <lior.m.kde@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "classmodel.h"
0009 #include "classmodelnode.h"
0010 #include "allclassesfolder.h"
0011 #include "projectfolder.h"
0012 #include "../duchain/declaration.h"
0013 #include <typeinfo>
0014 
0015 #include "../../interfaces/icore.h"
0016 #include "../../interfaces/iproject.h"
0017 #include "../../interfaces/iprojectcontroller.h"
0018 
0019 using namespace KDevelop;
0020 using namespace ClassModelNodes;
0021 
0022 //////////////////////////////////////////////////////////////////////////////
0023 //////////////////////////////////////////////////////////////////////////////
0024 
0025 NodesModelInterface::~NodesModelInterface()
0026 {
0027 }
0028 
0029 //////////////////////////////////////////////////////////////////////////////
0030 //////////////////////////////////////////////////////////////////////////////
0031 
0032 ClassModel::ClassModel()
0033     : m_features(NodesModelInterface::AllProjectsClasses |
0034         NodesModelInterface::BaseAndDerivedClasses |
0035         NodesModelInterface::ClassInternals)
0036 {
0037     m_topNode = new FolderNode(QStringLiteral("Top Node"), this);
0038 
0039     if (features().testFlag(NodesModelInterface::AllProjectsClasses)) {
0040         m_allClassesNode = new FilteredAllClassesFolder(this);
0041         m_topNode->addNode(m_allClassesNode);
0042     }
0043 
0044     connect(ICore::self()->projectController(), &IProjectController::projectClosing,
0045             this, &ClassModel::removeProjectNode);
0046     connect(ICore::self()->projectController(), &IProjectController::projectOpened,
0047             this, &ClassModel::addProjectNode);
0048 
0049     const auto projects = ICore::self()->projectController()->projects();
0050     for (IProject* project : projects) {
0051         addProjectNode(project);
0052     }
0053 }
0054 
0055 ClassModel::~ClassModel()
0056 {
0057     delete m_topNode;
0058 }
0059 
0060 void ClassModel::updateFilterString(const QString& a_newFilterString)
0061 {
0062     m_allClassesNode->updateFilterString(a_newFilterString);
0063     for (ClassModelNodes::FilteredProjectFolder* folder : qAsConst(m_projectNodes)) {
0064         folder->updateFilterString(a_newFilterString);
0065     }
0066 }
0067 
0068 void ClassModel::collapsed(const QModelIndex& index)
0069 {
0070     Node* node = static_cast<Node*>(index.internalPointer());
0071 
0072     node->collapse();
0073 }
0074 
0075 void ClassModel::expanded(const QModelIndex& index)
0076 {
0077     Node* node = static_cast<Node*>(index.internalPointer());
0078 
0079     node->expand();
0080 }
0081 
0082 QFlags<Qt::ItemFlag> ClassModel::flags(const QModelIndex&) const
0083 {
0084     return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
0085 }
0086 
0087 int ClassModel::rowCount(const QModelIndex& parent) const
0088 {
0089     Node* node = m_topNode;
0090 
0091     if (parent.isValid())
0092         node = static_cast<Node*>(parent.internalPointer());
0093 
0094     return node->children().size();
0095 }
0096 
0097 QVariant ClassModel::data(const QModelIndex& index, int role) const
0098 {
0099     if (!index.isValid())
0100         return QVariant();
0101 
0102     Node* node = static_cast<Node*>(index.internalPointer());
0103 
0104     if (role == Qt::DisplayRole)
0105         return node->displayName();
0106 
0107     if (role == Qt::DecorationRole) {
0108         QIcon icon = node->cachedIcon();
0109         return icon.isNull() ? QVariant() : icon;
0110     }
0111 
0112     return QVariant();
0113 }
0114 
0115 QVariant ClassModel::headerData(int, Qt::Orientation, int role) const
0116 {
0117     if (role == Qt::DisplayRole)
0118         return QStringLiteral("Class");
0119 
0120     return QVariant();
0121 }
0122 
0123 int ClassModel::columnCount(const QModelIndex&) const
0124 {
0125     return 1;
0126 }
0127 
0128 bool ClassModel::hasChildren(const QModelIndex& parent) const
0129 {
0130     if (!parent.isValid())
0131         return true;
0132 
0133     Node* node = static_cast<Node*>(parent.internalPointer());
0134 
0135     return node->hasChildren();
0136 }
0137 
0138 QModelIndex ClassModel::index(int row, int column, const QModelIndex& parent) const
0139 {
0140     if (row < 0 || column != 0)
0141         return QModelIndex();
0142 
0143     Node* node = m_topNode;
0144     if (parent.isValid())
0145         node = static_cast<Node*>(parent.internalPointer());
0146 
0147     if (row >= node->children().size())
0148         return QModelIndex();
0149 
0150     return index(node->children()[row]);
0151 }
0152 
0153 QModelIndex ClassModel::parent(const QModelIndex& childIndex) const
0154 {
0155     if (!childIndex.isValid())
0156         return QModelIndex();
0157 
0158     Node* childNode = static_cast<Node*>(childIndex.internalPointer());
0159 
0160     if (childNode->parent() == m_topNode)
0161         return QModelIndex();
0162 
0163     return index(childNode->parent());
0164 }
0165 
0166 QModelIndex ClassModel::index(ClassModelNodes::Node* a_node) const
0167 {
0168     if (!a_node) {
0169         return QModelIndex();
0170     }
0171 
0172     // If no parent exists, we have an invalid index (root node or not part of a model).
0173     if (a_node->parent() == nullptr)
0174         return QModelIndex();
0175 
0176     return createIndex(a_node->row(), 0, a_node);
0177 }
0178 
0179 KDevelop::DUChainBase* ClassModel::duObjectForIndex(const QModelIndex& a_index)
0180 {
0181     if (!a_index.isValid())
0182         return nullptr;
0183 
0184     Node* node = static_cast<Node*>(a_index.internalPointer());
0185 
0186     if (auto* identifierNode = dynamic_cast<IdentifierNode*>(node))
0187         return identifierNode->declaration();
0188 
0189     // Non was found.
0190     return nullptr;
0191 }
0192 
0193 QModelIndex ClassModel::indexForIdentifier(const KDevelop::IndexedQualifiedIdentifier& a_id)
0194 {
0195     ClassNode* node = m_allClassesNode->findClassNode(a_id);
0196     if (node == nullptr)
0197         return QModelIndex();
0198 
0199     return index(node);
0200 }
0201 
0202 void ClassModel::nodesLayoutAboutToBeChanged(ClassModelNodes::Node*)
0203 {
0204     emit layoutAboutToBeChanged();
0205 }
0206 
0207 void ClassModel::nodesLayoutChanged(ClassModelNodes::Node*)
0208 {
0209     const QModelIndexList oldIndexList = persistentIndexList();
0210     QModelIndexList newIndexList;
0211 
0212     newIndexList.reserve(oldIndexList.size());
0213     for (const QModelIndex& oldIndex : oldIndexList) {
0214         Node* node = static_cast<Node*>(oldIndex.internalPointer());
0215         if (node) {
0216             // Re-map the index.
0217             newIndexList << createIndex(node->row(), 0, node);
0218         } else
0219             newIndexList << oldIndex;
0220     }
0221 
0222     changePersistentIndexList(oldIndexList, newIndexList);
0223 
0224     emit layoutChanged();
0225 }
0226 
0227 void ClassModel::nodesAboutToBeRemoved(ClassModelNodes::Node* a_parent, int a_first, int a_last)
0228 {
0229     beginRemoveRows(index(a_parent), a_first, a_last);
0230 }
0231 
0232 void ClassModel::nodesRemoved(ClassModelNodes::Node*)
0233 {
0234     endRemoveRows();
0235 }
0236 
0237 void ClassModel::nodesAboutToBeAdded(ClassModelNodes::Node* a_parent, int a_pos, int a_size)
0238 {
0239     beginInsertRows(index(a_parent), a_pos, a_pos + a_size - 1);
0240 }
0241 
0242 void ClassModel::nodesAdded(ClassModelNodes::Node*)
0243 {
0244     endInsertRows();
0245 }
0246 
0247 void ClassModel::addProjectNode(IProject* project)
0248 {
0249     m_projectNodes[project] = new ClassModelNodes::FilteredProjectFolder(this, project);
0250     nodesLayoutAboutToBeChanged(m_projectNodes[project]);
0251     m_topNode->addNode(m_projectNodes[project]);
0252     nodesLayoutChanged(m_projectNodes[project]);
0253 }
0254 
0255 void ClassModel::removeProjectNode(IProject* project)
0256 {
0257     m_topNode->removeNode(m_projectNodes[project]);
0258     m_projectNodes.remove(project);
0259 }
0260 
0261 #include "moc_classmodel.cpp"