qdoc: Teach qdoc to use multiple trees (part 2)
qdoc now knows how to search the forrest of node trees in an optimal order. But there remain some problems with specific searches that cross module boundaries. These include group membership and C++ and QML module membership, as well ass C++ base class resolution. Part 3 will be concerned with fixing these remaining bugs. With this update, qdoc now takes less time to generate the docs for Qt 5. Testing indicates that qdoc run time has dropped from about 14 minutes to about 7.5 minutes on an iMac. Task-number: QTBUG-35377 Change-Id: I6bded6ef54124b4f6e5914cad4548f0b600209b0 Reviewed-by: Martin Smith <martin.smith@digia.com>bb10
parent
e9954e3162
commit
5fecc6512f
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -412,9 +412,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 +431,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 +442,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 +458,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 +465,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 +473,7 @@ void CodeParser::checkModuleInclusion(Node* n)
|
|||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
@ -167,6 +169,7 @@ private:
|
|||
struct ConfigStrings
|
||||
{
|
||||
static QString ALIAS;
|
||||
static QString AUTOLINKERRORS;
|
||||
static QString BASE;
|
||||
static QString BASEDIR;
|
||||
static QString BUILDVERSION;
|
||||
|
|
@ -239,6 +242,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
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
#include "tokenizer.h"
|
||||
#include "qdocdatabase.h"
|
||||
#include <qdebug.h>
|
||||
#include "generator.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
|
@ -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,10 +219,10 @@ 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()
|
||||
{
|
||||
|
|
@ -263,11 +264,11 @@ void CppCodeParser::doneParsingHeaderFiles()
|
|||
*/
|
||||
void CppCodeParser::doneParsingSourceFiles()
|
||||
{
|
||||
qdb_->treeRoot()->clearCurrentChildPointers();
|
||||
qdb_->treeRoot()->normalizeOverloads();
|
||||
qdb_->primaryTreeRoot()->clearCurrentChildPointers();
|
||||
qdb_->primaryTreeRoot()->normalizeOverloads();
|
||||
qdb_->fixInheritance();
|
||||
qdb_->resolveProperties();
|
||||
qdb_->treeRoot()->makeUndocumentedChildrenInternal();
|
||||
qdb_->primaryTreeRoot()->makeUndocumentedChildrenInternal();
|
||||
}
|
||||
|
||||
static QSet<QString> topicCommands_;
|
||||
|
|
@ -326,38 +327,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());
|
||||
|
|
@ -370,7 +366,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()) {
|
||||
|
|
@ -392,7 +388,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);
|
||||
|
|
@ -421,21 +417,9 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
|
|||
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) {
|
||||
if (node == 0)
|
||||
node = qdb_->findNodeByNameAndType(path, type, subtype);
|
||||
}
|
||||
|
||||
if (node == 0) {
|
||||
doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file")
|
||||
.arg(arg.first).arg(command));
|
||||
|
|
@ -444,31 +428,33 @@ 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);
|
||||
DocNode* dn = new DocNode(qdb_->primaryTreeRoot(), arg.first, Node::File, Node::NoPageType);
|
||||
dn->setLocation(doc.startLocation());
|
||||
return dn;
|
||||
}
|
||||
|
|
@ -478,7 +464,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc,
|
|||
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;
|
||||
}
|
||||
|
|
@ -527,9 +513,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);
|
||||
|
|
@ -537,7 +523,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;
|
||||
}
|
||||
|
|
@ -577,7 +563,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
|
||||
|
|
@ -596,12 +582,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;
|
||||
}
|
||||
|
|
@ -1644,7 +1631,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) {
|
||||
|
|
@ -1704,7 +1691,7 @@ bool CppCodeParser::matchNamespaceDecl(InnerNode *parent)
|
|||
QString namespaceName = previousLexeme();
|
||||
NamespaceNode* ns = 0;
|
||||
if (parent)
|
||||
ns = static_cast<NamespaceNode*>(parent->findChildNodeByNameAndType(namespaceName, Node::Namespace));
|
||||
ns = static_cast<NamespaceNode*>(parent->findChildNode(namespaceName, Node::Namespace));
|
||||
if (!ns) {
|
||||
ns = new NamespaceNode(parent, namespaceName);
|
||||
ns->setAccess(access);
|
||||
|
|
@ -1842,7 +1829,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());
|
||||
|
|
@ -2077,7 +2064,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);
|
||||
}
|
||||
|
|
@ -2156,9 +2143,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);
|
||||
|
|
@ -2220,8 +2213,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
|
||||
|
|
@ -2358,7 +2352,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)
|
||||
|
|
|
|||
|
|
@ -667,13 +667,13 @@ 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();
|
||||
}
|
||||
|
||||
|
|
@ -3111,7 +3111,7 @@ void DitaXmlGenerator::generateOverviewList(const Node* relative)
|
|||
QMap<QString, DocNode*> uncategorizedNodeMap;
|
||||
QRegExp singleDigit("\\b([0-9])\\b");
|
||||
|
||||
const NodeList children = qdb_->treeRoot()->childNodes();
|
||||
const NodeList children = qdb_->primaryTreeRoot()->childNodes();
|
||||
foreach (Node* child, children) {
|
||||
if (child->type() == Node::Document && child != relative) {
|
||||
DocNode* docNode = static_cast<DocNode*>(child);
|
||||
|
|
@ -5511,7 +5511,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);
|
||||
|
|
@ -5537,9 +5537,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);
|
||||
|
|
@ -6132,7 +6132,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());
|
||||
|
|
@ -6154,7 +6154,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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
@ -535,7 +535,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;
|
||||
|
|
@ -880,7 +880,7 @@ void DocParser::parse(const QString& source,
|
|||
break;
|
||||
case CMD_GRANULARITY:
|
||||
priv->constructExtra();
|
||||
priv->extra->granularity = getSectioningUnit();
|
||||
priv->extra->granularity_ = getSectioningUnit();
|
||||
break;
|
||||
case CMD_HEADER:
|
||||
if (openedCommands.top() == CMD_TABLE) {
|
||||
|
|
@ -1025,7 +1025,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 +1626,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 +1668,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 +1883,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));
|
||||
|
|
@ -2958,10 +2958,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 +3007,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;
|
||||
|
|
|
|||
|
|
@ -97,23 +97,26 @@ 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::setDebugFlag(bool b)
|
||||
{
|
||||
#if 0
|
||||
if (b)
|
||||
qDebug() << "DEBUG: Setting debug flag.";
|
||||
else
|
||||
qDebug() << "DEBUG: Clearing debug flag.";
|
||||
#endif
|
||||
debugging_ = b;
|
||||
}
|
||||
|
||||
/*!
|
||||
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;
|
||||
|
|
@ -275,7 +278,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);
|
||||
|
||||
|
|
@ -1365,11 +1368,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)
|
||||
|
|
@ -1653,6 +1656,7 @@ void Generator::initialize(const Config &config)
|
|||
else
|
||||
outputPrefixes[QLatin1String("QML")] = QLatin1String("qml-");
|
||||
noLinkErrors_ = config.getBool(CONFIG_NOLINKERRORS);
|
||||
autolinkErrors_ = config.getBool(CONFIG_AUTOLINKERRORS);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -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,11 @@ 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 setDebugFlag(bool b);
|
||||
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); }
|
||||
|
|
@ -219,6 +220,7 @@ private:
|
|||
static QStringList styleFiles;
|
||||
static bool debugging_;
|
||||
static bool noLinkErrors_;
|
||||
static bool autolinkErrors_;
|
||||
static bool redirectDocumentationToDevNull_;
|
||||
static Passes qdocPass_;
|
||||
static bool useOutputSubdirs_;
|
||||
|
|
|
|||
|
|
@ -612,7 +612,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;
|
||||
|
|
|
|||
|
|
@ -264,16 +264,16 @@ 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);
|
||||
if (qflags)
|
||||
qflagsHref_ = linkForNode(qflags,0);
|
||||
if (!runPrepareOnly()) {
|
||||
Generator::generateTree();
|
||||
Generator::generateDocs();
|
||||
generateCollisionPages();
|
||||
}
|
||||
|
||||
|
|
@ -303,10 +303,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
|
|||
{
|
||||
int skipAhead = 0;
|
||||
static bool in_para = false;
|
||||
|
||||
#if 0
|
||||
if (Generator::debugging()) {
|
||||
atom->dump();
|
||||
}
|
||||
#endif
|
||||
switch (atom->type()) {
|
||||
case Atom::AbstractLeft:
|
||||
if (relative)
|
||||
|
|
@ -327,6 +328,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
|
|||
}
|
||||
else {
|
||||
out() << protectEnc(atom->string());
|
||||
if (autolinkErrors())
|
||||
relative->doc().location().warning(tr("Can't autolink to '%1'").arg(atom->string()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -1374,7 +1377,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());
|
||||
|
|
@ -1393,7 +1396,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;
|
||||
|
|
@ -2798,7 +2801,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative)
|
|||
QMap<QString, DocNode *> uncategorizedNodeMap;
|
||||
QRegExp singleDigit("\\b([0-9])\\b");
|
||||
|
||||
const NodeList children = qdb_->treeRoot()->childNodes();
|
||||
const NodeList children = qdb_->primaryTreeRoot()->childNodes();
|
||||
foreach (Node *child, children) {
|
||||
if (child->type() == Node::Document && child != relative) {
|
||||
DocNode *docNode = static_cast<DocNode *>(child);
|
||||
|
|
@ -3149,7 +3152,6 @@ 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);
|
||||
QString link = linkForNode(n, relative);
|
||||
addLink(link, arg, &html);
|
||||
|
|
@ -3165,7 +3167,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
|
|||
}
|
||||
}
|
||||
|
||||
// replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
|
||||
// replace all "(<@(type|headerfile)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
|
||||
src = html;
|
||||
html = QString();
|
||||
|
||||
|
|
@ -3175,7 +3177,7 @@ 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);
|
||||
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)
|
||||
|
|
@ -3194,13 +3196,16 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
|
|||
addLink(linkForNode(n,relative), arg, &html);
|
||||
handled = true;
|
||||
}
|
||||
#if 0
|
||||
// Apparently, this clause was never used.
|
||||
// <@func> is taken out above.
|
||||
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);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (!handled) {
|
||||
html += charLangle;
|
||||
html += charAt;
|
||||
|
|
@ -3755,11 +3760,11 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
|
|||
*node = qdb_->findNodeByNameAndType(QStringList(first), Node::Document, Node::NoSubType);
|
||||
}
|
||||
else {
|
||||
*node = qdb_->resolveTarget(first, relative);
|
||||
if (!*node) {
|
||||
if (!(*node))
|
||||
*node = qdb_->resolveTarget(first, relative);
|
||||
if (!(*node))
|
||||
*node = qdb_->findDocNodeByTitle(first, relative);
|
||||
}
|
||||
if (!*node) {
|
||||
if (!(*node)) {
|
||||
*node = qdb_->findUnambiguousTarget(first, ref, relative);
|
||||
if (*node && !(*node)->url().isEmpty() && !ref.isEmpty()) {
|
||||
QString final = (*node)->url() + "#" + ref;
|
||||
|
|
@ -3768,16 +3773,13 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
|
|||
}
|
||||
}
|
||||
if (*node) {
|
||||
if (!(*node)->url().isEmpty()) {
|
||||
if (!(*node)->url().isEmpty())
|
||||
return (*node)->url();
|
||||
}
|
||||
else {
|
||||
else
|
||||
path.removeFirst();
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
*node = relative;
|
||||
}
|
||||
|
||||
if (*node) {
|
||||
if ((*node)->status() == Node::Obsolete) {
|
||||
|
|
@ -3802,10 +3804,8 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
|
|||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
qDebug() << "Link to Obsolete entity"
|
||||
<< (*node)->name() << "no relative";
|
||||
}
|
||||
else
|
||||
qDebug() << "Link to Obsolete entity" << (*node)->name() << "no relative";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3833,9 +3833,8 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
|
|||
link = linkForNode(*node, relative);
|
||||
if (*node && (*node)->subType() == Node::Image)
|
||||
link = "images/used-in-examples/" + link;
|
||||
if (!ref.isEmpty()) {
|
||||
if (!ref.isEmpty())
|
||||
link += QLatin1Char('#') + ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
return link;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -282,6 +283,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"));
|
||||
|
||||
/*
|
||||
|
|
@ -371,6 +373,8 @@ static void processQdocconfFile(const QString &fileName)
|
|||
|
||||
//if (!Generator::runPrepareOnly())
|
||||
loadIndexFiles(config);
|
||||
qdb->newPrimaryTree(config.getString(CONFIG_PROJECT));
|
||||
qdb->setSearchOrder();
|
||||
|
||||
QSet<QString> excludedDirs;
|
||||
QSet<QString> excludedFiles;
|
||||
|
|
@ -379,7 +383,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);
|
||||
|
|
@ -388,14 +392,14 @@ static void processQdocconfFile(const QString &fileName)
|
|||
excludedDirs.insert(p);
|
||||
}
|
||||
|
||||
Generator::debugSegfault("Reading excludefiles");
|
||||
Generator::debug("Reading excludefiles");
|
||||
excludedFilesList = config.getCleanPathList(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;
|
||||
|
|
@ -409,7 +413,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;
|
||||
|
|
@ -426,7 +430,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])) {
|
||||
|
|
@ -436,7 +440,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) {
|
||||
|
|
@ -454,8 +458,9 @@ static void processQdocconfFile(const QString &fileName)
|
|||
to the big tree.
|
||||
*/
|
||||
QSet<CodeParser *> usedParsers;
|
||||
//Config::debug_ = true;
|
||||
|
||||
Generator::debugSegfault("Parsing header files");
|
||||
Generator::debug("Parsing header files");
|
||||
int parsed = 0;
|
||||
QMap<QString,QString>::ConstIterator h = headers.constBegin();
|
||||
while (h != headers.constEnd()) {
|
||||
|
|
@ -479,17 +484,21 @@ static void processQdocconfFile(const QString &fileName)
|
|||
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::setDebugFlag(true);
|
||||
Generator::debug(QString("Parsing " + s.key()));
|
||||
codeParser->parseSourceFile(config.location(), s.key());
|
||||
usedParsers.insert(codeParser);
|
||||
}
|
||||
++s;
|
||||
}
|
||||
Generator::debug(QString("Parsing done."));
|
||||
//Generator::setDebugFlag(false);
|
||||
|
||||
foreach (CodeParser *codeParser, usedParsers)
|
||||
codeParser->doneParsingSourceFiles();
|
||||
|
|
@ -499,7 +508,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();
|
||||
|
||||
/*
|
||||
|
|
@ -508,19 +517,19 @@ 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");
|
||||
|
||||
QDocDatabase::qdocDB()->setVersion(QString());
|
||||
Generator::terminate();
|
||||
|
|
@ -541,7 +550,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!");
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -641,8 +650,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::setDebugFlag(true);
|
||||
}
|
||||
else if (opt == "-prepare") {
|
||||
Generator::setQDocPass(Generator::Prepare);
|
||||
|
|
|
|||
|
|
@ -764,7 +764,7 @@ void InnerNode::getMemberClasses(NodeMap& out)
|
|||
sure to also look in the children of its property
|
||||
group nodes. Return the matching node or 0.
|
||||
*/
|
||||
Node *InnerNode::findChildNodeByName(const QString& name) const
|
||||
Node *InnerNode::findChildNode(const QString& name) const
|
||||
{
|
||||
Node *node = childMap.value(name);
|
||||
if (node && !node->isQmlPropertyGroup())
|
||||
|
|
@ -773,7 +773,7 @@ Node *InnerNode::findChildNodeByName(const QString& name) const
|
|||
for (int i=0; i<children_.size(); ++i) {
|
||||
Node* n = children_.at(i);
|
||||
if (n->isQmlPropertyGroup()) {
|
||||
node = static_cast<InnerNode*>(n)->findChildNodeByName(name);
|
||||
node = static_cast<InnerNode*>(n)->findChildNode(name);
|
||||
if (node)
|
||||
return node;
|
||||
}
|
||||
|
|
@ -782,6 +782,69 @@ Node *InnerNode::findChildNodeByName(const QString& name) const
|
|||
return primaryFunctionMap.value(name);
|
||||
}
|
||||
|
||||
/*!
|
||||
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. This is
|
||||
not a recearsive search.
|
||||
|
||||
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.
|
||||
*/
|
||||
Node* InnerNode::findChildNode(const QString& name, bool qml) const
|
||||
{
|
||||
QList<Node*> nodes = childMap.values(name);
|
||||
if (!nodes.isEmpty()) {
|
||||
for (int i=0; i<nodes.size(); ++i) {
|
||||
Node* node = nodes.at(i);
|
||||
if (!qml) {
|
||||
if (!node->isQmlNode())
|
||||
return node;
|
||||
}
|
||||
else if (node->isQmlNode() && !node->isQmlPropertyGroup())
|
||||
return node;
|
||||
}
|
||||
}
|
||||
if (qml && isQmlType()) {
|
||||
for (int i=0; i<children_.size(); ++i) {
|
||||
Node* node = children_.at(i);
|
||||
if (node->isQmlPropertyGroup()) {
|
||||
node = static_cast<InnerNode*>(node)->findChildNode(name);
|
||||
if (node)
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
return primaryFunctionMap.value(name);
|
||||
}
|
||||
|
||||
/*!
|
||||
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.
|
||||
|
||||
This function is not recursive and therefore can't handle
|
||||
collisions. If it finds a collision node named \a name, it
|
||||
will return that node. But it might not find the collision
|
||||
node because it looks up \a name in the child map, not the
|
||||
list.
|
||||
*/
|
||||
Node* InnerNode::findChildNode(const QString& name, Type type)
|
||||
{
|
||||
if (type == Function)
|
||||
return primaryFunctionMap.value(name);
|
||||
else {
|
||||
QList<Node*> nodes = childMap.values(name);
|
||||
for (int i=0; i<nodes.size(); ++i) {
|
||||
Node* node = nodes.at(i);
|
||||
if (node->type() == type)
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
void InnerNode::findNodes(const QString& name, QList<Node*>& n)
|
||||
|
|
@ -800,7 +863,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n)
|
|||
for (int i=0; i<children_.size(); ++i) {
|
||||
node = children_.at(i);
|
||||
if (node->isQmlPropertyGroup()) {
|
||||
node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
|
||||
node = static_cast<InnerNode*>(node)->findChildNode(name);
|
||||
if (node) {
|
||||
n.append(node);
|
||||
return;
|
||||
|
|
@ -824,7 +887,7 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n)
|
|||
if (!node->isQmlPropertyGroup())
|
||||
n.append(node);
|
||||
else {
|
||||
node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
|
||||
node = static_cast<InnerNode*>(node)->findChildNode(name);
|
||||
if (node)
|
||||
n.append(node);
|
||||
}
|
||||
|
|
@ -837,69 +900,6 @@ void InnerNode::findNodes(const QString& name, QList<Node*>& n)
|
|||
n.append(node);
|
||||
}
|
||||
|
||||
/*!
|
||||
Find the node in this node's children that has the given \a name. If
|
||||
this node is a QML class node, be sure to also look in the children
|
||||
of its property group nodes. Return the matching node or 0. This is
|
||||
not a recearsive search.
|
||||
|
||||
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.
|
||||
*/
|
||||
Node* InnerNode::findChildNodeByName(const QString& name, bool qml) const
|
||||
{
|
||||
QList<Node*> nodes = childMap.values(name);
|
||||
if (!nodes.isEmpty()) {
|
||||
for (int i=0; i<nodes.size(); ++i) {
|
||||
Node* node = nodes.at(i);
|
||||
if (!qml) {
|
||||
if (!node->isQmlNode())
|
||||
return node;
|
||||
}
|
||||
else if (node->isQmlNode() && !node->isQmlPropertyGroup())
|
||||
return node;
|
||||
}
|
||||
}
|
||||
if (qml && isQmlType()) {
|
||||
for (int i=0; i<children_.size(); ++i) {
|
||||
Node* node = children_.at(i);
|
||||
if (node->isQmlPropertyGroup()) {
|
||||
node = static_cast<InnerNode*>(node)->findChildNodeByName(name);
|
||||
if (node)
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
return primaryFunctionMap.value(name);
|
||||
}
|
||||
|
||||
/*!
|
||||
This function is like findChildNodeByName(), but if a node
|
||||
with the specified \a name is found but it is not of the
|
||||
specified \a type, 0 is returned.
|
||||
|
||||
This function is not recursive and therefore can't handle
|
||||
collisions. If it finds a collision node named \a name, it
|
||||
will return that node. But it might not find the collision
|
||||
node because it looks up \a name in the child map, not the
|
||||
list.
|
||||
*/
|
||||
Node* InnerNode::findChildNodeByNameAndType(const QString& name, Type type)
|
||||
{
|
||||
if (type == Function)
|
||||
return primaryFunctionMap.value(name);
|
||||
else {
|
||||
QList<Node*> nodes = childMap.values(name);
|
||||
for (int i=0; i<nodes.size(); ++i) {
|
||||
Node* node = nodes.at(i);
|
||||
if (node->type() == type)
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Find a function node that is a child of this nose, such
|
||||
that the function node has the specified \a name.
|
||||
|
|
@ -1258,6 +1258,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)
|
||||
|
|
@ -1288,6 +1299,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;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -1533,7 +1554,7 @@ void ClassNode::fixPropertyUsingBaseClasses(PropertyNode* pn)
|
|||
while (bc != baseClasses().constEnd()) {
|
||||
ClassNode* cn = bc->node_;
|
||||
if (cn) {
|
||||
Node* n = cn->findChildNodeByNameAndType(pn->name(), Node::Property);
|
||||
Node* n = cn->findChildNode(pn->name(), Node::Property);
|
||||
if (n) {
|
||||
PropertyNode* baseProperty = static_cast<PropertyNode*>(n);
|
||||
cn->fixPropertyUsingBaseClasses(baseProperty);
|
||||
|
|
@ -1552,7 +1573,7 @@ void ClassNode::fixPropertyUsingBaseClasses(PropertyNode* pn)
|
|||
*/
|
||||
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);
|
||||
|
|
@ -1665,6 +1686,15 @@ QString DocNode::title() const
|
|||
return title_;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the document node's \a title. This is used for the page title.
|
||||
*/
|
||||
void DocNode::setTitle(const QString &title)
|
||||
{
|
||||
title_ = title;
|
||||
parent()->addChild(this, title);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the document node's full title, which is usually
|
||||
just title(), but for some SubType values is different
|
||||
|
|
|
|||
|
|
@ -339,9 +339,9 @@ class InnerNode : public Node
|
|||
public:
|
||||
virtual ~InnerNode();
|
||||
|
||||
Node* findChildNodeByName(const QString& name) const;
|
||||
Node* findChildNodeByName(const QString& name, bool qml) const;
|
||||
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) const;
|
||||
FunctionNode* findFunctionNode(const FunctionNode* clone);
|
||||
|
|
@ -382,6 +382,7 @@ public:
|
|||
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);
|
||||
|
||||
void printChildren(const QString& title);
|
||||
void printMembers(const QString& title);
|
||||
|
|
@ -508,7 +509,7 @@ public:
|
|||
virtual ~DocNode() { }
|
||||
|
||||
void setQtVariable(const QString &variable) { qtVariable_ = variable; }
|
||||
void setTitle(const QString &title) { title_ = title; }
|
||||
void setTitle(const QString &title);
|
||||
void setSubTitle(const QString &subTitle) { subtitle_ = subTitle; }
|
||||
|
||||
QString qtVariable() const { return qtVariable_; }
|
||||
|
|
@ -838,8 +839,6 @@ private:
|
|||
QString def;
|
||||
};
|
||||
|
||||
class PropertyNode;
|
||||
|
||||
class FunctionNode : public LeafNode
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ QT_BEGIN_NAMESPACE
|
|||
class Config;
|
||||
class Node;
|
||||
class QString;
|
||||
class Tree;
|
||||
|
||||
class PureDocParser : public CppCodeParser
|
||||
{
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -45,6 +45,8 @@
|
|||
#include <qstring.h>
|
||||
#include <qmap.h>
|
||||
#include "tree.h"
|
||||
#include "config.h"
|
||||
#include <qdebug.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
|
@ -54,10 +56,10 @@ 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;
|
||||
|
||||
class Atom;
|
||||
class Generator;
|
||||
class QDocDatabase;
|
||||
|
||||
enum FindFlag {
|
||||
SearchBaseClasses = 0x1,
|
||||
|
|
@ -65,20 +67,159 @@ 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_; }
|
||||
NamespaceNode* primaryTreeRoot() { return (primaryTree_ ? primaryTree_->root() : 0); }
|
||||
bool isEmpty() const { return searchOrder_.isEmpty(); }
|
||||
bool done() const { return (currentIndex_ >= searchOrder_.size()); }
|
||||
const QVector<Tree*>& searchOrder();
|
||||
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;
|
||||
}
|
||||
if (Config::debug_)
|
||||
qDebug() << "FAILED SEARCH 1" << path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Node* findNodeByNameAndType(const QStringList& path,
|
||||
Node::Type type,
|
||||
Node::SubType subtype,
|
||||
bool acceptCollision = false) {
|
||||
foreach (Tree* t, searchOrder_) {
|
||||
Node* n = t->findNodeByNameAndType(path, type, subtype, acceptCollision);
|
||||
if (n) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
if (Config::debug_)
|
||||
qDebug() << "FAILED SEARCH 2" << path << type << subtype;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ClassNode* findClassNode(const QStringList& path) {
|
||||
foreach (Tree* t, searchOrder_) {
|
||||
ClassNode* n = t->findClassNode(path);
|
||||
if (n) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
if (Config::debug_)
|
||||
qDebug() << "FAILED SEARCH 3" << path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
InnerNode* findRelatesNode(const QStringList& path) {
|
||||
foreach (Tree* t, searchOrder_) {
|
||||
InnerNode* n = t->findRelatesNode(path);
|
||||
if (n) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
if (Config::debug_)
|
||||
qDebug() << "FAILED SEARCH 4" << path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Node* resolveTarget(const QString& target, const Node* relative) {
|
||||
const Node* r = relative;
|
||||
foreach (Tree* t, searchOrder_) {
|
||||
const Node* n = resolveTargetHelper(target, relative, t);
|
||||
if (n) {
|
||||
return n;
|
||||
}
|
||||
relative = 0;
|
||||
}
|
||||
if (Config::debug_) {
|
||||
qDebug() << "FAILED SEARCH 6" << target << r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (Config::debug_)
|
||||
qDebug() << "FAILED SEARCH 5" << path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString findTarget(const QString& target, const Node* node) const
|
||||
{
|
||||
foreach (Tree* t, searchOrder_) {
|
||||
QString ref = t->findTarget(target, node);
|
||||
if (!ref.isEmpty()) {
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
if (Config::debug_)
|
||||
qDebug() << "FAILED SEARCH 7" << target;
|
||||
return QString();
|
||||
}
|
||||
|
||||
const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative)
|
||||
{
|
||||
foreach (Tree* t, searchOrder_) {
|
||||
const Node* n = t->findUnambiguousTarget(target, ref, relative);
|
||||
if (n) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
if (Config::debug_)
|
||||
qDebug() << "FAILED SEARCH 8" << target;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const DocNode* findDocNodeByTitle(const QString& title, const Node* relative) const
|
||||
{
|
||||
foreach (Tree* t, searchOrder_) {
|
||||
const DocNode* n = t->findDocNodeByTitle(title, relative);
|
||||
if (n) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
if (Config::debug_)
|
||||
qDebug() << "FAILED SEARCH 9" << title;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void newPrimaryTree(const QString& module);
|
||||
NamespaceNode* newIndexTree(const QString& module);
|
||||
const Node* resolveTargetHelper(const QString& target, const Node* relative, Tree* t);
|
||||
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<QString> moduleNames_;
|
||||
};
|
||||
|
||||
class QDocDatabase
|
||||
{
|
||||
|
|
@ -90,8 +231,8 @@ class QDocDatabase
|
|||
~QDocDatabase();
|
||||
|
||||
const DocNodeMap& groups() const { return groups_; }
|
||||
const DocNodeMap& modules() const { return modules_; }
|
||||
const DocNodeMap& qmlModules() const { return qmlModules_; }
|
||||
//const DocNodeMap& modules() const { return modules_; } // not used
|
||||
//const DocNodeMap& qmlModules() const { return qmlModules_; } // not used
|
||||
|
||||
DocNode* getGroup(const QString& name);
|
||||
DocNode* findGroup(const QString& name);
|
||||
|
|
@ -106,15 +247,15 @@ class QDocDatabase
|
|||
DocNode* addToModule(const QString& name, Node* node);
|
||||
void addToQmlModule(const QString& name, Node* node);
|
||||
|
||||
QmlClassNode* findQmlType(const QString& qmid, const QString& name) const;
|
||||
QmlClassNode* findQmlType(const QString& qmid, const QString& name);
|
||||
QmlClassNode* findQmlType(const ImportRec& import, const QString& name) const;
|
||||
|
||||
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 findAllClasses(InnerNode *node);
|
||||
void findAllFunctions(InnerNode *node);
|
||||
void findAllLegaleseTexts(InnerNode *node);
|
||||
void findAllNamespaces(InnerNode *node);
|
||||
void findAllObsoleteThings(InnerNode* node);
|
||||
void findAllSince(InnerNode *node);
|
||||
void buildCollections();
|
||||
|
||||
// special collection access functions
|
||||
|
|
@ -137,57 +278,63 @@ class QDocDatabase
|
|||
/* 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(); }
|
||||
void fixInheritance() { primaryTree()->fixInheritance(); }
|
||||
void resolveProperties() { primaryTree()->resolveProperties(); }
|
||||
|
||||
/*******************************************************************
|
||||
The functions declared below don't search in the tree(s).
|
||||
********************************************************************/
|
||||
QString findTarget(const QString &target, const Node *node) const;
|
||||
void resolveTargets(InnerNode* root);
|
||||
void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority);
|
||||
/*******************************************************************/
|
||||
void resolveTargets() {
|
||||
primaryTree()->resolveTargets(primaryTreeRoot());
|
||||
}
|
||||
void insertTarget(const QString& name, TargetRec::Type type, Node* node, int priority) {
|
||||
primaryTree()->insertTarget(name, type, node, priority);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
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);
|
||||
}
|
||||
FunctionNode* findNodeInOpenNamespace(const QStringList& parentPath, const FunctionNode* clone);
|
||||
Node* findNodeInOpenNamespace(QStringList& path, Node::Type type, Node::SubType subtype);
|
||||
NameCollisionNode* findCollisionNode(const QString& name) const {
|
||||
return tree_->findCollisionNode(name);
|
||||
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 tree_->findClassNode(path); }
|
||||
InnerNode* findRelatesNode(const QStringList& path) { return tree_->findRelatesNode(path); }
|
||||
const Node* resolveTarget(const QString& target, const Node* relative);
|
||||
const Node* findNodeForTarget(const QString& target, const Node* relative);
|
||||
const DocNode* findDocNodeByTitle(const QString& title, const Node* relative = 0) const;
|
||||
const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative);
|
||||
Node* findNodeByNameAndType(const QStringList& path, Node::Type type, Node::SubType subtype){
|
||||
return tree_->findNodeByNameAndType(path, type, subtype, 0);
|
||||
ClassNode* findClassNode(const QStringList& path) { return forest_.findClassNode(path); }
|
||||
InnerNode* findRelatesNode(const QStringList& path) { return forest_.findRelatesNode(path); }
|
||||
QString findTarget(const QString& target, const Node* node) const {
|
||||
return forest_.findTarget(target, node);
|
||||
}
|
||||
NameCollisionNode* checkForCollision(const QString& name) const {
|
||||
return tree_->checkForCollision(name);
|
||||
const Node* resolveTarget(const QString& target, const Node* relative) {
|
||||
return forest_.resolveTarget(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, const Node* relative = 0) const {
|
||||
return forest_.findDocNodeByTitle(title, relative);
|
||||
}
|
||||
const Node* findUnambiguousTarget(const QString& target, QString& ref, const Node* relative) {
|
||||
return forest_.findUnambiguousTarget(target, ref, relative);
|
||||
}
|
||||
Node* findNodeByNameAndType(const QStringList& path, Node::Type type, Node::SubType subtype){
|
||||
return forest_.findNodeByNameAndType(path, type, subtype, false);
|
||||
}
|
||||
/*******************************************************************/
|
||||
|
||||
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; }
|
||||
|
|
@ -205,6 +352,14 @@ class QDocDatabase
|
|||
void insertOpenNamespace(const QString& path) { openNamespaces_.insert(path); }
|
||||
void setShowInternal(bool value) { showInternal_ = value; }
|
||||
|
||||
// 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(); }
|
||||
|
||||
/* debugging functions */
|
||||
void printModules() const;
|
||||
void printQmlModules() const;
|
||||
|
|
@ -213,17 +368,25 @@ class QDocDatabase
|
|||
friend class QDocIndexFiles;
|
||||
friend class QDocTagFiles;
|
||||
|
||||
const Node* findNode(const QStringList& path, const Node* relative, int 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(); }
|
||||
|
||||
private:
|
||||
static QDocDatabase* qdocDB_;
|
||||
static NodeMap typeNodeMap_;
|
||||
bool showInternal_;
|
||||
QString version_;
|
||||
QDocMultiMap masterMap_;
|
||||
Tree* tree_;
|
||||
QDocForest forest_;
|
||||
DocNodeMap groups_;
|
||||
DocNodeMap modules_;
|
||||
DocNodeMap qmlModules_;
|
||||
|
|
@ -244,8 +407,6 @@ class QDocDatabase
|
|||
NodeMultiMapMap newSinceMaps_;
|
||||
NodeMapMap funcIndex_;
|
||||
TextToNodeMap legaleseTexts_;
|
||||
DocNodeMultiMap docNodesByTitle_;
|
||||
TargetRecMultiMap targetRecMultiMap_;
|
||||
QSet<QString> openNamespaces_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ QDocIndexFiles::QDocIndexFiles()
|
|||
QDocIndexFiles::~QDocIndexFiles()
|
||||
{
|
||||
qdb_ = 0;
|
||||
gen_ = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -109,10 +110,9 @@ void QDocIndexFiles::readIndexes(const QStringList& indexFiles)
|
|||
foreach (const QString& indexFile, indexFiles) {
|
||||
QString msg = "Loading index file: " + indexFile;
|
||||
Location::logToStdErr(msg);
|
||||
//qDebug() << "READING INDEX:" << indexFile;
|
||||
//qDebug() << " LOAD INDEX FILE:" << indexFile;
|
||||
readIndexFile(indexFile);
|
||||
}
|
||||
//qDebug() << "DONE READING INDEX FILES";
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -146,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();
|
||||
}
|
||||
|
||||
|
|
@ -523,7 +524,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);
|
||||
|
|
@ -768,7 +769,7 @@ 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);
|
||||
|
|
@ -1325,7 +1326,7 @@ 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.
|
||||
|
|
|
|||
|
|
@ -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. ***
|
||||
|
|
@ -244,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. ***
|
||||
|
|
@ -373,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();
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ QT_BEGIN_NAMESPACE
|
|||
class Config;
|
||||
class Node;
|
||||
class QString;
|
||||
class Tree;
|
||||
|
||||
class QmlCodeParser : public CodeParser
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -49,8 +49,6 @@
|
|||
#include <limits.h>
|
||||
#include <qdebug.h>
|
||||
|
||||
bool Tree::debug_ = false;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*!
|
||||
|
|
@ -62,23 +60,35 @@ 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_);
|
||||
}
|
||||
|
||||
/*!
|
||||
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
|
||||
}
|
||||
|
||||
/* API members */
|
||||
|
|
@ -163,7 +173,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) {
|
||||
|
|
@ -235,7 +245,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));
|
||||
|
|
@ -243,7 +253,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;
|
||||
|
|
@ -539,12 +549,9 @@ NodeList Tree::allBaseClasses(const ClassNode* classNode) const
|
|||
Node* Tree::findNodeByNameAndType(const QStringList& path,
|
||||
Node::Type type,
|
||||
Node::SubType subtype,
|
||||
Node* start,
|
||||
bool acceptCollision)
|
||||
{
|
||||
if (!start)
|
||||
start = const_cast<NamespaceNode*>(root());
|
||||
Node* result = findNodeRecursive(path, 0, start, type, subtype, acceptCollision);
|
||||
Node* result = findNodeRecursive(path, 0, root(), type, subtype, acceptCollision);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -745,14 +752,14 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
|
|||
if (node == 0 || !node->isInnerNode())
|
||||
break;
|
||||
|
||||
const Node* next = static_cast<const InnerNode*>(node)->findChildNodeByName(path.at(i), qml);
|
||||
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)->findChildNodeByName(path.at(i));
|
||||
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)
|
||||
|
|
@ -776,4 +783,236 @@ const Node* Tree::findNode(const QStringList& path, const Node* start, int findF
|
|||
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);
|
||||
}
|
||||
}
|
||||
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, const Node* relative)
|
||||
{
|
||||
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 (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* Tree::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("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;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a canonical title for the \a atom, if the \a atom
|
||||
is a SectionLeft or a Target.
|
||||
*/
|
||||
QString Tree::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();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#ifndef TREE_H
|
||||
#define TREE_H
|
||||
|
||||
#include <QtCore/qstack.h>
|
||||
#include "node.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
|
@ -53,23 +54,36 @@ 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;
|
||||
|
||||
class Tree
|
||||
{
|
||||
private:
|
||||
friend class QDocForest;
|
||||
friend class QDocDatabase;
|
||||
|
||||
typedef QMap<PropertyNode::FunctionRole, QString> RoleMap;
|
||||
typedef QMap<PropertyNode*, RoleMap> PropertyMap;
|
||||
|
||||
Tree(QDocDatabase* qdb);
|
||||
Tree(const QString& module, QDocDatabase* qdb);
|
||||
~Tree();
|
||||
|
||||
/* API members */
|
||||
ClassNode* findClassNode(const QStringList& path, Node* start = 0) const;
|
||||
NamespaceNode* findNamespaceNode(const QStringList& path) const;
|
||||
FunctionNode* findFunctionNode(const QStringList& parentPath, const FunctionNode* clone);
|
||||
|
||||
/* internal members */
|
||||
Node* findNodeRecursive(const QStringList& path,
|
||||
int pathIndex,
|
||||
Node* start,
|
||||
|
|
@ -90,19 +104,22 @@ class Tree
|
|||
int findFlags,
|
||||
bool qml) const;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
QmlClassNode* findQmlTypeNode(const QStringList& path);
|
||||
|
||||
Node* findNodeByNameAndType(const QStringList& path,
|
||||
Node::Type type,
|
||||
Node::SubType subtype,
|
||||
Node* start,
|
||||
bool acceptCollision = false);
|
||||
|
||||
|
||||
InnerNode* findRelatesNode(const QStringList& path);
|
||||
NameCollisionNode* checkForCollision(const QString& name) const;
|
||||
NameCollisionNode* checkForCollision(const QString& name);
|
||||
NameCollisionNode* findCollisionNode(const QString& name) const;
|
||||
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 Node* relative);
|
||||
const DocNode* findDocNodeByTitle(const QString& title, const Node* relative = 0) const;
|
||||
|
||||
void addPropertyFunction(PropertyNode *property,
|
||||
const QString &funcName,
|
||||
|
|
@ -122,14 +139,20 @@ class Tree
|
|||
FunctionNode *findVirtualFunctionInBaseClasses(ClassNode *classe,
|
||||
FunctionNode *clone);
|
||||
NodeList allBaseClasses(const ClassNode *classe) const;
|
||||
QString refForAtom(const Atom* atom);
|
||||
|
||||
public:
|
||||
static bool debug_;
|
||||
const QString& moduleName() const { return module_; }
|
||||
|
||||
private:
|
||||
QString module_;
|
||||
QDocDatabase* qdb_;
|
||||
NamespaceNode root_;
|
||||
PropertyMap unresolvedPropertyMap;
|
||||
DocNodeMultiMap docNodesByTitle_;
|
||||
TargetMap nodesByTarget_;
|
||||
//NodeMap nodesByName_;
|
||||
//NodeMap nodesByTitle_;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
Loading…
Reference in New Issue