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>");
68
69
70
71
74 auto result{classSet};
75 if (node->isInternal())
76 result +=
" internal"_L1;
81
82
83
86 if (!s_inUnorderedList) {
88 s_inUnorderedList =
true;
93
94
95
98 if (s_inUnorderedList) {
100 s_inUnorderedList =
false;
105
106
107
110 if (m_helpProjectWriter) {
111 delete m_helpProjectWriter;
112 m_helpProjectWriter =
nullptr;
115 if (m_manifestWriter) {
116 delete m_manifestWriter;
117 m_manifestWriter =
nullptr;
122
123
124
144 {
nullptr,
nullptr,
nullptr } };
147 config = &Config::instance();
150
151
152
153 for (
int i = 0; defaults[i].key; ++i) {
154 formattingLeftMap().insert(QLatin1String(defaults[i].key), QLatin1String(defaults[i].left));
155 formattingRightMap().insert(QLatin1String(defaults[i].key),
156 QLatin1String(defaults[i].right));
159 QString formatDot{HtmlGenerator::format() + Config::dot};
160 m_endHeader = config->get(formatDot +
CONFIG_ENDHEADER).asString(
"</head>\n<body>\n"_L1);
174 .asString(m_project +
" Reference Documentation"_L1);
176 m_projectUrl = config->get(
CONFIG_URL).asString();
185
186
187
188 if (m_helpProjectWriter)
189 m_helpProjectWriter->reset(m_project.toLower() +
".qhp",
this);
191 m_helpProjectWriter =
new HelpProjectWriter(m_project.toLower() +
".qhp",
this);
193 if (!m_manifestWriter)
206 .asString(m_homepage);
213 .asString(m_landingpage);
220 .asString(
"C++ Classes"_L1);
227 .asString(
"QML Types"_L1);
236
237
249
250
251
252
253
254
255
261 Node *qflags = m_qdb->findClassNode(QStringList(
"QFlags"_L1));
263 m_qflagsHref = linkForNode(qflags,
nullptr);
267 const QString fileBase =
"%1/%2"_L1.arg(
269 m_project.toLower().simplified().replace(
' '_L1,
'-'_L1)
276 const QString &rootTitle = m_landingpage.isEmpty() ? m_homepage : m_landingpage;
277 tocWriter
.generateTOC(
"%1_toc.xml"_L1.arg(fileBase), rootTitle);
279
280
281 if (!tagFile_.isEmpty()) {
289
290
293 SubTitleSize subTitleSize = LargeSubTitle;
294 QString fullTitle = en->fullTitle();
296 beginSubPage(en, linkForExampleFile(resolved_file.get_query()));
297 generateHeader(fullTitle, en, marker, u"auto-generated"_s);
298 generateTitle(en
->doc().title(),
Text() << en->subtitle(), subTitleSize, en, marker);
303 QString code = quoter.quoteTo(en->location(), QString(), QString());
304 CodeMarker *codeMarker = CodeMarker::markerForFileName(resolved_file.get_path());
308 generateText(text, en, codeMarker);
313
314
317 qsizetype idx, skipAhead = 0;
318 static bool in_para =
false;
319 Genus genus = Genus::DontCare;
323 QString name = atom->string();
324 if (relative && relative->name() == name.replace(QLatin1String(
"()"), QLatin1String())) {
325 out() << protectEnc(atom->string());
333 if (!m_inLink && !m_inContents && !m_inSectionHeading) {
334 const Node *node =
nullptr;
335 QString link = getAutoLink(atom, relative, &node, genus);
336 if (link.isEmpty()) {
341 QStringLiteral(
"Can't autolink to '%1'").arg(atom->string()));
346 if (link.isEmpty()) {
347 out() << protectEnc(atom->string());
349 beginLink(link, node, relative);
354 out() << protectEnc(atom->string());
361 skipAhead = skipAtoms(atom, Atom::BriefRight);
376 out() << protectEnc(plainCode(atom->string()));
380 out() <<
"<p class=\"figCaption\">";
391 out() <<
"<pre class=\"qml\" translate=\"no\"><code class=\"qml\">"
392 << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative,
394 m_codePrefix, m_codeSuffix)
395 <<
"</code></pre>\n";
399 if (atom->strings().count() == 2)
400 out() <<
"<pre class=\"" << atom->string(1) <<
"\" translate=\"no\"><code class=\"" << atom->string(1) <<
"\">";
402 out() <<
"<pre class=\"cpp\" translate=\"no\"><code class=\"cpp\">";
404 out() << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative),
405 m_codePrefix, m_codeSuffix)
406 <<
"</code></pre>\n";
409 out() <<
"<pre class=\"cpp plain\" translate=\"no\"><code class=\"text\">"
410 << trimmedTrailing(protectEnc(plainCode(indent(m_codeIndent, atom->string()))),
411 m_codePrefix, m_codeSuffix)
412 <<
"</code></pre>\n";
415 out() <<
"<details>\n";
417 out() <<
"<summary>...</summary>\n";
420 out() <<
"<summary>";
423 out() <<
"</summary>\n";
426 out() <<
"</details>\n";
430 if (!atom->string().isEmpty())
431 out() <<
' ' << atom->string();
454 if (atom->string().startsWith(
"span "))
455 out() <<
'<' + atom->string() <<
'>';
457 out() << formattingLeftMap()[atom->string()];
465 const Node *node{
nullptr};
466 const Atom tm_link(Atom::NavLink, m_trademarkspage);
467 if (
const auto &link = getLink(&tm_link, relative, &node);
468 !link.isEmpty() && node != relative)
469 out() <<
"<a href=\"%1\">%2</a>"_L1.arg(link, formattingRightMap()[atom->string()]);
471 out() << formattingRightMap()[atom->string()];
474 }
else if (atom->string().startsWith(
"span ")) {
477 out() << formattingRightMap()[atom->string()];
481 if (
const auto *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group); cn)
482 generateList(cn, marker, atom->string(), Generator::sortOrder(atom->strings().last()));
485 const auto sortOrder{Generator::sortOrder(atom->strings().last())};
486 if (atom->string() == QLatin1String(
"annotatedclasses")) {
487 generateAnnotatedList(relative, marker, m_qdb->getCppClasses().values(), sortOrder);
488 }
else if (atom->string() == QLatin1String(
"annotatedexamples")) {
489 generateAnnotatedLists(relative, marker, m_qdb->getExamples());
490 }
else if (atom->string() == QLatin1String(
"annotatedattributions")) {
491 generateAnnotatedLists(relative, marker, m_qdb->getAttributions());
492 }
else if (atom->string() == QLatin1String(
"classes")) {
493 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true,
495 }
else if (atom->string().contains(
"classes ")) {
496 QString rootName = atom->string().mid(atom->string().indexOf(
"classes") + 7).trimmed();
497 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true, rootName);
498 }
else if (atom->string() == QLatin1String(
"qmlvaluetypes")
499 || atom->string() == QLatin1String(
"qmlbasictypes")) {
500 generateCompactList(Generic, relative, m_qdb->getQmlValueTypes(),
true,
502 }
else if (atom->string() == QLatin1String(
"qmltypes")) {
503 generateCompactList(Generic, relative, m_qdb->getQmlTypes(),
true, QStringLiteral(
""));
504 }
else if ((idx = atom->string().indexOf(QStringLiteral(
"bymodule"))) != -1) {
506 QString moduleName = atom->string().mid(idx + 8).trimmed();
508 if (
const auto *cn = qdb->getCollectionNode(moduleName, moduleType)) {
510 switch (moduleType) {
514 generateAnnotatedList(relative, marker, map.values(), sortOrder);
517 if (atom->string().contains(QLatin1String(
"qmlvaluetypes")))
521 generateAnnotatedList(relative, marker, map.values(), sortOrder);
524 generateAnnotatedList(relative, marker, cn->members(), sortOrder);
528 }
else if (atom->string() == QLatin1String(
"classhierarchy")) {
529 generateClassHierarchy(relative, m_qdb->getCppClasses());
530 }
else if (atom->string() == QLatin1String(
"obsoleteclasses")) {
531 generateCompactList(Generic, relative, m_qdb->getObsoleteClasses(),
false,
532 QStringLiteral(
"Q"));
533 }
else if (atom->string() == QLatin1String(
"obsoleteqmltypes")) {
534 generateCompactList(Generic, relative, m_qdb->getObsoleteQmlTypes(),
false,
536 }
else if (atom->string() == QLatin1String(
"obsoletecppmembers")) {
537 generateCompactList(Obsolete, relative, m_qdb->getClassesWithObsoleteMembers(),
false,
538 QStringLiteral(
"Q"));
539 }
else if (atom->string() == QLatin1String(
"obsoleteqmlmembers")) {
540 generateCompactList(Obsolete, relative, m_qdb->getQmlTypesWithObsoleteMembers(),
false,
542 }
else if (atom->string() == QLatin1String(
"functionindex")) {
543 generateFunctionIndex(relative);
544 }
else if (atom->string() == QLatin1String(
"attributions")) {
545 generateAnnotatedList(relative, marker, m_qdb->getAttributions().values(), sortOrder);
546 }
else if (atom->string() == QLatin1String(
"legalese")) {
547 generateLegaleseList(relative, marker);
548 }
else if (atom->string() == QLatin1String(
"overviews")) {
549 generateList(relative, marker,
"overviews", sortOrder);
550 }
else if (atom->string() == QLatin1String(
"cpp-modules")) {
551 generateList(relative, marker,
"cpp-modules", sortOrder);
552 }
else if (atom->string() == QLatin1String(
"qml-modules")) {
553 generateList(relative, marker,
"qml-modules", sortOrder);
554 }
else if (atom->string() == QLatin1String(
"namespaces")) {
555 generateAnnotatedList(relative, marker, m_qdb->getNamespaces().values(), sortOrder);
556 }
else if (atom->string() == QLatin1String(
"related")) {
557 generateList(relative, marker,
"related", sortOrder);
559 const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group);
561 if (!generateGroupList(
const_cast<CollectionNode *>(cn), sortOrder))
563 QString(
"'\\generatelist %1' group is empty").arg(atom->string()));
566 QString(
"'\\generatelist %1' no such group").arg(atom->string()));
571 const NodeMultiMap &nsmap = m_qdb->getSinceMap(atom->string());
575 const NodeMultiMap &ncmap = m_qdb->getClassMap(atom->string());
576 const NodeMultiMap &nqcmap = m_qdb->getQmlTypeMap(atom->string());
581 for (
const auto §ion : sinceSections) {
582 if (!section.members().isEmpty()) {
584 <<
"<a href=\"#" << TextUtils::asAsciiPrintable(section.title()) <<
"\">"
585 << section.title() <<
"</a></li>\n";
591 for (
const auto §ion : sinceSections) {
592 if (!section.members().isEmpty()) {
593 out() <<
"<h3 id=\"" << TextUtils::asAsciiPrintable(section.title()) <<
"\">"
594 << protectEnc(section.title()) <<
"</h3>\n";
595 if (index == Sections::SinceClasses)
596 generateCompactList(Generic, relative, ncmap,
false, QStringLiteral(
"Q"));
597 else if (index == Sections::SinceQmlTypes)
598 generateCompactList(Generic, relative, nqcmap,
false, QStringLiteral(
""));
599 else if (index == Sections::SinceMemberFunctions
600 || index == Sections::SinceQmlMethods
601 || index == Sections::SinceQmlProperties) {
603 QMap<QString, NodeMultiMap> parentmaps;
605 const QList<Node *> &members = section.members();
606 for (
const auto &member : members) {
607 QString parent_full_name = (*member).parent()->fullName();
609 auto parent_entry = parentmaps.find(parent_full_name);
610 if (parent_entry == parentmaps.end())
611 parent_entry = parentmaps.insert(parent_full_name, NodeMultiMap());
612 parent_entry->insert(member->name(), member);
615 for (
auto map = parentmaps.begin(); map != parentmaps.end(); ++map) {
616 NodeVector nv = map->values().toVector();
617 auto parent = nv.front()->parent();
619 out() << ((index == Sections::SinceMemberFunctions) ?
"<p>Class " :
"<p>QML Type ");
621 out() <<
"<a href=\"" << linkForNode(parent, relative) <<
"\" translate=\"no\">";
622 QStringList pieces = parent->fullName().split(
"::");
623 out() << protectEnc(pieces.last());
627 generateSection(nv, relative, marker);
630 }
else if (index == Sections::SinceEnumValues) {
631 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
632 const auto map_it = m_qdb->newEnumValueMaps().constFind(atom->string());
633 for (
auto it = map_it->cbegin(); it != map_it->cend(); ++it) {
634 out() <<
"<tr><td class=\"memItemLeft\"> enum value </td><td class=\"memItemRight\">"
635 <<
"<b><a href=\"" << linkForNode(it.value(),
nullptr) <<
"\">"
636 << it.key() <<
"</a></b></td></tr>\n";
638 out() <<
"</table></div>\n";
640 generateSection(section.members(), relative, marker);
658 out() <<
"<p class=\"centerAlign\">";
660 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
661 if (!maybe_resolved_file) {
664 QStringLiteral(
"Missing image: %1").arg(protectEnc(atom->string())));
665 out() <<
"<font color=\"red\">[Missing image " << protectEnc(atom->string())
669 QString file_name{QFileInfo{file.get_path()}.fileName()};
689 "%1/%2"_L1.arg(outputDir(), imagesOutputDir()));
691 const auto &imgPath =
"%1/%2"_L1.arg(imagesOutputDir(), file_name);
693 out() <<
"<img src=\"%1\""_L1.arg(protectEnc(imgPath));
695 const QString altAndTitleText = protectEnc(text);
696 out() <<
" alt=\"" << altAndTitleText;
698 out() <<
"\" title=\"" << altAndTitleText;
702 m_helpProjectWriter->addExtraFile(imgPath);
703 setImageFileName(relative, imgPath);
715 QString admonType = atom->typeString();
718 out() <<
"<div class=\"admonition " << admonType.toLower() <<
"\">\n"
721 out() << admonType <<
": ";
731 out() <<
"<div class=\"LegaleseLeft\">";
745 const Node *node =
nullptr;
746 QString link = getLink(atom, relative, &node);
748 Location location = atom->isLinkAtom() ?
static_cast<
const LinkAtom*>(atom)->location
749 : relative->doc().location();
751 QStringLiteral(
"Can't link to '%1'").arg(atom->string()));
753 beginLink(link, node, relative);
757 QString link = linkForExampleFile(atom->string());
762 QString link = atom->string();
763 link =
"images/used-in-examples/" + link;
768 const Node *node =
static_cast<
const Node*>(
Utilities::nodeForString(atom->string()));
769 beginLink(linkForNode(node, relative), node, relative);
782 out() << R"(<div class="table"><table class="valuelist">)";
783 m_threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom);
784 if (m_threeColumnEnumValueTable) {
785 if (++m_numTableRows % 2 == 1)
786 out() << R"(<tr valign="top" class="odd">)";
788 out() << R"(<tr valign="top" class="even">)";
790 out() <<
"<th class=\"tblConst\">Constant</th>";
794 out() <<
"<th class=\"tblval\">Value</th>";
796 out() <<
"<th class=\"tbldscr\">Description</th></tr>\n";
798 out() <<
"<tr><th class=\"tblConst\">Constant</th><th "
799 "class=\"tblVal\">Value</th></tr>\n";
816 out() << QString(R"(<ol class="%1" type="%1" start="%2">)")
817 .arg(olType, atom
->next()->string());
819 out() << QString(R"(<ol class="%1" type="%1">)").arg(olType);
828 std::pair<QString,
int> pair = getAtomListValue(atom);
829 skipAhead = pair.second;
830 QString t = protectEnc(plainCode(marker->markedUpEnumValue(pair.first, relative)));
831 out() <<
"<tr><td class=\"topAlign\"><code translate=\"no\">" << t <<
"</code>";
834 out() <<
"</td><td class=\"topAlign tblval\">";
835 const auto *enume =
static_cast<
const EnumNode *>(relative);
836 QString itemValue = enume->itemValue(atom->next()->string());
837 if (itemValue.isEmpty())
840 out() <<
"<code translate=\"no\">" << protectEnc(itemValue) <<
"</code>";
853 if (m_threeColumnEnumValueTable) {
854 out() <<
"</td><td class=\"topAlign\">";
861 if (matchAhead(atom, Atom::ParaLeft))
868 out() <<
"</td></tr>\n";
879 out() <<
"</table></div>\n";
900 out() <<
"<blockquote>";
903 out() <<
"</blockquote>\n";
906 out() << atom->string();
912 int unit = atom->string().toInt() +
hOffset(relative
);
913 out() <<
"<h" + QString::number(unit) + QLatin1Char(
' ') <<
"id=\""
914 << Tree::refForAtom(atom) <<
"\">";
915 m_inSectionHeading =
true;
918 case Atom::SectionHeadingRight:
919 out() <<
"</h" + QString::number(atom->string().toInt() + hOffset(relative)) +
">\n";
920 m_inSectionHeading =
false;
927 if (m_inLink && !m_inContents && !m_inSectionHeading) {
930 out() << protectEnc(atom->string());
934 std::pair<QString, QString> pair = getTableWidthAttr(atom);
935 QString attr = pair.second;
936 QString width = pair.first;
943 out() << R"(<div class="table"><table class=")" << attr <<
'"';
944 if (!width.isEmpty())
945 out() <<
" style=\"width: " << width <<
'"';
950 out() <<
"</table></div>\n";
953 out() <<
"<thead><tr class=\"qt-style\">";
954 m_inTableHeader =
true;
960 out() <<
"\n<tr class=\"qt-style\">";
962 out() <<
"</thead>\n";
963 m_inTableHeader =
false;
967 if (!atom->string().isEmpty())
968 out() <<
"<tr " << atom->string() <<
'>';
969 else if (++m_numTableRows % 2 == 1)
970 out() << R"(<tr valign="top" class="odd">)";
972 out() << R"(<tr valign="top" class="even">)";
983 for (
int i = 0; i < atom->count(); ++i) {
986 const QString &p = atom->string(i);
987 if (p.contains(
'=')) {
990 QStringList spans = p.split(QLatin1Char(
','));
991 if (spans.size() == 2) {
992 if (spans.at(0) !=
"1")
993 out() <<
" colspan=\"" << spans.at(0) <<
'"';
994 if (spans.at(1) !=
"1")
995 out() <<
" rowspan=\"" << spans.at(1) <<
'"';
1000 if (matchAhead(atom, Atom::ParaLeft))
1004 if (m_inTableHeader)
1009 if (matchAhead(atom, Atom::ParaLeft))
1019 out() <<
"<span id=\"" <<
TextUtils::asAsciiPrintable(atom->string()) <<
"\"></span>";
1022 out() <<
"<b class=\"redFont\"><Missing HTML></b>";
1024 case Atom::UnknownCommand:
1025 out() << R"(<b class="redFont"><code translate=\"no\">\)" << protectEnc(atom->string()) <<
"</code></b>";
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1073 auto link_for_group = [
this](
const CollectionNode *group) -> QString {
1074 QString target{linkForNode(group,
nullptr)};
1075 return (target.isEmpty()) ? protectEnc(group->name()) :
"<a href=\"" + target +
"\">" + protectEnc(group->fullTitle()) +
"</a>";
1080 const QStringList &groups_names{node->groupNames()};
1081 if (groups_names.isEmpty())
1084 std::vector<CollectionNode *> groups_nodes(groups_names.size(),
nullptr);
1085 std::transform(groups_names.cbegin(), groups_names.cend(), groups_nodes.begin(),
1088 m_qdb->mergeCollections(group);
1089 return (group && group
->wasSeen()) ? group :
nullptr;
1091 groups_nodes.erase(
std::remove(groups_nodes.begin(), groups_nodes.end(),
nullptr), groups_nodes.end());
1093 if (!groups_nodes.empty()) {
1094 text += node->name() +
" is part of ";
1096 for (std::vector<CollectionNode *>::size_type index{0}; index < groups_nodes.size(); ++index) {
1097 text += link_for_group(groups_nodes[index]) + TextUtils::separator(index, groups_nodes.size());
1104
1105
1106
1107
1118 QString typeWord = aggregate->typeWord(
true);
1121 fullTitle = aggregate->plainFullName();
1122 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1123 ns =
static_cast<NamespaceNode *>(aggregate);
1125 fullTitle = aggregate->plainFullName();
1126 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1128 title = fullTitle = aggregate->fullTitle();
1129 if (!aggregate->doc().title().isEmpty())
1130 titleText << aggregate->name() <<
" - "_L1 << aggregate->doc().title();
1135 if (aggregate
->parent()->isInAPI() || templateDecl) {
1137 subtitleText <<
"%1 "_L1.arg((*templateDecl).to_qstring());
1138 subtitleText << aggregate->typeWord(
false) <<
" "_L1;
1139 auto ancestors = fullTitle.split(
"::"_L1);
1140 ancestors.pop_back();
1141 for (
const auto &a : ancestors)
1142 subtitleText << Atom(Atom::AutoLink, a) <<
"::"_L1;
1143 subtitleText << aggregate->plainName();
1146 generateHeader(title, aggregate, marker);
1147 generateTableOfContents(aggregate, marker, &summarySections);
1149 generateTitle(titleText, subtitleText, SmallSubTitle, aggregate, marker);
1151 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1155 brief <<
"The " << ns->name() <<
" namespace includes the following elements from module "
1158 addNodeLink(brief, fullNamespace,
" here.");
1160 generateText(brief, ns, marker);
1163 generateBrief(aggregate, marker);
1165 const auto parentIsClass = aggregate
->parent()->isClassNode();
1168 generateRequisites(aggregate, marker);
1173 QString membersLink = generateAllMembersFile(sections.allMembersSection(), marker);
1174 if (!membersLink.isEmpty()) {
1175 openUnorderedList();
1176 out() <<
"<li><a href=\"" << membersLink <<
"\">"
1177 <<
"List of all members, including inherited members</a></li>\n";
1179 QString obsoleteLink = generateObsoleteMembersFile(sections, marker);
1180 if (!obsoleteLink.isEmpty()) {
1181 openUnorderedList();
1182 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1183 <<
"Deprecated members</a></li>\n";
1186 if (QString groups_text{groupReferenceText(aggregate)}; !groups_text.isEmpty()) {
1187 openUnorderedList();
1189 out() <<
"<li>" << groups_text <<
"</li>\n";
1192 closeUnorderedList();
1197 bool needOtherSection =
false;
1199 for (
const auto §ion : summarySections) {
1200 if (section.members().isEmpty() && section.reimplementedMembers().isEmpty()) {
1201 if (!section.inheritedMembers().isEmpty())
1202 needOtherSection =
true;
1204 if (!section.members().isEmpty()) {
1205 QString ref = registerRef(section.title().toLower());
1206 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1207 generateSection(section.members(), aggregate, marker);
1209 if (!section.reimplementedMembers().isEmpty()) {
1210 QString name = QString(
"Reimplemented ") + section.title();
1211 QString ref = registerRef(name.toLower());
1212 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(name) <<
"</h2>\n";
1213 generateSection(section.reimplementedMembers(), aggregate, marker);
1216 if (!section.inheritedMembers().isEmpty()) {
1218 generateSectionInheritedList(section, aggregate);
1224 if (needOtherSection) {
1225 out() <<
"<h3>Additional Inherited Members</h3>\n"
1228 for (
const auto §ion : summarySections) {
1229 if (section.members().isEmpty() && !section.inheritedMembers().isEmpty())
1230 generateSectionInheritedList(section, aggregate);
1235 if (aggregate
->doc().isEmpty()) {
1236 QString command =
"documentation";
1238 command = R"('\class' comment)";
1241 QStringLiteral(
"No %1 for '%2'").arg(command, aggregate->plainSignature()));
1244 generateExtractionMark(aggregate, DetailedDescriptionMark);
1245 out() <<
"<div class=\"descr\">\n"
1246 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1247 <<
"Detailed Description"
1250 out() <<
"</div>\n";
1251 generateAlsoList(aggregate, marker);
1252 generateExtractionMark(aggregate, EndMark);
1255 for (
const auto §ion : detailsSections) {
1256 bool headerGenerated =
false;
1257 if (section.isEmpty())
1260 const QList<Node *> &members = section.members();
1261 for (
const auto &member : members) {
1262 if (!headerGenerated) {
1263 if (!section.divClass().isEmpty())
1264 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1265 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1266 headerGenerated =
true;
1268 if (!member->isClassNode())
1269 generateDetailedMember(member, aggregate, marker);
1272 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1273 out() <<
" class=\"%1\""_L1.arg(attrs);
1274 out() <<
"> class ";
1275 generateFullName(member, aggregate);
1277 generateBrief(member, marker, aggregate);
1280 if (headerGenerated && !section.divClass().isEmpty())
1281 out() <<
"</div>\n";
1283 generateFooter(aggregate);
1296 QString rawTitle = aggregate->plainName();
1297 QString fullTitle = aggregate->plainFullName();
1298 QString title = rawTitle +
" Proxy Page";
1299 generateHeader(title, aggregate, marker, u"auto-generated"_s);
1300 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1301 generateBrief(aggregate, marker);
1302 for (
const auto §ion : summarySections) {
1303 if (!section.members().isEmpty()) {
1304 QString ref = registerRef(section.title().toLower());
1305 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1306 generateSection(section.members(), aggregate, marker);
1310 if (!aggregate
->doc().isEmpty()) {
1311 generateExtractionMark(aggregate, DetailedDescriptionMark);
1312 out() <<
"<div class=\"descr\">\n"
1313 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1314 <<
"Detailed Description"
1317 out() <<
"</div>\n";
1318 generateAlsoList(aggregate, marker);
1319 generateExtractionMark(aggregate, EndMark);
1322 for (
const auto §ion : detailsSections) {
1323 if (section.isEmpty())
1326 if (!section.divClass().isEmpty())
1327 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1328 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1330 const QList<Node *> &members = section.members();
1331 for (
const auto &member : members) {
1332 if (!member->isClassNode()) {
1333 generateDetailedMember(member, aggregate, marker);
1336 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1337 out() <<
" class=\"%1\""_L1.arg(attrs);
1338 out() <<
"> class ";
1339 generateFullName(member, aggregate);
1341 generateBrief(member, marker, aggregate);
1344 if (!section.divClass().isEmpty())
1345 out() <<
"</div>\n";
1347 generateFooter(aggregate);
1351
1352
1353
1357 SubTitleSize subTitleSize = LargeSubTitle;
1358 QString htmlTitle = qcn->name();
1360 htmlTitle.append(
" QML Value Type");
1362 htmlTitle.append(
" QML Type");
1365 htmlTitle.append(
" (Singleton)"_L1);
1367 htmlTitle.append(
" (Uncreatable)"_L1);
1369 generateHeader(htmlTitle, qcn, marker);
1372 marker = CodeMarker::markerForLanguage(QLatin1String(
"QML"));
1373 generateTitle(htmlTitle,
Text() << qcn->subtitle(), subTitleSize, qcn, marker);
1374 generateBrief(qcn, marker);
1375 generateQmlRequisites(qcn, marker);
1379 out() <<
"<p><strong>Note:</strong> This type is a QML singleton. "_L1
1380 <<
"There is only one instance of this type in the QML engine.</p>\n"_L1;
1382 out() <<
"<p><strong>Note:</strong> This is an uncreatable type. "_L1
1383 <<
"It cannot be instantiated in QML.</p>\n"_L1;
1386 QString allQmlMembersLink;
1389 if (!qcn->isQmlBasicType())
1390 allQmlMembersLink = generateAllQmlMembersFile(sections, marker);
1391 QString obsoleteLink = generateObsoleteQmlMembersFile(sections, marker);
1392 if (!allQmlMembersLink.isEmpty() || !obsoleteLink.isEmpty()) {
1393 openUnorderedList();
1395 if (!allQmlMembersLink.isEmpty()) {
1396 out() <<
"<li><a href=\"" << allQmlMembersLink <<
"\">"
1397 <<
"List of all members, including inherited members</a></li>\n";
1399 if (!obsoleteLink.isEmpty()) {
1400 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1401 <<
"Deprecated members</a></li>\n";
1405 if (QString groups_text{groupReferenceText(qcn)}; !groups_text.isEmpty()) {
1406 openUnorderedList();
1408 out() <<
"<li>" << groups_text <<
"</li>\n";
1411 closeUnorderedList();
1414 for (
const auto §ion : qmlSummarySections) {
1415 if (!section.isEmpty()) {
1416 QString ref = registerRef(section.title().toLower());
1417 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1418 generateQmlSummary(section.members(), qcn, marker);
1422 generateExtractionMark(qcn, DetailedDescriptionMark);
1423 out() <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1424 <<
"Detailed Description"
1427 generateAlsoList(qcn, marker);
1428 generateExtractionMark(qcn, EndMark);
1431 for (
const auto §ion : qmlDetailsSections) {
1432 if (section.isEmpty())
1434 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1435 const QList<Node *> &members = section.members();
1436 for (
const auto member : members)
1437 generateDetailedQmlMember(member, qcn, marker);
1439 generateFooter(qcn);
1444
1445
1446
1449 generateHeader(pn->fullTitle(), pn, marker);
1451
1452
1453
1454 if ((pn->name() != QLatin1String(
"index.html")))
1455 generateTableOfContents(pn, marker,
nullptr);
1457 generateTitle(pn
->doc().title(),
Text() << pn->subtitle(), LargeSubTitle, pn, marker);
1459 generateBrief(pn, marker,
nullptr,
false);
1462 generateExtractionMark(pn, DetailedDescriptionMark);
1463 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1467 out() <<
"</div>\n";
1468 generateAlsoList(pn, marker);
1469 generateExtractionMark(pn, EndMark);
1475
1476
1479 SubTitleSize subTitleSize = LargeSubTitle;
1482 generateHeader(cn->fullTitle(), cn, marker);
1483 generateTableOfContents(cn, marker,
nullptr);
1484 generateTitle(cn
->doc().title(),
Text() << cn->subtitle(), subTitleSize, cn, marker);
1487 if (cn
->genus() != Genus::DOC && cn
->genus() != Genus::DontCare) {
1489 generateBrief(cn, marker);
1497 if (!nmm.isEmpty()) {
1498 ref = registerRef(
"namespaces");
1499 out() <<
"<h2 id=\"" << ref <<
"\">Namespaces</h2>\n";
1500 generateAnnotatedList(cn, marker, nmm.values());
1503 if (!nmm.isEmpty()) {
1504 ref = registerRef(
"classes");
1505 out() <<
"<h2 id=\"" << ref <<
"\">Classes</h2>\n";
1506 generateAnnotatedList(cn, marker, nmm.values());
1512 generateExtractionMark(cn, DetailedDescriptionMark);
1513 ref = registerRef(
"details");
1514 out() <<
"<div class=\"descr\">\n";
1515 out() <<
"<h2 id=\"" << ref <<
"\">"
1516 <<
"Detailed Description"
1519 generateExtractionMark(cn, DetailedDescriptionMark);
1520 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1525 out() <<
"</div>\n";
1526 generateAlsoList(cn, marker);
1527 generateExtractionMark(cn, EndMark);
1530 if (cn->isGroup() || cn->isQmlModule())
1531 generateAnnotatedList(cn, marker, cn->members());
1537
1538
1539
1540
1543 SubTitleSize subTitleSize = LargeSubTitle;
1544 QString fullTitle = cn->name();
1546 generateHeader(fullTitle, cn, marker, u"auto-generated"_s);
1547 generateTitle(fullTitle,
Text() << cn->subtitle(), subTitleSize, cn, marker);
1550 brief <<
"Each function or type documented here is related to a class or "
1551 <<
"namespace that is documented in a different module. The reference "
1552 <<
"page for that class or namespace will link to the function or type "
1555 generateText(brief, cn, marker);
1559 for (
const auto &member : members)
1560 generateDetailedMember(member, cn, marker);
1566
1567
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595void HtmlGenerator::generateNavigationBar(
const QString &title,
const Node *node,
1596 CodeMarker *marker,
const QString &buildversion,
1599 if (m_noNavigationBar || node ==
nullptr)
1610 auto addNavItem = [&](
const QString &link,
const QString &title) {
1611 navigationbar << Atom(itemLeft) << Atom(
Atom::NavLink, link)
1618 auto addNavItemNode = [&](
const Node *node,
const QString &title) {
1619 navigationbar << Atom(itemLeft);
1620 addNodeLink(navigationbar, node, title);
1621 navigationbar << Atom(itemRight);
1625 const auto *moduleNode = m_qdb->getModuleNode(node);
1626 QString moduleState;
1627 if (moduleNode && !moduleNode->state().isEmpty())
1628 moduleState = QStringLiteral(
" (%1)").arg(moduleNode->state());
1630 if (m_hometitle == title)
1632 if (!m_homepage.isEmpty())
1633 addNavItem(m_homepage, m_hometitle);
1634 if (!m_landingpage.isEmpty() && m_landingtitle != title)
1635 addNavItem(m_landingpage, m_landingtitle);
1638 if (!m_cppclassespage.isEmpty() && !m_cppclassestitle.isEmpty())
1639 addNavItem(m_cppclassespage, m_cppclassestitle);
1640 if (!node->physicalModuleName().isEmpty()) {
1644 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_cppclassespage))
1645 addNavItemNode(moduleNode, moduleNode->name() + moduleState);
1647 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1649 if (!m_qmltypespage.isEmpty() && !m_qmltypestitle.isEmpty())
1650 addNavItem(m_qmltypespage, m_qmltypestitle);
1654 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_qmltypespage)) {
1655 addNavItemNode(moduleNode, moduleNode->name() + moduleState);
1657 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1660 auto currentNode{
static_cast<
const PageNode*>(node)};
1661 std::deque<
const Node *> navNodes;
1663 qsizetype navItems = 0;
1664 while (currentNode->navigationParent() && ++navItems < 16) {
1665 if (
std::find(navNodes.cbegin(), navNodes.cend(),
1666 currentNode->navigationParent()) == navNodes.cend())
1667 navNodes.push_front(currentNode->navigationParent());
1668 currentNode = currentNode->navigationParent();
1672 if (navNodes.empty()) {
1673 const QStringList groups =
static_cast<
const PageNode *>(node)->groupNames();
1674 for (
const auto &groupName : groups) {
1675 const auto *groupNode = m_qdb->findNodeByNameAndType(QStringList{groupName}, &Node::isGroup);
1676 if (groupNode && !groupNode->title().isEmpty()) {
1677 navNodes.push_front(groupNode);
1682 while (!navNodes.empty()) {
1683 if (navNodes.front()->isPageNode())
1684 addNavItemNode(navNodes.front(), navNodes.front()->title());
1685 navNodes.pop_front();
1689 navigationbar << Atom(itemLeft) << Atom(
Atom::String, title) << Atom(itemRight);
1693 generateText(navigationbar, node, marker);
1695 if (buildversion.isEmpty())
1701 out() <<
"</tr></table><table class=\"buildversion\"><tr>\n"
1702 << R"(<td id="buildversion" width="100%" align="right">)";
1704 out() <<
"<li id=\"buildversion\">";
1708 if (!m_landingpage.isEmpty() && m_landingtitle != title) {
1709 navigationbar << Atom(Atom::NavLink, m_landingpage)
1711 << Atom(Atom::String, buildversion)
1713 generateText(navigationbar, node, marker);
1715 out() << buildversion;
1724 const QString &metaKeyword)
1726 out() <<
"<!DOCTYPE html>\n";
1727 out() << QString(
"<html lang=\"%1\">\n").arg(naturalLanguage);
1728 out() <<
"<head>\n";
1729 out() <<
" <meta charset=\"utf-8\">\n";
1734 out() <<
" <meta name=\"description\" content=\""
1735 << protectEnc(node->doc().briefText().toString())
1739 if (!metaKeyword.isEmpty()) {
1741 out() <<
" <meta name=\"keywords\" content=\"%1\">\n"_L1.arg(protectEnc(metaKeyword));
1744 QStringList keywords;
1746 for (
const auto &kw : metaTags->values(u"keywords"_s))
1747 keywords << kw.split(
','_L1, Qt::SkipEmptyParts);
1752 keywords << node->nodeTypeString().toLower().remove(
' '_L1);
1754 if (!keywords.isEmpty()) {
1755 std::transform(keywords.begin(), keywords.end(), keywords.begin(),
1756 [](
const QString &k) {
return k.trimmed(); });
1757 keywords.removeDuplicates();
1758 out() <<
" <meta name=\"keywords\" content=\"" << protectEnc(keywords.join(
','_L1))
1764 QString titleSuffix;
1765 if (!m_landingtitle.isEmpty()) {
1767 titleSuffix = m_landingtitle;
1768 }
else if (!m_hometitle.isEmpty()) {
1771 if (title != m_hometitle)
1772 titleSuffix = m_hometitle;
1775 titleSuffix = m_productName.isEmpty() ? m_project : m_productName;
1777 if (title == titleSuffix)
1778 titleSuffix.clear();
1780 out() <<
" <title>";
1781 if (!titleSuffix.isEmpty() && !title.isEmpty()) {
1782 out() <<
"%1 | %2"_L1.arg(protectEnc(title), titleSuffix);
1784 out() << protectEnc(title);
1789 QVersionNumber projectVersion = QVersionNumber::fromString(m_qdb->version());
1790 if (!projectVersion.isNull()) {
1791 QVersionNumber titleVersion;
1792 static const QRegularExpression re(QLatin1String(R"(\d+\.\d+)"));
1793 const QString &versionedTitle = titleSuffix.isEmpty() ? title : titleSuffix;
1794 auto match = re.match(versionedTitle);
1795 if (match.hasMatch())
1796 titleVersion = QVersionNumber::fromString(match.captured());
1797 if (titleVersion.isNull() || !titleVersion.isPrefixOf(projectVersion)) {
1799 if (!m_productName.isEmpty() && titleSuffix != m_productName)
1800 out() <<
" | %1"_L1.arg(m_productName);
1801 out() <<
" %1"_L1.arg(projectVersion.toString());
1804 out() <<
"</title>\n";
1807 out() << m_headerStyles;
1808 out() << m_headerScripts;
1809 out() << m_endHeader;
1811 out() << QString(m_postHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1812 bool usingTable = m_postHeader.trimmed().endsWith(QLatin1String(
"<tr>"));
1813 generateNavigationBar(title, node, marker, m_buildversion, usingTable);
1814 out() << QString(m_postPostHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1816 m_navigationLinks.clear();
1819 if (node && !node->links().empty()) {
1820 std::pair<QString, QString> linkPair;
1821 std::pair<QString, QString> anchorPair;
1822 const Node *linkNode;
1823 bool useSeparator =
false;
1825 if (node->links().contains(Node::PreviousLink)) {
1826 linkPair = node->links()[Node::PreviousLink];
1827 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1830 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1831 if (linkNode ==
nullptr || linkNode == node)
1832 anchorPair = linkPair;
1834 anchorPair = anchorForNode(linkNode);
1836 out() << R"( <link rel="prev" href=")" << anchorPair.first <<
"\" />\n";
1838 m_navigationLinks += R"(<a class="prevPage" href=")" + anchorPair.first +
"\">";
1839 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
1840 m_navigationLinks += protect(anchorPair.second);
1842 m_navigationLinks += protect(linkPair.second);
1843 m_navigationLinks +=
"</a>\n";
1844 useSeparator = !m_navigationSeparator.isEmpty();
1846 if (node->links().contains(Node::NextLink)) {
1847 linkPair = node->links()[Node::NextLink];
1848 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1851 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1852 if (linkNode ==
nullptr || linkNode == node)
1853 anchorPair = linkPair;
1855 anchorPair = anchorForNode(linkNode);
1857 out() << R"( <link rel="next" href=")" << anchorPair.first <<
"\" />\n";
1860 m_navigationLinks += m_navigationSeparator;
1862 m_navigationLinks += R"(<a class="nextPage" href=")" + anchorPair.first +
"\">";
1863 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
1864 m_navigationLinks += protect(anchorPair.second);
1866 m_navigationLinks += protect(linkPair.second);
1867 m_navigationLinks +=
"</a>\n";
1869 if (node->links().contains(Node::StartLink)) {
1870 linkPair = node->links()[Node::StartLink];
1871 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1874 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1875 if (linkNode ==
nullptr || linkNode == node)
1876 anchorPair =
std::move(linkPair);
1878 anchorPair = anchorForNode(linkNode);
1879 out() << R"( <link rel="start" href=")" << anchorPair.first <<
"\" />\n";
1883 if (node && !node->links().empty())
1884 out() <<
"<p class=\"naviNextPrevious headerNavi\">\n" << m_navigationLinks <<
"</p>\n";
1888 SubTitleSize subTitleSize,
const Node *relative,
1891 out() << QString(m_prologue).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1894 attribute = R"( translate="no")";
1897 out() <<
"<h1 class=\"title\"" << attribute <<
">";
1898 generateText(title, relative, marker);
1903 if (subTitleSize == SmallSubTitle)
1904 out() <<
" class=\"small-subtitle\"" << attribute <<
">";
1906 out() <<
" class=\"subtitle\"" << attribute <<
">";
1907 generateText(subtitle, relative, marker);
1908 out() <<
"</span>\n";
1914 if (node && !node->links().empty())
1915 out() <<
"<p class=\"naviNextPrevious footerNavi\">\n" << m_navigationLinks <<
"</p>\n";
1917 out() << QString(m_footer).replace(
"\\" +
COMMAND_VERSION, m_qdb->version())
1918 << QString(m_address).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1920 out() <<
"</body>\n";
1921 out() <<
"</html>\n";
1925
1926
1927
1930 QMap<QString, Text> requisites;
1933 const QString headerText =
"Header";
1934 const QString sinceText =
"Since";
1935 const QString inheritedByText =
"Inherited By";
1936 const QString inheritsText =
"Inherits";
1937 const QString nativeTypeText =
"In QML";
1938 const QString qtVariableText =
"qmake";
1939 const QString cmakeText =
"CMake";
1940 const QString statusText =
"Status";
1943 const QStringList requisiteorder { headerText, cmakeText, qtVariableText, sinceText,
1944 nativeTypeText, inheritsText, inheritedByText, statusText };
1946 addIncludeFileToMap(aggregate, requisites, text, headerText);
1947 addSinceToMap(aggregate, requisites, &text, sinceText);
1950 addCMakeInfoToMap(aggregate, requisites, &text, cmakeText);
1951 addQtVariableToMap(aggregate, requisites, &text, qtVariableText);
1955 auto *classe =
dynamic_cast<
ClassNode *>(aggregate);
1957 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1959 if (InclusionFilter::isIncluded(policy, context))
1960 addQmlNativeTypesToMap(requisites, &text, nativeTypeText, classe);
1963 const auto *metaTags = classe ? classe
->doc().metaTagMap() :
nullptr;
1964 if (!metaTags || !metaTags->contains(u"qdoc-suppress-inheritance"_s))
1965 addInheritsToMap(requisites, &text, inheritsText, classe);
1966 addInheritedByToMap(requisites, &text, inheritedByText, classe);
1970 addStatusToMap(aggregate, requisites, text, statusText);
1972 if (!requisites.isEmpty()) {
1974 generateTheTable(requisiteorder, requisites, aggregate, marker);
1979
1980
1981void HtmlGenerator::generateTheTable(
const QStringList &requisiteOrder,
1982 const QMap<QString, Text> &requisites,
1985 out() <<
"<div class=\"table\"><table class=\"alignedsummary requisites\" translate=\"no\">\n";
1987 for (
auto it = requisiteOrder.constBegin(); it != requisiteOrder.constEnd(); ++it) {
1989 if (requisites.contains(*it)) {
1991 <<
"<td class=\"memItemLeft rightAlign topAlign\"> " << *it
1993 "</td><td class=\"memItemRight bottomAlign\"> ";
1995 generateText(requisites.value(*it), aggregate, marker);
1996 out() <<
"</td></tr>\n";
1999 out() <<
"</table></div>\n";
2003
2004
2005
2006void HtmlGenerator::addInheritedByToMap(QMap<QString, Text> &requisites,
Text *text,
2007 const QString &inheritedByText,
ClassNode *classe)
2009 if (!classe->derivedClasses().isEmpty()) {
2012 int count = appendSortedNames(*text, classe, classe->derivedClasses());
2015 requisites.insert(inheritedByText, *text);
2020
2021
2022
2023void HtmlGenerator::addInheritsToMap(QMap<QString, Text> &requisites,
Text *text,
2024 const QString &inheritsText,
ClassNode *classe)
2026 if (!classe->baseClasses().isEmpty()) {
2029 const auto baseClasses = classe->baseClasses();
2030 for (
const auto &cls : baseClasses) {
2032 appendFullName(*text, cls.m_node, classe);
2034 if (cls.m_access == Access::Protected) {
2035 *text <<
" (protected)";
2036 }
else if (cls.m_access == Access::Private) {
2037 *text <<
" (private)";
2039 *text << TextUtils::comma(index++, classe->baseClasses().size());
2044 requisites.insert(inheritsText, *text);
2049
2050
2051
2052void HtmlGenerator::addQmlNativeTypesToMap(QMap<QString, Text> &requisites,
Text *text,
2053 const QString &nativeTypeText,
ClassNode *classe)
const
2060 QList<QmlTypeNode *> nativeTypes { classe->qmlNativeTypes().cbegin(), classe->qmlNativeTypes().cend()};
2062 qsizetype index { 0 };
2064 for (
const auto &item : std::as_const(nativeTypes)) {
2065 addNodeLink(*text, item);
2066 *text << TextUtils::comma(index++, nativeTypes.size());
2068 requisites.insert(nativeTypeText, *text);
2072
2073
2074
2076 Text *text,
const QString &CMakeInfo)
const
2078 if (!aggregate->physicalModuleName().isEmpty() && text !=
nullptr) {
2080 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2082 const auto result = cmakeRequisite(cn);
2095 requisites.insert(CMakeInfo, *text);
2100
2101
2102
2104 Text *text,
const QString &qtVariableText)
const
2106 if (!aggregate->physicalModuleName().isEmpty()) {
2108 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2110 if (cn && !cn->qtVariable().isEmpty()) {
2113 requisites.insert(qtVariableText, *text);
2119
2120
2121
2122
2124 Text *text,
const QString &sinceText)
const
2126 if (!aggregate->since().isEmpty() && text !=
nullptr) {
2129 requisites.insert(sinceText, *text);
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2145 Text &text,
const QString &statusText)
const
2147 auto status{formatStatus(aggregate, m_qdb)};
2153 spanClass = u"deprecated"_s;
2155 spanClass =
TextUtils::asAsciiPrintable(status.value());
2158 text << Atom(Atom::String, status.value())
2160 "class=\"status %1\""_L1.arg(spanClass))
2162 requisites.insert(statusText, text);
2166
2167
2168
2169
2171 QMap<QString, Text> &requisites,
Text& text,
2172 const QString &headerText)
2174 if (aggregate->includeFile()) {
2176 text << openCodeTag <<
"#include <%1>"_L1.arg(*aggregate->includeFile()) << closeCodeTag;
2177 requisites.insert(headerText, text);
2182
2183
2184
2190 QMap<QString, Text> requisites;
2193 const QString importText =
"Import Statement";
2194 const QString sinceText =
"Since";
2195 const QString inheritedByText =
"Inherited By";
2196 const QString inheritsText =
"Inherits";
2197 const QString nativeTypeText =
"In C++";
2198 const QString statusText =
"Status";
2201 QString logicalModuleVersion;
2206 bool generate_import =
true;
2208 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2212 if (generate_import) {
2216 requisites.insert(importText, text);
2219 qcn
->doc().location().warning(QStringLiteral(
"Could not resolve QML import statement for type '%1'").arg(qcn->name()),
2224 if (!qcn->since().isEmpty()) {
2227 requisites.insert(sinceText, text);
2232 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2236 addNodeLink(text, cn);
2237 requisites.insert(nativeTypeText, text);
2245 QStringList knownTypeNames{qcn->name()};
2247 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2255 knownTypeNames << base->name();
2258 addNodeLink(text, base);
2261 for (
const auto sub : std::as_const(subs)) {
2262 if (knownTypeNames.contains(sub->name())) {
2263 text << Atom(Atom::String,
" (%1)"_L1.arg(base->logicalModuleName()));
2268 requisites.insert(inheritsText, text);
2272 if (!subs.isEmpty()) {
2275 int count = appendSortedQmlNames(text, qcn, knownTypeNames, subs);
2278 requisites.insert(inheritedByText, text);
2282 addStatusToMap(qcn, requisites, text, statusText);
2285 const QStringList requisiteorder {
std::move(importText),
std::move(sinceText),
2286 std::move(nativeTypeText),
std::move(inheritsText),
2287 std::move(inheritedByText),
std::move(statusText)};
2289 if (!requisites.isEmpty())
2290 generateTheTable(requisiteorder, requisites, qcn, marker);
2302 QStringLiteral(
"'\\brief' statement does not end with a full stop."));
2304 generateExtractionMark(node, BriefMark);
2306 generateText(brief, node, marker);
2309 if (!relative || node == relative)
2310 out() <<
" <a href=\"#";
2312 out() <<
" <a href=\"" << linkForNode(node, relative) <<
'#';
2313 out() << registerRef(
"details") <<
"\">More...</a>";
2317 generateExtractionMark(node, EndMark);
2322
2323
2324
2330 toc = node
->doc().tableOfContents();
2331 if (tocDepth == 0 || (toc.isEmpty() && !sections && !node
->isModule())) {
2336 int sectionNumber = 1;
2337 int detailsBase = 0;
2340 m_inContents =
true;
2342 out() <<
"<div class=\"sidebar\">\n";
2343 out() <<
"<div class=\"toc\">\n";
2344 out() <<
"<h3 id=\"toc\">Contents</h3>\n";
2347 openUnorderedList();
2348 if (!
static_cast<
const CollectionNode *>(node)->noAutoList()) {
2350 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2351 << registerRef(
"namespaces") <<
"\">Namespaces</a></li>\n";
2354 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2355 << registerRef(
"classes") <<
"\">Classes</a></li>\n";
2358 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#" << registerRef(
"details")
2359 <<
"\">Detailed Description</a></li>\n";
2360 for (
const auto &entry : std::as_const(toc)) {
2361 if (entry->string().toInt() == 1) {
2367 for (
const auto §ion : *sections) {
2368 if (!section.members().isEmpty()) {
2369 openUnorderedList();
2370 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2371 << registerRef(section.plural()) <<
"\">" << section.title() <<
"</a></li>\n";
2373 if (!section.reimplementedMembers().isEmpty()) {
2374 openUnorderedList();
2375 QString ref = QString(
"Reimplemented ") + section.plural();
2376 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2377 << registerRef(ref.toLower()) <<
"\">"
2378 << QString(
"Reimplemented ") + section.title() <<
"</a></li>\n";
2382 openUnorderedList();
2383 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2384 << registerRef(
"details") <<
"\">Detailed Description</a></li>\n";
2386 for (
const auto &entry : toc) {
2387 if (entry->string().toInt() == 1) {
2394 for (
const auto &atom : toc) {
2395 sectionNumber = atom->string().toInt() + detailsBase;
2398 if (sectionNumber <= tocDepth || tocDepth < 0) {
2399 openUnorderedList();
2401 Text headingText = Text::sectionHeading(atom);
2402 out() <<
"<li class=\"level" << sectionNumber <<
"\">";
2403 out() <<
"<a href=\"" <<
'#' << Tree::refForAtom(atom) <<
"\">";
2404 generateAtomList(headingText.firstAtom(), node, marker,
true, numAtoms);
2405 out() <<
"</a></li>\n";
2408 closeUnorderedList();
2409 out() <<
"</div>\n";
2410 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2411 out() <<
"</div>\n";
2412 m_inContents =
false;
2417
2418
2421 out() <<
"<div class=\"sidebar\">";
2422 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2423 out() <<
"</div>\n";
2432 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2433 beginSubPage(aggregate, fileName);
2434 QString title =
"List of All Members for " + aggregate->plainFullName();
2435 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2437 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2438 out() <<
"<p>This is the complete list of members for ";
2439 generateFullName(aggregate,
nullptr);
2440 out() <<
", including inherited members.</p>\n";
2442 generateSectionList(section, aggregate, marker);
2450
2451
2452
2453
2454
2462 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2463 beginSubPage(aggregate, fileName);
2464 QString title =
"List of All Members for " + aggregate->name();
2465 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2467 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2468 out() <<
"<p>This is the complete list of members for ";
2469 generateFullName(aggregate,
nullptr);
2470 out() <<
", including inherited members.</p>\n";
2473 for (
int i = 0; i < cknl.size(); i++) {
2474 const auto &ckn = cknl[i];
2477 if (nodes.isEmpty())
2480 out() <<
"<p>The following members are inherited from ";
2481 generateFullName(qcn,
nullptr);
2484 openUnorderedList();
2485 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2486 for (
int j = 0; j < nodes.size(); j++) {
2487 Node *node = nodes[j];
2494 std::function<
void(
Node *)> generate = [&](Node *n) {
2495 out() <<
"<li class=\"fn\" translate=\"no\">";
2496 generateQmlItem(n, aggregate, marker,
true);
2497 if (n->isQmlProperty()) {
2498 auto qpn =
static_cast<QmlPropertyNode *>(n);
2499 QStringList hints = qpn->hints();
2500 if (qpn->isAttached())
2501 hints <<
"attached"_L1;
2502 if (!hints.isEmpty())
2503 out() <<
" [" << hints.join(
' '_L1) <<
"]";
2504 }
else if (n->isAttached()) {
2506 out() <<
" [attached]";
2509 if (n->isPropertyGroup()) {
2511 const QList<Node *> &collective =
2512 static_cast<SharedCommentNode *>(n)->collective();
2513 std::for_each(collective.begin(), collective.end(), generate);
2520 closeUnorderedList();
2537 QString title =
"Obsolete Members for " + aggregate->plainFullName();
2538 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2540 beginSubPage(aggregate, fileName);
2541 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2543 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2545 out() <<
"<p><b>The following members of class "
2546 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\" translate=\"no\">"
2547 << protectEnc(aggregate->name()) <<
"</a>"
2548 <<
" are deprecated.</b> "
2549 <<
"They are provided to keep old source code working. "
2550 <<
"We strongly advise against using them in new code.</p>\n";
2552 for (
const auto §ion : summary_spv) {
2553 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2554 generateSectionList(*section, aggregate, marker,
true);
2557 for (
const auto §ion : details_spv) {
2558 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2560 const NodeVector &members = section->obsoleteMembers();
2561 for (
const auto &member : members)
2562 generateDetailedMember(member, aggregate, marker);
2571
2572
2573
2574
2583 QString title =
"Obsolete Members for " + aggregate->name();
2584 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2586 beginSubPage(aggregate, fileName);
2587 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2589 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2591 out() <<
"<p><b>The following members of QML type "
2592 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\">"
2593 << protectEnc(aggregate->name()) <<
"</a>"
2594 <<
" are deprecated.</b> "
2595 <<
"They are provided to keep old source code working. "
2596 <<
"We strongly advise against using them in new code.</p>\n";
2598 for (
const auto §ion : summary_spv) {
2599 QString ref = registerRef(section->title().toLower());
2600 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section->title()) <<
"</h2>\n";
2601 generateQmlSummary(section->obsoleteMembers(), aggregate, marker);
2604 for (
const auto §ion : details_spv) {
2605 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2606 const NodeVector &members = section->obsoleteMembers();
2607 for (
const auto &member : members) {
2608 generateDetailedQmlMember(member, aggregate, marker);
2620 if (classMap.isEmpty())
2624 for (
const auto &it : classMap) {
2625 auto *classe =
static_cast<ClassNode *>(it);
2626 if (classe->baseClasses().isEmpty())
2627 topLevel.insert(classe->name(), classe);
2630 QStack<NodeMap> stack;
2631 stack.push(topLevel);
2634 while (!stack.isEmpty()) {
2635 if (stack.top().isEmpty()) {
2641 generateFullName(child, relative);
2643 stack.top().erase(stack.top().begin());
2646 const auto derivedClasses = child->derivedClasses();
2647 for (
const RelatedClass &d : derivedClasses) {
2648 if (d.m_node && d.m_node->isInAPI())
2649 newTop.insert(d.m_node->name(), d.m_node);
2651 if (!newTop.isEmpty()) {
2660
2661
2662
2664 const NodeList &unsortedNodes, Qt::SortOrder sortOrder)
2666 if (unsortedNodes.isEmpty() || relative ==
nullptr)
2670 bool allInternal =
true;
2671 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2672 for (
auto *node : unsortedNodes) {
2673 const NodeContext context = node->createContext();
2674 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated()) {
2675 allInternal =
false;
2676 nmm.insert(node->fullName(relative), node);
2681 out() <<
"<div class=\"table\"><table class=\"annotated\">\n";
2685 if (sortOrder == Qt::DescendingOrder)
2690 for (
const auto *node : std::as_const(nodes)) {
2692 out() <<
"<tr class=\"odd topAlign\">";
2694 out() <<
"<tr class=\"even topAlign\">";
2695 out() <<
"<td class=\"tblName\" translate=\"no\"><p>";
2696 generateFullName(node, relative);
2697 out() <<
"</p></td>";
2699 if (!node->isTextPageNode()) {
2700 Text brief = node->doc().trimmedBriefText(node->name());
2701 if (!brief.isEmpty()) {
2702 out() <<
"<td class=\"tblDescr\"><p>";
2703 generateText(brief, node, marker);
2704 out() <<
"</p></td>";
2705 }
else if (!node->reconstitutedBrief().isEmpty()) {
2706 out() <<
"<td class=\"tblDescr\"><p>";
2707 out() << node->reconstitutedBrief();
2708 out() <<
"</p></td>";
2711 out() <<
"<td class=\"tblDescr\"><p>";
2712 if (!node->reconstitutedBrief().isEmpty()) {
2713 out() << node->reconstitutedBrief();
2715 out() << protectEnc(node->doc().briefText().toString());
2716 out() <<
"</p></td>";
2720 out() <<
"</table></div>\n";
2724
2725
2726
2730 const auto &uniqueKeys = nmm.uniqueKeys();
2731 for (
const QString &name : uniqueKeys) {
2732 if (!name.isEmpty()) {
2733 out() <<
"<h2 id=\"" << registerRef(name.toLower()) <<
"\">" << protectEnc(name)
2736 generateAnnotatedList(relative, marker, nmm.values(name));
2741
2742
2743
2744
2745
2746
2747
2748
2749
2752 const QString &commonPrefix)
2757 const int NumParagraphs = 37;
2758 qsizetype commonPrefixLen = commonPrefix.size();
2761
2762
2763
2764
2765
2767 QString paragraphName[NumParagraphs + 1];
2768 QSet<
char> usedParagraphNames;
2770 for (
auto c = nmm.constBegin(); c != nmm.constEnd(); ++c) {
2771 QStringList pieces = c.key().split(
"::");
2772 int idx = commonPrefixLen;
2773 if (idx > 0 && !pieces.last().startsWith(commonPrefix, Qt::CaseInsensitive))
2775 QString last = pieces.last().toLower();
2776 QString key = last.mid(idx);
2778 int paragraphNr = NumParagraphs - 1;
2780 if (key[0].digitValue() != -1) {
2781 paragraphNr = key[0].digitValue();
2782 }
else if (key[0] >= QLatin1Char(
'a') && key[0] <= QLatin1Char(
'z')) {
2783 paragraphNr = 10 + key[0].unicode() -
'a';
2786 paragraphName[paragraphNr] = key[0].toUpper();
2787 usedParagraphNames.insert(key[0].toLower().cell());
2788 paragraph[paragraphNr].insert(last, c.value());
2792
2793
2794
2795
2796
2797
2798
2799 qsizetype paragraphOffset[NumParagraphs + 1];
2800 paragraphOffset[0] = 0;
2801 for (
int i = 0; i < NumParagraphs; i++)
2802 paragraphOffset[i + 1] = paragraphOffset[i] + paragraph[i].size();
2805
2806
2807 if (includeAlphabet) {
2808 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
2809 for (
int i = 0; i < 26; i++) {
2811 if (usedParagraphNames.contains(
char(
'a' + i)))
2812 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
2814 out() <<
"</b></p>\n";
2818
2819
2820 out() <<
"<div class=\"flowListDiv\" translate=\"no\">\n";
2824 QHash<QString,
int> nameOccurrences;
2825 for (
const auto &[key, node] : nmm.asKeyValueRange()) {
2826 QStringList pieces{node->fullName(relative).split(
"::"_L1)};
2827 const QString &name{pieces.last()};
2828 nameOccurrences[name]++;
2832 int curParOffset = 0;
2834 for (
int i = 0; i < nmm.size(); i++) {
2835 while ((curParNr < NumParagraphs) && (curParOffset == paragraph[curParNr].size())) {
2841
2842
2843 if (curParOffset == 0) {
2846 if (++m_numTableRows % 2 == 1)
2847 out() <<
"<dl class=\"flowList odd\">";
2849 out() <<
"<dl class=\"flowList even\">";
2850 out() <<
"<dt class=\"alphaChar\"";
2851 if (includeAlphabet)
2852 out() << QString(
" id=\"%1\"").arg(paragraphName[curParNr][0].toLower());
2853 out() <<
"><b>" << paragraphName[curParNr] <<
"</b></dt>\n";
2857
2858
2860 if ((curParNr < NumParagraphs) && !paragraphName[curParNr].isEmpty()) {
2861 NodeMultiMap::Iterator it;
2862 NodeMultiMap::Iterator next;
2863 it = paragraph[curParNr].begin();
2864 for (
int j = 0; j < curParOffset; j++)
2869
2870
2871
2872 out() <<
"<a href=\"" << linkForNode(it.value(), relative) <<
"\">";
2874 QString fileName = fileBase(it.value()) +
"-obsolete." + fileExtension();
2876 if (useOutputSubdirs())
2877 link =
"../%1/"_L1.arg(it.value()->tree()->physicalModuleName());
2879 out() <<
"<a href=\"" << link <<
"\">";
2882 QStringList pieces{it.value()->fullName(relative).split(
"::"_L1)};
2883 const auto &name{pieces.last()};
2886 if (nameOccurrences[name] > 1) {
2887 const QString moduleName = it.value()->isQmlNode() ? it.value()->logicalModuleName()
2888 : it.value()->tree()->camelCaseModuleName();
2889 pieces.last().append(
": %1"_L1.arg(moduleName));
2892 out() << protectEnc(pieces.last());
2894 if (pieces.size() > 1) {
2896 generateFullName(it.value()->parent(), relative);
2906 out() <<
"</div>\n";
2911 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
2912 for (
int i = 0; i < 26; i++) {
2914 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
2916 out() <<
"</b></p>\n";
2918 char nextLetter =
'a';
2920 out() <<
"<ul translate=\"no\">\n";
2921 NodeMapMap &funcIndex = m_qdb->getFunctionIndex();
2922 for (
auto fnMap = funcIndex.constBegin(); fnMap != funcIndex.constEnd(); ++fnMap) {
2923 const QString &key = fnMap.key();
2924 const QChar firstLetter = key.isEmpty() ? QChar(
'A') : key.front();
2925 Q_ASSERT_X(firstLetter.unicode() < 256,
"generateFunctionIndex",
2926 "Only valid C++ identifiers were expected");
2927 const char currentLetter = firstLetter.isLower() ? firstLetter.unicode() : nextLetter - 1;
2929 if (currentLetter < nextLetter) {
2933 while (nextLetter < currentLetter)
2934 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
2935 Q_ASSERT(nextLetter == currentLetter);
2936 out() << QStringLiteral(
"<li id=\"%1\">").arg(nextLetter++);
2938 out() << protectEnc(key) <<
':';
2940 for (
auto it = (*fnMap).constBegin(); it != (*fnMap).constEnd(); ++it) {
2942 generateFullName((*it)->parent(), relative, *it);
2946 while (nextLetter <=
'z')
2947 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
2954 for (
auto it = legaleseTexts.cbegin(), end = legaleseTexts.cend(); it != end; ++it) {
2955 Text text = it.key();
2956 generateText(text, relative, marker);
2960 generateFullName(it.value(), relative);
2963 }
while (it != legaleseTexts.constEnd() && it.key() == text);
2971 QString marked = marker->markedUpQmlItem(node, summary);
2972 marked.replace(
"@param>",
"i>");
2974 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
2975 .arg(summary ?
"summary"_L1 :
"details"_L1));
2976 marked.replace(
"</@extra>",
"</code>");
2980 marked.remove(
"<@name>");
2981 marked.remove(
"</@name>");
2982 marked.remove(
"<@type>");
2983 marked.remove(
"</@type>");
2985 out() << highlightedCode(marked, relative,
false, Genus::QML);
2989
2990
2991
2992
2993
2994
2995
2998 m_qdb->mergeCollections(cn);
3003 if (sortOrder == Qt::DescendingOrder)
3008 for (
const auto *node : std::as_const(members)) {
3009 out() <<
"<li translate=\"no\">";
3010 generateFullName(node,
nullptr);
3018 const QString &selector, Qt::SortOrder sortOrder)
3022 if (selector == QLatin1String(
"overviews"))
3024 else if (selector == QLatin1String(
"cpp-modules"))
3026 else if (selector == QLatin1String(
"qml-modules"))
3030 m_qdb->mergeCollections(type, cnm, relative);
3031 const auto collectionList = cnm.values();
3032 nodeList.reserve(collectionList.size());
3033 for (
auto *collectionNode : collectionList)
3034 nodeList.append(collectionNode);
3035 generateAnnotatedList(relative, marker, nodeList, sortOrder);
3038
3039
3040
3041
3044 QStringLiteral(
"\\generatelist {%1} is only allowed in \\group, "
3045 "\\module and \\qmlmodule comments.")
3049 auto *node =
const_cast<
Node *>(relative);
3050 auto *collectionNode =
static_cast<CollectionNode *>(node);
3051 if (!collectionNode)
3053 m_qdb->mergeCollections(collectionNode);
3054 generateAnnotatedList(collectionNode, marker, collectionNode->members(), sortOrder);
3060 bool alignNames =
true;
3061 if (!nv.isEmpty()) {
3062 bool twoColumn =
false;
3063 if (nv.first()->isProperty()) {
3064 twoColumn = (nv.size() >= 5);
3068 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3071 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3072 <<
"<tr><td class=\"topAlign\">";
3077 for (
const auto &member : nv) {
3080 out() <<
"<tr><td class=\"memItemLeft rightAlign topAlign\"> ";
3082 if (twoColumn && i == (nv.size() + 1) / 2)
3083 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3084 out() <<
"<li class=\"fn\" translate=\"no\">";
3087 generateSynopsis(member, relative, marker, Section::Summary, alignNames);
3089 out() <<
"</td></tr>\n";
3095 out() <<
"</table></div>\n";
3099 out() <<
"</td></tr>\n</table></div>\n";
3107 bool alignNames =
true;
3110 if (!members.isEmpty()) {
3111 bool hasPrivateSignals =
false;
3112 bool isInvokable =
false;
3113 bool twoColumn =
false;
3116 twoColumn = (members.size() >= 16);
3117 }
else if (members.first()->isProperty()) {
3118 twoColumn = (members.size() >= 5);
3122 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3125 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3126 <<
"<tr><td class=\"topAlign\">";
3131 for (
const auto &member : members) {
3134 if (member->name().isEmpty())
3138 out() <<
"<tr><td class=\"memItemLeft topAlign rightAlign\"> ";
3140 if (twoColumn && i == (members.size() + 1) / 2)
3141 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3142 out() <<
"<li class=\"fn\" translate=\"no\">";
3145 generateSynopsis(member, relative, marker, section.style(), alignNames);
3146 if (member->isFunction()) {
3147 const auto *fn =
static_cast<
const FunctionNode *>(member);
3148 if (fn->isPrivateSignal()) {
3149 hasPrivateSignals =
true;
3151 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3152 }
else if (fn->isInvokable()) {
3155 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3159 out() <<
"</td></tr>\n";
3165 out() <<
"</table></div>\n";
3169 out() <<
"</td></tr>\n</table></div>\n";
3172 if (hasPrivateSignals)
3180 && !section.inheritedMembers().isEmpty()) {
3182 generateSectionInheritedList(section, relative);
3189 const QList<std::pair<
const Aggregate *,
int>> &inheritedMembers = section.inheritedMembers();
3190 for (
const auto &member : inheritedMembers) {
3191 out() <<
"<li class=\"fn\" translate=\"no\">";
3192 out() << member.second <<
' ';
3193 if (member.second == 1) {
3194 out() << section.singular();
3196 out() << section.plural();
3198 out() <<
" inherited from <a href=\"" << fileName(member.first) <<
'#'
3199 << Generator::cleanRef(section.title().toLower()) <<
"\">"
3200 << protectEnc(member.first->plainFullName(relative)) <<
"</a></li>\n";
3207 QString marked = marker->markedUpSynopsis(node, relative, style);
3208 marked.replace(
"@param>",
"i>");
3211 marked.remove(
"<@name>");
3212 marked.remove(
"</@name>");
3216 static const QRegularExpression extraRegExp(
"<@extra>.*</@extra>",
3217 QRegularExpression::InvertedGreedinessOption);
3218 marked.remove(extraRegExp);
3220 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3221 .arg(style == Section::Summary ?
"summary"_L1 :
"details"_L1));
3222 marked.replace(
"</@extra>",
"</code>");
3226 marked.remove(
"<@type>");
3227 marked.remove(
"</@type>");
3230 out() << highlightedCode(marked, relative, alignNames);
3233QString
HtmlGenerator::highlightedCode(
const QString &markedCode,
const Node *relative,
3234 bool alignNames, Genus genus)
3236 QString src = markedCode;
3238 html.reserve(src.size());
3242 const QChar charLangle =
'<';
3243 const QChar charAt =
'@';
3245 static const QString typeTag(
"type");
3246 static const QString headerTag(
"headerfile");
3247 static const QString funcTag(
"func");
3248 static const QString linkTag(
"link");
3249 static const QString extrefTag(
"extref");
3252 static const QHash<QString, QString> extrefUrls = {
3253 {
"cpp-explicitly-defaulted"_L1,
3254 "https://en.cppreference.com/w/cpp/language/function#Defaulted_functions"_L1},
3255 {
"cpp-deleted-functions"_L1,
3256 "https://en.cppreference.com/w/cpp/language/function#Deleted_functions"_L1},
3263 for (
int i = 0, srcSize = src.size(); i < srcSize;) {
3264 if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
3265 if (alignNames && !done) {
3266 html += QLatin1String(
"</td><td class=\"memItemRight bottomAlign\">");
3270 if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) {
3271 html += QLatin1String(
"<b>");
3272 const Node *n =
static_cast<
const Node*>(
Utilities::nodeForString(par1.toString()));
3273 QString link = linkForNode(n, relative);
3274 addLink(link, arg, &html);
3275 html += QLatin1String(
"</b>");
3276 }
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
3277 const FunctionNode *fn = m_qdb->findFunctionNode(par1.toString(), relative, genus);
3278 QString link = linkForNode(fn, relative);
3279 addLink(link, arg, &html);
3280 par1 = QStringView();
3281 }
else if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
3282 par1 = QStringView();
3283 const Node *n = m_qdb->findTypeNode(arg.toString(), relative, genus);
3284 html += QLatin1String(
"<span class=\"type\">");
3287 addLink(linkForNode(n, relative), arg, &html);
3291 addLink(linkForNode(n, relative), arg, &html);
3292 html += QLatin1String(
"</span>");
3293 }
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
3294 par1 = QStringView();
3295 if (arg.startsWith(QLatin1Char(
'&')))
3298 const Node *n = m_qdb->findNodeForInclude(QStringList(arg.toString()));
3299 if (n && n != relative)
3300 addLink(linkForNode(n, relative), arg, &html);
3304 }
else if (parseArg(src, extrefTag, &i, srcSize, &arg, &par1)) {
3305 QString url = extrefUrls.value(par1.toString());
3307 addLink(url, arg, &html);
3315 html += src.at(i++);
3324 html.reserve(src.size());
3327 QLatin1StringView tag;
3328 QLatin1StringView span;
3330 static constexpr SpanTag spanTags[] = {
3331 {
"comment>"_L1,
"<span class=\"comment\">"_L1},
3332 {
"preprocessor>"_L1,
"<span class=\"preprocessor\">"_L1},
3333 {
"string>"_L1,
"<span class=\"string\">"_L1},
3334 {
"char>"_L1,
"<span class=\"char\">"_L1},
3335 {
"number>"_L1,
"<span class=\"number\">"_L1},
3336 {
"op>"_L1,
"<span class=\"operator\">"_L1},
3337 {
"type>"_L1,
"<span class=\"type\">"_L1},
3338 {
"name>"_L1,
"<span class=\"name\">"_L1},
3339 {
"keyword>"_L1,
"<span class=\"keyword\">"_L1},
3340 {
"template-block>"_L1,
"<span class=\"template-block\">"_L1},
3344 const qsizetype n = src.size();
3345 const QStringView sv(src);
3347 if (sv.at(i) ==
'<'_L1) {
3348 if (i + 1 < n && sv.at(i + 1) ==
'@'_L1) {
3350 bool handled =
false;
3351 for (
const auto &st : spanTags) {
3352 if (i + st.tag.size() <= n
3353 && st.tag == sv.sliced(i, st.tag.size())) {
3362 while (i < n && sv.at(i) !=
'>'_L1)
3368 }
else if (i + 2 < n && sv.at(i + 1) ==
'/'_L1 && sv.at(i + 2) ==
'@'_L1) {
3370 bool handled =
false;
3371 for (
const auto &st : spanTags) {
3372 if (i + st.tag.size() <= n
3373 && st.tag == sv.sliced(i, st.tag.size())) {
3374 html +=
"</span>"_L1;
3382 while (i < n && sv.at(i) !=
'>'_L1)
3400 if (m_linkNode && m_linkNode->isFunction()) {
3402 if (match.hasMatch()) {
3404 qsizetype leftParenLoc = match.capturedStart(1);
3405 out() << protectEnc(atom->string().left(leftParenLoc));
3407 out() << protectEnc(atom->string().mid(leftParenLoc));
3411 out() << protectEnc(atom->string());
3416 return protect(string);
3421 if (string.isEmpty())
3425 if (html.isEmpty()) {
3432 qsizetype n = string.size();
3434 for (
int i = 0; i < n; ++i) {
3435 QChar ch = string.at(i);
3437 if (ch == QLatin1Char(
'&')) {
3439 }
else if (ch == QLatin1Char(
'<')) {
3441 }
else if (ch == QLatin1Char(
'>')) {
3443 }
else if (ch == QChar(8211)) {
3445 }
else if (ch == QChar(8212)) {
3447 }
else if (ch == QLatin1Char(
'"')) {
3450 if (!html.isEmpty())
3455 if (!html.isEmpty())
3464 QString result = Generator::fileBase(node);
3466 result += QLatin1String(
"-obsolete");
3473 return node->name();
3474 return Generator::fileName(node);
3478 const Node *actualNode)
3480 if (actualNode ==
nullptr)
3481 actualNode = apparentNode;
3482 bool link = !linkForNode(actualNode, relative).isEmpty();
3484 out() <<
"<a href=\"" << linkForNode(actualNode, relative);
3486 out() <<
"\" class=\"obsolete";
3489 out() << protectEnc(apparentNode->fullName(relative));
3495
3496
3497
3504 const auto srcLink = Config::instance().getSourceLink();
3505 if (!srcLink.enabled)
3510 if (loc
.isEmpty() || srcLink.baseUrl.isEmpty() || srcLink.rootPath.isEmpty())
3513 QString srcUrl{srcLink.baseUrl};
3514 if (!srcUrl.contains(
'\1'_L1)) {
3515 if (!srcUrl.endsWith(
'/'_L1))
3520 QDir rootDir{srcLink.rootPath};
3521 srcUrl.replace(
'\1'_L1, rootDir.relativeFilePath(loc.filePath()));
3522 srcUrl.replace(
'\2'_L1, QString::number(loc.lineNo()));
3523 const auto &description{
"View declaration of this %1"_L1.arg(node->nodeTypeString())};
3524 out() <<
"<a class=\"srclink\" href=\"%1\" title=\"%2\">%3</a>"_L1
3525 .arg(srcUrl, description, srcLink.linkText);
3532 generateExtractionMark(node, MemberMark);
3533 QString nodeRef =
nullptr;
3536 const QList<Node *> &collective = scn->collective();
3537 if (collective.size() > 1)
3538 out() <<
"<div class=\"fngroup\">\n";
3539 for (
const auto *sharedNode : collective) {
3540 out() << headingStart.arg(getClassAttr(sharedNode,
"fn fngroupitem"_L1),
3541 refForNode(sharedNode));
3542 generateSynopsis(sharedNode, relative, marker, Section::Details);
3543 generateSourceLink(sharedNode);
3544 out() << headingEnd;
3546 if (collective.size() > 1)
3550 if (node->isEnumType(Genus::CPP) && (etn =
static_cast<
const EnumNode *>(node))->flagsType()) {
3551 out() << headingStart.arg(getClassAttr(node,
"flags"_L1), refForNode(node));
3555 generateSourceLink(node);
3556 out() << headingEnd;
3558 out() << headingStart.arg(getClassAttr(node,
"fn"_L1), refForNode(node));
3560 generateSourceLink(node);
3561 out() << headingEnd;
3568 const auto *func =
static_cast<
const FunctionNode *>(node);
3569 if (func->hasOverloads() && (func->isSignal() || func->isSlot()))
3578 const auto property =
static_cast<
const PropertyNode *>(node);
3588 out() <<
"<p><b>Access functions:</b></p>\n";
3589 generateSectionList(section, node, marker);
3596 out() <<
"<p><b>Notifier signal:</b></p>\n";
3597 generateSectionList(notifiers, node, marker);
3601 const auto *enumTypeNode =
static_cast<
const EnumNode *>(node);
3602 if (enumTypeNode->flagsType()) {
3603 out() <<
"<p>The " << protectEnc(enumTypeNode->flagsType()->name())
3604 <<
" type is a typedef for "
3605 <<
"<a href=\"" << m_qflagsHref <<
"\">QFlags</a><"
3606 << protectEnc(enumTypeNode->name()) <<
">. It stores an OR combination of "
3607 << protectEnc(enumTypeNode->name()) <<
" values.</p>\n";
3610 generateAlsoList(node, marker);
3611 generateExtractionMark(node, EndMark);
3615
3616
3617
3618
3623 m_linkNode =
nullptr;
3625 if (!m_link.isEmpty())
3626 out() <<
"<a href=\"" << m_link <<
"\" translate=\"no\">";
3634 if (m_link.isEmpty())
3637 const QString &translate_attr =
3638 (node && isApiGenus(node->genus())) ?
" translate=\"no\""_L1 :
""_L1;
3640 if (node ==
nullptr || (relative !=
nullptr && node->status() == relative->status()))
3641 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3642 else if (node->isDeprecated())
3643 out() <<
"<a href=\"" << m_link <<
"\" class=\"obsolete\"%1>"_L1.arg(translate_attr);
3645 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3654 m_linkNode =
nullptr;
3656 if (!m_link.isEmpty())
3661
3662
3663
3667 if (!members.isEmpty()) {
3669 for (
const auto &member : members) {
3670 out() <<
"<li class=\"fn\" translate=\"no\">";
3671 generateQmlItem(member, relative, marker,
true);
3672 if (member->isPropertyGroup()) {
3673 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
3674 if (scn->count() > 0) {
3676 const QList<Node *> &sharedNodes = scn->collective();
3677 for (
const auto &node : sharedNodes) {
3678 if (node->isQmlProperty()) {
3679 out() <<
"<li class=\"fn\" translate=\"no\">";
3680 generateQmlItem(node, relative, marker,
true);
3694
3695
3698 out() << headingStart.arg(getClassAttr(scn,
"fn qml-member qml-property-group"_L1),
3700 <<
"<b>" << scn->name() <<
" group</b>"
3705
3706
3707
3711 generateExtractionMark(node, MemberMark);
3713 auto generateQmlProperty = [&](
Node *n,
bool isGroupItem =
false) {
3714 const auto cssClasses = isGroupItem ?
"fn qml-member qml-property fngroupitem"_L1 :
"fn qml-member qml-property"_L1;
3715 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3716 generateQmlItem(n, relative, marker,
false);
3717 generateSourceLink(n);
3718 out() << headingEnd;
3721 auto generateQmlMethod = [&](
Node *n,
bool isGroupItem =
false) {
3722 const auto cssClasses = isGroupItem ?
"fn qml-member qml-method fngroupitem"_L1 :
"fn qml-member qml-method"_L1;
3723 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3725 generateSourceLink(n);
3726 out() << headingEnd;
3730 auto *scn =
static_cast<
const SharedCommentNode *>(node);
3731 const auto shared = scn->collective();
3733 if (scn->isPropertyGroup() && !scn->name().isEmpty())
3734 emitGroupHeader(scn);
3736 const bool isGroup = shared.size() > 1;
3739 out() <<
"<div class=\"fngroup\">\n"_L1;
3741 for (
auto *child : std::as_const(shared)) {
3742 if (child->isQmlProperty())
3743 generateQmlProperty(child, isGroup);
3745 generateQmlMethod(child, isGroup);
3749 out() <<
"</div>"_L1;
3752 generateQmlProperty(node);
3754 generateQmlMethod(node);
3761 generateAlsoList(node, marker);
3762 generateExtractionMark(node, EndMark);
3765void HtmlGenerator::generateExtractionMark(
const Node *node, ExtractionMarkType markType)
3767 if (markType != EndMark) {
3768 out() <<
"<!-- $$$" + node->name();
3769 if (markType == MemberMark) {
3771 const auto *func =
static_cast<
const FunctionNode *>(node);
3772 if (!func->hasAssociatedProperties()) {
3773 if (func->overloadNumber() == 0)
3774 out() <<
"[overload1]";
3775 out() <<
"$$$" + func->name() + func->parameters().rawSignature().remove(
' ');
3779 const auto *prop =
static_cast<
const PropertyNode *>(node);
3780 const NodeList &list = prop->functions();
3781 for (
const auto *propFuncNode : list) {
3782 if (propFuncNode->isFunction()) {
3783 const auto *func =
static_cast<
const FunctionNode *>(propFuncNode);
3784 out() <<
"$$$" + func->name()
3785 + func->parameters().rawSignature().remove(
' ');
3789 const auto *enumNode =
static_cast<
const EnumNode *>(node);
3790 const auto &items = enumNode->items();
3791 for (
const auto &item : items)
3792 out() <<
"$$$" + item.name();
3794 }
else if (markType == BriefMark) {
3796 }
else if (markType == DetailedDescriptionMark) {
3797 out() <<
"-description";
3801 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 const Atom closeCodeTag
static void addLink(const QString &linkTarget, QStringView nestedStuff, QString *res)
static const auto headingStart
static const auto headingEnd
static const Atom openCodeTag
#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
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 isExample() const
Returns true if the node type is Example.
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
Represents a file that is reachable by QDoc based on its current configuration.