QualifiedIdentifier has no left() so instead use mid().
[kdevelopdvcssupport.git] / plugins / classbrowser / classmodel.cpp
blobbd34eff591b0f37c9960fc6687e737d688cebd03
1 /*
2 * KDevelop Class Browser
4 * Copyright 2007-2008 Hamish Rodda <rodda@kde.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "classmodel.h"
24 #include <klocale.h>
25 #include <kmessagebox.h>
26 #include <ktemporaryfile.h>
27 #include <kprocess.h>
29 #include <QMap>
31 #include "interfaces/idocument.h"
32 #include "interfaces/icore.h"
33 #include "interfaces/ilanguagecontroller.h"
34 #include "interfaces/iprojectcontroller.h"
35 #include "interfaces/iproject.h"
37 #include "language/backgroundparser/backgroundparser.h"
38 #include "language/backgroundparser/parsejob.h"
40 #include "language/duchain/topducontext.h"
41 #include "language/duchain/classmemberdeclaration.h"
42 #include "language/duchain/classfunctiondeclaration.h"
43 #include "language/duchain/parsingenvironment.h"
44 #include "language/duchain/duchain.h"
45 #include "language/duchain/duchainlock.h"
46 #include "language/duchain/duchainutils.h"
47 #include "language/duchain/codemodel.h"
48 #include "language/duchain/types/functiontype.h"
49 #include "language/duchain/persistentsymboltable.h"
51 #include "classbrowserplugin.h"
52 #include <language/duchain/functiondefinition.h>
54 //#include "modeltest.h"
56 using namespace KTextEditor;
57 using namespace KDevelop;
59 ClassModel::ClassModel(ClassBrowserPlugin* parent)
60 : QAbstractItemModel(parent)
61 , m_topNode(0L)
62 , m_globalFunctions(0)
63 , m_globalVariables(0)
64 , m_filterDocument(0L)
65 , m_filterProject(true)
66 , m_loading(false)
68 //new ModelTest(this);
70 bool success = connect(DUChain::self()->notifier(), SIGNAL(branchAdded(KDevelop::DUContextPointer)), SLOT(branchAdded(KDevelop::DUContextPointer)), Qt::QueuedConnection);
71 success &= connect(DUChain::self()->notifier(), SIGNAL(branchModified(KDevelop::DUContextPointer)), SLOT(branchModified(KDevelop::DUContextPointer)), Qt::QueuedConnection);
73 success &= connect (ICore::self()->projectController(), SIGNAL(projectOpened(KDevelop::IProject*)), this, SLOT(projectOpened(KDevelop::IProject*)));
74 success &= connect (ICore::self()->projectController(), SIGNAL(projectClosing(KDevelop::IProject*)), this, SLOT(projectClosing(KDevelop::IProject*)));
76 resetModel();
78 Q_ASSERT(success);
80 kDebug() << "Class model initialized" << success;
83 void ClassModel::projectOpened(KDevelop::IProject* project)
85 // TODO Need to connect to signals which notify of files added or removed.
86 kDebug() << project->folder().prettyUrl();
88 foreach(const IndexedString& file, project->fileSet()) {
89 refreshNodes(file);
93 void ClassModel::projectClosing(KDevelop::IProject* project)
95 foreach(const IndexedString& file, project->fileSet()) {
96 //TODO
97 //fileRemoved(file);
101 ClassBrowserPlugin* ClassModel::plugin() const {
102 return qobject_cast<ClassBrowserPlugin*>(QObject::parent());
105 ClassModel::~ClassModel()
107 delete m_topNode;
110 void ClassModel::resetModel()
112 delete m_topNode;
113 delete m_globalVariables;
114 delete m_globalFunctions;
115 m_codeModelObjects.clear();
116 m_knownObjects.clear();
118 startLoading();
120 initialize();
122 finishLoading();
124 reset();
127 void ClassModel::initialize()
129 foreach (KDevelop::IProject* project, ICore::self()->projectController()->projects())
130 projectOpened(project);
133 void ClassModel::startLoading()
135 m_loading = true;
137 m_topNode = new Node(0, 0);
139 m_globalFunctions = new Node(Identifier(i18n("Global Functions")), m_topNode);
140 m_globalFunctions->setKind(CodeModelItem::Function);
141 m_globalFunctions->setSpecialNode();
142 m_topNode->insertChild(m_globalFunctions, 0);
144 m_globalVariables = new Node(Identifier(i18n("Global Variables")), m_topNode);
145 m_globalVariables->setKind(CodeModelItem::Variable);
146 m_globalVariables->setSpecialNode();
147 m_topNode->insertChild(m_globalVariables, 0);
150 void ClassModel::finishLoading()
152 m_loading = false;
154 m_topNode->sortChildren();
155 m_topNode->setChildrenDiscovered();
158 void ClassModel::setFilterDocument(KDevelop::IDocument* document)
160 if (m_filterDocument != document) {
161 m_filterProject = false;
162 m_filterDocument = document;
163 resetModel();
167 void ClassModel::searchStringChanged(const QString& string)
169 //TODO improve efficiency
170 #if 0
171 if (m_searchString != string) {
172 m_searchString = string;
173 resetModel();
175 #endif
178 void ClassModel::setFilterByProject(bool filterByProject)
180 if (m_filterProject != filterByProject) {
181 m_filterProject = filterByProject;
182 resetModel();
186 bool ClassModel::filterObject(DUChainBase* object) const
188 ENSURE_CHAIN_READ_LOCKED
190 //If the range is empty, it was probably created from a macro like Q_OBJECT
191 if(object->range().isEmpty() && dynamic_cast<Declaration*>(object))
192 return true;
194 KUrl url(object->url().str());
196 if (m_filterDocument)
197 return m_filterDocument && !(url == m_filterDocument->url());
199 if (!m_searchString.isEmpty())
200 if (Declaration* declaration = dynamic_cast<Declaration*>(object))
201 // TODO regexp?
202 if (!declaration->identifier().toString().contains(m_searchString, Qt::CaseInsensitive))
203 return true;
205 return false;
208 int ClassModel::columnCount(const QModelIndex & parent) const
210 Q_UNUSED(parent);
212 return 1;
215 ClassModel::Node* ClassModel::objectForIndex(const QModelIndex& index) const
217 if (!index.isValid())
218 return m_topNode;
220 return static_cast<Node*>(index.internalPointer());
223 KDevelop::DUChainBasePointer ClassModel::duObjectForIndex(const QModelIndex& index) const
225 Node* n = objectForIndex(index);
227 if (n) {
228 getDuObject( n );
229 return n->duObject();
232 return KDevelop::DUChainBasePointer();
235 ClassModel::Node* ClassModel::objectForIdentifier(const KDevelop::IndexedQualifiedIdentifier& identifier) const
237 if (m_codeModelObjects.contains(identifier))
238 return m_codeModelObjects[identifier];
240 return 0;
243 ClassModel::Node* ClassModel::objectForIdentifier(const KDevelop::QualifiedIdentifier& identifier) const
245 if (identifier.isEmpty())
246 return 0;
248 IndexedQualifiedIdentifier id(identifier);
250 if (!m_codeModelObjects.contains(id))
251 return 0;
253 return m_codeModelObjects[id];
256 QModelIndex ClassModel::index(int row, int column, const QModelIndex & parentIndex) const
258 if (row < 0 || column < 0 || column > 0)
259 return QModelIndex();
261 DUChainReadLocker readLock(DUChain::lock());
263 Node* node;
264 if (!parentIndex.isValid()) {
265 node = m_topNode;
267 } else {
268 node = objectForIndex(parentIndex);
271 if (!node)
272 return QModelIndex();
274 if (row < discover(node)->children().count())
275 return createIndex(row, column, node->children().at(row));
277 return QModelIndex();
280 QModelIndex ClassModel::indexForObject(Node * node) const
282 if (!node)
283 return QModelIndex();
285 if (!node->parent())
286 return QModelIndex();
288 if (node == m_topNode)
289 return QModelIndex();
291 int row = node->parent()->children().indexOf(node);
292 Q_ASSERT(row != -1);
294 return createIndex(row, 0, node);
297 bool ClassModel::hasChildren(const QModelIndex& parentIndex) const
299 DUChainReadLocker readLock(DUChain::lock());
301 Node* parent = objectForIndex(parentIndex);
302 if (!parent)
303 return false;
305 if (parent->childrenDiscovered())
306 return !parent->children().isEmpty();
308 if (parent->kind() == CodeModelItem::Class || parent->kind() == CodeModelItem::Namespace)
309 return true;
311 return false;
314 int ClassModel::rowCount(const QModelIndex & parentIndex) const
316 Node* parent = objectForIndex(parentIndex);
317 if (!parent)
318 return 0;
320 return discover(parent)->children().count();
323 QModelIndex ClassModel::parent(const QModelIndex & index) const
325 if (!index.isValid())
326 return QModelIndex();
328 Node* base = objectForIndex(index);
329 if (!base)
330 return QModelIndex();
332 return indexForObject(base->parent());
335 int declarationScore(Declaration* d)
337 if (dynamic_cast<ClassFunctionDeclaration*>(d))
338 return 1;
340 if (dynamic_cast<ClassMemberDeclaration*>(d))
341 return 2;
343 if (dynamic_cast<AbstractFunctionDeclaration*>(d))
344 return 1;
346 return 0;
349 int typeScore(Declaration* d)
351 int ret = 0;
353 if (d->kind() == Declaration::Instance)
354 return 4;
356 switch (d->abstractType()->whichType()) {
357 case AbstractType::TypeIntegral:
358 ret += 2;
359 case AbstractType::TypePointer:
360 ret += 2;
361 case AbstractType::TypeReference:
362 ret += 2;
363 case AbstractType::TypeFunction:
364 ret += 1;
365 case AbstractType::TypeStructure:
366 ret += 0;
367 case AbstractType::TypeArray:
368 ret += 2;
369 case AbstractType::TypeDelayed:
370 ret += 3;
371 case AbstractType::TypeAbstract:
372 ret += 3;
373 default:
374 ret += 5;
377 return ret;
380 int codeModelScore(ClassModel::Node* n)
382 switch (n->kind()) {
383 case CodeModelItem::Namespace:
384 return 0;
385 case CodeModelItem::Class:
386 return 1;
387 case CodeModelItem::Function:
388 return 2;
389 case CodeModelItem::Variable:
390 return 3;
391 default:
392 return 4;
396 bool ClassModel::orderItems(ClassModel::Node* p1, ClassModel::Node* p2)
398 int codeModelScore1 = codeModelScore(p1);
399 int codeModelScore2 = codeModelScore(p2);
401 //kDebug() << p1->qualifiedIdentifier().toString() << p2->qualifiedIdentifier().toString() << codeModelScore1 << codeModelScore2;
403 if (codeModelScore1 < codeModelScore2)
404 return true;
405 if (codeModelScore1 > codeModelScore2)
406 return false;
408 if (codeModelScore1 == codeModelScore2) {
409 switch (p1->kind()) {
410 case CodeModelItem::Namespace:
411 case CodeModelItem::Class:
412 goto compareNames;
413 default:
414 // Look up duchain info to see if they should be sorted on the basis of that first
415 break;
419 /*if (Declaration* d = dynamic_cast<Declaration*>(p1->duObject().data())) {
420 if (Declaration* d2 = dynamic_cast<Declaration*>(p2->duObject().data())) {
421 if (d->kind() != d2->kind())
422 if (d->kind() == Declaration::Instance)
423 return false;
424 else
425 return true;
427 int declarationScore1, declarationScore2;
428 declarationScore1 = declarationScore( d );
429 declarationScore2 = declarationScore( d2 );
430 if (declarationScore1 < declarationScore2)
431 return true;
432 if (declarationScore1 > declarationScore2)
433 return false;
435 if (d->abstractType()) {
436 if (d2->abstractType()) {
437 if (d->abstractType() != d2->abstractType()) {
438 int typeScore1, typeScore2;
439 typeScore1 = typeScore(d);
440 typeScore2 = typeScore(d2);
441 if (typeScore1 < typeScore2)
442 return true;
443 else if (typeScore1 > typeScore2)
444 return false;
445 // else fallthrough intended
447 } // else fallthrough intended
448 } else {
449 return false;
451 } else {
452 if (d2->abstractType())
453 return false;
455 } else {
456 return true;
460 compareNames:
462 QString s1 = ClassModel::data(p1).toString();
463 QString s2 = ClassModel::data(p2).toString();
465 int result = QString::localeAwareCompare(s1, s2);
467 //kDebug() << "String compare" << result << (result < 0);
469 return result < 0;
472 void ClassModel::Node::addRelevantFile(const IndexedString& file)
474 m_relevantFiles.insert(file);
477 const QSet<KDevelop::IndexedString>& ClassModel::Node::relevantFiles() const
479 return m_relevantFiles;
482 const KDevelop::Identifier& ClassModel::Node::identifier() const
484 return m_id;
487 KDevelop::QualifiedIdentifier ClassModel::Node::qualifiedIdentifier() const
489 if (!parent() || isSpecialNode())
490 return KDevelop::QualifiedIdentifier();
492 KDevelop::QualifiedIdentifier id = parent() ? parent()->qualifiedIdentifier() : KDevelop::QualifiedIdentifier();
493 id.push(identifier());
494 return id;
497 KDevelop::CodeModelItem::Kind ClassModel::Node::kind() const
499 return m_kind;
502 void ClassModel::Node::setKind(KDevelop::CodeModelItem::Kind kind)
504 m_kind = kind;
507 const KDevelop::DUChainBasePointer& ClassModel::Node::duObject() const
509 return m_duobject;
512 void ClassModel::Node::setDuObject(KDevelop::DUChainBase* object)
514 m_duobject = object;
517 void ClassModel::refreshNodes(const IndexedString& file, int level, const QualifiedIdentifier& from) const
519 //kDebug() << file.str() << level << from.toString();
521 uint itemCount = 0;
522 const CodeModelItem* items;
524 CodeModel::self().items(file, itemCount, items);
526 for(uint a = 0; a < itemCount; ++a) {
527 IndexedQualifiedIdentifier id(items[a].id);
528 //kDebug() << "Node" << id.identifier().toString();
530 // Don't insert unknown or forward declarations into the class browser
531 if (items[a].kind == CodeModelItem::Unknown || items[a].kind == CodeModelItem::ForwardDeclaration)
532 continue;
534 Node* topParent = m_topNode;
535 switch (items[a].kind) {
536 case CodeModelItem::Function:
537 if (level == 1)
538 topParent = m_globalFunctions;
539 break;
540 case CodeModelItem::Variable:
541 if (level == 1)
542 topParent = m_globalVariables;
543 break;
544 default:
545 break;
548 // Check if we already have this node
549 Node* n = objectForIdentifier(id);
551 if (n) {
552 // We already have the relevant node.
553 //kDebug() << "Found preexisting node " << n->qualifiedIdentifier().toString();
554 continue;
556 } else {
557 QualifiedIdentifier qi = id.identifier();
558 if (level > qi.count()) {
559 //kDebug() << "Greater level than id count";
560 continue;
563 if (!from.isEmpty() && !qi.beginsWith(from)) {
564 //kDebug() << "Does not begin with identifier of interest";
565 continue;
568 bool isSubIdentifier = false;
569 if (level != qi.count()) {
570 //kDebug() << "Sub-identifier " << qi.left(level).toString();
571 isSubIdentifier = true;
573 n = objectForIdentifier(qi.mid(0,level));
576 if (!n) {
577 int newLevel = level;
578 for (int i = level - 1; i > 0; --i) {
579 n = objectForIdentifier(qi.left(i));
580 if (n) {
581 newLevel = i + 1;
582 break;
586 if (!n) {
587 n = topParent;
588 newLevel = 1;
591 // Found it, generate nodes up to this level
592 for (int i = newLevel; i <= level; ++i) {
593 Node* newChild = createPointer(qi.left(i), n);
594 if (i == level)
595 newChild->setKind(items[a].kind);
597 n->insertChild( newChild, m_loading ? 0 : this);
598 n = newChild;
599 //kDebug() << "Created node " << n->qualifiedIdentifier().toString();
602 } else {
603 //kDebug() << "Found sub-identifier node";
606 if (!n->relevantFiles().contains(file)) {
607 n->addRelevantFile( file );
608 if (n->childrenDiscovered())
609 // TODO may lead to too much refreshing?
610 refreshNode(n);
616 void ClassModel::refreshNode(Node* node, KDevelop::DUChainBase* base, QList<Node*>* resultChildren) const
618 ENSURE_CHAIN_READ_LOCKED
620 Q_ASSERT(node);
622 bool childrenDiscovered = node->childrenDiscovered();
623 node->setChildrenDiscovering();
625 if (childrenDiscovered)
626 node->resetEncounteredStatus();
628 if (!base) {
629 // Load objects from the code model
630 int level = node->depth();
631 foreach (const IndexedString& file, node->relevantFiles()) {
632 refreshNodes(file, level, node->qualifiedIdentifier());
635 } else {
636 if (DUContext* context = contextForBase(base)) {
637 if (!filterObject(context)) {
638 switch (context->type()) {
639 default:
640 case DUContext::Class:
641 // We only add the definitions, not the contexts
642 foreach (Declaration* declaration, context->localDeclarations())
643 declaration->identifier().isEmpty();
644 foreach (Declaration* declaration, context->localDeclarations()) {
645 if (!declaration->isForwardDeclaration() && !filterObject(declaration)) {
647 if (!m_filterDocument && dynamic_cast<FunctionDefinition*>(declaration))
648 // This is a definition, skip it
649 continue;
651 if (declaration->identifier().isEmpty())
652 // Skip anonymous declarations
653 continue;
655 if (declaration->kind() == Declaration::NamespaceAlias)
656 // Skip importing declarations
657 continue;
659 Node* newChild = createPointer(declaration, node);
660 node->insertChild(newChild, childrenDiscovered ? this : 0);
662 if (newChild->childrenDiscovered())
663 refreshNode(newChild);
665 if (resultChildren)
666 resultChildren->append(newChild);
669 break;
671 /*case DUContext::Namespace: {
672 Node* ns;
673 if (m_namespaces.contains(child->scopeIdentifier())) {
674 continue;
676 // TODO figure out what's going on here
677 ns = m_namespaces[child->scopeIdentifier()];
679 if (node->children().contains(ns))
680 break;
682 } else {
683 ns = createPointer(child, node);
686 ns->addNamespaceContext(DUContextPointer(child));
688 node->insertChild(ns, childrenDiscovered ? this : 0);
690 if (ns->childrenDiscovered())
691 refreshNode(ns);
693 kDebug() << "Adding namespace " << child->scopeIdentifier() << " to list";
695 break;
702 if (childrenDiscovered) {
703 node->removeStaleItems(this);
705 } else {
706 node->sortChildren();
707 node->setChildrenDiscovered();
711 void ClassModel::getDuObject(Node* node)
713 if (node->duObject())
714 return;
716 // Find the object from the symbol table
717 uint count;
718 const IndexedDeclaration* declarations;
719 PersistentSymbolTable::self().declarations(node->qualifiedIdentifier(), count, declarations);
721 for (uint i = 0; i < count; ++i) {
722 // Hrm, multiple declarations for a code model item? just get the first for now
723 if (Declaration* d = declarations[i].declaration()) {
724 node->setDuObject(d);
725 return;
730 DUContext* ClassModel::trueParent(DUContext* parent) const
732 ENSURE_CHAIN_READ_LOCKED
734 while (parent) {
735 switch (parent->type()) {
736 case DUContext::Class:
737 case DUContext::Namespace:
738 return parent;
740 default:
741 break;
744 parent = parent->parentContext();
747 return 0L;
750 void ClassModel::branchAdded(DUContextPointer context)
752 DUChainReadLocker readLock(DUChain::lock());
754 if (context) {
755 branchAddedInternal(context.data());
759 void ClassModel::branchAddedInternal(KDevelop::DUContext * context)
761 Node* node = pointer(trueParent(context->parentContext()));
763 if (!node)
764 node = objectForIdentifier(context->scopeIdentifier(true));
766 if (node && node->childrenDiscovered())
767 refreshNode(node);
768 // Else, the parent node is not yet discovered, it will be figured out later if needed
771 void ClassModel::branchModified(KDevelop::DUContextPointer context)
773 DUChainReadLocker readLock(DUChain::lock());
775 if (context) {
776 Node* node = pointer(trueParent(context->parentContext()));
778 if (!node)
779 node = objectForIdentifier(context->scopeIdentifier(true));
781 if (node && node->childrenDiscovered())
782 refreshNode(node);
786 void ClassModel::branchRemoved(DUContextPointer context, DUContextPointer parentContext)
788 #if 0
789 DUChainReadLocker readLock(DUChain::lock());
791 if (context) {
792 Node* parent = pointer(trueParent(parentContext.data()));
794 if (!parent)
795 parent = objectForIdentifier(parentContext->scopeIdentifier(true));
797 if (!parent) {
798 if (m_topLists.contains(context.data())) {
799 QList<Node*>* topList = m_topLists[context.data()];
800 foreach (Node* node, *topList) {
801 int index = topList->indexOf(node);
802 beginRemoveRows(QModelIndex(), index, index);
803 topList->removeAt(index);
804 endRemoveRows();
805 delete node;
807 m_topLists.remove(context.data());
808 delete topList;
812 if (!parent->childrenDiscovered())
813 // The parent node is not yet discovered, it will be figured out later if needed
814 return;
816 Q_ASSERT(parent->parent());
817 parent->removeChild(parent, this);
819 #endif
822 ClassModel::Node* ClassModel::pointer(DUChainBase* object) const
824 Node* ret = 0L;
826 if (object &&m_knownObjects.contains(object))
827 ret = m_knownObjects[object];
829 return ret;
832 ClassModel::Node* ClassModel::createPointer(const KDevelop::QualifiedIdentifier& id, Node* parent) const
834 IndexedQualifiedIdentifier iid = id;
836 if (m_codeModelObjects.contains(iid))
837 return m_codeModelObjects[iid];
839 Node* n = new Node(id.last(), parent);
840 m_codeModelObjects.insert(iid, n);
841 return n;
844 ClassModel::Node* ClassModel::createPointer(DUContext* context, Node* parent) const
846 ENSURE_CHAIN_READ_LOCKED
848 return createPointer(static_cast<DUChainBase*>(context), parent);
851 ClassModel::Node* ClassModel::createPointer(DUChainBase* object, Node* parent) const
853 ENSURE_CHAIN_READ_LOCKED
855 Node* ret;
857 if (!m_knownObjects.contains(object)) {
858 ret = new Node(object, parent);
859 m_knownObjects.insert(object, ret);
861 } else {
862 ret = m_knownObjects[object];
865 return ret;
868 QVariant ClassModel::data(const QModelIndex& index, int role) const
870 if (!index.isValid())
871 return QVariant();
873 Node* basep = objectForIndex(index);
874 return data(basep, role);
877 QVariant ClassModel::data(Node* node, int role)
879 // Don't retrieve the duchains where not required
880 if (node->duObject() || (node->kind() != CodeModelItem::Class || node->kind() != CodeModelItem::Namespace)) {
881 DUChainReadLocker readLock(DUChain::lock());
883 getDuObject(node);
884 DUChainBase* base = node->duObject().data();
886 if (base) {
887 if (DUContext* context = dynamic_cast<DUContext*>(base)) {
888 switch (context->type()) {
889 case DUContext::Namespace:
890 switch (role) {
891 case Qt::DisplayRole:
892 return context->localScopeIdentifier().toString();
893 case Qt::DecorationRole:
894 return KIcon("namespace");
897 default:
898 break;
901 } else if (Declaration* dec = dynamic_cast<Declaration*>(base)) {
902 switch (role) {
903 case Qt::DisplayRole: {
904 bool fullScope = false;
905 if(dynamic_cast<FunctionDefinition*>(dec)) {
906 Declaration* decl = static_cast<FunctionDefinition*>(dec)->declaration();
907 if(decl) {
908 dec = decl;
909 fullScope = true;
913 QString ret;
914 if(!fullScope)
915 ret = dec->identifier().toString();
916 else
917 ret = dec->qualifiedIdentifier().toString();
919 if (FunctionType::Ptr type = dec->type<FunctionType>())
920 ret += type->partToString(FunctionType::SignatureArguments);
921 return ret;
923 case Qt::DecorationRole:
924 return DUChainUtils::iconForDeclaration(dec);
927 } else {
928 switch (role) {
929 case Qt::DisplayRole:
930 return i18n("Unknown object!");
936 switch (role) {
937 case Qt::DisplayRole:
938 return node->identifier().toString();
939 case Qt::DecorationRole:
940 switch (node->kind()) {
941 case CodeModelItem::Namespace:
942 return KIcon("namespace");
943 case CodeModelItem::Class:
944 return KIcon("class");
945 default:
946 break;
948 default:
949 break;
953 return QVariant();
957 Declaration* ClassModel::declarationForObject(const DUChainBasePointer& pointer) const
959 ENSURE_CHAIN_READ_LOCKED
961 if (!pointer)
962 return 0L;
964 if (Declaration* declaration = dynamic_cast<Declaration*>(pointer.data())) {
966 if(FunctionDefinition* def = dynamic_cast<FunctionDefinition*>(declaration))
967 if(def->declaration())
968 return def->declaration();
970 return declaration;
972 } else if (DUContext* context = dynamic_cast<DUContext*>(pointer.data())) {
973 if (context->owner())
974 if(dynamic_cast<FunctionDefinition*>(context->owner()) && static_cast<FunctionDefinition*>(context->owner())->declaration())
975 return static_cast<FunctionDefinition*>(context->owner())->declaration();
976 else
977 return context->owner();
980 return 0L;
983 Declaration* ClassModel::definitionForObject(const DUChainBasePointer& pointer) const
985 ENSURE_CHAIN_READ_LOCKED
987 if (!pointer)
988 return 0L;
990 if (Declaration* d = dynamic_cast<Declaration*>(pointer.data())) {
991 if(!dynamic_cast<FunctionDefinition*>(d)) {
992 if(FunctionDefinition::definition(d))
993 return FunctionDefinition::definition(d);
994 else
995 return 0L;
997 return d;
998 } else if (DUContext* context = dynamic_cast<DUContext*>(pointer.data())) {
999 if (context->owner()) {
1000 if(context->owner()->isDefinition())
1001 return context->owner();
1002 else
1003 if(FunctionDefinition::definition(context->owner()))
1004 return FunctionDefinition::definition(context->owner());
1008 return 0L;
1011 void ClassModel::Node::insertChild(Node * node, const ClassModel * model)
1013 if (m_children.contains(node)) {
1014 if (m_childrenEncountered)
1015 (*m_childrenEncountered)[m_children.indexOf(node)] = true;
1016 return;
1019 int index = m_children.count();
1021 if (m_childrenDiscovered) {
1022 QList<Node*>::Iterator it = qUpperBound(m_children.begin(), m_children.end(), node, orderItems);
1024 if (it != m_children.end())
1025 index = m_children.indexOf(*it);
1028 if (model)
1029 const_cast<ClassModel*>(model)->beginInsertRows(model->indexForObject(this), index, index);
1031 m_children.insert(index, node);
1032 if (m_childrenEncountered)
1033 m_childrenEncountered->insert(index, true);
1035 if (model)
1036 const_cast<ClassModel*>(model)->endInsertRows();
1039 void ClassModel::Node::removeChild(Node * node, const ClassModel * model)
1041 int index = m_children.indexOf(node);
1042 if (index == -1)
1043 return;
1045 if (model)
1046 const_cast<ClassModel*>(model)->beginRemoveRows(model->indexForObject(this), index, index);
1048 m_children.removeAt(index);
1050 if (model)
1051 const_cast<ClassModel*>(model)->endRemoveRows();
1054 void ClassModel::Node::resetEncounteredStatus()
1056 // Top level node doesn't use this functionality, the class model coordinates this
1057 if (!m_parent)
1058 return;
1060 Q_ASSERT(!m_childrenEncountered);
1062 m_childrenEncountered = new QVector<bool>(m_children.count());
1065 void ClassModel::Node::removeStaleItems(const ClassModel * model)
1067 // Top level node doesn't use this functionality, the class model coordinates this
1068 if (!m_parent)
1069 return;
1071 Q_ASSERT(m_childrenEncountered);
1073 for (int i = m_childrenEncountered->count() - 1; i >= 0; --i)
1074 if (!m_childrenEncountered->at(i))
1075 removeChild(m_children[i], model);
1077 delete m_childrenEncountered;
1078 m_childrenEncountered = 0;
1081 void ClassModel::Node::setChildrenDiscovered(bool discovered)
1083 m_childrenDiscovered = discovered;
1086 KDevelop::DUContext * ClassModel::contextForBase(KDevelop::DUChainBase * base) const
1088 if (DUContext* context = dynamic_cast<DUContext*>(base))
1089 return context;
1091 if (Declaration* declaration = dynamic_cast<Declaration*>(base))
1092 if (declaration->internalContext())
1093 if (declaration->internalContext()->type() == DUContext::Class)
1094 return declaration->internalContext();
1096 return 0;
1099 ClassModel::Node::~ Node()
1101 qDeleteAll(m_children);
1102 delete m_childrenEncountered;
1105 ClassModel::Node* ClassModel::discover(Node * node) const
1107 if (!node->childrenDiscovering()) {
1108 DUChainReadLocker readLock(DUChain::lock());
1110 refreshNode(node);
1113 return node;
1117 #include "classmodel.moc"
1119 // kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; auto-insert-doxygen on
1121 ClassModel::Node * ClassModel::Node::findChild(KDevelop::DUChainBase * base) const
1123 foreach (Node* child, m_children)
1124 if (child->duObject().data() == base)
1125 return child;
1127 return 0;
1130 void ClassModel::Node::hideChildren()
1132 m_childrenHidden = true;
1135 void ClassModel::Node::showChildren()
1137 m_childrenHidden = false;
1140 QList< ClassModel::Node * > ClassModel::Node::children() const
1142 if (m_childrenHidden)
1143 return QList<Node*>();
1145 return m_children;
1148 ClassModel::Node::Node(const KDevelop::Identifier& id, Node* parent)
1149 : m_parent(parent)
1150 , m_childrenEncountered(0)
1151 , m_kind(CodeModelItem::Unknown)
1152 , m_id(id)
1153 , m_childrenDiscovering(false)
1154 , m_childrenDiscovered(false)
1155 , m_childrenHidden(false)
1156 , m_specialNode(false)
1160 ClassModel::Node::Node(KDevelop::DUChainBase * p, Node * parent)
1161 : m_parent(parent)
1162 , m_childrenEncountered(0)
1163 , m_kind(CodeModelItem::Unknown)
1164 , m_duobject(p)
1165 , m_childrenDiscovering(false)
1166 , m_childrenDiscovered(false)
1167 , m_childrenHidden(false)
1168 , m_specialNode(false)
1172 bool ClassModel::Node::isSpecialNode() const
1174 return m_specialNode;
1177 void ClassModel::Node::setSpecialNode()
1179 m_specialNode = true;
1182 void ClassModel::Node::sortChildren()
1184 qSort(m_children.begin(), m_children.end(), orderItems);
1187 QPair<ClassModel::Node*, DUChainBase*> ClassModel::firstKnownObjectForBranch(KDevelop::DUChainBase* base) const
1189 if (Node* n = pointer(base))
1190 return qMakePair(n, static_cast<DUChainBase*>(0));
1192 DUChainBase* oldBase = base;
1194 if (Declaration* declaration = dynamic_cast<Declaration*>(base))
1195 base = declaration->context();
1197 if (DUContext* context = dynamic_cast<DUContext*>(base)) {
1198 QualifiedIdentifier id = context->scopeIdentifier(true);
1200 while (id.count() > 1) {
1201 id.pop();
1203 QList<Declaration*> declarations = context->findDeclarations(id, base->range().start);
1204 foreach (Declaration* d, declarations)
1205 if (Node* n = pointer(d))
1206 return qMakePair(n, oldBase);
1208 QList<DUContext*> contexts = context->findContexts(DUContext::Class, id, base->range().start);
1209 foreach (DUContext* c, contexts)
1210 if (Node* n = pointer(c))
1211 return qMakePair(n, oldBase);
1213 contexts = context->findContexts(DUContext::Namespace, id, base->range().start);
1214 foreach (DUContext* c, contexts)
1215 if (Node* n = pointer(c))
1216 return qMakePair(n, oldBase);
1218 oldBase = context;
1222 return qMakePair(static_cast<Node*>(0), static_cast<DUChainBase*>(0));