summaryrefslogtreecommitdiffstats
path: root/src/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/bootstrap/bootstrap.pro1
-rw-r--r--src/tools/moc/generator.cpp6
-rw-r--r--src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp6
-rw-r--r--src/tools/qdoc/atom.cpp47
-rw-r--r--src/tools/qdoc/atom.h54
-rw-r--r--src/tools/qdoc/codemarker.cpp19
-rw-r--r--src/tools/qdoc/codemarker.h3
-rw-r--r--src/tools/qdoc/codeparser.cpp61
-rw-r--r--src/tools/qdoc/codeparser.h2
-rw-r--r--src/tools/qdoc/config.cpp108
-rw-r--r--src/tools/qdoc/config.h8
-rw-r--r--src/tools/qdoc/cppcodemarker.cpp43
-rw-r--r--src/tools/qdoc/cppcodemarker.h2
-rw-r--r--src/tools/qdoc/cppcodeparser.cpp226
-rw-r--r--src/tools/qdoc/ditaxmlgenerator.cpp663
-rw-r--r--src/tools/qdoc/ditaxmlgenerator.h12
-rw-r--r--src/tools/qdoc/doc.cpp161
-rw-r--r--src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc21
-rw-r--r--src/tools/qdoc/generator.cpp299
-rw-r--r--src/tools/qdoc/generator.h30
-rw-r--r--src/tools/qdoc/helpprojectwriter.cpp111
-rw-r--r--src/tools/qdoc/htmlgenerator.cpp972
-rw-r--r--src/tools/qdoc/htmlgenerator.h16
-rw-r--r--src/tools/qdoc/main.cpp48
-rw-r--r--src/tools/qdoc/node.cpp889
-rw-r--r--src/tools/qdoc/node.h338
-rw-r--r--src/tools/qdoc/puredocparser.cpp2
-rw-r--r--src/tools/qdoc/puredocparser.h1
-rw-r--r--src/tools/qdoc/qdocdatabase.cpp1495
-rw-r--r--src/tools/qdoc/qdocdatabase.h352
-rw-r--r--src/tools/qdoc/qdocindexfiles.cpp436
-rw-r--r--src/tools/qdoc/qdocindexfiles.h6
-rw-r--r--src/tools/qdoc/qdoctagfiles.cpp38
-rw-r--r--src/tools/qdoc/qmlcodeparser.h1
-rw-r--r--src/tools/qdoc/qmlvisitor.cpp14
-rw-r--r--src/tools/qdoc/tree.cpp1132
-rw-r--r--src/tools/qdoc/tree.h140
-rw-r--r--src/tools/rcc/rcc.cpp21
38 files changed, 4670 insertions, 3114 deletions
diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro
index 310ea317ac..2b58bff8f3 100644
--- a/src/tools/bootstrap/bootstrap.pro
+++ b/src/tools/bootstrap/bootstrap.pro
@@ -61,6 +61,7 @@ SOURCES += \
../../corelib/io/qabstractfileengine.cpp \
../../corelib/io/qbuffer.cpp \
../../corelib/io/qdatastream.cpp \
+ ../../corelib/io/qdebug.cpp \
../../corelib/io/qdir.cpp \
../../corelib/io/qdiriterator.cpp \
../../corelib/io/qfile.cpp \
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index a67ea05956..c63e80f90f 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -266,10 +266,12 @@ void Generator::generateCode()
{
int idx = 0;
for (int i = 0; i < strings.size(); ++i) {
- if (i)
- fprintf(out, ",\n");
const QByteArray &str = strings.at(i);
fprintf(out, "QT_MOC_LITERAL(%d, %d, %d)", i, idx, str.length());
+ if (i != strings.size() - 1)
+ fputc(',', out);
+ const QByteArray comment = str.length() > 32 ? str.left(29) + "..." : str;
+ fprintf(out, " // \"%s\"\n", comment.constData());
idx += str.length() + 1;
for (int j = 0; j < str.length(); ++j) {
if (str.at(j) == '\\') {
diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
index b4f9aedd7a..0df82cb4f5 100644
--- a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
+++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
@@ -705,9 +705,9 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
if (isNoReply)
hs << " callWithArgumentList(QDBus::NoBlock, "
- << "QLatin1String(\"" << method.name << "\"), argumentList);" << endl;
+ << "QStringLiteral(\"" << method.name << "\"), argumentList);" << endl;
else
- hs << " return asyncCallWithArgumentList(QLatin1String(\""
+ hs << " return asyncCallWithArgumentList(QStringLiteral(\""
<< method.name << "\"), argumentList);" << endl;
// close the function:
@@ -737,7 +737,7 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
}
hs << " QDBusMessage reply = callWithArgumentList(QDBus::Block, "
- << "QLatin1String(\"" << method.name << "\"), argumentList);" << endl;
+ << "QStringLiteral(\"" << method.name << "\"), argumentList);" << endl;
argPos++;
hs << " if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().count() == "
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 99f2abfb2f..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();
}
@@ -648,7 +649,7 @@ QString CodeMarker::macName(const Node *node, const QString &name)
/*!
Returns an empty list of documentation sections.
*/
-QList<Section> CodeMarker::qmlSections(const QmlClassNode* , SynopsisStyle )
+QList<Section> CodeMarker::qmlSections(QmlClassNode* , SynopsisStyle )
{
return QList<Section>();
}
diff --git a/src/tools/qdoc/codemarker.h b/src/tools/qdoc/codemarker.h
index 02caedf9b8..aa38b82e24 100644
--- a/src/tools/qdoc/codemarker.h
+++ b/src/tools/qdoc/codemarker.h
@@ -54,7 +54,6 @@
QT_BEGIN_NAMESPACE
class Config;
-class Tree;
typedef QMultiMap<QString, Node*> MemberMap; // the string is the member signature
typedef QPair<const QmlClassNode*, MemberMap> ClassMap; // the node is the QML type
@@ -155,7 +154,7 @@ public:
virtual QList<Section> sections(const InnerNode *inner,
SynopsisStyle style,
Status status) = 0;
- virtual QList<Section> qmlSections(const QmlClassNode* qmlClassNode, SynopsisStyle style);
+ virtual QList<Section> qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style);
virtual QStringList macRefsForNode(Node* node);
static void initialize(const Config& config);
diff --git a/src/tools/qdoc/codeparser.cpp b/src/tools/qdoc/codeparser.cpp
index a0ea561b28..e25056e353 100644
--- a/src/tools/qdoc/codeparser.cpp
+++ b/src/tools/qdoc/codeparser.cpp
@@ -76,7 +76,6 @@ QT_BEGIN_NAMESPACE
QString CodeParser::currentSubDir_;
QList<CodeParser *> CodeParser::parsers;
bool CodeParser::showInternal = false;
-QMap<QString,QString> CodeParser::nameToTitle;
/*!
The constructor adds this code parser to the static
@@ -300,50 +299,30 @@ void CodeParser::processCommonMetaCommand(const Location& location,
else if (command == COMMAND_PAGEKEYWORDS) {
node->addPageKeywords(arg.first);
}
- else if (command == COMMAND_SUBTITLE) {
- if (node->type() == Node::Document) {
- DocNode *dn = static_cast<DocNode *>(node);
- dn->setSubTitle(arg.first);
- }
- else
- location.warning(tr("Ignored '\\%1'").arg(COMMAND_SUBTITLE));
- }
else if (command == COMMAND_THREADSAFE) {
node->setThreadSafeness(Node::ThreadSafe);
}
else if (command == COMMAND_TITLE) {
- if (node->type() == Node::Document) {
- DocNode *dn = static_cast<DocNode *>(node);
- dn->setTitle(arg.first);
- if (dn->subType() == Node::Example) {
- ExampleNode::exampleNodeMap.insert(dn->title(),static_cast<ExampleNode*>(dn));
- }
- nameToTitle.insert(dn->name(),arg.first);
- }
- else
- location.warning(tr("Ignored '\\%1'").arg(COMMAND_TITLE));
+ node->setTitle(arg.first);
+ if (!node->isDocNode() && !node->isCollectionNode())
+ location.warning(tr("Ignored '\\%1'").arg(COMMAND_SUBTITLE));
+ else if (node->isExample())
+ qdb_->addExampleNode(static_cast<ExampleNode*>(node));
+ }
+ else if (command == COMMAND_SUBTITLE) {
+ node->setSubTitle(arg.first);
+ if (!node->isDocNode() && !node->isCollectionNode())
+ location.warning(tr("Ignored '\\%1'").arg(COMMAND_SUBTITLE));
}
else if (command == COMMAND_QTVARIABLE) {
- if (node->subType() == Node::Module) {
- DocNode *dn = static_cast<DocNode *>(node);
- dn->setQtVariable(arg.first);
- }
- else
- location.warning(tr("Command '\\%1' found outside of '\\module'. It can only be used within a module page.")
+ node->setQtVariable(arg.first);
+ if (!node->isModule() && !node->isQmlModule())
+ location.warning(tr("Command '\\%1' is only meanigfule in '\\module' and '\\qmlmodule'.")
.arg(COMMAND_QTVARIABLE));
}
}
/*!
- Find the page title given the page \a name and return it.
- */
-const QString CodeParser::titleFromName(const QString& name)
-{
- const QString t = nameToTitle.value(name);
- return t;
-}
-
-/*!
\internal
*/
void CodeParser::extractPageLinkAndDesc(const QString& arg,
@@ -412,9 +391,9 @@ bool CodeParser::isParsingQdoc() const
for an entity that will produce a documentation page will contain an
\inmodule command to tell qdoc which module the entity belongs to.
- But now that we normally run qdoc on each module in two passes. The
- first produces an index file; the second pass generates the docs
- after reading all the index files it needs.
+ But now we normally run qdoc on each module in two passes. The first
+ produces an index file; the second pass generates the docs after
+ reading all the index files it needs.
This means that all the pages generated during each pass 2 run of
qdoc almost certainly belong to a single module, and the name of
@@ -431,10 +410,10 @@ bool CodeParser::isParsingQdoc() const
void CodeParser::checkModuleInclusion(Node* n)
{
if (n->moduleName().isEmpty()) {
+ n->setModuleName(Generator::defaultModuleName());
switch (n->type()) {
case Node::Class:
if (n->access() != Node::Private && !n->doc().isEmpty()) {
- n->setModuleName(Generator::defaultModuleName());
n->doc().location().warning(tr("Class %1 has no \\inmodule command; "
"using project name by default: %2")
.arg(n->name()).arg(Generator::defaultModuleName()));
@@ -442,16 +421,15 @@ void CodeParser::checkModuleInclusion(Node* n)
break;
case Node::Namespace:
if (n->access() != Node::Private && !n->name().isEmpty() && !n->doc().isEmpty()) {
- n->setModuleName(Generator::defaultModuleName());
n->doc().location().warning(tr("Namespace %1 has no \\inmodule command; "
"using project name by default: %2")
.arg(n->name()).arg(Generator::defaultModuleName()));
}
break;
+#if 0
case Node::Document:
if (n->access() != Node::Private && !n->doc().isEmpty()) {
if (n->subType() == Node::HeaderFile) {
- n->setModuleName(Generator::defaultModuleName());
#if 0
n->doc().location().warning(tr("Header file with title \"%1\" has no \\inmodule command; "
"using project name by default: %2")
@@ -459,7 +437,6 @@ void CodeParser::checkModuleInclusion(Node* n)
#endif
}
else if (n->subType() == Node::Page) {
- n->setModuleName(Generator::defaultModuleName());
#if 0
n->doc().location().warning(tr("Page with title \"%1\" has no \\inmodule command; "
"using project name by default: %2")
@@ -467,7 +444,6 @@ void CodeParser::checkModuleInclusion(Node* n)
#endif
}
else if (n->subType() == Node::Example) {
- n->setModuleName(Generator::defaultModuleName());
#if 0
n->doc().location().warning(tr("Example with title \"%1\" has no \\inmodule command; "
"using project name by default: %2")
@@ -476,6 +452,7 @@ void CodeParser::checkModuleInclusion(Node* n)
}
}
break;
+#endif
default:
break;
}
diff --git a/src/tools/qdoc/codeparser.h b/src/tools/qdoc/codeparser.h
index 89f661abeb..baa82fc650 100644
--- a/src/tools/qdoc/codeparser.h
+++ b/src/tools/qdoc/codeparser.h
@@ -81,7 +81,6 @@ public:
static CodeParser *parserForLanguage(const QString& language);
static CodeParser *parserForHeaderFile(const QString &filePath);
static CodeParser *parserForSourceFile(const QString &filePath);
- static const QString titleFromName(const QString& name);
static void setLink(Node* node, Node::LinkType linkType, const QString& arg);
static const QString& currentOutputSubdirectory() { return currentSubDir_; }
@@ -101,7 +100,6 @@ private:
static QString currentSubDir_;
static QList<CodeParser *> parsers;
static bool showInternal;
- static QMap<QString,QString> nameToTitle;
};
QT_END_NAMESPACE
diff --git a/src/tools/qdoc/config.cpp b/src/tools/qdoc/config.cpp
index 56e7287c40..644eab8a56 100644
--- a/src/tools/qdoc/config.cpp
+++ b/src/tools/qdoc/config.cpp
@@ -56,6 +56,7 @@
QT_BEGIN_NAMESPACE
QString ConfigStrings::ALIAS = QStringLiteral("alias");
+QString ConfigStrings::AUTOLINKERRORS = QStringLiteral("autolinkerrors");
QString ConfigStrings::BASE = QStringLiteral("base");
QString ConfigStrings::BASEDIR = QStringLiteral("basedir");
QString ConfigStrings::BUILDVERSION = QStringLiteral("buildversion");
@@ -242,6 +243,7 @@ QStringList MetaStack::getExpanded(const Location& location)
}
QT_STATIC_CONST_IMPL QString Config::dot = QLatin1String(".");
+bool Config::debug_ = false;
bool Config::generateExamples = true;
QString Config::overrideOutputDir;
QString Config::installDir;
@@ -452,87 +454,21 @@ QStringList Config::getStringList(const QString& var) const
}
/*!
- \brief Returns the a path list where all paths are canonicalized, then
- made relative to the config file.
- \param var The variable containing the list of paths.
- \see Location::canonicalRelativePath()
- */
-QStringList Config::getCanonicalPathList(const QString& var) const
-{
- QStringList t;
- QList<ConfigVar> configVars = configVars_.values(var);
- if (!configVars.empty()) {
- int i = configVars.size() - 1;
- while (i >= 0) {
- const ConfigVar& cv = configVars[i];
- if (!cv.location_.isEmpty())
- (Location&) lastLocation_ = cv.location_;
- if (!cv.plus_)
- t.clear();
- const QString d = cv.currentPath_;
- const QStringList& sl = cv.values_;
- if (!sl.isEmpty()) {
- t.reserve(t.size() + sl.size());
- for (int i=0; i<sl.size(); ++i) {
- QDir dir(d + "/" + sl[i]);
- t.append(dir.canonicalPath());
- }
- }
- --i;
- }
- }
- return t;
-}
+ Returns the a path list where all paths from the config variable \a var
+ are canonicalized. If \a validate is true, a warning for invalid paths is
+ generated.
-/*!
- This function should only be called when the configuration
- variable \a var maps to string lists that contain file paths.
- It cleans the paths with QDir::cleanPath() before returning
- them.
- */
-QStringList Config::getCleanPathList(const QString& var) const
-{
- QStringList t;
- QList<ConfigVar> configVars = configVars_.values(var);
- if (!configVars.empty()) {
- int i = configVars.size() - 1;
- while (i >= 0) {
- const ConfigVar& cv = configVars[i];
- if (!cv.plus_)
- t.clear();
- if (!cv.location_.isEmpty())
- (Location&) lastLocation_ = cv.location_;
- const QStringList& sl = cv.values_;
- if (!sl.isEmpty()) {
- t.reserve(t.size() + sl.size());
- for (int i=0; i<sl.size(); ++i) {
- t.append(QDir::cleanPath(sl[i].simplified()));
- }
- }
- --i;
- }
- }
- return t;
-}
-
-/*!
- This function should only be called when the configuration
- variable \a var maps to string lists that contain file paths.
- It cleans the paths with QDir::cleanPath() before returning
- them.
-
- First, this function looks up the configuration variable \a var
- in the location map and, if found, sets the internal variable
- \c{lastLocation_} the Location that \a var maps to.
+ First, this function looks up the configuration variable \a var
+ in the location map and, if found, sets the internal variable
+ \c{lastLocation_} the Location that \a var maps to.
- Then it looks up the configuration variable \a var in the string
- list map, which maps to one or more records that each contains a
- list of file paths.
+ Then it looks up the configuration variable \a var in the string
+ list map, which maps to one or more records that each contains a
+ list of file paths.
- These paths might not be clean, so QDir::cleanPath() is called
- for each one. The string list returned contains cleaned paths.
+ \sa Location::canonicalRelativePath()
*/
-QStringList Config::getPathList(const QString& var) const
+QStringList Config::getCanonicalPathList(const QString& var, bool validate) const
{
QStringList t;
QList<ConfigVar> configVars = configVars_.values(var);
@@ -540,22 +476,23 @@ QStringList Config::getPathList(const QString& var) const
int i = configVars.size() - 1;
while (i >= 0) {
const ConfigVar& cv = configVars[i];
- if (!cv.plus_)
- t.clear();
if (!cv.location_.isEmpty())
(Location&) lastLocation_ = cv.location_;
+ if (!cv.plus_)
+ t.clear();
const QString d = cv.currentPath_;
const QStringList& sl = cv.values_;
if (!sl.isEmpty()) {
t.reserve(t.size() + sl.size());
for (int i=0; i<sl.size(); ++i) {
- QFileInfo fileInfo;
- QString path = d + "/" + QDir::cleanPath(sl[i].simplified());
- fileInfo.setFile(path);
- if (!fileInfo.exists())
- lastLocation_.warning(tr("File '%1' does not exist").arg(path));
+ QDir dir(sl[i].simplified());
+ QString path = dir.path();
+ if (dir.isRelative())
+ dir.setPath(d + "/" + path);
+ if (validate && !QFileInfo::exists(dir.path()))
+ lastLocation_.warning(tr("Cannot find file or directory: %1").arg(path));
else
- t.append(path);
+ t.append(dir.canonicalPath());
}
}
--i;
@@ -564,7 +501,6 @@ QStringList Config::getPathList(const QString& var) const
return t;
}
-
/*!
Calls getRegExpList() with the control variable \a var and
iterates through the resulting list of regular expressions,
diff --git a/src/tools/qdoc/config.h b/src/tools/qdoc/config.h
index 54ee8de47f..622573dac2 100644
--- a/src/tools/qdoc/config.h
+++ b/src/tools/qdoc/config.h
@@ -88,6 +88,8 @@ public:
Config(const QString& programName);
~Config();
+ static bool debug_;
+
void load(const QString& fileName);
void setStringList(const QString& var, const QStringList& values);
@@ -101,9 +103,7 @@ public:
QString getString(const QString& var) const;
QSet<QString> getStringSet(const QString& var) const;
QStringList getStringList(const QString& var) const;
- QStringList getCanonicalPathList(const QString& var) const;
- QStringList getCleanPathList(const QString& var) const;
- QStringList getPathList(const QString& var) const;
+ QStringList getCanonicalPathList(const QString& var, bool validate = false) const;
QRegExp getRegExp(const QString& var) const;
QList<QRegExp> getRegExpList(const QString& var) const;
QSet<QString> subVars(const QString& var) const;
@@ -167,6 +167,7 @@ private:
struct ConfigStrings
{
static QString ALIAS;
+ static QString AUTOLINKERRORS;
static QString BASE;
static QString BASEDIR;
static QString BUILDVERSION;
@@ -239,6 +240,7 @@ struct ConfigStrings
};
#define CONFIG_ALIAS ConfigStrings::ALIAS
+#define CONFIG_AUTOLINKERRORS ConfigStrings::AUTOLINKERRORS
#define CONFIG_BASE ConfigStrings::BASE
#define CONFIG_BASEDIR ConfigStrings::BASEDIR
#define CONFIG_BUILDVERSION ConfigStrings::BUILDVERSION
diff --git a/src/tools/qdoc/cppcodemarker.cpp b/src/tools/qdoc/cppcodemarker.cpp
index 64b11109f7..60c7142229 100644
--- a/src/tools/qdoc/cppcodemarker.cpp
+++ b/src/tools/qdoc/cppcodemarker.cpp
@@ -629,7 +629,8 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner,
QList<RelatedClass>::ConstIterator r =
ancestorClass->baseClasses().constBegin();
while (r != ancestorClass->baseClasses().constEnd()) {
- stack.prepend((*r).node);
+ if ((*r).node_)
+ stack.prepend((*r).node_);
++r;
}
}
@@ -724,7 +725,8 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner,
QList<RelatedClass>::ConstIterator r =
ancestorClass->baseClasses().constBegin();
while (r != ancestorClass->baseClasses().constEnd()) {
- stack.prepend((*r).node);
+ if ((*r).node_)
+ stack.prepend((*r).node_);
++r;
}
}
@@ -748,6 +750,16 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner,
style == Detailed ? "types" : QString(),
"type",
"types");
+ FastSection variables(inner,
+ style == Summary ? "Variables" : "Variable Documentation",
+ style == Detailed ? "vars" : QString(),
+ "variable",
+ "variables");
+ FastSection staticVariables(inner,
+ "Static Variables",
+ QString(),
+ "static variable",
+ "static variables");
FastSection functions(inner,
style == Summary ?
"Functions" : "Function Documentation",
@@ -786,14 +798,27 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner,
insert(functions, *n, style, status);
}
break;
+ case Node::Variable:
+ {
+ const VariableNode* var = static_cast<const VariableNode*>(*n);
+ if (!var->doc().isEmpty()) {
+ if (var->isStatic())
+ insert(staticVariables,*n,style,status);
+ else
+ insert(variables, *n, style, status);
+ }
+ }
+ break;
default:
- ;
+ break;
}
++n;
}
append(sections, namespaces);
append(sections, classes);
append(sections, types);
+ append(sections, variables);
+ append(sections, staticVariables);
append(sections, functions);
append(sections, macros);
}
@@ -1066,7 +1091,7 @@ QString CppCodeMarker::addMarkUp(const QString &in,
the list of documentation sections for the children of the
\a qmlClassNode.
*/
-QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, SynopsisStyle style)
+QList<Section> CppCodeMarker::qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style)
{
QList<Section> sections;
if (qmlClassNode) {
@@ -1107,7 +1132,7 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno
"method",
"methods");
- const QmlClassNode* qcn = qmlClassNode;
+ QmlClassNode* qcn = qmlClassNode;
while (qcn != 0) {
NodeList::ConstIterator c = qcn->childNodes().constBegin();
while (c != qcn->childNodes().constEnd()) {
@@ -1146,7 +1171,7 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno
++c;
}
if (qcn->qmlBaseNode() != 0) {
- qcn = static_cast<const QmlClassNode*>(qcn->qmlBaseNode());
+ qcn = static_cast<QmlClassNode*>(qcn->qmlBaseNode());
if (!qcn->isAbstract())
qcn = 0;
}
@@ -1172,7 +1197,7 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno
FastSection qmlmethods(qmlClassNode,"Method Documentation","qmlmeth","member","members");
FastSection qmlattachedmethods(qmlClassNode,"Attached Method Documentation","qmlattmeth",
"member","members");
- const QmlClassNode* qcn = qmlClassNode;
+ QmlClassNode* qcn = qmlClassNode;
while (qcn != 0) {
NodeList::ConstIterator c = qcn->childNodes().constBegin();
while (c != qcn->childNodes().constEnd()) {
@@ -1210,7 +1235,7 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno
++c;
}
if (qcn->qmlBaseNode() != 0) {
- qcn = static_cast<const QmlClassNode*>(qcn->qmlBaseNode());
+ qcn = static_cast<QmlClassNode*>(qcn->qmlBaseNode());
if (!qcn->isAbstract())
qcn = 0;
}
@@ -1232,7 +1257,7 @@ QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, Syno
*/
ClassMap* classMap = 0;
FastSection all(qmlClassNode,QString(),QString(),"member","members");
- const QmlClassNode* current = qmlClassNode;
+ QmlClassNode* current = qmlClassNode;
while (current != 0) {
/*
If the QML type is abstract, do not create
diff --git a/src/tools/qdoc/cppcodemarker.h b/src/tools/qdoc/cppcodemarker.h
index 91a9c01a28..74faf1ca57 100644
--- a/src/tools/qdoc/cppcodemarker.h
+++ b/src/tools/qdoc/cppcodemarker.h
@@ -78,7 +78,7 @@ public:
virtual QList<Section> sections(const InnerNode *innerNode,
SynopsisStyle style,
Status status);
- virtual QList<Section> qmlSections(const QmlClassNode* qmlClassNode, SynopsisStyle style);
+ virtual QList<Section> qmlSections(QmlClassNode* qmlClassNode, SynopsisStyle style);
private:
QString addMarkUp(const QString& protectedCode,
diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp
index bb403bd4d9..2755bf7254 100644
--- a/src/tools/qdoc/cppcodeparser.cpp
+++ b/src/tools/qdoc/cppcodeparser.cpp
@@ -52,6 +52,7 @@
#include "tokenizer.h"
#include "qdocdatabase.h"
#include <qdebug.h>
+#include "generator.h"
QT_BEGIN_NAMESPACE
@@ -99,8 +100,8 @@ void CppCodeParser::initializeParser(const Config &config)
nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property);
nodeTypeMap.insert(COMMAND_VARIABLE, Node::Variable);
- exampleFiles = config.getCleanPathList(CONFIG_EXAMPLES);
- exampleDirs = config.getCleanPathList(CONFIG_EXAMPLEDIRS);
+ exampleFiles = config.getCanonicalPathList(CONFIG_EXAMPLES);
+ exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS);
QStringList exampleFilePatterns = config.getStringList(
CONFIG_EXAMPLES + Config::dot + CONFIG_FILEEXTENSIONS);
@@ -173,7 +174,7 @@ void CppCodeParser::parseHeaderFile(const Location& location, const QString& fil
Tokenizer fileTokenizer(fileLocation, in);
tokenizer = &fileTokenizer;
readToken();
- matchDeclList(qdb_->treeRoot());
+ matchDeclList(qdb_->primaryTreeRoot());
if (!fileTokenizer.version().isEmpty())
qdb_->setVersion(fileTokenizer.version());
in.close();
@@ -218,15 +219,13 @@ void CppCodeParser::parseSourceFile(const Location& location, const QString& fil
}
/*!
- This is called after all the header files have been parsed.
- I think the most important thing it does is resolve class
- inheritance links in the tree. But it also initializes a
- bunch of stuff.
+ This is called after all the C++ header files have been
+ parsed. The most important thing it does is resolve C++
+ class inheritance links in the tree. It also initializes
+ a bunch of other collections.
*/
void CppCodeParser::doneParsingHeaderFiles()
{
- qdb_->resolveInheritance();
-
QMapIterator<QString, QString> i(sequentialIteratorClasses);
while (i.hasNext()) {
i.next();
@@ -265,11 +264,10 @@ void CppCodeParser::doneParsingHeaderFiles()
*/
void CppCodeParser::doneParsingSourceFiles()
{
- qdb_->treeRoot()->clearCurrentChildPointers();
- qdb_->treeRoot()->normalizeOverloads();
+ qdb_->primaryTreeRoot()->normalizeOverloads();
qdb_->fixInheritance();
qdb_->resolveProperties();
- qdb_->treeRoot()->makeUndocumentedChildrenInternal();
+ qdb_->primaryTreeRoot()->makeUndocumentedChildrenInternal();
}
static QSet<QString> topicCommands_;
@@ -328,38 +326,33 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
doc.startLocation().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_FN));
}
else {
- func = qdb_->findNodeInOpenNamespace(parentPath, clone);
- /*
- Search the root namespace if no match was found.
- */
+ func = qdb_->findFunctionNode(parentPath, clone);
if (func == 0) {
- func = qdb_->findFunctionNode(parentPath, clone);
+ if (parentPath.isEmpty() && !lastPath_.isEmpty())
+ func = qdb_->findFunctionNode(lastPath_, clone);
}
+ /*
+ If the node was not found, then search for it in the
+ open C++ namespaces. We don't expect this search to
+ be necessary often. Nor do we expect it to succeed
+ very often.
+ */
+ if (func == 0)
+ func = qdb_->findNodeInOpenNamespace(parentPath, clone);
+
if (func == 0) {
- if (parentPath.isEmpty() && !lastPath_.isEmpty()) {
- func = qdb_->findFunctionNode(lastPath_, clone);
- }
- if (func == 0) {
- doc.location().warning(tr("Cannot find '%1' in '\\%2' %3")
- .arg(clone->name() + "(...)")
- .arg(COMMAND_FN)
- .arg(arg.first),
- tr("I cannot find any function of that name with the "
- "specified signature. Make sure that the signature "
- "is identical to the declaration, including 'const' "
- "qualifiers."));
- }
- else {
- doc.location().warning(tr("Missing '%1::' for '%2' in '\\%3'")
- .arg(lastPath_.join("::"))
- .arg(clone->name() + "()")
- .arg(COMMAND_FN));
- }
+ doc.location().warning(tr("Cannot find '%1' in '\\%2' %3")
+ .arg(clone->name() + "(...)")
+ .arg(COMMAND_FN)
+ .arg(arg.first),
+ tr("I cannot find any function of that name with the "
+ "specified signature. Make sure that the signature "
+ "is identical to the declaration, including 'const' "
+ "qualifiers."));
}
- else {
+ else
lastPath_ = parentPath;
- }
if (func) {
func->borrowParameterNames(clone);
func->setParentPath(clone->parentPath());
@@ -372,7 +365,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
QStringList parentPath;
FunctionNode *func = 0;
- extra.root = qdb_->treeRoot();
+ extra.root = qdb_->primaryTreeRoot();
extra.isMacro = true;
if (makeFunctionNode(arg.first, &parentPath, &func, extra)) {
if (!parentPath.isEmpty()) {
@@ -394,7 +387,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
return func;
}
else if (QRegExp("[A-Za-z_][A-Za-z0-9_]+").exactMatch(arg.first)) {
- func = new FunctionNode(qdb_->treeRoot(), arg.first);
+ func = new FunctionNode(qdb_->primaryTreeRoot(), arg.first);
func->setAccess(Node::Public);
func->setLocation(doc.startLocation());
func->setMetaness(FunctionNode::MacroWithoutParams);
@@ -415,29 +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;
- /*
- If the command refers to something that can be in a
- C++ namespace, search for it first in all the known
- C++ namespaces.
- */
- node = qdb_->findNodeInOpenNamespace(path, type, subtype);
-
- /*
- If the node was not found in a C++ namespace, search
- for it in the root namespace.
- */
- if (node == 0) {
- node = qdb_->findNodeByNameAndType(path, type, subtype);
- }
-
+ node = qdb_->findNodeInOpenNamespace(path, type);
+ if (node == 0)
+ 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));
@@ -446,53 +423,58 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
}
else if (node->isInnerNode()) {
/*
- This treets a class as a namespace.
+ This treats a class as a namespace.
*/
- if (path.size() > 1) {
- path.pop_back();
- QString ns = path.join("::");
- qdb_->insertOpenNamespace(ns);
+ if ((type == Node::Class) || (type == Node::Namespace)) {
+ if (path.size() > 1) {
+ path.pop_back();
+ QString ns = path.join("::");
+ qdb_->insertOpenNamespace(ns);
+ }
}
}
return node;
}
else if (command == COMMAND_EXAMPLE) {
if (Config::generateExamples) {
- ExampleNode* en = new ExampleNode(qdb_->treeRoot(), arg.first);
+ ExampleNode* en = new ExampleNode(qdb_->primaryTreeRoot(), arg.first);
en->setLocation(doc.startLocation());
createExampleFileNodes(en);
return en;
}
}
else if (command == COMMAND_EXTERNALPAGE) {
- DocNode* dn = new DocNode(qdb_->treeRoot(), arg.first, Node::ExternalPage, Node::ArticlePage);
+ DocNode* dn = new DocNode(qdb_->primaryTreeRoot(), arg.first, Node::ExternalPage, Node::ArticlePage);
dn->setLocation(doc.startLocation());
return dn;
}
else if (command == COMMAND_FILE) {
- DocNode* dn = new DocNode(qdb_->treeRoot(), arg.first, Node::File, Node::NoPageType);
- dn->setLocation(doc.startLocation());
- return dn;
- }
- else if (command == COMMAND_GROUP) {
- DocNode* dn = qdb_->addGroup(arg.first);
+ DocNode* dn = new DocNode(qdb_->primaryTreeRoot(), arg.first, Node::File, Node::NoPageType);
dn->setLocation(doc.startLocation());
return dn;
}
else if (command == COMMAND_HEADERFILE) {
- DocNode* dn = new DocNode(qdb_->treeRoot(), arg.first, Node::HeaderFile, Node::ApiPage);
+ DocNode* dn = new DocNode(qdb_->primaryTreeRoot(), arg.first, Node::HeaderFile, Node::ApiPage);
dn->setLocation(doc.startLocation());
return dn;
}
+ else if (command == COMMAND_GROUP) {
+ GroupNode* gn = qdb_->addGroup(arg.first);
+ gn->setLocation(doc.startLocation());
+ gn->markSeen();
+ return gn;
+ }
else if (command == COMMAND_MODULE) {
- DocNode* dn = qdb_->addModule(arg.first);
- dn->setLocation(doc.startLocation());
- return dn;
+ ModuleNode* mn = qdb_->addModule(arg.first);
+ mn->setLocation(doc.startLocation());
+ mn->markSeen();
+ return mn;
}
else if (command == COMMAND_QMLMODULE) {
- DocNode* dn = qdb_->addQmlModule(arg.first);
- dn->setLocation(doc.startLocation());
- return dn;
+ QmlModuleNode* qmn = qdb_->addQmlModule(arg.first);
+ qmn->setLocation(doc.startLocation());
+ qmn->markSeen();
+ return qmn;
}
else if (command == COMMAND_PAGE) {
Node::PageType ptype = Node::ArticlePage;
@@ -529,9 +511,9 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
NameCollisionNode* ncn = qdb_->checkForCollision(args[0]);
DocNode* dn = 0;
if (ptype == Node::DitaMapPage)
- dn = new DitaMapNode(qdb_->treeRoot(), args[0]);
+ dn = new DitaMapNode(qdb_->primaryTreeRoot(), args[0]);
else
- dn = new DocNode(qdb_->treeRoot(), args[0], Node::Page, ptype);
+ dn = new DocNode(qdb_->primaryTreeRoot(), args[0], Node::Page, ptype);
dn->setLocation(doc.startLocation());
if (ncn) {
ncn->addCollision(dn);
@@ -539,7 +521,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
return dn;
}
else if (command == COMMAND_DITAMAP) {
- DocNode* dn = new DitaMapNode(qdb_->treeRoot(), arg.first);
+ DocNode* dn = new DitaMapNode(qdb_->primaryTreeRoot(), arg.first);
dn->setLocation(doc.startLocation());
return dn;
}
@@ -579,7 +561,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
node and return that one.
*/
NameCollisionNode* ncn = qdb_->checkForCollision(names[0]);
- QmlClassNode* qcn = new QmlClassNode(qdb_->treeRoot(), names[0]);
+ QmlClassNode* qcn = new QmlClassNode(qdb_->primaryTreeRoot(), names[0]);
qcn->setClassNode(classNode);
qcn->setLocation(doc.startLocation());
#if 0
@@ -598,12 +580,13 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
}
}
#endif
- if (ncn)
+ if (ncn) {
ncn->addCollision(qcn);
+ }
return qcn;
}
else if (command == COMMAND_QMLBASICTYPE) {
- QmlBasicTypeNode* n = new QmlBasicTypeNode(qdb_->treeRoot(), arg.first);
+ QmlBasicTypeNode* n = new QmlBasicTypeNode(qdb_->primaryTreeRoot(), arg.first);
n->setLocation(doc.startLocation());
return n;
}
@@ -959,38 +942,12 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc,
}
}
else if (command == COMMAND_RELATES) {
- /*
- Find the node that this node relates to.
- */
- Node* n = 0;
- if (arg.startsWith(QLatin1Char('<')) || arg.startsWith('"')) {
- /*
- It should be a header file, I think.
- */
- n = qdb_->findNodeByNameAndType(QStringList(arg), Node::Document, Node::NoSubType);
- }
- else {
- /*
- If it wasn't a file, it should be either a class or a namespace.
- */
- QStringList newPath = arg.split("::");
- n = qdb_->findClassNode(newPath);
- if (!n)
- n = qdb_->findNamespaceNode(newPath);
- }
-
- if (!n) {
- /*
- Didn't ind it. Error...
- */
+ QStringList path = arg.split("::");
+ Node* n = qdb_->findRelatesNode(path);
+ if (!n)
doc.location().warning(tr("Cannot find '%1' in '\\%2'").arg(arg).arg(COMMAND_RELATES));
- }
- else {
- /*
- Found it. This node relates to it.
- */
+ else
node->setRelates(static_cast<InnerNode*>(n));
- }
}
else if (command == COMMAND_CONTENTSPAGE) {
setLink(node, Node::ContentsLink, arg);
@@ -1010,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);
@@ -1062,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);
@@ -1636,11 +1592,7 @@ bool CppCodeParser::matchBaseSpecifier(ClassNode *classe, bool isClass)
if (!matchDataType(&baseClass))
return false;
- qdb_->addBaseClass(classe,
- access,
- baseClass.toPath(),
- baseClass.toString(),
- classe->parent());
+ classe->addUnresolvedBaseClass(access, baseClass.toPath(), baseClass.toString());
return true;
}
@@ -1676,7 +1628,7 @@ bool CppCodeParser::matchClassDecl(InnerNode *parent,
while (tok == Tok_Ident)
readToken();
if (tok == Tok_Gulbrandsen) {
- Node* n = parent->findChildNodeByNameAndType(previousLexeme(),Node::Class);
+ Node* n = parent->findChildNode(previousLexeme(),Node::Class);
if (n) {
parent = static_cast<InnerNode*>(n);
if (parent) {
@@ -1735,9 +1687,8 @@ bool CppCodeParser::matchNamespaceDecl(InnerNode *parent)
*/
QString namespaceName = previousLexeme();
NamespaceNode* ns = 0;
- if (parent) {
- ns = static_cast<NamespaceNode*>(parent->findChildNodeByNameAndType(namespaceName, Node::Namespace));
- }
+ if (parent)
+ ns = static_cast<NamespaceNode*>(parent->findChildNode(namespaceName, Node::Namespace));
if (!ns) {
ns = new NamespaceNode(parent, namespaceName);
ns->setAccess(access);
@@ -1875,7 +1826,7 @@ bool CppCodeParser::matchTypedefDecl(InnerNode *parent)
if (!match(Tok_Semicolon))
return false;
- if (parent && !parent->findChildNodeByNameAndType(name, Node::Typedef)) {
+ if (parent && !parent->findChildNode(name, Node::Typedef)) {
TypedefNode* td = new TypedefNode(parent, name);
td->setAccess(access);
td->setLocation(location());
@@ -2110,7 +2061,7 @@ bool CppCodeParser::matchDeclList(InnerNode *parent)
TypedefNode *flagsNode = new TypedefNode(parent, flagsType);
flagsNode->setAccess(access);
flagsNode->setLocation(location());
- EnumNode* en = static_cast<EnumNode*>(parent->findChildNodeByNameAndType(name, Node::Enum));
+ EnumNode* en = static_cast<EnumNode*>(parent->findChildNode(name, Node::Enum));
if (en)
en->setFlagsType(flagsNode);
}
@@ -2189,9 +2140,15 @@ bool CppCodeParser::matchDocsAndStuff()
FunctionNode *func = 0;
if (matchFunctionDecl(0, &parentPath, &clone, QString(), extra)) {
- func = qdb_->findNodeInOpenNamespace(parentPath, clone);
+ func = qdb_->findFunctionNode(parentPath, clone);
+ /*
+ If the node was not found, then search for it in the
+ open C++ namespaces. We don't expect this search to
+ be necessary often. Nor do we expect it to succeed
+ very often.
+ */
if (func == 0)
- func = qdb_->findFunctionNode(parentPath, clone);
+ func = qdb_->findNodeInOpenNamespace(parentPath, clone);
if (func) {
func->borrowParameterNames(clone);
@@ -2253,8 +2210,9 @@ bool CppCodeParser::matchDocsAndStuff()
checkModuleInclusion(*n);
if ((*n)->isInnerNode() && ((InnerNode *)*n)->includes().isEmpty()) {
InnerNode *m = static_cast<InnerNode *>(*n);
- while (m->parent() != qdb_->treeRoot())
+ while (m->parent() && m->moduleName().isEmpty()) {
m = m->parent();
+ }
if (m == *n)
((InnerNode *)*n)->addInclude((*n)->name());
else
@@ -2391,7 +2349,7 @@ void CppCodeParser::instantiateIteratorMacro(const QString &container,
Tokenizer stringTokenizer(loc, latin1);
tokenizer = &stringTokenizer;
readToken();
- matchDeclList(QDocDatabase::qdocDB()->treeRoot());
+ matchDeclList(QDocDatabase::qdocDB()->primaryTreeRoot());
}
void CppCodeParser::createExampleFileNodes(DocNode *dn)
diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp
index e3b9bdd264..bbd32204ce 100644
--- a/src/tools/qdoc/ditaxmlgenerator.cpp
+++ b/src/tools/qdoc/ditaxmlgenerator.cpp
@@ -667,13 +667,12 @@ GuidMap* DitaXmlGenerator::lookupGuidMap(const QString& fileName)
}
/*!
- Traverses the database generating all the DITA XML documentation.
+ Traverses the current tree generating all the DITA XML documentation.
*/
-void DitaXmlGenerator::generateTree()
+void DitaXmlGenerator::generateDocs()
{
- qdb_->buildCollections();
if (!runPrepareOnly()) {
- Generator::generateTree();
+ Generator::generateDocs();
generateCollisionPages();
}
@@ -820,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;
@@ -1013,9 +1011,9 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
break;
case Atom::AnnotatedList:
{
- DocNode* dn = qdb_->getGroup(atom->string());
- if (dn)
- generateAnnotatedList(relative, marker, dn->members());
+ GroupNode* gn = qdb_->getGroup(atom->string());
+ if (gn)
+ generateAnnotatedList(relative, marker, gn->members());
}
break;
case Atom::GeneratedList:
@@ -1032,10 +1030,10 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
QString arg = atom->string().trimmed();
QString moduleName = atom->string().mid(atom->string().indexOf("classesbymodule") + 15).trimmed();
QDocDatabase* qdb = QDocDatabase::qdocDB();
- DocNode* dn = qdb->findModule(moduleName);
- if (dn) {
+ ModuleNode* mn = qdb->findModule(moduleName);
+ if (mn) {
NodeMap m;
- dn->getMemberClasses(m);
+ mn->getMemberClasses(m);
if (!m.isEmpty()) {
generateAnnotatedList(relative, marker, m);
}
@@ -1084,9 +1082,11 @@ int DitaXmlGenerator::generateAtom(const Atom *atom,
generateAnnotatedList(relative, marker, qdb_->getNamespaces());
}
else if (atom->string() == "related") {
- const DocNode *dn = static_cast<const DocNode *>(relative);
- if (dn)
- generateAnnotatedList(dn, marker, dn->members());
+ if (relative && relative->isCollectionNode()) {
+ const CollectionNode* cn = static_cast<const CollectionNode *>(relative);
+ if (cn)
+ generateAnnotatedList(cn, marker, cn->members());
+ }
}
break;
case Atom::SinceList:
@@ -1105,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);
@@ -1255,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);
@@ -1312,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_)
@@ -2051,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();
@@ -2167,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();
@@ -2216,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)
@@ -2250,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;
}
@@ -2263,24 +2287,6 @@ void DitaXmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
writeStartTag(DT_body);
enterSection(QString(), QString());
- if (dn->subType() == Node::Module) {
- generateStatus(dn, marker);
- NodeMap nm;
- dn->getMemberNamespaces(nm);
- if (!nm.isEmpty()) {
- enterSection("h2","Namespaces");
- generateAnnotatedList(dn, marker, nm);
- leaveSection();
- }
- nm.clear();
- dn->getMemberClasses(nm);
- if (!nm.isEmpty()) {
- enterSection("h2","Classes");
- generateAnnotatedList(dn, marker, nm);
- leaveSection();
- }
- nm.clear();
- }
if (dn->doc().isEmpty()) {
if (dn->subType() == Node::File) {
@@ -2299,23 +2305,70 @@ void DitaXmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
}
}
else {
- if (dn->subType() == Node::Module) {
+ generateBody(dn, marker);
+ generateAlsoList(dn, marker);
+ }
+ leaveSection(); // </section>
+ if (!writeEndTag()) { // </body>
+ dn->doc().location().warning(tr("Pop of empty XML tag stack; generating DITA for '%1'").arg(dn->name()));
+ return;
+ }
+ writeRelatedLinks(dn);
+ writeEndTag(); // </topic>
+}
+
+/*!
+ Generate the DITA XML file for a group, module, or QML module.
+ */
+void DitaXmlGenerator::generateCollectionNode(CollectionNode* cn, CodeMarker* marker)
+{
+ QList<Section> sections;
+ QList<Section>::const_iterator s;
+ QString fullTitle = cn->fullTitle();
+
+ generateHeader(cn, fullTitle);
+ generateBrief(cn, marker); // <shortdesc>
+ writeProlog(cn);
+
+ writeStartTag(DT_body);
+ enterSection(QString(), QString());
+ if (cn->isModule()) {
+ generateStatus(cn, marker);
+ NodeMap nm;
+ cn->getMemberNamespaces(nm);
+ if (!nm.isEmpty()) {
+ enterSection("h2","Namespaces");
+ generateAnnotatedList(cn, marker, nm);
+ leaveSection();
+ }
+ nm.clear();
+ cn->getMemberClasses(nm);
+ if (!nm.isEmpty()) {
+ enterSection("h2","Classes");
+ generateAnnotatedList(cn, marker, nm);
+ leaveSection();
+ }
+ nm.clear();
+ }
+
+ if (!cn->doc().isEmpty()) {
+ if (cn->isModule()) {
enterSection(QString(), QString());
- generateBody(dn, marker);
+ generateBody(cn, marker);
leaveSection();
}
else {
- generateBody(dn, marker);
+ generateBody(cn, marker);
}
- generateAlsoList(dn, marker);
- generateAnnotatedList(dn, marker, dn->members());
+ generateAlsoList(cn, marker);
+ generateAnnotatedList(cn, marker, cn->members());
}
leaveSection(); // </section>
if (!writeEndTag()) { // </body>
- dn->doc().location().warning(tr("Pop of empty XML tag stack; generating DITA for '%1'").arg(dn->name()));
+ cn->doc().location().warning(tr("Pop of empty XML tag stack; generating DITA for '%1'").arg(cn->name()));
return;
}
- writeRelatedLinks(dn);
+ writeRelatedLinks(cn);
writeEndTag(); // </topic>
}
@@ -2350,7 +2403,7 @@ void DitaXmlGenerator::writeLink(const Node* node,
value of the \e role attribute is \c{parent} for the
\c{start} link.
*/
-void DitaXmlGenerator::writeRelatedLinks(const DocNode* node)
+void DitaXmlGenerator::writeRelatedLinks(const Node* node)
{
const Node* linkNode = 0;
QPair<QString,QString> linkPair;
@@ -2361,7 +2414,7 @@ void DitaXmlGenerator::writeRelatedLinks(const DocNode* 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();
}
@@ -2372,7 +2425,7 @@ void DitaXmlGenerator::writeRelatedLinks(const DocNode* 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();
}
@@ -2383,7 +2436,7 @@ void DitaXmlGenerator::writeRelatedLinks(const DocNode* 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();
}
@@ -2405,12 +2458,9 @@ QString DitaXmlGenerator::fileExtension() const
Writes an XML file header to the current XML stream. This
depends on which kind of DITA XML file is being generated,
which is determined by the \a node type and subtype and the
- \a subpage flag. If the \subpage flag is true, a \c{<topic>}
- header is written, regardless of the type of \a node.
+ \a subpage flag.
*/
-void DitaXmlGenerator::generateHeader(const Node* node,
- const QString& name,
- bool subpage)
+void DitaXmlGenerator::generateHeader(const Node* node, const QString& name)
{
if (!node)
return;
@@ -2423,7 +2473,7 @@ void DitaXmlGenerator::generateHeader(const Node* node,
QString version;
QString outputclass;
- if (node->type() == Node::Class) {
+ if (node->isClass()) {
mainTag = DT_cxxClass;
nameTag = DT_apiName;
dtd = "dtd/cxxClass.dtd";
@@ -2432,7 +2482,7 @@ void DitaXmlGenerator::generateHeader(const Node* node,
" PUBLIC \"-//NOKIA//DTD DITA C++ API Class Reference Type v" +
version + "//EN\" \"" + dtd + "\">";
}
- else if (node->type() == Node::Namespace) {
+ else if (node->isNamespace()) {
mainTag = DT_cxxClass;
nameTag = DT_apiName;
dtd = "dtd/cxxClass.dtd";
@@ -2442,8 +2492,28 @@ void DitaXmlGenerator::generateHeader(const Node* node,
version + "//EN\" \"" + dtd + "\">";
outputclass = "namespace";
}
- else if (node->type() == Node::Document || subpage) {
- if (node->subType() == Node::HeaderFile) {
+ else if (node->isCollectionNode()) {
+ mainTag = DT_topic;
+ nameTag = DT_title;
+ dtd = "dtd/topic.dtd";
+ doctype = "<!DOCTYPE " + ditaTags[mainTag] +
+ " PUBLIC \"-//OASIS//DTD DITA Topic//EN\" \"" + dtd + "\">";
+ switch (node->type()) {
+ case Node::Group:
+ outputclass = "group";
+ break;
+ case Node::Module:
+ outputclass = "module";
+ break;
+ case Node::QmlModule:
+ outputclass = "qmlmodule";
+ break;
+ default:
+ outputclass = "page";
+ }
+ }
+ else if (node->isDocNode()) {
+ if (node->isHeaderFile()) {
mainTag = DT_cxxClass;
nameTag = DT_apiName;
dtd = "dtd/cxxClass.dtd";
@@ -2453,7 +2523,7 @@ void DitaXmlGenerator::generateHeader(const Node* node,
version + "//EN\" \"" + dtd + "\">";
outputclass = "headerfile";
}
- else if (node->subType() == Node::QmlClass) {
+ else if (node->isQmlType()) {
mainTag = DT_qmlType;
nameTag = DT_apiName;
dtd = "dtd/qmlType.dtd";
@@ -2473,9 +2543,6 @@ void DitaXmlGenerator::generateHeader(const Node* node,
case Node::Page:
outputclass = node->pageTypeString();
break;
- case Node::Group:
- outputclass = "group";
- break;
case Node::Example:
outputclass = "example";
break;
@@ -2485,9 +2552,6 @@ void DitaXmlGenerator::generateHeader(const Node* node,
case Node::Image: // not used
outputclass = "image";
break;
- case Node::Module:
- outputclass = "module";
- break;
case Node::ExternalPage: // not used
outputclass = "externalpage";
break;
@@ -2696,8 +2760,8 @@ void DitaXmlGenerator::generateClassHierarchy(const Node* relative, NodeMap& cla
NodeMap newTop;
foreach (const RelatedClass &d, child->derivedClasses()) {
- if (d.access != Node::Private && !d.node->doc().isEmpty())
- newTop.insert(d.node->name(), d.node);
+ if (d.node_ && d.access_ != Node::Private && !d.node_->doc().isEmpty())
+ newTop.insert(d.node_->name(), d.node_);
}
if (!newTop.isEmpty()) {
stack.push(newTop);
@@ -2763,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);
@@ -2985,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("::");
@@ -3106,100 +3170,57 @@ void DitaXmlGenerator::generateQmlItem(const Node* node,
*/
void DitaXmlGenerator::generateOverviewList(const Node* relative)
{
- QMap<const DocNode*, QMap<QString, DocNode*> > docNodeMap;
- QMap<QString, const DocNode*> groupTitlesMap;
- QMap<QString, DocNode*> uncategorizedNodeMap;
+ CNMap groups;
+ CNMap modules;
+ CNMap qmlModules;
QRegExp singleDigit("\\b([0-9])\\b");
- const NodeList children = qdb_->treeRoot()->childNodes();
- foreach (Node* child, children) {
- if (child->type() == Node::Document && child != relative) {
- DocNode* docNode = static_cast<DocNode*>(child);
-
- // Check whether the page is part of a group or is the group
- // definition page.
- QString group;
- bool isGroupPage = false;
- if (docNode->doc().metaCommandsUsed().contains("group")) {
- group = docNode->doc().metaCommandArgs("group")[0].first;
- isGroupPage = true;
- }
-
- // there are too many examples; they would clutter the list
- if (docNode->subType() == Node::Example)
- continue;
-
- // not interested either in individual (Qt Designer etc.) manual chapters
- if (docNode->links().contains(Node::ContentsLink))
- continue;
-
- // Discard external nodes.
- if (docNode->subType() == Node::ExternalPage)
- continue;
-
- QString sortKey = docNode->fullTitle().toLower();
- if (sortKey.startsWith("the "))
- sortKey.remove(0, 4);
- sortKey.replace(singleDigit, "0\\1");
-
- if (!group.isEmpty()) {
- if (isGroupPage) {
- // If we encounter a group definition page, we add all
- // the pages in that group to the list for that group.
- foreach (Node* member, docNode->members()) {
- if (member->isInternal() || member->type() != Node::Document)
- continue;
- DocNode* page = static_cast<DocNode*>(member);
- if (page) {
- QString sortKey = page->fullTitle().toLower();
- if (sortKey.startsWith("the "))
- sortKey.remove(0, 4);
- sortKey.replace(singleDigit, "0\\1");
- docNodeMap[const_cast<const DocNode*>(docNode)].insert(sortKey, page);
- groupTitlesMap[docNode->fullTitle()] = const_cast<const DocNode*>(docNode);
- }
- }
- }
- else if (!isGroupPage) {
- // If we encounter a page that belongs to a group then
- // we add that page to the list for that group.
- const DocNode* gn = qdb_->getGroup(group);
- if (gn && !docNode->isInternal())
- docNodeMap[gn].insert(sortKey, docNode);
- }
- }
- }
- }
-
- // We now list all the pages found that belong to groups.
- // If only certain pages were found for a group, but the definition page
- // for that group wasn't listed, the list of pages will be intentionally
- // incomplete. However, if the group definition page was listed, all the
- // pages in that group are listed for completeness.
+ qdb_->mergeCollections(Node::Group, groups, relative);
+ qdb_->mergeCollections(Node::Module, modules, relative);
+ qdb_->mergeCollections(Node::QmlModule, qmlModules, relative);
- if (!docNodeMap.isEmpty()) {
- foreach (const QString& groupTitle, groupTitlesMap.keys()) {
- const DocNode* groupNode = groupTitlesMap[groupTitle];
+ QStringList keys = groups.uniqueKeys();
+ foreach (QString key, keys) {
+ GroupNode* gn = static_cast<GroupNode*>(groups.value(key));
+ if (gn) {
writeStartTag(DT_p);
xmlWriter().writeAttribute("outputclass","h3");
writeStartTag(DT_xref);
// formathtml
- xmlWriter().writeAttribute("href",linkForNode(groupNode, relative));
- writeCharacters(protectEnc(groupNode->fullTitle()));
+ xmlWriter().writeAttribute("href",linkForNode(gn, relative));
+ writeCharacters(protectEnc(gn->fullTitle()));
writeEndTag(); // </xref>
writeEndTag(); // </p>
- if (docNodeMap[groupNode].count() == 0)
+
+ if (gn->members().isEmpty())
continue;
+ NodeMap nm;
+ foreach (Node* member, gn->members()) {
+ if (member->isInternal() || member->isExample() || member->isExternalPage() ||
+ member->isObsolete())
+ continue;
+ // not interested either in individual (Qt Designer etc.) manual chapters
+ if (member->links().contains(Node::ContentsLink))
+ continue;
+ QString sortKey = member->fullTitle().toLower();
+ if (sortKey.startsWith("the "))
+ sortKey.remove(0, 4);
+ sortKey.replace(singleDigit, "0\\1");
+ nm.insert(sortKey, member);
+ }
+
writeStartTag(DT_ul);
- foreach (const DocNode* docNode, docNodeMap[groupNode]) {
- QString title = docNode->fullTitle();
+ QStringList titles = nm.keys();
+ foreach (QString t, titles) {
+ Node* member = nm.value(t);
+ QString title = member->fullTitle();
if (title.startsWith("The "))
title.remove(0, 4);
writeStartTag(DT_li);
writeStartTag(DT_xref);
// formathtml
- xmlWriter().writeAttribute("href",linkForNode(docNode, relative));
+ xmlWriter().writeAttribute("href",linkForNode(member, relative));
writeCharacters(protectEnc(title));
writeEndTag(); // </xref>
writeEndTag(); // </li>
@@ -3207,27 +3228,6 @@ void DitaXmlGenerator::generateOverviewList(const Node* relative)
writeEndTag(); // </ul>
}
}
-
- if (!uncategorizedNodeMap.isEmpty()) {
- writeStartTag(DT_p);
- xmlWriter().writeAttribute("outputclass","h3");
- xmlWriter().writeCharacters("Miscellaneous");
- writeEndTag(); // </p>
- writeStartTag(DT_ul);
- foreach (const DocNode *docNode, uncategorizedNodeMap) {
- QString title = docNode->fullTitle();
- if (title.startsWith("The "))
- title.remove(0, 4);
- writeStartTag(DT_li);
- writeStartTag(DT_xref);
- // formathtml
- xmlWriter().writeAttribute("href",linkForNode(docNode, relative));
- writeCharacters(protectEnc(title));
- writeEndTag(); // </xref>
- writeEndTag(); // </li>
- }
- writeEndTag(); // </ul>
- }
}
/*!
@@ -3412,68 +3412,71 @@ void DitaXmlGenerator::writeText(const QString& markedCode, const Node* relative
for (int k = 0; k != 6; ++k) {
if (parseArg(src, markTags[k], &i, n, &arg, &par1)) {
const Node* n = 0;
- if (k == 0) { // <@link>
- if (!text.isEmpty()) {
- writeCharacters(text);
- text.clear();
- }
- n = CodeMarker::nodeForString(par1.toString());
- QString link = linkForNode(n, relative);
- addLink(link, arg);
- }
- else if (k == 4) { // <@param>
- if (!text.isEmpty()) {
- writeCharacters(text);
- text.clear();
- }
- writeStartTag(DT_i);
- //writeCharacters(" " + arg.toString());
- writeCharacters(arg.toString());
- writeEndTag(); // </i>
- }
- else if (k == 5) { // <@extra>
- if (!text.isEmpty()) {
- writeCharacters(text);
- text.clear();
- }
- writeStartTag(DT_tt);
- writeCharacters(arg.toString());
- writeEndTag(); // </tt>
- }
- else {
- if (!text.isEmpty()) {
- writeCharacters(text);
- text.clear();
- }
- par1 = QStringRef();
- QString link;
- n = qdb_->resolveTarget(arg.toString(), relative);
- if (n && n->subType() == Node::QmlBasicType) {
- if (relative && relative->subType() == Node::QmlClass) {
- link = linkForNode(n,relative);
- addLink(link, arg);
+ switch (k) {
+ case 0: // <@link>
+ if (!text.isEmpty()) {
+ writeCharacters(text);
+ text.clear();
}
- else {
- writeCharacters(arg.toString());
+ n = CodeMarker::nodeForString(par1.toString());
+ addLink(linkForNode(n, relative), arg);
+ break;
+ case 4: // <@param>
+ if (!text.isEmpty()) {
+ writeCharacters(text);
+ text.clear();
}
- }
- else {
- // (zzz) Is this correct for all cases?
- link = linkForNode(n,relative);
- addLink(link, arg);
- }
- }
+ writeStartTag(DT_i);
+ //writeCharacters(" " + arg.toString());
+ writeCharacters(arg.toString());
+ writeEndTag(); // </i>
+ break;
+ case 5: // <@extra>
+ if (!text.isEmpty()) {
+ writeCharacters(text);
+ text.clear();
+ }
+ writeStartTag(DT_tt);
+ writeCharacters(arg.toString());
+ writeEndTag(); // </tt>
+ break;
+ case 3:
+ if (!text.isEmpty()) {
+ writeCharacters(text);
+ text.clear();
+ }
+ par1 = QStringRef();
+ n = qdb_->resolveFunctionTarget(arg.toString(), relative);
+ addLink(linkForNode(n, relative), arg);
+ break;
+ case 1:
+ case 2:
+ default:
+ if (!text.isEmpty()) {
+ writeCharacters(text);
+ text.clear();
+ }
+ par1 = QStringRef();
+ n = qdb_->resolveType(arg.toString(), relative);
+ if (n && n->isQmlBasicType()) {
+ if (relative && relative->isQmlType())
+ addLink(linkForNode(n, relative), arg);
+ else
+ writeCharacters(arg.toString());
+ }
+ else
+ addLink(linkForNode(n, relative), arg); // (zzz) Is this correct for all cases?
+ break;
+ } // switch
break;
}
}
}
- else {
+ else
text += src.at(i++);
- }
}
- if (!text.isEmpty()) {
+ if (!text.isEmpty())
writeCharacters(text);
- }
}
void DitaXmlGenerator::generateLink(const Atom* atom, CodeMarker* marker)
@@ -3703,13 +3706,12 @@ QString DitaXmlGenerator::guidForNode(const Node* node)
/*!
Constructs a file name appropriate for the \a node and returns
- it. If the \a node is not a fake node, or if it is a fake node but
- it is neither an external page node nor an image node or a ditamap,
- call the Generator::fileName() function.
+ it. If the \a node is not a not an external page, an image, or
+ a ditamap, call fileName() in the base class, Generator.
*/
QString DitaXmlGenerator::fileName(const Node* node)
{
- if (node->type() == Node::Document) {
+ if (node->isDocNode()) {
if (static_cast<const DocNode*>(node)->pageType() == Node::DitaMapPage)
return node->name();
if (static_cast<const DocNode*>(node)->subType() == Node::ExternalPage)
@@ -3733,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
@@ -3796,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:
@@ -3854,18 +3857,18 @@ QString DitaXmlGenerator::getLink(const Atom* atom, const Node* relative, const
QString ref;
QString first = path.first().trimmed();
- if (first.isEmpty()) {
+ if (first.isEmpty())
*node = relative;
- }
- else if (first.endsWith(".html")) {
- *node = qdb_->treeRoot()->findChildNodeByNameAndType(first, Node::Document);
- }
+ else if (first.endsWith(".html"))
+ *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 {
*node = qdb_->resolveTarget(first, relative);
+ if (!(*node))
+ *node = qdb_->findDocNodeByTitle(first);
if (!*node)
- *node = qdb_->findDocNodeByTitle(first, relative);
- if (!*node)
- *node = qdb_->findUnambiguousTarget(first, ref, relative);
+ *node = qdb_->findUnambiguousTarget(first, ref);
}
if (*node) {
@@ -3881,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;
@@ -4050,7 +4053,7 @@ void DitaXmlGenerator::startQmlProperty(QmlPropertyNode* qpn,
writeStartTag(DT_qmlPropertyDetail);
writeStartTag(DT_qmlPropertyDef);
if (!qpn->isReadOnlySet())
- qpn->setReadOnly(!qpn->isWritable(qdb_));
+ qpn->setReadOnly(!qpn->isWritable());
if (qpn->isReadOnly()) {
writeStartTag(DT_qmlQualifier);
xmlWriter().writeAttribute("name","read-only");
@@ -4187,11 +4190,11 @@ void DitaXmlGenerator::generateQmlModuleDef(QmlClassNode* qcn)
Output the "Inherits" line for the QML element,
if there should be one.
*/
-void DitaXmlGenerator::generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker)
+void DitaXmlGenerator::generateQmlInherits(QmlClassNode* qcn, CodeMarker* marker)
{
if (!qcn)
return;
- const QmlClassNode* base = qcn->qmlBaseNode();
+ QmlClassNode* base = qcn->qmlBaseNode();
while (base && base->isInternal()) {
base = base->qmlBaseNode();
}
@@ -4365,25 +4368,27 @@ void DitaXmlGenerator::writeDerivations(const ClassNode* cn)
writeStartTag(DT_cxxClassDerivations);
r = cn->baseClasses().constBegin();
while (r != cn->baseClasses().constEnd()) {
- writeStartTag(DT_cxxClassDerivation);
- writeStartTag(DT_cxxClassDerivationAccessSpecifier);
- xmlWriter().writeAttribute("value",(*r).accessString());
- writeEndTag(); // </cxxClassDerivationAccessSpecifier>
+ ClassNode* bcn = (*r).node_;
+ if (bcn) {
+ writeStartTag(DT_cxxClassDerivation);
+ writeStartTag(DT_cxxClassDerivationAccessSpecifier);
+ xmlWriter().writeAttribute("value",(*r).accessString());
+ writeEndTag(); // </cxxClassDerivationAccessSpecifier>
- // not included: <cxxClassDerivationVirtual>
+ // not included: <cxxClassDerivationVirtual>
- writeStartTag(DT_cxxClassBaseClass);
- QString attr = fileName((*r).node) + QLatin1Char('#') + (*r).node->guid();
- xmlWriter().writeAttribute("href",attr);
- writeCharacters((*r).node->plainFullName());
- writeEndTag(); // </cxxClassBaseClass>
+ writeStartTag(DT_cxxClassBaseClass);
+ QString attr = fileName(bcn) + QLatin1Char('#') + bcn->guid();
+ xmlWriter().writeAttribute("href",attr);
+ writeCharacters(bcn->plainFullName());
+ writeEndTag(); // </cxxClassBaseClass>
- // not included: <ClassBaseStruct> or <cxxClassBaseUnion>
+ // not included: <ClassBaseStruct> or <cxxClassBaseUnion>
- writeEndTag(); // </cxxClassDerivation>
-
- // not included: <cxxStructDerivation>
+ writeEndTag(); // </cxxClassDerivation>
+ // not included: <cxxStructDerivation>
+ }
++r;
}
writeEndTag(); // </cxxClassDerivations>
@@ -4623,10 +4628,10 @@ void DitaXmlGenerator::replaceTypesWithLinks(const Node* n, const InnerNode* par
}
i += 2;
if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
- const Node* tn = qdb_->resolveTarget(arg.toString(), parent, n);
+ 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);
@@ -4781,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;
}
@@ -5287,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;
@@ -5298,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;
/*
@@ -5311,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();
}
@@ -5397,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)
@@ -5420,6 +5421,26 @@ 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);
+ break;
+ case Node::Module:
+ if (!isDuplicate(nodeTypeMaps[Node::Module],child->title(),child))
+ nodeTypeMaps[Node::Module]->insert(child->title(),child);
+ break;
+ case Node::QmlModule:
+ if (!isDuplicate(nodeTypeMaps[Node::QmlModule],child->title(),child))
+ nodeTypeMaps[Node::QmlModule]->insert(child->title(),child);
+ break;
case Node::Document:
switch (child->subType()) {
case Node::Example:
@@ -5434,14 +5455,6 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
break;
case Node::Image:
break;
- case Node::Group:
- if (!isDuplicate(nodeSubtypeMaps[Node::Group],child->title(),child))
- nodeSubtypeMaps[Node::Group]->insert(child->title(),child);
- break;
- case Node::Module:
- if (!isDuplicate(nodeSubtypeMaps[Node::Module],child->title(),child))
- nodeSubtypeMaps[Node::Module]->insert(child->title(),child);
- break;
case Node::Page:
if (!isDuplicate(pageTypeMaps[child->pageType()],child->title(),child))
pageTypeMaps[child->pageType()]->insert(child->title(),child);
@@ -5450,18 +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::QmlModule:
- if (!isDuplicate(nodeSubtypeMaps[Node::QmlModule],child->title(),child))
- nodeSubtypeMaps[Node::QmlModule]->insert(child->title(),child);
- break;
case Node::Collision:
if (!isDuplicate(nodeSubtypeMaps[Node::Collision],child->title(),child))
nodeSubtypeMaps[Node::Collision]->insert(child->title(),child);
@@ -5509,7 +5510,7 @@ void DitaXmlGenerator::writeDitaMap()
Remove #if 0 to get a flat ditamap.
*/
#if 0
- beginSubPage(qdb_->treeRoot(),"qt.ditamap");
+ beginSubPage(qdb_->primaryTreeRoot(),"qt.ditamap");
doctype = "<!DOCTYPE map PUBLIC \"-//OASIS//DTD DITA Map//EN\" \"map.dtd\">";
xmlWriter().writeDTD(doctype);
writeStartTag(DT_map);
@@ -5535,9 +5536,9 @@ void DitaXmlGenerator::writeDitaMap()
nodeSubtypeMaps[i] = new NodeMultiMap;
for (unsigned i=0; i<Node::OnBeyondZebra; ++i)
pageTypeMaps[i] = new NodeMultiMap;
- Node* rootPageNode = collectNodesByTypeAndSubtype(qdb_->treeRoot());
+ Node* rootPageNode = collectNodesByTypeAndSubtype(qdb_->primaryTreeRoot());
- beginSubPage(qdb_->treeRoot(),"qt.ditamap");
+ beginSubPage(qdb_->primaryTreeRoot(),"qt.ditamap");
doctype = "<!DOCTYPE map PUBLIC \"-//OASIS//DTD DITA Map//EN\" \"map.dtd\">";
xmlWriter().writeDTD(doctype);
@@ -5565,22 +5566,26 @@ void DitaXmlGenerator::writeDitaMap()
writeTopicrefs(pageTypeMaps[Node::FAQPage], "FAQs");
writeTopicrefs(pageTypeMaps[Node::ArticlePage], "Articles");
writeTopicrefs(nodeSubtypeMaps[Node::Example], "Examples");
- if (nodeSubtypeMaps[Node::QmlModule]->size() > 1)
- writeTopicrefs(nodeSubtypeMaps[Node::QmlModule], "QML modules");
- if (nodeSubtypeMaps[Node::QmlModule]->size() == 1)
- writeTopicrefs(nodeSubtypeMaps[Node::QmlClass], "QML types", nodeSubtypeMaps[Node::QmlModule]->values()[0]);
+
+ if (nodeTypeMaps[Node::QmlModule]->size() > 1)
+ writeTopicrefs(nodeTypeMaps[Node::QmlModule], "QML modules");
+
+ if (nodeTypeMaps[Node::QmlModule]->size() == 1)
+ 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");
- if (nodeSubtypeMaps[Node::Module]->size() > 1)
- writeTopicrefs(nodeSubtypeMaps[Node::Module], "Modules");
- if (nodeSubtypeMaps[Node::Module]->size() == 1)
- writeTopicrefs(nodeTypeMaps[Node::Class], "C++ classes", nodeSubtypeMaps[Node::Module]->values()[0]);
+ writeTopicrefs(nodeTypeMaps[Node::QmlType], "QML types");
+ writeTopicrefs(nodeTypeMaps[Node::QmlBasicType], "QML basic types");
+
+ if (nodeTypeMaps[Node::Module]->size() > 1)
+ writeTopicrefs(nodeTypeMaps[Node::Module], "Modules");
+
+ if (nodeTypeMaps[Node::Module]->size() == 1)
+ writeTopicrefs(nodeTypeMaps[Node::Class], "C++ classes", nodeTypeMaps[Node::Module]->values()[0]);
else
writeTopicrefs(nodeTypeMaps[Node::Class], "C++ classes");
writeTopicrefs(nodeTypeMaps[Node::Namespace], "C++ namespaces");
writeTopicrefs(nodeSubtypeMaps[Node::HeaderFile], "Header files");
- writeTopicrefs(nodeSubtypeMaps[Node::Group], "Groups");
+ writeTopicrefs(nodeTypeMaps[Node::Group], "Groups");
writeEndTag(); // </topicref>
endSubPage();
@@ -5925,30 +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::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->isModule())
+ category = "Module";
+ else if (inner->isQmlModule())
+ category = "QML Module";
+ else if (inner->isGroup())
+ category = "Group";
+ else if (inner->isDocNode()) {
+ if (inner->isHeaderFile())
category = "Header File";
- else if (inner->subType() == Node::Module)
- category = "Module";
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::Group)
- category = "Group";
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);
@@ -5990,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;
@@ -6096,7 +6102,6 @@ void DitaXmlGenerator::generateCollisionPages()
if (collisions.size() <= 1)
continue;
- ncn->clearCurrentChild();
beginSubPage(ncn, Generator::fileName(ncn));
QString fullTitle = ncn->fullTitle();
QString ditaTitle = fullTitle;
@@ -6130,7 +6135,7 @@ void DitaXmlGenerator::generateCollisionPages()
int count = 0;
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- if (n->findChildNodeByName(t.key())) {
+ if (n->findChildNode(t.key())) {
++count;
if (count > 1) {
targets.append(t.key());
@@ -6152,7 +6157,7 @@ void DitaXmlGenerator::generateCollisionPages()
writeStartTag(DT_ul);
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- Node* p = n->findChildNodeByName(*t);
+ Node* p = n->findChildNode(*t);
if (p) {
QString link = linkForNode(p,0);
QString label;
diff --git a/src/tools/qdoc/ditaxmlgenerator.h b/src/tools/qdoc/ditaxmlgenerator.h
index da05bb0274..0239151402 100644
--- a/src/tools/qdoc/ditaxmlgenerator.h
+++ b/src/tools/qdoc/ditaxmlgenerator.h
@@ -302,7 +302,7 @@ public:
virtual void terminateGenerator();
virtual QString format();
virtual bool canHandleFormat(const QString& format);
- virtual void generateTree();
+ virtual void generateDocs();
void generateCollisionPages();
QString protectEnc(const QString& string);
@@ -315,7 +315,9 @@ 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;
virtual QString guidForNode(const Node* node);
virtual QString linkForNode(const Node* node, const Node* relative);
@@ -349,7 +351,7 @@ protected:
CodeMarker* marker,
const QString& attribute = QString());
void writePropertyParameter(const QString& tag, const NodeList& nlist);
- void writeRelatedLinks(const DocNode* dn);
+ void writeRelatedLinks(const Node* dn);
void writeLink(const Node* node, const QString& tex, const QString& role);
void writeProlog(const InnerNode* inner);
bool writeMetadataElement(const InnerNode* inner,
@@ -364,9 +366,7 @@ private:
enum SubTitleSize { SmallSubTitle, LargeSubTitle };
const QPair<QString,QString> anchorForNode(const Node* node);
- void generateHeader(const Node* node,
- const QString& name,
- bool subpage = false);
+ void generateHeader(const Node* node, const QString& name);
void generateBrief(const Node* node, CodeMarker* marker);
void generateTableOfContents(const Node* node,
CodeMarker* marker,
@@ -403,7 +403,7 @@ private:
void generateDetailedQmlMember(Node* node,
const InnerNode* relative,
CodeMarker* marker);
- void generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker);
+ void generateQmlInherits(QmlClassNode* qcn, CodeMarker* marker);
void generateQmlInheritedBy(const QmlClassNode* qcn, CodeMarker* marker);
void generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker);
void generateInstantiatedBy(ClassNode* cn, CodeMarker* marker);
diff --git a/src/tools/qdoc/doc.cpp b/src/tools/qdoc/doc.cpp
index 6e70671d1d..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
@@ -316,17 +316,17 @@ Q_GLOBAL_STATIC(QHash_QString_Macro, macroHash)
class DocPrivateExtra
{
public:
- Doc::Sections granularity;
- Doc::Sections section; // ###
- QList<Atom*> tableOfContents;
- QList<int> tableOfContentsLevels;
- QList<Atom*> keywords;
- QList<Atom*> targets;
- QStringMultiMap metaMap;
+ Doc::Sections granularity_;
+ Doc::Sections section_; // ###
+ QList<Atom*> tableOfContents_;
+ QList<int> tableOfContentsLevels_;
+ QList<Atom*> keywords_;
+ QList<Atom*> targets_;
+ QStringMultiMap metaMap_;
DocPrivateExtra()
- : granularity(Doc::Part)
- , section(Doc::NoSection)
+ : granularity_(Doc::Part)
+ , section_(Doc::NoSection)
{ }
};
@@ -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();
@@ -535,7 +538,7 @@ private:
int braceDepth;
int minIndent;
Doc::Sections currentSection;
- QMap<QString, Location> targetMap;
+ QMap<QString, Location> targetMap_;
QMap<int, QString> pendingFormats;
QStack<int> openedCommands;
QStack<OpenedList> openedLists;
@@ -876,11 +879,17 @@ void DocParser::parse(const QString& source,
append(Atom::SinceList, getRestOfLine().simplified());
break;
case CMD_GENERATELIST:
- append(Atom::GeneratedList, getArgument());
+ {
+ QString arg1 = getArgument();
+ QString arg2 = getOptionalArgument();
+ if (!arg2.isEmpty())
+ arg1 += " " + arg2;
+ append(Atom::GeneratedList, arg1);
+ }
break;
case CMD_GRANULARITY:
priv->constructExtra();
- priv->extra->granularity = getSectioningUnit();
+ priv->extra->granularity_ = getSectioningUnit();
break;
case CMD_HEADER:
if (openedCommands.top() == CMD_TABLE) {
@@ -959,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);
@@ -974,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);
@@ -1025,7 +1036,7 @@ void DocParser::parse(const QString& source,
case CMD_META:
priv->constructExtra();
p1 = getArgument();
- priv->extra->metaMap.insert(p1, getArgument());
+ priv->extra->metaMap_.insert(p1, getArgument());
break;
case CMD_NEWCODE:
location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_NEWCODE)));
@@ -1626,8 +1637,8 @@ void DocParser::parse(const QString& source,
currentSection = Doc::NoSection;
}
- if (priv->extra && priv->extra->granularity < priv->extra->section)
- priv->extra->granularity = priv->extra->section;
+ if (priv->extra && priv->extra->granularity_ < priv->extra->section_)
+ priv->extra->granularity_ = priv->extra->section_;
priv->text.stripFirstAtom();
}
@@ -1668,18 +1679,18 @@ QString DocParser::detailsUnknownCommand(const QSet<QString> &metaCommandSet,
void DocParser::insertTarget(const QString &target, bool keyword)
{
- if (targetMap.contains(target)) {
+ if (targetMap_.contains(target)) {
location().warning(tr("Duplicate target name '%1'").arg(target));
- targetMap[target].warning(tr("(The previous occurrence is here)"));
+ targetMap_[target].warning(tr("(The previous occurrence is here)"));
}
else {
- targetMap.insert(target, location());
+ targetMap_.insert(target, location());
append(Atom::Target, target);
priv->constructExtra();
if (keyword)
- priv->extra->keywords.append(priv->text.lastAtom());
+ priv->extra->keywords_.append(priv->text.lastAtom());
else
- priv->extra->targets.append(priv->text.lastAtom());
+ priv->extra->targets_.append(priv->text.lastAtom());
}
}
@@ -1883,15 +1894,15 @@ void DocParser::startSection(Doc::Sections unit, int cmd)
if (currentSection == Doc::NoSection) {
currentSection = (Doc::Sections) (unit);
priv->constructExtra();
- priv->extra->section = currentSection;
+ priv->extra->section_ = currentSection;
}
else
endSection(unit,cmd);
append(Atom::SectionLeft, QString::number(unit));
priv->constructExtra();
- priv->extra->tableOfContents.append(priv->text.lastAtom());
- priv->extra->tableOfContentsLevels.append(unit);
+ priv->extra->tableOfContents_.append(priv->text.lastAtom());
+ priv->extra->tableOfContentsLevels_.append(unit);
enterPara(Atom::SectionHeadingLeft,
Atom::SectionHeadingRight,
QString::number(unit));
@@ -1978,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)
@@ -2239,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)
{
@@ -2373,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();
@@ -2521,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.
*/
@@ -2958,10 +3035,10 @@ Text Doc::legaleseText() const
Doc::Sections Doc::granularity() const
{
if (priv == 0 || priv->extra == 0) {
- return DocPrivateExtra().granularity;
+ return DocPrivateExtra().granularity_;
}
else {
- return priv->extra->granularity;
+ return priv->extra->granularity_;
}
}
@@ -3007,46 +3084,46 @@ const QList<Text> &Doc::alsoList() const
bool Doc::hasTableOfContents() const
{
- return priv && priv->extra && !priv->extra->tableOfContents.isEmpty();
+ return priv && priv->extra && !priv->extra->tableOfContents_.isEmpty();
}
bool Doc::hasKeywords() const
{
- return priv && priv->extra && !priv->extra->keywords.isEmpty();
+ return priv && priv->extra && !priv->extra->keywords_.isEmpty();
}
bool Doc::hasTargets() const
{
- return priv && priv->extra && !priv->extra->targets.isEmpty();
+ return priv && priv->extra && !priv->extra->targets_.isEmpty();
}
const QList<Atom *> &Doc::tableOfContents() const
{
priv->constructExtra();
- return priv->extra->tableOfContents;
+ return priv->extra->tableOfContents_;
}
const QList<int> &Doc::tableOfContentsLevels() const
{
priv->constructExtra();
- return priv->extra->tableOfContentsLevels;
+ return priv->extra->tableOfContentsLevels_;
}
const QList<Atom *> &Doc::keywords() const
{
priv->constructExtra();
- return priv->extra->keywords;
+ return priv->extra->keywords_;
}
const QList<Atom *> &Doc::targets() const
{
priv->constructExtra();
- return priv->extra->targets;
+ return priv->extra->targets_;
}
const QStringMultiMap &Doc::metaTagMap() const
{
- return priv && priv->extra ? priv->extra->metaMap : *null_QStringMultiMap();
+ return priv && priv->extra ? priv->extra->metaMap_ : *null_QStringMultiMap();
}
const Config* Doc::config_ = 0;
@@ -3054,10 +3131,10 @@ const Config* Doc::config_ = 0;
void Doc::initialize(const Config& config)
{
DocParser::tabSize = config.getInt(CONFIG_TABSIZE);
- DocParser::exampleFiles = config.getCleanPathList(CONFIG_EXAMPLES);
- DocParser::exampleDirs = config.getCleanPathList(CONFIG_EXAMPLEDIRS);
- DocParser::sourceFiles = config.getCleanPathList(CONFIG_SOURCES);
- DocParser::sourceDirs = config.getCleanPathList(CONFIG_SOURCEDIRS);
+ DocParser::exampleFiles = config.getCanonicalPathList(CONFIG_EXAMPLES);
+ DocParser::exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS);
+ DocParser::sourceFiles = config.getCanonicalPathList(CONFIG_SOURCES);
+ DocParser::sourceDirs = config.getCanonicalPathList(CONFIG_SOURCEDIRS);
DocParser::quoting = config.getBool(CONFIG_QUOTINGINFORMATION);
QmlClassNode::qmlOnly = config.getBool(CONFIG_QMLONLY);
diff --git a/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc b/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc
index fe43938968..435e243014 100644
--- a/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc
+++ b/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc
@@ -3251,9 +3251,9 @@
\target generatelist-command
\section1 \\generatelist
- The \\generatelist command expands to a list of various
- documentation or links to documentation. Below is an example from
- the Qt Reference Documentation:
+ The \\generatelist command expands to a list of links to the
+ documentation entities in a group. Below is an example from the Qt
+ Reference Documentation:
\code
/ *!
@@ -3263,7 +3263,7 @@
For a shorter list that only includes the most
frequently used classes, see \l{Qt's Main Classes}.
- \generatelist classes
+ \generatelist classes Q
* /
\endcode
@@ -3295,10 +3295,17 @@
of the class comment's \l {brief-command} {\\brief} command.
\target list example
- \section2 \c classes
+ \section2 \c {classes <prefix>}
The \c classes argument provides a complete alphabetical list of
- the classes. Each class name is a link to the class's reference
+ the classes. The second argument, \c{<prefix>}, is the common
+ prefix for the class names. The class names will be sorted on the
+ character that follows the common prefix. e.g. The common prefix
+ for the Qt classes is \c Q. The common prefix argument is
+ optional. If no common prefix is provided, the class names will
+ be sorted on their first character.
+
+ Each class name becomes a link to the class's reference
documentation. This command is used to generate the
\e {All Classes} page this way:
@@ -3315,7 +3322,7 @@
Classes}. For classes that have been deprecated, see the
\l{Obsolete Classes} list.
- \generatelist classes
+ \generatelist classes Q
* /
\endcode
diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp
index 9b82e80927..6bba83efdb 100644
--- a/src/tools/qdoc/generator.cpp
+++ b/src/tools/qdoc/generator.cpp
@@ -97,26 +97,30 @@ QStringList Generator::styleDirs;
QStringList Generator::styleFiles;
bool Generator::debugging_ = false;
bool Generator::noLinkErrors_ = false;
+bool Generator::autolinkErrors_ = false;
bool Generator::redirectDocumentationToDevNull_ = false;
Generator::Passes Generator::qdocPass_ = Both;
bool Generator::useOutputSubdirs_ = true;
-void Generator::setDebugSegfaultFlag(bool b)
+void Generator::startDebugging(const QString& message)
{
- if (b)
- qDebug() << "DEBUG: Setting debug flag.";
- else
- qDebug() << "DEBUG: Clearing debug flag.";
- debugging_ = b;
+ debugging_ = true;
+ qDebug() << "START DEBUGGING:" << message;
+}
+
+void Generator::stopDebugging(const QString& message)
+{
+ debugging_ = false;
+ qDebug() << "STOP DEBUGGING:" << message;
}
/*!
Prints \a message as an aid to debugging the release version.
*/
-void Generator::debugSegfault(const QString& message)
+void Generator::debug(const QString& message)
{
if (debugging())
- qDebug() << "DEBUG:" << message;
+ qDebug() << " DEBUG:" << message;
}
/*!
@@ -189,19 +193,20 @@ void Generator::appendFullNames(Text& text, const NodeList& nodes, const Node* r
}
}
-void Generator::appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes)
+void Generator::appendSortedNames(Text& text, const ClassNode* cn, const QList<RelatedClass>& rc)
{
QList<RelatedClass>::ConstIterator r;
QMap<QString,Text> classMap;
int index = 0;
- r = classes.constBegin();
- while (r != classes.constEnd()) {
- if ((*r).node->access() == Node::Public &&
- (*r).node->status() != Node::Internal
- && !(*r).node->doc().isEmpty()) {
+ r = rc.constBegin();
+ while (r != rc.constEnd()) {
+ ClassNode* rcn = (*r).node_;
+ if (rcn && rcn->access() == Node::Public &&
+ rcn->status() != Node::Internal &&
+ !rcn->doc().isEmpty()) {
Text className;
- appendFullName(className, (*r).node, classe);
+ appendFullName(className, rcn, cn);
classMap[className.toString().toLower()] = className;
}
++r;
@@ -274,7 +279,7 @@ void Generator::beginSubPage(const InnerNode* node, const QString& fileName)
node->location().error(tr("HTML file already exists; overwriting %1").arg(outFile->fileName()));
if (!outFile->open(QFile::WriteOnly))
node->location().fatal(tr("Cannot open output file '%1'").arg(outFile->fileName()));
- Generator::debugSegfault("Writing: " + path);
+ Generator::debug("Writing: " + path);
outFileNames.insert(fileName,fileName);
QTextStream* out = new QTextStream(outFile);
@@ -308,47 +313,18 @@ QString Generator::fileBase(const Node *node) const
node = node->parent();
}
- if (node->type() == Node::Document && node->subType() == Node::Collision) {
- const NameCollisionNode* ncn = static_cast<const NameCollisionNode*>(node);
- if (ncn->currentChild())
- return fileBase(ncn->currentChild());
- }
-
- if (node->hasBaseName())
- return node->baseName();
+ if (node->hasFileNameBase())
+ return node->fileNameBase();
QString base;
- if (node->type() == Node::Document) {
+ if (node->isDocNode()) {
base = node->name();
- if (node->subType() == Node::Collision) {
- const NameCollisionNode* ncn = static_cast<const NameCollisionNode*>(node);
- if (ncn->currentChild())
- return fileBase(ncn->currentChild());
+ if (node->subType() == Node::Collision)
base.prepend("collision-");
- }
//Was QDOC2_COMPAT, required for index.html
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")));
- }
- }
- else if (node->subType() == Node::QmlModule) {
- base.append("-qmlmodule");
- }
- else if (node->subType() == Node::Module) {
- base.append("-module");
- }
if (node->isExample() || node->isExampleFile()) {
QString modPrefix(node->moduleName());
if (modPrefix.isEmpty()) {
@@ -360,12 +336,37 @@ 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"))
+ base.truncate(base.length() - 5);
+
+ if (node->isQmlModule()) {
+ base.append("-qmlmodule");
+ }
+ else if (node->isModule()) {
+ base.append("-module");
+ }
+ // Why not add "-group" for gropup pages?
+ }
else {
const Node *p = node;
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;
@@ -401,7 +402,7 @@ QString Generator::fileBase(const Node *node) const
while (res.endsWith(QLatin1Char('-')))
res.chop(1);
Node* n = const_cast<Node*>(node);
- n->setBaseName(res);
+ n->setFileNameBase(res);
return res;
}
@@ -455,7 +456,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
if (!fdl.isEmpty())
fdl.append(QLatin1Char('/'));
}
- if (node->type() == Node::Namespace) {
+ if (node->isNamespace()) {
// The root namespace has no name - check for this before creating
// an attribute containing the location of any documentation.
@@ -465,26 +466,23 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir)
else
return QString();
}
- else if (node->type() == Node::Document) {
- if ((node->subType() == Node::QmlClass) ||
- (node->subType() == Node::QmlBasicType)) {
- 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();
@@ -561,7 +559,11 @@ 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:
+ case Node::QmlModule:
{
parentName = fileBase(node);
parentName.replace(QLatin1Char('/'), QLatin1Char('-')).replace(QLatin1Char('.'), QLatin1Char('-'));
@@ -573,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(),
@@ -678,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;
@@ -808,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) {
@@ -841,6 +848,10 @@ void Generator::generateDocNode(DocNode* /* dn */, CodeMarker* /* marker */)
{
}
+void Generator::generateCollectionNode(CollectionNode* , CodeMarker* )
+{
+}
+
/*!
This function is called when the documentation for an
example is being formatted. It outputs the list of source
@@ -936,18 +947,20 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker)
r = classe->baseClasses().constBegin();
index = 0;
while (r != classe->baseClasses().constEnd()) {
- text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node))
- << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, (*r).dataTypeWithTemplateArgs)
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
-
- if ((*r).access == Node::Protected) {
- text << " (protected)";
- }
- else if ((*r).access == Node::Private) {
- text << " (private)";
+ if ((*r).node_) {
+ text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node_))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, (*r).signature_)
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+
+ if ((*r).access_ == Node::Protected) {
+ text << " (protected)";
+ }
+ else if ((*r).access_ == Node::Private) {
+ text << " (private)";
+ }
+ text << separator(index++, classe->baseClasses().count());
}
- text << separator(index++, classe->baseClasses().count());
++r;
}
text << Atom::ParaRight;
@@ -958,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.
@@ -971,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;
@@ -982,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;
/*
@@ -996,19 +1012,61 @@ void Generator::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 {
- beginSubPage(node, fileName(node));
- if (node->type() == Node::Namespace || node->type() == Node::Class) {
+ if (node->isNamespace() || node->isClass()) {
+ beginSubPage(node, fileName(node));
generateClassLikeNode(node, marker);
+ endSubPage();
}
- else if (node->type() == Node::Document) {
+ 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);
+ /*
+ A collection node is one of: group, module,
+ or QML module.
+
+ Don't output an HTML page for the collection
+ node unless the \group, \module, or \qmlmodule
+ command was actually seen by qdoc in the qdoc
+ comment for the node.
+
+ A key prerequisite in this case is the call to
+ mergeCollections(cn). We don't know if this
+ collection (group, module, or QML module) has
+ members in other modules. We know at this point
+ that cn's members list contains only members in
+ the current module. Therefore, before outputting
+ the page for cn, we must search for members of
+ cn in the other modules and add them to the
+ members list.
+ */
+ if (cn->wasSeen()) {
+ qdb_->mergeCollections(cn);
+ beginSubPage(node, fileName(node));
+ generateCollectionNode(cn, marker);
+ endSubPage();
+ }
}
- endSubPage();
}
}
@@ -1066,7 +1124,7 @@ void Generator::generateQmlInheritedBy(const QmlClassNode* qcn,
/*!
*/
-void Generator::generateQmlInherits(const QmlClassNode* , CodeMarker* )
+void Generator::generateQmlInherits(QmlClassNode* , CodeMarker* )
{
// stub.
}
@@ -1203,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)
@@ -1362,11 +1425,11 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker)
}
/*!
- Traverses the database recursivly to generate all the documentation.
+ Traverses the current tree to generate all the documentation.
*/
-void Generator::generateTree()
+void Generator::generateDocs()
{
- generateInnerNode(qdb_->treeRoot());
+ generateInnerNode(qdb_->primaryTreeRoot());
}
Generator *Generator::generatorForFormat(const QString& format)
@@ -1380,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
@@ -1412,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
@@ -1546,13 +1616,13 @@ void Generator::initialize(const Config &config)
config.lastLocation().fatal(tr("Cannot create style directory '%1'").arg(outDir_ + "/style"));
}
- imageFiles = config.getCleanPathList(CONFIG_IMAGES);
- imageDirs = config.getCleanPathList(CONFIG_IMAGEDIRS);
- scriptFiles = config.getCleanPathList(CONFIG_SCRIPTS);
- scriptDirs = config.getCleanPathList(CONFIG_SCRIPTDIRS);
- styleFiles = config.getCleanPathList(CONFIG_STYLES);
- styleDirs = config.getCleanPathList(CONFIG_STYLEDIRS);
- exampleDirs = config.getCleanPathList(CONFIG_EXAMPLEDIRS);
+ imageFiles = config.getCanonicalPathList(CONFIG_IMAGES);
+ imageDirs = config.getCanonicalPathList(CONFIG_IMAGEDIRS);
+ scriptFiles = config.getCanonicalPathList(CONFIG_SCRIPTS);
+ scriptDirs = config.getCanonicalPathList(CONFIG_SCRIPTDIRS);
+ styleFiles = config.getCanonicalPathList(CONFIG_STYLES);
+ styleDirs = config.getCanonicalPathList(CONFIG_STYLEDIRS);
+ exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS);
exampleImgExts = config.getStringList(CONFIG_EXAMPLES + Config::dot + CONFIG_IMAGEEXTENSIONS);
QString imagesDotFileExtensions = CONFIG_IMAGES + Config::dot + CONFIG_FILEEXTENSIONS;
@@ -1568,9 +1638,9 @@ void Generator::initialize(const Config &config)
if (outputFormats.contains((*g)->format())) {
currentGenerator_ = (*g);
(*g)->initializeGenerator(config);
- QStringList extraImages = config.getPathList((*g)->format() +
+ QStringList extraImages = config.getCanonicalPathList((*g)->format() +
Config::dot +
- CONFIG_EXTRAIMAGES);
+ CONFIG_EXTRAIMAGES, true);
QStringList::ConstIterator e = extraImages.constBegin();
while (e != extraImages.constEnd()) {
QString filePath = *e;
@@ -1581,7 +1651,7 @@ void Generator::initialize(const Config &config)
}
// Documentation template handling
- QStringList scripts = config.getPathList((*g)->format()+Config::dot+CONFIG_SCRIPTS);
+ QStringList scripts = config.getCanonicalPathList((*g)->format()+Config::dot+CONFIG_SCRIPTS, true);
e = scripts.constBegin();
while (e != scripts.constEnd()) {
QString filePath = *e;
@@ -1591,7 +1661,7 @@ void Generator::initialize(const Config &config)
++e;
}
- QStringList styles = config.getPathList((*g)->format()+Config::dot+CONFIG_STYLESHEETS);
+ QStringList styles = config.getCanonicalPathList((*g)->format()+Config::dot+CONFIG_STYLESHEETS, true);
e = styles.constBegin();
while (e != styles.constEnd()) {
QString filePath = *e;
@@ -1650,6 +1720,7 @@ void Generator::initialize(const Config &config)
else
outputPrefixes[QLatin1String("QML")] = QLatin1String("qml-");
noLinkErrors_ = config.getBool(CONFIG_NOLINKERRORS);
+ autolinkErrors_ = config.getBool(CONFIG_AUTOLINKERRORS);
}
/*!
@@ -1916,7 +1987,6 @@ void Generator::terminate()
imageDirs.clear();
outDir_.clear();
QmlClassNode::terminate();
- ExampleNode::terminate();
}
void Generator::terminateGenerator()
@@ -1942,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 b464014308..81b63ef29a 100644
--- a/src/tools/qdoc/generator.h
+++ b/src/tools/qdoc/generator.h
@@ -77,7 +77,7 @@ public:
virtual bool canHandleFormat(const QString &format) { return format == this->format(); }
virtual QString format() = 0;
- virtual void generateTree();
+ virtual void generateDocs();
virtual void initializeGenerator(const Config &config);
virtual void terminateGenerator();
@@ -92,10 +92,12 @@ public:
static void terminate();
static void writeOutFileNames();
static void augmentImageDirs(QSet<QString>& moreImageDirs);
- static void debugSegfault(const QString& message);
- static void setDebugSegfaultFlag(bool b);
+ static void debug(const QString& message);
+ static void startDebugging(const QString& message);
+ static void stopDebugging(const QString& message);
static bool debugging() { return debugging_; }
static bool noLinkErrors() { return noLinkErrors_; }
+ static bool autolinkErrors() { return autolinkErrors_; }
static void setQDocPass(Passes pass) { qdocPass_ = pass; }
static bool runPrepareOnly() { return (qdocPass_ == Prepare); }
static bool runGenerateOnly() { return (qdocPass_ == Generate); }
@@ -109,27 +111,24 @@ protected:
virtual QString fileBase(const Node* node) const;
virtual QString fileExtension() const = 0;
virtual void generateAlsoList(const Node *node, CodeMarker *marker);
- virtual int generateAtom(const Atom *atom,
- const Node *relative,
- CodeMarker *marker);
+ 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 generateInheritedBy(const ClassNode *classe,
- CodeMarker *marker);
- virtual void generateInherits(const ClassNode *classe,
- CodeMarker *marker);
+ virtual void generateCollectionNode(CollectionNode* cn, CodeMarker* marker);
+ virtual void generateInheritedBy(const ClassNode *classe, CodeMarker *marker);
+ virtual void generateInherits(const ClassNode *classe, CodeMarker *marker);
virtual void generateInnerNode(InnerNode* node);
virtual void generateMaintainerList(const InnerNode* node, CodeMarker* marker);
virtual void generateQmlInheritedBy(const QmlClassNode* qcn, CodeMarker* marker);
- virtual void generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker);
+ virtual void generateQmlInherits(QmlClassNode* qcn, CodeMarker* marker);
virtual bool generateQmlText(const Text& text,
const Node *relative,
CodeMarker *marker,
const QString& qmlName);
- virtual bool generateText(const Text& text,
- const Node *relative,
- CodeMarker *marker);
+ virtual bool generateText(const Text& text, const Node *relative, CodeMarker *marker);
virtual QString imageFileName(const Node *relative, const QString& fileBase);
virtual int skipAtoms(const Atom *atom, Atom::Type type) const;
virtual QString typeString(const Node *node);
@@ -158,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);
@@ -219,6 +218,7 @@ private:
static QStringList styleFiles;
static bool debugging_;
static bool noLinkErrors_;
+ static bool autolinkErrors_;
static bool redirectDocumentationToDevNull_;
static Passes qdocPass_;
static bool useOutputSubdirs_;
diff --git a/src/tools/qdoc/helpprojectwriter.cpp b/src/tools/qdoc/helpprojectwriter.cpp
index d46f887518..a1121a95cb 100644
--- a/src/tools/qdoc/helpprojectwriter.cpp
+++ b/src/tools/qdoc/helpprojectwriter.cpp
@@ -131,22 +131,23 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList
typeHash["function"] = Node::Function;
typeHash["property"] = Node::Property;
typeHash["variable"] = Node::Variable;
+ typeHash["group"] = Node::Group;
+ typeHash["module"] = Node::Module;
+ typeHash["qmlmodule"] = Node::QmlModule;
typeHash["qmlproperty"] = Node::QmlProperty;
typeHash["qmlsignal"] = Node::QmlSignal;
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;
subTypeHash["headerfile"] = Node::HeaderFile;
subTypeHash["file"] = Node::File;
- subTypeHash["group"] = Node::Group;
- subTypeHash["module"] = Node::Module;
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());
@@ -210,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();
@@ -247,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();
}
@@ -287,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));
@@ -316,6 +334,34 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
}
break;
+ case Node::Group:
+ case Node::Module:
+ case Node::QmlModule:
+ {
+ const CollectionNode* cn = static_cast<const CollectionNode*>(node);
+ if (!cn->fullTitle().isEmpty()) {
+ if (cn->doc().hasKeywords()) {
+ foreach (const Atom* keyword, cn->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
+ cn->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::Property:
case Node::QmlProperty:
case Node::QmlSignal:
@@ -529,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)
@@ -583,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.
@@ -590,17 +641,25 @@ 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
}
break;
+ case Node::Group:
+ case Node::Module:
+ case Node::QmlModule:
+ {
+ const CollectionNode* cn = static_cast<const CollectionNode*>(node);
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", href);
+ writer.writeAttribute("title", cn->fullTitle());
+ writer.writeEndElement(); // section
+ }
+ break;
default:
;
}
@@ -612,7 +671,7 @@ void HelpProjectWriter::generateProject(HelpProject &project)
if (!project.indexRoot.isEmpty())
rootNode = qdb_->findDocNodeByTitle(project.indexRoot);
else
- rootNode = qdb_->treeRoot();
+ rootNode = qdb_->primaryTreeRoot();
if (!rootNode)
return;
@@ -655,7 +714,7 @@ void HelpProjectWriter::generateProject(HelpProject &project)
writer.writeStartElement("section");
const Node* node = qdb_->findDocNodeByTitle(project.indexTitle);
if (node == 0)
- node = qdb_->findNode(QStringList("index.html"));
+ 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 407253ff64..be8c68fc11 100644
--- a/src/tools/qdoc/htmlgenerator.cpp
+++ b/src/tools/qdoc/htmlgenerator.cpp
@@ -264,16 +264,15 @@ QString HtmlGenerator::format()
}
/*!
- Traverses the database generating all the HTML documentation.
+ Traverses the current tree generating all the HTML documentation.
*/
-void HtmlGenerator::generateTree()
+void HtmlGenerator::generateDocs()
{
- qdb_->buildCollections();
- Node* qflags = qdb_->findNodeByNameAndType(QStringList("QFlags"), Node::Class, Node::NoSubType);
+ Node* qflags = qdb_->findClassNode(QStringList("QFlags"));
if (qflags)
qflagsHref_ = linkForNode(qflags,0);
if (!runPrepareOnly()) {
- Generator::generateTree();
+ Generator::generateDocs();
generateCollisionPages();
}
@@ -304,9 +303,6 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
int skipAhead = 0;
static bool in_para = false;
- if (Generator::debugging()) {
- atom->dump();
- }
switch (atom->type()) {
case Atom::AbstractLeft:
if (relative)
@@ -319,15 +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());
- }
}
else {
out() << protectEnc(atom->string());
@@ -336,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>";
@@ -374,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:
@@ -485,9 +486,9 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
break;
case Atom::AnnotatedList:
{
- DocNode* dn = qdb_->getGroup(atom->string());
- if (dn)
- generateAnnotatedList(relative, marker, dn->members());
+ GroupNode* gn = qdb_->getGroup(atom->string());
+ if (gn)
+ generateList(gn, marker, atom->string());
}
break;
case Atom::GeneratedList:
@@ -495,19 +496,22 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
generateAnnotatedList(relative, marker, qdb_->getCppClasses());
}
else if (atom->string() == "classes") {
- generateCompactList(Generic, relative, qdb_->getCppClasses(), true, QStringLiteral("Q"));
+ generateCompactList(Generic, relative, qdb_->getCppClasses(), true, QStringLiteral(""));
+ }
+ else if (atom->string().contains("classes ")) {
+ QString rootName = atom->string().mid(atom->string().indexOf("classes") + 7).trimmed();
+ generateCompactList(Generic, relative, qdb_->getCppClasses(), true, rootName);
}
else if (atom->string() == "qmltypes") {
generateCompactList(Generic, relative, qdb_->getQmlTypes(), true, QStringLiteral(""));
}
else if (atom->string().contains("classesbymodule")) {
- QString arg = atom->string().trimmed();
QString moduleName = atom->string().mid(atom->string().indexOf("classesbymodule") + 15).trimmed();
QDocDatabase* qdb = QDocDatabase::qdocDB();
- DocNode* dn = qdb->findModule(moduleName);
- if (dn) {
+ ModuleNode* mn = qdb->findModule(moduleName);
+ if (mn) {
NodeMap m;
- dn->getMemberClasses(m);
+ mn->getMemberClasses(m);
if (!m.isEmpty()) {
generateAnnotatedList(relative, marker, m);
}
@@ -550,16 +554,25 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
generateCompactList(Generic, relative, qdb_->getServiceClasses(), false, QStringLiteral("Q"));
}
else if (atom->string() == "overviews") {
- generateOverviewList(relative);
+ generateList(relative, marker, "overviews");
+ }
+ else if (atom->string() == "cpp-modules") {
+ generateList(relative, marker, "cpp-modules");
+ }
+ else if (atom->string() == "qml-modules") {
+ generateList(relative, marker, "qml-modules");
}
else if (atom->string() == "namespaces") {
generateAnnotatedList(relative, marker, qdb_->getNamespaces());
}
else if (atom->string() == "related") {
- const DocNode *dn = static_cast<const DocNode *>(relative);
- if (dn)
- generateAnnotatedList(dn, marker, dn->members());
+ generateList(relative, marker, "related");
}
+#if 0
+ /*
+ This is not used in Qt5, as of 10/02/2014
+ Remove permanently if it is not missed.
+ */
else if (atom->string() == "relatedinline") {
const DocNode *dn = static_cast<const DocNode *>(relative);
if (dn && !dn->members().isEmpty()) {
@@ -573,6 +586,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
generateBody(node, marker);
}
}
+#endif
break;
case Atom::SinceList:
{
@@ -591,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);
@@ -750,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);
@@ -794,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;
@@ -1117,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)
{
@@ -1304,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
@@ -1341,7 +1452,6 @@ void HtmlGenerator::generateCollisionPages()
if (collisions.size() <= 1)
continue;
- ncn->clearCurrentChild();
beginSubPage(ncn, Generator::fileName(ncn));
QString fullTitle = ncn->fullTitle();
CodeMarker* marker = CodeMarker::markerForFileName(ncn->location().filePath());
@@ -1373,7 +1483,7 @@ void HtmlGenerator::generateCollisionPages()
int count = 0;
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- if (n->findChildNodeByName(t.key())) {
+ if (n->findChildNode(t.key())) {
++count;
if (count > 1) {
targets.append(t.key());
@@ -1392,7 +1502,7 @@ void HtmlGenerator::generateCollisionPages()
out() << "<ul>\n";
for (int i=0; i<collisions.size(); ++i) {
InnerNode* n = static_cast<InnerNode*>(collisions.at(i));
- Node* p = n->findChildNodeByName(*t);
+ Node* p = n->findChildNode(*t);
if (p) {
QString link = linkForNode(p,0);
QString label;
@@ -1437,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,
@@ -1470,29 +1563,7 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
dn,
marker);
- if (dn->subType() == Node::Module) {
- // Generate brief text and status for modules.
- generateBrief(dn, marker);
- generateStatus(dn, marker);
- generateSince(dn, marker);
-
- NodeMap nm;
- dn->getMemberNamespaces(nm);
- if (!nm.isEmpty()) {
- out() << "<a name=\"" << registerRef("namespaces") << "\"></a>" << divNavTop << '\n';
- out() << "<h2>Namespaces</h2>\n";
- generateAnnotatedList(dn, marker, nm);
- }
- nm.clear();
- dn->getMemberClasses(nm);
- if (!nm.isEmpty()) {
- out() << "<a name=\"" << registerRef("classes") << "\"></a>" << divNavTop << '\n';
- out() << "<h2>Classes</h2>\n";
- generateAnnotatedList(dn, marker, nm);
- }
- nm.clear();
- }
- else if (dn->subType() == Node::HeaderFile) {
+ if (dn->subType() == Node::HeaderFile) {
// Generate brief text and status for modules.
generateBrief(dn, marker);
generateStatus(dn, marker);
@@ -1522,88 +1593,110 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
out() << "</ul>\n";
}
- else if (dn->subType() == Node::QmlClass) {
- const_cast<DocNode*>(dn)->setCurrentChild();
- 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";
- }
+ sections = marker->sections(dn, CodeMarker::Summary, CodeMarker::Okay);
+ s = sections.constBegin();
+ while (s != sections.constEnd()) {
+ out() << "<a name=\"" << registerRef((*s).name) << "\"></a>" << divNavTop << '\n';
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+ generateSectionList(*s, dn, marker, CodeMarker::Summary);
+ ++s;
+ }
- 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() << "<div class=\"descr\"> <a name=\"" << registerRef("details") << "\"></a>\n"; // QTBUG-9504
- 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);
+ generateBody(dn, marker);
+ out() << "</div>\n"; // QTBUG-9504
+ generateAlsoList(dn, marker);
+ generateExtractionMark(dn, EndMark);
+
+ sections = marker->sections(dn, CodeMarker::Detailed, CodeMarker::Okay);
+ s = sections.constBegin();
+ while (s != sections.constEnd()) {
//out() << "<hr />\n";
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\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;
+ NodeList::ConstIterator m = (*s).members.constBegin();
+ while (m != (*s).members.constEnd()) {
+ generateDetailedMember(*m, dn, marker);
+ ++m;
}
- generateFooter(dn);
- const_cast<DocNode*>(dn)->clearCurrentChild();
- return;
+ ++s;
}
+ generateFooter(dn);
+}
- sections = marker->sections(dn, CodeMarker::Summary, CodeMarker::Okay);
+/*!
+ Generate the HTML page for a group, module, or QML module.
+ */
+void HtmlGenerator::generateCollectionNode(CollectionNode* cn, CodeMarker* marker)
+{
+ SubTitleSize subTitleSize = LargeSubTitle;
+ QList<Section> sections;
+ QList<Section>::const_iterator s;
+ QString fullTitle = cn->fullTitle();
+ QString htmlTitle = fullTitle;
+
+ generateHeader(htmlTitle, cn, marker);
+ generateTableOfContents(cn,marker,0);
+ generateTitle(fullTitle, Text() << cn->subTitle(), subTitleSize, cn, marker);
+
+ if (cn->isModule()) {
+ // Generate brief text and status for modules.
+ generateBrief(cn, marker);
+ generateStatus(cn, marker);
+ generateSince(cn, marker);
+
+ NodeMap nm;
+ cn->getMemberNamespaces(nm);
+ if (!nm.isEmpty()) {
+ out() << "<a name=\"" << registerRef("namespaces") << "\"></a>" << divNavTop << '\n';
+ out() << "<h2>Namespaces</h2>\n";
+ generateAnnotatedList(cn, marker, nm);
+ }
+ nm.clear();
+ cn->getMemberClasses(nm);
+ if (!nm.isEmpty()) {
+ out() << "<a name=\"" << registerRef("classes") << "\"></a>" << divNavTop << '\n';
+ out() << "<h2>Classes</h2>\n";
+ generateAnnotatedList(cn, marker, nm);
+ }
+ nm.clear();
+ }
+
+ sections = marker->sections(cn, CodeMarker::Summary, CodeMarker::Okay);
s = sections.constBegin();
while (s != sections.constEnd()) {
out() << "<a name=\"" << registerRef((*s).name) << "\"></a>" << divNavTop << '\n';
out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
- generateSectionList(*s, dn, marker, CodeMarker::Summary);
+ generateSectionList(*s, cn, marker, CodeMarker::Summary);
++s;
}
- Text brief = dn->doc().briefText();
- if (dn->subType() == Node::Module && !brief.isEmpty()) {
- generateExtractionMark(dn, DetailedDescriptionMark);
+ Text brief = cn->doc().briefText();
+ if (cn->isModule() && !brief.isEmpty()) {
+ generateExtractionMark(cn, DetailedDescriptionMark);
out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << '\n';
out() << "<div class=\"descr\">\n"; // QTBUG-9504
out() << "<h2>" << "Detailed Description" << "</h2>\n";
}
else {
- generateExtractionMark(dn, DetailedDescriptionMark);
+ generateExtractionMark(cn, DetailedDescriptionMark);
out() << "<div class=\"descr\"> <a name=\"" << registerRef("details") << "\"></a>\n"; // QTBUG-9504
}
- generateBody(dn, marker);
+ generateBody(cn, marker);
out() << "</div>\n"; // QTBUG-9504
- generateAlsoList(dn, marker);
- generateExtractionMark(dn, EndMark);
+ generateAlsoList(cn, marker);
+ generateExtractionMark(cn, EndMark);
- if ((dn->subType() == Node::Group))
- generateAnnotatedList(dn, marker, dn->members());
- else if (dn->subType() == Node::QmlModule)
- generateAnnotatedList(dn, marker, dn->members());
+ if (cn->isGroup())
+ generateAnnotatedList(cn, marker, cn->members());
+ else if (cn->isQmlModule())
+ generateAnnotatedList(cn, marker, cn->members());
- sections = marker->sections(dn, CodeMarker::Detailed, CodeMarker::Okay);
+ sections = marker->sections(cn, CodeMarker::Detailed, CodeMarker::Okay);
s = sections.constBegin();
while (s != sections.constEnd()) {
//out() << "<hr />\n";
@@ -1611,12 +1704,12 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
NodeList::ConstIterator m = (*s).members.constBegin();
while (m != (*s).members.constEnd()) {
- generateDetailedMember(*m, dn, marker);
+ generateDetailedMember(*m, cn, marker);
++m;
}
++s;
}
- generateFooter(dn);
+ generateFooter(cn);
}
/*!
@@ -1650,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();
@@ -1667,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)
@@ -1892,7 +1994,7 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker)
if (inner->type() == Node::Class || inner->type() == Node::Namespace) {
//add the QT variable to the map
if (!inner->moduleName().isEmpty()) {
- DocNode * moduleNode = qdb_->findModule(inner->moduleName());
+ ModuleNode* moduleNode = qdb_->findModule(inner->moduleName());
if (moduleNode && !moduleNode->qtVariable().isEmpty()) {
text.clear();
text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_TELETYPE)
@@ -1923,18 +2025,20 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker)
r = classe->baseClasses().constBegin();
index = 0;
while (r != classe->baseClasses().constEnd()) {
- text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node))
- << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, (*r).dataTypeWithTemplateArgs)
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
-
- if ((*r).access == Node::Protected) {
- text << " (protected)";
- }
- else if ((*r).access == Node::Private) {
- text << " (private)";
+ if ((*r).node_) {
+ text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node_))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, (*r).signature_)
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+
+ if ((*r).access_ == Node::Protected) {
+ text << " (protected)";
+ }
+ else if ((*r).access_ == Node::Private) {
+ text << " (private)";
+ }
+ text << separator(index++, classe->baseClasses().count());
}
- text << separator(index++, classe->baseClasses().count());
++r;
}
text << Atom::ParaRight;
@@ -2002,9 +2106,9 @@ void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker)
//add the module name and version to the map
QString qmlModuleVersion;
- DocNode* dn = qdb_->findQmlModule(qcn->qmlModuleName());
- if (dn)
- qmlModuleVersion = dn->qmlModuleVersion();
+ QmlModuleNode* qmn = qdb_->findQmlModule(qcn->qmlModuleName());
+ if (qmn)
+ qmlModuleVersion = qmn->qmlModuleVersion();
else
qmlModuleVersion = qcn->qmlModuleVersion();
text.clear();
@@ -2044,7 +2148,7 @@ void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker)
}
//add the inherits to the map
- const QmlClassNode* base = qcn->qmlBaseNode();
+ QmlClassNode* base = qcn->qmlBaseNode();
while (base && base->isInternal()) {
base = base->qmlBaseNode();
}
@@ -2136,7 +2240,7 @@ void HtmlGenerator::generateTableOfContents(const Node *node,
QList<Atom*> toc;
if (node->doc().hasTableOfContents())
toc = node->doc().tableOfContents();
- if (toc.isEmpty() && !sections && (node->subType() != Node::Module))
+ if (toc.isEmpty() && !sections && !node->isModule())
return;
QStringList sectionNumber;
@@ -2151,7 +2255,7 @@ void HtmlGenerator::generateTableOfContents(const Node *node,
sectionNumber.append("1");
out() << "<ul>\n";
- if (node->subType() == Node::Module) {
+ if (node->isModule()) {
if (node->hasNamespaces()) {
out() << "<li class=\"level"
<< sectionNumber.size()
@@ -2178,9 +2282,7 @@ void HtmlGenerator::generateTableOfContents(const Node *node,
}
}
}
- else if (sections && ((node->type() == Node::Class) ||
- (node->type() == Node::Namespace) ||
- (node->subType() == Node::QmlClass))) {
+ else if (sections && (node->isClass() || node->isNamespace() || node->isQmlType())) {
QList<Section>::ConstIterator s = sections->constBegin();
while (s != sections->constEnd()) {
if (!s->members.isEmpty() || !s->reimpMembers.isEmpty()) {
@@ -2278,8 +2380,7 @@ QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner,
the members of QML class \a qml_cn, including the inherited
members. The \a marker is used for formatting stuff.
*/
-QString HtmlGenerator::generateAllQmlMembersFile(const QmlClassNode* qml_cn,
- CodeMarker* marker)
+QString HtmlGenerator::generateAllQmlMembersFile(QmlClassNode* qml_cn, CodeMarker* marker)
{
QList<Section> sections;
QList<Section>::ConstIterator s;
@@ -2448,8 +2549,8 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, NodeMap& classM
NodeMap newTop;
foreach (const RelatedClass &d, child->derivedClasses()) {
- if (d.access != Node::Private && !d.node->doc().isEmpty())
- newTop.insert(d.node->name(), d.node);
+ if (d.node_ && !d.isPrivate() && !d.node_->isInternal() && d.node_->hasDoc())
+ newTop.insert(d.node_->name(), d.node_);
}
if (!newTop.isEmpty()) {
stack.push(newTop);
@@ -2469,33 +2570,29 @@ void HtmlGenerator::generateAnnotatedList(const Node* relative,
{
if (nodeMap.isEmpty())
return;
- NodeList nl;
- NodeMap::const_iterator i = nodeMap.begin();
- while (i != nodeMap.end()) {
- nl.append(i.value());
- ++i;
- }
- generateAnnotatedList(relative, marker, nl);
+ generateAnnotatedList(relative, marker, nodeMap.values());
}
+/*!
+ */
void HtmlGenerator::generateAnnotatedList(const Node *relative,
CodeMarker *marker,
- const NodeList& nodes)
+ const NodeList& unsortedNodes)
{
+ NodeMap nm;
bool allInternal = true;
- foreach (const Node* node, nodes) {
- if (!node->isInternal() && node->status() != Node::Obsolete) {
+ foreach (Node* node, unsortedNodes) {
+ if (!node->isInternal() && !node->isObsolete()) {
allInternal = false;
+ nm.insert(node->fullName(relative), node);
}
}
if (allInternal)
return;
out() << "<table class=\"annotated\">\n";
int row = 0;
+ NodeList nodes = nm.values();
foreach (const Node* node, nodes) {
- if (node->isInternal() || node->status() == Node::Obsolete)
- continue;
-
if (++row % 2 == 1)
out() << "<tr class=\"odd topAlign\">";
else
@@ -2504,7 +2601,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative,
generateFullName(node, relative);
out() << "</p></td>";
- if (!(node->type() == Node::Document)) {
+ if (!node->isDocNode()) {
Text brief = node->doc().trimmedBriefText(node->name());
if (!brief.isEmpty()) {
out() << "<td class=\"tblDescr\"><p>";
@@ -2680,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("::");
@@ -2786,117 +2883,105 @@ void HtmlGenerator::generateQmlItem(const Node *node,
marked.remove("<@type>");
marked.remove("</@type>");
}
- out() << highlightedCode(marked, relative, false, node);
+ out() << highlightedCode(marked, relative, false);
}
-void HtmlGenerator::generateOverviewList(const Node *relative)
+void HtmlGenerator::generateList(const Node* relative, CodeMarker* marker, const QString& selector)
{
- QMap<const DocNode *, QMap<QString, DocNode *> > docNodeMap;
- QMap<QString, const DocNode *> groupTitlesMap;
- QMap<QString, DocNode *> uncategorizedNodeMap;
+ NodeList nl;
+ CollectionList cl;
QRegExp singleDigit("\\b([0-9])\\b");
- const NodeList children = qdb_->treeRoot()->childNodes();
- foreach (Node *child, children) {
- if (child->type() == Node::Document && child != relative) {
- DocNode *docNode = static_cast<DocNode *>(child);
-
- // Check whether the page is part of a group or is the group
- // definition page.
- QString group;
- bool isGroupPage = false;
- if (docNode->doc().metaCommandsUsed().contains("group")) {
- group = docNode->doc().metaCommandArgs("group")[0].first;
- isGroupPage = true;
- }
-
- // there are too many examples; they would clutter the list
- if (docNode->subType() == Node::Example)
- continue;
-
- // not interested either in individual (Qt Designer etc.) manual chapters
- if (docNode->links().contains(Node::ContentsLink))
- continue;
-
- // Discard external nodes.
- if (docNode->subType() == Node::ExternalPage)
- continue;
-
- QString sortKey = docNode->fullTitle().toLower();
- if (sortKey.startsWith("the "))
- sortKey.remove(0, 4);
- sortKey.replace(singleDigit, "0\\1");
-
- if (!group.isEmpty()) {
- if (isGroupPage) {
- // If we encounter a group definition page, we add all
- // the pages in that group to the list for that group.
- foreach (Node *member, docNode->members()) {
- if (member->isInternal() || member->type() != Node::Document)
- continue;
- DocNode *page = static_cast<DocNode *>(member);
- if (page) {
- QString sortKey = page->fullTitle().toLower();
- if (sortKey.startsWith("the "))
- sortKey.remove(0, 4);
- sortKey.replace(singleDigit, "0\\1");
- docNodeMap[const_cast<const DocNode *>(docNode)].insert(sortKey, page);
- groupTitlesMap[docNode->fullTitle()] = const_cast<const DocNode *>(docNode);
- }
- }
- }
- else if (!isGroupPage) {
- // If we encounter a page that belongs to a group then
- // we add that page to the list for that group.
- const DocNode* gn = qdb_->getGroup(group);
- if (gn && !docNode->isInternal())
- docNodeMap[gn].insert(sortKey, docNode);
- }
- }
+ if (selector == "overviews") {
+ CNMap groups;
+ qdb_->mergeCollections(Node::Group, groups, relative);
+ cl = groups.values();
+ foreach (CollectionNode* cn, cl)
+ nl.append(cn);
+ generateAnnotatedList(relative, marker, nl);
+ }
+ else if (selector == "cpp-modules") {
+ CNMap modules;
+ qdb_->mergeCollections(Node::Module, modules, relative);
+ cl = modules.values();
+ foreach (CollectionNode* cn, cl)
+ nl.append(cn);
+ generateAnnotatedList(relative, marker, nl);
+ }
+ else if (selector == "qml-modules") {
+ CNMap qmlModules;
+ qdb_->mergeCollections(Node::QmlModule, qmlModules, relative);
+ cl = qmlModules.values();
+ foreach (CollectionNode* cn, cl)
+ nl.append(cn);
+ generateAnnotatedList(relative, marker, nl);
+ }
+ else {
+ /*
+ \generatelist {selector} is only allowed in a
+ comment where the topic is \group, \module, or
+ \qmlmodule.
+ */
+ if (!relative || !relative->isCollectionNode()) {
+ relative->doc().location().warning(tr("\\generatelist {%1} is only allowed in \\group, \\module, and \\qmlmodule comments.").arg(selector));
+ return;
+ }
+ if (selector == "related") {
+ Node* n = const_cast<Node*>(relative);
+ CollectionNode* cn = static_cast<CollectionNode*>(n);
+ qdb_->mergeCollections(cn);
+ generateAnnotatedList(cn, marker, cn->members());
+ }
+ else {
+ Node* n = const_cast<Node*>(relative);
+ CollectionNode* cn = static_cast<CollectionNode*>(n);
+ qdb_->mergeCollections(cn);
+ generateAnnotatedList(cn, marker, cn->members());
}
}
- // We now list all the pages found that belong to groups.
- // If only certain pages were found for a group, but the definition page
- // for that group wasn't listed, the list of pages will be intentionally
- // incomplete. However, if the group definition page was listed, all the
- // pages in that group are listed for completeness.
-
- if (!docNodeMap.isEmpty()) {
- foreach (const QString &groupTitle, groupTitlesMap.keys()) {
- const DocNode *groupNode = groupTitlesMap[groupTitle];
+#if 0
+ QStringList keys = groups.uniqueKeys();
+ foreach (QString key, keys) {
+ GroupNode* gn = static_cast<GroupNode*>(groups.value(key));
+ if (gn) {
out() << QString("<h3><a href=\"%1\">%2</a></h3>\n").arg(
- linkForNode(groupNode, relative)).arg(
- protectEnc(groupNode->fullTitle()));
-
- if (docNodeMap[groupNode].count() == 0)
+ linkForNode(gn, relative)).arg(
+ protectEnc(gn->fullTitle()));
+#if 0
+ if (gn->members().isEmpty())
continue;
- out() << "<ul>\n";
+ NodeMap nm;
+ foreach (Node* member, gn->members()) {
+ if (member->isInternal() || member->isExample() || member->isExternalPage() ||
+ member->isObsolete())
+ continue;
+ // not interested either in individual (Qt Designer etc.) manual chapters
+ if (member->links().contains(Node::ContentsLink))
+ continue;
+ QString sortKey = member->fullTitle().toLower();
+ if (sortKey.startsWith("the "))
+ sortKey.remove(0, 4);
+ sortKey.replace(singleDigit, "0\\1");
+ nm.insert(sortKey, member);
+ }
- foreach (const DocNode *docNode, docNodeMap[groupNode]) {
- QString title = docNode->fullTitle();
+ out() << "<ul>\n";
+ QStringList titles = nm.keys();
+ foreach (QString t, titles) {
+ Node* member = nm.value(t);
+ QString title = member->fullTitle();
if (title.startsWith("The "))
title.remove(0, 4);
- out() << "<li><a href=\"" << linkForNode(docNode, relative) << "\">"
+ out() << "<li><a href=\"" << linkForNode(member, relative) << "\">"
<< protectEnc(title) << "</a></li>\n";
}
out() << "</ul>\n";
+#endif
}
}
-
- if (!uncategorizedNodeMap.isEmpty()) {
- out() << QString("<h3>Miscellaneous</h3>\n");
- out() << "<ul>\n";
- foreach (const DocNode *docNode, uncategorizedNodeMap) {
- QString title = docNode->fullTitle();
- if (title.startsWith("The "))
- title.remove(0, 4);
- out() << "<li><a href=\"" << linkForNode(docNode, relative) << "\">"
- << protectEnc(title) << "</a></li>\n";
- }
- out() << "</ul>\n";
- }
+#endif
}
void HtmlGenerator::generateSection(const NodeList& nl,
@@ -3099,8 +3184,7 @@ void HtmlGenerator::generateSynopsis(const Node *node,
QString HtmlGenerator::highlightedCode(const QString& markedCode,
const Node* relative,
- bool alignNames,
- const Node* self)
+ bool alignNames)
{
QString src = markedCode;
QString html;
@@ -3148,8 +3232,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
i += 2;
if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
-
- const Node* n = qdb_->resolveTarget(par1.toString(), relative);
+ const Node* n = qdb_->resolveFunctionTarget(par1.toString(), relative);
QString link = linkForNode(n, relative);
addLink(link, arg, &html);
par1 = QStringRef();
@@ -3164,7 +3247,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
}
}
- // replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
+ // replace all "(<@(type|headerfile)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
src = html;
html = QString();
@@ -3174,10 +3257,10 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
bool handled = false;
if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
- const Node* n = qdb_->resolveTarget(arg.toString(), relative, self);
+ 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();
@@ -3189,17 +3272,18 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
}
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
par1 = QStringRef();
- const Node* n = qdb_->resolveTarget(arg.toString(), relative);
- addLink(linkForNode(n,relative), arg, &html);
- handled = true;
- }
- else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
- par1 = QStringRef();
- const Node* n = qdb_->resolveTarget(arg.toString(), relative);
- addLink(linkForNode(n,relative), arg, &html);
+ if (arg.at(0) == QChar('&'))
+ html += arg.toString();
+ else {
+ // zzz resolveClassTarget()
+ const Node* n = qdb_->resolveTarget(arg.toString(), relative);
+ if (n)
+ addLink(linkForNode(n,relative), arg, &html);
+ else
+ html += arg.toString();
+ }
handled = true;
}
-
if (!handled) {
html += charLangle;
html += charAt;
@@ -3537,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
@@ -3680,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:
@@ -3715,128 +3800,134 @@ 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:"))) {
+ return atom->string(); // It's some kind of protocol.
+ }
- 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:"))) {
+ QString ref;
+ QString link;
+ QString first;
+ QStringList path;
- link = atom->string();
+ *node = 0;
+ if (atom->string().contains('#')) {
+ path = atom->string().split('#');
+ first = path.first().trimmed();
+ path.removeFirst();
}
- else {
- QStringList path;
- if (atom->string().contains('#')) {
- path = atom->string().split('#');
- }
- else {
- path.append(atom->string());
- }
+ else
+ first = atom->string();
- QString ref;
- QString first = path.first().trimmed();
- if (first.isEmpty()) {
- *node = relative;
+ if (first.isEmpty())
+ *node = relative; // search for a target on the current page.
+ else {
+ 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(".html")) {
- /*
- This is not a recursive search. That's ok in
- this case, because we are searching for a page
- node, which must be a direct child of the tree
- root.
- */
- *node = qdb_->treeRoot()->findChildNodeByNameAndType(first, Node::Document);
+ else if (first.endsWith("()")) { // The target is a C++ function or QML method.
+ *node = qdb_->resolveFunctionTarget(first, relative);
}
else {
*node = qdb_->resolveTarget(first, relative);
- if (!*node) {
- *node = qdb_->findDocNodeByTitle(first, relative);
- }
- if (!*node) {
- *node = qdb_->findUnambiguousTarget(first, ref, relative);
+ if (!(*node))
+ *node = qdb_->findDocNodeByTitle(first);
+ if (!(*node)) {
+ *node = qdb_->findUnambiguousTarget(first, ref);
if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
QString final = (*node)->url() + "#" + ref;
return final;
}
}
}
- 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;
}
@@ -3861,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")
@@ -4018,7 +4097,7 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
out() << "<td class=\"tblQmlPropNode\"><p>";
out() << "<a name=\"" + refForNode(qpn) + "\"></a>";
- if (!qpn->isWritable(qdb_))
+ if (!qpn->isWritable())
out() << "<span class=\"qmlreadonly\">read-only</span>";
if (qpn->isDefault())
out() << "<span class=\"qmldefault\">default</span>";
@@ -4039,7 +4118,7 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
out() << "<a name=\"" + refForNode(qpn) + "\"></a>";
if (!qpn->isReadOnlySet()) {
if (qpn->declarativeCppNode())
- qpn->setReadOnly(!qpn->isWritable(qdb_));
+ qpn->setReadOnly(!qpn->isWritable());
}
if (qpn->isReadOnly())
out() << "<span class=\"qmlreadonly\">read-only</span>";
@@ -4101,11 +4180,11 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
Output the "Inherits" line for the QML element,
if there should be one.
*/
-void HtmlGenerator::generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker)
+void HtmlGenerator::generateQmlInherits(QmlClassNode* qcn, CodeMarker* marker)
{
if (!qcn)
return;
- const QmlClassNode* base = qcn->qmlBaseNode();
+ QmlClassNode* base = qcn->qmlBaseNode();
while (base && base->isInternal()) {
base = base->qmlBaseNode();
}
@@ -4229,7 +4308,7 @@ void HtmlGenerator::generateManifestFiles()
{
generateManifestFile("examples", "example");
generateManifestFile("demos", "demo");
- ExampleNode::exampleNodeMap.clear();
+ qdb_->exampleNodeMap().clear();
manifestMetaContent.clear();
}
@@ -4240,7 +4319,8 @@ void HtmlGenerator::generateManifestFiles()
*/
void HtmlGenerator::generateManifestFile(QString manifest, QString element)
{
- if (ExampleNode::exampleNodeMap.isEmpty())
+ ExampleNodeMap& exampleNodeMap = qdb_->exampleNodeMap();
+ if (exampleNodeMap.isEmpty())
return;
QString fileName = manifest +"-manifest.xml";
QFile file(outputDir() + QLatin1Char('/') + fileName);
@@ -4251,8 +4331,8 @@ void HtmlGenerator::generateManifestFile(QString manifest, QString element)
demos = true;
bool proceed = false;
- ExampleNodeMap::Iterator i = ExampleNode::exampleNodeMap.begin();
- while (i != ExampleNode::exampleNodeMap.end()) {
+ ExampleNodeMap::Iterator i = exampleNodeMap.begin();
+ while (i != exampleNodeMap.end()) {
const ExampleNode* en = i.value();
if (demos) {
if (en->name().startsWith("demos")) {
@@ -4276,8 +4356,8 @@ void HtmlGenerator::generateManifestFile(QString manifest, QString element)
writer.writeAttribute("module", project);
writer.writeStartElement(manifest);
- i = ExampleNode::exampleNodeMap.begin();
- while (i != ExampleNode::exampleNodeMap.end()) {
+ i = exampleNodeMap.begin();
+ while (i != exampleNodeMap.end()) {
const ExampleNode* en = i.value();
if (demos) {
if (!en->name().startsWith("demos")) {
@@ -4501,6 +4581,16 @@ 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:
+ break;
+ case Node::QmlModule:
+ break;
case Node::Document:
switch (child->subType()) {
case Node::Example:
@@ -4511,20 +4601,10 @@ void HtmlGenerator::reportOrphans(const InnerNode* parent)
break;
case Node::Image:
break;
- case Node::Group:
- break;
- case Node::Module:
- break;
case Node::Page:
break;
case Node::ExternalPage:
break;
- case Node::QmlClass:
- break;
- case Node::QmlBasicType:
- break;
- case Node::QmlModule:
- break;
case Node::Collision:
break;
default:
diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h
index ae16f3c54f..395ccdb8bf 100644
--- a/src/tools/qdoc/htmlgenerator.h
+++ b/src/tools/qdoc/htmlgenerator.h
@@ -88,7 +88,7 @@ public:
virtual void initializeGenerator(const Config& config);
virtual void terminateGenerator();
virtual QString format();
- virtual void generateTree();
+ virtual void generateDocs();
void generateCollisionPages();
void generateManifestFiles();
@@ -102,7 +102,10 @@ 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;
virtual QString refForNode(const Node *node);
virtual QString linkForNode(const Node *node, const Node *relative);
@@ -152,8 +155,7 @@ private:
QList<Section>* sections = 0);
QString generateListOfAllMemberFile(const InnerNode *inner,
CodeMarker *marker);
- QString generateAllQmlMembersFile(const QmlClassNode* qml_cn,
- CodeMarker* marker);
+ QString generateAllQmlMembersFile(QmlClassNode* qml_cn, CodeMarker* marker);
QString generateLowStatusMemberFile(InnerNode *inner,
CodeMarker *marker,
CodeMarker::Status status);
@@ -167,7 +169,7 @@ private:
QString commonPrefix);
void generateFunctionIndex(const Node *relative);
void generateLegaleseList(const Node *relative, CodeMarker *marker);
- void generateOverviewList(const Node *relative);
+ void generateList(const Node* relative, CodeMarker* marker, const QString& selector);
void generateSectionList(const Section& section,
const Node *relative,
CodeMarker *marker,
@@ -182,7 +184,7 @@ private:
void generateDetailedQmlMember(Node *node,
const InnerNode *relative,
CodeMarker *marker);
- void generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker);
+ void generateQmlInherits(QmlClassNode* qcn, CodeMarker* marker);
void generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker);
void generateInstantiatedBy(ClassNode* cn, CodeMarker* marker);
@@ -200,8 +202,7 @@ private:
void generateSectionInheritedList(const Section& section, const Node *relative);
QString highlightedCode(const QString& markedCode,
const Node* relative,
- bool alignNames = false,
- const Node* self = 0);
+ bool alignNames = false);
void generateFullName(const Node *apparentNode, const Node *relative, const Node *actualNode = 0);
void generateDetailedMember(const Node *node,
@@ -216,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 8998a27081..21ca2c4820 100644
--- a/src/tools/qdoc/main.cpp
+++ b/src/tools/qdoc/main.cpp
@@ -78,6 +78,7 @@ static bool highlighting = false;
static bool showInternal = false;
static bool redirectDocumentationToDevNull = false;
static bool noLinkErrors = false;
+static bool autolinkErrors = false;
static bool obsoleteLinks = false;
static QStringList defines;
static QStringList dependModules;
@@ -275,6 +276,7 @@ static void processQdocconfFile(const QString &fileName)
config.setStringList(CONFIG_SHOWINTERNAL, QStringList(showInternal ? "true" : "false"));
config.setStringList(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL, QStringList(redirectDocumentationToDevNull ? "true" : "false"));
config.setStringList(CONFIG_NOLINKERRORS, QStringList(noLinkErrors ? "true" : "false"));
+ config.setStringList(CONFIG_AUTOLINKERRORS, QStringList(autolinkErrors ? "true" : "false"));
config.setStringList(CONFIG_OBSOLETELINKS, QStringList(obsoleteLinks ? "true" : "false"));
/*
@@ -289,7 +291,8 @@ static void processQdocconfFile(const QString &fileName)
currentDir = QFileInfo(fileName).path();
Location::initialize(config);
config.load(fileName);
-
+ QString project = config.getString(CONFIG_PROJECT).toLower();
+ //qDebug() << "\nSTART PROJECT:" << project;
/*
Add the defines to the configuration variables.
*/
@@ -363,7 +366,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;
@@ -372,7 +379,7 @@ static void processQdocconfFile(const QString &fileName)
QStringList excludedDirsList;
QStringList excludedFilesList;
- Generator::debugSegfault("Reading excludedirs");
+ Generator::debug("Reading excludedirs");
excludedDirsList = config.getCanonicalPathList(CONFIG_EXCLUDEDIRS);
foreach (const QString &excludeDir, excludedDirsList) {
QString p = QDir::fromNativeSeparators(excludeDir);
@@ -381,14 +388,14 @@ static void processQdocconfFile(const QString &fileName)
excludedDirs.insert(p);
}
- Generator::debugSegfault("Reading excludefiles");
- excludedFilesList = config.getCleanPathList(CONFIG_EXCLUDEFILES);
+ Generator::debug("Reading excludefiles");
+ excludedFilesList = config.getCanonicalPathList(CONFIG_EXCLUDEFILES);
foreach (const QString& excludeFile, excludedFilesList) {
QString p = QDir::fromNativeSeparators(excludeFile);
excludedFiles.insert(p);
}
- Generator::debugSegfault("Reading headerdirs");
+ Generator::debug("Reading headerdirs");
headerList = config.getAllFiles(CONFIG_HEADERS,CONFIG_HEADERDIRS,excludedDirs,excludedFiles);
QMap<QString,QString> headers;
QMultiMap<QString,QString> headerFileNames;
@@ -402,7 +409,7 @@ static void processQdocconfFile(const QString &fileName)
headerFileNames.insert(t,t);
}
- Generator::debugSegfault("Reading sourcedirs");
+ Generator::debug("Reading sourcedirs");
sourceList = config.getAllFiles(CONFIG_SOURCES,CONFIG_SOURCEDIRS,excludedDirs,excludedFiles);
QMap<QString,QString> sources;
QMultiMap<QString,QString> sourceFileNames;
@@ -419,7 +426,7 @@ static void processQdocconfFile(const QString &fileName)
Find all the qdoc files in the example dirs, and add
them to the source files to be parsed.
*/
- Generator::debugSegfault("Reading exampledirs");
+ Generator::debug("Reading exampledirs");
QStringList exampleQdocList = config.getExampleQdocFiles(excludedDirs, excludedFiles);
for (int i=0; i<exampleQdocList.size(); ++i) {
if (!sources.contains(exampleQdocList[i])) {
@@ -429,7 +436,7 @@ static void processQdocconfFile(const QString &fileName)
}
}
- Generator::debugSegfault("Adding doc/image dirs found in exampledirs to imagedirs");
+ Generator::debug("Adding doc/image dirs found in exampledirs to imagedirs");
QSet<QString> exampleImageDirs;
QStringList exampleImageList = config.getExampleImageFiles(excludedDirs, excludedFiles);
for (int i=0; i<exampleImageList.size(); ++i) {
@@ -448,7 +455,7 @@ static void processQdocconfFile(const QString &fileName)
*/
QSet<CodeParser *> usedParsers;
- Generator::debugSegfault("Parsing header files");
+ Generator::debug("Parsing header files");
int parsed = 0;
QMap<QString,QString>::ConstIterator h = headers.constBegin();
while (h != headers.constEnd()) {
@@ -465,22 +472,26 @@ static void processQdocconfFile(const QString &fileName)
codeParser->doneParsingHeaderFiles();
usedParsers.clear();
+ qdb->resolveInheritance();
+
/*
Parse each source text file in the set using the appropriate parser and
add it to the big tree.
*/
parsed = 0;
- Generator::debugSegfault("Parsing source files");
+ Generator::debug("Parsing source files");
QMap<QString,QString>::ConstIterator s = sources.constBegin();
while (s != sources.constEnd()) {
CodeParser *codeParser = CodeParser::parserForSourceFile(s.key());
if (codeParser) {
++parsed;
+ Generator::debug(QString("Parsing " + s.key()));
codeParser->parseSourceFile(config.location(), s.key());
usedParsers.insert(codeParser);
}
++s;
}
+ Generator::debug(QString("Parsing done."));
foreach (CodeParser *codeParser, usedParsers)
codeParser->doneParsingSourceFiles();
@@ -490,7 +501,7 @@ static void processQdocconfFile(const QString &fileName)
source files. Resolve all the class names, function names,
targets, URLs, links, and other stuff that needs resolving.
*/
- Generator::debugSegfault("Resolving stuff prior to generating docs");
+ Generator::debug("Resolving stuff prior to generating docs");
qdb->resolveIssues();
/*
@@ -499,19 +510,21 @@ static void processQdocconfFile(const QString &fileName)
documentation output. More than one output format can be
requested. The tree is traversed for each one.
*/
- Generator::debugSegfault("Generating docs");
+ Generator::debug("Generating docs");
QSet<QString>::ConstIterator of = outputFormats.constBegin();
while (of != outputFormats.constEnd()) {
Generator* generator = Generator::generatorForFormat(*of);
if (generator == 0)
outputFormatsLocation.fatal(QCoreApplication::translate("QDoc", "Unknown output format '%1'").arg(*of));
- generator->generateTree();
+ generator->generateDocs();
++of;
}
//Generator::writeOutFileNames();
- Generator::debugSegfault("Shutting down qdoc");
+ Generator::debug("Shutting down qdoc");
+ if (Generator::debugging())
+ Generator::stopDebugging(project);
QDocDatabase::qdocDB()->setVersion(QString());
Generator::terminate();
@@ -532,7 +545,7 @@ static void processQdocconfFile(const QString &fileName)
#ifdef DEBUG_SHUTDOWN_CRASH
qDebug() << "main(): qdoc database deleted";
#endif
- Generator::debugSegfault("qdoc finished!");
+ Generator::debug("qdoc finished!");
}
extern Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed;
@@ -633,8 +646,11 @@ int main(int argc, char **argv)
else if (opt == "-no-link-errors") {
noLinkErrors = true;
}
+ else if (opt == "-autolink-errors") {
+ autolinkErrors = true;
+ }
else if (opt == "-debug") {
- Generator::setDebugSegfaultFlag(true);
+ Generator::startDebugging(QString("command line"));
}
else if (opt == "-prepare") {
Generator::setQDocPass(Generator::Prepare);
diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp
index c88ebfc760..fd610dedb6 100644
--- a/src/tools/qdoc/node.cpp
+++ b/src/tools/qdoc/node.cpp
@@ -50,8 +50,39 @@
QT_BEGIN_NAMESPACE
int Node::propertyGroupCount_ = 0;
-ExampleNodeMap ExampleNode::exampleNodeMap;
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
@@ -127,14 +158,14 @@ QString Node::plainFullName(const Node* relative) const
*/
QString Node::fullName(const Node* relative) const
{
- if (type() == Node::Document) {
+ if (isDocNode() || isCollectionNode()) {
const DocNode* dn = static_cast<const DocNode*>(this);
// Only print modulename::type on collision pages.
if (!dn->qmlModuleName().isEmpty() && relative != 0 && relative->isCollisionNode())
return dn->qmlModuleName() + "::" + dn->title();
return dn->title();
}
- else if (type() == Node::Class) {
+ else if (isClass()) {
const ClassNode* cn = static_cast<const ClassNode*>(this);
if (!cn->serviceName().isEmpty())
return cn->serviceName();
@@ -143,6 +174,31 @@ QString Node::fullName(const Node* relative) const
}
/*!
+ Try to match this node's type and subtype with one of the
+ pairs in \a types. If a match is found, return true. If no
+ match is found, return false.
+
+ \a types is a list of type/subtype pairs, where the first
+ value in the pair is a Node::Type, and the second value is
+ a Node::SubType. The second value is used in the match if
+ this node's type is Node::Document.
+ */
+bool Node::match(const NodeTypeList& types) const
+{
+ for (int i=0; i<types.size(); ++i) {
+ if (type() == types.at(i).first) {
+ if (type() == Node::Document) {
+ if (subType() == types.at(i).second)
+ return true;
+ }
+ else
+ return true;
+ }
+ }
+ return false;
+}
+
+/*!
Sets this Node's Doc to \a doc. If \a replace is false and
this Node already has a Doc, a warning is reported that the
Doc is being overridden, and it reports where the previous
@@ -170,7 +226,6 @@ Node::Node(Type type, InnerNode *parent, const QString& name)
pageType_(NoPageType),
status_(Commendable),
indexNodeFlag_(false),
- seen_(true),
parent_(parent),
relatesTo_(0),
name_(name)
@@ -224,21 +279,13 @@ Node::Node(Type type, InnerNode *parent, const QString& name)
}
}
-/*!
+/*! \fn QString Node::url() const
Returns the node's URL.
*/
-QString Node::url() const
-{
- return url_;
-}
-/*!
+/*! \fn void Node::setUrl(const QString &url)
Sets the node's URL to \a url
*/
-void Node::setUrl(const QString &url)
-{
- url_ = url;
-}
/*!
Returns this node's page type as a string, for use as an
@@ -309,6 +356,16 @@ QString Node::nodeTypeString(unsigned t)
return "property";
case Variable:
return "variable";
+ case Group:
+ return "group";
+ case Module:
+ return "module";
+ case QmlType:
+ return "QML type";
+ case QmlBasicType:
+ return "QML basic type";
+ case QmlModule:
+ return "QML module";
case QmlProperty:
return "QML property";
case QmlPropertyGroup:
@@ -351,20 +408,10 @@ QString Node::nodeSubtypeString(unsigned t)
return "file";
case Image:
return "image";
- case Group:
- return "group";
- case Module:
- return "module";
case Page:
return "page";
case ExternalPage:
return "external page";
- case QmlClass:
- return "QML type";
- case QmlBasicType:
- return "QML basic type";
- case QmlModule:
- return "QML module";
case DitaMap:
return "ditamap";
case Collision:
@@ -515,7 +562,7 @@ QString Node::extractClassName(const QString &string) const
*/
QString RelatedClass::accessString() const
{
- switch (access) {
+ switch (access_) {
case Node::Protected:
return "protected";
case Node::Private:
@@ -601,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;
@@ -640,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
*/
@@ -654,101 +709,21 @@ InnerNode::~InnerNode()
}
/*!
- Returns \c true if this node's members coolection is not empty.
- */
-bool InnerNode::hasMembers() const
-{
- return !members_.isEmpty();
-}
-
-/*!
- Appends \a node to the members list, if and only if it
- isn't already in the members list.
- */
-void InnerNode::addMember(Node* node)
-{
- if (!members_.contains(node))
- members_.append(node);
-}
-
-/*!
- Returns \c true if this node's members collection contains at
- least one namespace node.
- */
-bool InnerNode::hasNamespaces() const
-{
- if (!members_.isEmpty()) {
- NodeList::const_iterator i = members_.begin();
- while (i != members_.end()) {
- if ((*i)->isNamespace())
- return true;
- ++i;
- }
- }
- return false;
-}
-
-/*!
- Returns \c true if this node's members collection contains at
- least one class node.
- */
-bool InnerNode::hasClasses() const
-{
- if (!members_.isEmpty()) {
- NodeList::const_iterator i = members_.begin();
- while (i != members_.end()) {
- if ((*i)->isClass())
- return true;
- ++i;
- }
- }
- return false;
-}
-
-/*!
- Loads \a out with all this node's member nodes that are namespace nodes.
- */
-void InnerNode::getMemberNamespaces(NodeMap& out)
-{
- out.clear();
- NodeList::const_iterator i = members_.begin();
- while (i != members_.end()) {
- if ((*i)->isNamespace())
- out.insert((*i)->name(),(*i));
- ++i;
- }
-}
-
-/*!
- Loads \a out with all this node's member nodes that are class nodes.
- */
-void InnerNode::getMemberClasses(NodeMap& out)
-{
- out.clear();
- NodeList::const_iterator i = members_.begin();
- while (i != members_.end()) {
- if ((*i)->isClass())
- out.insert((*i)->name(),(*i));
- ++i;
- }
-}
-
-/*!
Find the node in this node's children that has the
given \a name. If this node is a QML class node, be
sure to also look in the children of its property
group nodes. Return the matching node or 0.
*/
-Node *InnerNode::findChildNodeByName(const QString& name)
+Node *InnerNode::findChildNode(const QString& name) const
{
Node *node = childMap.value(name);
- if (node && node->type() != QmlPropertyGroup)
+ if (node && !node->isQmlPropertyGroup())
return node;
- if ((type() == Document) && (subType() == QmlClass)) {
+ if (isQmlType()) {
for (int i=0; i<children_.size(); ++i) {
Node* n = children_.at(i);
- if (n->type() == QmlPropertyGroup) {
- node = static_cast<InnerNode*>(n)->findChildNodeByName(name);
+ if (n->isQmlPropertyGroup()) {
+ node = static_cast<InnerNode*>(n)->findChildNode(name);
if (node)
return node;
}
@@ -756,58 +731,6 @@ Node *InnerNode::findChildNodeByName(const QString& name)
}
return primaryFunctionMap.value(name);
}
-void InnerNode::findNodes(const QString& name, QList<Node*>& n)
-{
- n.clear();
- Node* node = 0;
- QList<Node*> nodes = childMap.values(name);
- /*
- <sigh> If this node's child map contains no nodes named
- name, then if this node is a QML class, seach each of its
- property group nodes for a node named name. If a match is
- found, append it to the output list and return immediately.
- */
- if (nodes.isEmpty()) {
- if ((type() == Document) && (subType() == QmlClass)) {
- for (int i=0; i<children_.size(); ++i) {
- node = children_.at(i);
- if (node->type() == QmlPropertyGroup) {
- node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
- if (node) {
- n.append(node);
- return;
- }
- }
- }
- }
- }
- else {
- /*
- If the childMap does contain one or more nodes named
- name, traverse the list of matching nodes. Append each
- matching node that is not a property group node to the
- output list. Search each property group node for a node
- named name and append that node to the output list.
- This is overkill, I think, but should produce a useful
- list.
- */
- for (int i=0; i<nodes.size(); ++i) {
- node = nodes.at(i);
- if (node->type() != QmlPropertyGroup)
- n.append(node);
- else {
- node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
- if (node)
- n.append(node);
- }
- }
- }
- if (!n.isEmpty())
- return;
- node = primaryFunctionMap.value(name);
- if (node)
- n.append(node);
-}
/*!
Find the node in this node's children that has the given \a name. If
@@ -819,7 +742,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n)
returns \c true. If \a qml is false, only match a node for which
node->isQmlNode() returns \c false.
*/
-Node* InnerNode::findChildNodeByName(const QString& name, bool qml)
+Node* InnerNode::findChildNode(const QString& name, bool qml) const
{
QList<Node*> nodes = childMap.values(name);
if (!nodes.isEmpty()) {
@@ -829,15 +752,15 @@ Node* InnerNode::findChildNodeByName(const QString& name, bool qml)
if (!node->isQmlNode())
return node;
}
- else if (node->isQmlNode() && (node->type() != QmlPropertyGroup))
+ else if (node->isQmlNode())
return node;
}
}
- if (qml && (type() == Document) && (subType() == QmlClass)) {
+ if (qml && isQmlType()) {
for (int i=0; i<children_.size(); ++i) {
Node* node = children_.at(i);
- if (node->type() == QmlPropertyGroup) {
- node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
+ if (node->isQmlPropertyGroup()) {
+ node = static_cast<InnerNode*>(node)->findChildNode(name);
if (node)
return node;
}
@@ -847,7 +770,7 @@ Node* InnerNode::findChildNodeByName(const QString& name, bool qml)
}
/*!
- This function is like findChildNodeByName(), but if a node
+ This function is like findChildNode(), but if a node
with the specified \a name is found but it is not of the
specified \a type, 0 is returned.
@@ -857,7 +780,7 @@ Node* InnerNode::findChildNodeByName(const QString& name, bool qml)
node because it looks up \a name in the child map, not the
list.
*/
-Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type)
+Node* InnerNode::findChildNode(const QString& name, Type type)
{
if (type == Function)
return primaryFunctionMap.value(name);
@@ -873,10 +796,65 @@ Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type)
}
/*!
+ */
+void InnerNode::findNodes(const QString& name, QList<Node*>& n)
+{
+ n.clear();
+ Node* node = 0;
+ QList<Node*> nodes = childMap.values(name);
+ /*
+ <sigh> If this node's child map contains no nodes named
+ name, then if this node is a QML class, search each of its
+ property group nodes for a node named name. If a match is
+ found, append it to the output list and return immediately.
+ */
+ if (nodes.isEmpty()) {
+ if (isQmlType()) {
+ for (int i=0; i<children_.size(); ++i) {
+ node = children_.at(i);
+ if (node->isQmlPropertyGroup()) {
+ node = static_cast<InnerNode*>(node)->findChildNode(name);
+ if (node) {
+ n.append(node);
+ return;
+ }
+ }
+ }
+ }
+ }
+ else {
+ /*
+ If the childMap does contain one or more nodes named
+ name, traverse the list of matching nodes. Append each
+ matching node that is not a property group node to the
+ output list. Search each property group node for a node
+ named name and append that node to the output list.
+ This is overkill, I think, but should produce a useful
+ list.
+ */
+ for (int i=0; i<nodes.size(); ++i) {
+ node = nodes.at(i);
+ if (!node->isQmlPropertyGroup())
+ n.append(node);
+ else {
+ node = static_cast<InnerNode*>(node)->findChildNode(name);
+ if (node)
+ n.append(node);
+ }
+ }
+ }
+ if (!n.isEmpty())
+ return;
+ node = primaryFunctionMap.value(name);
+ if (node)
+ n.append(node);
+}
+
+/*!
Find a function node that is a child of this nose, such
that the function node has the specified \a name.
*/
-FunctionNode *InnerNode::findFunctionNode(const QString& name)
+FunctionNode *InnerNode::findFunctionNode(const QString& name) const
{
return static_cast<FunctionNode *>(primaryFunctionMap.value(name));
}
@@ -985,19 +963,6 @@ void InnerNode::makeUndocumentedChildrenInternal()
}
/*!
- In each child node that is a collision node,
- clear the current child pointer.
- */
-void InnerNode::clearCurrentChildPointers()
-{
- foreach (Node* child, childNodes()) {
- if (child->subType() == Collision) {
- child->clearCurrentChild();
- }
- }
-}
-
-/*!
*/
void InnerNode::normalizeOverloads()
{
@@ -1092,64 +1057,17 @@ bool Node::isWrapper() const
}
/*!
- */
-const Node *InnerNode::findChildNodeByName(const QString& name) const
-{
- InnerNode *that = (InnerNode *) this;
- return that->findChildNodeByName(name);
-}
-
-/*!
- If \a qml is true, only match a node for which node->isQmlNode()
- returns \c true. If \a qml is false, only match a node for which
- node->isQmlNode() returns \c false.
- */
-const Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const
-{
- InnerNode*that = (InnerNode*) this;
- return that->findChildNodeByName(name, qml);
-}
-
-/*!
- Searches this node's children for a child named \a name
- with the specified node \a type.
- */
-const Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type) const
-{
- InnerNode *that = (InnerNode *) this;
- return that->findChildNodeByNameAndType(name, type);
-}
-
-/*!
- Find a function node that is a child of this nose, such
- that the function node has the specified \a name. This
- function calls the non-const version of itself.
- */
-const FunctionNode *InnerNode::findFunctionNode(const QString& name) const
-{
- InnerNode *that = (InnerNode *) this;
- return that->findFunctionNode(name);
-}
-
-/*!
- Find the function node that is a child of this node, such
- that the function has the same name and signature as the
- \a clone node. This function calls the non-const version.
- */
-const FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone) const
-{
- InnerNode *that = (InnerNode *) this;
- return that->findFunctionNode(clone);
-}
-
-/*!
+ Finds the enum type node that has \a enumValue as one of
+ its enum values and returns a pointer to it. Returns 0 if
+ no enum type node is found that has \a enumValue as one
+ of its values.
*/
const EnumNode *InnerNode::findEnumNodeForValue(const QString &enumValue) const
{
foreach (const Node *node, enumChildren_) {
- const EnumNode *enume = static_cast<const EnumNode *>(node);
- if (enume->hasItem(enumValue))
- return enume;
+ const EnumNode *en = static_cast<const EnumNode *>(node);
+ if (en->hasItem(enumValue))
+ return en;
}
return 0;
}
@@ -1194,6 +1112,7 @@ InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name)
{
switch (type) {
case Class:
+ case QmlType:
case Namespace:
setPageType(ApiPage);
break;
@@ -1278,6 +1197,17 @@ void InnerNode::addChild(Node *child)
}
/*!
+ Adds the \a child to this node's child map using \a title
+ as the key. The \a child is not added to the child list
+ again, because it is presumed to already be there. We just
+ want to be able to find the child by its \a title.
+ */
+void InnerNode::addChild(Node* child, const QString& title)
+{
+ childMap.insertMulti(title, child);
+}
+
+/*!
*/
void InnerNode::removeChild(Node *child)
{
@@ -1307,6 +1237,16 @@ void InnerNode::removeChild(Node *child)
}
++ent;
}
+ if (child->title().isEmpty())
+ return;
+ ent = childMap.find(child->title());
+ while (ent != childMap.end() && ent.key() == child->title()) {
+ if (*ent == child) {
+ childMap.erase(ent);
+ break;
+ }
+ ++ent;
+ }
}
/*!
@@ -1381,7 +1321,7 @@ QmlPropertyNode* InnerNode::hasQmlProperty(const QString& n) const
if (child->name() == n)
return static_cast<QmlPropertyNode*>(child);
}
- else if (child->type() == Node::QmlPropertyGroup) {
+ else if (child->isQmlPropertyGroup()) {
QmlPropertyNode* t = child->hasQmlProperty(n);
if (t)
return t;
@@ -1414,6 +1354,7 @@ LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name)
case QmlSignal:
case QmlSignalHandler:
case QmlMethod:
+ case QmlBasicType:
setPageType(ApiPage);
break;
default:
@@ -1457,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);
}
@@ -1480,13 +1421,36 @@ ClassNode::ClassNode(InnerNode *parent, const QString& name)
}
/*!
+ Adds the base class \a node to this class's list of base
+ classes. The base class has the specified \a access. This
+ is a resolved base class.
*/
-void ClassNode::addBaseClass(Access access,
- ClassNode *node,
- const QString &dataTypeWithTemplateArgs)
+void ClassNode::addResolvedBaseClass(Access access, ClassNode* node)
{
- bases.append(RelatedClass(access, node, dataTypeWithTemplateArgs));
- node->derived.append(RelatedClass(access, this));
+ bases_.append(RelatedClass(access, node));
+ node->derived_.append(RelatedClass(access, this));
+}
+
+/*!
+ Adds the derived class \a node to this class's list of derived
+ classes. The derived class inherits this class with \a access.
+ */
+void ClassNode::addDerivedClass(Access access, ClassNode* node)
+{
+ derived_.append(RelatedClass(access, node));
+}
+
+/*!
+ Add an unresolved base class to this class node's list of
+ base classes. The unresolved base class will be resolved
+ before the generate phase of qdoc. In an unresolved base
+ class, the pointer to the base class node is 0.
+ */
+void ClassNode::addUnresolvedBaseClass(Access access,
+ const QStringList& path,
+ const QString& signature)
+{
+ bases_.append(RelatedClass(access, path, signature));
}
/*!
@@ -1498,15 +1462,15 @@ void ClassNode::fixBaseClasses()
QSet<ClassNode *> found;
// Remove private and duplicate base classes.
- while (i < bases.size()) {
- ClassNode* bc = bases.at(i).node;
- if (bc->access() == Node::Private || found.contains(bc)) {
- RelatedClass rc = bases.at(i);
- bases.removeAt(i);
- ignoredBases.append(rc);
+ while (i < bases_.size()) {
+ ClassNode* bc = bases_.at(i).node_;
+ if (bc && (bc->access() == Node::Private || found.contains(bc))) {
+ RelatedClass rc = bases_.at(i);
+ bases_.removeAt(i);
+ ignoredBases_.append(rc);
const QList<RelatedClass> &bb = bc->baseClasses();
for (int j = bb.size() - 1; j >= 0; --j)
- bases.insert(i, bb.at(j));
+ bases_.insert(i, bb.at(j));
}
else {
++i;
@@ -1515,13 +1479,13 @@ void ClassNode::fixBaseClasses()
}
i = 0;
- while (i < derived.size()) {
- ClassNode* dc = derived.at(i).node;
- if (dc->access() == Node::Private) {
- derived.removeAt(i);
+ while (i < derived_.size()) {
+ ClassNode* dc = derived_.at(i).node_;
+ if (dc && dc->access() == Node::Private) {
+ derived_.removeAt(i);
const QList<RelatedClass> &dd = dc->derivedClasses();
for (int j = dd.size() - 1; j >= 0; --j)
- derived.insert(i, dd.at(j));
+ derived_.insert(i, dd.at(j));
}
else {
++i;
@@ -1530,12 +1494,34 @@ void ClassNode::fixBaseClasses()
}
/*!
+ Not sure why this is needed.
+ */
+void ClassNode::fixPropertyUsingBaseClasses(PropertyNode* pn)
+{
+ QList<RelatedClass>::const_iterator bc = baseClasses().constBegin();
+ while (bc != baseClasses().constEnd()) {
+ ClassNode* cn = bc->node_;
+ if (cn) {
+ Node* n = cn->findChildNode(pn->name(), Node::Property);
+ if (n) {
+ PropertyNode* baseProperty = static_cast<PropertyNode*>(n);
+ cn->fixPropertyUsingBaseClasses(baseProperty);
+ pn->setOverriddenFrom(baseProperty);
+ }
+ else
+ cn->fixPropertyUsingBaseClasses(pn);
+ }
+ ++bc;
+ }
+}
+
+/*!
Search the child list to find the property node with the
specified \a name.
*/
PropertyNode* ClassNode::findPropertyNode(const QString& name)
{
- Node* n = findChildNodeByNameAndType(name, Node::Property);
+ Node* n = findChildNode(name, Node::Property);
if (n)
return static_cast<PropertyNode*>(n);
@@ -1545,19 +1531,23 @@ PropertyNode* ClassNode::findPropertyNode(const QString& name)
const QList<RelatedClass> &bases = baseClasses();
if (!bases.isEmpty()) {
for (int i = 0; i < bases.size(); ++i) {
- ClassNode* cn = bases[i].node;
- pn = cn->findPropertyNode(name);
- if (pn)
- break;
+ ClassNode* cn = bases[i].node_;
+ if (cn) {
+ pn = cn->findPropertyNode(name);
+ if (pn)
+ break;
+ }
}
}
const QList<RelatedClass>& ignoredBases = ignoredBaseClasses();
if (!ignoredBases.isEmpty()) {
for (int i = 0; i < ignoredBases.size(); ++i) {
- ClassNode* cn = ignoredBases[i].node;
- pn = cn->findPropertyNode(name);
- if (pn)
- break;
+ ClassNode* cn = ignoredBases[i].node_;
+ if (cn) {
+ pn = cn->findPropertyNode(name);
+ if (pn)
+ break;
+ }
}
}
@@ -1577,13 +1567,13 @@ QmlClassNode* ClassNode::findQmlBaseNode()
if (!bases.isEmpty()) {
for (int i = 0; i < bases.size(); ++i) {
- ClassNode* cn = bases[i].node;
+ ClassNode* cn = bases[i].node_;
if (cn && cn->qmlElement()) {
return cn->qmlElement();
}
}
for (int i = 0; i < bases.size(); ++i) {
- ClassNode* cn = bases[i].node;
+ ClassNode* cn = bases[i].node_;
if (cn) {
result = cn->findQmlBaseNode();
if (result != 0) {
@@ -1614,17 +1604,6 @@ DocNode::DocNode(InnerNode* parent, const QString& name, SubType subtype, Node::
case DitaMap:
setPageType(ptype);
break;
- case Module:
- case Group:
- setPageType(OverviewPage);
- break;
- case QmlModule:
- setPageType(OverviewPage);
- break;
- case QmlClass:
- case QmlBasicType:
- setPageType(ApiPage);
- break;
case Example:
setPageType(ExamplePage);
break;
@@ -1636,12 +1615,17 @@ DocNode::DocNode(InnerNode* parent, const QString& name, SubType subtype, Node::
}
}
-/*!
+/*! \fn QString DocNode::title() const
Returns the document node's title. This is used for the page title.
*/
-QString DocNode::title() const
+
+/*!
+ Sets the document node's \a title. This is used for the page title.
+ */
+void DocNode::setTitle(const QString &title)
{
- return title_;
+ title_ = title;
+ parent()->addChild(this, title);
}
/*!
@@ -1693,16 +1677,6 @@ QString DocNode::subTitle() const
}
/*!
- The constructor calls the DocNode constructor with
- \a parent, \a name, and Node::Example.
- */
-ExampleNode::ExampleNode(InnerNode* parent, const QString& name)
- : DocNode(parent, name, Node::Example, Node::ExamplePage)
-{
- // nothing
-}
-
-/*!
\class EnumNode
*/
@@ -2115,18 +2089,17 @@ 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),
cnode_(0),
qmlModule_(0),
- baseNode_(0)
+ qmlBaseNode_(0)
{
int i = 0;
if (name.startsWith("QML:")) {
@@ -2134,6 +2107,7 @@ QmlClassNode::QmlClassNode(InnerNode *parent, const QString& name)
i = 4;
}
setTitle(name.mid(i));
+ setPageType(Node::ApiPage);
}
/*!
@@ -2198,6 +2172,14 @@ void QmlModuleNode::setQmlModuleInfo(const QString& arg)
}
}
+QmlClassNode* QmlClassNode::qmlBaseNode()
+{
+ if (!qmlBaseNode_ && !qmlBaseName_.isEmpty()) {
+ qmlBaseNode_ = QDocDatabase::qdocDB()->findQmlType(qmlBaseName_);
+ }
+ return qmlBaseNode_;
+}
+
/*!
If this QML type node has a base type node,
return the fully qualified name of that QML
@@ -2206,45 +2188,13 @@ void QmlModuleNode::setQmlModuleInfo(const QString& arg)
QString QmlClassNode::qmlFullBaseName() const
{
QString result;
- if (baseNode_) {
- result = baseNode_->qmlModuleName() + "::" + baseNode_->name();
+ if (qmlBaseNode_) {
+ result = qmlBaseNode_->qmlModuleName() + "::" + qmlBaseNode_->name();
}
return result;
}
/*!
- The name of this QML class node might be the same as the
- name of some other QML class node. If so, then this node's
- parent will be a NameCollisionNode.This function sets the
- NameCollisionNode's current child to this node. This is
- important when outputting the documentation for this node,
- when, for example, the documentation contains a link to
- the page being output. We don't want to generate a link
- to the disambiguation page if we can avoid it, and to be
- able to avoid it, the NameCollisionNode must maintain the
- current child pointer. That's the purpose of this function.
- */
-void QmlClassNode::setCurrentChild()
-{
- if (parent()) {
- InnerNode* n = parent();
- if (n->subType() == Node::Collision)
- n->setCurrentChild(this);
- }
-}
-
-/*!
- */
-void QmlClassNode::clearCurrentChild()
-{
- if (parent()) {
- InnerNode* n = parent();
- if (n->subType() == Node::Collision)
- n->clearCurrentChild();
- }
-}
-
-/*!
If the QML type's QML module pointer is set, return the QML
module name from the QML module node. Otherwise, return the
empty string.
@@ -2275,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);
}
@@ -2345,7 +2294,7 @@ QmlPropertyNode::QmlPropertyNode(InnerNode* parent,
...because the tokenizer gets confused on \e{explicit}.
*/
-bool QmlPropertyNode::isWritable(QDocDatabase* qdb)
+bool QmlPropertyNode::isWritable()
{
if (readOnly_ != FlagValueDefault)
return !fromFlagValue(readOnly_, false);
@@ -2354,7 +2303,7 @@ bool QmlPropertyNode::isWritable(QDocDatabase* qdb)
if (qcn) {
if (qcn->cppClassRequired()) {
if (qcn->classNode()) {
- PropertyNode* pn = correspondingProperty(qdb);
+ PropertyNode* pn = findCorrespondingCppProperty();
if (pn)
return pn->isWritable();
else
@@ -2377,49 +2326,63 @@ bool QmlPropertyNode::isWritable(QDocDatabase* qdb)
Returns a pointer this QML property's corresponding C++
property, if it has one.
*/
-PropertyNode* QmlPropertyNode::correspondingProperty(QDocDatabase* qdb)
+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);
ClassNode* cn = qcn->classNode();
if (cn) {
+ /*
+ If there is a dot in the property name, first
+ find the C++ property corresponding to the QML
+ property group.
+ */
QStringList dotSplit = name().split(QChar('.'));
pn = cn->findPropertyNode(dotSplit[0]);
if (pn) {
+ /*
+ Now find the C++ property corresponding to
+ the QML property in the QML property group,
+ <group>.<property>.
+ */
if (dotSplit.size() > 1) {
- // Find the C++ property corresponding to the QML property in
- // the property group, <group>.<property>.
-
QStringList path(extractClassName(pn->qualifiedDataType()));
- Node* nn = qdb->findClassNode(path);
+ Node* nn = QDocDatabase::qdocDB()->findClassNode(path);
if (nn) {
ClassNode* cn = static_cast<ClassNode*>(nn);
PropertyNode *pn2 = cn->findPropertyNode(dotSplit[1]);
- if (pn2)
- return pn2; // Return the property for the QML property.
- else
- return pn; // Return the property for the QML group.
+ /*
+ If found, return the C++ property
+ corresponding to the QML property.
+ Otherwise, return the C++ property
+ corresponding to the QML property
+ group.
+ */
+ return (pn2 ? pn2 : pn);
}
}
else
return pn;
}
- else {
- pn = cn->findPropertyNode(dotSplit[0]);
- if (pn)
- return pn;
- }
}
}
-
return 0;
}
+/*!
+ This returns the name of the owning QML type.
+ */
+QString QmlPropertyNode::element() const
+{
+ if (parent()->isQmlPropertyGroup())
+ return parent()->element();
+ return parent()->name();
+}
+
/*! \class NameCollisionNode
An instance of this node is inserted in the tree
@@ -2437,7 +2400,6 @@ NameCollisionNode::NameCollisionNode(InnerNode* child)
{
setTitle("Name Collision: " + child->name());
addCollision(child);
- current = 0;
}
/*!
@@ -2463,28 +2425,11 @@ NameCollisionNode::~NameCollisionNode()
// nothing.
}
-/*! \fn const InnerNode* NameCollisionNode::currentChild() const
- Returns a pointer to the current child, which may be 0.
- */
-
-/*! \fn void NameCollisionNode::setCurrentChild(InnerNode* child)
- Sets the current child to \a child. The current child is
- valid only within the file where it is defined.
- */
-
-/*! \fn void NameCollisionNode::clearCurrentChild()
- Sets the current child to 0. This should be called at the
- end of each file, because the current child is only valid
- within the file where the child is defined.
- */
-
/*!
Returns \c true if this collision node's current node is a QML node.
*/
bool NameCollisionNode::isQmlNode() const
{
- if (current)
- return current->isQmlNode();
return false;
}
@@ -2494,10 +2439,6 @@ bool NameCollisionNode::isQmlNode() const
*/
InnerNode* NameCollisionNode::findAny(Node::Type t, Node::SubType st)
{
- if (current) {
- if (current->type() == t && current->subType() == st)
- return current;
- }
const NodeList& cn = childNodes();
NodeList::ConstIterator i = cn.constBegin();
while (i != cn.constEnd()) {
@@ -2520,7 +2461,7 @@ const Node* NameCollisionNode::applyModuleName(const Node* origin) const
const NodeList& cn = childNodes();
NodeList::ConstIterator i = cn.constBegin();
while (i != cn.constEnd()) {
- if ((*i)->type() == Node::Document && (*i)->subType() == Node::QmlClass) {
+ if ((*i)->isQmlType()) {
if (origin->qmlModuleName() == (*i)->qmlModuleName())
return (*i);
}
@@ -2531,6 +2472,49 @@ const Node* NameCollisionNode::applyModuleName(const Node* origin) const
}
/*!
+ First, find all the colliding nodes that have the correct
+ type \a t and subtype \a st. If there is only one node
+ having the correct type and subtype, return that one.
+ If there is more than one node having the correct type
+ and subtype, then, in that subset, if there is only one
+ non-index node, return that one. If there are multiple
+ non-index nodes, return this collision node because we
+ can't disambiguate. Otherwise, if there are multiple
+ nodes having the correct type and subtype, return this
+ collision node because, again, we can't disambiguate.
+ But if there are no nodes at all that have the correct
+ type and subtype, return 0.
+ */
+Node* NameCollisionNode::disambiguate(Type t, SubType st)
+{
+ NodeList nl;
+ const NodeList& cn = childNodes();
+ NodeList::ConstIterator i = cn.constBegin();
+ while (i != cn.constEnd()) {
+ if ((*i)->type() == t) {
+ if ((st == NoSubType) || ((*i)->subType() == st))
+ nl.append((*i));
+ }
+ ++i;
+ }
+ Node* n = 0;
+ if (!nl.isEmpty()) {
+ i = nl.constBegin();
+ if (nl.size() == 1)
+ return (*i);
+ while (i != nl.constEnd()) {
+ if (!(*i)->isIndexNode()) {
+ if (n)
+ return this;
+ n = (*i);
+ }
+ ++i;
+ }
+ }
+ return n;
+}
+
+/*!
Construct the full document name for this node and return it.
*/
QString Node::fullDocumentName() const
@@ -2539,15 +2523,17 @@ QString Node::fullDocumentName() const
const Node* n = this;
do {
- if (!n->name().isEmpty() && n->type() != Node::QmlPropertyGroup)
+ 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();
@@ -2557,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);
@@ -2732,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:"
@@ -2752,15 +2737,16 @@ 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::Group:
- case Node::Module:
case Node::HeaderFile:
str = title();
if (str.isEmpty()) {
@@ -2778,12 +2764,6 @@ QString Node::idForNode() const
str = name();
str.replace(QLatin1Char('/'), QLatin1Char('-'));
break;
- case Node::QmlBasicType:
- str = "qml-basic-type-" + name();
- break;
- case Node::QmlModule:
- str = "qml-module-" + name();
- break;
case Node::Collision:
str = title();
str.replace(": ","-");
@@ -2795,6 +2775,19 @@ QString Node::idForNode() const
}
}
break;
+ case Node::Group:
+ case Node::Module:
+ str = title();
+ if (str.isEmpty()) {
+ str = name();
+ if (str.endsWith(".html"))
+ str.remove(str.size()-5,5);
+ }
+ str.replace(QLatin1Char('/'), QLatin1Char('-'));
+ break;
+ case Node::QmlModule:
+ str = "qml-module-" + name();
+ break;
case Node::QmlProperty:
str = "qml-property-" + name();
break;
@@ -2855,10 +2848,93 @@ void InnerNode::printChildren(const QString& title)
}
/*!
- Prints the inner node's list of members.
+ Returns \c true if the collection node's member list is
+ not empty.
+ */
+bool CollectionNode::hasMembers() const
+{
+ return !members_.isEmpty();
+}
+
+/*!
+ Appends \a node to the collection node's member list, if
+ and only if it isn't already in the member list.
+ */
+void CollectionNode::addMember(Node* node)
+{
+ if (!members_.contains(node))
+ members_.append(node);
+}
+
+/*!
+ Returns \c true if this collection node contains at least
+ one namespace node.
+ */
+bool CollectionNode::hasNamespaces() const
+{
+ if (!members_.isEmpty()) {
+ NodeList::const_iterator i = members_.begin();
+ while (i != members_.end()) {
+ if ((*i)->isNamespace())
+ return true;
+ ++i;
+ }
+ }
+ return false;
+}
+
+/*!
+ Returns \c true if this collection node contains at least
+ one class node.
+ */
+bool CollectionNode::hasClasses() const
+{
+ if (!members_.isEmpty()) {
+ NodeList::const_iterator i = members_.begin();
+ while (i != members_.end()) {
+ if ((*i)->isClass())
+ return true;
+ ++i;
+ }
+ }
+ return false;
+}
+
+/*!
+ Loads \a out with all this collection node's members that
+ are namespace nodes.
+ */
+void CollectionNode::getMemberNamespaces(NodeMap& out)
+{
+ out.clear();
+ NodeList::const_iterator i = members_.begin();
+ while (i != members_.end()) {
+ if ((*i)->isNamespace())
+ out.insert((*i)->name(),(*i));
+ ++i;
+ }
+}
+
+/*!
+ Loads \a out with all this collection node's members that
+ are class nodes.
+ */
+void CollectionNode::getMemberClasses(NodeMap& out)
+{
+ out.clear();
+ NodeList::const_iterator i = members_.begin();
+ while (i != members_.end()) {
+ if ((*i)->isClass())
+ out.insert((*i)->name(),(*i));
+ ++i;
+ }
+}
+
+/*!
+ Prints the collection node's list of members.
For debugging only.
*/
-void InnerNode::printMembers(const QString& title)
+void CollectionNode::printMembers(const QString& title)
{
qDebug() << title << name() << members_.size();
if (members_.size() > 0) {
@@ -2869,4 +2945,13 @@ void InnerNode::printMembers(const QString& title)
}
}
+/*!
+ Sets the document node's \a title. This is used for the page title.
+ */
+void CollectionNode::setTitle(const QString& title)
+{
+ title_ = title;
+ parent()->addChild(this, title);
+}
+
QT_END_NAMESPACE
diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h
index 236b495bd0..ebdaad9010 100644
--- a/src/tools/qdoc/node.h
+++ b/src/tools/qdoc/node.h
@@ -49,24 +49,32 @@
#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;
class ExampleNode;
+class TypedefNode;
class QmlClassNode;
class QDocDatabase;
+class FunctionNode;
+class PropertyNode;
class QmlModuleNode;
+class CollectionNode;
class QmlPropertyNode;
+class NameCollisionNode;
typedef QList<Node*> NodeList;
typedef QMap<QString, Node*> NodeMap;
typedef QMultiMap<QString, Node*> NodeMultiMap;
-typedef QMultiMap<QString, const ExampleNode*> ExampleNodeMap;
+typedef QPair<int, int> NodeTypePair;
+typedef QList<NodeTypePair> NodeTypeList;
+typedef QMap<QString, CollectionNode*> CNMap;
+typedef QMultiMap<QString, CollectionNode*> CNMultiMap;
class Node
{
@@ -74,6 +82,7 @@ class Node
public:
enum Type {
+ NoType,
Namespace,
Class,
Document,
@@ -82,11 +91,16 @@ public:
Function,
Property,
Variable,
+ Group,
+ Module,
+ QmlType,
+ QmlModule,
QmlPropertyGroup,
QmlProperty,
QmlSignal,
QmlSignalHandler,
QmlMethod,
+ QmlBasicType,
LastType
};
@@ -96,13 +110,8 @@ public:
HeaderFile,
File,
Image,
- Group,
- Module,
Page,
ExternalPage,
- QmlClass,
- QmlBasicType,
- QmlModule,
DitaMap,
Collision,
LastSubtype
@@ -165,10 +174,11 @@ public:
QString plainName() const;
QString plainFullName(const Node* relative = 0) const;
QString fullName(const Node* relative=0) const;
- const QString& baseName() const { return baseName_; }
- bool hasBaseName() const { return !baseName_.isEmpty(); }
- void setBaseName(const QString& bn) { baseName_ = bn; }
+ const QString& fileNameBase() const { return fileNameBase_; }
+ bool hasFileNameBase() const { return !fileNameBase_.isEmpty(); }
+ void setFileNameBase(const QString& t) { fileNameBase_ = t; }
+
void setAccess(Access access) { access_ = access; }
void setLocation(const Location& location) { loc_ = location; }
void setDoc(const Doc& doc, bool replace = false);
@@ -181,8 +191,7 @@ public:
void setSince(const QString &since);
void setRelates(InnerNode* pseudoParent);
void setModuleName(const QString &name) { moduleName_ = name; }
- void setLink(LinkType linkType, const QString &link, const QString &desc);
- void setUrl(const QString &url);
+ void setUrl(const QString& url) { url_ = url; }
void setTemplateStuff(const QString &templateStuff) { templateStuff_ = templateStuff; }
void setReconstitutedBrief(const QString &t) { reconstitutedBrief_ = t; }
void setPageType(PageType t) { pageType_ = t; }
@@ -190,14 +199,18 @@ public:
void setParent(InnerNode* n) { parent_ = n; }
void setIndexNodeFlag() { indexNodeFlag_ = true; }
virtual void setOutputFileName(const QString& ) { }
- void markSeen() { seen_ = true; }
- void markNotSeen() { seen_ = false; }
virtual bool isInnerNode() const = 0;
+ virtual bool isDocNode() const { return false; }
+ virtual bool isCollectionNode() const { return false; }
+ virtual bool isGroup() const { return false; }
+ virtual bool isModule() const { return false; }
virtual bool isQmlModule() const { return false; }
virtual bool isQmlType() const { return false; }
+ virtual bool isQmlBasicType() const { return false; }
virtual bool isExample() const { return false; }
virtual bool isExampleFile() const { return false; }
+ virtual bool isHeaderFile() const { return false; }
virtual bool isLeaf() const { return false; }
virtual bool isReimp() const { return false; }
virtual bool isFunction() const { return false; }
@@ -210,7 +223,6 @@ public:
virtual bool isCollisionNode() const { return false; }
virtual bool isAttached() const { return false; }
virtual bool isAlias() const { return false; }
- virtual bool isGroup() const { return false; }
virtual bool isWrapper() const;
virtual bool isReadOnly() const { return false; }
virtual bool isDefault() const { return false; }
@@ -221,34 +233,50 @@ public:
virtual bool hasClasses() const { return false; }
virtual void setAbstract(bool ) { }
virtual void setWrapper() { }
- virtual QString title() const { return QString(); }
+ virtual QString title() const { return name(); }
+ virtual QString fullTitle() const { return name(); }
+ virtual QString subTitle() const { return QString(); }
+ virtual void setTitle(const QString& ) { }
+ virtual void setSubTitle(const QString& ) { }
virtual QmlPropertyNode* hasQmlProperty(const QString& ) const { return 0; }
virtual void getMemberNamespaces(NodeMap& ) { }
virtual void getMemberClasses(NodeMap& ) { }
virtual bool isInternal() const;
virtual void setDataType(const QString& ) { }
virtual void setReadOnly(bool ) { }
+ virtual Node* disambiguate(Type , SubType ) { return this; }
+ 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_; }
- bool wasSeen() const { return seen_; }
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_; }
- const QMap<LinkType, QPair<QString,QString> >& links() const { return linkMap_; }
QString moduleName() const;
- QString url() const;
+ QString url() const { return url_; }
virtual QString nameForLists() const { return name_; }
virtual QString outputFileName() const { return QString(); }
virtual QString obsoleteLink() const { return QString(); }
virtual void setObsoleteLink(const QString& ) { };
+ virtual void setQtVariable(const QString& ) { }
+ virtual QString qtVariable() const { return QString(); }
+
+ const QMap<LinkType, QPair<QString,QString> >& links() const { return linkMap_; }
+ void setLink(LinkType linkType, const QString &link, const QString &desc);
Access access() const { return access_; }
QString accessString() const;
const Location& location() const { return loc_; }
const Doc& doc() const { return doc_; }
+ bool hasDoc() const { return !doc_.isEmpty(); }
Status status() const { return status_; }
Status inheritedStatus() const;
+ bool isObsolete() const { return (status_ == Obsolete); }
ThreadSafeness threadSafeness() const;
ThreadSafeness inheritedThreadSafeness() const;
QString since() const { return since_; }
@@ -274,7 +302,6 @@ public:
virtual void setQmlModule(QmlModuleNode* ) { }
virtual ClassNode* classNode() { return 0; }
virtual void setClassNode(ClassNode* ) { }
- virtual void clearCurrentChild() { }
virtual const Node* applyModuleName(const Node* ) const { return 0; }
virtual QString idNumber() { return "0"; }
QmlClassNode* qmlClassNode();
@@ -293,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);
@@ -305,7 +334,6 @@ private:
PageType pageType_;
Status status_;
bool indexNodeFlag_;
- bool seen_;
InnerNode* parent_;
InnerNode* relatesTo_;
@@ -313,7 +341,7 @@ private:
Location loc_;
Doc doc_;
QMap<LinkType, QPair<QString, QString> > linkMap_;
- QString baseName_;
+ QString fileNameBase_;
QString moduleName_;
QString url_;
QString since_;
@@ -323,51 +351,34 @@ private:
QString outSubDir_;
static QStringMap operators_;
static int propertyGroupCount_;
+ static QMap<QString,Node::Type> goals_;
};
-class FunctionNode;
-class EnumNode;
-class NameCollisionNode;
-
class InnerNode : public Node
{
public:
virtual ~InnerNode();
- Node* findChildNodeByName(const QString& name);
- Node* findChildNodeByName(const QString& name, bool qml);
- Node* findChildNodeByNameAndType(const QString& name, Type type);
+ Node* findChildNode(const QString& name) const;
+ Node* findChildNode(const QString& name, bool qml) const;
+ Node* findChildNode(const QString& name, Type type);
void findNodes(const QString& name, QList<Node*>& n);
- FunctionNode* findFunctionNode(const QString& name);
+ FunctionNode* findFunctionNode(const QString& name) const;
FunctionNode* findFunctionNode(const FunctionNode* clone);
void addInclude(const QString &include);
void setIncludes(const QStringList &includes);
void setOverload(const FunctionNode* func, bool overlode);
void normalizeOverloads();
void makeUndocumentedChildrenInternal();
- void clearCurrentChildPointers();
void deleteChildren();
void removeFromRelated();
virtual bool isInnerNode() const { return true; }
virtual bool isLeaf() const { return false; }
- const Node* findChildNodeByName(const QString& name) const;
- const Node* findChildNodeByName(const QString& name, bool qml) const;
- const Node* findChildNodeByNameAndType(const QString& name, Type type) const;
- const FunctionNode* findFunctionNode(const QString& name) const;
- const FunctionNode* findFunctionNode(const FunctionNode* clone) const;
const EnumNode* findEnumNodeForValue(const QString &enumValue) const;
const NodeList & childNodes() const { return children_; }
const NodeList & relatedNodes() const { return related_; }
- virtual void addMember(Node* node);
- const NodeList& members() const { return members_; }
- virtual bool hasMembers() const;
- virtual bool hasNamespaces() const;
- virtual bool hasClasses() const;
- virtual void getMemberNamespaces(NodeMap& out);
- virtual void getMemberClasses(NodeMap& out);
-
int count() const { return children_.size(); }
int overloadNumber(const FunctionNode* func) const;
NodeList overloads(const QString &funcName) const;
@@ -377,14 +388,13 @@ public:
QStringList secondaryKeys();
const QStringList& pageKeywords() const { return pageKeywds; }
virtual void addPageKeywords(const QString& t) { pageKeywds << t; }
- virtual void setCurrentChild() { }
- virtual void setCurrentChild(InnerNode* ) { }
virtual void setOutputFileName(const QString& f) { outputFileName_ = f; }
virtual QString outputFileName() const { return outputFileName_; }
virtual QmlPropertyNode* hasQmlProperty(const QString& ) const;
-
+ void addChild(Node* child, const QString& title);
+ const QStringList& groupNames() const { return groupNames_; }
+ virtual void appendGroupName(const QString& t) { groupNames_.append(t); }
void printChildren(const QString& title);
- void printMembers(const QString& title);
protected:
InnerNode(Type type, InnerNode* parent, const QString& name);
@@ -401,8 +411,8 @@ private:
QString outputFileName_;
QStringList pageKeywds;
QStringList includes_;
+ QStringList groupNames_;
NodeList children_;
- NodeList members_;
NodeList enumChildren_;
NodeList related_;
QMap<QString, Node*> childMap;
@@ -430,28 +440,31 @@ 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; }
-class ClassNode;
+ private:
+ Tree* tree_;
+};
struct RelatedClass
{
RelatedClass() { }
- RelatedClass(Node::Access access0,
- ClassNode* node0,
- const QString& dataTypeWithTemplateArgs0 = QString())
- : access(access0),
- node(node0),
- dataTypeWithTemplateArgs(dataTypeWithTemplateArgs0) { }
+ // constructor for resolved base class
+ RelatedClass(Node::Access access, ClassNode* node)
+ : access_(access), node_(node) { }
+ // constructor for unresolved base class
+ RelatedClass(Node::Access access, const QStringList& path, const QString& signature)
+ : access_(access), node_(0), path_(path), signature_(signature) { }
QString accessString() const;
+ bool isPrivate() const { return (access_ == Node::Private); }
- Node::Access access;
- ClassNode* node;
- QString dataTypeWithTemplateArgs;
+ Node::Access access_;
+ ClassNode* node_;
+ QStringList path_;
+ QString signature_;
};
-class PropertyNode;
-
class ClassNode : public InnerNode
{
public:
@@ -463,14 +476,19 @@ public:
virtual void setObsoleteLink(const QString& t) { obsoleteLink_ = t; }
virtual void setWrapper() { wrapper_ = true; }
- void addBaseClass(Access access,
- ClassNode* node,
- const QString &dataTypeWithTemplateArgs = QString());
+ void addResolvedBaseClass(Access access, ClassNode* node);
+ void addDerivedClass(Access access, ClassNode* node);
+ void addUnresolvedBaseClass(Access access, const QStringList& path, const QString& signature);
void fixBaseClasses();
+ void fixPropertyUsingBaseClasses(PropertyNode* pn);
- const QList<RelatedClass> &baseClasses() const { return bases; }
- const QList<RelatedClass> &derivedClasses() const { return derived; }
- const QList<RelatedClass> &ignoredBaseClasses() const { return ignoredBases; }
+ QList<RelatedClass>& baseClasses() { return bases_; }
+ QList<RelatedClass>& derivedClasses() { return derived_; }
+ QList<RelatedClass>& ignoredBaseClasses() { return ignoredBases_; }
+
+ const QList<RelatedClass> &baseClasses() const { return bases_; }
+ const QList<RelatedClass> &derivedClasses() const { return derived_; }
+ const QList<RelatedClass> &ignoredBaseClasses() const { return ignoredBases_; }
QString serviceName() const { return sname; }
void setServiceName(const QString& value) { sname = value; }
@@ -482,9 +500,9 @@ public:
QmlClassNode* findQmlBaseNode();
private:
- QList<RelatedClass> bases;
- QList<RelatedClass> derived;
- QList<RelatedClass> ignoredBases;
+ QList<RelatedClass> bases_;
+ QList<RelatedClass> derived_;
+ QList<RelatedClass> ignoredBases_;
bool abstract_;
bool wrapper_;
QString sname;
@@ -502,49 +520,26 @@ public:
PageType ptype);
virtual ~DocNode() { }
- void setQtVariable(const QString &variable) { qtVariable_ = variable; }
- void setTitle(const QString &title) { title_ = title; }
- void setSubTitle(const QString &subTitle) { subtitle_ = subTitle; }
+ virtual void setTitle(const QString &title);
+ virtual void setSubTitle(const QString &subTitle) { subtitle_ = subTitle; }
- QString qtVariable() const { return qtVariable_; }
SubType subType() const { return nodeSubtype_; }
- virtual QString title() const;
+ virtual QString title() const { return title_; }
virtual QString fullTitle() const;
virtual QString subTitle() const;
virtual QString imageFileName() const { return QString(); }
virtual QString nameForLists() const { return title(); }
virtual void setImageFileName(const QString& ) { }
- virtual bool isGroup() const { return (subType() == Node::Group); }
+ virtual bool isHeaderFile() const { return (subType() == Node::HeaderFile); }
virtual bool isExample() const { return (subType() == Node::Example); }
virtual bool isExampleFile() const { return (parent() && parent()->isExample()); }
virtual bool isExternalPage() const { return nodeSubtype_ == ExternalPage; }
+ virtual bool isDocNode() const { return true; }
protected:
SubType nodeSubtype_;
QString title_;
QString subtitle_;
-
-private:
- QString qtVariable_;
-};
-
-class QmlModuleNode : public DocNode
-{
- public:
- QmlModuleNode(InnerNode* parent, const QString& name)
- : DocNode(parent, name, Node::QmlModule, Node::OverviewPage) { }
- virtual ~QmlModuleNode() { }
-
- virtual bool isQmlModule() const { return true; }
- virtual QString qmlModuleName() const { return qmlModuleName_; }
- virtual QString qmlModuleVersion() const { return qmlModuleVersionMajor_ + "." + qmlModuleVersionMinor_; }
- virtual QString qmlModuleIdentifier() const { return qmlModuleName_ + qmlModuleVersionMajor_; }
- virtual void setQmlModuleInfo(const QString& );
-
- private:
- QString qmlModuleName_;
- QString qmlModuleVersionMajor_;
- QString qmlModuleVersionMinor_;
};
class NameCollisionNode : public DocNode
@@ -552,35 +547,28 @@ class NameCollisionNode : public DocNode
public:
NameCollisionNode(InnerNode* child);
~NameCollisionNode();
- const InnerNode* currentChild() const { return current; }
- virtual void setCurrentChild(InnerNode* child) { current = child; }
- virtual void clearCurrentChild() { current = 0; }
virtual bool isQmlNode() const;
virtual bool isCollisionNode() const { return true; }
virtual const Node* applyModuleName(const Node* origin) const;
+ virtual Node* disambiguate(Type t, SubType st);
InnerNode* findAny(Node::Type t, Node::SubType st);
void addCollision(InnerNode* child);
const QMap<QString,QString>& linkTargets() const { return targets; }
void addLinkTarget(const QString& t, const QString& v) { targets.insert(t,v); }
private:
- InnerNode* current;
QMap<QString,QString> targets;
};
class ExampleNode : public DocNode
{
public:
- ExampleNode(InnerNode* parent, const QString& name);
+ ExampleNode(InnerNode* parent, const QString& name)
+ : DocNode(parent, name, Node::Example, Node::ExamplePage) { }
virtual ~ExampleNode() { }
virtual QString imageFileName() const { return imageFileName_; }
virtual void setImageFileName(const QString& ifn) { imageFileName_ = ifn; }
- static void terminate() { exampleNodeMap.clear(); }
-
-public:
- static ExampleNodeMap exampleNodeMap;
-
private:
QString imageFileName_;
};
@@ -605,7 +593,7 @@ struct ImportRec {
typedef QList<ImportRec> ImportList;
-class QmlClassNode : public DocNode
+class QmlClassNode : public InnerNode
{
public:
QmlClassNode(InnerNode* parent, const QString& name);
@@ -615,8 +603,6 @@ public:
virtual bool isQtQuickNode() const { return (qmlModuleName() == QLatin1String("QtQuick")); }
virtual ClassNode* classNode() { return cnode_; }
virtual void setClassNode(ClassNode* cn) { cnode_ = cn; }
- virtual void setCurrentChild();
- virtual void clearCurrentChild();
virtual bool isAbstract() const { return abstract_; }
virtual bool isWrapper() const { return wrapper_; }
virtual void setAbstract(bool b) { abstract_ = b; }
@@ -632,10 +618,11 @@ public:
virtual void setQmlModule(QmlModuleNode* t) { qmlModule_ = t; }
const ImportList& importList() const { return importList_; }
void setImportList(const ImportList& il) { importList_ = il; }
- const QString& qmlBaseName() const { return baseName_; }
- void setQmlBaseName(const QString& name) { baseName_ = name; }
- const QmlClassNode* qmlBaseNode() const { return baseNode_; }
- void setQmlBaseNode(QmlClassNode* b) { baseNode_ = b; }
+ const QString& qmlBaseName() const { return qmlBaseName_; }
+ void setQmlBaseName(const QString& name) { qmlBaseName_ = name; }
+ bool qmlBaseNodeNotSet() const { return (qmlBaseNode_ == 0); }
+ QmlClassNode* qmlBaseNode();
+ void setQmlBaseNode(QmlClassNode* b) { qmlBaseNode_ = b; }
void requireCppClass() { cnodeRequired_ = true; }
bool cppClassRequired() const { return cnodeRequired_; }
static void addInheritedBy(const QString& base, Node* sub);
@@ -651,20 +638,21 @@ private:
bool cnodeRequired_;
bool wrapper_;
ClassNode* cnode_;
- QString baseName_;
+ QString qmlBaseName_;
QString obsoleteLink_;
QmlModuleNode* qmlModule_;
- QmlClassNode* baseNode_;
+ QmlClassNode* qmlBaseNode_;
ImportList importList_;
};
-class QmlBasicTypeNode : public DocNode
+class QmlBasicTypeNode : public InnerNode
{
public:
QmlBasicTypeNode(InnerNode* parent,
const QString& name);
virtual ~QmlBasicTypeNode() { }
virtual bool isQmlNode() const { return true; }
+ virtual bool isQmlBasicType() const { return true; }
};
class QmlPropertyGroupNode : public InnerNode
@@ -681,14 +669,12 @@ public:
virtual QString idNumber();
virtual bool isQmlPropertyGroup() const { return true; }
- const QString& element() const { return parent()->name(); }
+ virtual QString element() const { return parent()->name(); }
private:
int idNumber_;
};
-class QmlPropertyNode;
-
class QmlPropertyNode : public LeafNode
{
Q_DECLARE_TR_FUNCTIONS(QDoc::QmlPropertyNode)
@@ -711,7 +697,7 @@ public:
bool isReadOnlySet() const { return (readOnly_ != FlagValueDefault); }
bool isStored() const { return fromFlagValue(stored_,true); }
bool isDesignable() const { return fromFlagValue(designable_,false); }
- bool isWritable(QDocDatabase* qdb);
+ bool isWritable();
virtual bool isDefault() const { return isdefault_; }
virtual bool isReadOnly() const { return fromFlagValue(readOnly_,false); }
virtual bool isAlias() const { return isAlias_; }
@@ -722,10 +708,10 @@ public:
virtual QString qmlModuleName() const { return parent()->qmlModuleName(); }
virtual QString qmlModuleVersion() const { return parent()->qmlModuleVersion(); }
virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); }
+ virtual QString element() const;
- PropertyNode* correspondingProperty(QDocDatabase* qdb);
-
- const QString& element() const { return static_cast<QmlPropertyGroupNode*>(parent())->element(); }
+ private:
+ PropertyNode* findCorrespondingCppProperty();
private:
QString type_;
@@ -743,21 +729,15 @@ 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 TypedefNode;
-
class EnumNode : public LeafNode
{
public:
@@ -831,8 +811,6 @@ private:
QString def;
};
-class PropertyNode;
-
class FunctionNode : public LeafNode
{
public:
@@ -886,7 +864,7 @@ public:
QStringList reconstructParams(bool values = false) const;
QString signature(bool values = false) const;
- const QString& element() const { return parent()->name(); }
+ virtual QString element() const { return parent()->name(); }
virtual bool isAttached() const { return attached_; }
virtual bool isQmlNode() const {
return ((type() == QmlSignal) ||
@@ -1049,6 +1027,94 @@ public:
const DitaRefList& map() const { return doc().ditamap(); }
};
+class CollectionNode : public InnerNode
+{
+ public:
+ CollectionNode(Type type, InnerNode* parent, const QString& name)
+ : InnerNode(type, parent, name), seen_(false) {
+ setPageType(Node::OverviewPage);
+ }
+ virtual ~CollectionNode() { }
+
+ virtual bool isCollectionNode() const { return true; }
+ virtual void addMember(Node* node);
+ virtual bool hasMembers() const;
+ virtual bool hasNamespaces() const;
+ virtual bool hasClasses() const;
+ virtual void getMemberNamespaces(NodeMap& out);
+ virtual void getMemberClasses(NodeMap& out);
+ virtual bool wasSeen() const { return seen_; }
+ virtual QString title() const { return title_; }
+ virtual QString subTitle() const { return subtitle_; }
+ virtual QString fullTitle() const { return title_; }
+ virtual QString nameForLists() const { return title_; }
+ virtual void setTitle(const QString &title);
+ virtual void setSubTitle(const QString &subTitle) { subtitle_ = subTitle; }
+
+ const NodeList& members() const { return members_; }
+ void printMembers(const QString& title);
+
+ void markSeen() { seen_ = true; }
+ void markNotSeen() { seen_ = false; }
+
+ private:
+ bool seen_;
+ QString title_;
+ QString subtitle_;
+ NodeList members_;
+};
+
+class GroupNode : public CollectionNode
+{
+ public:
+ GroupNode(InnerNode* parent, const QString& name)
+ : CollectionNode(Node::Group, parent, name) { }
+ virtual ~GroupNode() { }
+
+ virtual bool isGroup() const { return true; }
+};
+
+class ModuleNode : public CollectionNode
+{
+ public:
+ ModuleNode(InnerNode* parent, const QString& name)
+ : CollectionNode(Node::Module, parent, name) { }
+ virtual ~ModuleNode() { }
+
+ virtual bool isModule() const { return true; }
+ virtual void setQtVariable(const QString& v) { qtVariable_ = v; }
+ virtual QString qtVariable() const { return qtVariable_; }
+
+ private:
+ QString qtVariable_;
+};
+
+class QmlModuleNode : public CollectionNode
+{
+ public:
+ QmlModuleNode(InnerNode* parent, const QString& name)
+ : CollectionNode(Node::QmlModule, parent, name) { }
+ virtual ~QmlModuleNode() { }
+
+ virtual bool isQmlModule() const { return true; }
+ virtual QString qmlModuleName() const { return qmlModuleName_; }
+ virtual QString qmlModuleVersion() const {
+ return qmlModuleVersionMajor_ + "." + qmlModuleVersionMinor_;
+ }
+ virtual QString qmlModuleIdentifier() const {
+ return qmlModuleName_ + qmlModuleVersionMajor_;
+ }
+ virtual void setQmlModuleInfo(const QString& );
+ virtual void setQtVariable(const QString& v) { qtVariable_ = v; }
+ virtual QString qtVariable() const { return qtVariable_; }
+
+ private:
+ QString qmlModuleName_;
+ QString qmlModuleVersionMajor_;
+ QString qmlModuleVersionMinor_;
+ QString qtVariable_;
+};
+
QT_END_NAMESPACE
#endif
diff --git a/src/tools/qdoc/puredocparser.cpp b/src/tools/qdoc/puredocparser.cpp
index 644fe05438..e8292e787e 100644
--- a/src/tools/qdoc/puredocparser.cpp
+++ b/src/tools/qdoc/puredocparser.cpp
@@ -202,7 +202,7 @@ bool PureDocParser::processQdocComments()
}
}
- Node* treeRoot = QDocDatabase::qdocDB()->treeRoot();
+ Node* treeRoot = QDocDatabase::qdocDB()->primaryTreeRoot();
NodeList::Iterator n = nodes.begin();
QList<Doc>::Iterator d = docs.begin();
while (n != nodes.end()) {
diff --git a/src/tools/qdoc/puredocparser.h b/src/tools/qdoc/puredocparser.h
index 0174af7a4e..b664367527 100644
--- a/src/tools/qdoc/puredocparser.h
+++ b/src/tools/qdoc/puredocparser.h
@@ -56,7 +56,6 @@ QT_BEGIN_NAMESPACE
class Config;
class Node;
class QString;
-class Tree;
class PureDocParser : public CppCodeParser
{
diff --git a/src/tools/qdoc/qdocdatabase.cpp b/src/tools/qdoc/qdocdatabase.cpp
index 1011a3ac97..8bf83ca796 100644
--- a/src/tools/qdoc/qdocdatabase.cpp
+++ b/src/tools/qdoc/qdocdatabase.cpp
@@ -51,46 +51,439 @@ QT_BEGIN_NAMESPACE
static NodeMap emptyNodeMap_;
static NodeMultiMap emptyNodeMultiMap_;
+bool QDocDatabase::debug = false;
+
+/*! \class QDocForest
+ This class manages a collection of trees. Each tree is an
+ instance of class Tree, which is a private class.
+
+ The forest is populated as each index file is loaded.
+ Each index file adds a tree to the forest. Each tree
+ is named with the name of the module it represents.
+
+ The search order is created by searchOrder(), if it has
+ not already been created. The search order and module
+ names arrays have parallel structure, i.e. modulNames_[i]
+ is the module name of the Tree at searchOrder_[i].
+ */
+
+/*!
+ Destroys the qdoc forest. This requires deleting
+ each Tree in the forest. Note that the forest has
+ been transferred into the search order array, so
+ what is really being used to destroy the forest
+ is the search order array.
+ */
+QDocForest::~QDocForest()
+{
+ for (int i=0; i<searchOrder_.size(); ++i)
+ delete searchOrder_.at(i);
+ forest_.clear();
+ searchOrder_.clear();
+ indexSearchOrder_.clear();
+ moduleNames_.clear();
+ primaryTree_ = 0;
+}
+
+/*!
+ Initializes the forest prior to a traversal and
+ returns a pointer to the root node of the primary
+ tree. If the forest is empty, it return 0
+ */
+NamespaceNode* QDocForest::firstRoot()
+{
+ currentIndex_ = 0;
+ return (!searchOrder().isEmpty() ? searchOrder()[0]->root() : 0);
+}
+
+/*!
+ Increments the forest's current tree index. If the current
+ tree index is still within the forest, the function returns
+ the root node of the current tree. Otherwise it returns 0.
+ */
+NamespaceNode* QDocForest::nextRoot()
+{
+ ++currentIndex_;
+ return (currentIndex_ < searchOrder().size() ? searchOrder()[currentIndex_]->root() : 0);
+}
+
+/*!
+ Initializes the forest prior to a traversal and
+ returns a pointer to the primary tree. If the
+ forest is empty, it returns 0.
+ */
+Tree* QDocForest::firstTree()
+{
+ currentIndex_ = 0;
+ return (!searchOrder().isEmpty() ? searchOrder()[0] : 0);
+}
+
+/*!
+ Increments the forest's current tree index. If the current
+ tree index is still within the forest, the function returns
+ the pointer to the current tree. Otherwise it returns 0.
+ */
+Tree* QDocForest::nextTree()
+{
+ ++currentIndex_;
+ return (currentIndex_ < searchOrder().size() ? searchOrder()[currentIndex_] : 0);
+}
+
+/*!
+ \fn Tree* QDocForest::primaryTree()
+
+ Returns the pointer to the primary tree.
+ */
+
+/*!
+ If the search order array is empty, create the search order.
+ If the search order array is not empty, do nothing.
+ */
+void QDocForest::setSearchOrder()
+{
+ if (!searchOrder_.isEmpty())
+ return;
+ QString primaryName = primaryTree()->moduleName();
+ searchOrder_.clear();
+ searchOrder_.reserve(forest_.size()+1);
+ moduleNames_.reserve(forest_.size()+1);
+ searchOrder_.append(primaryTree_);
+ moduleNames_.append(primaryName);
+ QMap<QString, Tree*>::iterator i;
+ if (primaryName != "QtCore") {
+ i = forest_.find("QtCore");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtCore");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtGui") {
+ i = forest_.find("QtGui");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtGui");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtNetwork") {
+ i = forest_.find("QtNetwork");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtNetwork");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtOpenGL") {
+ i = forest_.find("QtOpenGL");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtOpenGL");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtWidgets") {
+ i = forest_.find("QtWidgets");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtWidgets");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtSql") {
+ i = forest_.find("QtSql");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtSql");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtXml") {
+ i = forest_.find("QtXml");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtXml");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtSvg") {
+ i = forest_.find("QtSvg");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtSvg");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtDoc") {
+ i = forest_.find("QtDoc");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtDoc");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtQuick") {
+ i = forest_.find("QtQuick");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtQuick");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtQml") {
+ i = forest_.find("QtQml");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtQml");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtPrintSupport") {
+ i = forest_.find("QtPrintSupport");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtPrintSupport");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtGraphicalEffects") {
+ i = forest_.find("QtGraphicalEffects");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtGraphicalEffects");
+ forest_.erase(i);
+ }
+ }
+ if (primaryName != "QtConcurrent") {
+ i = forest_.find("QtConcurrent");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("QtConcurrent");
+ forest_.erase(i);
+ }
+ }
+#if 0
+ if (primaryName != "zzz") {
+ i = forest_.find("zzz");
+ if (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append("zzz");
+ forest_.erase(i);
+ }
+ }
+#endif
+ /*
+ If any trees remain in the forest, just add them
+ to the search order sequentially, because we don't
+ know any better at this point.
+ */
+ if (!forest_.isEmpty()) {
+ i = forest_.begin();
+ while (i != forest_.end()) {
+ searchOrder_.append(i.value());
+ moduleNames_.append(i.key());
+ ++i;
+ }
+ 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)
+ qDebug() << " " << i+1 << "." << moduleNames_.at(i);
+#endif
+}
+
+/*!
+ Returns an ordered array of Tree pointers that represents
+ the order in which the trees should be searched. The first
+ Tree in the array is the tree for the current module, i.e.
+ the module for which qdoc is generating documentation.
+
+ The other Tree pointers in the array represent the index
+ files that were loaded in preparation for generating this
+ module's documentation. Each Tree pointer represents one
+ index file. The index file Tree points have been ordered
+ heuristically to, hopefully, minimize searching. Thr order
+ will probably be changed.
+
+ If the search order array is empty, this function calls
+ indexSearchOrder(). The search order array is empty while
+ the index files are being loaded, but some searches must
+ be performed during this time, notably searches for base
+ class nodes. These searches require a temporary search
+ order. The temporary order changes throughout the loading
+ of the index files, but it is always the tree for the
+ current index file first, followed by the trees for the
+ index files that have already been loaded. The only
+ ordering required in this temporary search order is that
+ the current tree must be searched first.
+ */
+const QVector<Tree*>& QDocForest::searchOrder()
+{
+ if (searchOrder_.isEmpty())
+ return indexSearchOrder();
+ return searchOrder_;
+}
+
+/*!
+ There are two search orders used by qdoc when searching for
+ things. The normal search order is returned by searchOrder(),
+ but this normal search order is not known until all the index
+ files have been read. At that point, setSearchOrder() is
+ called.
+
+ During the reading of the index files, the vector holding
+ the normal search order remains empty. Whenever the search
+ order is requested, if that vector is empty, this function
+ is called to return a temporary search order, which includes
+ all the index files that have been read so far, plus the
+ one being read now. That one is prepended to the front of
+ the vector.
+ */
+const QVector<Tree*>& QDocForest::indexSearchOrder()
+{
+ if (forest_.size() > indexSearchOrder_.size())
+ indexSearchOrder_.prepend(primaryTree_);
+ return indexSearchOrder_;
+}
+
+/*!
+ Create a new Tree for the index file for the specified
+ \a module and add it to the forest. Return the pointer
+ to its root.
+ */
+NamespaceNode* QDocForest::newIndexTree(const QString& module)
+{
+ primaryTree_ = new Tree(module, qdb_);
+ forest_.insert(module, primaryTree_);
+ return primaryTree_->root();
+}
+
+/*!
+ Create a new Tree for use as the primary tree. This tree
+ will represent the primary module.
+ */
+void QDocForest::newPrimaryTree(const QString& module)
+{
+ primaryTree_ = new Tree(module, qdb_);
+}
+
+/*!
+ Searches the trees for a node named \a target and returns
+ a pointer to it if found. The \a relative node is the starting
+ point, but it only makes sense in the primary tree, which is
+ searched first. After the primary tree is searched, \a relative
+ is set to 0 for searching the index trees. When relative is 0,
+ the root node of the index tree is the starting point.
+ */
+const Node* QDocForest::resolveTarget(const QString& target, const Node* relative)
+{
+ QStringList path = target.split("::");
+ int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
+
+ foreach (Tree* t, searchOrder()) {
+ const Node* n = t->findNode(path, relative, flags);
+ if (n)
+ return n;
+#if 0
+ n = t->findDocNodeByTitle(target);
+ if (n)
+ return n;
+#endif
+ relative = 0;
+ }
+ return 0;
+}
+
+/*!
+ Searches the Tree \a t for a type node named by the \a path
+ and returns a pointer to it if found. The \a relative node
+ is the starting point, but it only makes sense when searching
+ the primary tree. Therefore, when this function is called with
+ \a t being an index tree, \a relative is 0. When relative is 0,
+ the root node of \a t is the starting point.
+ */
+const Node* QDocForest::resolveTypeHelper(const QStringList& path, const Node* relative, Tree* t)
+{
+ int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
+ return t->findNode(path, relative, flags);
+}
+
+/*!
+ This function merges all the collection maps for collection
+ nodes of node type \a t into the collection multimap \a cnmm,
+ which is cleared before starting.
+
+ This is mainly useful for groups, which often cross module
+ boundaries. It might be true that neither modules nor QML
+ modules cross module boundaries, but this function works for
+ those cases as well.
+ */
+void QDocForest::mergeCollectionMaps(Node::Type nt, CNMultiMap& cnmm)
+{
+ foreach (Tree* t, searchOrder()) {
+ const CNMap& cnm = t->getCollections(nt);
+ if (!cnm.isEmpty()) {
+ CNMap::const_iterator i = cnm.begin();
+ while (i != cnm.end()) {
+ if (!i.value()->isInternal())
+ cnmm.insert(i.key(), i.value());
+ ++i;
+ }
+ }
+ }
+}
/*! \class QDocDatabase
+ This class provides exclusive access to the qdoc database,
+ which consists of a forrest of trees and a lot of maps and
+ other useful data structures.
*/
QDocDatabase* QDocDatabase::qdocDB_ = NULL;
+NodeMap QDocDatabase::typeNodeMap_;
/*!
- Constructs the singleton qdoc database object.
- It constructs a singleton Tree object with this
- qdoc database pointer.
+ Constructs the singleton qdoc database object. The singleton
+ constructs the \a forest_ object, which is also a singleton.
+ \a showInternal_ is normally false. If it is true, qdoc will
+ write documentation for nodes marked \c internal.
*/
-QDocDatabase::QDocDatabase() : showInternal_(false)
+QDocDatabase::QDocDatabase() : showInternal_(false), forest_(this)
{
- tree_ = new Tree(this);
+ // nothing
}
/*!
- Destroys the qdoc database object. This requires deleting
- the tree of nodes, which deletes each node.
+ Destroys the qdoc database object. This requires destroying
+ the forest object, which contains an array of tree pointers.
+ Each tree is deleted.
*/
QDocDatabase::~QDocDatabase()
{
- masterMap_.clear();
- delete tree_;
+ // nothing.
}
-/*! \fn Tree* QDocDatabase::tree()
- Returns the pointer to the tree. This function is for compatibility
- with the current qdoc. It will be removed when the QDocDatabase class
- replaces the current structures.
- */
-
/*!
Creates the singleton. Allows only one instance of the class
to be created. Returns a pointer to the singleton.
*/
QDocDatabase* QDocDatabase::qdocDB()
{
- if (!qdocDB_)
+ if (!qdocDB_) {
qdocDB_ = new QDocDatabase;
+ initializeDB();
+ }
return qdocDB_;
}
@@ -106,36 +499,192 @@ void QDocDatabase::destroyQdocDB()
}
/*!
- \fn const DocNodeMap& QDocDatabase::groups() const
+ Initialize data structures in the singleton qdoc database.
+
+ In particular, the type node map is initialized with a lot
+ type names that don't refer to documented types. For example,
+ the C++ standard types are included. These might be documented
+ here at some point, but for now they are not. Other examples
+ 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);
+ typeNodeMap_.insert( "alias", 0);
+ typeNodeMap_.insert( "anchors", 0);
+ typeNodeMap_.insert( "any", 0);
+ typeNodeMap_.insert( "array", 0);
+ typeNodeMap_.insert( "autoSearch", 0);
+ typeNodeMap_.insert( "axis", 0);
+ typeNodeMap_.insert( "backClicked", 0);
+ typeNodeMap_.insert( "bool", 0);
+ typeNodeMap_.insert( "boomTime", 0);
+ typeNodeMap_.insert( "border", 0);
+ typeNodeMap_.insert( "buttonClicked", 0);
+ typeNodeMap_.insert( "callback", 0);
+ typeNodeMap_.insert( "char", 0);
+ typeNodeMap_.insert( "clicked", 0);
+ typeNodeMap_.insert( "close", 0);
+ typeNodeMap_.insert( "closed", 0);
+ typeNodeMap_.insert( "color", 0);
+ typeNodeMap_.insert( "cond", 0);
+ typeNodeMap_.insert( "data", 0);
+ typeNodeMap_.insert( "dataReady", 0);
+ typeNodeMap_.insert( "dateString", 0);
+ typeNodeMap_.insert( "dateTimeString", 0);
+ typeNodeMap_.insert( "datetime", 0);
+ typeNodeMap_.insert( "day", 0);
+ typeNodeMap_.insert( "deactivated", 0);
+ typeNodeMap_.insert( "double", 0);
+ typeNodeMap_.insert( "drag", 0);
+ typeNodeMap_.insert( "easing", 0);
+ typeNodeMap_.insert( "enumeration", 0);
+ typeNodeMap_.insert( "error", 0);
+ typeNodeMap_.insert( "exposure", 0);
+ typeNodeMap_.insert( "fatalError", 0);
+ typeNodeMap_.insert( "fileSelected", 0);
+ typeNodeMap_.insert( "flags", 0);
+ typeNodeMap_.insert( "float", 0);
+ typeNodeMap_.insert( "focus", 0);
+ typeNodeMap_.insert( "focusZone", 0);
+ typeNodeMap_.insert( "format", 0);
+ typeNodeMap_.insert( "framePainted", 0);
+ typeNodeMap_.insert( "from", 0);
+ typeNodeMap_.insert( "frontClicked", 0);
+ typeNodeMap_.insert( "function", 0);
+ typeNodeMap_.insert( "hasOpened", 0);
+ typeNodeMap_.insert( "hovered", 0);
+ typeNodeMap_.insert( "hoveredTitle", 0);
+ typeNodeMap_.insert( "hoveredUrl", 0);
+ typeNodeMap_.insert( "imageCapture", 0);
+ typeNodeMap_.insert( "imageProcessing", 0);
+ typeNodeMap_.insert( "index", 0);
+ typeNodeMap_.insert( "initialized", 0);
+ typeNodeMap_.insert( "int", 0);
+ typeNodeMap_.insert( "isLoaded", 0);
+ typeNodeMap_.insert( "item", 0);
+ typeNodeMap_.insert( "jsdict", 0);
+ typeNodeMap_.insert( "jsobject", 0);
+ typeNodeMap_.insert( "key", 0);
+ typeNodeMap_.insert( "keysequence", 0);
+ typeNodeMap_.insert( "list", 0);
+ typeNodeMap_.insert( "listViewClicked", 0);
+ typeNodeMap_.insert( "loadRequest", 0);
+ typeNodeMap_.insert( "locale", 0);
+ typeNodeMap_.insert( "location", 0);
+ typeNodeMap_.insert( "long", 0);
+ typeNodeMap_.insert( "message", 0);
+ typeNodeMap_.insert( "messageReceived", 0);
+ typeNodeMap_.insert( "mode", 0);
+ typeNodeMap_.insert( "month", 0);
+ typeNodeMap_.insert( "name", 0);
+ typeNodeMap_.insert( "number", 0);
+ typeNodeMap_.insert( "object", 0);
+ typeNodeMap_.insert( "offset", 0);
+ typeNodeMap_.insert( "ok", 0);
+ typeNodeMap_.insert( "openCamera", 0);
+ typeNodeMap_.insert( "openImage", 0);
+ typeNodeMap_.insert( "openVideo", 0);
+ typeNodeMap_.insert( "padding", 0);
+ typeNodeMap_.insert( "parent", 0);
+ typeNodeMap_.insert( "path", 0);
+ typeNodeMap_.insert( "photoModeSelected", 0);
+ typeNodeMap_.insert( "position", 0);
+ typeNodeMap_.insert( "precision", 0);
+ typeNodeMap_.insert( "presetClicked", 0);
+ typeNodeMap_.insert( "preview", 0);
+ typeNodeMap_.insert( "previewSelected", 0);
+ typeNodeMap_.insert( "progress", 0);
+ typeNodeMap_.insert( "puzzleLost", 0);
+ typeNodeMap_.insert( "qmlSignal", 0);
+ typeNodeMap_.insert( "real", 0);
+ typeNodeMap_.insert( "rectangle", 0);
+ typeNodeMap_.insert( "request", 0);
+ typeNodeMap_.insert( "requestId", 0);
+ typeNodeMap_.insert( "section", 0);
+ typeNodeMap_.insert( "selected", 0);
+ typeNodeMap_.insert( "send", 0);
+ typeNodeMap_.insert( "settingsClicked", 0);
+ typeNodeMap_.insert( "shoe", 0);
+ typeNodeMap_.insert( "short", 0);
+ typeNodeMap_.insert( "signed", 0);
+ typeNodeMap_.insert( "sizeChanged", 0);
+ typeNodeMap_.insert( "size_t", 0);
+ typeNodeMap_.insert( "sockaddr", 0);
+ typeNodeMap_.insert( "someOtherSignal", 0);
+ typeNodeMap_.insert( "sourceSize", 0);
+ typeNodeMap_.insert( "startButtonClicked", 0);
+ typeNodeMap_.insert( "state", 0);
+ typeNodeMap_.insert( "std::initializer_list", 0);
+ typeNodeMap_.insert( "std::list", 0);
+ typeNodeMap_.insert( "std::map", 0);
+ typeNodeMap_.insert( "std::pair", 0);
+ typeNodeMap_.insert( "std::string", 0);
+ typeNodeMap_.insert( "std::vector", 0);
+ typeNodeMap_.insert( "string", 0);
+ typeNodeMap_.insert( "stringlist", 0);
+ typeNodeMap_.insert( "swapPlayers", 0);
+ typeNodeMap_.insert( "symbol", 0);
+ typeNodeMap_.insert( "t", 0);
+ typeNodeMap_.insert( "T", 0);
+ typeNodeMap_.insert( "tagChanged", 0);
+ typeNodeMap_.insert( "timeString", 0);
+ typeNodeMap_.insert( "timeout", 0);
+ typeNodeMap_.insert( "to", 0);
+ typeNodeMap_.insert( "toggled", 0);
+ typeNodeMap_.insert( "type", 0);
+ typeNodeMap_.insert( "unsigned", 0);
+ typeNodeMap_.insert( "urllist", 0);
+ typeNodeMap_.insert( "va_list", 0);
+ typeNodeMap_.insert( "value", 0);
+ typeNodeMap_.insert( "valueEmitted", 0);
+ typeNodeMap_.insert( "videoFramePainted", 0);
+ typeNodeMap_.insert( "videoModeSelected", 0);
+ typeNodeMap_.insert( "videoRecorder", 0);
+ typeNodeMap_.insert( "void", 0);
+ typeNodeMap_.insert( "volatile", 0);
+ typeNodeMap_.insert( "wchar_t", 0);
+ typeNodeMap_.insert( "x", 0);
+ typeNodeMap_.insert( "y", 0);
+ typeNodeMap_.insert( "zoom", 0);
+ typeNodeMap_.insert( "zoomTo", 0);
+}
+
+/*! \fn NamespaceNode* QDocDatabase::primaryTreeRoot()
+ Returns a pointer to the root node of the primary tree.
+ */
+
+/*!
+ \fn const GroupMap& QDocDatabase::groups()
Returns a const reference to the collection of all
- group nodes.
+ group nodes in the primary tree.
*/
/*!
- \fn const DocNodeMap& QDocDatabase::modules() const
+ \fn const ModuleMap& QDocDatabase::modules()
Returns a const reference to the collection of all
- module nodes.
+ module nodes in the primary tree.
*/
/*!
- \fn const DocNodeMap& QDocDatabase::qmlModules() const
+ \fn const QmlModuleMap& QDocDatabase::qmlModules()
Returns a const reference to the collection of all
- QML module nodes.
+ QML module nodes in the primary tree.
*/
-/*!
+/*! \fn GroupNode* QDocDatabase::getGroup(const QString& name)
Find the group node named \a name and return a pointer
to it. If a matching node is not found, return 0.
*/
-DocNode* QDocDatabase::getGroup(const QString& name)
-{
- DocNodeMap::const_iterator i = groups_.find(name);
- if (i != groups_.end())
- return i.value();
- return 0;
-}
-/*!
+/*! \fn GroupNode* QDocDatabase::findGroup(const QString& name)
Find the group node named \a name and return a pointer
to it. If a matching node is not found, add a new group
node named \a name and return a pointer to that one.
@@ -143,20 +692,8 @@ DocNode* QDocDatabase::getGroup(const QString& name)
If a new group node is added, its parent is the tree root,
and the new group node is marked \e{not seen}.
*/
-DocNode* QDocDatabase::findGroup(const QString& name)
-{
- DocNodeMap::const_iterator i = groups_.find(name);
- if (i != groups_.end())
- return i.value();
- DocNode* dn = new DocNode(tree_->root(), name, Node::Group, Node::OverviewPage);
- dn->markNotSeen();
- groups_.insert(name,dn);
- if (!masterMap_.contains(name,dn))
- masterMap_.insert(name,dn);
- return dn;
-}
-/*!
+/*! \fn ModuleNode* QDocDatabase::findModule(const QString& name)
Find the module node named \a name and return a pointer
to it. If a matching node is not found, add a new module
node named \a name and return a pointer to that one.
@@ -164,20 +701,8 @@ DocNode* QDocDatabase::findGroup(const QString& name)
If a new module node is added, its parent is the tree root,
and the new module node is marked \e{not seen}.
*/
-DocNode* QDocDatabase::findModule(const QString& name)
-{
- DocNodeMap::const_iterator i = modules_.find(name);
- if (i != modules_.end())
- return i.value();
- DocNode* dn = new DocNode(tree_->root(), name, Node::Module, Node::OverviewPage);
- dn->markNotSeen();
- modules_.insert(name,dn);
- if (!masterMap_.contains(name,dn))
- masterMap_.insert(name,dn);
- return dn;
-}
-/*!
+/*! \fn QmlModuleNode* QDocDatabase::findQmlModule(const QString& name)
Find the QML module node named \a name and return a pointer
to it. If a matching node is not found, add a new QML module
node named \a name and return a pointer to that one.
@@ -185,68 +710,32 @@ DocNode* QDocDatabase::findModule(const QString& name)
If a new QML module node is added, its parent is the tree root,
and the new QML module node is marked \e{not seen}.
*/
-QmlModuleNode* QDocDatabase::findQmlModule(const QString& name)
-{
- if (qmlModules_.contains(name))
- return static_cast<QmlModuleNode*>(qmlModules_.value(name));
-
- QmlModuleNode* qmn = new QmlModuleNode(tree_->root(), name);
- qmn->markNotSeen();
- qmn->setQmlModuleInfo(name);
- qmlModules_.insert(name, qmn);
- masterMap_.insert(name, qmn);
- return qmn;
-}
-/*!
- Looks up the group node named \a name in the collection
- of all group nodes. If a match is found, a pointer to the
- node is returned. Otherwise, a new group node named \a name
- is created and inserted into the collection, and the pointer
- to that node is returned. The group node is marked \e{seen}
- in either case.
+/*! \fn GroupNode* QDocDatabase::addGroup(const QString& name)
+ Looks up the group named \a name in the primary tree. If
+ a match is found, a pointer to the node is returned.
+ Otherwise, a new group node named \a name is created and
+ inserted into the collection, and the pointer to that node
+ is returned.
*/
-DocNode* QDocDatabase::addGroup(const QString& name)
-{
- DocNode* group = findGroup(name);
- group->markSeen();
- return group;
-}
-/*!
- Looks up the module node named \a name in the collection
- of all module nodes. If a match is found, a pointer to the
- node is returned. Otherwise, a new module node named \a name
- is created and inserted into the collection, and the pointer
- to that node is returned. The module node is marked \e{seen}
- in either case.
+/*! \fn ModuleNode* QDocDatabase::addModule(const QString& name)
+ Looks up the module named \a name in the primary tree. If
+ a match is found, a pointer to the node is returned.
+ Otherwise, a new module node named \a name is created and
+ inserted into the collection, and the pointer to that node
+ is returned.
*/
-DocNode* QDocDatabase::addModule(const QString& name)
-{
- DocNode* module = findModule(name);
- module->markSeen();
- return module;
-}
-/*!
- Looks up the QML module node named \a name in the collection
- of all QML module nodes. If a match is found, a pointer to the
- node is returned. Otherwise, a new QML module node named \a name
- is created and inserted into the collection, and the pointer
- to that node is returned. The QML module node is marked \e{seen}
- in either case.
- */
-QmlModuleNode* QDocDatabase::addQmlModule(const QString& name)
-{
- QStringList blankSplit = name.split(QLatin1Char(' '));
- QmlModuleNode* qmn = findQmlModule(blankSplit[0]);
- qmn->setQmlModuleInfo(name);
- qmn->markSeen();
- //masterMap_.insert(qmn->qmlModuleIdentifier(),qmn);
- return qmn;
-}
+/*! \fn QmlModuleNode* QDocDatabase::addQmlModule(const QString& name)
+ Looks up the QML module named \a name in the primary tree.
+ If a match is found, a pointer to the node is returned.
+ Otherwise, a new QML module node named \a name is created
+ and inserted into the collection, and the pointer to that
+ node is returned.
+ */
-/*!
+/*! \fn GroupNode* QDocDatabase::addToGroup(const QString& name, Node* node)
Looks up the group node named \a name in the collection
of all group nodes. If a match is not found, a new group
node named \a name is created and inserted into the collection.
@@ -255,62 +744,31 @@ QmlModuleNode* QDocDatabase::addQmlModule(const QString& name)
\a node is not changed by this function. Returns a pointer to
the group node.
*/
-DocNode* QDocDatabase::addToGroup(const QString& name, Node* node)
-{
- DocNode* dn = findGroup(name);
- dn->addMember(node);
- node->addMember(dn);
- return dn;
-}
-/*!
+/*! \fn ModuleNode* QDocDatabase::addToModule(const QString& name, Node* node)
Looks up the module node named \a name in the collection
of all module nodes. If a match is not found, a new module
node named \a name is created and inserted into the collection.
Then append \a node to the module's members list. The parent of
\a node is not changed by this function. Returns the module node.
*/
-DocNode* QDocDatabase::addToModule(const QString& name, Node* node)
-{
- DocNode* dn = findModule(name);
- dn->addMember(node);
- node->setModuleName(name);
- return dn;
-}
-/*!
+/*! \fn QmlModuleNode* QDocDatabase::addToQmlModule(const QString& name, Node* node)
Looks up the QML module named \a name. If it isn't there,
create it. Then append \a node to the QML module's member
list. The parent of \a node is not changed by this function.
*/
-void QDocDatabase::addToQmlModule(const QString& name, Node* node)
-{
- QStringList qmid;
- QStringList dotSplit;
- QStringList blankSplit = name.split(QLatin1Char(' '));
- qmid.append(blankSplit[0]);
- if (blankSplit.size() > 1) {
- qmid.append(blankSplit[0] + blankSplit[1]);
- dotSplit = blankSplit[1].split(QLatin1Char('.'));
- qmid.append(blankSplit[0] + dotSplit[0]);
- }
- QmlModuleNode* qmn = findQmlModule(blankSplit[0]);
- qmn->addMember(node);
- node->setQmlModule(qmn);
-
- if (node->subType() == Node::QmlClass) {
- QmlClassNode* n = static_cast<QmlClassNode*>(node);
- for (int i=0; i<qmid.size(); ++i) {
- QString key = qmid[i] + "::" + node->name();
- if (!qmlTypeMap_.contains(key))
- qmlTypeMap_.insert(key,n);
- if (!masterMap_.contains(key))
- masterMap_.insert(key,node);
- }
- if (!masterMap_.contains(node->name(),node))
- masterMap_.insert(node->name(),node);
- }
+/*!
+ Looks up the QML type node identified by the qualified Qml
+ type \a name and returns a pointer to the QML type node.
+ */
+QmlClassNode* QDocDatabase::findQmlType(const QString& name)
+{
+ QmlClassNode* qcn = forest_.lookupQmlType(name);
+ if (qcn)
+ return qcn;
+ return 0;
}
/*!
@@ -321,20 +779,24 @@ void QDocDatabase::addToQmlModule(const QString& name, Node* node)
If the QML module id is empty, it looks up the QML type by
\a name only.
*/
-QmlClassNode* QDocDatabase::findQmlType(const QString& qmid, const QString& name) const
+QmlClassNode* QDocDatabase::findQmlType(const QString& qmid, const QString& name)
{
- if (!qmid.isEmpty())
- return qmlTypeMap_.value(qmid + "::" + name);
+ if (!qmid.isEmpty()) {
+ QString t = qmid + "::" + name;
+ QmlClassNode* qcn = forest_.lookupQmlType(t);
+ if (qcn)
+ return qcn;
+ }
QStringList path(name);
- Node* n = tree_->findNodeByNameAndType(path, Node::Document, Node::QmlClass, 0, 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;
@@ -346,7 +808,7 @@ QmlClassNode* QDocDatabase::findQmlType(const QString& qmid, const QString& name
QML type \a name and returns a pointer to the QML type node.
If a QML type node is not found, 0 is returned.
*/
-QmlClassNode* QDocDatabase::findQmlType(const ImportRec& import, const QString& name) const
+QmlClassNode* QDocDatabase::findQmlType(const ImportRec& import, const QString& name)
{
if (!import.isEmpty()) {
QStringList dotSplit;
@@ -358,7 +820,7 @@ QmlClassNode* QDocDatabase::findQmlType(const ImportRec& import, const QString&
qmName = import.importUri_;
for (int i=0; i<dotSplit.size(); ++i) {
QString qualifiedName = qmName + "::" + dotSplit[i];
- QmlClassNode* qcn = qmlTypeMap_.value(qualifiedName);
+ QmlClassNode* qcn = forest_.lookupQmlType(qualifiedName);
if (qcn)
return qcn;
}
@@ -367,59 +829,157 @@ QmlClassNode* QDocDatabase::findQmlType(const ImportRec& import, const QString&
}
/*!
- For debugging only.
+ This function calls \a func for each tree in the forest.
*/
-void QDocDatabase::printModules() const
+void QDocDatabase::processForest(void (QDocDatabase::*func) (InnerNode*))
{
- DocNodeMap::const_iterator i = modules_.begin();
- while (i != modules_.end()) {
- qDebug() << " " << i.key();
- ++i;
+ Tree* t = forest_.firstTree();
+ while (t) {
+ (this->*(func))(t->root());
+ t = forest_.nextTree();
}
}
/*!
- For debugging only.
+ Constructs the collection of legalese texts, if it has not
+ already been constructed and returns a reference to it.
*/
-void QDocDatabase::printQmlModules() const
+TextToNodeMap& QDocDatabase::getLegaleseTexts()
{
- DocNodeMap::const_iterator i = qmlModules_.begin();
- while (i != qmlModules_.end()) {
- qDebug() << " " << i.key();
- ++i;
- }
+ if (legaleseTexts_.isEmpty())
+ processForest(&QDocDatabase::findAllLegaleseTexts);
+ return legaleseTexts_;
}
/*!
- Traverses the database to construct useful data structures
- for use when outputting certain significant collections of
- things, C++ classes, QML types, "since" lists, and other
- stuff.
+ Construct the data structures for obsolete things, if they
+ have not already been constructed. Returns a reference to
+ the map of C++ classes with obsolete members.
*/
-void QDocDatabase::buildCollections()
+NodeMap& QDocDatabase::getClassesWithObsoleteMembers()
{
- nonCompatClasses_.clear();
- mainClasses_.clear();
- compatClasses_.clear();
- obsoleteClasses_.clear();
- funcIndex_.clear();
- legaleseTexts_.clear();
- serviceClasses_.clear();
- qmlClasses_.clear();
-
- findAllClasses(treeRoot());
- findAllFunctions(treeRoot());
- findAllLegaleseTexts(treeRoot());
- findAllNamespaces(treeRoot());
- findAllSince(treeRoot());
- findAllObsoleteThings(treeRoot());
+ if (obsoleteClasses_.isEmpty() && obsoleteQmlTypes_.isEmpty())
+ processForest(&QDocDatabase::findAllObsoleteThings);
+ return classesWithObsoleteMembers_;
+}
+
+/*!
+ Construct the data structures for obsolete things, if they
+ have not already been constructed. Returns a reference to
+ the map of obsolete QML types.
+ */
+NodeMap& QDocDatabase::getObsoleteQmlTypes()
+{
+ if (obsoleteClasses_.isEmpty() && obsoleteQmlTypes_.isEmpty())
+ processForest(&QDocDatabase::findAllObsoleteThings);
+ return obsoleteQmlTypes_;
+}
+
+/*!
+ Construct the data structures for obsolete things, if they
+ have not already been constructed. Returns a reference to
+ the map of QML types with obsolete members.
+ */
+NodeMap& QDocDatabase::getQmlTypesWithObsoleteMembers()
+{
+ if (obsoleteClasses_.isEmpty() && obsoleteQmlTypes_.isEmpty())
+ processForest(&QDocDatabase::findAllObsoleteThings);
+ return qmlTypesWithObsoleteMembers_;
+}
+
+/*!
+ Constructs the C++ namespace data structure, if it has not
+ already been constructed. Returns a reference to it.
+ */
+NodeMap& QDocDatabase::getNamespaces()
+{
+ if (namespaceIndex_.isEmpty())
+ processForest(&QDocDatabase::findAllNamespaces);
+ return namespaceIndex_;
+}
+
+/*!
+ Construct the C++ class data structures, if they have not
+ already been constructed. Returns a reference to the map
+ of C++ service clases.
+
+ \note This is currently not used.
+ */
+NodeMap& QDocDatabase::getServiceClasses()
+{
+ if (nonCompatClasses_.isEmpty() && qmlClasses_.isEmpty())
+ processForest(&QDocDatabase::findAllClasses);
+ return serviceClasses_;
+}
+
+/*!
+ Construct the data structures for obsolete things, if they
+ have not already been constructed. Returns a reference to
+ the map of obsolete QML types.
+ */
+NodeMap& QDocDatabase::getQmlTypes()
+{
+ if (nonCompatClasses_.isEmpty() && qmlClasses_.isEmpty())
+ processForest(&QDocDatabase::findAllClasses);
+ return qmlClasses_;
+}
+
+/*!
+ Construct the data structures for obsolete things, if they
+ have not already been constructed. Returns a reference to
+ the map of obsolete C++ clases.
+ */
+NodeMap& QDocDatabase::getObsoleteClasses()
+{
+ if (obsoleteClasses_.isEmpty() && obsoleteQmlTypes_.isEmpty())
+ processForest(&QDocDatabase::findAllObsoleteThings);
+ return obsoleteClasses_;
+}
+
+/*!
+ Construct the C++ class data structures, if they have not
+ already been constructed. Returns a reference to the map
+ of compatibility C++ clases.
+ */
+NodeMap& QDocDatabase::getCompatibilityClasses()
+{
+ if (nonCompatClasses_.isEmpty() && qmlClasses_.isEmpty())
+ processForest(&QDocDatabase::findAllClasses);
+ return compatClasses_;
+}
+
+/*!
+ Construct the C++ class data structures, if they have not
+ already been constructed. Returns a reference to the map
+ of main C++ clases.
+
+ \note The main C++ classes data structure is currently not
+ used.
+ */
+NodeMap& QDocDatabase::getMainClasses()
+{
+ if (nonCompatClasses_.isEmpty() && qmlClasses_.isEmpty())
+ processForest(&QDocDatabase::findAllClasses);
+ return mainClasses_;
+}
+
+/*!
+ Construct the C++ class data structures, if they have not
+ already been constructed. Returns a reference to the map
+ of all C++ classes.
+ */
+NodeMap& QDocDatabase::getCppClasses()
+{
+ if (nonCompatClasses_.isEmpty() && qmlClasses_.isEmpty())
+ processForest(&QDocDatabase::findAllClasses);
+ return nonCompatClasses_;
}
/*!
Finds all the C++ class nodes and QML type nodes and
sorts them into maps.
*/
-void QDocDatabase::findAllClasses(const InnerNode* node)
+void QDocDatabase::findAllClasses(InnerNode* node)
{
NodeList::const_iterator c = node->childNodes().constBegin();
while (c != node->childNodes().constEnd()) {
@@ -445,9 +1005,7 @@ void QDocDatabase::findAllClasses(const 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);
@@ -463,15 +1021,26 @@ void QDocDatabase::findAllClasses(const InnerNode* node)
}
/*!
+ Construct the function index data structure and return it.
+ This data structure is used to output the function index page.
+ */
+NodeMapMap& QDocDatabase::getFunctionIndex()
+{
+ funcIndex_.clear();
+ processForest(&QDocDatabase::findAllFunctions);
+ return funcIndex_;
+}
+
+/*!
Finds all the function nodes
*/
-void QDocDatabase::findAllFunctions(const InnerNode* node)
+void QDocDatabase::findAllFunctions(InnerNode* node)
{
NodeList::ConstIterator c = node->childNodes().constBegin();
while (c != node->childNodes().constEnd()) {
if ((*c)->access() != Node::Private) {
if ((*c)->isInnerNode()) {
- findAllFunctions(static_cast<const InnerNode*>(*c));
+ findAllFunctions(static_cast<InnerNode*>(*c));
}
else if ((*c)->type() == Node::Function) {
const FunctionNode* func = static_cast<const FunctionNode*>(*c);
@@ -491,7 +1060,7 @@ void QDocDatabase::findAllFunctions(const InnerNode* node)
Finds all the nodes containing legalese text and puts them
in a map.
*/
-void QDocDatabase::findAllLegaleseTexts(const InnerNode* node)
+void QDocDatabase::findAllLegaleseTexts(InnerNode* node)
{
NodeList::ConstIterator c = node->childNodes().constBegin();
while (c != node->childNodes().constEnd()) {
@@ -499,7 +1068,7 @@ void QDocDatabase::findAllLegaleseTexts(const InnerNode* node)
if (!(*c)->doc().legaleseText().isEmpty())
legaleseTexts_.insertMulti((*c)->doc().legaleseText(), *c);
if ((*c)->isInnerNode())
- findAllLegaleseTexts(static_cast<const InnerNode *>(*c));
+ findAllLegaleseTexts(static_cast<InnerNode *>(*c));
}
++c;
}
@@ -508,13 +1077,13 @@ void QDocDatabase::findAllLegaleseTexts(const InnerNode* node)
/*!
Finds all the namespace nodes and puts them in an index.
*/
-void QDocDatabase::findAllNamespaces(const InnerNode* node)
+void QDocDatabase::findAllNamespaces(InnerNode* node)
{
NodeList::ConstIterator c = node->childNodes().constBegin();
while (c != node->childNodes().constEnd()) {
if ((*c)->access() != Node::Private) {
if ((*c)->isInnerNode()) {
- findAllNamespaces(static_cast<const InnerNode *>(*c));
+ findAllNamespaces(static_cast<InnerNode *>(*c));
if ((*c)->type() == Node::Namespace) {
// Ensure that the namespace's name is not empty (the root
// namespace has no name).
@@ -532,7 +1101,7 @@ void QDocDatabase::findAllNamespaces(const InnerNode* node)
maps. They can be C++ classes, QML types, or they can be
functions, enum types, typedefs, methods, etc.
*/
-void QDocDatabase::findAllObsoleteThings(const InnerNode* node)
+void QDocDatabase::findAllObsoleteThings(InnerNode* node)
{
NodeList::const_iterator c = node->childNodes().constBegin();
while (c != node->childNodes().constEnd()) {
@@ -545,7 +1114,7 @@ void QDocDatabase::findAllObsoleteThings(const 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;
@@ -581,7 +1150,7 @@ void QDocDatabase::findAllObsoleteThings(const 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();
@@ -596,7 +1165,7 @@ void QDocDatabase::findAllObsoleteThings(const 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);
@@ -627,7 +1196,7 @@ void QDocDatabase::findAllObsoleteThings(const InnerNode* node)
This function is used for generating the "New Classes... in x.y"
section on the \e{What's New in Qt x.y} page.
*/
-void QDocDatabase::findAllSince(const InnerNode* node)
+void QDocDatabase::findAllSince(InnerNode* node)
{
NodeList::const_iterator child = node->childNodes().constBegin();
while (child != node->childNodes().constEnd()) {
@@ -665,7 +1234,7 @@ void QDocDatabase::findAllSince(const 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()) {
@@ -702,8 +1271,10 @@ void QDocDatabase::findAllSince(const InnerNode* node)
reference to the value, which is a NodeMap. If \a key is not
found, return a reference to an empty NodeMap.
*/
-const NodeMap& QDocDatabase::getClassMap(const QString& key) const
+const NodeMap& QDocDatabase::getClassMap(const QString& key)
{
+ if (newSinceMaps_.isEmpty() && newClassMaps_.isEmpty() && newQmlTypeMaps_.isEmpty())
+ processForest(&QDocDatabase::findAllSince);
NodeMapMap::const_iterator i = newClassMaps_.constFind(key);
if (i != newClassMaps_.constEnd())
return i.value();
@@ -715,8 +1286,10 @@ const NodeMap& QDocDatabase::getClassMap(const QString& key) const
reference to the value, which is a NodeMap. If the \a key is not
found, return a reference to an empty NodeMap.
*/
-const NodeMap& QDocDatabase::getQmlTypeMap(const QString& key) const
+const NodeMap& QDocDatabase::getQmlTypeMap(const QString& key)
{
+ if (newSinceMaps_.isEmpty() && newClassMaps_.isEmpty() && newQmlTypeMaps_.isEmpty())
+ processForest(&QDocDatabase::findAllSince);
NodeMapMap::const_iterator i = newQmlTypeMaps_.constFind(key);
if (i != newQmlTypeMaps_.constEnd())
return i.value();
@@ -728,8 +1301,10 @@ const NodeMap& QDocDatabase::getQmlTypeMap(const QString& key) const
a reference to the value, which is a NodeMultiMap. If \a key
is not found, return a reference to an empty NodeMultiMap.
*/
-const NodeMultiMap& QDocDatabase::getSinceMap(const QString& key) const
+const NodeMultiMap& QDocDatabase::getSinceMap(const QString& key)
{
+ if (newSinceMaps_.isEmpty() && newClassMaps_.isEmpty() && newQmlTypeMaps_.isEmpty())
+ processForest(&QDocDatabase::findAllSince);
NodeMultiMapMap::const_iterator i = newSinceMaps_.constFind(key);
if (i != newSinceMaps_.constEnd())
return i.value();
@@ -742,209 +1317,55 @@ const NodeMultiMap& QDocDatabase::getSinceMap(const QString& key) const
to generating documentation.
*/
void QDocDatabase::resolveIssues() {
- resolveQmlInheritance(treeRoot());
- resolveTargets(treeRoot());
- tree_->resolveCppToQmlLinks();
+ resolveQmlInheritance(primaryTreeRoot());
+ resolveTargets();
+ primaryTree()->resolveCppToQmlLinks();
}
/*!
- Searches the \a database for a node named \a target and returns
- a pointer to it if found.
+ This function is called for autolinking to a \a type,
+ which could be a function return type or a parameter
+ type. The tree node that represents the \a type is
+ returned. All the trees are searched until a match is
+ found. When searching the primary tree, the search
+ begins at \a relative and proceeds up the parent chain.
+ When searching the index trees, the search begins at the
+ root.
*/
-const Node* QDocDatabase::resolveTarget(const QString& target,
- const Node* relative,
- const Node* self)
+const Node* QDocDatabase::resolveType(const QString& type, const Node* relative)
{
- const Node* node = 0;
- if (target.endsWith("()")) {
- QString funcName = target;
- funcName.chop(2);
- QStringList path = funcName.split("::");
- const FunctionNode* fn = tree_->findFunctionNode(path, relative, SearchBaseClasses);
- if (fn) {
- /*
- Why is this case not accepted?
- */
- if (fn->metaness() != FunctionNode::MacroWithoutParams)
- node = fn;
- }
+ QStringList path = type.split("::");
+ if ((path.size() == 1) && (path.at(0)[0].isLower() || path.at(0) == QString("T"))) {
+ NodeMap::iterator i = typeNodeMap_.find(path.at(0));
+ if (i != typeNodeMap_.end())
+ return i.value();
}
- else if (target.contains(QLatin1Char('#'))) {
- // This error message is never printed; I think we can remove the case.
- qDebug() << "qdoc: target case not handled:" << target;
- }
- else {
- QStringList path = target.split("::");
- int flags = SearchBaseClasses | SearchEnumValues | NonFunction;
- node = tree_->findNode(path, relative, flags, self);
- }
- return node;
+ return forest_.resolveType(path, relative);
}
/*!
Finds the node that will generate the documentation that
contains the \a target and returns a pointer to it.
+
+ Can this be improved by using the target map in Tree?
*/
const Node* QDocDatabase::findNodeForTarget(const QString& target, const Node* relative)
{
const Node* node = 0;
if (target.isEmpty())
node = relative;
- else if (target.endsWith(".html"))
- node = tree_->root()->findChildNodeByNameAndType(target, Node::Document);
+ else if (target.endsWith(".html")) {
+ node = findNodeByNameAndType(QStringList(target), Node::Document);
+ }
else {
node = resolveTarget(target, relative);
if (!node)
- node = findDocNodeByTitle(target, relative);
+ node = findDocNodeByTitle(target);
}
return node;
}
/*!
- Inserts a new target into the target table with the specified
- \a name, \a node, and \a priority.
- */
-void QDocDatabase::insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority)
-{
- TargetRec target;
- target.type_ = type;
- target.node_ = node;
- target.priority_ = priority;
- Atom a = Atom(Atom::Target, name);
- target.ref_ = refForAtom(&a);
- targetRecMultiMap_.insert(name, target);
-}
-
-/*!
- This function searches for a \a target anchor node. If it
- finds one, it sets \a ref and returns the found node.
- */
-const Node*
-QDocDatabase::findUnambiguousTarget(const QString& target, QString& ref, const Node* relative)
-{
- TargetRec bestTarget;
- int numBestTargets = 0;
- QList<TargetRec> bestTargetList;
-
- QString key = Doc::canonicalTitle(target);
- TargetRecMultiMap::iterator i = targetRecMultiMap_.find(key);
- while (i != targetRecMultiMap_.end()) {
- if (i.key() != key)
- break;
- const TargetRec& candidate = i.value();
- if (candidate.priority_ < bestTarget.priority_) {
- bestTarget = candidate;
- bestTargetList.clear();
- bestTargetList.append(candidate);
- numBestTargets = 1;
- } else if (candidate.priority_ == bestTarget.priority_) {
- bestTargetList.append(candidate);
- ++numBestTargets;
- }
- ++i;
- }
- if (numBestTargets > 0) {
- if (numBestTargets == 1) {
- ref = bestTarget.ref_;
- return bestTarget.node_;
- }
- else if (bestTargetList.size() > 1) {
- if (relative && !relative->qmlModuleName().isEmpty()) {
- for (int i=0; i<bestTargetList.size(); ++i) {
- const Node* n = bestTargetList.at(i).node_;
- if (n && relative->qmlModuleName() == n->qmlModuleName()) {
- ref = bestTargetList.at(i).ref_;
- return n;
- }
- }
- }
- }
- }
- ref.clear();
- return 0;
-}
-
-/*!
- This function searches for a node with the specified \a title.
- If \a relative node is provided, it is used to disambiguate if
- it has a QML module identifier.
- */
-const DocNode* QDocDatabase::findDocNodeByTitle(const QString& title, const Node* relative) const
-{
- QString key = Doc::canonicalTitle(title);
- DocNodeMultiMap::const_iterator i = docNodesByTitle_.constFind(key);
- if (i != docNodesByTitle_.constEnd()) {
- if (relative && !relative->qmlModuleName().isEmpty()) {
- const DocNode* dn = i.value();
- InnerNode* parent = dn->parent();
- if (parent && parent->type() == Node::Document && parent->subType() == Node::Collision) {
- const NodeList& nl = parent->childNodes();
- NodeList::ConstIterator it = nl.constBegin();
- while (it != nl.constEnd()) {
- if ((*it)->qmlModuleName() == relative->qmlModuleName()) {
- /*
- By returning here, we avoid printing
- all the duplicate header warnings,
- which are not really duplicates now,
- because of the QML module name being
- used as a namespace qualifier.
- */
- dn = static_cast<const DocNode*>(*it);
- return dn;
- }
- ++it;
- }
- }
- }
- /*
- Reporting all these duplicate section titles is probably
- overkill. We should report the duplicate file and let
- that suffice.
- */
- DocNodeMultiMap::const_iterator j = i;
- ++j;
- if (j != docNodesByTitle_.constEnd() && j.key() == i.key()) {
- QList<Location> internalLocations;
- while (j != docNodesByTitle_.constEnd()) {
- if (j.key() == i.key() && j.value()->url().isEmpty()) {
- internalLocations.append(j.value()->location());
- break; // Just report one duplicate for now.
- }
- ++j;
- }
- if (internalLocations.size() > 0) {
- i.value()->location().warning(tr("This page title exists in more than one file: \"%1\"").arg(title));
- foreach (const Location &location, internalLocations)
- location.warning(tr("[It also exists here]"));
- }
- }
- return i.value();
- }
- return 0;
-}
-
-/*!
- This function searches for a node with a canonical title
- constructed from \a target. If the node it finds is \a node,
- it returns the ref from that node. Otherwise it returns an
- empty string.
- */
-QString QDocDatabase::findTarget(const QString& target, const Node* node) const
-{
- QString key = Doc::canonicalTitle(target);
- TargetRecMultiMap::const_iterator i = targetRecMultiMap_.constFind(key);
-
- if (i != targetRecMultiMap_.constEnd()) {
- do {
- if (i.value().node_ == node)
- return i.value().ref_;
- ++i;
- } while (i != targetRecMultiMap_.constEnd() && i.key() == key);
- }
- return QString();
-}
-
-/*!
For each QML Type node in the tree beginning at \a root,
if it has a QML base type name but its QML base type node
pointer is 0, use the QML base type name to look up the
@@ -953,111 +1374,40 @@ QString QDocDatabase::findTarget(const QString& target, const Node* node) const
*/
void QDocDatabase::resolveQmlInheritance(InnerNode* root)
{
- // Dop we need recursion?
+ 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->qmlBaseNode() == 0) && !qcn->qmlBaseName().isEmpty()) {
- QmlClassNode* bqcn = 0;
- if (qcn->qmlBaseName().contains("::")) {
- bqcn = qmlTypeMap_.value(qcn->qmlBaseName());
- }
- else {
- const ImportList& imports = qcn->importList();
- for (int i=0; i<imports.size(); ++i) {
- bqcn = findQmlType(imports[i], qcn->qmlBaseName());
- if (bqcn)
- break;
- }
- }
- if (bqcn == 0) {
- bqcn = findQmlType(QString(), qcn->qmlBaseName());
- }
- if (bqcn) {
+ if (qcn->qmlBaseNodeNotSet() && !qcn->qmlBaseName().isEmpty()) {
+ QmlClassNode* bqcn = static_cast<QmlClassNode*>(previousSearches.value(qcn->qmlBaseName()));
+ if (bqcn)
qcn->setQmlBaseNode(bqcn);
- }
-#if 0
else {
- qDebug() << "Temporary error message (ignore): UNABLE to resolve QML base type:"
- << qcn->qmlBaseName() << "for QML type:" << qcn->name();
- }
-#endif
- }
- }
- }
-}
-
-/*!
- */
-void QDocDatabase::resolveTargets(InnerNode* root)
-{
- // need recursion
-
- foreach (Node* child, root->childNodes()) {
- if (child->type() == Node::Document) {
- DocNode* node = static_cast<DocNode*>(child);
- if (!node->title().isEmpty()) {
- QString key = Doc::canonicalTitle(node->title());
- QList<DocNode*> nodes = docNodesByTitle_.values(key);
- bool alreadyThere = false;
- if (!nodes.empty()) {
- for (int i=0; i< nodes.size(); ++i) {
- if (nodes[i]->subType() == Node::ExternalPage) {
- if (node->name() == nodes[i]->name()) {
- alreadyThere = true;
+ if (!qcn->importList().isEmpty()) {
+ const ImportList& imports = qcn->importList();
+ for (int i=0; i<imports.size(); ++i) {
+ bqcn = findQmlType(imports[i], qcn->qmlBaseName());
+ if (bqcn)
break;
- }
}
}
- }
- if (!alreadyThere) {
- docNodesByTitle_.insert(key, node);
- }
- }
- if (node->subType() == Node::Collision) {
- resolveTargets(node);
- }
- }
-
- if (child->doc().hasTableOfContents()) {
- const QList<Atom*>& toc = child->doc().tableOfContents();
- TargetRec target;
- target.node_ = child;
- target.priority_ = 3;
-
- for (int i = 0; i < toc.size(); ++i) {
- target.ref_ = refForAtom(toc.at(i));
- QString title = Text::sectionHeading(toc.at(i)).toString();
- if (!title.isEmpty()) {
- QString key = Doc::canonicalTitle(title);
- targetRecMultiMap_.insert(key, target);
+ if (bqcn == 0) {
+ bqcn = findQmlType(QString(), qcn->qmlBaseName());
+ }
+ if (bqcn) {
+ qcn->setQmlBaseNode(bqcn);
+ previousSearches.insert(qcn->qmlBaseName(), bqcn);
+ }
+#if 0
+ else {
+ qDebug() << "Temporary error message (ignore): UNABLE to resolve QML base type:"
+ << qcn->qmlBaseName() << "for QML type:" << qcn->name();
+ }
+#endif
}
}
}
- if (child->doc().hasKeywords()) {
- const QList<Atom*>& keywords = child->doc().keywords();
- TargetRec target;
- target.node_ = child;
- target.priority_ = 1;
-
- for (int i = 0; i < keywords.size(); ++i) {
- target.ref_ = refForAtom(keywords.at(i));
- QString key = Doc::canonicalTitle(keywords.at(i)->string());
- targetRecMultiMap_.insert(key, target);
- }
- }
- if (child->doc().hasTargets()) {
- const QList<Atom*>& toc = child->doc().targets();
- TargetRec target;
- target.node_ = child;
- target.priority_ = 2;
-
- for (int i = 0; i < toc.size(); ++i) {
- target.ref_ = refForAtom(toc.at(i));
- QString key = Doc::canonicalTitle(toc.at(i)->string());
- targetRecMultiMap_.insert(key, target);
- }
- }
}
}
@@ -1096,17 +1446,6 @@ void QDocDatabase::generateIndex(const QString& fileName,
QDocIndexFiles::destroyQDocIndexFiles();
}
-QString QDocDatabase::refForAtom(const Atom* atom)
-{
- if (atom) {
- if (atom->type() == Atom::SectionLeft)
- return Doc::canonicalTitle(Text::sectionHeading(atom).toString());
- if (atom->type() == Atom::Target)
- return Doc::canonicalTitle(atom->string());
- }
- return QString();
-}
-
/*!
If there are open namespaces, search for the function node
having the same function name as the \a clone node in each
@@ -1135,21 +1474,28 @@ 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. If such a 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.
- */
-Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path,
- Node::Type type,
- Node::SubType subtype)
+ 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)
{
+ if (path.isEmpty())
+ return 0;
Node* n = 0;
if (!openNamespaces_.isEmpty()) {
foreach (const QString& t, openNamespaces_) {
- QStringList p = t.split("::") + path;
- n = findNodeByNameAndType(p, type, subtype);
+ QStringList p;
+ if (t != path[0])
+ p = t.split("::") + path;
+ else
+ p = path;
+ n = primaryTree()->findNodeByNameAndType(p, type);
if (n) {
path = p;
break;
@@ -1159,4 +1505,129 @@ Node* QDocDatabase::findNodeInOpenNamespace(QStringList& path,
return n;
}
+/*!
+ Finds all the collection nodes of type \a nt into the
+ collection node map \a cnn. Nodes that match \a relative
+ are not included.
+ */
+void QDocDatabase::mergeCollections(Node::Type nt, CNMap& cnm, const Node* relative)
+{
+ QRegExp singleDigit("\\b([0-9])\\b");
+ CNMultiMap cnmm;
+ forest_.mergeCollectionMaps(nt, cnmm);
+ cnm.clear();
+ if (cnmm.isEmpty())
+ return;
+ QStringList keys = cnmm.uniqueKeys();
+ foreach (QString key, keys) {
+ QList<CollectionNode*> values = cnmm.values(key);
+ CollectionNode* n = 0;
+ foreach (CollectionNode* v, values) {
+ if (v && v->wasSeen() && (v != relative)) {
+ n = v;
+ break;
+ }
+ }
+ if (n) {
+ if (values.size() > 1) {
+ foreach (CollectionNode* v, values) {
+ if (v != n) {
+ foreach (Node* t, v->members())
+ n->addMember(t);
+ }
+ }
+ }
+ if (!n->members().isEmpty()) {
+ QString sortKey = n->fullTitle().toLower();
+ if (sortKey.startsWith("the "))
+ sortKey.remove(0, 4);
+ sortKey.replace(singleDigit, "0\\1");
+ cnm.insert(sortKey, n);
+ }
+ }
+ }
+}
+
+/*!
+ Finds all the collection nodes with the same name
+ and type as \a cn and merges their members into the
+ members list of \a cn.
+ */
+void QDocDatabase::mergeCollections(CollectionNode* cn)
+{
+ CollectionList cl;
+ forest_.getCorrespondingCollections(cn, cl);
+ if (!cl.empty()) {
+ foreach (CollectionNode* v, cl) {
+ if (v != cn) {
+ foreach (Node* t, v->members())
+ cn->addMember(t);
+ }
+ }
+ }
+}
+
QT_END_NAMESPACE
+
+#if 0
+ void getAllGroups(CNMM& t);
+ void getAllModules(CNMM& t);
+ void getAllQmlModules(CNMM& t);
+
+/*!
+ For each tree in the forest, get the group map from the tree.
+ Insert each pair from the group map into the collection node
+ multimap \a t.
+ */
+void QDocForest::getAllGroups(CNMM& t)
+{
+ foreach (Tree* t, searchOrder()) {
+ const GroupMap& gm = t->groups();
+ if (!gm.isEmpty()) {
+ GroupMap::const_iterator i = gm.begin();
+ while (i != gm.end()) {
+ t.insert(i.key(), i.value());
+ ++i;
+ }
+ }
+ }
+}
+
+/*!
+ For each tree in the forest, get the module map from the tree.
+ Insert each pair from the module map into the collection node
+ multimap \a t.
+ */
+void QDocForest::getAllModules(CNMM& t)
+{
+ foreach (Tree* t, searchOrder()) {
+ const ModuleMap& mm = t->modules();
+ if (!mm.isEmpty()) {
+ ModuleMap::const_iterator i = mm.begin();
+ while (i != mm.end()) {
+ t.insert(i.key(), i.value());
+ ++i;
+ }
+ }
+ }
+}
+
+/*!
+ For each tree in the forest, get the QML module map from the
+ tree. Insert each pair from the QML module map into the
+ collection node multimap \a t.
+ */
+void QDocForest::getAllQmlModules(CNMM& t)
+{
+ foreach (Tree* t, searchOrder()) {
+ const QmlModuleMap& qmm = t->groups();
+ if (!qmm.isEmpty()) {
+ QmlModuleMap::const_iterator i = qmm.begin();
+ while (i != qmm.end()) {
+ t.insert(i.key(), i.value());
+ ++i;
+ }
+ }
+ }
+}
+#endif
diff --git a/src/tools/qdoc/qdocdatabase.h b/src/tools/qdoc/qdocdatabase.h
index 4decba5f79..8741443a7c 100644
--- a/src/tools/qdoc/qdocdatabase.h
+++ b/src/tools/qdoc/qdocdatabase.h
@@ -45,19 +45,21 @@
#include <qstring.h>
#include <qmap.h>
#include "tree.h"
+#include "config.h"
+#include "text.h"
+#include <qdebug.h>
QT_BEGIN_NAMESPACE
-typedef QMap<QString, DocNode*> DocNodeMap;
-typedef QMap<QString, QmlClassNode*> QmlTypeMap;
typedef QMap<QString, NodeMap> NodeMapMap;
typedef QMap<QString, NodeMultiMap> NodeMultiMapMap;
typedef QMultiMap<QString, Node*> QDocMultiMap;
typedef QMap<Text, const Node*> TextToNodeMap;
-typedef QMultiMap<QString, DocNode*> DocNodeMultiMap;
+typedef QList<CollectionNode*> CollectionList;
class Atom;
class Generator;
+class QDocDatabase;
enum FindFlag {
SearchBaseClasses = 0x1,
@@ -65,20 +67,139 @@ enum FindFlag {
NonFunction = 0x4
};
-struct TargetRec
+class QDocForest
{
public:
- enum Type { Unknown, Target, Keyword, Contents, Class, Function, Page, Subtitle };
- TargetRec() : node_(0), priority_(INT_MAX), type_(Unknown) { }
- bool isEmpty() const { return ref_.isEmpty(); }
- //void debug(int idx, const QString& key);
- Node* node_;
- QString ref_;
- int priority_;
- Type type_;
-};
-typedef QMultiMap<QString, TargetRec> TargetRecMultiMap;
+ friend class QDocDatabase;
+ QDocForest(QDocDatabase* qdb)
+ : qdb_(qdb), primaryTree_(0), currentIndex_(0) { }
+ ~QDocForest();
+
+ NamespaceNode* firstRoot();
+ NamespaceNode* nextRoot();
+ 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()); }
+ const QVector<Tree*>& searchOrder();
+ const QVector<Tree*>& indexSearchOrder();
+ void setSearchOrder();
+
+ const Node* findNode(const QStringList& path, const Node* relative, int findFlags) {
+ foreach (Tree* t, searchOrder()) {
+ const Node* n = t->findNode(path, relative, findFlags);
+ if (n)
+ return n;
+ relative = 0;
+ }
+ return 0;
+ }
+
+ Node* findNodeByNameAndType(const QStringList& path, Node::Type type) {
+ foreach (Tree* t, searchOrder()) {
+ Node* n = t->findNodeByNameAndType(path, type);
+ if (n)
+ return n;
+ }
+ return 0;
+ }
+
+ ClassNode* findClassNode(const QStringList& path) {
+ foreach (Tree* t, searchOrder()) {
+ ClassNode* n = t->findClassNode(path);
+ if (n)
+ return n;
+ }
+ return 0;
+ }
+
+ InnerNode* findRelatesNode(const QStringList& path) {
+ foreach (Tree* t, searchOrder()) {
+ InnerNode* n = t->findRelatesNode(path);
+ if (n)
+ return n;
+ }
+ return 0;
+ }
+
+ const Node* resolveFunctionTarget(const QString& target, const Node* relative) {
+ foreach (Tree* t, searchOrder()) {
+ const Node* n = t->resolveFunctionTarget(target, relative);
+ if (n)
+ return n;
+ relative = 0;
+ }
+ return 0;
+ }
+ const Node* resolveTarget(const QString& target, const Node* relative);
+
+ const Node* resolveType(const QStringList& path, const Node* relative)
+ {
+ foreach (Tree* t, searchOrder()) {
+ const Node* n = resolveTypeHelper(path, relative, t);
+ if (n)
+ return n;
+ relative = 0;
+ }
+ return 0;
+ }
+
+ const Node* findUnambiguousTarget(const QString& target, QString& ref)
+ {
+ foreach (Tree* t, searchOrder()) {
+ const Node* n = t->findUnambiguousTarget(target, ref);
+ if (n)
+ return n;
+ }
+ return 0;
+ }
+
+ const DocNode* findDocNodeByTitle(const QString& title)
+ {
+ foreach (Tree* t, searchOrder()) {
+ const DocNode* n = t->findDocNodeByTitle(title);
+ if (n)
+ return n;
+ }
+ return 0;
+ }
+
+ QmlClassNode* lookupQmlType(const QString& name)
+ {
+ foreach (Tree* t, searchOrder()) {
+ QmlClassNode* qcn = t->lookupQmlType(name);
+ if (qcn)
+ return qcn;
+ }
+ return 0;
+ }
+ void mergeCollectionMaps(Node::Type nt, CNMultiMap& cnmm);
+ void getCorrespondingCollections(CollectionNode* cn, CollectionList& cl)
+ {
+ foreach (Tree* t, searchOrder()) {
+ CollectionNode* ccn = t->getCorrespondingCollection(cn);
+ if (ccn)
+ cl.append(ccn);
+ }
+ }
+ private:
+ void newPrimaryTree(const QString& module);
+ NamespaceNode* newIndexTree(const QString& module);
+ const Node* resolveTypeHelper(const QStringList& path, const Node* relative, Tree* t);
+
+ private:
+ QDocDatabase* qdb_;
+ Tree* primaryTree_;
+ int currentIndex_;
+ QMap<QString, Tree*> forest_;
+ QVector<Tree*> searchOrder_;
+ QVector<Tree*> indexSearchOrder_;
+ QVector<QString> moduleNames_;
+};
class QDocDatabase
{
@@ -89,100 +210,125 @@ class QDocDatabase
static void destroyQdocDB();
~QDocDatabase();
- const DocNodeMap& groups() const { return groups_; }
- const DocNodeMap& modules() const { return modules_; }
- const DocNodeMap& qmlModules() const { return qmlModules_; }
-
- DocNode* getGroup(const QString& name);
- DocNode* findGroup(const QString& name);
- DocNode* findModule(const QString& name);
- QmlModuleNode* findQmlModule(const QString& name);
+ 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(); }
- DocNode* addGroup(const QString& name);
- DocNode* addModule(const QString& name);
- QmlModuleNode* addQmlModule(const QString& name);
+ GroupNode* getGroup(const QString& name) { return primaryTree()->getGroup(name); }
+ GroupNode* findGroup(const QString& name) { return primaryTree()->findGroup(name); }
+ ModuleNode* findModule(const QString& name) { return primaryTree()->findModule(name); }
+ QmlModuleNode* findQmlModule(const QString& name) { return primaryTree()->findQmlModule(name); }
- DocNode* addToGroup(const QString& name, Node* node);
- DocNode* addToModule(const QString& name, Node* node);
- void addToQmlModule(const QString& name, Node* node);
+ GroupNode* addGroup(const QString& name) { return primaryTree()->addGroup(name); }
+ ModuleNode* addModule(const QString& name) { return primaryTree()->addModule(name); }
+ QmlModuleNode* addQmlModule(const QString& name) { return primaryTree()->addQmlModule(name); }
- QmlClassNode* findQmlType(const QString& qmid, const QString& name) const;
- QmlClassNode* findQmlType(const ImportRec& import, const QString& name) const;
+ GroupNode* addToGroup(const QString& name, Node* node) {
+ return primaryTree()->addToGroup(name, node);
+ }
+ ModuleNode* addToModule(const QString& name, Node* node) {
+ return primaryTree()->addToModule(name, node);
+ }
+ QmlModuleNode* addToQmlModule(const QString& name, Node* node) {
+ return primaryTree()->addToQmlModule(name, node);
+ }
+ void addExampleNode(ExampleNode* n) { primaryTree()->addExampleNode(n); }
+ ExampleNodeMap& exampleNodeMap() { return primaryTree()->exampleNodeMap(); }
- void findAllClasses(const InnerNode *node);
- void findAllFunctions(const InnerNode *node);
- void findAllLegaleseTexts(const InnerNode *node);
- void findAllNamespaces(const InnerNode *node);
- void findAllObsoleteThings(const InnerNode* node);
- void findAllSince(const InnerNode *node);
- void buildCollections();
+ QmlClassNode* findQmlType(const QString& name);
+ QmlClassNode* findQmlType(const QString& qmid, const QString& name);
+ QmlClassNode* findQmlType(const ImportRec& import, const QString& name);
+ private:
+ void findAllClasses(InnerNode *node);
+ void findAllFunctions(InnerNode *node);
+ void findAllLegaleseTexts(InnerNode *node);
+ void findAllNamespaces(InnerNode *node);
+ void findAllObsoleteThings(InnerNode* node);
+ void findAllSince(InnerNode *node);
+
+ public:
// special collection access functions
- NodeMap& getCppClasses() { return nonCompatClasses_; }
- NodeMap& getMainClasses() { return mainClasses_; }
- NodeMap& getCompatibilityClasses() { return compatClasses_; }
- NodeMap& getObsoleteClasses() { return obsoleteClasses_; }
- NodeMap& getClassesWithObsoleteMembers() { return classesWithObsoleteMembers_; }
- NodeMap& getObsoleteQmlTypes() { return obsoleteQmlTypes_; }
- NodeMap& getQmlTypesWithObsoleteMembers() { return qmlTypesWithObsoleteMembers_; }
- NodeMap& getNamespaces() { return namespaceIndex_; }
- NodeMap& getServiceClasses() { return serviceClasses_; }
- NodeMap& getQmlTypes() { return qmlClasses_; }
- NodeMapMap& getFunctionIndex() { return funcIndex_; }
- TextToNodeMap& getLegaleseTexts() { return legaleseTexts_; }
- const NodeMap& getClassMap(const QString& key) const;
- const NodeMap& getQmlTypeMap(const QString& key) const;
- const NodeMultiMap& getSinceMap(const QString& key) const;
-
- const Node* resolveTarget(const QString& target, const Node* relative, const Node* self=0);
- const Node* findNodeForTarget(const QString& target, const Node* relative);
- void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority);
+ NodeMap& getCppClasses();
+ NodeMap& getMainClasses();
+ NodeMap& getCompatibilityClasses();
+ NodeMap& getObsoleteClasses();
+ NodeMap& getClassesWithObsoleteMembers();
+ NodeMap& getObsoleteQmlTypes();
+ NodeMap& getQmlTypesWithObsoleteMembers();
+ NodeMap& getNamespaces();
+ NodeMap& getServiceClasses();
+ NodeMap& getQmlTypes();
+ NodeMapMap& getFunctionIndex();
+ TextToNodeMap& getLegaleseTexts();
+ const NodeMap& getClassMap(const QString& key);
+ const NodeMap& getQmlTypeMap(const QString& key);
+ const NodeMultiMap& getSinceMap(const QString& key);
/* convenience functions
Many of these will be either eliminated or replaced.
*/
- QString refForAtom(const Atom* atom);
- Tree* tree() { return tree_; }
- NamespaceNode* treeRoot() { return tree_->root(); }
- void resolveInheritance() { tree_->resolveInheritance(); }
+ void resolveInheritance() { primaryTree()->resolveInheritance(); }
void resolveQmlInheritance(InnerNode* root);
void resolveIssues();
- void fixInheritance() { tree_->fixInheritance(); }
- void resolveProperties() { tree_->resolveProperties(); }
-
- const Node* findNode(const QStringList& path) { return tree_->findNode(path); }
- ClassNode* findClassNode(const QStringList& path) { return tree_->findClassNode(path); }
- NamespaceNode* findNamespaceNode(const QStringList& path) { return tree_->findNamespaceNode(path); }
+ void fixInheritance() { primaryTree()->fixInheritance(); }
+ void resolveProperties() { primaryTree()->resolveProperties(); }
- NameCollisionNode* findCollisionNode(const QString& name) const {
- return tree_->findCollisionNode(name);
+ void resolveTargets() {
+ primaryTree()->resolveTargets(primaryTreeRoot());
+ }
+ void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority) {
+ primaryTree()->insertTarget(name, type, node, priority);
}
- const DocNode* findDocNodeByTitle(const QString& title, const Node* relative = 0) const;
- const Node *findUnambiguousTarget(const QString &target, QString& ref, const Node* relative);
- QString findTarget(const QString &target, const Node *node) const;
- void resolveTargets(InnerNode* root);
-
+ /*******************************************************************
+ The functions declared below are called for the current tree only.
+ ********************************************************************/
FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone) {
- return tree_->findFunctionNode(parentPath, clone);
+ return primaryTree()->findFunctionNode(parentPath, clone);
}
- Node* findNodeByNameAndType(const QStringList& path, Node::Type type, Node::SubType subtype){
- return tree_->findNodeByNameAndType(path, type, subtype, 0);
+ FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone);
+ Node* findNodeInOpenNamespace(QStringList& path, Node::Type type);
+ NameCollisionNode* findCollisionNode(const QString& name) {
+ return primaryTree()->findCollisionNode(name);
+ }
+ NameCollisionNode* checkForCollision(const QString& name) {
+ return primaryTree()->checkForCollision(name);
+ }
+ /*******************************************************************/
+
+ /*******************************************************************
+ The functions declared below are called for all trees.
+ ********************************************************************/
+ ClassNode* findClassNode(const QStringList& path) { return forest_.findClassNode(path); }
+ InnerNode* findRelatesNode(const QStringList& path) { return forest_.findRelatesNode(path); }
+ const Node* resolveTarget(const QString& target, const Node* relative) {
+ return forest_.resolveTarget(target, relative);
+ }
+ const Node* resolveFunctionTarget(const QString& target, const Node* relative) {
+ return forest_.resolveFunctionTarget(target, relative);
+ }
+ const Node* resolveType(const QString& type, const Node* relative);
+ const Node* findNodeForTarget(const QString& target, const Node* relative);
+ const DocNode* findDocNodeByTitle(const QString& title) {
+ return forest_.findDocNodeByTitle(title);
+ }
+ const Node* findUnambiguousTarget(const QString& target, QString& ref) {
+ return forest_.findUnambiguousTarget(target, ref);
}
- NameCollisionNode* checkForCollision(const QString& name) const {
- return tree_->checkForCollision(name);
+ Node* findNodeByNameAndType(const QStringList& path, Node::Type type) {
+ return forest_.findNodeByNameAndType(path, type);
}
- void addBaseClass(ClassNode* subclass,
- Node::Access access,
- const QStringList& basePath,
- const QString& dataTypeWithTemplateArgs,
- InnerNode* parent) {
- tree_->addBaseClass(subclass, access, basePath, dataTypeWithTemplateArgs, parent);
+ /*******************************************************************/
+
+ 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) {
- tree_->addPropertyFunction(property, funcName, funcRole);
+ primaryTree()->addPropertyFunction(property, funcName, funcRole);
}
void setVersion(const QString& v) { version_ = v; }
@@ -198,37 +344,43 @@ class QDocDatabase
void clearOpenNamespaces() { openNamespaces_.clear(); }
void insertOpenNamespace(const QString& path) { openNamespaces_.insert(path); }
- FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone);
- Node* findNodeInOpenNamespace(QStringList& path, Node::Type type, Node::SubType subtype);
void setShowInternal(bool value) { showInternal_ = value; }
- /* debugging functions */
- void printModules() const;
- void printQmlModules() const;
+ // Try to make this function private.
+ QDocForest& forest() { return forest_; }
+ NamespaceNode* primaryTreeRoot() { return forest_.primaryTreeRoot(); }
+ void newPrimaryTree(const QString& module) { forest_.newPrimaryTree(module); }
+ NamespaceNode* newIndexTree(const QString& module) { return forest_.newIndexTree(module); }
+ const QVector<Tree*>& searchOrder() { return forest_.searchOrder(); }
+ void setSearchOrder() { forest_.setSearchOrder(); }
+ void mergeCollections(Node::Type nt, CNMap& cnm, const Node* relative);
+ void mergeCollections(CollectionNode* cn);
private:
friend class QDocIndexFiles;
friend class QDocTagFiles;
const Node* findNode(const QStringList& path, const Node* relative, int findFlags) {
- return tree_->findNode(path, relative, findFlags);
+ return forest_.findNode(path, relative, findFlags);
}
+ void processForest(void (QDocDatabase::*) (InnerNode*));
+ static void initializeDB();
private:
QDocDatabase();
- QDocDatabase(QDocDatabase const& ) { }; // copy constructor is private
- QDocDatabase& operator=(QDocDatabase const& ); // assignment operator is private
+ QDocDatabase(QDocDatabase const& ) : showInternal_(false), forest_(this) { }
+ QDocDatabase& operator=(QDocDatabase const& );
+ Tree* primaryTree() { return forest_.primaryTree(); }
+
+ public:
+ static bool debug;
private:
static QDocDatabase* qdocDB_;
+ static NodeMap typeNodeMap_;
bool showInternal_;
QString version_;
- QDocMultiMap masterMap_;
- Tree* tree_;
- DocNodeMap groups_;
- DocNodeMap modules_;
- DocNodeMap qmlModules_;
- QmlTypeMap qmlTypeMap_;
+ QDocForest forest_;
NodeMap nonCompatClasses_;
NodeMap mainClasses_;
@@ -245,8 +397,6 @@ class QDocDatabase
NodeMultiMapMap newSinceMaps_;
NodeMapMap funcIndex_;
TextToNodeMap legaleseTexts_;
- DocNodeMultiMap docNodesByTitle_;
- TargetRecMultiMap targetRecMultiMap_;
QSet<QString> openNamespaces_;
};
diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp
index 00c9c55020..25f6b8eec9 100644
--- a/src/tools/qdoc/qdocindexfiles.cpp
+++ b/src/tools/qdoc/qdocindexfiles.cpp
@@ -77,6 +77,7 @@ QDocIndexFiles::QDocIndexFiles()
QDocIndexFiles::~QDocIndexFiles()
{
qdb_ = 0;
+ gen_ = 0;
}
/*!
@@ -109,6 +110,7 @@ void QDocIndexFiles::readIndexes(const QStringList& indexFiles)
foreach (const QString& indexFile, indexFiles) {
QString msg = "Loading index file: " + indexFile;
Location::logToStdErr(msg);
+ //qDebug() << " LOAD INDEX FILE:" << indexFile;
readIndexFile(indexFile);
}
}
@@ -144,12 +146,13 @@ void QDocIndexFiles::readIndexFile(const QString& path)
basesList_.clear();
relatedList_.clear();
+ NamespaceNode* root = qdb_->newIndexTree(project_);
+
// Scan all elements in the XML file, constructing a map that contains
// base classes for each class found.
-
QDomElement child = indexElement.firstChildElement();
while (!child.isNull()) {
- readIndexSection(child, qdb_->treeRoot(), indexUrl);
+ readIndexSection(child, root, indexUrl);
child = child.nextSiblingElement();
}
@@ -189,9 +192,11 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
}
else if (element.nodeName() == "class") {
node = new ClassNode(parent, name);
- basesList_.append(QPair<ClassNode*,QString>(static_cast<ClassNode*>(node),
- element.attribute("bases")));
-
+ if (element.hasAttribute("bases")) {
+ QString bases = element.attribute("bases");
+ if (!bases.isEmpty())
+ basesList_.append(QPair<ClassNode*,QString>(static_cast<ClassNode*>(node), bases));
+ }
if (!indexUrl.isEmpty())
location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html");
else if (!indexUrl.isNull())
@@ -201,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");
@@ -213,8 +217,9 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
abstract = true;
qcn->setAbstract(abstract);
QString qmlFullBaseName = element.attribute("qml-base-type");
- if (!qmlFullBaseName.isEmpty())
+ if (!qmlFullBaseName.isEmpty()) {
qcn->setQmlBaseName(qmlFullBaseName);
+ }
if (element.hasAttribute("location"))
name = element.attribute("location", QString());
if (!indexUrl.isEmpty())
@@ -254,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);
}
@@ -277,6 +282,31 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
FunctionNode* fn = new FunctionNode(t, parent, name, attached);
node = fn;
}
+ else if (element.nodeName() == "group") {
+ GroupNode* gn = qdb_->addGroup(name);
+ gn->setTitle(element.attribute("title"));
+ gn->setSubTitle(element.attribute("subtitle"));
+ if (element.attribute("seen") == "true")
+ gn->markSeen();
+ node = gn;
+ }
+ else if (element.nodeName() == "module") {
+ ModuleNode* mn = qdb_->addModule(name);
+ mn->setTitle(element.attribute("title"));
+ mn->setSubTitle(element.attribute("subtitle"));
+ if (element.attribute("seen") == "true")
+ mn->markSeen();
+ node = mn;
+ }
+ else if (element.nodeName() == "qmlmodule") {
+ QString t = element.attribute("qml-module-name") + " " + element.attribute("qml-module-version");
+ QmlModuleNode* qmn = qdb_->addQmlModule(t);
+ qmn->setTitle(element.attribute("title"));
+ qmn->setSubTitle(element.attribute("subtitle"));
+ if (element.attribute("seen") == "true")
+ qmn->markSeen();
+ node = qmn;
+ }
else if (element.nodeName() == "page") {
Node::SubType subtype;
Node::PageType ptype = Node::NoPageType;
@@ -293,18 +323,6 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
subtype = Node::File;
ptype = Node::NoPageType;
}
- else if (attr == "group") {
- subtype = Node::Group;
- ptype = Node::OverviewPage;
- }
- else if (attr == "module") {
- subtype = Node::Module;
- ptype = Node::OverviewPage;
- }
- else if (attr == "qmlmodule") {
- subtype = Node::QmlModule;
- ptype = Node::OverviewPage;
- }
else if (attr == "page") {
subtype = Node::Page;
ptype = Node::ArticlePage;
@@ -313,25 +331,10 @@ 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;
- DocNode* docNode = 0;
- if (subtype == Node::QmlModule) {
- QString t = element.attribute("qml-module-name") + " " +
- element.attribute("qml-module-version");
- docNode = qdb_->addQmlModule(t);
- }
- else
- docNode = new DocNode(parent, name, subtype, ptype);
+ DocNode* docNode = new DocNode(parent, name, subtype, ptype);
docNode->setTitle(element.attribute("title"));
if (element.hasAttribute("location"))
@@ -383,31 +386,33 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
}
else if (element.nodeName() == "function") {
FunctionNode::Virtualness virt;
- if (element.attribute("virtual") == "non")
+ QString t = element.attribute("virtual");
+ if (t == "non")
virt = FunctionNode::NonVirtual;
- else if (element.attribute("virtual") == "impure")
+ else if (t == "impure")
virt = FunctionNode::ImpureVirtual;
- else if (element.attribute("virtual") == "pure")
+ else if (t == "pure")
virt = FunctionNode::PureVirtual;
else
return;
+ t = element.attribute("meta");
FunctionNode::Metaness meta;
- if (element.attribute("meta") == "plain")
+ if (t == "plain")
meta = FunctionNode::Plain;
- else if (element.attribute("meta") == "signal")
+ else if (t == "signal")
meta = FunctionNode::Signal;
- else if (element.attribute("meta") == "slot")
+ else if (t == "slot")
meta = FunctionNode::Slot;
- else if (element.attribute("meta") == "constructor")
+ else if (t == "constructor")
meta = FunctionNode::Ctor;
- else if (element.attribute("meta") == "destructor")
+ else if (t == "destructor")
meta = FunctionNode::Dtor;
- else if (element.attribute("meta") == "macro")
+ else if (t == "macro")
meta = FunctionNode::MacroWithParams;
- else if (element.attribute("meta") == "macrowithparams")
+ else if (t == "macrowithparams")
meta = FunctionNode::MacroWithParams;
- else if (element.attribute("meta") == "macrowithoutparams")
+ else if (t == "macrowithoutparams")
meta = FunctionNode::MacroWithoutParams;
else
return;
@@ -426,6 +431,10 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
QPair<FunctionNode*,QString>(functionNode,
element.attribute("relates")));
}
+ /*
+ Note: The "signature" attribute was written to the
+ index file, but it is not read back in. Is that ok?
+ */
QDomElement child = element.firstChildElement("parameter");
while (!child.isNull()) {
@@ -513,7 +522,7 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
QString moduleName = element.attribute("module");
if (!moduleName.isEmpty())
- node->setModuleName(moduleName);
+ qdb_->addToModule(moduleName, node);
if (!href.isEmpty()) {
if (node->isExternalPage())
node->setUrl(href);
@@ -529,15 +538,8 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
QString groupsAttr = element.attribute("groups");
if (!groupsAttr.isEmpty()) {
QStringList groupNames = groupsAttr.split(",");
- for (int i=0; i<groupNames.size(); ++i) {
- DocNode* dn = qdb_->findGroup(groupNames[i]);
- if (dn) {
- dn->addMember(node);
- }
- else {
- qDebug() << "NODE:" << node->name() << "GROUPS:" << groupNames;
- qDebug() << "DID NOT FIND GROUP for:" << node->name();
- }
+ foreach (QString name, groupNames) {
+ qdb_->addToGroup(name, node);
}
}
@@ -584,57 +586,44 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element,
}
/*!
+ This function tries to resolve class inheritance immediately
+ after the index file is read. It is not always possible to
+ resolve a class inheritance at this point, because the base
+ class might be in an index file that hasn't been read yet, or
+ it might be in one of the header files that will be read for
+ the current module. These cases will be resolved after all
+ the index files and header and source files have been read,
+ just prior to beginning the generate phase for the current
+ module.
+
+ I don't think this is completely correct because it always
+ sets the access to public.
*/
void QDocIndexFiles::resolveIndex()
{
QPair<ClassNode*,QString> pair;
foreach (pair, basesList_) {
foreach (const QString& base, pair.second.split(QLatin1Char(','))) {
- Node* n = qdb_->treeRoot()->findChildNodeByNameAndType(base, Node::Class);
- if (n) {
- pair.first->addBaseClass(Node::Public, static_cast<ClassNode*>(n));
- }
+ QStringList basePath = base.split(QString("::"));
+ Node* n = qdb_->findClassNode(basePath);
+ if (n)
+ pair.first->addResolvedBaseClass(Node::Public, static_cast<ClassNode*>(n));
+ else
+ pair.first->addUnresolvedBaseClass(Node::Public, basePath, QString());
}
}
QPair<FunctionNode*,QString> relatedPair;
foreach (relatedPair, relatedList_) {
- Node* n = qdb_->treeRoot()->findChildNodeByNameAndType(relatedPair.second, Node::Class);
+ QStringList path = relatedPair.second.split("::");
+ Node* n = qdb_->findRelatesNode(path);
if (n)
relatedPair.first->setRelates(static_cast<ClassNode*>(n));
}
-}
-
-/*!
- Normally this is used for writing the \e groups attribute,
- but it can be used for writing any attribute with a list
- value that comes from some subset of the members of \a n.
- \note The members of \a n are \e not the children of \a n.
-
- The names we want to include are the names of the members
- of \a n that have node type \a t and node subtype \a st.
- The attribute name is \a attr. The names are joined with
- the space character and written with \a writer.
- */
-void QDocIndexFiles::writeMembersAttribute(QXmlStreamWriter& writer,
- const InnerNode* n,
- Node::Type t,
- Node::SubType st,
- const QString& attr)
-{
- const NodeList& members = n->members();
- if (!members.isEmpty()) {
- QStringList names;
- NodeList::ConstIterator i = members.constBegin();
- while (i != members.constEnd()) {
- if ((*i)->type() == t && (*i)->subType() == st)
- names.append((*i)->name());
- ++i;
- }
- if (!names.isEmpty())
- writer.writeAttribute(attr, names.join(","));
- }
+ // No longer needed.
+ basesList_.clear();
+ relatedList_.clear();
}
/*!
@@ -663,17 +652,29 @@ 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";
+ break;
+ case Node::Module:
+ nodeName = "module";
+ break;
+ case Node::QmlModule:
+ nodeName = "qmlmodule";
break;
case Node::Enum:
nodeName = "enum";
@@ -741,14 +742,14 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
QString objName = node->name();
// Special case: only the root node should have an empty name.
- if (objName.isEmpty() && node != qdb_->treeRoot())
+ if (objName.isEmpty() && node != qdb_->primaryTreeRoot())
return false;
writer.writeStartElement(nodeName);
QXmlStreamAttributes attributes;
- if (node->type() != Node::Document) {
+ if (!node->isDocNode() && !node->isGroup() && !node->isModule() && !node->isQmlModule()) {
QString threadSafety;
switch (node->threadSafeness()) {
case Node::NonReentrant:
@@ -832,10 +833,12 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
if (!href.isEmpty())
writer.writeAttribute("href", href);
- writer.writeAttribute("access", access);
writer.writeAttribute("status", status);
- if (node->isAbstract())
- writer.writeAttribute("abstract", "true");
+ if (!node->isDocNode() && !node->isGroup() && !node->isModule() && !node->isQmlModule()) {
+ writer.writeAttribute("access", access);
+ if (node->isAbstract())
+ writer.writeAttribute("abstract", "true");
+ }
if (!node->location().fileName().isEmpty())
writer.writeAttribute("location", node->location().fileName());
if (!node->location().filePath().isEmpty()) {
@@ -847,7 +850,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeAttribute("since", node->since());
}
- QString brief = node->doc().briefText().toString();
+ QString brief = node->doc().trimmedBriefText(node->name()).toString();
switch (node->type()) {
case Node::Class:
{
@@ -856,13 +859,16 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
QList<RelatedClass> bases = classNode->baseClasses();
QSet<QString> baseStrings;
foreach (const RelatedClass& related, bases) {
- ClassNode* baseClassNode = related.node;
- baseStrings.insert(baseClassNode->name());
+ ClassNode* n = related.node_;
+ if (n)
+ baseStrings.insert(n->fullName());
}
- writer.writeAttribute("bases", QStringList(baseStrings.toList()).join(","));
+ if (!baseStrings.isEmpty())
+ writer.writeAttribute("bases", QStringList(baseStrings.toList()).join(","));
if (!node->moduleName().isEmpty())
writer.writeAttribute("module", node->moduleName());
- writeMembersAttribute(writer, classNode, Node::Document, Node::Group, "groups");
+ if (!classNode->groupNames().isEmpty())
+ writer.writeAttribute("groups", classNode->groupNames().join(","));
if (!brief.isEmpty())
writer.writeAttribute("brief", brief);
}
@@ -872,7 +878,20 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
const NamespaceNode* namespaceNode = static_cast<const NamespaceNode*>(node);
if (!namespaceNode->moduleName().isEmpty())
writer.writeAttribute("module", namespaceNode->moduleName());
- writeMembersAttribute(writer, namespaceNode, Node::Document, Node::Group, "groups");
+ if (!namespaceNode->groupNames().isEmpty())
+ writer.writeAttribute("groups", namespaceNode->groupNames().join(","));
+ if (!brief.isEmpty())
+ 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);
}
@@ -880,8 +899,8 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
case Node::Document:
{
/*
- Document nodes (such as manual pages) contain subtypes,
- titles and other attributes.
+ Document nodes (such as manual pages) have a subtype,
+ a title, and other attributes.
*/
bool writeModuleName = false;
const DocNode* docNode = static_cast<const DocNode*>(node);
@@ -897,26 +916,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
case Node::File:
writer.writeAttribute("subtype", "file");
break;
- case Node::Group:
- {
- writer.writeAttribute("subtype", "group");
- writer.writeAttribute("seen", docNode->wasSeen() ? "true" : "false");
- // Groups contain information about their group members.
- const NodeList& members = docNode->members();
- QStringList names;
- foreach (const Node* member, members) {
- names.append(member->name());
- }
- writer.writeAttribute("members", names.join(","));
- writeModuleName = true;
- }
- break;
- case Node::Module:
- writer.writeAttribute("subtype", "module");
- break;
- case Node::QmlModule:
- writer.writeAttribute("subtype", "qmlmodule");
- break;
case Node::Page:
writer.writeAttribute("subtype", "page");
writeModuleName = true;
@@ -924,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;
}
@@ -939,7 +932,82 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
if (!node->moduleName().isEmpty() && writeModuleName) {
writer.writeAttribute("module", node->moduleName());
}
- writeMembersAttribute(writer, docNode, Node::Document, Node::Group, "groups");
+ if (!docNode->groupNames().isEmpty())
+ writer.writeAttribute("groups", docNode->groupNames().join(","));
+ if (!brief.isEmpty())
+ writer.writeAttribute("brief", brief);
+ }
+ break;
+ case Node::Group:
+ {
+ const GroupNode* gn = static_cast<const GroupNode*>(node);
+ writer.writeAttribute("seen", gn->wasSeen() ? "true" : "false");
+ writer.writeAttribute("title", gn->title());
+ if (!gn->subTitle().isEmpty())
+ writer.writeAttribute("subtitle", gn->subTitle());
+ if (!gn->moduleName().isEmpty())
+ writer.writeAttribute("module", gn->moduleName());
+ if (!gn->groupNames().isEmpty())
+ writer.writeAttribute("groups", gn->groupNames().join(","));
+ /*
+ This is not read back in, so it probably
+ shouldn't be written out in the first place.
+ */
+ if (!gn->members().isEmpty()) {
+ QStringList names;
+ foreach (const Node* member, gn->members())
+ names.append(member->name());
+ writer.writeAttribute("members", names.join(","));
+ }
+ if (!brief.isEmpty())
+ writer.writeAttribute("brief", brief);
+ }
+ break;
+ case Node::Module:
+ {
+ const ModuleNode* mn = static_cast<const ModuleNode*>(node);
+ writer.writeAttribute("seen", mn->wasSeen() ? "true" : "false");
+ writer.writeAttribute("title", mn->title());
+ if (!mn->subTitle().isEmpty())
+ writer.writeAttribute("subtitle", mn->subTitle());
+ if (!mn->moduleName().isEmpty())
+ writer.writeAttribute("module", mn->moduleName());
+ if (!mn->groupNames().isEmpty())
+ writer.writeAttribute("groups", mn->groupNames().join(","));
+ /*
+ This is not read back in, so it probably
+ shouldn't be written out in the first place.
+ */
+ if (!mn->members().isEmpty()) {
+ QStringList names;
+ foreach (const Node* member, mn->members())
+ names.append(member->name());
+ writer.writeAttribute("members", names.join(","));
+ }
+ if (!brief.isEmpty())
+ writer.writeAttribute("brief", brief);
+ }
+ case Node::QmlModule:
+ {
+ const QmlModuleNode* qmn = static_cast<const QmlModuleNode*>(node);
+ writer.writeAttribute("seen", qmn->wasSeen() ? "true" : "false");
+ writer.writeAttribute("title", qmn->title());
+ if (!qmn->subTitle().isEmpty())
+ writer.writeAttribute("subtitle", qmn->subTitle());
+ if (!qmn->moduleName().isEmpty())
+ writer.writeAttribute("module", qmn->moduleName());
+ if (!qmn->groupNames().isEmpty())
+ writer.writeAttribute("groups", qmn->groupNames().join(","));
+ /*
+ This is not read back in, so it probably
+ shouldn't be written out in the first place.
+ */
+ if (!qmn->members().isEmpty()) {
+ QStringList names;
+ foreach (const Node* member, qmn->members())
+ names.append(member->name());
+ writer.writeAttribute("members", names.join(","));
+ }
if (!brief.isEmpty())
writer.writeAttribute("brief", brief);
}
@@ -995,8 +1063,9 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
writer.writeAttribute("overload", functionNode->isOverload()?"true":"false");
if (functionNode->isOverload())
writer.writeAttribute("overload-number", QString::number(functionNode->overloadNumber()));
- if (functionNode->relates())
+ if (functionNode->relates()) {
writer.writeAttribute("relates", functionNode->relates()->name());
+ }
const PropertyNode* propertyNode = functionNode->associatedProperty();
if (propertyNode)
writer.writeAttribute("associated-property", propertyNode->name());
@@ -1010,7 +1079,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
writer.writeAttribute("type", qpn->dataType());
writer.writeAttribute("attached", qpn->isAttached() ? "true" : "false");
- writer.writeAttribute("writable", qpn->isWritable(qdb_) ? "true" : "false");
+ writer.writeAttribute("writable", qpn->isWritable() ? "true" : "false");
if (!brief.isEmpty())
writer.writeAttribute("brief", brief);
}
@@ -1127,36 +1196,11 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
}
else if (node->type() == Node::Function) {
const FunctionNode* functionNode = static_cast<const FunctionNode*>(node);
- // Write a signature attribute for convenience.
- QStringList signatureList;
- QStringList resolvedParameters;
- foreach (const Parameter& parameter, functionNode->parameters()) {
- QString leftType = parameter.leftType();
- const Node* leftNode = qdb_->findNode(parameter.leftType().split("::"),
- 0,
- SearchBaseClasses|NonFunction);
- if (!leftNode || leftNode->type() != Node::Typedef) {
- leftNode = qdb_->findNode(parameter.leftType().split("::"),
- node->parent(),
- SearchBaseClasses|NonFunction);
- }
- if (leftNode && leftNode->type() == Node::Typedef) {
- if (leftNode->type() == Node::Typedef) {
- const TypedefNode* typedefNode = static_cast<const TypedefNode*>(leftNode);
- if (typedefNode->associatedEnum()) {
- leftType = "QFlags<" + typedefNode->associatedEnum()->fullDocumentName() +
- QLatin1Char('>');
- }
- }
- else
- leftType = leftNode->fullDocumentName();
- }
- resolvedParameters.append(leftType);
- signatureList.append(leftType + QLatin1Char(' ') + parameter.name());
- }
-
- QString signature = functionNode->name() + QLatin1Char('(') + signatureList.join(", ") +
- QLatin1Char(')');
+ /*
+ Note: The "signature" attribute is written to the
+ index file, but it is not read back in. Is that ok?
+ */
+ QString signature = functionNode->signature();
if (functionNode->isConst())
signature += " const";
writer.writeAttribute("signature", signature);
@@ -1164,7 +1208,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer,
for (int i = 0; i < functionNode->parameters().size(); ++i) {
Parameter parameter = functionNode->parameters()[i];
writer.writeStartElement("parameter");
- writer.writeAttribute("left", resolvedParameters[i]);
+ writer.writeAttribute("left", parameter.leftType());
writer.writeAttribute("right", parameter.rightType());
writer.writeAttribute("name", parameter.name());
writer.writeAttribute("default", parameter.defaultValue());
@@ -1239,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())
@@ -1262,9 +1306,13 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer,
bool generateInternalNodes)
{
/*
- Note that the groups are written after all the other nodes.
+ Note that groups, modules, and QML modules are written
+ after all the other nodes.
*/
- if (!node->isGroup() && generateIndexSection(writer, node, generateInternalNodes)) {
+ if (node->isGroup() || node->isModule() || node->isQmlModule())
+ return;
+
+ if (generateIndexSection(writer, node, generateInternalNodes)) {
if (node->isInnerNode()) {
const InnerNode* inner = static_cast<const InnerNode*>(node);
@@ -1320,17 +1368,19 @@ void QDocIndexFiles::generateIndex(const QString& fileName,
writer.writeAttribute("version", qdb_->version());
writer.writeAttribute("project", g->config()->getString(CONFIG_PROJECT));
- generateIndexSections(writer, qdb_->treeRoot(), generateInternalNodes);
+ generateIndexSections(writer, qdb_->primaryTreeRoot(), generateInternalNodes);
/*
- We wait until the end of the index file to output the group elements.
- By waiting until the end, when we read each group element, its members
- will have already been created. It is then only necessary to create
- the group page and add each member to its member list.
+ We wait until the end of the index file to output the group, module,
+ and QML module elements. By outputting them at the end, when we read
+ the index file back in, all the group, module, and QML module member
+ elements will have already been created. It is then only necessary to
+ create the group, module, or QML module element and add each member to
+ its member list.
*/
- const DocNodeMap& groups = qdb_->groups();
+ const CNMap& groups = qdb_->groups();
if (!groups.isEmpty()) {
- DocNodeMap::ConstIterator g = groups.constBegin();
+ CNMap::ConstIterator g = groups.constBegin();
while (g != groups.constEnd()) {
if (generateIndexSection(writer, g.value(), generateInternalNodes))
writer.writeEndElement();
@@ -1338,6 +1388,26 @@ void QDocIndexFiles::generateIndex(const QString& fileName,
}
}
+ const CNMap& modules = qdb_->modules();
+ if (!modules.isEmpty()) {
+ CNMap::ConstIterator g = modules.constBegin();
+ while (g != modules.constEnd()) {
+ if (generateIndexSection(writer, g.value(), generateInternalNodes))
+ writer.writeEndElement();
+ ++g;
+ }
+ }
+
+ const CNMap& qmlModules = qdb_->qmlModules();
+ if (!qmlModules.isEmpty()) {
+ CNMap::ConstIterator g = qmlModules.constBegin();
+ while (g != qmlModules.constEnd()) {
+ if (generateIndexSection(writer, g.value(), generateInternalNodes))
+ writer.writeEndElement();
+ ++g;
+ }
+ }
+
writer.writeEndElement(); // INDEX
writer.writeEndElement(); // QDOCINDEX
writer.writeEndDocument();
diff --git a/src/tools/qdoc/qdocindexfiles.h b/src/tools/qdoc/qdocindexfiles.h
index e4a83176a2..bd94fdb215 100644
--- a/src/tools/qdoc/qdocindexfiles.h
+++ b/src/tools/qdoc/qdocindexfiles.h
@@ -76,11 +76,6 @@ class QDocIndexFiles
void resolveIndex();
bool generateIndexSection(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
void generateIndexSections(QXmlStreamWriter& writer, Node* node, bool generateInternalNodes = false);
- void writeMembersAttribute(QXmlStreamWriter& writer,
- const InnerNode* n,
- Node::Type t,
- Node::SubType st,
- const QString& attr);
private:
static QDocIndexFiles* qdocIndexFiles_;
@@ -89,7 +84,6 @@ class QDocIndexFiles
QString project_;
QList<QPair<ClassNode*,QString> > basesList_;
QList<QPair<FunctionNode*,QString> > relatedList_;
-
};
QT_END_NAMESPACE
diff --git a/src/tools/qdoc/qdoctagfiles.cpp b/src/tools/qdoc/qdoctagfiles.cpp
index a0054ea229..cc2bd3f1f0 100644
--- a/src/tools/qdoc/qdoctagfiles.cpp
+++ b/src/tools/qdoc/qdoctagfiles.cpp
@@ -147,7 +147,7 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Inne
QString objName = node->name();
// Special case: only the root node should have an empty name.
- if (objName.isEmpty() && node != qdb_->treeRoot())
+ if (objName.isEmpty() && node != qdb_->primaryTreeRoot())
continue;
// *** Write the starting tag for the element here. ***
@@ -162,8 +162,9 @@ void QDocTagFiles::generateTagFileCompounds(QXmlStreamWriter& writer, const Inne
const ClassNode* classNode = static_cast<const ClassNode*>(node);
QList<RelatedClass> bases = classNode->baseClasses();
foreach (const RelatedClass& related, bases) {
- ClassNode* baseClassNode = related.node;
- writer.writeTextElement("base", baseClassNode->name());
+ ClassNode* n = related.node_;
+ if (n)
+ writer.writeTextElement("base", n->name());
}
// Recurse to write all members.
@@ -243,7 +244,7 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const InnerN
QString objName = node->name();
// Special case: only the root node should have an empty name.
- if (objName.isEmpty() && node != qdb_->treeRoot())
+ if (objName.isEmpty() && node != qdb_->primaryTreeRoot())
continue;
// *** Write the starting tag for the element here. ***
@@ -294,31 +295,8 @@ void QDocTagFiles::generateTagFileMembers(QXmlStreamWriter& writer, const InnerN
QStringList pieces = gen_->fullDocumentLocation(node,Generator::useOutputSubdirs()).split(QLatin1Char('#'));
writer.writeTextElement("anchorfile", pieces[0]);
writer.writeTextElement("anchor", pieces[1]);
-
- // Write a signature attribute for convenience.
- QStringList signatureList;
-
- foreach (const Parameter& parameter, functionNode->parameters()) {
- QString leftType = parameter.leftType();
- const Node* leftNode = qdb_->findNode(parameter.leftType().split("::"),
- 0,
- SearchBaseClasses|NonFunction);
- if (!leftNode || leftNode->type() != Node::Typedef) {
- leftNode = qdb_->findNode(parameter.leftType().split("::"),
- node->parent(),
- SearchBaseClasses|NonFunction);
- }
- if (leftNode && leftNode->type() == Node::Typedef) {
- const TypedefNode* typedefNode = static_cast<const TypedefNode*>(leftNode);
- if (typedefNode->associatedEnum()) {
- leftType = "QFlags<" + typedefNode->associatedEnum()->fullDocumentName() +
- QLatin1Char('>');
- }
- }
- signatureList.append(leftType + QLatin1Char(' ') + parameter.name());
- }
-
- QString signature = QLatin1Char('(')+signatureList.join(", ")+QLatin1Char(')');
+ QString signature = functionNode->signature();
+ signature = signature.mid(signature.indexOf(QChar('('))).trimmed();
if (functionNode->isConst())
signature += " const";
if (functionNode->virtualness() == FunctionNode::PureVirtual)
@@ -395,7 +373,7 @@ void QDocTagFiles::generateTagFile(const QString& fileName, Generator* g)
writer.setAutoFormatting(true);
writer.writeStartDocument();
writer.writeStartElement("tagfile");
- generateTagFileCompounds(writer, qdb_->treeRoot());
+ generateTagFileCompounds(writer, qdb_->primaryTreeRoot());
writer.writeEndElement(); // tagfile
writer.writeEndDocument();
file.close();
diff --git a/src/tools/qdoc/qmlcodeparser.h b/src/tools/qdoc/qmlcodeparser.h
index 71b4660fe7..7f6f8d1a81 100644
--- a/src/tools/qdoc/qmlcodeparser.h
+++ b/src/tools/qdoc/qmlcodeparser.h
@@ -58,7 +58,6 @@ QT_BEGIN_NAMESPACE
class Config;
class Node;
class QString;
-class Tree;
class QmlCodeParser : public CodeParser
{
diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp
index ec1ef41256..2ef751e9bc 100644
--- a/src/tools/qdoc/qmlvisitor.cpp
+++ b/src/tools/qdoc/qmlvisitor.cpp
@@ -97,7 +97,7 @@ QmlDocVisitor::QmlDocVisitor(const QString &filePath,
this->engine = engine;
this->commands_ = commands;
this->topics_ = topics;
- current = QDocDatabase::qdocDB()->treeRoot();
+ current = QDocDatabase::qdocDB()->primaryTreeRoot();
}
/*!
@@ -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 113220059c..147abe21af 100644
--- a/src/tools/qdoc/tree.cpp
+++ b/src/tools/qdoc/tree.cpp
@@ -60,132 +60,91 @@ QT_BEGIN_NAMESPACE
This class is now private. Only class QDocDatabase has access.
Please don't change this. If you must access class Tree, do it
though the pointer to the singleton QDocDatabase.
+
+ Tree is being converted to a forest. A static member provides a
+ map of Tree* values with the module names as the keys. There is
+ one Tree in the map for each index file read, and there is one
+ tree that is not in the map for the module whose documentation
+ is being generated.
*/
/*!
- Constructs the singleton tree. \a qdb is the pointer to the
+ Constructs a Tree. \a qdb is the pointer to the singleton
qdoc database that is constructing the tree. This might not
be necessary, and it might be removed later.
*/
-Tree::Tree(QDocDatabase* qdb)
- : qdb_(qdb), root_(0, QString())
+Tree::Tree(const QString& module, QDocDatabase* qdb)
+ : module_(module), qdb_(qdb), root_(0, QString())
{
+ root_.setModuleName(module_);
+ root_.setTree(this);
}
/*!
- Destroys the singleton Tree.
+ Destroys the Tree. The root node is a data member
+ of this object, so its destructor is called. The
+ destructor of each child node is called, and these
+ destructors are recursive. Thus the entire tree is
+ destroyed.
*/
Tree::~Tree()
{
+ // nothing
}
-// 1 calls 2
+/* API members */
+
/*!
- Searches the tree for a node that matches the \a path. The
- search begins at \a start but can move up the parent chain
- recursively if no match is found.
+ Find the C++ class node named \a path. Begin the search at the
+ \a start node. If the \a start node is 0, begin the search
+ at the root of the tree. Only a C++ class node named \a path is
+ acceptible. If one is not found, 0 is returned.
*/
-const Node* Tree::findNode(const QStringList& path,
- const Node* start,
- int findFlags,
- const Node* self) const
+ClassNode* Tree::findClassNode(const QStringList& path, Node* start) const
{
- const Node* current = start;
- if (!current)
- current = root();
-
- /*
- First, search for a node assuming we don't want a QML node.
- If that search fails, search again assuming we do want a
- QML node.
- */
- const Node* n = findNode(path,current,findFlags,self,false);
- if (!n) {
- n = findNode(path,current,findFlags,self,true);
- }
- return n;
+ if (!start)
+ start = const_cast<NamespaceNode*>(root());
+ return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, Node::Class));
}
-// 2 is private; it is only called by 1.
/*!
- This overload function was extracted from the one above that has the
- same signature without the last bool parameter, \a qml. This version
- is called only by that other one. It is therefore private. It can
- be called a second time by that other version, if the first call
- returns null. If \a qml is false, the search will only match a node
- that is not a QML node. If \a qml is true, the search will only
- match a node that is a QML node.
-*/
-const Node* Tree::findNode(const QStringList& path,
- const Node* start,
- int findFlags,
- const Node* self,
- bool qml) const
+ Find the Namespace node named \a path. Begin the search at
+ the root of the tree. Only a Namespace node named \a path
+ is acceptible. If one is not found, 0 is returned.
+ */
+NamespaceNode* Tree::findNamespaceNode(const QStringList& path) const
{
- const Node* current = start;
- do {
- const Node* node = current;
- int i;
- int start_idx = 0;
-
- /*
- If the path contains one or two double colons ("::"),
- check first to see if the first two path strings refer
- to a QML element. If they do, path[0] will be the QML
- module identifier, and path[1] will be the QML type.
- If the anser is yes, the reference identifies a QML
- class node.
- */
- if (qml && path.size() >= 2 && !path[0].isEmpty()) {
- QmlClassNode* qcn = qdb_->findQmlType(path[0], path[1]);
- if (qcn) {
- node = qcn;
- if (path.size() == 2)
- return node;
- start_idx = 2;
- }
- }
-
- for (i = start_idx; i < path.size(); ++i) {
- if (node == 0 || !node->isInnerNode())
- break;
-
- const Node* next = static_cast<const InnerNode*>(node)->findChildNodeByName(path.at(i), qml);
- if (!next && (findFlags & SearchEnumValues) && i == path.size()-1)
- next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i));
+ Node* start = const_cast<NamespaceNode*>(root());
+ return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, Node::Namespace));
+}
- if (!next && !qml && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
- NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
- foreach (const Node* baseClass, baseClasses) {
- next = static_cast<const InnerNode*>(baseClass)->findChildNodeByName(path.at(i));
- if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1)
- next = static_cast<const InnerNode*>(baseClass)->findEnumNodeForValue(path.at(i));
- if (next)
- break;
- }
- }
- node = next;
- }
- if (node && i == path.size()
- && (!(findFlags & NonFunction) || node->type() != Node::Function
- || ((FunctionNode*)node)->metaness() == FunctionNode::MacroWithoutParams)) {
- if ((node != self) && (node->type() != Node::QmlPropertyGroup)) {
- if (node->subType() == Node::Collision) {
- node = node->applyModuleName(start);
- }
- return node;
- }
- }
- current = current->parent();
- } while (current);
+/*!
+ This function first ignores the \a clone node and searches
+ for the parent node with \a parentPath. If that search is
+ successful, it searches for a child node of the parent that
+ matches the \a clone node. If it finds a node that is just
+ like the \a clone, it returns a pointer to the found node.
- return 0;
+ There should be a way to avoid creating the clone in the
+ first place. Investigate when time allows.
+ */
+FunctionNode* Tree::findFunctionNode(const QStringList& parentPath, const FunctionNode* clone)
+{
+ const Node* parent = findNamespaceNode(parentPath);
+ if (parent == 0)
+ parent = findClassNode(parentPath, 0);
+ if (parent == 0)
+ parent = findNode(parentPath);
+ if (parent == 0 || !parent->isInnerNode())
+ return 0;
+ return ((InnerNode*)parent)->findFunctionNode(clone);
}
+
/*!
Find the Qml type node named \a path. Begin the search at the
\a start node. If the \a start node is 0, begin the search
- at the root of the tree. Only a Qml type node named \a path is
+ at the root of the tree. Only a Qml type node named <\a path is
acceptible. If one is not found, 0 is returned.
*/
QmlClassNode* Tree::findQmlTypeNode(const QStringList& path)
@@ -203,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));
}
/*!
@@ -215,7 +174,7 @@ QmlClassNode* Tree::findQmlTypeNode(const QStringList& path)
node as its first child, and return a pointer to the new
NameCollisionNode. Otherwise return 0.
*/
-NameCollisionNode* Tree::checkForCollision(const QString& name) const
+NameCollisionNode* Tree::checkForCollision(const QString& name)
{
Node* n = const_cast<Node*>(findNode(QStringList(name)));
if (n) {
@@ -248,18 +207,6 @@ NameCollisionNode* Tree::findCollisionNode(const QString& name) const
}
/*!
- This function just calls the const version of the same function
- and returns the function node.
- */
-FunctionNode* Tree::findFunctionNode(const QStringList& path,
- Node* relative,
- int findFlags)
-{
- return const_cast<FunctionNode*>
- (const_cast<const Tree*>(this)->findFunctionNode(path,relative,findFlags));
-}
-
-/*!
This function begins searching the tree at \a relative for
the \l {FunctionNode} {function node} identified by \a path.
The \a findFlags are used to restrict the search. If a node
@@ -274,17 +221,23 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
if (!relative)
relative = root();
- /*
- If the path contains two double colons ("::"), check
- first to see if it is a reference to a QML method. If
- it is a reference to a QML method, first look up the
- QML class node in the QML module map.
- */
if (path.size() == 3 && !path[0].isEmpty()) {
- QmlClassNode* qcn = qdb_->findQmlType(path[0], path[1]);
- if (qcn) {
- return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2]));
+ QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
+ if (!qcn) {
+ QStringList p(path[1]);
+ Node* n = findNodeByNameAndType(p, Node::QmlType);
+ if (n) {
+ 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::QmlType, Node::NoSubType));
+ }
+ }
}
+ if (qcn)
+ return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2]));
}
do {
@@ -299,7 +252,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
if (i == path.size() - 1)
next = ((InnerNode*) node)->findFunctionNode(path.at(i));
else
- next = ((InnerNode*) node)->findChildNodeByName(path.at(i));
+ next = ((InnerNode*) node)->findChildNode(path.at(i));
if (!next && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
@@ -307,7 +260,7 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
if (i == path.size() - 1)
next = static_cast<const InnerNode*>(baseClass)->findFunctionNode(path.at(i));
else
- next = static_cast<const InnerNode*>(baseClass)->findChildNodeByName(path.at(i));
+ next = static_cast<const InnerNode*>(baseClass)->findChildNode(path.at(i));
if (next)
break;
@@ -339,57 +292,34 @@ const FunctionNode* Tree::findFunctionNode(const QStringList& path,
return 0;
}
-/*!
- This function just calls the const version of itself and
- returns the result.
- */
-FunctionNode* Tree::findFunctionNode(const QStringList& parentPath,
- const FunctionNode* clone,
- Node* relative,
- int findFlags)
+static NodeTypeList t;
+static const NodeTypeList& relatesTypes()
{
- return const_cast<FunctionNode*>(
- const_cast<const Tree*>(this)->findFunctionNode(parentPath,
- clone,
- relative,
- findFlags));
+ if (t.isEmpty()) {
+ t.reserve(3);
+ t.append(NodeTypePair(Node::Class, Node::NoSubType));
+ t.append(NodeTypePair(Node::Namespace, Node::NoSubType));
+ t.append(NodeTypePair(Node::Document, Node::HeaderFile));
+ }
+ return t;
}
/*!
- This function first ignores the \a clone node and searches
- for the node having the \a parentPath by calling the main
- findFunction(\a {parentPath}, \a {relative}, \a {findFlags}).
- If that search is successful, then it searches for the \a clone
- in the found parent node.
- */
-const FunctionNode* Tree::findFunctionNode(const QStringList& parentPath,
- const FunctionNode* clone,
- const Node* relative,
- int findFlags) const
-{
- const Node* parent = findNamespaceNode(parentPath);
- if (parent == 0)
- parent = findClassNode(parentPath, 0);
- if (parent == 0)
- parent = findNode(parentPath, relative, findFlags);
- if (parent == 0 || !parent->isInnerNode())
- return 0;
- return ((InnerNode*)parent)->findFunctionNode(clone);
-}
+ This function searches for the node specified by \a path.
+ The matching node can be one of several different types
+ including a C++ class, a C++ namespace, or a C++ header
+ file.
-/*!
+ I'm not sure if it can be a QML type, but if that is a
+ possibility, the code can easily accommodate it.
+
+ If a matching node is found, a pointer to it is returned.
+ Otherwise 0 is returned.
*/
-void Tree::addBaseClass(ClassNode* subclass, Node::Access access,
- const QStringList& basePath,
- const QString& dataTypeWithTemplateArgs,
- InnerNode* parent)
+InnerNode* Tree::findRelatesNode(const QStringList& path)
{
- unresolvedInheritanceMap[subclass].append(
- InheritanceBound(access,
- basePath,
- dataTypeWithTemplateArgs,
- parent)
- );
+ Node* n = findNodeRecursive(path, 0, root(), relatesTypes());
+ return ((n && n->isInnerNode()) ? static_cast<InnerNode*>(n) : 0);
}
/*!
@@ -402,24 +332,25 @@ void Tree::addPropertyFunction(PropertyNode* property,
}
/*!
- This function resolves inheritance and reimplementation settings
- for each C++ class node found in the namspace beginning at \a rootNode.
- If it finds another namespace node in the child list of \a rootNode,
- it calls itself recursively. For each child of \a rootNode that is a
- class node, it calls the other resolveInheritance() function.
+ This function resolves C++ inheritance and reimplementation
+ settings for each C++ class node found in the tree beginning
+ at \a n. It also calls itself recursively for each C++ class
+ node or namespace node it encounters. For each child of \a n
+ that is a class node, it calls resolveInheritanceHelper().
This function does not resolve QML inheritance.
*/
-void Tree::resolveInheritance(NamespaceNode* rootNode)
+void Tree::resolveInheritance(InnerNode* n)
{
- if (!rootNode)
- rootNode = root();
+ if (!n)
+ n = root();
for (int pass = 0; pass < 2; pass++) {
- NodeList::ConstIterator c = rootNode->childNodes().constBegin();
- while (c != rootNode->childNodes().constEnd()) {
+ NodeList::ConstIterator c = n->childNodes().constBegin();
+ while (c != n->childNodes().constEnd()) {
if ((*c)->type() == Node::Class) {
- resolveInheritance(pass, (ClassNode*)* c);
+ resolveInheritanceHelper(pass, (ClassNode*)*c);
+ resolveInheritance((ClassNode*)*c);
}
else if ((*c)->type() == Node::Namespace) {
NamespaceNode* ns = static_cast<NamespaceNode*>(*c);
@@ -427,8 +358,73 @@ void Tree::resolveInheritance(NamespaceNode* rootNode)
}
++c;
}
- if (rootNode == root())
- unresolvedInheritanceMap.clear();
+ }
+}
+
+/*!
+ This function is run twice for eachclass node \a cn in the
+ tree. First it is run with \a pass set to 0 for each
+ class node \a cn. Then it is run with \a pass set to 1 for
+ eachclass node \a cn.
+
+ In \a pass 0, all the base classes ofclass node \a cn are
+ found and added to the base class list forclass node \a cn.
+
+ In \a pass 1, each child ofclass node \a cn that is a function
+ that is reimplemented from one of the base classes is marked
+ as being reimplemented from that class.
+
+ Some property node fixing up is also done in \a pass 1.
+ */
+void Tree::resolveInheritanceHelper(int pass, ClassNode* cn)
+{
+ if (pass == 0) {
+ QList<RelatedClass>& bases = cn->baseClasses();
+ QList<RelatedClass>::iterator b = bases.begin();
+ while (b != bases.end()) {
+ if (!(*b).node_) {
+ Node* n = qdb_->findClassNode((*b).path_);
+#if 0
+ /*
+ If the node for the base class was not found,
+ the reason might be that the subclass is in a
+ namespace and the base class is in the same
+ namespace, but the base class name was not
+ qualified with the namespace name. That is the
+ case most of the time. Then restart the search
+ at the parent of the subclass node (the namespace
+ node) using the unqualified base class name.
+ */
+ if (!n) {
+ InnerNode* parent = cn->parent();
+ n = findClassNode((*b).path_, parent);
+ }
+#endif
+ if (n) {
+ ClassNode* bcn = static_cast<ClassNode*>(n);
+ (*b).node_ = bcn;
+ bcn->addDerivedClass((*b).access_, cn);
+ }
+ }
+ ++b;
+ }
+ }
+ else {
+ NodeList::ConstIterator c = cn->childNodes().constBegin();
+ while (c != cn->childNodes().constEnd()) {
+ if ((*c)->type() == Node::Function) {
+ FunctionNode* func = (FunctionNode*)* c;
+ FunctionNode* from = findVirtualFunctionInBaseClasses(cn, func);
+ if (from != 0) {
+ if (func->virtualness() == FunctionNode::NonVirtual)
+ func->setVirtualness(FunctionNode::ImpureVirtual);
+ func->setReimplementedFrom(from);
+ }
+ }
+ else if ((*c)->type() == Node::Property)
+ cn->fixPropertyUsingBaseClasses(static_cast<PropertyNode*>(*c));
+ ++c;
+ }
}
}
@@ -486,57 +482,6 @@ void Tree::resolveProperties()
}
/*!
- This function is run twice for each \a classNode in the
- tree. First it is run with \a pass set to 0 for each
- \a classNode. Then it is run with \a pass set to 1 for
- each \a classNode.
-
- In \a pass 0, all the base classes of \a classNode are
- found and added to the base class list for \a classNode.
-
- In \a pass 1, each child of \a classNode that is a function
- that is reimplemented from one of the base classes is marked
- as being reimplemented from that class.
-
- Some property node fixing up is also done in \a pass 1.
- */
-void Tree::resolveInheritance(int pass, ClassNode* classNode)
-{
- if (pass == 0) {
- QList<InheritanceBound> bounds = unresolvedInheritanceMap[classNode];
- QList<InheritanceBound>::ConstIterator b = bounds.constBegin();
- while (b != bounds.constEnd()) {
- Node* n = findClassNode((*b).basePath);
- if (!n && (*b).parent) {
- n = findClassNode((*b).basePath, (*b).parent);
- }
- if (n) {
- classNode->addBaseClass((*b).access, static_cast<ClassNode*>(n), (*b).dataTypeWithTemplateArgs);
- }
- ++b;
- }
- }
- else {
- NodeList::ConstIterator c = classNode->childNodes().constBegin();
- while (c != classNode->childNodes().constEnd()) {
- if ((*c)->type() == Node::Function) {
- FunctionNode* func = (FunctionNode*)* c;
- FunctionNode* from = findVirtualFunctionInBaseClasses(classNode, func);
- if (from != 0) {
- if (func->virtualness() == FunctionNode::NonVirtual)
- func->setVirtualness(FunctionNode::ImpureVirtual);
- func->setReimplementedFrom(from);
- }
- }
- else if ((*c)->type() == Node::Property) {
- fixPropertyUsingBaseClasses(classNode, static_cast<PropertyNode*>(*c));
- }
- ++c;
- }
- }
-}
-
-/*!
For each QML class node that points to a C++ class node,
follow its C++ class node pointer and set the C++ class
node's QML class node pointer back to the QML class node.
@@ -545,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)
@@ -575,16 +520,18 @@ void Tree::fixInheritance(NamespaceNode* rootNode)
/*!
*/
-FunctionNode* Tree::findVirtualFunctionInBaseClasses(ClassNode* classNode,
- FunctionNode* clone)
+FunctionNode* Tree::findVirtualFunctionInBaseClasses(ClassNode* cn, FunctionNode* clone)
{
- QList<RelatedClass>::ConstIterator r = classNode->baseClasses().constBegin();
- while (r != classNode->baseClasses().constEnd()) {
+ const QList<RelatedClass>& rc = cn->baseClasses();
+ QList<RelatedClass>::ConstIterator r = rc.constBegin();
+ while (r != rc.constEnd()) {
FunctionNode* func;
- if (((func = findVirtualFunctionInBaseClasses((*r).node, clone)) != 0 ||
- (func = (*r).node->findFunctionNode(clone)) != 0)) {
- if (func->virtualness() != FunctionNode::NonVirtual)
- return func;
+ if ((*r).node_) {
+ if (((func = findVirtualFunctionInBaseClasses((*r).node_, clone)) != 0 ||
+ (func = (*r).node_->findFunctionNode(clone)) != 0)) {
+ if (func->virtualness() != FunctionNode::NonVirtual)
+ return func;
+ }
}
++r;
}
@@ -593,35 +540,30 @@ FunctionNode* Tree::findVirtualFunctionInBaseClasses(ClassNode* classNode,
/*!
*/
-void Tree::fixPropertyUsingBaseClasses(ClassNode* classNode, PropertyNode* property)
+NodeList Tree::allBaseClasses(const ClassNode* classNode) const
{
- QList<RelatedClass>::const_iterator r = classNode->baseClasses().constBegin();
- while (r != classNode->baseClasses().constEnd()) {
- Node* n = r->node->findChildNodeByNameAndType(property->name(), Node::Property);
- if (n) {
- PropertyNode* baseProperty = static_cast<PropertyNode*>(n);
- fixPropertyUsingBaseClasses(r->node, baseProperty);
- property->setOverriddenFrom(baseProperty);
- }
- else {
- fixPropertyUsingBaseClasses(r->node, property);
+ NodeList result;
+ foreach (const RelatedClass& r, classNode->baseClasses()) {
+ if (r.node_) {
+ result += r.node_;
+ result += allBaseClasses(r.node_);
}
- ++r;
}
+ return result;
}
/*!
+ 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}.
*/
-NodeList Tree::allBaseClasses(const ClassNode* classNode) const
+Node* Tree::findNodeByNameAndType(const QStringList& path, Node::Type type) const
{
- NodeList result;
- foreach (const RelatedClass& r, classNode->baseClasses()) {
- result += r.node;
- result += allBaseClasses(r.node);
- }
- 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
@@ -629,17 +571,12 @@ 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,
- Node* start,
- bool acceptCollision)
+Node* Tree::findHtmlFileNode(const QStringList& path) const
{
- if (!start)
- start = const_cast<NamespaceNode*>(root());
- Node* result = findNodeRecursive(path, 0, start, type, subtype, acceptCollision);
- return result;
+ return findNodeRecursive(path, 0, root());
}
+#endif
+/* internal members */
/*!
Recursive search for a node identified by \a path. Each
@@ -659,22 +596,19 @@ Node* Tree::findNodeByNameAndType(const QStringList& path,
*/
Node* Tree::findNodeRecursive(const QStringList& path,
int pathIndex,
- Node* start,
- Node::Type type,
- Node::SubType subtype,
- bool acceptCollision) const
+ const Node* start,
+ Node::Type type) const
{
if (!start || path.isEmpty())
return 0; // no place to start, or nothing to search for.
+ Node* node = const_cast<Node*>(start);
if (start->isLeaf()) {
if (pathIndex >= path.size())
- return start; // found a match.
+ return node; // found a match.
return 0; // premature leaf
}
- if (pathIndex >= path.size())
- return 0; // end of search path.
- InnerNode* current = static_cast<InnerNode*>(start);
+ InnerNode* current = static_cast<InnerNode*>(node);
const NodeList& children = current->childNodes();
const QString& name = path.at(pathIndex);
for (int i=0; i<children.size(); ++i) {
@@ -683,79 +617,637 @@ 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 && acceptCollision)
- return n;
- else if (subtype == Node::NoSubType)
- return n; // don't care what subtype is.
- return 0;
+ if (n->type() == type)
+ return n;
+ continue;
+ }
+ else { // Search the children of n for the next name in the path.
+ n = findNodeRecursive(path, pathIndex+1, n, type);
+ if (n)
+ return n;
+ }
+ }
+ }
+ return 0;
+}
+
+/*!
+ Recursive search for a node identified by \a path. Each
+ path element is a name. \a pathIndex specifies the index
+ of the name in \a path to try to match. \a start is the
+ node whose children shoulod be searched for one that has
+ that name. Each time a name match is found, increment the
+ \a pathIndex and call this function recursively.
+
+ If the end of the path is reached (i.e. if a matching
+ node is found for each name in the \a path), test the
+ matching node's type and subtype values against the ones
+ listed in \a types. If a match is found there, return the
+ pointer to the final node. Otherwise return 0.
+ */
+Node* Tree::findNodeRecursive(const QStringList& path,
+ int pathIndex,
+ Node* start,
+ const NodeTypeList& types) const
+{
+ if (!start || path.isEmpty())
+ return 0;
+ if (start->isLeaf())
+ return ((pathIndex >= path.size()) ? start : 0);
+ if (pathIndex >= path.size())
+ return 0;
+
+ InnerNode* current = static_cast<InnerNode*>(start);
+ const NodeList& children = current->childNodes();
+ for (int i=0; i<children.size(); ++i) {
+ Node* n = children.at(i);
+ if (n && n->name() == path.at(pathIndex)) {
+ if (pathIndex+1 >= path.size()) {
+ if (n->match(types))
+ return n;
+ }
+ else if (!n->isLeaf()) {
+ n = findNodeRecursive(path, pathIndex+1, n, types);
+ if (n)
+ return n;
+ }
+ }
+ }
+ return 0;
+}
+
+/*!
+ Searches the tree for a node that matches the \a path. The
+ search begins at \a start but can move up the parent chain
+ recursively if no match is found.
+
+ This findNode() callse the other findNode(), which is not
+ called anywhere else.
+ */
+const Node* Tree::findNode(const QStringList& path, const Node* start, int findFlags) const
+{
+ const Node* current = start;
+ if (!current)
+ current = root();
+
+ /*
+ First, search for a node assuming we don't want a QML node.
+ If that search fails, search again assuming we do want a
+ QML node.
+ */
+ const Node* n = findNode(path, current, findFlags, false);
+ if (n)
+ return n;
+ return findNode(path, current, findFlags, true);
+}
+
+/*!
+ This overload function was extracted from the one above that has the
+ same signature without the last bool parameter, \a qml. This version
+ is called only by that other one. It is therefore private. It can
+ be called a second time by that other version, if the first call
+ returns null. If \a qml is false, the search will only match a node
+ that is not a QML node. If \a qml is true, the search will only
+ match a node that is a QML node.
+
+ This findNode() is only called by the other findNode().
+*/
+const Node* Tree::findNode(const QStringList& path, const Node* start, int findFlags, bool qml) const
+{
+ const Node* current = start;
+ do {
+ const Node* node = current;
+ int i;
+ int start_idx = 0;
+
+ /*
+ If the path contains one or two double colons ("::"),
+ check first to see if the first two path strings refer
+ to a QML element. If they do, path[0] will be the QML
+ module identifier, and path[1] will be the QML type.
+ If the anser is yes, the reference identifies a QML
+ class node.
+ */
+ if (qml && path.size() >= 2 && !path[0].isEmpty()) {
+ QmlClassNode* qcn = lookupQmlType(QString(path[0] + "::" + path[1]));
+ if (qcn) {
+ node = qcn;
+ if (path.size() == 2)
+ return node;
+ start_idx = 2;
+ }
+ }
+
+ for (i = start_idx; i < path.size(); ++i) {
+ if (node == 0 || !node->isInnerNode())
+ break;
+
+ const Node* next = static_cast<const InnerNode*>(node)->findChildNode(path.at(i), qml);
+ if (!next && (findFlags & SearchEnumValues) && i == path.size()-1) {
+ next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i));
+ }
+ if (!next && !qml && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
+ NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
+ foreach (const Node* baseClass, baseClasses) {
+ next = static_cast<const InnerNode*>(baseClass)->findChildNode(path.at(i));
+ if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1)
+ next = static_cast<const InnerNode*>(baseClass)->findEnumNodeForValue(path.at(i));
+ if (next) {
+ break;
}
- else
- return n;
}
- else if (n->isCollisionNode()) {
- if (acceptCollision)
- return n;
- return findNodeRecursive(path, pathIndex, n, type, subtype);
+ }
+ node = next;
+ }
+ if (node && i == path.size()
+ && (!(findFlags & NonFunction) || node->type() != Node::Function
+ || ((FunctionNode*)node)->metaness() == FunctionNode::MacroWithoutParams)) {
+ if (node->isCollisionNode())
+ node = node->applyModuleName(start);
+ return node;
+ }
+ current = current->parent();
+ } while (current);
+
+ return 0;
+}
+
+/*!
+ This function searches for a node with a canonical title
+ constructed from \a target. If the node it finds is \a node,
+ it returns the ref from that node. Otherwise it returns an
+ empty string.
+ */
+QString Tree::findTarget(const QString& target, const Node* node) const
+{
+ QString key = Doc::canonicalTitle(target);
+ TargetMap::const_iterator i = nodesByTarget_.constFind(key);
+ if (i != nodesByTarget_.constEnd()) {
+ do {
+ if (i.value().node_ == node)
+ return i.value().ref_;
+ ++i;
+ } while (i != nodesByTarget_.constEnd() && i.key() == key);
+ }
+ return QString();
+}
+
+/*!
+ Inserts a new target into the target table. \a name is the
+ key. The target record contains the \a type, a pointer to
+ the \a node, the \a priority. and a canonicalized form of
+ the \a name, which is later used.
+ */
+void Tree::insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority)
+{
+ TargetRec target;
+ target.type_ = type;
+ target.node_ = node;
+ target.priority_ = priority;
+ target.ref_ = Doc::canonicalTitle(name);
+ nodesByTarget_.insert(name, target);
+}
+
+/*!
+ */
+void Tree::resolveTargets(InnerNode* root)
+{
+ // need recursion
+ foreach (Node* child, root->childNodes()) {
+ if (child->type() == Node::Document) {
+ DocNode* node = static_cast<DocNode*>(child);
+ if (!node->title().isEmpty()) {
+ QString key = Doc::canonicalTitle(node->title());
+ QList<DocNode*> nodes = docNodesByTitle_.values(key);
+ bool alreadyThere = false;
+ if (!nodes.empty()) {
+ for (int i=0; i< nodes.size(); ++i) {
+ if (nodes[i]->subType() == Node::ExternalPage) {
+ if (node->name() == nodes[i]->name()) {
+ alreadyThere = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!alreadyThere) {
+ docNodesByTitle_.insert(key, node);
}
- else
- return 0;
}
- else { // Not at the end of the path.
- n = findNodeRecursive(path, pathIndex+1, n, type, subtype);
- if (n)
- return n;
+ if (node->subType() == Node::Collision) {
+ resolveTargets(node);
+ }
+ }
+
+ if (child->doc().hasTableOfContents()) {
+ const QList<Atom*>& toc = child->doc().tableOfContents();
+ TargetRec target;
+ target.node_ = child;
+ target.priority_ = 3;
+
+ for (int i = 0; i < toc.size(); ++i) {
+ target.ref_ = refForAtom(toc.at(i));
+ QString title = Text::sectionHeading(toc.at(i)).toString();
+ if (!title.isEmpty()) {
+ QString key = Doc::canonicalTitle(title);
+ nodesByTarget_.insert(key, target);
+ }
+ }
+ }
+ if (child->doc().hasKeywords()) {
+ const QList<Atom*>& keywords = child->doc().keywords();
+ TargetRec target;
+ target.node_ = child;
+ target.priority_ = 1;
+
+ for (int i = 0; i < keywords.size(); ++i) {
+ target.ref_ = refForAtom(keywords.at(i));
+ QString key = Doc::canonicalTitle(keywords.at(i)->string());
+ nodesByTarget_.insert(key, target);
+ }
+ }
+ if (child->doc().hasTargets()) {
+ const QList<Atom*>& toc = child->doc().targets();
+ TargetRec target;
+ target.node_ = child;
+ target.priority_ = 2;
+
+ for (int i = 0; i < toc.size(); ++i) {
+ target.ref_ = refForAtom(toc.at(i));
+ QString key = Doc::canonicalTitle(toc.at(i)->string());
+ nodesByTarget_.insert(key, target);
}
}
}
+}
+
+/*!
+ This function searches for a \a target anchor node. If it
+ finds one, it sets \a ref and returns the found node.
+ */
+const Node*
+Tree::findUnambiguousTarget(const QString& target, QString& ref)
+{
+ TargetRec bestTarget;
+ int numBestTargets = 0;
+ QList<TargetRec> bestTargetList;
+
+ QString key = Doc::canonicalTitle(target);
+ TargetMap::iterator i = nodesByTarget_.find(key);
+ while (i != nodesByTarget_.end()) {
+ if (i.key() != key)
+ break;
+ const TargetRec& candidate = i.value();
+ if (candidate.priority_ < bestTarget.priority_) {
+ bestTarget = candidate;
+ bestTargetList.clear();
+ bestTargetList.append(candidate);
+ numBestTargets = 1;
+ } else if (candidate.priority_ == bestTarget.priority_) {
+ bestTargetList.append(candidate);
+ ++numBestTargets;
+ }
+ ++i;
+ }
+ if (numBestTargets > 0) {
+ if (numBestTargets == 1) {
+ ref = bestTarget.ref_;
+ return bestTarget.node_;
+ }
+ else if (bestTargetList.size() > 1) {
+#if 0
+ qDebug() << "TARGET:" << target << numBestTargets;
+ for (int i=0; i<bestTargetList.size(); ++i) {
+ const Node* n = bestTargetList.at(i).node_;
+ qDebug() << " " << n->name() << n->title();
+ }
+#endif
+ ref = bestTargetList.at(0).ref_;
+ return bestTargetList.at(0).node_;
+ }
+ }
+ ref.clear();
return 0;
}
/*!
- Find the Enum type node named \a path. Begin the search at the
- \a start node. If the \a start node is 0, begin the search
- at the root of the tree. Only an Enum type node named \a path is
- acceptible. If one is not found, 0 is returned.
+ This function searches for a node with the specified \a title.
*/
-EnumNode* Tree::findEnumNode(const QStringList& path, Node* start)
+const DocNode* Tree::findDocNodeByTitle(const QString& title) const
{
- if (!start)
- start = const_cast<NamespaceNode*>(root());
- return static_cast<EnumNode*>(findNodeRecursive(path, 0, start, Node::Enum, Node::NoSubType));
+ QString key = Doc::canonicalTitle(title);
+ DocNodeMultiMap::const_iterator i = docNodesByTitle_.constFind(key);
+ if (i != docNodesByTitle_.constEnd()) {
+ /*
+ Reporting all these duplicate section titles is probably
+ overkill. We should report the duplicate file and let
+ that suffice.
+ */
+ DocNodeMultiMap::const_iterator j = i;
+ ++j;
+ if (j != docNodesByTitle_.constEnd() && j.key() == i.key()) {
+ QList<Location> internalLocations;
+ while (j != docNodesByTitle_.constEnd()) {
+ if (j.key() == i.key() && j.value()->url().isEmpty()) {
+ internalLocations.append(j.value()->location());
+ break; // Just report one duplicate for now.
+ }
+ ++j;
+ }
+ if (internalLocations.size() > 0) {
+ i.value()->location().warning("This page title exists in more than one file: " + title);
+ foreach (const Location &location, internalLocations)
+ location.warning("[It also exists here]");
+ }
+ }
+ return i.value();
+ }
+ return 0;
}
/*!
- Find the C++ class node named \a path. Begin the search at the
- \a start node. If the \a start node is 0, begin the search
- at the root of the tree. Only a C++ class node named \a path is
- acceptible. If one is not found, 0 is returned.
+ Returns a canonical title for the \a atom, if the \a atom
+ is a SectionLeft or a Target.
*/
-ClassNode* Tree::findClassNode(const QStringList& path, Node* start) const
+QString Tree::refForAtom(const Atom* atom)
{
- if (!start)
- start = const_cast<NamespaceNode*>(root());
- return static_cast<ClassNode*>(findNodeRecursive(path, 0, start, Node::Class, Node::NoSubType));
+ if (atom) {
+ if (atom->type() == Atom::SectionLeft)
+ return Doc::canonicalTitle(Text::sectionHeading(atom).toString());
+ if (atom->type() == Atom::Target)
+ return Doc::canonicalTitle(atom->string());
+ }
+ return QString();
}
/*!
- Find the Namespace node named \a path. Begin the search at
- the root of the tree. Only a Namespace node named \a path
- is acceptible. If one is not found, 0 is returned.
+ \fn const CNMap& Tree::groups() const
+ Returns a const reference to the collection of all
+ group nodes.
+*/
+
+/*!
+ \fn const ModuleMap& Tree::modules() const
+ Returns a const reference to the collection of all
+ module nodes.
+*/
+
+/*!
+ \fn const QmlModuleMap& Tree::qmlModules() const
+ Returns a const reference to the collection of all
+ QML module nodes.
+*/
+
+/*!
+ Returns the collection node in this tree that has the same
+ name and type as \a cn. Returns 0 if no match is found.
+
+ If the matching node is \a cn, return 0.
*/
-NamespaceNode* Tree::findNamespaceNode(const QStringList& path) const
+CollectionNode* Tree::getCorrespondingCollection(CollectionNode* cn)
{
- Node* start = const_cast<NamespaceNode*>(root());
- return static_cast<NamespaceNode*>(findNodeRecursive(path, 0, start, Node::Namespace, Node::NoSubType));
+ CollectionNode* ccn = 0;
+ if (cn->isGroup())
+ ccn = getGroup(cn->name());
+ else if (cn->isModule())
+ ccn = getModule(cn->name());
+ else if (cn->isQmlModule())
+ ccn = getQmlModule(cn->name());
+ if (ccn == cn)
+ ccn = 0;
+ return ccn;
+}
+
+/*!
+ Find the group node named \a name and return a pointer
+ to it. If a matching node is not found, return 0.
+ */
+GroupNode* Tree::getGroup(const QString& name)
+{
+ CNMap::const_iterator i = groups_.find(name);
+ if (i != groups_.end())
+ return static_cast<GroupNode*>(i.value());
+ return 0;
+}
+
+/*!
+ Find the module node named \a name and return a pointer
+ to it. If a matching node is not found, return 0.
+ */
+ModuleNode* Tree::getModule(const QString& name)
+{
+ CNMap::const_iterator i = modules_.find(name);
+ if (i != modules_.end())
+ return static_cast<ModuleNode*>(i.value());
+ return 0;
+}
+
+/*!
+ Find the QML module node named \a name and return a pointer
+ to it. If a matching node is not found, return 0.
+ */
+QmlModuleNode* Tree::getQmlModule(const QString& name)
+{
+ CNMap::const_iterator i = qmlModules_.find(name);
+ if (i != qmlModules_.end())
+ return static_cast<QmlModuleNode*>(i.value());
+ return 0;
+}
+
+/*!
+ Find the group node named \a name and return a pointer
+ to it. If the group node is not found, add a new group
+ node named \a name and return a pointer to the new one.
+
+ If a new group node is added, its parent is the tree root,
+ and the new group node is marked \e{not seen}.
+ */
+GroupNode* Tree::findGroup(const QString& name)
+{
+ CNMap::const_iterator i = groups_.find(name);
+ if (i != groups_.end())
+ return static_cast<GroupNode*>(i.value());;
+ GroupNode* gn = new GroupNode(root(), name);
+ gn->markNotSeen();
+ groups_.insert(name, gn);
+ return gn;
+}
+
+/*!
+ Find the module node named \a name and return a pointer
+ to it. If a matching node is not found, add a new module
+ node named \a name and return a pointer to that one.
+
+ If a new module node is added, its parent is the tree root,
+ and the new module node is marked \e{not seen}.
+ */
+ModuleNode* Tree::findModule(const QString& name)
+{
+ CNMap::const_iterator i = modules_.find(name);
+ if (i != modules_.end())
+ return static_cast<ModuleNode*>(i.value());
+ ModuleNode* mn = new ModuleNode(root(), name);
+ mn->markNotSeen();
+ modules_.insert(name, mn);
+ return mn;
+}
+
+/*!
+ Find the QML module node named \a name and return a pointer
+ to it. If a matching node is not found, add a new QML module
+ node named \a name and return a pointer to that one.
+
+ If a new QML module node is added, its parent is the tree root,
+ and the new QML module node is marked \e{not seen}.
+ */
+QmlModuleNode* Tree::findQmlModule(const QString& name)
+{
+ CNMap::const_iterator i = qmlModules_.find(name);
+ if (i != qmlModules_.end())
+ return static_cast<QmlModuleNode*>(i.value());
+ QmlModuleNode* qmn = new QmlModuleNode(root(), name);
+ qmn->markNotSeen();
+ qmn->setQmlModuleInfo(name);
+ qmlModules_.insert(name, qmn);
+ return qmn;
+}
+
+/*!
+ Looks up the group node named \a name in the collection
+ of all group nodes. If a match is found, a pointer to the
+ node is returned. Otherwise, a new group node named \a name
+ is created and inserted into the collection, and the pointer
+ to that node is returned.
+ */
+GroupNode* Tree::addGroup(const QString& name)
+{
+ GroupNode* group = findGroup(name);
+ return group;
+}
+
+/*!
+ Looks up the module node named \a name in the collection
+ of all module nodes. If a match is found, a pointer to the
+ node is returned. Otherwise, a new module node named \a name
+ is created and inserted into the collection, and the pointer
+ to that node is returned.
+ */
+ModuleNode* Tree::addModule(const QString& name)
+{
+ ModuleNode* module = findModule(name);
+ return module;
+}
+
+/*!
+ Looks up the QML module node named \a name in the collection
+ of all QML module nodes. If a match is found, a pointer to the
+ node is returned. Otherwise, a new QML module node named \a name
+ is created and inserted into the collection, and the pointer
+ to that node is returned.
+ */
+QmlModuleNode* Tree::addQmlModule(const QString& name)
+{
+ QStringList blankSplit = name.split(QLatin1Char(' '));
+ QmlModuleNode* qmn = findQmlModule(blankSplit[0]);
+ qmn->setQmlModuleInfo(name);
+ return qmn;
+}
+
+/*!
+ Looks up the group node named \a name in the collection
+ of all group nodes. If a match is not found, a new group
+ node named \a name is created and inserted into the collection.
+ Then append \a node to the group's members list, and append the
+ group name to the list of group names in \a node. The parent of
+ \a node is not changed by this function. Returns a pointer to
+ the group node.
+ */
+GroupNode* Tree::addToGroup(const QString& name, Node* node)
+{
+ GroupNode* gn = findGroup(name);
+ if (!node->isInternal()) {
+ gn->addMember(node);
+ node->appendGroupName(name);
+ }
+ return gn;
+}
+
+/*!
+ Looks up the module node named \a name in the collection
+ of all module nodes. If a match is not found, a new module
+ node named \a name is created and inserted into the collection.
+ Then append \a node to the module's members list. The parent of
+ \a node is not changed by this function. Returns the module node.
+ */
+ModuleNode* Tree::addToModule(const QString& name, Node* node)
+{
+ ModuleNode* mn = findModule(name);
+ mn->addMember(node);
+ node->setModuleName(name);
+ return mn;
+}
+
+/*!
+ Looks up the QML module named \a name. If it isn't there,
+ create it. Then append \a node to the QML module's member
+ list. The parent of \a node is not changed by this function.
+ Returns the pointer to the QML module node.
+ */
+QmlModuleNode* Tree::addToQmlModule(const QString& name, Node* node)
+{
+ QStringList qmid;
+ QStringList dotSplit;
+ QStringList blankSplit = name.split(QLatin1Char(' '));
+ qmid.append(blankSplit[0]);
+ if (blankSplit.size() > 1) {
+ qmid.append(blankSplit[0] + blankSplit[1]);
+ dotSplit = blankSplit[1].split(QLatin1Char('.'));
+ qmid.append(blankSplit[0] + dotSplit[0]);
+ }
+
+ QmlModuleNode* qmn = findQmlModule(blankSplit[0]);
+ qmn->addMember(node);
+ node->setQmlModule(qmn);
+ if (node->isQmlType()) {
+ QmlClassNode* n = static_cast<QmlClassNode*>(node);
+ for (int i=0; i<qmid.size(); ++i) {
+ QString key = qmid[i] + "::" + node->name();
+ insertQmlType(key, n);
+ }
+ }
+ return qmn;
+}
+
+/*!
+ If the QML type map does not contain \a key, insert node
+ \a n with the specified \a key.
+ */
+void Tree::insertQmlType(const QString& key, QmlClassNode* n)
+{
+ if (!qmlTypeMap_.contains(key))
+ qmlTypeMap_.insert(key,n);
+}
+
+/*!
+ Split \a target on "::" and find the function node with that
+ path.
+ */
+const Node* Tree::resolveFunctionTarget(const QString& target, const Node* relative)
+{
+ QString t = target;
+ t.chop(2);
+ QStringList path = t.split("::");
+ const FunctionNode* fn = findFunctionNode(path, relative, SearchBaseClasses);
+ if (fn && fn->metaness() != FunctionNode::MacroWithoutParams)
+ return fn;
+ return 0;
}
QT_END_NAMESPACE
diff --git a/src/tools/qdoc/tree.h b/src/tools/qdoc/tree.h
index 26dd982abd..7160e321db 100644
--- a/src/tools/qdoc/tree.h
+++ b/src/tools/qdoc/tree.h
@@ -46,6 +46,7 @@
#ifndef TREE_H
#define TREE_H
+#include <QtCore/qstack.h>
#include "node.h"
QT_BEGIN_NAMESPACE
@@ -53,81 +54,75 @@ QT_BEGIN_NAMESPACE
class QStringList;
class QDocDatabase;
+struct TargetRec
+{
+ public:
+ enum Type { Unknown, Target, Keyword, Contents, Class, Function, Page, Subtitle };
+ TargetRec() : node_(0), priority_(INT_MAX), type_(Unknown) { }
+ bool isEmpty() const { return ref_.isEmpty(); }
+ Node* node_;
+ QString ref_;
+ int priority_;
+ Type type_;
+};
+
+typedef QMultiMap<QString, TargetRec> TargetMap;
+typedef QMultiMap<QString, DocNode*> DocNodeMultiMap;
+typedef QMap<QString, QmlClassNode*> QmlTypeMap;
+typedef QMultiMap<QString, const ExampleNode*> ExampleNodeMap;
+
class Tree
{
private:
+ friend class QDocForest;
friend class QDocDatabase;
typedef QMap<PropertyNode::FunctionRole, QString> RoleMap;
typedef QMap<PropertyNode*, RoleMap> PropertyMap;
- struct InheritanceBound
- {
- Node::Access access;
- QStringList basePath;
- QString dataTypeWithTemplateArgs;
- InnerNode* parent;
-
- InheritanceBound() : access(Node::Public) { }
- InheritanceBound(Node::Access access0,
- const QStringList& basePath0,
- const QString& dataTypeWithTemplateArgs0,
- InnerNode* parent)
- : access(access0), basePath(basePath0),
- dataTypeWithTemplateArgs(dataTypeWithTemplateArgs0),
- parent(parent) { }
- };
-
- Tree(QDocDatabase* qdb);
+ Tree(const QString& module, QDocDatabase* qdb);
~Tree();
- EnumNode* findEnumNode(const QStringList& path, Node* start = 0);
ClassNode* findClassNode(const QStringList& path, Node* start = 0) const;
- QmlClassNode* findQmlTypeNode(const QStringList& path);
NamespaceNode* findNamespaceNode(const QStringList& path) const;
-
- Node* findNodeByNameAndType(const QStringList& path,
- Node::Type type,
- Node::SubType subtype,
- Node* start,
- bool acceptCollision = false);
+ FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone);
+ const Node* resolveFunctionTarget(const QString& target, const Node* relative);
Node* findNodeRecursive(const QStringList& path,
int pathIndex,
+ const Node* start,
+ Node::Type type) const;
+ Node* findNodeRecursive(const QStringList& path,
+ int pathIndex,
Node* start,
- Node::Type type,
- Node::SubType subtype,
- bool acceptCollision = false) const;
+ const NodeTypeList& types) const;
const Node* findNode(const QStringList &path,
const Node* relative = 0,
- int findFlags = 0,
- const Node* self=0) const;
+ int findFlags = 0) const;
const Node* findNode(const QStringList& path,
const Node* start,
int findFlags,
- const Node* self,
bool qml) const;
- NameCollisionNode* checkForCollision(const QString& name) const;
+ QmlClassNode* findQmlTypeNode(const QStringList& path);
+
+ 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;
- FunctionNode *findFunctionNode(const QStringList &path,
- Node *relative = 0,
- int findFlags = 0);
- FunctionNode *findFunctionNode(const QStringList &parentPath,
- const FunctionNode *clone,
- Node *relative = 0,
- int findFlags = 0);
- void addBaseClass(ClassNode *subclass,
- Node::Access access,
- const QStringList &basePath,
- const QString &dataTypeWithTemplateArgs,
- InnerNode *parent);
+ QString findTarget(const QString& target, const Node* node) const;
+ void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority);
+ void resolveTargets(InnerNode* root);
+ const Node* findUnambiguousTarget(const QString& target, QString& ref);
+ const DocNode* findDocNodeByTitle(const QString& title) const;
+
void addPropertyFunction(PropertyNode *property,
const QString &funcName,
PropertyNode::FunctionRole funcRole);
- void resolveInheritance(NamespaceNode *rootNode = 0);
+ void resolveInheritance(InnerNode* n = 0);
+ void resolveInheritanceHelper(int pass, ClassNode* cn);
void resolveProperties();
void resolveCppToQmlLinks();
void fixInheritance(NamespaceNode *rootNode = 0);
@@ -136,23 +131,62 @@ class Tree
const FunctionNode *findFunctionNode(const QStringList &path,
const Node *relative = 0,
int findFlags = 0) const;
- const FunctionNode *findFunctionNode(const QStringList &parentPath,
- const FunctionNode *clone,
- const Node *relative = 0,
- int findFlags = 0) const;
const NamespaceNode *root() const { return &root_; }
- void resolveInheritance(int pass, ClassNode *classe);
FunctionNode *findVirtualFunctionInBaseClasses(ClassNode *classe,
FunctionNode *clone);
- void fixPropertyUsingBaseClasses(ClassNode *classe, PropertyNode *property);
NodeList allBaseClasses(const ClassNode *classe) const;
+ QString refForAtom(const Atom* atom);
+
+ const CNMap& groups() const { return groups_; }
+ const CNMap& modules() const { return modules_; }
+ const CNMap& qmlModules() const { return qmlModules_; }
+ const CNMap& getCollections(Node::Type t) const {
+ if (t == Node::Group)
+ return groups_;
+ if (t == Node::Module)
+ return modules_;
+ return qmlModules_;
+ }
+
+ CollectionNode* getCorrespondingCollection(CollectionNode* cn);
+
+ GroupNode* getGroup(const QString& name);
+ ModuleNode* getModule(const QString& name);
+ QmlModuleNode* getQmlModule(const QString& name);
+
+ GroupNode* findGroup(const QString& name);
+ ModuleNode* findModule(const QString& name);
+ QmlModuleNode* findQmlModule(const QString& name);
+
+ GroupNode* addGroup(const QString& name);
+ ModuleNode* addModule(const QString& name);
+ QmlModuleNode* addQmlModule(const QString& name);
+
+ GroupNode* addToGroup(const QString& name, Node* node);
+ ModuleNode* addToModule(const QString& name, Node* node);
+ QmlModuleNode* addToQmlModule(const QString& name, Node* node);
+
+ QmlClassNode* lookupQmlType(const QString& name) const { return qmlTypeMap_.value(name); }
+ void insertQmlType(const QString& key, QmlClassNode* n);
+ void addExampleNode(ExampleNode* n) { exampleNodeMap_.insert(n->title(), n); }
+ ExampleNodeMap& exampleNodeMap() { return exampleNodeMap_; }
+
+ public:
+ const QString& moduleName() const { return module_; }
private:
+ QString module_;
QDocDatabase* qdb_;
NamespaceNode root_;
- QMap<ClassNode* , QList<InheritanceBound> > unresolvedInheritanceMap;
PropertyMap unresolvedPropertyMap;
+ DocNodeMultiMap docNodesByTitle_;
+ TargetMap nodesByTarget_;
+ CNMap groups_;
+ CNMap modules_;
+ CNMap qmlModules_;
+ QmlTypeMap qmlTypeMap_;
+ ExampleNodeMap exampleNodeMap_;
};
QT_END_NAMESPACE
diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp
index cd9fe2ac86..0d0c4ea444 100644
--- a/src/tools/rcc/rcc.cpp
+++ b/src/tools/rcc/rcc.cpp
@@ -968,11 +968,12 @@ bool RCCResourceLibrary::writeInitializer()
{
if (m_format == C_Code) {
//write("\nQT_BEGIN_NAMESPACE\n");
- QString initName = m_initName;
- if (!initName.isEmpty()) {
- initName.prepend(QLatin1Char('_'));
- initName.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QLatin1String("_"));
+ QString initNameStr = m_initName;
+ if (!initNameStr.isEmpty()) {
+ initNameStr.prepend(QLatin1Char('_'));
+ initNameStr.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QLatin1String("_"));
}
+ QByteArray initName = initNameStr.toLatin1();
//init
if (m_useNameSpace)
@@ -987,10 +988,10 @@ bool RCCResourceLibrary::writeInitializer()
}
if (m_useNameSpace)
writeString("QT_END_NAMESPACE\n\n\n");
- QString initResources = QLatin1String("qInitResources");
+ QByteArray initResources = "qInitResources";
initResources += initName;
writeString("int ");
- writeMangleNamespaceFunction(initResources.toLatin1());
+ writeMangleNamespaceFunction(initResources);
writeString("()\n{\n");
if (m_root) {
@@ -1002,14 +1003,14 @@ bool RCCResourceLibrary::writeInitializer()
writeString(" return 1;\n");
writeString("}\n\n");
writeString("Q_CONSTRUCTOR_FUNCTION(");
- writeMangleNamespaceFunction(initResources.toLatin1());
+ writeMangleNamespaceFunction(initResources);
writeString(")\n\n");
//cleanup
- QString cleanResources = QLatin1String("qCleanupResources");
+ QByteArray cleanResources = "qCleanupResources";
cleanResources += initName;
writeString("int ");
- writeMangleNamespaceFunction(cleanResources.toLatin1());
+ writeMangleNamespaceFunction(cleanResources);
writeString("()\n{\n");
if (m_root) {
writeString(" ");
@@ -1020,7 +1021,7 @@ bool RCCResourceLibrary::writeInitializer()
writeString(" return 1;\n");
writeString("}\n\n");
writeString("Q_DESTRUCTOR_FUNCTION(");
- writeMangleNamespaceFunction(cleanResources.toLatin1());
+ writeMangleNamespaceFunction(cleanResources);
writeString(")\n\n");
} else if (m_format == Binary) {
int i = 4;