From 1ad78f5f29ef00abae4f718265fa4bc0c35b60f9 Mon Sep 17 00:00:00 2001
From: Topi Reinio <topi.reinio@digia.com>
Date: Tue, 21 Oct 2014 10:22:45 +0200
Subject: [PATCH] qdoc: Prepare QDoc for the new style on qt.io

The new template and CSS have some requirements that need changes
in the generated .html:

    - Generate a new div 'sidebar' and place the TOC (if one
      exists) inside it, allowing the template to extend the
      sidebar contents dynamically. Do this for all pages
      except index.html.

    - Change the DOCTYPE declaration to be html5-compliant

    - Replace <tt> tags with <code> to be html5-compliant

    - Add a new config variable HTML.prologue - this allows
      the template to insert custom html into beginning of
      the page, before the page title but after any navigation
      or table-of-contents items.

    - Wrap tables inside <div> elements. This allows for
      better-working CSS design for small-screen devices.

    - Write out extra parameters first when outputting
      function synopsis to have better styling.

    - Inject zero-width-space characters into function
      names to allow the browser break up long function
      signatures in a nice manner.

    - Edit the CSS for the offline style to adapt to
      above changes.

Task-number: QTBUG-42086
Change-Id: I3075cdc11bcb07a66150388519263fd721c8002b
Reviewed-by: Martin Smith <martin.smith@digia.com>
---
 doc/global/template/style/offline.css |  19 ++++-
 src/tools/qdoc/cppcodemarker.cpp      |  12 +--
 src/tools/qdoc/htmlgenerator.cpp      | 109 +++++++++++++++-----------
 src/tools/qdoc/htmlgenerator.h        |   3 +
 4 files changed, 90 insertions(+), 53 deletions(-)

diff --git a/doc/global/template/style/offline.css b/doc/global/template/style/offline.css
index 126df9d806f..dc0a6d1ec92 100644
--- a/doc/global/template/style/offline.css
+++ b/doc/global/template/style/offline.css
@@ -359,7 +359,9 @@ h3.fn, span.fn {
     margin: 0px;
     margin-top: 45px;
 }
-
+h3.fn code {
+    float: right;
+}
 h3.fn:target {
     background-color: #F6F6D6;
 }
@@ -705,8 +707,21 @@ Landing page
     float: left;
 }
 
-.icons1of3  h2 {
+.icons1of3 h2, .doc-column h2 {
     font-size: 15px;
     margin: 0px;
     padding: 0px;
 }
+
+div.multi-column {
+    position: relative;
+}
+
+div.multi-column div {
+    display: -moz-inline-box;
+    display: inline-block;
+    vertical-align: top;
+    margin-top: 1em;
+    margin-right: 4em;
+    width: 24em;
+}
diff --git a/src/tools/qdoc/cppcodemarker.cpp b/src/tools/qdoc/cppcodemarker.cpp
index 48218da5134..92b6ccca6af 100644
--- a/src/tools/qdoc/cppcodemarker.cpp
+++ b/src/tools/qdoc/cppcodemarker.cpp
@@ -136,7 +136,7 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
 
     if ((style == Detailed) && !node->parent()->name().isEmpty() &&
         (node->type() != Node::Property) && !node->isQmlNode())
-        name.prepend(taggedNode(node->parent()) + "::");
+        name.prepend(taggedNode(node->parent()) + "::&#8203;");
 
     switch (node->type()) {
     case Node::Namespace:
@@ -212,7 +212,7 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
                 bracketed += "slot";
             }
             if (!bracketed.isEmpty())
-                extra += " [" + bracketed.join(' ') + QLatin1Char(']');
+                extra += QLatin1Char('[') + bracketed.join(' ') + QStringLiteral("] ");
         }
         break;
     case Node::Enum:
@@ -283,13 +283,13 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
 
     if (style == Summary) {
         if (node->status() == Node::Preliminary) {
-            extra += " (preliminary)";
+            extra += "(preliminary) ";
         }
         else if (node->status() == Node::Deprecated) {
-            extra += " (deprecated)";
+            extra += "(deprecated) ";
         }
         else if (node->status() == Node::Obsolete) {
-            extra += " (obsolete)";
+            extra += "(obsolete) ";
         }
     }
 
@@ -297,7 +297,7 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node,
         extra.prepend("<@extra>");
         extra.append("</@extra>");
     }
