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>
42using namespace Qt::StringLiterals;
49static const auto headingStart =
"<h3 class=\"%1\" translate=\"no\" id=\"%2\">"_L1;
54static void addLink(
const QString &linkTarget, QStringView nestedStuff, QString *res)
56 if (!linkTarget.isEmpty()) {
57 *res += QLatin1String(
"<a href=\"");
59 *res += QLatin1String(
"\" translate=\"no\">");
61 *res += QLatin1String(
"</a>");
81 if (param.template_declaration) {
82 appendTemplateParametersAtoms(out, *param.template_declaration);
88 if (param.concept_name) {
89 const QString fq = QString::fromStdString(*param.concept_name);
99 case RelaxedTemplateParameter::Kind::NonTypeTemplateParameter:
100 if (!decl.type.empty())
101 out << Atom(Atom::AutoLink, QString::fromStdString(decl.type));
103 case RelaxedTemplateParameter::Kind::TemplateTemplateParameter:
104 out <<
"typename"_L1;
108 if (param.is_parameter_pack)
111 if (!decl.name.empty())
112 out <<
" "_L1 << QString::fromStdString(decl.name);
117 out <<
"template <"_L1;
120 for (
const auto ¶m : storage.parameters) {
121 if (param.sfinae_constraint)
126 appendTemplateParameterAtoms(out, param);
141 appendTemplateParametersAtoms(out, templateDecl);
143 if (!templateDecl.requires_clause || templateDecl.requires_clause->empty())
146 out <<
" requires "_L1;
147 const QString text = QString::fromStdString(*templateDecl.requires_clause);
149 QStringList concepts;
150 concepts.reserve(
int(templateDecl.referenced_concepts.size()));
151 for (
const auto &s : templateDecl.referenced_concepts)
152 concepts.append(QString::fromStdString(s));
154 if (concepts.isEmpty()) {
162 std::sort(concepts.begin(), concepts.end(),
163 [](
const QString &a,
const QString &b) {
return a.size() > b.size(); });
165 struct Match { qsizetype offset; qsizetype length; QString name; };
166 QList<Match> matches;
167 QList<
bool> occupied(text.size(),
false);
169 for (
const QString &concept_name : concepts) {
170 const QString unqualified = concept_name.section(
"::"_L1, -1);
171 QRegularExpression re(
"\\b"_L1 + QRegularExpression::escape(unqualified) +
"\\b"_L1);
172 auto it = re.globalMatch(text);
173 while (it.hasNext()) {
174 const auto m = it.next();
175 const qsizetype start = m.capturedStart();
176 const qsizetype len = m.capturedLength();
178 for (qsizetype i = start; i < start + len; ++i)
179 if (occupied[i]) { clear =
false;
break; }
182 for (qsizetype i = start; i < start + len; ++i)
184 matches.append({start, len, unqualified});
188 std::sort(matches.begin(), matches.end(),
189 [](
const Match &a,
const Match &b) {
return a.offset < b.offset; });
192 for (
const auto &m : matches) {
194 out << text.mid(pos, m.offset - pos);
195 out << Atom(Atom::AutoLink, m.name);
196 pos = m.offset + m.length;
198 if (pos < text.size())
199 out << text.mid(pos);
203
204
205
206
209 auto result{classSet};
210 if (node->isInternal())
211 result +=
" internal"_L1;
216
217
218
221 if (!s_inUnorderedList) {
223 s_inUnorderedList =
true;
228
229
230
233 if (s_inUnorderedList) {
235 s_inUnorderedList =
false;
240
241
242
245 if (m_helpProjectWriter) {
246 delete m_helpProjectWriter;
247 m_helpProjectWriter =
nullptr;
250 if (m_manifestWriter) {
251 delete m_manifestWriter;
252 m_manifestWriter =
nullptr;
257
258
259
279 {
nullptr,
nullptr,
nullptr } };
282 config = &Config::instance();
285
286
287
288 for (
int i = 0; defaults[i].key; ++i) {
289 formattingLeftMap().insert(QLatin1String(defaults[i].key), QLatin1String(defaults[i].left));
290 formattingRightMap().insert(QLatin1String(defaults[i].key),
291 QLatin1String(defaults[i].right));
294 QString formatDot{HtmlGenerator::format() + Config::dot};
295 m_endHeader = config->get(formatDot +
CONFIG_ENDHEADER).asString(
"</head>\n<body>\n"_L1);
309 .asString(m_project +
" Reference Documentation"_L1);
311 m_projectUrl = config->get(
CONFIG_URL).asString();
320
321
322
323 if (m_helpProjectWriter)
324 m_helpProjectWriter->reset(m_project.toLower() +
".qhp",
this);
326 m_helpProjectWriter =
new HelpProjectWriter(m_project.toLower() +
".qhp",
this);
328 if (!m_manifestWriter)
341 .asString(m_homepage);
348 .asString(m_landingpage);
355 .asString(
"C++ Classes"_L1);
362 .asString(
"QML Types"_L1);
371
372
384
385
386
387
388
389
390
396 Node *qflags = m_qdb->findClassNode(QStringList(
"QFlags"_L1));
398 m_qflagsHref = linkForNode(qflags,
nullptr);
402 const QString fileBase =
"%1/%2"_L1.arg(
404 m_project.toLower().simplified().replace(
' '_L1,
'-'_L1)
411 const QString &rootTitle = m_landingpage.isEmpty() ? m_homepage : m_landingpage;
412 tocWriter
.generateTOC(
"%1_toc.xml"_L1.arg(fileBase), rootTitle);
414
415
416 if (!tagFile_.isEmpty()) {
424
425
428 SubTitleSize subTitleSize = LargeSubTitle;
429 QString fullTitle = en->fullTitle();
431 beginSubPage(en, linkForExampleFile(resolved_file.get_query()));
432 generateHeader(fullTitle, en, marker, u"auto-generated"_s);
433 generateTitle(en
->doc().title(),
Text() << en->subtitle(), subTitleSize, en, marker);
438 QString code = quoter.quoteTo(en->location(), QString(), QString());
439 CodeMarker *codeMarker = CodeMarker::markerForFileName(resolved_file.get_path());
443 generateText(text, en, codeMarker);
448
449
452 qsizetype idx, skipAhead = 0;
453 static bool in_para =
false;
454 Genus genus = Genus::DontCare;
458 QString name = atom->string();
459 if (relative && relative->name() == name.replace(QLatin1String(
"()"), QLatin1String())) {
460 out() << protectEnc(atom->string());
468 if (!m_inLink && !m_inContents && !m_inSectionHeading) {
469 const Node *node =
nullptr;
470 QString link = getAutoLink(atom, relative, &node, genus);
471 if (link.isEmpty()) {
476 QStringLiteral(
"Can't autolink to '%1'").arg(atom->string()));
481 if (link.isEmpty()) {
482 out() << protectEnc(atom->string());
484 beginLink(link, node, relative);
489 out() << protectEnc(atom->string());
496 skipAhead = skipAtoms(atom, Atom::BriefRight);
511 out() << protectEnc(plainCode(atom->string()));
515 out() <<
"<p class=\"figCaption\">";
526 out() <<
"<pre class=\"qml\" translate=\"no\"><code class=\"qml\">"
527 << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative,
529 m_codePrefix, m_codeSuffix)
530 <<
"</code></pre>\n";
534 if (atom->strings().count() == 2)
535 out() <<
"<pre class=\"" << atom->string(1) <<
"\" translate=\"no\"><code class=\"" << atom->string(1) <<
"\">";
537 out() <<
"<pre class=\"cpp\" translate=\"no\"><code class=\"cpp\">";
539 out() << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative),
540 m_codePrefix, m_codeSuffix)
541 <<
"</code></pre>\n";
544 out() <<
"<pre class=\"cpp plain\" translate=\"no\"><code class=\"text\">"
545 << trimmedTrailing(protectEnc(plainCode(indent(m_codeIndent, atom->string()))),
546 m_codePrefix, m_codeSuffix)
547 <<
"</code></pre>\n";
550 out() <<
"<details>\n";
552 out() <<
"<summary>...</summary>\n";
555 out() <<
"<summary>";
558 out() <<
"</summary>\n";
561 out() <<
"</details>\n";
565 if (!atom->string().isEmpty())
566 out() <<
' ' << atom->string();
589 if (atom->string().startsWith(
"span "))
590 out() <<
'<' + atom->string() <<
'>';
592 out() << formattingLeftMap()[atom->string()];
600 const Node *node{
nullptr};
601 const Atom tm_link(Atom::NavLink, m_trademarkspage);
602 if (
const auto &link = getLink(&tm_link, relative, &node);
603 !link.isEmpty() && node != relative)
604 out() <<
"<a href=\"%1\">%2</a>"_L1.arg(link, formattingRightMap()[atom->string()]);
606 out() << formattingRightMap()[atom->string()];
609 }
else if (atom->string().startsWith(
"span ")) {
612 out() << formattingRightMap()[atom->string()];
616 if (
const auto *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group); cn)
617 generateList(cn, marker, atom->string(), Generator::sortOrder(atom->strings().last()));
620 const auto sortOrder{Generator::sortOrder(atom->strings().last())};
621 if (atom->string() == QLatin1String(
"annotatedclasses")) {
622 generateAnnotatedList(relative, marker, m_qdb->getCppClasses().values(), sortOrder);
623 }
else if (atom->string() == QLatin1String(
"annotatedexamples")) {
624 generateAnnotatedLists(relative, marker, m_qdb->getExamples());
625 }
else if (atom->string() == QLatin1String(
"annotatedattributions")) {
626 generateAnnotatedLists(relative, marker, m_qdb->getAttributions());
627 }
else if (atom->string() == QLatin1String(
"classes")) {
628 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true,
630 }
else if (atom->string().contains(
"classes ")) {
631 QString rootName = atom->string().mid(atom->string().indexOf(
"classes") + 7).trimmed();
632 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true, rootName);
633 }
else if (atom->string() == QLatin1String(
"qmlvaluetypes")
634 || atom->string() == QLatin1String(
"qmlbasictypes")) {
635 generateCompactList(Generic, relative, m_qdb->getQmlValueTypes(),
true,
637 }
else if (atom->string() == QLatin1String(
"qmltypes")) {
638 generateCompactList(Generic, relative, m_qdb->getQmlTypes(),
true, QStringLiteral(
""));
639 }
else if ((idx = atom->string().indexOf(QStringLiteral(
"bymodule"))) != -1) {
641 QString moduleName = atom->string().mid(idx + 8).trimmed();
643 if (
const auto *cn = qdb->getCollectionNode(moduleName, moduleType)) {
645 switch (moduleType) {
649 generateAnnotatedList(relative, marker, map.values(), sortOrder);
652 if (atom->string().contains(QLatin1String(
"qmlvaluetypes")))
656 generateAnnotatedList(relative, marker, map.values(), sortOrder);
659 generateAnnotatedList(relative, marker, cn->members(), sortOrder);
663 }
else if (atom->string() == QLatin1String(
"classhierarchy")) {
664 generateClassHierarchy(relative, m_qdb->getCppClasses());
665 }
else if (atom->string() == QLatin1String(
"obsoleteclasses")) {
666 generateCompactList(Generic, relative, m_qdb->getObsoleteClasses(),
false,
667 QStringLiteral(
"Q"));
668 }
else if (atom->string() == QLatin1String(
"obsoleteqmltypes")) {
669 generateCompactList(Generic, relative, m_qdb->getObsoleteQmlTypes(),
false,
671 }
else if (atom->string() == QLatin1String(
"obsoletecppmembers")) {
672 generateCompactList(Obsolete, relative, m_qdb->getClassesWithObsoleteMembers(),
false,
673 QStringLiteral(
"Q"));
674 }
else if (atom->string() == QLatin1String(
"obsoleteqmlmembers")) {
675 generateCompactList(Obsolete, relative, m_qdb->getQmlTypesWithObsoleteMembers(),
false,
677 }
else if (atom->string() == QLatin1String(
"functionindex")) {
678 generateFunctionIndex(relative);
679 }
else if (atom->string() == QLatin1String(
"attributions")) {
680 generateAnnotatedList(relative, marker, m_qdb->getAttributions().values(), sortOrder);
681 }
else if (atom->string() == QLatin1String(
"legalese")) {
682 generateLegaleseList(relative, marker);
683 }
else if (atom->string() == QLatin1String(
"overviews")) {
684 generateList(relative, marker,
"overviews", sortOrder);
685 }
else if (atom->string() == QLatin1String(
"cpp-modules")) {
686 generateList(relative, marker,
"cpp-modules", sortOrder);
687 }
else if (atom->string() == QLatin1String(
"qml-modules")) {
688 generateList(relative, marker,
"qml-modules", sortOrder);
689 }
else if (atom->string() == QLatin1String(
"namespaces")) {
690 generateAnnotatedList(relative, marker, m_qdb->getNamespaces().values(), sortOrder);
691 }
else if (atom->string() == QLatin1String(
"related")) {
692 generateList(relative, marker,
"related", sortOrder);
694 const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group);
696 if (!generateGroupList(
const_cast<CollectionNode *>(cn), sortOrder))
698 QString(
"'\\generatelist %1' group is empty").arg(atom->string()));
701 QString(
"'\\generatelist %1' no such group").arg(atom->string()));
706 const NodeMultiMap &nsmap = m_qdb->getSinceMap(atom->string());
710 const NodeMultiMap &ncmap = m_qdb->getClassMap(atom->string());
711 const NodeMultiMap &nqcmap = m_qdb->getQmlTypeMap(atom->string());
716 for (
const auto §ion : sinceSections) {
717 if (!section.members().isEmpty()) {
719 <<
"<a href=\"#" << TextUtils::asAsciiPrintable(section.title()) <<
"\">"
720 << section.title() <<
"</a></li>\n";
726 for (
const auto §ion : sinceSections) {
727 if (!section.members().isEmpty()) {
728 out() <<
"<h3 id=\"" << TextUtils::asAsciiPrintable(section.title()) <<
"\">"
729 << protectEnc(section.title()) <<
"</h3>\n";
730 if (index == Sections::SinceClasses)
731 generateCompactList(Generic, relative, ncmap,
false, QStringLiteral(
"Q"));
732 else if (index == Sections::SinceQmlTypes)
733 generateCompactList(Generic, relative, nqcmap,
false, QStringLiteral(
""));
734 else if (index == Sections::SinceMemberFunctions
735 || index == Sections::SinceQmlMethods
736 || index == Sections::SinceQmlProperties) {
738 QMap<QString, NodeMultiMap> parentmaps;
740 const QList<Node *> &members = section.members();
741 for (
const auto &member : members) {
742 QString parent_full_name = (*member).parent()->fullName();
744 auto parent_entry = parentmaps.find(parent_full_name);
745 if (parent_entry == parentmaps.end())
746 parent_entry = parentmaps.insert(parent_full_name, NodeMultiMap());
747 parent_entry->insert(member->name(), member);
750 for (
auto map = parentmaps.begin(); map != parentmaps.end(); ++map) {
751 NodeVector nv = map->values().toVector();
752 auto parent = nv.front()->parent();
754 out() << ((index == Sections::SinceMemberFunctions) ?
"<p>Class " :
"<p>QML Type ");
756 out() <<
"<a href=\"" << linkForNode(parent, relative) <<
"\" translate=\"no\">";
757 QStringList pieces = parent->fullName().split(
"::");
758 out() << protectEnc(pieces.last());
762 generateSection(nv, relative, marker);
765 }
else if (index == Sections::SinceEnumValues) {
766 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
767 const auto map_it = m_qdb->newEnumValueMaps().constFind(atom->string());
768 for (
auto it = map_it->cbegin(); it != map_it->cend(); ++it) {
769 out() <<
"<tr><td class=\"memItemLeft\"> enum value </td><td class=\"memItemRight\">"
770 <<
"<b><a href=\"" << linkForNode(it.value(),
nullptr) <<
"\">"
771 << it.key() <<
"</a></b></td></tr>\n";
773 out() <<
"</table></div>\n";
775 generateSection(section.members(), relative, marker);
793 out() <<
"<p class=\"centerAlign\">";
795 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
796 if (!maybe_resolved_file) {
799 QStringLiteral(
"Missing image: %1").arg(protectEnc(atom->string())));
800 out() <<
"<font color=\"red\">[Missing image " << protectEnc(atom->string())
804 QString file_name{QFileInfo{file.get_path()}.fileName()};
824 "%1/%2"_L1.arg(outputDir(), imagesOutputDir()));
826 const auto &imgPath =
"%1/%2"_L1.arg(imagesOutputDir(), file_name);
828 out() <<
"<img src=\"%1\""_L1.arg(protectEnc(imgPath));
830 const QString altAndTitleText = protectEnc(text);
831 out() <<
" alt=\"" << altAndTitleText;
833 out() <<
"\" title=\"" << altAndTitleText;
837 m_helpProjectWriter->addExtraFile(imgPath);
838 setImageFileName(relative, imgPath);
850 QString admonType = atom->typeString();
853 out() <<
"<div class=\"admonition " << admonType.toLower() <<
"\">\n"
856 out() << admonType <<
": ";
866 out() <<
"<div class=\"LegaleseLeft\">";
880 const Node *node =
nullptr;
881 QString link = getLink(atom, relative, &node);
883 Location location = atom->isLinkAtom() ?
static_cast<
const LinkAtom*>(atom)->location
884 : relative->doc().location();
886 QStringLiteral(
"Can't link to '%1'").arg(atom->string()));
888 beginLink(link, node, relative);
892 QString link = linkForExampleFile(atom->string());
897 QString link = atom->string();
898 link =
"images/used-in-examples/" + link;
903 const Node *node =
static_cast<
const Node*>(
Utilities::nodeForString(atom->string()));
904 beginLink(linkForNode(node, relative), node, relative);
917 out() << R"(<div class="table"><table class="valuelist">)";
918 m_threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom);
919 if (m_threeColumnEnumValueTable) {
920 if (++m_numTableRows % 2 == 1)
921 out() << R"(<tr valign="top" class="odd">)";
923 out() << R"(<tr valign="top" class="even">)";
925 out() <<
"<th class=\"tblConst\">Constant</th>";
929 out() <<
"<th class=\"tblval\">Value</th>";
931 out() <<
"<th class=\"tbldscr\">Description</th></tr>\n";
933 out() <<
"<tr><th class=\"tblConst\">Constant</th><th "
934 "class=\"tblVal\">Value</th></tr>\n";
951 out() << QString(R"(<ol class="%1" type="%1" start="%2">)")
952 .arg(olType, atom
->next()->string());
954 out() << QString(R"(<ol class="%1" type="%1">)").arg(olType);
963 std::pair<QString,
int> pair = getAtomListValue(atom);
964 skipAhead = pair.second;
965 QString t = protectEnc(plainCode(marker->markedUpEnumValue(pair.first, relative)));
966 out() <<
"<tr><td class=\"topAlign\"><code translate=\"no\">" << t <<
"</code>";
969 out() <<
"</td><td class=\"topAlign tblval\">";
970 const auto *enume =
static_cast<
const EnumNode *>(relative);
971 QString itemValue = enume->itemValue(atom->next()->string());
972 if (itemValue.isEmpty())
975 out() <<
"<code translate=\"no\">" << protectEnc(itemValue) <<
"</code>";
988 if (m_threeColumnEnumValueTable) {
989 out() <<
"</td><td class=\"topAlign\">";
996 if (matchAhead(atom, Atom::ParaLeft))
1003 out() <<
"</td></tr>\n";
1014 out() <<
"</table></div>\n";
1035 out() <<
"<blockquote>";
1038 out() <<
"</blockquote>\n";
1041 out() << atom->string();
1047 int unit = atom->string().toInt() +
hOffset(relative
);
1048 out() <<
"<h" + QString::number(unit) + QLatin1Char(
' ') <<
"id=\""
1049 << Tree::refForAtom(atom) <<
"\">";
1050 m_inSectionHeading =
true;
1053 case Atom::SectionHeadingRight:
1054 out() <<
"</h" + QString::number(atom->string().toInt() + hOffset(relative)) +
">\n";
1055 m_inSectionHeading =
false;
1062 if (m_inLink && !m_inContents && !m_inSectionHeading) {
1065 out() << protectEnc(atom->string());
1069 std::pair<QString, QString> pair = getTableWidthAttr(atom);
1070 QString attr = pair.second;
1071 QString width = pair.first;
1078 out() << R"(<div class="table"><table class=")" << attr <<
'"';
1079 if (!width.isEmpty())
1080 out() <<
" style=\"width: " << width <<
'"';
1085 out() <<
"</table></div>\n";
1088 out() <<
"<thead><tr class=\"qt-style\">";
1089 m_inTableHeader =
true;
1095 out() <<
"\n<tr class=\"qt-style\">";
1097 out() <<
"</thead>\n";
1098 m_inTableHeader =
false;
1102 if (!atom->string().isEmpty())
1103 out() <<
"<tr " << atom->string() <<
'>';
1104 else if (++m_numTableRows % 2 == 1)
1105 out() << R"(<tr valign="top" class="odd">)";
1107 out() << R"(<tr valign="top" class="even">)";
1113 if (m_inTableHeader)
1118 for (
int i = 0; i < atom->count(); ++i) {
1121 const QString &p = atom->string(i);
1122 if (p.contains(
'=')) {
1125 QStringList spans = p.split(QLatin1Char(
','));
1126 if (spans.size() == 2) {
1127 if (spans.at(0) !=
"1")
1128 out() <<
" colspan=\"" << spans.at(0) <<
'"';
1129 if (spans.at(1) !=
"1")
1130 out() <<
" rowspan=\"" << spans.at(1) <<
'"';
1135 if (matchAhead(atom, Atom::ParaLeft))
1139 if (m_inTableHeader)
1144 if (matchAhead(atom, Atom::ParaLeft))
1154 out() <<
"<span id=\"" <<
TextUtils::asAsciiPrintable(atom->string()) <<
"\"></span>";
1157 out() <<
"<b class=\"redFont\"><Missing HTML></b>";
1159 case Atom::UnknownCommand:
1160 out() << R"(<b class="redFont"><code translate=\"no\">\)" << protectEnc(atom->string()) <<
"</code></b>";
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1208 auto link_for_group = [
this](
const CollectionNode *group) -> QString {
1209 QString target{linkForNode(group,
nullptr)};
1210 return (target.isEmpty()) ? protectEnc(group->name()) :
"<a href=\"" + target +
"\">" + protectEnc(group->fullTitle()) +
"</a>";
1215 const QStringList &groups_names{node->groupNames()};
1216 if (groups_names.isEmpty())
1219 std::vector<CollectionNode *> groups_nodes(groups_names.size(),
nullptr);
1220 std::transform(groups_names.cbegin(), groups_names.cend(), groups_nodes.begin(),
1223 m_qdb->mergeCollections(group);
1224 return (group && group
->wasSeen()) ? group :
nullptr;
1226 groups_nodes.erase(
std::remove(groups_nodes.begin(), groups_nodes.end(),
nullptr), groups_nodes.end());
1228 if (!groups_nodes.empty()) {
1229 text += node->name() +
" is part of ";
1231 for (std::vector<CollectionNode *>::size_type index{0}; index < groups_nodes.size(); ++index) {
1232 text += link_for_group(groups_nodes[index]) + TextUtils::separator(index, groups_nodes.size());
1239
1240
1241
1242
1253 QString typeWord = aggregate->typeWord(
true);
1256 fullTitle = aggregate->plainFullName();
1257 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1258 ns =
static_cast<NamespaceNode *>(aggregate);
1260 fullTitle = aggregate->plainFullName();
1261 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1263 title = fullTitle = aggregate->fullTitle();
1264 if (!aggregate->doc().title().isEmpty())
1265 titleText << aggregate->name() <<
" - "_L1 << aggregate->doc().title();
1270 if (aggregate
->parent()->isInAPI() || templateDecl) {
1272 appendTemplateDeclAtoms(subtitleText, *templateDecl);
1273 subtitleText <<
" "_L1;
1275 subtitleText << aggregate->typeWord(
false) <<
" "_L1;
1276 auto ancestors = fullTitle.split(
"::"_L1);
1277 ancestors.pop_back();
1278 for (
const auto &a : ancestors)
1279 subtitleText << Atom(Atom::AutoLink, a) <<
"::"_L1;
1280 subtitleText << aggregate->plainName();
1283 generateHeader(title, aggregate, marker);
1284 generateTableOfContents(aggregate, marker, &summarySections);
1286 generateTitle(titleText, subtitleText, SmallSubTitle, aggregate, marker);
1288 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1292 brief <<
"The " << ns->name() <<
" namespace includes the following elements from module "
1295 addNodeLink(brief, fullNamespace,
" here.");
1297 generateText(brief, ns, marker);
1300 generateBrief(aggregate, marker);
1302 const auto parentIsClass = aggregate
->parent()->isClassNode();
1305 generateRequisites(aggregate, marker);
1310 QString membersLink = generateAllMembersFile(sections.allMembersSection(), marker);
1311 if (!membersLink.isEmpty()) {
1312 openUnorderedList();
1313 out() <<
"<li><a href=\"" << membersLink <<
"\">"
1314 <<
"List of all members, including inherited members</a></li>\n";
1316 QString obsoleteLink = generateObsoleteMembersFile(sections, marker);
1317 if (!obsoleteLink.isEmpty()) {
1318 openUnorderedList();
1319 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1320 <<
"Deprecated members</a></li>\n";
1323 if (QString groups_text{groupReferenceText(aggregate)}; !groups_text.isEmpty()) {
1324 openUnorderedList();
1326 out() <<
"<li>" << groups_text <<
"</li>\n";
1329 closeUnorderedList();
1334 bool needOtherSection =
false;
1336 for (
const auto §ion : summarySections) {
1337 if (section.members().isEmpty() && section.reimplementedMembers().isEmpty()) {
1338 if (!section.inheritedMembers().isEmpty())
1339 needOtherSection =
true;
1341 if (!section.members().isEmpty()) {
1342 QString ref = registerRef(section.title().toLower());
1343 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1344 generateSection(section.members(), aggregate, marker);
1346 if (!section.reimplementedMembers().isEmpty()) {
1347 QString name = QString(
"Reimplemented ") + section.title();
1348 QString ref = registerRef(name.toLower());
1349 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(name) <<
"</h2>\n";
1350 generateSection(section.reimplementedMembers(), aggregate, marker);
1353 if (!section.inheritedMembers().isEmpty()) {
1355 generateSectionInheritedList(section, aggregate);
1361 if (needOtherSection) {
1362 out() <<
"<h3>Additional Inherited Members</h3>\n"
1365 for (
const auto §ion : summarySections) {
1366 if (section.members().isEmpty() && !section.inheritedMembers().isEmpty())
1367 generateSectionInheritedList(section, aggregate);
1372 if (aggregate
->doc().isEmpty()) {
1373 QString command =
"documentation";
1375 command = R"('\class' comment)";
1378 QStringLiteral(
"No %1 for '%2'").arg(command, aggregate->plainSignature()));
1381 generateExtractionMark(aggregate, DetailedDescriptionMark);
1382 out() <<
"<div class=\"descr\">\n"
1383 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1384 <<
"Detailed Description"
1387 out() <<
"</div>\n";
1388 generateAlsoList(aggregate, marker);
1389 generateExtractionMark(aggregate, EndMark);
1392 for (
const auto §ion : detailsSections) {
1393 bool headerGenerated =
false;
1394 if (section.isEmpty())
1397 const QList<Node *> &members = section.members();
1398 for (
const auto &member : members) {
1399 if (!headerGenerated) {
1400 if (!section.divClass().isEmpty())
1401 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1402 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1403 headerGenerated =
true;
1405 if (!member->isClassNode())
1406 generateDetailedMember(member, aggregate, marker);
1409 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1410 out() <<
" class=\"%1\""_L1.arg(attrs);
1411 out() <<
"> class ";
1412 generateFullName(member, aggregate);
1414 generateBrief(member, marker, aggregate);
1417 if (headerGenerated && !section.divClass().isEmpty())
1418 out() <<
"</div>\n";
1420 generateFooter(aggregate);
1433 QString rawTitle = aggregate->plainName();
1434 QString fullTitle = aggregate->plainFullName();
1435 QString title = rawTitle +
" Proxy Page";
1436 generateHeader(title, aggregate, marker, u"auto-generated"_s);
1437 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1438 generateBrief(aggregate, marker);
1439 for (
const auto §ion : summarySections) {
1440 if (!section.members().isEmpty()) {
1441 QString ref = registerRef(section.title().toLower());
1442 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1443 generateSection(section.members(), aggregate, marker);
1447 if (!aggregate
->doc().isEmpty()) {
1448 generateExtractionMark(aggregate, DetailedDescriptionMark);
1449 out() <<
"<div class=\"descr\">\n"
1450 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1451 <<
"Detailed Description"
1454 out() <<
"</div>\n";
1455 generateAlsoList(aggregate, marker);
1456 generateExtractionMark(aggregate, EndMark);
1459 for (
const auto §ion : detailsSections) {
1460 if (section.isEmpty())
1463 if (!section.divClass().isEmpty())
1464 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1465 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1467 const QList<Node *> &members = section.members();
1468 for (
const auto &member : members) {
1469 if (!member->isClassNode()) {
1470 generateDetailedMember(member, aggregate, marker);
1473 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1474 out() <<
" class=\"%1\""_L1.arg(attrs);
1475 out() <<
"> class ";
1476 generateFullName(member, aggregate);
1478 generateBrief(member, marker, aggregate);
1481 if (!section.divClass().isEmpty())
1482 out() <<
"</div>\n";
1484 generateFooter(aggregate);
1488
1489
1490
1494 SubTitleSize subTitleSize = LargeSubTitle;
1495 QString htmlTitle = qcn->name();
1497 htmlTitle.append(
" QML Value Type");
1499 htmlTitle.append(
" QML Type");
1502 htmlTitle.append(
" (Singleton)"_L1);
1504 htmlTitle.append(
" (Uncreatable)"_L1);
1506 generateHeader(htmlTitle, qcn, marker);
1509 marker = CodeMarker::markerForLanguage(QLatin1String(
"QML"));
1510 generateTitle(htmlTitle,
Text() << qcn->subtitle(), subTitleSize, qcn, marker);
1511 generateBrief(qcn, marker);
1512 generateQmlRequisites(qcn, marker);
1516 out() <<
"<p><strong>Note:</strong> This type is a QML singleton. "_L1
1517 <<
"There is only one instance of this type in the QML engine.</p>\n"_L1;
1519 out() <<
"<p><strong>Note:</strong> This is an uncreatable type. "_L1
1520 <<
"It cannot be instantiated in QML.</p>\n"_L1;
1523 QString allQmlMembersLink;
1526 if (!qcn->isQmlBasicType())
1527 allQmlMembersLink = generateAllQmlMembersFile(sections, marker);
1528 QString obsoleteLink = generateObsoleteQmlMembersFile(sections, marker);
1529 if (!allQmlMembersLink.isEmpty() || !obsoleteLink.isEmpty()) {
1530 openUnorderedList();
1532 if (!allQmlMembersLink.isEmpty()) {
1533 out() <<
"<li><a href=\"" << allQmlMembersLink <<
"\">"
1534 <<
"List of all members, including inherited members</a></li>\n";
1536 if (!obsoleteLink.isEmpty()) {
1537 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1538 <<
"Deprecated members</a></li>\n";
1542 if (QString groups_text{groupReferenceText(qcn)}; !groups_text.isEmpty()) {
1543 openUnorderedList();
1545 out() <<
"<li>" << groups_text <<
"</li>\n";
1548 closeUnorderedList();
1551 for (
const auto §ion : qmlSummarySections) {
1552 if (!section.isEmpty()) {
1553 QString ref = registerRef(section.title().toLower());
1554 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1555 generateQmlSummary(section.members(), qcn, marker);
1559 generateExtractionMark(qcn, DetailedDescriptionMark);
1560 out() <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1561 <<
"Detailed Description"
1564 generateAlsoList(qcn, marker);
1565 generateExtractionMark(qcn, EndMark);
1568 for (
const auto §ion : qmlDetailsSections) {
1569 if (section.isEmpty())
1571 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1572 const QList<Node *> &members = section.members();
1573 for (
const auto member : members)
1574 generateDetailedQmlMember(member, qcn, marker);
1576 generateFooter(qcn);
1581
1582
1583
1586 generateHeader(pn->fullTitle(), pn, marker);
1588
1589
1590
1591 if ((pn->name() != QLatin1String(
"index.html")))
1592 generateTableOfContents(pn, marker,
nullptr);
1594 generateTitle(pn
->doc().title(),
Text() << pn->subtitle(), LargeSubTitle, pn, marker);
1596 generateBrief(pn, marker,
nullptr,
false);
1599 generateExtractionMark(pn, DetailedDescriptionMark);
1600 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1604 out() <<
"</div>\n";
1605 generateAlsoList(pn, marker);
1606 generateExtractionMark(pn, EndMark);
1612
1613
1616 SubTitleSize subTitleSize = LargeSubTitle;
1619 generateHeader(cn->fullTitle(), cn, marker);
1620 generateTableOfContents(cn, marker,
nullptr);
1621 generateTitle(cn
->doc().title(),
Text() << cn->subtitle(), subTitleSize, cn, marker);
1624 if (cn
->genus() != Genus::DOC && cn
->genus() != Genus::DontCare) {
1626 generateBrief(cn, marker);
1634 if (!nmm.isEmpty()) {
1635 ref = registerRef(
"namespaces");
1636 out() <<
"<h2 id=\"" << ref <<
"\">Namespaces</h2>\n";
1637 generateAnnotatedList(cn, marker, nmm.values());
1640 if (!nmm.isEmpty()) {
1641 ref = registerRef(
"classes");
1642 out() <<
"<h2 id=\"" << ref <<
"\">Classes</h2>\n";
1643 generateAnnotatedList(cn, marker, nmm.values());
1649 generateExtractionMark(cn, DetailedDescriptionMark);
1650 ref = registerRef(
"details");
1651 out() <<
"<div class=\"descr\">\n";
1652 out() <<
"<h2 id=\"" << ref <<
"\">"
1653 <<
"Detailed Description"
1656 generateExtractionMark(cn, DetailedDescriptionMark);
1657 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1662 out() <<
"</div>\n";
1663 generateAlsoList(cn, marker);
1664 generateExtractionMark(cn, EndMark);
1669 if (!users.isEmpty()) {
1670 ref = registerRef(
"users");
1671 out() <<
"<h2 id=\"" << ref <<
"\">Used by</h2>\n";
1672 generateAnnotatedList(cn, marker, users);
1675 generateAnnotatedList(cn, marker, cn->members());
1682
1683
1684
1685
1688 SubTitleSize subTitleSize = LargeSubTitle;
1689 QString fullTitle = cn->name();
1691 generateHeader(fullTitle, cn, marker, u"auto-generated"_s);
1692 generateTitle(fullTitle,
Text() << cn->subtitle(), subTitleSize, cn, marker);
1695 brief <<
"Each function or type documented here is related to a class or "
1696 <<
"namespace that is documented in a different module. The reference "
1697 <<
"page for that class or namespace will link to the function or type "
1700 generateText(brief, cn, marker);
1704 for (
const auto &member : members)
1705 generateDetailedMember(member, cn, marker);
1711
1712
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740void HtmlGenerator::generateNavigationBar(
const QString &title,
const Node *node,
1741 CodeMarker *marker,
const QString &buildversion,
1744 if (m_noNavigationBar || node ==
nullptr)
1755 auto addNavItem = [&](
const QString &link,
const QString &title) {
1756 navigationbar << Atom(itemLeft) << Atom(
Atom::NavLink, link)
1763 auto addNavItemNode = [&](
const Node *node,
const QString &title) {
1764 navigationbar << Atom(itemLeft);
1765 addNodeLink(navigationbar, node, title);
1766 navigationbar << Atom(itemRight);
1770 const auto *moduleNode = m_qdb->getModuleNode(node);
1771 QString moduleState;
1772 if (moduleNode && !moduleNode->state().isEmpty())
1773 moduleState = QStringLiteral(
" (%1)").arg(moduleNode->state());
1775 if (m_hometitle == title)
1777 if (!m_homepage.isEmpty())
1778 addNavItem(m_homepage, m_hometitle);
1779 if (!m_landingpage.isEmpty() && m_landingtitle != title)
1780 addNavItem(m_landingpage, m_landingtitle);
1783 if (!m_cppclassespage.isEmpty() && !m_cppclassestitle.isEmpty())
1784 addNavItem(m_cppclassespage, m_cppclassestitle);
1785 if (!node->physicalModuleName().isEmpty()) {
1789 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_cppclassespage))
1790 addNavItemNode(moduleNode, moduleNode->name() + moduleState);
1792 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1794 if (!m_qmltypespage.isEmpty() && !m_qmltypestitle.isEmpty())
1795 addNavItem(m_qmltypespage, m_qmltypestitle);
1799 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_qmltypespage)) {
1800 addNavItemNode(moduleNode, moduleNode->name() + moduleState);
1802 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1805 auto currentNode{
static_cast<
const PageNode*>(node)};
1806 std::deque<
const Node *> navNodes;
1808 qsizetype navItems = 0;
1809 while (currentNode->navigationParent() && ++navItems < 16) {
1810 if (
std::find(navNodes.cbegin(), navNodes.cend(),
1811 currentNode->navigationParent()) == navNodes.cend())
1812 navNodes.push_front(currentNode->navigationParent());
1813 currentNode = currentNode->navigationParent();
1817 if (navNodes.empty()) {
1818 const QStringList groups =
static_cast<
const PageNode *>(node)->groupNames();
1819 for (
const auto &groupName : groups) {
1820 const auto *groupNode = m_qdb->findNodeByNameAndType(QStringList{groupName}, &Node::isGroup);
1821 if (groupNode && !groupNode->title().isEmpty()) {
1822 navNodes.push_front(groupNode);
1827 while (!navNodes.empty()) {
1828 if (navNodes.front()->isPageNode())
1829 addNavItemNode(navNodes.front(), navNodes.front()->title());
1830 navNodes.pop_front();
1834 navigationbar << Atom(itemLeft) << Atom(
Atom::String, title) << Atom(itemRight);
1838 generateText(navigationbar, node, marker);
1840 if (buildversion.isEmpty())
1846 out() <<
"</tr></table><table class=\"buildversion\"><tr>\n"
1847 << R"(<td id="buildversion" width="100%" align="right">)";
1849 out() <<
"<li id=\"buildversion\">";
1853 if (!m_landingpage.isEmpty() && m_landingtitle != title) {
1854 navigationbar << Atom(Atom::NavLink, m_landingpage)
1856 << Atom(Atom::String, buildversion)
1858 generateText(navigationbar, node, marker);
1860 out() << buildversion;
1869 const QString &metaKeyword)
1871 out() <<
"<!DOCTYPE html>\n";
1872 out() << QString(
"<html lang=\"%1\">\n").arg(naturalLanguage);
1873 out() <<
"<head>\n";
1874 out() <<
" <meta charset=\"utf-8\">\n";
1879 out() <<
" <meta name=\"description\" content=\""
1880 << protectEnc(node->doc().briefText().toString())
1884 if (!metaKeyword.isEmpty()) {
1886 out() <<
" <meta name=\"keywords\" content=\"%1\">\n"_L1.arg(protectEnc(metaKeyword));
1889 QStringList keywords;
1891 for (
const auto &kw : metaTags->values(u"keywords"_s))
1892 keywords << kw.split(
','_L1, Qt::SkipEmptyParts);
1897 keywords << node->nodeTypeString().toLower().remove(
' '_L1);
1899 if (!keywords.isEmpty()) {
1900 std::transform(keywords.begin(), keywords.end(), keywords.begin(),
1901 [](
const QString &k) {
return k.trimmed(); });
1902 keywords.removeDuplicates();
1903 out() <<
" <meta name=\"keywords\" content=\"" << protectEnc(keywords.join(
','_L1))
1909 QString titleSuffix;
1910 if (!m_landingtitle.isEmpty()) {
1912 titleSuffix = m_landingtitle;
1913 }
else if (!m_hometitle.isEmpty()) {
1916 if (title != m_hometitle)
1917 titleSuffix = m_hometitle;
1920 titleSuffix = m_productName.isEmpty() ? m_project : m_productName;
1922 if (title == titleSuffix)
1923 titleSuffix.clear();
1925 out() <<
" <title>";
1926 if (!titleSuffix.isEmpty() && !title.isEmpty()) {
1927 out() <<
"%1 | %2"_L1.arg(protectEnc(title), titleSuffix);
1929 out() << protectEnc(title);
1934 QVersionNumber projectVersion = QVersionNumber::fromString(m_qdb->version());
1935 if (!projectVersion.isNull()) {
1936 QVersionNumber titleVersion;
1937 static const QRegularExpression re(QLatin1String(R"(\d+\.\d+)"));
1938 const QString &versionedTitle = titleSuffix.isEmpty() ? title : titleSuffix;
1939 auto match = re.match(versionedTitle);
1940 if (match.hasMatch())
1941 titleVersion = QVersionNumber::fromString(match.captured());
1942 if (titleVersion.isNull() || !titleVersion.isPrefixOf(projectVersion)) {
1944 if (!m_productName.isEmpty() && titleSuffix != m_productName)
1945 out() <<
" | %1"_L1.arg(m_productName);
1946 out() <<
" %1"_L1.arg(projectVersion.toString());
1949 out() <<
"</title>\n";
1952 out() << m_headerStyles;
1953 out() << m_headerScripts;
1954 out() << m_endHeader;
1956 out() << QString(m_postHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1957 bool usingTable = m_postHeader.trimmed().endsWith(QLatin1String(
"<tr>"));
1958 generateNavigationBar(title, node, marker, m_buildversion, usingTable);
1959 out() << QString(m_postPostHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1961 m_navigationLinks.clear();
1964 if (node && !node->links().empty()) {
1965 std::pair<QString, QString> linkPair;
1966 std::pair<QString, QString> anchorPair;
1967 const Node *linkNode;
1968 bool useSeparator =
false;
1970 if (node->links().contains(Node::PreviousLink)) {
1971 linkPair = node->links()[Node::PreviousLink];
1972 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1975 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1976 if (linkNode ==
nullptr || linkNode == node)
1977 anchorPair = linkPair;
1979 anchorPair = anchorForNode(linkNode);
1981 out() << R"( <link rel="prev" href=")" << anchorPair.first <<
"\" />\n";
1983 m_navigationLinks += R"(<a class="prevPage" href=")" + anchorPair.first +
"\">";
1984 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
1985 m_navigationLinks += protect(anchorPair.second);
1987 m_navigationLinks += protect(linkPair.second);
1988 m_navigationLinks +=
"</a>\n";
1989 useSeparator = !m_navigationSeparator.isEmpty();
1991 if (node->links().contains(Node::NextLink)) {
1992 linkPair = node->links()[Node::NextLink];
1993 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1996 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1997 if (linkNode ==
nullptr || linkNode == node)
1998 anchorPair = linkPair;
2000 anchorPair = anchorForNode(linkNode);
2002 out() << R"( <link rel="next" href=")" << anchorPair.first <<
"\" />\n";
2005 m_navigationLinks += m_navigationSeparator;
2007 m_navigationLinks += R"(<a class="nextPage" href=")" + anchorPair.first +
"\">";
2008 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
2009 m_navigationLinks += protect(anchorPair.second);
2011 m_navigationLinks += protect(linkPair.second);
2012 m_navigationLinks +=
"</a>\n";
2014 if (node->links().contains(Node::StartLink)) {
2015 linkPair = node->links()[Node::StartLink];
2016 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
2019 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
2020 if (linkNode ==
nullptr || linkNode == node)
2021 anchorPair =
std::move(linkPair);
2023 anchorPair = anchorForNode(linkNode);
2024 out() << R"( <link rel="start" href=")" << anchorPair.first <<
"\" />\n";
2028 if (node && !node->links().empty())
2029 out() <<
"<p class=\"naviNextPrevious headerNavi\">\n" << m_navigationLinks <<
"</p>\n";
2033 SubTitleSize subTitleSize,
const Node *relative,
2036 out() << QString(m_prologue).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
2039 attribute = R"( translate="no")";
2042 out() <<
"<h1 class=\"title\"" << attribute <<
">";
2043 generateText(title, relative, marker);
2048 if (subTitleSize == SmallSubTitle)
2049 out() <<
" class=\"small-subtitle\"" << attribute <<
">";
2051 out() <<
" class=\"subtitle\"" << attribute <<
">";
2052 generateText(subtitle, relative, marker);
2053 out() <<
"</span>\n";
2059 if (node && !node->links().empty())
2060 out() <<
"<p class=\"naviNextPrevious footerNavi\">\n" << m_navigationLinks <<
"</p>\n";
2062 out() << QString(m_footer).replace(
"\\" +
COMMAND_VERSION, m_qdb->version())
2063 << QString(m_address).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
2065 out() <<
"</body>\n";
2066 out() <<
"</html>\n";
2070
2071
2072
2075 QMap<QString, Text> requisites;
2078 const QString headerText =
"Header";
2079 const QString sinceText =
"Since";
2080 const QString inheritedByText =
"Inherited By";
2081 const QString inheritsText =
"Inherits";
2082 const QString nativeTypeText =
"In QML";
2083 const QString qtVariableText =
"qmake";
2084 const QString cmakeText =
"CMake";
2085 const QString statusText =
"Status";
2088 const QStringList requisiteorder { headerText, cmakeText, qtVariableText, sinceText,
2089 nativeTypeText, inheritsText, inheritedByText, statusText };
2091 addIncludeFileToMap(aggregate, requisites, text, headerText);
2092 addSinceToMap(aggregate, requisites, &text, sinceText);
2095 addCMakeInfoToMap(aggregate, requisites, &text, cmakeText);
2096 addQtVariableToMap(aggregate, requisites, &text, qtVariableText);
2100 auto *classe =
dynamic_cast<
ClassNode *>(aggregate);
2102 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2104 if (InclusionFilter::isIncluded(policy, context))
2105 addQmlNativeTypesToMap(requisites, &text, nativeTypeText, classe);
2108 const auto *metaTags = classe ? classe
->doc().metaTagMap() :
nullptr;
2109 if (!metaTags || !metaTags->contains(u"qdoc-suppress-inheritance"_s))
2110 addInheritsToMap(requisites, &text, inheritsText, classe);
2111 addInheritedByToMap(requisites, &text, inheritedByText, classe);
2115 addStatusToMap(aggregate, requisites, text, statusText);
2117 if (!requisites.isEmpty()) {
2119 generateTheTable(requisiteorder, requisites, aggregate, marker);
2124
2125
2126void HtmlGenerator::generateTheTable(
const QStringList &requisiteOrder,
2127 const QMap<QString, Text> &requisites,
2130 out() <<
"<div class=\"table\"><table class=\"alignedsummary requisites\" translate=\"no\">\n";
2132 for (
auto it = requisiteOrder.constBegin(); it != requisiteOrder.constEnd(); ++it) {
2134 if (requisites.contains(*it)) {
2136 <<
"<td class=\"memItemLeft rightAlign topAlign\"> " << *it
2138 "</td><td class=\"memItemRight bottomAlign\"> ";
2140 generateText(requisites.value(*it), aggregate, marker);
2141 out() <<
"</td></tr>\n";
2144 out() <<
"</table></div>\n";
2148
2149
2150
2151void HtmlGenerator::addInheritedByToMap(QMap<QString, Text> &requisites,
Text *text,
2152 const QString &inheritedByText,
ClassNode *classe)
2154 if (!classe->derivedClasses().isEmpty()) {
2157 int count = appendSortedNames(*text, classe, classe->derivedClasses());
2160 requisites.insert(inheritedByText, *text);
2165
2166
2167
2168void HtmlGenerator::addInheritsToMap(QMap<QString, Text> &requisites,
Text *text,
2169 const QString &inheritsText,
ClassNode *classe)
2171 if (!classe->baseClasses().isEmpty()) {
2174 const auto baseClasses = classe->baseClasses();
2175 for (
const auto &cls : baseClasses) {
2177 appendFullName(*text, cls.m_node, classe);
2179 if (cls.m_access == Access::Protected) {
2180 *text <<
" (protected)";
2181 }
else if (cls.m_access == Access::Private) {
2182 *text <<
" (private)";
2184 *text << TextUtils::comma(index++, classe->baseClasses().size());
2189 requisites.insert(inheritsText, *text);
2194
2195
2196
2197void HtmlGenerator::addQmlNativeTypesToMap(QMap<QString, Text> &requisites,
Text *text,
2198 const QString &nativeTypeText,
ClassNode *classe)
const
2205 QList<QmlTypeNode *> nativeTypes { classe->qmlNativeTypes().cbegin(), classe->qmlNativeTypes().cend()};
2207 qsizetype index { 0 };
2209 for (
const auto &item : std::as_const(nativeTypes)) {
2210 addNodeLink(*text, item);
2211 *text << TextUtils::comma(index++, nativeTypes.size());
2213 requisites.insert(nativeTypeText, *text);
2217
2218
2219
2221 Text *text,
const QString &CMakeInfo)
const
2223 if (!aggregate->physicalModuleName().isEmpty() && text !=
nullptr) {
2225 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2227 const auto result = cmakeRequisite(cn);
2240 requisites.insert(CMakeInfo, *text);
2245
2246
2247
2249 Text *text,
const QString &qtVariableText)
const
2251 if (!aggregate->physicalModuleName().isEmpty()) {
2253 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2255 if (cn && !cn->qtVariable().isEmpty()) {
2258 requisites.insert(qtVariableText, *text);
2264
2265
2266
2267
2269 Text *text,
const QString &sinceText)
const
2271 if (!aggregate->since().isEmpty() && text !=
nullptr) {
2274 requisites.insert(sinceText, *text);
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2290 Text &text,
const QString &statusText)
const
2292 auto status{formatStatus(aggregate, m_qdb)};
2298 spanClass = u"deprecated"_s;
2300 spanClass =
TextUtils::asAsciiPrintable(status.value());
2303 text << Atom(Atom::String, status.value())
2305 "class=\"status %1\""_L1.arg(spanClass))
2307 requisites.insert(statusText, text);
2311
2312
2313
2314
2316 QMap<QString, Text> &requisites,
Text& text,
2317 const QString &headerText)
2319 if (aggregate->includeFile()) {
2321 text << openCodeTag <<
"#include <%1>"_L1.arg(*aggregate->includeFile()) << closeCodeTag;
2322 requisites.insert(headerText, text);
2327
2328
2329
2335 QMap<QString, Text> requisites;
2338 const QString importText =
"Import Statement";
2339 const QString sinceText =
"Since";
2340 const QString inheritedByText =
"Inherited By";
2341 const QString inheritsText =
"Inherits";
2342 const QString nativeTypeText =
"In C++";
2343 const QString statusText =
"Status";
2346 QString logicalModuleVersion;
2351 bool generate_import =
true;
2353 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2357 if (generate_import) {
2361 requisites.insert(importText, text);
2364 qcn
->doc().location().warning(QStringLiteral(
"Could not resolve QML import statement for type '%1'").arg(qcn->name()),
2369 if (!qcn->since().isEmpty()) {
2372 requisites.insert(sinceText, text);
2377 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2381 addNodeLink(text, cn);
2382 requisites.insert(nativeTypeText, text);
2390 QStringList knownTypeNames{qcn->name()};
2392 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2400 knownTypeNames << base->name();
2403 addNodeLink(text, base);
2406 for (
const auto sub : std::as_const(subs)) {
2407 if (knownTypeNames.contains(sub->name())) {
2408 text << Atom(Atom::String,
" (%1)"_L1.arg(base->logicalModuleName()));
2413 requisites.insert(inheritsText, text);
2417 if (!subs.isEmpty()) {
2420 int count = appendSortedQmlNames(text, qcn, knownTypeNames, subs);
2423 requisites.insert(inheritedByText, text);
2427 addStatusToMap(qcn, requisites, text, statusText);
2430 const QStringList requisiteorder {
std::move(importText),
std::move(sinceText),
2431 std::move(nativeTypeText),
std::move(inheritsText),
2432 std::move(inheritedByText),
std::move(statusText)};
2434 if (!requisites.isEmpty())
2435 generateTheTable(requisiteorder, requisites, qcn, marker);
2447 QStringLiteral(
"'\\brief' statement does not end with a full stop."));
2449 generateExtractionMark(node, BriefMark);
2451 generateText(brief, node, marker);
2454 if (!relative || node == relative)
2455 out() <<
" <a href=\"#";
2457 out() <<
" <a href=\"" << linkForNode(node, relative) <<
'#';
2458 out() << registerRef(
"details") <<
"\">More...</a>";
2462 generateExtractionMark(node, EndMark);
2467
2468
2469
2475 toc = node
->doc().tableOfContents();
2476 if (tocDepth == 0 || (toc.isEmpty() && !sections && !node
->isModule())) {
2481 int sectionNumber = 1;
2482 int detailsBase = 0;
2485 m_inContents =
true;
2487 out() <<
"<div class=\"sidebar\">\n";
2488 out() <<
"<div class=\"toc\">\n";
2489 out() <<
"<h3 id=\"toc\">Contents</h3>\n";
2492 openUnorderedList();
2493 if (!
static_cast<
const CollectionNode *>(node)->noAutoList()) {
2495 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2496 << registerRef(
"namespaces") <<
"\">Namespaces</a></li>\n";
2499 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2500 << registerRef(
"classes") <<
"\">Classes</a></li>\n";
2503 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#" << registerRef(
"details")
2504 <<
"\">Detailed Description</a></li>\n";
2505 for (
const auto &entry : std::as_const(toc)) {
2506 if (entry->string().toInt() == 1) {
2512 for (
const auto §ion : *sections) {
2513 if (!section.members().isEmpty()) {
2514 openUnorderedList();
2515 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2516 << registerRef(section.plural()) <<
"\">" << section.title() <<
"</a></li>\n";
2518 if (!section.reimplementedMembers().isEmpty()) {
2519 openUnorderedList();
2520 QString ref = QString(
"Reimplemented ") + section.plural();
2521 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2522 << registerRef(ref.toLower()) <<
"\">"
2523 << QString(
"Reimplemented ") + section.title() <<
"</a></li>\n";
2527 openUnorderedList();
2528 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2529 << registerRef(
"details") <<
"\">Detailed Description</a></li>\n";
2531 for (
const auto &entry : toc) {
2532 if (entry->string().toInt() == 1) {
2539 for (
const auto &atom : toc) {
2540 sectionNumber = atom->string().toInt() + detailsBase;
2543 if (sectionNumber <= tocDepth || tocDepth < 0) {
2544 openUnorderedList();
2546 Text headingText = Text::sectionHeading(atom);
2547 out() <<
"<li class=\"level" << sectionNumber <<
"\">";
2548 out() <<
"<a href=\"" <<
'#' << Tree::refForAtom(atom) <<
"\">";
2549 generateAtomList(headingText.firstAtom(), node, marker,
true, numAtoms);
2550 out() <<
"</a></li>\n";
2553 closeUnorderedList();
2554 out() <<
"</div>\n";
2555 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2556 out() <<
"</div>\n";
2557 m_inContents =
false;
2562
2563
2566 out() <<
"<div class=\"sidebar\">";
2567 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2568 out() <<
"</div>\n";
2577 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2578 beginSubPage(aggregate, fileName);
2579 QString title =
"List of All Members for " + aggregate->plainFullName();
2580 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2582 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2583 out() <<
"<p>This is the complete list of members for ";
2584 generateFullName(aggregate,
nullptr);
2585 out() <<
", including inherited members.</p>\n";
2587 generateSectionList(section, aggregate, marker);
2595
2596
2597
2598
2599
2607 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2608 beginSubPage(aggregate, fileName);
2609 QString title =
"List of All Members for " + aggregate->name();
2610 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2612 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2613 out() <<
"<p>This is the complete list of members for ";
2614 generateFullName(aggregate,
nullptr);
2615 out() <<
", including inherited members.</p>\n";
2618 for (
int i = 0; i < cknl.size(); i++) {
2619 const auto &ckn = cknl[i];
2622 if (nodes.isEmpty())
2625 out() <<
"<p>The following members are inherited from ";
2626 generateFullName(qcn,
nullptr);
2629 openUnorderedList();
2630 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2631 for (
int j = 0; j < nodes.size(); j++) {
2632 Node *node = nodes[j];
2639 std::function<
void(
Node *)> generate = [&](Node *n) {
2640 out() <<
"<li class=\"fn\" translate=\"no\">";
2641 generateQmlItem(n, aggregate, marker,
true);
2642 if (n->isQmlProperty()) {
2643 auto qpn =
static_cast<QmlPropertyNode *>(n);
2644 QStringList hints = qpn->hints();
2645 if (qpn->isAttached())
2646 hints <<
"attached"_L1;
2647 if (!hints.isEmpty())
2648 out() <<
" [" << hints.join(
' '_L1) <<
"]";
2649 }
else if (n->isAttached()) {
2651 out() <<
" [attached]";
2654 if (n->isPropertyGroup()) {
2656 const QList<Node *> &collective =
2657 static_cast<SharedCommentNode *>(n)->collective();
2658 std::for_each(collective.begin(), collective.end(), generate);
2665 closeUnorderedList();
2682 QString title =
"Obsolete Members for " + aggregate->plainFullName();
2683 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2685 beginSubPage(aggregate, fileName);
2686 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2688 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2690 out() <<
"<p><b>The following members of class "
2691 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\" translate=\"no\">"
2692 << protectEnc(aggregate->name()) <<
"</a>"
2693 <<
" are deprecated.</b> "
2694 <<
"They are provided to keep old source code working. "
2695 <<
"We strongly advise against using them in new code.</p>\n";
2697 for (
const auto §ion : summary_spv) {
2698 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2699 generateSectionList(*section, aggregate, marker,
true);
2702 for (
const auto §ion : details_spv) {
2703 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2705 const NodeVector &members = section->obsoleteMembers();
2706 for (
const auto &member : members)
2707 generateDetailedMember(member, aggregate, marker);
2716
2717
2718
2719
2728 QString title =
"Obsolete Members for " + aggregate->name();
2729 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2731 beginSubPage(aggregate, fileName);
2732 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2734 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2736 out() <<
"<p><b>The following members of QML type "
2737 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\">"
2738 << protectEnc(aggregate->name()) <<
"</a>"
2739 <<
" are deprecated.</b> "
2740 <<
"They are provided to keep old source code working. "
2741 <<
"We strongly advise against using them in new code.</p>\n";
2743 for (
const auto §ion : summary_spv) {
2744 QString ref = registerRef(section->title().toLower());
2745 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section->title()) <<
"</h2>\n";
2746 generateQmlSummary(section->obsoleteMembers(), aggregate, marker);
2749 for (
const auto §ion : details_spv) {
2750 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2751 const NodeVector &members = section->obsoleteMembers();
2752 for (
const auto &member : members) {
2753 generateDetailedQmlMember(member, aggregate, marker);
2765 if (classMap.isEmpty())
2769 for (
const auto &it : classMap) {
2770 auto *classe =
static_cast<ClassNode *>(it);
2771 if (classe->baseClasses().isEmpty())
2772 topLevel.insert(classe->name(), classe);
2775 QStack<NodeMap> stack;
2776 stack.push(topLevel);
2779 while (!stack.isEmpty()) {
2780 if (stack.top().isEmpty()) {
2786 generateFullName(child, relative);
2788 stack.top().erase(stack.top().begin());
2791 const auto derivedClasses = child->derivedClasses();
2792 for (
const RelatedClass &d : derivedClasses) {
2793 if (d.m_node && d.m_node->isInAPI())
2794 newTop.insert(d.m_node->name(), d.m_node);
2796 if (!newTop.isEmpty()) {
2805
2806
2807
2812 if (relative ==
nullptr)
2815 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2816 for (
auto *node : nodes) {
2817 const NodeContext context = node->createContext();
2818 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
2819 included.insert(node->fullName(relative), node);
2825 const NodeList &unsortedNodes, Qt::SortOrder sortOrder)
2827 generateAnnotatedList(relative, marker, includedAnnotatedMembers(relative, unsortedNodes),
2834 if (nodeMap.isEmpty())
2836 out() <<
"<div class=\"table\"><table class=\"annotated\">\n";
2840 if (sortOrder == Qt::DescendingOrder)
2845 for (
const auto *node : std::as_const(nodes)) {
2847 out() <<
"<tr class=\"odd topAlign\">";
2849 out() <<
"<tr class=\"even topAlign\">";
2850 out() <<
"<td class=\"tblName\" translate=\"no\"><p>";
2851 generateFullName(node, relative);
2852 out() <<
"</p></td>";
2854 if (!node->isTextPageNode()) {
2855 Text brief = node->doc().trimmedBriefText(node->name());
2856 if (!brief.isEmpty()) {
2857 out() <<
"<td class=\"tblDescr\"><p>";
2858 generateText(brief, node, marker);
2859 out() <<
"</p></td>";
2860 }
else if (!node->reconstitutedBrief().isEmpty()) {
2861 out() <<
"<td class=\"tblDescr\"><p>";
2862 out() << node->reconstitutedBrief();
2863 out() <<
"</p></td>";
2866 out() <<
"<td class=\"tblDescr\"><p>";
2867 if (!node->reconstitutedBrief().isEmpty()) {
2868 out() << node->reconstitutedBrief();
2870 out() << protectEnc(node->doc().briefText().toString());
2871 out() <<
"</p></td>";
2875 out() <<
"</table></div>\n";
2879
2880
2881
2885 const auto &uniqueKeys = nmm.uniqueKeys();
2886 for (
const QString &name : uniqueKeys) {
2887 if (!name.isEmpty()) {
2888 out() <<
"<h2 id=\"" << registerRef(name.toLower()) <<
"\">" << protectEnc(name)
2891 generateAnnotatedList(relative, marker, nmm.values(name));
2896
2897
2898
2899
2900
2901
2902
2903
2904
2907 const QString &commonPrefix)
2912 const int NumParagraphs = 37;
2913 qsizetype commonPrefixLen = commonPrefix.size();
2916
2917
2918
2919
2920
2922 QString paragraphName[NumParagraphs + 1];
2923 QSet<
char> usedParagraphNames;
2925 for (
auto c = nmm.constBegin(); c != nmm.constEnd(); ++c) {
2926 QStringList pieces = c.key().split(
"::");
2927 int idx = commonPrefixLen;
2928 if (idx > 0 && !pieces.last().startsWith(commonPrefix, Qt::CaseInsensitive))
2930 QString last = pieces.last().toLower();
2931 QString key = last.mid(idx);
2933 int paragraphNr = NumParagraphs - 1;
2935 if (key[0].digitValue() != -1) {
2936 paragraphNr = key[0].digitValue();
2937 }
else if (key[0] >= QLatin1Char(
'a') && key[0] <= QLatin1Char(
'z')) {
2938 paragraphNr = 10 + key[0].unicode() -
'a';
2941 paragraphName[paragraphNr] = key[0].toUpper();
2942 usedParagraphNames.insert(key[0].toLower().cell());
2943 paragraph[paragraphNr].insert(last, c.value());
2947
2948
2949
2950
2951
2952
2953
2954 qsizetype paragraphOffset[NumParagraphs + 1];
2955 paragraphOffset[0] = 0;
2956 for (
int i = 0; i < NumParagraphs; i++)
2957 paragraphOffset[i + 1] = paragraphOffset[i] + paragraph[i].size();
2960
2961
2962 if (includeAlphabet) {
2963 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
2964 for (
int i = 0; i < 26; i++) {
2966 if (usedParagraphNames.contains(
char(
'a' + i)))
2967 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
2969 out() <<
"</b></p>\n";
2973
2974
2975 out() <<
"<div class=\"flowListDiv\" translate=\"no\">\n";
2979 QHash<QString,
int> nameOccurrences;
2980 for (
const auto &[key, node] : nmm.asKeyValueRange()) {
2981 QStringList pieces{node->fullName(relative).split(
"::"_L1)};
2982 const QString &name{pieces.last()};
2983 nameOccurrences[name]++;
2987 int curParOffset = 0;
2989 for (
int i = 0; i < nmm.size(); i++) {
2990 while ((curParNr < NumParagraphs) && (curParOffset == paragraph[curParNr].size())) {
2996
2997
2998 if (curParOffset == 0) {
3001 if (++m_numTableRows % 2 == 1)
3002 out() <<
"<dl class=\"flowList odd\">";
3004 out() <<
"<dl class=\"flowList even\">";
3005 out() <<
"<dt class=\"alphaChar\"";
3006 if (includeAlphabet)
3007 out() << QString(
" id=\"%1\"").arg(paragraphName[curParNr][0].toLower());
3008 out() <<
"><b>" << paragraphName[curParNr] <<
"</b></dt>\n";
3012
3013
3015 if ((curParNr < NumParagraphs) && !paragraphName[curParNr].isEmpty()) {
3016 NodeMultiMap::Iterator it;
3017 NodeMultiMap::Iterator next;
3018 it = paragraph[curParNr].begin();
3019 for (
int j = 0; j < curParOffset; j++)
3024
3025
3026
3027 out() <<
"<a href=\"" << linkForNode(it.value(), relative) <<
"\">";
3029 QString fileName = fileBase(it.value()) +
"-obsolete." + fileExtension();
3031 if (useOutputSubdirs())
3032 link =
"../%1/"_L1.arg(it.value()->tree()->physicalModuleName());
3034 out() <<
"<a href=\"" << link <<
"\">";
3037 QStringList pieces{it.value()->fullName(relative).split(
"::"_L1)};
3038 const auto &name{pieces.last()};
3041 if (nameOccurrences[name] > 1) {
3042 const QString moduleName = it.value()->isQmlNode() ? it.value()->logicalModuleName()
3043 : it.value()->tree()->camelCaseModuleName();
3044 pieces.last().append(
": %1"_L1.arg(moduleName));
3047 out() << protectEnc(pieces.last());
3049 if (pieces.size() > 1) {
3051 generateFullName(it.value()->parent(), relative);
3061 out() <<
"</div>\n";
3066 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
3067 for (
int i = 0; i < 26; i++) {
3069 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
3071 out() <<
"</b></p>\n";
3073 char nextLetter =
'a';
3075 out() <<
"<ul translate=\"no\">\n";
3076 NodeMapMap &funcIndex = m_qdb->getFunctionIndex();
3077 for (
auto fnMap = funcIndex.constBegin(); fnMap != funcIndex.constEnd(); ++fnMap) {
3078 const QString &key = fnMap.key();
3079 const QChar firstLetter = key.isEmpty() ? QChar(
'A') : key.front();
3080 Q_ASSERT_X(firstLetter.unicode() < 256,
"generateFunctionIndex",
3081 "Only valid C++ identifiers were expected");
3082 const char currentLetter = firstLetter.isLower() ? firstLetter.unicode() : nextLetter - 1;
3084 if (currentLetter < nextLetter) {
3088 while (nextLetter < currentLetter)
3089 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
3090 Q_ASSERT(nextLetter == currentLetter);
3091 out() << QStringLiteral(
"<li id=\"%1\">").arg(nextLetter++);
3093 out() << protectEnc(key) <<
':';
3095 for (
auto it = (*fnMap).constBegin(); it != (*fnMap).constEnd(); ++it) {
3097 generateFullName((*it)->parent(), relative, *it);
3101 while (nextLetter <=
'z')
3102 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
3109 for (
auto it = legaleseTexts.cbegin(), end = legaleseTexts.cend(); it != end; ++it) {
3110 Text text = it.key();
3111 generateText(text, relative, marker);
3115 generateFullName(it.value(), relative);
3118 }
while (it != legaleseTexts.constEnd() && it.key() == text);
3126 QString marked = marker->markedUpQmlItem(node, summary);
3127 marked.replace(
"@param>",
"i>");
3129 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3130 .arg(summary ?
"summary"_L1 :
"details"_L1));
3131 marked.replace(
"</@extra>",
"</code>");
3135 marked.remove(
"<@name>");
3136 marked.remove(
"</@name>");
3137 marked.remove(
"<@type>");
3138 marked.remove(
"</@type>");
3140 out() << highlightedCode(marked, relative,
false, Genus::QML);
3144
3145
3146
3147
3148
3149
3150
3153 m_qdb->mergeCollections(cn);
3158 if (sortOrder == Qt::DescendingOrder)
3163 for (
const auto *node : std::as_const(members)) {
3164 out() <<
"<li translate=\"no\">";
3165 generateFullName(node,
nullptr);
3173 const QString &selector, Qt::SortOrder sortOrder)
3177 if (selector == QLatin1String(
"overviews"))
3179 else if (selector == QLatin1String(
"cpp-modules"))
3181 else if (selector == QLatin1String(
"qml-modules"))
3185 m_qdb->mergeCollections(type, cnm, relative);
3186 const auto collectionList = cnm.values();
3187 nodeList.reserve(collectionList.size());
3188 for (
auto *collectionNode : collectionList)
3189 nodeList.append(collectionNode);
3190 generateAnnotatedList(relative, marker, nodeList, sortOrder);
3193
3194
3195
3196
3199 QStringLiteral(
"\\generatelist {%1} is only allowed in \\group, "
3200 "\\module and \\qmlmodule comments.")
3204 auto *node =
const_cast<
Node *>(relative);
3205 auto *collectionNode =
static_cast<CollectionNode *>(node);
3206 if (!collectionNode)
3208 m_qdb->mergeCollections(collectionNode);
3209 generateAnnotatedList(collectionNode, marker, collectionNode->members(), sortOrder);
3215 bool alignNames =
true;
3216 if (!nv.isEmpty()) {
3217 bool twoColumn =
false;
3218 if (nv.first()->isProperty()) {
3219 twoColumn = (nv.size() >= 5);
3223 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3226 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3227 <<
"<tr><td class=\"topAlign\">";
3232 for (
const auto &member : nv) {
3235 out() <<
"<tr><td class=\"memItemLeft rightAlign topAlign\"> ";
3237 if (twoColumn && i == (nv.size() + 1) / 2)
3238 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3239 out() <<
"<li class=\"fn\" translate=\"no\">";
3242 generateSynopsis(member, relative, marker, Section::Summary, alignNames);
3244 out() <<
"</td></tr>\n";
3250 out() <<
"</table></div>\n";
3254 out() <<
"</td></tr>\n</table></div>\n";
3262 bool alignNames =
true;
3265 if (!members.isEmpty()) {
3266 bool hasPrivateSignals =
false;
3267 bool isInvokable =
false;
3268 bool twoColumn =
false;
3271 twoColumn = (members.size() >= 16);
3272 }
else if (members.first()->isProperty()) {
3273 twoColumn = (members.size() >= 5);
3277 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3280 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3281 <<
"<tr><td class=\"topAlign\">";
3286 for (
const auto &member : members) {
3289 if (member->name().isEmpty())
3293 out() <<
"<tr><td class=\"memItemLeft topAlign rightAlign\"> ";
3295 if (twoColumn && i == (members.size() + 1) / 2)
3296 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3297 out() <<
"<li class=\"fn\" translate=\"no\">";
3300 generateSynopsis(member, relative, marker, section.style(), alignNames);
3301 if (member->isFunction()) {
3302 const auto *fn =
static_cast<
const FunctionNode *>(member);
3303 if (fn->isPrivateSignal()) {
3304 hasPrivateSignals =
true;
3306 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3307 }
else if (fn->isInvokable()) {
3310 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3314 out() <<
"</td></tr>\n";
3320 out() <<
"</table></div>\n";
3324 out() <<
"</td></tr>\n</table></div>\n";
3327 if (hasPrivateSignals)
3335 && !section.inheritedMembers().isEmpty()) {
3337 generateSectionInheritedList(section, relative);
3344 const QList<std::pair<
const Aggregate *,
int>> &inheritedMembers = section.inheritedMembers();
3345 for (
const auto &member : inheritedMembers) {
3346 out() <<
"<li class=\"fn\" translate=\"no\">";
3347 out() << member.second <<
' ';
3348 if (member.second == 1) {
3349 out() << section.singular();
3351 out() << section.plural();
3353 out() <<
" inherited from <a href=\"" << fileName(member.first) <<
'#'
3354 << Generator::cleanRef(section.title().toLower()) <<
"\">"
3355 << protectEnc(member.first->plainFullName(relative)) <<
"</a></li>\n";
3362 QString marked = marker->markedUpSynopsis(node, relative, style);
3363 marked.replace(
"@param>",
"i>");
3366 marked.remove(
"<@name>");
3367 marked.remove(
"</@name>");
3371 static const QRegularExpression extraRegExp(
"<@extra>.*</@extra>",
3372 QRegularExpression::InvertedGreedinessOption);
3373 marked.remove(extraRegExp);
3375 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3376 .arg(style == Section::Summary ?
"summary"_L1 :
"details"_L1));
3377 marked.replace(
"</@extra>",
"</code>");
3381 marked.remove(
"<@type>");
3382 marked.remove(
"</@type>");
3385 out() << highlightedCode(marked, relative, alignNames);
3388QString
HtmlGenerator::highlightedCode(
const QString &markedCode,
const Node *relative,
3389 bool alignNames, Genus genus)
3391 QString src = markedCode;
3393 html.reserve(src.size());
3397 const QChar charLangle =
'<';
3398 const QChar charAt =
'@';
3400 static const QString typeTag(
"type");
3401 static const QString headerTag(
"headerfile");
3402 static const QString funcTag(
"func");
3403 static const QString linkTag(
"link");
3404 static const QString extrefTag(
"extref");
3405 static const QString conceptTag(
"concept");
3408 static const QHash<QString, QString> extrefUrls = {
3409 {
"cpp-explicitly-defaulted"_L1,
3410 "https://en.cppreference.com/w/cpp/language/function#Defaulted_functions"_L1},
3411 {
"cpp-deleted-functions"_L1,
3412 "https://en.cppreference.com/w/cpp/language/function#Deleted_functions"_L1},
3419 for (
int i = 0, srcSize = src.size(); i < srcSize;) {
3420 if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
3421 if (alignNames && !done) {
3422 html += QLatin1String(
"</td><td class=\"memItemRight bottomAlign\">");
3426 if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) {
3427 html += QLatin1String(
"<b>");
3428 const Node *n =
static_cast<
const Node*>(
Utilities::nodeForString(par1.toString()));
3429 QString link = linkForNode(n, relative);
3430 addLink(link, arg, &html);
3431 html += QLatin1String(
"</b>");
3432 }
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
3433 const FunctionNode *fn = m_qdb->findFunctionNode(par1.toString(), relative, genus);
3434 QString link = linkForNode(fn, relative);
3435 addLink(link, arg, &html);
3436 par1 = QStringView();
3437 }
else if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
3438 par1 = QStringView();
3439 const Node *n = m_qdb->findTypeNode(arg.toString(), relative, genus);
3440 html += QLatin1String(
"<span class=\"type\">");
3443 addLink(linkForNode(n, relative), arg, &html);
3447 addLink(linkForNode(n, relative), arg, &html);
3448 html += QLatin1String(
"</span>");
3449 }
else if (parseArg(src, conceptTag, &i, srcSize, &arg, &par1)) {
3453 const QString target = par1.isEmpty() ? arg.toString() : par1.toString();
3454 par1 = QStringView();
3455 const Node *n = m_qdb->findConceptNode(target);
3457 addLink(linkForNode(n, relative), arg, &html);
3460 }
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
3461 par1 = QStringView();
3462 if (arg.startsWith(QLatin1Char(
'&')))
3465 const Node *n = m_qdb->findNodeForInclude(QStringList(arg.toString()));
3466 if (n && n != relative)
3467 addLink(linkForNode(n, relative), arg, &html);
3471 }
else if (parseArg(src, extrefTag, &i, srcSize, &arg, &par1)) {
3472 QString url = extrefUrls.value(par1.toString());
3474 addLink(url, arg, &html);
3482 html += src.at(i++);
3491 html.reserve(src.size());
3494 QLatin1StringView tag;
3495 QLatin1StringView span;
3497 static constexpr SpanTag spanTags[] = {
3498 {
"comment>"_L1,
"<span class=\"comment\">"_L1},
3499 {
"preprocessor>"_L1,
"<span class=\"preprocessor\">"_L1},
3500 {
"string>"_L1,
"<span class=\"string\">"_L1},
3501 {
"char>"_L1,
"<span class=\"char\">"_L1},
3502 {
"number>"_L1,
"<span class=\"number\">"_L1},
3503 {
"op>"_L1,
"<span class=\"operator\">"_L1},
3504 {
"type>"_L1,
"<span class=\"type\">"_L1},
3505 {
"name>"_L1,
"<span class=\"name\">"_L1},
3506 {
"keyword>"_L1,
"<span class=\"keyword\">"_L1},
3507 {
"template-block>"_L1,
"<span class=\"template-block\">"_L1},
3511 const qsizetype n = src.size();
3512 const QStringView sv(src);
3514 if (sv.at(i) ==
'<'_L1) {
3515 if (i + 1 < n && sv.at(i + 1) ==
'@'_L1) {
3517 bool handled =
false;
3518 for (
const auto &st : spanTags) {
3519 if (i + st.tag.size() <= n
3520 && st.tag == sv.sliced(i, st.tag.size())) {
3529 while (i < n && sv.at(i) !=
'>'_L1)
3535 }
else if (i + 2 < n && sv.at(i + 1) ==
'/'_L1 && sv.at(i + 2) ==
'@'_L1) {
3537 bool handled =
false;
3538 for (
const auto &st : spanTags) {
3539 if (i + st.tag.size() <= n
3540 && st.tag == sv.sliced(i, st.tag.size())) {
3541 html +=
"</span>"_L1;
3549 while (i < n && sv.at(i) !=
'>'_L1)
3567 if (m_linkNode && m_linkNode->isFunction()) {
3569 if (match.hasMatch()) {
3571 qsizetype leftParenLoc = match.capturedStart(1);
3572 out() << protectEnc(atom->string().left(leftParenLoc));
3574 out() << protectEnc(atom->string().mid(leftParenLoc));
3578 out() << protectEnc(atom->string());
3583 return protect(string);
3588 if (string.isEmpty())
3592 if (html.isEmpty()) {
3599 qsizetype n = string.size();
3601 for (
int i = 0; i < n; ++i) {
3602 QChar ch = string.at(i);
3604 if (ch == QLatin1Char(
'&')) {
3606 }
else if (ch == QLatin1Char(
'<')) {
3608 }
else if (ch == QLatin1Char(
'>')) {
3610 }
else if (ch == QChar(8211)) {
3612 }
else if (ch == QChar(8212)) {
3614 }
else if (ch == QLatin1Char(
'"')) {
3617 if (!html.isEmpty())
3622 if (!html.isEmpty())
3631 QString result = Generator::fileBase(node);
3633 result += QLatin1String(
"-obsolete");
3640 return node->name();
3641 return Generator::fileName(node);
3645 const Node *actualNode)
3647 if (actualNode ==
nullptr)
3648 actualNode = apparentNode;
3649 bool link = !linkForNode(actualNode, relative).isEmpty();
3651 out() <<
"<a href=\"" << linkForNode(actualNode, relative);
3653 out() <<
"\" class=\"obsolete";
3656 out() << protectEnc(apparentNode->fullName(relative));
3662
3663
3664
3671 const auto srcLink = Config::instance().getSourceLink();
3672 if (!srcLink.enabled)
3677 if (loc
.isEmpty() || srcLink.baseUrl.isEmpty() || srcLink.rootPath.isEmpty())
3680 QString srcUrl{srcLink.baseUrl};
3681 if (!srcUrl.contains(
'\1'_L1)) {
3682 if (!srcUrl.endsWith(
'/'_L1))
3687 QDir rootDir{srcLink.rootPath};
3688 srcUrl.replace(
'\1'_L1, rootDir.relativeFilePath(loc.filePath()));
3689 srcUrl.replace(
'\2'_L1, QString::number(loc.lineNo()));
3690 const auto &description{
"View declaration of this %1"_L1.arg(node->nodeTypeString())};
3691 out() <<
"<a class=\"srclink\" href=\"%1\" title=\"%2\">%3</a>"_L1
3692 .arg(srcUrl, description, srcLink.linkText);
3699 generateExtractionMark(node, MemberMark);
3700 QString nodeRef =
nullptr;
3703 const QList<Node *> &collective = scn->collective();
3704 if (collective.size() > 1)
3705 out() <<
"<div class=\"fngroup\">\n";
3706 for (
const auto *sharedNode : collective) {
3707 out() << headingStart.arg(getClassAttr(sharedNode,
"fn fngroupitem"_L1),
3708 refForNode(sharedNode));
3709 generateSynopsis(sharedNode, relative, marker, Section::Details);
3710 generateSourceLink(sharedNode);
3711 out() << headingEnd;
3713 if (collective.size() > 1)
3717 if (node->isEnumType(Genus::CPP) && (etn =
static_cast<
const EnumNode *>(node))->flagsType()) {
3718 out() << headingStart.arg(getClassAttr(node,
"flags"_L1), refForNode(node));
3722 generateSourceLink(node);
3723 out() << headingEnd;
3725 out() << headingStart.arg(getClassAttr(node,
"fn"_L1), refForNode(node));
3727 generateSourceLink(node);
3728 out() << headingEnd;
3735 const auto *func =
static_cast<
const FunctionNode *>(node);
3736 if (func->hasOverloads() && (func->isSignal() || func->isSlot()))
3745 const auto property =
static_cast<
const PropertyNode *>(node);
3755 out() <<
"<p><b>Access functions:</b></p>\n";
3756 generateSectionList(section, node, marker);
3763 out() <<
"<p><b>Notifier signal:</b></p>\n";
3764 generateSectionList(notifiers, node, marker);
3768 const auto *enumTypeNode =
static_cast<
const EnumNode *>(node);
3769 if (enumTypeNode->flagsType()) {
3770 out() <<
"<p>The " << protectEnc(enumTypeNode->flagsType()->name())
3771 <<
" type is a typedef for "
3772 <<
"<a href=\"" << m_qflagsHref <<
"\">QFlags</a><"
3773 << protectEnc(enumTypeNode->name()) <<
">. It stores an OR combination of "
3774 << protectEnc(enumTypeNode->name()) <<
" values.</p>\n";
3777 generateAlsoList(node, marker);
3778 generateExtractionMark(node, EndMark);
3782
3783
3784
3785
3790 m_linkNode =
nullptr;
3792 if (!m_link.isEmpty())
3793 out() <<
"<a href=\"" << m_link <<
"\" translate=\"no\">";
3801 if (m_link.isEmpty())
3804 const QString &translate_attr =
3805 (node && isApiGenus(node->genus())) ?
" translate=\"no\""_L1 :
""_L1;
3807 if (node ==
nullptr || (relative !=
nullptr && node->status() == relative->status()))
3808 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3809 else if (node->isDeprecated())
3810 out() <<
"<a href=\"" << m_link <<
"\" class=\"obsolete\"%1>"_L1.arg(translate_attr);
3812 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3821 m_linkNode =
nullptr;
3823 if (!m_link.isEmpty())
3828
3829
3830
3834 if (!members.isEmpty()) {
3836 for (
const auto &member : members) {
3837 out() <<
"<li class=\"fn\" translate=\"no\">";
3838 generateQmlItem(member, relative, marker,
true);
3839 if (member->isPropertyGroup()) {
3840 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
3841 if (scn->count() > 0) {
3843 const QList<Node *> &sharedNodes = scn->collective();
3844 for (
const auto &node : sharedNodes) {
3845 if (node->isQmlProperty()) {
3846 out() <<
"<li class=\"fn\" translate=\"no\">";
3847 generateQmlItem(node, relative, marker,
true);
3861
3862
3865 out() << headingStart.arg(getClassAttr(scn,
"fn qml-member qml-property-group"_L1),
3867 <<
"<b>" << scn->name() <<
" group</b>"
3872
3873
3874
3878 generateExtractionMark(node, MemberMark);
3880 auto generateQmlProperty = [&](
Node *n,
bool isGroupItem =
false) {
3881 const auto cssClasses = isGroupItem ?
"fn qml-member qml-property fngroupitem"_L1 :
"fn qml-member qml-property"_L1;
3882 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3883 generateQmlItem(n, relative, marker,
false);
3884 generateSourceLink(n);
3885 out() << headingEnd;
3888 auto generateQmlMethod = [&](
Node *n,
bool isGroupItem =
false) {
3889 const auto cssClasses = isGroupItem ?
"fn qml-member qml-method fngroupitem"_L1 :
"fn qml-member qml-method"_L1;
3890 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3892 generateSourceLink(n);
3893 out() << headingEnd;
3897 auto *scn =
static_cast<
const SharedCommentNode *>(node);
3898 const auto shared = scn->collective();
3900 if (scn->isPropertyGroup() && !scn->name().isEmpty())
3901 emitGroupHeader(scn);
3903 const bool isGroup = shared.size() > 1;
3906 out() <<
"<div class=\"fngroup\">\n"_L1;
3908 for (
auto *child : std::as_const(shared)) {
3909 if (child->isQmlProperty())
3910 generateQmlProperty(child, isGroup);
3912 generateQmlMethod(child, isGroup);
3916 out() <<
"</div>"_L1;
3919 generateQmlProperty(node);
3921 generateQmlMethod(node);
3928 generateAlsoList(node, marker);
3929 generateExtractionMark(node, EndMark);
3932void HtmlGenerator::generateExtractionMark(
const Node *node, ExtractionMarkType markType)
3934 if (markType != EndMark) {
3935 out() <<
"<!-- $$$" + node->name();
3936 if (markType == MemberMark) {
3938 const auto *func =
static_cast<
const FunctionNode *>(node);
3939 if (!func->hasAssociatedProperties()) {
3940 if (func->overloadNumber() == 0)
3941 out() <<
"[overload1]";
3942 out() <<
"$$$" + func->name() + func->parameters().rawSignature().remove(
' ');
3946 const auto *prop =
static_cast<
const PropertyNode *>(node);
3947 const NodeList &list = prop->functions();
3948 for (
const auto *propFuncNode : list) {
3949 if (propFuncNode->isFunction()) {
3950 const auto *func =
static_cast<
const FunctionNode *>(propFuncNode);
3951 out() <<
"$$$" + func->name()
3952 + func->parameters().rawSignature().remove(
' ');
3956 const auto *enumNode =
static_cast<
const EnumNode *>(node);
3957 const auto &items = enumNode->items();
3958 for (
const auto &item : items)
3959 out() <<
"$$$" + item.name();
3961 }
else if (markType == BriefMark) {
3963 }
else if (markType == DetailedDescriptionMark) {
3964 out() <<
"-description";
3968 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 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.
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.
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.
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
Represents a file that is reachable by QDoc based on its current configuration.