diff options
Diffstat (limited to 'src/tools/qdoc/ditaxmlgenerator.cpp')
-rw-r--r-- | src/tools/qdoc/ditaxmlgenerator.cpp | 527 |
1 files changed, 308 insertions, 219 deletions
diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp index 25c92fb44f..3f1e8c02e9 100644 --- a/src/tools/qdoc/ditaxmlgenerator.cpp +++ b/src/tools/qdoc/ditaxmlgenerator.cpp @@ -240,6 +240,7 @@ QString DitaXmlGenerator::ditaTags[] = "topicref", "tt", "u", + "uicontrol", "ul", "unknown", "vrm", @@ -417,7 +418,6 @@ DitaXmlGenerator::DitaXmlGenerator() sectionNestingLevel(0), tableColumnCount(0), funcLeftParen("\\S(\\()"), - tree_(0), nodeTypeMaps(Node::LastType,0), nodeSubtypeMaps(Node::LastSubtype,0), pageTypeMaps(Node::OnBeyondZebra,0) @@ -617,7 +617,7 @@ GuidMap* DitaXmlGenerator::lookupGuidMap(const QString& fileName) This is where the DITA XML files are written. \note The file is created in PageGenerator::generateTree(). */ -void DitaXmlGenerator::generateTree(const Tree *tree) +void DitaXmlGenerator::generateTree(Tree *tree) { tree_ = tree; nonCompatClasses.clear(); @@ -637,6 +637,7 @@ void DitaXmlGenerator::generateTree(const Tree *tree) findAllSince(tree->root()); Generator::generateTree(tree); + generateCollisionPages(); writeDitaMap(tree); } @@ -717,40 +718,39 @@ int DitaXmlGenerator::generateAtom(const Atom *atom, case Atom::BaseName: break; case Atom::BriefLeft: - //if (relative->type() == Node::Fake) { - //skipAhead = skipAtoms(atom, Atom::BriefRight); - //break; - //} - if (inSection()) { - writeStartTag(DT_p); - xmlWriter().writeAttribute("outputclass","brief"); - } - else { - noLinks = true; - writeStartTag(DT_shortdesc); - } - if (relative->type() == Node::Property || - relative->type() == Node::Variable) { - xmlWriter().writeCharacters("This "); - if (relative->type() == Node::Property) - xmlWriter().writeCharacters("property"); - else if (relative->type() == Node::Variable) - xmlWriter().writeCharacters("variable"); - xmlWriter().writeCharacters(" holds "); - } - if (noLinks) { - atom = atom->next(); - while (atom != 0 && atom->type() != Atom::BriefRight) { - if (atom->type() == Atom::String || - atom->type() == Atom::AutoLink) - str += atom->string(); - skipAhead++; + { + Node::Type t = relative->type(); + if (inSection()) { + writeStartTag(DT_p); + xmlWriter().writeAttribute("outputclass","brief"); + } + else { + noLinks = true; + writeStartTag(DT_shortdesc); + } + if (t == Node::Property || t == Node::Variable) { + xmlWriter().writeCharacters("This "); + if (relative->type() == Node::Property) + xmlWriter().writeCharacters("property"); + else if (relative->type() == Node::Variable) + xmlWriter().writeCharacters("variable"); + xmlWriter().writeCharacters(" holds "); + } + if (noLinks) { atom = atom->next(); + while (atom != 0 && atom->type() != Atom::BriefRight) { + if (atom->type() == Atom::String || + atom->type() == Atom::AutoLink) + str += atom->string(); + skipAhead++; + atom = atom->next(); + } + if (t == Node::Property || t == Node::Variable) + str[0] = str[0].toLower(); + if (str.endsWith(QLatin1Char('.'))) + str.truncate(str.length() - 1); + writeCharacters(str + QLatin1Char('.')); } - str[0] = str[0].toLower(); - if (str.endsWith(QLatin1Char('.'))) - str.truncate(str.length() - 1); - writeCharacters(str + QLatin1Char('.')); } break; case Atom::BriefRight: @@ -879,6 +879,8 @@ int DitaXmlGenerator::generateAtom(const Atom *atom, else if (atom->string().startsWith("span ")) { t = DT_keyword; } + else if (atom->string() == ATOM_FORMATTING_UICONTROL) + t = DT_uicontrol; else if (atom->string() == ATOM_FORMATTING_UNDERLINE) t = DT_u; else if (atom->string() == ATOM_FORMATTING_INDEX) @@ -1191,6 +1193,11 @@ int DitaXmlGenerator::generateAtom(const Atom *atom, } } break; + case Atom::HR: //<p outputclass="horizontal-rule" /> + writeStartTag(DT_p); + xmlWriter().writeAttribute("outputclass","horizontal-rule"); + writeEndTag(); // </p> + break; case Atom::Image: case Atom::InlineImage: { @@ -1202,7 +1209,7 @@ int DitaXmlGenerator::generateAtom(const Atom *atom, QString images = "images"; if (!baseDir().isEmpty()) images.prepend("../"); - if (atom->string()[0] != '/') + if (!atom->string().isEmpty() && atom->string()[0] != '/') images.append(QLatin1Char('/')); fileName = images + atom->string(); } @@ -1266,19 +1273,15 @@ int DitaXmlGenerator::generateAtom(const Atom *atom, const Node *node = 0; QString myLink = getLink(atom, relative, marker, &node); if (myLink.isEmpty()) { - relative->doc().location().warning(tr("Can't link to '%1' in %2") - .arg(atom->string()) - .arg(marker->plainFullName(relative))); + myLink = getCollisionLink(atom); + } + if (myLink.isEmpty()) { + relative->doc().location().warning(tr("Can't link to '%1'") + .arg(atom->string())); } else if (!inSectionHeading) { beginLink(myLink); } -#if 0 - else { - //xmlWriter().writeCharacters(atom->string()); - //qDebug() << "MYLINK:" << myLink << outFileName() << atom->string(); - } -#endif skipAhead = 1; } break; @@ -1741,7 +1744,7 @@ int DitaXmlGenerator::generateAtom(const Atom *atom, for marking up the code. I don't know what that means exactly. */ void -DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* marker) +DitaXmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker) { QList<Section>::ConstIterator s; @@ -1783,7 +1786,7 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark generateThreadSafeness(nsn, marker); generateSince(nsn, marker); - enterSection("h2","Detailed Description"); + enterSection("",""); generateBody(nsn, marker); generateAlsoList(nsn, marker); leaveSection(); @@ -1920,7 +1923,7 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark generateInheritedBy(cn, marker); generateThreadSafeness(cn, marker); generateSince(cn, marker); - enterSection("h2","Detailed Description"); + enterSection("",""); generateBody(cn, marker); generateAlsoList(cn, marker); leaveSection(); @@ -2045,7 +2048,7 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark generateThreadSafeness(fn, marker); generateSince(fn, marker); generateSince(fn, marker); - enterSection("h2","Detailed Description"); + enterSection("",""); generateBody(fn, marker); generateAlsoList(fn, marker); leaveSection(); @@ -2140,8 +2143,8 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark writeEndTag(); // </cxxClass> } else if ((inner->type() == Node::Fake) && (inner->subType() == Node::QmlClass)) { - const QmlClassNode* qcn = const_cast<QmlClassNode*>(static_cast<const QmlClassNode*>(inner)); - const ClassNode* cn = qcn->classNode(); + QmlClassNode* qcn = const_cast<QmlClassNode*>(static_cast<const QmlClassNode*>(inner)); + ClassNode* cn = qcn->classNode(); rawTitle = marker->plainName(inner); fullTitle = marker->plainFullName(inner); title = rawTitle + " Element"; @@ -2167,7 +2170,7 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark generateQmlInherits(qcn, marker); generateQmlInheritedBy(qcn, marker); generateSince(qcn, marker); - enterSection("h2","Detailed Description"); + enterSection("",""); generateBody(qcn, marker); if (cn) { generateQmlText(cn->doc().body(), cn, marker, qcn->name()); @@ -2245,7 +2248,7 @@ void DitaXmlGenerator::writeXrefListItem(const QString& link, const QString& tex Generate the DITA page for a qdoc file that doesn't map to an underlying c++ file. */ -void DitaXmlGenerator::generateFakeNode(const FakeNode* fake, CodeMarker* marker) +void DitaXmlGenerator::generateFakeNode(FakeNode* fake, CodeMarker* marker) { /* If the fake node is a page node, and if the page type @@ -2307,7 +2310,7 @@ void DitaXmlGenerator::generateFakeNode(const FakeNode* fake, CodeMarker* marker } else { if (fake->subType() == Node::Module) { - enterSection("h2","Detailed Description"); + enterSection("",""); generateBody(fake, marker); leaveSection(); } @@ -2496,6 +2499,9 @@ void DitaXmlGenerator::generateHeader(const Node* node, case Node::ExternalPage: // not used outputclass = "externalpage"; break; + case Node::Collision: + outputclass = "collision"; + break; default: outputclass = "page"; } @@ -3299,16 +3305,11 @@ void DitaXmlGenerator::generateOverviewList(const Node* relative, CodeMarker* /* else if (!isGroupPage) { // If we encounter a page that belongs to a group then // we add that page to the list for that group. - const FakeNode* groupNode = - static_cast<const FakeNode*>(tree_->root()->findNode(group, Node::Fake)); - if (groupNode) - fakeNodeMap[groupNode].insert(sortKey, fakeNode); - //else - // uncategorizedNodeMap.insert(sortKey, fakeNode); - }// else - // uncategorizedNodeMap.insert(sortKey, fakeNode); - }// else - // uncategorizedNodeMap.insert(sortKey, fakeNode); + const FakeNode* gn = tree_->findGroupNode(QStringList(group)); + if (gn) + fakeNodeMap[gn].insert(sortKey, fakeNode); + } + } } } @@ -3874,8 +3875,6 @@ QString DitaXmlGenerator::guidForNode(const Node* node) return node->guid(); case Node::Variable: return node->guid(); - case Node::Target: - return node->guid(); } return QString(); } @@ -3883,12 +3882,14 @@ QString DitaXmlGenerator::guidForNode(const Node* node) /*! Constructs a file name appropriate for the \a node and returns it. If the \a node is not a fake node, or if it is a fake node but - it is neither an external page node nor an image node, call the - PageGenerator::fileName() function. + it is neither an external page node nor an image node or a ditamap, + call the PageGenerator::fileName() function. */ QString DitaXmlGenerator::fileName(const Node* node) { if (node->type() == Node::Fake) { + if (static_cast<const FakeNode*>(node)->pageType() == Node::DitaMapPage) + return node->name(); if (static_cast<const FakeNode*>(node)->subType() == Node::ExternalPage) return node->name(); if (static_cast<const FakeNode*>(node)->subType() == Node::Image) @@ -4138,7 +4139,7 @@ const Node* DitaXmlGenerator::findNodeForTarget(const QString& target, node = relative; } else if (target.endsWith(".html")) { - node = tree_->root()->findNode(target, Node::Fake); + node = tree_->root()->findChildNodeByNameAndType(target, Node::Fake); } else if (marker) { node = marker->resolveTarget(target, tree_, relative); @@ -4199,7 +4200,7 @@ QString DitaXmlGenerator::getLink(const Atom* atom, *node = relative; } else if (first.endsWith(".html")) { - *node = tree_->root()->findNode(first, Node::Fake); + *node = tree_->root()->findChildNodeByNameAndType(first, Node::Fake); } else { *node = marker->resolveTarget(first, tree_, relative); @@ -4283,22 +4284,10 @@ QString DitaXmlGenerator::getLink(const Atom* atom, } if (!link.isEmpty() && link[0] == '#') { link.prepend(outFileName()); - qDebug() << "LOCAL LINK:" << link; } return link; } -/*! - This function can be called if getLink() returns an empty - string. - */ -QString DitaXmlGenerator::getDisambiguationLink(const Atom *, CodeMarker *) -{ - qDebug() << "Unimplemented function called: " - << "QString DitaXmlGenerator::getDisambiguationLink()"; - return QString(); -} - void DitaXmlGenerator::generateIndex(const QString& fileBase, const QString& url, const QString& title) @@ -4415,19 +4404,19 @@ void DitaXmlGenerator::generateQmlSummary(const Section& section, Outputs the DITA detailed documentation for a section on a QML element reference page. */ -void DitaXmlGenerator::generateDetailedQmlMember(const Node* node, +void DitaXmlGenerator::generateDetailedQmlMember(Node* node, const InnerNode* relative, CodeMarker* marker) { QString marked; - const QmlPropertyNode* qpn = 0; + QmlPropertyNode* qpn = 0; if (node->subType() == Node::QmlPropertyGroup) { const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); NodeList::ConstIterator p = qpgn->childNodes().begin(); writeStartTag(DT_ul); while (p != qpgn->childNodes().end()) { if ((*p)->type() == Node::QmlProperty) { - qpn = static_cast<const QmlPropertyNode*>(*p); + qpn = static_cast<QmlPropertyNode*>(*p); writeStartTag(DT_li); writeGuidAttribute((Node*)qpn); QString attr; @@ -4453,7 +4442,7 @@ void DitaXmlGenerator::generateDetailedQmlMember(const Node* node, writeEndTag(); // </ul> } else if (node->type() == Node::QmlProperty) { - qpn = static_cast<const QmlPropertyNode*>(node); + qpn = static_cast<QmlPropertyNode*>(node); /* If the QML property node has a single subproperty, override, replace qpn with that override node and @@ -4462,7 +4451,7 @@ void DitaXmlGenerator::generateDetailedQmlMember(const Node* node, if (qpn->qmlPropNodes().size() == 1) { Node* n = qpn->qmlPropNodes().at(0); if (n->type() == Node::QmlProperty) - qpn = static_cast<const QmlPropertyNode*>(n); + qpn = static_cast<QmlPropertyNode*>(n); } /* Now qpn either has no overrides, or it has more @@ -4596,10 +4585,9 @@ void DitaXmlGenerator::generateQmlInherits(const QmlClassNode* qcn, CodeMarker* If there is no class node, or if the class node status is set to Node::Internal, do nothing. */ -void DitaXmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, - CodeMarker* marker) +void DitaXmlGenerator::generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker) { - const ClassNode* cn = qcn->classNode(); + ClassNode* cn = qcn->classNode(); if (cn && (cn->status() != Node::Internal)) { writeStartTag(DT_p); xmlWriter().writeAttribute("outputclass","instantiates"); @@ -4627,8 +4615,7 @@ void DitaXmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, If there is no QML element, or if the class node status is set to Node::Internal, do nothing. */ -void DitaXmlGenerator::generateInstantiatedBy(const ClassNode* cn, - CodeMarker* marker) +void DitaXmlGenerator::generateInstantiatedBy(ClassNode* cn, CodeMarker* marker) { if (cn && cn->status() != Node::Internal && cn->qmlElement() != 0) { const QmlClassNode* qcn = cn->qmlElement(); @@ -4815,13 +4802,13 @@ void DitaXmlGenerator::writeFunctions(const Section& s, FunctionNode* fn = const_cast<FunctionNode*>(static_cast<const FunctionNode*>(*m)); writeStartTag(DT_cxxFunction); xmlWriter().writeAttribute("id",fn->guid()); + if (fn->metaness() == FunctionNode::Signal) + xmlWriter().writeAttribute("otherprops","signal"); + else if (fn->metaness() == FunctionNode::Slot) + xmlWriter().writeAttribute("otherprops","slot"); if (!attribute.isEmpty()) xmlWriter().writeAttribute("outputclass",attribute); writeStartTag(DT_apiName); - if (fn->metaness() == FunctionNode::Signal) - xmlWriter().writeAttribute("outputclass","signal"); - else if (fn->metaness() == FunctionNode::Slot) - xmlWriter().writeAttribute("outputclass","slot"); writeCharacters(fn->name()); writeEndTag(); // </apiName> generateBrief(fn,marker); @@ -4973,6 +4960,11 @@ void DitaXmlGenerator::replaceTypesWithLinks(const Node* n, else addLink(linkForNode(tn,parent),arg,DT_apiRelation); } + else { + // Write simple arguments, like void and bool, + // which do not have a Qt defined target. + writeCharacters(arg.toString()); + } } } else { @@ -5619,13 +5611,13 @@ void DitaXmlGenerator::writeNestedClasses(const Section& s, Recursive writing of DITA XML files from the root \a node. */ void -DitaXmlGenerator::generateInnerNode(const InnerNode* node) +DitaXmlGenerator::generateInnerNode(InnerNode* node) { if (!node->url().isNull()) return; if (node->type() == Node::Fake) { - const FakeNode *fakeNode = static_cast<const FakeNode *>(node); + FakeNode* fakeNode = static_cast<FakeNode*>(node); if (fakeNode->subType() == Node::ExternalPage) return; if (fakeNode->subType() == Node::Image) @@ -5644,27 +5636,38 @@ DitaXmlGenerator::generateInnerNode(const InnerNode* node) CodeMarker *marker = CodeMarker::markerForFileName(node->location().filePath()); if (node->parent() != 0) { - if (!node->name().endsWith(".ditamap")) - beginSubPage(node, fileName(node)); - if (node->type() == Node::Namespace || node->type() == Node::Class) { - generateClassLikeNode(node, marker); + /* + Skip name collision nodes here and process them + later in generateCollisionPages(). Each one is + appended to a list for later. + */ + if ((node->type() == Node::Fake) && (node->subType() == Node::Collision)) { + NameCollisionNode* ncn = static_cast<NameCollisionNode*>(node); + collisionNodes.append(const_cast<NameCollisionNode*>(ncn)); } - else if (node->type() == Node::Fake) { - if (node->subType() == Node::HeaderFile) - generateClassLikeNode(node, marker); - else if (node->subType() == Node::QmlClass) + else { + if (!node->name().endsWith(".ditamap")) + beginSubPage(node, fileName(node)); + if (node->type() == Node::Namespace || node->type() == Node::Class) { generateClassLikeNode(node, marker); - else - generateFakeNode(static_cast<const FakeNode*>(node), marker); + } + else if (node->type() == Node::Fake) { + if (node->subType() == Node::HeaderFile) + generateClassLikeNode(node, marker); + else if (node->subType() == Node::QmlClass) + generateClassLikeNode(node, marker); + else + generateFakeNode(static_cast<FakeNode*>(node), marker); + } + if (!node->name().endsWith(".ditamap")) + endSubPage(); } - if (!node->name().endsWith(".ditamap")) - endSubPage(); } NodeList::ConstIterator c = node->childNodes().begin(); while (c != node->childNodes().end()) { if ((*c)->isInnerNode() && (*c)->access() != Node::Private) - generateInnerNode((const InnerNode*) *c); + generateInnerNode((InnerNode*)*c); ++c; } } @@ -5734,7 +5737,7 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent) if (!child || child->isInternal() || child->doc().isEmpty()) continue; - if (child->name() == "index.html") { + if (child->name() == "index.html" || child->name() == "index") { rootPageNode = child; } @@ -5810,8 +5813,6 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent) break; case Node::Variable: break; - case Node::Target: - break; case Node::QmlProperty: break; case Node::QmlSignal: @@ -5831,10 +5832,13 @@ Node* DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent) Creates the DITA map for the qdoc run. The map is written to the file \e{qt.ditamap" in the DITA XML output directory. */ -void DitaXmlGenerator::writeDitaMap(const Tree *tree) +void DitaXmlGenerator::writeDitaMap(Tree *tree) { QString doctype; +/* + Remove #if 0 to get a flat ditamap. +*/ #if 0 beginSubPage(tree->root(),"qt.ditamap"); doctype = "<!DOCTYPE map PUBLIC \"-//OASIS//DTD DITA Map//EN\" \"map.dtd\">"; @@ -5892,7 +5896,7 @@ void DitaXmlGenerator::writeDitaMap(const Tree *tree) writeTopicrefs(pageTypeMaps[Node::FAQPage], "faqs"); writeTopicrefs(pageTypeMaps[Node::ArticlePage], "articles"); writeTopicrefs(nodeSubtypeMaps[Node::Example], "examples"); - writeTopicrefs(nodeSubtypeMaps[Node::QmlClass], "QML classes"); + writeTopicrefs(nodeSubtypeMaps[Node::QmlClass], "QML types"); writeTopicrefs(nodeTypeMaps[Node::Class], "C++ classes"); writeTopicrefs(nodeTypeMaps[Node::Namespace], "C++ namespaces"); writeTopicrefs(nodeSubtypeMaps[Node::HeaderFile], "header files"); @@ -5964,79 +5968,78 @@ void DitaXmlGenerator::writeTopicrefs(NodeMultiMap* nmm, const QString& navtitle return; writeStartTag(DT_topicref); xmlWriter().writeAttribute("navtitle",navtitle); - NodeMultiMap::iterator i = nmm->begin(); - while (i != nmm->end()) { - writeStartTag(DT_topicref); - xmlWriter().writeAttribute("navtitle",i.key()); - xmlWriter().writeAttribute("href",fileName(i.value())); - switch (i.value()->type()) { - case Node::Fake: { - const FakeNode* fn = static_cast<const FakeNode*>(i.value()); - switch (fn->subType()) { - case Node::Group: { - const NodeList& members = fn->groupMembers(); - for (int j=0; j<members.size(); ++j) { - writeStartTag(DT_topicref); - xmlWriter().writeAttribute("navtitle",members[j]->name()); - xmlWriter().writeAttribute("href",fileName(members[j])); - writeEndTag(); // </topicref> - } - break; + NodeMultiMap::iterator i; + NodeMultiMap *ditaMaps = pageTypeMaps[Node::DitaMapPage]; + + /*! + Put all pages that are already in a hand-written ditamap not in + the qt.ditamap separately. It loops through all ditamaps recursively + before deciding to write an article to qt.ditamap. + */ + if ((navtitle == "articles" && ditaMaps && ditaMaps->size() > 0)) { + NodeMultiMap::iterator mapIterator = ditaMaps->begin(); + while (mapIterator != ditaMaps->end()) { + writeStartTag(DT_mapref); + xmlWriter().writeAttribute("navtitle",mapIterator.key()); + xmlWriter().writeAttribute("href",fileName(mapIterator.value())); + writeEndTag(); + ++mapIterator; + } + i = nmm->begin(); + while (i != nmm->end()) { + // Hardcode not writing index.dita multiple times in the tree. + // index.dita should only appear at the top of the ditamap. + if (fileName(i.value()) == "index.dita") { + i++; + continue; } - case Node::QmlModule: { - const NodeList& members = fn->qmlModuleMembers(); - for (int j=0; j<members.size(); ++j) { - writeStartTag(DT_topicref); - xmlWriter().writeAttribute("navtitle",members[j]->name()); - xmlWriter().writeAttribute("href",fileName(members[j])); - writeEndTag(); // </topicref> + bool foundInDitaMap = false; + mapIterator = ditaMaps->begin(); + while (mapIterator != ditaMaps->end()) { + const DitaMapNode *dmNode = static_cast<const DitaMapNode *>(mapIterator.value()); + for (int count = 0; count < dmNode->map().count(); count++) { + if (dmNode->map().at(count)->navtitle() == i.key()) { + foundInDitaMap = true; + } + ++mapIterator; } - break; } - case Node::Example: { - const ExampleNode* en = static_cast<const ExampleNode*>(fn); - if (!en->imageFileName().isEmpty()) { - writeStartTag(DT_topicref); - xmlWriter().writeAttribute("navtitle","image"); - xmlWriter().writeAttribute("href",en->imageFileName()); - writeEndTag(); // </topicref> - } - const NodeList& files = en->childNodes(); - for (int j=0; j<files.size(); ++j) { - writeStartTag(DT_topicref); - xmlWriter().writeAttribute("href",files[j]->name()); - writeEndTag(); // </topicref> - } - break; + if (!foundInDitaMap) { + writeStartTag(DT_topicref); + xmlWriter().writeAttribute("navtitle",i.key()); + xmlWriter().writeAttribute("href",fileName(i.value())); + writeEndTag(); // </topicref> } - case Node::Module: { - if (moduleNamespaceMap.contains(fn->name())) { - const NodeMap& nodeMap = moduleNamespaceMap[fn->name()]; - foreach (const QString& name, nodeMap.keys()) { - const Node* node = nodeMap[name]; - if (node->status() == Node::Obsolete || - node->isInternal() || - node->access() == Node::Private || - node->doc().isEmpty()) - continue; - writeStartTag(DT_topicref); - xmlWriter().writeAttribute("navtitle",node->name()); - xmlWriter().writeAttribute("href",fileName(node)); - writeEndTag(); // </topicref> - } - } - if (moduleClassMap.contains(fn->name())) { - const NodeMap& nodeMap = moduleClassMap[fn->name()]; - foreach (const QString& name, nodeMap.keys()) { - const Node* node = nodeMap[name]; - if (node->status() == Node::Obsolete || - node->isInternal() || - node->access() == Node::Private || - node->doc().isEmpty()) - continue; + ++i; + } + } + /*! + Shortcut when there are no hand-written ditamaps or when we are + not generating the articles list. + */ + else { + i = nmm->begin(); + while (i != nmm->end()) { + // Hardcode not writing index.dita multiple times in the tree. + // index.dita should only appear at the top of the ditamap. + if (fileName(i.value()) == "index.dita") { + i++; + continue; + } + writeStartTag(DT_topicref); + xmlWriter().writeAttribute("navtitle",i.key()); + xmlWriter().writeAttribute("href",fileName(i.value())); + switch (i.value()->type()) { + case Node::Class: { + const NamespaceNode* nn = static_cast<const NamespaceNode*>(i.value()); + const NodeList& c = nn->childNodes(); + for (int j=0; j<c.size(); ++j) { + if (c[j]->isInternal() || c[j]->access() == Node::Private || c[j]->doc().isEmpty()) + continue; + if (c[j]->type() == Node::Class) { writeStartTag(DT_topicref); - xmlWriter().writeAttribute("navtitle",node->name()); - xmlWriter().writeAttribute("href",fileName(node)); + xmlWriter().writeAttribute("navtitle",c[j]->name()); + xmlWriter().writeAttribute("href",fileName(c[j])); writeEndTag(); // </topicref> } } @@ -6045,43 +6048,9 @@ void DitaXmlGenerator::writeTopicrefs(NodeMultiMap* nmm, const QString& navtitle default: break; } - break; - } - case Node::Namespace: { - const NamespaceNode* nn = static_cast<const NamespaceNode*>(i.value()); - const NodeList& c = nn->childNodes(); - for (int j=0; j<c.size(); ++j) { - if (c[j]->isInternal() || c[j]->access() == Node::Private || c[j]->doc().isEmpty()) - continue; - if (c[j]->type() == Node::Class) { - writeStartTag(DT_topicref); - xmlWriter().writeAttribute("navtitle",c[j]->name()); - xmlWriter().writeAttribute("href",fileName(c[j])); - writeEndTag(); // </topicref> - } - } - break; - } - case Node::Class: { - const NamespaceNode* nn = static_cast<const NamespaceNode*>(i.value()); - const NodeList& c = nn->childNodes(); - for (int j=0; j<c.size(); ++j) { - if (c[j]->isInternal() || c[j]->access() == Node::Private || c[j]->doc().isEmpty()) - continue; - if (c[j]->type() == Node::Class) { - writeStartTag(DT_topicref); - xmlWriter().writeAttribute("navtitle",c[j]->name()); - xmlWriter().writeAttribute("href",fileName(c[j])); - writeEndTag(); // </topicref> - } - } - break; - } - default: - break; + writeEndTag(); // </topicref> + ++i; } - writeEndTag(); // </topicref> - ++i; } writeEndTag(); // </topicref> } @@ -6397,5 +6366,125 @@ QString DitaXmlGenerator::stripMarkup(const QString& src) const return text; } +/*! + We delayed generation of the collision pages until now, after + all the other pages have been generated. We do this because we might + encounter a link command that tries to link to a target on a QML + type page, but the link doesn't specify the module identifer + for the QML type, and the QML type name without a module + identifier is ambiguous. When such a link is found, qdoc can't find + the target, so it appends the target to the NameCollisionNode. After + the tree has been traversed and all these ambiguous links have been + added to the name collision nodes, this function is called. The list + of collision nodes is traversed here, and the collision page for + each collision is generated. The collision page will not only + disambiguate links to the QML type pages, but it will also disambiguate + links to properties, section headers, etc. + */ +void DitaXmlGenerator::generateCollisionPages() +{ + if (collisionNodes.isEmpty()) + return; + + for (int i=0; i<collisionNodes.size(); ++i) { + NameCollisionNode* ncn = collisionNodes.at(i); + if (!ncn) + continue; + + NodeList collisions; + const NodeList& nl = ncn->childNodes(); + if (!nl.isEmpty()) { + NodeList::ConstIterator it = nl.begin(); + while (it != nl.end()) { + if (!(*it)->isInternal()) + collisions.append(*it); + ++it; + } + } + if (collisions.size() <= 1) + continue; + + ncn->clearCurrentChild(); + beginSubPage(ncn, Generator::fileName(ncn)); + QString fullTitle = ncn->fullTitle(); + QString ditaTitle = fullTitle; + CodeMarker* marker = CodeMarker::markerForFileName(ncn->location().filePath()); + if (ncn->isQmlNode()) { + // Replace the marker with a QML code marker. + if (ncn->isQmlNode()) + marker = CodeMarker::markerForLanguage(QLatin1String("QML")); + } + + generateHeader(ncn, ditaTitle); + writeProlog(ncn); + writeStartTag(DT_body); + enterSection(QString(),QString()); + + NodeMap nm; + for (int i=0; i<collisions.size(); ++i) { + Node* n = collisions.at(i); + QString t; + if (!n->qmlModuleIdentifier().isEmpty()) + t = n->qmlModuleIdentifier() + " "; + t += protectEnc(fullTitle); + nm.insertMulti(t,n); + } + generateAnnotatedList(ncn, marker, nm); + + QList<QString> targets; + if (!ncn->linkTargets().isEmpty()) { + QMap<QString,QString>::ConstIterator t = ncn->linkTargets().begin(); + while (t != ncn->linkTargets().end()) { + int count = 0; + for (int i=0; i<collisions.size(); ++i) { + InnerNode* n = static_cast<InnerNode*>(collisions.at(i)); + if (n->findChildNodeByName(t.key())) { + ++count; + if (count > 1) { + targets.append(t.key()); + break; + } + } + } + ++t; + } + } + if (!targets.isEmpty()) { + QList<QString>::ConstIterator t = targets.begin(); + while (t != targets.end()) { + writeStartTag(DT_p); + writeGuidAttribute(Doc::canonicalTitle(*t)); + xmlWriter().writeAttribute("outputclass","h2"); + writeCharacters(protectEnc(*t)); + writeEndTag(); // </p> + writeStartTag(DT_ul); + for (int i=0; i<collisions.size(); ++i) { + InnerNode* n = static_cast<InnerNode*>(collisions.at(i)); + Node* p = n->findChildNodeByName(*t); + if (p) { + QString link = linkForNode(p,0); + QString label; + if (!n->qmlModuleIdentifier().isEmpty()) + label = n->qmlModuleIdentifier() + "::"; + label += n->name() + "::" + p->name(); + writeStartTag(DT_li); + writeStartTag(DT_xref); + xmlWriter().writeAttribute("href", link); + writeCharacters(protectEnc(label)); + writeEndTag(); // </xref> + writeEndTag(); // </li> + } + } + writeEndTag(); // </ul> + ++t; + } + } + leaveSection(); // </section> + writeEndTag(); // </body> + endSubPage(); + } +} + + QT_END_NAMESPACE |