diff options
author | Topi Reinio <topi.reinio@qt.io> | 2023-04-18 20:44:37 +0000 |
---|---|---|
committer | Topi Reinio <topi.reinio@qt.io> | 2023-04-24 18:39:34 +0000 |
commit | 046447a6fa686ed076a7df8d27b00abe0811750b (patch) | |
tree | c9c37c295dea71830be609d765a61965e2eb9727 | |
parent | edf1e91454b1354bc3da718b2fe76930f894ff77 (diff) | |
download | qttools-046447a6fa686ed076a7df8d27b00abe0811750b.tar.gz |
qdoc: Add status information to the requisites table for types
QDoc provides various ways to document the status of an entity;
\deprecated, \preliminary, and \modulestate commands. These
commands produce a brief sentence describing the status, however,
for C++ and QML types, a logical place for this information is
also the 'requisites' table at the start of the page.
Having the status information in the table makes it more
apparent for the reader that they're looking at documentation
for a deprecated or preliminary type. For HTML generator, this
commit also adds a <span> element that allows additional
visuals via CSS (e.g. an icon) for a specific status.
Pick-to: 6.5
Fixes: QTBUG-113026
Change-Id: If38a6d51631277a0d98b2cb702acf2598b694643
Reviewed-by: Luca Di Sera <luca.disera@qt.io>
13 files changed, 184 insertions, 4 deletions
diff --git a/src/qdoc/qdoc/docbookgenerator.cpp b/src/qdoc/qdoc/docbookgenerator.cpp index cc75cac07..648a0a43d 100644 --- a/src/qdoc/qdoc/docbookgenerator.cpp +++ b/src/qdoc/qdoc/docbookgenerator.cpp @@ -2825,6 +2825,10 @@ void DocBookGenerator::generateRequisites(const Aggregate *aggregate) generateEndRequisite(); } + // Status. + if (auto status = formatStatus(aggregate, m_qdb); status) + generateRequisite("Status", status.value()); + // Write the elements as a list if not empty. delete m_writer; m_writer = oldWriter; @@ -2928,6 +2932,10 @@ void DocBookGenerator::generateQmlRequisites(const QmlTypeNode *qcn) generateEndRequisite(); } + // Status. + if (auto status = formatStatus(qcn, m_qdb); status) + generateRequisite("Status:", status.value()); + m_writer->writeEndElement(); // variablelist newLine(); } diff --git a/src/qdoc/qdoc/generator.cpp b/src/qdoc/qdoc/generator.cpp index f5df13087..174cb9c8f 100644 --- a/src/qdoc/qdoc/generator.cpp +++ b/src/qdoc/qdoc/generator.cpp @@ -1106,6 +1106,37 @@ QString Generator::formatSince(const Node *node) return node->since(); } +/*! + \internal + Returns a string representing status information of a \a node. + + If a status description is returned, it is one of: + \list + \li 'Deprecated [since <version>]' (\\deprecated [<version>]), + \li 'Preliminary' (\\preliminary), or + \li The description adopted from associated module's state: + \c {\modulestate {<description>}}. + \endlist + + Otherwise, returns \c std::nullopt. +*/ +std::optional<QString> formatStatus(const Node *node, QDocDatabase *qdb) +{ + QString status; + + if (node->status() == Node::Deprecated) { + status = u"Deprecated"_s; + if (const auto since = node->deprecatedSince(); !since.isEmpty()) + status += " since %1"_L1.arg(since); + } else if (node->status() == Node::Preliminary) { + status = u"Preliminary"_s; + } else if (const auto collection = qdb->getModuleNode(node); collection) { + status = collection->state(); + } + + return status.isEmpty() ? std::nullopt : std::optional(status); +} + void Generator::generateSince(const Node *node, CodeMarker *marker) { if (!node->since().isEmpty()) { diff --git a/src/qdoc/qdoc/generator.h b/src/qdoc/qdoc/generator.h index fbbff827f..6611cb7b6 100644 --- a/src/qdoc/qdoc/generator.h +++ b/src/qdoc/qdoc/generator.h @@ -13,6 +13,7 @@ #include <QtCore/qstring.h> #include <QtCore/qstringlist.h> #include <QtCore/qtextstream.h> +#include <optional> QT_BEGIN_NAMESPACE @@ -198,6 +199,8 @@ protected: QString m_sectionNumber {}; }; +std::optional<QString> formatStatus(const Node *node, QDocDatabase *qdb); + QT_END_NAMESPACE #endif diff --git a/src/qdoc/qdoc/htmlgenerator.cpp b/src/qdoc/qdoc/htmlgenerator.cpp index 304989f9c..545541aad 100644 --- a/src/qdoc/qdoc/htmlgenerator.cpp +++ b/src/qdoc/qdoc/htmlgenerator.cpp @@ -36,6 +36,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + bool HtmlGenerator::s_inUnorderedList { false }; HtmlGenerator::HtmlGenerator(FileResolver& file_resolver) : XmlGenerator(file_resolver) {} @@ -1917,10 +1919,11 @@ void HtmlGenerator::generateRequisites(Aggregate *aggregate, CodeMarker *marker) const QString instantiatedByText = "Instantiated By"; const QString qtVariableText = "qmake"; const QString cmakeText = "CMake"; + const QString statusText = "Status"; // The order of the requisites matter - const QStringList requisiteorder { headerText, cmakeText, qtVariableText, sinceText, - instantiatedByText, inheritsText, inheritedBytext }; + const QStringList requisiteorder { headerText, cmakeText, qtVariableText, sinceText, + instantiatedByText, inheritsText, inheritedBytext, statusText }; addIncludeFileToMap(aggregate, marker, requisites, text, headerText); addSinceToMap(aggregate, requisites, &text, sinceText); @@ -1939,6 +1942,9 @@ void HtmlGenerator::generateRequisites(Aggregate *aggregate, CodeMarker *marker) addInheritedByToMap(requisites, &text, inheritedBytext, classe); } + // Add the state description (if any) to the map + addStatusToMap(aggregate, requisites, text, statusText); + if (!requisites.isEmpty()) { // generate the table generateTheTable(requisiteorder, requisites, headerText, aggregate, marker); @@ -2097,6 +2103,38 @@ void HtmlGenerator::addSinceToMap(const Aggregate *aggregate, QMap<QString, Text /*! * \internal + * Adds the status description for \a aggregate, together with a <span> element, to the \a + * requisites map. + * + * The span element can be used for adding CSS styling/icon associated with a specific status. + * The span class name is constructed by converting the description (sans \\deprecated + * version info) to lowercase and replacing all non-alphanum characters with hyphens. In + * addition, the span has a class \c status. For example, + * 'Tech Preview' -> class="status tech-preview" +*/ +void HtmlGenerator::addStatusToMap(const Aggregate *aggregate, QMap<QString, Text> &requisites, + Text &text, const QString &statusText) const +{ + auto status{formatStatus(aggregate, m_qdb)}; + if (!status) + return; + + QString spanClass; + if (aggregate->status() == Node::Deprecated) + spanClass = u"deprecated"_s; // Disregard any version info + else + spanClass = Utilities::canonicalizeFileName(status.value()); + + text.clear(); + text << Atom(Atom::String, status.value()) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_SPAN + + "class=\"status %1\""_L1.arg(spanClass)) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_SPAN); + requisites.insert(statusText, text); +} + +/*! + * \internal * Adds the includes (from the \\includefile command) to the map. */ void HtmlGenerator::addIncludeFileToMap(const Aggregate *aggregate, CodeMarker *marker, @@ -2130,6 +2168,7 @@ void HtmlGenerator::generateQmlRequisites(QmlTypeNode *qcn, CodeMarker *marker) const QString inheritedBytext = "Inherited By:"; const QString inheritsText = "Inherits:"; const QString instantiatesText = "Instantiates:"; + const QString statusText = "Status:"; // add the module name and version to the map QString logicalModuleVersion; @@ -2189,9 +2228,12 @@ void HtmlGenerator::generateQmlRequisites(QmlTypeNode *qcn, CodeMarker *marker) requisites.insert(inheritedBytext, text); } + // Add the state description (if any) to the map + addStatusToMap(qcn, requisites, text, statusText); + // The order of the requisites matter const QStringList requisiteorder { importText, sinceText, instantiatesText, inheritsText, - inheritedBytext }; + inheritedBytext, statusText }; if (!requisites.isEmpty()) { // generate the table diff --git a/src/qdoc/qdoc/htmlgenerator.h b/src/qdoc/qdoc/htmlgenerator.h index 3c12ce328..4592e41d7 100644 --- a/src/qdoc/qdoc/htmlgenerator.h +++ b/src/qdoc/qdoc/htmlgenerator.h @@ -107,6 +107,8 @@ private: const QString &headerText); void addSinceToMap(const Aggregate *aggregate, QMap<QString, Text> &requisites, Text *text, const QString &sinceText) const; + void addStatusToMap(const Aggregate *aggregate, QMap<QString, Text> &requisites, Text &text, + const QString &statusText) const; void addCMakeInfoToMap(const Aggregate *aggregate, QMap<QString, Text> &requisites, Text *text, const QString &CMakeInfo) const; void addQtVariableToMap(const Aggregate *aggregate, QMap<QString, Text> &requisites, Text *text, diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-oldtype.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-oldtype.xml new file mode 100644 index 000000000..ce2999582 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-oldtype.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<db:article xmlns:db="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.2" xml:lang="en"> +<db:info> +<db:title>OldType QML Type</db:title> +<db:productname>Test</db:productname> +<db:titleabbrev>A test project for QDoc build artifacts</db:titleabbrev> +<db:abstract> +<db:para>Deprecated old type.</db:para> +<db:para><db:emphasis role="bold">This type is deprecated since 1.0. We strongly advise against using it in new code.</db:emphasis></db:para> +<db:para>This type was introduced in Qt 1.1.</db:para> +</db:abstract> +</db:info> +<db:variablelist> +<db:varlistentry> +<db:term>Import Statement</db:term> +<db:listitem> +<db:para>import QDoc.Test 1.1</db:para> +</db:listitem> +</db:varlistentry> +<db:varlistentry> +<db:term>Since:</db:term> +<db:listitem> +<db:para>Qt 1.1</db:para> +</db:listitem> +</db:varlistentry> +<db:varlistentry> +<db:term>Status:</db:term> +<db:listitem> +<db:para>Deprecated since 1.0</db:para> +</db:listitem> +</db:varlistentry> +</db:variablelist> +<db:section xml:id="details"> +<db:title>Detailed Description</db:title> +</db:section> +</db:article> diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-test-nover-typenoversion.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-test-nover-typenoversion.xml index 676098113..87576add4 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-test-nover-typenoversion.xml +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-test-nover-typenoversion.xml @@ -28,6 +28,12 @@ <db:para><db:link xlink:href="testqdoc-testderived.xml">TestDerived</db:link></db:para> </db:listitem> </db:varlistentry> +<db:varlistentry> +<db:term>Status:</db:term> +<db:listitem> +<db:para>Tech Preview</db:para> +</db:listitem> +</db:varlistentry> </db:variablelist> <db:section xml:id="details"> <db:title>Detailed Description</db:title> diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-oldtype.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-oldtype.html new file mode 100644 index 000000000..f314ad331 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-oldtype.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> +<!-- type.cpp --> + <meta name="description" content="Deprecated old type."> + <title>OldType QML Type | Test</title> +</head> +<body> +<li><a href="qdoc-test-qmlmodule.html" translate="no">Types</a></li> +<li>OldType</li> +<div class="sidebar"> +<div class="toc"> +<h3 id="toc">Contents</h3> +<ul> +<li class="level1"><a href="#details">Detailed Description</a></li> +</ul> +</div> +<div class="sidebar-content" id="sidebar-content"></div></div> +<h1 class="title" translate="no">OldType QML Type</h1> +<!-- $$$OldType-brief --> +<p>Deprecated old type. <a href="#details">More...</a></p> +<!-- @@@OldType --> +<div class="table"><table class="alignedsummary" translate="no"> +<tr><td class="memItemLeft rightAlign topAlign"> Import Statement:</td><td class="memItemRight bottomAlign"> import QDoc.Test 1.1</td></tr><tr><td class="memItemLeft rightAlign topAlign"> Since:</td><td class="memItemRight bottomAlign"> Qt 1.1</td></tr><tr><td class="memItemLeft rightAlign topAlign"> Status:</td><td class="memItemRight bottomAlign"> Deprecated since 1.0<span class="status deprecated"></span></td></tr></table></div><ul> +<li><a href="qml-qdoc-test-oldtype-members.html">List of all members, including inherited members</a></li> +</ul> +<!-- $$$OldType-description --> +<h2 id="details">Detailed Description</h2> +<!-- @@@OldType --> +</body> +</html> diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-test-nover-typenoversion.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-test-nover-typenoversion.html index 432085d63..b426c95a9 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/qml-test-nover-typenoversion.html +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-test-nover-typenoversion.html @@ -23,7 +23,7 @@ <p>Another QML type documented in a .cpp file. <a href="#details">More...</a></p> <!-- @@@TypeNoVersion --> <div class="table"><table class="alignedsummary" translate="no"> -<tr><td class="memItemLeft rightAlign topAlign"> Import Statement:</td><td class="memItemRight bottomAlign"> import Test.NoVer</td></tr><tr><td class="memItemLeft rightAlign topAlign"> Since:</td><td class="memItemRight bottomAlign"> Qt 1.1</td></tr><tr><td class="memItemLeft rightAlign topAlign"> Instantiates:</td><td class="memItemRight bottomAlign"> <a href="testqdoc-testderived.html" translate="no">TestDerived</a></td></tr></table></div><ul> +<tr><td class="memItemLeft rightAlign topAlign"> Import Statement:</td><td class="memItemRight bottomAlign"> import Test.NoVer</td></tr><tr><td class="memItemLeft rightAlign topAlign"> Since:</td><td class="memItemRight bottomAlign"> Qt 1.1</td></tr><tr><td class="memItemLeft rightAlign topAlign"> Instantiates:</td><td class="memItemRight bottomAlign"> <a href="testqdoc-testderived.html" translate="no">TestDerived</a></td></tr><tr><td class="memItemLeft rightAlign topAlign"> Status:</td><td class="memItemRight bottomAlign"> Tech Preview<span class="status tech-preview"></span></td></tr></table></div><ul> <li><a href="qml-test-nover-typenoversion-members.html">List of all members, including inherited members</a></li> </ul> <!-- $$$TypeNoVersion-description --> diff --git a/tests/auto/qdoc/generatedoutput/expected_output/test.qhp b/tests/auto/qdoc/generatedoutput/expected_output/test.qhp index 7ef863788..2070d5635 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/test.qhp +++ b/tests/auto/qdoc/generatedoutput/expected_output/test.qhp @@ -42,6 +42,9 @@ <section ref="qml-qdoc-test-doctest.html" title="DocTest Type Reference"> <section ref="qml-qdoc-test-doctest-members.html" title="List of all members"/> </section> + <section ref="qml-qdoc-test-oldtype.html" title="OldType Type Reference"> + <section ref="qml-qdoc-test-oldtype-members.html" title="List of all members"/> + </section> <section ref="qml-qdoc-test-type.html" title="Type Type Reference"> <section ref="qml-qdoc-test-type-members.html" title="List of all members"/> <section ref="qml-qdoc-test-type-obsolete.html" title="Obsolete members"/> @@ -72,6 +75,8 @@ <keyword name="DocTest" id="QML.DocTest" ref="qml-qdoc-test-doctest.html"/> <keyword name="DocTest" id="QML.QDoc.Test1.DocTest" ref="qml-qdoc-test-doctest.html"/> <keyword name="Obsolete Classes" id="Obsolete Classes" ref="obsolete-classes.html"/> + <keyword name="OldType" id="QML.OldType" ref="qml-qdoc-test-oldtype.html"/> + <keyword name="OldType" id="QML.QDoc.Test1.OldType" ref="qml-qdoc-test-oldtype.html"/> <keyword name="ProgressBar" id="QML.ProgressBar" ref="qml-uicomponents-progressbar.html"/> <keyword name="ProgressBar" id="QML.UIComponents1.ProgressBar" ref="qml-uicomponents-progressbar.html"/> <keyword name="QDOCTEST_MACRO" id="QDOCTEST_MACRO" ref="testqdoc.html#QDOCTEST_MACRO"/> @@ -172,6 +177,8 @@ <file>qml-qdoc-test-child.html</file> <file>qml-qdoc-test-doctest-members.html</file> <file>qml-qdoc-test-doctest.html</file> + <file>qml-qdoc-test-oldtype-members.html</file> + <file>qml-qdoc-test-oldtype.html</file> <file>qml-qdoc-test-type-members.html</file> <file>qml-qdoc-test-type-obsolete.html</file> <file>qml-qdoc-test-type.html</file> diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testtagfile.tags b/tests/auto/qdoc/generatedoutput/expected_output/testtagfile.tags index 891909786..729ced4c0 100644 --- a/tests/auto/qdoc/generatedoutput/expected_output/testtagfile.tags +++ b/tests/auto/qdoc/generatedoutput/expected_output/testtagfile.tags @@ -87,6 +87,10 @@ </member> </compound> <compound kind="class"> + <name>QDoc.Test.OldType</name> + <filename>qml-qdoc-test-oldtype.html</filename> + </compound> + <compound kind="class"> <name>UIComponents.ProgressBar</name> <filename>qml-uicomponents-progressbar.html</filename> </compound> diff --git a/tests/auto/qdoc/generatedoutput/testdata/qml/type.cpp b/tests/auto/qdoc/generatedoutput/testdata/qml/type.cpp index f0d913853..8e4d6e677 100644 --- a/tests/auto/qdoc/generatedoutput/testdata/qml/type.cpp +++ b/tests/auto/qdoc/generatedoutput/testdata/qml/type.cpp @@ -42,6 +42,13 @@ */ /*! + \qmltype OldType + \inqmlmodule QDoc.Test + \brief Deprecated old type. + \deprecated [1.0] +*/ + +/*! \qmlproperty int Type::id \readonly \brief A read-only property. diff --git a/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp b/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp index 552ed39cc..f39a87223 100644 --- a/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp +++ b/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp @@ -242,6 +242,7 @@ void tst_generatedOutput::htmlFromQml() "qml-qdoc-test-type-members.html " "qml-qdoc-test-type-obsolete.html " "qml-qdoc-test-type.html " + "qml-qdoc-test-oldtype.html " "qml-test-nover-typenoversion.html " "qml-test-nover-typenoversion-members.html " "qml-uicomponents-progressbar.html " @@ -332,6 +333,7 @@ void tst_generatedOutput::docBookFromQml() "docbook/qml-qdoc-test-yetanotherchild.xml " "docbook/qml-qdoc-test-doctest.xml " "docbook/qml-qdoc-test-type.xml " + "docbook/qml-qdoc-test-oldtype.xml " "docbook/qml-test-nover-typenoversion.xml " "docbook/qml-uicomponents-progressbar.xml " "docbook/qml-uicomponents-switch.xml " |