summaryrefslogtreecommitdiffstats
path: root/src/tools/qdoc/node.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/qdoc/node.cpp')
-rw-r--r--src/tools/qdoc/node.cpp2780
1 files changed, 2780 insertions, 0 deletions
diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp
new file mode 100644
index 00000000000..13c51c721d8
--- /dev/null
+++ b/src/tools/qdoc/node.cpp
@@ -0,0 +1,2780 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "node.h"
+#include "tree.h"
+#include "codemarker.h"
+#include "codeparser.h"
+#include <QUuid>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+ExampleNodeMap ExampleNode::exampleNodeMap;
+QStringMap Node::operators_;
+
+/*!
+ \class Node
+ \brief The Node class is a node in the Tree.
+
+ A Node represents a class or function or something else
+ from the source code..
+ */
+
+/*!
+ When this Node is destroyed, if it has a parent Node, it
+ removes itself from the parent node's child list.
+ */
+Node::~Node()
+{
+ if (parent_)
+ parent_->removeChild(this);
+ if (relatesTo_)
+ relatesTo_->removeRelated(this);
+}
+
+/*!
+ Sets this Node's Doc to \a doc. If \a replace is false and
+ this Node already has a Doc, a warning is reported that the
+ Doc is being overridden, and it reports where the previous
+ Doc was found. If \a replace is true, the Doc is replaced
+ silently.
+ */
+void Node::setDoc(const Doc& doc, bool replace)
+{
+ if (!d.isEmpty() && !replace) {
+ doc.location().warning(tr("Overrides a previous doc"));
+ d.location().warning(tr("(The previous doc is here)"));
+ }
+ d = doc;
+}
+
+/*!
+ Construct a node with the given \a type and having the
+ given \a parent and \a name. The new node is added to the
+ parent's child list.
+ */
+Node::Node(Type type, InnerNode *parent, const QString& name)
+ : nodeType_(type),
+ access_(Public),
+ safeness_(UnspecifiedSafeness),
+ pageType_(NoPageType),
+ status_(Commendable),
+ parent_(parent),
+ relatesTo_(0),
+ name_(name)
+{
+ if (parent_)
+ parent_->addChild(this);
+ outSubDir_ = CodeParser::currentOutputSubdirectory();
+ if (operators_.isEmpty()) {
+ operators_.insert("++","inc");
+ operators_.insert("--","dec");
+ operators_.insert("==","eq");
+ operators_.insert("!=","ne");
+ operators_.insert("<<","lt-lt");
+ operators_.insert(">>","gt-gt");
+ operators_.insert("+=","plus-assign");
+ operators_.insert("-=","minus-assign");
+ operators_.insert("*=","mult-assign");
+ operators_.insert("/=","div-assign");
+ operators_.insert("%=","mod-assign");
+ operators_.insert("&=","bitwise-and-assign");
+ operators_.insert("|=","bitwise-or-assign");
+ operators_.insert("^=","bitwise-xor-assign");
+ operators_.insert("<<=","bitwise-left-shift-assign");
+ operators_.insert(">>=","bitwise-right-shift-assign");
+ operators_.insert("||","logical-or");
+ operators_.insert("&&","logical-and");
+ operators_.insert("()","call");
+ operators_.insert("[]","subscript");
+ operators_.insert("->","pointer");
+ operators_.insert("->*","pointer-star");
+ operators_.insert("+","plus");
+ operators_.insert("-","minus");
+ operators_.insert("*","mult");
+ operators_.insert("/","div");
+ operators_.insert("%","mod");
+ operators_.insert("|","bitwise-or");
+ operators_.insert("&","bitwise-and");
+ operators_.insert("^","bitwise-xor");
+ operators_.insert("!","not");
+ operators_.insert("~","bitwise-not");
+ operators_.insert("<=","lt-eq");
+ operators_.insert(">=","gt-eq");
+ operators_.insert("<","lt");
+ operators_.insert(">","gt");
+ operators_.insert("=","assign");
+ operators_.insert(",","comma");
+ operators_.insert("delete[]","delete-array");
+ operators_.insert("delete","delete");
+ operators_.insert("new[]","new-array");
+ operators_.insert("new","new");
+ }
+}
+
+/*!
+ Returns the node's URL.
+ */
+QString Node::url() const
+{
+ return url_;
+}
+
+/*!
+ Sets the node's URL to \a url
+ */
+void Node::setUrl(const QString &url)
+{
+ url_ = url;
+}
+
+/*!
+ Returns this node's page type as a string, for use as an
+ attribute value in XML or HTML.
+ */
+QString Node::pageTypeString() const
+{
+ return pageTypeString(pageType_);
+}
+
+/*!
+ Returns the page type \a t as a string, for use as an
+ attribute value in XML or HTML.
+ */
+QString Node::pageTypeString(unsigned t)
+{
+ switch ((PageType)t) {
+ case Node::ApiPage:
+ return "api";
+ case Node::ArticlePage:
+ return "article";
+ case Node::ExamplePage:
+ return "example";
+ case Node::HowToPage:
+ return "howto";
+ case Node::OverviewPage:
+ return "overview";
+ case Node::TutorialPage:
+ return "tutorial";
+ case Node::FAQPage:
+ return "faq";
+ case Node::DitaMapPage:
+ return "ditamap";
+ default:
+ return "article";
+ }
+}
+
+/*!
+ Returns this node's type as a string for use as an
+ attribute value in XML or HTML.
+ */
+QString Node::nodeTypeString() const
+{
+ return nodeTypeString(type());
+}
+
+/*!
+ Returns the node type \a t as a string for use as an
+ attribute value in XML or HTML.
+ */
+QString Node::nodeTypeString(unsigned t)
+{
+ switch ((Type)t) {
+ case Namespace:
+ return "namespace";
+ case Class:
+ return "class";
+ case Fake:
+ return "fake";
+ case Enum:
+ return "enum";
+ case Typedef:
+ return "typedef";
+ case Function:
+ return "function";
+ case Property:
+ return "property";
+ case Variable:
+ return "variable";
+ case Target:
+ return "target";
+ case QmlProperty:
+ return "QML property";
+ case QmlSignal:
+ return "QML signal";
+ case QmlSignalHandler:
+ return "QML signal handler";
+ case QmlMethod:
+ return "QML method";
+ default:
+ break;
+ }
+ return "";
+}
+
+/*!
+ Returns this node's subtype as a string for use as an
+ attribute value in XML or HTML. This is only useful
+ in the case where the node type is Fake.
+ */
+QString Node::nodeSubtypeString() const
+{
+ return nodeSubtypeString(subType());
+}
+
+/*!
+ Returns the node subtype \a t as a string for use as an
+ attribute value in XML or HTML. This is only useful
+ in the case where the node type is Fake.
+ */
+QString Node::nodeSubtypeString(unsigned t)
+{
+ switch ((SubType)t) {
+ case Example:
+ return "example";
+ case HeaderFile:
+ return "header file";
+ case File:
+ return "file";
+ case Image:
+ return "image";
+ case Group:
+ return "group";
+ case Module:
+ return "module";
+ case Page:
+ return "page";
+ case ExternalPage:
+ return "external page";
+ case QmlClass:
+ return "QML class";
+ case QmlPropertyGroup:
+ return "QML property group";
+ case QmlBasicType:
+ return "QML basic type";
+ case QmlModule:
+ return "QML module";
+ case DitaMap:
+ return "ditamap";
+ case Collision:
+ return "collision";
+ case NoSubType:
+ default:
+ break;
+ }
+ return "";
+}
+
+/*!
+ Set the page type according to the string \a t.
+ */
+void Node::setPageType(const QString& t)
+{
+ if ((t == "API") || (t == "api"))
+ pageType_ = ApiPage;
+ else if (t == "howto")
+ pageType_ = HowToPage;
+ else if (t == "overview")
+ pageType_ = OverviewPage;
+ else if (t == "tutorial")
+ pageType_ = TutorialPage;
+ else if (t == "howto")
+ pageType_ = HowToPage;
+ else if (t == "article")
+ pageType_ = ArticlePage;
+ else if (t == "example")
+ pageType_ = ExamplePage;
+ else if (t == "ditamap")
+ pageType_ = DitaMapPage;
+}
+
+/*!
+ Sets the pointer to the node that this node relates to.
+ */
+void Node::setRelates(InnerNode *pseudoParent)
+{
+ if (relatesTo_) {
+ relatesTo_->removeRelated(this);
+ }
+ relatesTo_ = pseudoParent;
+ pseudoParent->related_.append(this);
+}
+
+/*!
+ This function creates a pair that describes a link.
+ The pair is composed from \a link and \a desc. The
+ \a linkType is the map index the pair is filed under.
+ */
+void Node::setLink(LinkType linkType, const QString &link, const QString &desc)
+{
+ QPair<QString,QString> linkPair;
+ linkPair.first = link;
+ linkPair.second = desc;
+ linkMap[linkType] = linkPair;
+}
+
+/*!
+ Sets the information about the project and version a node was introduced
+ in. The string is simplified, removing excess whitespace before being
+ stored.
+*/
+void Node::setSince(const QString &since)
+{
+ sinc = since.simplified();
+}
+
+/*!
+ Returns a string representing the access specifier.
+ */
+QString Node::accessString() const
+{
+ switch (access_) {
+ case Protected:
+ return "protected";
+ case Private:
+ return "private";
+ case Public:
+ default:
+ break;
+ }
+ return "public";
+}
+
+/*!
+ Extract a class name from the type \a string and return it.
+ */
+QString Node::extractClassName(const QString &string) const
+{
+ QString result;
+ for (int i=0; i<=string.size(); ++i) {
+ QChar ch;
+ if (i != string.size())
+ ch = string.at(i);
+
+ QChar lower = ch.toLower();
+ if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) ||
+ ch.digitValue() >= 0 ||
+ ch == QLatin1Char('_') ||
+ ch == QLatin1Char(':')) {
+ result += ch;
+ }
+ else if (!result.isEmpty()) {
+ if (result != QLatin1String("const"))
+ return result;
+ result.clear();
+ }
+ }
+ return result;
+}
+
+/*!
+ Returns a string representing the access specifier.
+ */
+QString RelatedClass::accessString() const
+{
+ switch (access) {
+ case Node::Protected:
+ return "protected";
+ case Node::Private:
+ return "private";
+ case Node::Public:
+ default:
+ break;
+ }
+ return "public";
+}
+
+/*!
+ Returns the inheritance status.
+ */
+Node::Status Node::inheritedStatus() const
+{
+ Status parentStatus = Commendable;
+ if (parent_)
+ parentStatus = parent_->inheritedStatus();
+ return (Status)qMin((int)status_, (int)parentStatus);
+}
+
+/*!
+ Returns the thread safeness value for whatever this node
+ represents. But if this node has a parent and the thread
+ safeness value of the parent is the same as the thread
+ safeness value of this node, what is returned is the
+ value \c{UnspecifiedSafeness}. Why?
+ */
+Node::ThreadSafeness Node::threadSafeness() const
+{
+ if (parent_ && safeness_ == parent_->inheritedThreadSafeness())
+ return UnspecifiedSafeness;
+ return safeness_;
+}
+
+/*!
+ If this node has a parent, the parent's thread safeness
+ value is returned. Otherwise, this node's thread safeness
+ value is returned. Why?
+ */
+Node::ThreadSafeness Node::inheritedThreadSafeness() const
+{
+ if (parent_ && safeness_ == UnspecifiedSafeness)
+ return parent_->inheritedThreadSafeness();
+ return safeness_;
+}
+
+/*!
+ Returns the sanitized file name without the path.
+ If the the file is an html file, the html suffix
+ is removed. Why?
+ */
+QString Node::fileBase() const
+{
+ QString base = name();
+ if (base.endsWith(".html"))
+ base.chop(5);
+ base.replace(QRegExp("[^A-Za-z0-9]+"), " ");
+ base = base.trimmed();
+ base.replace(QLatin1Char(' '), QLatin1Char('-'));
+ return base.toLower();
+}
+
+/*!
+ Returns this node's Universally Unique IDentifier as a
+ QString. Creates the UUID first, if it has not been created.
+ */
+QString Node::guid() const
+{
+ if (uuid.isEmpty())
+ uuid = idForNode();
+ return uuid;
+}
+
+#if 0
+// fossil
+QUuid quuid = QUuid::createUuid();
+QString t = quuid.toString();
+uuid = "id-" + t.mid(1,t.length()-2);
+#endif
+
+/*!
+ Composes a string to be used as an href attribute in DITA
+ XML. It is composed of the file name and the UUID separated
+ by a '#'. If this node is a class node, the file name is
+ taken from this node; if this node is a function node, the
+ file name is taken from the parent node of this node.
+ */
+QString Node::ditaXmlHref()
+{
+ QString href;
+ if ((type() == Function) ||
+ (type() == Property) ||
+ (type() == Variable)) {
+ href = parent()->fileBase();
+ }
+ else {
+ href = fileBase();
+ }
+ if (!href.endsWith(".xml"))
+ href += ".xml";
+ return href + QLatin1Char('#') + guid();
+}
+
+/*!
+ If this node is a QML class node, return a pointer to it.
+ If it is a child of a QML class node, return a pointer to
+ the QML class node. Otherwise, return 0;
+ */
+const QmlClassNode* Node::qmlClassNode() const
+{
+ if (isQmlNode()) {
+ const Node* n = this;
+ while (n && n->subType() != Node::QmlClass)
+ n = n->parent();
+ if (n && n->subType() == Node::QmlClass)
+ return static_cast<const QmlClassNode*>(n);
+ }
+ return 0;
+}
+
+/*!
+ If this node is a QML node, find its QML class node,
+ and return a pointer to the C++ class node from the
+ QML class node. That pointer will be null if the QML
+ class node is a component. It will be non-null if
+ the QML class node is a QML element.
+ */
+const ClassNode* Node::declarativeCppNode() const
+{
+ const QmlClassNode* qcn = qmlClassNode();
+ if (qcn)
+ return qcn->classNode();
+ return 0;
+}
+
+/*!
+ \class InnerNode
+ */
+
+/*!
+ The inner node destructor deletes the children and removes
+ this node from its related nodes.
+ */
+InnerNode::~InnerNode()
+{
+ deleteChildren();
+ removeFromRelated();
+}
+
+/*!
+ Find the node in this node's children that has the
+ given \a name. If this node is a QML class node, be
+ sure to also look in the children of its property
+ group nodes. Return the matching node or 0.
+ */
+Node *InnerNode::findNode(const QString& name)
+{
+ Node *node = childMap.value(name);
+ if (node && node->subType() != QmlPropertyGroup)
+ return node;
+ if ((type() == Fake) && (subType() == QmlClass)) {
+ for (int i=0; i<children.size(); ++i) {
+ Node* n = children.at(i);
+ if (n->subType() == QmlPropertyGroup) {
+ node = static_cast<InnerNode*>(n)->findNode(name);
+ if (node)
+ return node;
+ }
+ }
+ }
+ return primaryFunctionMap.value(name);
+}
+void InnerNode::findNodes(const QString& name, QList<Node*>& n)
+{
+ n.clear();
+ Node* node = 0;
+ QList<Node*> nodes = childMap.values(name);
+ /*
+ <sigh> If this node's child map contains no nodes named
+ name, then if this node is a QML class, seach each of its
+ property group nodes for a node named name. If a match is
+ found, append it to the output list and return immediately.
+ */
+ if (nodes.isEmpty()) {
+ if ((type() == Fake) && (subType() == QmlClass)) {
+ for (int i=0; i<children.size(); ++i) {
+ node = children.at(i);
+ if (node->subType() == QmlPropertyGroup) {
+ node = static_cast<InnerNode*>(node)->findNode(name);
+ if (node) {
+ n.append(node);
+ return;
+ }
+ }
+ }
+ }
+ }
+ else {
+ /*
+ If the childMap does contain one or more nodes named
+ name, traverse the list of matching nodes. Append each
+ matching node that is not a property group node to the
+ output list. Search each property group node for a node
+ named name and append that node to the output list.
+ This is overkill, I think, but should produce a useful
+ list.
+ */
+ for (int i=0; i<nodes.size(); ++i) {
+ node = nodes.at(i);
+ if (node->subType() != QmlPropertyGroup)
+ n.append(node);
+ else {
+ node = static_cast<InnerNode*>(node)->findNode(name);
+ if (node)
+ n.append(node);
+ }
+ }
+ }
+ if (!n.isEmpty())
+ return;
+ node = primaryFunctionMap.value(name);
+ if (node)
+ n.append(node);
+}
+
+/*!
+ Find the node in this node's children that has the given \a name. If
+ this node is a QML class node, be sure to also look in the children
+ of its property group nodes. Return the matching node or 0.
+
+ If \a qml is true, only match a node for which node->isQmlNode()
+ returns true. If \a qml is false, only match a node for which
+ node->isQmlNode() returns false.
+ */
+Node* InnerNode::findNode(const QString& name, bool qml)
+{
+ QList<Node*> nodes = childMap.values(name);
+ if (!nodes.isEmpty()) {
+ for (int i=0; i<nodes.size(); ++i) {
+ Node* node = nodes.at(i);
+ if (!qml) {
+ if (!node->isQmlNode())
+ return node;
+ }
+ else if (node->isQmlNode() && (node->subType() != QmlPropertyGroup))
+ return node;
+ }
+ }
+ if (qml && (type() == Fake) && (subType() == QmlClass)) {
+ for (int i=0; i<children.size(); ++i) {
+ Node* node = children.at(i);
+ if (node->subType() == QmlPropertyGroup) {
+ node = static_cast<InnerNode*>(node)->findNode(name);
+ if (node)
+ return node;
+ }
+ }
+ }
+ return primaryFunctionMap.value(name);
+}
+
+/*!
+ Same as the other findNode(), but if the node with the
+ specified \a name is not of the specified \a type, return
+ 0.
+ */
+Node *InnerNode::findNode(const QString& name, Type type)
+{
+ if (type == Function) {
+ return primaryFunctionMap.value(name);
+ }
+ else {
+ Node *node = childMap.value(name);
+ if (node && node->type() == type) {
+ return node;
+ }
+ else {
+ return 0;
+ }
+ }
+}
+
+/*!
+ Find the function node in this node for the function named \a name.
+ */
+FunctionNode *InnerNode::findFunctionNode(const QString& name)
+{
+ return static_cast<FunctionNode *>(primaryFunctionMap.value(name));
+}
+
+/*!
+ Find the function node in this node that has the same name as \a clone.
+ */
+FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone)
+{
+ QMap<QString, Node *>::ConstIterator c =
+ primaryFunctionMap.find(clone->name());
+ if (c != primaryFunctionMap.end()) {
+ if (isSameSignature(clone, (FunctionNode *) *c)) {
+ return (FunctionNode *) *c;
+ }
+ else if (secondaryFunctionMap.contains(clone->name())) {
+ const NodeList& secs = secondaryFunctionMap[clone->name()];
+ NodeList::ConstIterator s = secs.begin();
+ while (s != secs.end()) {
+ if (isSameSignature(clone, (FunctionNode *) *s))
+ return (FunctionNode *) *s;
+ ++s;
+ }
+ }
+ }
+ return 0;
+}
+
+/*!
+ Returns the list of keys from the primary function map.
+ */
+QStringList InnerNode::primaryKeys()
+{
+ QStringList t;
+ QMap<QString, Node*>::iterator i = primaryFunctionMap.begin();
+ while (i != primaryFunctionMap.end()) {
+ t.append(i.key());
+ ++i;
+ }
+ return t;
+}
+
+/*!
+ Returns the list of keys from the secondary function map.
+ */
+QStringList InnerNode::secondaryKeys()
+{
+ QStringList t;
+ QMap<QString, NodeList>::iterator i = secondaryFunctionMap.begin();
+ while (i != secondaryFunctionMap.end()) {
+ t.append(i.key());
+ ++i;
+ }
+ return t;
+}
+
+/*!
+ */
+void InnerNode::setOverload(const FunctionNode *func, bool overlode)
+{
+ Node *node = (Node *) func;
+ Node *&primary = primaryFunctionMap[func->name()];
+
+ if (secondaryFunctionMap.contains(func->name())) {
+ NodeList& secs = secondaryFunctionMap[func->name()];
+ if (overlode) {
+ if (primary == node) {
+ primary = secs.first();
+ secs.erase(secs.begin());
+ secs.append(node);
+ }
+ else {
+ secs.removeAll(node);
+ secs.append(node);
+ }
+ }
+ else {
+ if (primary != node) {
+ secs.removeAll(node);
+ secs.prepend(primary);
+ primary = node;
+ }
+ }
+ }
+}
+
+/*!
+ Mark all child nodes that have no documentation as having
+ private access and internal status. qdoc will then ignore
+ them for documentation purposes.
+
+ \note Exception: Name collision nodes are not marked
+ private/internal.
+ */
+void InnerNode::makeUndocumentedChildrenInternal()
+{
+ foreach (Node *child, childNodes()) {
+ if (child->doc().isEmpty()) {
+ if (child->subType() != Node::Collision) {
+ child->setAccess(Node::Private);
+ child->setStatus(Node::Internal);
+ }
+ }
+ }
+}
+
+/*!
+ In each child node that is a collision node,
+ clear the current child pointer.
+ */
+void InnerNode::clearCurrentChildPointers()
+{
+ foreach (Node* child, childNodes()) {
+ if (child->subType() == Collision) {
+ child->clearCurrentChild();
+ }
+ }
+}
+
+/*!
+ */
+void InnerNode::normalizeOverloads()
+{
+ QMap<QString, Node *>::Iterator p1 = primaryFunctionMap.begin();
+ while (p1 != primaryFunctionMap.end()) {
+ FunctionNode *primaryFunc = (FunctionNode *) *p1;
+ if (secondaryFunctionMap.contains(primaryFunc->name()) &&
+ (primaryFunc->status() != Commendable ||
+ primaryFunc->access() == Private)) {
+
+ NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
+ NodeList::ConstIterator s = secs.begin();
+ while (s != secs.end()) {
+ FunctionNode *secondaryFunc = (FunctionNode *) *s;
+
+ // Any non-obsolete, non-compatibility, non-private functions
+ // (i.e, visible functions) are preferable to the primary
+ // function.
+
+ if (secondaryFunc->status() == Commendable &&
+ secondaryFunc->access() != Private) {
+
+ *p1 = secondaryFunc;
+ int index = secondaryFunctionMap[primaryFunc->name()].indexOf(secondaryFunc);
+ secondaryFunctionMap[primaryFunc->name()].replace(index, primaryFunc);
+ break;
+ }
+ ++s;
+ }
+ }
+ ++p1;
+ }
+
+ QMap<QString, Node *>::ConstIterator p = primaryFunctionMap.begin();
+ while (p != primaryFunctionMap.end()) {
+ FunctionNode *primaryFunc = (FunctionNode *) *p;
+ if (primaryFunc->isOverload())
+ primaryFunc->ove = false;
+ if (secondaryFunctionMap.contains(primaryFunc->name())) {
+ NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
+ NodeList::ConstIterator s = secs.begin();
+ while (s != secs.end()) {
+ FunctionNode *secondaryFunc = (FunctionNode *) *s;
+ if (!secondaryFunc->isOverload())
+ secondaryFunc->ove = true;
+ ++s;
+ }
+ }
+ ++p;
+ }
+
+ NodeList::ConstIterator c = childNodes().begin();
+ while (c != childNodes().end()) {
+ if ((*c)->isInnerNode())
+ ((InnerNode *) *c)->normalizeOverloads();
+ ++c;
+ }
+}
+
+/*!
+ */
+void InnerNode::removeFromRelated()
+{
+ while (!related_.isEmpty()) {
+ Node *p = static_cast<Node *>(related_.takeFirst());
+
+ if (p != 0 && p->relates() == this) p->clearRelated();
+ }
+}
+
+/*!
+ Deletes all this node's children.
+ */
+void InnerNode::deleteChildren()
+{
+ NodeList childrenCopy = children; // `children` will be changed in ~Node()
+ qDeleteAll(childrenCopy);
+}
+
+/*! \fn bool InnerNode::isInnerNode() const
+ Returns true because this is an inner node.
+ */
+
+/*!
+ */
+const Node *InnerNode::findNode(const QString& name) const
+{
+ InnerNode *that = (InnerNode *) this;
+ return that->findNode(name);
+}
+
+/*!
+ If \a qml is true, only match a node for which node->isQmlNode()
+ returns true. If \a qml is false, only match a node for which
+ node->isQmlNode() returns false.
+ */
+const Node* InnerNode::findNode(const QString& name, bool qml) const
+{
+ InnerNode*that = (InnerNode*) this;
+ return that->findNode(name, qml);
+}
+
+/*!
+ */
+const Node *InnerNode::findNode(const QString& name, Type type) const
+{
+ InnerNode *that = (InnerNode *) this;
+ return that->findNode(name, type);
+}
+
+/*!
+ Find the function node in this node that has the given \a name.
+ */
+const FunctionNode *InnerNode::findFunctionNode(const QString& name) const
+{
+ InnerNode *that = (InnerNode *) this;
+ return that->findFunctionNode(name);
+}
+
+/*!
+ Find the function node in this node that has the same name as \a clone.
+ */
+const FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone) const
+{
+ InnerNode *that = (InnerNode *) this;
+ return that->findFunctionNode(clone);
+}
+
+/*!
+ */
+const EnumNode *InnerNode::findEnumNodeForValue(const QString &enumValue) const
+{
+ foreach (const Node *node, enumChildren) {
+ const EnumNode *enume = static_cast<const EnumNode *>(node);
+ if (enume->hasItem(enumValue))
+ return enume;
+ }
+ return 0;
+}
+
+/*!
+ Returnds the sequence number of the function node \a func
+ in the list of overloaded functions for a class, such that
+ all the functions have the same name as the \a func.
+ */
+int InnerNode::overloadNumber(const FunctionNode *func) const
+{
+ Node *node = (Node *) func;
+ if (primaryFunctionMap[func->name()] == node) {
+ return 1;
+ }
+ else {
+ return secondaryFunctionMap[func->name()].indexOf(node) + 2;
+ }
+}
+
+/*!
+ Returns the number of member functions of a class such that
+ the functions are all named \a funcName.
+ */
+int InnerNode::numOverloads(const QString& funcName) const
+{
+ if (primaryFunctionMap.contains(funcName)) {
+ return secondaryFunctionMap[funcName].count() + 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+/*!
+ Returns a node list containing all the member functions of
+ some class such that the functions overload the name \a funcName.
+ */
+NodeList InnerNode::overloads(const QString &funcName) const
+{
+ NodeList result;
+ Node *primary = primaryFunctionMap.value(funcName);
+ if (primary) {
+ result << primary;
+ result += secondaryFunctionMap[funcName];
+ }
+ return result;
+}
+
+/*!
+ Construct an inner node (i.e., not a leaf node) of the
+ given \a type and having the given \a parent and \a name.
+ */
+InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name)
+ : Node(type, parent, name)
+{
+ switch (type) {
+ case Class:
+ case Namespace:
+ setPageType(ApiPage);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ Appends an \a include file to the list of include files.
+ */
+void InnerNode::addInclude(const QString& include)
+{
+ inc.append(include);
+}
+
+/*!
+ Sets the list of include files to \a includes.
+ */
+void InnerNode::setIncludes(const QStringList& includes)
+{
+ inc = includes;
+}
+
+/*!
+ f1 is always the clone
+ */
+bool InnerNode::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
+{
+ if (f1->parameters().count() != f2->parameters().count())
+ return false;
+ if (f1->isConst() != f2->isConst())
+ return false;
+
+ QList<Parameter>::ConstIterator p1 = f1->parameters().begin();
+ QList<Parameter>::ConstIterator p2 = f2->parameters().begin();
+ while (p2 != f2->parameters().end()) {
+ if ((*p1).hasType() && (*p2).hasType()) {
+ if ((*p1).rightType() != (*p2).rightType())
+ return false;
+
+ QString t1 = p1->leftType();
+ QString t2 = p2->leftType();
+
+ if (t1.length() < t2.length())
+ qSwap(t1, t2);
+
+ /*
+ ### hack for C++ to handle superfluous
+ "Foo::" prefixes gracefully
+ */
+ if (t1 != t2 && t1 != (f2->parent()->name() + "::" + t2))
+ return false;
+ }
+ ++p1;
+ ++p2;
+ }
+ return true;
+}
+
+/*!
+ Adds the \a child to this node's child list.
+ */
+void InnerNode::addChild(Node *child)
+{
+ children.append(child);
+ if ((child->type() == Function) || (child->type() == QmlMethod)) {
+ FunctionNode *func = (FunctionNode *) child;
+ if (!primaryFunctionMap.contains(func->name())) {
+ primaryFunctionMap.insert(func->name(), func);
+ }
+ else {
+ NodeList &secs = secondaryFunctionMap[func->name()];
+ secs.append(func);
+ }
+ }
+ else {
+ if (child->type() == Enum)
+ enumChildren.append(child);
+ childMap.insertMulti(child->name(), child);
+ }
+}
+
+/*!
+ */
+void InnerNode::removeChild(Node *child)
+{
+ children.removeAll(child);
+ enumChildren.removeAll(child);
+ if (child->type() == Function) {
+ QMap<QString, Node *>::Iterator prim =
+ primaryFunctionMap.find(child->name());
+ NodeList& secs = secondaryFunctionMap[child->name()];
+ if (prim != primaryFunctionMap.end() && *prim == child) {
+ if (secs.isEmpty()) {
+ primaryFunctionMap.remove(child->name());
+ }
+ else {
+ primaryFunctionMap.insert(child->name(), secs.takeFirst());
+ }
+ }
+ else {
+ secs.removeAll(child);
+ }
+ }
+ QMap<QString, Node *>::Iterator ent = childMap.find(child->name());
+ while (ent != childMap.end() && ent.key() == child->name()) {
+ if (*ent == child) {
+ childMap.erase(ent);
+ break;
+ }
+ ++ent;
+ }
+}
+
+/*!
+ Find the module (QtCore, QtGui, etc.) to which the class belongs.
+ We do this by obtaining the full path to the header file's location
+ and examine everything between "src/" and the filename. This is
+ semi-dirty because we are assuming a particular directory structure.
+
+ This function is only really useful if the class's module has not
+ been defined in the header file with a QT_MODULE macro or with an
+ \inmodule command in the documentation.
+*/
+QString Node::moduleName() const
+{
+ if (!mod.isEmpty())
+ return mod;
+
+ QString path = location().filePath();
+ QString pattern = QString("src") + QDir::separator();
+ int start = path.lastIndexOf(pattern);
+
+ if (start == -1)
+ return "";
+
+ QString moduleDir = path.mid(start + pattern.size());
+ int finish = moduleDir.indexOf(QDir::separator());
+
+ if (finish == -1)
+ return "";
+
+ QString moduleName = moduleDir.left(finish);
+
+ if (moduleName == "corelib")
+ return "QtCore";
+ else if (moduleName == "uitools")
+ return "QtUiTools";
+ else if (moduleName == "gui")
+ return "QtGui";
+ else if (moduleName == "network")
+ return "QtNetwork";
+ else if (moduleName == "opengl")
+ return "QtOpenGL";
+ else if (moduleName == "qt3support")
+ return "Qt3Support";
+ else if (moduleName == "svg")
+ return "QtSvg";
+ else if (moduleName == "sql")
+ return "QtSql";
+ else if (moduleName == "qtestlib")
+ return "QtTest";
+ else if (moduleDir.contains("webkit"))
+ return "QtWebKit";
+ else if (moduleName == "xml")
+ return "QtXml";
+ else
+ return "";
+}
+
+/*!
+ */
+void InnerNode::removeRelated(Node *pseudoChild)
+{
+ related_.removeAll(pseudoChild);
+}
+
+/*!
+ \class LeafNode
+ */
+
+/*!
+ Returns false because this is a LeafNode.
+ */
+bool LeafNode::isInnerNode() const
+{
+ return false;
+}
+
+/*!
+ Constructs a leaf node named \a name of the specified
+ \a type. The new leaf node becomes a child of \a parent.
+ */
+LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name)
+ : Node(type, parent, name)
+{
+ switch (type) {
+ case Enum:
+ case Function:
+ case Typedef:
+ case Variable:
+ case QmlProperty:
+ case QmlSignal:
+ case QmlSignalHandler:
+ case QmlMethod:
+ setPageType(ApiPage);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ This constructor should only be used when this node's parent
+ is meant to be \a parent, but this node is not to be listed
+ as a child of \a parent. It is currently only used for the
+ documentation case where a \e{qmlproperty} command is used
+ to override the QML definition of a QML property.
+ */
+LeafNode::LeafNode(InnerNode* parent, Type type, const QString& name)
+ : Node(type, 0, name)
+{
+ setParent(parent);
+ switch (type) {
+ case Enum:
+ case Function:
+ case Typedef:
+ case Variable:
+ case QmlProperty:
+ case QmlSignal:
+ case QmlSignalHandler:
+ case QmlMethod:
+ setPageType(ApiPage);
+ break;
+ default:
+ break;
+ }
+}
+
+
+/*!
+ \class NamespaceNode
+ */
+
+/*!
+ Constructs a namespace node.
+ */
+NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name)
+ : InnerNode(Namespace, parent, name)
+{
+ setPageType(ApiPage);
+}
+
+/*!
+ \class ClassNode
+ \brief This class represents a C++ class.
+ */
+
+/*!
+ Constructs a class node. A class node will generate an API page.
+ */
+ClassNode::ClassNode(InnerNode *parent, const QString& name)
+ : InnerNode(Class, parent, name)
+{
+ hidden = false;
+ abstract = false;
+ qmlelement = 0;
+ setPageType(ApiPage);
+}
+
+/*!
+ */
+void ClassNode::addBaseClass(Access access,
+ ClassNode *node,
+ const QString &dataTypeWithTemplateArgs)
+{
+ bases.append(RelatedClass(access, node, dataTypeWithTemplateArgs));
+ node->derived.append(RelatedClass(access, this));
+}
+
+/*!
+ */
+void ClassNode::fixBaseClasses()
+{
+ int i;
+ i = 0;
+ QSet<ClassNode *> found;
+
+ // Remove private and duplicate base classes.
+ while (i < bases.size()) {
+ ClassNode* bc = bases.at(i).node;
+ if (bc->access() == Node::Private || found.contains(bc)) {
+ RelatedClass rc = bases.at(i);
+ bases.removeAt(i);
+ ignoredBases.append(rc);
+ const QList<RelatedClass> &bb = bc->baseClasses();
+ for (int j = bb.size() - 1; j >= 0; --j)
+ bases.insert(i, bb.at(j));
+ }
+ else {
+ ++i;
+ }
+ found.insert(bc);
+ }
+
+ i = 0;
+ while (i < derived.size()) {
+ ClassNode* dc = derived.at(i).node;
+ if (dc->access() == Node::Private) {
+ derived.removeAt(i);
+ const QList<RelatedClass> &dd = dc->derivedClasses();
+ for (int j = dd.size() - 1; j >= 0; --j)
+ derived.insert(i, dd.at(j));
+ }
+ else {
+ ++i;
+ }
+ }
+}
+
+/*!
+ Search the child list to find the property node with the
+ specified \a name.
+ */
+const PropertyNode *ClassNode::findPropertyNode(const QString &name) const
+{
+ const Node *n = findNode(name, Node::Property);
+
+ if (n)
+ return static_cast<const PropertyNode*>(n);
+
+ const PropertyNode *pn = 0;
+
+ const QList<RelatedClass> &bases = baseClasses();
+ if (!bases.isEmpty()) {
+ for (int i = 0; i < bases.size(); ++i) {
+ const ClassNode *cn = bases[i].node;
+ pn = cn->findPropertyNode(name);
+ if (pn)
+ break;
+ }
+ }
+ const QList<RelatedClass>& ignoredBases = ignoredBaseClasses();
+ if (!ignoredBases.isEmpty()) {
+ for (int i = 0; i < ignoredBases.size(); ++i) {
+ const ClassNode *cn = ignoredBases[i].node;
+ pn = cn->findPropertyNode(name);
+ if (pn)
+ break;
+ }
+ }
+
+ return pn;
+}
+
+/*!
+ This function does a recursive search of this class node's
+ base classes looking for one that has a QML element. If it
+ finds one, it returns the pointer to that QML element. If
+ it doesn't find one, it returns null.
+ */
+const QmlClassNode* ClassNode::findQmlBaseNode() const
+{
+ const QmlClassNode* result = 0;
+ const QList<RelatedClass>& bases = baseClasses();
+
+ if (!bases.isEmpty()) {
+ for (int i = 0; i < bases.size(); ++i) {
+ const ClassNode* cn = bases[i].node;
+ if (cn && cn->qmlElement()) {
+ return cn->qmlElement();
+ }
+ }
+ for (int i = 0; i < bases.size(); ++i) {
+ const ClassNode* cn = bases[i].node;
+ if (cn) {
+ result = cn->findQmlBaseNode();
+ if (result != 0) {
+ return result;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*!
+ \class FakeNode
+ */
+
+/*!
+ The type of a FakeNode is Fake, and it has a \a subtype,
+ which specifies the type of FakeNode. The page type for
+ the page index is set here.
+ */
+FakeNode::FakeNode(InnerNode* parent, const QString& name, SubType subtype, Node::PageType ptype)
+ : InnerNode(Fake, parent, name), nodeSubtype_(subtype)
+{
+ switch (subtype) {
+ case Page:
+ setPageType(ptype);
+ break;
+ case DitaMap:
+ setPageType(ptype);
+ break;
+ case Module:
+ case QmlModule:
+ case Group:
+ setPageType(OverviewPage);
+ break;
+ case QmlClass:
+ case QmlBasicType:
+ setPageType(ApiPage);
+ break;
+ case Example:
+ setPageType(ExamplePage);
+ break;
+ case Collision:
+ setPageType(ptype);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ Returns the fake node's title. This is used for the page title.
+*/
+QString FakeNode::title() const
+{
+ return title_;
+}
+
+/*!
+ Returns the fake node's full title, which is usually
+ just title(), but for some SubType values is different
+ from title()
+ */
+QString FakeNode::fullTitle() const
+{
+ if (nodeSubtype_ == File) {
+ if (title().isEmpty())
+ return name().mid(name().lastIndexOf('/') + 1) + " Example File";
+ else
+ return title();
+ }
+ else if (nodeSubtype_ == Image) {
+ if (title().isEmpty())
+ return name().mid(name().lastIndexOf('/') + 1) + " Image File";
+ else
+ return title();
+ }
+ else if ((nodeSubtype_ == HeaderFile) || (nodeSubtype_ == Collision)) {
+ if (title().isEmpty())
+ return name();
+ else
+ return name() + " - " + title();
+ }
+ else {
+ return title();
+ }
+}
+
+/*!
+ Returns the subtitle.
+ */
+QString FakeNode::subTitle() const
+{
+ if (!subtitle_.isEmpty())
+ return subtitle_;
+
+ if ((nodeSubtype_ == File) || (nodeSubtype_ == Image)) {
+ if (title().isEmpty() && name().contains(QLatin1Char('/')))
+ return name();
+ }
+ return QString();
+}
+
+/*!
+ The constructor calls the FakeNode constructor with
+ \a parent, \a name, and Node::Example.
+ */
+ExampleNode::ExampleNode(InnerNode* parent, const QString& name)
+ : FakeNode(parent, name, Node::Example, Node::ExamplePage)
+{
+ // nothing
+}
+
+/*!
+ \class EnumNode
+ */
+
+/*!
+ The constructor for the node representing an enum type
+ has a \a parent class and an enum type \a name.
+ */
+EnumNode::EnumNode(InnerNode *parent, const QString& name)
+ : LeafNode(Enum, parent, name), ft(0)
+{
+}
+
+/*!
+ Add \a item to the enum type's item list.
+ */
+void EnumNode::addItem(const EnumItem& item)
+{
+ itms.append(item);
+ names.insert(item.name());
+}
+
+/*!
+ Returns the access level of the enumeration item named \a name.
+ Apparently it is private if it has been omitted by qdoc's
+ omitvalue command. Otherwise it is public.
+ */
+Node::Access EnumNode::itemAccess(const QString &name) const
+{
+ if (doc().omitEnumItemNames().contains(name))
+ return Private;
+ return Public;
+}
+
+/*!
+ Returns the enum value associated with the enum \a name.
+ */
+QString EnumNode::itemValue(const QString &name) const
+{
+ foreach (const EnumItem &item, itms) {
+ if (item.name() == name)
+ return item.value();
+ }
+ return QString();
+}
+
+/*!
+ \class TypedefNode
+ */
+
+/*!
+ */
+TypedefNode::TypedefNode(InnerNode *parent, const QString& name)
+ : LeafNode(Typedef, parent, name), ae(0)
+{
+}
+
+/*!
+ */
+void TypedefNode::setAssociatedEnum(const EnumNode *enume)
+{
+ ae = enume;
+}
+
+/*!
+ \class Parameter
+ \brief The class Parameter contains one parameter.
+
+ A parameter can be a function parameter or a macro
+ parameter.
+ */
+
+/*!
+ Constructs this parameter from the left and right types
+ \a leftType and rightType, the parameter \a name, and the
+ \a defaultValue. In practice, \a rightType is not used,
+ and I don't know what is was meant for.
+ */
+Parameter::Parameter(const QString& leftType,
+ const QString& rightType,
+ const QString& name,
+ const QString& defaultValue)
+ : lef(leftType), rig(rightType), nam(name), def(defaultValue)
+{
+}
+
+/*!
+ The standard copy constructor copies the strings from \a p.
+ */
+Parameter::Parameter(const Parameter& p)
+ : lef(p.lef), rig(p.rig), nam(p.nam), def(p.def)
+{
+}
+
+/*!
+ Assigning Parameter \a p to this Parameter copies the
+ strings across.
+ */
+Parameter& Parameter::operator=(const Parameter& p)
+{
+ lef = p.lef;
+ rig = p.rig;
+ nam = p.nam;
+ def = p.def;
+ return *this;
+}
+
+/*!
+ Reconstructs the text describing the parameter and
+ returns it. If \a value is true, the default value
+ will be included, if there is one.
+ */
+QString Parameter::reconstruct(bool value) const
+{
+ QString p = lef + rig;
+ if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
+ p += QLatin1Char(' ');
+ p += nam;
+ if (value && !def.isEmpty())
+ p += " = " + def;
+ return p;
+}
+
+
+/*!
+ \class FunctionNode
+ */
+
+/*!
+ Construct a function node for a C++ function. It's parent
+ is \a parent, and it's name is \a name.
+ */
+FunctionNode::FunctionNode(InnerNode *parent, const QString& name)
+ : LeafNode(Function, parent, name),
+ met(Plain),
+ vir(NonVirtual),
+ con(false),
+ sta(false),
+ ove(false),
+ reimp(false),
+ attached_(false),
+ rf(0),
+ ap(0)
+{
+ // nothing.
+}
+
+/*!
+ Construct a function node for a QML method or signal, specified
+ by \a type. It's parent is \a parent, and it's name is \a name.
+ If \a attached is true, it is an attached method or signal.
+ */
+FunctionNode::FunctionNode(Type type, InnerNode *parent, const QString& name, bool attached)
+ : LeafNode(type, parent, name),
+ met(Plain),
+ vir(NonVirtual),
+ con(false),
+ sta(false),
+ ove(false),
+ reimp(false),
+ attached_(attached),
+ rf(0),
+ ap(0)
+{
+ // nothing.
+}
+
+/*!
+ Sets the \a virtualness of this function. If the \a virtualness
+ is PureVirtual, and if the parent() is a ClassNode, set the parent's
+ \e abstract flag to true.
+ */
+void FunctionNode::setVirtualness(Virtualness virtualness)
+{
+ vir = virtualness;
+ if ((virtualness == PureVirtual) && parent() &&
+ (parent()->type() == Node::Class))
+ parent()->setAbstract(true);
+}
+
+/*!
+ */
+void FunctionNode::setOverload(bool overlode)
+{
+ parent()->setOverload(this, overlode);
+ ove = overlode;
+}
+
+/*!
+ Sets the function node's reimplementation flag to \a r.
+ When \a r is true, it is supposed to mean that this function
+ is a reimplementation of a virtual function in a base class,
+ but it really just means the \e reimp command was seen in the
+ qdoc comment.
+ */
+void FunctionNode::setReimp(bool r)
+{
+ reimp = r;
+}
+
+/*!
+ */
+void FunctionNode::addParameter(const Parameter& parameter)
+{
+ params.append(parameter);
+}
+
+/*!
+ */
+void FunctionNode::borrowParameterNames(const FunctionNode *source)
+{
+ QList<Parameter>::Iterator t = params.begin();
+ QList<Parameter>::ConstIterator s = source->params.begin();
+ while (s != source->params.end() && t != params.end()) {
+ if (!(*s).name().isEmpty())
+ (*t).setName((*s).name());
+ ++s;
+ ++t;
+ }
+}
+
+/*!
+ If this function is a reimplementation, \a from points
+ to the FunctionNode of the function being reimplemented.
+ */
+void FunctionNode::setReimplementedFrom(FunctionNode *from)
+{
+ rf = from;
+ from->rb.append(this);
+}
+
+/*!
+ Sets the "associated" property to \a property. The function
+ might be the setter or getter for a property, for example.
+ */
+void FunctionNode::setAssociatedProperty(PropertyNode *property)
+{
+ ap = property;
+}
+
+/*!
+ Returns the overload number for this function obtained
+ from the parent.
+ */
+int FunctionNode::overloadNumber() const
+{
+ return parent()->overloadNumber(this);
+}
+
+/*!
+ Returns the number of times this function name has been
+ overloaded, obtained from the parent.
+ */
+int FunctionNode::numOverloads() const
+{
+ return parent()->numOverloads(name());
+}
+
+/*!
+ Returns the list of parameter names.
+ */
+QStringList FunctionNode::parameterNames() const
+{
+ QStringList names;
+ QList<Parameter>::ConstIterator p = parameters().begin();
+ while (p != parameters().end()) {
+ names << (*p).name();
+ ++p;
+ }
+ return names;
+}
+
+/*!
+ Returns a raw list of parameters. If \a names is true, the
+ names are included. If \a values is true, the default values
+ are included, if any are present.
+ */
+QString FunctionNode::rawParameters(bool names, bool values) const
+{
+ QString raw;
+ foreach (const Parameter &parameter, parameters()) {
+ raw += parameter.leftType() + parameter.rightType();
+ if (names)
+ raw += parameter.name();
+ if (values)
+ raw += parameter.defaultValue();
+ }
+ return raw;
+}
+
+/*!
+ Returns the list of reconstructed parameters. If \a values
+ is true, the default values are included, if any are present.
+ */
+QStringList FunctionNode::reconstructParams(bool values) const
+{
+ QStringList params;
+ QList<Parameter>::ConstIterator p = parameters().begin();
+ while (p != parameters().end()) {
+ params << (*p).reconstruct(values);
+ ++p;
+ }
+ return params;
+}
+
+/*!
+ Reconstructs and returns the function's signature. If \a values
+ is true, the default values of the parameters are included, if
+ present.
+ */
+QString FunctionNode::signature(bool values) const
+{
+ QString s;
+ if (!returnType().isEmpty())
+ s = returnType() + QLatin1Char(' ');
+ s += name() + QLatin1Char('(');
+ QStringList params = reconstructParams(values);
+ int p = params.size();
+ if (p > 0) {
+ for (int i=0; i<p; i++) {
+ s += params[i];
+ if (i < (p-1))
+ s += ", ";
+ }
+ }
+ s += QLatin1Char(')');
+ return s;
+}
+
+/*!
+ Returns true if the node's status is Internal, or if its
+ parent is a class with internal status.
+ */
+bool FunctionNode::isInternal() const
+{
+ if (status() == Internal)
+ return true;
+ if (parent() && parent()->status() == Internal)
+ return true;
+ if (relates() && relates()->status() == Internal)
+ return true;
+ return false;
+}
+
+/*!
+ Print some debugging stuff.
+ */
+void FunctionNode::debug() const
+{
+ qDebug("QML METHOD %s rt %s pp %s",
+ qPrintable(name()), qPrintable(rt), qPrintable(pp.join(" ")));
+}
+
+/*!
+ \class PropertyNode
+
+ This class describes one instance of using the Q_PROPERTY macro.
+ */
+
+/*!
+ The constructor sets the \a parent and the \a name, but
+ everything else is set to default values.
+ */
+PropertyNode::PropertyNode(InnerNode *parent, const QString& name)
+ : LeafNode(Property, parent, name),
+ sto(Trool_Default),
+ des(Trool_Default),
+ scr(Trool_Default),
+ wri(Trool_Default),
+ usr(Trool_Default),
+ cst(false),
+ fnl(false),
+ rev(-1),
+ overrides(0)
+{
+ // nothing.
+}
+
+/*!
+ Sets this property's \e {overridden from} property to
+ \a baseProperty, which indicates that this property
+ overrides \a baseProperty. To begin with, all the values
+ in this property are set to the corresponding values in
+ \a baseProperty.
+
+ We probably should ensure that the constant and final
+ attributes are not being overridden improperly.
+ */
+void PropertyNode::setOverriddenFrom(const PropertyNode* baseProperty)
+{
+ for (int i = 0; i < NumFunctionRoles; ++i) {
+ if (funcs[i].isEmpty())
+ funcs[i] = baseProperty->funcs[i];
+ }
+ if (sto == Trool_Default)
+ sto = baseProperty->sto;
+ if (des == Trool_Default)
+ des = baseProperty->des;
+ if (scr == Trool_Default)
+ scr = baseProperty->scr;
+ if (wri == Trool_Default)
+ wri = baseProperty->wri;
+ if (usr == Trool_Default)
+ usr = baseProperty->usr;
+ overrides = baseProperty;
+}
+
+/*!
+ */
+QString PropertyNode::qualifiedDataType() const
+{
+ if (setters().isEmpty() && resetters().isEmpty()) {
+ if (type_.contains(QLatin1Char('*')) || type_.contains(QLatin1Char('&'))) {
+ // 'QWidget *' becomes 'QWidget *' const
+ return type_ + " const";
+ }
+ else {
+ /*
+ 'int' becomes 'const int' ('int const' is
+ correct C++, but looks wrong)
+ */
+ return "const " + type_;
+ }
+ }
+ else {
+ return type_;
+ }
+}
+
+/*! Converts the \a boolean value to an enum representation
+ of the boolean type, which includes an enum value for the
+ \e {default value} of the item, i.e. true, false, or default.
+ */
+PropertyNode::Trool PropertyNode::toTrool(bool boolean)
+{
+ return boolean ? Trool_True : Trool_False;
+}
+
+/*!
+ Converts the enum \a troolean back to a boolean value.
+ If \a troolean is neither the true enum value nor the
+ false enum value, the boolean value returned is
+ \a defaultValue.
+
+ Note that runtimeDesignabilityFunction() should be called
+ first. If that function returns the name of a function, it
+ means the function must be called at runtime to determine
+ whether the property is Designable.
+ */
+bool PropertyNode::fromTrool(Trool troolean, bool defaultValue)
+{
+ switch (troolean) {
+ case Trool_True:
+ return true;
+ case Trool_False:
+ return false;
+ default:
+ return defaultValue;
+ }
+}
+
+/*!
+ \class TargetNode
+ */
+
+/*!
+ */
+TargetNode::TargetNode(InnerNode *parent, const QString& name)
+ : LeafNode(Target, parent, name)
+{
+}
+
+/*!
+ Returns false because this is a TargetNode.
+ */
+bool TargetNode::isInnerNode() const
+{
+ return false;
+}
+
+bool QmlClassNode::qmlOnly = false;
+QMultiMap<QString,Node*> QmlClassNode::inheritedBy;
+QMap<QString, QmlClassNode*> QmlClassNode::moduleMap;
+
+/*!
+ Constructs a Qml class node (i.e. a Fake node with the
+ subtype QmlClass. The new node has the given \a parent
+ and \a name and is associated with the C++ class node
+ specified by \a cn which may be null if the the Qml
+ class node is not associated with a C++ class node.
+ */
+QmlClassNode::QmlClassNode(InnerNode *parent,
+ const QString& name,
+ const ClassNode* cn)
+ : FakeNode(parent, name, QmlClass, Node::ApiPage),
+ abstract(false),
+ cnode_(cn),
+ base_(0)
+{
+ int i = 0;
+ if (name.startsWith("QML:")) {
+ qDebug() << "BOGUS:" << name;
+ i = 4;
+ }
+ setTitle(name.mid(i));
+}
+
+/*!
+ I made this so I could print a debug message here.
+ */
+QmlClassNode::~QmlClassNode()
+{
+#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
+ qDebug() << "Deleting QmlClassNode:" << name();
+#endif
+}
+
+/*!
+ Clear the static maps so that subsequent runs don't try to use
+ contents from a previous run.
+ */
+void QmlClassNode::terminate()
+{
+ inheritedBy.clear();
+ moduleMap.clear();
+}
+
+/*!
+ The base file name for this kind of node has "qml_"
+ prepended to it.
+
+ But not yet. Still testing.
+ */
+QString QmlClassNode::fileBase() const
+{
+ return Node::fileBase();
+}
+
+/*!
+ Record the fact that QML class \a base is inherited by
+ QML class \a sub.
+ */
+void QmlClassNode::addInheritedBy(const QString& base, Node* sub)
+{
+ if (inheritedBy.find(base,sub) == inheritedBy.end()) {
+ inheritedBy.insert(base,sub);
+ }
+#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
+ qDebug() << "QmlClassNode::addInheritedBy(): insert" << base << sub->name() << inheritedBy.size();
+#endif
+}
+
+/*!
+ Loads the list \a subs with the nodes of all the subclasses of \a base.
+ */
+void QmlClassNode::subclasses(const QString& base, NodeList& subs)
+{
+ subs.clear();
+ if (inheritedBy.count(base) > 0) {
+ subs = inheritedBy.values(base);
+#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
+ qDebug() << "QmlClassNode::subclasses():" << inheritedBy.count(base) << base
+ << "subs:" << subs.size() << "total size:" << inheritedBy.size();
+#endif
+ }
+}
+
+/*! \fn QString QmlClassNode::qmlModuleIdentifier() const
+ This function is called to get a string that is used either
+ as a prefix for the file name to use for QML element or
+ component reference page, or as a qualifier to prefix a
+ reference to a QML element or comnponent. The string that
+ is returned is the concatenation of the QML module name
+ and its version number. e.g., if an element or component
+ is defined to be in the QML module QtQuick 1, its module
+ identifier is "QtQuick1". See setQmlModuleName().
+ */
+
+/*!
+ This function splits \a arg on the blank character to get a
+ QML module name and version number. It stores these separately.
+ The version number is not required.
+ */
+void Node::setQmlModuleName(const QString& arg)
+{
+ QStringList blankSplit = arg.split(QLatin1Char(' '));
+ qmlModuleName_ = blankSplit[0];
+ if (blankSplit.size() > 1)
+ qmlModuleVersion_ = blankSplit[1];
+}
+
+/*!
+ The name of this QML class node might be the same as the
+ name of some other QML class node. If so, then this node's
+ parent will be a NameCollisionNode.This function sets the
+ NameCollisionNode's current child to this node. This is
+ important when outputing the documentation for this node,
+ when, for example, the documentation contains a link to
+ the page being output. We don't want to generate a link
+ to the disambiguation page if we can avoid it, and to be
+ able to avoid it, the NameCollisionNode must maintain the
+ current child pointer. That's the purpose of this function.
+ */
+void QmlClassNode::setCurrentChild()
+{
+ if (parent()) {
+ InnerNode* n = parent();
+ if (n->subType() == Node::Collision)
+ n->setCurrentChild(this);
+ }
+}
+
+/*!
+ */
+void QmlClassNode::clearCurrentChild()
+{
+ if (parent()) {
+ InnerNode* n = parent();
+ if (n->subType() == Node::Collision)
+ n->clearCurrentChild();
+ }
+}
+
+/*!
+ Most QML elements don't have an \\inherits command in their
+ \\qmlclass command. This leaves qdoc bereft, when it tries
+ to output the line in the documentation that specifies the
+ QML element that a QML element inherits.
+ */
+void QmlClassNode::resolveInheritance(const Tree* tree)
+{
+ if (!links().empty() && links().contains(Node::InheritsLink)) {
+ QPair<QString,QString> linkPair;
+ linkPair = links()[Node::InheritsLink];
+ QStringList strList = linkPair.first.split("::");
+ const Node* n = tree->findNode(strList,Node::Fake);
+ if (n && (n->subType() == Node::QmlClass || n->subType() == Node::Collision)) {
+ base_ = static_cast<const FakeNode*>(n);
+ if (base_ && base_->subType() == Node::QmlClass) {
+ return;
+ }
+ }
+ if (base_ && base_->subType() == Node::Collision) {
+ const NameCollisionNode* ncn = static_cast<const NameCollisionNode*>(base_);
+ const NodeList& children = ncn->childNodes();
+ for (int i=0; i<importList_.size(); ++i) {
+ QString qmid = importList_.at(i).first + importList_.at(i).second;
+ for (int j=0; j<children.size(); ++j) {
+ if (qmid == children.at(j)->qmlModuleIdentifier()) {
+ base_ = static_cast<const FakeNode*>(children.at(j));
+ return;
+ }
+ }
+ }
+ QString qmid = qmlModuleIdentifier();
+ for (int k=0; k<children.size(); ++k) {
+ if (qmid == children.at(k)->qmlModuleIdentifier()) {
+ base_ = static_cast<const QmlClassNode*>(children.at(k));
+ return;
+ }
+ }
+ }
+ if (base_)
+ return;
+ }
+ if (cnode_) {
+ const QmlClassNode* qcn = cnode_->findQmlBaseNode();
+ if (qcn != 0)
+ base_ = qcn;
+ }
+ return;
+}
+
+/*!
+ Constructs a Qml basic type node (i.e. a Fake node with
+ the subtype QmlBasicType. The new node has the given
+ \a parent and \a name.
+ */
+QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent,
+ const QString& name)
+ : FakeNode(parent, name, QmlBasicType, Node::ApiPage)
+{
+ setTitle(name);
+}
+
+/*!
+ Constructor for the Qml property group node. \a parent is
+ always a QmlClassNode.
+ */
+QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent,
+ const QString& name,
+ bool attached)
+ : FakeNode(parent, name, QmlPropertyGroup, Node::ApiPage),
+ isdefault_(false),
+ attached_(attached),
+ readOnly_(-1)
+{
+ // nothing.
+}
+
+/*!
+ Constructor for the QML property node, when the \a parent
+ is QML property group node. This constructor is only used
+ for creating QML property nodes for QML elements, i.e.
+ not for creating QML property nodes for QML components.
+ Hopefully, this constructor will become obsolete, so don't
+ use it unless one of the other two constructors can't be
+ used.
+ */
+QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent,
+ const QString& name,
+ const QString& type,
+ bool attached)
+ : LeafNode(QmlProperty, parent, name),
+ type_(type),
+ sto(Trool_Default),
+ des(Trool_Default),
+ isdefault_(false),
+ attached_(attached),
+ readOnly_(-1)
+{
+ setPageType(ApiPage);
+}
+
+/*!
+ Constructor for the QML property node, when the \a parent
+ is a QML class node.
+ */
+QmlPropertyNode::QmlPropertyNode(QmlClassNode *parent,
+ const QString& name,
+ const QString& type,
+ bool attached)
+ : LeafNode(QmlProperty, parent, name),
+ type_(type),
+ sto(Trool_Default),
+ des(Trool_Default),
+ isdefault_(false),
+ attached_(attached),
+ readOnly_(-1)
+{
+ setPageType(ApiPage);
+}
+
+/*!
+ Constructor for the QML property node, when the \a parent
+ is a QML property node. Strictly speaking, this is not the
+ way QML property nodes were originally meant to be built,
+ because this constructor has another QML property node as
+ its parent. But this constructor is useful for documenting
+ QML properties in QML components, i.e., when you override
+ the definition of a property with the \e{qmlproperty}
+ command. It actually uses the parent of \a parent as the
+ parent.
+ */
+QmlPropertyNode::QmlPropertyNode(QmlPropertyNode* parent,
+ const QString& name,
+ const QString& type,
+ bool attached)
+ : LeafNode(parent->parent(), QmlProperty, name),
+ type_(type),
+ sto(Trool_Default),
+ des(Trool_Default),
+ isdefault_(false),
+ attached_(attached),
+ readOnly_(-1)
+{
+ setPageType(ApiPage);
+}
+
+/*!
+ I don't know what this is.
+ */
+QmlPropertyNode::Trool QmlPropertyNode::toTrool(bool boolean)
+{
+ return boolean ? Trool_True : Trool_False;
+}
+
+/*!
+ I don't know what this is either.
+ */
+bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue)
+{
+ switch (troolean) {
+ case Trool_True:
+ return true;
+ case Trool_False:
+ return false;
+ default:
+ return defaultValue;
+ }
+}
+
+/*!
+ Returns true if a QML property or attached property is
+ read-only. The algorithm for figuring this out is long
+ amd tedious and almost certainly will break. It currently
+ doesn't work for qmlproperty bool PropertyChanges::explicit,
+ because the tokenizer gets confused on "explicit".
+ */
+bool QmlPropertyNode::isWritable(const Tree* tree) const
+{
+ if (wri != Trool_Default)
+ return fromTrool(wri, false);
+
+ const PropertyNode *pn = correspondingProperty(tree);
+ if (pn)
+ return pn->isWritable();
+ else {
+ location().warning(tr("Can't determine read-only status of QML property %1; writable assumed.").arg(name()));
+ return true;
+ }
+}
+
+const PropertyNode *QmlPropertyNode::correspondingProperty(const Tree *tree) const
+{
+ const PropertyNode *pn;
+
+ Node* n = parent();
+ while (n && n->subType() != Node::QmlClass)
+ n = n->parent();
+ if (n) {
+ const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n);
+ const ClassNode* cn = qcn->classNode();
+ if (cn) {
+ QStringList dotSplit = name().split(QChar('.'));
+ pn = cn->findPropertyNode(dotSplit[0]);
+ if (pn) {
+ if (dotSplit.size() > 1) {
+ // Find the C++ property corresponding to the QML property in
+ // the property group, <group>.<property>.
+
+ QStringList path(extractClassName(pn->qualifiedDataType()));
+ const Node* nn = tree->findNode(path,Class);
+ if (nn) {
+ const ClassNode* cn = static_cast<const ClassNode*>(nn);
+ const PropertyNode *pn2 = cn->findPropertyNode(dotSplit[1]);
+ if (pn2)
+ return pn2; // Return the property for the QML property.
+ else
+ return pn; // Return the property for the QML group.
+ }
+ }
+ else
+ return pn;
+ }
+ else {
+ pn = cn->findPropertyNode(dotSplit[0]);
+ if (pn)
+ return pn;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*! \class NameCollisionNode
+
+ An instance of this node is inserted in the tree
+ whenever qdoc discovers that two nodes have the
+ same name.
+ */
+
+/*!
+ Constructs a name collision node containing \a child
+ as its first child. The parent of \a child becomes
+ this node's parent.
+ */
+NameCollisionNode::NameCollisionNode(InnerNode* child)
+ : FakeNode(child->parent(), child->name(), Collision, Node::NoPageType)
+{
+ setTitle("Name Collisions For: " + child->name());
+ addCollision(child);
+ current = 0;
+}
+
+/*!
+ Add a collision to this collision node. \a child has
+ the same name as the other children in this collision
+ node. \a child becomes the current child.
+ */
+void NameCollisionNode::addCollision(InnerNode* child)
+{
+ if (child) {
+ if (child->parent())
+ child->parent()->removeChild(child);
+ child->setParent((InnerNode*)this);
+ children.append(child);
+ }
+}
+
+/*!
+ The destructor does nothing.
+ */
+NameCollisionNode::~NameCollisionNode()
+{
+ // nothing.
+}
+
+/*! \fn const InnerNode* NameCollisionNode::currentChild() const
+ Returns a pointer to the current child, which may be 0.
+ */
+
+/*! \fn void NameCollisionNode::setCurrentChild(InnerNode* child)
+ Sets the current child to \a child. The current child is
+ valid only within the file where it is defined.
+ */
+
+/*! \fn void NameCollisionNode::clearCurrentChild()
+ Sets the current child to 0. This should be called at the
+ end of each file, because the current child is only valid
+ within the file where the child is defined.
+ */
+
+/*!
+ Returns true if this collision node's current node is a QML node.
+ */
+bool NameCollisionNode::isQmlNode() const
+{
+ if (current)
+ return current->isQmlNode();
+ return false;
+}
+
+/*!
+ Find any of this collision node's children that has type \a t
+ and subtype \a st and return a pointer to it.
+*/
+const InnerNode* NameCollisionNode::findAny(Node::Type t, Node::SubType st) const
+{
+ if (current) {
+ if (current->type() == t && current->subType() == st)
+ return current;
+ }
+ const NodeList& cn = childNodes();
+ NodeList::ConstIterator i = cn.begin();
+ while (i != cn.end()) {
+ if ((*i)->type() == t && (*i)->subType() == st)
+ return static_cast<const InnerNode*>(*i);
+ ++i;
+ }
+ return 0;
+}
+
+/*!
+ This node is a name collision node. Find a child of this node
+ such that the child's QML module identifier matches origin's
+ QML module identifier. Return the matching node, or return this
+ node if there is no matching node.
+ */
+const Node* NameCollisionNode::applyModuleIdentifier(const Node* origin) const
+{
+ if (origin && !origin->qmlModuleIdentifier().isEmpty()) {
+ const NodeList& cn = childNodes();
+ NodeList::ConstIterator i = cn.begin();
+ while (i != cn.end()) {
+ if ((*i)->type() == Node::Fake && (*i)->subType() == Node::QmlClass) {
+ if (origin->qmlModuleIdentifier() == (*i)->qmlModuleIdentifier())
+ return (*i);
+ }
+ ++i;
+ }
+ }
+ return this;
+}
+
+/*!
+ Construct the full document name for this node and return it.
+ */
+QString Node::fullDocumentName() const
+{
+ QStringList pieces;
+ const Node* n = this;
+
+ do {
+ if (!n->name().isEmpty() &&
+ ((n->type() != Node::Fake) || (n->subType() != Node::QmlPropertyGroup)))
+ pieces.insert(0, n->name());
+
+ if ((n->type() == Node::Fake) && (n->subType() != Node::QmlPropertyGroup)) {
+ if ((n->subType() == Node::QmlClass) && !n->qmlModuleName().isEmpty())
+ pieces.insert(0, n->qmlModuleIdentifier());
+ break;
+ }
+
+ // Examine the parent node if one exists.
+ if (n->parent())
+ n = n->parent();
+ else
+ break;
+ } while (true);
+
+ // Create a name based on the type of the ancestor node.
+ QString concatenator = "::";
+ if ((n->type() == Node::Fake) && (n->subType() != Node::QmlClass))
+ concatenator = QLatin1Char('#');
+
+ return pieces.join(concatenator);
+}
+
+/*!
+ Returns the \a str as an NCName, which means the name can
+ be used as the value of an \e id attribute. Search for NCName
+ on the internet for details of what can be an NCName.
+ */
+QString Node::cleanId(QString str)
+{
+ QString clean;
+ QString name = str.simplified();
+
+ if (name.isEmpty())
+ return clean;
+
+ name = name.replace("::","-");
+ name = name.replace(" ","-");
+ name = name.replace("()","-call");
+
+ clean.reserve(name.size() + 20);
+ if (!str.startsWith("id-"))
+ clean = "id-";
+ const QChar c = name[0];
+ const uint u = c.unicode();
+
+ if ((u >= 'a' && u <= 'z') ||
+ (u >= 'A' && u <= 'Z') ||
+ (u >= '0' && u <= '9')) {
+ clean += c;
+ }
+ else if (u == '~') {
+ clean += "dtor.";
+ }
+ else if (u == '_') {
+ clean += "underscore.";
+ }
+ else {
+ clean += QLatin1Char('a');
+ }
+
+ for (int i = 1; i < (int) name.length(); i++) {
+ const QChar c = name[i];
+ const uint u = c.unicode();
+ if ((u >= 'a' && u <= 'z') ||
+ (u >= 'A' && u <= 'Z') ||
+ (u >= '0' && u <= '9') || u == '-' ||
+ u == '_' || u == '.') {
+ clean += c;
+ }
+ else if (c.isSpace() || u == ':' ) {
+ clean += QLatin1Char('-');
+ }
+ else if (u == '!') {
+ clean += "-not";
+ }
+ else if (u == '&') {
+ clean += "-and";
+ }
+ else if (u == '<') {
+ clean += "-lt";
+ }
+ else if (u == '=') {
+ clean += "-eq";
+ }
+ else if (u == '>') {
+ clean += "-gt";
+ }
+ else if (u == '#') {
+ clean += "-hash";
+ }
+ else if (u == '(') {
+ clean += "-";
+ }
+ else if (u == ')') {
+ clean += "-";
+ }
+ else {
+ clean += QLatin1Char('-');
+ clean += QString::number((int)u, 16);
+ }
+ }
+ return clean;
+}
+
+/*!
+ Creates a string that can be used as a UUID for the node,
+ depending on the type and subtype of the node. Uniquenss
+ is not guaranteed, but it is expected that strings created
+ here will be unique within an XML document. Hence, the
+ returned string can be used as the value of an \e id
+ attribute.
+ */
+QString Node::idForNode() const
+{
+ const FunctionNode* func;
+ const TypedefNode* tdn;
+ QString str;
+
+ switch (type()) {
+ case Node::Namespace:
+ str = "namespace-" + fullDocumentName();
+ break;
+ case Node::Class:
+ str = "class-" + fullDocumentName();
+ break;
+ case Node::Enum:
+ str = "enum-" + name();
+ break;
+ case Node::Typedef:
+ tdn = static_cast<const TypedefNode*>(this);
+ if (tdn->associatedEnum()) {
+ return tdn->associatedEnum()->idForNode();
+ }
+ else {
+ str = "typedef-" + name();
+ }
+ break;
+ case Node::Function:
+ func = static_cast<const FunctionNode*>(this);
+ if (func->associatedProperty()) {
+ return func->associatedProperty()->idForNode();
+ }
+ else {
+ if (func->name().startsWith("operator")) {
+ str = "";
+ /*
+ The test below should probably apply to all
+ functions, but for now, overloaded operators
+ are the only ones that produce duplicate id
+ attributes in the DITA XML files.
+ */
+ if (relatesTo_)
+ str = "nonmember-";
+ QString op = func->name().mid(8);
+ if (!op.isEmpty()) {
+ int i = 0;
+ while (i<op.size() && op.at(i) == ' ')
+ ++i;
+ if (i>0 && i<op.size()) {
+ op = op.mid(i);
+ }
+ if (!op.isEmpty()) {
+ i = 0;
+ while (i < op.size()) {
+ const QChar c = op.at(i);
+ const uint u = c.unicode();
+ if ((u >= 'a' && u <= 'z') ||
+ (u >= 'A' && u <= 'Z') ||
+ (u >= '0' && u <= '9'))
+ break;
+ ++i;
+ }
+ str += "operator-";
+ if (i>0) {
+ QString tail = op.mid(i);
+ op = op.left(i);
+ if (operators_.contains(op)) {
+ str += operators_.value(op);
+ if (!tail.isEmpty())
+ str += "-" + tail;
+ }
+ else
+ qDebug() << "qdoc3 internal error: Operator missing from operators_ map:" << op;
+ }
+ else {
+ str += op;
+ }
+ }
+ }
+ }
+ else if (parent_) {
+ if (parent_->type() == Class)
+ str = "class-member-" + func->name();
+ else if (parent_->type() == Namespace)
+ str = "namespace-member-" + func->name();
+ else if (parent_->type() == Fake) {
+ if (parent_->subType() == QmlClass)
+ str = "qml-method-" + func->name();
+ else
+ qDebug() << "qdoc3 internal error: Node subtype not handled:"
+ << parent_->subType() << func->name();
+ }
+ else
+ qDebug() << "qdoc3 internal error: Node type not handled:"
+ << parent_->type() << func->name();
+
+ }
+ if (func->overloadNumber() != 1)
+ str += QLatin1Char('-') + QString::number(func->overloadNumber());
+ }
+ break;
+ case Node::Fake:
+ {
+ switch (subType()) {
+ case Node::QmlClass:
+ str = "qml-class-" + name();
+ break;
+ case Node::QmlPropertyGroup:
+ str = "qml-property-" + name();
+ break;
+ case Node::Page:
+ case Node::Group:
+ case Node::Module:
+ case Node::HeaderFile:
+ str = title();
+ if (str.isEmpty()) {
+ str = name();
+ if (str.endsWith(".html"))
+ str.remove(str.size()-5,5);
+ }
+ str.replace("/","-");
+ break;
+ case Node::File:
+ str = name();
+ str.replace("/","-");
+ break;
+ case Node::Example:
+ str = name();
+ str.replace("/","-");
+ break;
+ case Node::QmlBasicType:
+ str = "qml-basic-type-" + name();
+ break;
+ case Node::QmlModule:
+ str = "qml-module-" + name();
+ break;
+ case Node::Collision:
+ str = title();
+ str.replace(": ","-");
+ break;
+ default:
+ qDebug() << "ERROR: A case was not handled in Node::idForNode():"
+ << "subType():" << subType() << "type():" << type();
+ break;
+ }
+ }
+ break;
+ case Node::QmlProperty:
+ str = "qml-property-" + name();
+ break;
+ case Node::Property:
+ str = "property-" + name();
+ break;
+ case Node::QmlSignal:
+ str = "qml-signal-" + name();
+ break;
+ case Node::QmlSignalHandler:
+ str = "qml-signal-handler-" + name();
+ break;
+ case Node::QmlMethod:
+ str = "qml-method-" + name();
+ break;
+ case Node::Variable:
+ str = "var-" + name();
+ break;
+ case Node::Target:
+ str = name();
+ break;
+ default:
+ qDebug() << "ERROR: A case was not handled in Node::idForNode():"
+ << "type():" << type() << "subType():" << subType();
+ break;
+ }
+ if (str.isEmpty()) {
+ qDebug() << "ERROR: A link text was empty in Node::idForNode():"
+ << "type():" << type() << "subType():" << subType()
+ << "name():" << name()
+ << "title():" << title();
+ }
+ else {
+ str = cleanId(str);
+ }
+ return str;
+}
+
+QT_END_NAMESPACE