30#include <QtCore/qlist.h>
31#include <QtCore/qmap.h>
32#include <QtCore/quuid.h>
33#include <QtCore/qversionnumber.h>
34#include <QtCore/qregularexpression.h>
43using namespace Qt::StringLiterals;
50static const auto headingStart =
"<h3 class=\"%1\" translate=\"no\" id=\"%2\">"_L1;
55static void addLink(
const QString &linkTarget, QStringView nestedStuff, QString *res)
57 if (!linkTarget.isEmpty()) {
58 *res += QLatin1String(
"<a href=\"");
60 *res += QLatin1String(
"\" translate=\"no\">");
62 *res += QLatin1String(
"</a>");
82 if (param.template_declaration) {
83 appendTemplateParametersAtoms(out, *param.template_declaration);
89 if (param.concept_name) {
90 const QString fq = QString::fromStdString(*param.concept_name);
100 case RelaxedTemplateParameter::Kind::NonTypeTemplateParameter:
101 if (!decl.type.empty())
102 out << Atom(Atom::AutoLink, QString::fromStdString(decl.type));
104 case RelaxedTemplateParameter::Kind::TemplateTemplateParameter:
105 out <<
"typename"_L1;
109 if (param.is_parameter_pack)
112 if (!decl.name.empty())
113 out <<
" "_L1 << QString::fromStdString(decl.name);
118 out <<
"template <"_L1;
121 for (
const auto ¶m : storage.parameters) {
122 if (param.sfinae_constraint)
127 appendTemplateParameterAtoms(out, param);
142 appendTemplateParametersAtoms(out, templateDecl);
144 if (!templateDecl.requires_clause || templateDecl.requires_clause->empty())
147 out <<
" requires "_L1;
148 const QString text = QString::fromStdString(*templateDecl.requires_clause);
150 QStringList concepts;
151 concepts.reserve(
int(templateDecl.referenced_concepts.size()));
152 for (
const auto &s : templateDecl.referenced_concepts)
153 concepts.append(QString::fromStdString(s));
155 if (concepts.isEmpty()) {
163 std::sort(concepts.begin(), concepts.end(),
164 [](
const QString &a,
const QString &b) {
return a.size() > b.size(); });
166 struct Match { qsizetype offset; qsizetype length; QString name; };
167 QList<Match> matches;
168 QList<
bool> occupied(text.size(),
false);
170 for (
const QString &concept_name : concepts) {
171 const QString unqualified = concept_name.section(
"::"_L1, -1);
172 QRegularExpression re(
"\\b"_L1 + QRegularExpression::escape(unqualified) +
"\\b"_L1);
173 auto it = re.globalMatch(text);
174 while (it.hasNext()) {
175 const auto m = it.next();
176 const qsizetype start = m.capturedStart();
177 const qsizetype len = m.capturedLength();
179 for (qsizetype i = start; i < start + len; ++i)
180 if (occupied[i]) { clear =
false;
break; }
183 for (qsizetype i = start; i < start + len; ++i)
185 matches.append({start, len, unqualified});
189 std::sort(matches.begin(), matches.end(),
190 [](
const Match &a,
const Match &b) {
return a.offset < b.offset; });
193 for (
const auto &m : matches) {
195 out << text.mid(pos, m.offset - pos);
196 out << Atom(Atom::AutoLink, m.name);
197 pos = m.offset + m.length;
199 if (pos < text.size())
200 out << text.mid(pos);
204
205
206
207
210 auto result{classSet};
211 if (node->isInternal())
212 result +=
" internal"_L1;
217
218
219
222 if (!s_inUnorderedList) {
224 s_inUnorderedList =
true;
229
230
231
234 if (s_inUnorderedList) {
236 s_inUnorderedList =
false;
241
242
243
246 if (m_helpProjectWriter) {
247 delete m_helpProjectWriter;
248 m_helpProjectWriter =
nullptr;
251 if (m_manifestWriter) {
252 delete m_manifestWriter;
253 m_manifestWriter =
nullptr;
258
259
260
280 {
nullptr,
nullptr,
nullptr } };
283 config = &Config::instance();
286
287
288
289 for (
int i = 0; defaults[i].key; ++i) {
290 formattingLeftMap().insert(QLatin1String(defaults[i].key), QLatin1String(defaults[i].left));
291 formattingRightMap().insert(QLatin1String(defaults[i].key),
292 QLatin1String(defaults[i].right));
295 QString formatDot{HtmlGenerator::format() + Config::dot};
296 m_endHeader = config->get(formatDot +
CONFIG_ENDHEADER).asString(
"</head>\n<body>\n"_L1);
310 .asString(m_project +
" Reference Documentation"_L1);
312 m_projectUrl = config->get(
CONFIG_URL).asString();
321
322
323
324
326 delete m_helpProjectWriter;
327 m_helpProjectWriter =
nullptr;
328 }
else if (m_helpProjectWriter) {
329 m_helpProjectWriter->reset(m_project.toLower() +
".qhp",
this);
331 m_helpProjectWriter =
new HelpProjectWriter(m_project.toLower() +
".qhp",
this);
334 if (!m_manifestWriter)
347 .asString(m_homepage);
354 .asString(m_landingpage);
361 .asString(
"C++ Classes"_L1);
368 .asString(
"QML Types"_L1);
377
378
390
391
392
393
394
395
396
402 Node *qflags = m_qdb->findClassNode(QStringList(
"QFlags"_L1));
404 m_qflagsHref = linkForNode(qflags,
nullptr);
408 const QString fileBase =
"%1/%2"_L1.arg(
410 m_project.toLower().simplified().replace(
' '_L1,
'-'_L1)
414 if (m_helpProjectWriter)
418 const QString &rootTitle = m_landingpage.isEmpty() ? m_homepage : m_landingpage;
419 tocWriter
.generateTOC(
"%1_toc.xml"_L1.arg(fileBase), rootTitle);
421
422
423 if (!tagFile_.isEmpty()) {
431
432
435 SubTitleSize subTitleSize = LargeSubTitle;
436 QString fullTitle = en->fullTitle();
438 beginSubPage(en, linkForExampleFile(resolved_file.get_query()));
439 generateHeader(fullTitle, en, marker, u"auto-generated"_s);
440 generateTitle(en
->doc().title(),
Text() << en->subtitle(), subTitleSize, en, marker);
445 QString code = quoter.quoteTo(en->location(), QString(), QString());
446 CodeMarker *codeMarker = CodeMarker::markerForFileName(resolved_file.get_path());
450 generateText(text, en, codeMarker);
455
456
459 qsizetype idx, skipAhead = 0;
460 static bool in_para =
false;
461 Genus genus = Genus::DontCare;
463 if (!m_inSectionHeading && atom->type() != Atom::Target
464 && atom->type() != Atom::SectionHeadingRight)
465 m_recentSectionRef.clear();
469 QString name = atom->string();
470 if (relative && relative->name() == name.replace(QLatin1String(
"()"), QLatin1String())) {
471 out() << protectEnc(atom->string());
479 if (!m_inLink && !m_inContents && !m_inSectionHeading) {
480 const Node *node =
nullptr;
481 QString link = getAutoLink(atom, relative, &node, genus);
482 if (link.isEmpty()) {
487 QStringLiteral(
"Can't autolink to '%1'").arg(atom->string()));
492 if (link.isEmpty()) {
493 out() << protectEnc(atom->string());
495 beginLink(link, node, relative);
500 out() << protectEnc(atom->string());
507 skipAhead = skipAtoms(atom, Atom::BriefRight);
522 out() << protectEnc(plainCode(atom->string()));
526 out() <<
"<p class=\"figCaption\">";
537 out() <<
"<pre class=\"qml\" translate=\"no\"><code class=\"qml\">"
538 << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative,
540 m_codePrefix, m_codeSuffix)
541 <<
"</code></pre>\n";
545 if (atom->strings().count() == 2)
546 out() <<
"<pre class=\"" << atom->string(1) <<
"\" translate=\"no\"><code class=\"" << atom->string(1) <<
"\">";
548 out() <<
"<pre class=\"cpp\" translate=\"no\"><code class=\"cpp\">";
550 out() << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative),
551 m_codePrefix, m_codeSuffix)
552 <<
"</code></pre>\n";
555 out() <<
"<pre class=\"cpp plain\" translate=\"no\"><code class=\"text\">"
556 << trimmedTrailing(protectEnc(plainCode(indent(m_codeIndent, atom->string()))),
557 m_codePrefix, m_codeSuffix)
558 <<
"</code></pre>\n";
561 out() <<
"<details>\n";
563 out() <<
"<summary>...</summary>\n";
566 out() <<
"<summary>";
569 out() <<
"</summary>\n";
572 out() <<
"</details>\n";
576 if (!atom->string().isEmpty())
577 out() <<
' ' << atom->string();
600 if (atom->string().startsWith(
"span "))
601 out() <<
'<' + atom->string() <<
'>';
603 out() << formattingLeftMap()[atom->string()];
611 const Node *node{
nullptr};
612 const Atom tm_link(Atom::NavLink, m_trademarkspage);
613 if (
const auto &link = getLink(&tm_link, relative, &node);
614 !link.isEmpty() && node != relative)
615 out() <<
"<a href=\"%1\">%2</a>"_L1.arg(link, formattingRightMap()[atom->string()]);
617 out() << formattingRightMap()[atom->string()];
620 }
else if (atom->string().startsWith(
"span ")) {
623 out() << formattingRightMap()[atom->string()];
627 if (
const auto *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group); cn)
628 generateList(cn, marker, atom->string(), Generator::sortOrder(atom->strings().last()));
631 const auto sortOrder{Generator::sortOrder(atom->strings().last())};
632 if (atom->string() == QLatin1String(
"annotatedclasses")) {
633 generateAnnotatedList(relative, marker, m_qdb->getCppClasses().values(), sortOrder);
634 }
else if (atom->string() == QLatin1String(
"annotatedexamples")) {
635 generateAnnotatedLists(relative, marker, m_qdb->getExamples());
636 }
else if (atom->string() == QLatin1String(
"annotatedattributions")) {
637 generateAnnotatedLists(relative, marker, m_qdb->getAttributions());
638 }
else if (atom->string() == QLatin1String(
"classes")) {
639 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true,
641 }
else if (atom->string().contains(
"classes ")) {
642 QString rootName = atom->string().mid(atom->string().indexOf(
"classes") + 7).trimmed();
643 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true, rootName);
644 }
else if (atom->string() == QLatin1String(
"qmlvaluetypes")
645 || atom->string() == QLatin1String(
"qmlbasictypes")) {
646 generateCompactList(Generic, relative, m_qdb->getQmlValueTypes(),
true,
648 }
else if (atom->string() == QLatin1String(
"qmltypes")) {
649 generateCompactList(Generic, relative, m_qdb->getQmlTypes(),
true, QStringLiteral(
""));
650 }
else if ((idx = atom->string().indexOf(QStringLiteral(
"bymodule"))) != -1) {
652 QString moduleName = atom->string().mid(idx + 8).trimmed();
654 if (
const auto *cn = qdb->getCollectionNode(moduleName, moduleType)) {
656 switch (moduleType) {
660 generateAnnotatedList(relative, marker, map.values(), sortOrder);
663 if (atom->string().contains(QLatin1String(
"qmlvaluetypes")))
667 generateAnnotatedList(relative, marker, map.values(), sortOrder);
670 generateAnnotatedList(relative, marker, cn->members(), sortOrder);
674 }
else if (atom->string() == QLatin1String(
"classhierarchy")) {
675 generateClassHierarchy(relative, m_qdb->getCppClasses());
676 }
else if (atom->string() == QLatin1String(
"obsoleteclasses")) {
677 generateCompactList(Generic, relative, m_qdb->getObsoleteClasses(),
false,
678 QStringLiteral(
"Q"));
679 }
else if (atom->string() == QLatin1String(
"obsoleteqmltypes")) {
680 generateCompactList(Generic, relative, m_qdb->getObsoleteQmlTypes(),
false,
682 }
else if (atom->string() == QLatin1String(
"obsoletecppmembers")) {
683 generateCompactList(Obsolete, relative, m_qdb->getClassesWithObsoleteMembers(),
false,
684 QStringLiteral(
"Q"));
685 }
else if (atom->string() == QLatin1String(
"obsoleteqmlmembers")) {
686 generateCompactList(Obsolete, relative, m_qdb->getQmlTypesWithObsoleteMembers(),
false,
688 }
else if (atom->string() == QLatin1String(
"functionindex")) {
689 generateFunctionIndex(relative);
690 }
else if (atom->string() == QLatin1String(
"attributions")) {
691 generateAnnotatedList(relative, marker, m_qdb->getAttributions().values(), sortOrder);
692 }
else if (atom->string() == QLatin1String(
"legalese")) {
693 generateLegaleseList(relative, marker);
694 }
else if (atom->string() == QLatin1String(
"overviews")) {
695 generateList(relative, marker,
"overviews", sortOrder);
696 }
else if (atom->string() == QLatin1String(
"cpp-modules")) {
697 generateList(relative, marker,
"cpp-modules", sortOrder);
698 }
else if (atom->string() == QLatin1String(
"qml-modules")) {
699 generateList(relative, marker,
"qml-modules", sortOrder);
700 }
else if (atom->string() == QLatin1String(
"namespaces")) {
701 generateAnnotatedList(relative, marker, m_qdb->getNamespaces().values(), sortOrder);
702 }
else if (atom->string() == QLatin1String(
"related")) {
703 generateList(relative, marker,
"related", sortOrder);
705 const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group);
707 if (!generateGroupList(
const_cast<CollectionNode *>(cn), sortOrder))
709 QString(
"'\\generatelist %1' group is empty").arg(atom->string()));
712 QString(
"'\\generatelist %1' no such group").arg(atom->string()));
717 const NodeMultiMap &nsmap = m_qdb->getSinceMap(atom->string());
721 const NodeMultiMap &ncmap = m_qdb->getClassMap(atom->string());
722 const NodeMultiMap &nqcmap = m_qdb->getQmlTypeMap(atom->string());
727 for (
const auto §ion : sinceSections) {
728 if (!section.members().isEmpty()) {
730 <<
"<a href=\"#" << TextUtils::asAsciiPrintable(section.title()) <<
"\">"
731 << section.title() <<
"</a></li>\n";
737 for (
const auto §ion : sinceSections) {
738 if (!section.members().isEmpty()) {
739 out() <<
"<h3 id=\"" << TextUtils::asAsciiPrintable(section.title()) <<
"\">"
740 << protectEnc(section.title()) <<
"</h3>\n";
741 if (index == Sections::SinceClasses)
742 generateCompactList(Generic, relative, ncmap,
false, QStringLiteral(
"Q"));
743 else if (index == Sections::SinceQmlTypes)
744 generateCompactList(Generic, relative, nqcmap,
false, QStringLiteral(
""));
745 else if (index == Sections::SinceMemberFunctions
746 || index == Sections::SinceQmlMethods
747 || index == Sections::SinceQmlProperties) {
749 QMap<QString, NodeMultiMap> parentmaps;
751 const QList<Node *> &members = section.members();
752 for (
const auto &member : members) {
753 QString parent_full_name = (*member).parent()->fullName();
755 auto parent_entry = parentmaps.find(parent_full_name);
756 if (parent_entry == parentmaps.end())
757 parent_entry = parentmaps.insert(parent_full_name, NodeMultiMap());
758 parent_entry->insert(member->name(), member);
761 for (
auto map = parentmaps.begin(); map != parentmaps.end(); ++map) {
762 NodeVector nv = map->values().toVector();
763 auto parent = nv.front()->parent();
765 out() << ((index == Sections::SinceMemberFunctions) ?
"<p>Class " :
"<p>QML Type ");
767 out() <<
"<a href=\"" << linkForNode(parent, relative) <<
"\" translate=\"no\">";
768 QStringList pieces = parent->fullName().split(
"::");
769 out() << protectEnc(pieces.last());
773 generateSection(nv, relative, marker);
776 }
else if (index == Sections::SinceEnumValues) {
777 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
778 const auto map_it = m_qdb->newEnumValueMaps().constFind(atom->string());
779 for (
auto it = map_it->cbegin(); it != map_it->cend(); ++it) {
780 out() <<
"<tr><td class=\"memItemLeft\"> enum value </td><td class=\"memItemRight\">"
781 <<
"<b><a href=\"" << linkForNode(it.value(),
nullptr) <<
"\">"
782 << it.key() <<
"</a></b></td></tr>\n";
784 out() <<
"</table></div>\n";
786 generateSection(section.members(), relative, marker);
804 out() <<
"<p class=\"centerAlign\">";
806 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
807 if (!maybe_resolved_file) {
810 QStringLiteral(
"Missing image: %1").arg(protectEnc(atom->string())));
811 out() <<
"<font color=\"red\">[Missing image " << protectEnc(atom->string())
815 QString file_name{QFileInfo{file.get_path()}.fileName()};
835 "%1/%2"_L1.arg(outputDir(), imagesOutputDir()));
837 const auto &imgPath =
"%1/%2"_L1.arg(imagesOutputDir(), file_name);
839 out() <<
"<img src=\"%1\""_L1.arg(protectEnc(imgPath));
841 const QString altAndTitleText = protectEnc(text);
842 out() <<
" alt=\"" << altAndTitleText;
844 out() <<
"\" title=\"" << altAndTitleText;
848 if (m_helpProjectWriter)
849 m_helpProjectWriter->addExtraFile(imgPath);
850 setImageFileName(relative, imgPath);
862 QString admonType = atom->typeString();
865 out() <<
"<div class=\"admonition " << admonType.toLower() <<
"\">\n"
868 out() << admonType <<
": ";
878 out() <<
"<div class=\"LegaleseLeft\">";
892 const Node *node =
nullptr;
893 QString link = getLink(atom, relative, &node);
895 Location location = atom->isLinkAtom() ?
static_cast<
const LinkAtom*>(atom)->location
896 : relative->doc().location();
898 QStringLiteral(
"Can't link to '%1'").arg(atom->string()));
900 beginLink(link, node, relative);
904 QString link = linkForExampleFile(atom->string());
909 QString link = atom->string();
910 link =
"images/used-in-examples/" + link;
915 const Node *node =
static_cast<
const Node*>(
Utilities::nodeForString(atom->string()));
916 beginLink(linkForNode(node, relative), node, relative);
929 out() << R"(<div class="table"><table class="valuelist">)";
930 m_threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom);
931 if (m_threeColumnEnumValueTable) {
932 if (++m_numTableRows % 2 == 1)
933 out() << R"(<tr valign="top" class="odd">)";
935 out() << R"(<tr valign="top" class="even">)";
937 out() <<
"<th class=\"tblConst\">Constant</th>";
941 out() <<
"<th class=\"tblval\">Value</th>";
943 out() <<
"<th class=\"tbldscr\">Description</th></tr>\n";
945 out() <<
"<tr><th class=\"tblConst\">Constant</th><th "
946 "class=\"tblVal\">Value</th></tr>\n";
963 out() << QString(R"(<ol class="%1" type="%1" start="%2">)")
964 .arg(olType, atom
->next()->string());
966 out() << QString(R"(<ol class="%1" type="%1">)").arg(olType);
975 std::pair<QString,
int> pair = getAtomListValue(atom);
976 skipAhead = pair.second;
977 QString t = protectEnc(plainCode(marker->markedUpEnumValue(pair.first, relative)));
978 out() <<
"<tr><td class=\"topAlign\"><code translate=\"no\">" << t <<
"</code>";
981 out() <<
"</td><td class=\"topAlign tblval\">";
982 const auto *enume =
static_cast<
const EnumNode *>(relative);
983 QString itemValue = enume->itemValue(atom->next()->string());
984 if (itemValue.isEmpty())
987 out() <<
"<code translate=\"no\">" << protectEnc(itemValue) <<
"</code>";
1000 if (m_threeColumnEnumValueTable) {
1001 out() <<
"</td><td class=\"topAlign\">";
1008 if (matchAhead(atom, Atom::ParaLeft))
1015 out() <<
"</td></tr>\n";
1026 out() <<
"</table></div>\n";
1047 out() <<
"<blockquote>";
1050 out() <<
"</blockquote>\n";
1053 out() << atom->string();
1059 int unit = atom->string().toInt() +
hOffset(relative
);
1060 m_recentSectionRef = Tree::refForAtom(atom);
1061 out() <<
"<h" + QString::number(unit) + QLatin1Char(
' ') <<
"id=\""
1062 << m_recentSectionRef <<
"\">";
1063 m_inSectionHeading =
true;
1066 case Atom::SectionHeadingRight:
1067 out() <<
"</h" + QString::number(atom->string().toInt() + hOffset(relative)) +
">\n";
1068 m_inSectionHeading =
false;
1075 if (m_inLink && !m_inContents && !m_inSectionHeading) {
1078 out() << protectEnc(atom->string());
1082 std::pair<QString, QString> pair = getTableWidthAttr(atom);
1083 QString attr = pair.second;
1084 QString width = pair.first;
1091 out() << R"(<div class="table"><table class=")" << attr <<
'"';
1092 if (!width.isEmpty())
1093 out() <<
" style=\"width: " << width <<
'"';
1098 out() <<
"</table></div>\n";
1101 out() <<
"<thead><tr class=\"qt-style\">";
1102 m_inTableHeader =
true;
1108 out() <<
"\n<tr class=\"qt-style\">";
1110 out() <<
"</thead>\n";
1111 m_inTableHeader =
false;
1115 if (!atom->string().isEmpty())
1116 out() <<
"<tr " << atom->string() <<
'>';
1117 else if (++m_numTableRows % 2 == 1)
1118 out() << R"(<tr valign="top" class="odd">)";
1120 out() << R"(<tr valign="top" class="even">)";
1126 if (m_inTableHeader)
1131 for (
int i = 0; i < atom->count(); ++i) {
1134 const QString &p = atom->string(i);
1135 if (p.contains(
'=')) {
1138 QStringList spans = p.split(QLatin1Char(
','));
1139 if (spans.size() == 2) {
1140 if (spans.at(0) !=
"1")
1141 out() <<
" colspan=\"" << spans.at(0) <<
'"';
1142 if (spans.at(1) !=
"1")
1143 out() <<
" rowspan=\"" << spans.at(1) <<
'"';
1148 if (matchAhead(atom, Atom::ParaLeft))
1152 if (m_inTableHeader)
1157 if (matchAhead(atom, Atom::ParaLeft))
1167 const QString ref = atom->count() == 2 ? atom->string(1)
1168 : TextUtils::asAsciiPrintable(atom->string());
1169 const Atom *next = atom;
1173 if (ref != m_recentSectionRef && (!section || Tree::refForAtom(section) != ref))
1174 out() <<
"<span id=\"" << ref <<
"\"></span>";
1178 out() <<
"<b class=\"redFont\"><Missing HTML></b>";
1180 case Atom::UnknownCommand:
1181 out() << R"(<b class="redFont"><code translate=\"no\">\)" << protectEnc(atom->string()) <<
"</code></b>";
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1229 auto link_for_group = [
this](
const CollectionNode *group) -> QString {
1230 QString target{linkForNode(group,
nullptr)};
1231 return (target.isEmpty()) ? protectEnc(group->name()) :
"<a href=\"" + target +
"\">" + protectEnc(group->fullTitle()) +
"</a>";
1236 const QStringList &groups_names{node->groupNames()};
1237 if (groups_names.isEmpty())
1240 std::vector<CollectionNode *> groups_nodes(groups_names.size(),
nullptr);
1241 std::transform(groups_names.cbegin(), groups_names.cend(), groups_nodes.begin(),
1244 m_qdb->mergeCollections(group);
1245 return (group && group
->wasSeen()) ? group :
nullptr;
1247 groups_nodes.erase(
std::remove(groups_nodes.begin(), groups_nodes.end(),
nullptr), groups_nodes.end());
1249 if (!groups_nodes.empty()) {
1250 text += node->name() +
" is part of ";
1252 for (std::vector<CollectionNode *>::size_type index{0}; index < groups_nodes.size(); ++index) {
1253 text += link_for_group(groups_nodes[index]) + TextUtils::separator(index, groups_nodes.size());
1260
1261
1262
1263
1274 QString typeWord = aggregate->typeWord(
true);
1277 fullTitle = aggregate->plainFullName();
1278 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1279 ns =
static_cast<NamespaceNode *>(aggregate);
1281 fullTitle = aggregate->plainFullName();
1282 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1284 title = fullTitle = aggregate->fullTitle();
1285 if (!aggregate->doc().title().isEmpty())
1286 titleText << aggregate->name() <<
" - "_L1 << aggregate->doc().title();
1291 if (aggregate
->parent()->isInAPI() || templateDecl) {
1293 appendTemplateDeclAtoms(subtitleText, *templateDecl);
1294 subtitleText <<
" "_L1;
1296 subtitleText << aggregate->typeWord(
false) <<
" "_L1;
1297 auto ancestors = fullTitle.split(
"::"_L1);
1298 ancestors.pop_back();
1299 for (
const auto &a : ancestors)
1300 subtitleText << Atom(Atom::AutoLink, a) <<
"::"_L1;
1301 subtitleText << aggregate->plainName();
1304 generateHeader(title, aggregate, marker);
1305 generateTableOfContents(aggregate, marker, &summarySections);
1307 generateTitle(titleText, subtitleText, SmallSubTitle, aggregate, marker);
1309 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1313 brief <<
"The " << ns->name() <<
" namespace includes the following elements from module "
1316 addNodeLink(brief, fullNamespace,
" here.");
1318 generateText(brief, ns, marker);
1321 generateBrief(aggregate, marker);
1323 const auto parentIsClass = aggregate
->parent()->isClassNode();
1326 generateRequisites(aggregate, marker);
1331 QString membersLink = generateAllMembersFile(sections.allMembersSection(), marker);
1332 if (!membersLink.isEmpty()) {
1333 openUnorderedList();
1334 out() <<
"<li><a href=\"" << membersLink <<
"\">"
1335 <<
"List of all members, including inherited members</a></li>\n";
1337 QString obsoleteLink = generateObsoleteMembersFile(sections, marker);
1338 if (!obsoleteLink.isEmpty()) {
1339 openUnorderedList();
1340 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1341 <<
"Deprecated members</a></li>\n";
1344 if (QString groups_text{groupReferenceText(aggregate)}; !groups_text.isEmpty()) {
1345 openUnorderedList();
1347 out() <<
"<li>" << groups_text <<
"</li>\n";
1350 closeUnorderedList();
1355 bool needOtherSection =
false;
1357 for (
const auto §ion : summarySections) {
1358 if (section.members().isEmpty() && section.reimplementedMembers().isEmpty()) {
1359 if (!section.inheritedMembers().isEmpty())
1360 needOtherSection =
true;
1362 if (!section.members().isEmpty()) {
1363 QString ref = registerRef(section.title().toLower());
1364 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1365 generateSection(section.members(), aggregate, marker);
1367 if (!section.reimplementedMembers().isEmpty()) {
1368 QString name = QString(
"Reimplemented ") + section.title();
1369 QString ref = registerRef(name.toLower());
1370 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(name) <<
"</h2>\n";
1371 generateSection(section.reimplementedMembers(), aggregate, marker);
1374 if (!section.inheritedMembers().isEmpty()) {
1376 generateSectionInheritedList(section, aggregate);
1382 if (needOtherSection) {
1383 out() <<
"<h3>Additional Inherited Members</h3>\n"
1386 for (
const auto §ion : summarySections) {
1387 if (section.members().isEmpty() && !section.inheritedMembers().isEmpty())
1388 generateSectionInheritedList(section, aggregate);
1393 if (aggregate
->doc().isEmpty()) {
1394 QString command =
"documentation";
1396 command = R"('\class' comment)";
1399 QStringLiteral(
"No %1 for '%2'").arg(command, aggregate->plainSignature()));
1402 generateExtractionMark(aggregate, DetailedDescriptionMark);
1403 out() <<
"<div class=\"descr\">\n"
1404 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1405 <<
"Detailed Description"
1408 out() <<
"</div>\n";
1409 generateAlsoList(aggregate, marker);
1410 generateExtractionMark(aggregate, EndMark);
1413 for (
const auto §ion : detailsSections) {
1414 bool headerGenerated =
false;
1415 if (section.isEmpty())
1418 const QList<Node *> &members = section.members();
1419 for (
const auto &member : members) {
1420 if (!headerGenerated) {
1421 if (!section.divClass().isEmpty())
1422 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1423 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1424 headerGenerated =
true;
1426 if (!member->isClassNode())
1427 generateDetailedMember(member, aggregate, marker);
1430 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1431 out() <<
" class=\"%1\""_L1.arg(attrs);
1432 out() <<
"> class ";
1433 generateFullName(member, aggregate);
1435 generateBrief(member, marker, aggregate);
1438 if (headerGenerated && !section.divClass().isEmpty())
1439 out() <<
"</div>\n";
1441 generateFooter(aggregate);
1454 QString rawTitle = aggregate->plainName();
1455 QString fullTitle = aggregate->plainFullName();
1456 QString title = rawTitle +
" Proxy Page";
1457 generateHeader(title, aggregate, marker, u"auto-generated"_s);
1458 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1459 generateBrief(aggregate, marker);
1460 for (
const auto §ion : summarySections) {
1461 if (!section.members().isEmpty()) {
1462 QString ref = registerRef(section.title().toLower());
1463 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1464 generateSection(section.members(), aggregate, marker);
1468 if (!aggregate
->doc().isEmpty()) {
1469 generateExtractionMark(aggregate, DetailedDescriptionMark);
1470 out() <<
"<div class=\"descr\">\n"
1471 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1472 <<
"Detailed Description"
1475 out() <<
"</div>\n";
1476 generateAlsoList(aggregate, marker);
1477 generateExtractionMark(aggregate, EndMark);
1480 for (
const auto §ion : detailsSections) {
1481 if (section.isEmpty())
1484 if (!section.divClass().isEmpty())
1485 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1486 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1488 const QList<Node *> &members = section.members();
1489 for (
const auto &member : members) {
1490 if (!member->isClassNode()) {
1491 generateDetailedMember(member, aggregate, marker);
1494 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1495 out() <<
" class=\"%1\""_L1.arg(attrs);
1496 out() <<
"> class ";
1497 generateFullName(member, aggregate);
1499 generateBrief(member, marker, aggregate);
1502 if (!section.divClass().isEmpty())
1503 out() <<
"</div>\n";
1505 generateFooter(aggregate);
1509
1510
1511
1515 SubTitleSize subTitleSize = LargeSubTitle;
1516 QString htmlTitle = qcn->name();
1518 htmlTitle.append(
" QML Value Type");
1520 htmlTitle.append(
" QML Type");
1523 htmlTitle.append(
" (Singleton)"_L1);
1525 htmlTitle.append(
" (Uncreatable)"_L1);
1527 generateHeader(htmlTitle, qcn, marker);
1530 marker = CodeMarker::markerForLanguage(QLatin1String(
"QML"));
1531 generateTitle(htmlTitle,
Text() << qcn->subtitle(), subTitleSize, qcn, marker);
1532 generateBrief(qcn, marker);
1533 generateQmlRequisites(qcn, marker);
1537 out() <<
"<p><strong>Note:</strong> This type is a QML singleton. "_L1
1538 <<
"There is only one instance of this type in the QML engine.</p>\n"_L1;
1540 out() <<
"<p><strong>Note:</strong> This is an uncreatable type. "_L1
1541 <<
"It cannot be instantiated in QML.</p>\n"_L1;
1544 QString allQmlMembersLink;
1547 if (!qcn->isQmlBasicType())
1548 allQmlMembersLink = generateAllQmlMembersFile(sections, marker);
1549 QString obsoleteLink = generateObsoleteQmlMembersFile(sections, marker);
1550 if (!allQmlMembersLink.isEmpty() || !obsoleteLink.isEmpty()) {
1551 openUnorderedList();
1553 if (!allQmlMembersLink.isEmpty()) {
1554 out() <<
"<li><a href=\"" << allQmlMembersLink <<
"\">"
1555 <<
"List of all members, including inherited members</a></li>\n";
1557 if (!obsoleteLink.isEmpty()) {
1558 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1559 <<
"Deprecated members</a></li>\n";
1563 if (QString groups_text{groupReferenceText(qcn)}; !groups_text.isEmpty()) {
1564 openUnorderedList();
1566 out() <<
"<li>" << groups_text <<
"</li>\n";
1569 closeUnorderedList();
1572 for (
const auto §ion : qmlSummarySections) {
1573 if (!section.isEmpty()) {
1574 QString ref = registerRef(section.title().toLower());
1575 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1576 generateQmlSummary(section.members(), qcn, marker);
1580 generateExtractionMark(qcn, DetailedDescriptionMark);
1581 out() <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1582 <<
"Detailed Description"
1585 generateAlsoList(qcn, marker);
1586 generateExtractionMark(qcn, EndMark);
1589 for (
const auto §ion : qmlDetailsSections) {
1590 if (section.isEmpty())
1592 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1593 const QList<Node *> &members = section.members();
1594 for (
const auto member : members)
1595 generateDetailedQmlMember(member, qcn, marker);
1597 generateFooter(qcn);
1602
1603
1604
1607 generateHeader(pn->fullTitle(), pn, marker);
1609
1610
1611
1612 if ((pn->name() != QLatin1String(
"index.html")))
1613 generateTableOfContents(pn, marker,
nullptr);
1615 generateTitle(pn
->doc().title(),
Text() << pn->subtitle(), LargeSubTitle, pn, marker);
1617 generateBrief(pn, marker,
nullptr,
false);
1620 generateExtractionMark(pn, DetailedDescriptionMark);
1621 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1625 out() <<
"</div>\n";
1626 generateAlsoList(pn, marker);
1627 generateExtractionMark(pn, EndMark);
1633
1634
1637 SubTitleSize subTitleSize = LargeSubTitle;
1640 generateHeader(cn->fullTitle(), cn, marker);
1641 generateTableOfContents(cn, marker,
nullptr);
1642 generateTitle(cn
->doc().title(),
Text() << cn->subtitle(), subTitleSize, cn, marker);
1645 if (cn
->genus() != Genus::DOC && cn
->genus() != Genus::DontCare) {
1647 generateBrief(cn, marker);
1655 if (!nmm.isEmpty()) {
1656 ref = registerRef(
"namespaces");
1657 out() <<
"<h2 id=\"" << ref <<
"\">Namespaces</h2>\n";
1658 generateAnnotatedList(cn, marker, nmm.values());
1661 if (!nmm.isEmpty()) {
1662 ref = registerRef(
"classes");
1663 out() <<
"<h2 id=\"" << ref <<
"\">Classes</h2>\n";
1664 generateAnnotatedList(cn, marker, nmm.values());
1670 generateExtractionMark(cn, DetailedDescriptionMark);
1671 ref = registerRef(
"details");
1672 out() <<
"<div class=\"descr\">\n";
1673 out() <<
"<h2 id=\"" << ref <<
"\">"
1674 <<
"Detailed Description"
1677 generateExtractionMark(cn, DetailedDescriptionMark);
1678 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1683 out() <<
"</div>\n";
1684 generateAlsoList(cn, marker);
1685 generateExtractionMark(cn, EndMark);
1690 if (!users.isEmpty()) {
1691 ref = registerRef(
"users");
1692 out() <<
"<h2 id=\"" << ref <<
"\">Used by</h2>\n";
1693 generateAnnotatedList(cn, marker, users);
1696 generateAnnotatedList(cn, marker, cn->members());
1703
1704
1705
1706
1709 SubTitleSize subTitleSize = LargeSubTitle;
1710 QString fullTitle = cn->name();
1712 generateHeader(fullTitle, cn, marker, u"auto-generated"_s);
1713 generateTitle(fullTitle,
Text() << cn->subtitle(), subTitleSize, cn, marker);
1716 brief <<
"Each function or type documented here is related to a class or "
1717 <<
"namespace that is documented in a different module. The reference "
1718 <<
"page for that class or namespace will link to the function or type "
1721 generateText(brief, cn, marker);
1725 for (
const auto &member : members)
1726 generateDetailedMember(member, cn, marker);
1732
1733
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761void HtmlGenerator::generateNavigationBar(
const QString &title,
const Node *node,
1762 CodeMarker *marker,
const QString &buildversion,
1765 if (m_noNavigationBar || node ==
nullptr)
1776 auto addNavItem = [&](
const QString &link,
const QString &title) {
1777 navigationbar << Atom(itemLeft) << Atom(
Atom::NavLink, link)
1784 auto addNavItemNode = [&](
const Node *node,
const QString &title) {
1785 navigationbar << Atom(itemLeft);
1786 addNodeLink(navigationbar, node, title);
1787 navigationbar << Atom(itemRight);
1791 const auto *moduleNode = m_qdb->getModuleNode(node);
1792 QString moduleState;
1793 if (moduleNode && !moduleNode->state().isEmpty())
1794 moduleState = QStringLiteral(
" (%1)").arg(moduleNode->state());
1796 if (m_hometitle == title)
1798 if (!m_homepage.isEmpty())
1799 addNavItem(m_homepage, m_hometitle);
1800 if (!m_landingpage.isEmpty() && m_landingtitle != title)
1801 addNavItem(m_landingpage, m_landingtitle);
1804 if (!m_cppclassespage.isEmpty() && !m_cppclassestitle.isEmpty())
1805 addNavItem(m_cppclassespage, m_cppclassestitle);
1806 if (!node->physicalModuleName().isEmpty()) {
1810 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_cppclassespage))
1811 addNavItemNode(moduleNode, moduleNode->name() + moduleState);
1813 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1815 if (!m_qmltypespage.isEmpty() && !m_qmltypestitle.isEmpty())
1816 addNavItem(m_qmltypespage, m_qmltypestitle);
1820 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_qmltypespage)) {
1821 addNavItemNode(moduleNode, moduleNode->name() + moduleState);
1823 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1826 auto currentNode{
static_cast<
const PageNode*>(node)};
1827 std::deque<
const Node *> navNodes;
1829 qsizetype navItems = 0;
1830 while (currentNode->navigationParent() && ++navItems < 16) {
1831 if (
std::find(navNodes.cbegin(), navNodes.cend(),
1832 currentNode->navigationParent()) == navNodes.cend())
1833 navNodes.push_front(currentNode->navigationParent());
1834 currentNode = currentNode->navigationParent();
1838 if (navNodes.empty()) {
1839 const QStringList groups =
static_cast<
const PageNode *>(node)->groupNames();
1840 for (
const auto &groupName : groups) {
1841 const auto *groupNode = m_qdb->findNodeByNameAndType(QStringList{groupName}, &Node::isGroup);
1842 if (groupNode && !groupNode->title().isEmpty()) {
1843 navNodes.push_front(groupNode);
1848 while (!navNodes.empty()) {
1849 if (navNodes.front()->isPageNode())
1850 addNavItemNode(navNodes.front(), navNodes.front()->title());
1851 navNodes.pop_front();
1855 navigationbar << Atom(itemLeft) << Atom(
Atom::String, title) << Atom(itemRight);
1859 generateText(navigationbar, node, marker);
1861 if (buildversion.isEmpty())
1867 out() <<
"</tr></table><table class=\"buildversion\"><tr>\n"
1868 << R"(<td id="buildversion" width="100%" align="right">)";
1870 out() <<
"<li id=\"buildversion\">";
1874 if (!m_landingpage.isEmpty() && m_landingtitle != title) {
1875 navigationbar << Atom(Atom::NavLink, m_landingpage)
1877 << Atom(Atom::String, buildversion)
1879 generateText(navigationbar, node, marker);
1881 out() << buildversion;
1890 const QString &metaKeyword)
1892 out() <<
"<!DOCTYPE html>\n";
1893 out() << QString(
"<html lang=\"%1\">\n").arg(naturalLanguage);
1894 out() <<
"<head>\n";
1895 out() <<
" <meta charset=\"utf-8\">\n";
1900 out() <<
" <meta name=\"description\" content=\""
1901 << protectEnc(node->doc().briefText().toString())
1905 if (!metaKeyword.isEmpty()) {
1907 out() <<
" <meta name=\"keywords\" content=\"%1\">\n"_L1.arg(protectEnc(metaKeyword));
1910 QStringList keywords;
1912 for (
const auto &kw : metaTags->values(u"keywords"_s))
1913 keywords << kw.split(
','_L1, Qt::SkipEmptyParts);
1918 keywords << node->nodeTypeString().toLower().remove(
' '_L1);
1920 if (!keywords.isEmpty()) {
1921 std::transform(keywords.begin(), keywords.end(), keywords.begin(),
1922 [](
const QString &k) {
return k.trimmed(); });
1923 keywords.removeDuplicates();
1924 out() <<
" <meta name=\"keywords\" content=\"" << protectEnc(keywords.join(
','_L1))
1930 QString titleSuffix;
1931 if (!m_landingtitle.isEmpty()) {
1933 titleSuffix = m_landingtitle;
1934 }
else if (!m_hometitle.isEmpty()) {
1937 if (title != m_hometitle)
1938 titleSuffix = m_hometitle;
1941 titleSuffix = m_productName.isEmpty() ? m_project : m_productName;
1943 if (title == titleSuffix)
1944 titleSuffix.clear();
1946 out() <<
" <title>";
1947 if (!titleSuffix.isEmpty() && !title.isEmpty()) {
1948 out() <<
"%1 | %2"_L1.arg(protectEnc(title), titleSuffix);
1950 out() << protectEnc(title);
1955 QVersionNumber projectVersion = QVersionNumber::fromString(m_qdb->version());
1956 if (!projectVersion.isNull()) {
1957 QVersionNumber titleVersion;
1958 static const QRegularExpression re(QLatin1String(R"(\d+\.\d+)"));
1959 const QString &versionedTitle = titleSuffix.isEmpty() ? title : titleSuffix;
1960 auto match = re.match(versionedTitle);
1961 if (match.hasMatch())
1962 titleVersion = QVersionNumber::fromString(match.captured());
1963 if (titleVersion.isNull() || !titleVersion.isPrefixOf(projectVersion)) {
1965 if (!m_productName.isEmpty() && titleSuffix != m_productName)
1966 out() <<
" | %1"_L1.arg(m_productName);
1967 out() <<
" %1"_L1.arg(projectVersion.toString());
1970 out() <<
"</title>\n";
1973 out() << m_headerStyles;
1974 out() << m_headerScripts;
1975 out() << m_endHeader;
1977 out() << QString(m_postHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1978 bool usingTable = m_postHeader.trimmed().endsWith(QLatin1String(
"<tr>"));
1979 generateNavigationBar(title, node, marker, m_buildversion, usingTable);
1980 out() << QString(m_postPostHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1982 m_navigationLinks.clear();
1984 m_recentSectionRef.clear();
1985 m_emittedMemberRefs.clear();
1987 if (node && !node->links().empty()) {
1988 std::pair<QString, QString> linkPair;
1989 std::pair<QString, QString> anchorPair;
1990 const Node *linkNode;
1991 bool useSeparator =
false;
1993 if (node->links().contains(Node::PreviousLink)) {
1994 linkPair = node->links()[Node::PreviousLink];
1995 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1998 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1999 if (linkNode ==
nullptr || linkNode == node)
2000 anchorPair = linkPair;
2002 anchorPair = anchorForNode(linkNode);
2004 out() << R"( <link rel="prev" href=")" << anchorPair.first <<
"\" />\n";
2006 m_navigationLinks += R"(<a class="prevPage" href=")" + anchorPair.first +
"\">";
2007 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
2008 m_navigationLinks += protect(anchorPair.second);
2010 m_navigationLinks += protect(linkPair.second);
2011 m_navigationLinks +=
"</a>\n";
2012 useSeparator = !m_navigationSeparator.isEmpty();
2014 if (node->links().contains(Node::NextLink)) {
2015 linkPair = node->links()[Node::NextLink];
2016 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
2019 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
2020 if (linkNode ==
nullptr || linkNode == node)
2021 anchorPair = linkPair;
2023 anchorPair = anchorForNode(linkNode);
2025 out() << R"( <link rel="next" href=")" << anchorPair.first <<
"\" />\n";
2028 m_navigationLinks += m_navigationSeparator;
2030 m_navigationLinks += R"(<a class="nextPage" href=")" + anchorPair.first +
"\">";
2031 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
2032 m_navigationLinks += protect(anchorPair.second);
2034 m_navigationLinks += protect(linkPair.second);
2035 m_navigationLinks +=
"</a>\n";
2037 if (node->links().contains(Node::StartLink)) {
2038 linkPair = node->links()[Node::StartLink];
2039 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
2042 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
2043 if (linkNode ==
nullptr || linkNode == node)
2044 anchorPair =
std::move(linkPair);
2046 anchorPair = anchorForNode(linkNode);
2047 out() << R"( <link rel="start" href=")" << anchorPair.first <<
"\" />\n";
2051 if (node && !node->links().empty())
2052 out() <<
"<p class=\"naviNextPrevious headerNavi\">\n" << m_navigationLinks <<
"</p>\n";
2056 SubTitleSize subTitleSize,
const Node *relative,
2059 out() << QString(m_prologue).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
2062 attribute = R"( translate="no")";
2065 out() <<
"<h1 class=\"title\"" << attribute <<
">";
2066 generateText(title, relative, marker);
2071 if (subTitleSize == SmallSubTitle)
2072 out() <<
" class=\"small-subtitle\"" << attribute <<
">";
2074 out() <<
" class=\"subtitle\"" << attribute <<
">";
2075 generateText(subtitle, relative, marker);
2076 out() <<
"</span>\n";
2082 if (node && !node->links().empty())
2083 out() <<
"<p class=\"naviNextPrevious footerNavi\">\n" << m_navigationLinks <<
"</p>\n";
2085 out() << QString(m_footer).replace(
"\\" +
COMMAND_VERSION, m_qdb->version())
2086 << QString(m_address).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
2088 out() <<
"</body>\n";
2089 out() <<
"</html>\n";
2093
2094
2095
2098 QMap<QString, Text> requisites;
2101 const QString headerText =
"Header";
2102 const QString sinceText =
"Since";
2103 const QString inheritedByText =
"Inherited By";
2104 const QString inheritsText =
"Inherits";
2105 const QString nativeTypeText =
"In QML";
2106 const QString qtVariableText =
"qmake";
2107 const QString cmakeText =
"CMake";
2108 const QString statusText =
"Status";
2111 const QStringList requisiteorder { headerText, cmakeText, qtVariableText, sinceText,
2112 nativeTypeText, inheritsText, inheritedByText, statusText };
2114 addIncludeFileToMap(aggregate, requisites, text, headerText);
2115 addSinceToMap(aggregate, requisites, &text, sinceText);
2118 addCMakeInfoToMap(aggregate, requisites, &text, cmakeText);
2119 addQtVariableToMap(aggregate, requisites, &text, qtVariableText);
2123 auto *classe =
dynamic_cast<
ClassNode *>(aggregate);
2125 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2127 if (InclusionFilter::isIncluded(policy, context))
2128 addQmlNativeTypesToMap(requisites, &text, nativeTypeText, classe);
2131 const auto *metaTags = classe ? classe
->doc().metaTagMap() :
nullptr;
2132 if (!metaTags || !metaTags->contains(u"qdoc-suppress-inheritance"_s))
2133 addInheritsToMap(requisites, &text, inheritsText, classe);
2134 addInheritedByToMap(requisites, &text, inheritedByText, classe);
2138 addStatusToMap(aggregate, requisites, text, statusText);
2140 if (!requisites.isEmpty()) {
2142 generateTheTable(requisiteorder, requisites, aggregate, marker);
2147
2148
2149void HtmlGenerator::generateTheTable(
const QStringList &requisiteOrder,
2150 const QMap<QString, Text> &requisites,
2153 out() <<
"<div class=\"table\"><table class=\"alignedsummary requisites\" translate=\"no\">\n";
2155 for (
auto it = requisiteOrder.constBegin(); it != requisiteOrder.constEnd(); ++it) {
2157 if (requisites.contains(*it)) {
2159 <<
"<td class=\"memItemLeft rightAlign topAlign\"> " << *it
2161 "</td><td class=\"memItemRight bottomAlign\"> ";
2163 generateText(requisites.value(*it), aggregate, marker);
2164 out() <<
"</td></tr>\n";
2167 out() <<
"</table></div>\n";
2171
2172
2173
2174void HtmlGenerator::addInheritedByToMap(QMap<QString, Text> &requisites,
Text *text,
2175 const QString &inheritedByText,
ClassNode *classe)
2177 if (!classe->derivedClasses().isEmpty()) {
2180 int count = appendSortedNames(*text, classe, classe->derivedClasses());
2183 requisites.insert(inheritedByText, *text);
2188
2189
2190
2191void HtmlGenerator::addInheritsToMap(QMap<QString, Text> &requisites,
Text *text,
2192 const QString &inheritsText,
ClassNode *classe)
2194 if (!classe->baseClasses().isEmpty()) {
2197 const auto baseClasses = classe->baseClasses();
2198 for (
const auto &cls : baseClasses) {
2200 appendFullName(*text, cls.m_node, classe);
2202 if (cls.m_access == Access::Protected) {
2203 *text <<
" (protected)";
2204 }
else if (cls.m_access == Access::Private) {
2205 *text <<
" (private)";
2207 *text << TextUtils::comma(index++, classe->baseClasses().size());
2212 requisites.insert(inheritsText, *text);
2217
2218
2219
2220void HtmlGenerator::addQmlNativeTypesToMap(QMap<QString, Text> &requisites,
Text *text,
2221 const QString &nativeTypeText,
ClassNode *classe)
const
2228 QList<QmlTypeNode *> nativeTypes { classe->qmlNativeTypes().cbegin(), classe->qmlNativeTypes().cend()};
2230 qsizetype index { 0 };
2232 for (
const auto &item : std::as_const(nativeTypes)) {
2233 addNodeLink(*text, item);
2234 *text << TextUtils::comma(index++, nativeTypes.size());
2236 requisites.insert(nativeTypeText, *text);
2240
2241
2242
2244 Text *text,
const QString &CMakeInfo)
const
2246 if (!aggregate->physicalModuleName().isEmpty() && text !=
nullptr) {
2248 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2250 const auto result = cmakeRequisite(cn);
2263 requisites.insert(CMakeInfo, *text);
2268
2269
2270
2272 Text *text,
const QString &qtVariableText)
const
2274 if (!aggregate->physicalModuleName().isEmpty()) {
2276 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2278 if (cn && !cn->qtVariable().isEmpty()) {
2281 requisites.insert(qtVariableText, *text);
2287
2288
2289
2290
2292 Text *text,
const QString &sinceText)
const
2294 if (!aggregate->since().isEmpty() && text !=
nullptr) {
2297 requisites.insert(sinceText, *text);
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2313 Text &text,
const QString &statusText)
const
2315 auto status{formatStatus(aggregate, m_qdb)};
2321 spanClass = u"deprecated"_s;
2323 spanClass =
TextUtils::asAsciiPrintable(status.value());
2326 text << Atom(Atom::String, status.value())
2328 "class=\"status %1\""_L1.arg(spanClass))
2330 requisites.insert(statusText, text);
2334
2335
2336
2337
2339 QMap<QString, Text> &requisites,
Text& text,
2340 const QString &headerText)
2342 if (aggregate->includeFile()) {
2344 text << openCodeTag <<
"#include <%1>"_L1.arg(*aggregate->includeFile()) << closeCodeTag;
2345 requisites.insert(headerText, text);
2350
2351
2352
2358 QMap<QString, Text> requisites;
2361 const QString importText =
"Import Statement";
2362 const QString sinceText =
"Since";
2363 const QString inheritedByText =
"Inherited By";
2364 const QString inheritsText =
"Inherits";
2365 const QString nativeTypeText =
"In C++";
2366 const QString statusText =
"Status";
2369 QString logicalModuleVersion;
2374 bool generate_import =
true;
2376 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2380 if (generate_import) {
2384 requisites.insert(importText, text);
2387 qcn
->doc().location().warning(QStringLiteral(
"Could not resolve QML import statement for type '%1'").arg(qcn->name()),
2392 if (!qcn->since().isEmpty()) {
2395 requisites.insert(sinceText, text);
2400 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2404 addNodeLink(text, cn);
2405 requisites.insert(nativeTypeText, text);
2413 QStringList knownTypeNames{qcn->name()};
2415 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2423 knownTypeNames << base->name();
2426 addNodeLink(text, base);
2429 for (
const auto sub : std::as_const(subs)) {
2430 if (knownTypeNames.contains(sub->name())) {
2431 text << Atom(Atom::String,
" (%1)"_L1.arg(base->logicalModuleName()));
2436 requisites.insert(inheritsText, text);
2440 if (!subs.isEmpty()) {
2443 int count = appendSortedQmlNames(text, qcn, knownTypeNames, subs);
2446 requisites.insert(inheritedByText, text);
2450 addStatusToMap(qcn, requisites, text, statusText);
2453 const QStringList requisiteorder {
std::move(importText),
std::move(sinceText),
2454 std::move(nativeTypeText),
std::move(inheritsText),
2455 std::move(inheritedByText),
std::move(statusText)};
2457 if (!requisites.isEmpty())
2458 generateTheTable(requisiteorder, requisites, qcn, marker);
2470 QStringLiteral(
"'\\brief' statement does not end with a full stop."));
2472 generateExtractionMark(node, BriefMark);
2474 generateText(brief, node, marker);
2477 if (!relative || node == relative)
2478 out() <<
" <a href=\"#";
2480 out() <<
" <a href=\"" << linkForNode(node, relative) <<
'#';
2481 out() << registerRef(
"details") <<
"\">More...</a>";
2485 generateExtractionMark(node, EndMark);
2490
2491
2492
2498 toc = node
->doc().tableOfContents();
2499 if (tocDepth == 0 || (toc.isEmpty() && !sections && !node
->isModule())) {
2504 int sectionNumber = 1;
2505 int detailsBase = 0;
2508 m_inContents =
true;
2510 out() <<
"<div class=\"sidebar\">\n";
2511 out() <<
"<div class=\"toc\">\n";
2512 out() <<
"<h3 id=\"toc\">Contents</h3>\n";
2515 openUnorderedList();
2516 if (!
static_cast<
const CollectionNode *>(node)->noAutoList()) {
2518 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2519 << registerRef(
"namespaces") <<
"\">Namespaces</a></li>\n";
2522 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2523 << registerRef(
"classes") <<
"\">Classes</a></li>\n";
2526 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#" << registerRef(
"details")
2527 <<
"\">Detailed Description</a></li>\n";
2528 for (
const auto &entry : std::as_const(toc)) {
2529 if (entry->string().toInt() == 1) {
2535 for (
const auto §ion : *sections) {
2536 if (!section.members().isEmpty()) {
2537 openUnorderedList();
2538 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2539 << registerRef(section.plural()) <<
"\">" << section.title() <<
"</a></li>\n";
2541 if (!section.reimplementedMembers().isEmpty()) {
2542 openUnorderedList();
2543 QString ref = QString(
"Reimplemented ") + section.plural();
2544 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2545 << registerRef(ref.toLower()) <<
"\">"
2546 << QString(
"Reimplemented ") + section.title() <<
"</a></li>\n";
2550 openUnorderedList();
2551 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2552 << registerRef(
"details") <<
"\">Detailed Description</a></li>\n";
2554 for (
const auto &entry : toc) {
2555 if (entry->string().toInt() == 1) {
2562 for (
const auto &atom : toc) {
2563 sectionNumber = atom->string().toInt() + detailsBase;
2566 if (sectionNumber <= tocDepth || tocDepth < 0) {
2567 openUnorderedList();
2569 Text headingText = Text::sectionHeading(atom);
2570 out() <<
"<li class=\"level" << sectionNumber <<
"\">";
2571 out() <<
"<a href=\"" <<
'#' << Tree::refForAtom(atom) <<
"\">";
2572 generateAtomList(headingText.firstAtom(), node, marker,
true, numAtoms);
2573 out() <<
"</a></li>\n";
2576 closeUnorderedList();
2577 out() <<
"</div>\n";
2578 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2579 out() <<
"</div>\n";
2580 m_inContents =
false;
2585
2586
2589 out() <<
"<div class=\"sidebar\">";
2590 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2591 out() <<
"</div>\n";
2600 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2601 beginSubPage(aggregate, fileName);
2602 QString title =
"List of All Members for " + aggregate->plainFullName();
2603 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2605 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2606 out() <<
"<p>This is the complete list of members for ";
2607 generateFullName(aggregate,
nullptr);
2608 out() <<
", including inherited members.</p>\n";
2610 generateSectionList(section, aggregate, marker);
2618
2619
2620
2621
2622
2630 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2631 beginSubPage(aggregate, fileName);
2632 QString title =
"List of All Members for " + aggregate->name();
2633 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2635 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2636 out() <<
"<p>This is the complete list of members for ";
2637 generateFullName(aggregate,
nullptr);
2638 out() <<
", including inherited members.</p>\n";
2641 for (
int i = 0; i < cknl.size(); i++) {
2642 const auto &ckn = cknl[i];
2645 if (nodes.isEmpty())
2648 out() <<
"<p>The following members are inherited from ";
2649 generateFullName(qcn,
nullptr);
2652 openUnorderedList();
2653 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2654 for (
int j = 0; j < nodes.size(); j++) {
2655 Node *node = nodes[j];
2662 std::function<
void(
Node *)> generate = [&](Node *n) {
2663 out() <<
"<li class=\"fn\" translate=\"no\">";
2664 generateQmlItem(n, aggregate, marker,
true);
2665 if (n->isQmlProperty()) {
2666 auto qpn =
static_cast<QmlPropertyNode *>(n);
2667 QStringList hints = qpn->hints();
2668 if (qpn->isAttached())
2669 hints <<
"attached"_L1;
2670 if (!hints.isEmpty())
2671 out() <<
" [" << hints.join(
' '_L1) <<
"]";
2672 }
else if (n->isAttached()) {
2674 out() <<
" [attached]";
2677 if (n->isPropertyGroup()) {
2679 const QList<Node *> &collective =
2680 static_cast<SharedCommentNode *>(n)->collective();
2681 std::for_each(collective.begin(), collective.end(), generate);
2688 closeUnorderedList();
2705 QString title =
"Obsolete Members for " + aggregate->plainFullName();
2706 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2708 beginSubPage(aggregate, fileName);
2709 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2711 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2713 out() <<
"<p><b>The following members of class "
2714 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\" translate=\"no\">"
2715 << protectEnc(aggregate->name()) <<
"</a>"
2716 <<
" are deprecated.</b> "
2717 <<
"They are provided to keep old source code working. "
2718 <<
"We strongly advise against using them in new code.</p>\n";
2720 for (
const auto §ion : summary_spv) {
2721 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2722 generateSectionList(*section, aggregate, marker,
true);
2725 for (
const auto §ion : details_spv) {
2726 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2728 const NodeVector &members = section->obsoleteMembers();
2729 for (
const auto &member : members)
2730 generateDetailedMember(member, aggregate, marker);
2739
2740
2741
2742
2751 QString title =
"Obsolete Members for " + aggregate->name();
2752 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2754 beginSubPage(aggregate, fileName);
2755 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2757 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2759 out() <<
"<p><b>The following members of QML type "
2760 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\">"
2761 << protectEnc(aggregate->name()) <<
"</a>"
2762 <<
" are deprecated.</b> "
2763 <<
"They are provided to keep old source code working. "
2764 <<
"We strongly advise against using them in new code.</p>\n";
2766 for (
const auto §ion : summary_spv) {
2767 QString ref = registerRef(section->title().toLower());
2768 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section->title()) <<
"</h2>\n";
2769 generateQmlSummary(section->obsoleteMembers(), aggregate, marker);
2772 for (
const auto §ion : details_spv) {
2773 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2774 const NodeVector &members = section->obsoleteMembers();
2775 for (
const auto &member : members) {
2776 generateDetailedQmlMember(member, aggregate, marker);
2788 if (classMap.isEmpty())
2792 for (
const auto &it : classMap) {
2793 auto *classe =
static_cast<ClassNode *>(it);
2794 if (classe->baseClasses().isEmpty())
2795 topLevel.insert(classe->name(), classe);
2798 QStack<NodeMap> stack;
2799 stack.push(topLevel);
2802 while (!stack.isEmpty()) {
2803 if (stack.top().isEmpty()) {
2809 generateFullName(child, relative);
2811 stack.top().erase(stack.top().begin());
2814 const auto derivedClasses = child->derivedClasses();
2815 for (
const RelatedClass &d : derivedClasses) {
2816 if (d.m_node && d.m_node->isInAPI())
2817 newTop.insert(d.m_node->name(), d.m_node);
2819 if (!newTop.isEmpty()) {
2828
2829
2830
2835 if (relative ==
nullptr)
2838 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2839 for (
auto *node : nodes) {
2840 const NodeContext context = node->createContext();
2841 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
2842 included.insert(node->fullName(relative), node);
2848 const NodeList &unsortedNodes, Qt::SortOrder sortOrder)
2850 generateAnnotatedList(relative, marker, includedAnnotatedMembers(relative, unsortedNodes),
2857 if (nodeMap.isEmpty())
2859 out() <<
"<div class=\"table\"><table class=\"annotated\">\n";
2863 if (sortOrder == Qt::DescendingOrder)
2869 auto sameLocation = [
this](
const Node *a,
const Node *b) {
2870 return fullDocumentLocation(a) == fullDocumentLocation(b);
2872 nodes.erase(
std::unique(nodes.begin(), nodes.end(), sameLocation), nodes.end());
2874 for (
const auto *node : std::as_const(nodes)) {
2876 out() <<
"<tr class=\"odd topAlign\">";
2878 out() <<
"<tr class=\"even topAlign\">";
2879 out() <<
"<td class=\"tblName\" translate=\"no\"><p>";
2880 generateFullName(node, relative);
2881 out() <<
"</p></td>";
2883 if (!node->isTextPageNode()) {
2884 Text brief = node->doc().trimmedBriefText(node->name());
2885 if (!brief.isEmpty()) {
2886 out() <<
"<td class=\"tblDescr\"><p>";
2887 generateText(brief, node, marker);
2888 out() <<
"</p></td>";
2889 }
else if (!node->reconstitutedBrief().isEmpty()) {
2890 out() <<
"<td class=\"tblDescr\"><p>";
2891 out() << node->reconstitutedBrief();
2892 out() <<
"</p></td>";
2895 out() <<
"<td class=\"tblDescr\"><p>";
2896 if (!node->reconstitutedBrief().isEmpty()) {
2897 out() << node->reconstitutedBrief();
2899 out() << protectEnc(node->doc().briefText().toString());
2900 out() <<
"</p></td>";
2904 out() <<
"</table></div>\n";
2908
2909
2910
2914 const auto &uniqueKeys = nmm.uniqueKeys();
2915 for (
const QString &name : uniqueKeys) {
2916 if (!name.isEmpty()) {
2917 out() <<
"<h2 id=\"" << registerRef(name.toLower()) <<
"\">" << protectEnc(name)
2920 generateAnnotatedList(relative, marker, nmm.values(name));
2925
2926
2927
2928
2929
2930
2931
2932
2933
2936 const QString &commonPrefix)
2941 const int NumParagraphs = 37;
2942 qsizetype commonPrefixLen = commonPrefix.size();
2945
2946
2947
2948
2949
2951 QString paragraphName[NumParagraphs + 1];
2952 QSet<
char> usedParagraphNames;
2954 for (
auto c = nmm.constBegin(); c != nmm.constEnd(); ++c) {
2955 QStringList pieces = c.key().split(
"::");
2956 int idx = commonPrefixLen;
2957 if (idx > 0 && !pieces.last().startsWith(commonPrefix, Qt::CaseInsensitive))
2959 QString last = pieces.last().toLower();
2960 QString key = last.mid(idx);
2962 int paragraphNr = NumParagraphs - 1;
2964 if (key[0].digitValue() != -1) {
2965 paragraphNr = key[0].digitValue();
2966 }
else if (key[0] >= QLatin1Char(
'a') && key[0] <= QLatin1Char(
'z')) {
2967 paragraphNr = 10 + key[0].unicode() -
'a';
2970 paragraphName[paragraphNr] = key[0].toUpper();
2971 usedParagraphNames.insert(key[0].toLower().cell());
2972 paragraph[paragraphNr].insert(last, c.value());
2976
2977
2978
2979
2980
2981
2982
2983 qsizetype paragraphOffset[NumParagraphs + 1];
2984 paragraphOffset[0] = 0;
2985 for (
int i = 0; i < NumParagraphs; i++)
2986 paragraphOffset[i + 1] = paragraphOffset[i] + paragraph[i].size();
2989
2990
2991 if (includeAlphabet) {
2992 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
2993 for (
int i = 0; i < 26; i++) {
2995 if (usedParagraphNames.contains(
char(
'a' + i)))
2996 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
2998 out() <<
"</b></p>\n";
3002
3003
3004 out() <<
"<div class=\"flowListDiv\" translate=\"no\">\n";
3008 QHash<QString,
int> nameOccurrences;
3009 for (
const auto &[key, node] : nmm.asKeyValueRange()) {
3010 QStringList pieces{node->fullName(relative).split(
"::"_L1)};
3011 const QString &name{pieces.last()};
3012 nameOccurrences[name]++;
3016 int curParOffset = 0;
3018 for (
int i = 0; i < nmm.size(); i++) {
3019 while ((curParNr < NumParagraphs) && (curParOffset == paragraph[curParNr].size())) {
3025
3026
3027 if (curParOffset == 0) {
3030 if (++m_numTableRows % 2 == 1)
3031 out() <<
"<dl class=\"flowList odd\">";
3033 out() <<
"<dl class=\"flowList even\">";
3034 out() <<
"<dt class=\"alphaChar\"";
3035 if (includeAlphabet)
3036 out() << QString(
" id=\"%1\"").arg(paragraphName[curParNr][0].toLower());
3037 out() <<
"><b>" << paragraphName[curParNr] <<
"</b></dt>\n";
3041
3042
3044 if ((curParNr < NumParagraphs) && !paragraphName[curParNr].isEmpty()) {
3045 NodeMultiMap::Iterator it;
3046 NodeMultiMap::Iterator next;
3047 it = paragraph[curParNr].begin();
3048 for (
int j = 0; j < curParOffset; j++)
3053
3054
3055
3056 out() <<
"<a href=\"" << linkForNode(it.value(), relative) <<
"\">";
3058 QString fileName = fileBase(it.value()) +
"-obsolete." + fileExtension();
3060 if (useOutputSubdirs())
3061 link =
"../%1/"_L1.arg(it.value()->tree()->physicalModuleName());
3063 out() <<
"<a href=\"" << link <<
"\">";
3066 QStringList pieces{it.value()->fullName(relative).split(
"::"_L1)};
3067 const auto &name{pieces.last()};
3070 if (nameOccurrences[name] > 1) {
3071 const QString moduleName = it.value()->isQmlNode() ? it.value()->logicalModuleName()
3072 : it.value()->tree()->camelCaseModuleName();
3073 pieces.last().append(
": %1"_L1.arg(moduleName));
3076 out() << protectEnc(pieces.last());
3078 if (pieces.size() > 1) {
3080 generateFullName(it.value()->parent(), relative);
3090 out() <<
"</div>\n";
3095 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
3096 for (
int i = 0; i < 26; i++) {
3098 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
3100 out() <<
"</b></p>\n";
3102 char nextLetter =
'a';
3104 out() <<
"<ul translate=\"no\">\n";
3105 NodeMapMap &funcIndex = m_qdb->getFunctionIndex();
3106 for (
auto fnMap = funcIndex.constBegin(); fnMap != funcIndex.constEnd(); ++fnMap) {
3107 const QString &key = fnMap.key();
3108 const QChar firstLetter = key.isEmpty() ? QChar(
'A') : key.front();
3109 Q_ASSERT_X(firstLetter.unicode() < 256,
"generateFunctionIndex",
3110 "Only valid C++ identifiers were expected");
3111 const char currentLetter = firstLetter.isLower() ? firstLetter.unicode() : nextLetter - 1;
3113 if (currentLetter < nextLetter) {
3117 while (nextLetter < currentLetter)
3118 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
3119 Q_ASSERT(nextLetter == currentLetter);
3120 out() << QStringLiteral(
"<li id=\"%1\">").arg(nextLetter++);
3122 out() << protectEnc(key) <<
':';
3124 for (
auto it = (*fnMap).constBegin(); it != (*fnMap).constEnd(); ++it) {
3126 generateFullName((*it)->parent(), relative, *it);
3130 while (nextLetter <=
'z')
3131 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
3138 for (
auto it = legaleseTexts.cbegin(), end = legaleseTexts.cend(); it != end; ++it) {
3139 Text text = it.key();
3140 generateText(text, relative, marker);
3144 generateFullName(it.value(), relative);
3147 }
while (it != legaleseTexts.constEnd() && it.key() == text);
3155 QString marked = marker->markedUpQmlItem(node, summary);
3156 marked.replace(
"@param>",
"i>");
3158 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3159 .arg(summary ?
"summary"_L1 :
"details"_L1));
3160 marked.replace(
"</@extra>",
"</code>");
3164 marked.remove(
"<@name>");
3165 marked.remove(
"</@name>");
3166 marked.remove(
"<@type>");
3167 marked.remove(
"</@type>");
3169 out() << highlightedCode(marked, relative,
false, Genus::QML);
3173
3174
3175
3176
3177
3178
3179
3182 m_qdb->mergeCollections(cn);
3187 if (sortOrder == Qt::DescendingOrder)
3192 for (
const auto *node : std::as_const(members)) {
3193 out() <<
"<li translate=\"no\">";
3194 generateFullName(node,
nullptr);
3202 const QString &selector, Qt::SortOrder sortOrder)
3206 if (selector == QLatin1String(
"overviews"))
3208 else if (selector == QLatin1String(
"cpp-modules"))
3210 else if (selector == QLatin1String(
"qml-modules"))
3214 m_qdb->mergeCollections(type, cnm, relative);
3215 const auto collectionList = cnm.values();
3216 nodeList.reserve(collectionList.size());
3217 for (
auto *collectionNode : collectionList)
3218 nodeList.append(collectionNode);
3219 generateAnnotatedList(relative, marker, nodeList, sortOrder);
3222
3223
3224
3225
3228 QStringLiteral(
"\\generatelist {%1} is only allowed in \\group, "
3229 "\\module and \\qmlmodule comments.")
3233 auto *node =
const_cast<
Node *>(relative);
3234 auto *collectionNode =
static_cast<CollectionNode *>(node);
3235 if (!collectionNode)
3237 m_qdb->mergeCollections(collectionNode);
3238 generateAnnotatedList(collectionNode, marker, collectionNode->members(), sortOrder);
3244 bool alignNames =
true;
3245 if (!nv.isEmpty()) {
3246 bool twoColumn =
false;
3247 if (nv.first()->isProperty()) {
3248 twoColumn = (nv.size() >= 5);
3252 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3255 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3256 <<
"<tr><td class=\"topAlign\">";
3261 for (
const auto &member : nv) {
3264 out() <<
"<tr><td class=\"memItemLeft rightAlign topAlign\"> ";
3266 if (twoColumn && i == (nv.size() + 1) / 2)
3267 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3268 out() <<
"<li class=\"fn\" translate=\"no\">";
3271 generateSynopsis(member, relative, marker, Section::Summary, alignNames);
3273 out() <<
"</td></tr>\n";
3279 out() <<
"</table></div>\n";
3283 out() <<
"</td></tr>\n</table></div>\n";
3291 bool alignNames =
true;
3294 if (!members.isEmpty()) {
3295 bool hasPrivateSignals =
false;
3296 bool isInvokable =
false;
3297 bool twoColumn =
false;
3300 twoColumn = (members.size() >= 16);
3301 }
else if (members.first()->isProperty()) {
3302 twoColumn = (members.size() >= 5);
3306 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3309 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3310 <<
"<tr><td class=\"topAlign\">";
3315 for (
const auto &member : members) {
3318 if (member->name().isEmpty())
3322 out() <<
"<tr><td class=\"memItemLeft topAlign rightAlign\"> ";
3324 if (twoColumn && i == (members.size() + 1) / 2)
3325 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3326 out() <<
"<li class=\"fn\" translate=\"no\">";
3329 generateSynopsis(member, relative, marker, section.style(), alignNames);
3330 if (member->isFunction()) {
3331 const auto *fn =
static_cast<
const FunctionNode *>(member);
3332 if (fn->isPrivateSignal()) {
3333 hasPrivateSignals =
true;
3335 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3336 }
else if (fn->isInvokable()) {
3339 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3343 out() <<
"</td></tr>\n";
3349 out() <<
"</table></div>\n";
3353 out() <<
"</td></tr>\n</table></div>\n";
3356 if (hasPrivateSignals)
3364 && !section.inheritedMembers().isEmpty()) {
3366 generateSectionInheritedList(section, relative);
3373 const QList<std::pair<
const Aggregate *,
int>> &inheritedMembers = section.inheritedMembers();
3374 for (
const auto &member : inheritedMembers) {
3375 out() <<
"<li class=\"fn\" translate=\"no\">";
3376 out() << member.second <<
' ';
3377 if (member.second == 1) {
3378 out() << section.singular();
3380 out() << section.plural();
3382 out() <<
" inherited from <a href=\"" << fileName(member.first) <<
'#'
3383 << Generator::cleanRef(section.title().toLower()) <<
"\">"
3384 << protectEnc(member.first->plainFullName(relative)) <<
"</a></li>\n";
3391 QString marked = marker->markedUpSynopsis(node, relative, style);
3392 marked.replace(
"@param>",
"i>");
3395 marked.remove(
"<@name>");
3396 marked.remove(
"</@name>");
3400 static const QRegularExpression extraRegExp(
"<@extra>.*</@extra>",
3401 QRegularExpression::InvertedGreedinessOption);
3402 marked.remove(extraRegExp);
3404 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3405 .arg(style == Section::Summary ?
"summary"_L1 :
"details"_L1));
3406 marked.replace(
"</@extra>",
"</code>");
3410 marked.remove(
"<@type>");
3411 marked.remove(
"</@type>");
3414 out() << highlightedCode(marked, relative, alignNames);
3417QString
HtmlGenerator::highlightedCode(
const QString &markedCode,
const Node *relative,
3418 bool alignNames, Genus genus)
3420 QString src = markedCode;
3422 html.reserve(src.size());
3426 const QChar charLangle =
'<';
3427 const QChar charAt =
'@';
3429 static const QString typeTag(
"type");
3430 static const QString headerTag(
"headerfile");
3431 static const QString funcTag(
"func");
3432 static const QString linkTag(
"link");
3433 static const QString extrefTag(
"extref");
3434 static const QString conceptTag(
"concept");
3437 static const QHash<QString, QString> extrefUrls = {
3438 {
"cpp-explicitly-defaulted"_L1,
3439 "https://en.cppreference.com/w/cpp/language/function#Defaulted_functions"_L1},
3440 {
"cpp-deleted-functions"_L1,
3441 "https://en.cppreference.com/w/cpp/language/function#Deleted_functions"_L1},
3448 for (
int i = 0, srcSize = src.size(); i < srcSize;) {
3449 if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
3450 if (alignNames && !done) {
3451 html += QLatin1String(
"</td><td class=\"memItemRight bottomAlign\">");
3455 if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) {
3456 html += QLatin1String(
"<b>");
3457 const Node *n =
static_cast<
const Node*>(
Utilities::nodeForString(par1.toString()));
3458 QString link = linkForNode(n, relative);
3459 addLink(link, arg, &html);
3460 html += QLatin1String(
"</b>");
3461 }
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
3462 const FunctionNode *fn = m_qdb->findFunctionNode(par1.toString(), relative, genus);
3463 QString link = linkForNode(fn, relative);
3464 addLink(link, arg, &html);
3465 par1 = QStringView();
3466 }
else if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
3467 par1 = QStringView();
3468 const Node *n = m_qdb->findTypeNode(arg.toString(), relative, genus);
3469 html += QLatin1String(
"<span class=\"type\">");
3472 addLink(linkForNode(n, relative), arg, &html);
3476 addLink(linkForNode(n, relative), arg, &html);
3477 html += QLatin1String(
"</span>");
3478 }
else if (parseArg(src, conceptTag, &i, srcSize, &arg, &par1)) {
3482 const QString target = par1.isEmpty() ? arg.toString() : par1.toString();
3483 par1 = QStringView();
3484 const Node *n = m_qdb->findConceptNode(target);
3486 addLink(linkForNode(n, relative), arg, &html);
3489 }
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
3490 par1 = QStringView();
3491 if (arg.startsWith(QLatin1Char(
'&')))
3494 const Node *n = m_qdb->findNodeForInclude(QStringList(arg.toString()));
3495 if (n && n != relative)
3496 addLink(linkForNode(n, relative), arg, &html);
3500 }
else if (parseArg(src, extrefTag, &i, srcSize, &arg, &par1)) {
3501 QString url = extrefUrls.value(par1.toString());
3503 addLink(url, arg, &html);
3511 html += src.at(i++);
3520 html.reserve(src.size());
3523 QLatin1StringView tag;
3524 QLatin1StringView span;
3526 static constexpr SpanTag spanTags[] = {
3527 {
"comment>"_L1,
"<span class=\"comment\">"_L1},
3528 {
"preprocessor>"_L1,
"<span class=\"preprocessor\">"_L1},
3529 {
"string>"_L1,
"<span class=\"string\">"_L1},
3530 {
"char>"_L1,
"<span class=\"char\">"_L1},
3531 {
"number>"_L1,
"<span class=\"number\">"_L1},
3532 {
"op>"_L1,
"<span class=\"operator\">"_L1},
3533 {
"type>"_L1,
"<span class=\"type\">"_L1},
3534 {
"name>"_L1,
"<span class=\"name\">"_L1},
3535 {
"keyword>"_L1,
"<span class=\"keyword\">"_L1},
3536 {
"template-block>"_L1,
"<span class=\"template-block\">"_L1},
3540 const qsizetype n = src.size();
3541 const QStringView sv(src);
3543 if (sv.at(i) ==
'<'_L1) {
3544 if (i + 1 < n && sv.at(i + 1) ==
'@'_L1) {
3546 bool handled =
false;
3547 for (
const auto &st : spanTags) {
3548 if (i + st.tag.size() <= n
3549 && st.tag == sv.sliced(i, st.tag.size())) {
3558 while (i < n && sv.at(i) !=
'>'_L1)
3564 }
else if (i + 2 < n && sv.at(i + 1) ==
'/'_L1 && sv.at(i + 2) ==
'@'_L1) {
3566 bool handled =
false;
3567 for (
const auto &st : spanTags) {
3568 if (i + st.tag.size() <= n
3569 && st.tag == sv.sliced(i, st.tag.size())) {
3570 html +=
"</span>"_L1;
3578 while (i < n && sv.at(i) !=
'>'_L1)
3596 if (m_linkNode && m_linkNode->isFunction()) {
3598 if (match.hasMatch()) {
3600 qsizetype leftParenLoc = match.capturedStart(1);
3601 out() << protectEnc(atom->string().left(leftParenLoc));
3603 out() << protectEnc(atom->string().mid(leftParenLoc));
3607 out() << protectEnc(atom->string());
3612 return protect(string);
3617 if (string.isEmpty())
3621 if (html.isEmpty()) {
3628 qsizetype n = string.size();
3630 for (
int i = 0; i < n; ++i) {
3631 QChar ch = string.at(i);
3633 if (ch == QLatin1Char(
'&')) {
3635 }
else if (ch == QLatin1Char(
'<')) {
3637 }
else if (ch == QLatin1Char(
'>')) {
3639 }
else if (ch == QChar(8211)) {
3641 }
else if (ch == QChar(8212)) {
3643 }
else if (ch == QLatin1Char(
'"')) {
3646 if (!html.isEmpty())
3651 if (!html.isEmpty())
3660 QString result = Generator::fileBase(node);
3662 result += QLatin1String(
"-obsolete");
3669 return node->name();
3670 return Generator::fileName(node);
3674 const Node *actualNode)
3676 if (actualNode ==
nullptr)
3677 actualNode = apparentNode;
3678 bool link = !linkForNode(actualNode, relative).isEmpty();
3680 out() <<
"<a href=\"" << linkForNode(actualNode, relative);
3682 out() <<
"\" class=\"obsolete";
3685 out() << protectEnc(apparentNode->fullName(relative));
3691
3692
3693
3700 const auto srcLink = Config::instance().getSourceLink();
3701 if (!srcLink.enabled)
3706 if (loc
.isEmpty() || srcLink.baseUrl.isEmpty() || srcLink.rootPath.isEmpty())
3709 QString srcUrl{srcLink.baseUrl};
3710 if (!srcUrl.contains(
'\1'_L1)) {
3711 if (!srcUrl.endsWith(
'/'_L1))
3716 QDir rootDir{srcLink.rootPath};
3717 srcUrl.replace(
'\1'_L1, rootDir.relativeFilePath(loc.filePath()));
3718 srcUrl.replace(
'\2'_L1, QString::number(loc.lineNo()));
3719 const auto &description{
"View declaration of this %1"_L1.arg(node->nodeTypeString())};
3720 out() <<
"<a class=\"srclink\" href=\"%1\" title=\"%2\">%3</a>"_L1
3721 .arg(srcUrl, description, srcLink.linkText);
3728 const QString base = refForNode(node);
3730 for (
int n = 2; m_emittedMemberRefs.contains(ref); ++n)
3731 ref = base +
'-'_L1 + QString::number(n);
3732 m_emittedMemberRefs.insert(ref);
3740 generateExtractionMark(node, MemberMark);
3743 const QList<Node *> &collective = scn->collective();
3744 if (collective.size() > 1)
3745 out() <<
"<div class=\"fngroup\">\n";
3746 QSet<
const Node *> emitted;
3747 for (
const auto *sharedNode : collective) {
3748 if (emitted.contains(sharedNode))
3750 emitted.insert(sharedNode);
3751 out() << headingStart.arg(getClassAttr(sharedNode,
"fn fngroupitem"_L1),
3752 memberHeadingRef(sharedNode));
3753 generateSynopsis(sharedNode, relative, marker, Section::Details);
3754 generateSourceLink(sharedNode);
3755 out() << headingEnd;
3757 if (collective.size() > 1)
3761 if (node->isEnumType(Genus::CPP) && (etn =
static_cast<
const EnumNode *>(node))->flagsType()) {
3762 out() << headingStart.arg(getClassAttr(node,
"flags"_L1), memberHeadingRef(node));
3766 generateSourceLink(node);
3767 out() << headingEnd;
3769 out() << headingStart.arg(getClassAttr(node,
"fn"_L1), memberHeadingRef(node));
3771 generateSourceLink(node);
3772 out() << headingEnd;
3779 const auto *func =
static_cast<
const FunctionNode *>(node);
3780 if (func->hasOverloads() && (func->isSignal() || func->isSlot()))
3789 const auto property =
static_cast<
const PropertyNode *>(node);
3799 out() <<
"<p><b>Access functions:</b></p>\n";
3800 generateSectionList(section, node, marker);
3807 out() <<
"<p><b>Notifier signal:</b></p>\n";
3808 generateSectionList(notifiers, node, marker);
3812 const auto *enumTypeNode =
static_cast<
const EnumNode *>(node);
3813 if (enumTypeNode->flagsType()) {
3814 out() <<
"<p>The " << protectEnc(enumTypeNode->flagsType()->name())
3815 <<
" type is a typedef for "
3816 <<
"<a href=\"" << m_qflagsHref <<
"\">QFlags</a><"
3817 << protectEnc(enumTypeNode->name()) <<
">. It stores an OR combination of "
3818 << protectEnc(enumTypeNode->name()) <<
" values.</p>\n";
3821 generateAlsoList(node, marker);
3822 generateExtractionMark(node, EndMark);
3826
3827
3828
3829
3834 m_linkNode =
nullptr;
3836 if (!m_link.isEmpty())
3837 out() <<
"<a href=\"" << m_link <<
"\" translate=\"no\">";
3845 if (m_link.isEmpty())
3848 const QString &translate_attr =
3849 (node && isApiGenus(node->genus())) ?
" translate=\"no\""_L1 :
""_L1;
3851 if (node ==
nullptr || (relative !=
nullptr && node->status() == relative->status()))
3852 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3853 else if (node->isDeprecated())
3854 out() <<
"<a href=\"" << m_link <<
"\" class=\"obsolete\"%1>"_L1.arg(translate_attr);
3856 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3865 m_linkNode =
nullptr;
3867 if (!m_link.isEmpty())
3872
3873
3874
3878 if (!members.isEmpty()) {
3880 for (
const auto &member : members) {
3881 out() <<
"<li class=\"fn\" translate=\"no\">";
3882 generateQmlItem(member, relative, marker,
true);
3883 if (member->isPropertyGroup()) {
3884 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
3885 if (scn->count() > 0) {
3887 const QList<Node *> &sharedNodes = scn->collective();
3888 for (
const auto &node : sharedNodes) {
3889 if (node->isQmlProperty()) {
3890 out() <<
"<li class=\"fn\" translate=\"no\">";
3891 generateQmlItem(node, relative, marker,
true);
3905
3906
3909 out() << headingStart.arg(getClassAttr(scn,
"fn qml-member qml-property-group"_L1),
3911 <<
"<b>" << scn->name() <<
" group</b>"
3916
3917
3918
3922 generateExtractionMark(node, MemberMark);
3924 auto generateQmlProperty = [&](
Node *n,
bool isGroupItem =
false) {
3925 const auto cssClasses = isGroupItem ?
"fn qml-member qml-property fngroupitem"_L1 :
"fn qml-member qml-property"_L1;
3926 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3927 generateQmlItem(n, relative, marker,
false);
3928 generateSourceLink(n);
3929 out() << headingEnd;
3932 auto generateQmlMethod = [&](
Node *n,
bool isGroupItem =
false) {
3933 const auto cssClasses = isGroupItem ?
"fn qml-member qml-method fngroupitem"_L1 :
"fn qml-member qml-method"_L1;
3934 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3936 generateSourceLink(n);
3937 out() << headingEnd;
3941 auto *scn =
static_cast<
const SharedCommentNode *>(node);
3942 const auto shared = scn->collective();
3944 if (scn->isPropertyGroup() && !scn->name().isEmpty())
3945 emitGroupHeader(scn);
3947 const bool isGroup = shared.size() > 1;
3950 out() <<
"<div class=\"fngroup\">\n"_L1;
3952 for (
auto *child : std::as_const(shared)) {
3953 if (child->isQmlProperty())
3954 generateQmlProperty(child, isGroup);
3956 generateQmlMethod(child, isGroup);
3960 out() <<
"</div>"_L1;
3963 generateQmlProperty(node);
3965 generateQmlMethod(node);
3972 generateAlsoList(node, marker);
3973 generateExtractionMark(node, EndMark);
3976void HtmlGenerator::generateExtractionMark(
const Node *node, ExtractionMarkType markType)
3978 if (markType != EndMark) {
3979 out() <<
"<!-- $$$" + node->name();
3980 if (markType == MemberMark) {
3982 const auto *func =
static_cast<
const FunctionNode *>(node);
3983 if (!func->hasAssociatedProperties()) {
3984 if (func->overloadNumber() == 0)
3985 out() <<
"[overload1]";
3986 out() <<
"$$$" + func->name() + func->parameters().rawSignature().remove(
' ');
3990 const auto *prop =
static_cast<
const PropertyNode *>(node);
3991 const NodeList &list = prop->functions();
3992 for (
const auto *propFuncNode : list) {
3993 if (propFuncNode->isFunction()) {
3994 const auto *func =
static_cast<
const FunctionNode *>(propFuncNode);
3995 out() <<
"$$$" + func->name()
3996 + func->parameters().rawSignature().remove(
' ');
4000 const auto *enumNode =
static_cast<
const EnumNode *>(node);
4001 const auto &items = enumNode->items();
4002 for (
const auto &item : items)
4003 out() <<
"$$$" + item.name();
4005 }
else if (markType == BriefMark) {
4007 }
else if (markType == DetailedDescriptionMark) {
4008 out() <<
"-description";
4012 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.
virtual bool generatesHelpProject() const
Returns true if this generator writes a Qt help project (.qhp) file.
qsizetype generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker) override
Generate html from an instance of Atom.
static bool isIncluded(const InclusionPolicy &policy, const NodeContext &context)
The Location class provides a way to mark a location in a file.
bool isEmpty() const
Returns true if there is no file name set yet; returns false otherwise.
The ManifestWriter is responsible for writing manifest files.
void generateManifestFiles()
This function outputs one or more manifest files in XML.
This class represents a C++ namespace.
NamespaceNode * docNode() const
Returns a pointer to the NamespaceNode that represents where the namespace documentation is actually ...
Tree * tree() const override
Returns a pointer to the Tree that contains this NamespaceNode.
bool isDocumentedHere() const
Returns true if this namespace is to be documented in the current module.
A PageNode is a Node that generates a documentation page.
bool noAutoList() const
Returns the value of the no auto-list flag.
This class describes one instance of using the Q_PROPERTY macro.
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
Status
Specifies the status of the QQmlIncubator.
ClassNode * classNode() const override
If this is a QmlTypeNode, this function returns the pointer to the C++ ClassNode that this QML type r...
bool isUncreatable() const
static void subclasses(const Node *base, NodeList &subs, bool recurse=false)
Loads the list subs with the nodes of all the subclasses of base.
QString logicalModuleVersion() const override
If the QML type's QML module pointer is set, return the QML module version from the QML module node.
QString logicalModuleName() const override
If the QML type's QML module pointer is set, return the QML module name from the QML module node.
QmlTypeNode * qmlBaseNode() const override
If this Aggregate is a QmlTypeNode, this function returns a pointer to the QmlTypeNode that is its ba...
CollectionNode * logicalModule() const override
If this is a QmlTypeNode, a pointer to its QML module is returned, which is a pointer to a Collection...
A class for containing the elements of one documentation section.
const NodeVector & obsoleteMembers() const
void appendMembers(const NodeVector &nv)
const Aggregate * aggregate() const
const ClassNodesList & classNodesList() const
const NodeVector & members() const
A class for creating vectors of collections for documentation.
const Aggregate * aggregate() const
SectionVector & summarySections()
SectionVector & sinceSections()
Sections(const Aggregate *aggregate)
This constructor builds the section vectors based on the type of the aggregate node.
Sections(const NodeMultiMap &nsmap)
This constructor builds the since sections from the since node map, nsmap.
bool hasObsoleteMembers(SectionPtrVector *summary_spv, SectionPtrVector *details_spv) const
Returns true if any sections in this object contain obsolete members.
SectionVector & detailsSections()
const Section & allMembersSection() const
Table of contents writer.
void generateTOC(const QString &fileName, const QString &indexTitle)
Writes the TOC entries for project to fileName, starting from a page with a title matching indexTitle...
This class handles the generation of the QDoc tag files.
void generateTagFile(const QString &fileName, Generator *generator)
Writes a tag file named fileName.
const QString & camelCaseModuleName() const
static void rewritePropertyBrief(const Atom *atom, const Node *relative)
Rewrites the brief of this node depending on its first word.
static int hOffset(const Node *node)
Header offset depending on the type of the node.
static bool hasBrief(const Node *node)
Do not display.
XmlGenerator(FileResolver &file_resolver)
static const QRegularExpression m_funcLeftParen
static NodeType typeFromString(const Atom *atom)
Returns the type of this atom as an enumeration.
#define COMMAND_INQMLMODULE
#define CONFIG_USEALTTEXTASTITLE
#define CONFIG_CPPCLASSESTITLE
#define CONFIG_CODEPREFIX
#define CONFIG_QMLTYPESPAGE
#define CONFIG_HEADERSCRIPTS
#define CONFIG_DESCRIPTION
#define CONFIG_CODEINDENT
#define CONFIG_TRADEMARKSPAGE
#define CONFIG_CPPCLASSESPAGE
#define CONFIG_NATURALLANGUAGE
#define CONFIG_PRODUCTNAME
#define CONFIG_NAVIGATION
#define CONFIG_BUILDVERSION
#define CONFIG_LANDINGPAGE
#define CONFIG_CODESUFFIX
#define CONFIG_LANDINGTITLE
#define CONFIG_HEADERSTYLES
#define CONFIG_QMLTYPESTITLE
static QString getClassAttr(const Node *node, const QString &classSet)
Extends the class HTML attribute generated for node.
static void appendTemplateParametersAtoms(Text &out, const TemplateDeclarationStorage &storage)
static const Atom closeCodeTag
static void addLink(const QString &linkTarget, QStringView nestedStuff, QString *res)
static const auto headingStart
static void appendTemplateParameterAtoms(Text &out, const RelaxedTemplateParameter ¶m)
static const auto headingEnd
static const Atom openCodeTag
static void appendTemplateDeclAtoms(Text &out, const RelaxedTemplateDeclaration &templateDecl)
#define HTMLGENERATOR_PROLOGUE
#define HTMLGENERATOR_NONAVIGATIONBAR
#define HTMLGENERATOR_TOCDEPTH
#define HTMLGENERATOR_NAVIGATIONSEPARATOR
#define HTMLGENERATOR_POSTPOSTHEADER
#define HTMLGENERATOR_ADDRESS
#define HTMLGENERATOR_FOOTER
#define HTMLGENERATOR_POSTHEADER
Pure string helpers with no dependencies on QDoc driver types.
This namespace holds QDoc-internal utility methods.
QList< Node * > NodeVector
QMap< QString, Node * > NodeMap
QMap< QString, NodeMap > NodeMapMap
QMap< QString, CollectionNode * > CNMap
QT_BEGIN_NAMESPACE typedef QMultiMap< Text, const Node * > TextToNodeMap
QList< const Section * > SectionPtrVector
QList< Section > SectionVector
QList< ClassNodes > ClassNodesList
The Node class is the base class for all the nodes in QDoc's parse tree.
bool isExternalPage() const
Returns true if the node type is ExternalPage.
const Doc & doc() const
Returns a reference to the node's Doc data member.
virtual bool hasClasses() const
Returns true if this is a CollectionNode and its members list contains class nodes.
virtual bool hasNamespaces() const
Returns true if this is a CollectionNode and its members list contains namespace nodes.
bool isEnumType(Genus g) const
bool isGroup() const
Returns true if the node type is Group.
SharedCommentNode * sharedCommentNode()
bool isNamespace() const
Returns true if the node type is Namespace.
bool isQmlBasicType() const
Returns true if the node type is QmlBasicType.
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
bool isSharedCommentNode() const
Returns true if the node type is SharedComment.
bool isHeader() const
Returns true if the node type is HeaderFile.
Genus genus() const override
Returns this node's Genus.
virtual bool isPageNode() const
Returns true if this node represents something that generates a documentation page.
bool isEnumType() const
Returns true if the node type is Enum.
virtual Status status() const
Returns the node's status value.
Aggregate * parent() const
Returns the node's parent pointer, that is, the aggregate under which the node is documented.
virtual bool isDeprecated() const
Returns true if this node's status is Deprecated.
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
static bool nodeNameLessThan(const Node *first, const Node *second)
Returns true if the node n1 is less than node n2.
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.
bool isProxyNode() const
Returns true if the node type is Proxy.
const std::optional< RelaxedTemplateDeclaration > & templateDecl() const
bool isFunction(Genus g=Genus::DontCare) const
Returns true if this is a FunctionNode and its Genus is set to g.
bool isProperty() const
Returns true if the node type is Property.
const Location & declLocation() const
Returns the Location where this node's declaration was seen.
NodeContext createContext() const
bool isModule() const
Returns true if the node type is Module.
bool isSharingComment() const
This function returns true if the node is sharing a comment with other nodes.
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
static bool nodeSortKeyOrNameLessThan(const Node *n1, const Node *n2)
Returns true if node n1 is less than node n2 when comparing the sort keys, defined with.
bool isQmlModule() const
Returns true if the node type is QmlModule.
bool isExample() const
Returns true if the node type is Example.
bool isQmlProperty() const
Returns true if the node type is QmlProperty.
ValuedDeclaration valued_declaration
Represents a file that is reachable by QDoc based on its current configuration.