summaryrefslogtreecommitdiffstats
path: root/src/tools
diff options
context:
space:
mode:
authorMartin Smith <martin.smith@digia.com>2014-05-23 13:26:36 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-06-01 13:40:53 +0200
commit46959875cf7ddeb9bbcee883e4bfaef63992b870 (patch)
tree727c786536dbd21b28eaa8fcaf429259c97f6dc1 /src/tools
parentbb794270ec6cffb5f95bd7d18056b9e7bede7baa (diff)
qdoc: Give documenter more control of linking
This update is preparation for implementing the actual task described in the bug. To implement it required converting the QML type node and the QML basic type node to be first order tree nodes instead of subtypes of the documentation node. This cleans up a lot of messy logic in some places. It was also necessary to split the getLink() function in the html output generator into two functions, one still called getLink(), which handles the \l command, and one called qetAutoLink() which is called for generating auto links. This should make qdoc run faster. The basic infrastructure was also added for parsing the string in the square brackets for the \l command. There will be a further update to complete this task. Note that some autolinks might not be generated due to this change. I haven't seen any yet, but I believe there will be some. This can be fixed later, if it is a problem. Task-number: QTBUG-39221 Change-Id: I8135229984398408205ba901b9ef95ceac74683c Reviewed-by: Topi Reiniƶ <topi.reinio@digia.com>
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/qdoc/atom.cpp47
-rw-r--r--src/tools/qdoc/atom.h54
-rw-r--r--src/tools/qdoc/codemarker.cpp17
-rw-r--r--src/tools/qdoc/cppcodeparser.cpp15
-rw-r--r--src/tools/qdoc/ditaxmlgenerator.cpp153
-rw-r--r--src/tools/qdoc/ditaxmlgenerator.h1
-rw-r--r--src/tools/qdoc/doc.cpp81
-rw-r--r--src/tools/qdoc/generator.cpp117
-rw-r--r--src/tools/qdoc/generator.h4
-rw-r--r--src/tools/qdoc/helpprojectwriter.cpp65
-rw-r--r--src/tools/qdoc/htmlgenerator.cpp470
-rw-r--r--src/tools/qdoc/htmlgenerator.h3
-rw-r--r--src/tools/qdoc/main.cpp8
-rw-r--r--src/tools/qdoc/node.cpp110
-rw-r--r--src/tools/qdoc/node.h26
-rw-r--r--src/tools/qdoc/qdocdatabase.cpp55
-rw-r--r--src/tools/qdoc/qdocdatabase.h40
-rw-r--r--src/tools/qdoc/qdocindexfiles.cpp60
-rw-r--r--src/tools/qdoc/qmlvisitor.cpp12
-rw-r--r--src/tools/qdoc/tree.cpp76
-rw-r--r--src/tools/qdoc/tree.h11
21 files changed, 816 insertions, 609 deletions
diff --git a/src/tools/qdoc/atom.cpp b/src/tools/qdoc/atom.cpp
index 6f9da3790d..8816ea5d6f 100644
--- a/src/tools/qdoc/atom.cpp
+++ b/src/tools/qdoc/atom.cpp
@@ -42,31 +42,12 @@
#include <qregexp.h>
#include "atom.h"
#include "location.h"
+#include "qdocdatabase.h"
#include <stdio.h>
+#include <qdebug.h>
QT_BEGIN_NAMESPACE
-QLatin1String Atom::BOLD_ ("bold");
-QLatin1String Atom::INDEX_ ("index");
-QLatin1String Atom::ITALIC_ ("italic");
-QLatin1String Atom::LINK_ ("link");
-QLatin1String Atom::PARAMETER_ ("parameter");
-QLatin1String Atom::SPAN_ ("span");
-QLatin1String Atom::SUBSCRIPT_ ("subscript");
-QLatin1String Atom::SUPERSCRIPT_ ("superscript");
-QLatin1String Atom::TELETYPE_ ("teletype");
-QLatin1String Atom::UICONTROL_ ("uicontrol");
-QLatin1String Atom::UNDERLINE_ ("underline");
-
-QLatin1String Atom::BULLET_ ("bullet");
-QLatin1String Atom::TAG_ ("tag");
-QLatin1String Atom::VALUE_ ("value");
-QLatin1String Atom::LOWERALPHA_ ("loweralpha");
-QLatin1String Atom::LOWERROMAN_ ("lowerroman");
-QLatin1String Atom::NUMERIC_ ("numeric");
-QLatin1String Atom::UPPERALPHA_ ("upperalpha");
-QLatin1String Atom::UPPERROMAN_ ("upperroman");
-
/*! \class Atom
\brief The Atom class is the fundamental unit for representing
documents internally.
@@ -387,4 +368,28 @@ void Atom::dump() const
str.toLatin1().data());
}
+/*!
+ The only constructor for LinkAtom. It only create an Atom
+ of type Atom::Link with \a p1 being the link text. \a p2
+ contains some search parameters.
+ */
+LinkAtom::LinkAtom(const QString& p1, const QString& p2)
+ : Atom(Link, p1), qml_(false), goal_(Node::NoType), domain_(0)
+{
+ QStringList params = p2.toLower().split(QLatin1Char(' '));
+ foreach (const QString& p, params) {
+ if (p == "qml")
+ qml_ = true;
+ else {
+ if (!domain_) {
+ domain_ = QDocDatabase::qdocDB()->findTree(p);
+ if (domain_)
+ continue;
+ }
+ if (goal_ == Node::NoType)
+ goal_ = Node::goal(p);
+ }
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/tools/qdoc/atom.h b/src/tools/qdoc/atom.h
index 84a52c9257..999919482b 100644
--- a/src/tools/qdoc/atom.h
+++ b/src/tools/qdoc/atom.h
@@ -39,17 +39,16 @@
**
****************************************************************************/
-/*
- atom.h
-*/
-
#ifndef ATOM_H
#define ATOM_H
#include <qstringlist.h>
+#include "node.h"
QT_BEGIN_NAMESPACE
+class Tree;
+
class Atom
{
public:
@@ -169,6 +168,8 @@ public:
previous->next_ = this;
}
+ virtual ~Atom() { }
+
void appendChar(QChar ch) { strs[0] += ch; }
void appendString(const QString& string) { strs[0] += string; }
void chopString() { strs[0].chop(1); }
@@ -186,33 +187,34 @@ public:
int count() const { return strs.size(); }
void dump() const;
- static QLatin1String BOLD_;
- static QLatin1String INDEX_;
- static QLatin1String ITALIC_;
- static QLatin1String LINK_;
- static QLatin1String PARAMETER_;
- static QLatin1String SPAN_;
- static QLatin1String SUBSCRIPT_;
- static QLatin1String SUPERSCRIPT_;
- static QLatin1String TELETYPE_;
- static QLatin1String UICONTROL_;
- static QLatin1String UNDERLINE_;
-
- static QLatin1String BULLET_;
- static QLatin1String TAG_;
- static QLatin1String VALUE_;
- static QLatin1String LOWERALPHA_;
- static QLatin1String LOWERROMAN_;
- static QLatin1String NUMERIC_;
- static QLatin1String UPPERALPHA_;
- static QLatin1String UPPERROMAN_;
-
-private:
+ virtual bool qml() const { return false; }
+ virtual bool specifiesDomain() const { return false; }
+ virtual Tree* domain() const { return 0; }
+ virtual Node::Type goal() const { return Node::NoType; }
+
+ protected:
Atom* next_;
Type type_;
QStringList strs;
};
+class LinkAtom : public Atom
+{
+ public:
+ LinkAtom(const QString& p1, const QString& p2);
+ virtual ~LinkAtom() { }
+
+ virtual bool qml() const { return qml_; }
+ virtual bool specifiesDomain() const { return (domain_ != 0); }
+ virtual Tree* domain() const { return domain_; }
+ virtual Node::Type goal() const { return goal_; }
+
+ protected:
+ bool qml_;
+ Node::Type goal_;
+ Tree* domain_;
+};
+
#define ATOM_FORMATTING_BOLD "bold"
#define ATOM_FORMATTING_INDEX "index"
#define ATOM_FORMATTING_ITALIC "italic"
diff --git a/src/tools/qdoc/codemarker.cpp b/src/tools/qdoc/codemarker.cpp
index ec342c6df0..235b3c3f04 100644
--- a/src/tools/qdoc/codemarker.cpp
+++ b/src/tools/qdoc/codemarker.cpp
@@ -273,7 +273,7 @@ QString CodeMarker::taggedNode(const Node* node)
case Node::Property:
tag = QLatin1String("@property");
break;
- case Node::Document:
+ case Node::QmlType:
/*
Remove the "QML:" prefix, if present.
There shouldn't be any of these "QML:"
@@ -282,10 +282,11 @@ QString CodeMarker::taggedNode(const Node* node)
qualifiers, but this code is kept to
be backward compatible.
*/
- if (node->subType() == Node::QmlClass) {
- if (node->name().startsWith(QLatin1String("QML:")))
- name = name.mid(4);
- }
+ if (node->name().startsWith(QLatin1String("QML:")))
+ name = name.mid(4);
+ tag = QLatin1String("@property");
+ break;
+ case Node::Document:
tag = QLatin1String("@property");
break;
case Node::QmlMethod:
@@ -400,9 +401,8 @@ void CodeMarker::insert(FastSection &fastSection,
InnerNode* p = node->parent();
if (p->type() == Node::QmlPropertyGroup)
p = p->parent();
- if (p != fastSection.parent_) { // && !node->parent()->isAbstract()) {
- if (p->subType() != Node::QmlClass || !p->isAbstract()) {
- //if (node->type() != Node::QmlProperty) {
+ if (p != fastSection.parent_) {
+ if (!p->isQmlType() || !p->isAbstract()) {
inheritedMember = true;
}
}
@@ -622,6 +622,7 @@ QStringList CodeMarker::macRefsForNode(Node *node)
}
case Node::Namespace:
case Node::Document:
+ case Node::QmlType:
default:
return QStringList();
}
diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp
index cda541c928..2755bf7254 100644
--- a/src/tools/qdoc/cppcodeparser.cpp
+++ b/src/tools/qdoc/cppcodeparser.cpp
@@ -408,17 +408,13 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
without including the namespace qualifier.
*/
Node::Type type = nodeTypeMap[command];
- Node::SubType subtype = Node::NoSubType;
- if (type == Node::Document)
- subtype = Node::QmlClass;
-
QStringList paths = arg.first.split(QLatin1Char(' '));
QStringList path = paths[0].split("::");
Node *node = 0;
- node = qdb_->findNodeInOpenNamespace(path, type, subtype);
+ node = qdb_->findNodeInOpenNamespace(path, type);
if (node == 0)
- node = qdb_->findNodeByNameAndType(path, type, subtype);
+ node = qdb_->findNodeByNameAndType(path, type);
if (node == 0) {
doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file")
.arg(arg.first).arg(command));
@@ -971,14 +967,14 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
else if (command == COMMAND_QMLINHERITS) {
if (node->name() == arg)
doc.location().warning(tr("%1 tries to inherit itself").arg(arg));
- else if (node->subType() == Node::QmlClass) {
+ else if (node->isQmlType()) {
QmlClassNode *qmlClass = static_cast<QmlClassNode*>(node);
qmlClass->setQmlBaseName(arg);
QmlClassNode::addInheritedBy(arg,node);
}
}
else if (command == COMMAND_QMLINSTANTIATES) {
- if ((node->type() == Node::Document) && (node->subType() == Node::QmlClass)) {
+ if (node->isQmlType()) {
ClassNode* classNode = qdb_->findClassNode(arg.split("::"));
if (classNode)
node->setClassNode(classNode);
@@ -1023,9 +1019,8 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
}
}
else if (command == COMMAND_QMLABSTRACT) {
- if ((node->type() == Node::Document) && (node->subType() == Node::QmlClass)) {
+ if (node->isQmlType())
node->setAbstract(true);
- }
}
else {
processCommonMetaCommand(doc.location(),command,argLocPair,node);
diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp
index 90661d80e0..bbd32204ce 100644
--- a/src/tools/qdoc/ditaxmlgenerator.cpp
+++ b/src/tools/qdoc/ditaxmlgenerator.cpp
@@ -819,7 +819,6 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
}
break;
case Atom::BriefRight:
- // if (relative->type() != Node::Document)
writeEndTag(); // </shortdesc> or </p>
if (in_para)
in_para = false;
@@ -1106,10 +1105,8 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
while (n != nsmap.constEnd()) {
const Node* node = n.value();
switch (node->type()) {
- case Node::Document:
- if (node->subType() == Node::QmlClass) {
- sections[QmlClass].appendMember((Node*)node);
- }
+ case Node::QmlType:
+ sections[QmlClass].appendMember((Node*)node);
break;
case Node::Namespace:
sections[Namespace].appendMember((Node*)node);
@@ -1256,8 +1253,7 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
images.append(QLatin1Char('/'));
fileName = images + atom->string();
}
- if (relative && (relative->type() == Node::Document) &&
- (relative->subType() == Node::Example)) {
+ if (relative && relative->isExample()) {
const ExampleNode* cen = static_cast<const ExampleNode*>(relative);
if (cen->imageFileName().isEmpty()) {
ExampleNode* en = const_cast<ExampleNode*>(cen);
@@ -1313,8 +1309,8 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
{
const Node *node = 0;
QString myLink = getLink(atom, relative, &node);
- if (myLink.isEmpty())
- myLink = getCollisionLink(atom);
+ //if (myLink.isEmpty())
+ //myLink = getCollisionLink(atom);
if (myLink.isEmpty() && !noLinkErrors())
relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string()));
else if (!inSectionHeading_)
@@ -2052,7 +2048,7 @@ DitaXmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
generateLowStatusMembers(inner,marker,CodeMarker::Compat);
writeEndTag(); // </cxxClass>
}
- else if ((inner->type() == Node::Document) && (inner->subType() == Node::HeaderFile)) {
+ else if (inner->isHeaderFile()) {
const DocNode* dn = const_cast<DocNode*>(static_cast<const DocNode*>(inner));
rawTitle = inner->plainName();
fullTitle = inner->plainFullName();
@@ -2168,7 +2164,7 @@ DitaXmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
generateLowStatusMembers(inner,marker,CodeMarker::Compat);
writeEndTag(); // </cxxClass>
}
- else if ((inner->type() == Node::Document) && (inner->subType() == Node::QmlClass)) {
+ else if (inner->isQmlType()) {
QmlClassNode* qcn = const_cast<QmlClassNode*>(static_cast<const QmlClassNode*>(inner));
ClassNode* cn = qcn->classNode();
rawTitle = inner->plainName();
@@ -2217,6 +2213,36 @@ DitaXmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
}
/*!
+ Generate the DITA page for a qdoc file that doesn't map
+ to an underlying c++ file.
+ */
+void DitaXmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker)
+{
+ QList<Section> sections;
+ QList<Section>::const_iterator s;
+ QString fullTitle = "QML Basic Type: " + qbtn->fullTitle();
+
+ generateHeader(qbtn, fullTitle);
+ generateBrief(qbtn, marker); // <shortdesc>
+ writeProlog(qbtn);
+
+ writeStartTag(DT_body);
+ enterSection(QString(), QString());
+
+ if (!qbtn->doc().isEmpty()) {
+ generateBody(qbtn, marker);
+ generateAlsoList(qbtn, marker);
+ }
+ leaveSection(); // </section>
+ if (!writeEndTag()) { // </body>
+ qbtn->doc().location().warning(tr("Pop of empty XML tag stack; generating DITA for '%1'").arg(qbtn->name()));
+ return;
+ }
+ writeRelatedLinks(qbtn);
+ writeEndTag(); // </topic>
+}
+
+/*!
Write a list item for a \a link with the given \a text.
*/
void DitaXmlGenerator::writeXrefListItem(const QString& link, const QString& text)
@@ -2251,10 +2277,7 @@ void DitaXmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
QList<Section>::const_iterator s;
QString fullTitle = dn->fullTitle();
- if (dn->subType() == Node::QmlBasicType) {
- fullTitle = "QML Basic Type: " + fullTitle;
- }
- else if (dn->subType() == Node::Collision) {
+ if (dn->subType() == Node::Collision) {
fullTitle = "Name Collision: " + fullTitle;
}
@@ -2391,7 +2414,7 @@ void DitaXmlGenerator::writeRelatedLinks(const Node* node)
linkNode = qdb_->findNodeForTarget(linkPair.first, node);
if (!linkNode)
node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first));
- if (linkNode && linkNode->type() == Node::Document) {
+ if (linkNode && linkNode->isDocNode()) {
const DocNode *docNode = static_cast<const DocNode*>(linkNode);
linkPair.second = docNode->title();
}
@@ -2402,7 +2425,7 @@ void DitaXmlGenerator::writeRelatedLinks(const Node* node)
linkNode = qdb_->findNodeForTarget(linkPair.first, node);
if (!linkNode)
node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first));
- if (linkNode && linkNode->type() == Node::Document) {
+ if (linkNode && linkNode->isDocNode()) {
const DocNode *docNode = static_cast<const DocNode*>(linkNode);
linkPair.second = docNode->title();
}
@@ -2413,7 +2436,7 @@ void DitaXmlGenerator::writeRelatedLinks(const Node* node)
linkNode = qdb_->findNodeForTarget(linkPair.first, node);
if (!linkNode)
node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first));
- if (linkNode && linkNode->type() == Node::Document) {
+ if (linkNode && linkNode->isDocNode()) {
const DocNode *docNode = static_cast<const DocNode*>(linkNode);
linkPair.second = docNode->title();
}
@@ -2804,7 +2827,7 @@ void DitaXmlGenerator::generateAnnotatedList(const Node* relative,
writeEndTag(); // </p>
writeEndTag(); // <entry>
- if (!(node->type() == Node::Document)) {
+ if (!node->isDocNode()) {
Text brief = node->doc().trimmedBriefText(node->name());
if (!brief.isEmpty()) {
writeStartTag(DT_entry);
@@ -3026,7 +3049,7 @@ void DitaXmlGenerator::generateCompactList(ListType , // currently not needed fo
writeHrefAttribute(linkForNode(it.value(), relative));
QStringList pieces;
- if (it.value()->subType() == Node::QmlClass)
+ if (it.value()->isQmlType())
pieces << it.value()->name();
else
pieces = it.value()->fullName(relative).split("::");
@@ -3435,8 +3458,8 @@ void DitaXmlGenerator::writeText(const QString& markedCode, const Node* relative
}
par1 = QStringRef();
n = qdb_->resolveType(arg.toString(), relative);
- if (n && n->subType() == Node::QmlBasicType) {
- if (relative && relative->subType() == Node::QmlClass)
+ if (n && n->isQmlBasicType()) {
+ if (relative && relative->isQmlType())
addLink(linkForNode(n, relative), arg);
else
writeCharacters(arg.toString());
@@ -3712,7 +3735,7 @@ QString DitaXmlGenerator::linkForNode(const Node* node, const Node* relative)
QString fn = fileName(node);
if (node && relative && node->parent() != relative) {
- if (node->parent()->subType() == Node::QmlClass && relative->subType() == Node::QmlClass) {
+ if (node->parent()->isQmlType() && relative->isQmlType()) {
if (node->parent()->isAbstract()) {
/*
This is a bit of a hack. What we discover with
@@ -3775,6 +3798,7 @@ int DitaXmlGenerator::hOffset(const Node* node)
case Node::Namespace:
case Node::Class:
return 2;
+ case Node::QmlType:
case Node::Document:
return 1;
case Node::Enum:
@@ -3836,7 +3860,7 @@ QString DitaXmlGenerator::getLink(const Atom* atom, const Node* relative, const
if (first.isEmpty())
*node = relative;
else if (first.endsWith(".html"))
- *node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document, Node::NoSubType);
+ *node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document);
else if (first.endsWith("()")) // The target is a C++ function or QML method.
*node = qdb_->resolveFunctionTarget(first, relative);
else {
@@ -3860,7 +3884,7 @@ QString DitaXmlGenerator::getLink(const Atom* atom, const Node* relative, const
if (relative && (relative->parent() != *node) &&
(relative->status() != Node::Obsolete)) {
bool porting = false;
- if (relative->type() == Node::Document) {
+ if (relative->isDocNode()) {
const DocNode* fake = static_cast<const DocNode*>(relative);
if (fake->title().startsWith("Porting"))
porting = true;
@@ -4607,7 +4631,7 @@ void DitaXmlGenerator::replaceTypesWithLinks(const Node* n, const InnerNode* par
const Node* tn = qdb_->resolveType(arg.toString(), parent);
if (tn) {
//Do not generate a link from a C++ function to a QML Basic Type (such as int)
- if (n->type() == Node::Function && tn->subType() == Node::QmlBasicType)
+ if (n->isFunction() && tn->isQmlBasicType())
writeCharacters(arg.toString());
else
addLink(linkForNode(tn,parent),arg,DT_apiRelation);
@@ -4762,12 +4786,13 @@ void DitaXmlGenerator::writeEnumerations(const Section& s,
}
// not included: <cxxEnumeratorAPIItemLocation>
-
+#if 0
if (!(*i).text().isEmpty()) {
writeStartTag(DT_apiDesc);
generateText((*i).text(), en, marker);
writeEndTag(); // </apiDesc>
}
+#endif
writeEndTag(); // <cxxEnumerator>
++i;
}
@@ -5268,7 +5293,7 @@ DitaXmlGenerator::generateInnerNode(InnerNode* node)
if (!node->url().isNull())
return;
- if (node->type() == Node::Document) {
+ if (node->isDocNode()) {
DocNode* docNode = static_cast<DocNode*>(node);
if (docNode->subType() == Node::ExternalPage)
return;
@@ -5279,7 +5304,7 @@ DitaXmlGenerator::generateInnerNode(InnerNode* node)
qDebug("PAGE %s HAS CHILDREN", qPrintable(docNode->title()));
}
}
- else if (node->type() == Node::QmlPropertyGroup)
+ else if (node->isQmlPropertyGroup())
return;
/*
@@ -5292,24 +5317,19 @@ DitaXmlGenerator::generateInnerNode(InnerNode* node)
later in generateCollisionPages(). Each one is
appended to a list for later.
*/
- if ((node->type() == Node::Document) && (node->subType() == Node::Collision)) {
+ if (node->isCollisionNode()) {
NameCollisionNode* ncn = static_cast<NameCollisionNode*>(node);
collisionNodes.append(const_cast<NameCollisionNode*>(ncn));
}
else {
if (!node->name().endsWith(".ditamap"))
beginSubPage(node, fileName(node));
- if (node->type() == Node::Namespace || node->type() == Node::Class) {
+ if (node->isNamespace() || node->isClass() || node->isQmlType() || node->isHeaderFile())
generateClassLikeNode(node, marker);
- }
- else if (node->type() == Node::Document) {
- if (node->subType() == Node::HeaderFile)
- generateClassLikeNode(node, marker);
- else if (node->subType() == Node::QmlClass)
- generateClassLikeNode(node, marker);
- else
- generateDocNode(static_cast<DocNode*>(node), marker);
- }
+ else if (node->isDocNode())
+ generateDocNode(static_cast<DocNode*>(node), marker);
+ else if (node->isQmlBasicType())
+ generateQmlBasicTypePage(static_cast<QmlBasicTypeNode*>(node), marker);
if (!node->name().endsWith(".ditamap"))
endSubPage();
}
@@ -5378,7 +5398,7 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
QString message;
for (int i=0; i<children.size(); ++i) {
Node* child = children[i];
- if ((child->type() == Node::Document) && (child->subType() == Node::Collision)) {
+ if (child->isCollisionNode()) {
const DocNode* fake = static_cast<const DocNode*>(child);
Node* n = collectNodesByTypeAndSubtype(fake);
if (n)
@@ -5401,6 +5421,14 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
if (!isDuplicate(nodeTypeMaps[Node::Class],child->name(),child))
nodeTypeMaps[Node::Class]->insert(child->name(),child);
break;
+ case Node::QmlType:
+ if (!isDuplicate(nodeTypeMaps[Node::QmlType],child->name(),child))
+ nodeTypeMaps[Node::QmlType]->insert(child->name(),child);
+ break;
+ case Node::QmlBasicType:
+ if (!isDuplicate(nodeTypeMaps[Node::QmlBasicType],child->title(),child))
+ nodeTypeMaps[Node::QmlBasicType]->insert(child->title(),child);
+ break;
case Node::Group:
if (!isDuplicate(nodeTypeMaps[Node::Group],child->title(),child))
nodeTypeMaps[Node::Group]->insert(child->title(),child);
@@ -5435,14 +5463,6 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
if (!isDuplicate(nodeSubtypeMaps[Node::ExternalPage],child->title(),child))
nodeSubtypeMaps[Node::ExternalPage]->insert(child->title(),child);
break;
- case Node::QmlClass:
- if (!isDuplicate(nodeSubtypeMaps[Node::QmlClass],child->title(),child))
- nodeSubtypeMaps[Node::QmlClass]->insert(child->title(),child);
- break;
- case Node::QmlBasicType:
- if (!isDuplicate(nodeSubtypeMaps[Node::QmlBasicType],child->title(),child))
- nodeSubtypeMaps[Node::QmlBasicType]->insert(child->title(),child);
- break;
case Node::Collision:
if (!isDuplicate(nodeSubtypeMaps[Node::Collision],child->title(),child))
nodeSubtypeMaps[Node::Collision]->insert(child->title(),child);
@@ -5551,10 +5571,10 @@ void DitaXmlGenerator::writeDitaMap()
writeTopicrefs(nodeTypeMaps[Node::QmlModule], "QML modules");
if (nodeTypeMaps[Node::QmlModule]->size() == 1)
- writeTopicrefs(nodeSubtypeMaps[Node::QmlClass], "QML types", nodeTypeMaps[Node::QmlModule]->values()[0]);
+ writeTopicrefs(nodeTypeMaps[Node::QmlType], "QML types", nodeTypeMaps[Node::QmlModule]->values()[0]);
else
- writeTopicrefs(nodeSubtypeMaps[Node::QmlClass], "QML types");
- writeTopicrefs(nodeSubtypeMaps[Node::QmlBasicType], "QML basic types");
+ writeTopicrefs(nodeTypeMaps[Node::QmlType], "QML types");
+ writeTopicrefs(nodeTypeMaps[Node::QmlBasicType], "QML basic types");
if (nodeTypeMaps[Node::Module]->size() > 1)
writeTopicrefs(nodeTypeMaps[Node::Module], "Modules");
@@ -5910,32 +5930,32 @@ DitaXmlGenerator::writeProlog(const InnerNode* inner)
if (!writeMetadataElement(inner,DT_category,false)) {
writeStartTag(DT_category);
QString category = "Page";
- if (inner->type() == Node::Class)
+ if (inner->isClass())
category = "Class reference";
- else if (inner->type() == Node::Namespace)
+ if (inner->isQmlType())
+ category = "QML Reference";
+ else if (inner->isQmlBasicType())
+ category = "QML Basic Type";
+ else if (inner->isNamespace())
category = "Namespace";
- else if (inner->type() == Node::Module)
+ else if (inner->isModule())
category = "Module";
- else if (inner->type() == Node::QmlModule)
+ else if (inner->isQmlModule())
category = "QML Module";
- else if (inner->type() == Node::Group)
+ else if (inner->isGroup())
category = "Group";
- else if (inner->type() == Node::Document) {
- if (inner->subType() == Node::QmlClass)
- category = "QML Reference";
- else if (inner->subType() == Node::QmlBasicType)
- category = "QML Basic Type";
- else if (inner->subType() == Node::HeaderFile)
+ else if (inner->isDocNode()) {
+ if (inner->isHeaderFile())
category = "Header File";
else if (inner->subType() == Node::File)
category = "Example Source File";
- else if (inner->subType() == Node::Example)
+ else if (inner->isExample())
category = "Example";
else if (inner->subType() == Node::Image)
category = "Image";
else if (inner->subType() == Node::Page)
category = "Page";
- else if (inner->subType() == Node::ExternalPage)
+ else if (inner->isExternalPage())
category = "External Page"; // Is this necessary?
}
xmlWriter().writeCharacters(category);
@@ -5977,8 +5997,7 @@ DitaXmlGenerator::writeProlog(const InnerNode* inner)
xmlWriter().writeAttribute("content",i.value());
writeEndTag(); // </othermeta>
}
- if ((tagStack.first() == DT_cxxClass && !inner->includes().isEmpty()) ||
- (inner->type() == Node::Document && inner->subType() == Node::HeaderFile)) {
+ if ((tagStack.first() == DT_cxxClass && !inner->includes().isEmpty()) || inner->isHeaderFile()) {
writeStartTag(DT_othermeta);
xmlWriter().writeAttribute("name","includeFile");
QString text;
diff --git a/src/tools/qdoc/ditaxmlgenerator.h b/src/tools/qdoc/ditaxmlgenerator.h
index a65ddfabed..0239151402 100644
--- a/src/tools/qdoc/ditaxmlgenerator.h
+++ b/src/tools/qdoc/ditaxmlgenerator.h
@@ -315,6 +315,7 @@ protected:
const Node* relative,
CodeMarker* marker);
virtual void generateClassLikeNode(InnerNode* inner, CodeMarker* marker);
+ virtual void generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker);
virtual void generateDocNode(DocNode* dn, CodeMarker* marker);
virtual void generateCollectionNode(CollectionNode* cn, CodeMarker* marker);
virtual QString fileExtension() const;
diff --git a/src/tools/qdoc/doc.cpp b/src/tools/qdoc/doc.cpp
index b3fe9e444e..4fe0972d72 100644
--- a/src/tools/qdoc/doc.cpp
+++ b/src/tools/qdoc/doc.cpp
@@ -46,6 +46,7 @@
#include "openedlist.h"
#include "quoter.h"
#include "text.h"
+#include "atom.h"
#include "tokenizer.h"
#include <qdatetime.h>
#include <qfile.h>
@@ -63,7 +64,6 @@ Q_GLOBAL_STATIC(QSet<QString>, null_Set_QString)
Q_GLOBAL_STATIC(TopicList, nullTopicList)
Q_GLOBAL_STATIC(QStringList, null_QStringList)
Q_GLOBAL_STATIC(QList<Text>, null_QList_Text)
-//Q_GLOBAL_STATIC(QStringMap, null_QStringMap)
Q_GLOBAL_STATIC(QStringMultiMap, null_QStringMultiMap)
struct Macro
@@ -477,6 +477,7 @@ private:
void parseAlso();
void append(Atom::Type type, const QString& string = QString());
void append(Atom::Type type, const QString& p1, const QString& p2);
+ void append(const QString& p1, const QString& p2);
void appendChar(QChar ch);
void appendWord(const QString &word);
void appendToCode(const QString &code);
@@ -495,6 +496,7 @@ private:
Doc::Sections getSectioningUnit();
QString getArgument(bool verbatim = false);
QString getBracedArgument(bool verbatim);
+ QString getBracketedArgument();
QString getOptionalArgument();
QString getRestOfLine();
QString getMetaCommandArgument(const QString &cmdStr);
@@ -504,6 +506,7 @@ private:
bool isBlankLine();
bool isLeftBraceAhead();
+ bool isLeftBracketAhead();
void skipSpacesOnLine();
void skipSpacesOrOneEndl();
void skipAllSpaces();
@@ -965,9 +968,11 @@ void DocParser::parse(const QString& source,
break;
case CMD_L:
enterPara();
+ if (isLeftBracketAhead())
+ p2 = getBracketedArgument();
if (isLeftBraceAhead()) {
p1 = getArgument();
- append(Atom::Link, p1);
+ append(p1, p2);
if (isLeftBraceAhead()) {
currentLinkAtom = priv->text.lastAtom();
startFormat(ATOM_FORMATTING_LINK, cmd);
@@ -980,7 +985,7 @@ void DocParser::parse(const QString& source,
}
else {
p1 = getArgument();
- append(Atom::Link, p1);
+ append(p1, p2);
append(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
append(Atom::String, cleanLink(p1));
append(Atom::FormattingRight, ATOM_FORMATTING_LINK);
@@ -1984,6 +1989,17 @@ void DocParser::append(Atom::Type type, const QString& p1, const QString& p2)
priv->text << Atom(type, p1, p2);
}
+void DocParser::append(const QString& p1, const QString& p2)
+{
+ Atom::Type lastType = priv->text.lastAtom()->type();
+ if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n")))
+ priv->text.lastAtom()->chopString();
+ if (p2.isEmpty())
+ priv->text << Atom(Atom::Link, p1, p2);
+ else
+ priv->text << LinkAtom(p1, p2);
+}
+
void DocParser::appendChar(QChar ch)
{
if (priv->text.lastAtom()->type() != Atom::String)
@@ -2245,10 +2261,10 @@ Doc::Sections DocParser::getSectioningUnit()
Gets an argument that is enclosed in braces and returns it
without the enclosing braces. On entry, the current character
is the left brace. On exit, the current character is the one
- that comes afterr the right brace.
+ that comes after the right brace.
If \a verbatim is true, extra whitespace is retained in the
- returned string. Otherwise, extr whitespace is removed.
+ returned string. Otherwise, extra whitespace is removed.
*/
QString DocParser::getBracedArgument(bool verbatim)
{
@@ -2379,6 +2395,47 @@ QString DocParser::getArgument(bool verbatim)
return arg.simplified();
}
+/*!
+ Gets an argument that is enclosed in brackets and returns it
+ without the enclosing brackets. On entry, the current character
+ is the left bracket. On exit, the current character is the one
+ that comes after the right bracket.
+ */
+QString DocParser::getBracketedArgument()
+{
+ QString arg;
+ int delimDepth = 0;
+ skipSpacesOrOneEndl();
+ if (pos < in.length() && in[pos] == '[') {
+ pos++;
+ while (pos < in.length() && delimDepth >= 0) {
+ switch (in[pos].unicode()) {
+ case '[':
+ delimDepth++;
+ arg += QLatin1Char('[');
+ pos++;
+ break;
+ case ']':
+ delimDepth--;
+ if (delimDepth >= 0)
+ arg += QLatin1Char(']');
+ pos++;
+ break;
+ case '\\':
+ arg += in[pos];
+ pos++;
+ break;
+ default:
+ arg += in[pos];
+ pos++;
+ }
+ }
+ if (delimDepth > 0)
+ location().warning(tr("Missing ']'"));
+ }
+ return arg;
+}
+
QString DocParser::getOptionalArgument()
{
skipSpacesOrOneEndl();
@@ -2527,6 +2584,20 @@ bool DocParser::isLeftBraceAhead()
return numEndl < 2 && i < len && in[i] == '{';
}
+bool DocParser::isLeftBracketAhead()
+{
+ int numEndl = 0;
+ int i = pos;
+
+ while (i < len && in[i].isSpace() && numEndl < 2) {
+ // ### bug with '\\'
+ if (in[i] == '\n')
+ numEndl++;
+ i++;
+ }
+ return numEndl < 2 && i < len && in[i] == '[';
+}
+
/*!
Skips to the next non-space character or EOL.
*/
diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp
index 32fc17d5eb..6bba83efdb 100644
--- a/src/tools/qdoc/generator.cpp
+++ b/src/tools/qdoc/generator.cpp
@@ -325,19 +325,6 @@ QString Generator::fileBase(const Node *node) const
if (base.endsWith(".html"))
base.truncate(base.length() - 5);
- if (node->isQmlNode()) {
- if (!node->qmlModuleName().isEmpty()) {
- base.prepend(node->qmlModuleName() + QLatin1Char('-'));
- }
- /*
- To avoid file name conflicts in the html directory,
- we prepend a prefix (by default, "qml-") to the file name of QML
- element doc files.
- */
- if ((node->subType() == Node::QmlClass) || (node->subType() == Node::QmlBasicType)) {
- base.prepend(outputPrefix(QLatin1String("QML")));
- }
- }
if (node->isExample() || node->isExampleFile()) {
QString modPrefix(node->moduleName());
if (modPrefix.isEmpty()) {
@@ -349,6 +336,18 @@ QString Generator::fileBase(const Node *node) const
base.append(QLatin1String("-example"));
}
}
+ else if (node->isQmlType() || node->isQmlBasicType()) {
+ base = node->name();
+ if (!node->qmlModuleName().isEmpty()) {
+ base.prepend(node->qmlModuleName() + QLatin1Char('-'));
+ }
+ /*
+ To avoid file name conflicts in the html directory,
+ we prepend a prefix (by default, "qml-") to the file name of QML
+ element doc files.
+ */
+ base.prepend(outputPrefix(QLatin1String("QML")));
+ }
else if (node->isCollectionNode()) {
base = node->name();
if (base.endsWith(".html"))
@@ -367,7 +366,7 @@ QString Generator::fileBase(const Node *node) const
forever {
const Node *pp = p->parent();
base.prepend(p->name());
- if (!pp || pp->name().isEmpty() || pp->type() == Node::Document)
+ if (!pp || pp->name().isEmpty() || pp->isDocNode())
break;
base.prepend(QLatin1Char('-'));
p = pp;
@@ -467,25 +466,23 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
else
return QString();
}
- else if (node->isDocNode() || node->isCollectionNode()) {
- if (node->isQmlType() || node->isQmlBasicType()) {
- QString fb = fileBase(node);
- if (fb.startsWith(Generator::outputPrefix(QLatin1String("QML"))))
- return fb + QLatin1Char('.') + currentGenerator()->fileExtension();
- else {
- QString mq;
- if (!node->qmlModuleName().isEmpty()) {
- mq = node->qmlModuleName().replace(QChar('.'),QChar('-'));
- mq = mq.toLower() + QLatin1Char('-');
- }
- return fdl+ Generator::outputPrefix(QLatin1String("QML")) + mq +
- fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension();
- }
- }
+ else if (node->isQmlType() || node->isQmlBasicType()) {
+ QString fb = fileBase(node);
+ if (fb.startsWith(Generator::outputPrefix(QLatin1String("QML"))))
+ return fb + QLatin1Char('.') + currentGenerator()->fileExtension();
else {
- parentName = fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension();
+ QString mq;
+ if (!node->qmlModuleName().isEmpty()) {
+ mq = node->qmlModuleName().replace(QChar('.'),QChar('-'));
+ mq = mq.toLower() + QLatin1Char('-');
+ }
+ return fdl+ Generator::outputPrefix(QLatin1String("QML")) + mq +
+ fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension();
}
}
+ else if (node->isDocNode() || node->isCollectionNode()) {
+ parentName = fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension();
+ }
else if (fileBase(node).isEmpty())
return QString();
@@ -562,6 +559,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
case Node::Variable:
anchorRef = QLatin1Char('#') + node->name() + "-var";
break;
+ case Node::QmlType:
case Node::Document:
case Node::Group:
case Node::Module:
@@ -577,7 +575,8 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
}
// Various objects can be compat (deprecated) or obsolete.
- if (node->type() != Node::Class && node->type() != Node::Namespace) {
+ // Is this even correct?
+ if (!node->isClass() && !node->isNamespace()) {
switch (node->status()) {
case Node::Compat:
parentName.replace(QLatin1Char('.') + currentGenerator()->fileExtension(),
@@ -682,6 +681,10 @@ const Atom *Generator::generateAtomList(const Atom *atom,
return 0;
}
+/*!
+ Generate the body of the documentation from the qdoc comment
+ found with the entity represented by the \a node.
+ */
void Generator::generateBody(const Node *node, CodeMarker *marker)
{
bool quiet = false;
@@ -812,9 +815,9 @@ void Generator::generateBody(const Node *node, CodeMarker *marker)
}
}
- if (node->type() == Node::Document) {
+ if (node->isDocNode()) {
const DocNode *dn = static_cast<const DocNode *>(node);
- if (dn->subType() == Node::Example) {
+ if (dn->isExample()) {
generateExampleFiles(dn, marker);
}
else if (dn->subType() == Node::File) {
@@ -968,6 +971,9 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker)
/*!
Recursive writing of HTML files from the root \a node.
+ \note DitaXmlGenerator overrides this function, but
+ HtmlGenerator does not.
+
\note NameCollisionNodes are skipped here and processed
later. See HtmlGenerator::generateCollisionPages() for
more on this.
@@ -981,7 +987,7 @@ void Generator::generateInnerNode(InnerNode* node)
if (node->isInternal() && !showInternal_)
return;
- if (node->type() == Node::Document) {
+ if (node->isDocNode()) {
DocNode* docNode = static_cast<DocNode*>(node);
if (docNode->subType() == Node::ExternalPage)
return;
@@ -992,7 +998,7 @@ void Generator::generateInnerNode(InnerNode* node)
qDebug("PAGE %s HAS CHILDREN", qPrintable(docNode->title()));
}
}
- else if (node->type() == Node::QmlPropertyGroup)
+ else if (node->isQmlPropertyGroup())
return;
/*
@@ -1016,11 +1022,23 @@ void Generator::generateInnerNode(InnerNode* node)
generateClassLikeNode(node, marker);
endSubPage();
}
+ if (node->isQmlType()) {
+ beginSubPage(node, fileName(node));
+ QmlClassNode* qcn = static_cast<QmlClassNode*>(node);
+ generateQmlTypePage(qcn, marker);
+ endSubPage();
+ }
else if (node->isDocNode()) {
beginSubPage(node, fileName(node));
generateDocNode(static_cast<DocNode*>(node), marker);
endSubPage();
}
+ else if (node->isQmlBasicType()) {
+ beginSubPage(node, fileName(node));
+ QmlBasicTypeNode* qbtn = static_cast<QmlBasicTypeNode*>(node);
+ generateQmlBasicTypePage(qbtn, marker);
+ endSubPage();
+ }
else if (node->isCollectionNode()) {
CollectionNode* cn = static_cast<CollectionNode*>(node);
/*
@@ -1243,6 +1261,11 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker)
generateText(text, node, marker);
}
+/*!
+ Generate the documentation for \a relative. i.e. \a relative
+ is the node that reporesentas the entity where a qdoc comment
+ was found, and \a text represents the qdoc comment.
+ */
bool Generator::generateText(const Text& text,
const Node *relative,
CodeMarker *marker)
@@ -1420,7 +1443,14 @@ Generator *Generator::generatorForFormat(const QString& format)
return 0;
}
+#if 0
/*!
+ This function might be useless now with the addition of
+ multiple node trees. It is called a few hundred times,
+ but it never finds a collision node. The single call has
+ been commented out by mws (19/05/2014). If it is no
+ longer needed, it will be removed.
+
This function can be called if getLink() returns an empty
string. It tests the \a atom string to see if it is a link
of the form <element> :: <name>, where <element> is a QML
@@ -1452,7 +1482,7 @@ QString Generator::getCollisionLink(const Atom* atom)
}
return link;
}
-
+#endif
/*!
Looks up the tag \a t in the map of metadata values for the
@@ -1982,17 +2012,12 @@ QString Generator::typeString(const Node *node)
return "namespace";
case Node::Class:
return "class";
+ case Node::QmlType:
+ return "type";
+ case Node::QmlBasicType:
+ return "type";
case Node::Document:
- {
- switch (node->subType()) {
- case Node::QmlClass:
- return "type";
- case Node::QmlBasicType:
- return "type";
- default:
- return "documentation";
- }
- }
+ return "documentation";
case Node::Enum:
return "enum";
case Node::Typedef:
diff --git a/src/tools/qdoc/generator.h b/src/tools/qdoc/generator.h
index bcc1ea9502..81b63ef29a 100644
--- a/src/tools/qdoc/generator.h
+++ b/src/tools/qdoc/generator.h
@@ -114,6 +114,8 @@ protected:
virtual int generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker);
virtual void generateBody(const Node *node, CodeMarker *marker);
virtual void generateClassLikeNode(InnerNode* inner, CodeMarker* marker);
+ virtual void generateQmlTypePage(QmlClassNode* , CodeMarker* ) { }
+ virtual void generateQmlBasicTypePage(QmlBasicTypeNode* , CodeMarker* ) { }
virtual void generateDocNode(DocNode* dn, CodeMarker* marker);
virtual void generateCollectionNode(CollectionNode* cn, CodeMarker* marker);
virtual void generateInheritedBy(const ClassNode *classe, CodeMarker *marker);
@@ -155,7 +157,7 @@ protected:
void generateSince(const Node *node, CodeMarker *marker);
void generateStatus(const Node *node, CodeMarker *marker);
void generateThreadSafeness(const Node *node, CodeMarker *marker);
- QString getCollisionLink(const Atom* atom);
+ //QString getCollisionLink(const Atom* atom);
QString getMetadataElement(const InnerNode* inner, const QString& t);
QStringList getMetadataElements(const InnerNode* inner, const QString& t);
QString indent(int level, const QString& markedCode);
diff --git a/src/tools/qdoc/helpprojectwriter.cpp b/src/tools/qdoc/helpprojectwriter.cpp
index be81d5c8dd..a1121a95cb 100644
--- a/src/tools/qdoc/helpprojectwriter.cpp
+++ b/src/tools/qdoc/helpprojectwriter.cpp
@@ -139,6 +139,8 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList
typeHash["qmlsignalhandler"] = Node::QmlSignalHandler;
typeHash["qmlmethod"] = Node::QmlMethod;
typeHash["qmlpropertygroup"] = Node::QmlPropertyGroup;
+ typeHash["qmlclass"] = Node::QmlType;
+ typeHash["qmlbasictype"] = Node::QmlBasicType;
QHash<QString, Node::SubType> subTypeHash;
subTypeHash["example"] = Node::Example;
@@ -146,8 +148,6 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList
subTypeHash["file"] = Node::File;
subTypeHash["page"] = Node::Page;
subTypeHash["externalpage"] = Node::ExternalPage;
- subTypeHash["qmlclass"] = Node::QmlClass;
- subTypeHash["qmlbasictype"] = Node::QmlBasicType;
QSet<Node::SubType> allSubTypes = QSet<Node::SubType>::fromList(subTypeHash.values());
@@ -211,16 +211,14 @@ QStringList HelpProjectWriter::keywordDetails(const Node *node) const
// "id"
details << node->parent()->name()+"::"+node->name();
}
- else if (node->type() == Node::Document) {
+ else if (node->isQmlType() || node->isQmlBasicType()) {
+ details << node->name();
+ details << "QML." + node->name();
+ }
+ else if (node->isDocNode()) {
const DocNode *fake = static_cast<const DocNode *>(node);
- if (fake->subType() == Node::QmlClass) {
- details << (QmlClassNode::qmlOnly ? fake->name() : fake->fullTitle());
- details << "QML." + fake->name();
- }
- else {
- details << fake->fullTitle();
- details << fake->fullTitle();
- }
+ details << fake->fullTitle();
+ details << fake->fullTitle();
}
else {
details << node->name();
@@ -248,7 +246,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
return false;
QString objName;
- if (node->type() == Node::Document) {
+ if (node->isDocNode()) {
const DocNode *fake = static_cast<const DocNode *>(node);
objName = fake->fullTitle();
}
@@ -288,6 +286,25 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
project.keywords.append(keywordDetails(node));
project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()));
break;
+ case Node::QmlType:
+ case Node::QmlBasicType:
+ if (node->doc().hasKeywords()) {
+ foreach (const Atom* keyword, node->doc().keywords()) {
+ if (!keyword->string().isEmpty()) {
+ QStringList details;
+ details << keyword->string()
+ << keyword->string()
+ << gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()) +
+ QLatin1Char('#') + Doc::canonicalTitle(keyword->string());
+ project.keywords.append(details);
+ }
+ else
+ node->doc().location().warning(tr("Bad keyword in %1").arg(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs())));
+ }
+ }
+ project.keywords.append(keywordDetails(node));
+ project.files.insert(gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()));
+ break;
case Node::Namespace:
project.keywords.append(keywordDetails(node));
@@ -558,17 +575,14 @@ void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &write
if (href.isEmpty())
return;
- Node::SubType subType = static_cast<const DocNode*>(node)->subType();
-
bool derivedClass = false;
if (node->type() == Node::Class)
derivedClass = !(static_cast<const ClassNode *>(node)->baseClasses().isEmpty());
// Do not generate a 'List of all members' for namespaces or header files,
// but always generate it for derived classes and QML classes
- if (node->type() != Node::Namespace && subType != Node::HeaderFile &&
- (derivedClass || subType == Node::QmlClass ||
- !project.memberStatus[node].isEmpty())) {
+ if (!node->isNamespace() && !node->isHeaderFile() &&
+ (derivedClass || node->isQmlType() || !project.memberStatus[node].isEmpty())) {
QString membersPath = href + QStringLiteral("-members.html");
project.files.insert(membersPath);
if (writeSections)
@@ -612,6 +626,14 @@ void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer
writeSection(writer, href, objName);
break;
+ case Node::QmlType:
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", href);
+ writer.writeAttribute("title", tr("%1 Type Reference").arg(node->fullTitle()));
+ addMembers(project, writer, node);
+ writer.writeEndElement(); // section
+ break;
+
case Node::Document: {
// Document nodes (such as manual pages) contain subtypes, titles and other
// attributes.
@@ -619,12 +641,9 @@ void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer
writer.writeStartElement("section");
writer.writeAttribute("ref", href);
- if (docNode->subType() == Node::QmlClass)
- writer.writeAttribute("title", tr("%1 Type Reference").arg(docNode->fullTitle()));
- else
- writer.writeAttribute("title", docNode->fullTitle());
+ writer.writeAttribute("title", docNode->fullTitle());
- if ((docNode->subType() == Node::HeaderFile) || (docNode->subType() == Node::QmlClass))
+ if (docNode->subType() == Node::HeaderFile)
addMembers(project, writer, node);
writer.writeEndElement(); // section
@@ -695,7 +714,7 @@ void HelpProjectWriter::generateProject(HelpProject &project)
writer.writeStartElement("section");
const Node* node = qdb_->findDocNodeByTitle(project.indexTitle);
if (node == 0)
- node = qdb_->findNodeByNameAndType(QStringList("index.html"), Node::Document, Node::Page);
+ node = qdb_->findNodeByNameAndType(QStringList("index.html"), Node::Document);
QString indexPath;
// Never use a collision node as a landing page
if (node && !node->isCollisionNode())
diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp
index 99e59f60a3..be8c68fc11 100644
--- a/src/tools/qdoc/htmlgenerator.cpp
+++ b/src/tools/qdoc/htmlgenerator.cpp
@@ -268,7 +268,7 @@ QString HtmlGenerator::format()
*/
void HtmlGenerator::generateDocs()
{
- Node* qflags = qdb_->findNodeByNameAndType(QStringList("QFlags"), Node::Class, Node::NoSubType);
+ Node* qflags = qdb_->findClassNode(QStringList("QFlags"));
if (qflags)
qflagsHref_ = linkForNode(qflags,0);
if (!runPrepareOnly()) {
@@ -315,17 +315,22 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
case Atom::AutoLink:
if (!inLink_ && !inContents_ && !inSectionHeading_) {
const Node *node = 0;
- QString link = getLink(atom, relative, &node);
- if (!link.isEmpty()) {
+ QString link = getAutoLink(atom, relative, &node);
+ if (link.isEmpty()) {
+ if (autolinkErrors())
+ relative->doc().location().warning(tr("Can't autolink to '%1'").arg(atom->string()));
+ }
+ else if (node && node->status() == Node::Obsolete) {
+ if ((relative->parent() != node) && !relative->isObsolete())
+ link.clear();
+ }
+ if (link.isEmpty())
+ out() << protectEnc(atom->string());
+ else {
beginLink(link, node, relative);
generateLink(atom, marker);
endLink();
}
- else {
- out() << protectEnc(atom->string());
- if (autolinkErrors())
- relative->doc().location().warning(tr("Can't autolink to '%1'").arg(atom->string()));
- }
}
else {
out() << protectEnc(atom->string());
@@ -334,11 +339,9 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
case Atom::BaseName:
break;
case Atom::BriefLeft:
- if (relative->type() == Node::Document) {
- if (relative->subType() != Node::Example) {
- skipAhead = skipAtoms(atom, Atom::BriefRight);
- break;
- }
+ if (relative->isQmlBasicType() || (relative->isDocNode() && !relative->isExample())) {
+ skipAhead = skipAtoms(atom, Atom::BriefRight);
+ break;
}
out() << "<p>";
@@ -372,7 +375,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
}
break;
case Atom::BriefRight:
- if (relative->type() != Node::Document)
+ if (!relative->isDocNode())
out() << "</p>\n";
break;
case Atom::C:
@@ -602,10 +605,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
while (n != nsmap.constEnd()) {
const Node* node = n.value();
switch (node->type()) {
- case Node::Document:
- if (node->subType() == Node::QmlClass) {
- sections[QmlClass].appendMember((Node*)node);
- }
+ case Node::QmlType:
+ sections[QmlClass].appendMember((Node*)node);
break;
case Node::Namespace:
sections[Namespace].appendMember((Node*)node);
@@ -761,8 +762,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
out() << " alt=\"\"";
out() << " />";
helpProjectWriter->addExtraFile(fileName);
- if ((relative->type() == Node::Document) &&
- (relative->subType() == Node::Example)) {
+ if (relative->isExample()) {
const ExampleNode* cen = static_cast<const ExampleNode*>(relative);
if (cen->imageFileName().isEmpty()) {
ExampleNode* en = const_cast<ExampleNode*>(cen);
@@ -805,17 +805,26 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
break;
case Atom::Link:
{
+ inObsoleteLink = false;
const Node *node = 0;
- QString myLink = getLink(atom, relative, &node);
- if (myLink.isEmpty()) {
- myLink = getCollisionLink(atom);
- if (myLink.isEmpty() && !noLinkErrors()) {
- relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string()));
+ QString link = getLink(atom, relative, &node);
+ if (link.isEmpty() && !noLinkErrors()) {
+ relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string()));
+ }
+ else {
+ node = 0;
+ if (node && node->status() == Node::Obsolete) {
+ if ((relative->parent() != node) && !relative->isObsolete()) {
+ inObsoleteLink = true;
+ if (obsoleteLinks) {
+ relative->doc().location().warning(tr("Link to obsolete item '%1' in %2")
+ .arg(atom->string())
+ .arg(relative->plainFullName()));
+ }
+ }
}
- else
- node = 0;
}
- beginLink(myLink, node, relative);
+ beginLink(link, node, relative);
skipAhead = 1;
}
break;
@@ -1128,7 +1137,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
}
/*!
- Generate a reference page for a C++ class.
+ Generate a reference page for a C++ class or a C++ namespace.
*/
void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
{
@@ -1315,6 +1324,97 @@ void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
}
/*!
+ Generate the HTML page for a QML type. \qcn is the QML type.
+ \marker is the code markeup object.
+ */
+void HtmlGenerator::generateQmlTypePage(QmlClassNode* qcn, CodeMarker* marker)
+{
+ SubTitleSize subTitleSize = LargeSubTitle;
+ QList<Section>::const_iterator s;
+ QString fullTitle = qcn->fullTitle();
+ QString htmlTitle = fullTitle;
+
+ generateHeader(htmlTitle, qcn, marker);
+ QList<Section> sections = marker->qmlSections(qcn, CodeMarker::Summary);
+ generateTableOfContents(qcn, marker, &sections);
+ marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
+ generateTitle(fullTitle, Text() << qcn->subTitle(), subTitleSize, qcn, marker);
+ generateBrief(qcn, marker);
+ generateQmlRequisites(qcn, marker);
+
+ QString allQmlMembersLink = generateAllQmlMembersFile(qcn, marker);
+ if (!allQmlMembersLink.isEmpty()) {
+ out() << "<ul>\n";
+ out() << "<li><a href=\"" << allQmlMembersLink << "\">"
+ << "List of all members, including inherited members</a></li>\n";
+ out() << "</ul>\n";
+ }
+
+ s = sections.constBegin();
+ while (s != sections.constEnd()) {
+ out() << "<a name=\"" << registerRef((*s).name.toLower())
+ << "\"></a>" << divNavTop << '\n';
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+ generateQmlSummary(*s, qcn, marker);
+ ++s;
+ }
+
+ generateExtractionMark(qcn, DetailedDescriptionMark);
+ out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << '\n';
+ out() << "<h2>" << "Detailed Description" << "</h2>\n";
+ generateBody(qcn, marker);
+ ClassNode* cn = qcn->classNode();
+ if (cn)
+ generateQmlText(cn->doc().body(), cn, marker, qcn->name());
+ generateAlsoList(qcn, marker);
+ generateExtractionMark(qcn, EndMark);
+ //out() << "<hr />\n";
+
+ sections = marker->qmlSections(qcn,CodeMarker::Detailed);
+ s = sections.constBegin();
+ while (s != sections.constEnd()) {
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+ NodeList::ConstIterator m = (*s).members.constBegin();
+ while (m != (*s).members.constEnd()) {
+ generateDetailedQmlMember(*m, qcn, marker);
+ out() << "<br/>\n";
+ ++m;
+ }
+ ++s;
+ }
+ generateFooter(qcn);
+}
+
+/*!
+ Generate the HTML page for the QML basic type represented
+ by the QML basic type node \a qbtn.
+ */
+void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker)
+{
+ SubTitleSize subTitleSize = LargeSubTitle;
+ QList<Section>::const_iterator s;
+ QString htmlTitle = qbtn->fullTitle();
+ QString fullTitle = "QML Basic Type: " + htmlTitle;
+
+ marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
+
+ generateHeader(htmlTitle, qbtn, marker);
+ generateTitle(fullTitle,
+ Text() << qbtn->subTitle(),
+ subTitleSize,
+ qbtn,
+ marker);
+ generateExtractionMark(qbtn, DetailedDescriptionMark);
+ out() << "<div class=\"descr\"> <a name=\"" << registerRef("details") << "\"></a>\n"; // QTBUG-9504
+
+ generateBody(qbtn, marker);
+ out() << "</div>\n"; // QTBUG-9504
+ generateAlsoList(qbtn, marker);
+ generateExtractionMark(qbtn, EndMark);
+ generateFooter(qbtn);
+}
+
+/*!
We delayed generation of the disambiguation pages until now, after
all the other pages have been generated. We do this because we might
encounter a link command that tries to link to a target on a QML
@@ -1447,31 +1547,14 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
QList<Section>::const_iterator s;
QString fullTitle = dn->fullTitle();
- if (dn->subType() == Node::QmlBasicType) {
- fullTitle = "QML Basic Type: " + fullTitle;
-
- // Replace the marker with a QML code marker.
- marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
- }
- else if (dn->subType() == Node::QmlClass) {
- fullTitle = fullTitle + " QML Type";
- }
-
generateHeader(fullTitle, dn, marker);
/*
Generate the TOC for the new doc format.
Don't generate a TOC for the home page.
*/
- QmlClassNode* qml_cn = 0;
- if (dn->subType() == Node::QmlClass) {
- qml_cn = static_cast<QmlClassNode*>(dn);
- sections = marker->qmlSections(qml_cn,CodeMarker::Summary);
- generateTableOfContents(dn,marker,&sections);
-
- // Replace the marker with a QML code marker.
- marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
- }
- else if (dn->subType() != Node::Collision && dn->name() != QString("index.html") && dn->name() != QString("qtexamplesandtutorials.html"))
+ if ((dn->subType() != Node::Collision) &&
+ (dn->name() != QString("index.html")) &&
+ (dn->name() != QString("qtexamplesandtutorials.html")))
generateTableOfContents(dn,marker,0);
generateTitle(fullTitle,
@@ -1510,53 +1593,6 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
out() << "</ul>\n";
}
- else if (dn->subType() == Node::QmlClass) {
- ClassNode* cn = qml_cn->classNode();
- generateBrief(qml_cn, marker);
- generateQmlRequisites(qml_cn, marker);
-
- QString allQmlMembersLink = generateAllQmlMembersFile(qml_cn, marker);
- if (!allQmlMembersLink.isEmpty()) {
- out() << "<ul>\n";
- out() << "<li><a href=\"" << allQmlMembersLink << "\">"
- << "List of all members, including inherited members</a></li>\n";
- out() << "</ul>\n";
- }
-
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- out() << "<a name=\"" << registerRef((*s).name.toLower())
- << "\"></a>" << divNavTop << '\n';
- out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
- generateQmlSummary(*s,dn,marker);
- ++s;
- }
-
- generateExtractionMark(dn, DetailedDescriptionMark);
- out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << '\n';
- out() << "<h2>" << "Detailed Description" << "</h2>\n";
- generateBody(dn, marker);
- if (cn)
- generateQmlText(cn->doc().body(), cn, marker, dn->name());
- generateAlsoList(dn, marker);
- generateExtractionMark(dn, EndMark);
- //out() << "<hr />\n";
-
- sections = marker->qmlSections(qml_cn,CodeMarker::Detailed);
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
- NodeList::ConstIterator m = (*s).members.constBegin();
- while (m != (*s).members.constEnd()) {
- generateDetailedQmlMember(*m, dn, marker);
- out() << "<br/>\n";
- ++m;
- }
- ++s;
- }
- generateFooter(dn);
- return;
- }
sections = marker->sections(dn, CodeMarker::Summary, CodeMarker::Okay);
s = sections.constBegin();
@@ -1707,7 +1743,7 @@ void HtmlGenerator::generateNavigationBar(const QString &title,
<< Atom(Atom::AutoLink, landingpage)
<< Atom(Atom::ListItemRight);
- if (node->type() == Node::Class) {
+ if (node->isClass()) {
const ClassNode *cn = static_cast<const ClassNode *>(node);
QString name = node->moduleName();
@@ -1724,18 +1760,27 @@ void HtmlGenerator::generateNavigationBar(const QString &title,
<< Atom(Atom::String, cn->name())
<< Atom(Atom::ListItemRight);
}
- else if (node->type() == Node::Document) {
+ else if (node->isQmlType()) {
+ if (!qmltypespage.isEmpty())
+ navigationbar << Atom(Atom::ListItemLeft)
+ << Atom(Atom::Link, qmltypespage)
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, QLatin1String("QML Types"))
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << Atom(Atom::ListItemRight);
+ }
+ else if (node->isQmlBasicType()) {
+ if (!qmltypespage.isEmpty())
+ navigationbar << Atom(Atom::ListItemLeft)
+ << Atom(Atom::Link, qmltypespage)
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, QLatin1String("QML Types"))
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << Atom(Atom::ListItemRight);
+ }
+ else if (node->isDocNode()) {
const DocNode *dn = static_cast<const DocNode *>(node);
- if (node->subType() == Node::QmlClass || node->subType() == Node::QmlBasicType) {
- if (!qmltypespage.isEmpty())
- navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::Link, qmltypespage)
- << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, QLatin1String("QML Types"))
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
- << Atom(Atom::ListItemRight);
- }
- else if (dn && dn->isExampleFile()) {
+ if (dn && dn->isExampleFile()) {
navigationbar << Atom(Atom::ListItemLeft)
<< Atom(Atom::Link, dn->parent()->name())
<< Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
@@ -2732,7 +2777,7 @@ void HtmlGenerator::generateCompactList(ListType listType,
}
QStringList pieces;
- if (it.value()->subType() == Node::QmlClass)
+ if (it.value()->isQmlType())
pieces << it.value()->name();
else
pieces = it.value()->fullName(relative).split("::");
@@ -3214,8 +3259,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
par1 = QStringRef();
const Node* n = qdb_->resolveType(arg.toString(), relative);
html += QLatin1String("<span class=\"type\">");
- if (n && n->subType() == Node::QmlBasicType) {
- if (relative && relative->subType() == Node::QmlClass)
+ if (n && n->isQmlBasicType()) {
+ if (relative && relative->isQmlType())
addLink(linkForNode(n,relative), arg, &html);
else
html += arg.toString();
@@ -3576,7 +3621,7 @@ QString HtmlGenerator::linkForNode(const Node *node, const Node *relative)
QString fn = fileName(node);
if (node && relative && node->parent() != relative) {
- if (node->parent()->subType() == Node::QmlClass && relative->subType() == Node::QmlClass) {
+ if (node->parent()->isQmlType() && relative->isQmlType()) {
if (node->parent()->isAbstract()) {
/*
This is a bit of a hack. What we discover with
@@ -3719,6 +3764,7 @@ int HtmlGenerator::hOffset(const Node *node)
case Node::Namespace:
case Node::Class:
return 2;
+ case Node::QmlType:
case Node::Document:
return 1;
case Node::Enum:
@@ -3754,32 +3800,48 @@ const QPair<QString,QString> HtmlGenerator::anchorForNode(const Node *node)
return anchorPair;
}
+/*!
+ This function is called for links, i.e. for words that
+ are marked with the qdoc link command. For autolinks
+ that are not marked with the qdoc link command, qdoc
+ calls getAutoLink().
+
+ Return the link represented by the \a atom, and set \a node
+ to point to the target node for that link. \a relative points
+ to the node holding the qdoc comment where the link command
+ was found.
+ */
QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Node** node)
{
- QString link;
- *node = 0;
- inObsoleteLink = false;
-
if (atom->string().contains(QLatin1Char(':')) && (atom->string().startsWith("file:") ||
atom->string().startsWith("http:") ||
atom->string().startsWith("https:") ||
atom->string().startsWith("ftp:") ||
atom->string().startsWith("mailto:"))) {
- link = atom->string(); // It's some kind of protocol.
+ return atom->string(); // It's some kind of protocol.
+ }
+
+ QString ref;
+ QString link;
+ QString first;
+ QStringList path;
+
+ *node = 0;
+ if (atom->string().contains('#')) {
+ path = atom->string().split('#');
+ first = path.first().trimmed();
+ path.removeFirst();
}
+ else
+ first = atom->string();
+
+ if (first.isEmpty())
+ *node = relative; // search for a target on the current page.
else {
- QStringList path;
- if (atom->string().contains('#'))
- path = atom->string().split('#'); // The target is in the html file.
- else
- path.append(atom->string()); // It's a general case target.
-
- QString ref;
- QString first = path.first().trimmed();
- if (first.isEmpty())
- *node = relative;
- else if (first.endsWith(".html")) // The target is an html file.
- *node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document, Node::NoSubType);
+ if (first.endsWith(".html")) { // The target is an html file.
+ *node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document);
+ //Node* n = qdb_->findHtmlFileNode(atom);
+ }
else if (first.endsWith("()")) { // The target is a C++ function or QML method.
*node = qdb_->resolveFunctionTarget(first, relative);
}
@@ -3795,71 +3857,77 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
}
}
}
- if (*node) {
- if (!(*node)->url().isEmpty())
- return (*node)->url();
- else
- path.removeFirst();
- }
- else
- *node = relative;
-
- if (*node) {
- if ((*node)->status() == Node::Obsolete) {
- if (relative) {
- if (relative->parent() != *node) {
- if (relative->status() != Node::Obsolete) {
- bool porting = false;
- if (relative->type() == Node::Document) {
- const DocNode* dn = static_cast<const DocNode*>(relative);
- if (dn->title().startsWith("Porting"))
- porting = true;
- }
- QString name = relative->plainFullName();
- if (!porting && !name.startsWith("Q3")) {
- if (obsoleteLinks) {
- relative->doc().location().warning(tr("Link to obsolete item '%1' in %2")
- .arg(atom->string())
- .arg(name));
- }
- inObsoleteLink = true;
- }
- }
- }
- }
- else
- qDebug() << "Link to Obsolete entity" << (*node)->name() << "no relative";
- }
- }
+ }
+ if (!(*node))
+ return link; // empty
- /*
- This loop really only makes sense if *node is not 0.
- In that case, The node *node points to represents a
- qdoc page, so the link will ultimately point to some
- target on that page. This loop finds that target on
- the page that *node represents. ref is that target.
- */
- while (!path.isEmpty()) {
- ref = qdb_->findTarget(path.first(), *node);
- if (ref.isEmpty())
- break;
- path.removeFirst();
- }
+ if (!(*node)->url().isEmpty())
+ return (*node)->url();
- /*
- Given that *node is not null, we now cconstruct a link
- to the page that *node represents, and then if there is
- a target on that page, we connect the target to the link
- with '#'.
- */
- if (path.isEmpty()) {
- link = linkForNode(*node, relative);
- if (*node && (*node)->subType() == Node::Image)
- link = "images/used-in-examples/" + link;
- if (!ref.isEmpty())
- link += QLatin1Char('#') + ref;
+ if (!path.isEmpty()) {
+ ref = qdb_->findTarget(path.first(), *node);
+ if (ref.isEmpty())
+ return link; // empty
+ }
+
+ /*
+ Given that *node is not null, we now cconstruct a link
+ to the page that *node represents, and then if we found
+ a target on that page, we connect the target to the link
+ with '#'.
+ */
+ link = linkForNode(*node, relative);
+ if (*node && (*node)->subType() == Node::Image)
+ link = "images/used-in-examples/" + link;
+ if (!ref.isEmpty())
+ link += QLatin1Char('#') + ref;
+ return link;
+}
+
+/*!
+ This function is called for autolinks, i.e. for words that
+ are not marked with the qdoc link command that qdoc has
+ reason to believe should be links. For links marked with
+ the qdoc link command, qdoc calls getLink().
+
+ Return the link represented by the \a atom, and set \a node
+ to point to the target node for that link. \a relative points
+ to the node holding the qdoc comment where the link command
+ was found.
+ */
+QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const Node** node)
+{
+ QString ref;
+ QString link;
+ QString path = atom->string().trimmed();
+ *node = 0;
+
+ if (path.endsWith("()")) { // The target is a C++ function or QML method.
+ *node = qdb_->resolveFunctionTarget(path, relative);
+ }
+ else {
+ *node = qdb_->resolveTarget(path, relative);
+ if (!(*node)) {
+ *node = qdb_->findDocNodeByTitle(path);
+ }
+ if (!(*node)) {
+ *node = qdb_->findUnambiguousTarget(path, ref);
+ if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
+ QString final = (*node)->url() + "#" + ref;
+ return final;
+ }
}
}
+
+ if (!(*node))
+ return link; // empty
+
+ if (!(*node)->url().isEmpty())
+ return (*node)->url();
+
+ link = linkForNode(*node, relative);
+ if (!ref.isEmpty())
+ link += QLatin1Char('#') + ref;
return link;
}
@@ -3884,19 +3952,7 @@ void HtmlGenerator::generateStatus(const Node *node, CodeMarker *marker)
<< "We strongly advise against "
<< "using it in new code. See ";
- const DocNode *docNode = qdb_->findDocNodeByTitle("Porting To Qt 4");
- QString ref;
- if (docNode && node->type() == Node::Class) {
- QString oldName(node->name());
- oldName.remove(QLatin1Char('3'));
- ref = qdb_->findTarget(oldName, docNode);
- }
-
- if (!ref.isEmpty()) {
- text << Atom(Atom::Link, linkForNode(docNode, node) + QLatin1Char('#') + ref);
- }
- else
- text << Atom(Atom::Link, "Porting to Qt 4");
+ text << Atom(Atom::Link, "Porting to Qt 4");
text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
<< Atom(Atom::String, "Porting to Qt 4")
@@ -4525,6 +4581,10 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent)
break;
case Node::Class:
break;
+ case Node::QmlType:
+ break;
+ case Node::QmlBasicType:
+ break;
case Node::Group:
break;
case Node::Module:
@@ -4545,10 +4605,6 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent)
break;
case Node::ExternalPage:
break;
- case Node::QmlClass:
- break;
- case Node::QmlBasicType:
- break;
case Node::Collision:
break;
default:
diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h
index 58289d7030..395ccdb8bf 100644
--- a/src/tools/qdoc/htmlgenerator.h
+++ b/src/tools/qdoc/htmlgenerator.h
@@ -102,6 +102,8 @@ protected:
const Node *relative,
CodeMarker *marker);
virtual void generateClassLikeNode(InnerNode* inner, CodeMarker* marker);
+ virtual void generateQmlTypePage(QmlClassNode* qcn, CodeMarker* marker);
+ virtual void generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker);
virtual void generateDocNode(DocNode* dn, CodeMarker* marker);
virtual void generateCollectionNode(CollectionNode* cn, CodeMarker* marker);
virtual QString fileExtension() const;
@@ -215,6 +217,7 @@ private:
static int hOffset(const Node *node);
static bool isThreeColumnEnumValueTable(const Atom *atom);
QString getLink(const Atom *atom, const Node *relative, const Node** node);
+ QString getAutoLink(const Atom *atom, const Node *relative, const Node** node);
#ifdef GENERATE_MAC_REFS
void generateMacRef(const Node *node, CodeMarker *marker);
#endif
diff --git a/src/tools/qdoc/main.cpp b/src/tools/qdoc/main.cpp
index d1af5abf7b..3f3c11cc90 100644
--- a/src/tools/qdoc/main.cpp
+++ b/src/tools/qdoc/main.cpp
@@ -298,7 +298,8 @@ static void processQdocconfFile(const QString &fileName)
currentDir = QFileInfo(fileName).path();
Location::initialize(config);
config.load(fileName);
- //qDebug() << "\nSTART PROJECT:" << config.getString(CONFIG_PROJECT).toLower();
+ QString project = config.getString(CONFIG_PROJECT).toLower();
+ //qDebug() << "\nSTART PROJECT:" << project;
/*
Add the defines to the configuration variables.
*/
@@ -372,9 +373,11 @@ static void processQdocconfFile(const QString &fileName)
Location outputFormatsLocation = config.lastLocation();
//if (!Generator::runPrepareOnly())
+ Generator::debug(" loading index files");
loadIndexFiles(config);
qdb->newPrimaryTree(config.getString(CONFIG_PROJECT));
qdb->setSearchOrder();
+ Generator::debug(" done loading index files");
QSet<QString> excludedDirs;
QSet<QString> excludedFiles;
@@ -458,7 +461,6 @@ static void processQdocconfFile(const QString &fileName)
to the big tree.
*/
QSet<CodeParser *> usedParsers;
- //Config::debug_ = true;
Generator::debug("Parsing header files");
int parsed = 0;
@@ -528,6 +530,8 @@ static void processQdocconfFile(const QString &fileName)
//Generator::writeOutFileNames();
Generator::debug("Shutting down qdoc");
+ if (Generator::debugging())
+ Generator::stopDebugging(project);
QDocDatabase::qdocDB()->setVersion(QString());
Generator::terminate();
diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp
index ce97ffec01..fd610dedb6 100644
--- a/src/tools/qdoc/node.cpp
+++ b/src/tools/qdoc/node.cpp
@@ -51,6 +51,38 @@ QT_BEGIN_NAMESPACE
int Node::propertyGroupCount_ = 0;
QStringMap Node::operators_;
+QMap<QString,Node::Type> Node::goals_;
+
+/*!
+ Initialize the map of search goals. This is called once
+ by QDocDatabase::initializeDB(). The map key is a string
+ representing a value in the enum Node::Type. The map value
+ is the enum value.
+
+ There should be an entry in the map for each value in the
+ Type enum.
+ */
+void Node::initialize()
+{
+ goals_.insert("class", Node::Class);
+ goals_.insert("qmltype", Node::QmlType);
+ goals_.insert("page", Node::Document);
+ goals_.insert("function", Node::Function);
+ goals_.insert("property", Node::Property);
+ goals_.insert("variable", Node::Variable);
+ goals_.insert("group", Node::Group);
+ goals_.insert("module", Node::Module);
+ goals_.insert("qmlmodule", Node::QmlModule);
+ goals_.insert("qmppropertygroup", Node::QmlPropertyGroup);
+ goals_.insert("qmlproperty", Node::QmlProperty);
+ goals_.insert("qmlsignal", Node::QmlSignal);
+ goals_.insert("qmlsignalhandler", Node::QmlSignalHandler);
+ goals_.insert("qmlmethod", Node::QmlMethod);
+ goals_.insert("qmlbasictype", Node::QmlBasicType);
+ goals_.insert("enum", Node::Enum);
+ goals_.insert("typedef", Node::Typedef);
+ goals_.insert("namespace", Node::Namespace);
+}
/*!
Increment the number of property groups seen in the current
@@ -328,6 +360,10 @@ QString Node::nodeTypeString(unsigned t)
return "group";
case Module:
return "module";
+ case QmlType:
+ return "QML type";
+ case QmlBasicType:
+ return "QML basic type";
case QmlModule:
return "QML module";
case QmlProperty:
@@ -376,10 +412,6 @@ QString Node::nodeSubtypeString(unsigned t)
return "page";
case ExternalPage:
return "external page";
- case QmlClass:
- return "QML type";
- case QmlBasicType:
- return "QML basic type";
case DitaMap:
return "ditamap";
case Collision:
@@ -616,9 +648,9 @@ QmlClassNode* Node::qmlClassNode()
{
if (isQmlNode()) {
Node* n = this;
- while (n && n->subType() != Node::QmlClass)
+ while (n && !n->isQmlType())
n = n->parent();
- if (n && n->subType() == Node::QmlClass)
+ if (n && n->isQmlType())
return static_cast<QmlClassNode*>(n);
}
return 0;
@@ -655,6 +687,14 @@ bool Node::isInternal() const
}
/*!
+ Returns a pointer to the root of the Tree this node is in.
+ */
+const Node* Node::root() const
+{
+ return (parent() ? parent()->root() : this);
+}
+
+/*!
\class InnerNode
*/
@@ -1072,6 +1112,7 @@ InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name)
{
switch (type) {
case Class:
+ case QmlType:
case Namespace:
setPageType(ApiPage);
break;
@@ -1313,6 +1354,7 @@ LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name)
case QmlSignal:
case QmlSignalHandler:
case QmlMethod:
+ case QmlBasicType:
setPageType(ApiPage);
break;
default:
@@ -1356,7 +1398,7 @@ LeafNode::LeafNode(InnerNode* parent, Type type, const QString& name)
Constructs a namespace node.
*/
NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name)
- : InnerNode(Namespace, parent, name)
+ : InnerNode(Namespace, parent, name), tree_(0)
{
setPageType(ApiPage);
}
@@ -1562,10 +1604,6 @@ DocNode::DocNode(InnerNode* parent, const QString& name, SubType subtype, Node::
case DitaMap:
setPageType(ptype);
break;
- case QmlClass:
- case QmlBasicType:
- setPageType(ApiPage);
- break;
case Example:
setPageType(ExamplePage);
break;
@@ -2051,12 +2089,11 @@ bool QmlClassNode::qmlOnly = false;
QMultiMap<QString,Node*> QmlClassNode::inheritedBy;
/*!
- Constructs a Qml class node (i.e. a Document node with the
- subtype QmlClass. The new node has the given \a parent
- and \a name.
+ Constructs a Qml class node. The new node has the given
+ \a parent and \a name.
*/
QmlClassNode::QmlClassNode(InnerNode *parent, const QString& name)
- : DocNode(parent, name, QmlClass, Node::ApiPage),
+ : InnerNode(QmlType, parent, name),
abstract_(false),
cnodeRequired_(false),
wrapper_(false),
@@ -2070,6 +2107,7 @@ QmlClassNode::QmlClassNode(InnerNode *parent, const QString& name)
i = 4;
}
setTitle(name.mid(i));
+ setPageType(Node::ApiPage);
}
/*!
@@ -2187,13 +2225,12 @@ QString QmlClassNode::qmlModuleIdentifier() const
}
/*!
- Constructs a Qml basic type node (i.e. a Document node with
- the subtype QmlBasicType. The new node has the given
+ Constructs a Qml basic type node. The new node has the given
\a parent and \a name.
*/
QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent,
const QString& name)
- : DocNode(parent, name, QmlBasicType, Node::ApiPage)
+ : InnerNode(QmlBasicType, parent, name)
{
setTitle(name);
}
@@ -2293,7 +2330,7 @@ PropertyNode* QmlPropertyNode::findCorrespondingCppProperty()
{
PropertyNode* pn;
Node* n = parent();
- while (n && n->subType() != Node::QmlClass)
+ while (n && !n->isQmlType())
n = n->parent();
if (n) {
QmlClassNode* qcn = static_cast<QmlClassNode*>(n);
@@ -2489,12 +2526,14 @@ QString Node::fullDocumentName() const
if (!n->name().isEmpty() && !n->isQmlPropertyGroup())
pieces.insert(0, n->name());
- if (n->type() == Node::Document) {
- if ((n->subType() == Node::QmlClass) && !n->qmlModuleName().isEmpty())
- pieces.insert(0, n->qmlModuleName());
+ if (n->isQmlType() && !n->qmlModuleName().isEmpty()) {
+ pieces.insert(0, n->qmlModuleName());
break;
}
+ if (n->isDocNode())
+ break;
+
// Examine the parent node if one exists.
if (n->parent())
n = n->parent();
@@ -2504,7 +2543,7 @@ QString Node::fullDocumentName() const
// Create a name based on the type of the ancestor node.
QString concatenator = "::";
- if ((n->type() == Node::Document) && (n->subType() != Node::QmlClass))
+ if (n->isDocNode())
concatenator = QLatin1Char('#');
return pieces.join(concatenator);
@@ -2679,16 +2718,15 @@ QString Node::idForNode() const
}
}
else if (parent_) {
- if (parent_->type() == Class)
+ if (parent_->isClass())
str = "class-member-" + func->name();
- else if (parent_->type() == Namespace)
+ else if (parent_->isNamespace())
str = "namespace-member-" + func->name();
+ else if (parent_->isQmlType())
+ str = "qml-method-" + parent_->name().toLower() + "-" + func->name();
else if (parent_->type() == Document) {
- if (parent_->subType() == QmlClass)
- str = "qml-method-" + parent_->name().toLower() + "-" + func->name();
- else
- qDebug() << "qdoc internal error: Node subtype not handled:"
- << parent_->subType() << func->name();
+ qDebug() << "qdoc internal error: Node subtype not handled:"
+ << parent_->subType() << func->name();
}
else
qDebug() << "qdoc internal error: Node type not handled:"
@@ -2699,12 +2737,15 @@ QString Node::idForNode() const
str += QLatin1Char('-') + QString::number(func->overloadNumber());
}
break;
+ case Node::QmlType:
+ str = "qml-class-" + name();
+ break;
+ case Node::QmlBasicType:
+ str = "qml-basic-type-" + name();
+ break;
case Node::Document:
{
switch (subType()) {
- case Node::QmlClass:
- str = "qml-class-" + name();
- break;
case Node::Page:
case Node::HeaderFile:
str = title();
@@ -2723,9 +2764,6 @@ QString Node::idForNode() const
str = name();
str.replace(QLatin1Char('/'), QLatin1Char('-'));
break;
- case Node::QmlBasicType:
- str = "qml-basic-type-" + name();
- break;
case Node::Collision:
str = title();
str.replace(": ","-");
diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h
index bbbc29d51a..ebdaad9010 100644
--- a/src/tools/qdoc/node.h
+++ b/src/tools/qdoc/node.h
@@ -49,12 +49,11 @@
#include "codechunk.h"
#include "doc.h"
-#include "location.h"
-#include "text.h"
QT_BEGIN_NAMESPACE
class Node;
+class Tree;
class EnumNode;
class ClassNode;
class InnerNode;
@@ -83,6 +82,7 @@ class Node
public:
enum Type {
+ NoType,
Namespace,
Class,
Document,
@@ -93,12 +93,14 @@ public:
Variable,
Group,
Module,
+ QmlType,
QmlModule,
QmlPropertyGroup,
QmlProperty,
QmlSignal,
QmlSignalHandler,
QmlMethod,
+ QmlBasicType,
LastType
};
@@ -110,8 +112,6 @@ public:
Image,
Page,
ExternalPage,
- QmlClass,
- QmlBasicType,
DitaMap,
Collision,
LastSubtype
@@ -248,11 +248,13 @@ public:
virtual bool wasSeen() const { return false; }
virtual void appendGroupName(const QString& ) { }
virtual QString element() const { return QString(); }
+ virtual Tree* tree() const { return 0; }
bool isIndexNode() const { return indexNodeFlag_; }
Type type() const { return nodeType_; }
virtual SubType subType() const { return NoSubType; }
bool match(const NodeTypeList& types) const;
InnerNode* parent() const { return parent_; }
+ const Node* root() const;
InnerNode* relates() const { return relatesTo_; }
const QString& name() const { return name_; }
QString moduleName() const;
@@ -318,6 +320,8 @@ public:
static QString nodeSubtypeString(unsigned t);
static int incPropertyGroupCount();
static void clearPropertyGroupCount();
+ static void initialize();
+ static Type goal(const QString& t) { return goals_.value(t); }
protected:
Node(Type type, InnerNode* parent, const QString& name);
@@ -347,6 +351,7 @@ private:
QString outSubDir_;
static QStringMap operators_;
static int propertyGroupCount_;
+ static QMap<QString,Node::Type> goals_;
};
class InnerNode : public Node
@@ -435,6 +440,11 @@ public:
NamespaceNode(InnerNode* parent, const QString& name);
virtual ~NamespaceNode() { }
virtual bool isNamespace() const { return true; }
+ virtual Tree* tree() const { return tree_; }
+ void setTree(Tree* t) { tree_ = t; }
+
+ private:
+ Tree* tree_;
};
struct RelatedClass
@@ -583,7 +593,7 @@ struct ImportRec {
typedef QList<ImportRec> ImportList;
-class QmlClassNode : public DocNode
+class QmlClassNode : public InnerNode
{
public:
QmlClassNode(InnerNode* parent, const QString& name);
@@ -635,7 +645,7 @@ private:
ImportList importList_;
};
-class QmlBasicTypeNode : public DocNode
+class QmlBasicTypeNode : public InnerNode
{
public:
QmlBasicTypeNode(InnerNode* parent,
@@ -719,17 +729,13 @@ public:
EnumItem() { }
EnumItem(const QString& name, const QString& value)
: nam(name), val(value) { }
- EnumItem(const QString& name, const QString& value, const Text &txt)
- : nam(name), val(value), txt(txt) { }
const QString& name() const { return nam; }
const QString& value() const { return val; }
- const Text &text() const { return txt; }
private:
QString nam;
QString val;
- Text txt;
};
class EnumNode : public LeafNode
diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp
index ffd2dd9b3b..8bf83ca796 100644
--- a/src/tools/qdoc/qdocdatabase.cpp
+++ b/src/tools/qdoc/qdocdatabase.cpp
@@ -286,6 +286,16 @@ void QDocForest::setSearchOrder()
}
forest_.clear();
}
+
+ /*
+ Rebuild the forest after constructing the search order.
+ It was destroyed during construction of the search order,
+ but it is needed for module-specific searches.
+ */
+ for (int i=0; i<searchOrder_.size(); ++i) {
+ forest_.insert(moduleNames_.at(i).toLower(), searchOrder_.at(i));
+ }
+
#if 0
qDebug() << " SEARCH ORDER:";
for (int i=0; i<moduleNames_.size(); ++i)
@@ -498,9 +508,12 @@ void QDocDatabase::destroyQdocDB()
include \c array and \c data, which are just generic names
used as place holders in function signatures that appear in
the documentation.
+
+ Also calls Node::initialize() to initialize the search goal map.
*/
void QDocDatabase::initializeDB()
{
+ Node::initialize();
typeNodeMap_.insert( "accepted", 0);
typeNodeMap_.insert( "actionPerformed", 0);
typeNodeMap_.insert( "activated", 0);
@@ -776,14 +789,14 @@ QmlClassNode* QDocDatabase::findQmlType(const QString& qmid, const QString& name
}
QStringList path(name);
- Node* n = forest_.findNodeByNameAndType(path, Node::Document, Node::QmlClass, true);
+ Node* n = forest_.findNodeByNameAndType(path, Node::QmlType);
if (n) {
- if (n->subType() == Node::QmlClass)
+ if (n->isQmlType())
return static_cast<QmlClassNode*>(n);
- else if (n->subType() == Node::Collision) {
+ else if (n->isCollisionNode()) {
NameCollisionNode* ncn;
ncn = static_cast<NameCollisionNode*>(n);
- return static_cast<QmlClassNode*>(ncn->findAny(Node::Document,Node::QmlClass));
+ return static_cast<QmlClassNode*>(ncn->findAny(Node::QmlType, Node::NoSubType));
}
}
return 0;
@@ -992,9 +1005,7 @@ void QDocDatabase::findAllClasses(InnerNode* node)
serviceClasses_.insert(serviceName, *c);
}
}
- else if ((*c)->type() == Node::Document &&
- (*c)->subType() == Node::QmlClass &&
- !(*c)->doc().isEmpty()) {
+ else if ((*c)->isQmlType() && !(*c)->doc().isEmpty()) {
QString qmlTypeName = (*c)->name();
if (qmlTypeName.startsWith(QLatin1String("QML:")))
qmlClasses_.insert(qmlTypeName.mid(4),*c);
@@ -1103,7 +1114,7 @@ void QDocDatabase::findAllObsoleteThings(InnerNode* node)
name = (*c)->parent()->name() + "::" + name;
obsoleteClasses_.insert(name, *c);
}
- else if ((*c)->type() == Node::Document && (*c)->subType() == Node::QmlClass) {
+ else if ((*c)->isQmlType()) {
if (name.startsWith(QLatin1String("QML:")))
name = name.mid(4);
name = (*c)->qmlModuleName() + "::" + name;
@@ -1139,7 +1150,7 @@ void QDocDatabase::findAllObsoleteThings(InnerNode* node)
++p;
}
}
- else if ((*c)->type() == Node::Document && (*c)->subType() == Node::QmlClass) {
+ else if ((*c)->isQmlType()) {
InnerNode* n = static_cast<InnerNode*>(*c);
bool inserted = false;
NodeList::const_iterator p = n->childNodes().constBegin();
@@ -1154,7 +1165,7 @@ void QDocDatabase::findAllObsoleteThings(InnerNode* node)
Node* parent = (*c)->parent();
if (parent->type() == Node::QmlPropertyGroup && parent->parent())
parent = parent->parent();
- if (parent && parent->subType() == Node::QmlClass && !parent->name().isEmpty())
+ if (parent && parent->isQmlType() && !parent->name().isEmpty())
name = parent->name() + "::" + name;
}
qmlTypesWithObsoleteMembers_.insert(name,*c);
@@ -1223,7 +1234,7 @@ void QDocDatabase::findAllSince(InnerNode* node)
nsmap.value().insert(className,(*child));
ncmap.value().insert(className,(*child));
}
- else if ((*child)->subType() == Node::QmlClass) {
+ else if ((*child)->isQmlType()) {
// Insert QML elements into the since and element maps.
QString className = (*child)->name();
if ((*child)->parent() && !(*child)->parent()->name().isEmpty()) {
@@ -1344,7 +1355,7 @@ const Node* QDocDatabase::findNodeForTarget(const QString& target, const Node* r
if (target.isEmpty())
node = relative;
else if (target.endsWith(".html")) {
- node = findNodeByNameAndType(QStringList(target), Node::Document, Node::NoSubType);
+ node = findNodeByNameAndType(QStringList(target), Node::Document);
}
else {
node = resolveTarget(target, relative);
@@ -1366,7 +1377,7 @@ void QDocDatabase::resolveQmlInheritance(InnerNode* root)
NodeMap previousSearches;
// Do we need recursion?
foreach (Node* child, root->childNodes()) {
- if (child->type() == Node::Document && child->subType() == Node::QmlClass) {
+ if (child->isQmlType()) {
QmlClassNode* qcn = static_cast<QmlClassNode*>(child);
if (qcn->qmlBaseNodeNotSet() && !qcn->qmlBaseName().isEmpty()) {
QmlClassNode* bqcn = static_cast<QmlClassNode*>(previousSearches.value(qcn->qmlBaseName()));
@@ -1463,18 +1474,16 @@ FunctionNode* QDocDatabase::findNodeInOpenNamespace(const QStringList& parentPat
}
/*!
- Find a node of the specified \a type and \a subtype that is
- reached with the specified \a path qualified with the name
- of one of the open namespaces (might not be any open ones).
- If the node is found in an open namespace, prefix \a path
- with the name of the open namespace and "::" and return a
- pointer to the node. Othewrwise return 0.
+ Find a node of the specified \a type that is reached with
+ the specified \a path qualified with the name of one of the
+ open namespaces (might not be any open ones). If the node
+ is found in an open namespace, prefix \a path with the name
+ of the open namespace and "::" and return a pointer to the
+ node. Othewrwise return 0.
This function only searches in the current primary tree.
*/
-Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path,
- Node::Type type,
- Node::SubType subtype)
+Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path, Node::Type type)
{
if (path.isEmpty())
return 0;
@@ -1486,7 +1495,7 @@ Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path,
p = t.split("::") + path;
else
p = path;
- n = primaryTree()->findNodeByNameAndType(p, type, subtype);
+ n = primaryTree()->findNodeByNameAndType(p, type);
if (n) {
path = p;
break;
diff --git a/src/tools/qdoc/qdocdatabase.h b/src/tools/qdoc/qdocdatabase.h
index 7bbff89fa3..8741443a7c 100644
--- a/src/tools/qdoc/qdocdatabase.h
+++ b/src/tools/qdoc/qdocdatabase.h
@@ -46,6 +46,7 @@
#include <qmap.h>
#include "tree.h"
#include "config.h"
+#include "text.h"
#include <qdebug.h>
QT_BEGIN_NAMESPACE
@@ -79,6 +80,7 @@ class QDocForest
Tree* firstTree();
Tree* nextTree();
Tree* primaryTree() { return primaryTree_; }
+ Tree* findTree(const QString& t) { return forest_.value(t); }
NamespaceNode* primaryTreeRoot() { return (primaryTree_ ? primaryTree_->root() : 0); }
bool isEmpty() { return searchOrder().isEmpty(); }
bool done() { return (currentIndex_ >= searchOrder().size()); }
@@ -93,20 +95,15 @@ class QDocForest
return n;
relative = 0;
}
- //qDebug() << "FAILED SEARCH 1" << path;
return 0;
}
- Node* findNodeByNameAndType(const QStringList& path,
- Node::Type type,
- Node::SubType subtype,
- bool acceptCollision = false) {
+ Node* findNodeByNameAndType(const QStringList& path, Node::Type type) {
foreach (Tree* t, searchOrder()) {
- Node* n = t->findNodeByNameAndType(path, type, subtype, acceptCollision);
+ Node* n = t->findNodeByNameAndType(path, type);
if (n)
return n;
}
- //qDebug() << "FAILED SEARCH 2" << path << type << subtype;
return 0;
}
@@ -116,7 +113,6 @@ class QDocForest
if (n)
return n;
}
- //qDebug() << "FAILED SEARCH 3" << path;
return 0;
}
@@ -126,7 +122,6 @@ class QDocForest
if (n)
return n;
}
- //qDebug() << "FAILED SEARCH 4" << path;
return 0;
}
@@ -149,21 +144,9 @@ class QDocForest
return n;
relative = 0;
}
- //qDebug() << "FAILED SEARCH 5" << path;
return 0;
}
- QString findTarget(const QString& target, const Node* node)
- {
- foreach (Tree* t, searchOrder()) {
- QString ref = t->findTarget(target, node);
- if (!ref.isEmpty())
- return ref;
- }
- //qDebug() << "FAILED SEARCH 7" << target;
- return QString();
- }
-
const Node* findUnambiguousTarget(const QString& target, QString& ref)
{
foreach (Tree* t, searchOrder()) {
@@ -171,7 +154,6 @@ class QDocForest
if (n)
return n;
}
- //qDebug() << "FAILED SEARCH 8" << target;
return 0;
}
@@ -182,7 +164,6 @@ class QDocForest
if (n)
return n;
}
- //qDebug() << "FAILED SEARCH 9" << title;
return 0;
}
@@ -229,6 +210,7 @@ class QDocDatabase
static void destroyQdocDB();
~QDocDatabase();
+ Tree* findTree(const QString& t) { return forest_.findTree(t); }
const CNMap& groups() { return primaryTree()->groups(); }
const CNMap& modules() { return primaryTree()->modules(); }
const CNMap& qmlModules() { return primaryTree()->qmlModules(); }
@@ -307,7 +289,7 @@ class QDocDatabase
return primaryTree()->findFunctionNode(parentPath, clone);
}
FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone);
- Node* findNodeInOpenNamespace(QStringList& path, Node::Type type, Node::SubType subtype);
+ Node* findNodeInOpenNamespace(QStringList& path, Node::Type type);
NameCollisionNode* findCollisionNode(const QString& name) {
return primaryTree()->findCollisionNode(name);
}
@@ -321,9 +303,6 @@ class QDocDatabase
********************************************************************/
ClassNode* findClassNode(const QStringList& path) { return forest_.findClassNode(path); }
InnerNode* findRelatesNode(const QStringList& path) { return forest_.findRelatesNode(path); }
- QString findTarget(const QString& target, const Node* node) {
- return forest_.findTarget(target, node);
- }
const Node* resolveTarget(const QString& target, const Node* relative) {
return forest_.resolveTarget(target, relative);
}
@@ -338,11 +317,14 @@ class QDocDatabase
const Node* findUnambiguousTarget(const QString& target, QString& ref) {
return forest_.findUnambiguousTarget(target, ref);
}
- Node* findNodeByNameAndType(const QStringList& path, Node::Type type, Node::SubType subtype){
- return forest_.findNodeByNameAndType(path, type, subtype, false);
+ Node* findNodeByNameAndType(const QStringList& path, Node::Type type) {
+ return forest_.findNodeByNameAndType(path, type);
}
/*******************************************************************/
+ QString findTarget(const QString& target, const Node* node) {
+ return node->root()->tree()->findTarget(target, node);
+ }
void addPropertyFunction(PropertyNode* property,
const QString& funcName,
PropertyNode::FunctionRole funcRole) {
diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp
index be8184b596..25f6b8eec9 100644
--- a/src/tools/qdoc/qdocindexfiles.cpp
+++ b/src/tools/qdoc/qdocindexfiles.cpp
@@ -206,8 +206,7 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
abstract = true;
node->setAbstract(abstract);
}
- else if ((element.nodeName() == "qmlclass") ||
- ((element.nodeName() == "page") && (element.attribute("subtype") == "qmlclass"))) {
+ else if (element.nodeName() == "qmlclass") {
QmlClassNode* qcn = new QmlClassNode(parent, name);
qcn->setTitle(element.attribute("title"));
QString qmlModuleName = element.attribute("qml-module-name");
@@ -260,11 +259,11 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
if (element.attribute("writable") == "false")
readonly = true;
QmlPropertyNode* qpn = 0;
- if (parent->type() == Node::Document) {
+ if (parent->isQmlType()) {
QmlClassNode* qcn = static_cast<QmlClassNode*>(parent);
qpn = new QmlPropertyNode(qcn, name, type, attached);
}
- else if (parent->type() == Node::QmlPropertyGroup) {
+ else if (parent->isQmlPropertyGroup()) {
QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(parent);
qpn = new QmlPropertyNode(qpgn, name, type, attached);
}
@@ -332,14 +331,6 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
subtype = Node::ExternalPage;
ptype = Node::ArticlePage;
}
- else if (attr == "qmlclass") {
- subtype = Node::QmlClass;
- ptype = Node::ApiPage;
- }
- else if (attr == "qmlbasictype") {
- subtype = Node::QmlBasicType;
- ptype = Node::ApiPage;
- }
else
return;
@@ -614,7 +605,7 @@ void QDocIndexFiles::resolveIndex()
foreach (pair, basesList_) {
foreach (const QString& base, pair.second.split(QLatin1Char(','))) {
QStringList basePath = base.split(QString("::"));
- Node* n = qdb_->findNodeByNameAndType(basePath, Node::Class, Node::NoSubType);
+ Node* n = qdb_->findClassNode(basePath);
if (n)
pair.first->addResolvedBaseClass(Node::Public, static_cast<ClassNode*>(n));
else
@@ -661,17 +652,20 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
case Node::Class:
nodeName = "class";
break;
- case Node::Document:
- nodeName = "page";
- if (node->subType() == Node::QmlClass) {
+ case Node::QmlType:
+ {
nodeName = "qmlclass";
QmlModuleNode* qmn = node->qmlModule();
if (qmn)
qmlModuleName = qmn->qmlModuleName();
qmlFullBaseName = node->qmlFullBaseName();
}
- else if (node->subType() == Node::QmlBasicType)
- nodeName = "qmlbasictype";
+ break;
+ case Node::QmlBasicType:
+ nodeName = "qmlbasictype";
+ break;
+ case Node::Document:
+ nodeName = "page";
break;
case Node::Group:
nodeName = "group";
@@ -755,10 +749,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
QXmlStreamAttributes attributes;
- if ((node->type() != Node::Document) &&
- (node->type() != Node::Group) &&
- (node->type() != Node::Module) &&
- (node->type() != Node::QmlModule)) {
+ if (!node->isDocNode() && !node->isGroup() && !node->isModule() && !node->isQmlModule()) {
QString threadSafety;
switch (node->threadSafeness()) {
case Node::NonReentrant:
@@ -843,10 +834,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeAttribute("href", href);
writer.writeAttribute("status", status);
- if ((node->type() != Node::Document) &&
- (node->type() != Node::Group) &&
- (node->type() != Node::Module) &&
- (node->type() != Node::QmlModule)) {
+ if (!node->isDocNode() && !node->isGroup() && !node->isModule() && !node->isQmlModule()) {
writer.writeAttribute("access", access);
if (node->isAbstract())
writer.writeAttribute("abstract", "true");
@@ -896,6 +884,18 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeAttribute("brief", brief);
}
break;
+ case Node::QmlType:
+ {
+ const QmlClassNode* qcn = static_cast<const QmlClassNode*>(node);
+ writer.writeAttribute("title", qcn->title());
+ writer.writeAttribute("fulltitle", qcn->fullTitle());
+ writer.writeAttribute("subtitle", qcn->subTitle());
+ if (!qcn->groupNames().isEmpty())
+ writer.writeAttribute("groups", qcn->groupNames().join(","));
+ if (!brief.isEmpty())
+ writer.writeAttribute("brief", brief);
+ }
+ break;
case Node::Document:
{
/*
@@ -923,12 +923,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
case Node::ExternalPage:
writer.writeAttribute("subtype", "externalpage");
break;
- case Node::QmlClass:
- //writer.writeAttribute("subtype", "qmlclass");
- break;
- case Node::QmlBasicType:
- //writer.writeAttribute("subtype", "qmlbasictype");
- break;
default:
break;
}
@@ -1289,7 +1283,7 @@ bool compareNodes(const Node* n1, const Node* n2)
return false;
}
- if (n1->type() == Node::Document && n2->type() == Node::Document) {
+ if (n1->isDocNode() && n2->isDocNode()) {
const DocNode* f1 = static_cast<const DocNode*>(n1);
const DocNode* f2 = static_cast<const DocNode*>(n2);
if (f1->fullTitle() < f2->fullTitle())
diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp
index d16fdfa5d4..2ef751e9bc 100644
--- a/src/tools/qdoc/qmlvisitor.cpp
+++ b/src/tools/qdoc/qmlvisitor.cpp
@@ -365,7 +365,7 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
QString command = *i;
ArgList args = doc.metaCommandArgs(command);
if (command == COMMAND_QMLABSTRACT) {
- if ((node->type() == Node::Document) && (node->subType() == Node::QmlClass)) {
+ if (node->isQmlType()) {
node->setAbstract(true);
}
}
@@ -378,7 +378,7 @@ void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
else if (command == COMMAND_QMLINHERITS) {
if (node->name() == args[0].first)
doc.location().warning(tr("%1 tries to inherit itself").arg(args[0].first));
- else if (node->subType() == Node::QmlClass) {
+ else if (node->isQmlType()) {
QmlClassNode *qmlClass = static_cast<QmlClassNode*>(node);
qmlClass->setQmlBaseName(args[0].first);
QmlClassNode::addInheritedBy(args[0].first,node);
@@ -541,7 +541,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
switch (member->type) {
case QQmlJS::AST::UiPublicMember::Signal:
{
- if (current->type() == Node::Document) {
+ if (current->isQmlType()) {
QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current);
if (qmlClass) {
@@ -564,7 +564,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
{
QString type = member->memberType.toString();
QString name = member->name.toString();
- if (current->type() == Node::Document) {
+ if (current->isQmlType()) {
QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current);
if (qmlClass) {
QString name = member->name.toString();
@@ -608,7 +608,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
if (nestingLevel > 1) {
return true;
}
- if (current->type() == Node::Document) {
+ if (current->isQmlType()) {
QmlClassNode* qmlClass = static_cast<QmlClassNode*>(current);
if (qmlClass) {
QString name = fd->name.toString();
@@ -661,7 +661,7 @@ bool QmlDocVisitor::visit(QQmlJS::AST::UiScriptBinding* )
if (nestingLevel > 1) {
return true;
}
- if (current->type() == Node::Document) {
+ if (current->isQmlType()) {
QString handler = sb->qualifiedId->name.toString();
if (handler.length() > 2 && handler.startsWith("on") && handler.at(2).isUpper()) {
QmlClassNode* qmlClass = static_cast<QmlClassNode*>(current);
diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp
index 6ed639307e..147abe21af 100644
--- a/src/tools/qdoc/tree.cpp
+++ b/src/tools/qdoc/tree.cpp
@@ -77,6 +77,7 @@ Tree::Tree(const QString& module, QDocDatabase* qdb)
: module_(module), qdb_(qdb), root_(0, QString())
{
root_.setModuleName(module_);
+ root_.setTree(this);
}
/*!
@@ -103,7 +104,7 @@ ClassNode* Tree::findClassNode(const QStringList& path, Node* start) const
{
if (!start)
start = const_cast<NamespaceNode*>(root());
- return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, Node::Class, Node::NoSubType));
+ return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, Node::Class));
}
/*!
@@ -114,7 +115,7 @@ ClassNode* Tree::findClassNode(const QStringList& path, Node* start) const
NamespaceNode* Tree::findNamespaceNode(const QStringList& path) const
{
Node* start = const_cast<NamespaceNode*>(root());
- return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, Node::Namespace, Node::NoSubType));
+ return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, Node::Namespace));
}
/*!
@@ -161,7 +162,7 @@ QmlClassNode* Tree::findQmlTypeNode(const QStringList& path)
if (qcn)
return qcn;
}
- return static_cast<QmlClassNode*>(findNodeRecursive(path, 0, root(), Node::Document, Node::QmlClass));
+ return static_cast<QmlClassNode*>(findNodeRecursive(path, 0, root(), Node::QmlType));
}
/*!
@@ -224,14 +225,14 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
if (!qcn) {
QStringList p(path[1]);
- Node* n = findNodeByNameAndType(p, Node::Document, Node::QmlClass, true);
+ Node* n = findNodeByNameAndType(p, Node::QmlType);
if (n) {
- if (n->subType() == Node::QmlClass)
+ if (n->isQmlType())
qcn = static_cast<QmlClassNode*>(n);
else if (n->subType() == Node::Collision) {
NameCollisionNode* ncn;
ncn = static_cast<NameCollisionNode*>(n);
- qcn = static_cast<QmlClassNode*>(ncn->findAny(Node::Document, Node::QmlClass));
+ qcn = static_cast<QmlClassNode*>(ncn->findAny(Node::QmlType, Node::NoSubType));
}
}
}
@@ -489,7 +490,7 @@ void Tree::resolveCppToQmlLinks()
{
foreach (Node* child, root_.childNodes()) {
- if (child->type() == Node::Document && child->subType() == Node::QmlClass) {
+ if (child->isQmlType()) {
QmlClassNode* qcn = static_cast<QmlClassNode*>(child);
ClassNode* cn = const_cast<ClassNode*>(qcn->classNode());
if (cn)
@@ -558,15 +559,23 @@ NodeList Tree::allBaseClasses(const ClassNode* classNode) const
search at the tree root. \a subtype is not used unless
\a type is \c{Document}.
*/
-Node* Tree::findNodeByNameAndType(const QStringList& path,
- Node::Type type,
- Node::SubType subtype,
- bool acceptCollision) const
+Node* Tree::findNodeByNameAndType(const QStringList& path, Node::Type type) const
{
- Node* result = findNodeRecursive(path, 0, root(), type, subtype, acceptCollision);
- return result;
+ return findNodeRecursive(path, 0, root(), type);
}
-
+#if 0
+/*!
+ Find the node with the specified \a path name that is of
+ the specified \a type and \a subtype. Begin the search at
+ the \a start node. If the \a start node is 0, begin the
+ search at the tree root. \a subtype is not used unless
+ \a type is \c{Document}.
+ */
+Node* Tree::findHtmlFileNode(const QStringList& path) const
+{
+ return findNodeRecursive(path, 0, root());
+}
+#endif
/* internal members */
/*!
@@ -588,9 +597,7 @@ Node* Tree::findNodeByNameAndType(const QStringList& path,
Node* Tree::findNodeRecursive(const QStringList& path,
int pathIndex,
const Node* start,
- Node::Type type,
- Node::SubType subtype,
- bool acceptCollision) const
+ Node::Type type) const
{
if (!start || path.isEmpty())
return 0; // no place to start, or nothing to search for.
@@ -600,8 +607,6 @@ Node* Tree::findNodeRecursive(const QStringList& path,
return node; // found a match.
return 0; // premature leaf
}
- if (pathIndex >= path.size())
- return 0; // end of search path.
InnerNode* current = static_cast<InnerNode*>(node);
const NodeList& children = current->childNodes();
@@ -612,39 +617,19 @@ Node* Tree::findNodeRecursive(const QStringList& path,
continue;
if (n->isQmlPropertyGroup()) {
if (type == Node::QmlProperty) {
- n = findNodeRecursive(path, pathIndex, n, type, subtype);
+ n = findNodeRecursive(path, pathIndex, n, type);
if (n)
return n;
}
}
else if (n->name() == name) {
if (pathIndex+1 >= path.size()) {
- if (n->type() == type) {
- if (type == Node::Document) {
- if (n->subType() == subtype)
- return n;
- else if (n->subType() == Node::Collision) {
- if (acceptCollision)
- return n;
- return n->disambiguate(type, subtype);
- }
- else if (subtype == Node::NoSubType)
- return n;
- continue;
- }
+ if (n->type() == type)
return n;
- }
- else if (n->isCollisionNode()) {
- if (acceptCollision)
- return n;
- return findNodeRecursive(path, pathIndex, n, type, subtype);
- }
- else {
- continue;
- }
+ continue;
}
else { // Search the children of n for the next name in the path.
- n = findNodeRecursive(path, pathIndex+1, n, type, subtype);
+ n = findNodeRecursive(path, pathIndex+1, n, type);
if (n)
return n;
}
@@ -672,9 +657,6 @@ Node* Tree::findNodeRecursive(const QStringList& path,
Node* start,
const NodeTypeList& types) const
{
- /*
- Safety checks
- */
if (!start || path.isEmpty())
return 0;
if (start->isLeaf())
@@ -1233,7 +1215,7 @@ QmlModuleNode* Tree::addToQmlModule(const QString& name, Node* node)
QmlModuleNode* qmn = findQmlModule(blankSplit[0]);
qmn->addMember(node);
node->setQmlModule(qmn);
- if (node->subType() == Node::QmlClass) {
+ if (node->isQmlType()) {
QmlClassNode* n = static_cast<QmlClassNode*>(node);
for (int i=0; i<qmid.size(); ++i) {
QString key = qmid[i] + "::" + node->name();
diff --git a/src/tools/qdoc/tree.h b/src/tools/qdoc/tree.h
index 916682daad..7160e321db 100644
--- a/src/tools/qdoc/tree.h
+++ b/src/tools/qdoc/tree.h
@@ -91,9 +91,7 @@ class Tree
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
const Node* start,
- Node::Type type,
- Node::SubType subtype,
- bool acceptCollision = false) const;
+ Node::Type type) const;
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
Node* start,
@@ -110,12 +108,7 @@ class Tree
QmlClassNode* findQmlTypeNode(const QStringList& path);
- Node* findNodeByNameAndType(const QStringList& path,
- Node::Type type,
- Node::SubType subtype,
- bool acceptCollision = false) const;
-
-
+ Node* findNodeByNameAndType(const QStringList& path, Node::Type type) const;
InnerNode* findRelatesNode(const QStringList& path);
NameCollisionNode* checkForCollision(const QString& name);
NameCollisionNode* findCollisionNode(const QString& name) const;