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.data(), 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.reset(new QXmlStreamWriter(&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.data(), 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 Node *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);
151 // generateIndexSections does nothing for groups, so handle them explicitly
152 if (node->isGroup())
153 std::ignore = qdocIndexFiles->generateIndexSection(writer, node, 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
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
397 if (!m_inLink) {
398 QString link = linkForExampleFile(atom->string());
399 if (!link.isEmpty())
400 startLink(writer, atom, relative, link);
401 }
402 } break;
403
405 if (!m_inLink) {
406 QString link = atom->string();
407 if (!link.isEmpty())
408 startLink(writer, atom, nullptr, "images/used-in-examples/" + link);
409 }
410 } break;
411
413 writer.writeStartElement("footnote");
414 break;
415
417 writer.writeEndElement(); // footnote
418 break;
419
421 writer.writeEndElement(); // raw
422 break;
423 case Atom::FormatIf:
424 writer.writeStartElement("raw");
425 writer.writeAttribute("format", atom->string());
426 break;
428 if (atom->string() == ATOM_FORMATTING_BOLD)
429 writer.writeStartElement("bold");
430 else if (atom->string() == ATOM_FORMATTING_ITALIC)
431 writer.writeStartElement("italic");
432 else if (atom->string() == ATOM_FORMATTING_UNDERLINE)
433 writer.writeStartElement("underline");
434 else if (atom->string() == ATOM_FORMATTING_SUBSCRIPT)
435 writer.writeStartElement("subscript");
436 else if (atom->string() == ATOM_FORMATTING_SUPERSCRIPT)
437 writer.writeStartElement("superscript");
438 else if (atom->string() == ATOM_FORMATTING_TELETYPE || atom->string() == ATOM_FORMATTING_NOTRANSLATE)
439 writer.writeStartElement("teletype");
440 else if (atom->string() == ATOM_FORMATTING_PARAMETER)
441 writer.writeStartElement("argument");
442 else if (atom->string() == ATOM_FORMATTING_INDEX)
443 writer.writeStartElement("index");
444 } break;
445
447 if (atom->string() == ATOM_FORMATTING_BOLD)
448 writer.writeEndElement();
449 else if (atom->string() == ATOM_FORMATTING_ITALIC)
450 writer.writeEndElement();
451 else if (atom->string() == ATOM_FORMATTING_UNDERLINE)
452 writer.writeEndElement();
453 else if (atom->string() == ATOM_FORMATTING_SUBSCRIPT)
454 writer.writeEndElement();
455 else if (atom->string() == ATOM_FORMATTING_SUPERSCRIPT)
456 writer.writeEndElement();
457 else if (atom->string() == ATOM_FORMATTING_TELETYPE || atom->string() == ATOM_FORMATTING_NOTRANSLATE)
458 writer.writeEndElement();
459 else if (atom->string() == ATOM_FORMATTING_PARAMETER)
460 writer.writeEndElement();
461 else if (atom->string() == ATOM_FORMATTING_INDEX)
462 writer.writeEndElement();
463 else if (atom->string() == ATOM_FORMATTING_TRADEMARK && appendTrademark(atom))
464 writer.writeCharacters(QChar(0x2122)); // 'TM' symbol
465 }
466 if (m_inLink) {
467 writer.writeEndElement(); // link
468 m_inLink = false;
469 }
470 break;
471
473 writer.writeStartElement("generatedlist");
474 writer.writeAttribute("contents", atom->string());
475 writer.writeEndElement();
476 break;
477
478 // TODO: The other generators treat inlineimage and image
479 // simultaneously as the diffirences aren't big. It should be
480 // possible to do the same for webxmlgenerator instead of
481 // repeating the code.
482
483 // TODO: [generator-insufficient-structural-abstraction]
484 case Atom::Image: {
485 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
486 if (!maybe_resolved_file) {
487 // TODO: [uncentralized-admonition][failed-resolve-file]
488 relative->location().warning(QStringLiteral("Missing image: %1").arg(atom->string()));
489 } else {
490 ResolvedFile file{*maybe_resolved_file};
491 QString file_name{QFileInfo{file.get_path()}.fileName()};
492
493 // TODO: [uncentralized-output-directory-structure]
494 Config::copyFile(relative->doc().location(), file.get_path(), file_name, outputDir() + QLatin1String("/images"));
495
496 writer.writeStartElement("image");
497 // TODO: [uncentralized-output-directory-structure]
498 writer.writeAttribute("href", "images/" + file_name);
499 writer.writeEndElement();
500 // TODO: [uncentralized-output-directory-structure]
501 setImageFileName(relative, "images/" + file_name);
502 }
503 break;
504 }
505 // TODO: [generator-insufficient-structural-abstraction]
506 case Atom::InlineImage: {
507 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
508 if (!maybe_resolved_file) {
509 // TODO: [uncentralized-admonition][failed-resolve-file]
510 relative->location().warning(QStringLiteral("Missing image: %1").arg(atom->string()));
511 } else {
512 ResolvedFile file{*maybe_resolved_file};
513 QString file_name{QFileInfo{file.get_path()}.fileName()};
514
515 // TODO: [uncentralized-output-directory-structure]
516 Config::copyFile(relative->doc().location(), file.get_path(), file_name, outputDir() + QLatin1String("/images"));
517
518 writer.writeStartElement("inlineimage");
519 // TODO: [uncentralized-output-directory-structure]
520 writer.writeAttribute("href", "images/" + file_name);
521 writer.writeEndElement();
522 // TODO: [uncentralized-output-directory-structure]
523 setImageFileName(relative, "images/" + file_name);
524 }
525 break;
526 }
527 case Atom::ImageText:
528 break;
529
531 writer.writeStartElement("para");
532 writer.writeTextElement("bold", "Important:");
533 writer.writeCharacters(" ");
534 break;
535
537 writer.writeStartElement("legalese");
538 break;
539
541 writer.writeEndElement(); // legalese
542 break;
543
544 case Atom::Link:
545 case Atom::LinkNode:
546 if (!m_inLink) {
547 const Node *node = nullptr;
548 QString link = getLink(atom, relative, &node);
549 if (!link.isEmpty())
550 startLink(writer, atom, node, link);
551 }
552 break;
553
554 case Atom::ListLeft:
555 writer.writeStartElement("list");
556
557 if (atom->string() == ATOM_LIST_BULLET)
558 writer.writeAttribute("type", "bullet");
559 else if (atom->string() == ATOM_LIST_TAG)
560 writer.writeAttribute("type", "definition");
561 else if (atom->string() == ATOM_LIST_VALUE) {
562 if (relative->isEnumType())
563 writer.writeAttribute("type", "enum");
564 else
565 writer.writeAttribute("type", "definition");
566 } else {
567 writer.writeAttribute("type", "ordered");
568 if (atom->string() == ATOM_LIST_UPPERALPHA)
569 writer.writeAttribute("start", "A");
570 else if (atom->string() == ATOM_LIST_LOWERALPHA)
571 writer.writeAttribute("start", "a");
572 else if (atom->string() == ATOM_LIST_UPPERROMAN)
573 writer.writeAttribute("start", "I");
574 else if (atom->string() == ATOM_LIST_LOWERROMAN)
575 writer.writeAttribute("start", "i");
576 else // (atom->string() == ATOM_LIST_NUMERIC)
577 writer.writeAttribute("start", "1");
578 }
579 break;
580
582 break;
583 case Atom::ListTagLeft: {
584 writer.writeStartElement("definition");
585
586 writer.writeTextElement(
587 "term", plainCode(marker->markedUpEnumValue(atom->next()->string(), relative)));
588 } break;
589
591 writer.writeEndElement(); // definition
592 break;
593
595 writer.writeStartElement("item");
596 break;
597
599 writer.writeEndElement(); // item
600 break;
601
602 case Atom::ListRight:
603 writer.writeEndElement(); // list
604 break;
605
606 case Atom::NoteLeft:
607 writer.writeStartElement("para");
608 writer.writeTextElement("bold", "Note:");
609 writer.writeCharacters(" ");
610 break;
611
612 // End admonition elements
614 case Atom::NoteRight:
616 writer.writeEndElement(); // para
617 break;
618
619 case Atom::Nop:
620 break;
621
623 case Atom::ParaLeft:
624 writer.writeStartElement("para");
625 break;
626
628 case Atom::ParaRight:
629 writer.writeEndElement(); // para
630 break;
631
633 writer.writeStartElement("quote");
634 break;
635
637 writer.writeEndElement(); // quote
638 break;
639
640 case Atom::RawString:
641 writer.writeCharacters(atom->string());
642 break;
643
645 writer.writeStartElement("section");
646 writer.writeAttribute("id",
647 Utilities::asAsciiPrintable(Text::sectionHeading(atom).toString()));
648 break;
649
651 writer.writeEndElement(); // section
652 break;
653
655 writer.writeStartElement("heading");
656 int unit = atom->string().toInt(); // + hOffset(relative)
657 writer.writeAttribute("level", QString::number(unit));
658 m_inSectionHeading = true;
659 } break;
660
662 writer.writeEndElement(); // heading
663 m_inSectionHeading = false;
664 break;
665
668 break;
669
671 if (m_quoting) {
672 writer.writeStartElement(atom->string());
673 }
674 break;
675
677 if (m_quoting) {
678 writer.writeAttribute("identifier", atom->string());
679 writer.writeEndElement();
680 keepQuoting = true;
681 }
682 break;
683
685 if (m_quoting) {
686 const QString &location = atom->string();
687 writer.writeAttribute("location", location);
688 auto maybe_resolved_file{file_resolver.resolve(location)};
689 // const QString resolved = Doc::resolveFile(Location(), location);
690 if (maybe_resolved_file)
691 writer.writeAttribute("path", (*maybe_resolved_file).get_path());
692 else {
693 // TODO: [uncetnralized-admonition][failed-resolve-file]
694 QString details = std::transform_reduce(
695 file_resolver.get_search_directories().cbegin(),
696 file_resolver.get_search_directories().cend(),
697 u"Searched directories:"_s,
698 std::plus(),
699 [](const DirectoryPath &directory_path) -> QString { return u' ' + directory_path.value(); }
700 );
701
702 relative->location().warning(u"Cannot find file to quote from: %1"_s.arg(location), details);
703 }
704 }
705 break;
706
707 case Atom::String:
708 writer.writeCharacters(atom->string());
709 break;
710 case Atom::TableLeft:
711 writer.writeStartElement("table");
712 if (atom->string().contains("%"))
713 writer.writeAttribute("width", atom->string());
714 break;
715
716 case Atom::TableRight:
717 writer.writeEndElement(); // table
718 break;
719
721 writer.writeStartElement("header");
722 break;
723
725 writer.writeEndElement(); // header
726 break;
727
729 writer.writeStartElement("row");
730 break;
731
733 writer.writeEndElement(); // row
734 break;
735
736 case Atom::TableItemLeft: {
737 writer.writeStartElement("item");
738 QStringList spans = atom->string().split(",");
739 if (spans.size() == 2) {
740 if (spans.at(0) != "1")
741 writer.writeAttribute("colspan", spans.at(0).trimmed());
742 if (spans.at(1) != "1")
743 writer.writeAttribute("rowspan", spans.at(1).trimmed());
744 }
745 } break;
747 writer.writeEndElement(); // item
748 break;
749
751 // Skip to the closing \endtoc atom
752 if (const auto *endtoc = atom->find(Atom::TableOfContentsRight))
753 atom = endtoc;
754 break;
755
756 case Atom::Target:
757 writer.writeStartElement("target");
758 writer.writeAttribute("name", Utilities::asAsciiPrintable(atom->string()));
759 writer.writeEndElement();
760 break;
761
763 writer.writeStartElement("para");
764 writer.writeTextElement("bold", "Warning:");
765 writer.writeCharacters(" ");
766 break;
767
770 writer.writeCharacters(atom->typeString());
771 break;
772 default:
773 break;
774 }
775
776 m_hasQuotingInformation = keepQuoting;
777 return atom->next();
778}
779
780void WebXMLGenerator::startLink(QXmlStreamWriter &writer, const Atom *atom, const Node *node,
781 const QString &link)
782{
783 QString fullName = link;
784 if (node)
785 fullName = node->fullName();
786 if (!fullName.isEmpty() && !link.isEmpty()) {
787 writer.writeStartElement("link");
788 if (atom && !atom->string().isEmpty())
789 writer.writeAttribute("raw", atom->string());
790 else
791 writer.writeAttribute("raw", fullName);
792 writer.writeAttribute("href", link);
793 writer.writeAttribute("type", targetType(node));
794 if (node) {
795 switch (node->nodeType()) {
796 case NodeType::Enum:
797 writer.writeAttribute("enum", fullName);
798 break;
799 case NodeType::Example: {
800 const auto *en = static_cast<const ExampleNode *>(node);
801 const QString fileTitle = atom ? exampleFileTitle(en, atom->string()) : QString();
802 if (!fileTitle.isEmpty()) {
803 writer.writeAttribute("page", fileTitle);
804 break;
805 }
806 }
807 Q_FALLTHROUGH();
808 case NodeType::Page:
809 writer.writeAttribute("page", fullName);
810 break;
811 case NodeType::Property: {
812 const auto *propertyNode = static_cast<const PropertyNode *>(node);
813 if (!propertyNode->getters().empty())
814 writer.writeAttribute("getter", propertyNode->getters().at(0)->fullName());
815 } break;
816 default:
817 break;
818 }
819 }
820 m_inLink = true;
821 }
822}
823
824void WebXMLGenerator::endLink(QXmlStreamWriter &writer)
825{
826 if (m_inLink) {
827 writer.writeEndElement(); // link
828 m_inLink = false;
829 }
830}
831
832void WebXMLGenerator::generateRelations(QXmlStreamWriter &writer, const Node *node)
833{
834 if (node && !node->links().empty()) {
835 std::pair<QString, QString> anchorPair;
836 const Node *linkNode;
837
838 for (auto it = node->links().cbegin(); it != node->links().cend(); ++it) {
839
840 linkNode = m_qdb->findNodeForTarget(it.value().first, node);
841
842 if (!linkNode)
843 linkNode = node;
844
845 if (linkNode == node)
846 anchorPair = it.value();
847 else
848 anchorPair = anchorForNode(linkNode);
849
850 writer.writeStartElement("relation");
851 writer.writeAttribute("href", anchorPair.first);
852 writer.writeAttribute("type", targetType(linkNode));
853
854 switch (it.key()) {
855 case Node::StartLink:
856 writer.writeAttribute("meta", "start");
857 break;
858 case Node::NextLink:
859 writer.writeAttribute("meta", "next");
860 break;
861 case Node::PreviousLink:
862 writer.writeAttribute("meta", "previous");
863 break;
864 case Node::ContentsLink:
865 writer.writeAttribute("meta", "contents");
866 break;
867 default:
868 writer.writeAttribute("meta", "");
869 }
870 writer.writeAttribute("description", anchorPair.second);
871 writer.writeEndElement(); // link
872 }
873 }
874}
875
876void WebXMLGenerator::generateAnnotatedList(QXmlStreamWriter &writer, const Node *relative,
877 const NodeMap &nodeMap)
878{
879 generateAnnotatedList(writer, relative, nodeMap.values());
880}
881
882void WebXMLGenerator::generateAnnotatedList(QXmlStreamWriter &writer, const Node *relative,
883 const NodeList &nodeList)
884{
885 writer.writeStartElement("table");
886 writer.writeAttribute("width", "100%");
887
888 for (const auto *node : nodeList) {
889 writer.writeStartElement("row");
890 writer.writeStartElement("item");
891 writer.writeStartElement("para");
892 const QString link = linkForNode(node, relative);
893 startLink(writer, node->doc().body().firstAtom(), node, link);
894 endLink(writer);
895 writer.writeEndElement(); // para
896 writer.writeEndElement(); // item
897
898 writer.writeStartElement("item");
899 writer.writeStartElement("para");
900 writer.writeCharacters(node->doc().briefText().toString());
901 writer.writeEndElement(); // para
902 writer.writeEndElement(); // item
903 writer.writeEndElement(); // row
904 }
905 writer.writeEndElement(); // table
906}
907
909{
910 return Generator::fileBase(node);
911}
912
913QT_END_NAMESPACE
#define ATOM_LIST_BULLET
Definition atom.h:215
#define ATOM_FORMATTING_TELETYPE
Definition atom.h:210
#define ATOM_LIST_LOWERALPHA
Definition atom.h:218
#define ATOM_FORMATTING_UNDERLINE
Definition atom.h:213
#define ATOM_LIST_UPPERALPHA
Definition atom.h:221
#define ATOM_FORMATTING_NOTRANSLATE
Definition atom.h:205
#define ATOM_LIST_TAG
Definition atom.h:216
#define ATOM_LIST_LOWERROMAN
Definition atom.h:219
#define ATOM_FORMATTING_SUBSCRIPT
Definition atom.h:208
#define ATOM_FORMATTING_BOLD
Definition atom.h:201
#define ATOM_FORMATTING_TRADEMARK
Definition atom.h:211
#define ATOM_LIST_VALUE
Definition atom.h:217
#define ATOM_FORMATTING_ITALIC
Definition atom.h:203
#define ATOM_LIST_UPPERROMAN
Definition atom.h:222
#define ATOM_FORMATTING_SUPERSCRIPT
Definition atom.h:209
#define ATOM_FORMATTING_INDEX
Definition atom.h:202
#define ATOM_FORMATTING_PARAMETER
Definition atom.h:206
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:151
@ CaptionLeft
Definition atom.h:29
@ ListTagLeft
Definition atom.h:65
@ TableRight
Definition atom.h:95
@ GeneratedList
Definition atom.h:50
@ BriefRight
Definition atom.h:27
@ CodeQuoteArgument
Definition atom.h:33
@ WarningLeft
Definition atom.h:106
@ TableOfContentsLeft
Definition atom.h:102
@ SidebarLeft
Definition atom.h:85
@ TableHeaderRight
Definition atom.h:97
@ InlineImage
Definition atom.h:56
@ TableRowRight
Definition atom.h:99
@ FootnoteRight
Definition atom.h:44
@ SnippetCommand
Definition atom.h:90
@ TableRowLeft
Definition atom.h:98
@ Nop
Definition atom.h:72
@ WarningRight
Definition atom.h:107
@ LegaleseRight
Definition atom.h:59
@ ListTagRight
Definition atom.h:66
@ CaptionRight
Definition atom.h:30
@ ListItemNumber
Definition atom.h:64
@ CodeBad
Definition atom.h:32
@ RawString
Definition atom.h:80
@ Target
Definition atom.h:104
@ AnnotatedList
Definition atom.h:22
@ SectionRight
Definition atom.h:82
@ SectionHeadingLeft
Definition atom.h:83
@ TableLeft
Definition atom.h:94
@ ListItemRight
Definition atom.h:68
@ Image
Definition atom.h:52
@ TableItemRight
Definition atom.h:101
@ ListItemLeft
Definition atom.h:67
@ ImportantRight
Definition atom.h:55
@ Code
Definition atom.h:31
@ String
Definition atom.h:93
@ ListLeft
Definition atom.h:63
@ CodeQuoteCommand
Definition atom.h:34
@ BriefLeft
Definition atom.h:26
@ ImageText
Definition atom.h:53
@ ExampleFileLink
Definition atom.h:41
@ LegaleseLeft
Definition atom.h:58
@ ListRight
Definition atom.h:69
@ C
Definition atom.h:28
@ ParaRight
Definition atom.h:76
@ FormattingLeft
Definition atom.h:48
@ FormattingRight
Definition atom.h:49
@ SectionHeadingRight
Definition atom.h:84
@ Link
Definition atom.h:61
@ ImportantLeft
Definition atom.h:54
@ FormatEndif
Definition atom.h:46
@ UnhandledFormat
Definition atom.h:105
@ ExampleImageLink
Definition atom.h:42
@ FootnoteLeft
Definition atom.h:43
@ AutoLink
Definition atom.h:23
@ SnippetLocation
Definition atom.h:92
@ TableHeaderLeft
Definition atom.h:96
@ QuotationLeft
Definition atom.h:78
@ SectionLeft
Definition atom.h:81
@ LinkNode
Definition atom.h:62
@ TableItemLeft
Definition atom.h:100
@ NoteRight
Definition atom.h:74
@ QuotationRight
Definition atom.h:79
@ ParaLeft
Definition atom.h:75
@ BaseName
Definition atom.h:24
@ FormatIf
Definition atom.h:47
@ SnippetIdentifier
Definition atom.h:91
@ NoteLeft
Definition atom.h:73
@ SidebarRight
Definition atom.h:86
@ UnknownCommand
Definition atom.h:108
const Atom * next() const
Return the next atom in the atom list.
Definition atom.h:148
A class for holding the members of a collection of doc pages.
bool hasClasses() const override
Returns true if this collection node contains at least one class node.
const NodeList & members() const
bool hasNamespaces() const override
Returns true if this collection node contains at least one namespace node.
NodeMap getMembers(NodeType type) const
Definition doc.h:31
const Location & location() const
Returns the starting location of a qdoc comment.
Definition doc.cpp:90
static void quoteFromFile(const Location &location, Quoter &quoter, ResolvedFile resolved_file)
Definition doc.cpp:421
const Text & body() const
Definition doc.cpp:115
Encapsulate the logic that QDoc uses to find files whose path is provided by the user and that are re...
bool m_quoting
Definition generator.h:223
FileResolver & file_resolver
Definition generator.h:215
QDocDatabase * m_qdb
Definition generator.h:217
bool m_inLink
Definition generator.h:218
static bool appendTrademark(const Atom *atom)
Returns true if a trademark symbol should be appended to the output as determined by atom.
bool m_inSectionHeading
Definition generator.h:220
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
bool noAutoList() const
Returns the value of the no auto-list flag.
Definition pagenode.h:42
This class describes one instance of using the Q_PROPERTY macro.
const NodeList & getters() const
void mergeCollections(CollectionNode *c)
Finds all the collection nodes with the same name and type as c and merges their members into the mem...
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
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 generateExampleFilePage(const Node *en, ResolvedFile file, CodeMarker *marker=nullptr) override
Generate an html file with the contents of a C++ or QML source file.
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 format() override
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 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:389
NodeType
Definition genustypes.h:150
QList< Node * > NodeList
Definition node.h:44
QMap< QString, Node * > NodeMap
Definition node.h:47
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:106
const Doc & doc() const
Returns a reference to the node's Doc data member.
Definition node.h:242
bool isGroup() const
Returns true if the node type is Group.
Definition node.h:111
bool isNamespace() const
Returns true if the node type is Namespace.
Definition node.h:115
bool isHeader() const
Returns true if the node type is HeaderFile.
Definition node.h:112
NodeType nodeType() const override
Returns this node's type.
Definition node.h:89
bool isEnumType() const
Returns true if the node type is Enum.
Definition node.h:100
virtual bool isTextPageNode() const
Returns true if the node is a PageNode but not an Aggregate.
Definition node.h:160
Aggregate * parent() const
Returns the node's parent pointer.
Definition node.h:215
bool isVariable() const
Returns true if the node type is Variable.
Definition node.h:138
virtual bool isDeprecated() const
Returns true if this node's status is Deprecated.
Definition node.h:141
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:143
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.
Definition node.h:238
virtual bool wasSeen() const
Returns the seen flag data member of this node if it is a NamespaceNode or a CollectionNode.
Definition node.h:199
bool isProperty() const
Returns true if the node type is Property.
Definition node.h:119
NodeContext createContext() const
Definition node.cpp:116
bool isModule() const
Returns true if the node type is Module.
Definition node.h:114
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
Definition node.h:150
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
Definition node.h:151
bool isExample() const
Returns true if the node type is Example.
Definition node.h:105
bool isIndexNode() const
Returns true if this node was created from something in an index file.
Definition node.h:113
Represents a file that is reachable by QDoc based on its current configuration.
static CodeMarker * marker_