30#include <QtCore/qxmlstream.h>
51
52
53
54
59
60
68
69
77
78
79
82 if (s_qdocIndexFiles ==
nullptr)
84 return s_qdocIndexFiles;
88
89
92 if (s_qdocIndexFiles !=
nullptr) {
93 delete s_qdocIndexFiles;
94 s_qdocIndexFiles =
nullptr;
99
100
103 for (
const QString &file : indexFiles) {
104 qCDebug(lcQdoc) <<
"Loading index file: " << file;
110
111
117 if (!file.open(QFile::ReadOnly)) {
118 qWarning() <<
"Could not read index file" << path;
122 QXmlStreamReader reader(&file);
123 reader.setNamespaceProcessing(
false);
125 if (!reader.readNextStartElement())
128 if (reader.name() != QLatin1String(
"INDEX"))
131 QXmlStreamAttributes attrs = reader.attributes();
133 QString indexUrl {attrs.value(QLatin1String(
"url")).toString()};
140 if (!Config::installDir.isEmpty() && indexUrl == Config::instance().get(
CONFIG_URL).asString()) {
143 QDir installDir(path.section(
'/', 0, -3) +
'/' + Generator::outputSubdir());
144 indexUrl = installDir.relativeFilePath(path).section(
'/', 0, -2);
146 m_project = attrs.value(QLatin1String(
"project")).toString();
147 QString indexTitle = attrs.value(QLatin1String(
"indexTitle")).toString();
149 m_relatedNodes.clear();
153 qWarning() <<
"Issue parsing index tree" << path;
157 root
->tree()->setIndexTitle(indexTitle);
161 while (reader.readNextStartElement()) {
162 readIndexSection(reader, root, indexUrl);
171
172
173
175 const QString &indexUrl)
177 QXmlStreamAttributes attributes = reader.attributes();
178 QStringView elementName = reader.name();
180 QString name = attributes.value(QLatin1String(
"name")).toString();
181 QString href = attributes.value(QLatin1String(
"href")).toString();
185 bool hasReadChildren =
false;
188 parent =
static_cast<
Aggregate *>(current);
190 if (attributes.hasAttribute(QLatin1String(
"related"))) {
191 bool isIntTypeRelatedValue =
false;
192 int relatedIndex = attributes.value(QLatin1String(
"related")).toInt(&isIntTypeRelatedValue);
193 if (isIntTypeRelatedValue) {
194 if (adoptRelatedNode(parent, relatedIndex)) {
195 reader.skipCurrentElement();
199 QList<Node *>::iterator nodeIterator =
200 std::find_if(m_relatedNodes.begin(), m_relatedNodes.end(), [&](
const Node *relatedNode) {
201 return (name == relatedNode->name() && href == relatedNode->url().section(QLatin1Char(
'/'), -1));
204 if (nodeIterator != m_relatedNodes.end() && parent) {
206 reader.skipCurrentElement();
214 if (attributes.hasAttribute(QLatin1String(
"filepath"))) {
215 filePath = attributes.value(QLatin1String(
"filepath")).toString();
216 lineNo = attributes.value(
"lineno").toInt();
218 if (elementName == QLatin1String(
"namespace")) {
220 node = namespaceNode;
221 if (!indexUrl.isEmpty())
222 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
223 else if (!indexUrl.isNull())
224 location
= Location(name.toLower() +
".html");
225 }
else if (elementName == QLatin1String(
"class") || elementName == QLatin1String(
"struct")
226 || elementName == QLatin1String(
"union")) {
228 if (elementName == QLatin1String(
"class"))
230 else if (elementName == QLatin1String(
"struct"))
232 else if (elementName == QLatin1String(
"union"))
234 node =
new ClassNode(type, parent, name);
235 if (attributes.hasAttribute(QLatin1String(
"bases"))) {
236 QString bases = attributes.value(QLatin1String(
"bases")).toString();
237 if (!bases.isEmpty())
239 std::pair<ClassNode *, QString>(
static_cast<ClassNode *>(node), bases));
241 if (!indexUrl.isEmpty())
242 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
243 else if (!indexUrl.isNull())
244 location
= Location(name.toLower() +
".html");
245 bool abstract =
false;
246 if (attributes.value(QLatin1String(
"abstract")) == QLatin1String(
"true"))
249 }
else if (elementName == QLatin1String(
"header")) {
252 if (attributes.hasAttribute(QLatin1String(
"location")))
253 name = attributes.value(QLatin1String(
"location")).toString();
255 if (!indexUrl.isEmpty())
256 location
= Location(indexUrl + QLatin1Char(
'/') + name);
257 else if (!indexUrl.isNull())
259 }
else if (parent && ((elementName == QLatin1String(
"qmlclass") || elementName == QLatin1String(
"qmlvaluetype")
260 || elementName == QLatin1String(
"qmlbasictype")))) {
263 QString logicalModuleName = attributes.value(QLatin1String(
"qml-module-name")).toString();
264 if (!logicalModuleName.isEmpty())
265 m_qdb->addToQmlModule(logicalModuleName, qmlTypeNode);
266 bool abstract =
false;
267 if (attributes.value(QLatin1String(
"abstract")) == QLatin1String(
"true"))
269 qmlTypeNode->setAbstract(abstract);
270 qmlTypeNode->setSingleton(attributes.value(QLatin1String(
"singleton")) == QLatin1String(
"true"));
271 QString qmlFullBaseName = attributes.value(QLatin1String(
"qml-base-type")).toString();
272 if (!qmlFullBaseName.isEmpty()) {
273 qmlTypeNode->setQmlBaseName(qmlFullBaseName);
275 if (attributes.hasAttribute(QLatin1String(
"location")))
276 name = attributes.value(
"location").toString();
277 if (!indexUrl.isEmpty())
278 location
= Location(indexUrl + QLatin1Char(
'/') + name);
279 else if (!indexUrl.isNull())
282 }
else if (parent && elementName == QLatin1String(
"qmlproperty")) {
284 QString propertyGroup = attributes.value(
"inpropertygroup").toString();
286 if (attributes.value(
"propertygroup") ==
"true") {
288 propertyGroup = attributes.value(
"fullname").toString();
290 QString type = attributes.value(QLatin1String(
"type")).toString();
291 bool attached =
false;
292 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
294 bool readonly =
false;
295 if (attributes.value(QLatin1String(
"writable")) == QLatin1String(
"false"))
298 qmlPropertyNode->markReadOnly(readonly);
299 if (attributes.value(QLatin1String(
"required")) == QLatin1String(
"true"))
300 qmlPropertyNode->setRequired();
302 node = qmlPropertyNode;
305 if (!propertyGroup.isEmpty()) {
318 hasReadChildren =
true;
321 }
else if (elementName == QLatin1String(
"group")) {
322 auto *collectionNode = m_qdb->addGroup(name);
323 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
324 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
325 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
326 collectionNode->markSeen();
327 node = collectionNode;
328 }
else if (elementName == QLatin1String(
"module")) {
329 auto *collectionNode = m_qdb->addModule(name);
330 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
331 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
332 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
333 collectionNode->markSeen();
334 node = collectionNode;
335 }
else if (elementName == QLatin1String(
"qmlmodule")) {
336 auto *collectionNode = m_qdb->addQmlModule(name);
337 const QStringList info = QStringList()
339 << QString(attributes.value(QLatin1String(
"qml-module-version")).toString());
340 collectionNode->setLogicalModuleInfo(info);
341 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
342 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
343 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
344 collectionNode->markSeen();
345 node = collectionNode;
346 }
else if (elementName == QLatin1String(
"page")) {
348 QString attr = attributes.value(QLatin1String(
"subtype")).toString();
349 if (attr == QLatin1String(
"attribution")) {
351 }
else if (attr == QLatin1String(
"example")) {
353 }
else if (attr == QLatin1String(
"file")) {
355 }
else if (attr == QLatin1String(
"image")) {
357 }
else if (attr == QLatin1String(
"page")) {
359 }
else if (attr == QLatin1String(
"externalpage")) {
365 auto *exampleNode =
static_cast<
ExampleNode *>(current);
367 exampleNode->appendFile(name);
370 exampleNode->appendImage(name);
380 pageNode =
new PageNode(parent, name);
384 pageNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
386 if (attributes.hasAttribute(QLatin1String(
"location")))
387 name = attributes.value(QLatin1String(
"location")).toString();
389 if (!indexUrl.isEmpty())
390 location
= Location(indexUrl + QLatin1Char(
'/') + name);
391 else if (!indexUrl.isNull())
396 }
else if (elementName == QLatin1String(
"enum") || elementName == QLatin1String(
"qmlenum")) {
398 if (elementName == QLatin1String(
"enum"))
399 enumNode =
new EnumNode(parent, name, attributes.hasAttribute(
"scoped"));
403 if (!indexUrl.isEmpty())
404 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
405 else if (!indexUrl.isNull())
406 location
= Location(parent->name().toLower() +
".html");
408 if (attributes.value(
"anonymous") ==
"true")
411 while (reader.readNextStartElement()) {
412 QXmlStreamAttributes childAttributes = reader.attributes();
413 if (reader.name() == QLatin1String(
"value")) {
414 EnumItem item(childAttributes.value(QLatin1String(
"name")).toString(),
415 childAttributes.value(QLatin1String(
"value")).toString(),
416 childAttributes.value(QLatin1String(
"since")).toString()
419 }
else if (reader.name() == QLatin1String(
"keyword")) {
421 }
else if (reader.name() == QLatin1String(
"target")) {
424 reader.skipCurrentElement();
429 hasReadChildren =
true;
430 }
else if (elementName == QLatin1String(
"typedef")) {
432 if (attributes.hasAttribute(
"aliasedtype"))
433 typedefNode =
new TypeAliasNode(parent, name, attributes.value(QLatin1String(
"aliasedtype")).toString());
438 if (attributes.hasAttribute(
"enum")) {
439 auto path = attributes.value(QLatin1String(
"enum")).toString();
440 const Node *enode = m_qdb->findNodeForTarget(path, typedefNode);
448 if (!indexUrl.isEmpty())
449 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
450 else if (!indexUrl.isNull())
451 location
= Location(parent->name().toLower() +
".html");
452 }
else if (elementName == QLatin1String(
"property")) {
455 if (attributes.value(QLatin1String(
"bindable")) == QLatin1String(
"true"))
458 propNode->setWritable(attributes.value(QLatin1String(
"writable")) != QLatin1String(
"false"));
459 propNode->setDataType(attributes.value(QLatin1String(
"dataType")).toString());
461 if (attributes.value(QLatin1String(
"constant")) == QLatin1String(
"true"))
462 propNode->setConstant();
464 if (!indexUrl.isEmpty())
465 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
466 else if (!indexUrl.isNull())
467 location
= Location(parent->name().toLower() +
".html");
469 }
else if (elementName == QLatin1String(
"function")) {
470 QString t = attributes.value(QLatin1String(
"meta")).toString();
471 bool attached =
false;
474 metaness = FunctionNode::getMetaness(t);
475 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
477 auto *fn =
new FunctionNode(metaness, parent, name, attached);
479 fn->setReturnType(attributes.value(QLatin1String(
"type")).toString());
481 const auto &declaredTypeAttr = attributes.value(QLatin1String(
"declaredtype"));
482 if (!declaredTypeAttr.isEmpty())
483 fn->setDeclaredReturnType(declaredTypeAttr.toString());
485 if (fn->isCppNode()) {
486 fn->setVirtualness(attributes.value(QLatin1String(
"virtual")).toString());
487 fn->setConst(attributes.value(QLatin1String(
"const")) == QLatin1String(
"true"));
488 fn->setStatic(attributes.value(QLatin1String(
"static")) == QLatin1String(
"true"));
489 fn->setFinal(attributes.value(QLatin1String(
"final")) == QLatin1String(
"true"));
490 fn->setOverride(attributes.value(QLatin1String(
"override")) == QLatin1String(
"true"));
492 if (attributes.value(QLatin1String(
"explicit")) == QLatin1String(
"true"))
495 if (attributes.value(QLatin1String(
"constexpr")) == QLatin1String(
"true"))
498 if (attributes.value(QLatin1String(
"noexcept")) == QLatin1String(
"true")) {
499 fn->markNoexcept(attributes.value(
"noexcept_expression").toString());
502 qsizetype refness = attributes.value(QLatin1String(
"refness")).toUInt();
505 else if (refness == 2)
508
509
510
511
512
513 if (attributes.value(QLatin1String(
"overload")) == QLatin1String(
"true"))
514 fn->setOverloadNumber(attributes.value(QLatin1String(
"overload-number")).toUInt());
516 fn->setOverloadNumber(0);
520
521
522
523
524
525
526 while (reader.readNextStartElement()) {
527 QXmlStreamAttributes childAttributes = reader.attributes();
528 if (reader.name() == QLatin1String(
"parameter")) {
529 QString type = childAttributes.value(QLatin1String(
"type")).toString();
530 QString name = childAttributes.value(QLatin1String(
"name")).toString();
531 QString default_ = childAttributes.value(QLatin1String(
"default")).toString();
532 fn->parameters().append(type, name, default_);
533 }
else if (reader.name() == QLatin1String(
"keyword")) {
535 }
else if (reader.name() == QLatin1String(
"target")) {
538 reader.skipCurrentElement();
542 if (!indexUrl.isEmpty())
543 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
544 else if (!indexUrl.isNull())
545 location
= Location(parent->name().toLower() +
".html");
547 hasReadChildren =
true;
548 }
else if (elementName == QLatin1String(
"variable")) {
550 varNode->setLeftType(attributes.value(
"type").toString());
551 varNode->setStatic((attributes.value(
"static").toString() ==
"true") ?
true :
false);
553 if (!indexUrl.isEmpty())
554 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
555 else if (!indexUrl.isNull())
556 location
= Location(parent->name().toLower() +
".html");
557 }
else if (elementName == QLatin1String(
"keyword")) {
560 }
else if (elementName == QLatin1String(
"target")) {
563 }
else if (elementName == QLatin1String(
"contents")) {
566 }
else if (elementName == QLatin1String(
"proxy")) {
568 if (!indexUrl.isEmpty())
569 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
570 else if (!indexUrl.isNull())
571 location
= Location(name.toLower() +
".html");
577 if (!href.isEmpty()) {
581 node->setUrl(indexUrl + QLatin1Char(
'/') + href);
584 const QString access = attributes.value(QLatin1String(
"access")).toString();
585 if (access ==
"protected")
587 else if (access ==
"private")
592 if (attributes.hasAttribute(QLatin1String(
"related"))) {
594 m_relatedNodes << node;
597 if (attributes.hasAttribute(QLatin1String(
"threadsafety"))) {
598 QString threadSafety = attributes.value(QLatin1String(
"threadsafety")).toString();
599 if (threadSafety == QLatin1String(
"non-reentrant"))
601 else if (threadSafety == QLatin1String(
"reentrant"))
603 else if (threadSafety == QLatin1String(
"thread safe"))
610 const QString category = attributes.value(QLatin1String(
"comparison_category")).toString();
613 QString status = attributes.value(QLatin1String(
"status")).toString();
615 if (status == QLatin1String(
"obsolete") || status == QLatin1String(
"deprecated"))
617 else if (status == QLatin1String(
"preliminary"))
619 else if (status == QLatin1String(
"internal"))
621 else if (status == QLatin1String(
"ignored"))
626 QString physicalModuleName = attributes.value(QLatin1String(
"module")).toString();
627 if (!physicalModuleName.isEmpty())
628 m_qdb->addToModule(physicalModuleName, node);
630 QString since = attributes.value(QLatin1String(
"since")).toString();
631 if (!since.isEmpty()) {
632 node->setSince(since);
635 if (attributes.hasAttribute(QLatin1String(
"documented"))) {
636 if (attributes.value(QLatin1String(
"documented")) == QLatin1String(
"true"))
640 QString groupsAttr = attributes.value(QLatin1String(
"groups")).toString();
641 if (!groupsAttr.isEmpty()) {
642 const QStringList groupNames = groupsAttr.split(QLatin1Char(
','));
643 for (
const auto &group : groupNames) {
644 m_qdb->addToGroup(group, node);
649 QSet<QString> emptySet;
651 if (!filePath.isEmpty()) {
656 Doc doc(location, location, QString(), emptySet, emptySet);
659 QString briefAttr = attributes.value(QLatin1String(
"brief")).toString();
660 if (!briefAttr.isEmpty()) {
661 node->setReconstitutedBrief(briefAttr);
664 if (
const auto sortKey = attributes.value(QLatin1String(
"sortkey")).toString(); !sortKey.isEmpty()) {
667 metaMap->insert(
"sortkey", sortKey);
669 if (!hasReadChildren) {
670 bool useParent = (elementName == QLatin1String(
"namespace") && name.isEmpty());
671 while (reader.readNextStartElement()) {
673 readIndexSection(reader, parent, indexUrl);
675 readIndexSection(reader, node, indexUrl);
681 while (!reader.isEndElement()) {
682 if (reader.readNext() == QXmlStreamReader::Invalid) {
689 const QXmlStreamAttributes &attributes,
Node *node)
706 QString name = attributes.value(QLatin1String(
"name")).toString();
707 QString title = attributes.value(QLatin1String(
"title")).toString();
708 m_qdb->insertTarget(name, title, type, node, priority);
712
713
714
715
716
717
718
719
720
721
722
723
724
727 for (
const auto &pair : std::as_const(m_basesList)) {
728 const QStringList bases = pair.second.split(QLatin1Char(
','));
729 for (
const auto &base : bases) {
730 QStringList basePath = base.split(QString(
"::"));
731 Node *n = m_qdb->findClassNode(basePath);
733 pair.first->addResolvedBaseClass(Access::Public,
static_cast<ClassNode *>(n));
735 pair.first->addUnresolvedBaseClass(Access::Public, basePath);
747 return QLatin1String(
"public");
749 return QLatin1String(
"protected");
751 return QLatin1String(
"private");
755 return QLatin1String(
"public");
762 return QLatin1String(
"deprecated");
764 return QLatin1String(
"preliminary");
766 return QLatin1String(
"active");
768 return QLatin1String(
"internal");
770 return QLatin1String(
"ignored");
774 return QLatin1String(
"active");
781 return QLatin1String(
"non-reentrant");
783 return QLatin1String(
"reentrant");
785 return QLatin1String(
"thread safe");
790 return QLatin1String(
"unspecified");
794
795
798 qsizetype i = m_relatedNodes.indexOf(node);
800 i = m_relatedNodes.size();
801 m_relatedNodes << node;
807
808
809
812 Node *related = m_relatedNodes.value(index);
814 if (adoptiveParent && related) {
823
824
825
826
827
831 for (
const Atom *target : std::as_const(node->doc().targets())) {
832 const QString &title = target->string();
833 const QString &name{Utilities::asAsciiPrintable(title)};
834 writer.writeStartElement(
"target");
835 writer.writeAttribute(
"name", node->isExternalPage() ? title : name);
837 writer.writeAttribute(
"title", title);
838 writer.writeEndElement();
842 for (
const Atom *keyword : std::as_const(node->doc().keywords())) {
843 const QString &title = keyword->string();
844 const QString &name{Utilities::asAsciiPrintable(title)};
845 writer.writeStartElement(
"keyword");
846 writer.writeAttribute(
"name", name);
848 writer.writeAttribute(
"title", title);
849 writer.writeEndElement();
855
856
857
858
859
860
864 if (m_gen ==
nullptr)
871
872
877 QString logicalModuleName;
878 QString logicalModuleVersion;
879 QString qmlFullBaseName;
880 QString baseNameAttr;
881 QString moduleNameAttr;
882 QString moduleVerAttr;
886 nodeName =
"namespace";
901 nodeName =
"qmlenum";
906 logicalModuleName = node->logicalModuleName();
907 baseNameAttr =
"qml-base-type";
908 moduleNameAttr =
"qml-module-name";
909 moduleVerAttr =
"qml-module-version";
910 qmlFullBaseName = node->qmlFullBaseName();
924 nodeName =
"qmlmodule";
925 moduleNameAttr =
"qml-module-name";
926 moduleVerAttr =
"qml-module-version";
927 logicalModuleName = node->logicalModuleName();
928 logicalModuleVersion = node->logicalModuleVersion();
935 nodeName =
"typedef";
938 nodeName =
"property";
941 nodeName =
"variable";
947 nodeName =
"qmlproperty";
950 nodeName =
"qmlproperty";
960 QString objName = node->name();
965 writer.writeStartElement(nodeName);
968 if (node->threadSafeness() != Node::UnspecifiedSafeness)
969 writer.writeAttribute(
"threadsafety", getThreadSafenessString(node->threadSafeness()));
972 writer.writeAttribute(
"name", objName);
975 writer.writeAttribute(
"propertygroup",
"true");
980 if (!moduleNameAttr.isEmpty()) {
981 if (!logicalModuleName.isEmpty())
982 writer.writeAttribute(moduleNameAttr, logicalModuleName);
983 if (!logicalModuleVersion.isEmpty())
984 writer.writeAttribute(moduleVerAttr, logicalModuleVersion);
986 if (!baseNameAttr.isEmpty() && !qmlFullBaseName.isEmpty())
987 writer.writeAttribute(baseNameAttr, qmlFullBaseName);
988 else if (!baseNameAttr.isEmpty()) {
989 auto qmlBase =
static_cast<
QmlTypeNode *>(node)->qmlBaseName();
990 if (!qmlBase.isEmpty())
991 writer.writeAttribute(baseNameAttr, qmlBase);
996 QString fullName = node->fullDocumentName();
997 if (fullName != objName)
998 writer.writeAttribute(
"fullname", fullName);
999 href = m_gen->fullDocumentLocation(node);
1001 href = node->name();
1007 if (!href.isEmpty())
1008 writer.writeAttribute(
"href", href);
1010 writer.writeAttribute(
"status", getStatusString(node->status()));
1012 writer.writeAttribute(
"access", getAccessString(node->access()));
1014 writer.writeAttribute(
"abstract",
"true");
1017 if (!declLocation.fileName().isEmpty())
1018 writer.writeAttribute(
"location", declLocation.fileName());
1019 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
1020 writer.writeAttribute(
"filepath", declLocation.filePath());
1021 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
1024 if (node->isRelatedNonmember())
1025 writer.writeAttribute(
"related", QString::number(indexForNode(node)));
1027 if (!node->since().isEmpty())
1028 writer.writeAttribute(
"since", node->since());
1031 writer.writeAttribute(
"documented",
"true");
1033 QStringList groups = m_qdb->groupNamesForNode(node);
1034 if (!groups.isEmpty())
1035 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
1038 if (
const auto sortKey = metamap->value(
"sortkey"); !sortKey.isEmpty())
1039 writer.writeAttribute(
"sortkey", sortKey);
1041 QString brief = node
->doc().trimmedBriefText(node->name()).toString();
1047 const auto *classNode =
static_cast<
const ClassNode *>(node);
1048 const QList<RelatedClass> &bases = classNode->baseClasses();
1049 QSet<QString> baseStrings;
1050 for (
const auto &related : bases) {
1051 ClassNode *n = related.m_node;
1053 baseStrings.insert(n->fullName());
1054 else if (!related.m_path.isEmpty())
1055 baseStrings.insert(related.m_path.join(QLatin1String(
"::")));
1057 if (!baseStrings.isEmpty()) {
1058 QStringList baseStringsAsList = baseStrings.values();
1059 baseStringsAsList.sort();
1060 writer.writeAttribute(
"bases", baseStringsAsList.join(QLatin1Char(
',')));
1062 if (!node->physicalModuleName().isEmpty())
1063 writer.writeAttribute(
"module", node->physicalModuleName());
1064 if (!brief.isEmpty())
1065 writer.writeAttribute(
"brief", brief);
1070 const auto *headerNode =
static_cast<
const HeaderNode *>(node);
1071 if (!headerNode->physicalModuleName().isEmpty())
1072 writer.writeAttribute(
"module", headerNode->physicalModuleName());
1073 if (!brief.isEmpty())
1074 writer.writeAttribute(
"brief", brief);
1075 writer.writeAttribute(
"title", headerNode->title());
1076 writer.writeAttribute(
"fulltitle", headerNode->fullTitle());
1077 writer.writeAttribute(
"subtitle", headerNode->subtitle());
1080 const auto *namespaceNode =
static_cast<
const NamespaceNode *>(node);
1081 if (!namespaceNode->physicalModuleName().isEmpty())
1082 writer.writeAttribute(
"module", namespaceNode->physicalModuleName());
1083 if (!brief.isEmpty())
1084 writer.writeAttribute(
"brief", brief);
1088 const auto *qmlTypeNode =
static_cast<
const QmlTypeNode *>(node);
1090 writer.writeAttribute(
"singleton",
"true");
1091 if (!brief.isEmpty())
1092 writer.writeAttribute(
"brief", brief);
1098 writer.writeAttribute(
"subtype",
"example");
1100 writer.writeAttribute(
"subtype",
"externalpage");
1104 const auto *pageNode =
static_cast<
const PageNode *>(node);
1105 writer.writeAttribute(
"title", pageNode->title());
1106 writer.writeAttribute(
"fulltitle", pageNode->fullTitle());
1107 writer.writeAttribute(
"subtitle", pageNode->subtitle());
1108 if (!brief.isEmpty())
1109 writer.writeAttribute(
"brief", brief);
1114 const auto *collectionNode =
static_cast<
const CollectionNode *>(node);
1115 writer.writeAttribute(
"seen", collectionNode
->wasSeen() ?
"true" :
"false");
1116 writer.writeAttribute(
"title", collectionNode->title());
1117 if (!collectionNode->subtitle().isEmpty())
1118 writer.writeAttribute(
"subtitle", collectionNode->subtitle());
1119 if (!collectionNode->physicalModuleName().isEmpty())
1120 writer.writeAttribute(
"module", collectionNode->physicalModuleName());
1121 if (!brief.isEmpty())
1122 writer.writeAttribute(
"brief", brief);
1126 writer.writeAttribute(
"type", qmlPropertyNode->dataType());
1127 writer.writeAttribute(
"attached", qmlPropertyNode
->isAttached() ?
"true" :
"false");
1128 writer.writeAttribute(
"writable", qmlPropertyNode
->isReadOnly() ?
"false" :
"true");
1130 writer.writeAttribute(
"required",
"true");
1131 if (!brief.isEmpty())
1132 writer.writeAttribute(
"brief", brief);
1135 const auto *propertyNode =
static_cast<
const PropertyNode *>(node);
1138 writer.writeAttribute(
"bindable",
"true");
1141 writer.writeAttribute(
"writable",
"false");
1144 writer.writeAttribute(
"constant",
"true");
1146 writer.writeAttribute(
"dataType", propertyNode->dataType());
1148 if (!brief.isEmpty())
1149 writer.writeAttribute(
"brief", brief);
1151 for (qsizetype i{0}; i < (qsizetype)PropertyNode::FunctionRole::NumFunctionRoles; ++i) {
1153 for (
const auto *fnNode : propertyNode->functions(role)) {
1154 writer.writeStartElement(PropertyNode::roleName(role));
1155 writer.writeAttribute(
"name", fnNode->name());
1156 writer.writeEndElement();
1161 const auto *variableNode =
static_cast<
const VariableNode *>(node);
1162 writer.writeAttribute(
"type", variableNode->dataType());
1163 writer.writeAttribute(
"static", variableNode
->isStatic() ?
"true" :
"false");
1164 if (!brief.isEmpty())
1165 writer.writeAttribute(
"brief", brief);
1169 const auto *enumNode =
static_cast<
const EnumNode *>(node);
1171 writer.writeAttribute(
"scoped",
"true");
1173 writer.writeAttribute(
"typedef", enumNode
->flagsType()->fullDocumentName());
1175 writer.writeAttribute(
"anonymous",
"true");
1176 const auto &items = enumNode->items();
1177 for (
const auto &item : items) {
1178 writer.writeStartElement(
"value");
1179 writer.writeAttribute(
"name", item.name());
1180 if (node->isEnumType(Genus::CPP))
1181 writer.writeAttribute(
"value", item.value());
1182 if (!item.since().isEmpty())
1183 writer.writeAttribute(
"since", item.since());
1184 writer.writeEndElement();
1188 const auto *typedefNode =
static_cast<
const TypedefNode *>(node);
1193 writer.writeAttribute(
"aliasedtype",
static_cast<
const TypeAliasNode *>(node)->aliasedType());
1200 writeTargets(writer, node);
1203
1204
1205
1206
1207
1208
1211 for (
int i = 0; i < node
->doc().tableOfContents().size(); ++i) {
1213 int level = node
->doc().tableOfContentsLevels()[i];
1215 writer.writeStartElement(
"contents");
1216 writer.writeAttribute(
"name", Tree::refForAtom(item));
1217 writer.writeAttribute(
"title", title);
1218 writer.writeAttribute(
"level", QString::number(level));
1219 writer.writeEndElement();
1225 if (node
->isExample() && m_gen->format() != QLatin1String(
"WebXML")) {
1226 const auto *exampleNode =
static_cast<
const ExampleNode *>(node);
1227 const auto &files = exampleNode->files();
1228 for (
const QString &file : files) {
1229 writer.writeStartElement(
"page");
1230 writer.writeAttribute(
"name", file);
1231 QString href = m_gen->linkForExampleFile(file);
1232 writer.writeAttribute(
"href", href);
1233 writer.writeAttribute(
"status",
"active");
1234 writer.writeAttribute(
"subtype",
"file");
1235 writer.writeAttribute(
"title",
"");
1236 writer.writeAttribute(
"fulltitle", Generator::exampleFileTitle(exampleNode, file));
1237 writer.writeAttribute(
"subtitle", file);
1238 writer.writeEndElement();
1240 const auto &images = exampleNode->images();
1241 for (
const QString &file : images) {
1242 writer.writeStartElement(
"page");
1243 writer.writeAttribute(
"name", file);
1244 QString href = m_gen->linkForExampleFile(file);
1245 writer.writeAttribute(
"href", href);
1246 writer.writeAttribute(
"status",
"active");
1247 writer.writeAttribute(
"subtype",
"image");
1248 writer.writeAttribute(
"title",
"");
1249 writer.writeAttribute(
"fulltitle", Generator::exampleFileTitle(exampleNode, file));
1250 writer.writeAttribute(
"subtitle", file);
1251 writer.writeEndElement();
1263
1264
1265
1268 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1273 const QString objName = fn->name();
1274 writer.writeStartElement(
"function");
1275 writer.writeAttribute(
"name", objName);
1277 const QString fullName = fn->fullDocumentName();
1278 if (fullName != objName)
1279 writer.writeAttribute(
"fullname", fullName);
1280 const QString href = m_gen->fullDocumentLocation(fn);
1281 if (!href.isEmpty())
1282 writer.writeAttribute(
"href", href);
1283 if (fn->threadSafeness() != Node::UnspecifiedSafeness)
1284 writer.writeAttribute(
"threadsafety", getThreadSafenessString(fn->threadSafeness()));
1285 writer.writeAttribute(
"status", getStatusString(fn->status()));
1286 writer.writeAttribute(
"access", getAccessString(fn->access()));
1289 if (!declLocation.fileName().isEmpty())
1290 writer.writeAttribute(
"location", declLocation.fileName());
1291 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
1292 writer.writeAttribute(
"filepath", declLocation.filePath());
1293 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
1297 writer.writeAttribute(
"documented",
"true");
1298 if (fn->isRelatedNonmember())
1299 writer.writeAttribute(
"related", QString::number(indexForNode(fn)));
1300 if (!fn->since().isEmpty())
1301 writer.writeAttribute(
"since", fn->since());
1303 const QString brief = fn
->doc().trimmedBriefText(fn->name()).toString();
1304 writer.writeAttribute(
"meta", fn->metanessString());
1307 writer.writeAttribute(
"virtual", fn->virtualness());
1310 writer.writeAttribute(
"const",
"true");
1312 writer.writeAttribute(
"static",
"true");
1314 writer.writeAttribute(
"final",
"true");
1316 writer.writeAttribute(
"override",
"true");
1318 writer.writeAttribute(
"explicit",
"true");
1320 writer.writeAttribute(
"constexpr",
"true");
1322 if (
auto noexcept_info = fn->getNoexcept()) {
1323 writer.writeAttribute(
"noexcept",
"true");
1324 if (!(*noexcept_info).isEmpty()) writer.writeAttribute(
"noexcept_expression", *noexcept_info);
1328
1329
1330
1331
1332
1334 writer.writeAttribute(
"overload",
"true");
1335 writer.writeAttribute(
"overload-number", QString::number(fn->overloadNumber()));
1338 writer.writeAttribute(
"refness", QString::number(1));
1339 else if (fn->isRefRef())
1340 writer.writeAttribute(
"refness", QString::number(2));
1342 QStringList associatedProperties;
1343 for (
const auto *node : fn->associatedProperties()) {
1344 associatedProperties << node->name();
1346 associatedProperties.sort();
1347 writer.writeAttribute(
"associated-property",
1348 associatedProperties.join(QLatin1Char(
',')));
1352 writer.writeAttribute(
"attached",
"true");
1355 const auto &return_type = fn->returnType();
1356 if (!return_type.isEmpty())
1357 writer.writeAttribute(
"type",
std::move(return_type));
1359 const auto &declared_return_type = fn->declaredReturnType();
1360 if (declared_return_type.has_value())
1361 writer.writeAttribute(
"declaredtype", declared_return_type.value());
1364 if (!brief.isEmpty())
1365 writer.writeAttribute(
"brief", brief);
1368
1369
1370
1371
1372 const QString signature = appendAttributesToSignature(fn);
1373 writer.writeAttribute(
"signature", signature);
1375 QStringList groups = m_qdb->groupNamesForNode(fn);
1376 if (!groups.isEmpty())
1377 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
1382 writer.writeStartElement(
"parameter");
1383 writer.writeAttribute(
"type", parameter.type());
1384 writer.writeAttribute(
"name", parameter.name());
1385 writer.writeAttribute(
"default", parameter.defaultValue());
1386 writer.writeEndElement();
1389 writeTargets(writer, fn);
1395 writer.writeEndElement();
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1414 signature +=
" final";
1416 signature +=
" override";
1418 signature +=
" = 0";
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1436 for (
auto functions : std::as_const(aggregate->functionMap())) {
1437 std::for_each(functions.begin(), functions.end(),
1438 [
this,&writer](FunctionNode *fn) {
1439 generateFunctionSection(writer, fn);
1446
1447
1448
1453
1454
1455
1460 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
1465 if (generateIndexSection(writer, node, post)) {
1467 auto *aggregate =
static_cast<
Aggregate *>(node);
1469 generateFunctionSections(writer, aggregate);
1471 for (
auto *node : nonFunctionList)
1472 generateIndexSections(writer, node, post);
1475 if (node ==
root_) {
1477
1478
1479
1480
1481
1482
1484 if (!groups.isEmpty()) {
1485 for (
auto it = groups.constBegin(); it != groups.constEnd(); ++it) {
1486 if (generateIndexSection(writer, it.value(), post))
1487 writer.writeEndElement();
1492 if (!modules.isEmpty()) {
1493 for (
auto it = modules.constBegin(); it != modules.constEnd(); ++it) {
1494 if (generateIndexSection(writer, it.value(), post))
1495 writer.writeEndElement();
1500 if (!qmlModules.isEmpty()) {
1501 for (
auto it = qmlModules.constBegin(); it != qmlModules.constEnd(); ++it) {
1502 if (generateIndexSection(writer, it.value(), post))
1503 writer.writeEndElement();
1507 for (
auto *p : m_qdb->primaryTree()->proxies()) {
1508 if (generateIndexSection(writer, p, post)) {
1509 auto aggregate =
static_cast<Aggregate *>(p);
1510 generateFunctionSections(writer, aggregate);
1511 for (
auto *n : aggregate->nonfunctionList())
1512 generateIndexSections(writer, n, post);
1513 writer.writeEndElement();
1518 writer.writeEndElement();
1523
1524
1525
1526
1527
1528void QDocIndexFiles::generateIndex(
const QString &fileName,
const QString &url,
1529 const QString &title)
1531 QFile file(fileName);
1532 if (!file.open(QFile::WriteOnly | QFile::Text))
1535 qCDebug(lcQdoc) <<
"Writing index file:" << fileName;
1538 m_relatedNodes.clear();
1539 QXmlStreamWriter writer(&file);
1540 writer.setAutoFormatting(
true);
1541 writer.writeStartDocument();
1542 writer.writeDTD(
"<!DOCTYPE QDOCINDEX>");
1544 writer.writeStartElement(
"INDEX");
1545 writer.writeAttribute(
"url", url);
1546 writer.writeAttribute(
"title", title);
1547 writer.writeAttribute(
"version", m_qdb->version());
1548 writer.writeAttribute(
"project", Config::instance().get(
CONFIG_PROJECT).asString());
1552 writer.writeAttribute(
"indexTitle",
root_->tree()->indexTitle());
1554 generateIndexSections(writer,
root_,
nullptr);
1556 writer.writeEndElement();
1557 writer.writeEndElement();
1558 writer.writeEndDocument();
void adoptChild(Node *child)
This Aggregate becomes the adoptive parent of child.
const NodeList & nonfunctionList()
Returns a const reference to the list of child nodes of this aggregate that are not function nodes.
The Atom class is the fundamental unit for representing documents internally.
The ClassNode represents a C++ class.
A class for holding the members of a collection of doc pages.
bool wasSeen() const override
Returns the seen flag data member of this node if it is a NamespaceNode or a CollectionNode.
bool hasTableOfContents() const
QStringMultiMap * metaTagMap() const
void constructExtra() const
void setFlagsType(TypedefNode *typedefNode)
void addItem(const EnumItem &item)
Add item to the enum type's item list.
void setAnonymous(bool anonymous)
const TypedefNode * flagsType() const
The ExternalPageNode represents an external documentation page.
This node is used to represent any kind of function being documented.
signed short overloadNumber() const
Returns the overload number for this function.
bool isPureVirtual() const override
bool isNonvirtual() const
bool isAttached() const override
Returns true if the QML property or QML method node is marked as attached.
bool isStatic() const override
Returns true if the FunctionNode represents a static function.
Parameters & parameters()
bool hasAssociatedProperties() const
static Generator * currentGenerator()
static bool isPubliclyVisible(const InclusionPolicy &policy, const NodeContext &context)
virtual void append(QXmlStreamWriter &writer, Node *node)=0
The Location class provides a way to mark a location in a file.
int lineNo() const
Returns the current line number.
Location & operator=(const Location &other)
The assignment operator does a deep copy of the entire state of other into this Location.
This class represents a C++ namespace.
Tree * tree() const override
Returns a pointer to the Tree that contains this NamespaceNode.
A PageNode is a Node that generates a documentation page.
bool isAttribution() const
The Parameter class describes one function parameter.
This class describes one instance of using the Q_PROPERTY macro.
PropertyType propertyType() const
A class for representing an Aggregate that is documented in a different module.
This class provides exclusive access to the qdoc database, which consists of a forrest of trees and a...
static QDocDatabase * qdocDB()
Creates the singleton.
const CNMap & qmlModules()
Returns a const reference to the collection of all QML module nodes in the primary tree.
NamespaceNode * primaryTreeRoot()
Returns a pointer to the root node of the primary tree.
const CNMap & modules()
Returns a const reference to the collection of all module nodes in the primary tree.
const CNMap & groups()
Returns a const reference to the collection of all group nodes in the primary tree.
This class handles qdoc index files.
bool isRequired()
Returns true if this QML property is marked with \required or the corresponding C++ property uses the...
bool isReadOnly()
Returns true if this QML property or attached property is read-only.
bool isAttached() const override
Returns true if the QML property or QML method node is marked as attached.
static Text sectionHeading(const Atom *sectionBegin)
const EnumNode * associatedEnum() const
bool isStatic() const override
Returns true if the FunctionNode represents a static function.
static std::string comparisonCategoryAsString(ComparisonCategory category)
#define CONFIG_LOCATIONINFO
Combined button and popup list for selecting options.
QMap< QString, CollectionNode * > CNMap
static QHash< QString, SharedCommentNode * > sharedDocNodes_
static QString getStatusString(Node::Status t)
static QString getAccessString(Access t)
static IndexSectionWriter * post_
static QString getThreadSafenessString(Node::ThreadSafeness t)
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.
bool isQmlNode() const
Returns true if this node's Genus value is QML.
bool isGroup() const
Returns true if the node type is Group.
void setAccess(Access t)
Sets the node's access type to t.
void setIndexNodeFlag(bool isIndexNode=true)
Sets a flag in this Node that indicates the node was created for something in an index file.
virtual bool isAbstract() const
Returns true if the ClassNode or QmlTypeNode is marked abstract.
SharedCommentNode * sharedCommentNode()
ComparisonCategory comparisonCategory() const
bool isQmlType() const
Returns true if the node type is QmlType or QmlValueType.
bool isHeader() const
Returns true if the node type is HeaderFile.
NodeType nodeType() const override
Returns this node's type.
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 bool isTextPageNode() const
Returns true if the node is a PageNode but not an Aggregate.
Aggregate * parent() const
Returns the node's parent pointer.
void setLocation(const Location &t)
Sets the node's declaration location, its definition location, or both, depending on the suffix of th...
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
virtual void setRelatedNonmember(bool b)
Sets a flag in the node indicating whether this node is a related nonmember of something.
void setComparisonCategory(const ComparisonCategory &category)
bool isProxyNode() const
Returns true if the node type is Proxy.
virtual Tree * tree() const
Returns a pointer to the Tree this node is in.
const Location & declLocation() const
Returns the Location where this node's declaration was seen.
NodeContext createContext() const
void setDoc(const Doc &doc, bool replace=false)
Sets this Node's Doc to doc.
bool isModule() const
Returns true if the node type is Module.
virtual bool isPropertyGroup() const
Returns true if the node is a SharedCommentNode for documenting multiple C++ properties or multiple Q...
ThreadSafeness
An unsigned char that specifies the degree of thread-safeness of the element.
bool isSharingComment() const
This function returns true if the node is sharing a comment with other nodes.
virtual void setAbstract(bool)
If this node is a ClassNode or a QmlTypeNode, the node's abstract flag data member is set to b.
bool hasDoc() const
Returns true if this node is documented, or it represents a documented node read from the index ('had...
bool isCppNode() const
Returns true if this node's Genus value is CPP.
void setStatus(Status t)
Sets the node's status to t.
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
void setThreadSafeness(ThreadSafeness t)
Sets the node's thread safeness to t.
Status
An unsigned char that specifies the status of the documentation element in the documentation set.
bool isQmlModule() const
Returns true if the node type is QmlModule.
bool isExample() const
Returns true if the node type is Example.
bool isIndexNode() const
Returns true if this node was created from something in an index file.
const Parameter & at(int i) const
A record of a linkable target within the documentation.
TargetType
A type of a linkable target record.