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