-    return synopsis + extra;
+    return extra + synopsis;
 }
 
 /*!
diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp
index 5b8ccd9902d..bd8d45ab534 100644
--- a/src/tools/qdoc/htmlgenerator.cpp
+++ b/src/tools/qdoc/htmlgenerator.cpp
@@ -121,7 +121,7 @@ void HtmlGenerator::initializeGenerator(const Config &config)
         { ATOM_FORMATTING_PARAMETER, "<i>", "</i>" },
         { ATOM_FORMATTING_SUBSCRIPT, "<sub>", "</sub>" },
         { ATOM_FORMATTING_SUPERSCRIPT, "<sup>", "</sup>" },
-        { ATOM_FORMATTING_TELETYPE, "<tt>", "</tt>" },
+        { 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 }
@@ -149,6 +149,10 @@ void HtmlGenerator::initializeGenerator(const Config &config)
     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);
@@ -845,7 +849,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
             out() << "<dl>\n";
         }
         else if (atom->string() == ATOM_LIST_VALUE) {
-            out() << "<table class=\"valuelist\">";
+            out() << "<div class=\"table\"><table class=\"valuelist\">";
             threeColumnEnumValueTable_ = isThreeColumnEnumValueTable(atom);
             if (threeColumnEnumValueTable_) {
                 if (++numTableRows_ % 2 == 1)
@@ -897,7 +901,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
             // ### Trenton
 
             QString t= protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(),relative)));
-            out() << "<tr><td class=\"topAlign\"><tt>" << t << "</tt>";
+            out() << "<tr><td class=\"topAlign\"><code>" << t << "</code>";
 
             if (relative->type() == Node::Enum) {
                 out() << "</td><td class=\"topAlign\">";
@@ -907,7 +911,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
                 if (itemValue.isEmpty())
                     out() << '?';
                 else
-                    out() << "<tt>" << protectEnc(itemValue) << "</tt>";
+                    out() << "<code>" << protectEnc(itemValue) << "</code>";
             }
             skipAhead = 1;
         }
@@ -952,7 +956,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
             out() << "</dl>\n";
         }
         else if (atom->string() == ATOM_LIST_VALUE) {
-            out() << "</table>\n";
+            out() << "</table></div>\n";
         }
         else {
             out() << "</ol>\n";
@@ -1040,7 +1044,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
             else if (p2.contains("%"))
                 width = p2;
         }
-        out() << "<table class=\"" << attr << "\"";
+        out() << "<div class=\"table\"><table class=\"" << attr << "\"";
         if (!width.isEmpty())
             out() << " width=\"" << width << "\"";
         out() << ">\n ";
@@ -1048,7 +1052,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark
     }
         break;
     case Atom::TableRight:
-        out() << "</table>\n";
+        out() << "</table></div>\n";
         break;
     case Atom::TableHeaderLeft:
         out() << "<thead><tr class=\"qt-style\">";
@@ -1456,8 +1460,7 @@ void HtmlGenerator::generateDocNode(DocNode* dn, CodeMarker* marker)
       Generate the TOC for the new doc format.
       Don't generate a TOC for the home page.
     */
-    if ((dn->name() != QString("index.html")) &&
-        (dn->name() != QString("qtexamplesandtutorials.html")))
+    if ((dn->name() != QStringLiteral("index.html")))
         generateTableOfContents(dn,marker,0);
 
     generateTitle(fullTitle,
@@ -1707,8 +1710,8 @@ void HtmlGenerator::generateHeader(const QString& title,
 #else
     out() << QString("<?xml version=\"1.0\"?>\n");
 #endif
-    out() << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n";
-    out() << QString("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"%1\" lang=\"%1\">\n").arg(naturalLanguage);
+    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())
@@ -1775,7 +1778,8 @@ void HtmlGenerator::generateHeader(const QString& title,
 
     out() << QString(postHeader).replace("\\" + COMMAND_VERSION, qdb_->version());
     generateNavigationBar(title,node,marker);
-    out() << "<li id=\"buildversion\">\n" << buildversion << "</li>\n";
+    if (!buildversion.isEmpty())
+        out() << "<li id=\"buildversion\">" << buildversion << "</li>\n";
     out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, qdb_->version());
 
     navigationLinks.clear();
@@ -1849,6 +1853,7 @@ void HtmlGenerator::generateTitle(const QString& title,
                                   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()) {
@@ -1993,7 +1998,7 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker)
 
     if (!requisites.isEmpty()) {
         //generate the table
-        out() << "<table class=\"alignedsummary\">\n";
+        out() << "<div class=\"table\"><table class=\"alignedsummary\">\n";
 
         QStringList::ConstIterator i;
         for (i = requisiteorder.begin(); i != requisiteorder.constEnd(); ++i) {
@@ -2011,7 +2016,7 @@ void HtmlGenerator::generateRequisites(InnerNode *inner, CodeMarker *marker)
                 out() << "</td></tr>";
             }
         }
-        out() << "</table>";
+        out() << "</table></div>";
     }
 }
 
