30#include <QtCore/qlist.h>
31#include <QtCore/qmap.h>
32#include <QtCore/quuid.h>
33#include <QtCore/qversionnumber.h>
34#include <QtCore/qregularexpression.h>
43using namespace Qt::StringLiterals;
50static const auto headingStart =
"<h3 class=\"%1\" translate=\"no\" id=\"%2\">"_L1;
55static void addLink(
const QString &linkTarget, QStringView nestedStuff, QString *res)
57 if (!linkTarget.isEmpty()) {
58 *res += QLatin1String(
"<a href=\"");
60 *res += QLatin1String(
"\" translate=\"no\">");
62 *res += QLatin1String(
"</a>");
82 if (param.template_declaration) {
83 appendTemplateParametersAtoms(out, *param.template_declaration);
89 if (param.concept_name) {
90 const QString fq = QString::fromStdString(*param.concept_name);
101 if (!decl
.type.empty())
102 out << Atom(Atom::AutoLink, QString::fromStdString(decl.type));
105 out <<
"typename"_L1;
112 if (!decl.name.empty())
113 out <<
" "_L1 << QString::fromStdString(decl.name);
118 out <<
"template <"_L1;
121 for (
const auto ¶m : storage.parameters) {
122 if (param.sfinae_constraint)
127 appendTemplateParameterAtoms(out, param);
142 appendTemplateParametersAtoms(out, templateDecl);
144 if (!templateDecl.requires_clause || templateDecl.requires_clause->empty())
147 out <<
" requires "_L1;
148 const QString text = QString::fromStdString(*templateDecl.requires_clause);
150 QStringList concepts;
151 concepts.reserve(
int(templateDecl.referenced_concepts.size()));
152 for (
const auto &s : templateDecl.referenced_concepts)
153 concepts.append(QString::fromStdString(s));
155 if (concepts.isEmpty()) {
163 std::sort(concepts.begin(), concepts.end(),
164 [](
const QString &a,
const QString &b) {
return a.size() > b.size(); });
166 struct Match { qsizetype offset; qsizetype length; QString name; };
167 QList<Match> matches;
168 QList<
bool> occupied(text.size(),
false);
170 for (
const QString &concept_name : concepts) {
171 const QString unqualified = concept_name.section(
"::"_L1, -1);
172 QRegularExpression re(
"\\b"_L1 + QRegularExpression::escape(unqualified) +
"\\b"_L1);
173 auto it = re.globalMatch(text);
174 while (it.hasNext()) {
175 const auto m = it.next();
176 const qsizetype start = m.capturedStart();
177 const qsizetype len = m.capturedLength();
179 for (qsizetype i = start; i < start + len; ++i)
180 if (occupied[i]) { clear =
false;
break; }
183 for (qsizetype i = start; i < start + len; ++i)
185 matches.append({start, len, unqualified});
189 std::sort(matches.begin(), matches.end(),
190 [](
const Match &a,
const Match &b) {
return a.offset < b.offset; });
193 for (
const auto &m : matches) {
195 out << text.mid(pos, m.offset - pos);
196 out << Atom(Atom::AutoLink, m.name);
197 pos = m.offset + m.length;
199 if (pos < text.size())
200 out << text.mid(pos);
204
205
206
207
210 auto result{classSet};
212 result +=
" internal"_L1;
217
218
219
222 if (!s_inUnorderedList) {
224 s_inUnorderedList =
true;
229
230
231
234 if (s_inUnorderedList) {
236 s_inUnorderedList =
false;
241
242
243
246 if (m_helpProjectWriter) {
247 delete m_helpProjectWriter;
248 m_helpProjectWriter =
nullptr;
251 if (m_manifestWriter) {
252 delete m_manifestWriter;
253 m_manifestWriter =
nullptr;
258
259
260
280 {
nullptr,
nullptr,
nullptr } };
283 config = &Config::instance();
286
287
288
289 for (
int i = 0; defaults[i].key; ++i) {
290 formattingLeftMap().insert(QLatin1String(defaults[i].key), QLatin1String(defaults[i].left));
291 formattingRightMap().insert(QLatin1String(defaults[i].key),
292 QLatin1String(defaults[i].right));
295 QString formatDot{HtmlGenerator::format() + Config::dot};
296 m_endHeader = config->get(formatDot +
CONFIG_ENDHEADER).asString(
"</head>\n<body>\n"_L1);
310 .asString(m_project +
" Reference Documentation"_L1);
312 m_projectUrl = config->get(
CONFIG_URL).asString();
321
322
323
324
326 delete m_helpProjectWriter;
327 m_helpProjectWriter =
nullptr;
328 }
else if (m_helpProjectWriter) {
329 m_helpProjectWriter->reset(m_project.toLower() +
".qhp",
this);
331 m_helpProjectWriter =
new HelpProjectWriter(m_project.toLower() +
".qhp",
this);
334 if (!m_manifestWriter)
347 .asString(m_homepage);
354 .asString(m_landingpage);
361 .asString(
"C++ Classes"_L1);
368 .asString(
"QML Types"_L1);
377
378
390
391
392
393
394
395
396
402 Node *qflags = m_qdb->findClassNode(QStringList(
"QFlags"_L1));
404 m_qflagsHref = linkForNode(qflags,
nullptr);
408 const QString fileBase =
"%1/%2"_L1.arg(
410 m_project.toLower().simplified().replace(
' '_L1,
'-'_L1)
414 if (m_helpProjectWriter)
418 const QString &rootTitle = m_landingpage.isEmpty() ? m_homepage : m_landingpage;
419 tocWriter
.generateTOC(
"%1_toc.xml"_L1.arg(fileBase), rootTitle);
421
422
423 if (!tagFile_.isEmpty()) {
431
432
435 SubTitleSize subTitleSize = LargeSubTitle;
436 QString fullTitle = en->fullTitle();
438 beginSubPage(en, linkForExampleFile(resolved_file.get_query()));
439 generateHeader(fullTitle, en, marker, u"auto-generated"_s);
440 generateTitle(en
->doc().title(),
Text() << en->subtitle(), subTitleSize, en, marker);
445 QString code = quoter.quoteTo(en->location(), QString(), QString());
446 CodeMarker *codeMarker = CodeMarker::markerForFileName(resolved_file.get_path());
450 generateText(text, en, codeMarker);
455
456
459 qsizetype idx, skipAhead = 0;
460 static bool in_para =
false;
461 Genus genus = Genus::DontCare;
463 if (!m_inSectionHeading && atom->type() != Atom::Target
464 && atom->type() != Atom::SectionHeadingRight)
465 m_recentSectionRef.clear();
469 QString name = atom->string();
470 if (relative && relative->name() == name.replace(QLatin1String(
"()"), QLatin1String())) {
471 out() << protectEnc(atom->string());
479 if (!m_inLink && !m_inContents && !m_inSectionHeading) {
480 const Node *node =
nullptr;
481 QString link = getAutoLink(atom, relative, &node, genus);
482 if (link.isEmpty()) {
487 QStringLiteral(
"Can't autolink to '%1'").arg(atom->string()));
492 if (link.isEmpty()) {
493 out() << protectEnc(atom->string());
495 beginLink(link, node, relative);
500 out() << protectEnc(atom->string());
507 skipAhead = skipAtoms(atom, Atom::BriefRight);
522 out() << protectEnc(plainCode(atom->string()));
526 out() <<
"<p class=\"figCaption\">";
537 out() <<
"<pre class=\"qml\" translate=\"no\"><code class=\"qml\">"
538 << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative,
540 m_codePrefix, m_codeSuffix)
541 <<
"</code></pre>\n";
545 if (atom->strings().count() == 2)
546 out() <<
"<pre class=\"" << atom->string(1) <<
"\" translate=\"no\"><code class=\"" << atom->string(1) <<
"\">";
548 out() <<
"<pre class=\"cpp\" translate=\"no\"><code class=\"cpp\">";
550 out() << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative),
551 m_codePrefix, m_codeSuffix)
552 <<
"</code></pre>\n";
555 out() <<
"<pre class=\"cpp plain\" translate=\"no\"><code class=\"text\">"
556 << trimmedTrailing(protectEnc(plainCode(indent(m_codeIndent, atom->string()))),
557 m_codePrefix, m_codeSuffix)
558 <<
"</code></pre>\n";
561 out() <<
"<details>\n";
563 out() <<
"<summary>...</summary>\n";
566 out() <<
"<summary>";
569 out() <<
"</summary>\n";
572 out() <<
"</details>\n";
576 if (!atom->string().isEmpty())
577 out() <<
' ' << atom->string();
600 if (atom->string().startsWith(
"span "))
601 out() <<
'<' + atom->string() <<
'>';
603 out() << formattingLeftMap()[atom->string()];
611 const Node *node{
nullptr};
612 const Atom tm_link(Atom::NavLink, m_trademarkspage);
613 if (
const auto &link = getLink(&tm_link, relative, &node);
614 !link.isEmpty() && node != relative)
615 out() <<
"<a href=\"%1\">%2</a>"_L1.arg(link, formattingRightMap()[atom->string()]);
617 out() << formattingRightMap()[atom->string()];
620 }
else if (atom->string().startsWith(
"span ")) {
623 out() << formattingRightMap()[atom->string()];
627 if (
const auto *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group); cn)
628 generateList(cn, marker, atom->string(), Generator::sortOrder(atom->strings().last()));
631 const auto sortOrder{Generator::sortOrder(atom->strings().last())};
632 if (atom->string() == QLatin1String(
"annotatedclasses")) {
633 generateAnnotatedList(relative, marker, m_qdb->getCppClasses().values(), sortOrder);
634 }
else if (atom->string() == QLatin1String(
"annotatedexamples")) {
635 generateAnnotatedLists(relative, marker, m_qdb->getExamples());
636 }
else if (atom->string() == QLatin1String(
"annotatedattributions")) {
637 generateAnnotatedLists(relative, marker, m_qdb->getAttributions());
638 }
else if (atom->string() == QLatin1String(
"classes")) {
639 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true,
641 }
else if (atom->string().contains(
"classes ")) {
642 QString rootName = atom->string().mid(atom->string().indexOf(
"classes") + 7).trimmed();
643 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true, rootName);
644 }
else if (atom->string() == QLatin1String(
"qmlvaluetypes")
645 || atom->string() == QLatin1String(
"qmlbasictypes")) {
646 generateCompactList(Generic, relative, m_qdb->getQmlValueTypes(),
true,
648 }
else if (atom->string() == QLatin1String(
"qmltypes")) {
649 generateCompactList(Generic, relative, m_qdb->getQmlTypes(),
true, QStringLiteral(
""));
650 }
else if ((idx = atom->string().indexOf(QStringLiteral(
"bymodule"))) != -1) {
652 QString moduleName = atom->string().mid(idx + 8).trimmed();
654 if (
const auto *cn = qdb->getCollectionNode(moduleName, moduleType)) {
656 switch (moduleType) {
660 generateAnnotatedList(relative, marker, map.values(), sortOrder);
663 if (atom->string().contains(QLatin1String(
"qmlvaluetypes")))
667 generateAnnotatedList(relative, marker, map.values(), sortOrder);
670 generateAnnotatedList(relative, marker, cn->members(), sortOrder);
674 }
else if (atom->string() == QLatin1String(
"classhierarchy")) {
675 generateClassHierarchy(relative, m_qdb->getCppClasses());
676 }
else if (atom->string() == QLatin1String(
"obsoleteclasses")) {
677 generateCompactList(Generic, relative, m_qdb->getObsoleteClasses(),
false,
678 QStringLiteral(
"Q"));
679 }
else if (atom->string() == QLatin1String(
"obsoleteqmltypes")) {
680 generateCompactList(Generic, relative, m_qdb->getObsoleteQmlTypes(),
false,
682 }
else if (atom->string() == QLatin1String(
"obsoletecppmembers")) {
683 generateCompactList(Obsolete, relative, m_qdb->getClassesWithObsoleteMembers(),
false,
684 QStringLiteral(
"Q"));
685 }
else if (atom->string() == QLatin1String(
"obsoleteqmlmembers")) {
686 generateCompactList(Obsolete, relative, m_qdb->getQmlTypesWithObsoleteMembers(),
false,
688 }
else if (atom->string() == QLatin1String(
"functionindex")) {
689 generateFunctionIndex(relative);
690 }
else if (atom->string() == QLatin1String(
"attributions")) {
691 generateAnnotatedList(relative, marker, m_qdb->getAttributions().values(), sortOrder);
692 }
else if (atom->string() == QLatin1String(
"legalese")) {
693 generateLegaleseList(relative, marker);
694 }
else if (atom->string() == QLatin1String(
"overviews")) {
695 generateList(relative, marker,
"overviews", sortOrder);
696 }
else if (atom->string() == QLatin1String(
"cpp-modules")) {
697 generateList(relative, marker,
"cpp-modules", sortOrder);
698 }
else if (atom->string() == QLatin1String(
"qml-modules")) {
699 generateList(relative, marker,
"qml-modules", sortOrder);
700 }
else if (atom->string() == QLatin1String(
"namespaces")) {
701 generateAnnotatedList(relative, marker, m_qdb->getNamespaces().values(), sortOrder);
702 }
else if (atom->string() == QLatin1String(
"related")) {
703 generateList(relative, marker,
"related", sortOrder);
705 const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group);
707 if (!generateGroupList(
const_cast<CollectionNode *>(cn), sortOrder))
709 QString(
"'\\generatelist %1' group is empty").arg(atom->string()));
712 QString(
"'\\generatelist %1' no such group").arg(atom->string()));
717 const NodeMultiMap &nsmap = m_qdb->getSinceMap(atom->string());
721 const NodeMultiMap &ncmap = m_qdb->getClassMap(atom->string());
722 const NodeMultiMap &nqcmap = m_qdb->getQmlTypeMap(atom->string());
727 for (
const auto §ion : sinceSections) {
728 if (!section.members().isEmpty()) {
730 <<
"<a href=\"#" << TextUtils::asAsciiPrintable(section.title()) <<
"\">"
731 << section.title() <<
"</a></li>\n";
737 for (
const auto §ion : sinceSections) {
738 if (!section.members().isEmpty()) {
739 out() <<
"<h3 id=\"" << TextUtils::asAsciiPrintable(section.title()) <<
"\">"
740 << protectEnc(section.title()) <<
"</h3>\n";
741 if (index == Sections::SinceClasses)
742 generateCompactList(Generic, relative, ncmap,
false, QStringLiteral(
"Q"));
743 else if (index == Sections::SinceQmlTypes)
744 generateCompactList(Generic, relative, nqcmap,
false, QStringLiteral(
""));
745 else if (index == Sections::SinceMemberFunctions
746 || index == Sections::SinceQmlMethods
747 || index == Sections::SinceQmlProperties) {
749 QMap<QString, NodeMultiMap> parentmaps;
751 const QList<Node *> &members = section.members();
752 for (
const auto &member : members) {
753 QString parent_full_name = (*member).parent()->fullName();
755 auto parent_entry = parentmaps.find(parent_full_name);
756 if (parent_entry == parentmaps.end())
757 parent_entry = parentmaps.insert(parent_full_name, NodeMultiMap());
758 parent_entry->insert(member->name(), member);
761 for (
auto map = parentmaps.begin(); map != parentmaps.end(); ++map) {
762 NodeVector nv = map->values().toVector();
763 auto parent = nv.front()->parent();
765 out() << ((index == Sections::SinceMemberFunctions) ?
"<p>Class " :
"<p>QML Type ");
767 out() <<
"<a href=\"" << linkForNode(parent, relative) <<
"\" translate=\"no\">";
768 QStringList pieces = parent->fullName().split(
"::");
769 out() << protectEnc(pieces.last());
773 generateSection(nv, relative, marker);
776 }
else if (index == Sections::SinceEnumValues) {
777 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
778 const auto map_it = m_qdb->newEnumValueMaps().constFind(atom->string());
779 for (
auto it = map_it->cbegin(); it != map_it->cend(); ++it) {
780 out() <<
"<tr><td class=\"memItemLeft\"> enum value </td><td class=\"memItemRight\">"
781 <<
"<b><a href=\"" << linkForNode(it.value(),
nullptr) <<
"\">"
782 << it.key() <<
"</a></b></td></tr>\n";
784 out() <<
"</table></div>\n";
786 generateSection(section.members(), relative, marker);
804 out() <<
"<p class=\"centerAlign\">";
806 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
807 if (!maybe_resolved_file) {
810 QStringLiteral(
"Missing image: %1").arg(protectEnc(atom->string())));
811 out() <<
"<font color=\"red\">[Missing image " << protectEnc(atom->string())
815 QString file_name{QFileInfo{file.get_path()}.fileName()};
835 "%1/%2"_L1.arg(outputDir(), imagesOutputDir()));
837 const auto &imgPath =
"%1/%2"_L1.arg(imagesOutputDir(), file_name);
839 out() <<
"<img src=\"%1\""_L1.arg(protectEnc(imgPath));
841 const QString altAndTitleText = protectEnc(text);
842 out() <<
" alt=\"" << altAndTitleText;
844 out() <<
"\" title=\"" << altAndTitleText;
848 if (m_helpProjectWriter)
849 m_helpProjectWriter->addExtraFile(imgPath);
850 setImageFileName(relative, imgPath);
862 QString admonType = atom->typeString();
865 out() <<
"<div class=\"admonition " << admonType.toLower() <<
"\">\n"
868 out() << admonType <<
": ";
878 out() <<
"<div class=\"LegaleseLeft\">";
892 const Node *node =
nullptr;
893 QString link = getLink(atom, relative, &node);
895 Location location = atom->isLinkAtom() ?
static_cast<
const LinkAtom*>(atom)->location
896 : relative->doc().location();
898 QStringLiteral(
"Can't link to '%1'").arg(atom->string()));
900 beginLink(link, node, relative);
904 QString link = linkForExampleFile(atom->string());
909 QString link = atom->string();
910 link =
"images/used-in-examples/" + link;
915 const Node *node =
static_cast<
const Node*>(
Utilities::nodeForString(atom->string()));
916 beginLink(linkForNode(node, relative), node, relative);
929 out() << R"(<div class="table"><table class="valuelist">)";
930 m_threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom);
931 if (m_threeColumnEnumValueTable) {
932 if (++m_numTableRows % 2 == 1)
933 out() << R"(<tr valign="top" class="odd">)";
935 out() << R"(<tr valign="top" class="even">)";
937 out() <<
"<th class=\"tblConst\">Constant</th>";
941 out() <<
"<th class=\"tblval\">Value</th>";
943 out() <<
"<th class=\"tbldscr\">Description</th></tr>\n";
945 out() <<
"<tr><th class=\"tblConst\">Constant</th><th "
946 "class=\"tblVal\">Value</th></tr>\n";
963 out() << QString(R"(<ol class="%1" type="%1" start="%2">)")
964 .arg(olType, atom
->next()->string());
966 out() << QString(R"(<ol class="%1" type="%1">)").arg(olType);
975 std::pair<QString,
int> pair = getAtomListValue(atom);
976 skipAhead = pair.second;
977 QString t = protectEnc(plainCode(marker->markedUpEnumValue(pair.first, relative)));
978 out() <<
"<tr><td class=\"topAlign\"><code translate=\"no\">" << t <<
"</code>";
981 out() <<
"</td><td class=\"topAlign tblval\">";
982 const auto *enume =
static_cast<
const EnumNode *>(relative);
983 QString itemValue = enume->itemValue(atom->next()->string());
984 if (itemValue.isEmpty())
987 out() <<
"<code translate=\"no\">" << protectEnc(itemValue) <<
"</code>";
1000 if (m_threeColumnEnumValueTable) {
1001 out() <<
"</td><td class=\"topAlign\">";
1008 if (matchAhead(atom, Atom::ParaLeft))
1015 out() <<
"</td></tr>\n";
1026 out() <<
"</table></div>\n";
1047 out() <<
"<blockquote>";
1050 out() <<
"</blockquote>\n";
1053 out() << atom->string();
1059 int unit = atom->string().toInt() +
hOffset(relative
);
1060 m_recentSectionRef = Tree::refForAtom(atom);
1061 out() <<
"<h" + QString::number(unit) + QLatin1Char(
' ') <<
"id=\""
1062 << m_recentSectionRef <<
"\">";
1063 m_inSectionHeading =
true;
1067 out() <<
"</h" + QString::number(atom->string().toInt() + hOffset(relative)) +
">\n";
1068 m_inSectionHeading =
false;
1075 if (m_inLink && !m_inContents && !m_inSectionHeading) {
1078 out() << protectEnc(atom->string());
1082 std::pair<QString, QString> pair = getTableWidthAttr(atom);
1083 QString attr = pair.second;
1084 QString width = pair.first;
1091 out() << R"(<div class="table"><table class=")" << attr <<
'"';
1092 if (!width.isEmpty())
1093 out() <<
" style=\"width: " << width <<
'"';
1098 out() <<
"</table></div>\n";
1101 out() <<
"<thead><tr class=\"qt-style\">";
1102 m_inTableHeader =
true;
1108 out() <<
"\n<tr class=\"qt-style\">";
1110 out() <<
"</thead>\n";
1111 m_inTableHeader =
false;
1115 if (!atom->string().isEmpty())
1116 out() <<
"<tr " << atom->string() <<
'>';
1117 else if (++m_numTableRows % 2 == 1)
1118 out() << R"(<tr valign="top" class="odd">)";
1120 out() << R"(<tr valign="top" class="even">)";
1126 if (m_inTableHeader)
1131 for (
int i = 0; i < atom->count(); ++i) {
1134 const QString &p = atom->string(i);
1135 if (p.contains(
'=')) {
1138 QStringList spans = p.split(QLatin1Char(
','));
1139 if (spans.size() == 2) {
1140 if (spans.at(0) !=
"1")
1141 out() <<
" colspan=\"" << spans.at(0) <<
'"';
1142 if (spans.at(1) !=
"1")
1143 out() <<
" rowspan=\"" << spans.at(1) <<
'"';
1148 if (matchAhead(atom, Atom::ParaLeft))
1152 if (m_inTableHeader)
1157 if (matchAhead(atom, Atom::ParaLeft))
1167 const QString ref = atom->count() == 2 ? atom->string(1)
1168 : TextUtils::asAsciiPrintable(atom->string());
1169 const Atom *next = atom;
1173 if (ref != m_recentSectionRef && (!section || Tree::refForAtom(section) != ref))
1174 out() <<
"<span id=\"" << ref <<
"\"></span>";
1178 out() <<
"<b class=\"redFont\"><Missing HTML></b>";
1180 case Atom::UnknownCommand:
1181 out() << R"(<b class="redFont"><code translate=\"no\">\)" << protectEnc(atom->string()) <<
"</code></b>";
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1229 auto link_for_group = [
this](
const CollectionNode *group) -> QString {
1230 QString target{linkForNode(group,
nullptr)};
1231 return (target.isEmpty()) ? protectEnc(group->name()) :
"<a href=\"" + target +
"\">" + protectEnc(group->fullTitle()) +
"</a>";
1236 const QStringList &groups_names{node->groupNames()};
1237 if (groups_names.isEmpty())
1240 std::vector<CollectionNode *> groups_nodes(groups_names.size(),
nullptr);
1241 std::transform(groups_names.cbegin(), groups_names.cend(), groups_nodes.begin(),
1244 m_qdb->mergeCollections(group);
1245 return (group && group
->wasSeen()) ? group :
nullptr;
1247 groups_nodes.erase(
std::remove(groups_nodes.begin(), groups_nodes.end(),
nullptr), groups_nodes.end());
1249 if (!groups_nodes.empty()) {
1250 text += node->name() +
" is part of ";
1252 for (std::vector<CollectionNode *>::size_type index{0}; index < groups_nodes.size(); ++index) {
1253 text += link_for_group(groups_nodes[index]) + TextUtils::separator(index, groups_nodes.size());
1260
1261
1262
1263
1274 QString typeWord = aggregate->typeWord(
true);
1277 fullTitle = aggregate->plainFullName();
1278 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1279 ns =
static_cast<NamespaceNode *>(aggregate);
1281 fullTitle = aggregate->plainFullName();
1282 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1284 title = fullTitle = aggregate->fullTitle();
1285 if (!aggregate->doc().title().isEmpty())
1286 titleText << aggregate->name() <<
" - "_L1 << aggregate->doc().title();
1291 if (aggregate
->parent()->isInAPI() || templateDecl) {
1293 appendTemplateDeclAtoms(subtitleText, *templateDecl);
1294 subtitleText <<
" "_L1;
1296 subtitleText << aggregate->typeWord(
false) <<
" "_L1;
1297 auto ancestors = fullTitle.split(
"::"_L1);
1298 ancestors.pop_back();
1299 for (
const auto &a : ancestors)
1300 subtitleText << Atom(Atom::AutoLink, a) <<
"::"_L1;
1301 subtitleText << aggregate->plainName();
1304 generateHeader(title, aggregate, marker);
1305 generateTableOfContents(aggregate, marker, &summarySections);
1307 generateTitle(titleText, subtitleText, SmallSubTitle, aggregate, marker);
1309 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1313 brief <<
"The " << ns->name() <<
" namespace includes the following elements from module "
1316 addNodeLink(brief, fullNamespace,
" here.");
1318 generateText(brief, ns, marker);
1321 generateBrief(aggregate, marker);
1323 const auto parentIsClass = aggregate
->parent()->isClassNode();
1326 generateRequisites(aggregate, marker);
1331 QString membersLink = generateAllMembersFile(sections.allMembersSection(), marker);
1332 if (!membersLink.isEmpty()) {
1333 openUnorderedList();
1334 out() <<
"<li><a href=\"" << membersLink <<
"\">"
1335 <<
"List of all members, including inherited members</a></li>\n";
1337 QString obsoleteLink = generateObsoleteMembersFile(sections, marker);
1338 if (!obsoleteLink.isEmpty()) {
1339 openUnorderedList();
1340 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1341 <<
"Deprecated members</a></li>\n";
1344 if (QString groups_text{groupReferenceText(aggregate)}; !groups_text.isEmpty()) {
1345 openUnorderedList();
1347 out() <<
"<li>" << groups_text <<
"</li>\n";
1350 closeUnorderedList();
1355 bool needOtherSection =
false;
1357 for (
const auto §ion : summarySections) {
1358 if (section.members().isEmpty() && section.reimplementedMembers().isEmpty()) {
1359 if (!section.inheritedMembers().isEmpty())
1360 needOtherSection =
true;
1362 if (!section.members().isEmpty()) {
1363 QString ref = registerRef(section.title().toLower());
1364 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1365 generateSection(section.members(), aggregate, marker);
1367 if (!section.reimplementedMembers().isEmpty()) {
1368 QString name = QString(
"Reimplemented ") + section.title();
1369 QString ref = registerRef(name.toLower());
1370 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(name) <<
"</h2>\n";
1371 generateSection(section.reimplementedMembers(), aggregate, marker);
1374 if (!section.inheritedMembers().isEmpty()) {
1376 generateSectionInheritedList(section, aggregate);
1382 if (needOtherSection) {
1383 out() <<
"<h3>Additional Inherited Members</h3>\n"
1386 for (
const auto §ion : summarySections) {
1387 if (section.members().isEmpty() && !section.inheritedMembers().isEmpty())
1388 generateSectionInheritedList(section, aggregate);
1393 if (aggregate
->doc().isEmpty()) {
1394 QString command =
"documentation";
1396 command = R"('\class' comment)";
1399 QStringLiteral(
"No %1 for '%2'").arg(command, aggregate->plainSignature()));
1402 generateExtractionMark(aggregate, DetailedDescriptionMark);
1403 out() <<
"<div class=\"descr\">\n"
1404 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1405 <<
"Detailed Description"
1408 out() <<
"</div>\n";
1409 generateAlsoList(aggregate, marker);
1410 generateExtractionMark(aggregate, EndMark);
1413 for (
const auto §ion : detailsSections) {
1414 bool headerGenerated =
false;
1415 if (section.isEmpty())
1418 const QList<Node *> &members = section.members();
1419 for (
const auto &member : members) {
1420 if (!headerGenerated) {
1421 if (!section.divClass().isEmpty())
1422 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1423 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1424 headerGenerated =
true;
1426 if (!member->isClassNode())
1427 generateDetailedMember(member, aggregate, marker);
1430 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1431 out() <<
" class=\"%1\""_L1.arg(attrs);
1432 out() <<
"> class ";
1433 generateFullName(member, aggregate);
1435 generateBrief(member, marker, aggregate);
1438 if (headerGenerated && !section.divClass().isEmpty())
1439 out() <<
"</div>\n";
1441 generateFooter(aggregate);
1454 QString rawTitle = aggregate->plainName();
1455 QString fullTitle = aggregate->plainFullName();
1456 QString title = rawTitle +
" Proxy Page";
1457 generateHeader(title, aggregate, marker, u"auto-generated"_s);
1458 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1459 generateBrief(aggregate, marker);
1460 for (
const auto §ion : summarySections) {
1461 if (!section.members().isEmpty()) {
1462 QString ref = registerRef(section.title().toLower());
1463 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1464 generateSection(section.members(), aggregate, marker);
1468 if (!aggregate
->doc().isEmpty()) {
1469 generateExtractionMark(aggregate, DetailedDescriptionMark);
1470 out() <<
"<div class=\"descr\">\n"
1471 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1472 <<
"Detailed Description"
1475 out() <<
"</div>\n";
1476 generateAlsoList(aggregate, marker);
1477 generateExtractionMark(aggregate, EndMark);
1480 for (
const auto §ion : detailsSections) {
1481 if (section.isEmpty())
1484 if (!section.divClass().isEmpty())
1485 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1486 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1488 const QList<Node *> &members = section.members();
1489 for (
const auto &member : members) {
1490 if (!member->isClassNode()) {
1491 generateDetailedMember(member, aggregate, marker);
1494 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1495 out() <<
" class=\"%1\""_L1.arg(attrs);
1496 out() <<
"> class ";
1497 generateFullName(member, aggregate);
1499 generateBrief(member, marker, aggregate);
1502 if (!section.divClass().isEmpty())
1503 out() <<
"</div>\n";
1505 generateFooter(aggregate);
1509
1510
1511
1515 SubTitleSize subTitleSize = LargeSubTitle;
1516 QString htmlTitle = qcn->name();
1518 htmlTitle.append(
" QML Value Type");
1520 htmlTitle.append(
" QML Type");
1523 htmlTitle.append(
" (Singleton)"_L1);
1525 htmlTitle.append(
" (Uncreatable)"_L1);
1527 generateHeader(htmlTitle, qcn, marker);
1530 marker = CodeMarker::markerForLanguage(QLatin1String(
"QML"));
1531 generateTitle(htmlTitle,
Text() << qcn->subtitle(), subTitleSize, qcn, marker);
1532 generateBrief(qcn, marker);
1533 generateQmlRequisites(qcn, marker);
1537 out() <<
"<p><strong>Note:</strong> This type is a QML singleton. "_L1
1538 <<
"There is only one instance of this type in the QML engine.</p>\n"_L1;
1540 out() <<
"<p><strong>Note:</strong> This is an uncreatable type. "_L1
1541 <<
"It cannot be instantiated in QML.</p>\n"_L1;
1544 QString allQmlMembersLink;
1548 allQmlMembersLink = generateAllQmlMembersFile(sections, marker);
1549 QString obsoleteLink = generateObsoleteQmlMembersFile(sections, marker);
1550 if (!allQmlMembersLink.isEmpty() || !obsoleteLink.isEmpty()) {
1551 openUnorderedList();
1553 if (!allQmlMembersLink.isEmpty()) {
1554 out() <<
"<li><a href=\"" << allQmlMembersLink <<
"\">"
1555 <<
"List of all members, including inherited members</a></li>\n";
1557 if (!obsoleteLink.isEmpty()) {
1558 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1559 <<
"Deprecated members</a></li>\n";
1563 if (QString groups_text{groupReferenceText(qcn)}; !groups_text.isEmpty()) {
1564 openUnorderedList();
1566 out() <<
"<li>" << groups_text <<
"</li>\n";
1569 closeUnorderedList();
1572 for (
const auto §ion : qmlSummarySections) {
1573 if (!section.isEmpty()) {
1574 QString ref = registerRef(section.title().toLower());
1575 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1576 generateQmlSummary(section.members(), qcn, marker);
1580 generateExtractionMark(qcn, DetailedDescriptionMark);
1581 out() <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1582 <<
"Detailed Description"
1585 generateAlsoList(qcn, marker);
1586 generateExtractionMark(qcn, EndMark);
1589 for (
const auto §ion : qmlDetailsSections) {
1590 if (section.isEmpty())
1592 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1593 const QList<Node *> &members = section.members();
1594 for (
const auto member : members)
1595 generateDetailedQmlMember(member, qcn, marker);
1597 generateFooter(qcn);
1602
1603
1604
1607 generateHeader(pn->fullTitle(), pn, marker);
1609
1610
1611
1612 if ((pn->name() != QLatin1String(
"index.html")))
1613 generateTableOfContents(pn, marker,
nullptr);
1615 generateTitle(pn
->doc().title(),
Text() << pn->subtitle(), LargeSubTitle, pn, marker);
1617 generateBrief(pn, marker,
nullptr,
false);
1620 generateExtractionMark(pn, DetailedDescriptionMark);
1621 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1625 out() <<
"</div>\n";
1626 generateAlsoList(pn, marker);
1627 generateExtractionMark(pn, EndMark);
1633
1634
1637 SubTitleSize subTitleSize = LargeSubTitle;
1640 generateHeader(cn->fullTitle(), cn, marker);
1641 generateTableOfContents(cn, marker,
nullptr);
1642 generateTitle(cn
->doc().title(),
Text() << cn->subtitle(), subTitleSize, cn, marker);
1645 if (cn
->genus() != Genus::DOC && cn
->genus() != Genus::DontCare) {
1647 generateBrief(cn, marker);
1655 if (!nmm.isEmpty()) {
1656 ref = registerRef(
"namespaces");
1657 out() <<
"<h2 id=\"" << ref <<
"\">Namespaces</h2>\n";
1658 generateAnnotatedList(cn, marker, nmm.values());
1661 if (!nmm.isEmpty()) {
1662 ref = registerRef(
"classes");
1663 out() <<
"<h2 id=\"" << ref <<
"\">Classes</h2>\n";
1664 generateAnnotatedList(cn, marker, nmm.values());
1670 generateExtractionMark(cn, DetailedDescriptionMark);
1671 ref = registerRef(
"details");
1672 out() <<
"<div class=\"descr\">\n";
1673 out() <<
"<h2 id=\"" << ref <<
"\">"
1674 <<
"Detailed Description"
1677 generateExtractionMark(cn, DetailedDescriptionMark);
1678 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1683 out() <<
"</div>\n";
1684 generateAlsoList(cn, marker);
1685 generateExtractionMark(cn, EndMark);
1690 if (!users.isEmpty()) {
1691 ref = registerRef(
"users");
1692 out() <<
"<h2 id=\"" << ref <<
"\">Used by</h2>\n";
1693 generateAnnotatedList(cn, marker, users);
1696 generateAnnotatedList(cn, marker, cn->members());
1703
1704
1705
1706
1709 SubTitleSize subTitleSize = LargeSubTitle;
1710 QString fullTitle = cn->name();
1712 generateHeader(fullTitle, cn, marker, u"auto-generated"_s);
1713 generateTitle(fullTitle,
Text() << cn->subtitle(), subTitleSize, cn, marker);
1716 brief <<
"Each function or type documented here is related to a class or "
1717 <<
"namespace that is documented in a different module. The reference "
1718 <<
"page for that class or namespace will link to the function or type "
1721 generateText(brief, cn, marker);
1725 for (
const auto &member : members)
1726 generateDetailedMember(member, cn, marker);
1732
1733
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764void HtmlGenerator::generateNavigationBar(
const QString &title,
const Node *node,
1765 CodeMarker *marker,
const QString &buildversion,
1768 if (m_noNavigationBar || node ==
nullptr)
1779 auto addNavItem = [&](
const QString &link,
const QString &title) {
1780 navigationbar << Atom(itemLeft) << Atom(
Atom::NavLink, link)
1787 auto addNavItemNode = [&](
const Node *node,
const QString &title) {
1788 navigationbar << Atom(itemLeft);
1789 addNodeLink(navigationbar, node, title);
1790 navigationbar << Atom(itemRight);
1794 const auto *moduleNode = m_qdb->getModuleNode(node);
1795 QString moduleState;
1796 if (moduleNode && !moduleNode->state().isEmpty())
1797 moduleState = QStringLiteral(
" (%1)").arg(moduleNode->state());
1799 if (m_hometitle == title)
1801 if (!m_homepage.isEmpty())
1802 addNavItem(m_homepage, m_hometitle);
1803 if (!m_landingpage.isEmpty() && m_landingtitle != title)
1804 addNavItem(m_landingpage, m_landingtitle);
1807 const bool hasClassesItem = !m_cppclassespage.isEmpty() && !m_cppclassestitle.isEmpty();
1809 addNavItem(m_cppclassespage, m_cppclassestitle);
1810 if (!node->physicalModuleName().isEmpty()) {
1814 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_cppclassespage)) {
1815 const QString moduleText = hasClassesItem || moduleNode->title().isEmpty()
1816 ? moduleNode->name() : moduleNode->title();
1817 addNavItemNode(moduleNode, moduleText + moduleState);
1820 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1822 const bool hasTypesItem = !m_qmltypespage.isEmpty() && !m_qmltypestitle.isEmpty();
1824 addNavItem(m_qmltypespage, m_qmltypestitle);
1828 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_qmltypespage)) {
1829 const QString moduleText = hasTypesItem || moduleNode->title().isEmpty()
1830 ? moduleNode->name() : moduleNode->title();
1831 addNavItemNode(moduleNode, moduleText + moduleState);
1833 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1836 auto currentNode{
static_cast<
const PageNode*>(node)};
1837 std::deque<
const Node *> navNodes;
1839 qsizetype navItems = 0;
1840 while (currentNode->navigationParent() && ++navItems < 16) {
1841 if (
std::find(navNodes.cbegin(), navNodes.cend(),
1842 currentNode->navigationParent()) == navNodes.cend())
1843 navNodes.push_front(currentNode->navigationParent());
1844 currentNode = currentNode->navigationParent();
1848 if (navNodes.empty()) {
1849 const QStringList groups =
static_cast<
const PageNode *>(node)->groupNames();
1850 for (
const auto &groupName : groups) {
1851 const auto *groupNode = m_qdb->findNodeByNameAndType(QStringList{groupName}, &Node::isGroup);
1852 if (groupNode && !groupNode->title().isEmpty()) {
1853 navNodes.push_front(groupNode);
1858 while (!navNodes.empty()) {
1859 if (navNodes.front()->isPageNode())
1860 addNavItemNode(navNodes.front(), navNodes.front()->title());
1861 navNodes.pop_front();
1865 navigationbar << Atom(itemLeft) << Atom(
Atom::String, title) << Atom(itemRight);
1869 generateText(navigationbar, node, marker);
1871 if (buildversion.isEmpty())
1877 out() <<
"</tr></table><table class=\"buildversion\"><tr>\n"
1878 << R"(<td id="buildversion" width="100%" align="right">)";
1880 out() <<
"<li id=\"buildversion\">";
1884 if (!m_landingpage.isEmpty() && m_landingtitle != title) {
1885 navigationbar << Atom(Atom::NavLink, m_landingpage)
1887 << Atom(Atom::String, buildversion)
1889 generateText(navigationbar, node, marker);
1891 out() << buildversion;
1900 const QString &metaKeyword)
1902 out() <<
"<!DOCTYPE html>\n";
1903 out() << QString(
"<html lang=\"%1\">\n").arg(naturalLanguage);
1904 out() <<
"<head>\n";
1905 out() <<
" <meta charset=\"utf-8\">\n";
1910 out() <<
" <meta name=\"description\" content=\""
1911 << protectEnc(node->doc().briefText().toString())
1915 if (!metaKeyword.isEmpty()) {
1917 out() <<
" <meta name=\"keywords\" content=\"%1\">\n"_L1.arg(protectEnc(metaKeyword));
1920 QStringList keywords;
1922 for (
const auto &kw : metaTags->values(u"keywords"_s))
1923 keywords << kw.split(
','_L1, Qt::SkipEmptyParts);
1928 keywords << node->nodeTypeString().toLower().remove(
' '_L1);
1930 if (!keywords.isEmpty()) {
1931 std::transform(keywords.begin(), keywords.end(), keywords.begin(),
1932 [](
const QString &k) {
return k.trimmed(); });
1933 keywords.removeDuplicates();
1934 out() <<
" <meta name=\"keywords\" content=\"" << protectEnc(keywords.join(
','_L1))
1940 QString titleSuffix;
1941 if (!m_landingtitle.isEmpty()) {
1943 titleSuffix = m_landingtitle;
1944 }
else if (!m_hometitle.isEmpty()) {
1947 if (title != m_hometitle)
1948 titleSuffix = m_hometitle;
1951 titleSuffix = m_productName.isEmpty() ? m_project : m_productName;
1953 if (title == titleSuffix)
1954 titleSuffix.clear();
1956 out() <<
" <title>";
1957 if (!titleSuffix.isEmpty() && !title.isEmpty()) {
1958 out() <<
"%1 | %2"_L1.arg(protectEnc(title), titleSuffix);
1960 out() << protectEnc(title);
1965 QVersionNumber projectVersion = QVersionNumber::fromString(m_qdb->version());
1966 if (!projectVersion.isNull()) {
1967 QVersionNumber titleVersion;
1968 static const QRegularExpression re(QLatin1String(R"(\d+\.\d+)"));
1969 const QString &versionedTitle = titleSuffix.isEmpty() ? title : titleSuffix;
1970 auto match = re.match(versionedTitle);
1971 if (match.hasMatch())
1972 titleVersion = QVersionNumber::fromString(match.captured());
1973 if (titleVersion.isNull() || !titleVersion.isPrefixOf(projectVersion)) {
1975 if (!m_productName.isEmpty() && titleSuffix != m_productName)
1976 out() <<
" | %1"_L1.arg(m_productName);
1977 out() <<
" %1"_L1.arg(projectVersion.toString());
1980 out() <<
"</title>\n";
1983 out() << m_headerStyles;
1984 out() << m_headerScripts;
1985 out() << m_endHeader;
1988 bool usingTable = m_postHeader.trimmed().endsWith(QLatin1String(
"<tr>"));
1989 generateNavigationBar(title, node, marker, m_buildversion, usingTable);
1990 out() << QString(m_postPostHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1992 m_navigationLinks.clear();
1994 m_recentSectionRef.clear();
1995 m_emittedMemberRefs.clear();
1997 if (node && !node->links().empty()) {
1998 std::pair<QString, QString> linkPair;
1999 std::pair<QString, QString> anchorPair;
2000 const Node *linkNode;
2001 bool useSeparator =
false;
2005 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
2008 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
2009 if (linkNode ==
nullptr || linkNode == node)
2010 anchorPair = linkPair;
2012 anchorPair = anchorForNode(linkNode);
2014 out() << R"( <link rel="prev" href=")" << anchorPair.first <<
"\" />\n";
2016 m_navigationLinks += R"(<a class="prevPage" href=")" + anchorPair.first +
"\">";
2017 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
2018 m_navigationLinks += protect(anchorPair.second);
2020 m_navigationLinks += protect(linkPair.second);
2021 m_navigationLinks +=
"</a>\n";
2022 useSeparator = !m_navigationSeparator.isEmpty();
2026 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
2029 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
2030 if (linkNode ==
nullptr || linkNode == node)
2031 anchorPair = linkPair;
2033 anchorPair = anchorForNode(linkNode);
2035 out() << R"( <link rel="next" href=")" << anchorPair.first <<
"\" />\n";
2038 m_navigationLinks += m_navigationSeparator;
2040 m_navigationLinks += R"(<a class="nextPage" href=")" + anchorPair.first +
"\">";
2041 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
2042 m_navigationLinks += protect(anchorPair.second);
2044 m_navigationLinks += protect(linkPair.second);
2045 m_navigationLinks +=
"</a>\n";
2049 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
2052 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
2053 if (linkNode ==
nullptr || linkNode == node)
2054 anchorPair =
std::move(linkPair);
2056 anchorPair = anchorForNode(linkNode);
2057 out() << R"( <link rel="start" href=")" << anchorPair.first <<
"\" />\n";
2061 if (node && !node->links().empty())
2062 out() <<
"<p class=\"naviNextPrevious headerNavi\">\n" << m_navigationLinks <<
"</p>\n";
2066 SubTitleSize subTitleSize,
const Node *relative,
2072 attribute = R"( translate="no")";
2075 out() <<
"<h1 class=\"title\"" << attribute <<
">";
2076 generateText(title, relative, marker);
2081 if (subTitleSize == SmallSubTitle)
2082 out() <<
" class=\"small-subtitle\"" << attribute <<
">";
2084 out() <<
" class=\"subtitle\"" << attribute <<
">";
2085 generateText(subtitle, relative, marker);
2086 out() <<
"</span>\n";
2092 if (node && !node->links().empty())
2093 out() <<
"<p class=\"naviNextPrevious footerNavi\">\n" << m_navigationLinks <<
"</p>\n";
2095 out() << QString(m_footer).replace(
"\\" +
COMMAND_VERSION, m_qdb->version())
2096 << QString(m_address).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
2098 out() <<
"</body>\n";
2099 out() <<
"</html>\n";
2103
2104
2105
2108 QMap<QString, Text> requisites;
2111 const QString headerText =
"Header";
2112 const QString sinceText =
"Since";
2113 const QString inheritedByText =
"Inherited By";
2114 const QString inheritsText =
"Inherits";
2115 const QString nativeTypeText =
"In QML";
2116 const QString qtVariableText =
"qmake";
2117 const QString cmakeText =
"CMake";
2118 const QString statusText =
"Status";
2121 const QStringList requisiteorder { headerText, cmakeText, qtVariableText, sinceText,
2122 nativeTypeText, inheritsText, inheritedByText, statusText };
2124 addIncludeFileToMap(aggregate, requisites, text, headerText);
2125 addSinceToMap(aggregate, requisites, &text, sinceText);
2128 addCMakeInfoToMap(aggregate, requisites, &text, cmakeText);
2129 addQtVariableToMap(aggregate, requisites, &text, qtVariableText);
2133 auto *classe =
dynamic_cast<
ClassNode *>(aggregate);
2135 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2137 if (InclusionFilter::isIncluded(policy, context))
2138 addQmlNativeTypesToMap(requisites, &text, nativeTypeText, classe);
2141 const auto *metaTags = classe ? classe
->doc().metaTagMap() :
nullptr;
2142 if (!metaTags || !metaTags->contains(u"qdoc-suppress-inheritance"_s))
2143 addInheritsToMap(requisites, &text, inheritsText, classe);
2144 addInheritedByToMap(requisites, &text, inheritedByText, classe);
2148 addStatusToMap(aggregate, requisites, text, statusText);
2150 if (!requisites.isEmpty()) {
2152 generateTheTable(requisiteorder, requisites, aggregate, marker);
2157
2158
2159void HtmlGenerator::generateTheTable(
const QStringList &requisiteOrder,
2160 const QMap<QString, Text> &requisites,
2163 out() <<
"<div class=\"table\"><table class=\"alignedsummary requisites\" translate=\"no\">\n";
2165 for (
auto it = requisiteOrder.constBegin(); it != requisiteOrder.constEnd(); ++it) {
2167 if (requisites.contains(*it)) {
2169 <<
"<td class=\"memItemLeft rightAlign topAlign\"> " << *it
2171 "</td><td class=\"memItemRight bottomAlign\"> ";
2173 generateText(requisites.value(*it), aggregate, marker);
2174 out() <<
"</td></tr>\n";
2177 out() <<
"</table></div>\n";
2181
2182
2183
2184void HtmlGenerator::addInheritedByToMap(QMap<QString, Text> &requisites,
Text *text,
2185 const QString &inheritedByText,
ClassNode *classe)
2187 if (!classe->derivedClasses().isEmpty()) {
2190 int count = appendSortedNames(*text, classe, classe->derivedClasses());
2193 requisites.insert(inheritedByText, *text);
2198
2199
2200
2201void HtmlGenerator::addInheritsToMap(QMap<QString, Text> &requisites,
Text *text,
2202 const QString &inheritsText,
ClassNode *classe)
2204 if (!classe->baseClasses().isEmpty()) {
2207 const auto baseClasses = classe->baseClasses();
2208 for (
const auto &cls : baseClasses) {
2210 appendFullName(*text, cls.m_node, classe);
2212 if (cls.m_access == Access::Protected) {
2213 *text <<
" (protected)";
2214 }
else if (cls.m_access == Access::Private) {
2215 *text <<
" (private)";
2217 *text << TextUtils::comma(index++, classe->baseClasses().size());
2222 requisites.insert(inheritsText, *text);
2227
2228
2229
2230void HtmlGenerator::addQmlNativeTypesToMap(QMap<QString, Text> &requisites,
Text *text,
2231 const QString &nativeTypeText,
ClassNode *classe)
const
2238 QList<QmlTypeNode *> nativeTypes { classe->qmlNativeTypes().cbegin(), classe->qmlNativeTypes().cend()};
2240 qsizetype index { 0 };
2242 for (
const auto &item : std::as_const(nativeTypes)) {
2243 addNodeLink(*text, item);
2244 *text << TextUtils::comma(index++, nativeTypes.size());
2246 requisites.insert(nativeTypeText, *text);
2250
2251
2252
2254 Text *text,
const QString &CMakeInfo)
const
2256 if (!aggregate->physicalModuleName().isEmpty() && text !=
nullptr) {
2258 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2260 const auto result = cmakeRequisite(cn);
2273 requisites.insert(CMakeInfo, *text);
2278
2279
2280
2282 Text *text,
const QString &qtVariableText)
const
2284 if (!aggregate->physicalModuleName().isEmpty()) {
2286 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2288 if (cn && !cn->qtVariable().isEmpty()) {
2291 requisites.insert(qtVariableText, *text);
2297
2298
2299
2300
2302 Text *text,
const QString &sinceText)
const
2304 if (!aggregate->since().isEmpty() && text !=
nullptr) {
2307 requisites.insert(sinceText, *text);
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2323 Text &text,
const QString &statusText)
const
2325 auto status{formatStatus(aggregate, m_qdb)};
2331 spanClass = u"deprecated"_s;
2333 spanClass =
TextUtils::asAsciiPrintable(status.value());
2336 text << Atom(Atom::String, status.value())
2338 "class=\"status %1\""_L1.arg(spanClass))
2340 requisites.insert(statusText, text);
2344
2345
2346
2347
2349 QMap<QString, Text> &requisites,
Text& text,
2350 const QString &headerText)
2352 if (aggregate->includeFile()) {
2354 text << openCodeTag <<
"#include <%1>"_L1.arg(*aggregate->includeFile()) << closeCodeTag;
2355 requisites.insert(headerText, text);
2360
2361
2362
2368 QMap<QString, Text> requisites;
2371 const QString importText =
"Import Statement";
2372 const QString sinceText =
"Since";
2373 const QString inheritedByText =
"Inherited By";
2374 const QString inheritsText =
"Inherits";
2375 const QString nativeTypeText =
"In C++";
2376 const QString statusText =
"Status";
2379 QString logicalModuleVersion;
2384 bool generate_import =
true;
2386 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2390 if (generate_import) {
2394 requisites.insert(importText, text);
2397 qcn
->doc().location().warning(QStringLiteral(
"Could not resolve QML import statement for type '%1'").arg(qcn->name()),
2402 if (!qcn->since().isEmpty()) {
2405 requisites.insert(sinceText, text);
2410 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2414 addNodeLink(text, cn);
2415 requisites.insert(nativeTypeText, text);
2423 QStringList knownTypeNames{qcn->name()};
2425 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2433 knownTypeNames << base->name();
2436 addNodeLink(text, base);
2439 for (
const auto sub : std::as_const(subs)) {
2440 if (knownTypeNames.contains(sub->name())) {
2441 text << Atom(Atom::String,
" (%1)"_L1.arg(base->logicalModuleName()));
2446 requisites.insert(inheritsText, text);
2450 if (!subs.isEmpty()) {
2453 int count = appendSortedQmlNames(text, qcn, knownTypeNames, subs);
2456 requisites.insert(inheritedByText, text);
2460 addStatusToMap(qcn, requisites, text, statusText);
2463 const QStringList requisiteorder {
std::move(importText),
std::move(sinceText),
2464 std::move(nativeTypeText),
std::move(inheritsText),
2465 std::move(inheritedByText),
std::move(statusText)};
2467 if (!requisites.isEmpty())
2468 generateTheTable(requisiteorder, requisites, qcn, marker);
2480 QStringLiteral(
"'\\brief' statement does not end with a full stop."));
2482 generateExtractionMark(node, BriefMark);
2484 generateText(brief, node, marker);
2487 if (!relative || node == relative)
2488 out() <<
" <a href=\"#";
2490 out() <<
" <a href=\"" << linkForNode(node, relative) <<
'#';
2491 out() << registerRef(
"details") <<
"\">More...</a>";
2495 generateExtractionMark(node, EndMark);
2500
2501
2502
2508 toc = node
->doc().tableOfContents();
2509 if (tocDepth == 0 || (toc.isEmpty() && !sections && !node
->isModule())) {
2514 int sectionNumber = 1;
2515 int detailsBase = 0;
2518 m_inContents =
true;
2520 out() <<
"<div class=\"sidebar\">\n";
2521 out() <<
"<div class=\"toc\">\n";
2522 out() <<
"<h3 id=\"toc\">Contents</h3>\n";
2525 openUnorderedList();
2526 if (!
static_cast<
const CollectionNode *>(node)->noAutoList()) {
2528 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2529 << registerRef(
"namespaces") <<
"\">Namespaces</a></li>\n";
2532 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2533 << registerRef(
"classes") <<
"\">Classes</a></li>\n";
2536 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#" << registerRef(
"details")
2537 <<
"\">Detailed Description</a></li>\n";
2538 for (
const auto &entry : std::as_const(toc)) {
2539 if (entry->string().toInt() == 1) {
2545 for (
const auto §ion : *sections) {
2546 if (!section.members().isEmpty()) {
2547 openUnorderedList();
2548 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2549 << registerRef(section.plural()) <<
"\">" << section.title() <<
"</a></li>\n";
2551 if (!section.reimplementedMembers().isEmpty()) {
2552 openUnorderedList();
2553 QString ref = QString(
"Reimplemented ") + section.plural();
2554 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2555 << registerRef(ref.toLower()) <<
"\">"
2556 << QString(
"Reimplemented ") + section.title() <<
"</a></li>\n";
2560 openUnorderedList();
2561 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2562 << registerRef(
"details") <<
"\">Detailed Description</a></li>\n";
2564 for (
const auto &entry : toc) {
2565 if (entry->string().toInt() == 1) {
2572 for (
const auto &atom : toc) {
2573 sectionNumber = atom->string().toInt() + detailsBase;
2576 if (sectionNumber <= tocDepth || tocDepth < 0) {
2577 openUnorderedList();
2579 Text headingText = Text::sectionHeading(atom);
2580 out() <<
"<li class=\"level" << sectionNumber <<
"\">";
2581 out() <<
"<a href=\"" <<
'#' << Tree::refForAtom(atom) <<
"\">";
2582 generateAtomList(headingText.firstAtom(), node, marker,
true, numAtoms);
2583 out() <<
"</a></li>\n";
2586 closeUnorderedList();
2587 out() <<
"</div>\n";
2588 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2589 out() <<
"</div>\n";
2590 m_inContents =
false;
2595
2596
2599 out() <<
"<div class=\"sidebar\">";
2600 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2601 out() <<
"</div>\n";
2610 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2611 beginSubPage(aggregate, fileName);
2612 QString title =
"List of All Members for " + aggregate->plainFullName();
2613 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2615 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2616 out() <<
"<p>This is the complete list of members for ";
2617 generateFullName(aggregate,
nullptr);
2618 out() <<
", including inherited members.</p>\n";
2620 generateSectionList(section, aggregate, marker);
2628
2629
2630
2631
2632
2640 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2641 beginSubPage(aggregate, fileName);
2642 QString title =
"List of All Members for " + aggregate->name();
2643 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2645 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2646 out() <<
"<p>This is the complete list of members for ";
2647 generateFullName(aggregate,
nullptr);
2648 out() <<
", including inherited members.</p>\n";
2651 for (
int i = 0; i < cknl.size(); i++) {
2652 const auto &ckn = cknl[i];
2655 if (nodes.isEmpty())
2658 out() <<
"<p>The following members are inherited from ";
2659 generateFullName(qcn,
nullptr);
2662 openUnorderedList();
2663 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2664 for (
int j = 0; j < nodes.size(); j++) {
2665 Node *node = nodes[j];
2672 std::function<
void(
Node *)> generate = [&](Node *n) {
2673 out() <<
"<li class=\"fn\" translate=\"no\">";
2674 generateQmlItem(n, aggregate, marker,
true);
2675 if (n->isQmlProperty()) {
2676 auto qpn =
static_cast<QmlPropertyNode *>(n);
2677 QStringList hints = qpn->hints();
2678 if (qpn->isAttached())
2679 hints <<
"attached"_L1;
2680 if (!hints.isEmpty())
2681 out() <<
" [" << hints.join(
' '_L1) <<
"]";
2682 }
else if (n->isAttached()) {
2684 out() <<
" [attached]";
2687 if (n->isPropertyGroup()) {
2689 const QList<Node *> &collective =
2690 static_cast<SharedCommentNode *>(n)->collective();
2691 std::for_each(collective.begin(), collective.end(), generate);
2698 closeUnorderedList();
2715 QString title =
"Obsolete Members for " + aggregate->plainFullName();
2716 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2718 beginSubPage(aggregate, fileName);
2719 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2721 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2723 out() <<
"<p><b>The following members of class "
2724 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\" translate=\"no\">"
2725 << protectEnc(aggregate->name()) <<
"</a>"
2726 <<
" are deprecated.</b> "
2727 <<
"They are provided to keep old source code working. "
2728 <<
"We strongly advise against using them in new code.</p>\n";
2730 for (
const auto §ion : summary_spv) {
2731 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2732 generateSectionList(*section, aggregate, marker,
true);
2735 for (
const auto §ion : details_spv) {
2736 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2738 const NodeVector &members = section->obsoleteMembers();
2739 for (
const auto &member : members)
2740 generateDetailedMember(member, aggregate, marker);
2749
2750
2751
2752
2761 QString title =
"Obsolete Members for " + aggregate->name();
2762 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2764 beginSubPage(aggregate, fileName);
2765 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2767 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2769 out() <<
"<p><b>The following members of QML type "
2770 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\">"
2771 << protectEnc(aggregate->name()) <<
"</a>"
2772 <<
" are deprecated.</b> "
2773 <<
"They are provided to keep old source code working. "
2774 <<
"We strongly advise against using them in new code.</p>\n";
2776 for (
const auto §ion : summary_spv) {
2777 QString ref = registerRef(section->title().toLower());
2778 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section->title()) <<
"</h2>\n";
2779 generateQmlSummary(section->obsoleteMembers(), aggregate, marker);
2782 for (
const auto §ion : details_spv) {
2783 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2784 const NodeVector &members = section->obsoleteMembers();
2785 for (
const auto &member : members) {
2786 generateDetailedQmlMember(member, aggregate, marker);
2798 if (classMap.isEmpty())
2802 for (
const auto &it : classMap) {
2803 auto *classe =
static_cast<ClassNode *>(it);
2804 if (classe->baseClasses().isEmpty())
2805 topLevel.insert(classe->name(), classe);
2808 QStack<NodeMap> stack;
2809 stack.push(topLevel);
2812 while (!stack.isEmpty()) {
2813 if (stack.top().isEmpty()) {
2819 generateFullName(child, relative);
2821 stack.top().erase(stack.top().begin());
2824 const auto derivedClasses = child->derivedClasses();
2825 for (
const RelatedClass &d : derivedClasses) {
2826 if (d.m_node && d.m_node->isInAPI())
2827 newTop.insert(d.m_node->name(), d.m_node);
2829 if (!newTop.isEmpty()) {
2838
2839
2840
2845 if (relative ==
nullptr)
2848 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2849 for (
auto *node : nodes) {
2850 const NodeContext context = node->createContext();
2851 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
2852 included.insert(node->fullName(relative), node);
2858 const NodeList &unsortedNodes, Qt::SortOrder sortOrder)
2860 generateAnnotatedList(relative, marker, includedAnnotatedMembers(relative, unsortedNodes),
2867 if (nodeMap.isEmpty())
2869 out() <<
"<div class=\"table\"><table class=\"annotated\">\n";
2873 if (sortOrder == Qt::DescendingOrder)
2879 auto sameLocation = [
this](
const Node *a,
const Node *b) {
2880 return fullDocumentLocation(a) == fullDocumentLocation(b);
2882 nodes.erase(
std::unique(nodes.begin(), nodes.end(), sameLocation), nodes.end());
2884 for (
const auto *node : std::as_const(nodes)) {
2886 out() <<
"<tr class=\"odd topAlign\">";
2888 out() <<
"<tr class=\"even topAlign\">";
2889 out() <<
"<td class=\"tblName\" translate=\"no\"><p>";
2890 generateFullName(node, relative);
2891 out() <<
"</p></td>";
2893 if (!node->isTextPageNode()) {
2894 Text brief = node->doc().trimmedBriefText(node->name());
2895 if (!brief.isEmpty()) {
2896 out() <<
"<td class=\"tblDescr\"><p>";
2897 generateText(brief, node, marker);
2898 out() <<
"</p></td>";
2899 }
else if (!node->reconstitutedBrief().isEmpty()) {
2900 out() <<
"<td class=\"tblDescr\"><p>";
2901 out() << node->reconstitutedBrief();
2902 out() <<
"</p></td>";
2905 out() <<
"<td class=\"tblDescr\"><p>";
2906 if (!node->reconstitutedBrief().isEmpty()) {
2907 out() << node->reconstitutedBrief();
2909 out() << protectEnc(node->doc().briefText().toString());
2910 out() <<
"</p></td>";
2914 out() <<
"</table></div>\n";
2918
2919
2920
2924 const auto &uniqueKeys = nmm.uniqueKeys();
2925 for (
const QString &name : uniqueKeys) {
2926 if (!name.isEmpty()) {
2927 out() <<
"<h2 id=\"" << registerRef(name.toLower()) <<
"\">" << protectEnc(name)
2930 generateAnnotatedList(relative, marker, nmm.values(name));
2935
2936
2937
2938
2939
2940
2941
2942
2943
2946 const QString &commonPrefix)
2951 const int NumParagraphs = 37;
2952 qsizetype commonPrefixLen = commonPrefix.size();
2955
2956
2957
2958
2959
2961 QString paragraphName[NumParagraphs + 1];
2962 QSet<
char> usedParagraphNames;
2964 for (
auto c = nmm.constBegin(); c != nmm.constEnd(); ++c) {
2965 QStringList pieces = c.key().split(
"::");
2966 int idx = commonPrefixLen;
2967 if (idx > 0 && !pieces.last().startsWith(commonPrefix, Qt::CaseInsensitive))
2969 QString last = pieces.last().toLower();
2970 QString key = last.mid(idx);
2972 int paragraphNr = NumParagraphs - 1;
2974 if (key[0].digitValue() != -1) {
2975 paragraphNr = key[0].digitValue();
2976 }
else if (key[0] >= QLatin1Char(
'a') && key[0] <= QLatin1Char(
'z')) {
2977 paragraphNr = 10 + key[0].unicode() -
'a';
2980 paragraphName[paragraphNr] = key[0].toUpper();
2981 usedParagraphNames.insert(key[0].toLower().cell());
2982 paragraph[paragraphNr].insert(last, c.value());
2986
2987
2988
2989
2990
2991
2992
2993 qsizetype paragraphOffset[NumParagraphs + 1];
2994 paragraphOffset[0] = 0;
2995 for (
int i = 0; i < NumParagraphs; i++)
2996 paragraphOffset[i + 1] = paragraphOffset[i] + paragraph[i].size();
2999
3000
3001 if (includeAlphabet) {
3002 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
3003 for (
int i = 0; i < 26; i++) {
3005 if (usedParagraphNames.contains(
char(
'a' + i)))
3006 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
3008 out() <<
"</b></p>\n";
3012
3013
3014 out() <<
"<div class=\"flowListDiv\" translate=\"no\">\n";
3018 QHash<QString,
int> nameOccurrences;
3019 for (
const auto &[key, node] : nmm.asKeyValueRange()) {
3020 QStringList pieces{node->fullName(relative).split(
"::"_L1)};
3021 const QString &name{pieces.last()};
3022 nameOccurrences[name]++;
3026 int curParOffset = 0;
3028 for (
int i = 0; i < nmm.size(); i++) {
3029 while ((curParNr < NumParagraphs) && (curParOffset == paragraph[curParNr].size())) {
3035
3036
3037 if (curParOffset == 0) {
3040 if (++m_numTableRows % 2 == 1)
3041 out() <<
"<dl class=\"flowList odd\">";
3043 out() <<
"<dl class=\"flowList even\">";
3044 out() <<
"<dt class=\"alphaChar\"";
3045 if (includeAlphabet)
3046 out() << QString(
" id=\"%1\"").arg(paragraphName[curParNr][0].toLower());
3047 out() <<
"><b>" << paragraphName[curParNr] <<
"</b></dt>\n";
3051
3052
3054 if ((curParNr < NumParagraphs) && !paragraphName[curParNr].isEmpty()) {
3055 NodeMultiMap::Iterator it;
3056 NodeMultiMap::Iterator next;
3057 it = paragraph[curParNr].begin();
3058 for (
int j = 0; j < curParOffset; j++)
3063
3064
3065
3066 out() <<
"<a href=\"" << linkForNode(it.value(), relative) <<
"\">";
3068 QString fileName = fileBase(it.value()) +
"-obsolete." + fileExtension();
3071 link =
"../%1/"_L1.arg(it.value()->tree()->physicalModuleName());
3073 out() <<
"<a href=\"" << link <<
"\">";
3076 QStringList pieces{it.value()->fullName(relative).split(
"::"_L1)};
3077 const auto &name{pieces.last()};
3080 if (nameOccurrences[name] > 1) {
3081 const QString moduleName = it.value()->isQmlNode() ? it.value()->logicalModuleName()
3082 : it.value()->tree()->camelCaseModuleName();
3083 pieces.last().append(
": %1"_L1.arg(moduleName));
3086 out() << protectEnc(pieces.last());
3088 if (pieces.size() > 1) {
3090 generateFullName(it.value()->parent(), relative);
3100 out() <<
"</div>\n";
3105 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
3106 for (
int i = 0; i < 26; i++) {
3108 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
3110 out() <<
"</b></p>\n";
3112 char nextLetter =
'a';
3114 out() <<
"<ul translate=\"no\">\n";
3115 NodeMapMap &funcIndex = m_qdb->getFunctionIndex();
3116 for (
auto fnMap = funcIndex.constBegin(); fnMap != funcIndex.constEnd(); ++fnMap) {
3117 const QString &key = fnMap.key();
3118 const QChar firstLetter = key.isEmpty() ? QChar(
'A') : key.front();
3119 Q_ASSERT_X(firstLetter.unicode() < 256,
"generateFunctionIndex",
3120 "Only valid C++ identifiers were expected");
3121 const char currentLetter = firstLetter.isLower() ? firstLetter.unicode() : nextLetter - 1;
3123 if (currentLetter < nextLetter) {
3127 while (nextLetter < currentLetter)
3128 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
3129 Q_ASSERT(nextLetter == currentLetter);
3130 out() << QStringLiteral(
"<li id=\"%1\">").arg(nextLetter++);
3132 out() << protectEnc(key) <<
':';
3134 for (
auto it = (*fnMap).constBegin(); it != (*fnMap).constEnd(); ++it) {
3136 generateFullName((*it)->parent(), relative, *it);
3140 while (nextLetter <=
'z')
3141 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
3148 for (
auto it = legaleseTexts.cbegin(), end = legaleseTexts.cend(); it != end; ++it) {
3149 Text text = it.key();
3150 generateText(text, relative, marker);
3154 generateFullName(it.value(), relative);
3157 }
while (it != legaleseTexts.constEnd() && it.key() == text);
3165 QString marked = marker->markedUpQmlItem(node, summary);
3166 marked.replace(
"@param>",
"i>");
3168 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3169 .arg(summary ?
"summary"_L1 :
"details"_L1));
3170 marked.replace(
"</@extra>",
"</code>");
3174 marked.remove(
"<@name>");
3175 marked.remove(
"</@name>");
3176 marked.remove(
"<@type>");
3177 marked.remove(
"</@type>");
3179 out() << highlightedCode(marked, relative,
false, Genus::QML);
3183
3184
3185
3186
3187
3188
3189
3192 m_qdb->mergeCollections(cn);
3197 if (sortOrder == Qt::DescendingOrder)
3202 for (
const auto *node : std::as_const(members)) {
3203 out() <<
"<li translate=\"no\">";
3204 generateFullName(node,
nullptr);
3212 const QString &selector, Qt::SortOrder sortOrder)
3216 if (selector == QLatin1String(
"overviews"))
3218 else if (selector == QLatin1String(
"cpp-modules"))
3220 else if (selector == QLatin1String(
"qml-modules"))
3224 m_qdb->mergeCollections(type, cnm, relative);
3225 const auto collectionList = cnm.values();
3226 nodeList.reserve(collectionList.size());
3227 for (
auto *collectionNode : collectionList)
3228 nodeList.append(collectionNode);
3229 generateAnnotatedList(relative, marker, nodeList, sortOrder);
3232
3233
3234
3235
3238 QStringLiteral(
"\\generatelist {%1} is only allowed in \\group, "
3239 "\\module and \\qmlmodule comments.")
3243 auto *node =
const_cast<
Node *>(relative);
3244 auto *collectionNode =
static_cast<CollectionNode *>(node);
3245 if (!collectionNode)
3247 m_qdb->mergeCollections(collectionNode);
3248 generateAnnotatedList(collectionNode, marker, collectionNode->members(), sortOrder);
3254 bool alignNames =
true;
3255 if (!nv.isEmpty()) {
3256 bool twoColumn =
false;
3257 if (nv.first()->isProperty()) {
3258 twoColumn = (nv.size() >= 5);
3262 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3265 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3266 <<
"<tr><td class=\"topAlign\">";
3271 for (
const auto &member : nv) {
3274 out() <<
"<tr><td class=\"memItemLeft rightAlign topAlign\"> ";
3276 if (twoColumn && i == (nv.size() + 1) / 2)
3277 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3278 out() <<
"<li class=\"fn\" translate=\"no\">";
3281 generateSynopsis(member, relative, marker, Section::Summary, alignNames);
3283 out() <<
"</td></tr>\n";
3289 out() <<
"</table></div>\n";
3293 out() <<
"</td></tr>\n</table></div>\n";
3301 bool alignNames =
true;
3304 if (!members.isEmpty()) {
3305 bool hasPrivateSignals =
false;
3306 bool isInvokable =
false;
3307 bool twoColumn =
false;
3310 twoColumn = (members.size() >= 16);
3311 }
else if (members.first()->isProperty()) {
3312 twoColumn = (members.size() >= 5);
3316 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3319 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3320 <<
"<tr><td class=\"topAlign\">";
3325 for (
const auto &member : members) {
3328 if (member->name().isEmpty())
3332 out() <<
"<tr><td class=\"memItemLeft topAlign rightAlign\"> ";
3334 if (twoColumn && i == (members.size() + 1) / 2)
3335 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3336 out() <<
"<li class=\"fn\" translate=\"no\">";
3339 generateSynopsis(member, relative, marker, section.style(), alignNames);
3340 if (member->isFunction()) {
3341 const auto *fn =
static_cast<
const FunctionNode *>(member);
3342 if (fn->isPrivateSignal()) {
3343 hasPrivateSignals =
true;
3345 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3346 }
else if (fn->isInvokable()) {
3349 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3353 out() <<
"</td></tr>\n";
3359 out() <<
"</table></div>\n";
3363 out() <<
"</td></tr>\n</table></div>\n";
3366 if (hasPrivateSignals)
3374 && !section.inheritedMembers().isEmpty()) {
3376 generateSectionInheritedList(section, relative);
3383 const QList<std::pair<
const Aggregate *,
int>> &inheritedMembers = section.inheritedMembers();
3384 for (
const auto &member : inheritedMembers) {
3385 out() <<
"<li class=\"fn\" translate=\"no\">";
3386 out() << member.second <<
' ';
3387 if (member.second == 1) {
3388 out() << section.singular();
3390 out() << section.plural();
3392 out() <<
" inherited from <a href=\"" << fileName(member.first) <<
'#'
3393 << Generator::cleanRef(section.title().toLower()) <<
"\">"
3394 << protectEnc(member.first->plainFullName(relative)) <<
"</a></li>\n";
3401 QString marked = marker->markedUpSynopsis(node, relative, style);
3402 marked.replace(
"@param>",
"i>");
3405 marked.remove(
"<@name>");
3406 marked.remove(
"</@name>");
3410 static const QRegularExpression extraRegExp(
"<@extra>.*</@extra>",
3411 QRegularExpression::InvertedGreedinessOption);
3412 marked.remove(extraRegExp);
3414 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3415 .arg(style == Section::Summary ?
"summary"_L1 :
"details"_L1));
3416 marked.replace(
"</@extra>",
"</code>");
3420 marked.remove(
"<@type>");
3421 marked.remove(
"</@type>");
3424 out() << highlightedCode(marked, relative, alignNames);
3427QString
HtmlGenerator::highlightedCode(
const QString &markedCode,
const Node *relative,
3428 bool alignNames, Genus genus)
3430 QString src = markedCode;
3432 html.reserve(src.size());
3436 const QChar charLangle =
'<';
3437 const QChar charAt =
'@';
3439 static const QString typeTag(
"type");
3440 static const QString headerTag(
"headerfile");
3441 static const QString funcTag(
"func");
3442 static const QString linkTag(
"link");
3443 static const QString extrefTag(
"extref");
3444 static const QString conceptTag(
"concept");
3447 static const QHash<QString, QString> extrefUrls = {
3448 {
"cpp-explicitly-defaulted"_L1,
3449 "https://en.cppreference.com/w/cpp/language/function#Defaulted_functions"_L1},
3450 {
"cpp-deleted-functions"_L1,
3451 "https://en.cppreference.com/w/cpp/language/function#Deleted_functions"_L1},
3458 for (
int i = 0, srcSize = src.size(); i < srcSize;) {
3459 if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
3460 if (alignNames && !done) {
3461 html += QLatin1String(
"</td><td class=\"memItemRight bottomAlign\">");
3465 if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) {
3466 html += QLatin1String(
"<b>");
3467 const Node *n =
static_cast<
const Node*>(
Utilities::nodeForString(par1.toString()));
3468 QString link = linkForNode(n, relative);
3469 addLink(link, arg, &html);
3470 html += QLatin1String(
"</b>");
3471 }
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
3472 const FunctionNode *fn = m_qdb->findFunctionNode(par1.toString(), relative, genus);
3473 QString link = linkForNode(fn, relative);
3474 addLink(link, arg, &html);
3475 par1 = QStringView();
3476 }
else if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
3477 par1 = QStringView();
3478 const Node *n = m_qdb->findTypeNode(arg.toString(), relative, genus);
3479 html += QLatin1String(
"<span class=\"type\">");
3482 addLink(linkForNode(n, relative), arg, &html);
3486 addLink(linkForNode(n, relative), arg, &html);
3487 html += QLatin1String(
"</span>");
3488 }
else if (parseArg(src, conceptTag, &i, srcSize, &arg, &par1)) {
3492 const QString target = par1.isEmpty() ? arg.toString() : par1.toString();
3493 par1 = QStringView();
3494 const Node *n = m_qdb->findConceptNode(target);
3496 addLink(linkForNode(n, relative), arg, &html);
3499 }
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
3500 par1 = QStringView();
3501 if (arg.startsWith(QLatin1Char(
'&')))
3504 const Node *n = m_qdb->findNodeForInclude(QStringList(arg.toString()));
3505 if (n && n != relative)
3506 addLink(linkForNode(n, relative), arg, &html);
3510 }
else if (parseArg(src, extrefTag, &i, srcSize, &arg, &par1)) {
3511 QString url = extrefUrls.value(par1.toString());
3513 addLink(url, arg, &html);
3521 html += src.at(i++);
3530 html.reserve(src.size());
3533 QLatin1StringView tag;
3534 QLatin1StringView span;
3536 static constexpr SpanTag spanTags[] = {
3537 {
"comment>"_L1,
"<span class=\"comment\">"_L1},
3538 {
"preprocessor>"_L1,
"<span class=\"preprocessor\">"_L1},
3539 {
"string>"_L1,
"<span class=\"string\">"_L1},
3540 {
"char>"_L1,
"<span class=\"char\">"_L1},
3541 {
"number>"_L1,
"<span class=\"number\">"_L1},
3542 {
"op>"_L1,
"<span class=\"operator\">"_L1},
3543 {
"type>"_L1,
"<span class=\"type\">"_L1},
3544 {
"name>"_L1,
"<span class=\"name\">"_L1},
3545 {
"keyword>"_L1,
"<span class=\"keyword\">"_L1},
3546 {
"template-block>"_L1,
"<span class=\"template-block\">"_L1},
3550 const qsizetype n = src.size();
3551 const QStringView sv(src);
3553 if (sv.at(i) ==
'<'_L1) {
3554 if (i + 1 < n && sv.at(i + 1) ==
'@'_L1) {
3556 bool handled =
false;
3557 for (
const auto &st : spanTags) {
3558 if (i + st.tag.size() <= n
3559 && st.tag == sv.sliced(i, st.tag.size())) {
3568 while (i < n && sv.at(i) !=
'>'_L1)
3574 }
else if (i + 2 < n && sv.at(i + 1) ==
'/'_L1 && sv.at(i + 2) ==
'@'_L1) {
3576 bool handled =
false;
3577 for (
const auto &st : spanTags) {
3578 if (i + st.tag.size() <= n
3579 && st.tag == sv.sliced(i, st.tag.size())) {
3580 html +=
"</span>"_L1;
3588 while (i < n && sv.at(i) !=
'>'_L1)
3606 if (m_linkNode && m_linkNode->isFunction()) {
3608 if (match.hasMatch()) {
3610 qsizetype leftParenLoc = match.capturedStart(1);
3611 out() << protectEnc(atom->string().left(leftParenLoc));
3613 out() << protectEnc(atom->string().mid(leftParenLoc));
3617 out() << protectEnc(atom->string());
3622 return protect(string);
3627 if (string.isEmpty())
3631 if (html.isEmpty()) {
3638 qsizetype n = string.size();
3640 for (
int i = 0; i < n; ++i) {
3641 QChar ch = string.at(i);
3643 if (ch == QLatin1Char(
'&')) {
3645 }
else if (ch == QLatin1Char(
'<')) {
3647 }
else if (ch == QLatin1Char(
'>')) {
3649 }
else if (ch == QChar(8211)) {
3651 }
else if (ch == QChar(8212)) {
3653 }
else if (ch == QLatin1Char(
'"')) {
3656 if (!html.isEmpty())
3661 if (!html.isEmpty())
3670 QString result = Generator::fileBase(node);
3672 result += QLatin1String(
"-obsolete");
3679 return node->name();
3680 return Generator::fileName(node);
3684 const Node *actualNode)
3686 if (actualNode ==
nullptr)
3687 actualNode = apparentNode;
3688 bool link = !linkForNode(actualNode, relative).isEmpty();
3690 out() <<
"<a href=\"" << linkForNode(actualNode, relative);
3692 out() <<
"\" class=\"obsolete";
3695 out() << protectEnc(apparentNode->fullName(relative));
3701
3702
3703
3710 const auto srcLink = Config::instance().getSourceLink();
3711 if (!srcLink.enabled)
3716 if (loc
.isEmpty() || srcLink.baseUrl.isEmpty() || srcLink.rootPath.isEmpty())
3719 QString srcUrl{srcLink.baseUrl};
3720 if (!srcUrl.contains(
'\1'_L1)) {
3721 if (!srcUrl.endsWith(
'/'_L1))
3726 QDir rootDir{srcLink.rootPath};
3727 srcUrl.replace(
'\1'_L1, rootDir.relativeFilePath(loc.filePath()));
3728 srcUrl.replace(
'\2'_L1, QString::number(loc.lineNo()));
3729 const auto &description{
"View declaration of this %1"_L1.arg(node->nodeTypeString())};
3730 out() <<
"<a class=\"srclink\" href=\"%1\" title=\"%2\">%3</a>"_L1
3731 .arg(srcUrl, description, srcLink.linkText);
3738 const QString base = refForNode(node);
3740 for (
int n = 2; m_emittedMemberRefs.contains(ref); ++n)
3741 ref = base +
'-'_L1 + QString::number(n);
3742 m_emittedMemberRefs.insert(ref);
3750 generateExtractionMark(node, MemberMark);
3753 const QList<Node *> &collective = scn->collective();
3754 if (collective.size() > 1)
3755 out() <<
"<div class=\"fngroup\">\n";
3756 QSet<
const Node *> emitted;
3757 for (
const auto *sharedNode : collective) {
3758 if (emitted.contains(sharedNode))
3760 emitted.insert(sharedNode);
3761 out() << headingStart.arg(getClassAttr(sharedNode,
"fn fngroupitem"_L1),
3762 memberHeadingRef(sharedNode));
3763 generateSynopsis(sharedNode, relative, marker, Section::Details);
3764 generateSourceLink(sharedNode);
3765 out() << headingEnd;
3767 if (collective.size() > 1)
3771 if (node->isEnumType(Genus::CPP) && (etn =
static_cast<
const EnumNode *>(node))->flagsType()) {
3772 out() << headingStart.arg(getClassAttr(node,
"flags"_L1), memberHeadingRef(node));
3776 generateSourceLink(node);
3777 out() << headingEnd;
3779 out() << headingStart.arg(getClassAttr(node,
"fn"_L1), memberHeadingRef(node));
3781 generateSourceLink(node);
3782 out() << headingEnd;
3789 const auto *func =
static_cast<
const FunctionNode *>(node);
3790 if (func->hasOverloads() && (func->isSignal() || func->isSlot()))
3799 const auto property =
static_cast<
const PropertyNode *>(node);
3809 out() <<
"<p><b>Access functions:</b></p>\n";
3810 generateSectionList(section, node, marker);
3817 out() <<
"<p><b>Notifier signal:</b></p>\n";
3818 generateSectionList(notifiers, node, marker);
3822 const auto *enumTypeNode =
static_cast<
const EnumNode *>(node);
3823 if (enumTypeNode->flagsType()) {
3824 out() <<
"<p>The " << protectEnc(enumTypeNode->flagsType()->name())
3825 <<
" type is a typedef for "
3826 <<
"<a href=\"" << m_qflagsHref <<
"\">QFlags</a><"
3827 << protectEnc(enumTypeNode->name()) <<
">. It stores an OR combination of "
3828 << protectEnc(enumTypeNode->name()) <<
" values.</p>\n";
3831 generateAlsoList(node, marker);
3832 generateExtractionMark(node, EndMark);
3836
3837
3838
3839
3844 m_linkNode =
nullptr;
3846 if (!m_link.isEmpty())
3847 out() <<
"<a href=\"" << m_link <<
"\" translate=\"no\">";
3855 if (m_link.isEmpty())
3858 const QString &translate_attr =
3859 (node && isApiGenus(node->genus())) ?
" translate=\"no\""_L1 :
""_L1;
3861 if (node ==
nullptr || (relative !=
nullptr && node->status() == relative->status()))
3862 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3863 else if (node->isDeprecated())
3864 out() <<
"<a href=\"" << m_link <<
"\" class=\"obsolete\"%1>"_L1.arg(translate_attr);
3866 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3875 m_linkNode =
nullptr;
3877 if (!m_link.isEmpty())
3882
3883
3884
3888 if (!members.isEmpty()) {
3890 for (
const auto &member : members) {
3891 out() <<
"<li class=\"fn\" translate=\"no\">";
3892 generateQmlItem(member, relative, marker,
true);
3893 if (member->isPropertyGroup()) {
3894 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
3895 if (scn->count() > 0) {
3897 const QList<Node *> &sharedNodes = scn->collective();
3898 for (
const auto &node : sharedNodes) {
3899 if (node->isQmlProperty()) {
3900 out() <<
"<li class=\"fn\" translate=\"no\">";
3901 generateQmlItem(node, relative, marker,
true);
3915
3916
3919 out() << headingStart.arg(getClassAttr(scn,
"fn qml-member qml-property-group"_L1),
3921 <<
"<b>" << scn->name() <<
" group</b>"
3926
3927
3928
3932 generateExtractionMark(node, MemberMark);
3934 auto generateQmlProperty = [&](
Node *n,
bool isGroupItem =
false) {
3935 const auto cssClasses = isGroupItem ?
"fn qml-member qml-property fngroupitem"_L1 :
"fn qml-member qml-property"_L1;
3936 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3937 generateQmlItem(n, relative, marker,
false);
3938 generateSourceLink(n);
3939 out() << headingEnd;
3942 auto generateQmlMethod = [&](
Node *n,
bool isGroupItem =
false) {
3943 const auto cssClasses = isGroupItem ?
"fn qml-member qml-method fngroupitem"_L1 :
"fn qml-member qml-method"_L1;
3944 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3946 generateSourceLink(n);
3947 out() << headingEnd;
3951 auto *scn =
static_cast<
const SharedCommentNode *>(node);
3952 const auto shared = scn->collective();
3954 if (scn->isPropertyGroup() && !scn->name().isEmpty())
3955 emitGroupHeader(scn);
3957 const bool isGroup = shared.size() > 1;
3960 out() <<
"<div class=\"fngroup\">\n"_L1;
3962 for (
auto *child : std::as_const(shared)) {
3963 if (child->isQmlProperty())
3964 generateQmlProperty(child, isGroup);
3966 generateQmlMethod(child, isGroup);
3970 out() <<
"</div>"_L1;
3973 generateQmlProperty(node);
3975 generateQmlMethod(node);
3982 generateAlsoList(node, marker);
3983 generateExtractionMark(node, EndMark);
3986void HtmlGenerator::generateExtractionMark(
const Node *node, ExtractionMarkType markType)
3988 if (markType != EndMark) {
3989 out() <<
"<!-- $$$" + node->name();
3990 if (markType == MemberMark) {
3992 const auto *func =
static_cast<
const FunctionNode *>(node);
3993 if (!func->hasAssociatedProperties()) {
3994 if (func->overloadNumber() == 0)
3995 out() <<
"[overload1]";
3996 out() <<
"$$$" + func->name() + func->parameters().rawSignature().remove(
' ');
4000 const auto *prop =
static_cast<
const PropertyNode *>(node);
4001 const NodeList &list = prop->functions();
4002 for (
const auto *propFuncNode : list) {
4003 if (propFuncNode->isFunction()) {
4004 const auto *func =
static_cast<
const FunctionNode *>(propFuncNode);
4005 out() <<
"$$$" + func->name()
4006 + func->parameters().rawSignature().remove(
' ');
4010 const auto *enumNode =
static_cast<
const EnumNode *>(node);
4011 const auto &items = enumNode->items();
4012 for (
const auto &item : items)
4013 out() <<
"$$$" + item.name();
4015 }
else if (markType == BriefMark) {
4017 }
else if (markType == DetailedDescriptionMark) {
4018 out() <<
"-description";
4022 out() <<
"<!-- @@@" + node->name() +
" -->\n";
#define ATOM_FORMATTING_TELETYPE
#define ATOM_LIST_LOWERALPHA
#define ATOM_FORMATTING_UNDERLINE
#define ATOM_LIST_UPPERALPHA
#define ATOM_FORMATTING_NOTRANSLATE
#define ATOM_LIST_LOWERROMAN
#define ATOM_FORMATTING_SPAN
#define ATOM_FORMATTING_SUBSCRIPT
#define ATOM_FORMATTING_BOLD
#define ATOM_FORMATTING_TRADEMARK
#define ATOM_FORMATTING_ITALIC
#define ATOM_LIST_UPPERROMAN
#define ATOM_FORMATTING_LINK
#define ATOM_FORMATTING_SUPERSCRIPT
#define ATOM_FORMATTING_INDEX
#define ATOM_FORMATTING_UICONTROL
#define ATOM_FORMATTING_PARAMETER
The Atom class is the fundamental unit for representing documents internally.
AtomType type() const
Return the type of this atom.
AtomType
\value AnnotatedList \value AutoLink \value BaseName \value BriefLeft \value BriefRight \value C \val...
const Atom * next() const
Return the next atom in the atom list.
const Atom * next(AtomType t) const
Return the next Atom in the list if it is of AtomType t.
The ClassNode represents a C++ class.
virtual Atom::AtomType atomType() const
A class for holding the members of a collection of doc pages.
const NodeList & members() const
bool wasSeen() const override
Returns the seen flag data member of this node if it is a NamespaceNode or a CollectionNode.
NodeMap getMembers(NodeType type) const
const Location & location() const
Returns the starting location of a qdoc comment.
bool hasTableOfContents() const
static void quoteFromFile(const Location &location, Quoter "er, ResolvedFile resolved_file, CodeMarker *marker=nullptr)
Text briefText(bool inclusive=false) const
QStringMultiMap * metaTagMap() const
const TypedefNode * flagsType() const
Encapsulate the logic that QDoc uses to find files whose path is provided by the user and that are re...
This node is used to represent any kind of function being documented.
bool generateComparisonCategory(const Node *node, CodeMarker *marker=nullptr)
static void setQmlTypeContext(QmlTypeNode *t)
void generateStatus(const Node *node, CodeMarker *marker)
void generateThreadSafeness(const Node *node, CodeMarker *marker)
Generates text that explains how threadsafe and/or reentrant node is.
static bool useOutputSubdirs()
static bool noLinkErrors()
void generateNoexceptNote(const Node *node, CodeMarker *marker)
void unknownAtom(const Atom *atom)
virtual void terminateGenerator()
static bool matchAhead(const Atom *atom, Atom::AtomType expectedAtomType)
virtual void generateDocs()
Traverses the database recursively to generate all the documentation.
static bool appendTrademark(const Atom *atom)
Returns true if a trademark symbol should be appended to the output as determined by atom.
static bool s_redirectDocumentationToDevNull
virtual void generateBody(const Node *node, CodeMarker *marker)
Generate the body of the documentation from the qdoc comment found with the entity represented by the...
void generateSince(const Node *node, CodeMarker *marker)
void endSubPage()
Flush the text stream associated with the subpage, and then pop it off the text stream stack and dele...
static bool autolinkErrors()
bool generateComparisonTable(const Node *node)
Generates a table of comparison categories for node, combining both self-comparison (from \compares) ...
virtual void initializeGenerator()
No-op base implementation.
QString fileExtension() const override
Returns "html" for this subclass of Generator.
void generateProxyPage(Aggregate *aggregate, CodeMarker *marker) override
void generatePageNode(PageNode *pn, CodeMarker *marker) override
Generate the HTML page for an entity that doesn't map to any underlying parsable C++ or QML element.
void generateCppReferencePage(Aggregate *aggregate, CodeMarker *marker) override
Generate a reference page for the C++ class, namespace, or header file documented in node using the c...
void generateDocs() override
If qdoc is in the {-prepare} phase, traverse the primary tree to generate the index file for the curr...
void generateCollectionNode(CollectionNode *cn, CodeMarker *marker) override
Generate the HTML page for a group, module, or QML module.
~HtmlGenerator() override
Destroys the HTML output generator.
HtmlGenerator(FileResolver &file_resolver)
void generateExampleFilePage(const PageNode *en, ResolvedFile resolved_file, CodeMarker *marker) override
Generate an html file with the contents of a C++ or QML source file.
QString fileBase(const Node *node) const override
void generateGenericCollectionPage(CollectionNode *cn, CodeMarker *marker) override
Generate the HTML page for a generic collection.
void generateQmlTypePage(QmlTypeNode *qcn, CodeMarker *marker) override
Generate the HTML page for a QML type.
void initializeGenerator() override
Initializes the HTML output generator's data structures from the configuration (Config) singleton.
QString format() const override
Returns the format identifier for this producer (e.g., "HTML", "DocBook", "template").
void terminateGenerator() override
Gracefully terminates the HTML output generator.
virtual bool generatesHelpProject() const
Returns true if this generator writes a Qt help project (.qhp) file.
qsizetype generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker) override
Generate html from an instance of Atom.
static bool isIncluded(const InclusionPolicy &policy, const NodeContext &context)
The Location class provides a way to mark a location in a file.
bool isEmpty() const
Returns true if there is no file name set yet; returns false otherwise.
The ManifestWriter is responsible for writing manifest files.
void generateManifestFiles()
This function outputs one or more manifest files in XML.
This class represents a C++ namespace.
NamespaceNode * docNode() const
Returns a pointer to the NamespaceNode that represents where the namespace documentation is actually ...
Tree * tree() const override
Returns a pointer to the Tree that contains this NamespaceNode.
bool isDocumentedHere() const
Returns true if this namespace is to be documented in the current module.
A PageNode is a Node that generates a documentation page.
bool noAutoList() const
Returns the value of the no auto-list flag.
This class describes one instance of using the Q_PROPERTY macro.
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
Status
Specifies the status of the QQmlIncubator.
ClassNode * classNode() const override
If this is a QmlTypeNode, this function returns the pointer to the C++ ClassNode that this QML type r...
bool isUncreatable() const
static void subclasses(const Node *base, NodeList &subs, bool recurse=false)
Loads the list subs with the nodes of all the subclasses of base.
QString logicalModuleVersion() const override
If the QML type's QML module pointer is set, return the QML module version from the QML module node.
QString logicalModuleName() const override
If the QML type's QML module pointer is set, return the QML module name from the QML module node.
QmlTypeNode * qmlBaseNode() const override
If this Aggregate is a QmlTypeNode, this function returns a pointer to the QmlTypeNode that is its ba...
CollectionNode * logicalModule() const override
If this is a QmlTypeNode, a pointer to its QML module is returned, which is a pointer to a Collection...
A class for containing the elements of one documentation section.
const NodeVector & obsoleteMembers() const
void appendMembers(const NodeVector &nv)
const Aggregate * aggregate() const
const ClassNodesList & classNodesList() const
const NodeVector & members() const
A class for creating vectors of collections for documentation.
const Aggregate * aggregate() const
SectionVector & summarySections()
SectionVector & sinceSections()
Sections(const Aggregate *aggregate)
This constructor builds the section vectors based on the type of the aggregate node.
Sections(const NodeMultiMap &nsmap)
This constructor builds the since sections from the since node map, nsmap.
bool hasObsoleteMembers(SectionPtrVector *summary_spv, SectionPtrVector *details_spv) const
Returns true if any sections in this object contain obsolete members.
SectionVector & detailsSections()
const Section & allMembersSection() const
Table of contents writer.
void generateTOC(const QString &fileName, const QString &indexTitle)
Writes the TOC entries for project to fileName, starting from a page with a title matching indexTitle...
This class handles the generation of the QDoc tag files.
void generateTagFile(const QString &fileName, Generator *generator)
Writes a tag file named fileName.
const QString & camelCaseModuleName() const
static void rewritePropertyBrief(const Atom *atom, const Node *relative)
Rewrites the brief of this node depending on its first word.
static int hOffset(const Node *node)
Header offset depending on the type of the node.
static bool hasBrief(const Node *node)
Do not display.
XmlGenerator(FileResolver &file_resolver)
static const QRegularExpression m_funcLeftParen
static NodeType typeFromString(const Atom *atom)
Returns the type of this atom as an enumeration.
#define COMMAND_INQMLMODULE
#define CONFIG_USEALTTEXTASTITLE
#define CONFIG_CPPCLASSESTITLE
#define CONFIG_CODEPREFIX
#define CONFIG_QMLTYPESPAGE
#define CONFIG_HEADERSCRIPTS
#define CONFIG_DESCRIPTION
#define CONFIG_CODEINDENT
#define CONFIG_TRADEMARKSPAGE
#define CONFIG_CPPCLASSESPAGE
#define CONFIG_NATURALLANGUAGE
#define CONFIG_PRODUCTNAME
#define CONFIG_NAVIGATION
#define CONFIG_BUILDVERSION
#define CONFIG_LANDINGPAGE
#define CONFIG_CODESUFFIX
#define CONFIG_LANDINGTITLE
#define CONFIG_HEADERSTYLES
#define CONFIG_QMLTYPESTITLE
static QString getClassAttr(const Node *node, const QString &classSet)
Extends the class HTML attribute generated for node.
static void appendTemplateParametersAtoms(Text &out, const TemplateDeclarationStorage &storage)
static const Atom closeCodeTag
static void addLink(const QString &linkTarget, QStringView nestedStuff, QString *res)
static const auto headingStart
static void appendTemplateParameterAtoms(Text &out, const RelaxedTemplateParameter ¶m)
static const auto headingEnd
static const Atom openCodeTag
static void appendTemplateDeclAtoms(Text &out, const RelaxedTemplateDeclaration &templateDecl)
#define HTMLGENERATOR_PROLOGUE
#define HTMLGENERATOR_NONAVIGATIONBAR
#define HTMLGENERATOR_TOCDEPTH
#define HTMLGENERATOR_NAVIGATIONSEPARATOR
#define HTMLGENERATOR_POSTPOSTHEADER
#define HTMLGENERATOR_ADDRESS
#define HTMLGENERATOR_FOOTER
#define HTMLGENERATOR_POSTHEADER
Pure string helpers with no dependencies on QDoc driver types.
This namespace holds QDoc-internal utility methods.
QList< Node * > NodeVector
QMap< QString, Node * > NodeMap
QMap< QString, NodeMap > NodeMapMap
QMap< QString, CollectionNode * > CNMap
QT_BEGIN_NAMESPACE typedef QMultiMap< Text, const Node * > TextToNodeMap
QList< const Section * > SectionPtrVector
QList< Section > SectionVector
QList< ClassNodes > ClassNodesList
The Node class is the base class for all the nodes in QDoc's parse tree.
bool isExternalPage() const
Returns true if the node type is ExternalPage.
const Doc & doc() const
Returns a reference to the node's Doc data member.
virtual bool hasClasses() const
Returns true if this is a CollectionNode and its members list contains class nodes.
virtual bool hasNamespaces() const
Returns true if this is a CollectionNode and its members list contains namespace nodes.
bool isEnumType(Genus g) const
bool isGroup() const
Returns true if the node type is Group.
SharedCommentNode * sharedCommentNode()
bool isNamespace() const
Returns true if the node type is Namespace.
bool isQmlBasicType() const
Returns true if the node type is QmlBasicType.
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
bool isSharedCommentNode() const
Returns true if the node type is SharedComment.
virtual bool isInternal() const
Returns true if the node's status is Internal, or if its parent is a class with Internal status.
bool isHeader() const
Returns true if the node type is HeaderFile.
Genus genus() const override
Returns this node's Genus.
virtual bool isPageNode() const
Returns true if this node represents something that generates a documentation page.
bool isEnumType() const
Returns true if the node type is Enum.
virtual Status status() const
Returns the node's status value.
Aggregate * parent() const
Returns the node's parent pointer, that is, the aggregate under which the node is documented.
virtual bool isDeprecated() const
Returns true if this node's status is Deprecated.
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
static bool nodeNameLessThan(const Node *first, const Node *second)
Returns true if the node n1 is less than node n2.
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.
bool isProxyNode() const
Returns true if the node type is Proxy.
const std::optional< RelaxedTemplateDeclaration > & templateDecl() const
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
bool isProperty() const
Returns true if the node type is Property.
const Location & declLocation() const
Returns the Location where this node's declaration was seen.
NodeContext createContext() const
bool isModule() const
Returns true if the node type is Module.
bool isSharingComment() const
This function returns true if the node is sharing a comment with other nodes.
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
static bool nodeSortKeyOrNameLessThan(const Node *n1, const Node *n2)
Returns true if node n1 is less than node n2 when comparing the sort keys, defined with.
bool isQmlModule() const
Returns true if the node type is QmlModule.
bool isExample() const
Returns true if the node type is Example.
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
ValuedDeclaration valued_declaration
@ NonTypeTemplateParameter
@ TemplateTemplateParameter
Represents a file that is reachable by QDoc based on its current configuration.