Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
webxmlgenerator.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include "aggregate.h"
8#include "config.h"
10#include "node.h"
11#include "nodecontext.h"
12#include "propertynode.h"
13#include "qdocdatabase.h"
14#include "quoter.h"
16#include "utilities.h"
17#include "textutils.h"
18
19#include <QtCore/qxmlstream.h>
20
22
23using namespace Qt::StringLiterals;
24
25static CodeMarker *marker_ = nullptr;
26
28
33
38
40{
41 return "WebXML";
42}
43
45{
46 // As this is meant to be an intermediate format,
47 // use .html for internal references. The name of
48 // the output file is set separately in
49 // beginSubPage() calls.
50 return "html";
51}
52
53/*!
54 Most of the output is generated by QDocIndexFiles and the append() callback.
55 Some pages produce supplementary output while being generated, and that's
56 handled here.
57*/
58qsizetype WebXMLGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker)
59{
60 if (m_supplement && currentWriter)
61 addAtomElements(*currentWriter, atom, relative, marker);
62 return 0;
63}
64
66{
67 QByteArray data;
68 QXmlStreamWriter writer(&data);
69 writer.setAutoFormatting(true);
70 beginSubPage(aggregate, Generator::fileName(aggregate, "webxml"));
71 writer.writeStartDocument();
72 writer.writeStartElement("WebXML");
73 writer.writeStartElement("document");
74
75 generateIndexSections(writer, aggregate);
76
77 writer.writeEndElement(); // document
78 writer.writeEndElement(); // WebXML
79 writer.writeEndDocument();
80
81 out() << data;
82 endSubPage();
83}
84
86{
87 QByteArray data;
88 currentWriter.emplace(&data);
89 currentWriter->setAutoFormatting(true);
90 beginSubPage(pn, Generator::fileName(pn, "webxml"));
91 currentWriter->writeStartDocument();
92 currentWriter->writeStartElement("WebXML");
93 currentWriter->writeStartElement("document");
94
95 generateIndexSections(*currentWriter, pn);
96
97 currentWriter->writeEndElement(); // document
98 currentWriter->writeEndElement(); // WebXML
99 currentWriter->writeEndDocument();
100
101 out() << data;
102 endSubPage();
103}
104
105void WebXMLGenerator::generateExampleFilePage(const PageNode *en, ResolvedFile resolved_file, CodeMarker* /* marker */)
106{
107 // TODO: [generator-insufficient-structural-abstraction]
108
109 QByteArray data;
110 QXmlStreamWriter writer(&data);
111 writer.setAutoFormatting(true);
112 beginSubPage(en, linkForExampleFile(resolved_file.get_query(), "webxml"));
113 writer.writeStartDocument();
114 writer.writeStartElement("WebXML");
115 writer.writeStartElement("document");
116 writer.writeStartElement("page");
117 writer.writeAttribute("name", resolved_file.get_query());
118 writer.writeAttribute("href", linkForExampleFile(resolved_file.get_query()));
119 const QString title = exampleFileTitle(static_cast<const ExampleNode *>(en), resolved_file.get_query());
120 writer.writeAttribute("title", title);
121 writer.writeAttribute("fulltitle", title);
122 writer.writeAttribute("subtitle", resolved_file.get_query());
123 writer.writeStartElement("description");
124
125 if (Config::instance().get(CONFIG_LOCATIONINFO).asBool()) {
126 writer.writeAttribute("path", resolved_file.get_path());
127 writer.writeAttribute("line", "0");
128 writer.writeAttribute("column", "0");
129 }
130
131 Quoter quoter;
132 Doc::quoteFromFile(en->doc().location(), quoter, std::move(resolved_file));
133 QString code = quoter.quoteTo(en->location(), QString(), QString());
134 writer.writeTextElement("code", trimmedTrailing(code, QString(), QString()));
135
136 writer.writeEndElement(); // description
137 writer.writeEndElement(); // page
138 writer.writeEndElement(); // document
139 writer.writeEndElement(); // WebXML
140 writer.writeEndDocument();
141
142 out() << data;
143 endSubPage();
144}
145
146void WebXMLGenerator::generateIndexSections(QXmlStreamWriter &writer, Node *node)
147{
148 marker_ = CodeMarker::markerForFileName(node->location().filePath());
149 auto qdocIndexFiles = QDocIndexFiles::qdocIndexFiles();
150 if (qdocIndexFiles) {
151 qdocIndexFiles->generateIndexSections(writer, node, this, this);
152 // generateIndexSections returns early for collection nodes (groups,
153 // modules, QML modules, concepts) so their member listings can be
154 // written last in an index file. When rendering a single collection
155 // page, that leaves the document empty, so emit the section explicitly.
156 if (node->isCollectionNode())
157 std::ignore = qdocIndexFiles->generateIndexSection(writer, node, this, this);
158 }
159}
160
161// Handles callbacks from QDocIndexFiles to add documentation to node
162void WebXMLGenerator::append(QXmlStreamWriter &writer, Node *node)
163{
164 Q_ASSERT(marker_);
165
166 // The index walk doesn't visit shared comment nodes; capture the prose here
167 const Doc &effectiveDoc = (node->doc().body().isEmpty() && node->isSharingComment())
169 : node->doc();
170
171 writer.writeStartElement("description");
172 if (Config::instance().get(CONFIG_LOCATIONINFO).asBool()) {
173 writer.writeAttribute("path", effectiveDoc.location().filePath());
174 writer.writeAttribute("line", QString::number(effectiveDoc.location().lineNo()));
175 writer.writeAttribute("column", QString::number(effectiveDoc.location().columnNo()));
176 }
177
178 if (node->isTextPageNode())
179 generateRelations(writer, node);
180
181 if (node->isModule()) {
182 writer.writeStartElement("generatedlist");
183 writer.writeAttribute("contents", "classesbymodule");
184 auto *cnn = static_cast<CollectionNode *>(node);
185
186 if (cnn->hasNamespaces()) {
187 writer.writeStartElement("section");
188 writer.writeStartElement("heading");
189 writer.writeAttribute("level", "1");
190 writer.writeCharacters("Namespaces");
191 writer.writeEndElement(); // heading
192 NodeMap namespaces{cnn->getMembers(NodeType::Namespace)};
193 generateAnnotatedList(writer, node, namespaces);
194 writer.writeEndElement(); // section
195 }
196 if (cnn->hasClasses()) {
197 writer.writeStartElement("section");
198 writer.writeStartElement("heading");
199 writer.writeAttribute("level", "1");
200 writer.writeCharacters("Classes");
201 writer.writeEndElement(); // heading
202 NodeMap classes{cnn->getMembers([](const Node *n){ return n->isClassNode(); })};
203 generateAnnotatedList(writer, node, classes);
204 writer.writeEndElement(); // section
205 }
206 writer.writeEndElement(); // generatedlist
207 }
208
209 m_inLink = m_inSectionHeading = m_hasQuotingInformation = false;
210
211 const Atom *atom = effectiveDoc.body().firstAtom();
212 while (atom)
213 atom = addAtomElements(writer, atom, node, marker_);
214
215 QList<Text> alsoList = effectiveDoc.alsoList();
216 supplementAlsoList(node, alsoList);
217
218 if (!alsoList.isEmpty()) {
219 writer.writeStartElement("see-also");
220 for (const auto &item : alsoList) {
221 const auto *atom = item.firstAtom();
222 while (atom)
223 atom = addAtomElements(writer, atom, node, marker_);
224 }
225 writer.writeEndElement(); // see-also
226 }
227
228 if (node->isExample()) {
229 m_supplement = true;
231 m_supplement = false;
232 } else if (node->isGroup()) {
233 auto *cn = static_cast<CollectionNode *>(node);
234 if (!cn->noAutoList())
235 generateAnnotatedList(writer, node, cn->members());
236 }
237
238 writer.writeEndElement(); // description
239}
240
242{
243 // Don't generate nodes that are already processed, or if they're not supposed to
244 // generate output, ie. external, index or images nodes.
245 if (!node->url().isNull() || node->isExternalPage() || node->isIndexNode())
246 return;
247
248 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
249 const NodeContext context = node->createContext();
250 if (!InclusionFilter::isIncluded(policy, context))
251 return;
252
253 if (node->parent()) {
254 if (node->isNamespace() || node->isClassNode() || node->isHeader())
255 generateCppReferencePage(static_cast<Aggregate *>(node), nullptr);
256 else if (node->isCollectionNode()) {
257 if (node->wasSeen()) {
258 // see remarks in base class impl.
259 m_qdb->mergeCollections(static_cast<CollectionNode *>(node));
260 generatePageNode(static_cast<PageNode *>(node), nullptr);
261 }
262 } else if (node->isTextPageNode())
263 generatePageNode(static_cast<PageNode *>(node), nullptr);
264 // else if TODO: anything else?
265 }
266
267 if (node->isAggregate()) {
268 auto *aggregate = static_cast<Aggregate *>(node);
269 for (auto c : aggregate->childNodes()) {
270 if ((c->isAggregate() || c->isTextPageNode() || c->isCollectionNode())
271 && !c->isPrivate())
272 generateDocumentation(c);
273 }
274 }
275}
276
277const Atom *WebXMLGenerator::addAtomElements(QXmlStreamWriter &writer, const Atom *atom,
278 const Node *relative, CodeMarker *marker)
279{
280 bool keepQuoting = false;
281
282 if (!atom)
283 return nullptr;
284
285 switch (atom->type()) {
286 case Atom::AnnotatedList: {
287 const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group);
288 if (cn)
289 generateAnnotatedList(writer, relative, cn->members());
290 } break;
291 case Atom::AutoLink: {
292 const Node *node{nullptr};
293 QString link{};
294
295 if (!m_inLink && !m_inSectionHeading) {
296 link = getAutoLink(atom, relative, &node, Genus::API);
297
298 if (!link.isEmpty() && node && node->isDeprecated()
299 && relative->parent() != node && !relative->isDeprecated()) {
300 link.clear();
301 }
302 }
303
304 startLink(writer, atom, node, link);
305
306 writer.writeCharacters(atom->string());
307
308 if (m_inLink) {
309 writer.writeEndElement(); // link
310 m_inLink = false;
311 }
312
313 break;
314 }
315 case Atom::BaseName:
316 break;
317 case Atom::BriefLeft:
318
319 writer.writeStartElement("brief");
320 switch (relative->nodeType()) {
322 writer.writeCharacters("This property");
323 break;
325 writer.writeCharacters("This variable");
326 break;
327 default:
328 break;
329 }
330 if (relative->isProperty() || relative->isVariable()) {
331 QString str;
332 const Atom *a = atom->next();
333 while (a != nullptr && a->type() != Atom::BriefRight) {
335 str += a->string();
336 a = a->next();
337 }
338 str[0] = str[0].toLower();
339 if (str.endsWith('.'))
340 str.chop(1);
341
342 const QList<QStringView> words = QStringView{str}.split(' ');
343 if (!words.isEmpty()) {
344 QStringView first(words.at(0));
345 if (!(first == u"contains" || first == u"specifies" || first == u"describes"
346 || first == u"defines" || first == u"holds" || first == u"determines"))
347 writer.writeCharacters(" holds ");
348 else
349 writer.writeCharacters(" ");
350 }
351 }
352 break;
353
354 case Atom::BriefRight:
355 if (relative->isProperty() || relative->isVariable())
356 writer.writeCharacters(".");
357
358 writer.writeEndElement(); // brief
359 break;
360
361 case Atom::C:
362 writer.writeStartElement("teletype");
363 if (m_inLink)
364 writer.writeAttribute("type", "normal");
365 else
366 writer.writeAttribute("type", "highlighted");
367
368 writer.writeCharacters(plainCode(atom->string()));
369 writer.writeEndElement(); // teletype
370 break;
371
372 case Atom::Code:
373 if (!m_hasQuotingInformation)
374 writer.writeTextElement(
375 "code", trimmedTrailing(plainCode(atom->string()), QString(), QString()));
376 else
377 keepQuoting = true;
378 break;
379
380 case Atom::CodeBad:
381 writer.writeTextElement("badcode",
382 trimmedTrailing(plainCode(atom->string()), QString(), QString()));
383 break;
384
386 if (m_quoting) {
387 if (quoteCommand == "dots") {
388 writer.writeAttribute("indent", atom->string());
389 writer.writeCharacters("...");
390 } else {
391 writer.writeCharacters(atom->string());
392 }
393 writer.writeEndElement(); // code
394 keepQuoting = true;
395 }
396 break;
397
399 if (m_quoting) {
400 quoteCommand = atom->string();
401 writer.writeStartElement(quoteCommand);
402 }
403 break;
404
405 case Atom::DetailsSummaryLeft: // Ignore/skip \details summary
406 return atom->find(Atom::DetailsSummaryRight, nullptr);
407
409 break;
410
412 if (!m_inLink) {
413 QString link = linkForExampleFile(atom->string());
414 if (!link.isEmpty())
415 startLink(writer, atom, relative, link);
416 }
417 } break;
418
420 if (!m_inLink) {
421 QString link = atom->string();
422 if (!link.isEmpty())
423 startLink(writer, atom, nullptr, "images/used-in-examples/" + link);
424 }
425 } break;
426
428 writer.writeStartElement("footnote");
429 break;
430
432 writer.writeEndElement(); // footnote
433 break;
434
436 writer.writeEndElement(); // raw
437 break;
438 case Atom::FormatIf:
439 writer.writeStartElement("raw");
440 writer.writeAttribute("format", atom->string());
441 break;
443 if (atom->string() == ATOM_FORMATTING_BOLD)
444 writer.writeStartElement("bold");
445 else if (atom->string() == ATOM_FORMATTING_ITALIC)
446 writer.writeStartElement("italic");
447 else if (atom->string() == ATOM_FORMATTING_UNDERLINE)
448 writer.writeStartElement("underline");
449 else if (atom->string() == ATOM_FORMATTING_SUBSCRIPT)
450 writer.writeStartElement("subscript");
451 else if (atom->string() == ATOM_FORMATTING_SUPERSCRIPT)
452 writer.writeStartElement("superscript");
453 else if (atom->string() == ATOM_FORMATTING_TELETYPE || atom->string() == ATOM_FORMATTING_NOTRANSLATE)
454 writer.writeStartElement("teletype");
455 else if (atom->string() == ATOM_FORMATTING_PARAMETER)
456 writer.writeStartElement("argument");
457 else if (atom->string() == ATOM_FORMATTING_INDEX)
458 writer.writeStartElement("index");
459 } break;
460
462 if (atom->string() == ATOM_FORMATTING_BOLD)
463 writer.writeEndElement();
464 else if (atom->string() == ATOM_FORMATTING_ITALIC)
465 writer.writeEndElement();
466 else if (atom->string() == ATOM_FORMATTING_UNDERLINE)
467 writer.writeEndElement();
468 else if (atom->string() == ATOM_FORMATTING_SUBSCRIPT)
469 writer.writeEndElement();
470 else if (atom->string() == ATOM_FORMATTING_SUPERSCRIPT)
471 writer.writeEndElement();
472 else if (atom->string() == ATOM_FORMATTING_TELETYPE || atom->string() == ATOM_FORMATTING_NOTRANSLATE)
473 writer.writeEndElement();
474 else if (atom->string() == ATOM_FORMATTING_PARAMETER)
475 writer.writeEndElement();
476 else if (atom->string() == ATOM_FORMATTING_INDEX)
477 writer.writeEndElement();
478 else if (atom->string() == ATOM_FORMATTING_TRADEMARK && appendTrademark(atom))
479 writer.writeCharacters(QChar(0x2122)); // 'TM' symbol
480 }
481 if (m_inLink) {
482 writer.writeEndElement(); // link
483 m_inLink = false;
484 }
485 break;
486
488 writer.writeStartElement("generatedlist");
489 writer.writeAttribute("contents", atom->string());
490 writer.writeEndElement();
491 break;
492
493 // TODO: The other generators treat inlineimage and image
494 // simultaneously as the diffirences aren't big. It should be
495 // possible to do the same for webxmlgenerator instead of
496 // repeating the code.
497
498 // TODO: [generator-insufficient-structural-abstraction]
499 case Atom::Image:
500 case Atom::InlineImage: {
501 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
502 if (!maybe_resolved_file) {
503 // TODO: [uncentralized-admonition][failed-resolve-file]
504 relative->location().warning(QStringLiteral("Missing image: %1").arg(atom->string()));
505 } else {
506 ResolvedFile file{*maybe_resolved_file};
507 QString file_name{QFileInfo{file.get_path()}.fileName()};
508
509 // TODO: [uncentralized-output-directory-structure]
510 Config::copyFile(relative->doc().location(), file.get_path(), file_name,
511 "%1/%2"_L1.arg(outputDir(), imagesOutputDir()));
512
513 writer.writeStartElement(atom->typeString().toLower());
514 const auto &imgPath = "%1/%2"_L1.arg(imagesOutputDir(), file_name);
515 // TODO: [uncentralized-output-directory-structure]
516 writer.writeAttribute("href", imgPath);
517 writer.writeEndElement();
518 // TODO: [uncentralized-output-directory-structure]
519 setImageFileName(relative, imgPath);
520 }
521 break;
522 }
523 case Atom::ImageText:
524 break;
525
527 writer.writeStartElement("para");
528 writer.writeTextElement("bold", "Important:");
529 writer.writeCharacters(" ");
530 break;
531
533 writer.writeStartElement("legalese");
534 break;
535
537 writer.writeEndElement(); // legalese
538 break;
539
540 case Atom::Link:
541 case Atom::LinkNode:
542 if (!m_inLink) {
543 const Node *node = nullptr;
544 QString link = getLink(atom, relative, &node);
545 if (!link.isEmpty())
546 startLink(writer, atom, node, link);
547 }
548 break;
549
550 case Atom::ListLeft:
551 writer.writeStartElement("list");
552
553 if (atom->string() == ATOM_LIST_BULLET)
554 writer.writeAttribute("type", "bullet");
555 else if (atom->string() == ATOM_LIST_TAG)
556 writer.writeAttribute("type", "definition");
557 else if (atom->string() == ATOM_LIST_VALUE) {
558 if (relative->isEnumType())
559 writer.writeAttribute("type", "enum");
560 else
561 writer.writeAttribute("type", "definition");
562 } else {
563 writer.writeAttribute("type", "ordered");
564 if (atom->string() == ATOM_LIST_UPPERALPHA)
565 writer.writeAttribute("start", "A");
566 else if (atom->string() == ATOM_LIST_LOWERALPHA)
567 writer.writeAttribute("start", "a");
568 else if (atom->string() == ATOM_LIST_UPPERROMAN)
569 writer.writeAttribute("start", "I");
570 else if (atom->string() == ATOM_LIST_LOWERROMAN)
571 writer.writeAttribute("start", "i");
572 else if (atom->next() != nullptr) // ATOM_LIST_NUMERIC with explicit start
573 writer.writeAttribute("start", atom->next()->string());
574 else
575 writer.writeAttribute("start", "1");
576 }
577 break;
578
580 break;
581 case Atom::ListTagLeft: {
582 writer.writeStartElement("definition");
583
584 writer.writeTextElement(
585 "term", plainCode(marker->markedUpEnumValue(atom->next()->string(), relative)));
586 } break;
587
589 writer.writeEndElement(); // definition
590 break;
591
593 writer.writeStartElement("item");
594 break;
595
597 writer.writeEndElement(); // item
598 break;
599
600 case Atom::ListRight:
601 writer.writeEndElement(); // list
602 break;
603
604 case Atom::NoteLeft:
605 writer.writeStartElement("para");
606 writer.writeTextElement("bold", "Note:");
607 writer.writeCharacters(" ");
608 break;
609
610 // End admonition elements
612 case Atom::NoteRight:
614 writer.writeEndElement(); // para
615 break;
616
617 case Atom::Nop:
618 break;
619
621 case Atom::ParaLeft:
622 writer.writeStartElement("para");
623 break;
624
626 case Atom::ParaRight:
627 writer.writeEndElement(); // para
628 break;
629
631 writer.writeStartElement("quote");
632 break;
633
635 writer.writeEndElement(); // quote
636 break;
637
638 case Atom::RawString:
639 writer.writeCharacters(atom->string());
640 break;
641
643 writer.writeStartElement("section");
644 writer.writeAttribute("id",
645 TextUtils::asAsciiPrintable(Text::sectionHeading(atom).toString()));
646 break;
647
649 writer.writeEndElement(); // section
650 break;
651
653 writer.writeStartElement("heading");
654 int unit = atom->string().toInt(); // + hOffset(relative)
655 writer.writeAttribute("level", QString::number(unit));
656 m_inSectionHeading = true;
657 } break;
658
660 writer.writeEndElement(); // heading
661 m_inSectionHeading = false;
662 break;
663
666 break;
667
669 if (m_quoting) {
670 writer.writeStartElement(atom->string());
671 }
672 break;
673
675 if (m_quoting) {
676 writer.writeAttribute("identifier", atom->string());
677 writer.writeEndElement();
678 keepQuoting = true;
679 }
680 break;
681
683 if (m_quoting) {
684 const QString &location = atom->string();
685 writer.writeAttribute("location", location);
686 auto maybe_resolved_file{file_resolver.resolve(location)};
687 // const QString resolved = Doc::resolveFile(Location(), location);
688 if (maybe_resolved_file)
689 writer.writeAttribute("path", (*maybe_resolved_file).get_path());
690 else {
691 // TODO: [uncetnralized-admonition][failed-resolve-file]
692 QString details = std::transform_reduce(
693 file_resolver.get_search_directories().cbegin(),
694 file_resolver.get_search_directories().cend(),
695 u"Searched directories:"_s,
696 std::plus(),
697 [](const DirectoryPath &directory_path) -> QString { return u' ' + directory_path.value(); }
698 );
699
700 relative->location().warning(u"Cannot find file to quote from: %1"_s.arg(location), details);
701 }
702 }
703 break;
704
705 case Atom::String:
706 writer.writeCharacters(atom->string());
707 break;
708 case Atom::TableLeft:
709 writer.writeStartElement("table");
710 if (atom->string().contains("%"))
711 writer.writeAttribute("width", atom->string());
712 break;
713
714 case Atom::TableRight:
715 writer.writeEndElement(); // table
716 break;
717
719 writer.writeStartElement("header");
720 break;
721
723 writer.writeEndElement(); // header
724 break;
725
727 writer.writeStartElement("row");
728 break;
729
731 writer.writeEndElement(); // row
732 break;
733
734 case Atom::TableItemLeft: {
735 writer.writeStartElement("item");
736 QStringList spans = atom->string().split(",");
737 if (spans.size() == 2) {
738 if (spans.at(0) != "1")
739 writer.writeAttribute("colspan", spans.at(0).trimmed());
740 if (spans.at(1) != "1")
741 writer.writeAttribute("rowspan", spans.at(1).trimmed());
742 }
743 } break;
745 writer.writeEndElement(); // item
746 break;
747
749 // Skip to the closing \endtoc atom
750 if (const auto *endtoc = atom->find(Atom::TableOfContentsRight))
751 atom = endtoc;
752 break;
753
754 case Atom::Target:
755 writer.writeStartElement("target");
756 writer.writeAttribute("name", TextUtils::asAsciiPrintable(atom->string()));
757 writer.writeEndElement();
758 break;
759
761 writer.writeStartElement("para");
762 writer.writeTextElement("bold", "Warning:");
763 writer.writeCharacters(" ");
764 break;
765
768 writer.writeCharacters(atom->typeString());
769 break;
770 default:
771 break;
772 }
773
774 m_hasQuotingInformation = keepQuoting;
775 return atom->next();
776}
777
778void WebXMLGenerator::startLink(QXmlStreamWriter &writer, const Atom *atom, const Node *node,
779 const QString &link)
780{
781 QString fullName = link;
782 if (node)
783 fullName = node->fullName();
784 if (!fullName.isEmpty() && !link.isEmpty()) {
785 writer.writeStartElement("link");
786 if (atom && !atom->string().isEmpty())
787 writer.writeAttribute("raw", atom->string());
788 else
789 writer.writeAttribute("raw", fullName);
790 writer.writeAttribute("href", link);
791 writer.writeAttribute("type", targetType(node));
792 if (node) {
793 switch (node->nodeType()) {
794 case NodeType::Enum:
795 writer.writeAttribute("enum", fullName);
796 break;
797 case NodeType::Example: {
798 const auto *en = static_cast<const ExampleNode *>(node);
799 const QString fileTitle = atom ? exampleFileTitle(en, atom->string()) : QString();
800 if (!fileTitle.isEmpty()) {
801 writer.writeAttribute("page", fileTitle);
802 break;
803 }
804 }
805 Q_FALLTHROUGH();
806 case NodeType::Page:
807 writer.writeAttribute("page", fullName);
808 break;
809 case NodeType::Property: {
810 const auto *propertyNode = static_cast<const PropertyNode *>(node);
811 if (!propertyNode->getters().empty())
812 writer.writeAttribute("getter", propertyNode->getters().at(0)->fullName());
813 } break;
814 default:
815 break;
816 }
817 }
818 m_inLink = true;
819 }
820}
821
822void WebXMLGenerator::endLink(QXmlStreamWriter &writer)
823{
824 if (m_inLink) {
825 writer.writeEndElement(); // link
826 m_inLink = false;
827 }
828}
829
830void WebXMLGenerator::generateRelations(QXmlStreamWriter &writer, const Node *node)
831{
832 if (node && !node->links().empty()) {
833 std::pair<QString, QString> anchorPair;
834 const Node *linkNode;
835
836 for (auto it = node->links().cbegin(); it != node->links().cend(); ++it) {
837
838 linkNode = m_qdb->findNodeForTarget(it.value().first, node);
839
840 if (!linkNode)
841 linkNode = node;
842
843 if (linkNode == node)
844 anchorPair = it.value();
845 else
846 anchorPair = anchorForNode(linkNode);
847
848 writer.writeStartElement("relation");
849 writer.writeAttribute("href", anchorPair.first);
850 writer.writeAttribute("type", targetType(linkNode));
851
852 switch (it.key()) {
853 case Node::StartLink:
854 writer.writeAttribute("meta", "start");
855 break;
856 case Node::NextLink:
857 writer.writeAttribute("meta", "next");
858 break;
859 case Node::PreviousLink:
860 writer.writeAttribute("meta", "previous");
861 break;
862 case Node::ContentsLink:
863 writer.writeAttribute("meta", "contents");
864 break;
865 default:
866 writer.writeAttribute("meta", "");
867 }
868 writer.writeAttribute("description", anchorPair.second);
869 writer.writeEndElement(); // link
870 }
871 }
872}
873
874void WebXMLGenerator::generateAnnotatedList(QXmlStreamWriter &writer, const Node *relative,
875 const NodeMap &nodeMap)
876{
877 generateAnnotatedList(writer, relative, nodeMap.values());
878}
879
880void WebXMLGenerator::generateAnnotatedList(QXmlStreamWriter &writer, const Node *relative,
881 const NodeList &nodeList)
882{
883 writer.writeStartElement("table");
884 writer.writeAttribute("width", "100%");
885
886 for (const auto *node : nodeList) {
887 writer.writeStartElement("row");
888 writer.writeStartElement("item");
889 writer.writeStartElement("para");
890 const QString link = linkForNode(node, relative);
891 startLink(writer, node->doc().body().firstAtom(), node, link);
892 endLink(writer);
893 writer.writeEndElement(); // para
894 writer.writeEndElement(); // item
895
896 writer.writeStartElement("item");
897 writer.writeStartElement("para");
898 writer.writeCharacters(node->doc().briefText().toString());
899 writer.writeEndElement(); // para
900 writer.writeEndElement(); // item
901 writer.writeEndElement(); // row
902 }
903 writer.writeEndElement(); // table
904}
905
907{
908 return Generator::fileBase(node);
909}
910
911QT_END_NAMESPACE
#define ATOM_LIST_BULLET
Definition atom.h:209
#define ATOM_FORMATTING_TELETYPE
Definition atom.h:204
#define ATOM_LIST_LOWERALPHA
Definition atom.h:212
#define ATOM_FORMATTING_UNDERLINE
Definition atom.h:207
#define ATOM_LIST_UPPERALPHA
Definition atom.h:215
#define ATOM_FORMATTING_NOTRANSLATE
Definition atom.h:199
#define ATOM_LIST_TAG
Definition atom.h:210
#define ATOM_LIST_LOWERROMAN
Definition atom.h:213
#define ATOM_FORMATTING_SUBSCRIPT
Definition atom.h:202
#define ATOM_FORMATTING_BOLD
Definition atom.h:195
#define ATOM_FORMATTING_TRADEMARK
Definition atom.h:205
#define ATOM_LIST_VALUE
Definition atom.h:211
#define ATOM_FORMATTING_ITALIC
Definition atom.h:197
#define ATOM_LIST_UPPERROMAN
Definition atom.h:216
#define ATOM_FORMATTING_SUPERSCRIPT
Definition atom.h:203
#define ATOM_FORMATTING_INDEX
Definition atom.h:196
#define ATOM_FORMATTING_PARAMETER
Definition atom.h:200
The Atom class is the fundamental unit for representing documents internally.
Definition atom.h:19
AtomType type() const
Return the type of this atom.
Definition atom.h:144
@ CaptionLeft
Definition atom.h:29
@ ListTagLeft
Definition atom.h:67
@ TableRight
Definition atom.h:97
@ GeneratedList
Definition atom.h:52
@ BriefRight
Definition atom.h:27
@ CodeQuoteArgument
Definition atom.h:33
@ WarningLeft
Definition atom.h:110
@ TableOfContentsLeft
Definition atom.h:104
@ SidebarLeft
Definition atom.h:87
@ TableHeaderRight
Definition atom.h:99
@ InlineImage
Definition atom.h:58
@ TableRowRight
Definition atom.h:101
@ FootnoteRight
Definition atom.h:46
@ SnippetCommand
Definition atom.h:92
@ TableRowLeft
Definition atom.h:100
@ Nop
Definition atom.h:74
@ WarningRight
Definition atom.h:111
@ LegaleseRight
Definition atom.h:61
@ ListTagRight
Definition atom.h:68
@ CaptionRight
Definition atom.h:30
@ ListItemNumber
Definition atom.h:66
@ CodeBad
Definition atom.h:32
@ RawString
Definition atom.h:82
@ Target
Definition atom.h:106
@ AnnotatedList
Definition atom.h:22
@ SectionRight
Definition atom.h:84
@ SectionHeadingLeft
Definition atom.h:85
@ TableLeft
Definition atom.h:96
@ ListItemRight
Definition atom.h:70
@ Image
Definition atom.h:54
@ TableItemRight
Definition atom.h:103
@ ListItemLeft
Definition atom.h:69
@ ImportantRight
Definition atom.h:57
@ Code
Definition atom.h:31
@ String
Definition atom.h:95
@ ListLeft
Definition atom.h:65
@ CodeQuoteCommand
Definition atom.h:34
@ BriefLeft
Definition atom.h:26
@ ImageText
Definition atom.h:55
@ ExampleFileLink
Definition atom.h:43
@ LegaleseLeft
Definition atom.h:60
@ ListRight
Definition atom.h:71
@ C
Definition atom.h:28
@ ParaRight
Definition atom.h:78
@ FormattingLeft
Definition atom.h:50
@ FormattingRight
Definition atom.h:51
@ SectionHeadingRight
Definition atom.h:86
@ Link
Definition atom.h:63
@ ImportantLeft
Definition atom.h:56
@ FormatEndif
Definition atom.h:48
@ UnhandledFormat
Definition atom.h:109
@ ExampleImageLink
Definition atom.h:44
@ FootnoteLeft
Definition atom.h:45
@ AutoLink
Definition atom.h:23
@ SnippetLocation
Definition atom.h:94
@ TableHeaderLeft
Definition atom.h:98
@ QuotationLeft
Definition atom.h:80
@ SectionLeft
Definition atom.h:83
@ LinkNode
Definition atom.h:64
@ TableItemLeft
Definition atom.h:102
@ NoteRight
Definition atom.h:76
@ QuotationRight
Definition atom.h:81
@ ParaLeft
Definition atom.h:77
@ BaseName
Definition atom.h:24
@ FormatIf
Definition atom.h:49
@ SnippetIdentifier
Definition atom.h:93
@ NoteLeft
Definition atom.h:75
@ SidebarRight
Definition atom.h:88
@ UnknownCommand
Definition atom.h:112
@ DetailsSummaryRight
Definition atom.h:40
@ DetailsSummaryLeft
Definition atom.h:39
const Atom * next() const
Return the next atom in the atom list.
Definition atom.h:141
A class for holding the members of a collection of doc pages.
const NodeList & members() const
Definition doc.h:32
const Location & location() const
Returns the starting location of a qdoc comment.
Definition doc.cpp:89
static void quoteFromFile(const Location &location, Quoter &quoter, ResolvedFile resolved_file, CodeMarker *marker=nullptr)
Definition doc.cpp:463
const Text & body() const
Definition doc.cpp:114
Encapsulate the logic that QDoc uses to find files whose path is provided by the user and that are re...
static bool appendTrademark(const Atom *atom)
Returns true if a trademark symbol should be appended to the output as determined by atom.
QTextStream & out()
void endSubPage()
Flush the text stream associated with the subpage, and then pop it off the text stream stack and dele...
void generateRequiredLinks(const Node *node, CodeMarker *marker)
Generates either a link to the project folder for example node, or a list of links files/images if 'u...
HtmlGenerator(FileResolver &file_resolver)
void initializeGenerator() override
Initializes the HTML output generator's data structures from the configuration (Config) singleton.
void terminateGenerator() override
Gracefully terminates the HTML output generator.
static bool isIncluded(const InclusionPolicy &policy, const NodeContext &context)
A PageNode is a Node that generates a documentation page.
Definition pagenode.h:19
This class handles qdoc index files.
Definition text.h:12
static Text sectionHeading(const Atom *sectionBegin)
Definition text.cpp:157
const Atom * firstAtom() const
Definition text.h:33
bool isEmpty() const
Definition text.h:30
QString fileBase(const Node *node) const override
QString format() const override
Returns the format identifier for this producer (e.g., "HTML", "DocBook", "template").
virtual const Atom * addAtomElements(QXmlStreamWriter &writer, const Atom *atom, const Node *relative, CodeMarker *marker)
void terminateGenerator() override
Gracefully terminates the HTML output generator.
void generateDocumentation(Node *node) override
Recursive writing of HTML files from the root node.
void append(QXmlStreamWriter &writer, Node *node) override
virtual void generateIndexSections(QXmlStreamWriter &writer, Node *node)
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.
WebXMLGenerator(FileResolver &file_resolver)
QString fileExtension() const override
Returns "html" for this subclass of Generator.
void initializeGenerator() override
Initializes the HTML output generator's data structures from the configuration (Config) singleton.
void generateExampleFilePage(const PageNode *en, ResolvedFile file, CodeMarker *marker=nullptr) override
Generate an html file with the contents of a C++ or QML source file.
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...
qsizetype generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker) override
Most of the output is generated by QDocIndexFiles and the append() callback.
#define CONFIG_LOCATIONINFO
Definition config.h:421
NodeType
Definition genustypes.h:165
Combined button and popup list for selecting options.
QList< Node * > NodeList
Definition node.h:45
QMap< QString, Node * > NodeMap
Definition node.h:48
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.
Definition node.h:100
const Doc & doc() const
Returns a reference to the node's Doc data member.
Definition node.h:237
bool isGroup() const
Returns true if the node type is Group.
Definition node.h:105
SharedCommentNode * sharedCommentNode()
Definition node.h:250
bool isNamespace() const
Returns true if the node type is Namespace.
Definition node.h:110
bool isHeader() const
Returns true if the node type is HeaderFile.
Definition node.h:106
NodeType nodeType() const override
Returns this node's type.
Definition node.h:82
bool isEnumType() const
Returns true if the node type is Enum.
Definition node.h:94
virtual bool isTextPageNode() const
Returns true if the node is a PageNode but not an Aggregate.
Definition node.h:155
Aggregate * parent() const
Returns the node's parent pointer.
Definition node.h:210
bool isVariable() const
Returns true if the node type is Variable.
Definition node.h:133
virtual bool isDeprecated() const
Returns true if this node's status is Deprecated.
Definition node.h:136
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
Definition node.h:138
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.
Definition node.h:233
virtual bool wasSeen() const
Returns the seen flag data member of this node if it is a NamespaceNode or a CollectionNode.
Definition node.h:194
bool isProperty() const
Returns true if the node type is Property.
Definition node.h:114
NodeContext createContext() const
Definition node.cpp:175
bool isModule() const
Returns true if the node type is Module.
Definition node.h:108
bool isSharingComment() const
This function returns true if the node is sharing a comment with other nodes.
Definition node.h:248
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
Definition node.h:145
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
Definition node.h:146
bool isExample() const
Returns true if the node type is Example.
Definition node.h:99
bool isIndexNode() const
Returns true if this node was created from something in an index file.
Definition node.h:107
Represents a file that is reachable by QDoc based on its current configuration.
static CodeMarker * marker_