1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the tools applications of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
44 #include "codemarker.h"
45 #include "codeparser.h"
51 int Node::propertyGroupCount_ = 0;
52 ExampleNodeMap ExampleNode::exampleNodeMap;
53 QStringMap Node::operators_;
56 Increment the number of property groups seen in the current
57 file, and return the new value.
59 int Node::incPropertyGroupCount() { return ++propertyGroupCount_; }
62 Reset the number of property groups seen in the current file
63 to 0, because we are starting a new file.
65 void Node::clearPropertyGroupCount() { propertyGroupCount_ = 0; }
69 \brief The Node class is a node in the Tree.
71 A Node represents a class or function or something else
72 from the source code..
76 When this Node is destroyed, if it has a parent Node, it
77 removes itself from the parent node's child list.
82 parent_->removeChild(this);
84 relatesTo_->removeRelated(this);
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
94 void Node::setDoc(const Doc& doc, bool replace)
96 if (!d.isEmpty() && !replace) {
97 doc.location().warning(tr("Overrides a previous doc"));
98 d.location().warning(tr("(The previous doc is here)"));
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
108 Node::Node(Type type, InnerNode *parent, const QString& name)
111 safeness_(UnspecifiedSafeness),
112 pageType_(NoPageType),
113 status_(Commendable),
114 indexNodeFlag_(false),
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");
169 Returns the node's URL.
171 QString Node::url() const
177 Sets the node's URL to \a url
179 void Node::setUrl(const QString &url)
185 Returns this node's page type as a string, for use as an
186 attribute value in XML or HTML.
188 QString Node::pageTypeString() const
190 return pageTypeString(pageType_);
194 Returns the page type \a t as a string, for use as an
195 attribute value in XML or HTML.
197 QString Node::pageTypeString(unsigned t)
199 switch ((PageType)t) {
202 case Node::ArticlePage:
204 case Node::ExamplePage:
206 case Node::HowToPage:
208 case Node::OverviewPage:
210 case Node::TutorialPage:
214 case Node::DitaMapPage:
222 Returns this node's type as a string for use as an
223 attribute value in XML or HTML.
225 QString Node::nodeTypeString() const
227 return nodeTypeString(type());
231 Returns the node type \a t as a string for use as an
232 attribute value in XML or HTML.
234 QString Node::nodeTypeString(unsigned t)
254 return "QML property";
257 case QmlSignalHandler:
258 return "QML signal handler";
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.
272 QString Node::nodeSubtypeString() const
274 return nodeSubtypeString(subType());
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.
282 QString Node::nodeSubtypeString(unsigned t)
284 switch ((SubType)t) {
288 return "header file";
300 return "external page";
303 case QmlPropertyGroup:
304 return "QML property group";
306 return "QML basic type";
321 Set the page type according to the string \a t.
323 void Node::setPageType(const QString& t)
325 if ((t == "API") || (t == "api"))
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;
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.
347 Node::FlagValue Node::toFlagValue(bool b)
349 return b ? FlagValueTrue : FlagValueFalse;
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
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.
363 bool Node::fromFlagValue(FlagValue fv, bool defaultValue)
376 Sets the pointer to the node that this node relates to.
378 void Node::setRelates(InnerNode *pseudoParent)
381 relatesTo_->removeRelated(this);
383 relatesTo_ = pseudoParent;
384 pseudoParent->related_.append(this);
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.
392 void Node::setLink(LinkType linkType, const QString &link, const QString &desc)
394 QPair<QString,QString> linkPair;
395 linkPair.first = link;
396 linkPair.second = desc;
397 linkMap[linkType] = linkPair;
401 Sets the information about the project and version a node was introduced
402 in. The string is simplified, removing excess whitespace before being
405 void Node::setSince(const QString &since)
407 sinc = since.simplified();
411 Returns a string representing the access specifier.
413 QString Node::accessString() const
428 Extract a class name from the type \a string and return it.
430 QString Node::extractClassName(const QString &string) const
433 for (int i=0; i<=string.size(); ++i) {
435 if (i != string.size())
438 QChar lower = ch.toLower();
439 if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) ||
440 ch.digitValue() >= 0 ||
441 ch == QLatin1Char('_') ||
442 ch == QLatin1Char(':')) {
445 else if (!result.isEmpty()) {
446 if (result != QLatin1String("const"))
455 Returns a string representing the access specifier.
457 QString RelatedClass::accessString() const
460 case Node::Protected:
472 Returns the inheritance status.
474 Node::Status Node::inheritedStatus() const
476 Status parentStatus = Commendable;
478 parentStatus = parent_->inheritedStatus();
479 return (Status)qMin((int)status_, (int)parentStatus);
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?
489 Node::ThreadSafeness Node::threadSafeness() const
491 if (parent_ && safeness_ == parent_->inheritedThreadSafeness())
492 return UnspecifiedSafeness;
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?
501 Node::ThreadSafeness Node::inheritedThreadSafeness() const
503 if (parent_ && safeness_ == UnspecifiedSafeness)
504 return parent_->inheritedThreadSafeness();
509 Returns the sanitized file name without the path.
510 If the the file is an html file, the html suffix
513 QString Node::fileBase() const
515 QString base = name();
516 if (base.endsWith(".html"))
518 base.replace(QRegExp("[^A-Za-z0-9]+"), " ");
519 base = base.trimmed();
520 base.replace(QLatin1Char(' '), QLatin1Char('-'));
521 return base.toLower();
525 Returns this node's Universally Unique IDentifier as a
526 QString. Creates the UUID first, if it has not been created.
528 QString Node::guid() const
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.
542 QString Node::ditaXmlHref()
545 if ((type() == Function) ||
546 (type() == Property) ||
547 (type() == Variable)) {
548 href = parent()->fileBase();
553 if (!href.endsWith(".xml") && !href.endsWith(".dita"))
555 return href + QLatin1Char('#') + guid();
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;
563 QmlClassNode* Node::qmlClassNode()
567 while (n && n->subType() != Node::QmlClass)
569 if (n && n->subType() == Node::QmlClass)
570 return static_cast<QmlClassNode*>(n);
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.
582 ClassNode* Node::declarativeCppNode()
584 QmlClassNode* qcn = qmlClassNode();
586 return qcn->classNode();
591 Returns true if the node's status is Internal, or if its
592 parent is a class with internal status.
594 bool Node::isInternal() const
596 if (status() == Internal)
598 if (parent() && parent()->status() == Internal)
600 if (relates() && relates()->status() == Internal)
610 The inner node destructor deletes the children and removes
611 this node from its related nodes.
613 InnerNode::~InnerNode()
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.
625 Node *InnerNode::findChildNodeByName(const QString& name)
627 Node *node = childMap.value(name);
628 if (node && node->subType() != QmlPropertyGroup)
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);
640 return primaryFunctionMap.value(name);
642 void InnerNode::findNodes(const QString& name, QList<Node*>& n)
646 QList<Node*> nodes = childMap.values(name);
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.
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);
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
677 for (int i=0; i<nodes.size(); ++i) {
679 if (node->subType() != QmlPropertyGroup)
682 node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
690 node = primaryFunctionMap.value(name);
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.
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.
705 Node* InnerNode::findChildNodeByName(const QString& name, bool qml)
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);
712 if (!node->isQmlNode())
715 else if (node->isQmlNode() && (node->subType() != QmlPropertyGroup))
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);
729 return primaryFunctionMap.value(name);
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.
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
743 Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type)
745 if (type == Function)
746 return primaryFunctionMap.value(name);
748 Node *node = childMap.value(name);
749 if (node && node->type() == type)
756 Find a function node that is a child of this nose, such
757 that the function node has the specified \a name.
759 FunctionNode *InnerNode::findFunctionNode(const QString& name)
761 return static_cast<FunctionNode *>(primaryFunctionMap.value(name));
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
769 FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone)
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;
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;
790 Returns the list of keys from the primary function map.
792 QStringList InnerNode::primaryKeys()
795 QMap<QString, Node*>::iterator i = primaryFunctionMap.begin();
796 while (i != primaryFunctionMap.end()) {
804 Returns the list of keys from the secondary function map.
806 QStringList InnerNode::secondaryKeys()
809 QMap<QString, NodeList>::iterator i = secondaryFunctionMap.begin();
810 while (i != secondaryFunctionMap.end()) {
819 void InnerNode::setOverload(const FunctionNode *func, bool overlode)
821 Node *node = (Node *) func;
822 Node *&primary = primaryFunctionMap[func->name()];
824 if (secondaryFunctionMap.contains(func->name())) {
825 NodeList& secs = secondaryFunctionMap[func->name()];
827 if (primary == node) {
828 primary = secs.first();
829 secs.erase(secs.begin());
833 secs.removeAll(node);
838 if (primary != node) {
839 secs.removeAll(node);
840 secs.prepend(primary);
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.
852 \note Exception: Name collision nodes are not marked
855 void InnerNode::makeUndocumentedChildrenInternal()
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);
868 In each child node that is a collision node,
869 clear the current child pointer.
871 void InnerNode::clearCurrentChildPointers()
873 foreach (Node* child, childNodes()) {
874 if (child->subType() == Collision) {
875 child->clearCurrentChild();
882 void InnerNode::normalizeOverloads()
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)) {
891 NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
892 NodeList::ConstIterator s = secs.constBegin();
893 while (s != secs.constEnd()) {
894 FunctionNode *secondaryFunc = (FunctionNode *) *s;
896 // Any non-obsolete, non-compatibility, non-private functions
897 // (i.e, visible functions) are preferable to the primary
900 if (secondaryFunc->status() == Commendable &&
901 secondaryFunc->access() != Private) {
904 int index = secondaryFunctionMap[primaryFunc->name()].indexOf(secondaryFunc);
905 secondaryFunctionMap[primaryFunc->name()].replace(index, primaryFunc);
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;
932 NodeList::ConstIterator c = childNodes().constBegin();
933 while (c != childNodes().constEnd()) {
934 if ((*c)->isInnerNode())
935 ((InnerNode *) *c)->normalizeOverloads();
942 void InnerNode::removeFromRelated()
944 while (!related_.isEmpty()) {
945 Node *p = static_cast<Node *>(related_.takeFirst());
947 if (p != 0 && p->relates() == this) p->clearRelated();
952 Deletes all this node's children.
954 void InnerNode::deleteChildren()
956 NodeList childrenCopy = children; // `children` will be changed in ~Node()
957 qDeleteAll(childrenCopy);
960 /*! \fn bool InnerNode::isInnerNode() const
961 Returns true because this is an inner node.
966 const Node *InnerNode::findChildNodeByName(const QString& name) const
968 InnerNode *that = (InnerNode *) this;
969 return that->findChildNodeByName(name);
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.
977 const Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const
979 InnerNode*that = (InnerNode*) this;
980 return that->findChildNodeByName(name, qml);
984 Searches this node's children for a child named \a name
985 with the specified node \a type.
987 const Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type) const
989 InnerNode *that = (InnerNode *) this;
990 return that->findChildNodeByNameAndType(name, type);
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.
998 const FunctionNode *InnerNode::findFunctionNode(const QString& name) const
1000 InnerNode *that = (InnerNode *) this;
1001 return that->findFunctionNode(name);
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.
1009 const FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone) const
1011 InnerNode *that = (InnerNode *) this;
1012 return that->findFunctionNode(clone);
1017 const EnumNode *InnerNode::findEnumNodeForValue(const QString &enumValue) const
1019 foreach (const Node *node, enumChildren) {
1020 const EnumNode *enume = static_cast<const EnumNode *>(node);
1021 if (enume->hasItem(enumValue))
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.
1032 int InnerNode::overloadNumber(const FunctionNode *func) const
1034 Node *node = (Node *) func;
1035 if (primaryFunctionMap[func->name()] == node) {
1039 return secondaryFunctionMap[func->name()].indexOf(node) + 2;
1044 Returns a node list containing all the member functions of
1045 some class such that the functions overload the name \a funcName.
1047 NodeList InnerNode::overloads(const QString &funcName) const
1050 Node *primary = primaryFunctionMap.value(funcName);
1053 result += secondaryFunctionMap[funcName];
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.
1062 InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name)
1063 : Node(type, parent, name)
1068 setPageType(ApiPage);
1076 Appends an \a include file to the list of include files.
1078 void InnerNode::addInclude(const QString& include)
1080 inc.append(include);
1084 Sets the list of include files to \a includes.
1086 void InnerNode::setIncludes(const QStringList& includes)
1092 f1 is always the clone
1094 bool InnerNode::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
1096 if (f1->parameters().count() != f2->parameters().count())
1098 if (f1->isConst() != f2->isConst())
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())
1108 QString t1 = p1->leftType();
1109 QString t2 = p2->leftType();
1111 if (t1.length() < t2.length())
1115 ### hack for C++ to handle superfluous
1116 "Foo::" prefixes gracefully
1118 if (t1 != t2 && t1 != (f2->parent()->name() + "::" + t2))
1128 Adds the \a child to this node's child list.
1130 void InnerNode::addChild(Node *child)
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);
1139 NodeList &secs = secondaryFunctionMap[func->name()];
1144 if (child->type() == Enum)
1145 enumChildren.append(child);
1146 childMap.insertMulti(child->name(), child);
1152 void InnerNode::removeChild(Node *child)
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());
1165 primaryFunctionMap.insert(child->name(), secs.takeFirst());
1169 secs.removeAll(child);
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);
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.
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.
1192 QString Node::moduleName() const
1197 QString path = location().filePath();
1198 QString pattern = QString("src") + QDir::separator();
1199 int start = path.lastIndexOf(pattern);
1204 QString moduleDir = path.mid(start + pattern.size());
1205 int finish = moduleDir.indexOf(QDir::separator());
1210 QString moduleName = moduleDir.left(finish);
1212 if (moduleName == "corelib")
1214 else if (moduleName == "uitools")
1216 else if (moduleName == "gui")
1218 else if (moduleName == "network")
1220 else if (moduleName == "opengl")
1222 else if (moduleName == "svg")
1224 else if (moduleName == "sql")
1226 else if (moduleName == "qtestlib")
1228 else if (moduleDir.contains("webkit"))
1230 else if (moduleName == "xml")
1238 void InnerNode::removeRelated(Node *pseudoChild)
1240 related_.removeAll(pseudoChild);
1247 /*! \fn bool LeafNode::isInnerNode() const
1248 Returns false because this is a LeafNode.
1252 Constructs a leaf node named \a name of the specified
1253 \a type. The new leaf node becomes a child of \a parent.
1255 LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name)
1256 : Node(type, parent, name)
1265 case QmlSignalHandler:
1267 setPageType(ApiPage);
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.
1281 LeafNode::LeafNode(InnerNode* parent, Type type, const QString& name)
1282 : Node(type, 0, name)
1292 case QmlSignalHandler:
1294 setPageType(ApiPage);
1303 \class NamespaceNode
1307 Constructs a namespace node.
1309 NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name)
1310 : InnerNode(Namespace, parent, name)
1312 setPageType(ApiPage);
1317 \brief This class represents a C++ class.
1321 Constructs a class node. A class node will generate an API page.
1323 ClassNode::ClassNode(InnerNode *parent, const QString& name)
1324 : InnerNode(Class, parent, name)
1329 setPageType(ApiPage);
1334 void ClassNode::addBaseClass(Access access,
1336 const QString &dataTypeWithTemplateArgs)
1338 bases.append(RelatedClass(access, node, dataTypeWithTemplateArgs));
1339 node->derived.append(RelatedClass(access, this));
1344 void ClassNode::fixBaseClasses()
1348 QSet<ClassNode *> found;
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);
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));
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));
1383 Search the child list to find the property node with the
1386 PropertyNode* ClassNode::findPropertyNode(const QString& name)
1388 Node* n = findChildNodeByNameAndType(name, Node::Property);
1391 return static_cast<PropertyNode*>(n);
1393 PropertyNode* pn = 0;
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);
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);
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.
1423 QmlClassNode* ClassNode::findQmlBaseNode()
1425 QmlClassNode* result = 0;
1426 const QList<RelatedClass>& bases = baseClasses();
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();
1435 for (int i = 0; i < bases.size(); ++i) {
1436 ClassNode* cn = bases[i].node;
1438 result = cn->findQmlBaseNode();
1448 QMap<QString, FakeNode*> FakeNode::qmlModuleMap_;
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.
1459 FakeNode::FakeNode(InnerNode* parent, const QString& name, SubType subtype, Node::PageType ptype)
1460 : InnerNode(Fake, parent, name), nodeSubtype_(subtype)
1471 setPageType(OverviewPage);
1474 setPageType(OverviewPage);
1478 setPageType(ApiPage);
1481 setPageType(ExamplePage);
1492 Returns the fake node's title. This is used for the page title.
1494 QString FakeNode::title() const
1500 Returns the fake node's full title, which is usually
1501 just title(), but for some SubType values is different
1504 QString FakeNode::fullTitle() const
1506 if (nodeSubtype_ == File) {
1507 if (title().isEmpty())
1508 return name().mid(name().lastIndexOf('/') + 1) + " Example File";
1512 else if (nodeSubtype_ == Image) {
1513 if (title().isEmpty())
1514 return name().mid(name().lastIndexOf('/') + 1) + " Image File";
1518 else if (nodeSubtype_ == HeaderFile) {
1519 if (title().isEmpty())
1522 return name() + " - " + title();
1524 else if (nodeSubtype_ == Collision) {
1533 Returns the subtitle.
1535 QString FakeNode::subTitle() const
1537 if (!subtitle_.isEmpty())
1540 if ((nodeSubtype_ == File) || (nodeSubtype_ == Image)) {
1541 if (title().isEmpty() && name().contains(QLatin1Char('/')))
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>}
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.
1556 void FakeNode::insertQmlModuleNode(const QString& qmid, FakeNode* fn)
1558 if (!qmlModuleMap_.contains(qmid))
1559 qmlModuleMap_.insert(qmid,fn);
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.
1569 FakeNode* FakeNode::lookupQmlModuleNode(Tree* tree, const ArgLocPair& arg)
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];
1579 if (qmlModuleMap_.contains(qmid))
1580 fn = qmlModuleMap_.value(qmid);
1582 fn = new FakeNode(tree->root(), arg.first, Node::QmlModule, Node::OverviewPage);
1583 fn->setQmlModule(arg);
1584 insertQmlModuleNode(qmid,fn);
1590 Returns true if this QML type or property group contains a
1591 property named \a name.
1593 bool FakeNode::hasProperty(const QString& name) const
1595 foreach (Node* child, childNodes()) {
1596 if (child->type() == Node::Fake && child->subType() == Node::QmlPropertyGroup) {
1597 if (child->hasProperty(name))
1600 else if (child->type() == Node::QmlProperty) {
1601 if (child->hasProperty(name))
1609 The constructor calls the FakeNode constructor with
1610 \a parent, \a name, and Node::Example.
1612 ExampleNode::ExampleNode(InnerNode* parent, const QString& name)
1613 : FakeNode(parent, name, Node::Example, Node::ExamplePage)
1623 The constructor for the node representing an enum type
1624 has a \a parent class and an enum type \a name.
1626 EnumNode::EnumNode(InnerNode *parent, const QString& name)
1627 : LeafNode(Enum, parent, name), ft(0)
1633 Add \a item to the enum type's item list.
1635 void EnumNode::addItem(const EnumItem& item)
1638 names.insert(item.name());
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.
1646 Node::Access EnumNode::itemAccess(const QString &name) const
1648 if (doc().omitEnumItemNames().contains(name))
1654 Returns the enum value associated with the enum \a name.
1656 QString EnumNode::itemValue(const QString &name) const
1658 foreach (const EnumItem &item, itms) {
1659 if (item.name() == name)
1660 return item.value();
1671 TypedefNode::TypedefNode(InnerNode *parent, const QString& name)
1672 : LeafNode(Typedef, parent, name), ae(0)
1678 void TypedefNode::setAssociatedEnum(const EnumNode *enume)
1685 \brief The class Parameter contains one parameter.
1687 A parameter can be a function parameter or a macro
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.
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)
1706 The standard copy constructor copies the strings from \a p.
1708 Parameter::Parameter(const Parameter& p)
1709 : lef(p.lef), rig(p.rig), nam(p.nam), def(p.def)
1714 Assigning Parameter \a p to this Parameter copies the
1717 Parameter& Parameter::operator=(const Parameter& p)
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.
1731 QString Parameter::reconstruct(bool value) const
1733 QString p = lef + rig;
1734 if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
1735 p += QLatin1Char(' ');
1737 if (value && !def.isEmpty())
1748 Construct a function node for a C++ function. It's parent
1749 is \a parent, and it's name is \a name.
1751 FunctionNode::FunctionNode(InnerNode *parent, const QString& name)
1752 : LeafNode(Function, parent, name),
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.
1771 FunctionNode::FunctionNode(Type type, InnerNode *parent, const QString& name, bool attached)
1772 : LeafNode(type, parent, name),
1779 attached_(attached),
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.
1791 void FunctionNode::setVirtualness(Virtualness virtualness)
1794 if ((virtualness == PureVirtual) && parent() &&
1795 (parent()->type() == Node::Class))
1796 parent()->setAbstract(true);
1801 void FunctionNode::setOverload(bool overlode)
1803 parent()->setOverload(this, overlode);
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
1814 void FunctionNode::setReimp(bool r)
1821 void FunctionNode::addParameter(const Parameter& parameter)
1823 params.append(parameter);
1828 void FunctionNode::borrowParameterNames(const FunctionNode *source)
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());
1841 If this function is a reimplementation, \a from points
1842 to the FunctionNode of the function being reimplemented.
1844 void FunctionNode::setReimplementedFrom(FunctionNode *from)
1847 from->rb.append(this);
1851 Sets the "associated" property to \a property. The function
1852 might be the setter or getter for a property, for example.
1854 void FunctionNode::setAssociatedProperty(PropertyNode *property)
1860 Returns the overload number for this function obtained
1863 int FunctionNode::overloadNumber() const
1865 return parent()->overloadNumber(this);
1869 Returns the list of parameter names.
1871 QStringList FunctionNode::parameterNames() const
1874 QList<Parameter>::ConstIterator p = parameters().constBegin();
1875 while (p != parameters().constEnd()) {
1876 names << (*p).name();
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.
1887 QString FunctionNode::rawParameters(bool names, bool values) const
1890 foreach (const Parameter ¶meter, parameters()) {
1891 raw += parameter.leftType() + parameter.rightType();
1893 raw += parameter.name();
1895 raw += parameter.defaultValue();
1901 Returns the list of reconstructed parameters. If \a values
1902 is true, the default values are included, if any are present.
1904 QStringList FunctionNode::reconstructParams(bool values) const
1907 QList<Parameter>::ConstIterator p = parameters().constBegin();
1908 while (p != parameters().constEnd()) {
1909 params << (*p).reconstruct(values);
1916 Reconstructs and returns the function's signature. If \a values
1917 is true, the default values of the parameters are included, if
1920 QString FunctionNode::signature(bool values) const
1923 if (!returnType().isEmpty())
1924 s = returnType() + QLatin1Char(' ');
1925 s += name() + QLatin1Char('(');
1926 QStringList params = reconstructParams(values);
1927 int p = params.size();
1929 for (int i=0; i<p; i++) {
1935 s += QLatin1Char(')');
1940 Print some debugging stuff.
1942 void FunctionNode::debug() const
1944 qDebug("QML METHOD %s rt %s pp %s",
1945 qPrintable(name()), qPrintable(rt), qPrintable(pp.join(" ")));
1951 This class describes one instance of using the Q_PROPERTY macro.
1955 The constructor sets the \a parent and the \a name, but
1956 everything else is set to default values.
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),
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
1980 We probably should ensure that the constant and final
1981 attributes are not being overridden improperly.
1983 void PropertyNode::setOverriddenFrom(const PropertyNode* baseProperty)
1985 for (int i = 0; i < NumFunctionRoles; ++i) {
1986 if (funcs[i].isEmpty())
1987 funcs[i] = baseProperty->funcs[i];
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;
2004 QString PropertyNode::qualifiedDataType() const
2006 if (setters().isEmpty() && resetters().isEmpty()) {
2007 if (type_.contains(QLatin1Char('*')) || type_.contains(QLatin1Char('&'))) {
2008 // 'QWidget *' becomes 'QWidget *' const
2009 return type_ + " const";
2013 'int' becomes 'const int' ('int const' is
2014 correct C++, but looks wrong)
2016 return "const " + type_;
2024 bool QmlClassNode::qmlOnly = false;
2025 QMultiMap<QString,Node*> QmlClassNode::inheritedBy;
2026 QMap<QString, QmlClassNode*> QmlClassNode::qmlModuleMemberMap_;
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.
2035 QmlClassNode::QmlClassNode(InnerNode *parent,
2036 const QString& name,
2038 : FakeNode(parent, name, QmlClass, Node::ApiPage),
2040 cnodeRequired_(false),
2045 if (name.startsWith("QML:")) {
2046 qDebug() << "BOGUS QML qualifier:" << name;
2049 setTitle(name.mid(i));
2053 Needed for printing a debug messages.
2055 QmlClassNode::~QmlClassNode()
2061 Clear the static maps so that subsequent runs don't try to use
2062 contents from a previous run.
2064 void QmlClassNode::terminate()
2066 inheritedBy.clear();
2067 qmlModuleMemberMap_.clear();
2071 Insert the QML type node \a qcn into the static QML module
2072 member map. The key is \a qmid + "::" + qcn->name().
2074 void QmlClassNode::insertQmlModuleMember(const QString& qmid, QmlClassNode* qcn)
2076 qmlModuleMemberMap_.insert(qmid + "::" + qcn->name(), qcn);
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().
2084 QmlClassNode* QmlClassNode::lookupQmlTypeNode(const QString& qmid, const QString& name)
2086 return qmlModuleMemberMap_.value(qmid + "::" + name);
2090 The base file name for this kind of node has "qml_"
2093 But not yet. Still testing.
2095 QString QmlClassNode::fileBase() const
2097 return Node::fileBase();
2101 Record the fact that QML class \a base is inherited by
2104 void QmlClassNode::addInheritedBy(const QString& base, Node* sub)
2106 if (inheritedBy.constFind(base,sub) == inheritedBy.constEnd()) {
2107 inheritedBy.insert(base,sub);
2112 Loads the list \a subs with the nodes of all the subclasses of \a base.
2114 void QmlClassNode::subclasses(const QString& base, NodeList& subs)
2117 if (inheritedBy.count(base) > 0) {
2118 subs = inheritedBy.values(base);
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().
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.
2142 bool Node::setQmlModule(const ArgLocPair& arg)
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];
2157 arg.second.warning(tr("Minor version number must be included in second arg of '\\qmlmodule' and '\\inqmlmodule'; '.0' assumed."));
2160 arg.second.warning(tr("Module version number 'major.minor' must be second arg of '\\qmlmodule' and '\\inqmlmodule'; '1.0' assumed."));
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.
2176 void QmlClassNode::setCurrentChild()
2179 InnerNode* n = parent();
2180 if (n->subType() == Node::Collision)
2181 n->setCurrentChild(this);
2187 void QmlClassNode::clearCurrentChild()
2190 InnerNode* n = parent();
2191 if (n->subType() == Node::Collision)
2192 n->clearCurrentChild();
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.
2202 void QmlClassNode::resolveInheritance(Tree* tree)
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);
2210 base_ = static_cast<FakeNode*>(n);
2211 if (base_ && base_->subType() == Node::QmlClass) {
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));
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));
2239 QmlClassNode* qcn = cnode_->findQmlBaseNode();
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.
2251 QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent,
2252 const QString& name)
2253 : FakeNode(parent, name, QmlBasicType, Node::ApiPage)
2259 Constructor for the Qml property group node. \a parent is
2260 always a QmlClassNode.
2262 QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name)
2263 : FakeNode(parent, name, QmlPropertyGroup, Node::ApiPage)
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
2275 QString QmlPropGroupNode::idNumber()
2277 if (idNumber_ == -1)
2278 idNumber_ = incPropertyGroupCount();
2279 return QString().setNum(idNumber_);
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
2292 QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent,
2293 const QString& name,
2294 const QString& type,
2296 : LeafNode(QmlProperty, parent, name),
2298 stored_(FlagValueDefault),
2299 designable_(FlagValueDefault),
2301 attached_(attached),
2302 readOnly_(FlagValueDefault)
2304 setPageType(ApiPage);
2308 Constructor for the QML property node, when the \a parent
2309 is a QML class node.
2311 QmlPropertyNode::QmlPropertyNode(QmlClassNode *parent,
2312 const QString& name,
2313 const QString& type,
2315 : LeafNode(QmlProperty, parent, name),
2317 stored_(FlagValueDefault),
2318 designable_(FlagValueDefault),
2320 attached_(attached),
2321 readOnly_(FlagValueDefault)
2323 setPageType(ApiPage);
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
2337 QmlPropertyNode::QmlPropertyNode(QmlPropertyNode* parent,
2338 const QString& name,
2339 const QString& type,
2341 : LeafNode(parent->parent(), QmlProperty, name),
2343 stored_(FlagValueDefault),
2344 designable_(FlagValueDefault),
2346 attached_(attached),
2347 readOnly_(FlagValueDefault)
2349 setPageType(ApiPage);
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:
2359 bool PropertyChanges::explicit,
2362 ...because the tokenizer gets confused on \e{explicit}.
2364 bool QmlPropertyNode::isWritable(Tree* tree)
2366 if (readOnly_ != FlagValueDefault)
2367 return !fromFlagValue(readOnly_, false);
2369 QmlClassNode* qcn = qmlClassNode();
2371 if (qcn->cppClassRequired()) {
2372 if (qcn->classNode()) {
2373 PropertyNode* pn = correspondingProperty(tree);
2375 return pn->isWritable();
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()));
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()));
2393 Returns a pointer this QML property's corresponding C++
2394 property, if it has one.
2396 PropertyNode* QmlPropertyNode::correspondingProperty(Tree *tree)
2401 while (n && n->subType() != Node::QmlClass)
2404 QmlClassNode* qcn = static_cast<QmlClassNode*>(n);
2405 ClassNode* cn = qcn->classNode();
2407 QStringList dotSplit = name().split(QChar('.'));
2408 pn = cn->findPropertyNode(dotSplit[0]);
2410 if (dotSplit.size() > 1) {
2411 // Find the C++ property corresponding to the QML property in
2412 // the property group, <group>.<property>.
2414 QStringList path(extractClassName(pn->qualifiedDataType()));
2415 Node* nn = tree->findClassNode(path);
2417 ClassNode* cn = static_cast<ClassNode*>(nn);
2418 PropertyNode *pn2 = cn->findPropertyNode(dotSplit[1]);
2420 return pn2; // Return the property for the QML property.
2422 return pn; // Return the property for the QML group.
2429 pn = cn->findPropertyNode(dotSplit[0]);
2440 Returns true if this QML type or property group contains a
2441 property named \a name.
2443 bool QmlPropertyNode::hasProperty(const QString& n) const
2447 foreach (Node* child, qmlPropNodes()) {
2448 if (child->type() == Node::QmlProperty) {
2449 if (child->name() == n)
2456 /*! \class NameCollisionNode
2458 An instance of this node is inserted in the tree
2459 whenever qdoc discovers that two nodes have the
2464 Constructs a name collision node containing \a child
2465 as its first child. The parent of \a child becomes
2468 NameCollisionNode::NameCollisionNode(InnerNode* child)
2469 : FakeNode(child->parent(), child->name(), Collision, Node::NoPageType)
2471 setTitle("Name Collision: " + child->name());
2472 addCollision(child);
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.
2481 void NameCollisionNode::addCollision(InnerNode* child)
2484 if (child->parent())
2485 child->parent()->removeChild(child);
2486 child->setParent((InnerNode*)this);
2487 children.append(child);
2492 The destructor does nothing.
2494 NameCollisionNode::~NameCollisionNode()
2499 /*! \fn const InnerNode* NameCollisionNode::currentChild() const
2500 Returns a pointer to the current child, which may be 0.
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.
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.
2515 Returns true if this collision node's current node is a QML node.
2517 bool NameCollisionNode::isQmlNode() const
2520 return current->isQmlNode();
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.
2528 InnerNode* NameCollisionNode::findAny(Node::Type t, Node::SubType st)
2531 if (current->type() == t && current->subType() == st)
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);
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.
2550 const Node* NameCollisionNode::applyModuleIdentifier(const Node* origin) const
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())
2567 Construct the full document name for this node and return it.
2569 QString Node::fullDocumentName() const
2572 const Node* n = this;
2575 if (!n->name().isEmpty() &&
2576 ((n->type() != Node::Fake) || (n->subType() != Node::QmlPropertyGroup)))
2577 pieces.insert(0, n->name());
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());
2585 // Examine the parent node if one exists.
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('#');
2597 return pieces.join(concatenator);
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.
2605 QString Node::cleanId(QString str)
2608 QString name = str.simplified();
2613 name = name.replace("::","-");
2614 name = name.replace(QLatin1Char(' '), QLatin1Char('-'));
2615 name = name.replace("()","-call");
2617 clean.reserve(name.size() + 20);
2618 if (!str.startsWith("id-"))
2620 const QChar c = name[0];
2621 const uint u = c.unicode();
2623 if ((u >= 'a' && u <= 'z') ||
2624 (u >= 'A' && u <= 'Z') ||
2625 (u >= '0' && u <= '9')) {
2628 else if (u == '~') {
2631 else if (u == '_') {
2632 clean += "underscore.";
2635 clean += QLatin1Char('a');
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 == '.') {
2647 else if (c.isSpace() || u == ':' ) {
2648 clean += QLatin1Char('-');
2650 else if (u == '!') {
2653 else if (u == '&') {
2656 else if (u == '<') {
2659 else if (u == '=') {
2662 else if (u == '>') {
2665 else if (u == '#') {
2668 else if (u == '(') {
2669 clean += QLatin1Char('-');
2671 else if (u == ')') {
2672 clean += QLatin1Char('-');
2675 clean += QLatin1Char('-');
2676 clean += QString::number((int)u, 16);
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
2690 QString Node::idForNode() const
2692 const FunctionNode* func;
2693 const TypedefNode* tdn;
2697 case Node::Namespace:
2698 str = "namespace-" + fullDocumentName();
2701 str = "class-" + fullDocumentName();
2704 str = "enum-" + name();
2707 tdn = static_cast<const TypedefNode*>(this);
2708 if (tdn->associatedEnum()) {
2709 return tdn->associatedEnum()->idForNode();
2712 str = "typedef-" + name();
2715 case Node::Function:
2716 func = static_cast<const FunctionNode*>(this);
2717 if (func->associatedProperty()) {
2718 return func->associatedProperty()->idForNode();
2721 if (func->name().startsWith("operator")) {
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.
2731 QString op = func->name().mid(8);
2732 if (!op.isEmpty()) {
2734 while (i<op.size() && op.at(i) == ' ')
2736 if (i>0 && i<op.size()) {
2739 if (!op.isEmpty()) {
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'))
2752 QString tail = op.mid(i);
2754 if (operators_.contains(op)) {
2755 str += operators_.value(op);
2756 if (!tail.isEmpty())
2757 str += QLatin1Char('-') + tail;
2760 qDebug() << "qdoc internal error: Operator missing from operators_ map:" << op;
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();
2777 qDebug() << "qdoc internal error: Node subtype not handled:"
2778 << parent_->subType() << func->name();
2781 qDebug() << "qdoc internal error: Node type not handled:"
2782 << parent_->type() << func->name();
2785 if (func->overloadNumber() != 1)
2786 str += QLatin1Char('-') + QString::number(func->overloadNumber());
2791 switch (subType()) {
2792 case Node::QmlClass:
2793 str = "qml-class-" + name();
2795 case Node::QmlPropertyGroup:
2797 Node* n = const_cast<Node*>(this);
2798 str = "qml-propertygroup-" + n->name();
2804 case Node::HeaderFile:
2806 if (str.isEmpty()) {
2808 if (str.endsWith(".html"))
2809 str.remove(str.size()-5,5);
2811 str.replace(QLatin1Char('/'), QLatin1Char('-'));
2815 str.replace(QLatin1Char('/'), QLatin1Char('-'));
2819 str.replace(QLatin1Char('/'), QLatin1Char('-'));
2821 case Node::QmlBasicType:
2822 str = "qml-basic-type-" + name();
2824 case Node::QmlModule:
2825 str = "qml-module-" + name();
2827 case Node::Collision:
2829 str.replace(": ","-");
2832 qDebug() << "ERROR: A case was not handled in Node::idForNode():"
2833 << "subType():" << subType() << "type():" << type();
2838 case Node::QmlProperty:
2839 str = "qml-property-" + name();
2841 case Node::Property:
2842 str = "property-" + name();
2844 case Node::QmlSignal:
2845 str = "qml-signal-" + name();
2847 case Node::QmlSignalHandler:
2848 str = "qml-signal-handler-" + name();
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());
2856 case Node::Variable:
2857 str = "var-" + name();
2860 qDebug() << "ERROR: A case was not handled in Node::idForNode():"
2861 << "type():" << type() << "subType():" << subType();
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();