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);
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";
415 if (!atom->string().isEmpty())
416 out() <<
"<summary>" << protectEnc(atom->string()) <<
"</summary>\n";
418 out() <<
"<summary>...</summary>\n";
421 out() <<
"</details>\n";
425 if (!atom->string().isEmpty())
426 out() <<
' ' << atom->string();
449 if (atom->string().startsWith(
"span "))
450 out() <<
'<' + atom->string() <<
'>';
452 out() << formattingLeftMap()[atom->string()];
460 const Node *node{
nullptr};
461 const Atom tm_link(Atom::NavLink, m_trademarkspage);
462 if (
const auto &link = getLink(&tm_link, relative, &node);
463 !link.isEmpty() && node != relative)
464 out() <<
"<a href=\"%1\">%2</a>"_L1.arg(link, formattingRightMap()[atom->string()]);
466 out() << formattingRightMap()[atom->string()];
469 }
else if (atom->string().startsWith(
"span ")) {
472 out() << formattingRightMap()[atom->string()];
476 if (
const auto *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group); cn)
477 generateList(cn, marker, atom->string(), Generator::sortOrder(atom->strings().last()));
480 const auto sortOrder{Generator::sortOrder(atom->strings().last())};
481 if (atom->string() == QLatin1String(
"annotatedclasses")) {
482 generateAnnotatedList(relative, marker, m_qdb->getCppClasses().values(), sortOrder);
483 }
else if (atom->string() == QLatin1String(
"annotatedexamples")) {
484 generateAnnotatedLists(relative, marker, m_qdb->getExamples());
485 }
else if (atom->string() == QLatin1String(
"annotatedattributions")) {
486 generateAnnotatedLists(relative, marker, m_qdb->getAttributions());
487 }
else if (atom->string() == QLatin1String(
"classes")) {
488 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true,
490 }
else if (atom->string().contains(
"classes ")) {
491 QString rootName = atom->string().mid(atom->string().indexOf(
"classes") + 7).trimmed();
492 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true, rootName);
493 }
else if (atom->string() == QLatin1String(
"qmlvaluetypes")
494 || atom->string() == QLatin1String(
"qmlbasictypes")) {
495 generateCompactList(Generic, relative, m_qdb->getQmlValueTypes(),
true,
497 }
else if (atom->string() == QLatin1String(
"qmltypes")) {
498 generateCompactList(Generic, relative, m_qdb->getQmlTypes(),
true, QStringLiteral(
""));
499 }
else if ((idx = atom->string().indexOf(QStringLiteral(
"bymodule"))) != -1) {
501 QString moduleName = atom->string().mid(idx + 8).trimmed();
503 if (
const auto *cn = qdb->getCollectionNode(moduleName, moduleType)) {
505 switch (moduleType) {
509 generateAnnotatedList(relative, marker, map.values(), sortOrder);
512 if (atom->string().contains(QLatin1String(
"qmlvaluetypes")))
516 generateAnnotatedList(relative, marker, map.values(), sortOrder);
519 generateAnnotatedList(relative, marker, cn->members(), sortOrder);
523 }
else if (atom->string() == QLatin1String(
"classhierarchy")) {
524 generateClassHierarchy(relative, m_qdb->getCppClasses());
525 }
else if (atom->string() == QLatin1String(
"obsoleteclasses")) {
526 generateCompactList(Generic, relative, m_qdb->getObsoleteClasses(),
false,
527 QStringLiteral(
"Q"));
528 }
else if (atom->string() == QLatin1String(
"obsoleteqmltypes")) {
529 generateCompactList(Generic, relative, m_qdb->getObsoleteQmlTypes(),
false,
531 }
else if (atom->string() == QLatin1String(
"obsoletecppmembers")) {
532 generateCompactList(Obsolete, relative, m_qdb->getClassesWithObsoleteMembers(),
false,
533 QStringLiteral(
"Q"));
534 }
else if (atom->string() == QLatin1String(
"obsoleteqmlmembers")) {
535 generateCompactList(Obsolete, relative, m_qdb->getQmlTypesWithObsoleteMembers(),
false,
537 }
else if (atom->string() == QLatin1String(
"functionindex")) {
538 generateFunctionIndex(relative);
539 }
else if (atom->string() == QLatin1String(
"attributions")) {
540 generateAnnotatedList(relative, marker, m_qdb->getAttributions().values(), sortOrder);
541 }
else if (atom->string() == QLatin1String(
"legalese")) {
542 generateLegaleseList(relative, marker);
543 }
else if (atom->string() == QLatin1String(
"overviews")) {
544 generateList(relative, marker,
"overviews", sortOrder);
545 }
else if (atom->string() == QLatin1String(
"cpp-modules")) {
546 generateList(relative, marker,
"cpp-modules", sortOrder);
547 }
else if (atom->string() == QLatin1String(
"qml-modules")) {
548 generateList(relative, marker,
"qml-modules", sortOrder);
549 }
else if (atom->string() == QLatin1String(
"namespaces")) {
550 generateAnnotatedList(relative, marker, m_qdb->getNamespaces().values(), sortOrder);
551 }
else if (atom->string() == QLatin1String(
"related")) {
552 generateList(relative, marker,
"related", sortOrder);
554 const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group);
556 if (!generateGroupList(
const_cast<CollectionNode *>(cn), sortOrder))
558 QString(
"'\\generatelist %1' group is empty").arg(atom->string()));
561 QString(
"'\\generatelist %1' no such group").arg(atom->string()));
566 const NodeMultiMap &nsmap = m_qdb->getSinceMap(atom->string());
570 const NodeMultiMap &ncmap = m_qdb->getClassMap(atom->string());
571 const NodeMultiMap &nqcmap = m_qdb->getQmlTypeMap(atom->string());
576 for (
const auto §ion : sinceSections) {
577 if (!section.members().isEmpty()) {
579 <<
"<a href=\"#" << Utilities::asAsciiPrintable(section.title()) <<
"\">"
580 << section.title() <<
"</a></li>\n";
586 for (
const auto §ion : sinceSections) {
587 if (!section.members().isEmpty()) {
588 out() <<
"<h3 id=\"" << Utilities::asAsciiPrintable(section.title()) <<
"\">"
589 << protectEnc(section.title()) <<
"</h3>\n";
590 if (index == Sections::SinceClasses)
591 generateCompactList(Generic, relative, ncmap,
false, QStringLiteral(
"Q"));
592 else if (index == Sections::SinceQmlTypes)
593 generateCompactList(Generic, relative, nqcmap,
false, QStringLiteral(
""));
594 else if (index == Sections::SinceMemberFunctions
595 || index == Sections::SinceQmlMethods
596 || index == Sections::SinceQmlProperties) {
598 QMap<QString, NodeMultiMap> parentmaps;
600 const QList<Node *> &members = section.members();
601 for (
const auto &member : members) {
602 QString parent_full_name = (*member).parent()->fullName();
604 auto parent_entry = parentmaps.find(parent_full_name);
605 if (parent_entry == parentmaps.end())
606 parent_entry = parentmaps.insert(parent_full_name, NodeMultiMap());
607 parent_entry->insert(member->name(), member);
610 for (
auto map = parentmaps.begin(); map != parentmaps.end(); ++map) {
611 NodeVector nv = map->values().toVector();
612 auto parent = nv.front()->parent();
614 out() << ((index == Sections::SinceMemberFunctions) ?
"<p>Class " :
"<p>QML Type ");
616 out() <<
"<a href=\"" << linkForNode(parent, relative) <<
"\" translate=\"no\">";
617 QStringList pieces = parent->fullName().split(
"::");
618 out() << protectEnc(pieces.last());
622 generateSection(nv, relative, marker);
625 }
else if (index == Sections::SinceEnumValues) {
626 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
627 const auto map_it = m_qdb->newEnumValueMaps().constFind(atom->string());
628 for (
auto it = map_it->cbegin(); it != map_it->cend(); ++it) {
629 out() <<
"<tr><td class=\"memItemLeft\"> enum value </td><td class=\"memItemRight\">"
630 <<
"<b><a href=\"" << linkForNode(it.value(),
nullptr) <<
"\">"
631 << it.key() <<
"</a></b></td></tr>\n";
633 out() <<
"</table></div>\n";
635 generateSection(section.members(), relative, marker);
653 out() <<
"<p class=\"centerAlign\">";
655 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
656 if (!maybe_resolved_file) {
659 QStringLiteral(
"Missing image: %1").arg(protectEnc(atom->string())));
660 out() <<
"<font color=\"red\">[Missing image " << protectEnc(atom->string())
664 QString file_name{QFileInfo{file.get_path()}.fileName()};
684 "%1/%2"_L1.arg(outputDir(), imagesOutputDir()));
686 const auto &imgPath =
"%1/%2"_L1.arg(imagesOutputDir(), file_name);
688 out() <<
"<img src=\"%1\""_L1.arg(protectEnc(imgPath));
690 const QString altAndTitleText = protectEnc(text);
691 out() <<
" alt=\"" << altAndTitleText;
693 out() <<
"\" title=\"" << altAndTitleText;
697 m_helpProjectWriter->addExtraFile(imgPath);
698 setImageFileName(relative, imgPath);
710 QString admonType = atom->typeString();
713 out() <<
"<div class=\"admonition " << admonType.toLower() <<
"\">\n"
716 out() << admonType <<
": ";
726 out() <<
"<div class=\"LegaleseLeft\">";
740 const Node *node =
nullptr;
741 QString link = getLink(atom, relative, &node);
743 Location location = atom->isLinkAtom() ?
static_cast<
const LinkAtom*>(atom)->location
744 : relative->doc().location();
746 QStringLiteral(
"Can't link to '%1'").arg(atom->string()));
748 beginLink(link, node, relative);
752 QString link = linkForExampleFile(atom->string());
757 QString link = atom->string();
758 link =
"images/used-in-examples/" + link;
763 const Node *node =
static_cast<
const Node*>(Utilities::nodeForString(atom->string()));
764 beginLink(linkForNode(node, relative), node, relative);
777 out() << R"(<div class="table"><table class="valuelist">)";
778 m_threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom);
779 if (m_threeColumnEnumValueTable) {
780 if (++m_numTableRows % 2 == 1)
781 out() << R"(<tr valign="top" class="odd">)";
783 out() << R"(<tr valign="top" class="even">)";
785 out() <<
"<th class=\"tblConst\">Constant</th>";
789 out() <<
"<th class=\"tblval\">Value</th>";
791 out() <<
"<th class=\"tbldscr\">Description</th></tr>\n";
793 out() <<
"<tr><th class=\"tblConst\">Constant</th><th "
794 "class=\"tblVal\">Value</th></tr>\n";
811 out() << QString(R"(<ol class="%1" type="%1" start="%2">)")
812 .arg(olType, atom
->next()->string());
814 out() << QString(R"(<ol class="%1" type="%1">)").arg(olType);
823 std::pair<QString,
int> pair = getAtomListValue(atom);
824 skipAhead = pair.second;
825 QString t = protectEnc(plainCode(marker->markedUpEnumValue(pair.first, relative)));
826 out() <<
"<tr><td class=\"topAlign\"><code translate=\"no\">" << t <<
"</code>";
829 out() <<
"</td><td class=\"topAlign tblval\">";
830 const auto *enume =
static_cast<
const EnumNode *>(relative);
831 QString itemValue = enume->itemValue(atom->next()->string());
832 if (itemValue.isEmpty())
835 out() <<
"<code translate=\"no\">" << protectEnc(itemValue) <<
"</code>";
848 if (m_threeColumnEnumValueTable) {
849 out() <<
"</td><td class=\"topAlign\">";
856 if (matchAhead(atom, Atom::ParaLeft))
863 out() <<
"</td></tr>\n";
874 out() <<
"</table></div>\n";
895 out() <<
"<blockquote>";
898 out() <<
"</blockquote>\n";
901 out() << atom->string();
907 int unit = atom->string().toInt() +
hOffset(relative
);
908 out() <<
"<h" + QString::number(unit) + QLatin1Char(
' ') <<
"id=\""
909 << Tree::refForAtom(atom) <<
"\">";
910 m_inSectionHeading =
true;
913 case Atom::SectionHeadingRight:
914 out() <<
"</h" + QString::number(atom->string().toInt() + hOffset(relative)) +
">\n";
915 m_inSectionHeading =
false;
922 if (m_inLink && !m_inContents && !m_inSectionHeading) {
925 out() << protectEnc(atom->string());
929 std::pair<QString, QString> pair = getTableWidthAttr(atom);
930 QString attr = pair.second;
931 QString width = pair.first;
938 out() << R"(<div class="table"><table class=")" << attr <<
'"';
939 if (!width.isEmpty())
940 out() <<
" width=\"" << width <<
'"';
945 out() <<
"</table></div>\n";
948 out() <<
"<thead><tr class=\"qt-style\">";
949 m_inTableHeader =
true;
955 out() <<
"\n<tr class=\"qt-style\">";
957 out() <<
"</thead>\n";
958 m_inTableHeader =
false;
962 if (!atom->string().isEmpty())
963 out() <<
"<tr " << atom->string() <<
'>';
964 else if (++m_numTableRows % 2 == 1)
965 out() << R"(<tr valign="top" class="odd">)";
967 out() << R"(<tr valign="top" class="even">)";
978 for (
int i = 0; i < atom->count(); ++i) {
981 const QString &p = atom->string(i);
982 if (p.contains(
'=')) {
985 QStringList spans = p.split(QLatin1Char(
','));
986 if (spans.size() == 2) {
987 if (spans.at(0) !=
"1")
988 out() <<
" colspan=\"" << spans.at(0) <<
'"';
989 if (spans.at(1) !=
"1")
990 out() <<
" rowspan=\"" << spans.at(1) <<
'"';
995 if (matchAhead(atom, Atom::ParaLeft))
1004 if (matchAhead(atom, Atom::ParaLeft))
1014 out() <<
"<span id=\"" << Utilities::asAsciiPrintable(atom->string()) <<
"\"></span>";
1017 out() <<
"<b class=\"redFont\"><Missing HTML></b>";
1019 case Atom::UnknownCommand:
1020 out() << R"(<b class="redFont"><code translate=\"no\">\)" << protectEnc(atom->string()) <<
"</code></b>";
1038
1039
1040
1041
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
1068 auto link_for_group = [
this](
const CollectionNode *group) -> QString {
1069 QString target{linkForNode(group,
nullptr)};
1070 return (target.isEmpty()) ? protectEnc(group->name()) :
"<a href=\"" + target +
"\">" + protectEnc(group->fullTitle()) +
"</a>";
1075 const QStringList &groups_names{node->groupNames()};
1076 if (groups_names.isEmpty())
1079 std::vector<CollectionNode *> groups_nodes(groups_names.size(),
nullptr);
1080 std::transform(groups_names.cbegin(), groups_names.cend(), groups_nodes.begin(),
1083 m_qdb->mergeCollections(group);
1084 return (group && group
->wasSeen()) ? group :
nullptr;
1086 groups_nodes.erase(
std::remove(groups_nodes.begin(), groups_nodes.end(),
nullptr), groups_nodes.end());
1088 if (!groups_nodes.empty()) {
1089 text += node->name() +
" is part of ";
1091 for (std::vector<CollectionNode *>::size_type index{0}; index < groups_nodes.size(); ++index) {
1092 text += link_for_group(groups_nodes[index]) + Utilities::separator(index, groups_nodes.size());
1099
1100
1101
1102
1113 QString typeWord = aggregate->typeWord(
true);
1116 fullTitle = aggregate->plainFullName();
1117 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1118 ns =
static_cast<NamespaceNode *>(aggregate);
1122 fullTitle = aggregate->plainFullName();
1123 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();
1136 if (aggregate
->parent()->isInAPI() || templateDecl) {
1138 subtitleText <<
"%1 "_L1.arg((*templateDecl).to_qstring());
1139 subtitleText << aggregate->typeWord(
false) <<
" "_L1;
1140 auto ancestors = fullTitle.split(
"::"_L1);
1141 ancestors.pop_back();
1142 for (
const auto &a : ancestors)
1143 subtitleText << Atom(Atom::AutoLink, a) <<
"::"_L1;
1144 subtitleText << aggregate->plainName();
1147 generateHeader(title, aggregate, marker);
1148 generateTableOfContents(aggregate, marker, summarySections);
1150 generateTitle(titleText, subtitleText, SmallSubTitle, aggregate, marker);
1152 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1156 brief <<
"The " << ns->name() <<
" namespace includes the following elements from module "
1159 addNodeLink(brief, fullNamespace,
" here.");
1161 generateText(brief, ns, marker);
1164 generateBrief(aggregate, marker);
1166 const auto parentIsClass = aggregate
->parent()->isClassNode();
1169 generateRequisites(aggregate, marker);
1174 QString membersLink = generateAllMembersFile(Sections::allMembersSection(), marker);
1175 if (!membersLink.isEmpty()) {
1176 openUnorderedList();
1177 out() <<
"<li><a href=\"" << membersLink <<
"\">"
1178 <<
"List of all members, including inherited members</a></li>\n";
1180 QString obsoleteLink = generateObsoleteMembersFile(sections, marker);
1181 if (!obsoleteLink.isEmpty()) {
1182 openUnorderedList();
1183 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1184 <<
"Deprecated members</a></li>\n";
1187 if (QString groups_text{groupReferenceText(aggregate)}; !groups_text.isEmpty()) {
1188 openUnorderedList();
1190 out() <<
"<li>" << groups_text <<
"</li>\n";
1193 closeUnorderedList();
1198 bool needOtherSection =
false;
1200 for (
const auto §ion : std::as_const(*summarySections)) {
1201 if (section.members().isEmpty() && section.reimplementedMembers().isEmpty()) {
1202 if (!section.inheritedMembers().isEmpty())
1203 needOtherSection =
true;
1205 if (!section.members().isEmpty()) {
1206 QString ref = registerRef(section.title().toLower());
1207 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1208 generateSection(section.members(), aggregate, marker);
1210 if (!section.reimplementedMembers().isEmpty()) {
1211 QString name = QString(
"Reimplemented ") + section.title();
1212 QString ref = registerRef(name.toLower());
1213 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(name) <<
"</h2>\n";
1214 generateSection(section.reimplementedMembers(), aggregate, marker);
1217 if (!section.inheritedMembers().isEmpty()) {
1219 generateSectionInheritedList(section, aggregate);
1225 if (needOtherSection) {
1226 out() <<
"<h3>Additional Inherited Members</h3>\n"
1229 for (
const auto §ion : std::as_const(*summarySections)) {
1230 if (section.members().isEmpty() && !section.inheritedMembers().isEmpty())
1231 generateSectionInheritedList(section, aggregate);
1236 if (aggregate
->doc().isEmpty()) {
1237 QString command =
"documentation";
1239 command = R"('\class' comment)";
1242 QStringLiteral(
"No %1 for '%2'").arg(command, aggregate->plainSignature()));
1245 generateExtractionMark(aggregate, DetailedDescriptionMark);
1246 out() <<
"<div class=\"descr\">\n"
1247 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1248 <<
"Detailed Description"
1251 out() <<
"</div>\n";
1252 generateAlsoList(aggregate, marker);
1253 generateExtractionMark(aggregate, EndMark);
1256 for (
const auto §ion : std::as_const(*detailsSections)) {
1257 bool headerGenerated =
false;
1258 if (section.isEmpty())
1261 const QList<Node *> &members = section.members();
1262 for (
const auto &member : members) {
1263 if (!headerGenerated) {
1264 if (!section.divClass().isEmpty())
1265 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1266 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1267 headerGenerated =
true;
1269 if (!member->isClassNode())
1270 generateDetailedMember(member, aggregate, marker);
1273 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1274 out() <<
" class=\"%1\""_L1.arg(attrs);
1275 out() <<
"> class ";
1276 generateFullName(member, aggregate);
1278 generateBrief(member, marker, aggregate);
1281 if (headerGenerated && !section.divClass().isEmpty())
1282 out() <<
"</div>\n";
1284 generateFooter(aggregate);
1299 rawTitle = aggregate->plainName();
1300 fullTitle = aggregate->plainFullName();
1301 title = rawTitle +
" Proxy Page";
1304 generateHeader(title, aggregate, marker);
1305 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1306 generateBrief(aggregate, marker);
1307 for (
auto it = summarySections->constBegin(); it != summarySections->constEnd(); ++it) {
1308 if (!it->members().isEmpty()) {
1309 QString ref = registerRef(it->title().toLower());
1310 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(it->title()) <<
"</h2>\n";
1311 generateSection(it->members(), aggregate, marker);
1315 if (!aggregate
->doc().isEmpty()) {
1316 generateExtractionMark(aggregate, DetailedDescriptionMark);
1317 out() <<
"<div class=\"descr\">\n"
1318 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1319 <<
"Detailed Description"
1322 out() <<
"</div>\n";
1323 generateAlsoList(aggregate, marker);
1324 generateExtractionMark(aggregate, EndMark);
1327 for (
const auto §ion : std::as_const(*detailsSections)) {
1328 if (section.isEmpty())
1331 if (!section.divClass().isEmpty())
1332 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1333 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1335 const QList<Node *> &members = section.members();
1336 for (
const auto &member : members) {
1337 if (!member->isClassNode()) {
1338 generateDetailedMember(member, aggregate, marker);
1341 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1342 out() <<
" class=\"%1\""_L1.arg(attrs);
1343 out() <<
"> class ";
1344 generateFullName(member, aggregate);
1346 generateBrief(member, marker, aggregate);
1349 if (!section.divClass().isEmpty())
1350 out() <<
"</div>\n";
1352 generateFooter(aggregate);
1356
1357
1358
1362 SubTitleSize subTitleSize = LargeSubTitle;
1363 QString htmlTitle = qcn->name();
1365 htmlTitle.append(
" QML Value Type");
1367 htmlTitle.append(
" QML Type");
1370 htmlTitle.append(
" (Singleton)"_L1);
1372 generateHeader(htmlTitle, qcn, marker);
1374 generateTableOfContents(qcn, marker, §ions.stdQmlTypeSummarySections());
1375 marker = CodeMarker::markerForLanguage(QLatin1String(
"QML"));
1376 generateTitle(htmlTitle,
Text() << qcn->subtitle(), subTitleSize, qcn, marker);
1377 generateBrief(qcn, marker);
1378 generateQmlRequisites(qcn, marker);
1382 out() <<
"<p><strong>Note:</strong> This type is a QML singleton. "_L1
1383 <<
"There is only one instance of this type in the QML engine.</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 : stdQmlTypeSummarySections) {
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 : stdQmlTypeDetailsSections) {
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);
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;
1725 out() <<
"<!DOCTYPE html>\n";
1726 out() << QString(
"<html lang=\"%1\">\n").arg(naturalLanguage);
1727 out() <<
"<head>\n";
1728 out() <<
" <meta charset=\"utf-8\">\n";
1733 out() <<
" <meta name=\"description\" content=\""
1734 << protectEnc(node->doc().briefText().toString())
1741 QStringList keywords;
1742 for (
const auto &kw : metaTags->values(u"keywords"_s))
1743 keywords << kw.split(
','_L1, Qt::SkipEmptyParts);
1745 if (!keywords.isEmpty()) {
1746 std::transform(keywords.begin(), keywords.end(), keywords.begin(),
1747 [](
const QString &k) {
return k.trimmed(); });
1748 out() <<
" <meta name=\"keywords\" content=\""
1749 << protectEnc(keywords.join(
','_L1))
1756 QString titleSuffix;
1757 if (!m_landingtitle.isEmpty()) {
1759 titleSuffix = m_landingtitle;
1760 }
else if (!m_hometitle.isEmpty()) {
1763 if (title != m_hometitle)
1764 titleSuffix = m_hometitle;
1767 titleSuffix = m_productName.isEmpty() ? m_project : m_productName;
1769 if (title == titleSuffix)
1770 titleSuffix.clear();
1772 out() <<
" <title>";
1773 if (!titleSuffix.isEmpty() && !title.isEmpty()) {
1774 out() <<
"%1 | %2"_L1.arg(protectEnc(title), titleSuffix);
1776 out() << protectEnc(title);
1781 QVersionNumber projectVersion = QVersionNumber::fromString(m_qdb->version());
1782 if (!projectVersion.isNull()) {
1783 QVersionNumber titleVersion;
1784 static const QRegularExpression re(QLatin1String(R"(\d+\.\d+)"));
1785 const QString &versionedTitle = titleSuffix.isEmpty() ? title : titleSuffix;
1786 auto match = re.match(versionedTitle);
1787 if (match.hasMatch())
1788 titleVersion = QVersionNumber::fromString(match.captured());
1789 if (titleVersion.isNull() || !titleVersion.isPrefixOf(projectVersion)) {
1791 if (!m_productName.isEmpty() && titleSuffix != m_productName)
1792 out() <<
" | %1"_L1.arg(m_productName);
1793 out() <<
" %1"_L1.arg(projectVersion.toString());
1796 out() <<
"</title>\n";
1799 out() << m_headerStyles;
1800 out() << m_headerScripts;
1801 out() << m_endHeader;
1803 out() << QString(m_postHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1804 bool usingTable = m_postHeader.trimmed().endsWith(QLatin1String(
"<tr>"));
1805 generateNavigationBar(title, node, marker, m_buildversion, usingTable);
1806 out() << QString(m_postPostHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1808 m_navigationLinks.clear();
1811 if (node && !node->links().empty()) {
1812 std::pair<QString, QString> linkPair;
1813 std::pair<QString, QString> anchorPair;
1814 const Node *linkNode;
1815 bool useSeparator =
false;
1817 if (node->links().contains(Node::PreviousLink)) {
1818 linkPair = node->links()[Node::PreviousLink];
1819 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1822 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1823 if (linkNode ==
nullptr || linkNode == node)
1824 anchorPair = linkPair;
1826 anchorPair = anchorForNode(linkNode);
1828 out() << R"( <link rel="prev" href=")" << anchorPair.first <<
"\" />\n";
1830 m_navigationLinks += R"(<a class="prevPage" href=")" + anchorPair.first +
"\">";
1831 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
1832 m_navigationLinks += protect(anchorPair.second);
1834 m_navigationLinks += protect(linkPair.second);
1835 m_navigationLinks +=
"</a>\n";
1836 useSeparator = !m_navigationSeparator.isEmpty();
1838 if (node->links().contains(Node::NextLink)) {
1839 linkPair = node->links()[Node::NextLink];
1840 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1843 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1844 if (linkNode ==
nullptr || linkNode == node)
1845 anchorPair = linkPair;
1847 anchorPair = anchorForNode(linkNode);
1849 out() << R"( <link rel="next" href=")" << anchorPair.first <<
"\" />\n";
1852 m_navigationLinks += m_navigationSeparator;
1854 m_navigationLinks += R"(<a class="nextPage" href=")" + anchorPair.first +
"\">";
1855 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
1856 m_navigationLinks += protect(anchorPair.second);
1858 m_navigationLinks += protect(linkPair.second);
1859 m_navigationLinks +=
"</a>\n";
1861 if (node->links().contains(Node::StartLink)) {
1862 linkPair = node->links()[Node::StartLink];
1863 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1866 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1867 if (linkNode ==
nullptr || linkNode == node)
1868 anchorPair =
std::move(linkPair);
1870 anchorPair = anchorForNode(linkNode);
1871 out() << R"( <link rel="start" href=")" << anchorPair.first <<
"\" />\n";
1875 if (node && !node->links().empty())
1876 out() <<
"<p class=\"naviNextPrevious headerNavi\">\n" << m_navigationLinks <<
"</p>\n";
1880 SubTitleSize subTitleSize,
const Node *relative,
1883 out() << QString(m_prologue).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1886 attribute = R"( translate="no")";
1889 out() <<
"<h1 class=\"title\"" << attribute <<
">";
1890 generateText(title, relative, marker);
1895 if (subTitleSize == SmallSubTitle)
1896 out() <<
" class=\"small-subtitle\"" << attribute <<
">";
1898 out() <<
" class=\"subtitle\"" << attribute <<
">";
1899 generateText(subtitle, relative, marker);
1900 out() <<
"</span>\n";
1906 if (node && !node->links().empty())
1907 out() <<
"<p class=\"naviNextPrevious footerNavi\">\n" << m_navigationLinks <<
"</p>\n";
1909 out() << QString(m_footer).replace(
"\\" +
COMMAND_VERSION, m_qdb->version())
1910 << QString(m_address).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1912 out() <<
"</body>\n";
1913 out() <<
"</html>\n";
1917
1918
1919
1922 QMap<QString, Text> requisites;
1925 const QString headerText =
"Header";
1926 const QString sinceText =
"Since";
1927 const QString inheritedByText =
"Inherited By";
1928 const QString inheritsText =
"Inherits";
1929 const QString nativeTypeText =
"In QML";
1930 const QString qtVariableText =
"qmake";
1931 const QString cmakeText =
"CMake";
1932 const QString statusText =
"Status";
1935 const QStringList requisiteorder { headerText, cmakeText, qtVariableText, sinceText,
1936 nativeTypeText, inheritsText, inheritedByText, statusText };
1938 addIncludeFileToMap(aggregate, requisites, text, headerText);
1939 addSinceToMap(aggregate, requisites, &text, sinceText);
1942 addCMakeInfoToMap(aggregate, requisites, &text, cmakeText);
1943 addQtVariableToMap(aggregate, requisites, &text, qtVariableText);
1947 auto *classe =
dynamic_cast<
ClassNode *>(aggregate);
1949 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1951 if (InclusionFilter::isIncluded(policy, context))
1952 addQmlNativeTypesToMap(requisites, &text, nativeTypeText, classe);
1955 addInheritsToMap(requisites, &text, inheritsText, classe);
1956 addInheritedByToMap(requisites, &text, inheritedByText, classe);
1960 addStatusToMap(aggregate, requisites, text, statusText);
1962 if (!requisites.isEmpty()) {
1964 generateTheTable(requisiteorder, requisites, aggregate, marker);
1969
1970
1971void HtmlGenerator::generateTheTable(
const QStringList &requisiteOrder,
1972 const QMap<QString, Text> &requisites,
1975 out() <<
"<div class=\"table\"><table class=\"alignedsummary requisites\" translate=\"no\">\n";
1977 for (
auto it = requisiteOrder.constBegin(); it != requisiteOrder.constEnd(); ++it) {
1979 if (requisites.contains(*it)) {
1981 <<
"<td class=\"memItemLeft rightAlign topAlign\"> " << *it
1983 "</td><td class=\"memItemRight bottomAlign\"> ";
1985 generateText(requisites.value(*it), aggregate, marker);
1986 out() <<
"</td></tr>\n";
1989 out() <<
"</table></div>\n";
1993
1994
1995
1996void HtmlGenerator::addInheritedByToMap(QMap<QString, Text> &requisites,
Text *text,
1997 const QString &inheritedByText,
ClassNode *classe)
1999 if (!classe->derivedClasses().isEmpty()) {
2002 int count = appendSortedNames(*text, classe, classe->derivedClasses());
2005 requisites.insert(inheritedByText, *text);
2010
2011
2012
2013void HtmlGenerator::addInheritsToMap(QMap<QString, Text> &requisites,
Text *text,
2014 const QString &inheritsText,
ClassNode *classe)
2016 if (!classe->baseClasses().isEmpty()) {
2019 const auto baseClasses = classe->baseClasses();
2020 for (
const auto &cls : baseClasses) {
2022 appendFullName(*text, cls.m_node, classe);
2024 if (cls.m_access == Access::Protected) {
2025 *text <<
" (protected)";
2026 }
else if (cls.m_access == Access::Private) {
2027 *text <<
" (private)";
2029 *text << Utilities::comma(index++, classe->baseClasses().size());
2034 requisites.insert(inheritsText, *text);
2039
2040
2041
2042void HtmlGenerator::addQmlNativeTypesToMap(QMap<QString, Text> &requisites,
Text *text,
2043 const QString &nativeTypeText,
ClassNode *classe)
const
2050 QList<QmlTypeNode *> nativeTypes { classe->qmlNativeTypes().cbegin(), classe->qmlNativeTypes().cend()};
2052 qsizetype index { 0 };
2054 for (
const auto &item : std::as_const(nativeTypes)) {
2055 addNodeLink(*text, item);
2056 *text << Utilities::comma(index++, nativeTypes.size());
2058 requisites.insert(nativeTypeText, *text);
2062
2063
2064
2066 Text *text,
const QString &CMakeInfo)
const
2068 if (!aggregate->physicalModuleName().isEmpty() && text !=
nullptr) {
2070 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2072 const auto result = cmakeRequisite(cn);
2085 requisites.insert(CMakeInfo, *text);
2090
2091
2092
2094 Text *text,
const QString &qtVariableText)
const
2096 if (!aggregate->physicalModuleName().isEmpty()) {
2098 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2100 if (cn && !cn->qtVariable().isEmpty()) {
2103 requisites.insert(qtVariableText, *text);
2109
2110
2111
2112
2114 Text *text,
const QString &sinceText)
const
2116 if (!aggregate->since().isEmpty() && text !=
nullptr) {
2119 requisites.insert(sinceText, *text);
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2135 Text &text,
const QString &statusText)
const
2137 auto status{formatStatus(aggregate, m_qdb)};
2143 spanClass = u"deprecated"_s;
2145 spanClass = Utilities::asAsciiPrintable(status.value());
2148 text << Atom(Atom::String, status.value())
2150 "class=\"status %1\""_L1.arg(spanClass))
2152 requisites.insert(statusText, text);
2156
2157
2158
2159
2161 QMap<QString, Text> &requisites,
Text& text,
2162 const QString &headerText)
2164 if (aggregate->includeFile()) {
2166 text << openCodeTag <<
"#include <%1>"_L1.arg(*aggregate->includeFile()) << closeCodeTag;
2167 requisites.insert(headerText, text);
2172
2173
2174
2180 QMap<QString, Text> requisites;
2183 const QString importText =
"Import Statement";
2184 const QString sinceText =
"Since";
2185 const QString inheritedByText =
"Inherited By";
2186 const QString inheritsText =
"Inherits";
2187 const QString nativeTypeText =
"In C++";
2188 const QString statusText =
"Status";
2191 QString logicalModuleVersion;
2196 bool generate_import =
true;
2198 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2202 if (generate_import) {
2206 requisites.insert(importText, text);
2209 qcn
->doc().location().warning(QStringLiteral(
"Could not resolve QML import statement for type '%1'").arg(qcn->name()),
2214 if (!qcn->since().isEmpty()) {
2217 requisites.insert(sinceText, text);
2222 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2226 addNodeLink(text, cn);
2227 requisites.insert(nativeTypeText, text);
2235 QStringList knownTypeNames{qcn->name()};
2237 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2245 knownTypeNames << base->name();
2248 addNodeLink(text, base);
2251 for (
const auto sub : std::as_const(subs)) {
2252 if (knownTypeNames.contains(sub->name())) {
2253 text << Atom(Atom::String,
" (%1)"_L1.arg(base->logicalModuleName()));
2258 requisites.insert(inheritsText, text);
2262 if (!subs.isEmpty()) {
2265 int count = appendSortedQmlNames(text, qcn, knownTypeNames, subs);
2268 requisites.insert(inheritedByText, text);
2272 addStatusToMap(qcn, requisites, text, statusText);
2275 const QStringList requisiteorder {
std::move(importText),
std::move(sinceText),
2276 std::move(nativeTypeText),
std::move(inheritsText),
2277 std::move(inheritedByText),
std::move(statusText)};
2279 if (!requisites.isEmpty())
2280 generateTheTable(requisiteorder, requisites, qcn, marker);
2292 QStringLiteral(
"'\\brief' statement does not end with a full stop."));
2294 generateExtractionMark(node, BriefMark);
2296 generateText(brief, node, marker);
2299 if (!relative || node == relative)
2300 out() <<
" <a href=\"#";
2302 out() <<
" <a href=\"" << linkForNode(node, relative) <<
'#';
2303 out() << registerRef(
"details") <<
"\">More...</a>";
2307 generateExtractionMark(node, EndMark);
2312
2313
2314
2316 QList<Section> *sections)
2320 toc = node
->doc().tableOfContents();
2321 if (tocDepth == 0 || (toc.isEmpty() && !sections && !node
->isModule())) {
2326 int sectionNumber = 1;
2327 int detailsBase = 0;
2330 m_inContents =
true;
2332 out() <<
"<div class=\"sidebar\">\n";
2333 out() <<
"<div class=\"toc\">\n";
2334 out() <<
"<h3 id=\"toc\">Contents</h3>\n";
2337 openUnorderedList();
2338 if (!
static_cast<
const CollectionNode *>(node)->noAutoList()) {
2340 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2341 << registerRef(
"namespaces") <<
"\">Namespaces</a></li>\n";
2344 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2345 << registerRef(
"classes") <<
"\">Classes</a></li>\n";
2348 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#" << registerRef(
"details")
2349 <<
"\">Detailed Description</a></li>\n";
2350 for (
const auto &entry : std::as_const(toc)) {
2351 if (entry->string().toInt() == 1) {
2357 for (
const auto §ion : std::as_const(*sections)) {
2358 if (!section.members().isEmpty()) {
2359 openUnorderedList();
2360 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2361 << registerRef(section.plural()) <<
"\">" << section.title() <<
"</a></li>\n";
2363 if (!section.reimplementedMembers().isEmpty()) {
2364 openUnorderedList();
2365 QString ref = QString(
"Reimplemented ") + section.plural();
2366 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2367 << registerRef(ref.toLower()) <<
"\">"
2368 << QString(
"Reimplemented ") + section.title() <<
"</a></li>\n";
2372 openUnorderedList();
2373 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2374 << registerRef(
"details") <<
"\">Detailed Description</a></li>\n";
2376 for (
const auto &entry : toc) {
2377 if (entry->string().toInt() == 1) {
2384 for (
const auto &atom : toc) {
2385 sectionNumber = atom->string().toInt() + detailsBase;
2388 if (sectionNumber <= tocDepth || tocDepth < 0) {
2389 openUnorderedList();
2391 Text headingText = Text::sectionHeading(atom);
2392 out() <<
"<li class=\"level" << sectionNumber <<
"\">";
2393 out() <<
"<a href=\"" <<
'#' << Tree::refForAtom(atom) <<
"\">";
2394 generateAtomList(headingText.firstAtom(), node, marker,
true, numAtoms);
2395 out() <<
"</a></li>\n";
2398 closeUnorderedList();
2399 out() <<
"</div>\n";
2400 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2401 out() <<
"</div>\n";
2402 m_inContents =
false;
2407
2408
2411 out() <<
"<div class=\"sidebar\">";
2412 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2413 out() <<
"</div>\n";
2422 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2423 beginSubPage(aggregate, fileName);
2424 QString title =
"List of All Members for " + aggregate->plainFullName();
2425 generateHeader(title, aggregate, marker);
2427 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2428 out() <<
"<p>This is the complete list of members for ";
2429 generateFullName(aggregate,
nullptr);
2430 out() <<
", including inherited members.</p>\n";
2432 generateSectionList(section, aggregate, marker);
2440
2441
2442
2443
2444
2452 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2453 beginSubPage(aggregate, fileName);
2454 QString title =
"List of All Members for " + aggregate->name();
2455 generateHeader(title, aggregate, marker);
2457 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2458 out() <<
"<p>This is the complete list of members for ";
2459 generateFullName(aggregate,
nullptr);
2460 out() <<
", including inherited members.</p>\n";
2463 for (
int i = 0; i < cknl.size(); i++) {
2467 if (nodes.isEmpty())
2470 out() <<
"<p>The following members are inherited from ";
2471 generateFullName(qcn,
nullptr);
2474 openUnorderedList();
2475 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2476 for (
int j = 0; j < nodes.size(); j++) {
2477 Node *node = nodes[j];
2484 std::function<
void(
Node *)> generate = [&](Node *n) {
2485 out() <<
"<li class=\"fn\" translate=\"no\">";
2486 generateQmlItem(n, aggregate, marker,
true);
2487 if (n->isQmlProperty()) {
2488 auto qpn =
static_cast<QmlPropertyNode *>(n);
2489 QStringList hints = qpn->hints();
2490 if (qpn->isAttached())
2491 hints <<
"attached"_L1;
2492 if (!hints.isEmpty())
2493 out() <<
" [" << hints.join(
' '_L1) <<
"]";
2494 }
else if (n->isAttached()) {
2496 out() <<
" [attached]";
2499 if (n->isPropertyGroup()) {
2501 const QList<Node *> &collective =
2502 static_cast<SharedCommentNode *>(n)->collective();
2503 std::for_each(collective.begin(), collective.end(), generate);
2510 closeUnorderedList();
2527 QString title =
"Obsolete Members for " + aggregate->plainFullName();
2528 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2530 beginSubPage(aggregate, fileName);
2531 generateHeader(title, aggregate, marker);
2533 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2535 out() <<
"<p><b>The following members of class "
2536 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\" translate=\"no\">"
2537 << protectEnc(aggregate->name()) <<
"</a>"
2538 <<
" are deprecated.</b> "
2539 <<
"They are provided to keep old source code working. "
2540 <<
"We strongly advise against using them in new code.</p>\n";
2542 for (
const auto §ion : summary_spv) {
2543 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2544 generateSectionList(*section, aggregate, marker,
true);
2547 for (
const auto §ion : details_spv) {
2548 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2550 const NodeVector &members = section->obsoleteMembers();
2551 for (
const auto &member : members)
2552 generateDetailedMember(member, aggregate, marker);
2561
2562
2563
2564
2573 QString title =
"Obsolete Members for " + aggregate->name();
2574 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2576 beginSubPage(aggregate, fileName);
2577 generateHeader(title, aggregate, marker);
2579 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2581 out() <<
"<p><b>The following members of QML type "
2582 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\">"
2583 << protectEnc(aggregate->name()) <<
"</a>"
2584 <<
" are deprecated.</b> "
2585 <<
"They are provided to keep old source code working. "
2586 <<
"We strongly advise against using them in new code.</p>\n";
2588 for (
const auto §ion : summary_spv) {
2589 QString ref = registerRef(section->title().toLower());
2590 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section->title()) <<
"</h2>\n";
2591 generateQmlSummary(section->obsoleteMembers(), aggregate, marker);
2594 for (
const auto §ion : details_spv) {
2595 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2596 const NodeVector &members = section->obsoleteMembers();
2597 for (
const auto &member : members) {
2598 generateDetailedQmlMember(member, aggregate, marker);
2610 if (classMap.isEmpty())
2614 for (
const auto &it : classMap) {
2615 auto *classe =
static_cast<ClassNode *>(it);
2616 if (classe->baseClasses().isEmpty())
2617 topLevel.insert(classe->name(), classe);
2620 QStack<NodeMap> stack;
2621 stack.push(topLevel);
2624 while (!stack.isEmpty()) {
2625 if (stack.top().isEmpty()) {
2631 generateFullName(child, relative);
2633 stack.top().erase(stack.top().begin());
2636 const auto derivedClasses = child->derivedClasses();
2637 for (
const RelatedClass &d : derivedClasses) {
2638 if (d.m_node && d.m_node->isInAPI())
2639 newTop.insert(d.m_node->name(), d.m_node);
2641 if (!newTop.isEmpty()) {
2650
2651
2652
2654 const NodeList &unsortedNodes, Qt::SortOrder sortOrder)
2656 if (unsortedNodes.isEmpty() || relative ==
nullptr)
2660 bool allInternal =
true;
2661 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2662 for (
auto *node : unsortedNodes) {
2663 const NodeContext context = node->createContext();
2664 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated()) {
2665 allInternal =
false;
2666 nmm.insert(node->fullName(relative), node);
2671 out() <<
"<div class=\"table\"><table class=\"annotated\">\n";
2675 if (sortOrder == Qt::DescendingOrder)
2680 for (
const auto *node : std::as_const(nodes)) {
2682 out() <<
"<tr class=\"odd topAlign\">";
2684 out() <<
"<tr class=\"even topAlign\">";
2685 out() <<
"<td class=\"tblName\" translate=\"no\"><p>";
2686 generateFullName(node, relative);
2687 out() <<
"</p></td>";
2689 if (!node->isTextPageNode()) {
2690 Text brief = node->doc().trimmedBriefText(node->name());
2691 if (!brief.isEmpty()) {
2692 out() <<
"<td class=\"tblDescr\"><p>";
2693 generateText(brief, node, marker);
2694 out() <<
"</p></td>";
2695 }
else if (!node->reconstitutedBrief().isEmpty()) {
2696 out() <<
"<td class=\"tblDescr\"><p>";
2697 out() << node->reconstitutedBrief();
2698 out() <<
"</p></td>";
2701 out() <<
"<td class=\"tblDescr\"><p>";
2702 if (!node->reconstitutedBrief().isEmpty()) {
2703 out() << node->reconstitutedBrief();
2705 out() << protectEnc(node->doc().briefText().toString());
2706 out() <<
"</p></td>";
2710 out() <<
"</table></div>\n";
2714
2715
2716
2720 const auto &uniqueKeys = nmm.uniqueKeys();
2721 for (
const QString &name : uniqueKeys) {
2722 if (!name.isEmpty()) {
2723 out() <<
"<h2 id=\"" << registerRef(name.toLower()) <<
"\">" << protectEnc(name)
2726 generateAnnotatedList(relative, marker, nmm.values(name));
2731
2732
2733
2734
2735
2736
2737
2738
2739
2742 const QString &commonPrefix)
2747 const int NumParagraphs = 37;
2748 qsizetype commonPrefixLen = commonPrefix.size();
2751
2752
2753
2754
2755
2757 QString paragraphName[NumParagraphs + 1];
2758 QSet<
char> usedParagraphNames;
2760 for (
auto c = nmm.constBegin(); c != nmm.constEnd(); ++c) {
2761 QStringList pieces = c.key().split(
"::");
2762 int idx = commonPrefixLen;
2763 if (idx > 0 && !pieces.last().startsWith(commonPrefix, Qt::CaseInsensitive))
2765 QString last = pieces.last().toLower();
2766 QString key = last.mid(idx);
2768 int paragraphNr = NumParagraphs - 1;
2770 if (key[0].digitValue() != -1) {
2771 paragraphNr = key[0].digitValue();
2772 }
else if (key[0] >= QLatin1Char(
'a') && key[0] <= QLatin1Char(
'z')) {
2773 paragraphNr = 10 + key[0].unicode() -
'a';
2776 paragraphName[paragraphNr] = key[0].toUpper();
2777 usedParagraphNames.insert(key[0].toLower().cell());
2778 paragraph[paragraphNr].insert(last, c.value());
2782
2783
2784
2785
2786
2787
2788
2789 qsizetype paragraphOffset[NumParagraphs + 1];
2790 paragraphOffset[0] = 0;
2791 for (
int i = 0; i < NumParagraphs; i++)
2792 paragraphOffset[i + 1] = paragraphOffset[i] + paragraph[i].size();
2795
2796
2797 if (includeAlphabet) {
2798 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
2799 for (
int i = 0; i < 26; i++) {
2801 if (usedParagraphNames.contains(
char(
'a' + i)))
2802 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
2804 out() <<
"</b></p>\n";
2808
2809
2810 out() <<
"<div class=\"flowListDiv\" translate=\"no\">\n";
2814 QHash<QString,
int> nameOccurrences;
2815 for (
const auto &[key, node] : nmm.asKeyValueRange()) {
2816 QStringList pieces{node->fullName(relative).split(
"::"_L1)};
2817 const QString &name{pieces.last()};
2818 nameOccurrences[name]++;
2822 int curParOffset = 0;
2824 for (
int i = 0; i < nmm.size(); i++) {
2825 while ((curParNr < NumParagraphs) && (curParOffset == paragraph[curParNr].size())) {
2831
2832
2833 if (curParOffset == 0) {
2836 if (++m_numTableRows % 2 == 1)
2837 out() <<
"<dl class=\"flowList odd\">";
2839 out() <<
"<dl class=\"flowList even\">";
2840 out() <<
"<dt class=\"alphaChar\"";
2841 if (includeAlphabet)
2842 out() << QString(
" id=\"%1\"").arg(paragraphName[curParNr][0].toLower());
2843 out() <<
"><b>" << paragraphName[curParNr] <<
"</b></dt>\n";
2847
2848
2850 if ((curParNr < NumParagraphs) && !paragraphName[curParNr].isEmpty()) {
2851 NodeMultiMap::Iterator it;
2852 NodeMultiMap::Iterator next;
2853 it = paragraph[curParNr].begin();
2854 for (
int j = 0; j < curParOffset; j++)
2859
2860
2861
2862 out() <<
"<a href=\"" << linkForNode(it.value(), relative) <<
"\">";
2864 QString fileName = fileBase(it.value()) +
"-obsolete." + fileExtension();
2866 if (useOutputSubdirs())
2867 link =
"../%1/"_L1.arg(it.value()->tree()->physicalModuleName());
2869 out() <<
"<a href=\"" << link <<
"\">";
2872 QStringList pieces{it.value()->fullName(relative).split(
"::"_L1)};
2873 const auto &name{pieces.last()};
2876 if (nameOccurrences[name] > 1) {
2877 const QString moduleName = it.value()->isQmlNode() ? it.value()->logicalModuleName()
2878 : it.value()->tree()->camelCaseModuleName();
2879 pieces.last().append(
": %1"_L1.arg(moduleName));
2882 out() << protectEnc(pieces.last());
2884 if (pieces.size() > 1) {
2886 generateFullName(it.value()->parent(), relative);
2896 out() <<
"</div>\n";
2901 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
2902 for (
int i = 0; i < 26; i++) {
2904 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
2906 out() <<
"</b></p>\n";
2908 char nextLetter =
'a';
2910 out() <<
"<ul translate=\"no\">\n";
2911 NodeMapMap &funcIndex = m_qdb->getFunctionIndex();
2912 for (
auto fnMap = funcIndex.constBegin(); fnMap != funcIndex.constEnd(); ++fnMap) {
2913 const QString &key = fnMap.key();
2914 const QChar firstLetter = key.isEmpty() ? QChar(
'A') : key.front();
2915 Q_ASSERT_X(firstLetter.unicode() < 256,
"generateFunctionIndex",
2916 "Only valid C++ identifiers were expected");
2917 const char currentLetter = firstLetter.isLower() ? firstLetter.unicode() : nextLetter - 1;
2919 if (currentLetter < nextLetter) {
2923 while (nextLetter < currentLetter)
2924 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
2925 Q_ASSERT(nextLetter == currentLetter);
2926 out() << QStringLiteral(
"<li id=\"%1\">").arg(nextLetter++);
2928 out() << protectEnc(key) <<
':';
2930 for (
auto it = (*fnMap).constBegin(); it != (*fnMap).constEnd(); ++it) {
2932 generateFullName((*it)->parent(), relative, *it);
2936 while (nextLetter <=
'z')
2937 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
2944 for (
auto it = legaleseTexts.cbegin(), end = legaleseTexts.cend(); it != end; ++it) {
2945 Text text = it.key();
2946 generateText(text, relative, marker);
2950 generateFullName(it.value(), relative);
2953 }
while (it != legaleseTexts.constEnd() && it.key() == text);
2961 QString marked = marker->markedUpQmlItem(node, summary);
2962 marked.replace(
"@param>",
"i>");
2964 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
2965 .arg(summary ?
"summary"_L1 :
"details"_L1));
2966 marked.replace(
"</@extra>",
"</code>");
2970 marked.remove(
"<@name>");
2971 marked.remove(
"</@name>");
2972 marked.remove(
"<@type>");
2973 marked.remove(
"</@type>");
2975 out() << highlightedCode(marked, relative,
false, Genus::QML);
2979
2980
2981
2982
2983
2984
2985
2988 m_qdb->mergeCollections(cn);
2993 if (sortOrder == Qt::DescendingOrder)
2998 for (
const auto *node : std::as_const(members)) {
2999 out() <<
"<li translate=\"no\">";
3000 generateFullName(node,
nullptr);
3008 const QString &selector, Qt::SortOrder sortOrder)
3012 if (selector == QLatin1String(
"overviews"))
3014 else if (selector == QLatin1String(
"cpp-modules"))
3016 else if (selector == QLatin1String(
"qml-modules"))
3020 m_qdb->mergeCollections(type, cnm, relative);
3021 const auto collectionList = cnm.values();
3022 nodeList.reserve(collectionList.size());
3023 for (
auto *collectionNode : collectionList)
3024 nodeList.append(collectionNode);
3025 generateAnnotatedList(relative, marker, nodeList, sortOrder);
3028
3029
3030
3031
3034 QStringLiteral(
"\\generatelist {%1} is only allowed in \\group, "
3035 "\\module and \\qmlmodule comments.")
3039 auto *node =
const_cast<
Node *>(relative);
3040 auto *collectionNode =
static_cast<CollectionNode *>(node);
3041 if (!collectionNode)
3043 m_qdb->mergeCollections(collectionNode);
3044 generateAnnotatedList(collectionNode, marker, collectionNode->members(), sortOrder);
3050 bool alignNames =
true;
3051 if (!nv.isEmpty()) {
3052 bool twoColumn =
false;
3053 if (nv.first()->isProperty()) {
3054 twoColumn = (nv.size() >= 5);
3058 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3061 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3062 <<
"<tr><td class=\"topAlign\">";
3067 for (
const auto &member : nv) {
3070 out() <<
"<tr><td class=\"memItemLeft rightAlign topAlign\"> ";
3072 if (twoColumn && i == (nv.size() + 1) / 2)
3073 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3074 out() <<
"<li class=\"fn\" translate=\"no\">";
3077 generateSynopsis(member, relative, marker, Section::Summary, alignNames);
3079 out() <<
"</td></tr>\n";
3085 out() <<
"</table></div>\n";
3089 out() <<
"</td></tr>\n</table></div>\n";
3097 bool alignNames =
true;
3100 if (!members.isEmpty()) {
3101 bool hasPrivateSignals =
false;
3102 bool isInvokable =
false;
3103 bool twoColumn =
false;
3106 twoColumn = (members.size() >= 16);
3107 }
else if (members.first()->isProperty()) {
3108 twoColumn = (members.size() >= 5);
3112 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3115 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3116 <<
"<tr><td class=\"topAlign\">";
3121 for (
const auto &member : members) {
3124 if (member->name().isEmpty())
3128 out() <<
"<tr><td class=\"memItemLeft topAlign rightAlign\"> ";
3130 if (twoColumn && i == (members.size() + 1) / 2)
3131 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3132 out() <<
"<li class=\"fn\" translate=\"no\">";
3135 generateSynopsis(member, relative, marker, section.style(), alignNames);
3136 if (member->isFunction()) {
3137 const auto *fn =
static_cast<
const FunctionNode *>(member);
3138 if (fn->isPrivateSignal()) {
3139 hasPrivateSignals =
true;
3141 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3142 }
else if (fn->isInvokable()) {
3145 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3149 out() <<
"</td></tr>\n";
3155 out() <<
"</table></div>\n";
3159 out() <<
"</td></tr>\n</table></div>\n";
3162 if (hasPrivateSignals)
3170 && !section.inheritedMembers().isEmpty()) {
3172 generateSectionInheritedList(section, relative);
3179 const QList<std::pair<Aggregate *,
int>> &inheritedMembers = section.inheritedMembers();
3180 for (
const auto &member : inheritedMembers) {
3181 out() <<
"<li class=\"fn\" translate=\"no\">";
3182 out() << member.second <<
' ';
3183 if (member.second == 1) {
3184 out() << section.singular();
3186 out() << section.plural();
3188 out() <<
" inherited from <a href=\"" << fileName(member.first) <<
'#'
3189 << Generator::cleanRef(section.title().toLower()) <<
"\">"
3190 << protectEnc(member.first->plainFullName(relative)) <<
"</a></li>\n";
3197 QString marked = marker->markedUpSynopsis(node, relative, style);
3198 marked.replace(
"@param>",
"i>");
3201 marked.remove(
"<@name>");
3202 marked.remove(
"</@name>");
3206 static const QRegularExpression extraRegExp(
"<@extra>.*</@extra>",
3207 QRegularExpression::InvertedGreedinessOption);
3208 marked.remove(extraRegExp);
3210 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3211 .arg(style == Section::Summary ?
"summary"_L1 :
"details"_L1));
3212 marked.replace(
"</@extra>",
"</code>");
3216 marked.remove(
"<@type>");
3217 marked.remove(
"</@type>");
3220 out() << highlightedCode(marked, relative, alignNames);
3223QString
HtmlGenerator::highlightedCode(
const QString &markedCode,
const Node *relative,
3224 bool alignNames, Genus genus)
3226 QString src = markedCode;
3228 html.reserve(src.size());
3232 const QChar charLangle =
'<';
3233 const QChar charAt =
'@';
3235 static const QString typeTag(
"type");
3236 static const QString headerTag(
"headerfile");
3237 static const QString funcTag(
"func");
3238 static const QString linkTag(
"link");
3239 static const QString extrefTag(
"extref");
3242 static const QHash<QString, QString> extrefUrls = {
3243 {
"cpp-explicitly-defaulted"_L1,
3244 "https://en.cppreference.com/w/cpp/language/function#Defaulted_functions"_L1},
3245 {
"cpp-deleted-functions"_L1,
3246 "https://en.cppreference.com/w/cpp/language/function#Deleted_functions"_L1},
3253 for (
int i = 0, srcSize = src.size(); i < srcSize;) {
3254 if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
3255 if (alignNames && !done) {
3256 html += QLatin1String(
"</td><td class=\"memItemRight bottomAlign\">");
3260 if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) {
3261 html += QLatin1String(
"<b>");
3262 const Node *n =
static_cast<
const Node*>(Utilities::nodeForString(par1.toString()));
3263 QString link = linkForNode(n, relative);
3264 addLink(link, arg, &html);
3265 html += QLatin1String(
"</b>");
3266 }
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
3267 const FunctionNode *fn = m_qdb->findFunctionNode(par1.toString(), relative, genus);
3268 QString link = linkForNode(fn, relative);
3269 addLink(link, arg, &html);
3270 par1 = QStringView();
3271 }
else if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
3272 par1 = QStringView();
3273 const Node *n = m_qdb->findTypeNode(arg.toString(), relative, genus);
3274 html += QLatin1String(
"<span class=\"type\">");
3277 addLink(linkForNode(n, relative), arg, &html);
3281 addLink(linkForNode(n, relative), arg, &html);
3282 html += QLatin1String(
"</span>");
3283 }
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
3284 par1 = QStringView();
3285 if (arg.startsWith(QLatin1Char(
'&')))
3288 const Node *n = m_qdb->findNodeForInclude(QStringList(arg.toString()));
3289 if (n && n != relative)
3290 addLink(linkForNode(n, relative), arg, &html);
3294 }
else if (parseArg(src, extrefTag, &i, srcSize, &arg, &par1)) {
3295 QString url = extrefUrls.value(par1.toString());
3297 addLink(url, arg, &html);
3305 html += src.at(i++);
3314 html.reserve(src.size());
3317 QLatin1StringView tag;
3318 QLatin1StringView span;
3320 static constexpr SpanTag spanTags[] = {
3321 {
"comment>"_L1,
"<span class=\"comment\">"_L1},
3322 {
"preprocessor>"_L1,
"<span class=\"preprocessor\">"_L1},
3323 {
"string>"_L1,
"<span class=\"string\">"_L1},
3324 {
"char>"_L1,
"<span class=\"char\">"_L1},
3325 {
"number>"_L1,
"<span class=\"number\">"_L1},
3326 {
"op>"_L1,
"<span class=\"operator\">"_L1},
3327 {
"type>"_L1,
"<span class=\"type\">"_L1},
3328 {
"name>"_L1,
"<span class=\"name\">"_L1},
3329 {
"keyword>"_L1,
"<span class=\"keyword\">"_L1},
3330 {
"template-block>"_L1,
"<span class=\"template-block\">"_L1},
3334 const qsizetype n = src.size();
3335 const QStringView sv(src);
3337 if (sv.at(i) ==
'<'_L1) {
3338 if (i + 1 < n && sv.at(i + 1) ==
'@'_L1) {
3340 bool handled =
false;
3341 for (
const auto &st : spanTags) {
3342 if (i + st.tag.size() <= n
3343 && st.tag == sv.sliced(i, st.tag.size())) {
3352 while (i < n && sv.at(i) !=
'>'_L1)
3358 }
else if (i + 2 < n && sv.at(i + 1) ==
'/'_L1 && sv.at(i + 2) ==
'@'_L1) {
3360 bool handled =
false;
3361 for (
const auto &st : spanTags) {
3362 if (i + st.tag.size() <= n
3363 && st.tag == sv.sliced(i, st.tag.size())) {
3364 html +=
"</span>"_L1;
3372 while (i < n && sv.at(i) !=
'>'_L1)
3390 if (m_linkNode && m_linkNode->isFunction()) {
3392 if (match.hasMatch()) {
3394 qsizetype leftParenLoc = match.capturedStart(1);
3395 out() << protectEnc(atom->string().left(leftParenLoc));
3397 out() << protectEnc(atom->string().mid(leftParenLoc));
3401 out() << protectEnc(atom->string());
3406 return protect(string);
3411 if (string.isEmpty())
3415 if (html.isEmpty()) {
3422 qsizetype n = string.size();
3424 for (
int i = 0; i < n; ++i) {
3425 QChar ch = string.at(i);
3427 if (ch == QLatin1Char(
'&')) {
3429 }
else if (ch == QLatin1Char(
'<')) {
3431 }
else if (ch == QLatin1Char(
'>')) {
3433 }
else if (ch == QChar(8211)) {
3435 }
else if (ch == QChar(8212)) {
3437 }
else if (ch == QLatin1Char(
'"')) {
3440 if (!html.isEmpty())
3445 if (!html.isEmpty())
3454 QString result = Generator::fileBase(node);
3456 result += QLatin1String(
"-obsolete");
3463 return node->name();
3464 return Generator::fileName(node);
3468 const Node *actualNode)
3470 if (actualNode ==
nullptr)
3471 actualNode = apparentNode;
3472 bool link = !linkForNode(actualNode, relative).isEmpty();
3474 out() <<
"<a href=\"" << linkForNode(actualNode, relative);
3476 out() <<
"\" class=\"obsolete";
3479 out() << protectEnc(apparentNode->fullName(relative));
3485
3486
3487
3494 const auto srcLink = Config::instance().getSourceLink();
3495 if (!srcLink.enabled)
3500 if (loc
.isEmpty() || srcLink.baseUrl.isEmpty() || srcLink.rootPath.isEmpty())
3503 QString srcUrl{srcLink.baseUrl};
3504 if (!srcUrl.contains(
'\1'_L1)) {
3505 if (!srcUrl.endsWith(
'/'_L1))
3510 QDir rootDir{srcLink.rootPath};
3511 srcUrl.replace(
'\1'_L1, rootDir.relativeFilePath(loc.filePath()));
3512 srcUrl.replace(
'\2'_L1, QString::number(loc.lineNo()));
3513 const auto &description{
"View declaration of this %1"_L1.arg(node->nodeTypeString())};
3514 out() <<
"<a class=\"srclink\" href=\"%1\" title=\"%2\">%3</a>"_L1
3515 .arg(srcUrl, description, srcLink.linkText);
3522 generateExtractionMark(node, MemberMark);
3523 QString nodeRef =
nullptr;
3526 const QList<Node *> &collective = scn->collective();
3527 if (collective.size() > 1)
3528 out() <<
"<div class=\"fngroup\">\n";
3529 for (
const auto *sharedNode : collective) {
3530 out() << headingStart.arg(getClassAttr(sharedNode,
"fn fngroupitem"_L1),
3531 refForNode(sharedNode));
3532 generateSynopsis(sharedNode, relative, marker, Section::Details);
3533 generateSourceLink(sharedNode);
3534 out() << headingEnd;
3536 if (collective.size() > 1)
3540 if (node->isEnumType(Genus::CPP) && (etn =
static_cast<
const EnumNode *>(node))->flagsType()) {
3541 out() << headingStart.arg(getClassAttr(node,
"flags"_L1), refForNode(node));
3545 generateSourceLink(node);
3546 out() << headingEnd;
3548 out() << headingStart.arg(getClassAttr(node,
"fn"_L1), refForNode(node));
3550 generateSourceLink(node);
3551 out() << headingEnd;
3558 const auto *func =
static_cast<
const FunctionNode *>(node);
3559 if (func->hasOverloads() && (func->isSignal() || func->isSlot()))
3568 const auto property =
static_cast<
const PropertyNode *>(node);
3578 out() <<
"<p><b>Access functions:</b></p>\n";
3579 generateSectionList(section, node, marker);
3586 out() <<
"<p><b>Notifier signal:</b></p>\n";
3587 generateSectionList(notifiers, node, marker);
3591 const auto *enumTypeNode =
static_cast<
const EnumNode *>(node);
3592 if (enumTypeNode->flagsType()) {
3593 out() <<
"<p>The " << protectEnc(enumTypeNode->flagsType()->name())
3594 <<
" type is a typedef for "
3595 <<
"<a href=\"" << m_qflagsHref <<
"\">QFlags</a><"
3596 << protectEnc(enumTypeNode->name()) <<
">. It stores an OR combination of "
3597 << protectEnc(enumTypeNode->name()) <<
" values.</p>\n";
3600 generateAlsoList(node, marker);
3601 generateExtractionMark(node, EndMark);
3605
3606
3607
3608
3613 m_linkNode =
nullptr;
3615 if (!m_link.isEmpty())
3616 out() <<
"<a href=\"" << m_link <<
"\" translate=\"no\">";
3624 if (m_link.isEmpty())
3627 const QString &translate_attr =
3628 (node && isApiGenus(node->genus())) ?
" translate=\"no\""_L1 :
""_L1;
3630 if (node ==
nullptr || (relative !=
nullptr && node->status() == relative->status()))
3631 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3632 else if (node->isDeprecated())
3633 out() <<
"<a href=\"" << m_link <<
"\" class=\"obsolete\"%1>"_L1.arg(translate_attr);
3635 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3644 m_linkNode =
nullptr;
3646 if (!m_link.isEmpty())
3651
3652
3653
3657 if (!members.isEmpty()) {
3659 for (
const auto &member : members) {
3660 out() <<
"<li class=\"fn\" translate=\"no\">";
3661 generateQmlItem(member, relative, marker,
true);
3662 if (member->isPropertyGroup()) {
3663 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
3664 if (scn->count() > 0) {
3666 const QList<Node *> &sharedNodes = scn->collective();
3667 for (
const auto &node : sharedNodes) {
3668 if (node->isQmlProperty()) {
3669 out() <<
"<li class=\"fn\" translate=\"no\">";
3670 generateQmlItem(node, relative, marker,
true);
3684
3685
3688 out() << headingStart.arg(getClassAttr(scn,
"fn qml-member qml-property-group"_L1),
3690 <<
"<b>" << scn->name() <<
" group</b>"
3695
3696
3697
3701 generateExtractionMark(node, MemberMark);
3703 auto generateQmlProperty = [&](
Node *n,
bool isGroupItem =
false) {
3704 const auto cssClasses = isGroupItem ?
"fn qml-member qml-property fngroupitem"_L1 :
"fn qml-member qml-property"_L1;
3705 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3706 generateQmlItem(n, relative, marker,
false);
3707 generateSourceLink(n);
3708 out() << headingEnd;
3711 auto generateQmlMethod = [&](
Node *n,
bool isGroupItem =
false) {
3712 const auto cssClasses = isGroupItem ?
"fn qml-member qml-method fngroupitem"_L1 :
"fn qml-member qml-method"_L1;
3713 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3715 generateSourceLink(n);
3716 out() << headingEnd;
3720 auto *scn =
static_cast<
const SharedCommentNode *>(node);
3721 const auto shared = scn->collective();
3723 if (scn->isPropertyGroup() && !scn->name().isEmpty())
3724 emitGroupHeader(scn);
3726 const bool isGroup = shared.size() > 1;
3729 out() <<
"<div class=\"fngroup\">\n"_L1;
3731 for (
auto *child : std::as_const(shared)) {
3732 if (child->isQmlProperty())
3733 generateQmlProperty(child, isGroup);
3735 generateQmlMethod(child, isGroup);
3739 out() <<
"</div>"_L1;
3742 generateQmlProperty(node);
3744 generateQmlMethod(node);
3751 generateAlsoList(node, marker);
3752 generateExtractionMark(node, EndMark);
3755void HtmlGenerator::generateExtractionMark(
const Node *node, ExtractionMarkType markType)
3757 if (markType != EndMark) {
3758 out() <<
"<!-- $$$" + node->name();
3759 if (markType == MemberMark) {
3761 const auto *func =
static_cast<
const FunctionNode *>(node);
3762 if (!func->hasAssociatedProperties()) {
3763 if (func->overloadNumber() == 0)
3764 out() <<
"[overload1]";
3765 out() <<
"$$$" + func->name() + func->parameters().rawSignature().remove(
' ');
3769 const auto *prop =
static_cast<
const PropertyNode *>(node);
3770 const NodeList &list = prop->functions();
3771 for (
const auto *propFuncNode : list) {
3772 if (propFuncNode->isFunction()) {
3773 const auto *func =
static_cast<
const FunctionNode *>(propFuncNode);
3774 out() <<
"$$$" + func->name()
3775 + func->parameters().rawSignature().remove(
' ');
3779 const auto *enumNode =
static_cast<
const EnumNode *>(node);
3780 const auto &items = enumNode->items();
3781 for (
const auto &item : items)
3782 out() <<
"$$$" + item.name();
3784 }
else if (markType == BriefMark) {
3786 }
else if (markType == DetailedDescriptionMark) {
3787 out() <<
"-description";
3791 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.
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.
static void quoteFromFile(const Location &location, Quoter "er, ResolvedFile resolved_file)
const Text & title() const
bool hasTableOfContents() const
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 Node *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() 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)
ClassNodesList & classNodesList()
const Aggregate * aggregate() const
const NodeVector & members() const
A class for creating vectors of collections for documentation.
Aggregate * aggregate() const
Sections(Aggregate *aggregate)
This constructor builds the vectors of sections based on the type of the aggregate node.
SectionVector & stdCppClassSummarySections()
SectionVector & stdQmlTypeSummarySections()
SectionVector & stdDetailsSections()
SectionVector & stdCppClassDetailsSections()
SectionVector & stdQmlTypeDetailsSections()
SectionVector & sinceSections()
Sections(const NodeMultiMap &nsmap)
This constructor builds a vector of 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 & stdSummarySections()
static Section & allMembersSection()
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
QList< Node * > NodeVector
QMap< QString, Node * > NodeMap
QMap< QString, NodeMap > NodeMapMap
QMap< QString, CollectionNode * > CNMap
QT_BEGIN_NAMESPACE typedef QMultiMap< Text, const Node * > TextToNodeMap
std::pair< const QmlTypeNode *, NodeVector > ClassNodes
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.