26#include <QtCore/qxmlstream.h>
46
47
48
49
54
55
63
64
72
73
74
77 if (s_qdocIndexFiles ==
nullptr)
79 return s_qdocIndexFiles;
83
84
87 if (s_qdocIndexFiles !=
nullptr) {
88 delete s_qdocIndexFiles;
89 s_qdocIndexFiles =
nullptr;
94
95
98 for (
const QString &file : indexFiles) {
99 qCDebug(lcQdoc) <<
"Loading index file: " << file;
105
106
110 if (!file.open(QFile::ReadOnly)) {
111 qWarning() <<
"Could not read index file" << path;
115 QXmlStreamReader reader(&file);
116 reader.setNamespaceProcessing(
false);
118 if (!reader.readNextStartElement())
121 if (reader.name() != QLatin1String(
"INDEX"))
124 QXmlStreamAttributes attrs = reader.attributes();
126 QString indexUrl {attrs.value(QLatin1String(
"url")).toString()};
133 if (!Config::installDir.isEmpty() && indexUrl == Config::instance().get(
CONFIG_URL).asString()) {
136 QDir installDir(path.section(
'/', 0, -3) +
'/' + Generator::outputSubdir());
137 indexUrl = installDir.relativeFilePath(path).section(
'/', 0, -2);
139 m_project = attrs.value(QLatin1String(
"project")).toString();
140 QString indexTitle = attrs.value(QLatin1String(
"indexTitle")).toString();
142 m_relatedNodes.clear();
146 qWarning() <<
"Issue parsing index tree" << path;
150 root
->tree()->setIndexTitle(indexTitle);
154 while (reader.readNextStartElement()) {
155 readIndexSection(reader, root, indexUrl);
164
165
166
168 const QString &indexUrl)
170 QXmlStreamAttributes attributes = reader.attributes();
171 QStringView elementName = reader.name();
173 QString name = attributes.value(QLatin1String(
"name")).toString();
174 QString href = attributes.value(QLatin1String(
"href")).toString();
178 bool hasReadChildren =
false;
181 parent =
static_cast<
Aggregate *>(current);
183 if (attributes.hasAttribute(QLatin1String(
"related"))) {
184 bool isIntTypeRelatedValue =
false;
185 int relatedIndex = attributes.value(QLatin1String(
"related")).toInt(&isIntTypeRelatedValue);
186 if (isIntTypeRelatedValue) {
187 if (adoptRelatedNode(parent, relatedIndex)) {
188 reader.skipCurrentElement();
192 QList<Node *>::iterator nodeIterator =
193 std::find_if(m_relatedNodes.begin(), m_relatedNodes.end(), [&](
const Node *relatedNode) {
194 return (name == relatedNode->name() && href == relatedNode->url().section(QLatin1Char(
'/'), -1));
197 if (nodeIterator != m_relatedNodes.end() && parent) {
199 reader.skipCurrentElement();
207 if (attributes.hasAttribute(QLatin1String(
"filepath"))) {
208 filePath = attributes.value(QLatin1String(
"filepath")).toString();
209 lineNo = attributes.value(
"lineno").toInt();
211 if (elementName == QLatin1String(
"namespace")) {
213 node = namespaceNode;
214 if (!indexUrl.isEmpty())
215 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
216 else if (!indexUrl.isNull())
217 location
= Location(name.toLower() +
".html");
218 }
else if (elementName == QLatin1String(
"class") || elementName == QLatin1String(
"struct")
219 || elementName == QLatin1String(
"union")) {
221 if (elementName == QLatin1String(
"class"))
223 else if (elementName == QLatin1String(
"struct"))
225 else if (elementName == QLatin1String(
"union"))
227 node =
new ClassNode(type, parent, name);
228 if (attributes.hasAttribute(QLatin1String(
"bases"))) {
229 QString bases = attributes.value(QLatin1String(
"bases")).toString();
230 if (!bases.isEmpty())
232 std::pair<ClassNode *, QString>(
static_cast<ClassNode *>(node), bases));
234 if (!indexUrl.isEmpty())
235 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
236 else if (!indexUrl.isNull())
237 location
= Location(name.toLower() +
".html");
238 bool abstract =
false;
239 if (attributes.value(QLatin1String(
"abstract")) == QLatin1String(
"true"))
242 }
else if (elementName == QLatin1String(
"header")) {
245 if (attributes.hasAttribute(QLatin1String(
"location")))
246 name = attributes.value(QLatin1String(
"location")).toString();
248 if (!indexUrl.isEmpty())
249 location
= Location(indexUrl + QLatin1Char(
'/') + name);
250 else if (!indexUrl.isNull())
252 }
else if (elementName == QLatin1String(
"qmlclass") || elementName == QLatin1String(
"qmlvaluetype")
253 || elementName == QLatin1String(
"qmlbasictype")) {
256 qmlTypeNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
257 QString logicalModuleName = attributes.value(QLatin1String(
"qml-module-name")).toString();
258 if (!logicalModuleName.isEmpty())
259 m_qdb->addToQmlModule(logicalModuleName, qmlTypeNode);
260 bool abstract =
false;
261 if (attributes.value(QLatin1String(
"abstract")) == QLatin1String(
"true"))
263 qmlTypeNode->setAbstract(abstract);
264 QString qmlFullBaseName = attributes.value(QLatin1String(
"qml-base-type")).toString();
265 if (!qmlFullBaseName.isEmpty()) {
266 qmlTypeNode->setQmlBaseName(qmlFullBaseName);
268 if (attributes.hasAttribute(QLatin1String(
"location")))
269 name = attributes.value(
"location").toString();
270 if (!indexUrl.isEmpty())
271 location
= Location(indexUrl + QLatin1Char(
'/') + name);
272 else if (!indexUrl.isNull())
275 }
else if (elementName == QLatin1String(
"qmlproperty")) {
276 QString type = attributes.value(QLatin1String(
"type")).toString();
277 bool attached =
false;
278 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
280 bool readonly =
false;
281 if (attributes.value(QLatin1String(
"writable")) == QLatin1String(
"false"))
283 auto *qmlPropertyNode =
new QmlPropertyNode(parent, name, type, attached);
284 qmlPropertyNode->markReadOnly(readonly);
285 if (attributes.value(QLatin1String(
"required")) == QLatin1String(
"true"))
286 qmlPropertyNode->setRequired();
287 node = qmlPropertyNode;
288 }
else if (elementName == QLatin1String(
"group")) {
289 auto *collectionNode = m_qdb->addGroup(name);
290 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
291 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
292 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
293 collectionNode->markSeen();
294 node = collectionNode;
295 }
else if (elementName == QLatin1String(
"module")) {
296 auto *collectionNode = m_qdb->addModule(name);
297 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
298 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
299 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
300 collectionNode->markSeen();
301 node = collectionNode;
302 }
else if (elementName == QLatin1String(
"qmlmodule")) {
303 auto *collectionNode = m_qdb->addQmlModule(name);
304 const QStringList info = QStringList()
306 << QString(attributes.value(QLatin1String(
"qml-module-version")).toString());
307 collectionNode->setLogicalModuleInfo(info);
308 collectionNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
309 collectionNode->setSubtitle(attributes.value(QLatin1String(
"subtitle")).toString());
310 if (attributes.value(QLatin1String(
"seen")) == QLatin1String(
"true"))
311 collectionNode->markSeen();
312 node = collectionNode;
313 }
else if (elementName == QLatin1String(
"page")) {
315 QString attr = attributes.value(QLatin1String(
"subtype")).toString();
316 if (attr == QLatin1String(
"attribution")) {
318 }
else if (attr == QLatin1String(
"example")) {
320 }
else if (attr == QLatin1String(
"file")) {
322 }
else if (attr == QLatin1String(
"image")) {
324 }
else if (attr == QLatin1String(
"page")) {
326 }
else if (attr == QLatin1String(
"externalpage")) {
332 auto *exampleNode =
static_cast<
ExampleNode *>(current);
334 exampleNode->appendFile(name);
337 exampleNode->appendImage(name);
347 pageNode =
new PageNode(parent, name);
351 pageNode->setTitle(attributes.value(QLatin1String(
"title")).toString());
353 if (attributes.hasAttribute(QLatin1String(
"location")))
354 name = attributes.value(QLatin1String(
"location")).toString();
356 if (!indexUrl.isEmpty())
357 location
= Location(indexUrl + QLatin1Char(
'/') + name);
358 else if (!indexUrl.isNull())
363 }
else if (elementName == QLatin1String(
"enum")) {
364 auto *enumNode =
new EnumNode(parent, name, attributes.hasAttribute(
"scoped"));
366 if (!indexUrl.isEmpty())
367 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
368 else if (!indexUrl.isNull())
369 location
= Location(parent->name().toLower() +
".html");
371 while (reader.readNextStartElement()) {
372 QXmlStreamAttributes childAttributes = reader.attributes();
373 if (reader.name() == QLatin1String(
"value")) {
374 EnumItem item(childAttributes.value(QLatin1String(
"name")).toString(),
375 childAttributes.value(QLatin1String(
"value")).toString(),
376 childAttributes.value(QLatin1String(
"since")).toString()
378 enumNode->addItem(item);
379 }
else if (reader.name() == QLatin1String(
"keyword")) {
381 }
else if (reader.name() == QLatin1String(
"target")) {
384 reader.skipCurrentElement();
389 hasReadChildren =
true;
390 }
else if (elementName == QLatin1String(
"typedef")) {
391 if (attributes.hasAttribute(
"aliasedtype"))
392 node =
new TypeAliasNode(parent, name, attributes.value(QLatin1String(
"aliasedtype")).toString());
396 if (!indexUrl.isEmpty())
397 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
398 else if (!indexUrl.isNull())
399 location
= Location(parent->name().toLower() +
".html");
400 }
else if (elementName == QLatin1String(
"property")) {
403 if (attributes.value(QLatin1String(
"bindable")) == QLatin1String(
"true"))
406 propNode->setWritable(attributes.value(QLatin1String(
"writable")) != QLatin1String(
"false"));
408 if (!indexUrl.isEmpty())
409 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
410 else if (!indexUrl.isNull())
411 location
= Location(parent->name().toLower() +
".html");
413 }
else if (elementName == QLatin1String(
"function")) {
414 QString t = attributes.value(QLatin1String(
"meta")).toString();
415 bool attached =
false;
418 metaness = FunctionNode::getMetaness(t);
419 if (attributes.value(QLatin1String(
"attached")) == QLatin1String(
"true"))
421 auto *fn =
new FunctionNode(metaness, parent, name, attached);
423 fn->setReturnType(attributes.value(QLatin1String(
"type")).toString());
425 if (fn->isCppNode()) {
426 fn->setVirtualness(attributes.value(QLatin1String(
"virtual")).toString());
427 fn->setConst(attributes.value(QLatin1String(
"const")) == QLatin1String(
"true"));
428 fn->setStatic(attributes.value(QLatin1String(
"static")) == QLatin1String(
"true"));
429 fn->setFinal(attributes.value(QLatin1String(
"final")) == QLatin1String(
"true"));
430 fn->setOverride(attributes.value(QLatin1String(
"override")) == QLatin1String(
"true"));
432 if (attributes.value(QLatin1String(
"explicit")) == QLatin1String(
"true"))
435 if (attributes.value(QLatin1String(
"constexpr")) == QLatin1String(
"true"))
438 if (attributes.value(QLatin1String(
"noexcept")) == QLatin1String(
"true")) {
439 fn->markNoexcept(attributes.value(
"noexcept_expression").toString());
442 qsizetype refness = attributes.value(QLatin1String(
"refness")).toUInt();
445 else if (refness == 2)
448
449
450
451
452
453 if (attributes.value(QLatin1String(
"overload")) == QLatin1String(
"true"))
454 fn->setOverloadNumber(attributes.value(QLatin1String(
"overload-number")).toUInt());
456 fn->setOverloadNumber(0);
460
461
462
463
464
465
466 while (reader.readNextStartElement()) {
467 QXmlStreamAttributes childAttributes = reader.attributes();
468 if (reader.name() == QLatin1String(
"parameter")) {
471 QString type = childAttributes.value(QLatin1String(
"type")).toString();
472 QString name = childAttributes.value(QLatin1String(
"name")).toString();
473 fn->parameters().append(type, name);
474 }
else if (reader.name() == QLatin1String(
"keyword")) {
476 }
else if (reader.name() == QLatin1String(
"target")) {
479 reader.skipCurrentElement();
483 if (!indexUrl.isEmpty())
484 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
485 else if (!indexUrl.isNull())
486 location
= Location(parent->name().toLower() +
".html");
488 hasReadChildren =
true;
489 }
else if (elementName == QLatin1String(
"variable")) {
491 if (!indexUrl.isEmpty())
492 location
= Location(indexUrl + QLatin1Char(
'/') + parent->name().toLower() +
".html");
493 else if (!indexUrl.isNull())
494 location
= Location(parent->name().toLower() +
".html");
495 }
else if (elementName == QLatin1String(
"keyword")) {
498 }
else if (elementName == QLatin1String(
"target")) {
501 }
else if (elementName == QLatin1String(
"contents")) {
504 }
else if (elementName == QLatin1String(
"proxy")) {
506 if (!indexUrl.isEmpty())
507 location
= Location(indexUrl + QLatin1Char(
'/') + name.toLower() +
".html");
508 else if (!indexUrl.isNull())
509 location
= Location(name.toLower() +
".html");
515 if (!href.isEmpty()) {
519 node->setUrl(indexUrl + QLatin1Char(
'/') + href);
522 const QString access = attributes.value(QLatin1String(
"access")).toString();
523 if (access ==
"protected")
525 else if ((access ==
"private") || (access ==
"internal"))
530 if (attributes.hasAttribute(QLatin1String(
"related"))) {
532 m_relatedNodes << node;
535 if (attributes.hasAttribute(QLatin1String(
"threadsafety"))) {
536 QString threadSafety = attributes.value(QLatin1String(
"threadsafety")).toString();
537 if (threadSafety == QLatin1String(
"non-reentrant"))
539 else if (threadSafety == QLatin1String(
"reentrant"))
541 else if (threadSafety == QLatin1String(
"thread safe"))
548 const QString category = attributes.value(QLatin1String(
"comparison_category")).toString();
551 QString status = attributes.value(QLatin1String(
"status")).toString();
553 if (status == QLatin1String(
"obsolete") || status == QLatin1String(
"deprecated"))
555 else if (status == QLatin1String(
"preliminary"))
557 else if (status == QLatin1String(
"internal"))
559 else if (status == QLatin1String(
"ignored"))
564 QString physicalModuleName = attributes.value(QLatin1String(
"module")).toString();
565 if (!physicalModuleName.isEmpty())
566 m_qdb->addToModule(physicalModuleName, node);
568 QString since = attributes.value(QLatin1String(
"since")).toString();
569 if (!since.isEmpty()) {
570 node->setSince(since);
573 if (attributes.hasAttribute(QLatin1String(
"documented"))) {
574 if (attributes.value(QLatin1String(
"documented")) == QLatin1String(
"true"))
578 QString groupsAttr = attributes.value(QLatin1String(
"groups")).toString();
579 if (!groupsAttr.isEmpty()) {
580 const QStringList groupNames = groupsAttr.split(QLatin1Char(
','));
581 for (
const auto &group : groupNames) {
582 m_qdb->addToGroup(group, node);
587 QSet<QString> emptySet;
589 if (!filePath.isEmpty()) {
594 Doc doc(location, location, QString(), emptySet, emptySet);
597 QString briefAttr = attributes.value(QLatin1String(
"brief")).toString();
598 if (!briefAttr.isEmpty()) {
599 node->setReconstitutedBrief(briefAttr);
602 if (
const auto sortKey = attributes.value(QLatin1String(
"sortkey")).toString(); !sortKey.isEmpty()) {
605 metaMap->insert(
"sortkey", sortKey);
607 if (!hasReadChildren) {
608 bool useParent = (elementName == QLatin1String(
"namespace") && name.isEmpty());
609 while (reader.readNextStartElement()) {
611 readIndexSection(reader, parent, indexUrl);
613 readIndexSection(reader, node, indexUrl);
619 while (!reader.isEndElement()) {
620 if (reader.readNext() == QXmlStreamReader::Invalid) {
627 const QXmlStreamAttributes &attributes,
Node *node)
644 QString name = attributes.value(QLatin1String(
"name")).toString();
645 QString title = attributes.value(QLatin1String(
"title")).toString();
646 m_qdb->insertTarget(name, title, type, node, priority);
650
651
652
653
654
655
656
657
658
659
660
661
662
665 for (
const auto &pair : std::as_const(m_basesList)) {
666 const QStringList bases = pair.second.split(QLatin1Char(
','));
667 for (
const auto &base : bases) {
668 QStringList basePath = base.split(QString(
"::"));
669 Node *n = m_qdb->findClassNode(basePath);
671 pair.first->addResolvedBaseClass(Access::Public,
static_cast<ClassNode *>(n));
673 pair.first->addUnresolvedBaseClass(Access::Public, basePath);
685 return QLatin1String(
"public");
686 case Access::Protected:
687 return QLatin1String(
"protected");
688 case Access::Private:
689 return QLatin1String(
"private");
693 return QLatin1String(
"public");
700 return QLatin1String(
"deprecated");
702 return QLatin1String(
"preliminary");
704 return QLatin1String(
"active");
706 return QLatin1String(
"internal");
708 return QLatin1String(
"ignored");
712 return QLatin1String(
"active");
719 return QLatin1String(
"non-reentrant");
721 return QLatin1String(
"reentrant");
723 return QLatin1String(
"thread safe");
728 return QLatin1String(
"unspecified");
732
733
736 qsizetype i = m_relatedNodes.indexOf(node);
738 i = m_relatedNodes.size();
739 m_relatedNodes << node;
745
746
747
750 Node *related = m_relatedNodes.value(index);
752 if (adoptiveParent && related) {
761
762
763
764
765
769 for (
const Atom *target : std::as_const(node->doc().targets())) {
770 const QString &title = target->string();
771 const QString &name{Utilities::asAsciiPrintable(title)};
772 writer.writeStartElement(
"target");
773 writer.writeAttribute(
"name", node->isExternalPage() ? title : name);
775 writer.writeAttribute(
"title", title);
776 writer.writeEndElement();
780 for (
const Atom *keyword : std::as_const(node->doc().keywords())) {
781 const QString &title = keyword->string();
782 const QString &name{Utilities::asAsciiPrintable(title)};
783 writer.writeStartElement(
"keyword");
784 writer.writeAttribute(
"name", name);
786 writer.writeAttribute(
"title", title);
787 writer.writeEndElement();
793
794
795
796
797
798
802 if (m_gen ==
nullptr)
809
810
815 QString logicalModuleName;
816 QString logicalModuleVersion;
817 QString qmlFullBaseName;
818 QString baseNameAttr;
819 QString moduleNameAttr;
820 QString moduleVerAttr;
824 nodeName =
"namespace";
841 logicalModuleName = node->logicalModuleName();
842 baseNameAttr =
"qml-base-type";
843 moduleNameAttr =
"qml-module-name";
844 moduleVerAttr =
"qml-module-version";
845 qmlFullBaseName = node->qmlFullBaseName();
859 nodeName =
"qmlmodule";
860 moduleNameAttr =
"qml-module-name";
861 moduleVerAttr =
"qml-module-version";
862 logicalModuleName = node->logicalModuleName();
863 logicalModuleVersion = node->logicalModuleVersion();
870 nodeName =
"typedef";
873 nodeName =
"property";
876 nodeName =
"variable";
882 nodeName =
"qmlproperty";
885 nodeName =
"qmlproperty";
895 QString objName = node->name();
900 writer.writeStartElement(nodeName);
903 if (node->threadSafeness() != Node::UnspecifiedSafeness)
904 writer.writeAttribute(
"threadsafety", getThreadSafenessString(node->threadSafeness()));
907 writer.writeAttribute(
"name", objName);
910 if (!moduleNameAttr.isEmpty()) {
911 if (!logicalModuleName.isEmpty())
912 writer.writeAttribute(moduleNameAttr, logicalModuleName);
913 if (!logicalModuleVersion.isEmpty())
914 writer.writeAttribute(moduleVerAttr, logicalModuleVersion);
916 if (!baseNameAttr.isEmpty() && !qmlFullBaseName.isEmpty())
917 writer.writeAttribute(baseNameAttr, qmlFullBaseName);
921 QString fullName = node->fullDocumentName();
922 if (fullName != objName)
923 writer.writeAttribute(
"fullname", fullName);
924 href = m_gen->fullDocumentLocation(node);
933 writer.writeAttribute(
"href", href);
935 writer.writeAttribute(
"status", getStatusString(node->status()));
937 writer.writeAttribute(
"access", getAccessString(node->access()));
939 writer.writeAttribute(
"abstract",
"true");
942 if (!declLocation.fileName().isEmpty())
943 writer.writeAttribute(
"location", declLocation.fileName());
944 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
945 writer.writeAttribute(
"filepath", declLocation.filePath());
946 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
949 if (node->isRelatedNonmember())
950 writer.writeAttribute(
"related", QString::number(indexForNode(node)));
952 if (!node->since().isEmpty())
953 writer.writeAttribute(
"since", node->since());
956 writer.writeAttribute(
"documented",
"true");
958 QStringList groups = m_qdb->groupNamesForNode(node);
959 if (!groups.isEmpty())
960 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
963 if (
const auto sortKey = metamap->value(
"sortkey"); !sortKey.isEmpty())
964 writer.writeAttribute(
"sortkey", sortKey);
966 QString brief = node->doc().trimmedBriefText(node->name()).toString();
972 const auto *classNode =
static_cast<
const ClassNode *>(node);
973 const QList<RelatedClass> &bases = classNode->baseClasses();
974 QSet<QString> baseStrings;
975 for (
const auto &related : bases) {
976 ClassNode *n = related.m_node;
978 baseStrings.insert(n->fullName());
979 else if (!related.m_path.isEmpty())
980 baseStrings.insert(related.m_path.join(QLatin1String(
"::")));
982 if (!baseStrings.isEmpty()) {
983 QStringList baseStringsAsList = baseStrings.values();
984 baseStringsAsList.sort();
985 writer.writeAttribute(
"bases", baseStringsAsList.join(QLatin1Char(
',')));
987 if (!node->physicalModuleName().isEmpty())
988 writer.writeAttribute(
"module", node->physicalModuleName());
989 if (!brief.isEmpty())
990 writer.writeAttribute(
"brief", brief);
995 const auto *headerNode =
static_cast<
const HeaderNode *>(node);
996 if (!headerNode->physicalModuleName().isEmpty())
997 writer.writeAttribute(
"module", headerNode->physicalModuleName());
998 if (!brief.isEmpty())
999 writer.writeAttribute(
"brief", brief);
1000 writer.writeAttribute(
"title", headerNode->title());
1001 writer.writeAttribute(
"fulltitle", headerNode->fullTitle());
1002 writer.writeAttribute(
"subtitle", headerNode->subtitle());
1005 const auto *namespaceNode =
static_cast<
const NamespaceNode *>(node);
1006 if (!namespaceNode->physicalModuleName().isEmpty())
1007 writer.writeAttribute(
"module", namespaceNode->physicalModuleName());
1008 if (!brief.isEmpty())
1009 writer.writeAttribute(
"brief", brief);
1013 const auto *qmlTypeNode =
static_cast<
const QmlTypeNode *>(node);
1014 writer.writeAttribute(
"title", qmlTypeNode->title());
1015 writer.writeAttribute(
"fulltitle", qmlTypeNode->fullTitle());
1016 writer.writeAttribute(
"subtitle", qmlTypeNode->subtitle());
1017 if (!brief.isEmpty())
1018 writer.writeAttribute(
"brief", brief);
1024 writer.writeAttribute(
"subtype",
"example");
1026 writer.writeAttribute(
"subtype",
"externalpage");
1030 const auto *pageNode =
static_cast<
const PageNode *>(node);
1031 writer.writeAttribute(
"title", pageNode->title());
1032 writer.writeAttribute(
"fulltitle", pageNode->fullTitle());
1033 writer.writeAttribute(
"subtitle", pageNode->subtitle());
1034 if (!brief.isEmpty())
1035 writer.writeAttribute(
"brief", brief);
1040 const auto *collectionNode =
static_cast<
const CollectionNode *>(node);
1041 writer.writeAttribute(
"seen", collectionNode
->wasSeen() ?
"true" :
"false");
1042 writer.writeAttribute(
"title", collectionNode->title());
1043 if (!collectionNode->subtitle().isEmpty())
1044 writer.writeAttribute(
"subtitle", collectionNode->subtitle());
1045 if (!collectionNode->physicalModuleName().isEmpty())
1046 writer.writeAttribute(
"module", collectionNode->physicalModuleName());
1047 if (!brief.isEmpty())
1048 writer.writeAttribute(
"brief", brief);
1052 writer.writeAttribute(
"type", qmlPropertyNode->dataType());
1053 writer.writeAttribute(
"attached", qmlPropertyNode
->isAttached() ?
"true" :
"false");
1054 writer.writeAttribute(
"writable", qmlPropertyNode
->isReadOnly() ?
"false" :
"true");
1056 writer.writeAttribute(
"required",
"true");
1057 if (!brief.isEmpty())
1058 writer.writeAttribute(
"brief", brief);
1061 const auto *propertyNode =
static_cast<
const PropertyNode *>(node);
1064 writer.writeAttribute(
"bindable",
"true");
1067 writer.writeAttribute(
"writable",
"false");
1069 if (!brief.isEmpty())
1070 writer.writeAttribute(
"brief", brief);
1072 for (qsizetype i{0}; i < (qsizetype)PropertyNode::FunctionRole::NumFunctionRoles; ++i) {
1074 for (
const auto *fnNode : propertyNode->functions(role)) {
1075 writer.writeStartElement(PropertyNode::roleName(role));
1076 writer.writeAttribute(
"name", fnNode->name());
1077 writer.writeEndElement();
1082 const auto *variableNode =
static_cast<
const VariableNode *>(node);
1083 writer.writeAttribute(
"type", variableNode->dataType());
1084 writer.writeAttribute(
"static", variableNode
->isStatic() ?
"true" :
"false");
1085 if (!brief.isEmpty())
1086 writer.writeAttribute(
"brief", brief);
1089 const auto *enumNode =
static_cast<
const EnumNode *>(node);
1091 writer.writeAttribute(
"scoped",
"true");
1093 writer.writeAttribute(
"typedef", enumNode
->flagsType()->fullDocumentName());
1094 const auto &items = enumNode->items();
1095 for (
const auto &item : items) {
1096 writer.writeStartElement(
"value");
1097 writer.writeAttribute(
"name", item.name());
1098 writer.writeAttribute(
"value", item.value());
1099 if (!item.since().isEmpty())
1100 writer.writeAttribute(
"since", item.since());
1101 writer.writeEndElement();
1105 const auto *typedefNode =
static_cast<
const TypedefNode *>(node);
1110 writer.writeAttribute(
"aliasedtype",
static_cast<
const TypeAliasNode *>(node)->aliasedType());
1117 writeTargets(writer, node);
1120
1121
1122
1123
1124
1125
1128 for (
int i = 0; i < node
->doc().tableOfContents().size(); ++i) {
1130 int level = node
->doc().tableOfContentsLevels()[i];
1131 QString title = Text::sectionHeading(item).toString();
1132 writer.writeStartElement(
"contents");
1133 writer.writeAttribute(
"name", Tree::refForAtom(item));
1134 writer.writeAttribute(
"title", title);
1135 writer.writeAttribute(
"level", QString::number(level));
1136 writer.writeEndElement();
1142 if (node
->isExample() && m_gen->format() != QLatin1String(
"WebXML")) {
1143 const auto *exampleNode =
static_cast<
const ExampleNode *>(node);
1144 const auto &files = exampleNode->files();
1145 for (
const QString &file : files) {
1146 writer.writeStartElement(
"page");
1147 writer.writeAttribute(
"name", file);
1148 QString href = m_gen->linkForExampleFile(file);
1149 writer.writeAttribute(
"href", href);
1150 writer.writeAttribute(
"status",
"active");
1151 writer.writeAttribute(
"subtype",
"file");
1152 writer.writeAttribute(
"title",
"");
1153 writer.writeAttribute(
"fulltitle", Generator::exampleFileTitle(exampleNode, file));
1154 writer.writeAttribute(
"subtitle", file);
1155 writer.writeEndElement();
1157 const auto &images = exampleNode->images();
1158 for (
const QString &file : images) {
1159 writer.writeStartElement(
"page");
1160 writer.writeAttribute(
"name", file);
1161 QString href = m_gen->linkForExampleFile(file);
1162 writer.writeAttribute(
"href", href);
1163 writer.writeAttribute(
"status",
"active");
1164 writer.writeAttribute(
"subtype",
"image");
1165 writer.writeAttribute(
"title",
"");
1166 writer.writeAttribute(
"fulltitle", Generator::exampleFileTitle(exampleNode, file));
1167 writer.writeAttribute(
"subtitle", file);
1168 writer.writeEndElement();
1180
1181
1182
1185 if (fn->isInternal() && !Config::instance().showInternal())
1188 const QString objName = fn->name();
1189 writer.writeStartElement(
"function");
1190 writer.writeAttribute(
"name", objName);
1192 const QString fullName = fn->fullDocumentName();
1193 if (fullName != objName)
1194 writer.writeAttribute(
"fullname", fullName);
1195 const QString href = m_gen->fullDocumentLocation(fn);
1196 if (!href.isEmpty())
1197 writer.writeAttribute(
"href", href);
1198 if (fn->threadSafeness() != Node::UnspecifiedSafeness)
1199 writer.writeAttribute(
"threadsafety", getThreadSafenessString(fn->threadSafeness()));
1200 writer.writeAttribute(
"status", getStatusString(fn->status()));
1201 writer.writeAttribute(
"access", getAccessString(fn->access()));
1204 if (!declLocation.fileName().isEmpty())
1205 writer.writeAttribute(
"location", declLocation.fileName());
1206 if (m_storeLocationInfo && !declLocation.filePath().isEmpty()) {
1207 writer.writeAttribute(
"filepath", declLocation.filePath());
1208 writer.writeAttribute(
"lineno", QString(
"%1").arg(declLocation
.lineNo()));
1212 writer.writeAttribute(
"documented",
"true");
1213 if (fn->isRelatedNonmember())
1214 writer.writeAttribute(
"related", QString::number(indexForNode(fn)));
1215 if (!fn->since().isEmpty())
1216 writer.writeAttribute(
"since", fn->since());
1218 const QString brief = fn->doc().trimmedBriefText(fn->name()).toString();
1219 writer.writeAttribute(
"meta", fn->metanessString());
1222 writer.writeAttribute(
"virtual", fn->virtualness());
1225 writer.writeAttribute(
"const",
"true");
1227 writer.writeAttribute(
"static",
"true");
1229 writer.writeAttribute(
"final",
"true");
1231 writer.writeAttribute(
"override",
"true");
1233 writer.writeAttribute(
"explicit",
"true");
1235 writer.writeAttribute(
"constexpr",
"true");
1237 if (
auto noexcept_info = fn->getNoexcept()) {
1238 writer.writeAttribute(
"noexcept",
"true");
1239 if (!(*noexcept_info).isEmpty()) writer.writeAttribute(
"noexcept_expression", *noexcept_info);
1243
1244
1245
1246
1247
1249 writer.writeAttribute(
"overload",
"true");
1250 writer.writeAttribute(
"overload-number", QString::number(fn->overloadNumber()));
1253 writer.writeAttribute(
"refness", QString::number(1));
1254 else if (fn->isRefRef())
1255 writer.writeAttribute(
"refness", QString::number(2));
1257 QStringList associatedProperties;
1258 for (
const auto *node : fn->associatedProperties()) {
1259 associatedProperties << node->name();
1261 associatedProperties.sort();
1262 writer.writeAttribute(
"associated-property",
1263 associatedProperties.join(QLatin1Char(
',')));
1267 const auto return_type = fn->returnType();
1268 if (!return_type.isEmpty())
1269 writer.writeAttribute(
"type", return_type);
1272 if (!brief.isEmpty())
1273 writer.writeAttribute(
"brief", brief);
1276
1277
1278
1279
1280 const QString signature = appendAttributesToSignature(fn);
1281 writer.writeAttribute(
"signature", signature);
1283 QStringList groups = m_qdb->groupNamesForNode(fn);
1284 if (!groups.isEmpty())
1285 writer.writeAttribute(
"groups", groups.join(QLatin1Char(
',')));
1290 writer.writeStartElement(
"parameter");
1291 writer.writeAttribute(
"type", parameter.type());
1292 writer.writeAttribute(
"name", parameter.name());
1293 writer.writeAttribute(
"default", parameter.defaultValue());
1294 writer.writeEndElement();
1297 writeTargets(writer, fn);
1303 writer.writeEndElement();
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1319 QString signature = fn->signature(Node::SignatureReturnType);
1322 signature +=
" final";
1324 signature +=
" override";
1326 signature +=
" = 0";
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1344 for (
auto functions : std::as_const(aggregate->functionMap())) {
1345 std::for_each(functions.begin(), functions.end(),
1346 [
this,&writer](FunctionNode *fn) {
1347 generateFunctionSection(writer, fn);
1354
1355
1356
1361
1362
1363
1367 if (node->isInternal() && !Config::instance().showInternal())
1370 if (generateIndexSection(writer, node, post)) {
1372 auto *aggregate =
static_cast<
Aggregate *>(node);
1374 generateFunctionSections(writer, aggregate);
1376 for (
auto *node : nonFunctionList)
1377 generateIndexSections(writer, node, post);
1380 if (node ==
root_) {
1382
1383
1384
1385
1386
1387
1388
1390 if (!groups.isEmpty()) {
1391 for (
auto it = groups.constBegin(); it != groups.constEnd(); ++it) {
1392 if (generateIndexSection(writer, it.value(), post))
1393 writer.writeEndElement();
1398 if (!modules.isEmpty()) {
1399 for (
auto it = modules.constBegin(); it != modules.constEnd(); ++it) {
1400 if (generateIndexSection(writer, it.value(), post))
1401 writer.writeEndElement();
1406 if (!qmlModules.isEmpty()) {
1407 for (
auto it = qmlModules.constBegin(); it != qmlModules.constEnd(); ++it) {
1408 if (generateIndexSection(writer, it.value(), post))
1409 writer.writeEndElement();
1414 writer.writeEndElement();
1419
1420
1421
1422
1423
1424void QDocIndexFiles::generateIndex(
const QString &fileName,
const QString &url,
1427 QFile file(fileName);
1428 if (!file.open(QFile::WriteOnly | QFile::Text))
1431 qCDebug(lcQdoc) <<
"Writing index file:" << fileName;
1434 m_relatedNodes.clear();
1435 QXmlStreamWriter writer(&file);
1436 writer.setAutoFormatting(
true);
1437 writer.writeStartDocument();
1438 writer.writeDTD(
"<!DOCTYPE QDOCINDEX>");
1440 writer.writeStartElement(
"INDEX");
1441 writer.writeAttribute(
"url", url);
1442 writer.writeAttribute(
"title", title);
1443 writer.writeAttribute(
"version", m_qdb->version());
1444 writer.writeAttribute(
"project", Config::instance().get(
CONFIG_PROJECT).asString());
1448 writer.writeAttribute(
"indexTitle",
root_->tree()->indexTitle());
1450 generateIndexSections(writer,
root_,
nullptr);
1452 writer.writeEndElement();
1453 writer.writeEndElement();
1454 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
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 isNonvirtual() const
bool isPureVirtual() const
bool isStatic() const override
Returns true if the FunctionNode represents a static function.
Parameters & parameters()
bool hasAssociatedProperties() const
static Generator * currentGenerator()
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.
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.
NodeType
An unsigned char value that identifies an object as a particular subclass of Node.
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.
virtual bool isPageNode() const
Returns true if this node represents something that generates a documentation page.
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...
NodeType nodeType() const
Returns this node's type.
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)
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.
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.
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...
LinkType
An unsigned char value that probably should be moved out of the Node base class.
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.
A PageNode is a Node that generates a documentation page.
bool isAttribution() const
The Parameter class describes one function parameter.
const Parameter & at(int i) const
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.
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 QString getStatusString(Node::Status t)
static QString getAccessString(Access t)
static IndexSectionWriter * post_
static QString getThreadSafenessString(Node::ThreadSafeness t)
A record of a linkable target within the documentation.
TargetType
A type of a linkable target record.