29#include <QtCore/qlist.h>
30#include <QtCore/qmap.h>
31#include <QtCore/quuid.h>
32#include <QtCore/qversionnumber.h>
33#include <QtCore/qregularexpression.h>
41using namespace Qt::StringLiterals;
48static const auto headingStart =
"<h3 class=\"%1\" translate=\"no\" id=\"%2\">"_L1;
53static void addLink(
const QString &linkTarget, QStringView nestedStuff, QString *res)
55 if (!linkTarget.isEmpty()) {
56 *res += QLatin1String(
"<a href=\"");
58 *res += QLatin1String(
"\" translate=\"no\">");
60 *res += QLatin1String(
"</a>");
67
68
69
70
73 auto result{classSet};
74 if (node->isInternal())
75 result +=
" internal"_L1;
80
81
82
85 if (!s_inUnorderedList) {
87 s_inUnorderedList =
true;
92
93
94
97 if (s_inUnorderedList) {
99 s_inUnorderedList =
false;
104
105
106
109 if (m_helpProjectWriter) {
110 delete m_helpProjectWriter;
111 m_helpProjectWriter =
nullptr;
114 if (m_manifestWriter) {
115 delete m_manifestWriter;
116 m_manifestWriter =
nullptr;
121
122
123
143 {
nullptr,
nullptr,
nullptr } };
146 config = &Config::instance();
149
150
151
152 for (
int i = 0; defaults[i].key; ++i) {
153 formattingLeftMap().insert(QLatin1String(defaults[i].key), QLatin1String(defaults[i].left));
154 formattingRightMap().insert(QLatin1String(defaults[i].key),
155 QLatin1String(defaults[i].right));
158 QString formatDot{HtmlGenerator::format() + Config::dot};
159 m_endHeader = config->get(formatDot +
CONFIG_ENDHEADER).asString(
"</head>\n<body>\n"_L1);
173 .asString(m_project +
" Reference Documentation"_L1);
175 m_projectUrl = config->get(
CONFIG_URL).asString();
184
185
186
187 if (m_helpProjectWriter)
188 m_helpProjectWriter->reset(m_project.toLower() +
".qhp",
this);
190 m_helpProjectWriter =
new HelpProjectWriter(m_project.toLower() +
".qhp",
this);
192 if (!m_manifestWriter)
205 .asString(m_homepage);
212 .asString(m_landingpage);
219 .asString(
"C++ Classes"_L1);
226 .asString(
"QML Types"_L1);
235
236
248
249
250
251
252
253
254
260 Node *qflags = m_qdb->findClassNode(QStringList(
"QFlags"_L1));
262 m_qflagsHref = linkForNode(qflags,
nullptr);
266 const QString fileBase =
"%1/%2"_L1.arg(
268 m_project.toLower().simplified().replace(
' '_L1,
'-'_L1)
275 const QString &rootTitle = m_landingpage.isEmpty() ? m_homepage : m_landingpage;
276 tocWriter
.generateTOC(
"%1_toc.xml"_L1.arg(fileBase), rootTitle);
278
279
280 if (!tagFile_.isEmpty()) {
288
289
292 SubTitleSize subTitleSize = LargeSubTitle;
293 QString fullTitle = en->fullTitle();
295 beginSubPage(en, linkForExampleFile(resolved_file.get_query()));
296 generateHeader(fullTitle, en, marker);
297 generateTitle(en
->doc().title(),
Text() << en->subtitle(), subTitleSize, en, marker);
302 QString code = quoter.quoteTo(en->location(), QString(), QString());
303 CodeMarker *codeMarker = CodeMarker::markerForFileName(resolved_file.get_path());
307 generateText(text, en, codeMarker);
312
313
316 qsizetype idx, skipAhead = 0;
317 static bool in_para =
false;
318 Genus genus = Genus::DontCare;
322 QString name = atom->string();
323 if (relative && relative->name() == name.replace(QLatin1String(
"()"), QLatin1String())) {
324 out() << protectEnc(atom->string());
332 if (!m_inLink && !m_inContents && !m_inSectionHeading) {
333 const Node *node =
nullptr;
334 QString link = getAutoLink(atom, relative, &node, genus);
335 if (link.isEmpty()) {
340 QStringLiteral(
"Can't autolink to '%1'").arg(atom->string()));
345 if (link.isEmpty()) {
346 out() << protectEnc(atom->string());
348 beginLink(link, node, relative);
353 out() << protectEnc(atom->string());
360 skipAhead = skipAtoms(atom, Atom::BriefRight);
375 out() << protectEnc(plainCode(atom->string()));
379 out() <<
"<p class=\"figCaption\">";
390 out() <<
"<pre class=\"qml\" translate=\"no\"><code class=\"qml\">"
391 << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative,
393 m_codePrefix, m_codeSuffix)
394 <<
"</code></pre>\n";
398 if (atom->strings().count() == 2)
399 out() <<
"<pre class=\"" << atom->string(1) <<
"\" translate=\"no\"><code class=\"" << atom->string(1) <<
"\">";
401 out() <<
"<pre class=\"cpp\" translate=\"no\"><code class=\"cpp\">";
403 out() << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative),
404 m_codePrefix, m_codeSuffix)
405 <<
"</code></pre>\n";
408 out() <<
"<pre class=\"cpp plain\" translate=\"no\"><code class=\"text\">"
409 << trimmedTrailing(protectEnc(plainCode(indent(m_codeIndent, atom->string()))),
410 m_codePrefix, m_codeSuffix)
411 <<
"</code></pre>\n";
414 out() <<
"<details>\n";
416 out() <<
"<summary>...</summary>\n";
419 out() <<
"<summary>";
422 out() <<
"</summary>\n";
425 out() <<
"</details>\n";
429 if (!atom->string().isEmpty())
430 out() <<
' ' << atom->string();
453 if (atom->string().startsWith(
"span "))
454 out() <<
'<' + atom->string() <<
'>';
456 out() << formattingLeftMap()[atom->string()];
464 const Node *node{
nullptr};
465 const Atom tm_link(Atom::NavLink, m_trademarkspage);
466 if (
const auto &link = getLink(&tm_link, relative, &node);
467 !link.isEmpty() && node != relative)
468 out() <<
"<a href=\"%1\">%2</a>"_L1.arg(link, formattingRightMap()[atom->string()]);
470 out() << formattingRightMap()[atom->string()];
473 }
else if (atom->string().startsWith(
"span ")) {
476 out() << formattingRightMap()[atom->string()];
480 if (
const auto *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group); cn)
481 generateList(cn, marker, atom->string(), Generator::sortOrder(atom->strings().last()));
484 const auto sortOrder{Generator::sortOrder(atom->strings().last())};
485 if (atom->string() == QLatin1String(
"annotatedclasses")) {
486 generateAnnotatedList(relative, marker, m_qdb->getCppClasses().values(), sortOrder);
487 }
else if (atom->string() == QLatin1String(
"annotatedexamples")) {
488 generateAnnotatedLists(relative, marker, m_qdb->getExamples());
489 }
else if (atom->string() == QLatin1String(
"annotatedattributions")) {
490 generateAnnotatedLists(relative, marker, m_qdb->getAttributions());
491 }
else if (atom->string() == QLatin1String(
"classes")) {
492 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true,
494 }
else if (atom->string().contains(
"classes ")) {
495 QString rootName = atom->string().mid(atom->string().indexOf(
"classes") + 7).trimmed();
496 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true, rootName);
497 }
else if (atom->string() == QLatin1String(
"qmlvaluetypes")
498 || atom->string() == QLatin1String(
"qmlbasictypes")) {
499 generateCompactList(Generic, relative, m_qdb->getQmlValueTypes(),
true,
501 }
else if (atom->string() == QLatin1String(
"qmltypes")) {
502 generateCompactList(Generic, relative, m_qdb->getQmlTypes(),
true, QStringLiteral(
""));
503 }
else if ((idx = atom->string().indexOf(QStringLiteral(
"bymodule"))) != -1) {
505 QString moduleName = atom->string().mid(idx + 8).trimmed();
507 if (
const auto *cn = qdb->getCollectionNode(moduleName, moduleType)) {
509 switch (moduleType) {
513 generateAnnotatedList(relative, marker, map.values(), sortOrder);
516 if (atom->string().contains(QLatin1String(
"qmlvaluetypes")))
520 generateAnnotatedList(relative, marker, map.values(), sortOrder);
523 generateAnnotatedList(relative, marker, cn->members(), sortOrder);
527 }
else if (atom->string() == QLatin1String(
"classhierarchy")) {
528 generateClassHierarchy(relative, m_qdb->getCppClasses());
529 }
else if (atom->string() == QLatin1String(
"obsoleteclasses")) {
530 generateCompactList(Generic, relative, m_qdb->getObsoleteClasses(),
false,
531 QStringLiteral(
"Q"));
532 }
else if (atom->string() == QLatin1String(
"obsoleteqmltypes")) {
533 generateCompactList(Generic, relative, m_qdb->getObsoleteQmlTypes(),
false,
535 }
else if (atom->string() == QLatin1String(
"obsoletecppmembers")) {
536 generateCompactList(Obsolete, relative, m_qdb->getClassesWithObsoleteMembers(),
false,
537 QStringLiteral(
"Q"));
538 }
else if (atom->string() == QLatin1String(
"obsoleteqmlmembers")) {
539 generateCompactList(Obsolete, relative, m_qdb->getQmlTypesWithObsoleteMembers(),
false,
541 }
else if (atom->string() == QLatin1String(
"functionindex")) {
542 generateFunctionIndex(relative);
543 }
else if (atom->string() == QLatin1String(
"attributions")) {
544 generateAnnotatedList(relative, marker, m_qdb->getAttributions().values(), sortOrder);
545 }
else if (atom->string() == QLatin1String(
"legalese")) {
546 generateLegaleseList(relative, marker);
547 }
else if (atom->string() == QLatin1String(
"overviews")) {
548 generateList(relative, marker,
"overviews", sortOrder);
549 }
else if (atom->string() == QLatin1String(
"cpp-modules")) {
550 generateList(relative, marker,
"cpp-modules", sortOrder);
551 }
else if (atom->string() == QLatin1String(
"qml-modules")) {
552 generateList(relative, marker,
"qml-modules", sortOrder);
553 }
else if (atom->string() == QLatin1String(
"namespaces")) {
554 generateAnnotatedList(relative, marker, m_qdb->getNamespaces().values(), sortOrder);
555 }
else if (atom->string() == QLatin1String(
"related")) {
556 generateList(relative, marker,
"related", sortOrder);
558 const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group);
560 if (!generateGroupList(
const_cast<CollectionNode *>(cn), sortOrder))
562 QString(
"'\\generatelist %1' group is empty").arg(atom->string()));
565 QString(
"'\\generatelist %1' no such group").arg(atom->string()));
570 const NodeMultiMap &nsmap = m_qdb->getSinceMap(atom->string());
574 const NodeMultiMap &ncmap = m_qdb->getClassMap(atom->string());
575 const NodeMultiMap &nqcmap = m_qdb->getQmlTypeMap(atom->string());
580 for (
const auto §ion : sinceSections) {
581 if (!section.members().isEmpty()) {
583 <<
"<a href=\"#" << Utilities::asAsciiPrintable(section.title()) <<
"\">"
584 << section.title() <<
"</a></li>\n";
590 for (
const auto §ion : sinceSections) {
591 if (!section.members().isEmpty()) {
592 out() <<
"<h3 id=\"" << Utilities::asAsciiPrintable(section.title()) <<
"\">"
593 << protectEnc(section.title()) <<
"</h3>\n";
594 if (index == Sections::SinceClasses)
595 generateCompactList(Generic, relative, ncmap,
false, QStringLiteral(
"Q"));
596 else if (index == Sections::SinceQmlTypes)
597 generateCompactList(Generic, relative, nqcmap,
false, QStringLiteral(
""));
598 else if (index == Sections::SinceMemberFunctions
599 || index == Sections::SinceQmlMethods
600 || index == Sections::SinceQmlProperties) {
602 QMap<QString, NodeMultiMap> parentmaps;
604 const QList<Node *> &members = section.members();
605 for (
const auto &member : members) {
606 QString parent_full_name = (*member).parent()->fullName();
608 auto parent_entry = parentmaps.find(parent_full_name);
609 if (parent_entry == parentmaps.end())
610 parent_entry = parentmaps.insert(parent_full_name, NodeMultiMap());
611 parent_entry->insert(member->name(), member);
614 for (
auto map = parentmaps.begin(); map != parentmaps.end(); ++map) {
615 NodeVector nv = map->values().toVector();
616 auto parent = nv.front()->parent();
618 out() << ((index == Sections::SinceMemberFunctions) ?
"<p>Class " :
"<p>QML Type ");
620 out() <<
"<a href=\"" << linkForNode(parent, relative) <<
"\" translate=\"no\">";
621 QStringList pieces = parent->fullName().split(
"::");
622 out() << protectEnc(pieces.last());
626 generateSection(nv, relative, marker);
629 }
else if (index == Sections::SinceEnumValues) {
630 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
631 const auto map_it = m_qdb->newEnumValueMaps().constFind(atom->string());
632 for (
auto it = map_it->cbegin(); it != map_it->cend(); ++it) {
633 out() <<
"<tr><td class=\"memItemLeft\"> enum value </td><td class=\"memItemRight\">"
634 <<
"<b><a href=\"" << linkForNode(it.value(),
nullptr) <<
"\">"
635 << it.key() <<
"</a></b></td></tr>\n";
637 out() <<
"</table></div>\n";
639 generateSection(section.members(), relative, marker);
657 out() <<
"<p class=\"centerAlign\">";
659 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
660 if (!maybe_resolved_file) {
663 QStringLiteral(
"Missing image: %1").arg(protectEnc(atom->string())));
664 out() <<
"<font color=\"red\">[Missing image " << protectEnc(atom->string())
668 QString file_name{QFileInfo{file.get_path()}.fileName()};
688 "%1/%2"_L1.arg(outputDir(), imagesOutputDir()));
690 const auto &imgPath =
"%1/%2"_L1.arg(imagesOutputDir(), file_name);
692 out() <<
"<img src=\"%1\""_L1.arg(protectEnc(imgPath));
694 const QString altAndTitleText = protectEnc(text);
695 out() <<
" alt=\"" << altAndTitleText;
697 out() <<
"\" title=\"" << altAndTitleText;
701 m_helpProjectWriter->addExtraFile(imgPath);
702 setImageFileName(relative, imgPath);
714 QString admonType = atom->typeString();
717 out() <<
"<div class=\"admonition " << admonType.toLower() <<
"\">\n"
720 out() << admonType <<
": ";
730 out() <<
"<div class=\"LegaleseLeft\">";
744 const Node *node =
nullptr;
745 QString link = getLink(atom, relative, &node);
747 Location location = atom->isLinkAtom() ?
static_cast<
const LinkAtom*>(atom)->location
748 : relative->doc().location();
750 QStringLiteral(
"Can't link to '%1'").arg(atom->string()));
752 beginLink(link, node, relative);
756 QString link = linkForExampleFile(atom->string());
761 QString link = atom->string();
762 link =
"images/used-in-examples/" + link;
767 const Node *node =
static_cast<
const Node*>(
Utilities::nodeForString(atom->string()));
768 beginLink(linkForNode(node, relative), node, relative);
781 out() << R"(<div class="table"><table class="valuelist">)";
782 m_threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom);
783 if (m_threeColumnEnumValueTable) {
784 if (++m_numTableRows % 2 == 1)
785 out() << R"(<tr valign="top" class="odd">)";
787 out() << R"(<tr valign="top" class="even">)";
789 out() <<
"<th class=\"tblConst\">Constant</th>";
793 out() <<
"<th class=\"tblval\">Value</th>";
795 out() <<
"<th class=\"tbldscr\">Description</th></tr>\n";
797 out() <<
"<tr><th class=\"tblConst\">Constant</th><th "
798 "class=\"tblVal\">Value</th></tr>\n";
815 out() << QString(R"(<ol class="%1" type="%1" start="%2">)")
816 .arg(olType, atom
->next()->string());
818 out() << QString(R"(<ol class="%1" type="%1">)").arg(olType);
827 std::pair<QString,
int> pair = getAtomListValue(atom);
828 skipAhead = pair.second;
829 QString t = protectEnc(plainCode(marker->markedUpEnumValue(pair.first, relative)));
830 out() <<
"<tr><td class=\"topAlign\"><code translate=\"no\">" << t <<
"</code>";
833 out() <<
"</td><td class=\"topAlign tblval\">";
834 const auto *enume =
static_cast<
const EnumNode *>(relative);
835 QString itemValue = enume->itemValue(atom->next()->string());
836 if (itemValue.isEmpty())
839 out() <<
"<code translate=\"no\">" << protectEnc(itemValue) <<
"</code>";
852 if (m_threeColumnEnumValueTable) {
853 out() <<
"</td><td class=\"topAlign\">";
860 if (matchAhead(atom, Atom::ParaLeft))
867 out() <<
"</td></tr>\n";
878 out() <<
"</table></div>\n";
899 out() <<
"<blockquote>";
902 out() <<
"</blockquote>\n";
905 out() << atom->string();
911 int unit = atom->string().toInt() +
hOffset(relative
);
912 out() <<
"<h" + QString::number(unit) + QLatin1Char(
' ') <<
"id=\""
913 << Tree::refForAtom(atom) <<
"\">";
914 m_inSectionHeading =
true;
917 case Atom::SectionHeadingRight:
918 out() <<
"</h" + QString::number(atom->string().toInt() + hOffset(relative)) +
">\n";
919 m_inSectionHeading =
false;
926 if (m_inLink && !m_inContents && !m_inSectionHeading) {
929 out() << protectEnc(atom->string());
933 std::pair<QString, QString> pair = getTableWidthAttr(atom);
934 QString attr = pair.second;
935 QString width = pair.first;
942 out() << R"(<div class="table"><table class=")" << attr <<
'"';
943 if (!width.isEmpty())
944 out() <<
" style=\"width: " << width <<
'"';
949 out() <<
"</table></div>\n";
952 out() <<
"<thead><tr class=\"qt-style\">";
953 m_inTableHeader =
true;
959 out() <<
"\n<tr class=\"qt-style\">";
961 out() <<
"</thead>\n";
962 m_inTableHeader =
false;
966 if (!atom->string().isEmpty())
967 out() <<
"<tr " << atom->string() <<
'>';
968 else if (++m_numTableRows % 2 == 1)
969 out() << R"(<tr valign="top" class="odd">)";
971 out() << R"(<tr valign="top" class="even">)";
982 for (
int i = 0; i < atom->count(); ++i) {
985 const QString &p = atom->string(i);
986 if (p.contains(
'=')) {
989 QStringList spans = p.split(QLatin1Char(
','));
990 if (spans.size() == 2) {
991 if (spans.at(0) !=
"1")
992 out() <<
" colspan=\"" << spans.at(0) <<
'"';
993 if (spans.at(1) !=
"1")
994 out() <<
" rowspan=\"" << spans.at(1) <<
'"';
999 if (matchAhead(atom, Atom::ParaLeft))
1003 if (m_inTableHeader)
1008 if (matchAhead(atom, Atom::ParaLeft))
1018 out() <<
"<span id=\"" <<
Utilities::asAsciiPrintable(atom->string()) <<
"\"></span>";
1021 out() <<
"<b class=\"redFont\"><Missing HTML></b>";
1023 case Atom::UnknownCommand:
1024 out() << R"(<b class="redFont"><code translate=\"no\">\)" << protectEnc(atom->string()) <<
"</code></b>";
1042
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
1072 auto link_for_group = [
this](
const CollectionNode *group) -> QString {
1073 QString target{linkForNode(group,
nullptr)};
1074 return (target.isEmpty()) ? protectEnc(group->name()) :
"<a href=\"" + target +
"\">" + protectEnc(group->fullTitle()) +
"</a>";
1079 const QStringList &groups_names{node->groupNames()};
1080 if (groups_names.isEmpty())
1083 std::vector<CollectionNode *> groups_nodes(groups_names.size(),
nullptr);
1084 std::transform(groups_names.cbegin(), groups_names.cend(), groups_nodes.begin(),
1087 m_qdb->mergeCollections(group);
1088 return (group && group
->wasSeen()) ? group :
nullptr;
1090 groups_nodes.erase(
std::remove(groups_nodes.begin(), groups_nodes.end(),
nullptr), groups_nodes.end());
1092 if (!groups_nodes.empty()) {
1093 text += node->name() +
" is part of ";
1095 for (std::vector<CollectionNode *>::size_type index{0}; index < groups_nodes.size(); ++index) {
1096 text += link_for_group(groups_nodes[index]) + Utilities::separator(index, groups_nodes.size());
1103
1104
1105
1106
1117 QString typeWord = aggregate->typeWord(
true);
1120 fullTitle = aggregate->plainFullName();
1121 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1122 ns =
static_cast<NamespaceNode *>(aggregate);
1124 fullTitle = aggregate->plainFullName();
1125 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1127 title = fullTitle = aggregate->fullTitle();
1128 if (!aggregate->doc().title().isEmpty())
1129 titleText << aggregate->name() <<
" - "_L1 << aggregate->doc().title();
1134 if (aggregate
->parent()->isInAPI() || templateDecl) {
1136 subtitleText <<
"%1 "_L1.arg((*templateDecl).to_qstring());
1137 subtitleText << aggregate->typeWord(
false) <<
" "_L1;
1138 auto ancestors = fullTitle.split(
"::"_L1);
1139 ancestors.pop_back();
1140 for (
const auto &a : ancestors)
1141 subtitleText << Atom(Atom::AutoLink, a) <<
"::"_L1;
1142 subtitleText << aggregate->plainName();
1145 generateHeader(title, aggregate, marker);
1146 generateTableOfContents(aggregate, marker, &summarySections);
1148 generateTitle(titleText, subtitleText, SmallSubTitle, aggregate, marker);
1150 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1154 brief <<
"The " << ns->name() <<
" namespace includes the following elements from module "
1157 addNodeLink(brief, fullNamespace,
" here.");
1159 generateText(brief, ns, marker);
1162 generateBrief(aggregate, marker);
1164 const auto parentIsClass = aggregate
->parent()->isClassNode();
1167 generateRequisites(aggregate, marker);
1172 QString membersLink = generateAllMembersFile(sections.allMembersSection(), marker);
1173 if (!membersLink.isEmpty()) {
1174 openUnorderedList();
1175 out() <<
"<li><a href=\"" << membersLink <<
"\">"
1176 <<
"List of all members, including inherited members</a></li>\n";
1178 QString obsoleteLink = generateObsoleteMembersFile(sections, marker);
1179 if (!obsoleteLink.isEmpty()) {
1180 openUnorderedList();
1181 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1182 <<
"Deprecated members</a></li>\n";
1185 if (QString groups_text{groupReferenceText(aggregate)}; !groups_text.isEmpty()) {
1186 openUnorderedList();
1188 out() <<
"<li>" << groups_text <<
"</li>\n";
1191 closeUnorderedList();
1196 bool needOtherSection =
false;
1198 for (
const auto §ion : summarySections) {
1199 if (section.members().isEmpty() && section.reimplementedMembers().isEmpty()) {
1200 if (!section.inheritedMembers().isEmpty())
1201 needOtherSection =
true;
1203 if (!section.members().isEmpty()) {
1204 QString ref = registerRef(section.title().toLower());
1205 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1206 generateSection(section.members(), aggregate, marker);
1208 if (!section.reimplementedMembers().isEmpty()) {
1209 QString name = QString(
"Reimplemented ") + section.title();
1210 QString ref = registerRef(name.toLower());
1211 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(name) <<
"</h2>\n";
1212 generateSection(section.reimplementedMembers(), aggregate, marker);
1215 if (!section.inheritedMembers().isEmpty()) {
1217 generateSectionInheritedList(section, aggregate);
1223 if (needOtherSection) {
1224 out() <<
"<h3>Additional Inherited Members</h3>\n"
1227 for (
const auto §ion : summarySections) {
1228 if (section.members().isEmpty() && !section.inheritedMembers().isEmpty())
1229 generateSectionInheritedList(section, aggregate);
1234 if (aggregate
->doc().isEmpty()) {
1235 QString command =
"documentation";
1237 command = R"('\class' comment)";
1240 QStringLiteral(
"No %1 for '%2'").arg(command, aggregate->plainSignature()));
1243 generateExtractionMark(aggregate, DetailedDescriptionMark);
1244 out() <<
"<div class=\"descr\">\n"
1245 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1246 <<
"Detailed Description"
1249 out() <<
"</div>\n";
1250 generateAlsoList(aggregate, marker);
1251 generateExtractionMark(aggregate, EndMark);
1254 for (
const auto §ion : detailsSections) {
1255 bool headerGenerated =
false;
1256 if (section.isEmpty())
1259 const QList<Node *> &members = section.members();
1260 for (
const auto &member : members) {
1261 if (!headerGenerated) {
1262 if (!section.divClass().isEmpty())
1263 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1264 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1265 headerGenerated =
true;
1267 if (!member->isClassNode())
1268 generateDetailedMember(member, aggregate, marker);
1271 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1272 out() <<
" class=\"%1\""_L1.arg(attrs);
1273 out() <<
"> class ";
1274 generateFullName(member, aggregate);
1276 generateBrief(member, marker, aggregate);
1279 if (headerGenerated && !section.divClass().isEmpty())
1280 out() <<
"</div>\n";
1282 generateFooter(aggregate);
1295 QString rawTitle = aggregate->plainName();
1296 QString fullTitle = aggregate->plainFullName();
1297 QString title = rawTitle +
" Proxy Page";
1298 generateHeader(title, aggregate, marker);
1299 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1300 generateBrief(aggregate, marker);
1301 for (
const auto §ion : summarySections) {
1302 if (!section.members().isEmpty()) {
1303 QString ref = registerRef(section.title().toLower());
1304 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1305 generateSection(section.members(), aggregate, marker);
1309 if (!aggregate
->doc().isEmpty()) {
1310 generateExtractionMark(aggregate, DetailedDescriptionMark);
1311 out() <<
"<div class=\"descr\">\n"
1312 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1313 <<
"Detailed Description"
1316 out() <<
"</div>\n";
1317 generateAlsoList(aggregate, marker);
1318 generateExtractionMark(aggregate, EndMark);
1321 for (
const auto §ion : detailsSections) {
1322 if (section.isEmpty())
1325 if (!section.divClass().isEmpty())
1326 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1327 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1329 const QList<Node *> &members = section.members();
1330 for (
const auto &member : members) {
1331 if (!member->isClassNode()) {
1332 generateDetailedMember(member, aggregate, marker);
1335 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1336 out() <<
" class=\"%1\""_L1.arg(attrs);
1337 out() <<
"> class ";
1338 generateFullName(member, aggregate);
1340 generateBrief(member, marker, aggregate);
1343 if (!section.divClass().isEmpty())
1344 out() <<
"</div>\n";
1346 generateFooter(aggregate);
1350
1351
1352
1356 SubTitleSize subTitleSize = LargeSubTitle;
1357 QString htmlTitle = qcn->name();
1359 htmlTitle.append(
" QML Value Type");
1361 htmlTitle.append(
" QML Type");
1364 htmlTitle.append(
" (Singleton)"_L1);
1366 generateHeader(htmlTitle, qcn, marker);
1369 marker = CodeMarker::markerForLanguage(QLatin1String(
"QML"));
1370 generateTitle(htmlTitle,
Text() << qcn->subtitle(), subTitleSize, qcn, marker);
1371 generateBrief(qcn, marker);
1372 generateQmlRequisites(qcn, marker);
1376 out() <<
"<p><strong>Note:</strong> This type is a QML singleton. "_L1
1377 <<
"There is only one instance of this type in the QML engine.</p>\n"_L1;
1380 QString allQmlMembersLink;
1383 if (!qcn->isQmlBasicType())
1384 allQmlMembersLink = generateAllQmlMembersFile(sections, marker);
1385 QString obsoleteLink = generateObsoleteQmlMembersFile(sections, marker);
1386 if (!allQmlMembersLink.isEmpty() || !obsoleteLink.isEmpty()) {
1387 openUnorderedList();
1389 if (!allQmlMembersLink.isEmpty()) {
1390 out() <<
"<li><a href=\"" << allQmlMembersLink <<
"\">"
1391 <<
"List of all members, including inherited members</a></li>\n";
1393 if (!obsoleteLink.isEmpty()) {
1394 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1395 <<
"Deprecated members</a></li>\n";
1399 if (QString groups_text{groupReferenceText(qcn)}; !groups_text.isEmpty()) {
1400 openUnorderedList();
1402 out() <<
"<li>" << groups_text <<
"</li>\n";
1405 closeUnorderedList();
1408 for (
const auto §ion : qmlSummarySections) {
1409 if (!section.isEmpty()) {
1410 QString ref = registerRef(section.title().toLower());
1411 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1412 generateQmlSummary(section.members(), qcn, marker);
1416 generateExtractionMark(qcn, DetailedDescriptionMark);
1417 out() <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1418 <<
"Detailed Description"
1421 generateAlsoList(qcn, marker);
1422 generateExtractionMark(qcn, EndMark);
1425 for (
const auto §ion : qmlDetailsSections) {
1426 if (section.isEmpty())
1428 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1429 const QList<Node *> &members = section.members();
1430 for (
const auto member : members)
1431 generateDetailedQmlMember(member, qcn, marker);
1433 generateFooter(qcn);
1438
1439
1440
1443 generateHeader(pn->fullTitle(), pn, marker);
1445
1446
1447
1448 if ((pn->name() != QLatin1String(
"index.html")))
1449 generateTableOfContents(pn, marker,
nullptr);
1451 generateTitle(pn
->doc().title(),
Text() << pn->subtitle(), LargeSubTitle, pn, marker);
1453 generateBrief(pn, marker,
nullptr,
false);
1456 generateExtractionMark(pn, DetailedDescriptionMark);
1457 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1461 out() <<
"</div>\n";
1462 generateAlsoList(pn, marker);
1463 generateExtractionMark(pn, EndMark);
1469
1470
1473 SubTitleSize subTitleSize = LargeSubTitle;
1476 generateHeader(cn->fullTitle(), cn, marker);
1477 generateTableOfContents(cn, marker,
nullptr);
1478 generateTitle(cn
->doc().title(),
Text() << cn->subtitle(), subTitleSize, cn, marker);
1481 if (cn
->genus() != Genus::DOC && cn
->genus() != Genus::DontCare) {
1483 generateBrief(cn, marker);
1491 if (!nmm.isEmpty()) {
1492 ref = registerRef(
"namespaces");
1493 out() <<
"<h2 id=\"" << ref <<
"\">Namespaces</h2>\n";
1494 generateAnnotatedList(cn, marker, nmm.values());
1497 if (!nmm.isEmpty()) {
1498 ref = registerRef(
"classes");
1499 out() <<
"<h2 id=\"" << ref <<
"\">Classes</h2>\n";
1500 generateAnnotatedList(cn, marker, nmm.values());
1506 generateExtractionMark(cn, DetailedDescriptionMark);
1507 ref = registerRef(
"details");
1508 out() <<
"<div class=\"descr\">\n";
1509 out() <<
"<h2 id=\"" << ref <<
"\">"
1510 <<
"Detailed Description"
1513 generateExtractionMark(cn, DetailedDescriptionMark);
1514 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1519 out() <<
"</div>\n";
1520 generateAlsoList(cn, marker);
1521 generateExtractionMark(cn, EndMark);
1524 if (cn->isGroup() || cn->isQmlModule())
1525 generateAnnotatedList(cn, marker, cn->members());
1531
1532
1533
1534
1537 SubTitleSize subTitleSize = LargeSubTitle;
1538 QString fullTitle = cn->name();
1540 generateHeader(fullTitle, cn, marker);
1541 generateTitle(fullTitle,
Text() << cn->subtitle(), subTitleSize, cn, marker);
1544 brief <<
"Each function or type documented here is related to a class or "
1545 <<
"namespace that is documented in a different module. The reference "
1546 <<
"page for that class or namespace will link to the function or type "
1549 generateText(brief, cn, marker);
1553 for (
const auto &member : members)
1554 generateDetailedMember(member, cn, marker);
1560
1561
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589void HtmlGenerator::generateNavigationBar(
const QString &title,
const Node *node,
1590 CodeMarker *marker,
const QString &buildversion,
1593 if (m_noNavigationBar || node ==
nullptr)
1604 auto addNavItem = [&](
const QString &link,
const QString &title) {
1605 navigationbar << Atom(itemLeft) << Atom(
Atom::NavLink, link)
1612 auto addNavItemNode = [&](
const Node *node,
const QString &title) {
1613 navigationbar << Atom(itemLeft);
1614 addNodeLink(navigationbar, node, title);
1615 navigationbar << Atom(itemRight);
1619 const auto *moduleNode = m_qdb->getModuleNode(node);
1620 QString moduleState;
1621 if (moduleNode && !moduleNode->state().isEmpty())
1622 moduleState = QStringLiteral(
" (%1)").arg(moduleNode->state());
1624 if (m_hometitle == title)
1626 if (!m_homepage.isEmpty())
1627 addNavItem(m_homepage, m_hometitle);
1628 if (!m_landingpage.isEmpty() && m_landingtitle != title)
1629 addNavItem(m_landingpage, m_landingtitle);
1632 if (!m_cppclassespage.isEmpty() && !m_cppclassestitle.isEmpty())
1633 addNavItem(m_cppclassespage, m_cppclassestitle);
1634 if (!node->physicalModuleName().isEmpty()) {
1638 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_cppclassespage))
1639 addNavItemNode(moduleNode, moduleNode->name() + moduleState);
1641 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1643 if (!m_qmltypespage.isEmpty() && !m_qmltypestitle.isEmpty())
1644 addNavItem(m_qmltypespage, m_qmltypestitle);
1648 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_qmltypespage)) {
1649 addNavItemNode(moduleNode, moduleNode->name() + moduleState);
1651 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1654 auto currentNode{
static_cast<
const PageNode*>(node)};
1655 std::deque<
const Node *> navNodes;
1657 qsizetype navItems = 0;
1658 while (currentNode->navigationParent() && ++navItems < 16) {
1659 if (
std::find(navNodes.cbegin(), navNodes.cend(),
1660 currentNode->navigationParent()) == navNodes.cend())
1661 navNodes.push_front(currentNode->navigationParent());
1662 currentNode = currentNode->navigationParent();
1666 if (navNodes.empty()) {
1667 const QStringList groups =
static_cast<
const PageNode *>(node)->groupNames();
1668 for (
const auto &groupName : groups) {
1669 const auto *groupNode = m_qdb->findNodeByNameAndType(QStringList{groupName}, &Node::isGroup);
1670 if (groupNode && !groupNode->title().isEmpty()) {
1671 navNodes.push_front(groupNode);
1676 while (!navNodes.empty()) {
1677 if (navNodes.front()->isPageNode())
1678 addNavItemNode(navNodes.front(), navNodes.front()->title());
1679 navNodes.pop_front();
1683 navigationbar << Atom(itemLeft) << Atom(
Atom::String, title) << Atom(itemRight);
1687 generateText(navigationbar, node, marker);
1689 if (buildversion.isEmpty())
1695 out() <<
"</tr></table><table class=\"buildversion\"><tr>\n"
1696 << R"(<td id="buildversion" width="100%" align="right">)";
1698 out() <<
"<li id=\"buildversion\">";
1702 if (!m_landingpage.isEmpty() && m_landingtitle != title) {
1703 navigationbar << Atom(Atom::NavLink, m_landingpage)
1705 << Atom(Atom::String, buildversion)
1707 generateText(navigationbar, node, marker);
1709 out() << buildversion;
1719 out() <<
"<!DOCTYPE html>\n";
1720 out() << QString(
"<html lang=\"%1\">\n").arg(naturalLanguage);
1721 out() <<
"<head>\n";
1722 out() <<
" <meta charset=\"utf-8\">\n";
1727 out() <<
" <meta name=\"description\" content=\""
1728 << protectEnc(node->doc().briefText().toString())
1735 QStringList keywords;
1736 for (
const auto &kw : metaTags->values(u"keywords"_s))
1737 keywords << kw.split(
','_L1, Qt::SkipEmptyParts);
1739 if (!keywords.isEmpty()) {
1740 std::transform(keywords.begin(), keywords.end(), keywords.begin(),
1741 [](
const QString &k) {
return k.trimmed(); });
1742 out() <<
" <meta name=\"keywords\" content=\""
1743 << protectEnc(keywords.join(
','_L1))
1750 QString titleSuffix;
1751 if (!m_landingtitle.isEmpty()) {
1753 titleSuffix = m_landingtitle;
1754 }
else if (!m_hometitle.isEmpty()) {
1757 if (title != m_hometitle)
1758 titleSuffix = m_hometitle;
1761 titleSuffix = m_productName.isEmpty() ? m_project : m_productName;
1763 if (title == titleSuffix)
1764 titleSuffix.clear();
1766 out() <<
" <title>";
1767 if (!titleSuffix.isEmpty() && !title.isEmpty()) {
1768 out() <<
"%1 | %2"_L1.arg(protectEnc(title), titleSuffix);
1770 out() << protectEnc(title);
1775 QVersionNumber projectVersion = QVersionNumber::fromString(m_qdb->version());
1776 if (!projectVersion.isNull()) {
1777 QVersionNumber titleVersion;
1778 static const QRegularExpression re(QLatin1String(R"(\d+\.\d+)"));
1779 const QString &versionedTitle = titleSuffix.isEmpty() ? title : titleSuffix;
1780 auto match = re.match(versionedTitle);
1781 if (match.hasMatch())
1782 titleVersion = QVersionNumber::fromString(match.captured());
1783 if (titleVersion.isNull() || !titleVersion.isPrefixOf(projectVersion)) {
1785 if (!m_productName.isEmpty() && titleSuffix != m_productName)
1786 out() <<
" | %1"_L1.arg(m_productName);
1787 out() <<
" %1"_L1.arg(projectVersion.toString());
1790 out() <<
"</title>\n";
1793 out() << m_headerStyles;
1794 out() << m_headerScripts;
1795 out() << m_endHeader;
1797 out() << QString(m_postHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1798 bool usingTable = m_postHeader.trimmed().endsWith(QLatin1String(
"<tr>"));
1799 generateNavigationBar(title, node, marker, m_buildversion, usingTable);
1800 out() << QString(m_postPostHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1802 m_navigationLinks.clear();
1805 if (node && !node->links().empty()) {
1806 std::pair<QString, QString> linkPair;
1807 std::pair<QString, QString> anchorPair;
1808 const Node *linkNode;
1809 bool useSeparator =
false;
1811 if (node->links().contains(Node::PreviousLink)) {
1812 linkPair = node->links()[Node::PreviousLink];
1813 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1816 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1817 if (linkNode ==
nullptr || linkNode == node)
1818 anchorPair = linkPair;
1820 anchorPair = anchorForNode(linkNode);
1822 out() << R"( <link rel="prev" href=")" << anchorPair.first <<
"\" />\n";
1824 m_navigationLinks += R"(<a class="prevPage" href=")" + anchorPair.first +
"\">";
1825 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
1826 m_navigationLinks += protect(anchorPair.second);
1828 m_navigationLinks += protect(linkPair.second);
1829 m_navigationLinks +=
"</a>\n";
1830 useSeparator = !m_navigationSeparator.isEmpty();
1832 if (node->links().contains(Node::NextLink)) {
1833 linkPair = node->links()[Node::NextLink];
1834 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1837 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1838 if (linkNode ==
nullptr || linkNode == node)
1839 anchorPair = linkPair;
1841 anchorPair = anchorForNode(linkNode);
1843 out() << R"( <link rel="next" href=")" << anchorPair.first <<
"\" />\n";
1846 m_navigationLinks += m_navigationSeparator;
1848 m_navigationLinks += R"(<a class="nextPage" href=")" + anchorPair.first +
"\">";
1849 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
1850 m_navigationLinks += protect(anchorPair.second);
1852 m_navigationLinks += protect(linkPair.second);
1853 m_navigationLinks +=
"</a>\n";
1855 if (node->links().contains(Node::StartLink)) {
1856 linkPair = node->links()[Node::StartLink];
1857 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1860 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1861 if (linkNode ==
nullptr || linkNode == node)
1862 anchorPair =
std::move(linkPair);
1864 anchorPair = anchorForNode(linkNode);
1865 out() << R"( <link rel="start" href=")" << anchorPair.first <<
"\" />\n";
1869 if (node && !node->links().empty())
1870 out() <<
"<p class=\"naviNextPrevious headerNavi\">\n" << m_navigationLinks <<
"</p>\n";
1874 SubTitleSize subTitleSize,
const Node *relative,
1877 out() << QString(m_prologue).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1880 attribute = R"( translate="no")";
1883 out() <<
"<h1 class=\"title\"" << attribute <<
">";
1884 generateText(title, relative, marker);
1889 if (subTitleSize == SmallSubTitle)
1890 out() <<
" class=\"small-subtitle\"" << attribute <<
">";
1892 out() <<
" class=\"subtitle\"" << attribute <<
">";
1893 generateText(subtitle, relative, marker);
1894 out() <<
"</span>\n";
1900 if (node && !node->links().empty())
1901 out() <<
"<p class=\"naviNextPrevious footerNavi\">\n" << m_navigationLinks <<
"</p>\n";
1903 out() << QString(m_footer).replace(
"\\" +
COMMAND_VERSION, m_qdb->version())
1904 << QString(m_address).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1906 out() <<
"</body>\n";
1907 out() <<
"</html>\n";
1911
1912
1913
1916 QMap<QString, Text> requisites;
1919 const QString headerText =
"Header";
1920 const QString sinceText =
"Since";
1921 const QString inheritedByText =
"Inherited By";
1922 const QString inheritsText =
"Inherits";
1923 const QString nativeTypeText =
"In QML";
1924 const QString qtVariableText =
"qmake";
1925 const QString cmakeText =
"CMake";
1926 const QString statusText =
"Status";
1929 const QStringList requisiteorder { headerText, cmakeText, qtVariableText, sinceText,
1930 nativeTypeText, inheritsText, inheritedByText, statusText };
1932 addIncludeFileToMap(aggregate, requisites, text, headerText);
1933 addSinceToMap(aggregate, requisites, &text, sinceText);
1936 addCMakeInfoToMap(aggregate, requisites, &text, cmakeText);
1937 addQtVariableToMap(aggregate, requisites, &text, qtVariableText);
1941 auto *classe =
dynamic_cast<
ClassNode *>(aggregate);
1943 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1945 if (InclusionFilter::isIncluded(policy, context))
1946 addQmlNativeTypesToMap(requisites, &text, nativeTypeText, classe);
1949 const auto *metaTags = classe ? classe
->doc().metaTagMap() :
nullptr;
1950 if (!metaTags || !metaTags->contains(u"qdoc-suppress-inheritance"_s))
1951 addInheritsToMap(requisites, &text, inheritsText, classe);
1952 addInheritedByToMap(requisites, &text, inheritedByText, classe);
1956 addStatusToMap(aggregate, requisites, text, statusText);
1958 if (!requisites.isEmpty()) {
1960 generateTheTable(requisiteorder, requisites, aggregate, marker);
1965
1966
1967void HtmlGenerator::generateTheTable(
const QStringList &requisiteOrder,
1968 const QMap<QString, Text> &requisites,
1971 out() <<
"<div class=\"table\"><table class=\"alignedsummary requisites\" translate=\"no\">\n";
1973 for (
auto it = requisiteOrder.constBegin(); it != requisiteOrder.constEnd(); ++it) {
1975 if (requisites.contains(*it)) {
1977 <<
"<td class=\"memItemLeft rightAlign topAlign\"> " << *it
1979 "</td><td class=\"memItemRight bottomAlign\"> ";
1981 generateText(requisites.value(*it), aggregate, marker);
1982 out() <<
"</td></tr>\n";
1985 out() <<
"</table></div>\n";
1989
1990
1991
1992void HtmlGenerator::addInheritedByToMap(QMap<QString, Text> &requisites,
Text *text,
1993 const QString &inheritedByText,
ClassNode *classe)
1995 if (!classe->derivedClasses().isEmpty()) {
1998 int count = appendSortedNames(*text, classe, classe->derivedClasses());
2001 requisites.insert(inheritedByText, *text);
2006
2007
2008
2009void HtmlGenerator::addInheritsToMap(QMap<QString, Text> &requisites,
Text *text,
2010 const QString &inheritsText,
ClassNode *classe)
2012 if (!classe->baseClasses().isEmpty()) {
2015 const auto baseClasses = classe->baseClasses();
2016 for (
const auto &cls : baseClasses) {
2018 appendFullName(*text, cls.m_node, classe);
2020 if (cls.m_access == Access::Protected) {
2021 *text <<
" (protected)";
2022 }
else if (cls.m_access == Access::Private) {
2023 *text <<
" (private)";
2025 *text << Utilities::comma(index++, classe->baseClasses().size());
2030 requisites.insert(inheritsText, *text);
2035
2036
2037
2038void HtmlGenerator::addQmlNativeTypesToMap(QMap<QString, Text> &requisites,
Text *text,
2039 const QString &nativeTypeText,
ClassNode *classe)
const
2046 QList<QmlTypeNode *> nativeTypes { classe->qmlNativeTypes().cbegin(), classe->qmlNativeTypes().cend()};
2048 qsizetype index { 0 };
2050 for (
const auto &item : std::as_const(nativeTypes)) {
2051 addNodeLink(*text, item);
2052 *text << Utilities::comma(index++, nativeTypes.size());
2054 requisites.insert(nativeTypeText, *text);
2058
2059
2060
2062 Text *text,
const QString &CMakeInfo)
const
2064 if (!aggregate->physicalModuleName().isEmpty() && text !=
nullptr) {
2066 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2068 const auto result = cmakeRequisite(cn);
2081 requisites.insert(CMakeInfo, *text);
2086
2087
2088
2090 Text *text,
const QString &qtVariableText)
const
2092 if (!aggregate->physicalModuleName().isEmpty()) {
2094 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2096 if (cn && !cn->qtVariable().isEmpty()) {
2099 requisites.insert(qtVariableText, *text);
2105
2106
2107
2108
2110 Text *text,
const QString &sinceText)
const
2112 if (!aggregate->since().isEmpty() && text !=
nullptr) {
2115 requisites.insert(sinceText, *text);
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2131 Text &text,
const QString &statusText)
const
2133 auto status{formatStatus(aggregate, m_qdb)};
2139 spanClass = u"deprecated"_s;
2141 spanClass =
Utilities::asAsciiPrintable(status.value());
2144 text << Atom(Atom::String, status.value())
2146 "class=\"status %1\""_L1.arg(spanClass))
2148 requisites.insert(statusText, text);
2152
2153
2154
2155
2157 QMap<QString, Text> &requisites,
Text& text,
2158 const QString &headerText)
2160 if (aggregate->includeFile()) {
2162 text << openCodeTag <<
"#include <%1>"_L1.arg(*aggregate->includeFile()) << closeCodeTag;
2163 requisites.insert(headerText, text);
2168
2169
2170
2176 QMap<QString, Text> requisites;
2179 const QString importText =
"Import Statement";
2180 const QString sinceText =
"Since";
2181 const QString inheritedByText =
"Inherited By";
2182 const QString inheritsText =
"Inherits";
2183 const QString nativeTypeText =
"In C++";
2184 const QString statusText =
"Status";
2187 QString logicalModuleVersion;
2192 bool generate_import =
true;
2194 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2198 if (generate_import) {
2202 requisites.insert(importText, text);
2205 qcn
->doc().location().warning(QStringLiteral(
"Could not resolve QML import statement for type '%1'").arg(qcn->name()),
2210 if (!qcn->since().isEmpty()) {
2213 requisites.insert(sinceText, text);
2218 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2222 addNodeLink(text, cn);
2223 requisites.insert(nativeTypeText, text);
2231 QStringList knownTypeNames{qcn->name()};
2233 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2241 knownTypeNames << base->name();
2244 addNodeLink(text, base);
2247 for (
const auto sub : std::as_const(subs)) {
2248 if (knownTypeNames.contains(sub->name())) {
2249 text << Atom(Atom::String,
" (%1)"_L1.arg(base->logicalModuleName()));
2254 requisites.insert(inheritsText, text);
2258 if (!subs.isEmpty()) {
2261 int count = appendSortedQmlNames(text, qcn, knownTypeNames, subs);
2264 requisites.insert(inheritedByText, text);
2268 addStatusToMap(qcn, requisites, text, statusText);
2271 const QStringList requisiteorder {
std::move(importText),
std::move(sinceText),
2272 std::move(nativeTypeText),
std::move(inheritsText),
2273 std::move(inheritedByText),
std::move(statusText)};
2275 if (!requisites.isEmpty())
2276 generateTheTable(requisiteorder, requisites, qcn, marker);
2288 QStringLiteral(
"'\\brief' statement does not end with a full stop."));
2290 generateExtractionMark(node, BriefMark);
2292 generateText(brief, node, marker);
2295 if (!relative || node == relative)
2296 out() <<
" <a href=\"#";
2298 out() <<
" <a href=\"" << linkForNode(node, relative) <<
'#';
2299 out() << registerRef(
"details") <<
"\">More...</a>";
2303 generateExtractionMark(node, EndMark);
2308
2309
2310
2316 toc = node
->doc().tableOfContents();
2317 if (tocDepth == 0 || (toc.isEmpty() && !sections && !node
->isModule())) {
2322 int sectionNumber = 1;
2323 int detailsBase = 0;
2326 m_inContents =
true;
2328 out() <<
"<div class=\"sidebar\">\n";
2329 out() <<
"<div class=\"toc\">\n";
2330 out() <<
"<h3 id=\"toc\">Contents</h3>\n";
2333 openUnorderedList();
2334 if (!
static_cast<
const CollectionNode *>(node)->noAutoList()) {
2336 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2337 << registerRef(
"namespaces") <<
"\">Namespaces</a></li>\n";
2340 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2341 << registerRef(
"classes") <<
"\">Classes</a></li>\n";
2344 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#" << registerRef(
"details")
2345 <<
"\">Detailed Description</a></li>\n";
2346 for (
const auto &entry : std::as_const(toc)) {
2347 if (entry->string().toInt() == 1) {
2353 for (
const auto §ion : *sections) {
2354 if (!section.members().isEmpty()) {
2355 openUnorderedList();
2356 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2357 << registerRef(section.plural()) <<
"\">" << section.title() <<
"</a></li>\n";
2359 if (!section.reimplementedMembers().isEmpty()) {
2360 openUnorderedList();
2361 QString ref = QString(
"Reimplemented ") + section.plural();
2362 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2363 << registerRef(ref.toLower()) <<
"\">"
2364 << QString(
"Reimplemented ") + section.title() <<
"</a></li>\n";
2368 openUnorderedList();
2369 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2370 << registerRef(
"details") <<
"\">Detailed Description</a></li>\n";
2372 for (
const auto &entry : toc) {
2373 if (entry->string().toInt() == 1) {
2380 for (
const auto &atom : toc) {
2381 sectionNumber = atom->string().toInt() + detailsBase;
2384 if (sectionNumber <= tocDepth || tocDepth < 0) {
2385 openUnorderedList();
2387 Text headingText = Text::sectionHeading(atom);
2388 out() <<
"<li class=\"level" << sectionNumber <<
"\">";
2389 out() <<
"<a href=\"" <<
'#' << Tree::refForAtom(atom) <<
"\">";
2390 generateAtomList(headingText.firstAtom(), node, marker,
true, numAtoms);
2391 out() <<
"</a></li>\n";
2394 closeUnorderedList();
2395 out() <<
"</div>\n";
2396 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2397 out() <<
"</div>\n";
2398 m_inContents =
false;
2403
2404
2407 out() <<
"<div class=\"sidebar\">";
2408 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2409 out() <<
"</div>\n";
2418 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2419 beginSubPage(aggregate, fileName);
2420 QString title =
"List of All Members for " + aggregate->plainFullName();
2421 generateHeader(title, aggregate, marker);
2423 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2424 out() <<
"<p>This is the complete list of members for ";
2425 generateFullName(aggregate,
nullptr);
2426 out() <<
", including inherited members.</p>\n";
2428 generateSectionList(section, aggregate, marker);
2436
2437
2438
2439
2440
2448 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2449 beginSubPage(aggregate, fileName);
2450 QString title =
"List of All Members for " + aggregate->name();
2451 generateHeader(title, aggregate, marker);
2453 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2454 out() <<
"<p>This is the complete list of members for ";
2455 generateFullName(aggregate,
nullptr);
2456 out() <<
", including inherited members.</p>\n";
2459 for (
int i = 0; i < cknl.size(); i++) {
2460 const auto &ckn = cknl[i];
2463 if (nodes.isEmpty())
2466 out() <<
"<p>The following members are inherited from ";
2467 generateFullName(qcn,
nullptr);
2470 openUnorderedList();
2471 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2472 for (
int j = 0; j < nodes.size(); j++) {
2473 Node *node = nodes[j];
2480 std::function<
void(
Node *)> generate = [&](Node *n) {
2481 out() <<
"<li class=\"fn\" translate=\"no\">";
2482 generateQmlItem(n, aggregate, marker,
true);
2483 if (n->isQmlProperty()) {
2484 auto qpn =
static_cast<QmlPropertyNode *>(n);
2485 QStringList hints = qpn->hints();
2486 if (qpn->isAttached())
2487 hints <<
"attached"_L1;
2488 if (!hints.isEmpty())
2489 out() <<
" [" << hints.join(
' '_L1) <<
"]";
2490 }
else if (n->isAttached()) {
2492 out() <<
" [attached]";
2495 if (n->isPropertyGroup()) {
2497 const QList<Node *> &collective =
2498 static_cast<SharedCommentNode *>(n)->collective();
2499 std::for_each(collective.begin(), collective.end(), generate);
2506 closeUnorderedList();
2523 QString title =
"Obsolete Members for " + aggregate->plainFullName();
2524 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2526 beginSubPage(aggregate, fileName);
2527 generateHeader(title, aggregate, marker);
2529 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2531 out() <<
"<p><b>The following members of class "
2532 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\" translate=\"no\">"
2533 << protectEnc(aggregate->name()) <<
"</a>"
2534 <<
" are deprecated.</b> "
2535 <<
"They are provided to keep old source code working. "
2536 <<
"We strongly advise against using them in new code.</p>\n";
2538 for (
const auto §ion : summary_spv) {
2539 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2540 generateSectionList(*section, aggregate, marker,
true);
2543 for (
const auto §ion : details_spv) {
2544 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2546 const NodeVector &members = section->obsoleteMembers();
2547 for (
const auto &member : members)
2548 generateDetailedMember(member, aggregate, marker);
2557
2558
2559
2560
2569 QString title =
"Obsolete Members for " + aggregate->name();
2570 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2572 beginSubPage(aggregate, fileName);
2573 generateHeader(title, aggregate, marker);
2575 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2577 out() <<
"<p><b>The following members of QML type "
2578 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\">"
2579 << protectEnc(aggregate->name()) <<
"</a>"
2580 <<
" are deprecated.</b> "
2581 <<
"They are provided to keep old source code working. "
2582 <<
"We strongly advise against using them in new code.</p>\n";
2584 for (
const auto §ion : summary_spv) {
2585 QString ref = registerRef(section->title().toLower());
2586 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section->title()) <<
"</h2>\n";
2587 generateQmlSummary(section->obsoleteMembers(), aggregate, marker);
2590 for (
const auto §ion : details_spv) {
2591 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2592 const NodeVector &members = section->obsoleteMembers();
2593 for (
const auto &member : members) {
2594 generateDetailedQmlMember(member, aggregate, marker);
2606 if (classMap.isEmpty())
2610 for (
const auto &it : classMap) {
2611 auto *classe =
static_cast<ClassNode *>(it);
2612 if (classe->baseClasses().isEmpty())
2613 topLevel.insert(classe->name(), classe);
2616 QStack<NodeMap> stack;
2617 stack.push(topLevel);
2620 while (!stack.isEmpty()) {
2621 if (stack.top().isEmpty()) {
2627 generateFullName(child, relative);
2629 stack.top().erase(stack.top().begin());
2632 const auto derivedClasses = child->derivedClasses();
2633 for (
const RelatedClass &d : derivedClasses) {
2634 if (d.m_node && d.m_node->isInAPI())
2635 newTop.insert(d.m_node->name(), d.m_node);
2637 if (!newTop.isEmpty()) {
2646
2647
2648
2650 const NodeList &unsortedNodes, Qt::SortOrder sortOrder)
2652 if (unsortedNodes.isEmpty() || relative ==
nullptr)
2656 bool allInternal =
true;
2657 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2658 for (
auto *node : unsortedNodes) {
2659 const NodeContext context = node->createContext();
2660 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated()) {
2661 allInternal =
false;
2662 nmm.insert(node->fullName(relative), node);
2667 out() <<
"<div class=\"table\"><table class=\"annotated\">\n";
2671 if (sortOrder == Qt::DescendingOrder)
2676 for (
const auto *node : std::as_const(nodes)) {
2678 out() <<
"<tr class=\"odd topAlign\">";
2680 out() <<
"<tr class=\"even topAlign\">";
2681 out() <<
"<td class=\"tblName\" translate=\"no\"><p>";
2682 generateFullName(node, relative);
2683 out() <<
"</p></td>";
2685 if (!node->isTextPageNode()) {
2686 Text brief = node->doc().trimmedBriefText(node->name());
2687 if (!brief.isEmpty()) {
2688 out() <<
"<td class=\"tblDescr\"><p>";
2689 generateText(brief, node, marker);
2690 out() <<
"</p></td>";
2691 }
else if (!node->reconstitutedBrief().isEmpty()) {
2692 out() <<
"<td class=\"tblDescr\"><p>";
2693 out() << node->reconstitutedBrief();
2694 out() <<
"</p></td>";
2697 out() <<
"<td class=\"tblDescr\"><p>";
2698 if (!node->reconstitutedBrief().isEmpty()) {
2699 out() << node->reconstitutedBrief();
2701 out() << protectEnc(node->doc().briefText().toString());
2702 out() <<
"</p></td>";
2706 out() <<
"</table></div>\n";
2710
2711
2712
2716 const auto &uniqueKeys = nmm.uniqueKeys();
2717 for (
const QString &name : uniqueKeys) {
2718 if (!name.isEmpty()) {
2719 out() <<
"<h2 id=\"" << registerRef(name.toLower()) <<
"\">" << protectEnc(name)
2722 generateAnnotatedList(relative, marker, nmm.values(name));
2727
2728
2729
2730
2731
2732
2733
2734
2735
2738 const QString &commonPrefix)
2743 const int NumParagraphs = 37;
2744 qsizetype commonPrefixLen = commonPrefix.size();
2747
2748
2749
2750
2751
2753 QString paragraphName[NumParagraphs + 1];
2754 QSet<
char> usedParagraphNames;
2756 for (
auto c = nmm.constBegin(); c != nmm.constEnd(); ++c) {
2757 QStringList pieces = c.key().split(
"::");
2758 int idx = commonPrefixLen;
2759 if (idx > 0 && !pieces.last().startsWith(commonPrefix, Qt::CaseInsensitive))
2761 QString last = pieces.last().toLower();
2762 QString key = last.mid(idx);
2764 int paragraphNr = NumParagraphs - 1;
2766 if (key[0].digitValue() != -1) {
2767 paragraphNr = key[0].digitValue();
2768 }
else if (key[0] >= QLatin1Char(
'a') && key[0] <= QLatin1Char(
'z')) {
2769 paragraphNr = 10 + key[0].unicode() -
'a';
2772 paragraphName[paragraphNr] = key[0].toUpper();
2773 usedParagraphNames.insert(key[0].toLower().cell());
2774 paragraph[paragraphNr].insert(last, c.value());
2778
2779
2780
2781
2782
2783
2784
2785 qsizetype paragraphOffset[NumParagraphs + 1];
2786 paragraphOffset[0] = 0;
2787 for (
int i = 0; i < NumParagraphs; i++)
2788 paragraphOffset[i + 1] = paragraphOffset[i] + paragraph[i].size();
2791
2792
2793 if (includeAlphabet) {
2794 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
2795 for (
int i = 0; i < 26; i++) {
2797 if (usedParagraphNames.contains(
char(
'a' + i)))
2798 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
2800 out() <<
"</b></p>\n";
2804
2805
2806 out() <<
"<div class=\"flowListDiv\" translate=\"no\">\n";
2810 QHash<QString,
int> nameOccurrences;
2811 for (
const auto &[key, node] : nmm.asKeyValueRange()) {
2812 QStringList pieces{node->fullName(relative).split(
"::"_L1)};
2813 const QString &name{pieces.last()};
2814 nameOccurrences[name]++;
2818 int curParOffset = 0;
2820 for (
int i = 0; i < nmm.size(); i++) {
2821 while ((curParNr < NumParagraphs) && (curParOffset == paragraph[curParNr].size())) {
2827
2828
2829 if (curParOffset == 0) {
2832 if (++m_numTableRows % 2 == 1)
2833 out() <<
"<dl class=\"flowList odd\">";
2835 out() <<
"<dl class=\"flowList even\">";
2836 out() <<
"<dt class=\"alphaChar\"";
2837 if (includeAlphabet)
2838 out() << QString(
" id=\"%1\"").arg(paragraphName[curParNr][0].toLower());
2839 out() <<
"><b>" << paragraphName[curParNr] <<
"</b></dt>\n";
2843
2844
2846 if ((curParNr < NumParagraphs) && !paragraphName[curParNr].isEmpty()) {
2847 NodeMultiMap::Iterator it;
2848 NodeMultiMap::Iterator next;
2849 it = paragraph[curParNr].begin();
2850 for (
int j = 0; j < curParOffset; j++)
2855
2856
2857
2858 out() <<
"<a href=\"" << linkForNode(it.value(), relative) <<
"\">";
2860 QString fileName = fileBase(it.value()) +
"-obsolete." + fileExtension();
2862 if (useOutputSubdirs())
2863 link =
"../%1/"_L1.arg(it.value()->tree()->physicalModuleName());
2865 out() <<
"<a href=\"" << link <<
"\">";
2868 QStringList pieces{it.value()->fullName(relative).split(
"::"_L1)};
2869 const auto &name{pieces.last()};
2872 if (nameOccurrences[name] > 1) {
2873 const QString moduleName = it.value()->isQmlNode() ? it.value()->logicalModuleName()
2874 : it.value()->tree()->camelCaseModuleName();
2875 pieces.last().append(
": %1"_L1.arg(moduleName));
2878 out() << protectEnc(pieces.last());
2880 if (pieces.size() > 1) {
2882 generateFullName(it.value()->parent(), relative);
2892 out() <<
"</div>\n";
2897 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
2898 for (
int i = 0; i < 26; i++) {
2900 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
2902 out() <<
"</b></p>\n";
2904 char nextLetter =
'a';
2906 out() <<
"<ul translate=\"no\">\n";
2907 NodeMapMap &funcIndex = m_qdb->getFunctionIndex();
2908 for (
auto fnMap = funcIndex.constBegin(); fnMap != funcIndex.constEnd(); ++fnMap) {
2909 const QString &key = fnMap.key();
2910 const QChar firstLetter = key.isEmpty() ? QChar(
'A') : key.front();
2911 Q_ASSERT_X(firstLetter.unicode() < 256,
"generateFunctionIndex",
2912 "Only valid C++ identifiers were expected");
2913 const char currentLetter = firstLetter.isLower() ? firstLetter.unicode() : nextLetter - 1;
2915 if (currentLetter < nextLetter) {
2919 while (nextLetter < currentLetter)
2920 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
2921 Q_ASSERT(nextLetter == currentLetter);
2922 out() << QStringLiteral(
"<li id=\"%1\">").arg(nextLetter++);
2924 out() << protectEnc(key) <<
':';
2926 for (
auto it = (*fnMap).constBegin(); it != (*fnMap).constEnd(); ++it) {
2928 generateFullName((*it)->parent(), relative, *it);
2932 while (nextLetter <=
'z')
2933 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
2940 for (
auto it = legaleseTexts.cbegin(), end = legaleseTexts.cend(); it != end; ++it) {
2941 Text text = it.key();
2942 generateText(text, relative, marker);
2946 generateFullName(it.value(), relative);
2949 }
while (it != legaleseTexts.constEnd() && it.key() == text);
2957 QString marked = marker->markedUpQmlItem(node, summary);
2958 marked.replace(
"@param>",
"i>");
2960 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
2961 .arg(summary ?
"summary"_L1 :
"details"_L1));
2962 marked.replace(
"</@extra>",
"</code>");
2966 marked.remove(
"<@name>");
2967 marked.remove(
"</@name>");
2968 marked.remove(
"<@type>");
2969 marked.remove(
"</@type>");
2971 out() << highlightedCode(marked, relative,
false, Genus::QML);
2975
2976
2977
2978
2979
2980
2981
2984 m_qdb->mergeCollections(cn);
2989 if (sortOrder == Qt::DescendingOrder)
2994 for (
const auto *node : std::as_const(members)) {
2995 out() <<
"<li translate=\"no\">";
2996 generateFullName(node,
nullptr);
3004 const QString &selector, Qt::SortOrder sortOrder)
3008 if (selector == QLatin1String(
"overviews"))
3010 else if (selector == QLatin1String(
"cpp-modules"))
3012 else if (selector == QLatin1String(
"qml-modules"))
3016 m_qdb->mergeCollections(type, cnm, relative);
3017 const auto collectionList = cnm.values();
3018 nodeList.reserve(collectionList.size());
3019 for (
auto *collectionNode : collectionList)
3020 nodeList.append(collectionNode);
3021 generateAnnotatedList(relative, marker, nodeList, sortOrder);
3024
3025
3026
3027
3030 QStringLiteral(
"\\generatelist {%1} is only allowed in \\group, "
3031 "\\module and \\qmlmodule comments.")
3035 auto *node =
const_cast<
Node *>(relative);
3036 auto *collectionNode =
static_cast<CollectionNode *>(node);
3037 if (!collectionNode)
3039 m_qdb->mergeCollections(collectionNode);
3040 generateAnnotatedList(collectionNode, marker, collectionNode->members(), sortOrder);
3046 bool alignNames =
true;
3047 if (!nv.isEmpty()) {
3048 bool twoColumn =
false;
3049 if (nv.first()->isProperty()) {
3050 twoColumn = (nv.size() >= 5);
3054 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3057 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3058 <<
"<tr><td class=\"topAlign\">";
3063 for (
const auto &member : nv) {
3066 out() <<
"<tr><td class=\"memItemLeft rightAlign topAlign\"> ";
3068 if (twoColumn && i == (nv.size() + 1) / 2)
3069 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3070 out() <<
"<li class=\"fn\" translate=\"no\">";
3073 generateSynopsis(member, relative, marker, Section::Summary, alignNames);
3075 out() <<
"</td></tr>\n";
3081 out() <<
"</table></div>\n";
3085 out() <<
"</td></tr>\n</table></div>\n";
3093 bool alignNames =
true;
3096 if (!members.isEmpty()) {
3097 bool hasPrivateSignals =
false;
3098 bool isInvokable =
false;
3099 bool twoColumn =
false;
3102 twoColumn = (members.size() >= 16);
3103 }
else if (members.first()->isProperty()) {
3104 twoColumn = (members.size() >= 5);
3108 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3111 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3112 <<
"<tr><td class=\"topAlign\">";
3117 for (
const auto &member : members) {
3120 if (member->name().isEmpty())
3124 out() <<
"<tr><td class=\"memItemLeft topAlign rightAlign\"> ";
3126 if (twoColumn && i == (members.size() + 1) / 2)
3127 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3128 out() <<
"<li class=\"fn\" translate=\"no\">";
3131 generateSynopsis(member, relative, marker, section.style(), alignNames);
3132 if (member->isFunction()) {
3133 const auto *fn =
static_cast<
const FunctionNode *>(member);
3134 if (fn->isPrivateSignal()) {
3135 hasPrivateSignals =
true;
3137 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3138 }
else if (fn->isInvokable()) {
3141 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3145 out() <<
"</td></tr>\n";
3151 out() <<
"</table></div>\n";
3155 out() <<
"</td></tr>\n</table></div>\n";
3158 if (hasPrivateSignals)
3166 && !section.inheritedMembers().isEmpty()) {
3168 generateSectionInheritedList(section, relative);
3175 const QList<std::pair<
const Aggregate *,
int>> &inheritedMembers = section.inheritedMembers();
3176 for (
const auto &member : inheritedMembers) {
3177 out() <<
"<li class=\"fn\" translate=\"no\">";
3178 out() << member.second <<
' ';
3179 if (member.second == 1) {
3180 out() << section.singular();
3182 out() << section.plural();
3184 out() <<
" inherited from <a href=\"" << fileName(member.first) <<
'#'
3185 << Generator::cleanRef(section.title().toLower()) <<
"\">"
3186 << protectEnc(member.first->plainFullName(relative)) <<
"</a></li>\n";
3193 QString marked = marker->markedUpSynopsis(node, relative, style);
3194 marked.replace(
"@param>",
"i>");
3197 marked.remove(
"<@name>");
3198 marked.remove(
"</@name>");
3202 static const QRegularExpression extraRegExp(
"<@extra>.*</@extra>",
3203 QRegularExpression::InvertedGreedinessOption);
3204 marked.remove(extraRegExp);
3206 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3207 .arg(style == Section::Summary ?
"summary"_L1 :
"details"_L1));
3208 marked.replace(
"</@extra>",
"</code>");
3212 marked.remove(
"<@type>");
3213 marked.remove(
"</@type>");
3216 out() << highlightedCode(marked, relative, alignNames);
3219QString
HtmlGenerator::highlightedCode(
const QString &markedCode,
const Node *relative,
3220 bool alignNames, Genus genus)
3222 QString src = markedCode;
3224 html.reserve(src.size());
3228 const QChar charLangle =
'<';
3229 const QChar charAt =
'@';
3231 static const QString typeTag(
"type");
3232 static const QString headerTag(
"headerfile");
3233 static const QString funcTag(
"func");
3234 static const QString linkTag(
"link");
3235 static const QString extrefTag(
"extref");
3238 static const QHash<QString, QString> extrefUrls = {
3239 {
"cpp-explicitly-defaulted"_L1,
3240 "https://en.cppreference.com/w/cpp/language/function#Defaulted_functions"_L1},
3241 {
"cpp-deleted-functions"_L1,
3242 "https://en.cppreference.com/w/cpp/language/function#Deleted_functions"_L1},
3249 for (
int i = 0, srcSize = src.size(); i < srcSize;) {
3250 if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
3251 if (alignNames && !done) {
3252 html += QLatin1String(
"</td><td class=\"memItemRight bottomAlign\">");
3256 if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) {
3257 html += QLatin1String(
"<b>");
3258 const Node *n =
static_cast<
const Node*>(
Utilities::nodeForString(par1.toString()));
3259 QString link = linkForNode(n, relative);
3260 addLink(link, arg, &html);
3261 html += QLatin1String(
"</b>");
3262 }
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
3263 const FunctionNode *fn = m_qdb->findFunctionNode(par1.toString(), relative, genus);
3264 QString link = linkForNode(fn, relative);
3265 addLink(link, arg, &html);
3266 par1 = QStringView();
3267 }
else if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
3268 par1 = QStringView();
3269 const Node *n = m_qdb->findTypeNode(arg.toString(), relative, genus);
3270 html += QLatin1String(
"<span class=\"type\">");
3273 addLink(linkForNode(n, relative), arg, &html);
3277 addLink(linkForNode(n, relative), arg, &html);
3278 html += QLatin1String(
"</span>");
3279 }
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
3280 par1 = QStringView();
3281 if (arg.startsWith(QLatin1Char(
'&')))
3284 const Node *n = m_qdb->findNodeForInclude(QStringList(arg.toString()));
3285 if (n && n != relative)
3286 addLink(linkForNode(n, relative), arg, &html);
3290 }
else if (parseArg(src, extrefTag, &i, srcSize, &arg, &par1)) {
3291 QString url = extrefUrls.value(par1.toString());
3293 addLink(url, arg, &html);
3301 html += src.at(i++);
3310 html.reserve(src.size());
3313 QLatin1StringView tag;
3314 QLatin1StringView span;
3316 static constexpr SpanTag spanTags[] = {
3317 {
"comment>"_L1,
"<span class=\"comment\">"_L1},
3318 {
"preprocessor>"_L1,
"<span class=\"preprocessor\">"_L1},
3319 {
"string>"_L1,
"<span class=\"string\">"_L1},
3320 {
"char>"_L1,
"<span class=\"char\">"_L1},
3321 {
"number>"_L1,
"<span class=\"number\">"_L1},
3322 {
"op>"_L1,
"<span class=\"operator\">"_L1},
3323 {
"type>"_L1,
"<span class=\"type\">"_L1},
3324 {
"name>"_L1,
"<span class=\"name\">"_L1},
3325 {
"keyword>"_L1,
"<span class=\"keyword\">"_L1},
3326 {
"template-block>"_L1,
"<span class=\"template-block\">"_L1},
3330 const qsizetype n = src.size();
3331 const QStringView sv(src);
3333 if (sv.at(i) ==
'<'_L1) {
3334 if (i + 1 < n && sv.at(i + 1) ==
'@'_L1) {
3336 bool handled =
false;
3337 for (
const auto &st : spanTags) {
3338 if (i + st.tag.size() <= n
3339 && st.tag == sv.sliced(i, st.tag.size())) {
3348 while (i < n && sv.at(i) !=
'>'_L1)
3354 }
else if (i + 2 < n && sv.at(i + 1) ==
'/'_L1 && sv.at(i + 2) ==
'@'_L1) {
3356 bool handled =
false;
3357 for (
const auto &st : spanTags) {
3358 if (i + st.tag.size() <= n
3359 && st.tag == sv.sliced(i, st.tag.size())) {
3360 html +=
"</span>"_L1;
3368 while (i < n && sv.at(i) !=
'>'_L1)
3386 if (m_linkNode && m_linkNode->isFunction()) {
3388 if (match.hasMatch()) {
3390 qsizetype leftParenLoc = match.capturedStart(1);
3391 out() << protectEnc(atom->string().left(leftParenLoc));
3393 out() << protectEnc(atom->string().mid(leftParenLoc));
3397 out() << protectEnc(atom->string());
3402 return protect(string);
3407 if (string.isEmpty())
3411 if (html.isEmpty()) {
3418 qsizetype n = string.size();
3420 for (
int i = 0; i < n; ++i) {
3421 QChar ch = string.at(i);
3423 if (ch == QLatin1Char(
'&')) {
3425 }
else if (ch == QLatin1Char(
'<')) {
3427 }
else if (ch == QLatin1Char(
'>')) {
3429 }
else if (ch == QChar(8211)) {
3431 }
else if (ch == QChar(8212)) {
3433 }
else if (ch == QLatin1Char(
'"')) {
3436 if (!html.isEmpty())
3441 if (!html.isEmpty())
3450 QString result = Generator::fileBase(node);
3452 result += QLatin1String(
"-obsolete");
3459 return node->name();
3460 return Generator::fileName(node);
3464 const Node *actualNode)
3466 if (actualNode ==
nullptr)
3467 actualNode = apparentNode;
3468 bool link = !linkForNode(actualNode, relative).isEmpty();
3470 out() <<
"<a href=\"" << linkForNode(actualNode, relative);
3472 out() <<
"\" class=\"obsolete";
3475 out() << protectEnc(apparentNode->fullName(relative));
3481
3482
3483
3490 const auto srcLink = Config::instance().getSourceLink();
3491 if (!srcLink.enabled)
3496 if (loc
.isEmpty() || srcLink.baseUrl.isEmpty() || srcLink.rootPath.isEmpty())
3499 QString srcUrl{srcLink.baseUrl};
3500 if (!srcUrl.contains(
'\1'_L1)) {
3501 if (!srcUrl.endsWith(
'/'_L1))
3506 QDir rootDir{srcLink.rootPath};
3507 srcUrl.replace(
'\1'_L1, rootDir.relativeFilePath(loc.filePath()));
3508 srcUrl.replace(
'\2'_L1, QString::number(loc.lineNo()));
3509 const auto &description{
"View declaration of this %1"_L1.arg(node->nodeTypeString())};
3510 out() <<
"<a class=\"srclink\" href=\"%1\" title=\"%2\">%3</a>"_L1
3511 .arg(srcUrl, description, srcLink.linkText);
3518 generateExtractionMark(node, MemberMark);
3519 QString nodeRef =
nullptr;
3522 const QList<Node *> &collective = scn->collective();
3523 if (collective.size() > 1)
3524 out() <<
"<div class=\"fngroup\">\n";
3525 for (
const auto *sharedNode : collective) {
3526 out() << headingStart.arg(getClassAttr(sharedNode,
"fn fngroupitem"_L1),
3527 refForNode(sharedNode));
3528 generateSynopsis(sharedNode, relative, marker, Section::Details);
3529 generateSourceLink(sharedNode);
3530 out() << headingEnd;
3532 if (collective.size() > 1)
3536 if (node->isEnumType(Genus::CPP) && (etn =
static_cast<
const EnumNode *>(node))->flagsType()) {
3537 out() << headingStart.arg(getClassAttr(node,
"flags"_L1), refForNode(node));
3541 generateSourceLink(node);
3542 out() << headingEnd;
3544 out() << headingStart.arg(getClassAttr(node,
"fn"_L1), refForNode(node));
3546 generateSourceLink(node);
3547 out() << headingEnd;
3554 const auto *func =
static_cast<
const FunctionNode *>(node);
3555 if (func->hasOverloads() && (func->isSignal() || func->isSlot()))
3564 const auto property =
static_cast<
const PropertyNode *>(node);
3574 out() <<
"<p><b>Access functions:</b></p>\n";
3575 generateSectionList(section, node, marker);
3582 out() <<
"<p><b>Notifier signal:</b></p>\n";
3583 generateSectionList(notifiers, node, marker);
3587 const auto *enumTypeNode =
static_cast<
const EnumNode *>(node);
3588 if (enumTypeNode->flagsType()) {
3589 out() <<
"<p>The " << protectEnc(enumTypeNode->flagsType()->name())
3590 <<
" type is a typedef for "
3591 <<
"<a href=\"" << m_qflagsHref <<
"\">QFlags</a><"
3592 << protectEnc(enumTypeNode->name()) <<
">. It stores an OR combination of "
3593 << protectEnc(enumTypeNode->name()) <<
" values.</p>\n";
3596 generateAlsoList(node, marker);
3597 generateExtractionMark(node, EndMark);
3601
3602
3603
3604
3609 m_linkNode =
nullptr;
3611 if (!m_link.isEmpty())
3612 out() <<
"<a href=\"" << m_link <<
"\" translate=\"no\">";
3620 if (m_link.isEmpty())
3623 const QString &translate_attr =
3624 (node && isApiGenus(node->genus())) ?
" translate=\"no\""_L1 :
""_L1;
3626 if (node ==
nullptr || (relative !=
nullptr && node->status() == relative->status()))
3627 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3628 else if (node->isDeprecated())
3629 out() <<
"<a href=\"" << m_link <<
"\" class=\"obsolete\"%1>"_L1.arg(translate_attr);
3631 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3640 m_linkNode =
nullptr;
3642 if (!m_link.isEmpty())
3647
3648
3649
3653 if (!members.isEmpty()) {
3655 for (
const auto &member : members) {
3656 out() <<
"<li class=\"fn\" translate=\"no\">";
3657 generateQmlItem(member, relative, marker,
true);
3658 if (member->isPropertyGroup()) {
3659 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
3660 if (scn->count() > 0) {
3662 const QList<Node *> &sharedNodes = scn->collective();
3663 for (
const auto &node : sharedNodes) {
3664 if (node->isQmlProperty()) {
3665 out() <<
"<li class=\"fn\" translate=\"no\">";
3666 generateQmlItem(node, relative, marker,
true);
3680
3681
3684 out() << headingStart.arg(getClassAttr(scn,
"fn qml-member qml-property-group"_L1),
3686 <<
"<b>" << scn->name() <<
" group</b>"
3691
3692
3693
3697 generateExtractionMark(node, MemberMark);
3699 auto generateQmlProperty = [&](
Node *n,
bool isGroupItem =
false) {
3700 const auto cssClasses = isGroupItem ?
"fn qml-member qml-property fngroupitem"_L1 :
"fn qml-member qml-property"_L1;
3701 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3702 generateQmlItem(n, relative, marker,
false);
3703 generateSourceLink(n);
3704 out() << headingEnd;
3707 auto generateQmlMethod = [&](
Node *n,
bool isGroupItem =
false) {
3708 const auto cssClasses = isGroupItem ?
"fn qml-member qml-method fngroupitem"_L1 :
"fn qml-member qml-method"_L1;
3709 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3711 generateSourceLink(n);
3712 out() << headingEnd;
3716 auto *scn =
static_cast<
const SharedCommentNode *>(node);
3717 const auto shared = scn->collective();
3719 if (scn->isPropertyGroup() && !scn->name().isEmpty())
3720 emitGroupHeader(scn);
3722 const bool isGroup = shared.size() > 1;
3725 out() <<
"<div class=\"fngroup\">\n"_L1;
3727 for (
auto *child : std::as_const(shared)) {
3728 if (child->isQmlProperty())
3729 generateQmlProperty(child, isGroup);
3731 generateQmlMethod(child, isGroup);
3735 out() <<
"</div>"_L1;
3738 generateQmlProperty(node);
3740 generateQmlMethod(node);
3747 generateAlsoList(node, marker);
3748 generateExtractionMark(node, EndMark);
3751void HtmlGenerator::generateExtractionMark(
const Node *node, ExtractionMarkType markType)
3753 if (markType != EndMark) {
3754 out() <<
"<!-- $$$" + node->name();
3755 if (markType == MemberMark) {
3757 const auto *func =
static_cast<
const FunctionNode *>(node);
3758 if (!func->hasAssociatedProperties()) {
3759 if (func->overloadNumber() == 0)
3760 out() <<
"[overload1]";
3761 out() <<
"$$$" + func->name() + func->parameters().rawSignature().remove(
' ');
3765 const auto *prop =
static_cast<
const PropertyNode *>(node);
3766 const NodeList &list = prop->functions();
3767 for (
const auto *propFuncNode : list) {
3768 if (propFuncNode->isFunction()) {
3769 const auto *func =
static_cast<
const FunctionNode *>(propFuncNode);
3770 out() <<
"$$$" + func->name()
3771 + func->parameters().rawSignature().remove(
' ');
3775 const auto *enumNode =
static_cast<
const EnumNode *>(node);
3776 const auto &items = enumNode->items();
3777 for (
const auto &item : items)
3778 out() <<
"$$$" + item.name();
3780 }
else if (markType == BriefMark) {
3782 }
else if (markType == DetailedDescriptionMark) {
3783 out() <<
"-description";
3787 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...
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
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.