summaryrefslogtreecommitdiffstats
path: root/src/tools/qdoc/htmlgenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/qdoc/htmlgenerator.cpp')
-rw-r--r--src/tools/qdoc/htmlgenerator.cpp566
1 files changed, 352 insertions, 214 deletions
diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp
index ced7e637b3..8eb96bff17 100644
--- a/src/tools/qdoc/htmlgenerator.cpp
+++ b/src/tools/qdoc/htmlgenerator.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the tools applications of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -100,8 +100,10 @@ HtmlGenerator::HtmlGenerator()
*/
HtmlGenerator::~HtmlGenerator()
{
- if (helpProjectWriter)
+ if (helpProjectWriter) {
delete helpProjectWriter;
+ helpProjectWriter = 0;
+ }
}
/*!
@@ -130,6 +132,11 @@ void HtmlGenerator::initializeGenerator(const Config &config)
Generator::initializeGenerator(config);
obsoleteLinks = config.getBool(CONFIG_OBSOLETELINKS);
setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif");
+
+ /*
+ The formatting maps are owned by Generator. They are cleared in
+ Generator::terminate().
+ */
int i = 0;
while (defaults[i].key) {
formattingLeftMap().insert(defaults[i].key, defaults[i].left);
@@ -215,7 +222,14 @@ void HtmlGenerator::initializeGenerator(const Config &config)
// The following line was changed to fix QTBUG-27798
//codeIndent = config.getInt(CONFIG_CODEINDENT);
- helpProjectWriter = new HelpProjectWriter(config, project.toLower() + ".qhp", this);
+ /*
+ The help file write should be allocated once and only once
+ per qdoc execution.
+ */
+ if (helpProjectWriter)
+ helpProjectWriter->reset(config, project.toLower() + ".qhp", this);
+ else
+ helpProjectWriter = new HelpProjectWriter(config, project.toLower() + ".qhp", this);
// Documentation template handling
headerScripts = config.getString(HtmlGenerator::format() + Config::dot + CONFIG_HEADERSCRIPTS);
@@ -263,6 +277,20 @@ QString HtmlGenerator::format()
}
/*!
+ Generate targets for any \keyword commands that were seen
+ in the qdoc comment for the \a node.
+ */
+void HtmlGenerator::generateKeywordAnchors(const Node* node)
+{
+ if (!node->doc().isEmpty()) {
+ const QList<Atom*>& keywords = node->doc().keywords();
+ foreach (Atom* a, keywords) {
+ out() << "<a name=\"" << Doc::canonicalTitle(a->string()) << "\"></a>";
+ }
+ }
+}
+
+/*!
Traverses the current tree generating all the HTML documentation.
*/
void HtmlGenerator::generateDocs()
@@ -270,10 +298,12 @@ void HtmlGenerator::generateDocs()
Node* qflags = qdb_->findClassNode(QStringList("QFlags"));
if (qflags)
qflagsHref_ = linkForNode(qflags,0);
- if (!runPrepareOnly())
+ if (!preparing())
Generator::generateDocs();
+ if (Generator::generating() && Generator::writeQaPages())
+ generateQAPage();
- if (!runGenerateOnly()) {
+ if (!generating()) {
QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-'));
qdb_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index",
projectUrl,
@@ -282,7 +312,7 @@ void HtmlGenerator::generateDocs()
true);
}
- if (!runPrepareOnly()) {
+ if (!preparing()) {
helpProjectWriter->generate();
generateManifestFiles();
/*
@@ -293,6 +323,144 @@ void HtmlGenerator::generateDocs()
}
/*!
+ Output the module's Quality Assurance page.
+ */
+void HtmlGenerator::generateQAPage()
+{
+ NamespaceNode* node = qdb_->primaryTreeRoot();
+ beginSubPage(node, "aaa-" + defaultModuleName().toLower() + "-qa-page.html");
+ CodeMarker* marker = CodeMarker::markerForFileName(node->location().filePath());
+ QString title = "Quality Assurance Page for " + defaultModuleName();
+ QString t = "Quality assurance information for checking the " + defaultModuleName() + " documentation.";
+ generateHeader(title, node, marker);
+ generateTitle(title, Text() << t, LargeSubTitle, node, marker);
+
+ QStringList strings;
+ QVector<int> counts;
+ QString depends = qdb_->getLinkCounts(strings, counts);
+ if (!strings.isEmpty()) {
+ t = "Intermodule Link Counts";
+ QString ref = registerRef(t);
+ out() << "<a name=\"" << ref << "\"></a>" << divNavTop << '\n';
+ out() << "<h2 id=\"" << ref << "\">" << protectEnc(t) << "</h2>\n";
+ out() << "<table class=\"valuelist\"><tr valign=\"top\" "
+ << "class=\"even\"><th class=\"tblConst\">Destination Module</th>"
+ << "<th class=\"tblval\">Link Count</th></tr>\n";
+ QString fileName;
+ for (int i = 0; i< strings.size(); ++i) {
+ fileName = generateLinksToLinksPage(strings.at(i), marker);
+ out() << "<tr><td class=\"topAlign\"><tt>"
+ << "<a href=\"" << fileName << "\">"
+ << strings.at(i) << "</a>"
+ << "</tt></td><td class=\"topAlign\"><tt>" << counts.at(i)
+ << "</tt></td></tr>\n";
+ }
+ int count = 0;
+ fileName = generateLinksToBrokenLinksPage(marker, count);
+ if (count != 0) {
+ out() << "<tr><td class=\"topAlign\"><tt>"
+ << "<a href=\"" << fileName << "\">"
+ << "Broken Links" << "</a>"
+ << "</tt></td><td class=\"topAlign\"><tt>" << count
+ << "</tt></td></tr>\n";
+
+ }
+
+ out() << "</table>\n";
+ t = "The Optimal \"depends\" Variable";
+ out() << "<h2>" << protectEnc(t) << "</h2>\n";
+ t = "Consider replacing the depends variable in " + defaultModuleName().toLower() +
+ ".qdocconf with this one, if the two are not identical:";
+ out() << "<p>" << protectEnc(t) << "</p>\n";
+ out() << "<p>" << protectEnc(depends) << "</p>\n";
+ }
+ generateFooter();
+ endSubPage();
+}
+
+/*!
+ This function writes an html file containing a list of
+ links to links that originate in the current module and
+ go to targets in the specified \a module. The \a marker
+ is used for the same thing the marker is always used for.
+ */
+QString HtmlGenerator::generateLinksToLinksPage(const QString& module, CodeMarker* marker)
+{
+ NamespaceNode* node = qdb_->primaryTreeRoot();
+ QString fileName = "aaa-links-to-" + module + ".html";
+ beginSubPage(node, fileName);
+ QString title = "Links from " + defaultModuleName() + " to " + module;
+ generateHeader(title, node, marker);
+ generateTitle(title, Text(), SmallSubTitle, node, marker);
+ out() << "<p>This is a list of links from " << defaultModuleName()
+ << " to " << module << ". ";
+ out() << "Click on a link to go to the location of the link. The link is marked ";
+ out() << "with red asterisks. ";
+ out() << "Click on the marked link to see if it goes to the right place.</p>\n";
+ TargetList* tlist = qdb_->getTargetList(module);
+ if (tlist) {
+ out() << "<table class=\"valuelist\"><tr valign=\"top\" class=\"odd\"><th class=\"tblConst\">Link to link...</th><th class=\"tblval\">In file...</th><th class=\"tbldscr\">Somewhere after line number...</th></tr>\n";
+ foreach (TargetLoc* t, *tlist) {
+ // e.g.: <a name="link-8421"></a><a href="layout.html">Layout Management</a>
+ out() << "<tr><td class=\"topAlign\">";
+ out() << "<a href=\"" << t->fileName_ << "#" << t->target_ << "\">";
+ out() << t->text_ << "</a></td>";
+ out() << "<td class=\"topAlign\">";
+ QString f = t->loc_->doc().location().filePath();
+ out() << f << "</td>";
+ out() << "<td class=\"topAlign\">";
+ out() << t->loc_->doc().location().lineNo() << "</td></tr>\n";
+ }
+ out() << "</table>\n";
+ }
+ generateFooter();
+ endSubPage();
+ return fileName;
+}
+
+/*!
+ This function writes an html file containing a list of
+ links to broken links that originate in the current
+ module and go nowwhere. It returns the name of the file
+ it generates, and it sets \a count to the number of
+ broken links that were found. The \a marker is used for
+ the same thing the marker is always used for.
+ */
+QString HtmlGenerator::generateLinksToBrokenLinksPage(CodeMarker* marker, int& count)
+{
+ QString fileName;
+ NamespaceNode* node = qdb_->primaryTreeRoot();
+ TargetList* tlist = qdb_->getTargetList("broken");
+ if (tlist && !tlist->isEmpty()) {
+ count = tlist->size();
+ fileName = "aaa-links-to-broken-links.html";
+ beginSubPage(node, fileName);
+ QString title = "Broken links in " + defaultModuleName();
+ generateHeader(title, node, marker);
+ generateTitle(title, Text(), SmallSubTitle, node, marker);
+ out() << "<p>This is a list of broken links in " << defaultModuleName() << ". ";
+ out() << "Click on a link to go to the broken link. ";
+ out() << "The link's target could not be found.</p>\n";
+ out() << "<table class=\"valuelist\"><tr valign=\"top\" class=\"odd\"><th class=\"tblConst\">Link to broken link...</th><th class=\"tblval\">In file...</th><th class=\"tbldscr\">Somewhere after line number...</th></tr>\n";
+ foreach (TargetLoc* t, *tlist) {
+ // e.g.: <a name="link-8421"></a><a href="layout.html">Layout Management</a>
+ out() << "<tr><td class=\"topAlign\">";
+ out() << "<a href=\"" << t->fileName_ << "#" << t->target_ << "\">";
+ out() << t->text_ << "</a></td>";
+ out() << "<td class=\"topAlign\">";
+ QString f = t->loc_->doc().location().filePath();
+ out() << f << "</td>";
+ out() << "<td class=\"topAlign\">";
+ out() << t->loc_->doc().location().lineNo() << "</td></tr>\n";
+ }
+ out() << "</table>\n";
+ generateFooter();
+ endSubPage();
+ }
+ return fileName;
+}
+
+/*!
Generate html from an instance of Atom.
*/
int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker)
@@ -310,6 +478,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
case Atom::AbstractRight:
break;
case Atom::AutoLink:
+ case Atom::NavAutoLink:
if (!inLink_ && !inContents_ && !inSectionHeading_) {
const Node *node = 0;
QString link = getAutoLink(atom, relative, &node);
@@ -321,9 +490,15 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
if ((relative->parent() != node) && !relative->isObsolete())
link.clear();
}
- if (link.isEmpty())
+ if (link.isEmpty()) {
out() << protectEnc(atom->string());
+ }
else {
+ if (Generator::writeQaPages() && node && (atom->type() != Atom::NavAutoLink)) {
+ QString text = atom->string();
+ QString target = qdb_->getNewLinkTarget(relative, node, outFileName(), text);
+ out() << "<a id=\"" << Doc::canonicalTitle(target) << "\" class=\"qa-mark\"></a>";
+ }
beginLink(link, node, relative);
generateLink(atom, marker);
endLink();
@@ -338,7 +513,10 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
case Atom::BriefLeft:
// Do not output the brief for QML nodes, doc nodes or collections
// (groups, modules, qml module nodes)
- if (relative->isQmlType() || relative->isDocNode() || relative->isCollectionNode()) {
+ if (relative->isQmlType() ||
+ relative->isDocumentNode() ||
+ relative->isCollectionNode() ||
+ relative->isJsType()) {
skipAhead = skipAtoms(atom, Atom::BriefRight);
break;
}
@@ -374,7 +552,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
}
break;
case Atom::BriefRight:
- if (!relative->isDocNode())
+ if (!relative->isDocumentNode())
out() << "</p>\n";
break;
case Atom::C:
@@ -485,9 +663,9 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
break;
case Atom::AnnotatedList:
{
- GroupNode* gn = qdb_->getGroup(atom->string());
- if (gn)
- generateList(gn, marker, atom->string());
+ CollectionNode* cn = qdb_->getCollection(atom->string(), Node::DOC);
+ if (cn)
+ generateList(cn, marker, atom->string());
}
break;
case Atom::GeneratedList:
@@ -508,12 +686,12 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
generateCompactList(Generic, relative, qdb_->getQmlTypes(), true, QStringLiteral(""));
}
else if (atom->string().contains("classesbymodule")) {
- QString moduleName = atom->string().mid(atom->string().indexOf("classesbymodule") + 15).trimmed();
+ QString physicalModuleName = atom->string().mid(atom->string().indexOf("classesbymodule") + 15).trimmed();
QDocDatabase* qdb = QDocDatabase::qdocDB();
- ModuleNode* mn = qdb->findModule(moduleName);
- if (mn) {
+ CollectionNode* cn = qdb->findModule(physicalModuleName);
+ if (cn) {
NodeMap m;
- mn->getMemberClasses(m);
+ cn->getMemberClasses(m);
if (!m.isEmpty()) {
generateAnnotatedList(relative, marker, m);
}
@@ -576,7 +754,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
Remove permanently if it is not missed.
*/
else if (atom->string() == "relatedinline") {
- const DocNode *dn = static_cast<const DocNode *>(relative);
+ const DocumentNode *dn = static_cast<const DocumentNode *>(relative);
if (dn && !dn->members().isEmpty()) {
// Reverse the list into the original scan order.
// Should be sorted. But on what? It may not be a
@@ -806,14 +984,31 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
out() << "<br/>";
break;
case Atom::Link:
+ case Atom::NavLink:
{
inObsoleteLink = false;
const Node *node = 0;
QString link = getLink(atom, relative, &node);
if (link.isEmpty() && (node != relative) && !noLinkErrors()) {
relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string()));
+ if (Generator::writeQaPages() && (atom->type() != Atom::NavAutoLink)) {
+ QString text = atom->next()->next()->string();
+ QString target = qdb_->getNewLinkTarget(relative, node, outFileName(), text, true);
+ out() << "<a id=\"" << Doc::canonicalTitle(target) << "\" class=\"qa-mark\"></a>";
+ }
}
else {
+ if (Generator::writeQaPages() && node && (atom->type() != Atom::NavLink)) {
+ QString text = atom->next()->next()->string();
+ QString target = qdb_->getNewLinkTarget(relative, node, outFileName(), text);
+ out() << "<a id=\"" << Doc::canonicalTitle(target) << "\" class=\"qa-mark\"></a>";
+ }
+ /*
+ mws saw this on 17/10/2014.
+ Is this correct? Setting node to 0 means the
+ following test always fails. Did we decide to
+ no longer warn about linking to obsolete things?
+ */
node = 0;
if (node && node->status() == Node::Obsolete) {
if ((relative->parent() != node) && !relative->isObsolete()) {
@@ -1126,6 +1321,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
break;
case Atom::TableOfContents:
break;
+ case Atom::Keyword:
+ break;
case Atom::Target:
out() << "<a name=\"" << Doc::canonicalTitle(atom->string()) << "\"></a>";
break;
@@ -1173,8 +1370,10 @@ void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
subtitleText << "(" << Atom(Atom::AutoLink, fullTitle) << ")" << Atom(Atom::LineBreak);
generateHeader(title, inner, marker);
+
sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);
generateTableOfContents(inner,marker,&sections);
+ generateKeywordAnchors(inner);
generateTitle(title, subtitleText, SmallSubTitle, inner, marker);
generateBrief(inner, marker);
generateRequisites(inner, marker);
@@ -1336,16 +1535,22 @@ void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
Generate the HTML page for a QML type. \qcn is the QML type.
\marker is the code markeup object.
*/
-void HtmlGenerator::generateQmlTypePage(QmlClassNode* qcn, CodeMarker* marker)
+void HtmlGenerator::generateQmlTypePage(QmlTypeNode* qcn, CodeMarker* marker)
{
+ Generator::setQmlTypeContext(qcn);
SubTitleSize subTitleSize = LargeSubTitle;
QList<Section>::const_iterator s;
- QString htmlTitle = qcn->fullTitle() + " QML Type";
+ QString htmlTitle = qcn->fullTitle();
+ if (qcn->isJsType())
+ htmlTitle += " JavaScript Type";
+ else
+ htmlTitle += " QML Type";
generateHeader(htmlTitle, qcn, marker);
QList<Section> sections = marker->qmlSections(qcn, CodeMarker::Summary);
generateTableOfContents(qcn, marker, &sections);
marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
+ generateKeywordAnchors(qcn);
generateTitle(htmlTitle, Text() << qcn->subTitle(), subTitleSize, qcn, marker);
generateBrief(qcn, marker);
generateQmlRequisites(qcn, marker);
@@ -1400,6 +1605,7 @@ void HtmlGenerator::generateQmlTypePage(QmlClassNode* qcn, CodeMarker* marker)
++s;
}
generateFooter(qcn);
+ Generator::setQmlTypeContext(0);
}
/*!
@@ -1410,13 +1616,18 @@ void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker*
{
SubTitleSize subTitleSize = LargeSubTitle;
QList<Section>::const_iterator s;
- QString htmlTitle = qbtn->fullTitle() + " QML Basic Type";
+ QString htmlTitle = qbtn->fullTitle();
+ if (qbtn->isJsType())
+ htmlTitle += " JavaScript Basic Type";
+ else
+ htmlTitle += " QML Basic Type";
marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
generateHeader(htmlTitle, qbtn, marker);
QList<Section> sections = marker->sections(qbtn, CodeMarker::Summary, CodeMarker::Okay);
generateTableOfContents(qbtn,marker,&sections);
+ generateKeywordAnchors(qbtn);
generateTitle(htmlTitle,
Text() << qbtn->subTitle(),
subTitleSize,
@@ -1436,7 +1647,7 @@ void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker*
Generate the HTML page for an entity that doesn't map
to any underlying parsable C++ class or QML component.
*/
-void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
+void HtmlGenerator::generateDocumentNode(DocumentNode* dn, CodeMarker* marker)
{
/*
If the document node is a page node, and if the page type
@@ -1462,6 +1673,7 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
if ((dn->name() != QStringLiteral("index.html")))
generateTableOfContents(dn,marker,0);
+ generateKeywordAnchors(dn);
generateTitle(fullTitle,
Text() << dn->subTitle(),
subTitleSize,
@@ -1546,6 +1758,7 @@ void HtmlGenerator::generateCollectionNode(CollectionNode* cn, CodeMarker* marke
generateHeader(fullTitle, cn, marker);
generateTableOfContents(cn,marker,0);
+ generateKeywordAnchors(cn);
generateTitle(fullTitle, Text() << cn->subTitle(), subTitleSize, cn, marker);
if (cn->isModule()) {
@@ -1603,7 +1816,7 @@ void HtmlGenerator::generateCollectionNode(CollectionNode* cn, CodeMarker* marke
if (cn->isGroup())
generateAnnotatedList(cn, marker, cn->members());
- else if (cn->isQmlModule())
+ else if (cn->isQmlModule() || cn->isJsModule())
generateAnnotatedList(cn, marker, cn->members());
sections = marker->sections(cn, CodeMarker::Detailed, CodeMarker::Okay);
@@ -1646,20 +1859,20 @@ void HtmlGenerator::generateNavigationBar(const QString &title,
return;
if (!homepage.isEmpty())
navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::AutoLink, homepage)
+ << Atom(Atom::NavAutoLink, homepage)
<< Atom(Atom::ListItemRight);
if (!landingpage.isEmpty() && landingpage != title)
navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::AutoLink, landingpage)
+ << Atom(Atom::NavAutoLink, landingpage)
<< Atom(Atom::ListItemRight);
if (node->isClass()) {
const ClassNode *cn = static_cast<const ClassNode *>(node);
- QString name = node->moduleName();
+ QString name = node->physicalModuleName();
if (!cppclassespage.isEmpty())
navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::Link, cppclassespage)
+ << Atom(Atom::NavLink, cppclassespage)
<< Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
<< Atom(Atom::String, QLatin1String("C++ Classes"))
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
@@ -1670,10 +1883,11 @@ void HtmlGenerator::generateNavigationBar(const QString &title,
<< Atom(Atom::String, cn->name())
<< Atom(Atom::ListItemRight);
}
- else if (node->isQmlType() || node->isQmlBasicType()) {
+ else if (node->isQmlType() || node->isQmlBasicType() ||
+ node->isJsType() || node->isJsBasicType()) {
if (!qmltypespage.isEmpty())
navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::Link, qmltypespage)
+ << Atom(Atom::NavLink, qmltypespage)
<< Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
<< Atom(Atom::String, QLatin1String("QML Types"))
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
@@ -1685,7 +1899,7 @@ void HtmlGenerator::generateNavigationBar(const QString &title,
else {
if (node->isExampleFile()) {
navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::Link, node->parent()->name())
+ << Atom(Atom::NavLink, node->parent()->name())
<< Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
<< Atom(Atom::String, node->parent()->title())
<< Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
@@ -1930,11 +2144,11 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker)
if (inner->type() == Node::Class || inner->type() == Node::Namespace) {
//add the QT variable to the map
- if (!inner->moduleName().isEmpty()) {
- ModuleNode* moduleNode = qdb_->findModule(inner->moduleName());
- if (moduleNode && !moduleNode->qtVariable().isEmpty()) {
+ if (!inner->physicalModuleName().isEmpty()) {
+ CollectionNode* cn = qdb_->findModule(inner->physicalModuleName());
+ if (cn && !cn->qtVariable().isEmpty()) {
text.clear();
- text << "QT += " + moduleNode->qtVariable();
+ text << "QT += " + cn->qtVariable();
requisites.insert(qtVariableText, text);
}
}
@@ -2018,7 +2232,7 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker)
Lists the required imports and includes in a table.
The number of rows is known, so this path is simpler than the generateSection() path.
*/
-void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker)
+void HtmlGenerator::generateQmlRequisites(QmlTypeNode *qcn, CodeMarker *marker)
{
if (!qcn)
return;
@@ -2040,14 +2254,18 @@ void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker)
<< inheritedBytext;
//add the module name and version to the map
- QString qmlModuleVersion;
- QmlModuleNode* qmn = qdb_->findQmlModule(qcn->qmlModuleName());
- if (qmn)
- qmlModuleVersion = qmn->qmlModuleVersion();
+ QString logicalModuleVersion;
+ CollectionNode* collection = 0;
+ if (qcn->isJsNode())
+ qdb_->findJsModule(qcn->logicalModuleName());
+ else
+ qdb_->findQmlModule(qcn->logicalModuleName());
+ if (collection)
+ logicalModuleVersion = collection->logicalModuleVersion();
else
- qmlModuleVersion = qcn->qmlModuleVersion();
+ logicalModuleVersion = qcn->logicalModuleVersion();
text.clear();
- text << "import " + qcn->qmlModuleName() + " " + qmlModuleVersion;
+ text << "import " + qcn->logicalModuleName() + " " + logicalModuleVersion;
requisites.insert(importText, text);
//add the since and project into the map
@@ -2080,7 +2298,7 @@ void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker)
}
//add the inherits to the map
- QmlClassNode* base = qcn->qmlBaseNode();
+ QmlTypeNode* base = qcn->qmlBaseNode();
while (base && base->isInternal()) {
base = base->qmlBaseNode();
}
@@ -2097,7 +2315,7 @@ void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker)
//add the inherited-by to the map
NodeList subs;
- QmlClassNode::subclasses(qcn->name(), subs);
+ QmlTypeNode::subclasses(qcn->name(), subs);
if (!subs.isEmpty()) {
text.clear();
text << Atom::ParaLeft;
@@ -2217,7 +2435,10 @@ void HtmlGenerator::generateTableOfContents(const Node *node,
}
}
}
- else if (sections && (node->isClass() || node->isNamespace() || node->isQmlType())) {
+ else if (sections && (node->isClass() ||
+ node->isNamespace() ||
+ node->isQmlType() ||
+ node->isJsType())) {
QList<Section>::ConstIterator s = sections->constBegin();
while (s != sections->constEnd()) {
if (!s->members.isEmpty()) {
@@ -2329,7 +2550,7 @@ QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner,
out() << ", including inherited members.</p>\n";
Section section = sections.first();
- generateSectionList(section, 0, marker, CodeMarker::Subpage);
+ generateSectionList(section, inner, marker, CodeMarker::Subpage);
generateFooter();
endSubPage();
@@ -2341,7 +2562,7 @@ QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner,
the members of QML class \a qml_cn, including the inherited
members. The \a marker is used for formatting stuff.
*/
-QString HtmlGenerator::generateAllQmlMembersFile(QmlClassNode* qml_cn, CodeMarker* marker)
+QString HtmlGenerator::generateAllQmlMembersFile(QmlTypeNode* qml_cn, CodeMarker* marker)
{
QList<Section> sections;
QList<Section>::ConstIterator s;
@@ -2364,7 +2585,7 @@ QString HtmlGenerator::generateAllQmlMembersFile(QmlClassNode* qml_cn, CodeMarke
if (!cknl.isEmpty()) {
for (int i=0; i<cknl.size(); i++) {
ClassKeysNodes* ckn = cknl[i];
- const QmlClassNode* qcn = ckn->first;
+ const QmlTypeNode* qcn = ckn->first;
KeysAndNodes& kn = ckn->second;
QStringList& keys = kn.first;
NodeList& nodes = kn.second;
@@ -2386,7 +2607,7 @@ QString HtmlGenerator::generateAllQmlMembersFile(QmlClassNode* qml_cn, CodeMarke
prefix = keys.at(j).mid(1);
prefix = prefix.left(keys.at(j).indexOf("::")+1);
}
- generateQmlItem(nodes[j], qcn, marker, true);
+ generateQmlItem(nodes[j], qml_cn, marker, true);
if (nodes[j]->isAttached())
out() << " [attached]";
//generateSynopsis(nodes[j], qcn, marker, CodeMarker::Subpage, false, &prefix);
@@ -2490,7 +2711,7 @@ QString HtmlGenerator::generateLowStatusMemberFile(InnerNode *inner,
Note that this function currently only handles correctly the
case where \a status is \c {CodeMarker::Obsolete}.
*/
-QString HtmlGenerator::generateQmlMemberFile(QmlClassNode* qcn,
+QString HtmlGenerator::generateQmlMemberFile(QmlTypeNode* qcn,
CodeMarker *marker,
CodeMarker::Status status)
{
@@ -2646,7 +2867,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative,
generateFullName(node, relative);
out() << "</p></td>";
- if (!node->isDocNode()) {
+ if (!node->isDocumentNode()) {
Text brief = node->doc().trimmedBriefText(node->name());
if (!brief.isEmpty()) {
out() << "<td class=\"tblDescr\"><p>";
@@ -2815,14 +3036,15 @@ void HtmlGenerator::generateCompactList(ListType listType,
else if (listType == Obsolete) {
QString fileName = fileBase(it.value()) + "-obsolete." + fileExtension();
QString link;
- if (useOutputSubdirs())
+ if (useOutputSubdirs()) {
link = QString("../" + it.value()->outputSubdirectory() + QLatin1Char('/'));
+ }
link += fileName;
out() << "<a href=\"" << link << "\">";
}
QStringList pieces;
- if (it.value()->isQmlType())
+ if (it.value()->isQmlType() || it.value()->isJsType())
pieces << it.value()->name();
else
pieces = it.value()->fullName(relative).split("::");
@@ -2856,7 +3078,7 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative)
char currentLetter;
out() << "<ul>\n";
- NodeMapMap funcIndex = qdb_->getFunctionIndex();
+ NodeMapMap& funcIndex = qdb_->getFunctionIndex();
QMap<QString, NodeMap >::ConstIterator f = funcIndex.constBegin();
while (f != funcIndex.constEnd()) {
out() << "<li>";
@@ -2915,7 +3137,7 @@ void HtmlGenerator::generateQmlItem(const Node *node,
}
marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"),
"<i>\\1<sub>\\2</sub></i>");
- marked.replace("<@param>", "<i>");
+ marked.replace("<@param>", "<i> ");
marked.replace("</@param>", "</i>");
if (summary)
@@ -2933,30 +3155,20 @@ void HtmlGenerator::generateQmlItem(const Node *node,
void HtmlGenerator::generateList(const Node* relative, CodeMarker* marker, const QString& selector)
{
- NodeList nl;
- CollectionList cl;
- QRegExp singleDigit("\\b([0-9])\\b");
-
- if (selector == "overviews") {
- CNMap groups;
- qdb_->mergeCollections(Node::Group, groups, relative);
- cl = groups.values();
- foreach (CollectionNode* cn, cl)
- nl.append(cn);
- generateAnnotatedList(relative, marker, nl);
- }
- else if (selector == "cpp-modules") {
- CNMap modules;
- qdb_->mergeCollections(Node::Module, modules, relative);
- cl = modules.values();
- foreach (CollectionNode* cn, cl)
- nl.append(cn);
- generateAnnotatedList(relative, marker, nl);
- }
- else if (selector == "qml-modules") {
- CNMap qmlModules;
- qdb_->mergeCollections(Node::QmlModule, qmlModules, relative);
- cl = qmlModules.values();
+ CNMap cnm;
+ Node::Genus genus = Node::DontCare;
+ if (selector == "overviews")
+ genus = Node::DOC;
+ else if (selector == "cpp-modules")
+ genus = Node::CPP;
+ else if (selector == "qml-modules")
+ genus = Node::QML;
+ else if (selector == "js-modules")
+ genus = Node::JS;
+ if (genus != Node::DontCare) {
+ NodeList nl;
+ qdb_->mergeCollections(genus, cnm, relative);
+ CollectionList cl = cnm.values();
foreach (CollectionNode* cn, cl)
nl.append(cn);
generateAnnotatedList(relative, marker, nl);
@@ -2964,69 +3176,19 @@ void HtmlGenerator::generateList(const Node* relative, CodeMarker* marker, const
else {
/*
\generatelist {selector} is only allowed in a
- comment where the topic is \group, \module, or
- \qmlmodule.
+ comment where the topic is \group, \module,
+ \qmlmodule, or \jsmodule
*/
if (!relative || !relative->isCollectionNode()) {
- relative->doc().location().warning(tr("\\generatelist {%1} is only allowed in \\group, \\module, and \\qmlmodule comments.").arg(selector));
+ relative->doc().location().warning(tr("\\generatelist {%1} is only allowed in \\group, "
+ "\\module, \\qmlmodule, and \\jsmodule comments.").arg(selector));
return;
}
- if (selector == "related") {
- Node* n = const_cast<Node*>(relative);
- CollectionNode* cn = static_cast<CollectionNode*>(n);
- qdb_->mergeCollections(cn);
- generateAnnotatedList(cn, marker, cn->members());
- }
- else {
- Node* n = const_cast<Node*>(relative);
- CollectionNode* cn = static_cast<CollectionNode*>(n);
- qdb_->mergeCollections(cn);
- generateAnnotatedList(cn, marker, cn->members());
- }
- }
-
-#if 0
- QStringList keys = groups.uniqueKeys();
- foreach (QString key, keys) {
- GroupNode* gn = static_cast<GroupNode*>(groups.value(key));
- if (gn) {
- out() << QString("<h3><a href=\"%1\">%2</a></h3>\n").arg(
- linkForNode(gn, relative)).arg(
- protectEnc(gn->fullTitle()));
-#if 0
- if (gn->members().isEmpty())
- continue;
-
- NodeMap nm;
- foreach (Node* member, gn->members()) {
- if (member->isInternal() || member->isExample() || member->isExternalPage() ||
- member->isObsolete())
- continue;
- // not interested either in individual (Qt Designer etc.) manual chapters
- if (member->links().contains(Node::ContentsLink))
- continue;
- QString sortKey = member->fullTitle().toLower();
- if (sortKey.startsWith("the "))
- sortKey.remove(0, 4);
- sortKey.replace(singleDigit, "0\\1");
- nm.insert(sortKey, member);
- }
-
- out() << "<ul>\n";
- QStringList titles = nm.keys();
- foreach (QString t, titles) {
- Node* member = nm.value(t);
- QString title = member->fullTitle();
- if (title.startsWith("The "))
- title.remove(0, 4);
- out() << "<li><a href=\"" << linkForNode(member, relative) << "\">"
- << protectEnc(title) << "</a></li>\n";
- }
- out() << "</ul>\n";
-#endif
- }
+ Node* n = const_cast<Node*>(relative);
+ CollectionNode* cn = static_cast<CollectionNode*>(n);
+ qdb_->mergeCollections(cn);
+ generateAnnotatedList(cn, marker, cn->members());
}
-#endif
}
void HtmlGenerator::generateSection(const NodeList& nl,
@@ -3304,8 +3466,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode,
par1 = QStringRef();
const Node* n = qdb_->findTypeNode(arg.toString(), relative);
html += QLatin1String("<span class=\"type\">");
- if (n && n->isQmlBasicType()) {
- if (relative && relative->isQmlType())
+ if (n && (n->isQmlBasicType() || n->isJsBasicType())) {
+ if (relative && (relative->isQmlType() || relative->isJsType()))
addLink(linkForNode(n,relative), arg, &html);
else
html += arg;
@@ -3575,9 +3737,9 @@ QString HtmlGenerator::fileBase(const Node *node) const
QString HtmlGenerator::fileName(const Node *node)
{
if (node->type() == Node::Document) {
- if (static_cast<const DocNode *>(node)->subType() == Node::ExternalPage)
+ if (static_cast<const DocumentNode *>(node)->subType() == Node::ExternalPage)
return node->name();
- if (static_cast<const DocNode *>(node)->subType() == Node::Image)
+ if (static_cast<const DocumentNode *>(node)->subType() == Node::Image)
return node->name();
}
return Generator::fileName(node);
@@ -3675,34 +3837,7 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
if (t.startsWith("mailto:"))
return t;
}
-
- QString ref;
-
- *node = qdb_->findNodeForAtom(atom, relative, ref);
- if (!(*node))
- return QString();
-
- QString url = (*node)->url();
- if (!url.isEmpty()) {
- if (ref.isEmpty())
- return url;
- int hashtag = url.lastIndexOf(QChar('#'));
- if (hashtag != -1)
- url.truncate(hashtag);
- return url + "#" + ref;
- }
- /*
- Given that *node is not null, we now cconstruct a link
- to the page that *node represents, and then if we found
- a target on that page, we connect the target to the link
- with '#'.
- */
- QString link = linkForNode(*node, relative);
- if (*node && (*node)->subType() == Node::Image)
- link = "images/used-in-examples/" + link;
- if (!ref.isEmpty())
- link += QLatin1Char('#') + ref;
- return link;
+ return getAutoLink(atom, relative, node);
}
/*!
@@ -3720,29 +3855,29 @@ QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Nod
QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const Node** node)
{
QString ref;
- QString link;
*node = qdb_->findNodeForAtom(atom, relative, ref);
- if (!(*node))
+ if (!(*node)) {
return QString();
+ }
- QString url = (*node)->url();
- if (!url.isEmpty()) {
- if (ref.isEmpty())
- return url;
- int hashtag = url.lastIndexOf(QChar('#'));
+ QString link = (*node)->url();
+ if (link.isEmpty()) {
+ link = linkForNode(*node, relative);
+ if ((*node)->subType() == Node::Image)
+ link = "images/used-in-examples/" + link;
+ if (!ref.isEmpty())
+ link += QLatin1Char('#') + ref;
+ }
+ else if (!ref.isEmpty()) {
+ int hashtag = link.lastIndexOf(QChar('#'));
if (hashtag != -1)
- url.truncate(hashtag);
- return url + "#" + ref;
+ link.truncate(hashtag);
+ link += "#" + ref;
}
-
- link = linkForNode(*node, relative);
- if (!ref.isEmpty())
- link += QLatin1Char('#') + ref;
return link;
}
-
/*!
Construct the link string for the \a node and return it.
The \a relative node is use to decide the link we are
@@ -3762,25 +3897,15 @@ QString HtmlGenerator::linkForNode(const Node *node, const Node *relative)
return QString();
QString fn = fileName(node);
- if (node && relative && node->parent() != relative) {
- if (node->parent()->isQmlType() && relative->isQmlType()) {
- if (node->parent()->isAbstract()) {
- /*
- This is a bit of a hack. What we discover with
- the three 'if' statements immediately above,
- is that node's parent is marked \qmlabstract
- but the link appears in a qdoc comment for a
- subclass of the node's parent. This means the
- link should refer to the file for the relative
- node, not the file for node.
- */
- fn = fileName(relative);
- }
- }
+ if (node && node->parent() &&
+ (node->parent()->isQmlType() || node->parent()->isJsType())
+ && node->parent()->isAbstract()) {
+ if (Generator::qmlTypeContext())
+ fn = fileName(Generator::qmlTypeContext());
}
QString link = fn;
- if (!node->isInnerNode() || node->type() == Node::QmlPropertyGroup) {
+ if (!node->isInnerNode() || node->isQmlPropertyGroup() || node->isJsPropertyGroup()) {
QString ref = refForNode(node);
if (relative && fn == fileName(relative) && ref == refForNode(relative))
return QString();
@@ -3797,7 +3922,12 @@ QString HtmlGenerator::linkForNode(const Node *node, const Node *relative)
if (node && relative && (node != relative)) {
if (useOutputSubdirs() && !node->isExternalPage() &&
node->outputSubdirectory() != relative->outputSubdirectory()) {
- link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/')));
+ if (link.startsWith(QString(node->outputSubdirectory() + QLatin1Char('/')))) {
+ link.prepend(QString("../"));
+ }
+ else {
+ link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/')));
+ }
}
}
return link;
@@ -3835,6 +3965,7 @@ void HtmlGenerator::generateDetailedMember(const Node *node,
generateMacRef(node, marker);
#endif
generateExtractionMark(node, MemberMark);
+ generateKeywordAnchors(node);
QString nodeRef = refForNode(node);
if (node->type() == Node::Enum
&& (enume = static_cast<const EnumNode *>(node))->flagsType()) {
@@ -3937,7 +4068,7 @@ const QPair<QString,QString> HtmlGenerator::anchorForNode(const Node *node)
anchorPair.first = Generator::fileName(node);
if (node->type() == Node::Document) {
- const DocNode *docNode = static_cast<const DocNode*>(node);
+ const DocumentNode *docNode = static_cast<const DocumentNode*>(node);
anchorPair.second = docNode->title();
}
@@ -4071,6 +4202,7 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
generateMacRef(node, marker);
#endif
generateExtractionMark(node, MemberMark);
+ generateKeywordAnchors(node);
out() << "<div class=\"qmlitem\">";
QString nodeRef = refForNode(node);
if (node->type() == Node::QmlPropertyGroup) {
@@ -4176,11 +4308,11 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
Output the "Inherits" line for the QML element,
if there should be one.
*/
-void HtmlGenerator::generateQmlInherits(QmlClassNode* qcn, CodeMarker* marker)
+void HtmlGenerator::generateQmlInherits(QmlTypeNode* qcn, CodeMarker* marker)
{
if (!qcn)
return;
- QmlClassNode* base = qcn->qmlBaseNode();
+ QmlTypeNode* base = qcn->qmlBaseNode();
while (base && base->isInternal()) {
base = base->qmlBaseNode();
}
@@ -4203,7 +4335,7 @@ void HtmlGenerator::generateQmlInherits(QmlClassNode* qcn, CodeMarker* marker)
If there is no class node, or if the class node status
is set to Node::Internal, do nothing.
*/
-void HtmlGenerator::generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marker)
+void HtmlGenerator::generateQmlInstantiates(QmlTypeNode* qcn, CodeMarker* marker)
{
ClassNode* cn = qcn->classNode();
if (cn && (cn->status() != Node::Internal)) {
@@ -4240,14 +4372,17 @@ void HtmlGenerator::generateQmlInstantiates(QmlClassNode* qcn, CodeMarker* marke
void HtmlGenerator::generateInstantiatedBy(ClassNode* cn, CodeMarker* marker)
{
if (cn && cn->status() != Node::Internal && cn->qmlElement() != 0) {
- const QmlClassNode* qcn = cn->qmlElement();
+ const QmlTypeNode* qcn = cn->qmlElement();
Text text;
text << Atom::ParaLeft;
text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn));
text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
text << Atom(Atom::String, cn->name());
text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
- text << " is instantiated by QML Type ";
+ if (qcn->isQmlType())
+ text << " is instantiated by QML Type ";
+ else
+ text << " is instantiated by Javascript Type ";
text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn));
text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
text << Atom(Atom::String, qcn->name());
@@ -4313,7 +4448,7 @@ void HtmlGenerator::generateManifestFiles()
for each manifest file to be generated. \a manifest is the
type of manifest file.
*/
-void HtmlGenerator::generateManifestFile(QString manifest, QString element)
+void HtmlGenerator::generateManifestFile(const QString &manifest, const QString &element)
{
ExampleNodeMap& exampleNodeMap = qdb_->exampleNodeMap();
if (exampleNodeMap.isEmpty())
@@ -4524,6 +4659,9 @@ void HtmlGenerator::generateManifestFile(QString manifest, QString element)
Reads metacontent - additional attributes and tags to apply
when generating manifest files, read from config. Takes the
configuration class \a config as a parameter.
+
+ The manifest metacontent map is cleared immediately after
+ the manifest files have been generated.
*/
void HtmlGenerator::readManifestMetaContent(const Config &config)
{
@@ -4743,9 +4881,9 @@ void HtmlGenerator::writeDitaRefs(const DitaRefList& ditarefs)
xmlWriter().writeStartElement("topicref");
xmlWriter().writeAttribute("navtitle",t->navtitle());
if (t->href().isEmpty()) {
- const DocNode* fn = qdb_->findDocNodeByTitle(t->navtitle());
- if (fn)
- xmlWriter().writeAttribute("href",fileName(fn));
+ const DocumentNode* dn = qdb_->findDocumentNodeByTitle(t->navtitle());
+ if (dn)
+ xmlWriter().writeAttribute("href",fileName(dn));
}
else
xmlWriter().writeAttribute("href",t->href());