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