qdoc: Removed several #if 0 blocks.
[profile/ivi/qtbase.git] / src / tools / qdoc / node.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the tools applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "node.h"
43 #include "tree.h"
44 #include "codemarker.h"
45 #include "codeparser.h"
46 #include <QUuid>
47 #include <qdebug.h>
48
49 QT_BEGIN_NAMESPACE
50
51 int Node::propertyGroupCount_ = 0;
52 ExampleNodeMap ExampleNode::exampleNodeMap;
53 QStringMap Node::operators_;
54
55 /*!
56   Increment the number of property groups seen in the current
57   file, and return the new value.
58  */
59 int Node::incPropertyGroupCount() { return ++propertyGroupCount_; }
60
61 /*!
62   Reset the number of property groups seen in the current file
63   to 0, because we are starting a new file.
64  */
65 void Node::clearPropertyGroupCount() { propertyGroupCount_ = 0; }
66
67 /*!
68   \class Node
69   \brief The Node class is a node in the Tree.
70
71   A Node represents a class or function or something else
72   from the source code..
73  */
74
75 /*!
76   When this Node is destroyed, if it has a parent Node, it
77   removes itself from the parent node's child list.
78  */
79 Node::~Node()
80 {
81     if (parent_)
82         parent_->removeChild(this);
83     if (relatesTo_)
84         relatesTo_->removeRelated(this);
85 }
86
87 /*!
88   Sets this Node's Doc to \a doc. If \a replace is false and
89   this Node already has a Doc, a warning is reported that the
90   Doc is being overridden, and it reports where the previous
91   Doc was found. If \a replace is true, the Doc is replaced
92   silently.
93  */
94 void Node::setDoc(const Doc& doc, bool replace)
95 {
96     if (!d.isEmpty() && !replace) {
97         doc.location().warning(tr("Overrides a previous doc"));
98         d.location().warning(tr("(The previous doc is here)"));
99     }
100     d = doc;
101 }
102
103 /*!
104   Construct a node with the given \a type and having the
105   given \a parent and \a name. The new node is added to the
106   parent's child list.
107  */
108 Node::Node(Type type, InnerNode *parent, const QString& name)
109     : nodeType_(type),
110       access_(Public),
111       safeness_(UnspecifiedSafeness),
112       pageType_(NoPageType),
113       status_(Commendable),
114       indexNodeFlag_(false),
115       parent_(parent),
116       relatesTo_(0),
117       name_(name)
118 {
119     if (parent_)
120         parent_->addChild(this);
121     outSubDir_ = CodeParser::currentOutputSubdirectory();
122     if (operators_.isEmpty()) {
123         operators_.insert("++","inc");
124         operators_.insert("--","dec");
125         operators_.insert("==","eq");
126         operators_.insert("!=","ne");
127         operators_.insert("<<","lt-lt");
128         operators_.insert(">>","gt-gt");
129         operators_.insert("+=","plus-assign");
130         operators_.insert("-=","minus-assign");
131         operators_.insert("*=","mult-assign");
132         operators_.insert("/=","div-assign");
133         operators_.insert("%=","mod-assign");
134         operators_.insert("&=","bitwise-and-assign");
135         operators_.insert("|=","bitwise-or-assign");
136         operators_.insert("^=","bitwise-xor-assign");
137         operators_.insert("<<=","bitwise-left-shift-assign");
138         operators_.insert(">>=","bitwise-right-shift-assign");
139         operators_.insert("||","logical-or");
140         operators_.insert("&&","logical-and");
141         operators_.insert("()","call");
142         operators_.insert("[]","subscript");
143         operators_.insert("->","pointer");
144         operators_.insert("->*","pointer-star");
145         operators_.insert("+","plus");
146         operators_.insert("-","minus");
147         operators_.insert("*","mult");
148         operators_.insert("/","div");
149         operators_.insert("%","mod");
150         operators_.insert("|","bitwise-or");
151         operators_.insert("&","bitwise-and");
152         operators_.insert("^","bitwise-xor");
153         operators_.insert("!","not");
154         operators_.insert("~","bitwise-not");
155         operators_.insert("<=","lt-eq");
156         operators_.insert(">=","gt-eq");
157         operators_.insert("<","lt");
158         operators_.insert(">","gt");
159         operators_.insert("=","assign");
160         operators_.insert(",","comma");
161         operators_.insert("delete[]","delete-array");
162         operators_.insert("delete","delete");
163         operators_.insert("new[]","new-array");
164         operators_.insert("new","new");
165     }
166 }
167
168 /*!
169   Returns the node's URL.
170  */
171 QString Node::url() const
172 {
173     return url_;
174 }
175
176 /*!
177   Sets the node's URL to \a url
178  */
179 void Node::setUrl(const QString &url)
180 {
181     url_ = url;
182 }
183
184 /*!
185   Returns this node's page type as a string, for use as an
186   attribute value in XML or HTML.
187  */
188 QString Node::pageTypeString() const
189 {
190     return pageTypeString(pageType_);
191 }
192
193 /*!
194   Returns the page type \a t as a string, for use as an
195   attribute value in XML or HTML.
196  */
197 QString Node::pageTypeString(unsigned t)
198 {
199     switch ((PageType)t) {
200     case Node::ApiPage:
201         return "api";
202     case Node::ArticlePage:
203         return "article";
204     case Node::ExamplePage:
205         return "example";
206     case Node::HowToPage:
207         return "howto";
208     case Node::OverviewPage:
209         return "overview";
210     case Node::TutorialPage:
211         return "tutorial";
212     case Node::FAQPage:
213         return "faq";
214     case Node::DitaMapPage:
215         return "ditamap";
216     default:
217         return "article";
218     }
219 }
220
221 /*!
222   Returns this node's type as a string for use as an
223   attribute value in XML or HTML.
224  */
225 QString Node::nodeTypeString() const
226 {
227     return nodeTypeString(type());
228 }
229
230 /*!
231   Returns the node type \a t as a string for use as an
232   attribute value in XML or HTML.
233  */
234 QString Node::nodeTypeString(unsigned t)
235 {
236     switch ((Type)t) {
237     case Namespace:
238         return "namespace";
239     case Class:
240         return "class";
241     case Fake:
242         return "fake";
243     case Enum:
244         return "enum";
245     case Typedef:
246         return "typedef";
247     case Function:
248         return "function";
249     case Property:
250         return "property";
251     case Variable:
252         return "variable";
253     case QmlProperty:
254         return "QML property";
255     case QmlSignal:
256         return "QML signal";
257     case QmlSignalHandler:
258         return "QML signal handler";
259     case QmlMethod:
260         return "QML method";
261     default:
262         break;
263     }
264     return QString();
265 }
266
267 /*!
268   Returns this node's subtype as a string for use as an
269   attribute value in XML or HTML. This is only useful
270   in the case where the node type is Fake.
271  */
272 QString Node::nodeSubtypeString() const
273 {
274     return nodeSubtypeString(subType());
275 }
276
277 /*!
278   Returns the node subtype \a t as a string for use as an
279   attribute value in XML or HTML. This is only useful
280   in the case where the node type is Fake.
281  */
282 QString Node::nodeSubtypeString(unsigned t)
283 {
284     switch ((SubType)t) {
285     case Example:
286         return "example";
287     case HeaderFile:
288         return "header file";
289     case File:
290         return "file";
291     case Image:
292         return "image";
293     case Group:
294         return "group";
295     case Module:
296         return "module";
297     case Page:
298         return "page";
299     case ExternalPage:
300         return "external page";
301     case QmlClass:
302         return "QML class";
303     case QmlPropertyGroup:
304         return "QML property group";
305     case QmlBasicType:
306         return "QML basic type";
307     case QmlModule:
308         return "QML module";
309     case DitaMap:
310         return "ditamap";
311     case Collision:
312         return "collision";
313     case NoSubType:
314     default:
315         break;
316     }
317     return QString();
318 }
319
320 /*!
321   Set the page type according to the string \a t.
322  */
323 void Node::setPageType(const QString& t)
324 {
325     if ((t == "API") || (t == "api"))
326         pageType_ = ApiPage;
327     else if (t == "howto")
328         pageType_ = HowToPage;
329     else if (t == "overview")
330         pageType_ = OverviewPage;
331     else if (t == "tutorial")
332         pageType_ = TutorialPage;
333     else if (t == "howto")
334         pageType_ = HowToPage;
335     else if (t == "article")
336         pageType_ = ArticlePage;
337     else if (t == "example")
338         pageType_ = ExamplePage;
339     else if (t == "ditamap")
340         pageType_ = DitaMapPage;
341 }
342
343 /*! Converts the boolean value \a b to an enum representation
344   of the boolean type, which includes an enum value for the
345   \e {default value} of the item, i.e. true, false, or default.
346  */
347 Node::FlagValue Node::toFlagValue(bool b)
348 {
349     return b ? FlagValueTrue : FlagValueFalse;
350 }
351
352 /*!
353   Converts the enum \a fv back to a boolean value.
354   If \a fv is neither the true enum value nor the
355   false enum value, the boolean value returned is
356   \a defaultValue.
357
358   Note that runtimeDesignabilityFunction() should be called
359   first. If that function returns the name of a function, it
360   means the function must be called at runtime to determine
361   whether the property is Designable.
362  */
363 bool Node::fromFlagValue(FlagValue fv, bool defaultValue)
364 {
365     switch (fv) {
366     case FlagValueTrue:
367         return true;
368     case FlagValueFalse:
369         return false;
370     default:
371         return defaultValue;
372     }
373 }
374
375 /*!
376   Sets the pointer to the node that this node relates to.
377  */
378 void Node::setRelates(InnerNode *pseudoParent)
379 {
380     if (relatesTo_) {
381         relatesTo_->removeRelated(this);
382     }
383     relatesTo_ = pseudoParent;
384     pseudoParent->related_.append(this);
385 }
386
387 /*!
388   This function creates a pair that describes a link.
389   The pair is composed from \a link and \a desc. The
390   \a linkType is the map index the pair is filed under.
391  */
392 void Node::setLink(LinkType linkType, const QString &link, const QString &desc)
393 {
394     QPair<QString,QString> linkPair;
395     linkPair.first = link;
396     linkPair.second = desc;
397     linkMap[linkType] = linkPair;
398 }
399
400 /*!
401     Sets the information about the project and version a node was introduced
402     in. The string is simplified, removing excess whitespace before being
403     stored.
404 */
405 void Node::setSince(const QString &since)
406 {
407     sinc = since.simplified();
408 }
409
410 /*!
411   Returns a string representing the access specifier.
412  */
413 QString Node::accessString() const
414 {
415     switch (access_) {
416     case Protected:
417         return "protected";
418     case Private:
419         return "private";
420     case Public:
421     default:
422         break;
423     }
424     return "public";
425 }
426
427 /*!
428   Extract a class name from the type \a string and return it.
429  */
430 QString Node::extractClassName(const QString &string) const
431 {
432     QString result;
433     for (int i=0; i<=string.size(); ++i) {
434         QChar ch;
435         if (i != string.size())
436             ch = string.at(i);
437
438         QChar lower = ch.toLower();
439         if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) ||
440                 ch.digitValue() >= 0 ||
441                 ch == QLatin1Char('_') ||
442                 ch == QLatin1Char(':')) {
443             result += ch;
444         }
445         else if (!result.isEmpty()) {
446             if (result != QLatin1String("const"))
447                 return result;
448             result.clear();
449         }
450     }
451     return result;
452 }
453
454 /*!
455   Returns a string representing the access specifier.
456  */
457 QString RelatedClass::accessString() const
458 {
459     switch (access) {
460     case Node::Protected:
461         return "protected";
462     case Node::Private:
463         return "private";
464     case Node::Public:
465     default:
466         break;
467     }
468     return "public";
469 }
470
471 /*!
472   Returns the inheritance status.
473  */
474 Node::Status Node::inheritedStatus() const
475 {
476     Status parentStatus = Commendable;
477     if (parent_)
478         parentStatus = parent_->inheritedStatus();
479     return (Status)qMin((int)status_, (int)parentStatus);
480 }
481
482 /*!
483   Returns the thread safeness value for whatever this node
484   represents. But if this node has a parent and the thread
485   safeness value of the parent is the same as the thread
486   safeness value of this node, what is returned is the
487   value \c{UnspecifiedSafeness}. Why?
488  */
489 Node::ThreadSafeness Node::threadSafeness() const
490 {
491     if (parent_ && safeness_ == parent_->inheritedThreadSafeness())
492         return UnspecifiedSafeness;
493     return safeness_;
494 }
495
496 /*!
497   If this node has a parent, the parent's thread safeness
498   value is returned. Otherwise, this node's thread safeness
499   value is returned. Why?
500  */
501 Node::ThreadSafeness Node::inheritedThreadSafeness() const
502 {
503     if (parent_ && safeness_ == UnspecifiedSafeness)
504         return parent_->inheritedThreadSafeness();
505     return safeness_;
506 }
507
508 /*!
509   Returns the sanitized file name without the path.
510   If the the file is an html file, the html suffix
511   is removed. Why?
512  */
513 QString Node::fileBase() const
514 {
515     QString base = name();
516     if (base.endsWith(".html"))
517         base.chop(5);
518     base.replace(QRegExp("[^A-Za-z0-9]+"), " ");
519     base = base.trimmed();
520     base.replace(QLatin1Char(' '), QLatin1Char('-'));
521     return base.toLower();
522 }
523
524 /*!
525   Returns this node's Universally Unique IDentifier as a
526   QString. Creates the UUID first, if it has not been created.
527  */
528 QString Node::guid() const
529 {
530     if (uuid_.isEmpty())
531         uuid_ = idForNode();
532     return uuid_;
533 }
534
535 /*!
536   Composes a string to be used as an href attribute in DITA
537   XML. It is composed of the file name and the UUID separated
538   by a '#'. If this node is a class node, the file name is
539   taken from this node; if this node is a function node, the
540   file name is taken from the parent node of this node.
541  */
542 QString Node::ditaXmlHref()
543 {
544     QString href;
545     if ((type() == Function) ||
546             (type() == Property) ||
547             (type() == Variable)) {
548         href = parent()->fileBase();
549     }
550     else {
551         href = fileBase();
552     }
553     if (!href.endsWith(".xml") && !href.endsWith(".dita"))
554         href += ".dita";
555     return href + QLatin1Char('#') + guid();
556 }
557
558 /*!
559   If this node is a QML class node, return a pointer to it.
560   If it is a child of a QML class node, return a pointer to
561   the QML class node. Otherwise, return 0;
562  */
563 QmlClassNode* Node::qmlClassNode()
564 {
565     if (isQmlNode()) {
566         Node* n = this;
567         while (n && n->subType() != Node::QmlClass)
568             n = n->parent();
569         if (n && n->subType() == Node::QmlClass)
570             return static_cast<QmlClassNode*>(n);
571     }
572     return 0;
573 }
574
575 /*!
576   If this node is a QML node, find its QML class node,
577   and return a pointer to the C++ class node from the
578   QML class node. That pointer will be null if the QML
579   class node is a component. It will be non-null if
580   the QML class node is a QML element.
581  */
582 ClassNode* Node::declarativeCppNode()
583 {
584     QmlClassNode* qcn = qmlClassNode();
585     if (qcn)
586         return qcn->classNode();
587     return 0;
588 }
589
590 /*!
591   Returns true if the node's status is Internal, or if its
592   parent is a class with internal status.
593  */
594 bool Node::isInternal() const
595 {
596     if (status() == Internal)
597         return true;
598     if (parent() && parent()->status() == Internal)
599         return true;
600     if (relates() && relates()->status() == Internal)
601         return true;
602     return false;
603 }
604
605 /*!
606   \class InnerNode
607  */
608
609 /*!
610   The inner node destructor deletes the children and removes
611   this node from its related nodes.
612  */
613 InnerNode::~InnerNode()
614 {
615     deleteChildren();
616     removeFromRelated();
617 }
618
619 /*!
620   Find the node in this node's children that has the
621   given \a name. If this node is a QML class node, be
622   sure to also look in the children of its property
623   group nodes. Return the matching node or 0.
624  */
625 Node *InnerNode::findChildNodeByName(const QString& name)
626 {
627     Node *node = childMap.value(name);
628     if (node && node->subType() != QmlPropertyGroup)
629         return node;
630     if ((type() == Fake) && (subType() == QmlClass)) {
631         for (int i=0; i<children.size(); ++i) {
632             Node* n = children.at(i);
633             if (n->subType() == QmlPropertyGroup) {
634                 node = static_cast<InnerNode*>(n)->findChildNodeByName(name);
635                 if (node)
636                     return node;
637             }
638         }
639     }
640     return primaryFunctionMap.value(name);
641 }
642 void InnerNode::findNodes(const QString& name, QList<Node*>& n)
643 {
644     n.clear();
645     Node* node = 0;
646     QList<Node*> nodes = childMap.values(name);
647     /*
648       <sigh> If this node's child map contains no nodes named
649       name, then if this node is a QML class, seach each of its
650       property group nodes for a node named name. If a match is
651       found, append it to the output list and return immediately.
652      */
653     if (nodes.isEmpty()) {
654         if ((type() == Fake) && (subType() == QmlClass)) {
655             for (int i=0; i<children.size(); ++i) {
656                 node = children.at(i);
657                 if (node->subType() == QmlPropertyGroup) {
658                     node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
659                     if (node) {
660                         n.append(node);
661                         return;
662                     }
663                 }
664             }
665         }
666     }
667     else {
668         /*
669           If the childMap does contain one or more nodes named
670           name, traverse the list of matching nodes. Append each
671           matching node that is not a property group node to the
672           output list. Search each property group node for a node
673           named name and append that node to the output list.
674           This is overkill, I think, but should produce a useful
675           list.
676          */
677         for (int i=0; i<nodes.size(); ++i) {
678             node = nodes.at(i);
679             if (node->subType() != QmlPropertyGroup)
680                 n.append(node);
681             else {
682                 node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
683                 if (node)
684                     n.append(node);
685             }
686         }
687     }
688     if (!n.isEmpty())
689         return;
690     node = primaryFunctionMap.value(name);
691     if (node)
692         n.append(node);
693 }
694
695 /*!
696   Find the node in this node's children that has the given \a name. If
697   this node is a QML class node, be sure to also look in the children
698   of its property group nodes. Return the matching node or 0. This is
699   not a recearsive search.
700
701   If \a qml is true, only match a node for which node->isQmlNode()
702   returns true. If \a qml is false, only match a node for which
703   node->isQmlNode() returns false.
704  */
705 Node* InnerNode::findChildNodeByName(const QString& name, bool qml)
706 {
707     QList<Node*> nodes = childMap.values(name);
708     if (!nodes.isEmpty()) {
709         for (int i=0; i<nodes.size(); ++i) {
710             Node* node = nodes.at(i);
711             if (!qml) {
712                 if (!node->isQmlNode())
713                     return node;
714             }
715             else if (node->isQmlNode() && (node->subType() != QmlPropertyGroup))
716                 return node;
717         }
718     }
719     if (qml && (type() == Fake) && (subType() == QmlClass)) {
720         for (int i=0; i<children.size(); ++i) {
721             Node* node = children.at(i);
722             if (node->subType() == QmlPropertyGroup) {
723                 node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
724                 if (node)
725                     return node;
726             }
727         }
728     }
729     return primaryFunctionMap.value(name);
730 }
731
732 /*!
733   This function is like findChildNodeByName(), but if a node
734   with the specified \a name is found but it is not of the
735   specified \a type, 0 is returned.
736
737   This function is not recursive and therefore can't handle
738   collisions. If it finds a collision node named \a name, it
739   will return that node. But it might not find the collision
740   node because it looks up \a name in the child map, not the
741   list.
742  */
743 Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type)
744 {
745     if (type == Function)
746         return primaryFunctionMap.value(name);
747     else {
748         Node *node = childMap.value(name);
749         if (node && node->type() == type)
750             return node;
751     }
752     return 0;
753 }
754
755 /*!
756   Find a function node that is a child of this nose, such
757   that the function node has the specified \a name.
758  */
759 FunctionNode *InnerNode::findFunctionNode(const QString& name)
760 {
761     return static_cast<FunctionNode *>(primaryFunctionMap.value(name));
762 }
763
764 /*!
765   Find the function node that is a child of this node, such
766   that the function has the same name and signature as the
767   \a clone node.
768  */
769 FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone)
770 {
771     QMap<QString,Node*>::ConstIterator c = primaryFunctionMap.constFind(clone->name());
772     if (c != primaryFunctionMap.constEnd()) {
773         if (isSameSignature(clone, (FunctionNode *) *c)) {
774             return (FunctionNode *) *c;
775         }
776         else if (secondaryFunctionMap.contains(clone->name())) {
777             const NodeList& secs = secondaryFunctionMap[clone->name()];
778             NodeList::ConstIterator s = secs.constBegin();
779             while (s != secs.constEnd()) {
780                 if (isSameSignature(clone, (FunctionNode *) *s))
781                     return (FunctionNode *) *s;
782                 ++s;
783             }
784         }
785     }
786     return 0;
787 }
788
789 /*!
790   Returns the list of keys from the primary function map.
791  */
792 QStringList InnerNode::primaryKeys()
793 {
794     QStringList t;
795     QMap<QString, Node*>::iterator i = primaryFunctionMap.begin();
796     while (i != primaryFunctionMap.end()) {
797         t.append(i.key());
798         ++i;
799     }
800     return t;
801 }
802
803 /*!
804   Returns the list of keys from the secondary function map.
805  */
806 QStringList InnerNode::secondaryKeys()
807 {
808     QStringList t;
809     QMap<QString, NodeList>::iterator i = secondaryFunctionMap.begin();
810     while (i != secondaryFunctionMap.end()) {
811         t.append(i.key());
812         ++i;
813     }
814     return t;
815 }
816
817 /*!
818  */
819 void InnerNode::setOverload(const FunctionNode *func, bool overlode)
820 {
821     Node *node = (Node *) func;
822     Node *&primary = primaryFunctionMap[func->name()];
823
824     if (secondaryFunctionMap.contains(func->name())) {
825         NodeList& secs = secondaryFunctionMap[func->name()];
826         if (overlode) {
827             if (primary == node) {
828                 primary = secs.first();
829                 secs.erase(secs.begin());
830                 secs.append(node);
831             }
832             else {
833                 secs.removeAll(node);
834                 secs.append(node);
835             }
836         }
837         else {
838             if (primary != node) {
839                 secs.removeAll(node);
840                 secs.prepend(primary);
841                 primary = node;
842             }
843         }
844     }
845 }
846
847 /*!
848   Mark all child nodes that have no documentation as having
849   private access and internal status. qdoc will then ignore
850   them for documentation purposes.
851
852   \note Exception: Name collision nodes are not marked
853   private/internal.
854  */
855 void InnerNode::makeUndocumentedChildrenInternal()
856 {
857     foreach (Node *child, childNodes()) {
858         if (child->doc().isEmpty()) {
859             if (child->subType() != Node::Collision) {
860                 child->setAccess(Node::Private);
861                 child->setStatus(Node::Internal);
862             }
863         }
864     }
865 }
866
867 /*!
868   In each child node that is a collision node,
869   clear the current child pointer.
870  */
871 void InnerNode::clearCurrentChildPointers()
872 {
873     foreach (Node* child, childNodes()) {
874         if (child->subType() == Collision) {
875             child->clearCurrentChild();
876         }
877     }
878 }
879
880 /*!
881  */
882 void InnerNode::normalizeOverloads()
883 {
884     QMap<QString, Node *>::Iterator p1 = primaryFunctionMap.begin();
885     while (p1 != primaryFunctionMap.end()) {
886         FunctionNode *primaryFunc = (FunctionNode *) *p1;
887         if (secondaryFunctionMap.contains(primaryFunc->name()) &&
888                 (primaryFunc->status() != Commendable ||
889                  primaryFunc->access() == Private)) {
890
891             NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
892             NodeList::ConstIterator s = secs.constBegin();
893             while (s != secs.constEnd()) {
894                 FunctionNode *secondaryFunc = (FunctionNode *) *s;
895
896                 // Any non-obsolete, non-compatibility, non-private functions
897                 // (i.e, visible functions) are preferable to the primary
898                 // function.
899
900                 if (secondaryFunc->status() == Commendable &&
901                         secondaryFunc->access() != Private) {
902
903                     *p1 = secondaryFunc;
904                     int index = secondaryFunctionMap[primaryFunc->name()].indexOf(secondaryFunc);
905                     secondaryFunctionMap[primaryFunc->name()].replace(index, primaryFunc);
906                     break;
907                 }
908                 ++s;
909             }
910         }
911         ++p1;
912     }
913
914     QMap<QString, Node *>::ConstIterator p = primaryFunctionMap.constBegin();
915     while (p != primaryFunctionMap.constEnd()) {
916         FunctionNode *primaryFunc = (FunctionNode *) *p;
917         if (primaryFunc->isOverload())
918             primaryFunc->ove = false;
919         if (secondaryFunctionMap.contains(primaryFunc->name())) {
920             NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
921             NodeList::ConstIterator s = secs.constBegin();
922             while (s != secs.constEnd()) {
923                 FunctionNode *secondaryFunc = (FunctionNode *) *s;
924                 if (!secondaryFunc->isOverload())
925                     secondaryFunc->ove = true;
926                 ++s;
927             }
928         }
929         ++p;
930     }
931
932     NodeList::ConstIterator c = childNodes().constBegin();
933     while (c != childNodes().constEnd()) {
934         if ((*c)->isInnerNode())
935             ((InnerNode *) *c)->normalizeOverloads();
936         ++c;
937     }
938 }
939
940 /*!
941  */
942 void InnerNode::removeFromRelated()
943 {
944     while (!related_.isEmpty()) {
945         Node *p = static_cast<Node *>(related_.takeFirst());
946
947         if (p != 0 && p->relates() == this) p->clearRelated();
948     }
949 }
950
951 /*!
952   Deletes all this node's children.
953  */
954 void InnerNode::deleteChildren()
955 {
956     NodeList childrenCopy = children; // `children` will be changed in ~Node()
957     qDeleteAll(childrenCopy);
958 }
959
960 /*! \fn bool InnerNode::isInnerNode() const
961   Returns true because this is an inner node.
962  */
963
964 /*!
965  */
966 const Node *InnerNode::findChildNodeByName(const QString& name) const
967 {
968     InnerNode *that = (InnerNode *) this;
969     return that->findChildNodeByName(name);
970 }
971
972 /*!
973   If \a qml is true, only match a node for which node->isQmlNode()
974   returns true. If \a qml is false, only match a node for which
975   node->isQmlNode() returns false.
976  */
977 const Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const
978 {
979     InnerNode*that = (InnerNode*) this;
980     return that->findChildNodeByName(name, qml);
981 }
982
983 /*!
984   Searches this node's children for a child named \a name
985   with the specified node \a type.
986  */
987 const Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type) const
988 {
989     InnerNode *that = (InnerNode *) this;
990     return that->findChildNodeByNameAndType(name, type);
991 }
992
993 /*!
994   Find a function node that is a child of this nose, such
995   that the function node has the specified \a name. This
996   function calls the non-const version of itself.
997  */
998 const FunctionNode *InnerNode::findFunctionNode(const QString& name) const
999 {
1000     InnerNode *that = (InnerNode *) this;
1001     return that->findFunctionNode(name);
1002 }
1003
1004 /*!
1005   Find the function node that is a child of this node, such
1006   that the function has the same name and signature as the
1007   \a clone node. This function calls the non-const version.
1008  */
1009 const FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone) const
1010 {
1011     InnerNode *that = (InnerNode *) this;
1012     return that->findFunctionNode(clone);
1013 }
1014
1015 /*!
1016  */
1017 const EnumNode *InnerNode::findEnumNodeForValue(const QString &enumValue) const
1018 {
1019     foreach (const Node *node, enumChildren) {
1020         const EnumNode *enume = static_cast<const EnumNode *>(node);
1021         if (enume->hasItem(enumValue))
1022             return enume;
1023     }
1024     return 0;
1025 }
1026
1027 /*!
1028   Returnds the sequence number of the function node \a func
1029   in the list of overloaded functions for a class, such that
1030   all the functions have the same name as the \a func.
1031  */
1032 int InnerNode::overloadNumber(const FunctionNode *func) const
1033 {
1034     Node *node = (Node *) func;
1035     if (primaryFunctionMap[func->name()] == node) {
1036         return 1;
1037     }
1038     else {
1039         return secondaryFunctionMap[func->name()].indexOf(node) + 2;
1040     }
1041 }
1042
1043 /*!
1044   Returns a node list containing all the member functions of
1045   some class such that the functions overload the name \a funcName.
1046  */
1047 NodeList InnerNode::overloads(const QString &funcName) const
1048 {
1049     NodeList result;
1050     Node *primary = primaryFunctionMap.value(funcName);
1051     if (primary) {
1052         result << primary;
1053         result += secondaryFunctionMap[funcName];
1054     }
1055     return result;
1056 }
1057
1058 /*!
1059   Construct an inner node (i.e., not a leaf node) of the
1060   given \a type and having the given \a parent and \a name.
1061  */
1062 InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name)
1063     : Node(type, parent, name)
1064 {
1065     switch (type) {
1066     case Class:
1067     case Namespace:
1068         setPageType(ApiPage);
1069         break;
1070     default:
1071         break;
1072     }
1073 }
1074
1075 /*!
1076   Appends an \a include file to the list of include files.
1077  */
1078 void InnerNode::addInclude(const QString& include)
1079 {
1080     inc.append(include);
1081 }
1082
1083 /*!
1084   Sets the list of include files to \a includes.
1085  */
1086 void InnerNode::setIncludes(const QStringList& includes)
1087 {
1088     inc = includes;
1089 }
1090
1091 /*!
1092   f1 is always the clone
1093  */
1094 bool InnerNode::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
1095 {
1096     if (f1->parameters().count() != f2->parameters().count())
1097         return false;
1098     if (f1->isConst() != f2->isConst())
1099         return false;
1100
1101     QList<Parameter>::ConstIterator p1 = f1->parameters().constBegin();
1102     QList<Parameter>::ConstIterator p2 = f2->parameters().constBegin();
1103     while (p2 != f2->parameters().constEnd()) {
1104         if ((*p1).hasType() && (*p2).hasType()) {
1105             if ((*p1).rightType() != (*p2).rightType())
1106                 return false;
1107
1108             QString t1 = p1->leftType();
1109             QString t2 = p2->leftType();
1110
1111             if (t1.length() < t2.length())
1112                 qSwap(t1, t2);
1113
1114             /*
1115               ### hack for C++ to handle superfluous
1116               "Foo::" prefixes gracefully
1117             */
1118             if (t1 != t2 && t1 != (f2->parent()->name() + "::" + t2))
1119                 return false;
1120         }
1121         ++p1;
1122         ++p2;
1123     }
1124     return true;
1125 }
1126
1127 /*!
1128   Adds the \a child to this node's child list.
1129  */
1130 void InnerNode::addChild(Node *child)
1131 {
1132     children.append(child);
1133     if ((child->type() == Function) || (child->type() == QmlMethod)) {
1134         FunctionNode *func = (FunctionNode *) child;
1135         if (!primaryFunctionMap.contains(func->name())) {
1136             primaryFunctionMap.insert(func->name(), func);
1137         }
1138         else {
1139             NodeList &secs = secondaryFunctionMap[func->name()];
1140             secs.append(func);
1141         }
1142     }
1143     else {
1144         if (child->type() == Enum)
1145             enumChildren.append(child);
1146         childMap.insertMulti(child->name(), child);
1147     }
1148 }
1149
1150 /*!
1151  */
1152 void InnerNode::removeChild(Node *child)
1153 {
1154     children.removeAll(child);
1155     enumChildren.removeAll(child);
1156     if (child->type() == Function) {
1157         QMap<QString, Node *>::Iterator prim =
1158                 primaryFunctionMap.find(child->name());
1159         NodeList& secs = secondaryFunctionMap[child->name()];
1160         if (prim != primaryFunctionMap.end() && *prim == child) {
1161             if (secs.isEmpty()) {
1162                 primaryFunctionMap.remove(child->name());
1163             }
1164             else {
1165                 primaryFunctionMap.insert(child->name(), secs.takeFirst());
1166             }
1167         }
1168         else {
1169             secs.removeAll(child);
1170         }
1171     }
1172     QMap<QString, Node *>::Iterator ent = childMap.find(child->name());
1173     while (ent != childMap.end() && ent.key() == child->name()) {
1174         if (*ent == child) {
1175             childMap.erase(ent);
1176             break;
1177         }
1178         ++ent;
1179     }
1180 }
1181
1182 /*!
1183   Find the module (QtCore, QtGui, etc.) to which the class belongs.
1184   We do this by obtaining the full path to the header file's location
1185   and examine everything between "src/" and the filename.  This is
1186   semi-dirty because we are assuming a particular directory structure.
1187
1188   This function is only really useful if the class's module has not
1189   been defined in the header file with a QT_MODULE macro or with an
1190   \inmodule command in the documentation.
1191 */
1192 QString Node::moduleName() const
1193 {
1194     if (!mod.isEmpty())
1195         return mod;
1196
1197     QString path = location().filePath();
1198     QString pattern = QString("src") + QDir::separator();
1199     int start = path.lastIndexOf(pattern);
1200
1201     if (start == -1)
1202         return QString();
1203
1204     QString moduleDir = path.mid(start + pattern.size());
1205     int finish = moduleDir.indexOf(QDir::separator());
1206
1207     if (finish == -1)
1208         return QString();
1209
1210     QString moduleName = moduleDir.left(finish);
1211
1212     if (moduleName == "corelib")
1213         return "QtCore";
1214     else if (moduleName == "uitools")
1215         return "QtUiTools";
1216     else if (moduleName == "gui")
1217         return "QtGui";
1218     else if (moduleName == "network")
1219         return "QtNetwork";
1220     else if (moduleName == "opengl")
1221         return "QtOpenGL";
1222     else if (moduleName == "svg")
1223         return "QtSvg";
1224     else if (moduleName == "sql")
1225         return "QtSql";
1226     else if (moduleName == "qtestlib")
1227         return "QtTest";
1228     else if (moduleDir.contains("webkit"))
1229         return "QtWebKit";
1230     else if (moduleName == "xml")
1231         return "QtXml";
1232     else
1233         return QString();
1234 }
1235
1236 /*!
1237  */
1238 void InnerNode::removeRelated(Node *pseudoChild)
1239 {
1240     related_.removeAll(pseudoChild);
1241 }
1242
1243 /*!
1244   \class LeafNode
1245  */
1246
1247 /*! \fn bool LeafNode::isInnerNode() const
1248   Returns false because this is a LeafNode.
1249  */
1250
1251 /*!
1252   Constructs a leaf node named \a name of the specified
1253   \a type. The new leaf node becomes a child of \a parent.
1254  */
1255 LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name)
1256     : Node(type, parent, name)
1257 {
1258     switch (type) {
1259     case Enum:
1260     case Function:
1261     case Typedef:
1262     case Variable:
1263     case QmlProperty:
1264     case QmlSignal:
1265     case QmlSignalHandler:
1266     case QmlMethod:
1267         setPageType(ApiPage);
1268         break;
1269     default:
1270         break;
1271     }
1272 }
1273
1274 /*!
1275   This constructor should only be used when this node's parent
1276   is meant to be \a parent, but this node is not to be listed
1277   as a child of \a parent. It is currently only used for the
1278   documentation case where a \e{qmlproperty} command is used
1279   to override the QML definition of a QML property.
1280  */
1281 LeafNode::LeafNode(InnerNode* parent, Type type, const QString& name)
1282     : Node(type, 0, name)
1283 {
1284     setParent(parent);
1285     switch (type) {
1286     case Enum:
1287     case Function:
1288     case Typedef:
1289     case Variable:
1290     case QmlProperty:
1291     case QmlSignal:
1292     case QmlSignalHandler:
1293     case QmlMethod:
1294         setPageType(ApiPage);
1295         break;
1296     default:
1297         break;
1298     }
1299 }
1300
1301
1302 /*!
1303   \class NamespaceNode
1304  */
1305
1306 /*!
1307   Constructs a namespace node.
1308  */
1309 NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name)
1310     : InnerNode(Namespace, parent, name)
1311 {
1312     setPageType(ApiPage);
1313 }
1314
1315 /*!
1316   \class ClassNode
1317   \brief This class represents a C++ class.
1318  */
1319
1320 /*!
1321   Constructs a class node. A class node will generate an API page.
1322  */
1323 ClassNode::ClassNode(InnerNode *parent, const QString& name)
1324     : InnerNode(Class, parent, name)
1325 {
1326     hidden = false;
1327     abstract_ = false;
1328     qmlelement = 0;
1329     setPageType(ApiPage);
1330 }
1331
1332 /*!
1333  */
1334 void ClassNode::addBaseClass(Access access,
1335                              ClassNode *node,
1336                              const QString &dataTypeWithTemplateArgs)
1337 {
1338     bases.append(RelatedClass(access, node, dataTypeWithTemplateArgs));
1339     node->derived.append(RelatedClass(access, this));
1340 }
1341
1342 /*!
1343  */
1344 void ClassNode::fixBaseClasses()
1345 {
1346     int i;
1347     i = 0;
1348     QSet<ClassNode *> found;
1349
1350     // Remove private and duplicate base classes.
1351     while (i < bases.size()) {
1352         ClassNode* bc = bases.at(i).node;
1353         if (bc->access() == Node::Private || found.contains(bc)) {
1354             RelatedClass rc = bases.at(i);
1355             bases.removeAt(i);
1356             ignoredBases.append(rc);
1357             const QList<RelatedClass> &bb = bc->baseClasses();
1358             for (int j = bb.size() - 1; j >= 0; --j)
1359                 bases.insert(i, bb.at(j));
1360         }
1361         else {
1362             ++i;
1363         }
1364         found.insert(bc);
1365     }
1366
1367     i = 0;
1368     while (i < derived.size()) {
1369         ClassNode* dc = derived.at(i).node;
1370         if (dc->access() == Node::Private) {
1371             derived.removeAt(i);
1372             const QList<RelatedClass> &dd = dc->derivedClasses();
1373             for (int j = dd.size() - 1; j >= 0; --j)
1374                 derived.insert(i, dd.at(j));
1375         }
1376         else {
1377             ++i;
1378         }
1379     }
1380 }
1381
1382 /*!
1383   Search the child list to find the property node with the
1384   specified \a name.
1385  */
1386 PropertyNode* ClassNode::findPropertyNode(const QString& name)
1387 {
1388     Node* n = findChildNodeByNameAndType(name, Node::Property);
1389
1390     if (n)
1391         return static_cast<PropertyNode*>(n);
1392
1393     PropertyNode* pn = 0;
1394
1395     const QList<RelatedClass> &bases = baseClasses();
1396     if (!bases.isEmpty()) {
1397         for (int i = 0; i < bases.size(); ++i) {
1398             ClassNode* cn = bases[i].node;
1399             pn = cn->findPropertyNode(name);
1400             if (pn)
1401                 break;
1402         }
1403     }
1404     const QList<RelatedClass>& ignoredBases = ignoredBaseClasses();
1405     if (!ignoredBases.isEmpty()) {
1406         for (int i = 0; i < ignoredBases.size(); ++i) {
1407             ClassNode* cn = ignoredBases[i].node;
1408             pn = cn->findPropertyNode(name);
1409             if (pn)
1410                 break;
1411         }
1412     }
1413
1414     return pn;
1415 }
1416
1417 /*!
1418   This function does a recursive search of this class node's
1419   base classes looking for one that has a QML element. If it
1420   finds one, it returns the pointer to that QML element. If
1421   it doesn't find one, it returns null.
1422  */
1423 QmlClassNode* ClassNode::findQmlBaseNode()
1424 {
1425     QmlClassNode* result = 0;
1426     const QList<RelatedClass>& bases = baseClasses();
1427
1428     if (!bases.isEmpty()) {
1429         for (int i = 0; i < bases.size(); ++i) {
1430             ClassNode* cn = bases[i].node;
1431             if (cn && cn->qmlElement()) {
1432                 return cn->qmlElement();
1433             }
1434         }
1435         for (int i = 0; i < bases.size(); ++i) {
1436             ClassNode* cn = bases[i].node;
1437             if (cn) {
1438                 result = cn->findQmlBaseNode();
1439                 if (result != 0) {
1440                     return result;
1441                 }
1442             }
1443         }
1444     }
1445     return result;
1446 }
1447
1448 QMap<QString, FakeNode*> FakeNode::qmlModuleMap_;
1449
1450 /*!
1451   \class FakeNode
1452  */
1453
1454 /*!
1455   The type of a FakeNode is Fake, and it has a \a subtype,
1456   which specifies the type of FakeNode. The page type for
1457   the page index is set here.
1458  */
1459 FakeNode::FakeNode(InnerNode* parent, const QString& name, SubType subtype, Node::PageType ptype)
1460     : InnerNode(Fake, parent, name), nodeSubtype_(subtype)
1461 {
1462     switch (subtype) {
1463     case Page:
1464         setPageType(ptype);
1465         break;
1466     case DitaMap:
1467         setPageType(ptype);
1468         break;
1469     case Module:
1470     case Group:
1471         setPageType(OverviewPage);
1472         break;
1473     case QmlModule:
1474         setPageType(OverviewPage);
1475         break;
1476     case QmlClass:
1477     case QmlBasicType:
1478         setPageType(ApiPage);
1479         break;
1480     case Example:
1481         setPageType(ExamplePage);
1482         break;
1483     case Collision:
1484         setPageType(ptype);
1485         break;
1486     default:
1487         break;
1488     }
1489 }
1490
1491 /*!
1492   Returns the fake node's title. This is used for the page title.
1493 */
1494 QString FakeNode::title() const
1495 {
1496     return title_;
1497 }
1498
1499 /*!
1500   Returns the fake node's full title, which is usually
1501   just title(), but for some SubType values is different
1502   from title()
1503  */
1504 QString FakeNode::fullTitle() const
1505 {
1506     if (nodeSubtype_ == File) {
1507         if (title().isEmpty())
1508             return name().mid(name().lastIndexOf('/') + 1) + " Example File";
1509         else
1510             return title();
1511     }
1512     else if (nodeSubtype_ == Image) {
1513         if (title().isEmpty())
1514             return name().mid(name().lastIndexOf('/') + 1) + " Image File";
1515         else
1516             return title();
1517     }
1518     else if (nodeSubtype_ == HeaderFile) {
1519         if (title().isEmpty())
1520             return name();
1521         else
1522             return name() + " - " + title();
1523     }
1524     else if (nodeSubtype_ == Collision) {
1525         return title();
1526     }
1527     else {
1528         return title();
1529     }
1530 }
1531
1532 /*!
1533   Returns the subtitle.
1534  */
1535 QString FakeNode::subTitle() const
1536 {
1537     if (!subtitle_.isEmpty())
1538         return subtitle_;
1539
1540     if ((nodeSubtype_ == File) || (nodeSubtype_ == Image)) {
1541         if (title().isEmpty() && name().contains(QLatin1Char('/')))
1542             return name();
1543     }
1544     return QString();
1545 }
1546
1547 /*!
1548   The QML module map contains an entry for each QML module
1549   identifier. A QML module identifier is constucted from the
1550   QML module name and the module's major version number, like
1551   this: \e {<module-name><major-version>}
1552
1553   If the QML module map does not contain the module identifier
1554   \a qmid, insert the QML module node \a fn mapped to \a qmid.
1555  */
1556 void FakeNode::insertQmlModuleNode(const QString& qmid, FakeNode* fn)
1557 {
1558     if (!qmlModuleMap_.contains(qmid))
1559         qmlModuleMap_.insert(qmid,fn);
1560 }
1561
1562 /*!
1563   Returns a pointer to the QML module node (FakeNode) that is
1564   mapped to the QML module identifier constructed from \a arg.
1565   If that QML module node does not yet exist, it is constructed
1566   and inserted into the QML module map mapped to the QML module
1567   identifier constructed from \a arg.
1568  */
1569 FakeNode* FakeNode::lookupQmlModuleNode(Tree* tree, const ArgLocPair& arg)
1570 {
1571     QStringList dotSplit;
1572     QStringList blankSplit = arg.first.split(QLatin1Char(' '));
1573     QString qmid = blankSplit[0];
1574     if (blankSplit.size() > 1) {
1575         dotSplit = blankSplit[1].split(QLatin1Char('.'));
1576         qmid += dotSplit[0];
1577     }
1578     FakeNode* fn = 0;
1579     if (qmlModuleMap_.contains(qmid))
1580         fn = qmlModuleMap_.value(qmid);
1581     if (!fn) {
1582         fn = new FakeNode(tree->root(), arg.first, Node::QmlModule, Node::OverviewPage);
1583         fn->setQmlModule(arg);
1584         insertQmlModuleNode(qmid,fn);
1585     }
1586     return fn;
1587 }
1588
1589 /*!
1590   Returns true if this QML type or property group contains a
1591   property named \a name.
1592  */
1593 bool FakeNode::hasProperty(const QString& name) const
1594 {
1595     foreach (Node* child, childNodes()) {
1596         if (child->type() == Node::Fake && child->subType() == Node::QmlPropertyGroup) {
1597             if (child->hasProperty(name))
1598                 return true;
1599         }
1600         else if (child->type() == Node::QmlProperty) {
1601             if (child->hasProperty(name))
1602                 return true;
1603         }
1604     }
1605     return false;
1606 }
1607
1608 /*!
1609   The constructor calls the FakeNode constructor with
1610   \a parent, \a name, and Node::Example.
1611  */
1612 ExampleNode::ExampleNode(InnerNode* parent, const QString& name)
1613     : FakeNode(parent, name, Node::Example, Node::ExamplePage)
1614 {
1615     // nothing
1616 }
1617
1618 /*!
1619   \class EnumNode
1620  */
1621
1622 /*!
1623   The constructor for the node representing an enum type
1624   has a \a parent class and an enum type \a name.
1625  */
1626 EnumNode::EnumNode(InnerNode *parent, const QString& name)
1627     : LeafNode(Enum, parent, name), ft(0)
1628 {
1629     // nothing.
1630 }
1631
1632 /*!
1633   Add \a item to the enum type's item list.
1634  */
1635 void EnumNode::addItem(const EnumItem& item)
1636 {
1637     itms.append(item);
1638     names.insert(item.name());
1639 }
1640
1641 /*!
1642   Returns the access level of the enumeration item named \a name.
1643   Apparently it is private if it has been omitted by qdoc's
1644   omitvalue command. Otherwise it is public.
1645  */
1646 Node::Access EnumNode::itemAccess(const QString &name) const
1647 {
1648     if (doc().omitEnumItemNames().contains(name))
1649         return Private;
1650     return Public;
1651 }
1652
1653 /*!
1654   Returns the enum value associated with the enum \a name.
1655  */
1656 QString EnumNode::itemValue(const QString &name) const
1657 {
1658     foreach (const EnumItem &item, itms) {
1659         if (item.name() == name)
1660             return item.value();
1661     }
1662     return QString();
1663 }
1664
1665 /*!
1666   \class TypedefNode
1667  */
1668
1669 /*!
1670  */
1671 TypedefNode::TypedefNode(InnerNode *parent, const QString& name)
1672     : LeafNode(Typedef, parent, name), ae(0)
1673 {
1674 }
1675
1676 /*!
1677  */
1678 void TypedefNode::setAssociatedEnum(const EnumNode *enume)
1679 {
1680     ae = enume;
1681 }
1682
1683 /*!
1684   \class Parameter
1685   \brief The class Parameter contains one parameter.
1686
1687   A parameter can be a function parameter or a macro
1688   parameter.
1689  */
1690
1691 /*!
1692   Constructs this parameter from the left and right types
1693   \a leftType and rightType, the parameter \a name, and the
1694   \a defaultValue. In practice, \a rightType is not used,
1695   and I don't know what is was meant for.
1696  */
1697 Parameter::Parameter(const QString& leftType,
1698                      const QString& rightType,
1699                      const QString& name,
1700                      const QString& defaultValue)
1701     : lef(leftType), rig(rightType), nam(name), def(defaultValue)
1702 {
1703 }
1704
1705 /*!
1706   The standard copy constructor copies the strings from \a p.
1707  */
1708 Parameter::Parameter(const Parameter& p)
1709     : lef(p.lef), rig(p.rig), nam(p.nam), def(p.def)
1710 {
1711 }
1712
1713 /*!
1714   Assigning Parameter \a p to this Parameter copies the
1715   strings across.
1716  */
1717 Parameter& Parameter::operator=(const Parameter& p)
1718 {
1719     lef = p.lef;
1720     rig = p.rig;
1721     nam = p.nam;
1722     def = p.def;
1723     return *this;
1724 }
1725
1726 /*!
1727   Reconstructs the text describing the parameter and
1728   returns it. If \a value is true, the default value
1729   will be included, if there is one.
1730  */
1731 QString Parameter::reconstruct(bool value) const
1732 {
1733     QString p = lef + rig;
1734     if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
1735         p += QLatin1Char(' ');
1736     p += nam;
1737     if (value && !def.isEmpty())
1738         p += " = " + def;
1739     return p;
1740 }
1741
1742
1743 /*!
1744   \class FunctionNode
1745  */
1746
1747 /*!
1748   Construct a function node for a C++ function. It's parent
1749   is \a parent, and it's name is \a name.
1750  */
1751 FunctionNode::FunctionNode(InnerNode *parent, const QString& name)
1752     : LeafNode(Function, parent, name),
1753       met(Plain),
1754       vir(NonVirtual),
1755       con(false),
1756       sta(false),
1757       ove(false),
1758       reimp(false),
1759       attached_(false),
1760       rf(0),
1761       ap(0)
1762 {
1763     // nothing.
1764 }
1765
1766 /*!
1767   Construct a function node for a QML method or signal, specified
1768   by \a type. It's parent is \a parent, and it's name is \a name.
1769   If \a attached is true, it is an attached method or signal.
1770  */
1771 FunctionNode::FunctionNode(Type type, InnerNode *parent, const QString& name, bool attached)
1772     : LeafNode(type, parent, name),
1773       met(Plain),
1774       vir(NonVirtual),
1775       con(false),
1776       sta(false),
1777       ove(false),
1778       reimp(false),
1779       attached_(attached),
1780       rf(0),
1781       ap(0)
1782 {
1783     // nothing.
1784 }
1785
1786 /*!
1787   Sets the \a virtualness of this function. If the \a virtualness
1788   is PureVirtual, and if the parent() is a ClassNode, set the parent's
1789   \e abstract flag to true.
1790  */
1791 void FunctionNode::setVirtualness(Virtualness virtualness)
1792 {
1793     vir = virtualness;
1794     if ((virtualness == PureVirtual) && parent() &&
1795             (parent()->type() == Node::Class))
1796         parent()->setAbstract(true);
1797 }
1798
1799 /*!
1800  */
1801 void FunctionNode::setOverload(bool overlode)
1802 {
1803     parent()->setOverload(this, overlode);
1804     ove = overlode;
1805 }
1806
1807 /*!
1808   Sets the function node's reimplementation flag to \a r.
1809   When \a r is true, it is supposed to mean that this function
1810   is a reimplementation of a virtual function in a base class,
1811   but it really just means the \e reimp command was seen in the
1812   qdoc comment.
1813  */
1814 void FunctionNode::setReimp(bool r)
1815 {
1816     reimp = r;
1817 }
1818
1819 /*!
1820  */
1821 void FunctionNode::addParameter(const Parameter& parameter)
1822 {
1823     params.append(parameter);
1824 }
1825
1826 /*!
1827  */
1828 void FunctionNode::borrowParameterNames(const FunctionNode *source)
1829 {
1830     QList<Parameter>::Iterator t = params.begin();
1831     QList<Parameter>::ConstIterator s = source->params.constBegin();
1832     while (s != source->params.constEnd() && t != params.end()) {
1833         if (!(*s).name().isEmpty())
1834             (*t).setName((*s).name());
1835         ++s;
1836         ++t;
1837     }
1838 }
1839
1840 /*!
1841   If this function is a reimplementation, \a from points
1842   to the FunctionNode of the function being reimplemented.
1843  */
1844 void FunctionNode::setReimplementedFrom(FunctionNode *from)
1845 {
1846     rf = from;
1847     from->rb.append(this);
1848 }
1849
1850 /*!
1851   Sets the "associated" property to \a property. The function
1852   might be the setter or getter for a property, for example.
1853  */
1854 void FunctionNode::setAssociatedProperty(PropertyNode *property)
1855 {
1856     ap = property;
1857 }
1858
1859 /*!
1860   Returns the overload number for this function obtained
1861   from the parent.
1862  */
1863 int FunctionNode::overloadNumber() const
1864 {
1865     return parent()->overloadNumber(this);
1866 }
1867
1868 /*!
1869   Returns the list of parameter names.
1870  */
1871 QStringList FunctionNode::parameterNames() const
1872 {
1873     QStringList names;
1874     QList<Parameter>::ConstIterator p = parameters().constBegin();
1875     while (p != parameters().constEnd()) {
1876         names << (*p).name();
1877         ++p;
1878     }
1879     return names;
1880 }
1881
1882 /*!
1883   Returns a raw list of parameters. If \a names is true, the
1884   names are included. If \a values is true, the default values
1885   are included, if any are present.
1886  */
1887 QString FunctionNode::rawParameters(bool names, bool values) const
1888 {
1889     QString raw;
1890     foreach (const Parameter &parameter, parameters()) {
1891         raw += parameter.leftType() + parameter.rightType();
1892         if (names)
1893             raw += parameter.name();
1894         if (values)
1895             raw += parameter.defaultValue();
1896     }
1897     return raw;
1898 }
1899
1900 /*!
1901   Returns the list of reconstructed parameters. If \a values
1902   is true, the default values are included, if any are present.
1903  */
1904 QStringList FunctionNode::reconstructParams(bool values) const
1905 {
1906     QStringList params;
1907     QList<Parameter>::ConstIterator p = parameters().constBegin();
1908     while (p != parameters().constEnd()) {
1909         params << (*p).reconstruct(values);
1910         ++p;
1911     }
1912     return params;
1913 }
1914
1915 /*!
1916   Reconstructs and returns the function's signature. If \a values
1917   is true, the default values of the parameters are included, if
1918   present.
1919  */
1920 QString FunctionNode::signature(bool values) const
1921 {
1922     QString s;
1923     if (!returnType().isEmpty())
1924         s = returnType() + QLatin1Char(' ');
1925     s += name() + QLatin1Char('(');
1926     QStringList params = reconstructParams(values);
1927     int p = params.size();
1928     if (p > 0) {
1929         for (int i=0; i<p; i++) {
1930             s += params[i];
1931             if (i < (p-1))
1932                 s += ", ";
1933         }
1934     }
1935     s += QLatin1Char(')');
1936     return s;
1937 }
1938
1939 /*!
1940   Print some debugging stuff.
1941  */
1942 void FunctionNode::debug() const
1943 {
1944     qDebug("QML METHOD %s rt %s pp %s",
1945            qPrintable(name()), qPrintable(rt), qPrintable(pp.join(" ")));
1946 }
1947
1948 /*!
1949   \class PropertyNode
1950
1951   This class describes one instance of using the Q_PROPERTY macro.
1952  */
1953
1954 /*!
1955   The constructor sets the \a parent and the \a name, but
1956   everything else is set to default values.
1957  */
1958 PropertyNode::PropertyNode(InnerNode *parent, const QString& name)
1959     : LeafNode(Property, parent, name),
1960       stored_(FlagValueDefault),
1961       designable_(FlagValueDefault),
1962       scriptable_(FlagValueDefault),
1963       writable_(FlagValueDefault),
1964       user_(FlagValueDefault),
1965       cst(false),
1966       fnl(false),
1967       rev(-1),
1968       overrides(0)
1969 {
1970     // nothing.
1971 }
1972
1973 /*!
1974   Sets this property's \e {overridden from} property to
1975   \a baseProperty, which indicates that this property
1976   overrides \a baseProperty. To begin with, all the values
1977   in this property are set to the corresponding values in
1978   \a baseProperty.
1979
1980   We probably should ensure that the constant and final
1981   attributes are not being overridden improperly.
1982  */
1983 void PropertyNode::setOverriddenFrom(const PropertyNode* baseProperty)
1984 {
1985     for (int i = 0; i < NumFunctionRoles; ++i) {
1986         if (funcs[i].isEmpty())
1987             funcs[i] = baseProperty->funcs[i];
1988     }
1989     if (stored_ == FlagValueDefault)
1990         stored_ = baseProperty->stored_;
1991     if (designable_ == FlagValueDefault)
1992         designable_ = baseProperty->designable_;
1993     if (scriptable_ == FlagValueDefault)
1994         scriptable_ = baseProperty->scriptable_;
1995     if (writable_ == FlagValueDefault)
1996         writable_ = baseProperty->writable_;
1997     if (user_ == FlagValueDefault)
1998         user_ = baseProperty->user_;
1999     overrides = baseProperty;
2000 }
2001
2002 /*!
2003  */
2004 QString PropertyNode::qualifiedDataType() const
2005 {
2006     if (setters().isEmpty() && resetters().isEmpty()) {
2007         if (type_.contains(QLatin1Char('*')) || type_.contains(QLatin1Char('&'))) {
2008             // 'QWidget *' becomes 'QWidget *' const
2009             return type_ + " const";
2010         }
2011         else {
2012             /*
2013               'int' becomes 'const int' ('int const' is
2014               correct C++, but looks wrong)
2015             */
2016             return "const " + type_;
2017         }
2018     }
2019     else {
2020         return type_;
2021     }
2022 }
2023
2024 bool QmlClassNode::qmlOnly = false;
2025 QMultiMap<QString,Node*> QmlClassNode::inheritedBy;
2026 QMap<QString, QmlClassNode*> QmlClassNode::qmlModuleMemberMap_;
2027
2028 /*!
2029   Constructs a Qml class node (i.e. a Fake node with the
2030   subtype QmlClass. The new node has the given \a parent
2031   and \a name and is associated with the C++ class node
2032   specified by \a cn which may be null if the the Qml
2033   class node is not associated with a C++ class node.
2034  */
2035 QmlClassNode::QmlClassNode(InnerNode *parent,
2036                            const QString& name,
2037                            ClassNode* cn)
2038     : FakeNode(parent, name, QmlClass, Node::ApiPage),
2039       abstract_(false),
2040       cnodeRequired_(false),
2041       cnode_(cn),
2042       base_(0)
2043 {
2044     int i = 0;
2045     if (name.startsWith("QML:")) {
2046         qDebug() << "BOGUS QML qualifier:" << name;
2047         i = 4;
2048     }
2049     setTitle(name.mid(i));
2050 }
2051
2052 /*!
2053   Needed for printing a debug messages.
2054  */
2055 QmlClassNode::~QmlClassNode()
2056 {
2057     // nothing.
2058 }
2059
2060 /*!
2061   Clear the static maps so that subsequent runs don't try to use
2062   contents from a previous run.
2063  */
2064 void QmlClassNode::terminate()
2065 {
2066     inheritedBy.clear();
2067     qmlModuleMemberMap_.clear();
2068 }
2069
2070 /*!
2071   Insert the QML type node \a qcn into the static QML module
2072   member map. The key is \a qmid + "::" + qcn->name().
2073  */
2074 void QmlClassNode::insertQmlModuleMember(const QString& qmid, QmlClassNode* qcn)
2075 {
2076     qmlModuleMemberMap_.insert(qmid + "::" + qcn->name(), qcn);
2077 }
2078
2079 /*!
2080   Lookup the QML type node identified by the Qml module id
2081   \a qmid and QML type \a name, and return a pointer to the
2082   node. The key is \a qmid + "::" + qcn->name().
2083  */
2084 QmlClassNode* QmlClassNode::lookupQmlTypeNode(const QString& qmid, const QString& name)
2085 {
2086     return qmlModuleMemberMap_.value(qmid + "::" + name);
2087 }
2088
2089 /*!
2090   The base file name for this kind of node has "qml_"
2091   prepended to it.
2092
2093   But not yet. Still testing.
2094  */
2095 QString QmlClassNode::fileBase() const
2096 {
2097     return Node::fileBase();
2098 }
2099
2100 /*!
2101   Record the fact that QML class \a base is inherited by
2102   QML class \a sub.
2103  */
2104 void QmlClassNode::addInheritedBy(const QString& base, Node* sub)
2105 {
2106     if (inheritedBy.constFind(base,sub) == inheritedBy.constEnd()) {
2107         inheritedBy.insert(base,sub);
2108     }
2109 }
2110
2111 /*!
2112   Loads the list \a subs with the nodes of all the subclasses of \a base.
2113  */
2114 void QmlClassNode::subclasses(const QString& base, NodeList& subs)
2115 {
2116     subs.clear();
2117     if (inheritedBy.count(base) > 0) {
2118         subs = inheritedBy.values(base);
2119     }
2120 }
2121
2122 /*! \fn QString QmlClassNode::qmlModuleIdentifier() const
2123   This function is called to get a string that is used either
2124   as a prefix for the file name to use for QML element or
2125   component reference page, or as a qualifier to prefix a
2126   reference to a QML element or comnponent. The string that
2127   is returned is the concatenation of the QML module name
2128   and its version number. e.g., if an element or component
2129   is defined to be in the QML module QtQuick 1, its module
2130   identifier is "QtQuick1". See setQmlModule().
2131  */
2132
2133 /*!
2134   This function splits \a arg on the blank character to get a
2135   QML module name and version number. It then spilts the version
2136   number on the '.' character to get a major version number and
2137   a minor vrsion number. Both version numbers must be present.
2138   It stores these components separately. If all three are found,
2139   true is returned. If any of the three is not found or is not
2140   correct, false is returned.
2141  */
2142 bool Node::setQmlModule(const ArgLocPair& arg)
2143 {
2144     QStringList dotSplit;
2145     QStringList blankSplit = arg.first.split(QLatin1Char(' '));
2146     qmlModuleName_ = blankSplit[0];
2147     qmlModuleVersionMajor_ = "1";
2148     qmlModuleVersionMinor_ = "0";
2149     if (blankSplit.size() > 1) {
2150         dotSplit = blankSplit[1].split(QLatin1Char('.'));
2151         qmlModuleVersionMajor_ = dotSplit[0];
2152         if (dotSplit.size() > 1) {
2153             qmlModuleVersionMinor_ = dotSplit[1];
2154             return true;
2155         }
2156         else
2157             arg.second.warning(tr("Minor version number must be included in second arg of '\\qmlmodule' and '\\inqmlmodule'; '.0' assumed."));
2158     }
2159     else
2160         arg.second.warning(tr("Module version number 'major.minor' must be second arg of '\\qmlmodule' and '\\inqmlmodule'; '1.0' assumed."));
2161     return false;
2162 }
2163
2164 /*!
2165   The name of this QML class node might be the same as the
2166   name of some other QML class node. If so, then this node's
2167   parent will be a NameCollisionNode.This function sets the
2168   NameCollisionNode's current child to this node. This is
2169   important when outputing the documentation for this node,
2170   when, for example, the documentation contains a link to
2171   the page being output. We don't want to generate a link
2172   to the disambiguation page if we can avoid it, and to be
2173   able to avoid it, the NameCollisionNode must maintain the
2174   current child pointer. That's the purpose of this function.
2175  */
2176 void QmlClassNode::setCurrentChild()
2177 {
2178     if (parent()) {
2179         InnerNode* n = parent();
2180         if (n->subType() == Node::Collision)
2181             n->setCurrentChild(this);
2182     }
2183 }
2184
2185 /*!
2186  */
2187 void QmlClassNode::clearCurrentChild()
2188 {
2189     if (parent()) {
2190         InnerNode* n = parent();
2191         if (n->subType() == Node::Collision)
2192             n->clearCurrentChild();
2193     }
2194 }
2195
2196 /*!
2197   Most QML elements don't have an \\inherits command in their
2198   \\qmlclass command. This leaves qdoc bereft, when it tries
2199   to output the line in the documentation that specifies the
2200   QML element that a QML element inherits.
2201  */
2202 void QmlClassNode::resolveInheritance(Tree* tree)
2203 {
2204     if (!links().empty() && links().contains(Node::InheritsLink)) {
2205         QPair<QString,QString> linkPair;
2206         linkPair = links()[Node::InheritsLink];
2207         QStringList strList = linkPair.first.split("::");
2208         Node* n = tree->findQmlClassNode(strList);
2209         if (n) {
2210             base_ = static_cast<FakeNode*>(n);
2211             if (base_ && base_->subType() == Node::QmlClass) {
2212                 return;
2213             }
2214         }
2215         if (base_ && base_->subType() == Node::Collision) {
2216             const NameCollisionNode* ncn = static_cast<const NameCollisionNode*>(base_);
2217             const NodeList& children = ncn->childNodes();
2218             for (int i=0; i<importList_.size(); ++i) {
2219                 QString qmid = importList_.at(i).first + importList_.at(i).second;
2220                 for (int j=0; j<children.size(); ++j) {
2221                     if (qmid == children.at(j)->qmlModuleIdentifier()) {
2222                         base_ = static_cast<FakeNode*>(children.at(j));
2223                         return;
2224                     }
2225                 }
2226             }
2227             QString qmid = qmlModuleIdentifier();
2228             for (int k=0; k<children.size(); ++k) {
2229                 if (qmid == children.at(k)->qmlModuleIdentifier()) {
2230                     base_ = static_cast<QmlClassNode*>(children.at(k));
2231                     return;
2232                 }
2233             }
2234         }
2235         if (base_)
2236             return;
2237     }
2238     if (cnode_) {
2239         QmlClassNode* qcn = cnode_->findQmlBaseNode();
2240         if (qcn != 0)
2241             base_ = qcn;
2242     }
2243     return;
2244 }
2245
2246 /*!
2247   Constructs a Qml basic type node (i.e. a Fake node with
2248   the subtype QmlBasicType. The new node has the given
2249   \a parent and \a name.
2250  */
2251 QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent,
2252                                    const QString& name)
2253     : FakeNode(parent, name, QmlBasicType, Node::ApiPage)
2254 {
2255     setTitle(name);
2256 }
2257
2258 /*!
2259   Constructor for the Qml property group node. \a parent is
2260   always a QmlClassNode.
2261  */
2262 QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name)
2263     : FakeNode(parent, name, QmlPropertyGroup, Node::ApiPage)
2264 {
2265     idNumber_ = -1;
2266 }
2267
2268 /*!
2269   Return the property group node's id number for use in
2270   constructing an id attribute for the property group.
2271   If the id number is currently -1, increment the global
2272   property group count and set the id number to the new
2273   value.
2274  */
2275 QString QmlPropGroupNode::idNumber()
2276 {
2277     if (idNumber_ == -1)
2278         idNumber_ = incPropertyGroupCount();
2279     return QString().setNum(idNumber_);
2280 }
2281
2282
2283 /*!
2284   Constructor for the QML property node, when the \a parent
2285   is QML property group node. This constructor is only used
2286   for creating QML property nodes for QML elements, i.e.
2287   not for creating QML property nodes for QML components.
2288   Hopefully, this constructor will become obsolete, so don't
2289   use it unless one of the other two constructors can't be
2290   used.
2291  */
2292 QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent,
2293                                  const QString& name,
2294                                  const QString& type,
2295                                  bool attached)
2296     : LeafNode(QmlProperty, parent, name),
2297       type_(type),
2298       stored_(FlagValueDefault),
2299       designable_(FlagValueDefault),
2300       isdefault_(false),
2301       attached_(attached),
2302       readOnly_(FlagValueDefault)
2303 {
2304     setPageType(ApiPage);
2305 }
2306
2307 /*!
2308   Constructor for the QML property node, when the \a parent
2309   is a QML class node.
2310  */
2311 QmlPropertyNode::QmlPropertyNode(QmlClassNode *parent,
2312                                  const QString& name,
2313                                  const QString& type,
2314                                  bool attached)
2315     : LeafNode(QmlProperty, parent, name),
2316       type_(type),
2317       stored_(FlagValueDefault),
2318       designable_(FlagValueDefault),
2319       isdefault_(false),
2320       attached_(attached),
2321       readOnly_(FlagValueDefault)
2322 {
2323     setPageType(ApiPage);
2324 }
2325
2326 /*!
2327   Constructor for the QML property node, when the \a parent
2328   is a QML property node. Strictly speaking, this is not the
2329   way QML property nodes were originally meant to be built,
2330   because this constructor has another QML property node as
2331   its parent. But this constructor is useful for documenting
2332   QML properties in QML components, i.e., when you override
2333   the definition of a property with the \e{qmlproperty}
2334   command. It actually uses the parent of \a parent as the
2335   parent.
2336  */
2337 QmlPropertyNode::QmlPropertyNode(QmlPropertyNode* parent,
2338                                  const QString& name,
2339                                  const QString& type,
2340                                  bool attached)
2341     : LeafNode(parent->parent(), QmlProperty, name),
2342       type_(type),
2343       stored_(FlagValueDefault),
2344       designable_(FlagValueDefault),
2345       isdefault_(false),
2346       attached_(attached),
2347       readOnly_(FlagValueDefault)
2348 {
2349     setPageType(ApiPage);
2350 }
2351
2352 /*!
2353   Returns true if a QML property or attached property is
2354   not read-only. The algorithm for figuring this out is long
2355   amd tedious and almost certainly will break. It currently
2356   doesn't work for the qmlproperty:
2357
2358   \code
2359       bool PropertyChanges::explicit,
2360   \endcode
2361
2362   ...because the tokenizer gets confused on \e{explicit}.
2363  */
2364 bool QmlPropertyNode::isWritable(Tree* tree)
2365 {
2366     if (readOnly_ != FlagValueDefault)
2367         return !fromFlagValue(readOnly_, false);
2368
2369     QmlClassNode* qcn = qmlClassNode();
2370     if (qcn) {
2371         if (qcn->cppClassRequired()) {
2372             if (qcn->classNode()) {
2373                 PropertyNode* pn = correspondingProperty(tree);
2374                 if (pn)
2375                     return pn->isWritable();
2376                 else
2377                     location().warning(tr("No Q_PROPERTY for QML property %1::%2::%3 "
2378                                           "in C++ class documented as QML type: "
2379                                           "(property not found in the C++ class or its base classes)")
2380                                        .arg(qmlModuleIdentifier()).arg(qmlTypeName()).arg(name()));
2381             }
2382             else
2383                 location().warning(tr("No Q_PROPERTY for QML property %1::%2::%3 "
2384                                       "in C++ class documented as QML type: "
2385                                       "(C++ class not specified or not found).")
2386                                    .arg(qmlModuleIdentifier()).arg(qmlTypeName()).arg(name()));
2387         }
2388     }
2389     return true;
2390 }
2391
2392 /*!
2393   Returns a pointer this QML property's corresponding C++
2394   property, if it has one.
2395  */
2396 PropertyNode* QmlPropertyNode::correspondingProperty(Tree *tree)
2397 {
2398     PropertyNode* pn;
2399
2400     Node* n = parent();
2401     while (n && n->subType() != Node::QmlClass)
2402         n = n->parent();
2403     if (n) {
2404         QmlClassNode* qcn = static_cast<QmlClassNode*>(n);
2405         ClassNode* cn = qcn->classNode();
2406         if (cn) {
2407             QStringList dotSplit = name().split(QChar('.'));
2408             pn = cn->findPropertyNode(dotSplit[0]);
2409             if (pn) {
2410                 if (dotSplit.size() > 1) {
2411                     // Find the C++ property corresponding to the QML property in
2412                     // the property group, <group>.<property>.
2413
2414                     QStringList path(extractClassName(pn->qualifiedDataType()));
2415                     Node* nn = tree->findClassNode(path);
2416                     if (nn) {
2417                         ClassNode* cn = static_cast<ClassNode*>(nn);
2418                         PropertyNode *pn2 = cn->findPropertyNode(dotSplit[1]);
2419                         if (pn2)
2420                             return pn2; // Return the property for the QML property.
2421                         else
2422                             return pn;  // Return the property for the QML group.
2423                     }
2424                 }
2425                 else
2426                     return pn;
2427             }
2428             else {
2429                 pn = cn->findPropertyNode(dotSplit[0]);
2430                 if (pn)
2431                     return pn;
2432             }
2433         }
2434     }
2435
2436     return 0;
2437 }
2438
2439 /*!
2440   Returns true if this QML type or property group contains a
2441   property named \a name.
2442  */
2443 bool QmlPropertyNode::hasProperty(const QString& n) const
2444 {
2445     if (name() == n)
2446         return true;
2447     foreach (Node* child, qmlPropNodes()) {
2448         if (child->type() == Node::QmlProperty) {
2449             if (child->name() == n)
2450                 return true;
2451         }
2452     }
2453     return false;
2454 }
2455
2456 /*! \class NameCollisionNode
2457
2458   An instance of this node is inserted in the tree
2459   whenever qdoc discovers that two nodes have the
2460   same name.
2461  */
2462
2463 /*!
2464   Constructs a name collision node containing \a child
2465   as its first child. The parent of \a child becomes
2466   this node's parent.
2467  */
2468 NameCollisionNode::NameCollisionNode(InnerNode* child)
2469     : FakeNode(child->parent(), child->name(), Collision, Node::NoPageType)
2470 {
2471     setTitle("Name Collision: " + child->name());
2472     addCollision(child);
2473     current = 0;
2474 }
2475
2476 /*!
2477   Add a collision to this collision node. \a child has
2478   the same name as the other children in this collision
2479   node. \a child becomes the current child.
2480  */
2481 void NameCollisionNode::addCollision(InnerNode* child)
2482 {
2483     if (child) {
2484         if (child->parent())
2485             child->parent()->removeChild(child);
2486         child->setParent((InnerNode*)this);
2487         children.append(child);
2488     }
2489 }
2490
2491 /*!
2492   The destructor does nothing.
2493  */
2494 NameCollisionNode::~NameCollisionNode()
2495 {
2496     // nothing.
2497 }
2498
2499 /*! \fn const InnerNode* NameCollisionNode::currentChild() const
2500   Returns a pointer to the current child, which may be 0.
2501  */
2502
2503 /*! \fn void NameCollisionNode::setCurrentChild(InnerNode* child)
2504   Sets the current child to \a child. The current child is
2505   valid only within the file where it is defined.
2506  */
2507
2508 /*! \fn void NameCollisionNode::clearCurrentChild()
2509   Sets the current child to 0. This should be called at the
2510   end of each file, because the current child is only valid
2511   within the file where the child is defined.
2512  */
2513
2514 /*!
2515   Returns true if this collision node's current node is a QML node.
2516  */
2517 bool NameCollisionNode::isQmlNode() const
2518 {
2519     if (current)
2520         return current->isQmlNode();
2521     return false;
2522 }
2523
2524 /*!
2525   Find any of this collision node's children that has type \a t
2526   and subtype \a st and return a pointer to it.
2527 */
2528 InnerNode* NameCollisionNode::findAny(Node::Type t, Node::SubType st)
2529 {
2530     if (current) {
2531         if (current->type() == t && current->subType() == st)
2532             return current;
2533     }
2534     const NodeList& cn = childNodes();
2535     NodeList::ConstIterator i = cn.constBegin();
2536     while (i != cn.constEnd()) {
2537         if ((*i)->type() == t && (*i)->subType() == st)
2538             return static_cast<InnerNode*>(*i);
2539         ++i;
2540     }
2541     return 0;
2542 }
2543
2544 /*!
2545   This node is a name collision node. Find a child of this node
2546   such that the child's QML module identifier matches origin's
2547   QML module identifier. Return the matching node, or return this
2548   node if there is no matching node.
2549  */
2550 const Node* NameCollisionNode::applyModuleIdentifier(const Node* origin) const
2551 {
2552     if (origin && !origin->qmlModuleIdentifier().isEmpty()) {
2553         const NodeList& cn = childNodes();
2554         NodeList::ConstIterator i = cn.constBegin();
2555         while (i != cn.constEnd()) {
2556             if ((*i)->type() == Node::Fake && (*i)->subType() == Node::QmlClass) {
2557                 if (origin->qmlModuleIdentifier() == (*i)->qmlModuleIdentifier())
2558                     return (*i);
2559             }
2560             ++i;
2561         }
2562     }
2563     return this;
2564 }
2565
2566 /*!
2567   Construct the full document name for this node and return it.
2568  */
2569 QString Node::fullDocumentName() const
2570 {
2571     QStringList pieces;
2572     const Node* n = this;
2573
2574     do {
2575         if (!n->name().isEmpty() &&
2576                 ((n->type() != Node::Fake) || (n->subType() != Node::QmlPropertyGroup)))
2577             pieces.insert(0, n->name());
2578
2579         if ((n->type() == Node::Fake) && (n->subType() != Node::QmlPropertyGroup)) {
2580             if ((n->subType() == Node::QmlClass) && !n->qmlModuleName().isEmpty())
2581                 pieces.insert(0, n->qmlModuleIdentifier());
2582             break;
2583         }
2584
2585         // Examine the parent node if one exists.
2586         if (n->parent())
2587             n = n->parent();
2588         else
2589             break;
2590     } while (true);
2591
2592     // Create a name based on the type of the ancestor node.
2593     QString concatenator = "::";
2594     if ((n->type() == Node::Fake) && (n->subType() != Node::QmlClass))
2595         concatenator = QLatin1Char('#');
2596
2597     return pieces.join(concatenator);
2598 }
2599
2600 /*!
2601   Returns the \a str as an NCName, which means the name can
2602   be used as the value of an \e id attribute. Search for NCName
2603   on the internet for details of what can be an NCName.
2604  */
2605 QString Node::cleanId(QString str)
2606 {
2607     QString clean;
2608     QString name = str.simplified();
2609
2610     if (name.isEmpty())
2611         return clean;
2612
2613     name = name.replace("::","-");
2614     name = name.replace(QLatin1Char(' '), QLatin1Char('-'));
2615     name = name.replace("()","-call");
2616
2617     clean.reserve(name.size() + 20);
2618     if (!str.startsWith("id-"))
2619         clean = "id-";
2620     const QChar c = name[0];
2621     const uint u = c.unicode();
2622
2623     if ((u >= 'a' && u <= 'z') ||
2624             (u >= 'A' && u <= 'Z') ||
2625             (u >= '0' && u <= '9')) {
2626         clean += c;
2627     }
2628     else if (u == '~') {
2629         clean += "dtor.";
2630     }
2631     else if (u == '_') {
2632         clean += "underscore.";
2633     }
2634     else {
2635         clean += QLatin1Char('a');
2636     }
2637
2638     for (int i = 1; i < (int) name.length(); i++) {
2639         const QChar c = name[i];
2640         const uint u = c.unicode();
2641         if ((u >= 'a' && u <= 'z') ||
2642                 (u >= 'A' && u <= 'Z') ||
2643                 (u >= '0' && u <= '9') || u == '-' ||
2644                 u == '_' || u == '.') {
2645             clean += c;
2646         }
2647         else if (c.isSpace() || u == ':' ) {
2648             clean += QLatin1Char('-');
2649         }
2650         else if (u == '!') {
2651             clean += "-not";
2652         }
2653         else if (u == '&') {
2654             clean += "-and";
2655         }
2656         else if (u == '<') {
2657             clean += "-lt";
2658         }
2659         else if (u == '=') {
2660             clean += "-eq";
2661         }
2662         else if (u == '>') {
2663             clean += "-gt";
2664         }
2665         else if (u == '#') {
2666             clean += "-hash";
2667         }
2668         else if (u == '(') {
2669             clean += QLatin1Char('-');
2670         }
2671         else if (u == ')') {
2672             clean += QLatin1Char('-');
2673         }
2674         else {
2675             clean += QLatin1Char('-');
2676             clean += QString::number((int)u, 16);
2677         }
2678     }
2679     return clean;
2680 }
2681
2682 /*!
2683   Creates a string that can be used as a UUID for the node,
2684   depending on the type and subtype of the node. Uniquenss
2685   is not guaranteed, but it is expected that strings created
2686   here will be unique within an XML document. Hence, the
2687   returned string can be used as the value of an \e id
2688   attribute.
2689  */
2690 QString Node::idForNode() const
2691 {
2692     const FunctionNode* func;
2693     const TypedefNode* tdn;
2694     QString str;
2695
2696     switch (type()) {
2697     case Node::Namespace:
2698         str = "namespace-" + fullDocumentName();
2699         break;
2700     case Node::Class:
2701         str = "class-" + fullDocumentName();
2702         break;
2703     case Node::Enum:
2704         str = "enum-" + name();
2705         break;
2706     case Node::Typedef:
2707         tdn = static_cast<const TypedefNode*>(this);
2708         if (tdn->associatedEnum()) {
2709             return tdn->associatedEnum()->idForNode();
2710         }
2711         else {
2712             str = "typedef-" + name();
2713         }
2714         break;
2715     case Node::Function:
2716         func = static_cast<const FunctionNode*>(this);
2717         if (func->associatedProperty()) {
2718             return func->associatedProperty()->idForNode();
2719         }
2720         else {
2721             if (func->name().startsWith("operator")) {
2722                 str.clear();
2723                 /*
2724                   The test below should probably apply to all
2725                   functions, but for now, overloaded operators
2726                   are the only ones that produce duplicate id
2727                   attributes in the DITA XML files.
2728                  */
2729                 if (relatesTo_)
2730                     str = "nonmember-";
2731                 QString op = func->name().mid(8);
2732                 if (!op.isEmpty()) {
2733                     int i = 0;
2734                     while (i<op.size() && op.at(i) == ' ')
2735                         ++i;
2736                     if (i>0 && i<op.size()) {
2737                         op = op.mid(i);
2738                     }
2739                     if (!op.isEmpty()) {
2740                         i = 0;
2741                         while (i < op.size()) {
2742                             const QChar c = op.at(i);
2743                             const uint u = c.unicode();
2744                             if ((u >= 'a' && u <= 'z') ||
2745                                     (u >= 'A' && u <= 'Z') ||
2746                                     (u >= '0' && u <= '9'))
2747                                 break;
2748                             ++i;
2749                         }
2750                         str += "operator-";
2751                         if (i>0) {
2752                             QString tail = op.mid(i);
2753                             op = op.left(i);
2754                             if (operators_.contains(op)) {
2755                                 str += operators_.value(op);
2756                                 if (!tail.isEmpty())
2757                                     str += QLatin1Char('-') + tail;
2758                             }
2759                             else
2760                                 qDebug() << "qdoc internal error: Operator missing from operators_ map:" << op;
2761                         }
2762                         else {
2763                             str += op;
2764                         }
2765                     }
2766                 }
2767             }
2768             else if (parent_) {
2769                 if (parent_->type() == Class)
2770                     str = "class-member-" + func->name();
2771                 else if (parent_->type() == Namespace)
2772                     str = "namespace-member-" + func->name();
2773                 else if (parent_->type() == Fake) {
2774                     if (parent_->subType() == QmlClass)
2775                         str = "qml-method-" + parent_->name().toLower() + "-" + func->name();
2776                     else
2777                         qDebug() << "qdoc internal error: Node subtype not handled:"
2778                                  << parent_->subType() << func->name();
2779                 }
2780                 else
2781                     qDebug() << "qdoc internal error: Node type not handled:"
2782                              << parent_->type() << func->name();
2783
2784             }
2785             if (func->overloadNumber() != 1)
2786                 str += QLatin1Char('-') + QString::number(func->overloadNumber());
2787         }
2788         break;
2789     case Node::Fake:
2790         {
2791             switch (subType()) {
2792             case Node::QmlClass:
2793                 str = "qml-class-" + name();
2794                 break;
2795             case Node::QmlPropertyGroup:
2796                 {
2797                     Node* n = const_cast<Node*>(this);
2798                     str = "qml-propertygroup-" + n->name();
2799                 }
2800                 break;
2801             case Node::Page:
2802             case Node::Group:
2803             case Node::Module:
2804             case Node::HeaderFile:
2805                 str = title();
2806                 if (str.isEmpty()) {
2807                     str = name();
2808                     if (str.endsWith(".html"))
2809                         str.remove(str.size()-5,5);
2810                 }
2811                 str.replace(QLatin1Char('/'), QLatin1Char('-'));
2812                 break;
2813             case Node::File:
2814                 str = name();
2815                 str.replace(QLatin1Char('/'), QLatin1Char('-'));
2816                 break;
2817             case Node::Example:
2818                 str = name();
2819                 str.replace(QLatin1Char('/'), QLatin1Char('-'));
2820                 break;
2821             case Node::QmlBasicType:
2822                 str = "qml-basic-type-" + name();
2823                 break;
2824             case Node::QmlModule:
2825                 str = "qml-module-" + name();
2826                 break;
2827             case Node::Collision:
2828                 str = title();
2829                 str.replace(": ","-");
2830                 break;
2831             default:
2832                 qDebug() << "ERROR: A case was not handled in Node::idForNode():"
2833                          << "subType():" << subType() << "type():" << type();
2834                 break;
2835             }
2836         }
2837         break;
2838     case Node::QmlProperty:
2839         str = "qml-property-" + name();
2840         break;
2841     case Node::Property:
2842         str = "property-" + name();
2843         break;
2844     case Node::QmlSignal:
2845         str = "qml-signal-" + name();
2846         break;
2847     case Node::QmlSignalHandler:
2848         str = "qml-signal-handler-" + name();
2849         break;
2850     case Node::QmlMethod:
2851         func = static_cast<const FunctionNode*>(this);
2852         str = "qml-method-" + parent_->name().toLower() + "-" + func->name();
2853         if (func->overloadNumber() != 1)
2854             str += QLatin1Char('-') + QString::number(func->overloadNumber());
2855         break;
2856     case Node::Variable:
2857         str = "var-" + name();
2858         break;
2859     default:
2860         qDebug() << "ERROR: A case was not handled in Node::idForNode():"
2861                  << "type():" << type() << "subType():" << subType();
2862         break;
2863     }
2864     if (str.isEmpty()) {
2865         qDebug() << "ERROR: A link text was empty in Node::idForNode():"
2866                  << "type():" << type() << "subType():" << subType()
2867                  << "name():" << name()
2868                  << "title():" << title();
2869     }
2870     else {
2871         str = cleanId(str);
2872     }
2873     return str;
2874 }
2875
2876 QT_END_NAMESPACE