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"
25 #include <kmessagebox.h>
26 #include <ktemporaryfile.h>
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
)
62 , m_globalFunctions(0)
63 , m_globalVariables(0)
64 , m_filterDocument(0L)
65 , m_filterProject(true)
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
*)));
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()) {
93 void ClassModel::projectClosing(KDevelop::IProject
* project
)
95 foreach(const IndexedString
& file
, project
->fileSet()) {
101 ClassBrowserPlugin
* ClassModel::plugin() const {
102 return qobject_cast
<ClassBrowserPlugin
*>(QObject::parent());
105 ClassModel::~ClassModel()
110 void ClassModel::resetModel()
113 delete m_globalVariables
;
114 delete m_globalFunctions
;
115 m_codeModelObjects
.clear();
116 m_knownObjects
.clear();
127 void ClassModel::initialize()
129 foreach (KDevelop::IProject
* project
, ICore::self()->projectController()->projects())
130 projectOpened(project
);
133 void ClassModel::startLoading()
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()
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
;
167 void ClassModel::searchStringChanged(const QString
& string
)
169 //TODO improve efficiency
171 if (m_searchString
!= string
) {
172 m_searchString
= string
;
178 void ClassModel::setFilterByProject(bool filterByProject
)
180 if (m_filterProject
!= filterByProject
) {
181 m_filterProject
= filterByProject
;
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
))
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
))
202 if (!declaration
->identifier().toString().contains(m_searchString
, Qt::CaseInsensitive
))
208 int ClassModel::columnCount(const QModelIndex
& parent
) const
215 ClassModel::Node
* ClassModel::objectForIndex(const QModelIndex
& index
) const
217 if (!index
.isValid())
220 return static_cast<Node
*>(index
.internalPointer());
223 KDevelop::DUChainBasePointer
ClassModel::duObjectForIndex(const QModelIndex
& index
) const
225 Node
* n
= objectForIndex(index
);
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
];
243 ClassModel::Node
* ClassModel::objectForIdentifier(const KDevelop::QualifiedIdentifier
& identifier
) const
245 if (identifier
.isEmpty())
248 IndexedQualifiedIdentifier
id(identifier
);
250 if (!m_codeModelObjects
.contains(id
))
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());
264 if (!parentIndex
.isValid()) {
268 node
= objectForIndex(parentIndex
);
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
283 return QModelIndex();
286 return QModelIndex();
288 if (node
== m_topNode
)
289 return QModelIndex();
291 int row
= node
->parent()->children().indexOf(node
);
294 return createIndex(row
, 0, node
);
297 bool ClassModel::hasChildren(const QModelIndex
& parentIndex
) const
299 DUChainReadLocker
readLock(DUChain::lock());
301 Node
* parent
= objectForIndex(parentIndex
);
305 if (parent
->childrenDiscovered())
306 return !parent
->children().isEmpty();
308 if (parent
->kind() == CodeModelItem::Class
|| parent
->kind() == CodeModelItem::Namespace
)
314 int ClassModel::rowCount(const QModelIndex
& parentIndex
) const
316 Node
* parent
= objectForIndex(parentIndex
);
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
);
330 return QModelIndex();
332 return indexForObject(base
->parent());
335 int declarationScore(Declaration
* d
)
337 if (dynamic_cast<ClassFunctionDeclaration
*>(d
))
340 if (dynamic_cast<ClassMemberDeclaration
*>(d
))
343 if (dynamic_cast<AbstractFunctionDeclaration
*>(d
))
349 int typeScore(Declaration
* d
)
353 if (d
->kind() == Declaration::Instance
)
356 switch (d
->abstractType()->whichType()) {
357 case AbstractType::TypeIntegral
:
359 case AbstractType::TypePointer
:
361 case AbstractType::TypeReference
:
363 case AbstractType::TypeFunction
:
365 case AbstractType::TypeStructure
:
367 case AbstractType::TypeArray
:
369 case AbstractType::TypeDelayed
:
371 case AbstractType::TypeAbstract
:
380 int codeModelScore(ClassModel::Node
* n
)
383 case CodeModelItem::Namespace
:
385 case CodeModelItem::Class
:
387 case CodeModelItem::Function
:
389 case CodeModelItem::Variable
:
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
)
405 if (codeModelScore1
> codeModelScore2
)
408 if (codeModelScore1
== codeModelScore2
) {
409 switch (p1
->kind()) {
410 case CodeModelItem::Namespace
:
411 case CodeModelItem::Class
:
414 // Look up duchain info to see if they should be sorted on the basis of that first
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)
427 int declarationScore1, declarationScore2;
428 declarationScore1 = declarationScore( d );
429 declarationScore2 = declarationScore( d2 );
430 if (declarationScore1 < declarationScore2)
432 if (declarationScore1 > declarationScore2)
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)
443 else if (typeScore1 > typeScore2)
445 // else fallthrough intended
447 } // else fallthrough intended
452 if (d2->abstractType())
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);
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
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());
497 KDevelop::CodeModelItem::Kind
ClassModel::Node::kind() const
502 void ClassModel::Node::setKind(KDevelop::CodeModelItem::Kind kind
)
507 const KDevelop::DUChainBasePointer
& ClassModel::Node::duObject() const
512 void ClassModel::Node::setDuObject(KDevelop::DUChainBase
* object
)
517 void ClassModel::refreshNodes(const IndexedString
& file
, int level
, const QualifiedIdentifier
& from
) const
519 //kDebug() << file.str() << level << from.toString();
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
)
534 Node
* topParent
= m_topNode
;
535 switch (items
[a
].kind
) {
536 case CodeModelItem::Function
:
538 topParent
= m_globalFunctions
;
540 case CodeModelItem::Variable
:
542 topParent
= m_globalVariables
;
548 // Check if we already have this node
549 Node
* n
= objectForIdentifier(id
);
552 // We already have the relevant node.
553 //kDebug() << "Found preexisting node " << n->qualifiedIdentifier().toString();
557 QualifiedIdentifier qi
= id
.identifier();
558 if (level
> qi
.count()) {
559 //kDebug() << "Greater level than id count";
563 if (!from
.isEmpty() && !qi
.beginsWith(from
)) {
564 //kDebug() << "Does not begin with identifier of interest";
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
));
577 int newLevel
= level
;
578 for (int i
= level
- 1; i
> 0; --i
) {
579 n
= objectForIdentifier(qi
.left(i
));
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
);
595 newChild
->setKind(items
[a
].kind
);
597 n
->insertChild( newChild
, m_loading
? 0 : this);
599 //kDebug() << "Created node " << n->qualifiedIdentifier().toString();
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?
616 void ClassModel::refreshNode(Node
* node
, KDevelop::DUChainBase
* base
, QList
<Node
*>* resultChildren
) const
618 ENSURE_CHAIN_READ_LOCKED
622 bool childrenDiscovered
= node
->childrenDiscovered();
623 node
->setChildrenDiscovering();
625 if (childrenDiscovered
)
626 node
->resetEncounteredStatus();
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());
636 if (DUContext
* context
= contextForBase(base
)) {
637 if (!filterObject(context
)) {
638 switch (context
->type()) {
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
651 if (declaration
->identifier().isEmpty())
652 // Skip anonymous declarations
655 if (declaration
->kind() == Declaration::NamespaceAlias
)
656 // Skip importing declarations
659 Node
* newChild
= createPointer(declaration
, node
);
660 node
->insertChild(newChild
, childrenDiscovered
? this : 0);
662 if (newChild
->childrenDiscovered())
663 refreshNode(newChild
);
666 resultChildren
->append(newChild
);
671 /*case DUContext::Namespace: {
673 if (m_namespaces.contains(child->scopeIdentifier())) {
676 // TODO figure out what's going on here
677 ns = m_namespaces[child->scopeIdentifier()];
679 if (node->children().contains(ns))
683 ns = createPointer(child, node);
686 ns->addNamespaceContext(DUContextPointer(child));
688 node->insertChild(ns, childrenDiscovered ? this : 0);
690 if (ns->childrenDiscovered())
693 kDebug() << "Adding namespace " << child->scopeIdentifier() << " to list";
702 if (childrenDiscovered
) {
703 node
->removeStaleItems(this);
706 node
->sortChildren();
707 node
->setChildrenDiscovered();
711 void ClassModel::getDuObject(Node
* node
)
713 if (node
->duObject())
716 // Find the object from the symbol table
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
);
730 DUContext
* ClassModel::trueParent(DUContext
* parent
) const
732 ENSURE_CHAIN_READ_LOCKED
735 switch (parent
->type()) {
736 case DUContext::Class
:
737 case DUContext::Namespace
:
744 parent
= parent
->parentContext();
750 void ClassModel::branchAdded(DUContextPointer context
)
752 DUChainReadLocker
readLock(DUChain::lock());
755 branchAddedInternal(context
.data());
759 void ClassModel::branchAddedInternal(KDevelop::DUContext
* context
)
761 Node
* node
= pointer(trueParent(context
->parentContext()));
764 node
= objectForIdentifier(context
->scopeIdentifier(true));
766 if (node
&& node
->childrenDiscovered())
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());
776 Node
* node
= pointer(trueParent(context
->parentContext()));
779 node
= objectForIdentifier(context
->scopeIdentifier(true));
781 if (node
&& node
->childrenDiscovered())
786 void ClassModel::branchRemoved(DUContextPointer context
, DUContextPointer parentContext
)
789 DUChainReadLocker
readLock(DUChain::lock());
792 Node
* parent
= pointer(trueParent(parentContext
.data()));
795 parent
= objectForIdentifier(parentContext
->scopeIdentifier(true));
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
);
807 m_topLists
.remove(context
.data());
812 if (!parent
->childrenDiscovered())
813 // The parent node is not yet discovered, it will be figured out later if needed
816 Q_ASSERT(parent
->parent());
817 parent
->removeChild(parent
, this);
822 ClassModel::Node
* ClassModel::pointer(DUChainBase
* object
) const
826 if (object
&&m_knownObjects
.contains(object
))
827 ret
= m_knownObjects
[object
];
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
);
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
857 if (!m_knownObjects
.contains(object
)) {
858 ret
= new Node(object
, parent
);
859 m_knownObjects
.insert(object
, ret
);
862 ret
= m_knownObjects
[object
];
868 QVariant
ClassModel::data(const QModelIndex
& index
, int role
) const
870 if (!index
.isValid())
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());
884 DUChainBase
* base
= node
->duObject().data();
887 if (DUContext
* context
= dynamic_cast<DUContext
*>(base
)) {
888 switch (context
->type()) {
889 case DUContext::Namespace
:
891 case Qt::DisplayRole
:
892 return context
->localScopeIdentifier().toString();
893 case Qt::DecorationRole
:
894 return KIcon("namespace");
901 } else if (Declaration
* dec
= dynamic_cast<Declaration
*>(base
)) {
903 case Qt::DisplayRole
: {
904 bool fullScope
= false;
905 if(dynamic_cast<FunctionDefinition
*>(dec
)) {
906 Declaration
* decl
= static_cast<FunctionDefinition
*>(dec
)->declaration();
915 ret
= dec
->identifier().toString();
917 ret
= dec
->qualifiedIdentifier().toString();
919 if (FunctionType::Ptr type
= dec
->type
<FunctionType
>())
920 ret
+= type
->partToString(FunctionType::SignatureArguments
);
923 case Qt::DecorationRole
:
924 return DUChainUtils::iconForDeclaration(dec
);
929 case Qt::DisplayRole
:
930 return i18n("Unknown object!");
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");
957 Declaration
* ClassModel::declarationForObject(const DUChainBasePointer
& pointer
) const
959 ENSURE_CHAIN_READ_LOCKED
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();
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();
977 return context
->owner();
983 Declaration
* ClassModel::definitionForObject(const DUChainBasePointer
& pointer
) const
985 ENSURE_CHAIN_READ_LOCKED
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
);
998 } else if (DUContext
* context
= dynamic_cast<DUContext
*>(pointer
.data())) {
999 if (context
->owner()) {
1000 if(context
->owner()->isDefinition())
1001 return context
->owner();
1003 if(FunctionDefinition::definition(context
->owner()))
1004 return FunctionDefinition::definition(context
->owner());
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;
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
);
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);
1036 const_cast<ClassModel
*>(model
)->endInsertRows();
1039 void ClassModel::Node::removeChild(Node
* node
, const ClassModel
* model
)
1041 int index
= m_children
.indexOf(node
);
1046 const_cast<ClassModel
*>(model
)->beginRemoveRows(model
->indexForObject(this), index
, index
);
1048 m_children
.removeAt(index
);
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
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
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
))
1091 if (Declaration
* declaration
= dynamic_cast<Declaration
*>(base
))
1092 if (declaration
->internalContext())
1093 if (declaration
->internalContext()->type() == DUContext::Class
)
1094 return declaration
->internalContext();
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());
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
)
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
*>();
1148 ClassModel::Node::Node(const KDevelop::Identifier
& id
, Node
* parent
)
1150 , m_childrenEncountered(0)
1151 , m_kind(CodeModelItem::Unknown
)
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
)
1162 , m_childrenEncountered(0)
1163 , m_kind(CodeModelItem::Unknown
)
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) {
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
);
1222 return qMakePair(static_cast<Node
*>(0), static_cast<DUChainBase
*>(0));