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