@@ -2112,7 +2117,7 @@ void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker)
 
     if (!requisites.isEmpty()) {
         //generate the table
-        out() << "<table class=\"alignedsummary\">\n";
+        out() << "<div class=\"table\"><table class=\"alignedsummary\">\n";
 
         QStringList::ConstIterator i;
         for (i = requisiteorder.begin(); i != requisiteorder.constEnd(); ++i) {
@@ -2130,7 +2135,7 @@ void HtmlGenerator::generateQmlRequisites(QmlClassNode *qcn, CodeMarker *marker)
                 out() << "</td></tr>";
             }
         }
-        out() << "</table>";
+        out() << "</table></div>";
     }
 }
 
@@ -2176,12 +2181,10 @@ void HtmlGenerator::generateTableOfContents(const Node *node,
     QList<Atom*> toc;
     if (node->doc().hasTableOfContents())
         toc = node->doc().tableOfContents();
-    if (toc.isEmpty() && !sections && !node->isModule())
-        return;
-
-    //turn off table of contents if HTML.tocdepth is set to 0
-    if (tocDepth == 0)
+    if (tocDepth == 0 || (toc.isEmpty() && !sections && !node->isModule())) {
+        generateSidebar();
         return;
+    }
 
     QStringList sectionNumber;
     int detailsBase = 0;
@@ -2190,6 +2193,7 @@ void HtmlGenerator::generateTableOfContents(const Node *node,
     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");
@@ -2287,10 +2291,21 @@ void HtmlGenerator::generateTableOfContents(const Node *node,
     }
     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)
 {
@@ -2307,6 +2322,7 @@ QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner,
     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);
@@ -2338,6 +2354,7 @@ QString HtmlGenerator::generateAllQmlMembersFile(QmlClassNode* qml_cn, CodeMarke
     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);
@@ -2422,6 +2439,7 @@ QString HtmlGenerator::generateLowStatusMemberFile(InnerNode *inner,
 
     beginSubPage(inner, fileName);
     generateHeader(title, inner, marker);
+    generateSidebar();
     generateTitle(title, Text(), SmallSubTitle, inner, marker);
 
     if (status == CodeMarker::Compat) {
@@ -2498,6 +2516,7 @@ QString HtmlGenerator::generateQmlMemberFile(QmlClassNode* qcn,
 
     beginSubPage(qcn, fileName);
     generateHeader(title, qcn, marker);
+    generateSidebar();
     generateTitle(title, Text(), SmallSubTitle, qcn, marker);
 
     out() << "<p><b>The following members of QML type "
@@ -2615,7 +2634,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative,
     }
     if (allInternal)
         return;
-    out() << "<table class=\"annotated\">\n";
+    out() << "<div class=\"table\"><table class=\"annotated\">\n";
     int row = 0;
     NodeList nodes = nm.values();
     foreach (const Node* node, nodes) {
@@ -2651,7 +2670,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative,
         }
         out() << "</tr>\n";
     }
-    out() << "</table>\n";
+    out() << "</table></div>\n";
 }
 
 /*!
@@ -2902,8 +2921,8 @@ void HtmlGenerator::generateQmlItem(const Node *node,
     if (summary)
         marked.replace("@name>", "b>");
 
-    marked.replace("<@extra>", "<tt>");
-    marked.replace("</@extra>", "</tt>");
+    marked.replace("<@extra>", "<code>");
+    marked.replace("</@extra>", "</code>");
 
     if (summary) {
         marked.remove("<@type>");
@@ -3027,11 +3046,11 @@ void HtmlGenerator::generateSection(const NodeList& nl,
             alignNames = false;
         }
         if (alignNames) {
-            out() << "<table class=\"alignedsummary\">\n";
+            out() << "<div class=\"table\"><table class=\"alignedsummary\">\n";
         }
         else {
             if (twoColumn)
-                out() << "<table class=\"propsummary\">\n"
+                out() << "<div class=\"table\"><table class=\"propsummary\">\n"
                       << "<tr><td class=\"topAlign\">";
             out() << "<ul>\n";
         }
@@ -3062,11 +3081,11 @@ void HtmlGenerator::generateSection(const NodeList& nl,
             ++m;
         }
         if (alignNames)
-            out() << "</table>\n";
+            out() << "</table></div>\n";
         else {
             out() << "</ul>\n";
             if (twoColumn)
-                out() << "</td></tr>\n</table>\n";
+                out() << "</td></tr>\n</table></div>\n";
         }
     }
 }
@@ -3088,11 +3107,11 @@ void HtmlGenerator::generateSectionList(const Section& section,
             alignNames = false;
         }
         if (alignNames) {
-            out() << "<table class=\"alignedsummary\">\n";
+            out() << "<div class=\"table\"><table class=\"alignedsummary\">\n";
         }
         else {
             if (twoColumn)
-                out() << "<table class=\"propsummary\">\n"
+                out() << "<div class=\"table\"><table class=\"propsummary\">\n"
                       << "<tr><td class=\"topAlign\">";
             out() << "<ul>\n";
         }
@@ -3128,11 +3147,11 @@ void HtmlGenerator::generateSectionList(const Section& section,
             ++m;
         }
         if (alignNames)
-            out() << "</table>\n";
+            out() << "</table></div>\n";
         else {
             out() << "</ul>\n";
             if (twoColumn)
-                out() << "</td></tr>\n</table>\n";
+                out() << "</td></tr>\n</table></div>\n";
         }
     }
 
@@ -3196,8 +3215,8 @@ void HtmlGenerator::generateSynopsis(const Node *node,
         extraRegExp.setMinimal(true);
         marked.remove(extraRegExp);
     } else {
-        marked.replace("<@extra>", "<tt>");
-        marked.replace("</@extra>", "</tt>");
+        marked.replace("<@extra>", "<code>");
+        marked.replace("</@extra>", "</code>");
     }
 
     if (style != CodeMarker::Detailed) {
@@ -4058,7 +4077,7 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
         const QmlPropertyGroupNode* qpgn = static_cast<const QmlPropertyGroupNode*>(node);
         NodeList::ConstIterator p = qpgn->childNodes().constBegin();
         out() << "<div class=\"qmlproto\">";
-        out() << "<table class=\"qmlname\">";
+        out() << "<div class=\"table\"><table class=\"qmlname\">";
 
         QString heading = qpgn->name() + " group";
         out() << "<tr valign=\"top\" class=\"even\" id=\"" << nodeRef << "\">";
@@ -4083,13 +4102,13 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
             }
             ++p;
         }
-        out() << "</table>";
+        out() << "</table></div>";
         out() << "</div>";
     }
     else if (node->type() == Node::QmlProperty) {
         qpn = static_cast<QmlPropertyNode*>(node);
         out() << "<div class=\"qmlproto\">";
-        out() << "<table class=\"qmlname\">";
+        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>";
@@ -4103,43 +4122,43 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node,
             out() << "<span class=\"qmldefault\">default</span>";
         generateQmlItem(qpn, relative, marker, false);
         out() << "</p></td></tr>";
-        out() << "</table>";
+        out() << "</table></div>";
         out() << "</div>";
     }
     else if (node->type() == Node::QmlSignal) {
         const FunctionNode* qsn = static_cast<const FunctionNode*>(node);
         out() << "<div class=\"qmlproto\">";
-        out() << "<table class=\"qmlname\">";
+        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>";
+        out() << "</table></div>";
         out() << "</div>";
     }
     else if (node->type() == Node::QmlSignalHandler) {
         const FunctionNode* qshn = static_cast<const FunctionNode*>(node);
         out() << "<div class=\"qmlproto\">";
-        out() << "<table class=\"qmlname\">";
+        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>";
+        out() << "</table></div>";
         out() << "</div>";
     }
     else if (node->type() == Node::QmlMethod) {
         const FunctionNode* qmn = static_cast<const FunctionNode*>(node);
         out() << "<div class=\"qmlproto\">";
-        out() << "<table class=\"qmlname\">";
+        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>";
+        out() << "</table></div>";
         out() << "</div>";
     }
     out() << "<div class=\"qmldoc\">";
diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h
index 616a9893614..40360da02ef 100644
--- a/src/tools/qdoc/htmlgenerator.h
+++ b/src/tools/qdoc/htmlgenerator.h
@@ -144,6 +144,7 @@ private:
     void generateTableOfContents(const Node *node,
                                  CodeMarker *marker,
                                  QList<Section>* sections = 0);
+    void generateSidebar();
     QString generateListOfAllMemberFile(const InnerNode *inner,
                                         CodeMarker *marker);
     QString generateAllQmlMembersFile(QmlClassNode* qml_cn, CodeMarker* marker);
@@ -238,6 +239,7 @@ private:
     QString endHeader;
     QString postHeader;
     QString postPostHeader;
+    QString prologue;
     QString footer;
     QString address;
     bool pleaseGenerateMacRef;
@@ -272,6 +274,7 @@ public:
 #define HTMLGENERATOR_GENERATEMACREFS   "generatemacrefs" // ### document me
 #define HTMLGENERATOR_POSTHEADER        "postheader"
 #define HTMLGENERATOR_POSTPOSTHEADER    "postpostheader"
+#define HTMLGENERATOR_PROLOGUE          "prologue"
 #define HTMLGENERATOR_NONAVIGATIONBAR   "nonavigationbar"
 #define HTMLGENERATOR_NOSUBDIRS         "nosubdirs"
 #define HTMLGENERATOR_TOCDEPTH          "tocdepth"
-- 
GitLab