diff options
Diffstat (limited to 'src/tools/qdoc/qdocindexfiles.cpp')
-rw-r--r-- | src/tools/qdoc/qdocindexfiles.cpp | 634 |
1 files changed, 357 insertions, 277 deletions
diff --git a/src/tools/qdoc/qdocindexfiles.cpp b/src/tools/qdoc/qdocindexfiles.cpp index 00c9c55020..4531ce8eea 100644 --- a/src/tools/qdoc/qdocindexfiles.cpp +++ b/src/tools/qdoc/qdocindexfiles.cpp @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE +static Node* top = 0; + /*! \class QDocIndexFiles @@ -77,6 +79,7 @@ QDocIndexFiles::QDocIndexFiles() QDocIndexFiles::~QDocIndexFiles() { qdb_ = 0; + gen_ = 0; } /*! @@ -109,10 +112,13 @@ void QDocIndexFiles::readIndexes(const QStringList& indexFiles) foreach (const QString& indexFile, indexFiles) { QString msg = "Loading index file: " + indexFile; Location::logToStdErr(msg); + //qDebug() << msg; readIndexFile(indexFile); } } +static bool readingRoot = true; + /*! Reads and parses the index file at \a path. */ @@ -144,13 +150,16 @@ void QDocIndexFiles::readIndexFile(const QString& path) basesList_.clear(); relatedList_.clear(); + readingRoot = true; + 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(); + readingRoot = true; } // Now that all the base classes have been found for this index, @@ -164,13 +173,16 @@ void QDocIndexFiles::readIndexFile(const QString& path) appropriate node(s). */ void QDocIndexFiles::readIndexSection(const QDomElement& element, - InnerNode* parent, + Node* current, const QString& indexUrl) { QString name = element.attribute("name"); QString href = element.attribute("href"); Node* node; Location location; + InnerNode* parent = 0; + if (current->isInnerNode()) + parent = static_cast<InnerNode*>(current); QString filePath; int lineNo = 0; @@ -189,9 +201,11 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, } else if (element.nodeName() == "class") { node = new ClassNode(parent, name); - basesList_.append(QPair<ClassNode*,QString>(static_cast<ClassNode*>(node), - element.attribute("bases"))); - + if (element.hasAttribute("bases")) { + QString bases = element.attribute("bases"); + if (!bases.isEmpty()) + basesList_.append(QPair<ClassNode*,QString>(static_cast<ClassNode*>(node), bases)); + } if (!indexUrl.isEmpty()) location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html"); else if (!indexUrl.isNull()) @@ -201,8 +215,7 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, abstract = true; node->setAbstract(abstract); } - else if ((element.nodeName() == "qmlclass") || - ((element.nodeName() == "page") && (element.attribute("subtype") == "qmlclass"))) { + else if (element.nodeName() == "qmlclass") { QmlClassNode* qcn = new QmlClassNode(parent, name); qcn->setTitle(element.attribute("title")); QString qmlModuleName = element.attribute("qml-module-name"); @@ -213,8 +226,9 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, abstract = true; qcn->setAbstract(abstract); QString qmlFullBaseName = element.attribute("qml-base-type"); - if (!qmlFullBaseName.isEmpty()) + if (!qmlFullBaseName.isEmpty()) { qcn->setQmlBaseName(qmlFullBaseName); + } if (element.hasAttribute("location")) name = element.attribute("location", QString()); if (!indexUrl.isEmpty()) @@ -254,11 +268,11 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, if (element.attribute("writable") == "false") readonly = true; QmlPropertyNode* qpn = 0; - if (parent->type() == Node::Document) { + if (parent->isQmlType()) { QmlClassNode* qcn = static_cast<QmlClassNode*>(parent); qpn = new QmlPropertyNode(qcn, name, type, attached); } - else if (parent->type() == Node::QmlPropertyGroup) { + else if (parent->isQmlPropertyGroup()) { QmlPropertyGroupNode* qpgn = static_cast<QmlPropertyGroupNode*>(parent); qpn = new QmlPropertyNode(qpgn, name, type, attached); } @@ -277,6 +291,31 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, FunctionNode* fn = new FunctionNode(t, parent, name, attached); node = fn; } + else if (element.nodeName() == "group") { + GroupNode* gn = qdb_->addGroup(name); + gn->setTitle(element.attribute("title")); + gn->setSubTitle(element.attribute("subtitle")); + if (element.attribute("seen") == "true") + gn->markSeen(); + node = gn; + } + else if (element.nodeName() == "module") { + ModuleNode* mn = qdb_->addModule(name); + mn->setTitle(element.attribute("title")); + mn->setSubTitle(element.attribute("subtitle")); + if (element.attribute("seen") == "true") + mn->markSeen(); + node = mn; + } + else if (element.nodeName() == "qmlmodule") { + QString t = element.attribute("qml-module-name") + " " + element.attribute("qml-module-version"); + QmlModuleNode* qmn = qdb_->addQmlModule(t); + qmn->setTitle(element.attribute("title")); + qmn->setSubTitle(element.attribute("subtitle")); + if (element.attribute("seen") == "true") + qmn->markSeen(); + node = qmn; + } else if (element.nodeName() == "page") { Node::SubType subtype; Node::PageType ptype = Node::NoPageType; @@ -293,18 +332,6 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, subtype = Node::File; ptype = Node::NoPageType; } - else if (attr == "group") { - subtype = Node::Group; - ptype = Node::OverviewPage; - } - else if (attr == "module") { - subtype = Node::Module; - ptype = Node::OverviewPage; - } - else if (attr == "qmlmodule") { - subtype = Node::QmlModule; - ptype = Node::OverviewPage; - } else if (attr == "page") { subtype = Node::Page; ptype = Node::ArticlePage; @@ -313,25 +340,10 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, subtype = Node::ExternalPage; ptype = Node::ArticlePage; } - else if (attr == "qmlclass") { - subtype = Node::QmlClass; - ptype = Node::ApiPage; - } - else if (attr == "qmlbasictype") { - subtype = Node::QmlBasicType; - ptype = Node::ApiPage; - } else return; - DocNode* docNode = 0; - if (subtype == Node::QmlModule) { - QString t = element.attribute("qml-module-name") + " " + - element.attribute("qml-module-version"); - docNode = qdb_->addQmlModule(t); - } - else - docNode = new DocNode(parent, name, subtype, ptype); + DocNode* docNode = new DocNode(parent, name, subtype, ptype); docNode->setTitle(element.attribute("title")); if (element.hasAttribute("location")) @@ -383,31 +395,33 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, } else if (element.nodeName() == "function") { FunctionNode::Virtualness virt; - if (element.attribute("virtual") == "non") + QString t = element.attribute("virtual"); + if (t == "non") virt = FunctionNode::NonVirtual; - else if (element.attribute("virtual") == "impure") + else if (t == "impure") virt = FunctionNode::ImpureVirtual; - else if (element.attribute("virtual") == "pure") + else if (t == "pure") virt = FunctionNode::PureVirtual; else return; + t = element.attribute("meta"); FunctionNode::Metaness meta; - if (element.attribute("meta") == "plain") + if (t == "plain") meta = FunctionNode::Plain; - else if (element.attribute("meta") == "signal") + else if (t == "signal") meta = FunctionNode::Signal; - else if (element.attribute("meta") == "slot") + else if (t == "slot") meta = FunctionNode::Slot; - else if (element.attribute("meta") == "constructor") + else if (t == "constructor") meta = FunctionNode::Ctor; - else if (element.attribute("meta") == "destructor") + else if (t == "destructor") meta = FunctionNode::Dtor; - else if (element.attribute("meta") == "macro") + else if (t == "macro") meta = FunctionNode::MacroWithParams; - else if (element.attribute("meta") == "macrowithparams") + else if (t == "macrowithparams") meta = FunctionNode::MacroWithParams; - else if (element.attribute("meta") == "macrowithoutparams") + else if (t == "macrowithoutparams") meta = FunctionNode::MacroWithoutParams; else return; @@ -426,6 +440,10 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, QPair<FunctionNode*,QString>(functionNode, element.attribute("relates"))); } + /* + Note: The "signature" attribute was written to the + index file, but it is not read back in. Is that ok? + */ QDomElement child = element.firstChildElement("parameter"); while (!child.isNull()) { @@ -453,15 +471,15 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, location = Location(parent->name().toLower() + ".html"); } else if (element.nodeName() == "keyword") { - qdb_->insertTarget(name, TargetRec::Keyword, parent, 1); + qdb_->insertTarget(name, TargetRec::Keyword, current, 1); return; } else if (element.nodeName() == "target") { - qdb_->insertTarget(name, TargetRec::Target, parent, 2); + qdb_->insertTarget(name, TargetRec::Target, current, 2); return; } else if (element.nodeName() == "contents") { - qdb_->insertTarget(name, TargetRec::Contents, parent, 3); + qdb_->insertTarget(name, TargetRec::Contents, current, 3); return; } else @@ -513,7 +531,7 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, QString moduleName = element.attribute("module"); if (!moduleName.isEmpty()) - node->setModuleName(moduleName); + qdb_->addToModule(moduleName, node); if (!href.isEmpty()) { if (node->isExternalPage()) node->setUrl(href); @@ -529,15 +547,8 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, QString groupsAttr = element.attribute("groups"); if (!groupsAttr.isEmpty()) { QStringList groupNames = groupsAttr.split(","); - for (int i=0; i<groupNames.size(); ++i) { - DocNode* dn = qdb_->findGroup(groupNames[i]); - if (dn) { - dn->addMember(node); - } - else { - qDebug() << "NODE:" << node->name() << "GROUPS:" << groupNames; - qDebug() << "DID NOT FIND GROUP for:" << node->name(); - } + foreach (QString name, groupNames) { + qdb_->addToGroup(name, node); } } @@ -558,83 +569,59 @@ void QDocIndexFiles::readIndexSection(const QDomElement& element, node->setReconstitutedBrief(briefAttr); } - if (node->isInnerNode()) { - InnerNode* inner = static_cast<InnerNode*>(node); + // zzz + bool useParent = (element.nodeName() == "namespace" && name.isEmpty()); + if (element.hasChildNodes()) { QDomElement child = element.firstChildElement(); while (!child.isNull()) { - if (element.nodeName() == "class") { - readIndexSection(child, inner, indexUrl); - } - else if (element.nodeName() == "qmlclass") { - readIndexSection(child, inner, indexUrl); - } - else if (element.nodeName() == "page") { - readIndexSection(child, inner, indexUrl); - } - else if (element.nodeName() == "namespace" && !name.isEmpty()) { - // The root node in the index is a namespace with an empty name. - readIndexSection(child, inner, indexUrl); - } - else { + if (useParent) readIndexSection(child, parent, indexUrl); - } + else + readIndexSection(child, node, indexUrl); child = child.nextSiblingElement(); } } } /*! + This function tries to resolve class inheritance immediately + after the index file is read. It is not always possible to + resolve a class inheritance at this point, because the base + class might be in an index file that hasn't been read yet, or + it might be in one of the header files that will be read for + the current module. These cases will be resolved after all + the index files and header and source files have been read, + just prior to beginning the generate phase for the current + module. + + I don't think this is completely correct because it always + sets the access to public. */ void QDocIndexFiles::resolveIndex() { QPair<ClassNode*,QString> pair; foreach (pair, basesList_) { foreach (const QString& base, pair.second.split(QLatin1Char(','))) { - Node* n = qdb_->treeRoot()->findChildNodeByNameAndType(base, Node::Class); - if (n) { - pair.first->addBaseClass(Node::Public, static_cast<ClassNode*>(n)); - } + QStringList basePath = base.split(QString("::")); + Node* n = qdb_->findClassNode(basePath); + if (n) + pair.first->addResolvedBaseClass(Node::Public, static_cast<ClassNode*>(n)); + else + pair.first->addUnresolvedBaseClass(Node::Public, basePath, QString()); } } QPair<FunctionNode*,QString> relatedPair; foreach (relatedPair, relatedList_) { - Node* n = qdb_->treeRoot()->findChildNodeByNameAndType(relatedPair.second, Node::Class); + QStringList path = relatedPair.second.split("::"); + Node* n = qdb_->findRelatesNode(path); if (n) relatedPair.first->setRelates(static_cast<ClassNode*>(n)); } -} - -/*! - Normally this is used for writing the \e groups attribute, - but it can be used for writing any attribute with a list - value that comes from some subset of the members of \a n. - \note The members of \a n are \e not the children of \a n. - - The names we want to include are the names of the members - of \a n that have node type \a t and node subtype \a st. - The attribute name is \a attr. The names are joined with - the space character and written with \a writer. - */ -void QDocIndexFiles::writeMembersAttribute(QXmlStreamWriter& writer, - const InnerNode* n, - Node::Type t, - Node::SubType st, - const QString& attr) -{ - const NodeList& members = n->members(); - if (!members.isEmpty()) { - QStringList names; - NodeList::ConstIterator i = members.constBegin(); - while (i != members.constEnd()) { - if ((*i)->type() == t && (*i)->subType() == st) - names.append((*i)->name()); - ++i; - } - if (!names.isEmpty()) - writer.writeAttribute(attr, names.join(",")); - } + // No longer needed. + basesList_.clear(); + relatedList_.clear(); } /*! @@ -663,17 +650,29 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, case Node::Class: nodeName = "class"; break; - case Node::Document: - nodeName = "page"; - if (node->subType() == Node::QmlClass) { + case Node::QmlType: + { nodeName = "qmlclass"; QmlModuleNode* qmn = node->qmlModule(); if (qmn) qmlModuleName = qmn->qmlModuleName(); qmlFullBaseName = node->qmlFullBaseName(); } - else if (node->subType() == Node::QmlBasicType) - nodeName = "qmlbasictype"; + break; + case Node::QmlBasicType: + nodeName = "qmlbasictype"; + break; + case Node::Document: + nodeName = "page"; + break; + case Node::Group: + nodeName = "group"; + break; + case Node::Module: + nodeName = "module"; + break; + case Node::QmlModule: + nodeName = "qmlmodule"; break; case Node::Enum: nodeName = "enum"; @@ -741,14 +740,14 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, QString objName = node->name(); // Special case: only the root node should have an empty name. - if (objName.isEmpty() && node != qdb_->treeRoot()) + if (objName.isEmpty() && node != qdb_->primaryTreeRoot()) return false; writer.writeStartElement(nodeName); QXmlStreamAttributes attributes; - if (node->type() != Node::Document) { + if (!node->isDocNode() && !node->isGroup() && !node->isModule() && !node->isQmlModule()) { QString threadSafety; switch (node->threadSafeness()) { case Node::NonReentrant: @@ -832,10 +831,12 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, if (!href.isEmpty()) writer.writeAttribute("href", href); - writer.writeAttribute("access", access); writer.writeAttribute("status", status); - if (node->isAbstract()) - writer.writeAttribute("abstract", "true"); + if (!node->isDocNode() && !node->isGroup() && !node->isModule() && !node->isQmlModule()) { + writer.writeAttribute("access", access); + if (node->isAbstract()) + writer.writeAttribute("abstract", "true"); + } if (!node->location().fileName().isEmpty()) writer.writeAttribute("location", node->location().fileName()); if (!node->location().filePath().isEmpty()) { @@ -847,7 +848,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, writer.writeAttribute("since", node->since()); } - QString brief = node->doc().briefText().toString(); + QString brief = node->doc().trimmedBriefText(node->name()).toString(); switch (node->type()) { case Node::Class: { @@ -856,13 +857,16 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, QList<RelatedClass> bases = classNode->baseClasses(); QSet<QString> baseStrings; foreach (const RelatedClass& related, bases) { - ClassNode* baseClassNode = related.node; - baseStrings.insert(baseClassNode->name()); + ClassNode* n = related.node_; + if (n) + baseStrings.insert(n->fullName()); } - writer.writeAttribute("bases", QStringList(baseStrings.toList()).join(",")); + if (!baseStrings.isEmpty()) + writer.writeAttribute("bases", QStringList(baseStrings.toList()).join(",")); if (!node->moduleName().isEmpty()) writer.writeAttribute("module", node->moduleName()); - writeMembersAttribute(writer, classNode, Node::Document, Node::Group, "groups"); + if (!classNode->groupNames().isEmpty()) + writer.writeAttribute("groups", classNode->groupNames().join(",")); if (!brief.isEmpty()) writer.writeAttribute("brief", brief); } @@ -872,7 +876,20 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, const NamespaceNode* namespaceNode = static_cast<const NamespaceNode*>(node); if (!namespaceNode->moduleName().isEmpty()) writer.writeAttribute("module", namespaceNode->moduleName()); - writeMembersAttribute(writer, namespaceNode, Node::Document, Node::Group, "groups"); + if (!namespaceNode->groupNames().isEmpty()) + writer.writeAttribute("groups", namespaceNode->groupNames().join(",")); + if (!brief.isEmpty()) + writer.writeAttribute("brief", brief); + } + break; + case Node::QmlType: + { + const QmlClassNode* qcn = static_cast<const QmlClassNode*>(node); + writer.writeAttribute("title", qcn->title()); + writer.writeAttribute("fulltitle", qcn->fullTitle()); + writer.writeAttribute("subtitle", qcn->subTitle()); + if (!qcn->groupNames().isEmpty()) + writer.writeAttribute("groups", qcn->groupNames().join(",")); if (!brief.isEmpty()) writer.writeAttribute("brief", brief); } @@ -880,8 +897,8 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, case Node::Document: { /* - Document nodes (such as manual pages) contain subtypes, - titles and other attributes. + Document nodes (such as manual pages) have a subtype, + a title, and other attributes. */ bool writeModuleName = false; const DocNode* docNode = static_cast<const DocNode*>(node); @@ -897,26 +914,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, case Node::File: writer.writeAttribute("subtype", "file"); break; - case Node::Group: - { - writer.writeAttribute("subtype", "group"); - writer.writeAttribute("seen", docNode->wasSeen() ? "true" : "false"); - // Groups contain information about their group members. - const NodeList& members = docNode->members(); - QStringList names; - foreach (const Node* member, members) { - names.append(member->name()); - } - writer.writeAttribute("members", names.join(",")); - writeModuleName = true; - } - break; - case Node::Module: - writer.writeAttribute("subtype", "module"); - break; - case Node::QmlModule: - writer.writeAttribute("subtype", "qmlmodule"); - break; case Node::Page: writer.writeAttribute("subtype", "page"); writeModuleName = true; @@ -924,12 +921,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, case Node::ExternalPage: writer.writeAttribute("subtype", "externalpage"); break; - case Node::QmlClass: - //writer.writeAttribute("subtype", "qmlclass"); - break; - case Node::QmlBasicType: - //writer.writeAttribute("subtype", "qmlbasictype"); - break; default: break; } @@ -939,7 +930,82 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, if (!node->moduleName().isEmpty() && writeModuleName) { writer.writeAttribute("module", node->moduleName()); } - writeMembersAttribute(writer, docNode, Node::Document, Node::Group, "groups"); + if (!docNode->groupNames().isEmpty()) + writer.writeAttribute("groups", docNode->groupNames().join(",")); + if (!brief.isEmpty()) + writer.writeAttribute("brief", brief); + } + break; + case Node::Group: + { + const GroupNode* gn = static_cast<const GroupNode*>(node); + writer.writeAttribute("seen", gn->wasSeen() ? "true" : "false"); + writer.writeAttribute("title", gn->title()); + if (!gn->subTitle().isEmpty()) + writer.writeAttribute("subtitle", gn->subTitle()); + if (!gn->moduleName().isEmpty()) + writer.writeAttribute("module", gn->moduleName()); + if (!gn->groupNames().isEmpty()) + writer.writeAttribute("groups", gn->groupNames().join(",")); + /* + This is not read back in, so it probably + shouldn't be written out in the first place. + */ + if (!gn->members().isEmpty()) { + QStringList names; + foreach (const Node* member, gn->members()) + names.append(member->name()); + writer.writeAttribute("members", names.join(",")); + } + if (!brief.isEmpty()) + writer.writeAttribute("brief", brief); + } + break; + case Node::Module: + { + const ModuleNode* mn = static_cast<const ModuleNode*>(node); + writer.writeAttribute("seen", mn->wasSeen() ? "true" : "false"); + writer.writeAttribute("title", mn->title()); + if (!mn->subTitle().isEmpty()) + writer.writeAttribute("subtitle", mn->subTitle()); + if (!mn->moduleName().isEmpty()) + writer.writeAttribute("module", mn->moduleName()); + if (!mn->groupNames().isEmpty()) + writer.writeAttribute("groups", mn->groupNames().join(",")); + /* + This is not read back in, so it probably + shouldn't be written out in the first place. + */ + if (!mn->members().isEmpty()) { + QStringList names; + foreach (const Node* member, mn->members()) + names.append(member->name()); + writer.writeAttribute("members", names.join(",")); + } + if (!brief.isEmpty()) + writer.writeAttribute("brief", brief); + } + case Node::QmlModule: + { + const QmlModuleNode* qmn = static_cast<const QmlModuleNode*>(node); + writer.writeAttribute("seen", qmn->wasSeen() ? "true" : "false"); + writer.writeAttribute("title", qmn->title()); + if (!qmn->subTitle().isEmpty()) + writer.writeAttribute("subtitle", qmn->subTitle()); + if (!qmn->moduleName().isEmpty()) + writer.writeAttribute("module", qmn->moduleName()); + if (!qmn->groupNames().isEmpty()) + writer.writeAttribute("groups", qmn->groupNames().join(",")); + /* + This is not read back in, so it probably + shouldn't be written out in the first place. + */ + if (!qmn->members().isEmpty()) { + QStringList names; + foreach (const Node* member, qmn->members()) + names.append(member->name()); + writer.writeAttribute("members", names.join(",")); + } if (!brief.isEmpty()) writer.writeAttribute("brief", brief); } @@ -995,14 +1061,34 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, writer.writeAttribute("overload", functionNode->isOverload()?"true":"false"); if (functionNode->isOverload()) writer.writeAttribute("overload-number", QString::number(functionNode->overloadNumber())); - if (functionNode->relates()) + if (functionNode->relates()) { writer.writeAttribute("relates", functionNode->relates()->name()); + } const PropertyNode* propertyNode = functionNode->associatedProperty(); if (propertyNode) writer.writeAttribute("associated-property", propertyNode->name()); writer.writeAttribute("type", functionNode->returnType()); if (!brief.isEmpty()) writer.writeAttribute("brief", brief); + + /* + Note: The "signature" attribute is written to the + index file, but it is not read back in. Is that ok? + */ + QString signature = functionNode->signature(); + if (functionNode->isConst()) + signature += " const"; + writer.writeAttribute("signature", signature); + + for (int i = 0; i < functionNode->parameters().size(); ++i) { + Parameter parameter = functionNode->parameters()[i]; + writer.writeStartElement("parameter"); + writer.writeAttribute("left", parameter.leftType()); + writer.writeAttribute("right", parameter.rightType()); + writer.writeAttribute("name", parameter.name()); + writer.writeAttribute("default", parameter.defaultValue()); + writer.writeEndElement(); // parameter + } } break; case Node::QmlProperty: @@ -1010,7 +1096,7 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node); writer.writeAttribute("type", qpn->dataType()); writer.writeAttribute("attached", qpn->isAttached() ? "true" : "false"); - writer.writeAttribute("writable", qpn->isWritable(qdb_) ? "true" : "false"); + writer.writeAttribute("writable", qpn->isWritable() ? "true" : "false"); if (!brief.isEmpty()) writer.writeAttribute("brief", brief); } @@ -1070,10 +1156,68 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, writer.writeAttribute("brief", brief); } break; + case Node::Enum: + { + const EnumNode* enumNode = static_cast<const EnumNode*>(node); + if (enumNode->flagsType()) { + writer.writeAttribute("typedef",enumNode->flagsType()->fullDocumentName()); + } + foreach (const EnumItem& item, enumNode->items()) { + writer.writeStartElement("value"); + writer.writeAttribute("name", item.name()); + writer.writeAttribute("value", item.value()); + writer.writeEndElement(); // value + } + } + break; + case Node::Typedef: + { + const TypedefNode* typedefNode = static_cast<const TypedefNode*>(node); + if (typedefNode->associatedEnum()) { + writer.writeAttribute("enum",typedefNode->associatedEnum()->fullDocumentName()); + } + } + break; default: break; } + /* + For our pages, we canonicalize the target, keyword and content + item names so that they can be used by qdoc for other sets of + documentation. + + The reason we do this here is that we don't want to ruin + externally composed indexes, containing non-qdoc-style target names + when reading in indexes. + + targets and keywords are now allowed in any node, not just inner nodes. + */ + + if (node->doc().hasTargets()) { + bool external = false; + if (node->type() == Node::Document) { + const DocNode* docNode = static_cast<const DocNode*>(node); + if (docNode->subType() == Node::ExternalPage) + external = true; + } + foreach (const Atom* target, node->doc().targets()) { + QString targetName = target->string(); + if (!external) + targetName = Doc::canonicalTitle(targetName); + writer.writeStartElement("target"); + writer.writeAttribute("name", targetName); + writer.writeEndElement(); // target + } + } + if (node->doc().hasKeywords()) { + foreach (const Atom* keyword, node->doc().keywords()) { + writer.writeStartElement("keyword"); + writer.writeAttribute("name", Doc::canonicalTitle(keyword->string())); + writer.writeEndElement(); // keyword + } + } + // Inner nodes and function nodes contain child nodes of some sort, either // actual child nodes or function parameters. For these, we close the // opening tag, create child elements, then add a closing tag for the @@ -1082,36 +1226,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, if (node->isInnerNode()) { const InnerNode* inner = static_cast<const InnerNode*>(node); - // For internal pages, we canonicalize the target, keyword and content - // item names so that they can be used by qdoc for other sets of - // documentation. - // The reason we do this here is that we don't want to ruin - // externally composed indexes, containing non-qdoc-style target names - // when reading in indexes. - - if (inner->doc().hasTargets()) { - bool external = false; - if (inner->type() == Node::Document) { - const DocNode* docNode = static_cast<const DocNode*>(inner); - if (docNode->subType() == Node::ExternalPage) - external = true; - } - foreach (const Atom* target, inner->doc().targets()) { - QString targetName = target->string(); - if (!external) - targetName = Doc::canonicalTitle(targetName); - writer.writeStartElement("target"); - writer.writeAttribute("name", targetName); - writer.writeEndElement(); // target - } - } - if (inner->doc().hasKeywords()) { - foreach (const Atom* keyword, inner->doc().keywords()) { - writer.writeStartElement("keyword"); - writer.writeAttribute("name", Doc::canonicalTitle(keyword->string())); - writer.writeEndElement(); // keyword - } - } if (inner->doc().hasTableOfContents()) { for (int i = 0; i < inner->doc().tableOfContents().size(); ++i) { Atom* item = inner->doc().tableOfContents()[i]; @@ -1125,70 +1239,6 @@ bool QDocIndexFiles::generateIndexSection(QXmlStreamWriter& writer, } } } - else if (node->type() == Node::Function) { - const FunctionNode* functionNode = static_cast<const FunctionNode*>(node); - // Write a signature attribute for convenience. - QStringList signatureList; - QStringList resolvedParameters; - foreach (const Parameter& parameter, functionNode->parameters()) { - QString leftType = parameter.leftType(); - const Node* leftNode = qdb_->findNode(parameter.leftType().split("::"), - 0, - SearchBaseClasses|NonFunction); - if (!leftNode || leftNode->type() != Node::Typedef) { - leftNode = qdb_->findNode(parameter.leftType().split("::"), - node->parent(), - SearchBaseClasses|NonFunction); - } - if (leftNode && leftNode->type() == Node::Typedef) { - if (leftNode->type() == Node::Typedef) { - const TypedefNode* typedefNode = static_cast<const TypedefNode*>(leftNode); - if (typedefNode->associatedEnum()) { - leftType = "QFlags<" + typedefNode->associatedEnum()->fullDocumentName() + - QLatin1Char('>'); - } - } - else - leftType = leftNode->fullDocumentName(); - } - resolvedParameters.append(leftType); - signatureList.append(leftType + QLatin1Char(' ') + parameter.name()); - } - - QString signature = functionNode->name() + QLatin1Char('(') + signatureList.join(", ") + - QLatin1Char(')'); - if (functionNode->isConst()) - signature += " const"; - writer.writeAttribute("signature", signature); - - for (int i = 0; i < functionNode->parameters().size(); ++i) { - Parameter parameter = functionNode->parameters()[i]; - writer.writeStartElement("parameter"); - writer.writeAttribute("left", resolvedParameters[i]); - writer.writeAttribute("right", parameter.rightType()); - writer.writeAttribute("name", parameter.name()); - writer.writeAttribute("default", parameter.defaultValue()); - writer.writeEndElement(); // parameter - } - } - else if (node->type() == Node::Enum) { - const EnumNode* enumNode = static_cast<const EnumNode*>(node); - if (enumNode->flagsType()) { - writer.writeAttribute("typedef",enumNode->flagsType()->fullDocumentName()); - } - foreach (const EnumItem& item, enumNode->items()) { - writer.writeStartElement("value"); - writer.writeAttribute("name", item.name()); - writer.writeAttribute("value", item.value()); - writer.writeEndElement(); // value - } - } - else if (node->type() == Node::Typedef) { - const TypedefNode* typedefNode = static_cast<const TypedefNode*>(node); - if (typedefNode->associatedEnum()) { - writer.writeAttribute("enum",typedefNode->associatedEnum()->fullDocumentName()); - } - } return true; } @@ -1239,7 +1289,7 @@ bool compareNodes(const Node* n1, const Node* n2) return false; } - if (n1->type() == Node::Document && n2->type() == Node::Document) { + if (n1->isDocNode() && n2->isDocNode()) { const DocNode* f1 = static_cast<const DocNode*>(n1); const DocNode* f2 = static_cast<const DocNode*>(n2); if (f1->fullTitle() < f2->fullTitle()) @@ -1262,9 +1312,13 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer, bool generateInternalNodes) { /* - Note that the groups are written after all the other nodes. + Note that groups, modules, and QML modules are written + after all the other nodes. */ - if (!node->isGroup() && generateIndexSection(writer, node, generateInternalNodes)) { + if (node->isGroup() || node->isModule() || node->isQmlModule()) + return; + + if (generateIndexSection(writer, node, generateInternalNodes)) { if (node->isInnerNode()) { const InnerNode* inner = static_cast<const InnerNode*>(node); @@ -1288,6 +1342,47 @@ void QDocIndexFiles::generateIndexSections(QXmlStreamWriter& writer, generateIndexSections(writer, child, generateInternalNodes); } } + + if (node == top) { + /* + We wait until the end of the index file to output the group, module, + and QML module elements. By outputting them at the end, when we read + the index file back in, all the group, module, and QML module member + elements will have already been created. It is then only necessary to + create the group, module, or QML module element and add each member to + its member list. + */ + const CNMap& groups = qdb_->groups(); + if (!groups.isEmpty()) { + CNMap::ConstIterator g = groups.constBegin(); + while (g != groups.constEnd()) { + if (generateIndexSection(writer, g.value(), generateInternalNodes)) + writer.writeEndElement(); + ++g; + } + } + + const CNMap& modules = qdb_->modules(); + if (!modules.isEmpty()) { + CNMap::ConstIterator g = modules.constBegin(); + while (g != modules.constEnd()) { + if (generateIndexSection(writer, g.value(), generateInternalNodes)) + writer.writeEndElement(); + ++g; + } + } + + const CNMap& qmlModules = qdb_->qmlModules(); + if (!qmlModules.isEmpty()) { + CNMap::ConstIterator g = qmlModules.constBegin(); + while (g != qmlModules.constEnd()) { + if (generateIndexSection(writer, g.value(), generateInternalNodes)) + writer.writeEndElement(); + ++g; + } + } + } + writer.writeEndElement(); } } @@ -1320,23 +1415,8 @@ void QDocIndexFiles::generateIndex(const QString& fileName, writer.writeAttribute("version", qdb_->version()); writer.writeAttribute("project", g->config()->getString(CONFIG_PROJECT)); - generateIndexSections(writer, qdb_->treeRoot(), generateInternalNodes); - - /* - We wait until the end of the index file to output the group elements. - By waiting until the end, when we read each group element, its members - will have already been created. It is then only necessary to create - the group page and add each member to its member list. - */ - const DocNodeMap& groups = qdb_->groups(); - if (!groups.isEmpty()) { - DocNodeMap::ConstIterator g = groups.constBegin(); - while (g != groups.constEnd()) { - if (generateIndexSection(writer, g.value(), generateInternalNodes)) - writer.writeEndElement(); - ++g; - } - } + top = qdb_->primaryTreeRoot(); + generateIndexSections(writer, top, generateInternalNodes); writer.writeEndElement(); // INDEX writer.writeEndElement(); // QDOCINDEX |