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.cpp4894
1 files changed, 0 insertions, 4894 deletions
diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp
deleted file mode 100644
index 4aed6085cd..0000000000
--- a/src/tools/qdoc/htmlgenerator.cpp
+++ /dev/null
@@ -1,4894 +0,0 @@
-/****************************************************************************
-**
-** 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.
-**
-** $QT_BEGIN_LICENSE:LGPL21$
-** Commercial License Usage
-** 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 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
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** 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$
-**
-****************************************************************************/
-
-/*
- htmlgenerator.cpp
-*/
-
-#include "codemarker.h"
-#include "codeparser.h"
-#include "helpprojectwriter.h"
-#include "htmlgenerator.h"
-#include "node.h"
-#include "qdocdatabase.h"
-#include "separator.h"
-#include "tree.h"
-#include <ctype.h>
-#include <qdebug.h>
-#include <qlist.h>
-#include <qiterator.h>
-#include <qtextcodec.h>
-#include <quuid.h>
-
-QT_BEGIN_NAMESPACE
-
-#define COMMAND_VERSION Doc::alias("version")
-int HtmlGenerator::id = 0;
-bool HtmlGenerator::debugging_on = false;
-
-QString HtmlGenerator::divNavTop;
-
-static bool showBrokenLinks = false;
-
-static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)");
-static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)(</@func>)");
-static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)");
-static QRegExp spanTag("</@(?:comment|preprocessor|string|char|number|op|type|name|keyword)>");
-static QRegExp unknownTag("</?@[^>]*>");
-
-static void addLink(const QString &linkTarget,
- const QStringRef &nestedStuff,
- QString *res)
-{
- if (!linkTarget.isEmpty()) {
- *res += "<a href=\"";
- *res += linkTarget;
- *res += "\">";
- *res += nestedStuff;
- *res += "</a>";
- }
- else {
- *res += nestedStuff;
- }
-}
-
-/*!
- Constructs the HTML output generator.
- */
-HtmlGenerator::HtmlGenerator()
- : codeIndent(0),
- helpProjectWriter(0),
- inObsoleteLink(false),
- funcLeftParen("\\S(\\()"),
- obsoleteLinks(false)
-{
-}
-
-/*!
- Destroys the HTML output generator. Deletes the singleton
- instance of HelpProjectWriter.
- */
-HtmlGenerator::~HtmlGenerator()
-{
- if (helpProjectWriter) {
- delete helpProjectWriter;
- helpProjectWriter = 0;
- }
-}
-
-/*!
- Initializes the HTML output generator's data structures
- from the configuration class \a config.
- */
-void HtmlGenerator::initializeGenerator(const Config &config)
-{
- static const struct {
- const char *key;
- const char *left;
- const char *right;
- } defaults[] = {
- { ATOM_FORMATTING_BOLD, "<b>", "</b>" },
- { ATOM_FORMATTING_INDEX, "<!--", "-->" },
- { ATOM_FORMATTING_ITALIC, "<i>", "</i>" },
- { ATOM_FORMATTING_PARAMETER, "<i>", "</i>" },
- { ATOM_FORMATTING_SUBSCRIPT, "<sub>", "</sub>" },
- { ATOM_FORMATTING_SUPERSCRIPT, "<sup>", "</sup>" },
- { ATOM_FORMATTING_TELETYPE, "<code>", "</code>" }, // <tt> tag is not supported in HTML5
- { ATOM_FORMATTING_UICONTROL, "<b>", "</b>" },
- { ATOM_FORMATTING_UNDERLINE, "<u>", "</u>" },
- { 0, 0, 0 }
- };
-
- 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);
- formattingRightMap().insert(defaults[i].key, defaults[i].right);
- i++;
- }
-
- style = config.getString(HtmlGenerator::format() +
- Config::dot +
- CONFIG_STYLE);
- endHeader = config.getString(HtmlGenerator::format() +
- Config::dot +
- CONFIG_ENDHEADER);
- postHeader = config.getString(HtmlGenerator::format() +
- Config::dot +
- HTMLGENERATOR_POSTHEADER);
- postPostHeader = config.getString(HtmlGenerator::format() +
- Config::dot +
- HTMLGENERATOR_POSTPOSTHEADER);
- prologue = config.getString(HtmlGenerator::format() +
- Config::dot +
- HTMLGENERATOR_PROLOGUE);
-
- footer = config.getString(HtmlGenerator::format() +
- Config::dot +
- HTMLGENERATOR_FOOTER);
- address = config.getString(HtmlGenerator::format() +
- Config::dot +
- HTMLGENERATOR_ADDRESS);
- pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() +
- Config::dot +
- HTMLGENERATOR_GENERATEMACREFS);
- noNavigationBar = config.getBool(HtmlGenerator::format() +
- Config::dot +
- HTMLGENERATOR_NONAVIGATIONBAR);
- tocDepth = config.getInt(HtmlGenerator::format() +
- Config::dot +
- HTMLGENERATOR_TOCDEPTH);
-
- project = config.getString(CONFIG_PROJECT);
-
- projectDescription = config.getString(CONFIG_DESCRIPTION);
- if (projectDescription.isEmpty() && !project.isEmpty())
- projectDescription = project + " Reference Documentation";
-
- projectUrl = config.getString(CONFIG_URL);
- tagFile_ = config.getString(CONFIG_TAGFILE);
-
-#ifndef QT_NO_TEXTCODEC
- outputEncoding = config.getString(CONFIG_OUTPUTENCODING);
- if (outputEncoding.isEmpty())
- outputEncoding = QLatin1String("UTF-8");
- outputCodec = QTextCodec::codecForName(outputEncoding.toLocal8Bit());
-#endif
-
- naturalLanguage = config.getString(CONFIG_NATURALLANGUAGE);
- if (naturalLanguage.isEmpty())
- naturalLanguage = QLatin1String("en");
-
- QSet<QString> editionNames = config.subVars(CONFIG_EDITION);
- QSet<QString>::ConstIterator edition = editionNames.constBegin();
- while (edition != editionNames.constEnd()) {
- QString editionName = *edition;
- QStringList editionModules = config.getStringList(CONFIG_EDITION +
- Config::dot +
- editionName +
- Config::dot +
- "modules");
- QStringList editionGroups = config.getStringList(CONFIG_EDITION +
- Config::dot +
- editionName +
- Config::dot +
- "groups");
-
- if (!editionModules.isEmpty())
- editionModuleMap[editionName] = editionModules;
- if (!editionGroups.isEmpty())
- editionGroupMap[editionName] = editionGroups;
-
- ++edition;
- }
-
- // The following line was changed to fix QTBUG-27798
- //codeIndent = config.getInt(CONFIG_CODEINDENT);
-
- /*
- 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);
- headerStyles = config.getString(HtmlGenerator::format() + Config::dot + CONFIG_HEADERSTYLES);
-
- QString prefix = CONFIG_QHP + Config::dot + project + Config::dot;
- manifestDir = "qthelp://" + config.getString(prefix + "namespace");
- manifestDir += QLatin1Char('/') + config.getString(prefix + "virtualFolder") + QLatin1Char('/');
- readManifestMetaContent(config);
- examplesPath = config.getString(CONFIG_EXAMPLESINSTALLPATH);
- if (!examplesPath.isEmpty())
- examplesPath += QLatin1Char('/');
-
- //retrieve the config for the navigation bar
- homepage = config.getString(CONFIG_NAVIGATION
- + Config::dot
- + CONFIG_HOMEPAGE);
-
- landingpage = config.getString(CONFIG_NAVIGATION
- + Config::dot
- + CONFIG_LANDINGPAGE);
-
- cppclassespage = config.getString(CONFIG_NAVIGATION
- + Config::dot
- + CONFIG_CPPCLASSESPAGE);
-
- qmltypespage = config.getString(CONFIG_NAVIGATION
- + Config::dot
- + CONFIG_QMLTYPESPAGE);
-
- buildversion = config.getString(CONFIG_BUILDVERSION);
-}
-
-/*!
- Gracefully terminates the HTML output generator.
- */
-void HtmlGenerator::terminateGenerator()
-{
- Generator::terminateGenerator();
-}
-
-QString HtmlGenerator::format()
-{
- return "HTML";
-}
-
-/*!
- 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>";
- }
- }
-}
-
-/*!
- If qdoc is in the \c {-prepare} phase, traverse the primary
- tree to generate the index file for the current module.
-
- If qdoc is in the \c {-generate} phase, traverse the primary
- tree to generate all the HTML documentation for the current
- module. Then generate the help file and the tag file.
- */
-void HtmlGenerator::generateDocs()
-{
- Node* qflags = qdb_->findClassNode(QStringList("QFlags"));
- if (qflags)
- qflagsHref_ = linkForNode(qflags,0);
- if (!preparing())
- Generator::generateDocs();
- if (Generator::generating() && Generator::writeQaPages())
- generateQAPage();
-
- if (!generating()) {
- QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-'));
- qdb_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index",
- projectUrl,
- projectDescription,
- this,
- true);
- }
-
- if (!preparing()) {
- helpProjectWriter->generate();
- generateManifestFiles();
- /*
- Generate the XML tag file, if it was requested.
- */
- qdb_->generateTagFile(tagFile_, this);
- }
-}
-
-/*!
- 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)
-{
- int skipAhead = 0;
- static bool in_para = false;
-
- switch (atom->type()) {
- case Atom::AbstractLeft:
- if (relative)
- relative->doc().location().warning(tr("\abstract is not implemented."));
- else
- Location::information(tr("\abstract is not implemented."));
- break;
- case Atom::AbstractRight:
- break;
- case Atom::AutoLink:
- case Atom::NavAutoLink:
- if (!inLink_ && !inContents_ && !inSectionHeading_) {
- const Node *node = 0;
- QString link = getAutoLink(atom, relative, &node);
- if (link.isEmpty()) {
- if (autolinkErrors())
- relative->doc().location().warning(tr("Can't autolink to '%1'").arg(atom->string()));
- }
- else if (node && node->status() == Node::Obsolete) {
- if ((relative->parent() != node) && !relative->isObsolete())
- link.clear();
- }
- if (link.isEmpty()) {
- out() << protectEnc(atom->string());
- }
- else {
- 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();
- }
- }
- else {
- out() << protectEnc(atom->string());
- }
- break;
- case Atom::BaseName:
- break;
- case Atom::BriefLeft:
- // Do not output the brief for QML nodes, doc nodes or collections
- // (groups, modules, qml module nodes)
- if (relative->isQmlType() ||
- relative->isDocumentNode() ||
- relative->isCollectionNode() ||
- relative->isJsType()) {
- skipAhead = skipAtoms(atom, Atom::BriefRight);
- break;
- }
-
- out() << "<p>";
- if (relative->type() == Node::Property ||
- relative->type() == Node::Variable) {
- QString str;
- 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();
- }
- str[0] = str[0].toLower();
- if (str.endsWith(QLatin1Char('.')))
- str.truncate(str.length() - 1);
- out() << "This ";
- if (relative->type() == Node::Property)
- out() << "property";
- else
- out() << "variable";
- QStringList words = str.split(QLatin1Char(' '));
- if (!(words.first() == "contains" || words.first() == "specifies"
- || words.first() == "describes" || words.first() == "defines"
- || words.first() == "holds" || words.first() == "determines"))
- out() << " holds ";
- else
- out() << ' ';
- out() << str << '.';
- }
- break;
- case Atom::BriefRight:
- if (!relative->isDocumentNode())
- out() << "</p>\n";
- break;
- case Atom::C:
- // This may at one time have been used to mark up C++ code but it is
- // now widely used to write teletype text. As a result, text marked
- // with the \c command is not passed to a code marker.
- out() << formattingLeftMap()[ATOM_FORMATTING_TELETYPE];
- if (inLink_) {
- out() << protectEnc(plainCode(atom->string()));
- }
- else {
- out() << protectEnc(plainCode(atom->string()));
- }
- out() << formattingRightMap()[ATOM_FORMATTING_TELETYPE];
- break;
- case Atom::CaptionLeft:
- out() << "<p class=\"figCaption\">";
- in_para = true;
- break;
- case Atom::CaptionRight:
- endLink();
- if (in_para) {
- out() << "</p>\n";
- in_para = false;
- }
- break;
- case Atom::Code:
- out() << "<pre class=\"cpp\">"
- << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),relative))
- << "</pre>\n";
- break;
- case Atom::Qml:
- out() << "<pre class=\"qml\">"
- << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),relative))
- << "</pre>\n";
- break;
- case Atom::JavaScript:
- out() << "<pre class=\"js\">"
- << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),relative))
- << "</pre>\n";
- break;
- case Atom::CodeNew:
- out() << "<p>you can rewrite it as</p>\n"
- << "<pre class=\"cpp\">"
- << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),relative))
- << "</pre>\n";
- break;
- case Atom::CodeOld:
- out() << "<p>For example, if you have code like</p>\n";
- // fallthrough
- case Atom::CodeBad:
- out() << "<pre class=\"cpp\">"
- << trimmedTrailing(protectEnc(plainCode(indent(codeIndent,atom->string()))))
- << "</pre>\n";
- break;
- case Atom::DivLeft:
- out() << "<div";
- if (!atom->string().isEmpty())
- out() << ' ' << atom->string();
- out() << '>';
- break;
- case Atom::DivRight:
- out() << "</div>";
- break;
- case Atom::FootnoteLeft:
- // ### For now
- if (in_para) {
- out() << "</p>\n";
- in_para = false;
- }
- out() << "<!-- ";
- break;
- case Atom::FootnoteRight:
- // ### For now
- out() << "-->";
- break;
- case Atom::FormatElse:
- case Atom::FormatEndif:
- case Atom::FormatIf:
- break;
- case Atom::FormattingLeft:
- if (atom->string().startsWith("span ")) {
- out() << '<' + atom->string() << '>';
- }
- else
- out() << formattingLeftMap()[atom->string()];
- if (atom->string() == ATOM_FORMATTING_PARAMETER) {
- if (atom->next() != 0 && atom->next()->type() == Atom::String) {
- QRegExp subscriptRegExp("([a-z]+)_([0-9n])");
- if (subscriptRegExp.exactMatch(atom->next()->string())) {
- out() << subscriptRegExp.cap(1) << "<sub>"
- << subscriptRegExp.cap(2) << "</sub>";
- skipAhead = 1;
- }
- }
- }
- break;
- case Atom::FormattingRight:
- if (atom->string() == ATOM_FORMATTING_LINK) {
- endLink();
- }
- else if (atom->string().startsWith("span ")) {
- out() << "</span>";
- }
- else {
- out() << formattingRightMap()[atom->string()];
- }
- break;
- case Atom::AnnotatedList:
- {
- CollectionNode* cn = qdb_->getCollection(atom->string(), Node::DOC);
- if (cn)
- generateList(cn, marker, atom->string());
- }
- break;
- case Atom::GeneratedList:
- if (atom->string() == "annotatedclasses") {
- generateAnnotatedList(relative, marker, qdb_->getCppClasses());
- }
- else if (atom->string() == "classes") {
- generateCompactList(Generic, relative, qdb_->getCppClasses(), true, QStringLiteral(""));
- }
- else if (atom->string().contains("classes ")) {
- QString rootName = atom->string().mid(atom->string().indexOf("classes") + 7).trimmed();
- generateCompactList(Generic, relative, qdb_->getCppClasses(), true, rootName);
- }
- else if (atom->string() == "qmlbasictypes") {
- generateCompactList(Generic, relative, qdb_->getQmlBasicTypes(), true, QStringLiteral(""));
- }
- else if (atom->string() == "qmltypes") {
- generateCompactList(Generic, relative, qdb_->getQmlTypes(), true, QStringLiteral(""));
- }
- else if (atom->string().contains("classesbymodule")) {
- QString physicalModuleName = atom->string().mid(atom->string().indexOf("classesbymodule") + 15).trimmed();
- QDocDatabase* qdb = QDocDatabase::qdocDB();
- CollectionNode* cn = qdb->findModule(physicalModuleName);
- if (cn) {
- NodeMap m;
- cn->getMemberClasses(m);
- if (!m.isEmpty()) {
- generateAnnotatedList(relative, marker, m);
- }
- }
- }
- else if (atom->string() == "classhierarchy") {
- generateClassHierarchy(relative, qdb_->getCppClasses());
- }
- else if (atom->string() == "obsoleteclasses") {
- generateCompactList(Generic, relative, qdb_->getObsoleteClasses(), false, QStringLiteral("Q"));
- }
- else if (atom->string() == "obsoleteqmltypes") {
- generateCompactList(Generic, relative, qdb_->getObsoleteQmlTypes(), false, QStringLiteral(""));
- }
- else if (atom->string() == "obsoletecppmembers") {
- generateCompactList(Obsolete, relative, qdb_->getClassesWithObsoleteMembers(), false, QStringLiteral("Q"));
- }
- else if (atom->string() == "obsoleteqmlmembers") {
- generateCompactList(Obsolete, relative, qdb_->getQmlTypesWithObsoleteMembers(), false, QStringLiteral(""));
- }
- else if (atom->string() == "functionindex") {
- generateFunctionIndex(relative);
- }
- else if (atom->string() == "legalese") {
- generateLegaleseList(relative, marker);
- }
- else if (atom->string() == "overviews") {
- generateList(relative, marker, "overviews");
- }
- else if (atom->string() == "cpp-modules") {
- generateList(relative, marker, "cpp-modules");
- }
- else if (atom->string() == "qml-modules") {
- generateList(relative, marker, "qml-modules");
- }
- else if (atom->string() == "namespaces") {
- generateAnnotatedList(relative, marker, qdb_->getNamespaces());
- }
- else if (atom->string() == "related") {
- generateList(relative, marker, "related");
- }
-#if 0
- /*
- This is not used in Qt5, as of 10/02/2014
- Remove permanently if it is not missed.
- */
- else if (atom->string() == "relatedinline") {
- const 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
- // regular class or page definition.
- QList<const Node *> list;
- foreach (const Node *node, dn->members())
- list.prepend(node);
- foreach (const Node *node, list)
- generateBody(node, marker);
- }
- }
-#endif
- break;
- case Atom::SinceList:
- {
- const NodeMultiMap& nsmap = qdb_->getSinceMap(atom->string());
- const NodeMap& ncmap = qdb_->getClassMap(atom->string());
- const NodeMap& nqcmap = qdb_->getQmlTypeMap(atom->string());
-
- if (!nsmap.isEmpty()) {
- QList<Section> sections;
- QList<Section>::ConstIterator s;
-
- for (int i=0; i<LastSinceType; ++i)
- sections.append(Section(sinceTitle(i),QString(),QString(),QString()));
-
- NodeMultiMap::const_iterator n = nsmap.constBegin();
- while (n != nsmap.constEnd()) {
- Node* node = n.value();
- switch (node->type()) {
- case Node::QmlType:
- sections[QmlClass].appendMember(node);
- break;
- case Node::Namespace:
- sections[Namespace].appendMember(node);
- break;
- case Node::Class:
- sections[Class].appendMember(node);
- break;
- case Node::Enum:
- sections[Enum].appendMember(node);
- break;
- case Node::Typedef:
- sections[Typedef].appendMember(node);
- break;
- case Node::Function: {
- const FunctionNode* fn = static_cast<const FunctionNode*>(node);
- if (fn->isMacro())
- sections[Macro].appendMember(node);
- else {
- Node* p = fn->parent();
- if (p) {
- if (p->type() == Node::Class)
- sections[MemberFunction].appendMember(node);
- else if (p->type() == Node::Namespace) {
- if (p->name().isEmpty())
- sections[GlobalFunction].appendMember(node);
- else
- sections[NamespaceFunction].appendMember(node);
- }
- else
- sections[GlobalFunction].appendMember(node);
- }
- else
- sections[GlobalFunction].appendMember(node);
- }
- break;
- }
- case Node::Property:
- sections[Property].appendMember(node);
- break;
- case Node::Variable:
- sections[Variable].appendMember(node);
- break;
- case Node::QmlProperty:
- sections[QmlProperty].appendMember(node);
- break;
- case Node::QmlSignal:
- sections[QmlSignal].appendMember(node);
- break;
- case Node::QmlSignalHandler:
- sections[QmlSignalHandler].appendMember(node);
- break;
- case Node::QmlMethod:
- sections[QmlMethod].appendMember(node);
- break;
- default:
- break;
- }
- ++n;
- }
-
- out() << "<ul>\n";
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- if (!(*s).members.isEmpty()) {
-
- out() << "<li>"
- << "<a href=\"#"
- << Doc::canonicalTitle((*s).name)
- << "\">"
- << (*s).name
- << "</a></li>\n";
- }
- ++s;
- }
- out() << "</ul>\n";
-
- int idx = 0;
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- if (!(*s).members.isEmpty()) {
- out() << "<a name=\""
- << Doc::canonicalTitle((*s).name)
- << "\"></a>\n";
- out() << "<h3>" << protectEnc((*s).name) << "</h3>\n";
- if (idx == Class)
- generateCompactList(Generic, 0, ncmap, false, QStringLiteral("Q"));
- else if (idx == QmlClass)
- generateCompactList(Generic, 0, nqcmap, false, QStringLiteral(""));
- else if (idx == MemberFunction) {
- ParentMaps parentmaps;
- ParentMaps::iterator pmap;
- NodeList::const_iterator i = s->members.constBegin();
- while (i != s->members.constEnd()) {
- Node* p = (*i)->parent();
- pmap = parentmaps.find(p);
- if (pmap == parentmaps.end())
- pmap = parentmaps.insert(p,NodeMultiMap());
- pmap->insert((*i)->name(),(*i));
- ++i;
- }
- pmap = parentmaps.begin();
- while (pmap != parentmaps.end()) {
- NodeList nlist = pmap->values();
- out() << "<p>Class ";
-
- out() << "<a href=\""
- << linkForNode(pmap.key(), 0)
- << "\">";
- QStringList pieces = pmap.key()->fullName().split("::");
- out() << protectEnc(pieces.last());
- out() << "</a>" << ":</p>\n";
-
- generateSection(nlist, 0, marker, CodeMarker::Summary);
- out() << "<br/>";
- ++pmap;
- }
- }
- else
- generateSection(s->members, 0, marker, CodeMarker::Summary);
- }
- ++idx;
- ++s;
- }
- }
- }
- break;
- case Atom::BR:
- out() << "<br />\n";
- break;
- case Atom::HR:
- out() << "<hr />\n";
- break;
- case Atom::Image:
- case Atom::InlineImage:
- {
- QString fileName = imageFileName(relative, atom->string());
- QString text;
- if (atom->next() != 0)
- text = atom->next()->string();
- if (atom->type() == Atom::Image)
- out() << "<p class=\"centerAlign\">";
- if (fileName.isEmpty()) {
- relative->location().warning(tr("Missing image: %1").arg(protectEnc(atom->string())));
- out() << "<font color=\"red\">[Missing image "
- << protectEnc(atom->string()) << "]</font>";
- }
- else {
- QString prefix;
- out() << "<img src=\"" << protectEnc(prefix + fileName) << '"';
- if (!text.isEmpty())
- out() << " alt=\"" << protectEnc(text) << '"';
- else
- out() << " alt=\"\"";
- out() << " />";
- helpProjectWriter->addExtraFile(fileName);
- if (relative->isExample()) {
- const ExampleNode* cen = static_cast<const ExampleNode*>(relative);
- if (cen->imageFileName().isEmpty()) {
- ExampleNode* en = const_cast<ExampleNode*>(cen);
- en->setImageFileName(fileName);
- }
- }
- }
- if (atom->type() == Atom::Image)
- out() << "</p>";
- }
- break;
- case Atom::ImageText:
- break;
- case Atom::ImportantLeft:
- out() << "<p>";
- out() << formattingLeftMap()[ATOM_FORMATTING_BOLD];
- out() << "Important: ";
- out() << formattingRightMap()[ATOM_FORMATTING_BOLD];
- break;
- case Atom::ImportantRight:
- out() << "</p>";
- break;
- case Atom::NoteLeft:
- out() << "<p>";
- out() << formattingLeftMap()[ATOM_FORMATTING_BOLD];
- out() << "Note: ";
- out() << formattingRightMap()[ATOM_FORMATTING_BOLD];
- break;
- case Atom::NoteRight:
- out() << "</p>";
- break;
- case Atom::LegaleseLeft:
- out() << "<div class=\"LegaleseLeft\">";
- break;
- case Atom::LegaleseRight:
- out() << "</div>";
- break;
- case Atom::LineBreak:
- 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()) {
- inObsoleteLink = true;
- if (obsoleteLinks) {
- relative->doc().location().warning(tr("Link to obsolete item '%1' in %2")
- .arg(atom->string())
- .arg(relative->plainFullName()));
- }
- }
- }
- }
- beginLink(link, node, relative);
- skipAhead = 1;
- }
- break;
- case Atom::LinkNode:
- {
- const Node *node = CodeMarker::nodeForString(atom->string());
- beginLink(linkForNode(node, relative), node, relative);
- skipAhead = 1;
- }
- break;
- case Atom::ListLeft:
- if (in_para) {
- out() << "</p>\n";
- in_para = false;
- }
- if (atom->string() == ATOM_LIST_BULLET) {
- out() << "<ul>\n";
- }
- else if (atom->string() == ATOM_LIST_TAG) {
- out() << "<dl>\n";
- }
- else if (atom->string() == ATOM_LIST_VALUE) {
- out() << "<div class=\"table\"><table class=\"valuelist\">";
- threeColumnEnumValueTable_ = isThreeColumnEnumValueTable(atom);
- if (threeColumnEnumValueTable_) {
- if (++numTableRows_ % 2 == 1)
- out() << "<tr valign=\"top\" class=\"odd\">";
- else
- out() << "<tr valign=\"top\" class=\"even\">";
-
- out() << "<th class=\"tblConst\">Constant</th>";
-
- // If not in \enum topic, skip the value column
- if (relative->type() == Node::Enum)
- out() << "<th class=\"tblval\">Value</th>";
-
- out() << "<th class=\"tbldscr\">Description</th></tr>\n";
- }
- else {
- out() << "<tr><th class=\"tblConst\">Constant</th><th class=\"tblVal\">Value</th></tr>\n";
- }
- }
- else {
- out() << "<ol class=";
- if (atom->string() == ATOM_LIST_UPPERALPHA) {
- out() << "\"A\"";
- } /* why type? changed to */
- else if (atom->string() == ATOM_LIST_LOWERALPHA) {
- out() << "\"a\"";
- }
- else if (atom->string() == ATOM_LIST_UPPERROMAN) {
- out() << "\"I\"";
- }
- else if (atom->string() == ATOM_LIST_LOWERROMAN) {
- out() << "\"i\"";
- }
- else { // (atom->string() == ATOM_LIST_NUMERIC)
- out() << "\"1\"";
- }
- if (atom->next() != 0 && atom->next()->string().toInt() != 1)
- out() << " start=\"" << atom->next()->string() << '"';
- out() << ">\n";
- }
- break;
- case Atom::ListItemNumber:
- break;
- case Atom::ListTagLeft:
- if (atom->string() == ATOM_LIST_TAG) {
- out() << "<dt>";
- }
- else { // (atom->string() == ATOM_LIST_VALUE)
- // ### Trenton
-
- QString t= protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(),relative)));
- out() << "<tr><td class=\"topAlign\"><code>" << t << "</code>";
-
- if (relative->type() == Node::Enum) {
- out() << "</td><td class=\"topAlign\">";
- const EnumNode *enume = static_cast<const EnumNode *>(relative);
- QString itemValue = enume->itemValue(atom->next()->string());
-
- if (itemValue.isEmpty())
- out() << '?';
- else
- out() << "<code>" << protectEnc(itemValue) << "</code>";
- }
- skipAhead = 1;
- }
- break;
- case Atom::ListTagRight:
- if (atom->string() == ATOM_LIST_TAG)
- out() << "</dt>\n";
- break;
- case Atom::ListItemLeft:
- if (atom->string() == ATOM_LIST_TAG) {
- out() << "<dd>";
- }
- else if (atom->string() == ATOM_LIST_VALUE) {
- if (threeColumnEnumValueTable_) {
- out() << "</td><td class=\"topAlign\">";
- if (matchAhead(atom, Atom::ListItemRight))
- out() << "&nbsp;";
- }
- }
- else {
- out() << "<li>";
- }
- if (matchAhead(atom, Atom::ParaLeft))
- skipAhead = 1;
- break;
- case Atom::ListItemRight:
- if (atom->string() == ATOM_LIST_TAG) {
- out() << "</dd>\n";
- }
- else if (atom->string() == ATOM_LIST_VALUE) {
- out() << "</td></tr>\n";
- }
- else {
- out() << "</li>\n";
- }
- break;
- case Atom::ListRight:
- if (atom->string() == ATOM_LIST_BULLET) {
- out() << "</ul>\n";
- }
- else if (atom->string() == ATOM_LIST_TAG) {
- out() << "</dl>\n";
- }
- else if (atom->string() == ATOM_LIST_VALUE) {
- out() << "</table></div>\n";
- }
- else {
- out() << "</ol>\n";
- }
- break;
- case Atom::Nop:
- break;
- case Atom::ParaLeft:
- out() << "<p>";
- in_para = true;
- break;
- case Atom::ParaRight:
- endLink();
- if (in_para) {
- out() << "</p>\n";
- in_para = false;
- }
- //if (!matchAhead(atom, Atom::ListItemRight) && !matchAhead(atom, Atom::TableItemRight))
- // out() << "</p>\n";
- break;
- case Atom::QuotationLeft:
- out() << "<blockquote>";
- break;
- case Atom::QuotationRight:
- out() << "</blockquote>\n";
- break;
- case Atom::RawString:
- out() << atom->string();
- break;
- case Atom::SectionLeft:
- out() << "<a name=\"" << Doc::canonicalTitle(Text::sectionHeading(atom).toString())
- << "\"></a>" << divNavTop << '\n';
- break;
- case Atom::SectionRight:
- break;
- case Atom::SectionHeadingLeft: {
- int unit = atom->string().toInt() + hOffset(relative);
- out() << "<h" + QString::number(unit) + QLatin1Char(' ');
- if (unit < 3) {
- out() << "id=\"" << Doc::canonicalTitle(Text::sectionHeading(atom).toString()) << "\"";
- }
- out() << ">";
- inSectionHeading_ = true;
- break;
- }
- case Atom::SectionHeadingRight:
- out() << "</h" + QString::number(atom->string().toInt() + hOffset(relative)) + ">\n";
- inSectionHeading_ = false;
- break;
- case Atom::SidebarLeft:
- break;
- case Atom::SidebarRight:
- break;
- case Atom::String:
- if (inLink_ && !inContents_ && !inSectionHeading_) {
- generateLink(atom, marker);
- }
- else {
- out() << protectEnc(atom->string());
- }
- break;
- case Atom::TableLeft:
- {
- QString p1, p2;
- QString attr = "generic";
- QString width;
- if (in_para) {
- out() << "</p>\n";
- in_para = false;
- }
- if (atom->count() > 0) {
- p1 = atom->string(0);
- if (atom->count() > 1)
- p2 = atom->string(1);
- }
- if (!p1.isEmpty()) {
- if (p1 == "borderless")
- attr = p1;
- else if (p1.contains("%"))
- width = p1;
- }
- if (!p2.isEmpty()) {
- if (p2 == "borderless")
- attr = p2;
- else if (p2.contains("%"))
- width = p2;
- }
- out() << "<div class=\"table\"><table class=\"" << attr << "\"";
- if (!width.isEmpty())
- out() << " width=\"" << width << "\"";
- out() << ">\n ";
- numTableRows_ = 0;
- }
- break;
- case Atom::TableRight:
- out() << "</table></div>\n";
- break;
- case Atom::TableHeaderLeft:
- out() << "<thead><tr class=\"qt-style\">";
- inTableHeader_ = true;
- break;
- case Atom::TableHeaderRight:
- out() << "</tr>";
- if (matchAhead(atom, Atom::TableHeaderLeft)) {
- skipAhead = 1;
- out() << "\n<tr class=\"qt-style\">";
- }
- else {
- out() << "</thead>\n";
- inTableHeader_ = false;
- }
- break;
- case Atom::TableRowLeft:
- if (!atom->string().isEmpty())
- out() << "<tr " << atom->string() << '>';
- else if (++numTableRows_ % 2 == 1)
- out() << "<tr valign=\"top\" class=\"odd\">";
- else
- out() << "<tr valign=\"top\" class=\"even\">";
- break;
- case Atom::TableRowRight:
- out() << "</tr>\n";
- break;
- case Atom::TableItemLeft:
- {
- if (inTableHeader_)
- out() << "<th ";
- else
- out() << "<td ";
-
- for (int i=0; i<atom->count(); ++i) {
- if (i > 0)
- out() << ' ';
- QString p = atom->string(i);
- if (p.contains('=')) {
- out() << p;
- }
- else {
- QStringList spans = p.split(",");
- if (spans.size() == 2) {
- if (spans.at(0) != "1")
- out() << " colspan=\"" << spans.at(0) << '"';
- if (spans.at(1) != "1")
- out() << " rowspan=\"" << spans.at(1) << '"';
- }
- }
- }
- if (inTableHeader_)
- out() << '>';
- else {
- out() << '>';
- //out() << "><p>";
- }
- if (matchAhead(atom, Atom::ParaLeft))
- skipAhead = 1;
- }
- break;
- case Atom::TableItemRight:
- if (inTableHeader_)
- out() << "</th>";
- else {
- out() << "</td>";
- //out() << "</p></td>";
- }
- if (matchAhead(atom, Atom::ParaLeft))
- skipAhead = 1;
- break;
- case Atom::TableOfContents:
- break;
- case Atom::Keyword:
- break;
- case Atom::Target:
- out() << "<a name=\"" << Doc::canonicalTitle(atom->string()) << "\"></a>";
- break;
- case Atom::UnhandledFormat:
- out() << "<b class=\"redFont\">&lt;Missing HTML&gt;</b>";
- break;
- case Atom::UnknownCommand:
- out() << "<b class=\"redFont\"><code>\\" << protectEnc(atom->string())
- << "</code></b>";
- break;
- case Atom::QmlText:
- case Atom::EndQmlText:
- // don't do anything with these. They are just tags.
- break;
- default:
- unknownAtom(atom);
- }
- return skipAhead;
-}
-
-/*!
- Generate a reference page for a C++ class or a C++ namespace.
- */
-void HtmlGenerator::generateClassLikeNode(InnerNode* inner, CodeMarker* marker)
-{
- QList<Section> sections;
- QList<Section>::ConstIterator s;
-
- QString title;
- QString rawTitle;
- QString fullTitle;
- if (inner->type() == Node::Namespace) {
- rawTitle = inner->plainName();
- fullTitle = inner->plainFullName();
- title = rawTitle + " Namespace";
- }
- else if (inner->type() == Node::Class) {
- rawTitle = inner->plainName();
- fullTitle = inner->plainFullName();
- title = rawTitle + " Class";
- }
-
- Text subtitleText;
- if (rawTitle != fullTitle)
- 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);
- generateStatus(inner, marker);
- generateThreadSafeness(inner, marker);
-
- out() << "<ul>\n";
-
- QString membersLink = generateListOfAllMemberFile(inner, marker);
- if (!membersLink.isEmpty())
- out() << "<li><a href=\"" << membersLink << "\">"
- << "List of all members, including inherited members</a></li>\n";
-
- QString obsoleteLink = generateLowStatusMemberFile(inner,
- marker,
- CodeMarker::Obsolete);
- if (!obsoleteLink.isEmpty()) {
- out() << "<li><a href=\"" << obsoleteLink << "\">"
- << "Obsolete members</a></li>\n";
- }
-
- QString compatLink = generateLowStatusMemberFile(inner,
- marker,
- CodeMarker::Compat);
- if (!compatLink.isEmpty())
- out() << "<li><a href=\"" << compatLink << "\">"
- << "Compatibility members</a></li>\n";
-
- out() << "</ul>\n";
-
- bool needOtherSection = false;
-
- /*
- sections is built above for the call to generateTableOfContents().
- */
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- if (s->members.isEmpty() && s->reimpMembers.isEmpty()) {
- if (!s->inherited.isEmpty())
- needOtherSection = true;
- }
- else {
- if (!s->members.isEmpty()) {
- // out() << "<hr />\n";
- QString ref = registerRef((*s).name.toLower());
- out() << "<a name=\"" << ref << "\"></a>" << divNavTop << "\n";
- out() << "<h2 id=\"" << ref << "\">" << protectEnc((*s).name) << "</h2>\n";
- generateSection(s->members, inner, marker, CodeMarker::Summary);
- }
- if (!s->reimpMembers.isEmpty()) {
- QString name = QString("Reimplemented ") + (*s).name;
- QString ref = registerRef(name.toLower());
- // out() << "<hr />\n";
- out() << "<a name=\"" << ref << "\"></a>" << divNavTop << "\n";
- out() << "<h2 id=\"" << ref << "\">" << protectEnc(name) << "</h2>\n";
- generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
- }
-
- if (!s->inherited.isEmpty()) {
- out() << "<ul>\n";
- generateSectionInheritedList(*s, inner);
- out() << "</ul>\n";
- }
- }
- ++s;
- }
-
- if (needOtherSection) {
- out() << "<h3>Additional Inherited Members</h3>\n"
- "<ul>\n";
-
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- if (s->members.isEmpty() && !s->inherited.isEmpty())
- generateSectionInheritedList(*s, inner);
- ++s;
- }
- out() << "</ul>\n";
- }
-
- QString detailsRef = registerRef("details");
- out() << "<a name=\"" << detailsRef << "\"></a>" << divNavTop << '\n';
-
- if (!inner->doc().isEmpty()) {
- generateExtractionMark(inner, DetailedDescriptionMark);
- //out() << "<hr />\n"
- out() << "<div class=\"descr\">\n" // QTBUG-9504
- << "<h2 id=\"" << detailsRef << "\">" << "Detailed Description" << "</h2>\n";
- generateBody(inner, marker);
- out() << "</div>\n"; // QTBUG-9504
- generateAlsoList(inner, marker);
- generateMaintainerList(inner, marker);
- generateExtractionMark(inner, EndMark);
- }
-
- sections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- //out() << "<hr />\n";
- if (!(*s).divClass.isEmpty())
- out() << "<div class=\"" << (*s).divClass << "\">\n"; // QTBUG-9504
- out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
-
- NodeList::ConstIterator m = (*s).members.constBegin();
- while (m != (*s).members.constEnd()) {
- if ((*m)->access() != Node::Private) { // ### check necessary?
- if ((*m)->type() != Node::Class)
- generateDetailedMember(*m, inner, marker);
- else {
- out() << "<h3> class ";
- generateFullName(*m, inner);
- out() << "</h3>";
- generateBrief(*m, marker, inner);
- }
-
- QStringList names;
- names << (*m)->name();
- if ((*m)->type() == Node::Function) {
- const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m);
- if (func->metaness() == FunctionNode::Ctor ||
- func->metaness() == FunctionNode::Dtor ||
- func->overloadNumber() != 1)
- names.clear();
- }
- else if ((*m)->type() == Node::Property) {
- const PropertyNode *prop = reinterpret_cast<const PropertyNode *>(*m);
- if (!prop->getters().isEmpty() &&
- !names.contains(prop->getters().first()->name()))
- names << prop->getters().first()->name();
- if (!prop->setters().isEmpty())
- names << prop->setters().first()->name();
- if (!prop->resetters().isEmpty())
- names << prop->resetters().first()->name();
- if (!prop->notifiers().isEmpty())
- names << prop->notifiers().first()->name();
- }
- else if ((*m)->type() == Node::Enum) {
- const EnumNode *enume = reinterpret_cast<const EnumNode*>(*m);
- if (enume->flagsType())
- names << enume->flagsType()->name();
-
- foreach (const QString &enumName,
- enume->doc().enumItemNames().toSet() -
- enume->doc().omitEnumItemNames().toSet())
- names << plainCode(marker->markedUpEnumValue(enumName,
- enume));
- }
- }
- ++m;
- }
- if (!(*s).divClass.isEmpty())
- out() << "</div>\n"; // QTBUG-9504
- ++s;
- }
- generateFooter(inner);
-}
-
-/*!
- Generate the HTML page for a QML type. \qcn is the QML type.
- \marker is the code markeup object.
- */
-void HtmlGenerator::generateQmlTypePage(QmlTypeNode* qcn, CodeMarker* marker)
-{
- Generator::setQmlTypeContext(qcn);
- SubTitleSize subTitleSize = LargeSubTitle;
- QList<Section>::const_iterator s;
- 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);
-
- QString allQmlMembersLink = generateAllQmlMembersFile(qcn, marker);
- QString obsoleteLink = generateQmlMemberFile(qcn, marker, CodeMarker::Obsolete);
- if (!allQmlMembersLink.isEmpty() || !obsoleteLink.isEmpty()) {
- out() << "<ul>\n";
- if (!allQmlMembersLink.isEmpty()) {
- out() << "<li><a href=\"" << allQmlMembersLink << "\">"
- << "List of all members, including inherited members</a></li>\n";
- }
- if (!obsoleteLink.isEmpty()) {
- out() << "<li><a href=\"" << obsoleteLink << "\">"
- << "Obsolete members</a></li>\n";
- }
- out() << "</ul>\n";
- }
-
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- QString ref = registerRef((*s).name.toLower());
- out() << "<a name=\"" << ref
- << "\"></a>" << divNavTop << '\n';
- out() << "<h2 id=\"" << ref << "\">" << protectEnc((*s).name) << "</h2>\n";
- generateQmlSummary(*s, qcn, marker);
- ++s;
- }
-
- generateExtractionMark(qcn, DetailedDescriptionMark);
- QString detailsRef = registerRef("details");
- out() << "<a name=\"" << detailsRef << "\"></a>" << divNavTop << '\n';
- out() << "<h2 id=\"" << detailsRef << "\">" << "Detailed Description" << "</h2>\n";
- generateBody(qcn, marker);
- ClassNode* cn = qcn->classNode();
- if (cn)
- generateQmlText(cn->doc().body(), cn, marker, qcn->name());
- generateAlsoList(qcn, marker);
- generateExtractionMark(qcn, EndMark);
- //out() << "<hr />\n";
-
- sections = marker->qmlSections(qcn,CodeMarker::Detailed);
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
- NodeList::ConstIterator m = (*s).members.constBegin();
- while (m != (*s).members.constEnd()) {
- generateDetailedQmlMember(*m, qcn, marker);
- out() << "<br/>\n";
- ++m;
- }
- ++s;
- }
- generateFooter(qcn);
- Generator::setQmlTypeContext(0);
-}
-
-/*!
- Generate the HTML page for the QML basic type represented
- by the QML basic type node \a qbtn.
- */
-void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker)
-{
- SubTitleSize subTitleSize = LargeSubTitle;
- QList<Section>::const_iterator s;
- QString htmlTitle = qbtn->fullTitle();
- 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,
- qbtn,
- marker);
- generateExtractionMark(qbtn, DetailedDescriptionMark);
- out() << "<div class=\"descr\"> <a name=\"" << registerRef("details") << "\"></a>\n"; // QTBUG-9504
-
- generateBody(qbtn, marker);
- out() << "</div>\n"; // QTBUG-9504
- generateAlsoList(qbtn, marker);
- generateExtractionMark(qbtn, EndMark);
- generateFooter(qbtn);
-}
-
-/*!
- Generate the HTML page for an entity that doesn't map
- to any underlying parsable C++ class or QML component.
- */
-void HtmlGenerator::generateDocumentNode(DocumentNode* dn, CodeMarker* marker)
-{
- /*
- If the document node is a page node, and if the page type
- is DITA map page, write the node's contents as a dita
- map and return without doing anything else.
- */
- if (dn->subType() == Node::Page && dn->pageType() == Node::DitaMapPage) {
- const DitaMapNode* dmn = static_cast<const DitaMapNode*>(dn);
- writeDitaMap(dmn);
- return;
- }
-
- SubTitleSize subTitleSize = LargeSubTitle;
- QList<Section> sections;
- QList<Section>::const_iterator s;
- QString fullTitle = dn->fullTitle();
-
- generateHeader(fullTitle, dn, marker);
- /*
- Generate the TOC for the new doc format.
- Don't generate a TOC for the home page.
- */
- if ((dn->name() != QStringLiteral("index.html")))
- generateTableOfContents(dn,marker,0);
-
- generateKeywordAnchors(dn);
- generateTitle(fullTitle,
- Text() << dn->subTitle(),
- subTitleSize,
- dn,
- marker);
-
- if (dn->subType() == Node::HeaderFile) {
- // Generate brief text and status for modules.
- generateBrief(dn, marker);
- generateStatus(dn, marker);
- generateSince(dn, marker);
-
- out() << "<ul>\n";
-
- QString membersLink = generateListOfAllMemberFile(dn, marker);
- if (!membersLink.isEmpty())
- out() << "<li><a href=\"" << membersLink << "\">"
- << "List of all members, including inherited members</a></li>\n";
-
- QString obsoleteLink = generateLowStatusMemberFile(dn,
- marker,
- CodeMarker::Obsolete);
- if (!obsoleteLink.isEmpty()) {
- out() << "<li><a href=\"" << obsoleteLink << "\">"
- << "Obsolete members</a></li>\n";
- }
-
- QString compatLink = generateLowStatusMemberFile(dn,
- marker,
- CodeMarker::Compat);
- if (!compatLink.isEmpty())
- out() << "<li><a href=\"" << compatLink << "\">"
- << "Compatibility members</a></li>\n";
-
- out() << "</ul>\n";
- }
-
- sections = marker->sections(dn, CodeMarker::Summary, CodeMarker::Okay);
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- QString ref = registerRef((*s).name);
- out() << "<a name=\"" << ref << "\"></a>" << divNavTop << '\n';
- out() << "<h2 id=\"" << ref << "\">" << protectEnc((*s).name) << "</h2>\n";
- generateSectionList(*s, dn, marker, CodeMarker::Summary);
- ++s;
- }
-
- generateExtractionMark(dn, DetailedDescriptionMark);
- out() << "<div class=\"descr\"> <a name=\"" << registerRef("details") << "\"></a>\n"; // QTBUG-9504
-
- generateBody(dn, marker);
- out() << "</div>\n"; // QTBUG-9504
- generateAlsoList(dn, marker);
- generateExtractionMark(dn, EndMark);
-
- sections = marker->sections(dn, CodeMarker::Detailed, CodeMarker::Okay);
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- //out() << "<hr />\n";
- out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
-
- NodeList::ConstIterator m = (*s).members.constBegin();
- while (m != (*s).members.constEnd()) {
- generateDetailedMember(*m, dn, marker);
- ++m;
- }
- ++s;
- }
- generateFooter(dn);
-}
-
-/*!
- Generate the HTML page for a group, module, or QML module.
- */
-void HtmlGenerator::generateCollectionNode(CollectionNode* cn, CodeMarker* marker)
-{
- SubTitleSize subTitleSize = LargeSubTitle;
- QList<Section> sections;
- QList<Section>::const_iterator s;
- QString fullTitle = cn->fullTitle();
- QString ref;
-
- generateHeader(fullTitle, cn, marker);
- generateTableOfContents(cn,marker,0);
- generateKeywordAnchors(cn);
- generateTitle(fullTitle, Text() << cn->subTitle(), subTitleSize, cn, marker);
-
- if (cn->isModule()) {
- // Generate brief text and status for modules.
- generateBrief(cn, marker);
- generateStatus(cn, marker);
- generateSince(cn, marker);
-
- NodeMultiMap nmm;
- cn->getMemberNamespaces(nmm);
- if (!nmm.isEmpty()) {
- ref = registerRef("namespaces");
- out() << "<a name=\"" << ref << "\"></a>" << divNavTop << '\n';
- out() << "<h2 id=\"" << ref << "\">Namespaces</h2>\n";
- generateAnnotatedList(cn, marker, nmm);
- }
- nmm.clear();
- cn->getMemberClasses(nmm);
- if (!nmm.isEmpty()) {
- ref = registerRef("classes");
- out() << "<a name=\"" << ref << "\"></a>" << divNavTop << '\n';
- out() << "<h2 id=\"" << ref << "\">Classes</h2>\n";
- generateAnnotatedList(cn, marker, nmm);
- }
- nmm.clear();
- }
-
- sections = marker->sections(cn, CodeMarker::Summary, CodeMarker::Okay);
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- ref = registerRef((*s).name);
- out() << "<a name=\"" << ref << "\"></a>" << divNavTop << '\n';
- out() << "<h2 id=\"" << ref << "\">" << protectEnc((*s).name) << "</h2>\n";
- generateSectionList(*s, cn, marker, CodeMarker::Summary);
- ++s;
- }
-
- Text brief = cn->doc().briefText();
- if (cn->isModule() && !brief.isEmpty()) {
- generateExtractionMark(cn, DetailedDescriptionMark);
- ref = registerRef("details");
- out() << "<a name=\"" << ref << "\"></a>" << divNavTop << '\n';
- out() << "<div class=\"descr\">\n"; // QTBUG-9504
- out() << "<h2 id=\"" << ref << "\">" << "Detailed Description" << "</h2>\n";
- }
- else {
- generateExtractionMark(cn, DetailedDescriptionMark);
- out() << "<div class=\"descr\"> <a name=\"" << registerRef("details") << "\"></a>\n"; // QTBUG-9504
- }
-
- generateBody(cn, marker);
- out() << "</div>\n"; // QTBUG-9504
- generateAlsoList(cn, marker);
- generateExtractionMark(cn, EndMark);
-
- if (cn->isGroup())
- generateAnnotatedList(cn, marker, cn->members());
- else if (cn->isQmlModule() || cn->isJsModule())
- generateAnnotatedList(cn, marker, cn->members());
-
- sections = marker->sections(cn, CodeMarker::Detailed, CodeMarker::Okay);
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- //out() << "<hr />\n";
- out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
-
- NodeList::ConstIterator m = (*s).members.constBegin();
- while (m != (*s).members.constEnd()) {
- generateDetailedMember(*m, cn, marker);
- ++m;
- }
- ++s;
- }
- generateFooter(cn);
-}
-
-/*!
- Returns "html" for this subclass of Generator.
- */
-QString HtmlGenerator::fileExtension() const
-{
- return "html";
-}
-
-/*!
- Output navigation list in the html file.
- */
-void HtmlGenerator::generateNavigationBar(const QString &title,
- const Node *node,
- CodeMarker *marker)
-{
- if (noNavigationBar)
- return;
-
- Text navigationbar;
-
- if (homepage == title)
- return;
- if (!homepage.isEmpty())
- navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::NavAutoLink, homepage)
- << Atom(Atom::ListItemRight);
- if (!landingpage.isEmpty() && landingpage != title)
- navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::NavAutoLink, landingpage)
- << Atom(Atom::ListItemRight);
-
- if (node->isClass()) {
- const ClassNode *cn = static_cast<const ClassNode *>(node);
- QString name = node->physicalModuleName();
-
- if (!cppclassespage.isEmpty())
- navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::NavLink, cppclassespage)
- << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, QLatin1String("C++ Classes"))
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
- << Atom(Atom::ListItemRight);
-
- if (!cn->name().isEmpty())
- navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::String, cn->name())
- << Atom(Atom::ListItemRight);
- }
- else if (node->isQmlType() || node->isQmlBasicType() ||
- node->isJsType() || node->isJsBasicType()) {
- if (!qmltypespage.isEmpty())
- navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::NavLink, qmltypespage)
- << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, QLatin1String("QML Types"))
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
- << Atom(Atom::ListItemRight)
- << Atom(Atom::ListItemLeft)
- << Atom(Atom::String, title)
- << Atom(Atom::ListItemRight);
- }
- else {
- if (node->isExampleFile()) {
- navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::NavLink, node->parent()->name())
- << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, node->parent()->title())
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
- << Atom(Atom::ListItemRight);
-
- }
- navigationbar << Atom(Atom::ListItemLeft)
- << Atom(Atom::String, title)
- << Atom(Atom::ListItemRight);
- }
-
- generateText(navigationbar, node, marker);
-}
-
-void HtmlGenerator::generateHeader(const QString& title,
- const Node *node,
- CodeMarker *marker)
-{
-#ifndef QT_NO_TEXTCODEC
- out() << QString("<?xml version=\"1.0\" encoding=\"%1\"?>\n").arg(outputEncoding);
-#else
- out() << QString("<?xml version=\"1.0\"?>\n");
-#endif
- out() << "<!DOCTYPE html>\n";
- out() << QString("<html lang=\"%1\">\n").arg(naturalLanguage);
- out() << "<head>\n";
- out() << " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
- if (node && !node->doc().location().isEmpty())
- out() << "<!-- " << node->doc().location().fileName() << " -->\n";
-
- QString shortVersion = qdb_->version();
- if (shortVersion.count(QChar('.')) == 2)
- shortVersion.truncate(shortVersion.lastIndexOf(QChar('.')));
-
- //determine the rest of the <title> element content: "title | titleSuffix version"
- QString titleSuffix;
- if (!landingpage.isEmpty()) {
- //for normal pages: "title | landingpage version"
- titleSuffix = landingpage;
- }
- else if (!homepage.isEmpty()) {
- //for pages that set the homepage but not landing page: "title | homepage version"
- if (title != homepage)
- titleSuffix = homepage;
- }
- else if (!project.isEmpty()) {
- //for projects outside of Qt or Qt 5: "title | project version"
- if (title != project)
- titleSuffix = project;
- }
- else
- //default: "title | Qt version"
- titleSuffix = QLatin1String("Qt ");
-
- //for pages that duplicate the title and suffix (landing pages, home pages,
- // and module landing pages, clear the duplicate
- if (title == titleSuffix)
- titleSuffix.clear();
-
- //for pages that duplicate the version, clear the duplicate
- if (title.contains(shortVersion) || titleSuffix.contains(shortVersion))
- shortVersion.clear();
-
- QString divider;
- if (!titleSuffix.isEmpty() && !title.isEmpty())
- divider = QLatin1String(" | ");
-
- // Generating page title
- out() << " <title>"
- << protectEnc(title)
- << divider
- << titleSuffix
- << QLatin1Char(' ')
- << shortVersion
- << "</title>\n";
-
- // Include style sheet and script links.
- out() << headerStyles;
- out() << headerScripts;
- if (endHeader.isEmpty())
- out() << "</head>\n<body>\n";
- else
- out() << endHeader;
-
-#ifdef GENERATE_MAC_REFS
- if (mainPage)
- generateMacRef(node, marker);
-#endif
-
- out() << QString(postHeader).replace("\\" + COMMAND_VERSION, qdb_->version());
- generateNavigationBar(title,node,marker);
- if (!buildversion.isEmpty())
- out() << "<li id=\"buildversion\">" << buildversion << "</li>\n";
- out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, qdb_->version());
-
- navigationLinks.clear();
- refMap.clear();
-
- if (node && !node->links().empty()) {
- QPair<QString,QString> linkPair;
- QPair<QString,QString> anchorPair;
- const Node *linkNode;
-
- if (node->links().contains(Node::PreviousLink)) {
- linkPair = node->links()[Node::PreviousLink];
- linkNode = qdb_->findNodeForTarget(linkPair.first, node);
- if (!linkNode)
- node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first));
- if (!linkNode || linkNode == node)
- anchorPair = linkPair;
- else
- anchorPair = anchorForNode(linkNode);
-
- out() << " <link rel=\"prev\" href=\""
- << anchorPair.first << "\" />\n";
-
- navigationLinks += "<a class=\"prevPage\" href=\"" + anchorPair.first + "\">";
- if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
- navigationLinks += protect(anchorPair.second);
- else
- navigationLinks += protect(linkPair.second);
- navigationLinks += "</a>\n";
- }
- if (node->links().contains(Node::NextLink)) {
- linkPair = node->links()[Node::NextLink];
- linkNode = qdb_->findNodeForTarget(linkPair.first, node);
- if (!linkNode)
- node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first));
- if (!linkNode || linkNode == node)
- anchorPair = linkPair;
- else
- anchorPair = anchorForNode(linkNode);
-
- out() << " <link rel=\"next\" href=\""
- << anchorPair.first << "\" />\n";
-
- navigationLinks += "<a class=\"nextPage\" href=\"" + anchorPair.first + "\">";
- if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
- navigationLinks += protect(anchorPair.second);
- else
- navigationLinks += protect(linkPair.second);
- navigationLinks += "</a>\n";
- }
- if (node->links().contains(Node::StartLink)) {
- linkPair = node->links()[Node::StartLink];
- linkNode = qdb_->findNodeForTarget(linkPair.first, node);
- if (!linkNode)
- node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first));
- if (!linkNode || linkNode == node)
- anchorPair = linkPair;
- else
- anchorPair = anchorForNode(linkNode);
- out() << " <link rel=\"start\" href=\""
- << anchorPair.first << "\" />\n";
- }
- }
-
- if (node && !node->links().empty())
- out() << "<p class=\"naviNextPrevious headerNavi\">\n" << navigationLinks << "</p><p/>\n";
-}
-
-void HtmlGenerator::generateTitle(const QString& title,
- const Text &subTitle,
- SubTitleSize subTitleSize,
- const Node *relative,
- CodeMarker *marker)
-{
- out() << QString(prologue).replace("\\" + COMMAND_VERSION, qdb_->version());
- if (!title.isEmpty())
- out() << "<h1 class=\"title\">" << protectEnc(title) << "</h1>\n";
- if (!subTitle.isEmpty()) {
- out() << "<span";
- if (subTitleSize == SmallSubTitle)
- out() << " class=\"small-subtitle\">";
- else
- out() << " class=\"subtitle\">";
- generateText(subTitle, relative, marker);
- out() << "</span>\n";
- }
-}
-
-void HtmlGenerator::generateFooter(const Node *node)
-{
- if (node && !node->links().empty())
- out() << "<p class=\"naviNextPrevious footerNavi\">\n" << navigationLinks << "</p>\n";
-
- out() << QString(footer).replace("\\" + COMMAND_VERSION, qdb_->version())
- << QString(address).replace("\\" + COMMAND_VERSION, qdb_->version());
-
- out() << "</body>\n";
- out() << "</html>\n";
-}
-
-/*!
-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::generateRequisites(InnerNode *inner, CodeMarker *marker)
-{
- QMap<QString, Text> requisites;
- Text text;
-
- const QString headerText = "Header";
- const QString sinceText = "Since";
- const QString inheritedBytext = "Inherited By";
- const QString inheritsText = "Inherits";
- const QString instantiatedByText = "Instantiated By";
- const QString qtVariableText = "qmake";
-
- //add the includes to the map
- if (!inner->includes().isEmpty()) {
- text.clear();
- text << highlightedCode(indent(codeIndent,
- marker->markedUpIncludes(inner->includes())),
- inner);
- requisites.insert(headerText, text);
- }
-
- //The order of the requisites matter
- QStringList requisiteorder;
- requisiteorder << headerText
- << qtVariableText
- << sinceText
- << instantiatedByText
- << inheritsText
- << inheritedBytext;
-
- //add the since and project into the map
- if (!inner->since().isEmpty()) {
- text.clear();
- QStringList since = inner->since().split(QLatin1Char(' '));
- if (since.count() == 1) {
- // If there is only one argument, assume it is the Qt version number.
- text << " Qt " << since[0];
- }
- else {
- //Otherwise, reconstruct the <project> <version> string.
- text << " " << since.join(' ');
- }
- text << Atom::ParaRight;
- requisites.insert(sinceText, text);
- }
-
- if (inner->type() == Node::Class || inner->type() == Node::Namespace) {
- //add the QT variable to the map
- if (!inner->physicalModuleName().isEmpty()) {
- CollectionNode* cn = qdb_->findModule(inner->physicalModuleName());
- if (cn && !cn->qtVariable().isEmpty()) {
- text.clear();
- text << "QT += " + cn->qtVariable();
- requisites.insert(qtVariableText, text);
- }
- }
- }
-
- if (inner->type() == Node::Class) {
- ClassNode* classe = static_cast<ClassNode*>(inner);
- if (classe->qmlElement() != 0 && classe->status() != Node::Internal) {
- text.clear();
- text << Atom(Atom::LinkNode, CodeMarker::stringForNode(classe->qmlElement()))
- << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, classe->qmlElement()->name())
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
- requisites.insert(instantiatedByText, text);
-
- }
-
- //add the inherits to the map
- QList<RelatedClass>::ConstIterator r;
- int index;
- if (!classe->baseClasses().isEmpty()) {
- text.clear();
- r = classe->baseClasses().constBegin();
- index = 0;
- while (r != classe->baseClasses().constEnd()) {
- if ((*r).node_) {
- text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node_))
- << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, (*r).signature_)
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
-
- if ((*r).access_ == Node::Protected) {
- text << " (protected)";
- }
- else if ((*r).access_ == Node::Private) {
- text << " (private)";
- }
- text << comma(index++, classe->baseClasses().count());
- }
- ++r;
- }
- text << Atom::ParaRight;
- requisites.insert(inheritsText, text);
- }
-
- //add the inherited-by to the map
- if (!classe->derivedClasses().isEmpty()) {
- text.clear();
- text << Atom::ParaLeft;
- appendSortedNames(text, classe, classe->derivedClasses());
- text << Atom::ParaRight;
- requisites.insert(inheritedBytext, text);
- }
- }
-
- if (!requisites.isEmpty()) {
- //generate the table
- out() << "<div class=\"table\"><table class=\"alignedsummary\">\n";
-
- QStringList::ConstIterator i;
- for (i = requisiteorder.constBegin(); i != requisiteorder.constEnd(); ++i) {
-
- if (requisites.contains(*i)) {
- out() << "<tr>"
- << "<td class=\"memItemLeft rightAlign topAlign\"> "
- << *i << ":"
- << "</td><td class=\"memItemRight bottomAlign\"> ";
-
- if (*i == headerText)
- out() << requisites.value(*i).toString();
- else
- generateText(requisites.value(*i), inner, marker);
- out() << "</td></tr>";
- }
- }
- out() << "</table></div>";
- }
-}
-
-/*!
-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(QmlTypeNode *qcn, CodeMarker *marker)
-{
- if (!qcn)
- return;
- QMap<QString, Text> requisites;
- Text text;
-
- const QString importText = "Import Statement:";
- const QString sinceText = "Since:";
- const QString inheritedBytext = "Inherited By:";
- const QString inheritsText = "Inherits:";
- const QString instantiatesText = "Instantiates:";
-
- //The order of the requisites matter
- QStringList requisiteorder;
- requisiteorder << importText
- << sinceText
- << instantiatesText
- << inheritsText
- << inheritedBytext;
-
- //add the module name and version to the map
- QString logicalModuleVersion;
- CollectionNode* collection = 0;
- if (qcn->isJsNode())
- collection = qdb_->findJsModule(qcn->logicalModuleName());
- else
- collection = qdb_->findQmlModule(qcn->logicalModuleName());
- if (collection)
- logicalModuleVersion = collection->logicalModuleVersion();
- else
- logicalModuleVersion = qcn->logicalModuleVersion();
- text.clear();
- text << "import " + qcn->logicalModuleName() + " " + logicalModuleVersion;
- requisites.insert(importText, text);
-
- //add the since and project into the map
- if (!qcn->since().isEmpty()) {
- text.clear();
- QStringList since = qcn->since().split(QLatin1Char(' '));
- if (since.count() == 1) {
- // If there is only one argument, assume it is the Qt version number.
- text << " Qt " << since[0];
- }
- else {
- //Otherwise, reconstruct the <project> <version> string.
- text << " " << since.join(' ');
- }
- text << Atom::ParaRight;
- requisites.insert(sinceText, text);
- }
-
- //add the instantiates to the map
- ClassNode* cn = qcn->classNode();
- if (cn && (cn->status() != Node::Internal)) {
- text.clear();
- text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn));
- text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
- 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);
- requisites.insert(instantiatesText, text);
- }
-
- //add the inherits to the map
- QmlTypeNode* base = qcn->qmlBaseNode();
- while (base && base->isInternal()) {
- base = base->qmlBaseNode();
- }
- if (base) {
- text.clear();
- text << Atom::ParaLeft
- << Atom(Atom::LinkNode,CodeMarker::stringForNode(base))
- << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
- << Atom(Atom::String, base->name())
- << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
- << Atom::ParaRight;
- requisites.insert(inheritsText, text);
- }
-
- //add the inherited-by to the map
- NodeList subs;
- QmlTypeNode::subclasses(qcn->name(), subs);
- if (!subs.isEmpty()) {
- text.clear();
- text << Atom::ParaLeft;
- appendSortedQmlNames(text, qcn, subs);
- text << Atom::ParaRight;
- requisites.insert(inheritedBytext, text);
- }
-
- if (!requisites.isEmpty()) {
- //generate the table
- out() << "<div class=\"table\"><table class=\"alignedsummary\">\n";
-
- QStringList::ConstIterator i;
- for (i = requisiteorder.constBegin(); i != requisiteorder.constEnd(); ++i) {
-
- if (requisites.contains(*i)) {
- out() << "<tr>"
- << "<td class=\"memItemLeft rightAlign topAlign\"> "
- << *i
- << "</td><td class=\"memItemRight bottomAlign\"> ";
-
- if (*i == importText)
- out()<<requisites.value(*i).toString();
- else
- generateText(requisites.value(*i), qcn, marker);
- out() << "</td></tr>";
- }
- }
- out() << "</table></div>";
- }
-}
-
-void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker,
- const Node *relative)
-{
- Text brief = node->doc().briefText();
- if (!brief.isEmpty()) {
- generateExtractionMark(node, BriefMark);
- out() << "<p>";
- generateText(brief, node, marker);
-
- if (!relative || node == relative)
- out() << " <a href=\"#";
- else
- out() << " <a href=\"" << linkForNode(node, relative) << '#';
- out() << registerRef("details") << "\">More...</a></p>\n";
-
-
- generateExtractionMark(node, EndMark);
- }
-}
-
-void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker)
-{
- if (!inner->includes().isEmpty()) {
- out() << "<pre class=\"cpp\">"
- << trimmedTrailing(highlightedCode(indent(codeIndent,
- marker->markedUpIncludes(inner->includes())),
- inner))
- << "</pre>";
- }
-}
-
-/*!
- Revised for the new doc format.
- Generates a table of contents beginning at \a node.
- */
-void HtmlGenerator::generateTableOfContents(const Node *node,
- CodeMarker *marker,
- QList<Section>* sections)
-{
- QList<Atom*> toc;
- if (node->doc().hasTableOfContents())
- toc = node->doc().tableOfContents();
- if (tocDepth == 0 || (toc.isEmpty() && !sections && !node->isModule())) {
- generateSidebar();
- return;
- }
-
- QStringList sectionNumber;
- int detailsBase = 0;
-
- // disable nested links in table of contents
- inContents_ = true;
- inLink_ = true;
-
- out() << "<div class=\"sidebar\">\n";
- out() << "<div class=\"toc\">\n";
- out() << "<h3><a name=\"toc\">Contents</a></h3>\n";
- sectionNumber.append("1");
- out() << "<ul>\n";
-
- if (node->isModule()) {
- if (node->hasNamespaces()) {
- out() << "<li class=\"level"
- << sectionNumber.size()
- << "\"><a href=\"#"
- << registerRef("namespaces")
- << "\">Namespaces</a></li>\n";
- }
- if (node->hasClasses()) {
- out() << "<li class=\"level"
- << sectionNumber.size()
- << "\"><a href=\"#"
- << registerRef("classes")
- << "\">Classes</a></li>\n";
- }
- out() << "<li class=\"level"
- << sectionNumber.size()
- << "\"><a href=\"#"
- << registerRef("details")
- << "\">Detailed Description</a></li>\n";
- for (int i = 0; i < toc.size(); ++i) {
- if (toc.at(i)->string().toInt() == 1) {
- detailsBase = 1;
- break;
- }
- }
- }
- 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()) {
- out() << "<li class=\"level"
- << sectionNumber.size()
- << "\"><a href=\"#"
- << registerRef((*s).pluralMember)
- << "\">" << (*s).name
- << "</a></li>\n";
- }
- if (!s->reimpMembers.isEmpty()) {
- QString ref = QString("Reimplemented ") + (*s).pluralMember;
- out() << "<li class=\"level"
- << sectionNumber.size()
- << "\"><a href=\"#"
- << registerRef(ref.toLower())
- << "\">" << QString("Reimplemented ") + (*s).name
- << "</a></li>\n";
- }
- ++s;
- }
- out() << "<li class=\"level"
- << sectionNumber.size()
- << "\"><a href=\"#"
- << registerRef("details")
- << "\">Detailed Description</a></li>\n";
- for (int i = 0; i < toc.size(); ++i) {
- if (toc.at(i)->string().toInt() == 1) {
- detailsBase = 1;
- break;
- }
- }
- }
-
- for (int i = 0; i < toc.size(); ++i) {
- Atom *atom = toc.at(i);
- int nextLevel = atom->string().toInt() + detailsBase;
- if (nextLevel >= 0) {
- if (sectionNumber.size() < nextLevel) {
- do {
- sectionNumber.append("1");
- } while (sectionNumber.size() < nextLevel);
- }
- else {
- while (sectionNumber.size() > nextLevel) {
- sectionNumber.removeLast();
- }
- sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1);
- }
- }
-
- //restrict the ToC depth to the one set by the HTML.tocdepth variable or
- //print all levels if tocDepth is not set.
- if (sectionNumber.size() <= tocDepth || tocDepth < 0) {
- int numAtoms;
- Text headingText = Text::sectionHeading(atom);
- QString s = headingText.toString();
- out() << "<li class=\"level"
- << sectionNumber.size()
- << "\">";
- out() << "<a href=\""
- << '#'
- << Doc::canonicalTitle(s)
- << "\">";
- generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms);
- out() << "</a></li>\n";
- }
- }
- while (!sectionNumber.isEmpty()) {
- sectionNumber.removeLast();
- }
- out() << "</ul>\n";
- out() << "</div>\n";
- out() << "<div class=\"sidebar-content\" id=\"sidebar-content\"></div>";
- out() << "</div>\n";
- inContents_ = false;
- inLink_ = false;
-}
-
-/*!
- Outputs a placeholder div where the style can add customized sidebar content.
- */
-void HtmlGenerator::generateSidebar() {
- out() << "<div class=\"sidebar\">";
- out() << "<div class=\"sidebar-content\" id=\"sidebar-content\"></div>";
- out() << "</div>\n";
-}
-
-QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner,
- CodeMarker *marker)
-{
- QList<Section> sections;
- QList<Section>::ConstIterator s;
-
- sections = marker->sections(inner,
- CodeMarker::Subpage,
- CodeMarker::Okay);
- if (sections.isEmpty())
- return QString();
-
- QString fileName = fileBase(inner) + "-members." + fileExtension();
- beginSubPage(inner, fileName);
- QString title = "List of All Members for " + inner->name();
- generateHeader(title, inner, marker);
- generateSidebar();
- generateTitle(title, Text(), SmallSubTitle, inner, marker);
- out() << "<p>This is the complete list of members for ";
- generateFullName(inner, 0);
- out() << ", including inherited members.</p>\n";
-
- Section section = sections.first();
- generateSectionList(section, inner, marker, CodeMarker::Subpage);
-
- generateFooter();
- endSubPage();
- return fileName;
-}
-
-/*!
- This function creates an html page on which are listed all
- the members of QML class \a qml_cn, including the inherited
- members. The \a marker is used for formatting stuff.
- */
-QString HtmlGenerator::generateAllQmlMembersFile(QmlTypeNode* qml_cn, CodeMarker* marker)
-{
- QList<Section> sections;
- QList<Section>::ConstIterator s;
-
- sections = marker->qmlSections(qml_cn,CodeMarker::Subpage);
- if (sections.isEmpty())
- return QString();
-
- QString fileName = fileBase(qml_cn) + "-members." + fileExtension();
- beginSubPage(qml_cn, fileName);
- QString title = "List of All Members for " + qml_cn->name();
- generateHeader(title, qml_cn, marker);
- generateSidebar();
- generateTitle(title, Text(), SmallSubTitle, qml_cn, marker);
- out() << "<p>This is the complete list of members for ";
- generateFullName(qml_cn, 0);
- out() << ", including inherited members.</p>\n";
-
- ClassKeysNodesList& cknl = sections.first().classKeysNodesList_;
- if (!cknl.isEmpty()) {
- for (int i=0; i<cknl.size(); i++) {
- ClassKeysNodes* ckn = cknl[i];
- const QmlTypeNode* qcn = ckn->first;
- KeysAndNodes& kn = ckn->second;
- QStringList& keys = kn.first;
- NodeList& nodes = kn.second;
- if (nodes.isEmpty())
- continue;
- if (i != 0) {
- out() << "<p>The following members are inherited from ";
- generateFullName(qcn,0);
- out() << ".</p>\n";
- }
- out() << "<ul>\n";
- for (int j=0; j<keys.size(); j++) {
- if (nodes[j]->access() == Node::Private || nodes[j]->status() == Node::Internal) {
- continue;
- }
- out() << "<li class=\"fn\">";
- QString prefix;
- if (!keys.isEmpty()) {
- prefix = keys.at(j).mid(1);
- prefix = prefix.left(keys.at(j).indexOf("::")+1);
- }
- generateQmlItem(nodes[j], qml_cn, marker, true);
- if (nodes[j]->isAttached())
- out() << " [attached]";
- //generateSynopsis(nodes[j], qcn, marker, CodeMarker::Subpage, false, &prefix);
- out() << "</li>\n";
- }
- out() << "</ul>\n";
- }
- }
-
- generateFooter();
- endSubPage();
- return fileName;
-}
-
-QString HtmlGenerator::generateLowStatusMemberFile(InnerNode *inner,
- CodeMarker *marker,
- CodeMarker::Status status)
-{
- QList<Section> sections = marker->sections(inner,
- CodeMarker::Summary,
- status);
- QMutableListIterator<Section> j(sections);
- while (j.hasNext()) {
- if (j.next().members.size() == 0)
- j.remove();
- }
- if (sections.isEmpty())
- return QString();
-
- int i;
-
- QString title;
- QString fileName;
-
- if (status == CodeMarker::Compat) {
- title = "Compatibility Members for " + inner->name();
- fileName = fileBase(inner) + "-compat." + fileExtension();
- }
- else {
- title = "Obsolete Members for " + inner->name();
- fileName = fileBase(inner) + "-obsolete." + fileExtension();
- }
- if (status == CodeMarker::Obsolete) {
- QString link;
- if (useOutputSubdirs() && !Generator::outputSubdir().isEmpty())
- link = QString("../" + Generator::outputSubdir() + QLatin1Char('/'));
- link += fileName;
- inner->setObsoleteLink(link);
- }
-
- beginSubPage(inner, fileName);
- generateHeader(title, inner, marker);
- generateSidebar();
- generateTitle(title, Text(), SmallSubTitle, inner, marker);
-
- if (status == CodeMarker::Compat) {
- out() << "<p><b>The following members of class "
- << "<a href=\"" << linkForNode(inner, 0) << "\">"
- << protectEnc(inner->name()) << "</a>"
- << " are part of the "
- "Qt compatibility layer.</b> We advise against "
- "using them in new code.</p>\n";
- }
- else {
- out() << "<p><b>The following members of class "
- << "<a href=\"" << linkForNode(inner, 0) << "\">"
- << protectEnc(inner->name()) << "</a>"
- << " are obsolete.</b> "
- << "They are provided to keep old source code working. "
- << "We strongly advise against using them in new code.</p>\n";
- }
-
- for (i = 0; i < sections.size(); ++i) {
- out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n";
- generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary);
- }
-
- sections = marker->sections(inner, CodeMarker::Detailed, status);
- for (i = 0; i < sections.size(); ++i) {
- //out() << "<hr />\n";
- out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n";
-
- NodeList::ConstIterator m = sections.at(i).members.constBegin();
- while (m != sections.at(i).members.constEnd()) {
- if ((*m)->access() != Node::Private)
- generateDetailedMember(*m, inner, marker);
- ++m;
- }
- }
-
- generateFooter();
- endSubPage();
- return fileName;
-}
-
-/*!
- Generates a separate file where certain members of the QML
- type \a qcn are listed. The \a marker is used to generate
- the section lists, which are then traversed and output here.
-
- Note that this function currently only handles correctly the
- case where \a status is \c {CodeMarker::Obsolete}.
- */
-QString HtmlGenerator::generateQmlMemberFile(QmlTypeNode* qcn,
- CodeMarker *marker,
- CodeMarker::Status status)
-{
- QList<Section> sections = marker->qmlSections(qcn, CodeMarker::Summary, status);
- QMutableListIterator<Section> j(sections);
- while (j.hasNext()) {
- if (j.next().members.size() == 0)
- j.remove();
- }
- if (sections.isEmpty())
- return QString();
-
- QString title = "Obsolete Members for " + qcn->name();
- QString fileName = fileBase(qcn) + "-obsolete." + fileExtension();
-
- if (status == CodeMarker::Obsolete) {
- QString link;
- if (useOutputSubdirs() && !Generator::outputSubdir().isEmpty())
- link = QString("../" + Generator::outputSubdir() + QLatin1Char('/'));
- link += fileName;
- qcn->setObsoleteLink(link);
- }
-
- beginSubPage(qcn, fileName);
- generateHeader(title, qcn, marker);
- generateSidebar();
- generateTitle(title, Text(), SmallSubTitle, qcn, marker);
-
- out() << "<p><b>The following members of QML type "
- << "<a href=\"" << linkForNode(qcn, 0) << "\">"
- << protectEnc(qcn->name()) << "</a>"
- << " are obsolete.</b> "
- << "They are provided to keep old source code working. "
- << "We strongly advise against using them in new code.</p>\n";
-
- QList<Section>::const_iterator s = sections.constBegin();
- while (s != sections.constEnd()) {
- QString ref = registerRef((*s).name.toLower());
- out() << "<a name=\"" << ref
- << "\"></a>" << divNavTop << '\n';
- out() << "<h2 id=\"" << ref << "\">" << protectEnc((*s).name) << "</h2>\n";
- generateQmlSummary(*s, qcn, marker);
- ++s;
- }
-
- sections = marker->qmlSections(qcn, CodeMarker::Detailed, status);
- QMutableListIterator<Section> k(sections);
- while (k.hasNext()) {
- if (k.next().members.size() == 0)
- k.remove();
- }
- if (sections.isEmpty())
- return QString();
-
- s = sections.constBegin();
- while (s != sections.constEnd()) {
- out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
- NodeList::ConstIterator m = (*s).members.constBegin();
- while (m != (*s).members.constEnd()) {
- generateDetailedQmlMember(*m, qcn, marker);
- out() << "<br/>\n";
- ++m;
- }
- ++s;
- }
-
- generateFooter();
- endSubPage();
- return fileName;
-}
-
-void HtmlGenerator::generateClassHierarchy(const Node *relative, NodeMap& classMap)
-{
- if (classMap.isEmpty())
- return;
-
- NodeMap topLevel;
- NodeMap::Iterator c = classMap.begin();
- while (c != classMap.end()) {
- ClassNode *classe = static_cast<ClassNode *>(*c);
- if (classe->baseClasses().isEmpty())
- topLevel.insert(classe->name(), classe);
- ++c;
- }
-
- QStack<NodeMap > stack;
- stack.push(topLevel);
-
- out() << "<ul>\n";
- while (!stack.isEmpty()) {
- if (stack.top().isEmpty()) {
- stack.pop();
- out() << "</ul>\n";
- }
- else {
- ClassNode* child = static_cast<ClassNode*>(*stack.top().begin());
- out() << "<li>";
- generateFullName(child, relative);
- out() << "</li>\n";
- stack.top().erase(stack.top().begin());
-
- NodeMap newTop;
- foreach (const RelatedClass &d, child->derivedClasses()) {
- if (d.node_ && !d.isPrivate() && !d.node_->isInternal() && d.node_->hasDoc())
- newTop.insert(d.node_->name(), d.node_);
- }
- if (!newTop.isEmpty()) {
- stack.push(newTop);
- out() << "<ul>\n";
- }
- }
- }
-}
-
-/*!
- Output an annotated list of the nodes in \a nodeMap.
- A two-column table is output.
- */
-void HtmlGenerator::generateAnnotatedList(const Node* relative,
- CodeMarker* marker,
- const NodeMultiMap& nmm)
-{
- if (nmm.isEmpty())
- return;
- generateAnnotatedList(relative, marker, nmm.values());
-}
-
-/*!
- */
-void HtmlGenerator::generateAnnotatedList(const Node *relative,
- CodeMarker *marker,
- const NodeList& unsortedNodes)
-{
- NodeMultiMap nmm;
- bool allInternal = true;
- foreach (Node* node, unsortedNodes) {
- if (!node->isInternal() && !node->isObsolete()) {
- allInternal = false;
- nmm.insert(node->fullName(relative), node);
- }
- }
- if (allInternal)
- return;
- out() << "<div class=\"table\"><table class=\"annotated\">\n";
- int row = 0;
- NodeList nodes = nmm.values();
- foreach (const Node* node, nodes) {
- if (++row % 2 == 1)
- out() << "<tr class=\"odd topAlign\">";
- else
- out() << "<tr class=\"even topAlign\">";
- out() << "<td class=\"tblName\"><p>";
- generateFullName(node, relative);
- out() << "</p></td>";
-
- if (!node->isDocumentNode()) {
- Text brief = node->doc().trimmedBriefText(node->name());
- if (!brief.isEmpty()) {
- out() << "<td class=\"tblDescr\"><p>";
- generateText(brief, node, marker);
- out() << "</p></td>";
- }
- else if (!node->reconstitutedBrief().isEmpty()) {
- out() << "<td class=\"tblDescr\"><p>";
- out() << node->reconstitutedBrief();
- out() << "</p></td>";
- }
- }
- else {
- out() << "<td class=\"tblDescr\"><p>";
- if (!node->reconstitutedBrief().isEmpty()) {
- out() << node->reconstitutedBrief();
- }
- else
- out() << protectEnc(node->doc().briefText().toString());
- out() << "</p></td>";
- }
- out() << "</tr>\n";
- }
- out() << "</table></div>\n";
-}
-
-/*!
- This function finds the common prefix of the names of all
- the classes in the class map \a nmm and then generates a
- compact list of the class names alphabetized on the part
- of the name not including the common prefix. You can tell
- the function to use \a comonPrefix as the common prefix,
- but normally you let it figure it out itself by looking at
- the name of the first and last classes in the class map
- \a nmm.
- */
-void HtmlGenerator::generateCompactList(ListType listType,
- const Node *relative,
- const NodeMultiMap &nmm,
- bool includeAlphabet,
- QString commonPrefix)
-{
- if (nmm.isEmpty())
- return;
-
- const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_'
- int commonPrefixLen = commonPrefix.length();
-
- /*
- Divide the data into 37 paragraphs: 0, ..., 9, A, ..., Z,
- underscore (_). QAccel will fall in paragraph 10 (A) and
- QXtWidget in paragraph 33 (X). This is the only place where we
- assume that NumParagraphs is 37. Each paragraph is a NodeMultiMap.
- */
- NodeMultiMap paragraph[NumParagraphs+1];
- QString paragraphName[NumParagraphs+1];
- QSet<char> usedParagraphNames;
-
- NodeMultiMap::ConstIterator c = nmm.constBegin();
- while (c != nmm.constEnd()) {
- QStringList pieces = c.key().split("::");
- QString key;
- int idx = commonPrefixLen;
- if (idx > 0 && !pieces.last().startsWith(commonPrefix))
- idx = 0;
- if (pieces.size() == 1)
- key = pieces.last().mid(idx).toLower();
- else
- key = pieces.last().toLower();
-
- int paragraphNr = NumParagraphs - 1;
-
- if (key[0].digitValue() != -1) {
- paragraphNr = key[0].digitValue();
- }
- else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) {
- paragraphNr = 10 + key[0].unicode() - 'a';
- }
-
- paragraphName[paragraphNr] = key[0].toUpper();
- usedParagraphNames.insert(key[0].toLower().cell());
- paragraph[paragraphNr].insert(c.key(), c.value());
- ++c;
- }
-
- /*
- Each paragraph j has a size: paragraph[j].count(). In the
- discussion, we will assume paragraphs 0 to 5 will have sizes
- 3, 1, 4, 1, 5, 9.
-
- We now want to compute the paragraph offset. Paragraphs 0 to 6
- start at offsets 0, 3, 4, 8, 9, 14, 23.
- */
- int paragraphOffset[NumParagraphs + 1]; // 37 + 1
- paragraphOffset[0] = 0;
- for (int i=0; i<NumParagraphs; i++) // i = 0..36
- paragraphOffset[i+1] = paragraphOffset[i] + paragraph[i].count();
-
- /*
- Output the alphabet as a row of links.
- */
- if (includeAlphabet) {
- out() << "<p class=\"centerAlign functionIndex\"><b>";
- for (int i = 0; i < 26; i++) {
- QChar ch('a' + i);
- if (usedParagraphNames.contains(char('a' + i)))
- out() << QString("<a href=\"#%1\">%2</a>&nbsp;").arg(ch).arg(ch.toUpper());
- }
- out() << "</b></p>\n";
- }
-
- /*
- Output a <div> element to contain all the <dl> elements.
- */
- out() << "<div class=\"flowListDiv\">\n";
- numTableRows_ = 0;
-
- int curParNr = 0;
- int curParOffset = 0;
- QString previousName;
- bool multipleOccurrences = false;
-
- for (int i=0; i<nmm.count(); i++) {
- while ((curParNr < NumParagraphs) &&
- (curParOffset == paragraph[curParNr].count())) {
- ++curParNr;
- curParOffset = 0;
- }
-
- /*
- Starting a new paragraph means starting a new <dl>.
- */
- if (curParOffset == 0) {
- if (i > 0)
- out() << "</dl>\n";
- if (++numTableRows_ % 2 == 1)
- out() << "<dl class=\"flowList odd\">";
- else
- out() << "<dl class=\"flowList even\">";
- out() << "<dt class=\"alphaChar\">";
- if (includeAlphabet) {
- QChar c = paragraphName[curParNr][0].toLower();
- out() << QString("<a name=\"%1\"></a>").arg(c);
- }
- out() << "<b>"
- << paragraphName[curParNr]
- << "</b>";
- out() << "</dt>\n";
- }
-
- /*
- Output a <dd> for the current offset in the current paragraph.
- */
- out() << "<dd>";
- if ((curParNr < NumParagraphs) &&
- !paragraphName[curParNr].isEmpty()) {
- NodeMultiMap::Iterator it;
- NodeMultiMap::Iterator next;
- it = paragraph[curParNr].begin();
- for (int i=0; i<curParOffset; i++)
- ++it;
-
- if (listType == Generic) {
- /*
- Previously, we used generateFullName() for this, but we
- require some special formatting.
- */
- out() << "<a href=\"" << linkForNode(it.value(), relative) << "\">";
- }
- else if (listType == Obsolete) {
- QString fileName = fileBase(it.value()) + "-obsolete." + fileExtension();
- QString link;
- if (useOutputSubdirs()) {
- link = QString("../" + it.value()->outputSubdirectory() + QLatin1Char('/'));
- }
- link += fileName;
- out() << "<a href=\"" << link << "\">";
- }
-
- QStringList pieces;
- if (it.value()->isQmlType() || it.value()->isJsType()) {
- QString name = it.value()->name();
- next = it;
- ++next;
- if (name != previousName)
- multipleOccurrences = false;
- if ((next != paragraph[curParNr].end()) && (name == next.value()->name())) {
- multipleOccurrences = true;
- previousName = name;
- }
- if (multipleOccurrences)
- name += ": " + it.value()->tree()->camelCaseModuleName();
- pieces << name;
- }
- else
- pieces = it.value()->fullName(relative).split("::");
- out() << protectEnc(pieces.last());
- out() << "</a>";
- if (pieces.size() > 1) {
- out() << " (";
- generateFullName(it.value()->parent(), relative);
- out() << ')';
- }
- }
- out() << "</dd>\n";
- curParOffset++;
- }
- if (nmm.count() > 0)
- out() << "</dl>\n";
-
- out() << "</div>\n";
-}
-
-void HtmlGenerator::generateFunctionIndex(const Node *relative)
-{
- out() << "<p class=\"centerAlign functionIndex\"><b>";
- for (int i = 0; i < 26; i++) {
- QChar ch('a' + i);
- out() << QString("<a href=\"#%1\">%2</a>&nbsp;").arg(ch).arg(ch.toUpper());
- }
- out() << "</b></p>\n";
-
- char nextLetter = 'a';
- char currentLetter;
-
- out() << "<ul>\n";
- NodeMapMap& funcIndex = qdb_->getFunctionIndex();
- QMap<QString, NodeMap >::ConstIterator f = funcIndex.constBegin();
- while (f != funcIndex.constEnd()) {
- out() << "<li>";
- out() << protectEnc(f.key()) << ':';
-
- currentLetter = f.key()[0].unicode();
- while (islower(currentLetter) && currentLetter >= nextLetter) {
- out() << QString("<a name=\"%1\"></a>").arg(nextLetter);
- nextLetter++;
- }
-
- NodeMap::ConstIterator s = (*f).constBegin();
- while (s != (*f).constEnd()) {
- out() << ' ';
- generateFullName((*s)->parent(), relative, *s);
- ++s;
- }
- out() << "</li>";
- out() << '\n';
- ++f;
- }
- out() << "</ul>\n";
-}
-
-void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marker)
-{
- TextToNodeMap& legaleseTexts = qdb_->getLegaleseTexts();
- QMap<Text, const Node *>::ConstIterator it = legaleseTexts.constBegin();
- while (it != legaleseTexts.constEnd()) {
- Text text = it.key();
- //out() << "<hr />\n";
- generateText(text, relative, marker);
- out() << "<ul>\n";
- do {
- out() << "<li>";
- generateFullName(it.value(), relative);
- out() << "</li>\n";
- ++it;
- } while (it != legaleseTexts.constEnd() && it.key() == text);
- out() << "</ul>\n";
- }
-}
-
-void HtmlGenerator::generateQmlItem(const Node *node,
- const Node *relative,
- CodeMarker *marker,
- bool summary)
-{
- QString marked = marker->markedUpQmlItem(node,summary);
- QRegExp templateTag("(<[^@>]*>)");
- if (marked.indexOf(templateTag) != -1) {
- QString contents = protectEnc(marked.mid(templateTag.pos(1),
- templateTag.cap(1).length()));
- marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
- contents);
- }
- marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"),
- "<i>\\1<sub>\\2</sub></i>");
- marked.replace("<@param>", "<i> ");
- marked.replace("</@param>", "</i>");
-
- if (summary)
- marked.replace("@name>", "b>");
-
- marked.replace("<@extra>", "<code>");
- marked.replace("</@extra>", "</code>");
-
- if (summary) {
- marked.remove("<@type>");
- marked.remove("</@type>");
- }
- out() << highlightedCode(marked, relative, false);
-}
-
-void HtmlGenerator::generateList(const Node* relative, CodeMarker* marker, const QString& selector)
-{
- 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);
- }
- else {
- /*
- \generatelist {selector} is only allowed in a
- 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, \\qmlmodule, and \\jsmodule comments.").arg(selector));
- return;
- }
- Node* n = const_cast<Node*>(relative);
- CollectionNode* cn = static_cast<CollectionNode*>(n);
- qdb_->mergeCollections(cn);
- generateAnnotatedList(cn, marker, cn->members());
- }
-}
-
-void HtmlGenerator::generateSection(const NodeList& nl,
- const Node *relative,
- CodeMarker *marker,
- CodeMarker::SynopsisStyle style)
-{
- bool alignNames = true;
- if (!nl.isEmpty()) {
- bool twoColumn = false;
- if (style == CodeMarker::Subpage) {
- alignNames = false;
- twoColumn = (nl.count() >= 16);
- }
- else if (nl.first()->type() == Node::Property) {
- twoColumn = (nl.count() >= 5);
- alignNames = false;
- }
- if (alignNames) {
- out() << "<div class=\"table\"><table class=\"alignedsummary\">\n";
- }
- else {
- if (twoColumn)
- out() << "<div class=\"table\"><table class=\"propsummary\">\n"
- << "<tr><td class=\"topAlign\">";
- out() << "<ul>\n";
- }
-
- int i = 0;
- NodeList::ConstIterator m = nl.constBegin();
- while (m != nl.constEnd()) {
- if ((*m)->access() == Node::Private) {
- ++m;
- continue;
- }
-
- if (alignNames) {
- out() << "<tr><td class=\"memItemLeft rightAlign topAlign\"> ";
- }
- else {
- if (twoColumn && i == (int) (nl.count() + 1) / 2)
- out() << "</ul></td><td class=\"topAlign\"><ul>\n";
- out() << "<li class=\"fn\">";
- }
-
- generateSynopsis(*m, relative, marker, style, alignNames);
- if (alignNames)
- out() << "</td></tr>\n";
- else
- out() << "</li>\n";
- i++;
- ++m;
- }
- if (alignNames)
- out() << "</table></div>\n";
- else {
- out() << "</ul>\n";
- if (twoColumn)
- out() << "</td></tr>\n</table></div>\n";
- }
- }
-}
-
-void HtmlGenerator::generateSectionList(const Section& section,
- const Node *relative,
- CodeMarker *marker,
- CodeMarker::SynopsisStyle style)
-{
- bool alignNames = true;
- if (!section.members.isEmpty()) {
- bool hasPrivateSignals = false;
- bool twoColumn = false;
- if (style == CodeMarker::Subpage) {
- alignNames = false;
- twoColumn = (section.members.count() >= 16);
- }
- else if (section.members.first()->type() == Node::Property) {
- twoColumn = (section.members.count() >= 5);
- alignNames = false;
- }
- if (alignNames) {
- out() << "<div class=\"table\"><table class=\"alignedsummary\">\n";
- }
- else {
- if (twoColumn)
- out() << "<div class=\"table\"><table class=\"propsummary\">\n"
- << "<tr><td class=\"topAlign\">";
- out() << "<ul>\n";
- }
-
- int i = 0;
- NodeList::ConstIterator m = section.members.constBegin();
- while (m != section.members.constEnd()) {
- if ((*m)->access() == Node::Private) {
- ++m;
- continue;
- }
-
- if (alignNames) {
- out() << "<tr><td class=\"memItemLeft topAlign rightAlign\"> ";
- }
- else {
- if (twoColumn && i == (int) (section.members.count() + 1) / 2)
- out() << "</ul></td><td class=\"topAlign\"><ul>\n";
- out() << "<li class=\"fn\">";
- }
-
- QString prefix;
- if (!section.keys.isEmpty()) {
- prefix = section.keys.at(i).mid(1);
- prefix = prefix.left(section.keys.at(i).indexOf("::")+1);
- }
- generateSynopsis(*m, relative, marker, style, alignNames, &prefix);
- if ((*m)->isFunction()) {
- const FunctionNode* fn = static_cast<const FunctionNode*>(*m);
- if (fn->isPrivateSignal()) {
- hasPrivateSignals = true;
- if (alignNames)
- out() << "</td><td class=\"memItemRight bottomAlign\">[see note below]";
- }
- }
- if (alignNames)
- out() << "</td></tr>\n";
- else
- out() << "</li>\n";
- i++;
- ++m;
- }
- if (alignNames)
- out() << "</table></div>\n";
- else {
- out() << "</ul>\n";
- if (twoColumn)
- out() << "</td></tr>\n</table></div>\n";
- }
- if (hasPrivateSignals && alignNames) {
- generatePrivateSignalNote(relative, marker);
- }
- }
-
- if (style == CodeMarker::Summary && !section.inherited.isEmpty()) {
- out() << "<ul>\n";
- generateSectionInheritedList(section, relative);
- out() << "</ul>\n";
- }
-}
-
-void HtmlGenerator::generateSectionInheritedList(const Section& section, const Node *relative)
-{
- QList<QPair<InnerNode *, int> >::ConstIterator p = section.inherited.constBegin();
- while (p != section.inherited.constEnd()) {
- out() << "<li class=\"fn\">";
- out() << (*p).second << ' ';
- if ((*p).second == 1) {
- out() << section.singularMember;
- }
- else {
- out() << section.pluralMember;
- }
- out() << " inherited from <a href=\"" << fileName((*p).first)
- << '#' << Generator::cleanRef(section.name.toLower()) << "\">"
- << protectEnc((*p).first->plainFullName(relative))
- << "</a></li>\n";
- ++p;
- }
-}
-
-// generateSynopsis(qmn,relative,marker,CodeMarker::Detailed,false);
-void HtmlGenerator::generateSynopsis(const Node *node,
- const Node *relative,
- CodeMarker *marker,
- CodeMarker::SynopsisStyle style,
- bool alignNames,
- const QString* prefix)
-{
- QString marked = marker->markedUpSynopsis(node, relative, style);
-
- if (prefix)
- marked.prepend(*prefix);
- QRegExp templateTag("(<[^@>]*>)");
- if (marked.indexOf(templateTag) != -1) {
- QString contents = protectEnc(marked.mid(templateTag.pos(1),
- templateTag.cap(1).length()));
- marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
- contents);
- }
- marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"),
- "<i>\\1<sub>\\2</sub></i>");
- marked.replace("<@param>", "<i> ");
- marked.replace("</@param>", "</i>");
-
- if (style == CodeMarker::Summary) {
- marked.remove("<@name>"); // was "<b>"
- marked.remove("</@name>"); // was "</b>"
- }
-
- if (style == CodeMarker::Subpage) {
- QRegExp extraRegExp("<@extra>.*</@extra>");
- extraRegExp.setMinimal(true);
- marked.remove(extraRegExp);
- } else {
- marked.replace("<@extra>", "<code>");
- marked.replace("</@extra>", "</code>");
- }
-
- if (style != CodeMarker::Detailed) {
- marked.remove("<@type>");
- marked.remove("</@type>");
- }
-
- out() << highlightedCode(marked, relative, alignNames);
-}
-
-QString HtmlGenerator::highlightedCode(const QString& markedCode,
- const Node* relative,
- bool alignNames)
-{
- QString src = markedCode;
- QString html;
- QStringRef arg;
- QStringRef par1;
-
- const QChar charLangle = '<';
- const QChar charAt = '@';
-
- static const QString typeTag("type");
- static const QString headerTag("headerfile");
- static const QString funcTag("func");
- static const QString linkTag("link");
-
- // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(</@link>)"
- bool done = false;
- for (int i = 0, srcSize = src.size(); i < srcSize;) {
- if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
- if (alignNames && !done) {
- html += "</td><td class=\"memItemRight bottomAlign\">";
- done = true;
- }
- i += 2;
- if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) {
- html += "<b>";
- const Node* n = CodeMarker::nodeForString(par1.toString());
- QString link = linkForNode(n, relative);
- addLink(link, arg, &html);
- html += "</b>";
- }
- else {
- html += charLangle;
- html += charAt;
- }
- }
- else {
- html += src.at(i++);
- }
- }
-
- // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)"
- src = html;
- html = QString();
- for (int i = 0, srcSize = src.size(); i < srcSize;) {
- if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
- i += 2;
- if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
- const Node* n = qdb_->findFunctionNode(par1.toString(), relative, Node::DontCare);
- QString link = linkForNode(n, relative);
- addLink(link, arg, &html);
- par1 = QStringRef();
- }
- else {
- html += charLangle;
- html += charAt;
- }
- }
- else {
- html += src.at(i++);
- }
- }
-
- // replace all "(<@(type|headerfile)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
- src = html;
- html = QString();
-
- for (int i=0, srcSize=src.size(); i<srcSize;) {
- if (src.at(i) == charLangle && src.at(i+1) == charAt) {
- i += 2;
- bool handled = false;
- if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
- par1 = QStringRef();
- const Node* n = qdb_->findTypeNode(arg.toString(), relative);
- html += QLatin1String("<span class=\"type\">");
- if (n && (n->isQmlBasicType() || n->isJsBasicType())) {
- if (relative && (relative->isQmlType() || relative->isJsType()))
- addLink(linkForNode(n,relative), arg, &html);
- else
- html += arg;
- }
- else
- addLink(linkForNode(n,relative), arg, &html);
- html += QLatin1String("</span>");
- handled = true;
- }
- else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
- par1 = QStringRef();
- if (arg.at(0) == QChar('&'))
- html += arg;
- else {
- const Node* n = qdb_->findNodeForInclude(QStringList(arg.toString()));
- if (n && n != relative)
- addLink(linkForNode(n,relative), arg, &html);
- else
- html += arg;
- }
- handled = true;
- }
- if (!handled) {
- html += charLangle;
- html += charAt;
- }
- }
- else {
- html += src.at(i++);
- }
- }
-
- // replace all
- // "<@comment>" -> "<span class=\"comment\">";
- // "<@preprocessor>" -> "<span class=\"preprocessor\">";
- // "<@string>" -> "<span class=\"string\">";
- // "<@char>" -> "<span class=\"char\">";
- // "<@number>" -> "<span class=\"number\">";
- // "<@op>" -> "<span class=\"operator\">";
- // "<@type>" -> "<span class=\"type\">";
- // "<@name>" -> "<span class=\"name\">";
- // "<@keyword>" -> "<span class=\"keyword\">";
- // "</@(?:comment|preprocessor|string|char|number|op|type|name|keyword)>" -> "</span>"
- src = html;
- html = QString();
- static const QString spanTags[] = {
- "<@comment>", "<span class=\"comment\">",
- "<@preprocessor>", "<span class=\"preprocessor\">",
- "<@string>", "<span class=\"string\">",
- "<@char>", "<span class=\"char\">",
- "<@number>", "<span class=\"number\">",
- "<@op>", "<span class=\"operator\">",
- "<@type>", "<span class=\"type\">",
- "<@name>", "<span class=\"name\">",
- "<@keyword>", "<span class=\"keyword\">",
- "</@comment>", "</span>",
- "</@preprocessor>", "</span>",
- "</@string>", "</span>",
- "</@char>", "</span>",
- "</@number>", "</span>",
- "</@op>", "</span>",
- "</@type>", "</span>",
- "</@name>", "</span>",
- "</@keyword>", "</span>",
- };
- // Update the upper bound of k in the following code to match the length
- // of the above array.
- for (int i = 0, n = src.size(); i < n;) {
- if (src.at(i) == charLangle) {
- bool handled = false;
- for (int k = 0; k != 18; ++k) {
- const QString & tag = spanTags[2 * k];
- if (tag == QStringRef(&src, i, tag.length())) {
- html += spanTags[2 * k + 1];
- i += tag.length();
- handled = true;
- break;
- }
- }
- if (!handled) {
- ++i;
- if (src.at(i) == charAt ||
- (src.at(i) == QLatin1Char('/') && src.at(i + 1) == charAt)) {
- // drop 'our' unknown tags (the ones still containing '@')
- while (i < n && src.at(i) != QLatin1Char('>'))
- ++i;
- ++i;
- }
- else {
- // retain all others
- html += charLangle;
- }
- }
- }
- else {
- html += src.at(i);
- ++i;
- }
- }
- return html;
-}
-
-void HtmlGenerator::generateLink(const Atom* atom, CodeMarker* marker)
-{
- static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_");
-
- if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) {
- // hack for C++: move () outside of link
- int k = funcLeftParen.pos(1);
- out() << protectEnc(atom->string().left(k));
- if (link_.isEmpty()) {
- if (showBrokenLinks)
- out() << "</i>";
- } else {
- out() << "</a>";
- }
- inLink_ = false;
- out() << protectEnc(atom->string().mid(k));
- } else {
- out() << protectEnc(atom->string());
- }
-}
-
-QString HtmlGenerator::registerRef(const QString& ref)
-{
- QString clean = Generator::cleanRef(ref);
-
- for (;;) {
- QString& prevRef = refMap[clean.toLower()];
- if (prevRef.isEmpty()) {
- prevRef = ref;
- break;
- } else if (prevRef == ref) {
- break;
- }
- clean += QLatin1Char('x');
- }
- return clean;
-}
-
-QString HtmlGenerator::protectEnc(const QString &string)
-{
-#ifndef QT_NO_TEXTCODEC
- return protect(string, outputEncoding);
-#else
- return protect(string);
-#endif
-}
-
-QString HtmlGenerator::protect(const QString &string, const QString &outputEncoding)
-{
-#define APPEND(x) \
- if (html.isEmpty()) { \
- html = string; \
- html.truncate(i); \
-} \
- html += (x);
-
- QString html;
- int n = string.length();
-
- for (int i = 0; i < n; ++i) {
- QChar ch = string.at(i);
-
- if (ch == QLatin1Char('&')) {
- APPEND("&amp;");
- } else if (ch == QLatin1Char('<')) {
- APPEND("&lt;");
- } else if (ch == QLatin1Char('>')) {
- APPEND("&gt;");
- } else if (ch == QLatin1Char('"')) {
- APPEND("&quot;");
- } else if ((outputEncoding == "ISO-8859-1" && ch.unicode() > 0x007F)
- || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/'))
- || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) {
- // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator
- APPEND("&#x");
- html += QString::number(ch.unicode(), 16);
- html += QLatin1Char(';');
- } else {
- if (!html.isEmpty())
- html += ch;
- }
- }
-
- if (!html.isEmpty())
- return html;
- return string;
-
-#undef APPEND
-}
-
-QString HtmlGenerator::fileBase(const Node *node) const
-{
- QString result;
-
- result = Generator::fileBase(node);
-
- if (!node->isInnerNode()) {
- switch (node->status()) {
- case Node::Compat:
- result += "-compat";
- break;
- case Node::Obsolete:
- result += "-obsolete";
- break;
- default:
- ;
- }
- }
- return result;
-}
-
-QString HtmlGenerator::fileName(const Node *node)
-{
- if (node->type() == Node::Document) {
- if (static_cast<const DocumentNode *>(node)->subType() == Node::ExternalPage)
- return node->name();
- if (static_cast<const DocumentNode *>(node)->subType() == Node::Image)
- return node->name();
- }
- return Generator::fileName(node);
-}
-
-QString HtmlGenerator::refForNode(const Node *node)
-{
- const FunctionNode *func;
- const TypedefNode *typedeffe;
- QString ref;
-
- switch (node->type()) {
- case Node::Namespace:
- case Node::Class:
- default:
- break;
- case Node::Enum:
- ref = node->name() + "-enum";
- break;
- case Node::Typedef:
- typedeffe = static_cast<const TypedefNode *>(node);
- if (typedeffe->associatedEnum()) {
- return refForNode(typedeffe->associatedEnum());
- }
- else {
- ref = node->name() + "-typedef";
- }
- break;
- case Node::Function:
- func = static_cast<const FunctionNode *>(node);
- if (func->associatedProperty()) {
- return refForNode(func->associatedProperty());
- }
- else {
- ref = func->name();
- if (func->overloadNumber() != 1)
- ref += QLatin1Char('-') + QString::number(func->overloadNumber());
- }
- break;
- case Node::Document:
- break;
- case Node::QmlProperty:
- if (node->isAttached())
- ref = node->name() + "-attached-prop";
- else
- ref = node->name() + "-prop";
- break;
- case Node::QmlPropertyGroup:
- case Node::Property:
- ref = node->name() + "-prop";
- break;
- case Node::QmlSignal:
- ref = node->name() + "-signal";
- break;
- case Node::QmlSignalHandler:
- ref = node->name() + "-signal-handler";
- break;
- case Node::QmlMethod:
- func = static_cast<const FunctionNode *>(node);
- ref = func->name() + "-method";
- if (func->overloadNumber() != 1)
- ref += QLatin1Char('-') + QString::number(func->overloadNumber());
- break;
- case Node::Variable:
- ref = node->name() + "-var";
- break;
- }
- return registerRef(ref);
-}
-
-/*!
- This function is called for links, i.e. for words that
- are marked with the qdoc link command. For autolinks
- that are not marked with the qdoc link command, the
- getAutoLink() function is called
-
- It returns the string for a link found by using the data
- in the \a atom to search the database. It also sets \a node
- to point to the target node for that link. \a relative points
- to the node holding the qdoc comment where the link command
- was found.
- */
-QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Node** node)
-{
- const QString& t = atom->string();
- if (t.at(0) == QChar('h')) {
- if (t.startsWith("http:") || t.startsWith("https:"))
- return t;
- }
- else if (t.at(0) == QChar('f')) {
- if (t.startsWith("file:") || t.startsWith("ftp:"))
- return t;
- }
- else if (t.at(0) == QChar('m')) {
- if (t.startsWith("mailto:"))
- return t;
- }
- return getAutoLink(atom, relative, node);
-}
-
-/*!
- This function is called for autolinks, i.e. for words that
- are not marked with the qdoc link command that qdoc has
- reason to believe should be links. For links marked with
- the qdoc link command, the getLink() function is called.
-
- It returns the string for a link found by using the data
- in the \a atom to search the database. It also sets \a node
- to point to the target node for that link. \a relative points
- to the node holding the qdoc comment where the link command
- was found.
- */
-QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const Node** node)
-{
- QString ref;
-
- *node = qdb_->findNodeForAtom(atom, relative, ref);
- if (!(*node)) {
- return QString();
- }
-
- 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)
- link.truncate(hashtag);
- link += "#" + 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
- generating is in the same file as the target. Note the
- relative node can be 0, which pretty much guarantees
- that the link and the target aren't in the same file.
- */
-QString HtmlGenerator::linkForNode(const Node *node, const Node *relative)
-{
- if (node == 0)
- return QString();
- if (!node->url().isEmpty())
- return node->url();
- if (fileBase(node).isEmpty())
- return QString();
- if (node->access() == Node::Private)
- return QString();
-
- QString fn = fileName(node);
- 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->isQmlPropertyGroup() || node->isJsPropertyGroup()) {
- QString ref = refForNode(node);
- if (relative && fn == fileName(relative) && ref == refForNode(relative))
- return QString();
-
- link += QLatin1Char('#');
- link += ref;
- }
- /*
- If the output is going to subdirectories, then if the
- two nodes will be output to different directories, then
- the link must go up to the parent directory and then
- back down into the other subdirectory.
- */
- if (node && relative && (node != relative)) {
- if (useOutputSubdirs() && !node->isExternalPage() &&
- node->outputSubdirectory() != relative->outputSubdirectory()) {
- if (link.startsWith(QString(node->outputSubdirectory() + QLatin1Char('/')))) {
- link.prepend(QString("../"));
- }
- else {
- link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/')));
- }
- }
- }
- return link;
-}
-
-void HtmlGenerator::generateFullName(const Node *apparentNode, const Node *relative, const Node *actualNode)
-{
- if (actualNode == 0)
- actualNode = apparentNode;
- out() << "<a href=\"" << linkForNode(actualNode, relative);
- if (true || relative == 0 || relative->status() != actualNode->status()) {
- switch (actualNode->status()) {
- case Node::Obsolete:
- out() << "\" class=\"obsolete";
- break;
- case Node::Compat:
- out() << "\" class=\"compat";
- break;
- default:
- ;
- }
- }
- out() << "\">";
- out() << protectEnc(apparentNode->fullName(relative));
- out() << "</a>";
-}
-
-void HtmlGenerator::generateDetailedMember(const Node *node,
- const InnerNode *relative,
- CodeMarker *marker)
-{
- const EnumNode *enume;
-
-#ifdef GENERATE_MAC_REFS
- 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()) {
-#ifdef GENERATE_MAC_REFS
- generateMacRef(enume->flagsType(), marker);
-#endif
- out() << "<h3 class=\"flags\" id=\"" << nodeRef << "\">";
- out() << "<a name=\"" + nodeRef + "\"></a>";
- generateSynopsis(enume, relative, marker, CodeMarker::Detailed);
- out() << "<br/>";
- generateSynopsis(enume->flagsType(),
- relative,
- marker,
- CodeMarker::Detailed);
- out() << "</h3>\n";
- }
- else {
- out() << "<h3 class=\"fn\" id=\"" << nodeRef << "\">";
- out() << "<a name=\"" + nodeRef + "\"></a>";
- generateSynopsis(node, relative, marker, CodeMarker::Detailed);
- out() << "</h3>" << divNavTop << '\n';
- }
-
- generateStatus(node, marker);
- generateBody(node, marker);
- generateThreadSafeness(node, marker);
- generateSince(node, marker);
-
- if (node->type() == Node::Property) {
- const PropertyNode *property = static_cast<const PropertyNode *>(node);
- Section section;
-
- section.members += property->getters();
- section.members += property->setters();
- section.members += property->resetters();
-
- if (!section.members.isEmpty()) {
- out() << "<p><b>Access functions:</b></p>\n";
- generateSectionList(section, node, marker, CodeMarker::Accessors);
- }
-
- Section notifiers;
- notifiers.members += property->notifiers();
-
- if (!notifiers.members.isEmpty()) {
- out() << "<p><b>Notifier signal:</b></p>\n";
- //out() << "<p>This signal is emitted when the property value is changed.</p>\n";
- generateSectionList(notifiers, node, marker, CodeMarker::Accessors);
- }
- }
- else if (node->isFunction()) {
- const FunctionNode* fn = static_cast<const FunctionNode*>(node);
- if (fn->isPrivateSignal())
- generatePrivateSignalNote(node, marker);
- }
- else if (node->type() == Node::Enum) {
- const EnumNode *enume = static_cast<const EnumNode *>(node);
- if (enume->flagsType()) {
- out() << "<p>The " << protectEnc(enume->flagsType()->name())
- << " type is a typedef for "
- << "<a href=\"" << qflagsHref_ << "\">QFlags</a>&lt;"
- << protectEnc(enume->name())
- << "&gt;. It stores an OR combination of "
- << protectEnc(enume->name())
- << " values.</p>\n";
- }
- }
- generateAlsoList(node, marker);
- generateExtractionMark(node, EndMark);
-}
-
-int HtmlGenerator::hOffset(const Node *node)
-{
- switch (node->type()) {
- case Node::Namespace:
- case Node::Class:
- return 2;
- case Node::QmlBasicType:
- case Node::QmlType:
- case Node::Document:
- return 1;
- case Node::Enum:
- case Node::Typedef:
- case Node::Function:
- case Node::Property:
- default:
- return 3;
- }
-}
-
-bool HtmlGenerator::isThreeColumnEnumValueTable(const Atom *atom)
-{
- while (atom != 0 && !(atom->type() == Atom::ListRight && atom->string() == ATOM_LIST_VALUE)) {
- if (atom->type() == Atom::ListItemLeft && !matchAhead(atom, Atom::ListItemRight))
- return true;
- atom = atom->next();
- }
- return false;
-}
-
-
-const QPair<QString,QString> HtmlGenerator::anchorForNode(const Node *node)
-{
- QPair<QString,QString> anchorPair;
-
- anchorPair.first = Generator::fileName(node);
- if (node->type() == Node::Document) {
- const DocumentNode *docNode = static_cast<const DocumentNode*>(node);
- anchorPair.second = docNode->title();
- }
-
- return anchorPair;
-}
-
-void HtmlGenerator::generateStatus(const Node *node, CodeMarker *marker)
-{
- Text text;
-
- switch (node->status()) {
- case Node::Obsolete:
- if (node->isInnerNode())
- Generator::generateStatus(node, marker);
- break;
- case Node::Compat:
- // Porting to Qt 4 no longer supported
- break;
- default:
- Generator::generateStatus(node, marker);
- }
-}
-
-#ifdef GENERATE_MAC_REFS
-/*
- No longer valid.
- */
-void HtmlGenerator::generateMacRef(const Node *node, CodeMarker *marker)
-{
- if (!pleaseGenerateMacRef || marker == 0)
- return;
-
- QStringList macRefs = marker->macRefsForNode(node);
- foreach (const QString &macRef, macRefs)
- out() << "<a name=\"" << "//apple_ref/" << macRef << "\"></a>\n";
-}
-#endif
-
-void HtmlGenerator::beginLink(const QString &link, const Node *node, const Node *relative)
-{
- link_ = link;
- if (link_.isEmpty()) {
- if (showBrokenLinks)
- out() << "<i>";
- }
- else if (node == 0 ||
- (relative != 0 && node->status() == relative->status())) {
- out() << "<a href=\"" << link_ << "\">";
- }
- else {
- switch (node->status()) {
- case Node::Obsolete:
- out() << "<a href=\"" << link_ << "\" class=\"obsolete\">";
- break;
- case Node::Compat:
- out() << "<a href=\"" << link_ << "\" class=\"compat\">";
- break;
- default:
- out() << "<a href=\"" << link_ << "\">";
- }
- }
- inLink_ = true;
-}
-
-void HtmlGenerator::endLink()
-{
- if (inLink_) {
- if (link_.isEmpty()) {
- if (showBrokenLinks)
- out() << "</i>";
- }
- else {
- if (inObsoleteLink) {
- out() << "<sup>(obsolete)</sup>";
- }
- out() << "</a>";
- }
- }
- inLink_ = false;
- inObsoleteLink = false;
-}
-
-/*!
- Generates the summary for the \a section. Only used for
- sections of QML element documentation.
- */
-void HtmlGenerator::generateQmlSummary(const Section& section,
- const Node *relative,
- CodeMarker *marker)
-{
- if (!section.members.isEmpty()) {
- out() << "<ul>\n";
- NodeList::ConstIterator m;
- m = section.members.constBegin();
- while (m != section.members.constEnd()) {
- out() << "<li class=\"fn\">";
- generateQmlItem(*m,relative,marker,true);
- if ((*m)->type() == Node::QmlPropertyGroup) {
- const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(*m);
- if (!qpgn->childNodes().isEmpty()) {
- NodeList::ConstIterator p = qpgn->childNodes().constBegin();
- out() << "<ul>\n";
- while (p != qpgn->childNodes().constEnd()) {
- if ((*p)->type() == Node::QmlProperty) {
- out() << "<li class=\"fn\">";
- generateQmlItem(*p, relative, marker, true);
- out() << "</li>\n";
- }
- ++p;
- }
- out() << "</ul>\n";
- }
- }
- out() << "</li>\n";
- ++m;
- }
- out() << "</ul>\n";
- }
-}
-
-/*!
- Outputs the html detailed documentation for a section
- on a QML element reference page.
- */
-void HtmlGenerator::generateDetailedQmlMember(Node *node,
- const InnerNode *relative,
- CodeMarker *marker)
-{
- QmlPropertyNode* qpn = 0;
-#ifdef GENERATE_MAC_REFS
- generateMacRef(node, marker);
-#endif
- generateExtractionMark(node, MemberMark);
- generateKeywordAnchors(node);
- out() << "<div class=\"qmlitem\">";
- QString nodeRef = refForNode(node);
- if (node->type() == Node::QmlPropertyGroup) {
- const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(node);
- NodeList::ConstIterator p = qpgn->childNodes().constBegin();
- out() << "<div class=\"qmlproto\">";
- out() << "<div class=\"table\"><table class=\"qmlname\">";
-
- QString heading = qpgn->name() + " group";
- out() << "<tr valign=\"top\" class=\"even\" id=\"" << nodeRef << "\">";
- out() << "<th class=\"centerAlign\"><p>";
- out() << "<a name=\"" + nodeRef + "\"></a>";
- out() << "<b>" << heading << "</b>";
- out() << "</p></th></tr>";
- while (p != qpgn->childNodes().constEnd()) {
- if ((*p)->type() == Node::QmlProperty) {
- qpn = static_cast<QmlPropertyNode*>(*p);
- nodeRef = refForNode(qpn);
- out() << "<tr valign=\"top\" class=\"odd\" id=\"" << nodeRef << "\">";
- out() << "<td class=\"tblQmlPropNode\"><p>";
- out() << "<a name=\"" + nodeRef + "\"></a>";
-
- if (!qpn->isWritable())
- out() << "<span class=\"qmlreadonly\">read-only</span>";
- if (qpn->isDefault())
- out() << "<span class=\"qmldefault\">default</span>";
- generateQmlItem(qpn, relative, marker, false);
- out() << "</p></td></tr>";
- }
- ++p;
- }
- out() << "</table></div>";
- out() << "</div>";
- }
- else if (node->type() == Node::QmlProperty) {
- qpn = static_cast<QmlPropertyNode*>(node);
- out() << "<div class=\"qmlproto\">";
- out() << "<div class=\"table\"><table class=\"qmlname\">";
- out() << "<tr valign=\"top\" class=\"odd\" id=\"" << nodeRef << "\">";
- out() << "<td class=\"tblQmlPropNode\"><p>";
- out() << "<a name=\"" + refForNode(qpn) + "\"></a>";
- if (!qpn->isReadOnlySet()) {
- if (qpn->declarativeCppNode())
- qpn->setReadOnly(!qpn->isWritable());
- }
- if (qpn->isReadOnly())
- out() << "<span class=\"qmlreadonly\">read-only</span>";
- if (qpn->isDefault())
- out() << "<span class=\"qmldefault\">default</span>";
- generateQmlItem(qpn, relative, marker, false);
- out() << "</p></td></tr>";
- out() << "</table></div>";
- out() << "</div>";
- }
- else if (node->type() == Node::QmlSignal) {
- const FunctionNode* qsn = static_cast<const FunctionNode*>(node);
- out() << "<div class=\"qmlproto\">";
- out() << "<div class=\"table\"><table class=\"qmlname\">";
- out() << "<tr valign=\"top\" class=\"odd\" id=\"" << nodeRef << "\">";
- out() << "<td class=\"tblQmlFuncNode\"><p>";
- out() << "<a name=\"" + refForNode(qsn) + "\"></a>";
- generateSynopsis(qsn,relative,marker,CodeMarker::Detailed,false);
- out() << "</p></td></tr>";
- out() << "</table></div>";
- out() << "</div>";
- }
- else if (node->type() == Node::QmlSignalHandler) {
- const FunctionNode* qshn = static_cast<const FunctionNode*>(node);
- out() << "<div class=\"qmlproto\">";
- out() << "<div class=\"table\"><table class=\"qmlname\">";
- out() << "<tr valign=\"top\" class=\"odd\" id=\"" << nodeRef << "\">";
- out() << "<td class=\"tblQmlFuncNode\"><p>";
- out() << "<a name=\"" + refForNode(qshn) + "\"></a>";
- generateSynopsis(qshn,relative,marker,CodeMarker::Detailed,false);
- out() << "</p></td></tr>";
- out() << "</table></div>";
- out() << "</div>";
- }
- else if (node->type() == Node::QmlMethod) {
- const FunctionNode* qmn = static_cast<const FunctionNode*>(node);
- out() << "<div class=\"qmlproto\">";
- out() << "<div class=\"table\"><table class=\"qmlname\">";
- out() << "<tr valign=\"top\" class=\"odd\" id=\"" << nodeRef << "\">";
- out() << "<td class=\"tblQmlFuncNode\"><p>";
- out() << "<a name=\"" + refForNode(qmn) + "\"></a>";
- generateSynopsis(qmn,relative,marker,CodeMarker::Detailed,false);
- out() << "</p></td></tr>";
- out() << "</table></div>";
- out() << "</div>";
- }
- out() << "<div class=\"qmldoc\">";
- generateStatus(node, marker);
- generateBody(node, marker);
- generateThreadSafeness(node, marker);
- generateSince(node, marker);
- generateAlsoList(node, marker);
- out() << "</div>";
- out() << "</div>";
- generateExtractionMark(node, EndMark);
-}
-
-/*!
- Output the "Inherits" line for the QML element,
- if there should be one.
- */
-void HtmlGenerator::generateQmlInherits(QmlTypeNode* qcn, CodeMarker* marker)
-{
- if (!qcn)
- return;
- QmlTypeNode* base = qcn->qmlBaseNode();
- while (base && base->isInternal()) {
- base = base->qmlBaseNode();
- }
- if (base) {
- Text text;
- text << Atom::ParaLeft << "Inherits ";
- text << Atom(Atom::LinkNode,CodeMarker::stringForNode(base));
- text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
- text << Atom(Atom::String, base->name());
- text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
- text << Atom::ParaRight;
- generateText(text, qcn, marker);
- }
-}
-
-/*!
- Output the "[Xxx instantiates the C++ class QmlGraphicsXxx]"
- line for the QML element, if there should be one.
-
- If there is no class node, or if the class node status
- is set to Node::Internal, do nothing.
- */
-void HtmlGenerator::generateQmlInstantiates(QmlTypeNode* qcn, CodeMarker* marker)
-{
- ClassNode* cn = qcn->classNode();
- if (cn && (cn->status() != Node::Internal)) {
- Text text;
- text << Atom::ParaLeft;
- text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn));
- text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
- QString name = qcn->name();
- /*
- Remove the "QML:" prefix, if present.
- It shouldn't be present anymore.
- */
- if (name.startsWith(QLatin1String("QML:")))
- name = name.mid(4); // remove the "QML:" prefix
- text << Atom(Atom::String, name);
- text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
- text << " instantiates the C++ class ";
- 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 << Atom::ParaRight;
- generateText(text, qcn, marker);
- }
-}
-
-/*!
- Output the "[QmlGraphicsXxx is instantiated by QML Type Xxx]"
- line for the class, if there should be one.
-
- If there is no QML element, or if the class node status
- is set to Node::Internal, do nothing.
- */
-void HtmlGenerator::generateInstantiatedBy(ClassNode* cn, CodeMarker* marker)
-{
- if (cn && cn->status() != Node::Internal && cn->qmlElement() != 0) {
- 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);
- 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());
- text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
- text << Atom::ParaRight;
- generateText(text, cn, marker);
- }
-}
-
-void HtmlGenerator::generateExtractionMark(const Node *node, ExtractionMarkType markType)
-{
- if (markType != EndMark) {
- out() << "<!-- $$$" + node->name();
- if (markType == MemberMark) {
- if (node->type() == Node::Function) {
- const FunctionNode *func = static_cast<const FunctionNode *>(node);
- if (!func->associatedProperty()) {
- if (func->overloadNumber() == 1)
- out() << "[overload1]";
- out() << "$$$" + func->name() + func->rawParameters().remove(' ');
- }
- } else if (node->type() == Node::Property) {
- out() << "-prop";
- const PropertyNode *prop = static_cast<const PropertyNode *>(node);
- const NodeList &list = prop->functions();
- foreach (const Node *propFuncNode, list) {
- if (propFuncNode->type() == Node::Function) {
- const FunctionNode *func = static_cast<const FunctionNode *>(propFuncNode);
- out() << "$$$" + func->name() + func->rawParameters().remove(' ');
- }
- }
- } else if (node->type() == Node::Enum) {
- const EnumNode *enumNode = static_cast<const EnumNode *>(node);
- foreach (const EnumItem &item, enumNode->items())
- out() << "$$$" + item.name();
- }
- } else if (markType == BriefMark) {
- out() << "-brief";
- } else if (markType == DetailedDescriptionMark) {
- out() << "-description";
- }
- out() << " -->\n";
- } else {
- out() << "<!-- @@@" + node->name() + " -->\n";
- }
-}
-
-
-/*!
- This function outputs one or more manifest files in XML.
- They are used by Creator.
- */
-void HtmlGenerator::generateManifestFiles()
-{
- generateManifestFile("examples", "example");
- generateManifestFile("demos", "demo");
- qdb_->exampleNodeMap().clear();
- manifestMetaContent.clear();
-}
-
-/*!
- This function is called by generateManifestFiles(), once
- for each manifest file to be generated. \a manifest is the
- type of manifest file.
- */
-void HtmlGenerator::generateManifestFile(const QString &manifest, const QString &element)
-{
- ExampleNodeMap& exampleNodeMap = qdb_->exampleNodeMap();
- if (exampleNodeMap.isEmpty())
- return;
- QString fileName = manifest +"-manifest.xml";
- QFile file(outputDir() + QLatin1Char('/') + fileName);
- bool demos = false;
- if (manifest == "demos")
- demos = true;
-
- bool proceed = false;
- ExampleNodeMap::Iterator i = exampleNodeMap.begin();
- while (i != exampleNodeMap.end()) {
- const ExampleNode* en = i.value();
- if (demos) {
- if (en->name().startsWith("demos")) {
- proceed = true;
- break;
- }
- }
- else if (!en->name().startsWith("demos")) {
- proceed = true;
- break;
- }
- ++i;
- }
- if (!proceed || !file.open(QFile::WriteOnly | QFile::Text))
- return;
-
- QXmlStreamWriter writer(&file);
- writer.setAutoFormatting(true);
- writer.writeStartDocument();
- writer.writeStartElement("instructionals");
- writer.writeAttribute("module", project);
- writer.writeStartElement(manifest);
-
- QStringList usedAttributes;
- i = exampleNodeMap.begin();
- while (i != exampleNodeMap.end()) {
- const ExampleNode* en = i.value();
- if (demos) {
- if (!en->name().startsWith("demos")) {
- ++i;
- continue;
- }
- }
- else if (en->name().startsWith("demos")) {
- ++i;
- continue;
- }
- // attributes that are always written for the element
- usedAttributes.clear();
- usedAttributes << "name" << "docUrl" << "projectPath";
-
- writer.writeStartElement(element);
- writer.writeAttribute("name", en->title());
- QString docUrl = manifestDir + fileBase(en) + ".html";
- writer.writeAttribute("docUrl", docUrl);
- QStringList proFiles;
- foreach (const Node* child, en->childNodes()) {
- if (child->subType() == Node::File) {
- QString file = child->name();
- if (file.endsWith(".pro") || file.endsWith(".qmlproject")) {
- proFiles << file;
- }
- }
- }
- if (!proFiles.isEmpty()) {
- if (proFiles.size() == 1) {
- writer.writeAttribute("projectPath", examplesPath + proFiles[0]);
- }
- else {
- QString exampleName = en->name().split('/').last();
- bool proWithExampleNameFound = false;
- for (int j = 0; j < proFiles.size(); j++)
- {
- if (proFiles[j].endsWith(QStringLiteral("%1/%1.pro").arg(exampleName))
- || proFiles[j].endsWith(QStringLiteral("%1/%1.qmlproject").arg(exampleName))) {
- writer.writeAttribute("projectPath", examplesPath + proFiles[j]);
- proWithExampleNameFound = true;
- break;
- }
- }
- if (!proWithExampleNameFound)
- writer.writeAttribute("projectPath", examplesPath + proFiles[0]);
- }
- }
- if (!en->imageFileName().isEmpty()) {
- writer.writeAttribute("imageUrl", manifestDir + en->imageFileName());
- usedAttributes << "imageUrl";
- }
-
- QString fullName = project + QLatin1Char('/') + en->title();
- QSet<QString> tags;
- for (int idx=0; idx < manifestMetaContent.size(); ++idx) {
- foreach (const QString &name, manifestMetaContent[idx].names) {
- bool match = false;
- int wildcard = name.indexOf(QChar('*'));
- switch (wildcard) {
- case -1: // no wildcard, exact match
- match = (fullName == name);
- break;
- case 0: // '*' matches all
- match = true;
- break;
- default: // match with wildcard at the end
- match = fullName.startsWith(name.left(wildcard));
- }
- if (match) {
- tags += manifestMetaContent[idx].tags;
- foreach (const QString &attr, manifestMetaContent[idx].attributes) {
- QLatin1Char div(':');
- QStringList attrList = attr.split(div);
- if (attrList.count() == 1)
- attrList.append(QStringLiteral("true"));
- QString attrName = attrList.takeFirst();
- if (!usedAttributes.contains(attrName)) {
- writer.writeAttribute(attrName, attrList.join(div));
- usedAttributes << attrName;
- }
- }
- }
- }
- }
-
- writer.writeStartElement("description");
- Text brief = en->doc().briefText();
- if (!brief.isEmpty())
- writer.writeCDATA(brief.toString());
- else
- writer.writeCDATA(QString("No description available"));
- writer.writeEndElement(); // description
-
- // Add words from module name as tags
- // QtQuickControls -> qt,quick,controls
- // QtOpenGL -> qt,opengl
- QRegExp re("([A-Z]+[a-z0-9]*(3D|GL)?)");
- int pos = 0;
- while ((pos = re.indexIn(project, pos)) != -1) {
- tags << re.cap(1).toLower();
- pos += re.matchedLength();
- }
- tags += QSet<QString>::fromList(en->title().toLower().split(QLatin1Char(' ')));
-
- // Clean up tags, exclude invalid and common words
- QSet<QString>::iterator tag_it = tags.begin();
- QSet<QString> modified;
- while (tag_it != tags.end()) {
- QString s = *tag_it;
- if (s.at(0) == '(')
- s.remove(0, 1).chop(1);
- if (s.endsWith(QLatin1Char(':')))
- s.chop(1);
-
- if (s.length() < 2
- || s.at(0).isDigit()
- || s.at(0) == '-'
- || s == QStringLiteral("qt")
- || s == QStringLiteral("the")
- || s == QStringLiteral("and")
- || s.startsWith(QStringLiteral("example"))
- || s.startsWith(QStringLiteral("chapter")))
- tag_it = tags.erase(tag_it);
- else if (s != *tag_it) {
- modified << s;
- tag_it = tags.erase(tag_it);
- }
- else
- ++tag_it;
- }
- tags += modified;
-
- if (!tags.isEmpty()) {
- writer.writeStartElement("tags");
- bool wrote_one = false;
- foreach (QString tag, tags) {
- if (wrote_one)
- writer.writeCharacters(",");
- writer.writeCharacters(tag);
- wrote_one = true;
- }
- writer.writeEndElement(); // tags
- }
-
- QString ename = en->name().mid(en->name().lastIndexOf('/')+1);
- QMap<int, const Node*> filesToOpen;
- foreach (const Node* child, en->childNodes()) {
- if (child->subType() == Node::File) {
- QFileInfo fileInfo(child->name());
- QString fileName = fileInfo.fileName().toLower();
- // open .qml, .cpp and .h files with a
- // basename matching the example (project) name
- // QMap key indicates the priority -
- // the lowest value will be the top-most file
- if ((fileInfo.baseName().compare(ename, Qt::CaseInsensitive) == 0)) {
- if (fileName.endsWith(".qml"))
- filesToOpen.insert(0, child);
- else if (fileName.endsWith(".cpp"))
- filesToOpen.insert(1, child);
- else if (fileName.endsWith(".h"))
- filesToOpen.insert(2, child);
- }
- // main.qml takes precedence over main.cpp
- else if (fileName.endsWith("main.qml")) {
- filesToOpen.insert(3, child);
- }
- else if (fileName.endsWith("main.cpp")) {
- filesToOpen.insert(4, child);
- }
- }
- }
-
- QMap<int, const Node*>::const_iterator it = filesToOpen.constEnd();
- while (it != filesToOpen.constBegin()) {
- writer.writeStartElement("fileToOpen");
- if (--it == filesToOpen.constBegin()) {
- writer.writeAttribute(QStringLiteral("mainFile"), QStringLiteral("true"));
- }
- writer.writeCharacters(examplesPath + it.value()->name());
- writer.writeEndElement();
- }
-
- writer.writeEndElement(); // example
- ++i;
- }
-
- writer.writeEndElement(); // examples
- writer.writeEndElement(); // instructionals
- writer.writeEndDocument();
- file.close();
-}
-
-/*!
- 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)
-{
- QStringList names = config.getStringList(CONFIG_MANIFESTMETA + Config::dot + QStringLiteral("filters"));
-
- foreach (const QString &manifest, names) {
- ManifestMetaFilter filter;
- QString prefix = CONFIG_MANIFESTMETA + Config::dot + manifest + Config::dot;
- filter.names = config.getStringSet(prefix + QStringLiteral("names"));
- filter.attributes = config.getStringSet(prefix + QStringLiteral("attributes"));
- filter.tags = config.getStringSet(prefix + QStringLiteral("tags"));
- manifestMetaContent.append(filter);
- }
-}
-
-/*!
- Find global entities that have documentation but no
- \e{relates} comand. Report these as errors if they
- are not also marked \e {internal}.
-
- type: Class
- type: Namespace
-
- subtype: Example
- subtype: External page
- subtype: Group
- subtype: Header file
- subtype: Module
- subtype: Page
- subtype: QML basic type
- subtype: QML class
- subtype: QML module
- */
-void HtmlGenerator::reportOrphans(const InnerNode* parent)
-{
- const NodeList& children = parent->childNodes();
- if (children.size() == 0)
- return;
-
- bool related;
- QString message;
- for (int i=0; i<children.size(); ++i) {
- Node* child = children[i];
- if (!child || child->isInternal() || child->doc().isEmpty())
- continue;
- if (child->relates()) {
- related = true;
- message = child->relates()->name();
- }
- else {
- related = false;
- message = "has documentation but no \\relates command";
- }
- switch (child->type()) {
- case Node::Namespace:
- break;
- case Node::Class:
- break;
- case Node::QmlType:
- break;
- case Node::QmlBasicType:
- break;
- case Node::Group:
- break;
- case Node::Module:
- break;
- case Node::QmlModule:
- break;
- case Node::Document:
- switch (child->subType()) {
- case Node::Example:
- break;
- case Node::HeaderFile:
- break;
- case Node::File:
- break;
- case Node::Image:
- break;
- case Node::Page:
- break;
- case Node::ExternalPage:
- break;
- default:
- break;
- }
- break;
- case Node::Enum:
- if (!related)
- child->location().warning(tr("Global enum, %1, %2").arg(child->name()).arg(message));
- break;
- case Node::Typedef:
- if (!related)
- child->location().warning(tr("Global typedef, %1, %2").arg(child->name()).arg(message));
- break;
- case Node::Function:
- if (!related) {
- const FunctionNode* fn = static_cast<const FunctionNode*>(child);
- if (fn->isMacro())
- child->location().warning(tr("Global macro, %1, %2").arg(child->name()).arg(message));
- else
- child->location().warning(tr("Global function, %1(), %2").arg(child->name()).arg(message));
- }
- break;
- case Node::Property:
- break;
- case Node::Variable:
- if (!related)
- child->location().warning(tr("Global variable, %1, %2").arg(child->name()).arg(message));
- break;
- case Node::QmlPropertyGroup:
- break;
- case Node::QmlProperty:
- if (!related)
- child->location().warning(tr("Global QML property, %1, %2").arg(child->name()).arg(message));
- break;
- case Node::QmlSignal:
- if (!related)
- child->location().warning(tr("Global QML, signal, %1 %2").arg(child->name()).arg(message));
- break;
- case Node::QmlSignalHandler:
- if (!related)
- child->location().warning(tr("Global QML signal handler, %1, %2").arg(child->name()).arg(message));
- break;
- case Node::QmlMethod:
- if (!related)
- child->location().warning(tr("Global QML method, %1, %2").arg(child->name()).arg(message));
- break;
- default:
- break;
- }
- }
-}
-
-/*!
- Returns a reference to the XML stream writer currently in use.
- There is one XML stream writer open for each XML file being
- written, and they are kept on a stack. The one on top of the
- stack is the one being written to at the moment. In the HTML
- output generator, it is perhaps impossible for there to ever
- be more than one writer open.
- */
-QXmlStreamWriter& HtmlGenerator::xmlWriter()
-{
- return *xmlWriterStack.top();
-}
-
-/*!
- This function is only called for writing ditamaps.
-
- Calls beginSubPage() in the base class to open the file.
- Then creates a new XML stream writer using the IO device
- from opened file and pushes the XML writer onto a stackj.
- Creates the file named \a fileName in the output directory.
- Attaches a QTextStream to the created file, which is written
- to all over the place using out(). Finally, it sets some
- parameters in the XML writer and calls writeStartDocument().
-
- It also ensures that a GUID map is created for the output file.
- */
-void HtmlGenerator::beginDitamapPage(const InnerNode* node, const QString& fileName)
-{
- Generator::beginSubPage(node,fileName);
- QXmlStreamWriter* writer = new QXmlStreamWriter(out().device());
- xmlWriterStack.push(writer);
- writer->setAutoFormatting(true);
- writer->setAutoFormattingIndent(4);
- writer->writeStartDocument();
-}
-
-/*!
- This function is only called for writing ditamaps.
-
- Calls writeEndDocument() and then pops the XML stream writer
- off the stack and deletes it. Then it calls endSubPage() in
- the base class to close the device.
- */
-void HtmlGenerator::endDitamapPage()
-{
- xmlWriter().writeEndDocument();
- delete xmlWriterStack.pop();
- Generator::endSubPage();
-}
-
-/*!
- This function is only called for writing ditamaps.
-
- Creates the DITA map from the topicrefs in \a node,
- which is a DitaMapNode.
- */
-void HtmlGenerator::writeDitaMap(const DitaMapNode* node)
-{
- beginDitamapPage(node,node->name());
-
- QString doctype = "<!DOCTYPE map PUBLIC \"-//OASIS//DTD DITA Map//EN\" \"map.dtd\">";
-
- xmlWriter().writeDTD(doctype);
- xmlWriter().writeStartElement("map");
- xmlWriter().writeStartElement("topicmeta");
- xmlWriter().writeStartElement("shortdesc");
- xmlWriter().writeCharacters(node->title());
- xmlWriter().writeEndElement(); // </shortdesc>
- xmlWriter().writeEndElement(); // </topicmeta>
- DitaRefList map = node->map();
- writeDitaRefs(map);
- endDitamapPage();
-}
-
-/*!
- Write the \a ditarefs to the current output file.
- */
-void HtmlGenerator::writeDitaRefs(const DitaRefList& ditarefs)
-{
- foreach (DitaRef* t, ditarefs) {
- if (t->isMapRef())
- xmlWriter().writeStartElement("mapref");
- else
- xmlWriter().writeStartElement("topicref");
- xmlWriter().writeAttribute("navtitle",t->navtitle());
- if (t->href().isEmpty()) {
- const DocumentNode* dn = qdb_->findDocumentNodeByTitle(t->navtitle());
- if (dn)
- xmlWriter().writeAttribute("href",fileName(dn));
- }
- else
- xmlWriter().writeAttribute("href",t->href());
- if (t->subrefs() && !t->subrefs()->isEmpty())
- writeDitaRefs(*(t->subrefs()));
- xmlWriter().writeEndElement(); // </topicref> or </mapref>
- }
-}
-
-QT_END_NAMESPACE