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;
465 QString name = atom->string();
466 if (relative && relative->name() == name.replace(QLatin1String(
"()"), QLatin1String())) {
467 out() << protectEnc(atom->string());
475 if (!m_inLink && !m_inContents && !m_inSectionHeading) {
476 const Node *node =
nullptr;
477 QString link = getAutoLink(atom, relative, &node, genus);
478 if (link.isEmpty()) {
483 QStringLiteral(
"Can't autolink to '%1'").arg(atom->string()));
488 if (link.isEmpty()) {
489 out() << protectEnc(atom->string());
491 beginLink(link, node, relative);
496 out() << protectEnc(atom->string());
503 skipAhead = skipAtoms(atom, Atom::BriefRight);
518 out() << protectEnc(plainCode(atom->string()));
522 out() <<
"<p class=\"figCaption\">";
533 out() <<
"<pre class=\"qml\" translate=\"no\"><code class=\"qml\">"
534 << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative,
536 m_codePrefix, m_codeSuffix)
537 <<
"</code></pre>\n";
541 if (atom->strings().count() == 2)
542 out() <<
"<pre class=\"" << atom->string(1) <<
"\" translate=\"no\"><code class=\"" << atom->string(1) <<
"\">";
544 out() <<
"<pre class=\"cpp\" translate=\"no\"><code class=\"cpp\">";
546 out() << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative),
547 m_codePrefix, m_codeSuffix)
548 <<
"</code></pre>\n";
551 out() <<
"<pre class=\"cpp plain\" translate=\"no\"><code class=\"text\">"
552 << trimmedTrailing(protectEnc(plainCode(indent(m_codeIndent, atom->string()))),
553 m_codePrefix, m_codeSuffix)
554 <<
"</code></pre>\n";
557 out() <<
"<details>\n";
559 out() <<
"<summary>...</summary>\n";
562 out() <<
"<summary>";
565 out() <<
"</summary>\n";
568 out() <<
"</details>\n";
572 if (!atom->string().isEmpty())
573 out() <<
' ' << atom->string();
596 if (atom->string().startsWith(
"span "))
597 out() <<
'<' + atom->string() <<
'>';
599 out() << formattingLeftMap()[atom->string()];
607 const Node *node{
nullptr};
608 const Atom tm_link(Atom::NavLink, m_trademarkspage);
609 if (
const auto &link = getLink(&tm_link, relative, &node);
610 !link.isEmpty() && node != relative)
611 out() <<
"<a href=\"%1\">%2</a>"_L1.arg(link, formattingRightMap()[atom->string()]);
613 out() << formattingRightMap()[atom->string()];
616 }
else if (atom->string().startsWith(
"span ")) {
619 out() << formattingRightMap()[atom->string()];
623 if (
const auto *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group); cn)
624 generateList(cn, marker, atom->string(), Generator::sortOrder(atom->strings().last()));
627 const auto sortOrder{Generator::sortOrder(atom->strings().last())};
628 if (atom->string() == QLatin1String(
"annotatedclasses")) {
629 generateAnnotatedList(relative, marker, m_qdb->getCppClasses().values(), sortOrder);
630 }
else if (atom->string() == QLatin1String(
"annotatedexamples")) {
631 generateAnnotatedLists(relative, marker, m_qdb->getExamples());
632 }
else if (atom->string() == QLatin1String(
"annotatedattributions")) {
633 generateAnnotatedLists(relative, marker, m_qdb->getAttributions());
634 }
else if (atom->string() == QLatin1String(
"classes")) {
635 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true,
637 }
else if (atom->string().contains(
"classes ")) {
638 QString rootName = atom->string().mid(atom->string().indexOf(
"classes") + 7).trimmed();
639 generateCompactList(Generic, relative, m_qdb->getCppClasses(),
true, rootName);
640 }
else if (atom->string() == QLatin1String(
"qmlvaluetypes")
641 || atom->string() == QLatin1String(
"qmlbasictypes")) {
642 generateCompactList(Generic, relative, m_qdb->getQmlValueTypes(),
true,
644 }
else if (atom->string() == QLatin1String(
"qmltypes")) {
645 generateCompactList(Generic, relative, m_qdb->getQmlTypes(),
true, QStringLiteral(
""));
646 }
else if ((idx = atom->string().indexOf(QStringLiteral(
"bymodule"))) != -1) {
648 QString moduleName = atom->string().mid(idx + 8).trimmed();
650 if (
const auto *cn = qdb->getCollectionNode(moduleName, moduleType)) {
652 switch (moduleType) {
656 generateAnnotatedList(relative, marker, map.values(), sortOrder);
659 if (atom->string().contains(QLatin1String(
"qmlvaluetypes")))
663 generateAnnotatedList(relative, marker, map.values(), sortOrder);
666 generateAnnotatedList(relative, marker, cn->members(), sortOrder);
670 }
else if (atom->string() == QLatin1String(
"classhierarchy")) {
671 generateClassHierarchy(relative, m_qdb->getCppClasses());
672 }
else if (atom->string() == QLatin1String(
"obsoleteclasses")) {
673 generateCompactList(Generic, relative, m_qdb->getObsoleteClasses(),
false,
674 QStringLiteral(
"Q"));
675 }
else if (atom->string() == QLatin1String(
"obsoleteqmltypes")) {
676 generateCompactList(Generic, relative, m_qdb->getObsoleteQmlTypes(),
false,
678 }
else if (atom->string() == QLatin1String(
"obsoletecppmembers")) {
679 generateCompactList(Obsolete, relative, m_qdb->getClassesWithObsoleteMembers(),
false,
680 QStringLiteral(
"Q"));
681 }
else if (atom->string() == QLatin1String(
"obsoleteqmlmembers")) {
682 generateCompactList(Obsolete, relative, m_qdb->getQmlTypesWithObsoleteMembers(),
false,
684 }
else if (atom->string() == QLatin1String(
"functionindex")) {
685 generateFunctionIndex(relative);
686 }
else if (atom->string() == QLatin1String(
"attributions")) {
687 generateAnnotatedList(relative, marker, m_qdb->getAttributions().values(), sortOrder);
688 }
else if (atom->string() == QLatin1String(
"legalese")) {
689 generateLegaleseList(relative, marker);
690 }
else if (atom->string() == QLatin1String(
"overviews")) {
691 generateList(relative, marker,
"overviews", sortOrder);
692 }
else if (atom->string() == QLatin1String(
"cpp-modules")) {
693 generateList(relative, marker,
"cpp-modules", sortOrder);
694 }
else if (atom->string() == QLatin1String(
"qml-modules")) {
695 generateList(relative, marker,
"qml-modules", sortOrder);
696 }
else if (atom->string() == QLatin1String(
"namespaces")) {
697 generateAnnotatedList(relative, marker, m_qdb->getNamespaces().values(), sortOrder);
698 }
else if (atom->string() == QLatin1String(
"related")) {
699 generateList(relative, marker,
"related", sortOrder);
701 const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group);
703 if (!generateGroupList(
const_cast<CollectionNode *>(cn), sortOrder))
705 QString(
"'\\generatelist %1' group is empty").arg(atom->string()));
708 QString(
"'\\generatelist %1' no such group").arg(atom->string()));
713 const NodeMultiMap &nsmap = m_qdb->getSinceMap(atom->string());
717 const NodeMultiMap &ncmap = m_qdb->getClassMap(atom->string());
718 const NodeMultiMap &nqcmap = m_qdb->getQmlTypeMap(atom->string());
723 for (
const auto §ion : sinceSections) {
724 if (!section.members().isEmpty()) {
726 <<
"<a href=\"#" << TextUtils::asAsciiPrintable(section.title()) <<
"\">"
727 << section.title() <<
"</a></li>\n";
733 for (
const auto §ion : sinceSections) {
734 if (!section.members().isEmpty()) {
735 out() <<
"<h3 id=\"" << TextUtils::asAsciiPrintable(section.title()) <<
"\">"
736 << protectEnc(section.title()) <<
"</h3>\n";
737 if (index == Sections::SinceClasses)
738 generateCompactList(Generic, relative, ncmap,
false, QStringLiteral(
"Q"));
739 else if (index == Sections::SinceQmlTypes)
740 generateCompactList(Generic, relative, nqcmap,
false, QStringLiteral(
""));
741 else if (index == Sections::SinceMemberFunctions
742 || index == Sections::SinceQmlMethods
743 || index == Sections::SinceQmlProperties) {
745 QMap<QString, NodeMultiMap> parentmaps;
747 const QList<Node *> &members = section.members();
748 for (
const auto &member : members) {
749 QString parent_full_name = (*member).parent()->fullName();
751 auto parent_entry = parentmaps.find(parent_full_name);
752 if (parent_entry == parentmaps.end())
753 parent_entry = parentmaps.insert(parent_full_name, NodeMultiMap());
754 parent_entry->insert(member->name(), member);
757 for (
auto map = parentmaps.begin(); map != parentmaps.end(); ++map) {
758 NodeVector nv = map->values().toVector();
759 auto parent = nv.front()->parent();
761 out() << ((index == Sections::SinceMemberFunctions) ?
"<p>Class " :
"<p>QML Type ");
763 out() <<
"<a href=\"" << linkForNode(parent, relative) <<
"\" translate=\"no\">";
764 QStringList pieces = parent->fullName().split(
"::");
765 out() << protectEnc(pieces.last());
769 generateSection(nv, relative, marker);
772 }
else if (index == Sections::SinceEnumValues) {
773 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
774 const auto map_it = m_qdb->newEnumValueMaps().constFind(atom->string());
775 for (
auto it = map_it->cbegin(); it != map_it->cend(); ++it) {
776 out() <<
"<tr><td class=\"memItemLeft\"> enum value </td><td class=\"memItemRight\">"
777 <<
"<b><a href=\"" << linkForNode(it.value(),
nullptr) <<
"\">"
778 << it.key() <<
"</a></b></td></tr>\n";
780 out() <<
"</table></div>\n";
782 generateSection(section.members(), relative, marker);
800 out() <<
"<p class=\"centerAlign\">";
802 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
803 if (!maybe_resolved_file) {
806 QStringLiteral(
"Missing image: %1").arg(protectEnc(atom->string())));
807 out() <<
"<font color=\"red\">[Missing image " << protectEnc(atom->string())
811 QString file_name{QFileInfo{file.get_path()}.fileName()};
831 "%1/%2"_L1.arg(outputDir(), imagesOutputDir()));
833 const auto &imgPath =
"%1/%2"_L1.arg(imagesOutputDir(), file_name);
835 out() <<
"<img src=\"%1\""_L1.arg(protectEnc(imgPath));
837 const QString altAndTitleText = protectEnc(text);
838 out() <<
" alt=\"" << altAndTitleText;
840 out() <<
"\" title=\"" << altAndTitleText;
844 if (m_helpProjectWriter)
845 m_helpProjectWriter->addExtraFile(imgPath);
846 setImageFileName(relative, imgPath);
858 QString admonType = atom->typeString();
861 out() <<
"<div class=\"admonition " << admonType.toLower() <<
"\">\n"
864 out() << admonType <<
": ";
874 out() <<
"<div class=\"LegaleseLeft\">";
888 const Node *node =
nullptr;
889 QString link = getLink(atom, relative, &node);
891 Location location = atom->isLinkAtom() ?
static_cast<
const LinkAtom*>(atom)->location
892 : relative->doc().location();
894 QStringLiteral(
"Can't link to '%1'").arg(atom->string()));
896 beginLink(link, node, relative);
900 QString link = linkForExampleFile(atom->string());
905 QString link = atom->string();
906 link =
"images/used-in-examples/" + link;
911 const Node *node =
static_cast<
const Node*>(
Utilities::nodeForString(atom->string()));
912 beginLink(linkForNode(node, relative), node, relative);
925 out() << R"(<div class="table"><table class="valuelist">)";
926 m_threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom);
927 if (m_threeColumnEnumValueTable) {
928 if (++m_numTableRows % 2 == 1)
929 out() << R"(<tr valign="top" class="odd">)";
931 out() << R"(<tr valign="top" class="even">)";
933 out() <<
"<th class=\"tblConst\">Constant</th>";
937 out() <<
"<th class=\"tblval\">Value</th>";
939 out() <<
"<th class=\"tbldscr\">Description</th></tr>\n";
941 out() <<
"<tr><th class=\"tblConst\">Constant</th><th "
942 "class=\"tblVal\">Value</th></tr>\n";
959 out() << QString(R"(<ol class="%1" type="%1" start="%2">)")
960 .arg(olType, atom
->next()->string());
962 out() << QString(R"(<ol class="%1" type="%1">)").arg(olType);
971 std::pair<QString,
int> pair = getAtomListValue(atom);
972 skipAhead = pair.second;
973 QString t = protectEnc(plainCode(marker->markedUpEnumValue(pair.first, relative)));
974 out() <<
"<tr><td class=\"topAlign\"><code translate=\"no\">" << t <<
"</code>";
977 out() <<
"</td><td class=\"topAlign tblval\">";
978 const auto *enume =
static_cast<
const EnumNode *>(relative);
979 QString itemValue = enume->itemValue(atom->next()->string());
980 if (itemValue.isEmpty())
983 out() <<
"<code translate=\"no\">" << protectEnc(itemValue) <<
"</code>";
996 if (m_threeColumnEnumValueTable) {
997 out() <<
"</td><td class=\"topAlign\">";
1004 if (matchAhead(atom, Atom::ParaLeft))
1011 out() <<
"</td></tr>\n";
1022 out() <<
"</table></div>\n";
1043 out() <<
"<blockquote>";
1046 out() <<
"</blockquote>\n";
1049 out() << atom->string();
1055 int unit = atom->string().toInt() +
hOffset(relative
);
1056 out() <<
"<h" + QString::number(unit) + QLatin1Char(
' ') <<
"id=\""
1057 << Tree::refForAtom(atom) <<
"\">";
1058 m_inSectionHeading =
true;
1061 case Atom::SectionHeadingRight:
1062 out() <<
"</h" + QString::number(atom->string().toInt() + hOffset(relative)) +
">\n";
1063 m_inSectionHeading =
false;
1070 if (m_inLink && !m_inContents && !m_inSectionHeading) {
1073 out() << protectEnc(atom->string());
1077 std::pair<QString, QString> pair = getTableWidthAttr(atom);
1078 QString attr = pair.second;
1079 QString width = pair.first;
1086 out() << R"(<div class="table"><table class=")" << attr <<
'"';
1087 if (!width.isEmpty())
1088 out() <<
" style=\"width: " << width <<
'"';
1093 out() <<
"</table></div>\n";
1096 out() <<
"<thead><tr class=\"qt-style\">";
1097 m_inTableHeader =
true;
1103 out() <<
"\n<tr class=\"qt-style\">";
1105 out() <<
"</thead>\n";
1106 m_inTableHeader =
false;
1110 if (!atom->string().isEmpty())
1111 out() <<
"<tr " << atom->string() <<
'>';
1112 else if (++m_numTableRows % 2 == 1)
1113 out() << R"(<tr valign="top" class="odd">)";
1115 out() << R"(<tr valign="top" class="even">)";
1121 if (m_inTableHeader)
1126 for (
int i = 0; i < atom->count(); ++i) {
1129 const QString &p = atom->string(i);
1130 if (p.contains(
'=')) {
1133 QStringList spans = p.split(QLatin1Char(
','));
1134 if (spans.size() == 2) {
1135 if (spans.at(0) !=
"1")
1136 out() <<
" colspan=\"" << spans.at(0) <<
'"';
1137 if (spans.at(1) !=
"1")
1138 out() <<
" rowspan=\"" << spans.at(1) <<
'"';
1143 if (matchAhead(atom, Atom::ParaLeft))
1147 if (m_inTableHeader)
1152 if (matchAhead(atom, Atom::ParaLeft))
1162 out() <<
"<span id=\"" <<
TextUtils::asAsciiPrintable(atom->string()) <<
"\"></span>";
1165 out() <<
"<b class=\"redFont\"><Missing HTML></b>";
1167 case Atom::UnknownCommand:
1168 out() << R"(<b class="redFont"><code translate=\"no\">\)" << protectEnc(atom->string()) <<
"</code></b>";
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1216 auto link_for_group = [
this](
const CollectionNode *group) -> QString {
1217 QString target{linkForNode(group,
nullptr)};
1218 return (target.isEmpty()) ? protectEnc(group->name()) :
"<a href=\"" + target +
"\">" + protectEnc(group->fullTitle()) +
"</a>";
1223 const QStringList &groups_names{node->groupNames()};
1224 if (groups_names.isEmpty())
1227 std::vector<CollectionNode *> groups_nodes(groups_names.size(),
nullptr);
1228 std::transform(groups_names.cbegin(), groups_names.cend(), groups_nodes.begin(),
1231 m_qdb->mergeCollections(group);
1232 return (group && group
->wasSeen()) ? group :
nullptr;
1234 groups_nodes.erase(
std::remove(groups_nodes.begin(), groups_nodes.end(),
nullptr), groups_nodes.end());
1236 if (!groups_nodes.empty()) {
1237 text += node->name() +
" is part of ";
1239 for (std::vector<CollectionNode *>::size_type index{0}; index < groups_nodes.size(); ++index) {
1240 text += link_for_group(groups_nodes[index]) + TextUtils::separator(index, groups_nodes.size());
1247
1248
1249
1250
1261 QString typeWord = aggregate->typeWord(
true);
1264 fullTitle = aggregate->plainFullName();
1265 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1266 ns =
static_cast<NamespaceNode *>(aggregate);
1268 fullTitle = aggregate->plainFullName();
1269 title =
"%1 %2"_L1.arg(fullTitle, typeWord);
1271 title = fullTitle = aggregate->fullTitle();
1272 if (!aggregate->doc().title().isEmpty())
1273 titleText << aggregate->name() <<
" - "_L1 << aggregate->doc().title();
1278 if (aggregate
->parent()->isInAPI() || templateDecl) {
1280 appendTemplateDeclAtoms(subtitleText, *templateDecl);
1281 subtitleText <<
" "_L1;
1283 subtitleText << aggregate->typeWord(
false) <<
" "_L1;
1284 auto ancestors = fullTitle.split(
"::"_L1);
1285 ancestors.pop_back();
1286 for (
const auto &a : ancestors)
1287 subtitleText << Atom(Atom::AutoLink, a) <<
"::"_L1;
1288 subtitleText << aggregate->plainName();
1291 generateHeader(title, aggregate, marker);
1292 generateTableOfContents(aggregate, marker, &summarySections);
1294 generateTitle(titleText, subtitleText, SmallSubTitle, aggregate, marker);
1296 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1300 brief <<
"The " << ns->name() <<
" namespace includes the following elements from module "
1303 addNodeLink(brief, fullNamespace,
" here.");
1305 generateText(brief, ns, marker);
1308 generateBrief(aggregate, marker);
1310 const auto parentIsClass = aggregate
->parent()->isClassNode();
1313 generateRequisites(aggregate, marker);
1318 QString membersLink = generateAllMembersFile(sections.allMembersSection(), marker);
1319 if (!membersLink.isEmpty()) {
1320 openUnorderedList();
1321 out() <<
"<li><a href=\"" << membersLink <<
"\">"
1322 <<
"List of all members, including inherited members</a></li>\n";
1324 QString obsoleteLink = generateObsoleteMembersFile(sections, marker);
1325 if (!obsoleteLink.isEmpty()) {
1326 openUnorderedList();
1327 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1328 <<
"Deprecated members</a></li>\n";
1331 if (QString groups_text{groupReferenceText(aggregate)}; !groups_text.isEmpty()) {
1332 openUnorderedList();
1334 out() <<
"<li>" << groups_text <<
"</li>\n";
1337 closeUnorderedList();
1342 bool needOtherSection =
false;
1344 for (
const auto §ion : summarySections) {
1345 if (section.members().isEmpty() && section.reimplementedMembers().isEmpty()) {
1346 if (!section.inheritedMembers().isEmpty())
1347 needOtherSection =
true;
1349 if (!section.members().isEmpty()) {
1350 QString ref = registerRef(section.title().toLower());
1351 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1352 generateSection(section.members(), aggregate, marker);
1354 if (!section.reimplementedMembers().isEmpty()) {
1355 QString name = QString(
"Reimplemented ") + section.title();
1356 QString ref = registerRef(name.toLower());
1357 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(name) <<
"</h2>\n";
1358 generateSection(section.reimplementedMembers(), aggregate, marker);
1361 if (!section.inheritedMembers().isEmpty()) {
1363 generateSectionInheritedList(section, aggregate);
1369 if (needOtherSection) {
1370 out() <<
"<h3>Additional Inherited Members</h3>\n"
1373 for (
const auto §ion : summarySections) {
1374 if (section.members().isEmpty() && !section.inheritedMembers().isEmpty())
1375 generateSectionInheritedList(section, aggregate);
1380 if (aggregate
->doc().isEmpty()) {
1381 QString command =
"documentation";
1383 command = R"('\class' comment)";
1386 QStringLiteral(
"No %1 for '%2'").arg(command, aggregate->plainSignature()));
1389 generateExtractionMark(aggregate, DetailedDescriptionMark);
1390 out() <<
"<div class=\"descr\">\n"
1391 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1392 <<
"Detailed Description"
1395 out() <<
"</div>\n";
1396 generateAlsoList(aggregate, marker);
1397 generateExtractionMark(aggregate, EndMark);
1400 for (
const auto §ion : detailsSections) {
1401 bool headerGenerated =
false;
1402 if (section.isEmpty())
1405 const QList<Node *> &members = section.members();
1406 for (
const auto &member : members) {
1407 if (!headerGenerated) {
1408 if (!section.divClass().isEmpty())
1409 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1410 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1411 headerGenerated =
true;
1413 if (!member->isClassNode())
1414 generateDetailedMember(member, aggregate, marker);
1417 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1418 out() <<
" class=\"%1\""_L1.arg(attrs);
1419 out() <<
"> class ";
1420 generateFullName(member, aggregate);
1422 generateBrief(member, marker, aggregate);
1425 if (headerGenerated && !section.divClass().isEmpty())
1426 out() <<
"</div>\n";
1428 generateFooter(aggregate);
1441 QString rawTitle = aggregate->plainName();
1442 QString fullTitle = aggregate->plainFullName();
1443 QString title = rawTitle +
" Proxy Page";
1444 generateHeader(title, aggregate, marker, u"auto-generated"_s);
1445 generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker);
1446 generateBrief(aggregate, marker);
1447 for (
const auto §ion : summarySections) {
1448 if (!section.members().isEmpty()) {
1449 QString ref = registerRef(section.title().toLower());
1450 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1451 generateSection(section.members(), aggregate, marker);
1455 if (!aggregate
->doc().isEmpty()) {
1456 generateExtractionMark(aggregate, DetailedDescriptionMark);
1457 out() <<
"<div class=\"descr\">\n"
1458 <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1459 <<
"Detailed Description"
1462 out() <<
"</div>\n";
1463 generateAlsoList(aggregate, marker);
1464 generateExtractionMark(aggregate, EndMark);
1467 for (
const auto §ion : detailsSections) {
1468 if (section.isEmpty())
1471 if (!section.divClass().isEmpty())
1472 out() <<
"<div class=\"" << section.divClass() <<
"\">\n";
1473 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1475 const QList<Node *> &members = section.members();
1476 for (
const auto &member : members) {
1477 if (!member->isClassNode()) {
1478 generateDetailedMember(member, aggregate, marker);
1481 if (
const auto &attrs = getClassAttr(member,
""_L1); !attrs.isEmpty())
1482 out() <<
" class=\"%1\""_L1.arg(attrs);
1483 out() <<
"> class ";
1484 generateFullName(member, aggregate);
1486 generateBrief(member, marker, aggregate);
1489 if (!section.divClass().isEmpty())
1490 out() <<
"</div>\n";
1492 generateFooter(aggregate);
1496
1497
1498
1502 SubTitleSize subTitleSize = LargeSubTitle;
1503 QString htmlTitle = qcn->name();
1505 htmlTitle.append(
" QML Value Type");
1507 htmlTitle.append(
" QML Type");
1510 htmlTitle.append(
" (Singleton)"_L1);
1512 htmlTitle.append(
" (Uncreatable)"_L1);
1514 generateHeader(htmlTitle, qcn, marker);
1517 marker = CodeMarker::markerForLanguage(QLatin1String(
"QML"));
1518 generateTitle(htmlTitle,
Text() << qcn->subtitle(), subTitleSize, qcn, marker);
1519 generateBrief(qcn, marker);
1520 generateQmlRequisites(qcn, marker);
1524 out() <<
"<p><strong>Note:</strong> This type is a QML singleton. "_L1
1525 <<
"There is only one instance of this type in the QML engine.</p>\n"_L1;
1527 out() <<
"<p><strong>Note:</strong> This is an uncreatable type. "_L1
1528 <<
"It cannot be instantiated in QML.</p>\n"_L1;
1531 QString allQmlMembersLink;
1534 if (!qcn->isQmlBasicType())
1535 allQmlMembersLink = generateAllQmlMembersFile(sections, marker);
1536 QString obsoleteLink = generateObsoleteQmlMembersFile(sections, marker);
1537 if (!allQmlMembersLink.isEmpty() || !obsoleteLink.isEmpty()) {
1538 openUnorderedList();
1540 if (!allQmlMembersLink.isEmpty()) {
1541 out() <<
"<li><a href=\"" << allQmlMembersLink <<
"\">"
1542 <<
"List of all members, including inherited members</a></li>\n";
1544 if (!obsoleteLink.isEmpty()) {
1545 out() <<
"<li><a href=\"" << obsoleteLink <<
"\">"
1546 <<
"Deprecated members</a></li>\n";
1550 if (QString groups_text{groupReferenceText(qcn)}; !groups_text.isEmpty()) {
1551 openUnorderedList();
1553 out() <<
"<li>" << groups_text <<
"</li>\n";
1556 closeUnorderedList();
1559 for (
const auto §ion : qmlSummarySections) {
1560 if (!section.isEmpty()) {
1561 QString ref = registerRef(section.title().toLower());
1562 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section.title()) <<
"</h2>\n";
1563 generateQmlSummary(section.members(), qcn, marker);
1567 generateExtractionMark(qcn, DetailedDescriptionMark);
1568 out() <<
"<h2 id=\"" << registerRef(
"details") <<
"\">"
1569 <<
"Detailed Description"
1572 generateAlsoList(qcn, marker);
1573 generateExtractionMark(qcn, EndMark);
1576 for (
const auto §ion : qmlDetailsSections) {
1577 if (section.isEmpty())
1579 out() <<
"<h2>" << protectEnc(section.title()) <<
"</h2>\n";
1580 const QList<Node *> &members = section.members();
1581 for (
const auto member : members)
1582 generateDetailedQmlMember(member, qcn, marker);
1584 generateFooter(qcn);
1589
1590
1591
1594 generateHeader(pn->fullTitle(), pn, marker);
1596
1597
1598
1599 if ((pn->name() != QLatin1String(
"index.html")))
1600 generateTableOfContents(pn, marker,
nullptr);
1602 generateTitle(pn
->doc().title(),
Text() << pn->subtitle(), LargeSubTitle, pn, marker);
1604 generateBrief(pn, marker,
nullptr,
false);
1607 generateExtractionMark(pn, DetailedDescriptionMark);
1608 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1612 out() <<
"</div>\n";
1613 generateAlsoList(pn, marker);
1614 generateExtractionMark(pn, EndMark);
1620
1621
1624 SubTitleSize subTitleSize = LargeSubTitle;
1627 generateHeader(cn->fullTitle(), cn, marker);
1628 generateTableOfContents(cn, marker,
nullptr);
1629 generateTitle(cn
->doc().title(),
Text() << cn->subtitle(), subTitleSize, cn, marker);
1632 if (cn
->genus() != Genus::DOC && cn
->genus() != Genus::DontCare) {
1634 generateBrief(cn, marker);
1642 if (!nmm.isEmpty()) {
1643 ref = registerRef(
"namespaces");
1644 out() <<
"<h2 id=\"" << ref <<
"\">Namespaces</h2>\n";
1645 generateAnnotatedList(cn, marker, nmm.values());
1648 if (!nmm.isEmpty()) {
1649 ref = registerRef(
"classes");
1650 out() <<
"<h2 id=\"" << ref <<
"\">Classes</h2>\n";
1651 generateAnnotatedList(cn, marker, nmm.values());
1657 generateExtractionMark(cn, DetailedDescriptionMark);
1658 ref = registerRef(
"details");
1659 out() <<
"<div class=\"descr\">\n";
1660 out() <<
"<h2 id=\"" << ref <<
"\">"
1661 <<
"Detailed Description"
1664 generateExtractionMark(cn, DetailedDescriptionMark);
1665 out() << R"(<div class="descr" id=")" << registerRef(
"details")
1670 out() <<
"</div>\n";
1671 generateAlsoList(cn, marker);
1672 generateExtractionMark(cn, EndMark);
1677 if (!users.isEmpty()) {
1678 ref = registerRef(
"users");
1679 out() <<
"<h2 id=\"" << ref <<
"\">Used by</h2>\n";
1680 generateAnnotatedList(cn, marker, users);
1683 generateAnnotatedList(cn, marker, cn->members());
1690
1691
1692
1693
1696 SubTitleSize subTitleSize = LargeSubTitle;
1697 QString fullTitle = cn->name();
1699 generateHeader(fullTitle, cn, marker, u"auto-generated"_s);
1700 generateTitle(fullTitle,
Text() << cn->subtitle(), subTitleSize, cn, marker);
1703 brief <<
"Each function or type documented here is related to a class or "
1704 <<
"namespace that is documented in a different module. The reference "
1705 <<
"page for that class or namespace will link to the function or type "
1708 generateText(brief, cn, marker);
1712 for (
const auto &member : members)
1713 generateDetailedMember(member, cn, marker);
1719
1720
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748void HtmlGenerator::generateNavigationBar(
const QString &title,
const Node *node,
1749 CodeMarker *marker,
const QString &buildversion,
1752 if (m_noNavigationBar || node ==
nullptr)
1763 auto addNavItem = [&](
const QString &link,
const QString &title) {
1764 navigationbar << Atom(itemLeft) << Atom(
Atom::NavLink, link)
1771 auto addNavItemNode = [&](
const Node *node,
const QString &title) {
1772 navigationbar << Atom(itemLeft);
1773 addNodeLink(navigationbar, node, title);
1774 navigationbar << Atom(itemRight);
1778 const auto *moduleNode = m_qdb->getModuleNode(node);
1779 QString moduleState;
1780 if (moduleNode && !moduleNode->state().isEmpty())
1781 moduleState = QStringLiteral(
" (%1)").arg(moduleNode->state());
1783 if (m_hometitle == title)
1785 if (!m_homepage.isEmpty())
1786 addNavItem(m_homepage, m_hometitle);
1787 if (!m_landingpage.isEmpty() && m_landingtitle != title)
1788 addNavItem(m_landingpage, m_landingtitle);
1791 if (!m_cppclassespage.isEmpty() && !m_cppclassestitle.isEmpty())
1792 addNavItem(m_cppclassespage, m_cppclassestitle);
1793 if (!node->physicalModuleName().isEmpty()) {
1797 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_cppclassespage))
1798 addNavItemNode(moduleNode, moduleNode->name() + moduleState);
1800 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1802 if (!m_qmltypespage.isEmpty() && !m_qmltypestitle.isEmpty())
1803 addNavItem(m_qmltypespage, m_qmltypestitle);
1807 if (moduleNode && (!moduleState.isEmpty() || moduleNode->title() != m_qmltypespage)) {
1808 addNavItemNode(moduleNode, moduleNode->name() + moduleState);
1810 navigationbar << Atom(itemLeft) <<
Atom(
Atom::String, node->name()) << Atom(itemRight);
1813 auto currentNode{
static_cast<
const PageNode*>(node)};
1814 std::deque<
const Node *> navNodes;
1816 qsizetype navItems = 0;
1817 while (currentNode->navigationParent() && ++navItems < 16) {
1818 if (
std::find(navNodes.cbegin(), navNodes.cend(),
1819 currentNode->navigationParent()) == navNodes.cend())
1820 navNodes.push_front(currentNode->navigationParent());
1821 currentNode = currentNode->navigationParent();
1825 if (navNodes.empty()) {
1826 const QStringList groups =
static_cast<
const PageNode *>(node)->groupNames();
1827 for (
const auto &groupName : groups) {
1828 const auto *groupNode = m_qdb->findNodeByNameAndType(QStringList{groupName}, &Node::isGroup);
1829 if (groupNode && !groupNode->title().isEmpty()) {
1830 navNodes.push_front(groupNode);
1835 while (!navNodes.empty()) {
1836 if (navNodes.front()->isPageNode())
1837 addNavItemNode(navNodes.front(), navNodes.front()->title());
1838 navNodes.pop_front();
1842 navigationbar << Atom(itemLeft) << Atom(
Atom::String, title) << Atom(itemRight);
1846 generateText(navigationbar, node, marker);
1848 if (buildversion.isEmpty())
1854 out() <<
"</tr></table><table class=\"buildversion\"><tr>\n"
1855 << R"(<td id="buildversion" width="100%" align="right">)";
1857 out() <<
"<li id=\"buildversion\">";
1861 if (!m_landingpage.isEmpty() && m_landingtitle != title) {
1862 navigationbar << Atom(Atom::NavLink, m_landingpage)
1864 << Atom(Atom::String, buildversion)
1866 generateText(navigationbar, node, marker);
1868 out() << buildversion;
1877 const QString &metaKeyword)
1879 out() <<
"<!DOCTYPE html>\n";
1880 out() << QString(
"<html lang=\"%1\">\n").arg(naturalLanguage);
1881 out() <<
"<head>\n";
1882 out() <<
" <meta charset=\"utf-8\">\n";
1887 out() <<
" <meta name=\"description\" content=\""
1888 << protectEnc(node->doc().briefText().toString())
1892 if (!metaKeyword.isEmpty()) {
1894 out() <<
" <meta name=\"keywords\" content=\"%1\">\n"_L1.arg(protectEnc(metaKeyword));
1897 QStringList keywords;
1899 for (
const auto &kw : metaTags->values(u"keywords"_s))
1900 keywords << kw.split(
','_L1, Qt::SkipEmptyParts);
1905 keywords << node->nodeTypeString().toLower().remove(
' '_L1);
1907 if (!keywords.isEmpty()) {
1908 std::transform(keywords.begin(), keywords.end(), keywords.begin(),
1909 [](
const QString &k) {
return k.trimmed(); });
1910 keywords.removeDuplicates();
1911 out() <<
" <meta name=\"keywords\" content=\"" << protectEnc(keywords.join(
','_L1))
1917 QString titleSuffix;
1918 if (!m_landingtitle.isEmpty()) {
1920 titleSuffix = m_landingtitle;
1921 }
else if (!m_hometitle.isEmpty()) {
1924 if (title != m_hometitle)
1925 titleSuffix = m_hometitle;
1928 titleSuffix = m_productName.isEmpty() ? m_project : m_productName;
1930 if (title == titleSuffix)
1931 titleSuffix.clear();
1933 out() <<
" <title>";
1934 if (!titleSuffix.isEmpty() && !title.isEmpty()) {
1935 out() <<
"%1 | %2"_L1.arg(protectEnc(title), titleSuffix);
1937 out() << protectEnc(title);
1942 QVersionNumber projectVersion = QVersionNumber::fromString(m_qdb->version());
1943 if (!projectVersion.isNull()) {
1944 QVersionNumber titleVersion;
1945 static const QRegularExpression re(QLatin1String(R"(\d+\.\d+)"));
1946 const QString &versionedTitle = titleSuffix.isEmpty() ? title : titleSuffix;
1947 auto match = re.match(versionedTitle);
1948 if (match.hasMatch())
1949 titleVersion = QVersionNumber::fromString(match.captured());
1950 if (titleVersion.isNull() || !titleVersion.isPrefixOf(projectVersion)) {
1952 if (!m_productName.isEmpty() && titleSuffix != m_productName)
1953 out() <<
" | %1"_L1.arg(m_productName);
1954 out() <<
" %1"_L1.arg(projectVersion.toString());
1957 out() <<
"</title>\n";
1960 out() << m_headerStyles;
1961 out() << m_headerScripts;
1962 out() << m_endHeader;
1964 out() << QString(m_postHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1965 bool usingTable = m_postHeader.trimmed().endsWith(QLatin1String(
"<tr>"));
1966 generateNavigationBar(title, node, marker, m_buildversion, usingTable);
1967 out() << QString(m_postPostHeader).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
1969 m_navigationLinks.clear();
1972 if (node && !node->links().empty()) {
1973 std::pair<QString, QString> linkPair;
1974 std::pair<QString, QString> anchorPair;
1975 const Node *linkNode;
1976 bool useSeparator =
false;
1978 if (node->links().contains(Node::PreviousLink)) {
1979 linkPair = node->links()[Node::PreviousLink];
1980 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
1983 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
1984 if (linkNode ==
nullptr || linkNode == node)
1985 anchorPair = linkPair;
1987 anchorPair = anchorForNode(linkNode);
1989 out() << R"( <link rel="prev" href=")" << anchorPair.first <<
"\" />\n";
1991 m_navigationLinks += R"(<a class="prevPage" href=")" + anchorPair.first +
"\">";
1992 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
1993 m_navigationLinks += protect(anchorPair.second);
1995 m_navigationLinks += protect(linkPair.second);
1996 m_navigationLinks +=
"</a>\n";
1997 useSeparator = !m_navigationSeparator.isEmpty();
1999 if (node->links().contains(Node::NextLink)) {
2000 linkPair = node->links()[Node::NextLink];
2001 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
2004 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
2005 if (linkNode ==
nullptr || linkNode == node)
2006 anchorPair = linkPair;
2008 anchorPair = anchorForNode(linkNode);
2010 out() << R"( <link rel="next" href=")" << anchorPair.first <<
"\" />\n";
2013 m_navigationLinks += m_navigationSeparator;
2015 m_navigationLinks += R"(<a class="nextPage" href=")" + anchorPair.first +
"\">";
2016 if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
2017 m_navigationLinks += protect(anchorPair.second);
2019 m_navigationLinks += protect(linkPair.second);
2020 m_navigationLinks +=
"</a>\n";
2022 if (node->links().contains(Node::StartLink)) {
2023 linkPair = node->links()[Node::StartLink];
2024 linkNode = m_qdb->findNodeForTarget(linkPair.first, node);
2027 QStringLiteral(
"Cannot link to '%1'").arg(linkPair.first));
2028 if (linkNode ==
nullptr || linkNode == node)
2029 anchorPair =
std::move(linkPair);
2031 anchorPair = anchorForNode(linkNode);
2032 out() << R"( <link rel="start" href=")" << anchorPair.first <<
"\" />\n";
2036 if (node && !node->links().empty())
2037 out() <<
"<p class=\"naviNextPrevious headerNavi\">\n" << m_navigationLinks <<
"</p>\n";
2041 SubTitleSize subTitleSize,
const Node *relative,
2044 out() << QString(m_prologue).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
2047 attribute = R"( translate="no")";
2050 out() <<
"<h1 class=\"title\"" << attribute <<
">";
2051 generateText(title, relative, marker);
2056 if (subTitleSize == SmallSubTitle)
2057 out() <<
" class=\"small-subtitle\"" << attribute <<
">";
2059 out() <<
" class=\"subtitle\"" << attribute <<
">";
2060 generateText(subtitle, relative, marker);
2061 out() <<
"</span>\n";
2067 if (node && !node->links().empty())
2068 out() <<
"<p class=\"naviNextPrevious footerNavi\">\n" << m_navigationLinks <<
"</p>\n";
2070 out() << QString(m_footer).replace(
"\\" +
COMMAND_VERSION, m_qdb->version())
2071 << QString(m_address).replace(
"\\" +
COMMAND_VERSION, m_qdb->version());
2073 out() <<
"</body>\n";
2074 out() <<
"</html>\n";
2078
2079
2080
2083 QMap<QString, Text> requisites;
2086 const QString headerText =
"Header";
2087 const QString sinceText =
"Since";
2088 const QString inheritedByText =
"Inherited By";
2089 const QString inheritsText =
"Inherits";
2090 const QString nativeTypeText =
"In QML";
2091 const QString qtVariableText =
"qmake";
2092 const QString cmakeText =
"CMake";
2093 const QString statusText =
"Status";
2096 const QStringList requisiteorder { headerText, cmakeText, qtVariableText, sinceText,
2097 nativeTypeText, inheritsText, inheritedByText, statusText };
2099 addIncludeFileToMap(aggregate, requisites, text, headerText);
2100 addSinceToMap(aggregate, requisites, &text, sinceText);
2103 addCMakeInfoToMap(aggregate, requisites, &text, cmakeText);
2104 addQtVariableToMap(aggregate, requisites, &text, qtVariableText);
2108 auto *classe =
dynamic_cast<
ClassNode *>(aggregate);
2110 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2112 if (InclusionFilter::isIncluded(policy, context))
2113 addQmlNativeTypesToMap(requisites, &text, nativeTypeText, classe);
2116 const auto *metaTags = classe ? classe
->doc().metaTagMap() :
nullptr;
2117 if (!metaTags || !metaTags->contains(u"qdoc-suppress-inheritance"_s))
2118 addInheritsToMap(requisites, &text, inheritsText, classe);
2119 addInheritedByToMap(requisites, &text, inheritedByText, classe);
2123 addStatusToMap(aggregate, requisites, text, statusText);
2125 if (!requisites.isEmpty()) {
2127 generateTheTable(requisiteorder, requisites, aggregate, marker);
2132
2133
2134void HtmlGenerator::generateTheTable(
const QStringList &requisiteOrder,
2135 const QMap<QString, Text> &requisites,
2138 out() <<
"<div class=\"table\"><table class=\"alignedsummary requisites\" translate=\"no\">\n";
2140 for (
auto it = requisiteOrder.constBegin(); it != requisiteOrder.constEnd(); ++it) {
2142 if (requisites.contains(*it)) {
2144 <<
"<td class=\"memItemLeft rightAlign topAlign\"> " << *it
2146 "</td><td class=\"memItemRight bottomAlign\"> ";
2148 generateText(requisites.value(*it), aggregate, marker);
2149 out() <<
"</td></tr>\n";
2152 out() <<
"</table></div>\n";
2156
2157
2158
2159void HtmlGenerator::addInheritedByToMap(QMap<QString, Text> &requisites,
Text *text,
2160 const QString &inheritedByText,
ClassNode *classe)
2162 if (!classe->derivedClasses().isEmpty()) {
2165 int count = appendSortedNames(*text, classe, classe->derivedClasses());
2168 requisites.insert(inheritedByText, *text);
2173
2174
2175
2176void HtmlGenerator::addInheritsToMap(QMap<QString, Text> &requisites,
Text *text,
2177 const QString &inheritsText,
ClassNode *classe)
2179 if (!classe->baseClasses().isEmpty()) {
2182 const auto baseClasses = classe->baseClasses();
2183 for (
const auto &cls : baseClasses) {
2185 appendFullName(*text, cls.m_node, classe);
2187 if (cls.m_access == Access::Protected) {
2188 *text <<
" (protected)";
2189 }
else if (cls.m_access == Access::Private) {
2190 *text <<
" (private)";
2192 *text << TextUtils::comma(index++, classe->baseClasses().size());
2197 requisites.insert(inheritsText, *text);
2202
2203
2204
2205void HtmlGenerator::addQmlNativeTypesToMap(QMap<QString, Text> &requisites,
Text *text,
2206 const QString &nativeTypeText,
ClassNode *classe)
const
2213 QList<QmlTypeNode *> nativeTypes { classe->qmlNativeTypes().cbegin(), classe->qmlNativeTypes().cend()};
2215 qsizetype index { 0 };
2217 for (
const auto &item : std::as_const(nativeTypes)) {
2218 addNodeLink(*text, item);
2219 *text << TextUtils::comma(index++, nativeTypes.size());
2221 requisites.insert(nativeTypeText, *text);
2225
2226
2227
2229 Text *text,
const QString &CMakeInfo)
const
2231 if (!aggregate->physicalModuleName().isEmpty() && text !=
nullptr) {
2233 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2235 const auto result = cmakeRequisite(cn);
2248 requisites.insert(CMakeInfo, *text);
2253
2254
2255
2257 Text *text,
const QString &qtVariableText)
const
2259 if (!aggregate->physicalModuleName().isEmpty()) {
2261 m_qdb->getCollectionNode(aggregate->physicalModuleName(), NodeType::Module);
2263 if (cn && !cn->qtVariable().isEmpty()) {
2266 requisites.insert(qtVariableText, *text);
2272
2273
2274
2275
2277 Text *text,
const QString &sinceText)
const
2279 if (!aggregate->since().isEmpty() && text !=
nullptr) {
2282 requisites.insert(sinceText, *text);
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2298 Text &text,
const QString &statusText)
const
2300 auto status{formatStatus(aggregate, m_qdb)};
2306 spanClass = u"deprecated"_s;
2308 spanClass =
TextUtils::asAsciiPrintable(status.value());
2311 text << Atom(Atom::String, status.value())
2313 "class=\"status %1\""_L1.arg(spanClass))
2315 requisites.insert(statusText, text);
2319
2320
2321
2322
2324 QMap<QString, Text> &requisites,
Text& text,
2325 const QString &headerText)
2327 if (aggregate->includeFile()) {
2329 text << openCodeTag <<
"#include <%1>"_L1.arg(*aggregate->includeFile()) << closeCodeTag;
2330 requisites.insert(headerText, text);
2335
2336
2337
2343 QMap<QString, Text> requisites;
2346 const QString importText =
"Import Statement";
2347 const QString sinceText =
"Since";
2348 const QString inheritedByText =
"Inherited By";
2349 const QString inheritsText =
"Inherits";
2350 const QString nativeTypeText =
"In C++";
2351 const QString statusText =
"Status";
2354 QString logicalModuleVersion;
2359 bool generate_import =
true;
2361 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2365 if (generate_import) {
2369 requisites.insert(importText, text);
2372 qcn
->doc().location().warning(QStringLiteral(
"Could not resolve QML import statement for type '%1'").arg(qcn->name()),
2377 if (!qcn->since().isEmpty()) {
2380 requisites.insert(sinceText, text);
2385 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2389 addNodeLink(text, cn);
2390 requisites.insert(nativeTypeText, text);
2398 QStringList knownTypeNames{qcn->name()};
2400 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2408 knownTypeNames << base->name();
2411 addNodeLink(text, base);
2414 for (
const auto sub : std::as_const(subs)) {
2415 if (knownTypeNames.contains(sub->name())) {
2416 text << Atom(Atom::String,
" (%1)"_L1.arg(base->logicalModuleName()));
2421 requisites.insert(inheritsText, text);
2425 if (!subs.isEmpty()) {
2428 int count = appendSortedQmlNames(text, qcn, knownTypeNames, subs);
2431 requisites.insert(inheritedByText, text);
2435 addStatusToMap(qcn, requisites, text, statusText);
2438 const QStringList requisiteorder {
std::move(importText),
std::move(sinceText),
2439 std::move(nativeTypeText),
std::move(inheritsText),
2440 std::move(inheritedByText),
std::move(statusText)};
2442 if (!requisites.isEmpty())
2443 generateTheTable(requisiteorder, requisites, qcn, marker);
2455 QStringLiteral(
"'\\brief' statement does not end with a full stop."));
2457 generateExtractionMark(node, BriefMark);
2459 generateText(brief, node, marker);
2462 if (!relative || node == relative)
2463 out() <<
" <a href=\"#";
2465 out() <<
" <a href=\"" << linkForNode(node, relative) <<
'#';
2466 out() << registerRef(
"details") <<
"\">More...</a>";
2470 generateExtractionMark(node, EndMark);
2475
2476
2477
2483 toc = node
->doc().tableOfContents();
2484 if (tocDepth == 0 || (toc.isEmpty() && !sections && !node
->isModule())) {
2489 int sectionNumber = 1;
2490 int detailsBase = 0;
2493 m_inContents =
true;
2495 out() <<
"<div class=\"sidebar\">\n";
2496 out() <<
"<div class=\"toc\">\n";
2497 out() <<
"<h3 id=\"toc\">Contents</h3>\n";
2500 openUnorderedList();
2501 if (!
static_cast<
const CollectionNode *>(node)->noAutoList()) {
2503 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2504 << registerRef(
"namespaces") <<
"\">Namespaces</a></li>\n";
2507 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2508 << registerRef(
"classes") <<
"\">Classes</a></li>\n";
2511 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#" << registerRef(
"details")
2512 <<
"\">Detailed Description</a></li>\n";
2513 for (
const auto &entry : std::as_const(toc)) {
2514 if (entry->string().toInt() == 1) {
2520 for (
const auto §ion : *sections) {
2521 if (!section.members().isEmpty()) {
2522 openUnorderedList();
2523 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2524 << registerRef(section.plural()) <<
"\">" << section.title() <<
"</a></li>\n";
2526 if (!section.reimplementedMembers().isEmpty()) {
2527 openUnorderedList();
2528 QString ref = QString(
"Reimplemented ") + section.plural();
2529 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2530 << registerRef(ref.toLower()) <<
"\">"
2531 << QString(
"Reimplemented ") + section.title() <<
"</a></li>\n";
2535 openUnorderedList();
2536 out() <<
"<li class=\"level" << sectionNumber <<
"\"><a href=\"#"
2537 << registerRef(
"details") <<
"\">Detailed Description</a></li>\n";
2539 for (
const auto &entry : toc) {
2540 if (entry->string().toInt() == 1) {
2547 for (
const auto &atom : toc) {
2548 sectionNumber = atom->string().toInt() + detailsBase;
2551 if (sectionNumber <= tocDepth || tocDepth < 0) {
2552 openUnorderedList();
2554 Text headingText = Text::sectionHeading(atom);
2555 out() <<
"<li class=\"level" << sectionNumber <<
"\">";
2556 out() <<
"<a href=\"" <<
'#' << Tree::refForAtom(atom) <<
"\">";
2557 generateAtomList(headingText.firstAtom(), node, marker,
true, numAtoms);
2558 out() <<
"</a></li>\n";
2561 closeUnorderedList();
2562 out() <<
"</div>\n";
2563 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2564 out() <<
"</div>\n";
2565 m_inContents =
false;
2570
2571
2574 out() <<
"<div class=\"sidebar\">";
2575 out() << R"(<div class="sidebar-content" id="sidebar-content"></div>)";
2576 out() <<
"</div>\n";
2585 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2586 beginSubPage(aggregate, fileName);
2587 QString title =
"List of All Members for " + aggregate->plainFullName();
2588 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2590 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2591 out() <<
"<p>This is the complete list of members for ";
2592 generateFullName(aggregate,
nullptr);
2593 out() <<
", including inherited members.</p>\n";
2595 generateSectionList(section, aggregate, marker);
2603
2604
2605
2606
2607
2615 QString fileName = fileBase(aggregate) +
"-members." + fileExtension();
2616 beginSubPage(aggregate, fileName);
2617 QString title =
"List of All Members for " + aggregate->name();
2618 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2620 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2621 out() <<
"<p>This is the complete list of members for ";
2622 generateFullName(aggregate,
nullptr);
2623 out() <<
", including inherited members.</p>\n";
2626 for (
int i = 0; i < cknl.size(); i++) {
2627 const auto &ckn = cknl[i];
2630 if (nodes.isEmpty())
2633 out() <<
"<p>The following members are inherited from ";
2634 generateFullName(qcn,
nullptr);
2637 openUnorderedList();
2638 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2639 for (
int j = 0; j < nodes.size(); j++) {
2640 Node *node = nodes[j];
2647 std::function<
void(
Node *)> generate = [&](Node *n) {
2648 out() <<
"<li class=\"fn\" translate=\"no\">";
2649 generateQmlItem(n, aggregate, marker,
true);
2650 if (n->isQmlProperty()) {
2651 auto qpn =
static_cast<QmlPropertyNode *>(n);
2652 QStringList hints = qpn->hints();
2653 if (qpn->isAttached())
2654 hints <<
"attached"_L1;
2655 if (!hints.isEmpty())
2656 out() <<
" [" << hints.join(
' '_L1) <<
"]";
2657 }
else if (n->isAttached()) {
2659 out() <<
" [attached]";
2662 if (n->isPropertyGroup()) {
2664 const QList<Node *> &collective =
2665 static_cast<SharedCommentNode *>(n)->collective();
2666 std::for_each(collective.begin(), collective.end(), generate);
2673 closeUnorderedList();
2690 QString title =
"Obsolete Members for " + aggregate->plainFullName();
2691 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2693 beginSubPage(aggregate, fileName);
2694 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2696 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2698 out() <<
"<p><b>The following members of class "
2699 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\" translate=\"no\">"
2700 << protectEnc(aggregate->name()) <<
"</a>"
2701 <<
" are deprecated.</b> "
2702 <<
"They are provided to keep old source code working. "
2703 <<
"We strongly advise against using them in new code.</p>\n";
2705 for (
const auto §ion : summary_spv) {
2706 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2707 generateSectionList(*section, aggregate, marker,
true);
2710 for (
const auto §ion : details_spv) {
2711 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2713 const NodeVector &members = section->obsoleteMembers();
2714 for (
const auto &member : members)
2715 generateDetailedMember(member, aggregate, marker);
2724
2725
2726
2727
2736 QString title =
"Obsolete Members for " + aggregate->name();
2737 QString fileName = fileBase(aggregate) +
"-obsolete." + fileExtension();
2739 beginSubPage(aggregate, fileName);
2740 generateHeader(title, aggregate, marker, u"auto-generated"_s);
2742 generateTitle(title,
Text(), SmallSubTitle, aggregate, marker);
2744 out() <<
"<p><b>The following members of QML type "
2745 <<
"<a href=\"" << linkForNode(aggregate,
nullptr) <<
"\">"
2746 << protectEnc(aggregate->name()) <<
"</a>"
2747 <<
" are deprecated.</b> "
2748 <<
"They are provided to keep old source code working. "
2749 <<
"We strongly advise against using them in new code.</p>\n";
2751 for (
const auto §ion : summary_spv) {
2752 QString ref = registerRef(section->title().toLower());
2753 out() <<
"<h2 id=\"" << ref <<
"\">" << protectEnc(section->title()) <<
"</h2>\n";
2754 generateQmlSummary(section->obsoleteMembers(), aggregate, marker);
2757 for (
const auto §ion : details_spv) {
2758 out() <<
"<h2>" << protectEnc(section->title()) <<
"</h2>\n";
2759 const NodeVector &members = section->obsoleteMembers();
2760 for (
const auto &member : members) {
2761 generateDetailedQmlMember(member, aggregate, marker);
2773 if (classMap.isEmpty())
2777 for (
const auto &it : classMap) {
2778 auto *classe =
static_cast<ClassNode *>(it);
2779 if (classe->baseClasses().isEmpty())
2780 topLevel.insert(classe->name(), classe);
2783 QStack<NodeMap> stack;
2784 stack.push(topLevel);
2787 while (!stack.isEmpty()) {
2788 if (stack.top().isEmpty()) {
2794 generateFullName(child, relative);
2796 stack.top().erase(stack.top().begin());
2799 const auto derivedClasses = child->derivedClasses();
2800 for (
const RelatedClass &d : derivedClasses) {
2801 if (d.m_node && d.m_node->isInAPI())
2802 newTop.insert(d.m_node->name(), d.m_node);
2804 if (!newTop.isEmpty()) {
2813
2814
2815
2820 if (relative ==
nullptr)
2823 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
2824 for (
auto *node : nodes) {
2825 const NodeContext context = node->createContext();
2826 if (InclusionFilter::isIncluded(policy, context) && !node->isDeprecated())
2827 included.insert(node->fullName(relative), node);
2833 const NodeList &unsortedNodes, Qt::SortOrder sortOrder)
2835 generateAnnotatedList(relative, marker, includedAnnotatedMembers(relative, unsortedNodes),
2842 if (nodeMap.isEmpty())
2844 out() <<
"<div class=\"table\"><table class=\"annotated\">\n";
2848 if (sortOrder == Qt::DescendingOrder)
2854 auto sameLocation = [
this](
const Node *a,
const Node *b) {
2855 return fullDocumentLocation(a) == fullDocumentLocation(b);
2857 nodes.erase(
std::unique(nodes.begin(), nodes.end(), sameLocation), nodes.end());
2859 for (
const auto *node : std::as_const(nodes)) {
2861 out() <<
"<tr class=\"odd topAlign\">";
2863 out() <<
"<tr class=\"even topAlign\">";
2864 out() <<
"<td class=\"tblName\" translate=\"no\"><p>";
2865 generateFullName(node, relative);
2866 out() <<
"</p></td>";
2868 if (!node->isTextPageNode()) {
2869 Text brief = node->doc().trimmedBriefText(node->name());
2870 if (!brief.isEmpty()) {
2871 out() <<
"<td class=\"tblDescr\"><p>";
2872 generateText(brief, node, marker);
2873 out() <<
"</p></td>";
2874 }
else if (!node->reconstitutedBrief().isEmpty()) {
2875 out() <<
"<td class=\"tblDescr\"><p>";
2876 out() << node->reconstitutedBrief();
2877 out() <<
"</p></td>";
2880 out() <<
"<td class=\"tblDescr\"><p>";
2881 if (!node->reconstitutedBrief().isEmpty()) {
2882 out() << node->reconstitutedBrief();
2884 out() << protectEnc(node->doc().briefText().toString());
2885 out() <<
"</p></td>";
2889 out() <<
"</table></div>\n";
2893
2894
2895
2899 const auto &uniqueKeys = nmm.uniqueKeys();
2900 for (
const QString &name : uniqueKeys) {
2901 if (!name.isEmpty()) {
2902 out() <<
"<h2 id=\"" << registerRef(name.toLower()) <<
"\">" << protectEnc(name)
2905 generateAnnotatedList(relative, marker, nmm.values(name));
2910
2911
2912
2913
2914
2915
2916
2917
2918
2921 const QString &commonPrefix)
2926 const int NumParagraphs = 37;
2927 qsizetype commonPrefixLen = commonPrefix.size();
2930
2931
2932
2933
2934
2936 QString paragraphName[NumParagraphs + 1];
2937 QSet<
char> usedParagraphNames;
2939 for (
auto c = nmm.constBegin(); c != nmm.constEnd(); ++c) {
2940 QStringList pieces = c.key().split(
"::");
2941 int idx = commonPrefixLen;
2942 if (idx > 0 && !pieces.last().startsWith(commonPrefix, Qt::CaseInsensitive))
2944 QString last = pieces.last().toLower();
2945 QString key = last.mid(idx);
2947 int paragraphNr = NumParagraphs - 1;
2949 if (key[0].digitValue() != -1) {
2950 paragraphNr = key[0].digitValue();
2951 }
else if (key[0] >= QLatin1Char(
'a') && key[0] <= QLatin1Char(
'z')) {
2952 paragraphNr = 10 + key[0].unicode() -
'a';
2955 paragraphName[paragraphNr] = key[0].toUpper();
2956 usedParagraphNames.insert(key[0].toLower().cell());
2957 paragraph[paragraphNr].insert(last, c.value());
2961
2962
2963
2964
2965
2966
2967
2968 qsizetype paragraphOffset[NumParagraphs + 1];
2969 paragraphOffset[0] = 0;
2970 for (
int i = 0; i < NumParagraphs; i++)
2971 paragraphOffset[i + 1] = paragraphOffset[i] + paragraph[i].size();
2974
2975
2976 if (includeAlphabet) {
2977 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
2978 for (
int i = 0; i < 26; i++) {
2980 if (usedParagraphNames.contains(
char(
'a' + i)))
2981 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
2983 out() <<
"</b></p>\n";
2987
2988
2989 out() <<
"<div class=\"flowListDiv\" translate=\"no\">\n";
2993 QHash<QString,
int> nameOccurrences;
2994 for (
const auto &[key, node] : nmm.asKeyValueRange()) {
2995 QStringList pieces{node->fullName(relative).split(
"::"_L1)};
2996 const QString &name{pieces.last()};
2997 nameOccurrences[name]++;
3001 int curParOffset = 0;
3003 for (
int i = 0; i < nmm.size(); i++) {
3004 while ((curParNr < NumParagraphs) && (curParOffset == paragraph[curParNr].size())) {
3010
3011
3012 if (curParOffset == 0) {
3015 if (++m_numTableRows % 2 == 1)
3016 out() <<
"<dl class=\"flowList odd\">";
3018 out() <<
"<dl class=\"flowList even\">";
3019 out() <<
"<dt class=\"alphaChar\"";
3020 if (includeAlphabet)
3021 out() << QString(
" id=\"%1\"").arg(paragraphName[curParNr][0].toLower());
3022 out() <<
"><b>" << paragraphName[curParNr] <<
"</b></dt>\n";
3026
3027
3029 if ((curParNr < NumParagraphs) && !paragraphName[curParNr].isEmpty()) {
3030 NodeMultiMap::Iterator it;
3031 NodeMultiMap::Iterator next;
3032 it = paragraph[curParNr].begin();
3033 for (
int j = 0; j < curParOffset; j++)
3038
3039
3040
3041 out() <<
"<a href=\"" << linkForNode(it.value(), relative) <<
"\">";
3043 QString fileName = fileBase(it.value()) +
"-obsolete." + fileExtension();
3045 if (useOutputSubdirs())
3046 link =
"../%1/"_L1.arg(it.value()->tree()->physicalModuleName());
3048 out() <<
"<a href=\"" << link <<
"\">";
3051 QStringList pieces{it.value()->fullName(relative).split(
"::"_L1)};
3052 const auto &name{pieces.last()};
3055 if (nameOccurrences[name] > 1) {
3056 const QString moduleName = it.value()->isQmlNode() ? it.value()->logicalModuleName()
3057 : it.value()->tree()->camelCaseModuleName();
3058 pieces.last().append(
": %1"_L1.arg(moduleName));
3061 out() << protectEnc(pieces.last());
3063 if (pieces.size() > 1) {
3065 generateFullName(it.value()->parent(), relative);
3075 out() <<
"</div>\n";
3080 out() <<
"<p class=\"centerAlign functionIndex\" translate=\"no\"><b>";
3081 for (
int i = 0; i < 26; i++) {
3083 out() << QString(
"<a href=\"#%1\">%2</a> ").arg(ch).arg(ch.toUpper());
3085 out() <<
"</b></p>\n";
3087 char nextLetter =
'a';
3089 out() <<
"<ul translate=\"no\">\n";
3090 NodeMapMap &funcIndex = m_qdb->getFunctionIndex();
3091 for (
auto fnMap = funcIndex.constBegin(); fnMap != funcIndex.constEnd(); ++fnMap) {
3092 const QString &key = fnMap.key();
3093 const QChar firstLetter = key.isEmpty() ? QChar(
'A') : key.front();
3094 Q_ASSERT_X(firstLetter.unicode() < 256,
"generateFunctionIndex",
3095 "Only valid C++ identifiers were expected");
3096 const char currentLetter = firstLetter.isLower() ? firstLetter.unicode() : nextLetter - 1;
3098 if (currentLetter < nextLetter) {
3102 while (nextLetter < currentLetter)
3103 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
3104 Q_ASSERT(nextLetter == currentLetter);
3105 out() << QStringLiteral(
"<li id=\"%1\">").arg(nextLetter++);
3107 out() << protectEnc(key) <<
':';
3109 for (
auto it = (*fnMap).constBegin(); it != (*fnMap).constEnd(); ++it) {
3111 generateFullName((*it)->parent(), relative, *it);
3115 while (nextLetter <=
'z')
3116 out() << QStringLiteral(
"<li id=\"%1\"></li>").arg(nextLetter++);
3123 for (
auto it = legaleseTexts.cbegin(), end = legaleseTexts.cend(); it != end; ++it) {
3124 Text text = it.key();
3125 generateText(text, relative, marker);
3129 generateFullName(it.value(), relative);
3132 }
while (it != legaleseTexts.constEnd() && it.key() == text);
3140 QString marked = marker->markedUpQmlItem(node, summary);
3141 marked.replace(
"@param>",
"i>");
3143 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3144 .arg(summary ?
"summary"_L1 :
"details"_L1));
3145 marked.replace(
"</@extra>",
"</code>");
3149 marked.remove(
"<@name>");
3150 marked.remove(
"</@name>");
3151 marked.remove(
"<@type>");
3152 marked.remove(
"</@type>");
3154 out() << highlightedCode(marked, relative,
false, Genus::QML);
3158
3159
3160
3161
3162
3163
3164
3167 m_qdb->mergeCollections(cn);
3172 if (sortOrder == Qt::DescendingOrder)
3177 for (
const auto *node : std::as_const(members)) {
3178 out() <<
"<li translate=\"no\">";
3179 generateFullName(node,
nullptr);
3187 const QString &selector, Qt::SortOrder sortOrder)
3191 if (selector == QLatin1String(
"overviews"))
3193 else if (selector == QLatin1String(
"cpp-modules"))
3195 else if (selector == QLatin1String(
"qml-modules"))
3199 m_qdb->mergeCollections(type, cnm, relative);
3200 const auto collectionList = cnm.values();
3201 nodeList.reserve(collectionList.size());
3202 for (
auto *collectionNode : collectionList)
3203 nodeList.append(collectionNode);
3204 generateAnnotatedList(relative, marker, nodeList, sortOrder);
3207
3208
3209
3210
3213 QStringLiteral(
"\\generatelist {%1} is only allowed in \\group, "
3214 "\\module and \\qmlmodule comments.")
3218 auto *node =
const_cast<
Node *>(relative);
3219 auto *collectionNode =
static_cast<CollectionNode *>(node);
3220 if (!collectionNode)
3222 m_qdb->mergeCollections(collectionNode);
3223 generateAnnotatedList(collectionNode, marker, collectionNode->members(), sortOrder);
3229 bool alignNames =
true;
3230 if (!nv.isEmpty()) {
3231 bool twoColumn =
false;
3232 if (nv.first()->isProperty()) {
3233 twoColumn = (nv.size() >= 5);
3237 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3240 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3241 <<
"<tr><td class=\"topAlign\">";
3246 for (
const auto &member : nv) {
3249 out() <<
"<tr><td class=\"memItemLeft rightAlign topAlign\"> ";
3251 if (twoColumn && i == (nv.size() + 1) / 2)
3252 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3253 out() <<
"<li class=\"fn\" translate=\"no\">";
3256 generateSynopsis(member, relative, marker, Section::Summary, alignNames);
3258 out() <<
"</td></tr>\n";
3264 out() <<
"</table></div>\n";
3268 out() <<
"</td></tr>\n</table></div>\n";
3276 bool alignNames =
true;
3279 if (!members.isEmpty()) {
3280 bool hasPrivateSignals =
false;
3281 bool isInvokable =
false;
3282 bool twoColumn =
false;
3285 twoColumn = (members.size() >= 16);
3286 }
else if (members.first()->isProperty()) {
3287 twoColumn = (members.size() >= 5);
3291 out() <<
"<div class=\"table\"><table class=\"alignedsummary\" translate=\"no\">\n";
3294 out() <<
"<div class=\"table\"><table class=\"propsummary\" translate=\"no\">\n"
3295 <<
"<tr><td class=\"topAlign\">";
3300 for (
const auto &member : members) {
3303 if (member->name().isEmpty())
3307 out() <<
"<tr><td class=\"memItemLeft topAlign rightAlign\"> ";
3309 if (twoColumn && i == (members.size() + 1) / 2)
3310 out() <<
"</ul></td><td class=\"topAlign\"><ul>\n";
3311 out() <<
"<li class=\"fn\" translate=\"no\">";
3314 generateSynopsis(member, relative, marker, section.style(), alignNames);
3315 if (member->isFunction()) {
3316 const auto *fn =
static_cast<
const FunctionNode *>(member);
3317 if (fn->isPrivateSignal()) {
3318 hasPrivateSignals =
true;
3320 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3321 }
else if (fn->isInvokable()) {
3324 out() <<
"</td><td class=\"memItemRight bottomAlign\">[see note below]";
3328 out() <<
"</td></tr>\n";
3334 out() <<
"</table></div>\n";
3338 out() <<
"</td></tr>\n</table></div>\n";
3341 if (hasPrivateSignals)
3349 && !section.inheritedMembers().isEmpty()) {
3351 generateSectionInheritedList(section, relative);
3358 const QList<std::pair<
const Aggregate *,
int>> &inheritedMembers = section.inheritedMembers();
3359 for (
const auto &member : inheritedMembers) {
3360 out() <<
"<li class=\"fn\" translate=\"no\">";
3361 out() << member.second <<
' ';
3362 if (member.second == 1) {
3363 out() << section.singular();
3365 out() << section.plural();
3367 out() <<
" inherited from <a href=\"" << fileName(member.first) <<
'#'
3368 << Generator::cleanRef(section.title().toLower()) <<
"\">"
3369 << protectEnc(member.first->plainFullName(relative)) <<
"</a></li>\n";
3376 QString marked = marker->markedUpSynopsis(node, relative, style);
3377 marked.replace(
"@param>",
"i>");
3380 marked.remove(
"<@name>");
3381 marked.remove(
"</@name>");
3385 static const QRegularExpression extraRegExp(
"<@extra>.*</@extra>",
3386 QRegularExpression::InvertedGreedinessOption);
3387 marked.remove(extraRegExp);
3389 marked.replace(
"<@extra>",
"<code class=\"%1 extra\" translate=\"no\">"_L1
3390 .arg(style == Section::Summary ?
"summary"_L1 :
"details"_L1));
3391 marked.replace(
"</@extra>",
"</code>");
3395 marked.remove(
"<@type>");
3396 marked.remove(
"</@type>");
3399 out() << highlightedCode(marked, relative, alignNames);
3402QString
HtmlGenerator::highlightedCode(
const QString &markedCode,
const Node *relative,
3403 bool alignNames, Genus genus)
3405 QString src = markedCode;
3407 html.reserve(src.size());
3411 const QChar charLangle =
'<';
3412 const QChar charAt =
'@';
3414 static const QString typeTag(
"type");
3415 static const QString headerTag(
"headerfile");
3416 static const QString funcTag(
"func");
3417 static const QString linkTag(
"link");
3418 static const QString extrefTag(
"extref");
3419 static const QString conceptTag(
"concept");
3422 static const QHash<QString, QString> extrefUrls = {
3423 {
"cpp-explicitly-defaulted"_L1,
3424 "https://en.cppreference.com/w/cpp/language/function#Defaulted_functions"_L1},
3425 {
"cpp-deleted-functions"_L1,
3426 "https://en.cppreference.com/w/cpp/language/function#Deleted_functions"_L1},
3433 for (
int i = 0, srcSize = src.size(); i < srcSize;) {
3434 if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
3435 if (alignNames && !done) {
3436 html += QLatin1String(
"</td><td class=\"memItemRight bottomAlign\">");
3440 if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) {
3441 html += QLatin1String(
"<b>");
3442 const Node *n =
static_cast<
const Node*>(
Utilities::nodeForString(par1.toString()));
3443 QString link = linkForNode(n, relative);
3444 addLink(link, arg, &html);
3445 html += QLatin1String(
"</b>");
3446 }
else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
3447 const FunctionNode *fn = m_qdb->findFunctionNode(par1.toString(), relative, genus);
3448 QString link = linkForNode(fn, relative);
3449 addLink(link, arg, &html);
3450 par1 = QStringView();
3451 }
else if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
3452 par1 = QStringView();
3453 const Node *n = m_qdb->findTypeNode(arg.toString(), relative, genus);
3454 html += QLatin1String(
"<span class=\"type\">");
3457 addLink(linkForNode(n, relative), arg, &html);
3461 addLink(linkForNode(n, relative), arg, &html);
3462 html += QLatin1String(
"</span>");
3463 }
else if (parseArg(src, conceptTag, &i, srcSize, &arg, &par1)) {
3467 const QString target = par1.isEmpty() ? arg.toString() : par1.toString();
3468 par1 = QStringView();
3469 const Node *n = m_qdb->findConceptNode(target);
3471 addLink(linkForNode(n, relative), arg, &html);
3474 }
else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
3475 par1 = QStringView();
3476 if (arg.startsWith(QLatin1Char(
'&')))
3479 const Node *n = m_qdb->findNodeForInclude(QStringList(arg.toString()));
3480 if (n && n != relative)
3481 addLink(linkForNode(n, relative), arg, &html);
3485 }
else if (parseArg(src, extrefTag, &i, srcSize, &arg, &par1)) {
3486 QString url = extrefUrls.value(par1.toString());
3488 addLink(url, arg, &html);
3496 html += src.at(i++);
3505 html.reserve(src.size());
3508 QLatin1StringView tag;
3509 QLatin1StringView span;
3511 static constexpr SpanTag spanTags[] = {
3512 {
"comment>"_L1,
"<span class=\"comment\">"_L1},
3513 {
"preprocessor>"_L1,
"<span class=\"preprocessor\">"_L1},
3514 {
"string>"_L1,
"<span class=\"string\">"_L1},
3515 {
"char>"_L1,
"<span class=\"char\">"_L1},
3516 {
"number>"_L1,
"<span class=\"number\">"_L1},
3517 {
"op>"_L1,
"<span class=\"operator\">"_L1},
3518 {
"type>"_L1,
"<span class=\"type\">"_L1},
3519 {
"name>"_L1,
"<span class=\"name\">"_L1},
3520 {
"keyword>"_L1,
"<span class=\"keyword\">"_L1},
3521 {
"template-block>"_L1,
"<span class=\"template-block\">"_L1},
3525 const qsizetype n = src.size();
3526 const QStringView sv(src);
3528 if (sv.at(i) ==
'<'_L1) {
3529 if (i + 1 < n && sv.at(i + 1) ==
'@'_L1) {
3531 bool handled =
false;
3532 for (
const auto &st : spanTags) {
3533 if (i + st.tag.size() <= n
3534 && st.tag == sv.sliced(i, st.tag.size())) {
3543 while (i < n && sv.at(i) !=
'>'_L1)
3549 }
else if (i + 2 < n && sv.at(i + 1) ==
'/'_L1 && sv.at(i + 2) ==
'@'_L1) {
3551 bool handled =
false;
3552 for (
const auto &st : spanTags) {
3553 if (i + st.tag.size() <= n
3554 && st.tag == sv.sliced(i, st.tag.size())) {
3555 html +=
"</span>"_L1;
3563 while (i < n && sv.at(i) !=
'>'_L1)
3581 if (m_linkNode && m_linkNode->isFunction()) {
3583 if (match.hasMatch()) {
3585 qsizetype leftParenLoc = match.capturedStart(1);
3586 out() << protectEnc(atom->string().left(leftParenLoc));
3588 out() << protectEnc(atom->string().mid(leftParenLoc));
3592 out() << protectEnc(atom->string());
3597 return protect(string);
3602 if (string.isEmpty())
3606 if (html.isEmpty()) {
3613 qsizetype n = string.size();
3615 for (
int i = 0; i < n; ++i) {
3616 QChar ch = string.at(i);
3618 if (ch == QLatin1Char(
'&')) {
3620 }
else if (ch == QLatin1Char(
'<')) {
3622 }
else if (ch == QLatin1Char(
'>')) {
3624 }
else if (ch == QChar(8211)) {
3626 }
else if (ch == QChar(8212)) {
3628 }
else if (ch == QLatin1Char(
'"')) {
3631 if (!html.isEmpty())
3636 if (!html.isEmpty())
3645 QString result = Generator::fileBase(node);
3647 result += QLatin1String(
"-obsolete");
3654 return node->name();
3655 return Generator::fileName(node);
3659 const Node *actualNode)
3661 if (actualNode ==
nullptr)
3662 actualNode = apparentNode;
3663 bool link = !linkForNode(actualNode, relative).isEmpty();
3665 out() <<
"<a href=\"" << linkForNode(actualNode, relative);
3667 out() <<
"\" class=\"obsolete";
3670 out() << protectEnc(apparentNode->fullName(relative));
3676
3677
3678
3685 const auto srcLink = Config::instance().getSourceLink();
3686 if (!srcLink.enabled)
3691 if (loc
.isEmpty() || srcLink.baseUrl.isEmpty() || srcLink.rootPath.isEmpty())
3694 QString srcUrl{srcLink.baseUrl};
3695 if (!srcUrl.contains(
'\1'_L1)) {
3696 if (!srcUrl.endsWith(
'/'_L1))
3701 QDir rootDir{srcLink.rootPath};
3702 srcUrl.replace(
'\1'_L1, rootDir.relativeFilePath(loc.filePath()));
3703 srcUrl.replace(
'\2'_L1, QString::number(loc.lineNo()));
3704 const auto &description{
"View declaration of this %1"_L1.arg(node->nodeTypeString())};
3705 out() <<
"<a class=\"srclink\" href=\"%1\" title=\"%2\">%3</a>"_L1
3706 .arg(srcUrl, description, srcLink.linkText);
3713 generateExtractionMark(node, MemberMark);
3714 QString nodeRef =
nullptr;
3717 const QList<Node *> &collective = scn->collective();
3718 if (collective.size() > 1)
3719 out() <<
"<div class=\"fngroup\">\n";
3720 for (
const auto *sharedNode : collective) {
3721 out() << headingStart.arg(getClassAttr(sharedNode,
"fn fngroupitem"_L1),
3722 refForNode(sharedNode));
3723 generateSynopsis(sharedNode, relative, marker, Section::Details);
3724 generateSourceLink(sharedNode);
3725 out() << headingEnd;
3727 if (collective.size() > 1)
3731 if (node->isEnumType(Genus::CPP) && (etn =
static_cast<
const EnumNode *>(node))->flagsType()) {
3732 out() << headingStart.arg(getClassAttr(node,
"flags"_L1), refForNode(node));
3736 generateSourceLink(node);
3737 out() << headingEnd;
3739 out() << headingStart.arg(getClassAttr(node,
"fn"_L1), refForNode(node));
3741 generateSourceLink(node);
3742 out() << headingEnd;
3749 const auto *func =
static_cast<
const FunctionNode *>(node);
3750 if (func->hasOverloads() && (func->isSignal() || func->isSlot()))
3759 const auto property =
static_cast<
const PropertyNode *>(node);
3769 out() <<
"<p><b>Access functions:</b></p>\n";
3770 generateSectionList(section, node, marker);
3777 out() <<
"<p><b>Notifier signal:</b></p>\n";
3778 generateSectionList(notifiers, node, marker);
3782 const auto *enumTypeNode =
static_cast<
const EnumNode *>(node);
3783 if (enumTypeNode->flagsType()) {
3784 out() <<
"<p>The " << protectEnc(enumTypeNode->flagsType()->name())
3785 <<
" type is a typedef for "
3786 <<
"<a href=\"" << m_qflagsHref <<
"\">QFlags</a><"
3787 << protectEnc(enumTypeNode->name()) <<
">. It stores an OR combination of "
3788 << protectEnc(enumTypeNode->name()) <<
" values.</p>\n";
3791 generateAlsoList(node, marker);
3792 generateExtractionMark(node, EndMark);
3796
3797
3798
3799
3804 m_linkNode =
nullptr;
3806 if (!m_link.isEmpty())
3807 out() <<
"<a href=\"" << m_link <<
"\" translate=\"no\">";
3815 if (m_link.isEmpty())
3818 const QString &translate_attr =
3819 (node && isApiGenus(node->genus())) ?
" translate=\"no\""_L1 :
""_L1;
3821 if (node ==
nullptr || (relative !=
nullptr && node->status() == relative->status()))
3822 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3823 else if (node->isDeprecated())
3824 out() <<
"<a href=\"" << m_link <<
"\" class=\"obsolete\"%1>"_L1.arg(translate_attr);
3826 out() <<
"<a href=\"" << m_link <<
"\"%1>"_L1.arg(translate_attr);
3835 m_linkNode =
nullptr;
3837 if (!m_link.isEmpty())
3842
3843
3844
3848 if (!members.isEmpty()) {
3850 for (
const auto &member : members) {
3851 out() <<
"<li class=\"fn\" translate=\"no\">";
3852 generateQmlItem(member, relative, marker,
true);
3853 if (member->isPropertyGroup()) {
3854 const auto *scn =
static_cast<
const SharedCommentNode *>(member);
3855 if (scn->count() > 0) {
3857 const QList<Node *> &sharedNodes = scn->collective();
3858 for (
const auto &node : sharedNodes) {
3859 if (node->isQmlProperty()) {
3860 out() <<
"<li class=\"fn\" translate=\"no\">";
3861 generateQmlItem(node, relative, marker,
true);
3875
3876
3879 out() << headingStart.arg(getClassAttr(scn,
"fn qml-member qml-property-group"_L1),
3881 <<
"<b>" << scn->name() <<
" group</b>"
3886
3887
3888
3892 generateExtractionMark(node, MemberMark);
3894 auto generateQmlProperty = [&](
Node *n,
bool isGroupItem =
false) {
3895 const auto cssClasses = isGroupItem ?
"fn qml-member qml-property fngroupitem"_L1 :
"fn qml-member qml-property"_L1;
3896 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3897 generateQmlItem(n, relative, marker,
false);
3898 generateSourceLink(n);
3899 out() << headingEnd;
3902 auto generateQmlMethod = [&](
Node *n,
bool isGroupItem =
false) {
3903 const auto cssClasses = isGroupItem ?
"fn qml-member qml-method fngroupitem"_L1 :
"fn qml-member qml-method"_L1;
3904 out() << headingStart.arg(getClassAttr(n, cssClasses), refForNode(n));
3906 generateSourceLink(n);
3907 out() << headingEnd;
3911 auto *scn =
static_cast<
const SharedCommentNode *>(node);
3912 const auto shared = scn->collective();
3914 if (scn->isPropertyGroup() && !scn->name().isEmpty())
3915 emitGroupHeader(scn);
3917 const bool isGroup = shared.size() > 1;
3920 out() <<
"<div class=\"fngroup\">\n"_L1;
3922 for (
auto *child : std::as_const(shared)) {
3923 if (child->isQmlProperty())
3924 generateQmlProperty(child, isGroup);
3926 generateQmlMethod(child, isGroup);
3930 out() <<
"</div>"_L1;
3933 generateQmlProperty(node);
3935 generateQmlMethod(node);
3942 generateAlsoList(node, marker);
3943 generateExtractionMark(node, EndMark);
3946void HtmlGenerator::generateExtractionMark(
const Node *node, ExtractionMarkType markType)
3948 if (markType != EndMark) {
3949 out() <<
"<!-- $$$" + node->name();
3950 if (markType == MemberMark) {
3952 const auto *func =
static_cast<
const FunctionNode *>(node);
3953 if (!func->hasAssociatedProperties()) {
3954 if (func->overloadNumber() == 0)
3955 out() <<
"[overload1]";
3956 out() <<
"$$$" + func->name() + func->parameters().rawSignature().remove(
' ');
3960 const auto *prop =
static_cast<
const PropertyNode *>(node);
3961 const NodeList &list = prop->functions();
3962 for (
const auto *propFuncNode : list) {
3963 if (propFuncNode->isFunction()) {
3964 const auto *func =
static_cast<
const FunctionNode *>(propFuncNode);
3965 out() <<
"$$$" + func->name()
3966 + func->parameters().rawSignature().remove(
' ');
3970 const auto *enumNode =
static_cast<
const EnumNode *>(node);
3971 const auto &items = enumNode->items();
3972 for (
const auto &item : items)
3973 out() <<
"$$$" + item.name();
3975 }
else if (markType == BriefMark) {
3977 }
else if (markType == DetailedDescriptionMark) {
3978 out() <<
"-description";
3982 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.
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.