19#include <QtCore/qxmlstream.h>
23using namespace Qt::StringLiterals;
54
55
56
57
60 if (m_supplement && currentWriter)
68 QXmlStreamWriter writer(&data);
69 writer.setAutoFormatting(
true);
70 beginSubPage(aggregate, Generator::fileName(aggregate,
"webxml"));
71 writer.writeStartDocument();
72 writer.writeStartElement(
"WebXML");
73 writer.writeStartElement(
"document");
77 writer.writeEndElement();
78 writer.writeEndElement();
79 writer.writeEndDocument();
88 currentWriter.emplace(&data);
89 currentWriter->setAutoFormatting(
true);
90 beginSubPage(pn, Generator::fileName(pn,
"webxml"));
91 currentWriter->writeStartDocument();
92 currentWriter->writeStartElement(
"WebXML");
93 currentWriter->writeStartElement(
"document");
97 currentWriter->writeEndElement();
98 currentWriter->writeEndElement();
99 currentWriter->writeEndDocument();
110 QXmlStreamWriter writer(&data);
111 writer.setAutoFormatting(
true);
112 beginSubPage(en, linkForExampleFile(resolved_file.get_query(),
"webxml"));
113 writer.writeStartDocument();
114 writer.writeStartElement(
"WebXML");
115 writer.writeStartElement(
"document");
116 writer.writeStartElement(
"page");
117 writer.writeAttribute(
"name", resolved_file.get_query());
118 writer.writeAttribute(
"href", linkForExampleFile(resolved_file.get_query()));
119 const QString title = exampleFileTitle(
static_cast<
const ExampleNode *>(en), resolved_file.get_query());
120 writer.writeAttribute(
"title", title);
121 writer.writeAttribute(
"fulltitle", title);
122 writer.writeAttribute(
"subtitle", resolved_file.get_query());
123 writer.writeStartElement(
"description");
126 writer.writeAttribute(
"path", resolved_file.get_path());
127 writer.writeAttribute(
"line",
"0");
128 writer.writeAttribute(
"column",
"0");
133 QString code = quoter.quoteTo(en
->location(), QString(), QString());
134 writer.writeTextElement(
"code", trimmedTrailing(code, QString(), QString()));
136 writer.writeEndElement();
137 writer.writeEndElement();
138 writer.writeEndElement();
139 writer.writeEndElement();
140 writer.writeEndDocument();
150 if (qdocIndexFiles) {
151 qdocIndexFiles->generateIndexSections(writer, node,
this,
this);
154 std::ignore = qdocIndexFiles->generateIndexSection(writer, node,
this,
this);
163 writer.writeStartElement(
"description");
166 writer.writeAttribute(
"line", QString::number(node->doc().location().lineNo()));
167 writer.writeAttribute(
"column", QString::number(node->doc().location().columnNo()));
171 generateRelations(writer, node);
174 writer.writeStartElement(
"generatedlist");
175 writer.writeAttribute(
"contents",
"classesbymodule");
176 auto *cnn =
static_cast<CollectionNode *>(node);
178 if (cnn->hasNamespaces()) {
179 writer.writeStartElement(
"section");
180 writer.writeStartElement(
"heading");
181 writer.writeAttribute(
"level",
"1");
182 writer.writeCharacters(
"Namespaces");
183 writer.writeEndElement();
185 generateAnnotatedList(writer, node, namespaces);
186 writer.writeEndElement();
188 if (cnn->hasClasses()) {
189 writer.writeStartElement(
"section");
190 writer.writeStartElement(
"heading");
191 writer.writeAttribute(
"level",
"1");
192 writer.writeCharacters(
"Classes");
193 writer.writeEndElement();
195 generateAnnotatedList(writer, node, classes);
196 writer.writeEndElement();
198 writer.writeEndElement();
201 m_inLink = m_inSectionHeading = m_hasQuotingInformation =
false;
207 QList<Text> alsoList = node
->doc().alsoList();
208 supplementAlsoList(node, alsoList);
210 if (!alsoList.isEmpty()) {
211 writer.writeStartElement(
"see-also");
212 for (
const auto &item : alsoList) {
213 const auto *atom = item.firstAtom();
215 atom = addAtomElements(writer, atom, node, marker_);
217 writer.writeEndElement();
223 m_supplement =
false;
225 auto *cn =
static_cast<CollectionNode *>(node);
226 if (!cn->noAutoList())
227 generateAnnotatedList(writer, node, cn->members());
230 writer.writeEndElement();
240 const InclusionPolicy policy = Config::instance().createInclusionPolicy();
251 m_qdb->mergeCollections(
static_cast<CollectionNode *>(node));
260 auto *aggregate =
static_cast<Aggregate *>(node);
261 for (
auto c : aggregate->childNodes()) {
262 if ((c->isAggregate() || c->isTextPageNode() || c->isCollectionNode())
264 generateDocumentation(c);
272 bool keepQuoting =
false;
279 const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), NodeType::Group);
281 generateAnnotatedList(writer, relative, cn
->members());
284 const Node *node{
nullptr};
287 if (!m_inLink && !m_inSectionHeading) {
288 link = getAutoLink(atom, relative, &node, Genus::API);
296 startLink(writer, atom, node, link);
298 writer.writeCharacters(atom->string());
301 writer.writeEndElement();
311 writer.writeStartElement(
"brief");
314 writer.writeCharacters(
"This property");
317 writer.writeCharacters(
"This variable");
330 str[0] = str[0].toLower();
331 if (str.endsWith(
'.'))
334 const QList<QStringView> words = QStringView{str}.split(
' ');
335 if (!words.isEmpty()) {
336 QStringView first(words.at(0));
337 if (!(first == u"contains" || first == u"specifies" || first == u"describes"
338 || first == u"defines" || first == u"holds" || first == u"determines"))
339 writer.writeCharacters(
" holds ");
341 writer.writeCharacters(
" ");
348 writer.writeCharacters(
".");
350 writer.writeEndElement();
354 writer.writeStartElement(
"teletype");
356 writer.writeAttribute(
"type",
"normal");
358 writer.writeAttribute(
"type",
"highlighted");
360 writer.writeCharacters(plainCode(atom->string()));
361 writer.writeEndElement();
365 if (!m_hasQuotingInformation)
366 writer.writeTextElement(
367 "code", trimmedTrailing(plainCode(atom->string()), QString(), QString()));
373 writer.writeTextElement(
"badcode",
374 trimmedTrailing(plainCode(atom->string()), QString(), QString()));
379 if (quoteCommand ==
"dots") {
380 writer.writeAttribute(
"indent", atom->string());
381 writer.writeCharacters(
"...");
383 writer.writeCharacters(atom->string());
385 writer.writeEndElement();
392 quoteCommand = atom->string();
393 writer.writeStartElement(quoteCommand);
405 QString link = linkForExampleFile(atom->string());
407 startLink(writer, atom, relative, link);
413 QString link = atom->string();
415 startLink(writer, atom,
nullptr,
"images/used-in-examples/" + link);
420 writer.writeStartElement(
"footnote");
424 writer.writeEndElement();
428 writer.writeEndElement();
431 writer.writeStartElement(
"raw");
432 writer.writeAttribute(
"format", atom->string());
436 writer.writeStartElement(
"bold");
438 writer.writeStartElement(
"italic");
440 writer.writeStartElement(
"underline");
442 writer.writeStartElement(
"subscript");
444 writer.writeStartElement(
"superscript");
446 writer.writeStartElement(
"teletype");
448 writer.writeStartElement(
"argument");
450 writer.writeStartElement(
"index");
455 writer.writeEndElement();
457 writer.writeEndElement();
459 writer.writeEndElement();
461 writer.writeEndElement();
463 writer.writeEndElement();
465 writer.writeEndElement();
467 writer.writeEndElement();
469 writer.writeEndElement();
471 writer.writeCharacters(QChar(0x2122));
474 writer.writeEndElement();
480 writer.writeStartElement(
"generatedlist");
481 writer.writeAttribute(
"contents", atom->string());
482 writer.writeEndElement();
493 auto maybe_resolved_file{file_resolver.resolve(atom->string())};
494 if (!maybe_resolved_file) {
496 relative
->location().warning(QStringLiteral(
"Missing image: %1").arg(atom->string()));
499 QString file_name{QFileInfo{file.get_path()}.fileName()};
503 "%1/%2"_L1.arg(outputDir(), imagesOutputDir()));
505 writer.writeStartElement(atom->typeString().toLower());
506 const auto &imgPath =
"%1/%2"_L1.arg(imagesOutputDir(), file_name);
508 writer.writeAttribute(
"href", imgPath);
509 writer.writeEndElement();
511 setImageFileName(relative, imgPath);
519 writer.writeStartElement(
"para");
520 writer.writeTextElement(
"bold",
"Important:");
521 writer.writeCharacters(
" ");
525 writer.writeStartElement(
"legalese");
529 writer.writeEndElement();
535 const Node *node =
nullptr;
536 QString link = getLink(atom, relative, &node);
538 startLink(writer, atom, node, link);
543 writer.writeStartElement(
"list");
546 writer.writeAttribute(
"type",
"bullet");
548 writer.writeAttribute(
"type",
"definition");
551 writer.writeAttribute(
"type",
"enum");
553 writer.writeAttribute(
"type",
"definition");
555 writer.writeAttribute(
"type",
"ordered");
557 writer.writeAttribute(
"start",
"A");
559 writer.writeAttribute(
"start",
"a");
561 writer.writeAttribute(
"start",
"I");
563 writer.writeAttribute(
"start",
"i");
565 writer.writeAttribute(
"start", atom
->next()->string());
567 writer.writeAttribute(
"start",
"1");
574 writer.writeStartElement(
"definition");
576 writer.writeTextElement(
577 "term", plainCode(marker->markedUpEnumValue(atom
->next()->string(), relative)));
581 writer.writeEndElement();
585 writer.writeStartElement(
"item");
589 writer.writeEndElement();
593 writer.writeEndElement();
597 writer.writeStartElement(
"para");
598 writer.writeTextElement(
"bold",
"Note:");
599 writer.writeCharacters(
" ");
606 writer.writeEndElement();
614 writer.writeStartElement(
"para");
619 writer.writeEndElement();
623 writer.writeStartElement(
"quote");
627 writer.writeEndElement();
631 writer.writeCharacters(atom->string());
635 writer.writeStartElement(
"section");
636 writer.writeAttribute(
"id",
641 writer.writeEndElement();
645 writer.writeStartElement(
"heading");
646 int unit = atom->string().toInt();
647 writer.writeAttribute(
"level", QString::number(unit));
648 m_inSectionHeading =
true;
652 writer.writeEndElement();
653 m_inSectionHeading =
false;
662 writer.writeStartElement(atom->string());
668 writer.writeAttribute(
"identifier", atom->string());
669 writer.writeEndElement();
676 const QString &location = atom->string();
677 writer.writeAttribute(
"location", location);
678 auto maybe_resolved_file{file_resolver.resolve(location)};
680 if (maybe_resolved_file)
681 writer.writeAttribute(
"path", (*maybe_resolved_file).get_path());
684 QString details =
std::transform_reduce(
685 file_resolver.get_search_directories().cbegin(),
686 file_resolver.get_search_directories().cend(),
687 u"Searched directories:"_s,
689 [](
const DirectoryPath &directory_path) -> QString {
return u' ' + directory_path.value(); }
692 relative
->location().warning(u"Cannot find file to quote from: %1"_s.arg(location), details);
698 writer.writeCharacters(atom->string());
701 writer.writeStartElement(
"table");
702 if (atom->string().contains(
"%"))
703 writer.writeAttribute(
"width", atom->string());
707 writer.writeEndElement();
711 writer.writeStartElement(
"header");
715 writer.writeEndElement();
719 writer.writeStartElement(
"row");
723 writer.writeEndElement();
727 writer.writeStartElement(
"item");
728 QStringList spans = atom->string().split(
",");
729 if (spans.size() == 2) {
730 if (spans.at(0) !=
"1")
731 writer.writeAttribute(
"colspan", spans.at(0).trimmed());
732 if (spans.at(1) !=
"1")
733 writer.writeAttribute(
"rowspan", spans.at(1).trimmed());
737 writer.writeEndElement();
742 if (
const auto *endtoc = atom->find(Atom::TableOfContentsRight))
747 writer.writeStartElement(
"target");
748 writer.writeAttribute(
"name", TextUtils::asAsciiPrintable(atom->string()));
749 writer.writeEndElement();
753 writer.writeStartElement(
"para");
754 writer.writeTextElement(
"bold",
"Warning:");
755 writer.writeCharacters(
" ");
760 writer.writeCharacters(atom->typeString());
766 m_hasQuotingInformation = keepQuoting;
773 QString fullName = link;
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());
781 writer.writeAttribute(
"raw", fullName);
782 writer.writeAttribute(
"href", link);
783 writer.writeAttribute(
"type", targetType(node));
787 writer.writeAttribute(
"enum", fullName);
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);
799 writer.writeAttribute(
"page", fullName);
802 const auto *propertyNode =
static_cast<
const PropertyNode *>(node);
803 if (!propertyNode->getters().empty())
804 writer.writeAttribute(
"getter", propertyNode->getters().at(0)->fullName());
817 writer.writeEndElement();
824 if (node && !node->links().empty()) {
825 std::pair<QString, QString> anchorPair;
826 const Node *linkNode;
828 for (
auto it = node->links().cbegin(); it != node->links().cend(); ++it) {
830 linkNode = m_qdb->findNodeForTarget(it.value().first, node);
835 if (linkNode == node)
836 anchorPair = it.value();
838 anchorPair = anchorForNode(linkNode);
840 writer.writeStartElement(
"relation");
841 writer.writeAttribute(
"href", anchorPair.first);
842 writer.writeAttribute(
"type", targetType(linkNode));
845 case Node::StartLink:
846 writer.writeAttribute(
"meta",
"start");
849 writer.writeAttribute(
"meta",
"next");
851 case Node::PreviousLink:
852 writer.writeAttribute(
"meta",
"previous");
854 case Node::ContentsLink:
855 writer.writeAttribute(
"meta",
"contents");
858 writer.writeAttribute(
"meta",
"");
860 writer.writeAttribute(
"description", anchorPair.second);
861 writer.writeEndElement();
869 generateAnnotatedList(writer, relative, nodeMap.values());
875 writer.writeStartElement(
"table");
876 writer.writeAttribute(
"width",
"100%");
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);
885 writer.writeEndElement();
886 writer.writeEndElement();
888 writer.writeStartElement(
"item");
889 writer.writeStartElement(
"para");
890 writer.writeCharacters(node->doc().briefText().toString());
891 writer.writeEndElement();
892 writer.writeEndElement();
893 writer.writeEndElement();
895 writer.writeEndElement();
900 return Generator::fileBase(node);
#define ATOM_FORMATTING_TELETYPE
#define ATOM_LIST_LOWERALPHA
#define ATOM_FORMATTING_UNDERLINE
#define ATOM_LIST_UPPERALPHA
#define ATOM_FORMATTING_NOTRANSLATE
#define ATOM_LIST_LOWERROMAN
#define ATOM_FORMATTING_SUBSCRIPT
#define ATOM_FORMATTING_BOLD
#define ATOM_FORMATTING_TRADEMARK
#define ATOM_FORMATTING_ITALIC
#define ATOM_LIST_UPPERROMAN
#define ATOM_FORMATTING_SUPERSCRIPT
#define ATOM_FORMATTING_INDEX
#define ATOM_FORMATTING_PARAMETER
The Atom class is the fundamental unit for representing documents internally.
AtomType type() const
Return the type of this atom.
const Atom * next() const
Return the next atom in the atom list.
A class for holding the members of a collection of doc pages.
const NodeList & members() const
const Location & location() const
Returns the starting location of a qdoc comment.
static void quoteFromFile(const Location &location, Quoter "er, ResolvedFile resolved_file, CodeMarker *marker=nullptr)
const Text & body() const
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.
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.
This class handles qdoc index files.
static Text sectionHeading(const Atom *sectionBegin)
const Atom * firstAtom() const
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
Combined button and popup list for selecting options.
QMap< QString, Node * > NodeMap
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.
const Doc & doc() const
Returns a reference to the node's Doc data member.
bool isGroup() const
Returns true if the node type is Group.
bool isNamespace() const
Returns true if the node type is Namespace.
bool isHeader() const
Returns true if the node type is HeaderFile.
NodeType nodeType() const override
Returns this node's type.
bool isEnumType() const
Returns true if the node type is Enum.
virtual bool isTextPageNode() const
Returns true if the node is a PageNode but not an Aggregate.
Aggregate * parent() const
Returns the node's parent pointer.
bool isVariable() const
Returns true if the node type is Variable.
virtual bool isDeprecated() const
Returns true if this node's status is Deprecated.
virtual bool isAggregate() const
Returns true if this node is an aggregate, which means it inherits Aggregate and can therefore have c...
const Location & location() const
If this node's definition location is empty, this function returns this node's declaration location.
virtual bool wasSeen() const
Returns the seen flag data member of this node if it is a NamespaceNode or a CollectionNode.
bool isProperty() const
Returns true if the node type is Property.
NodeContext createContext() const
bool isModule() const
Returns true if the node type is Module.
virtual bool isClassNode() const
Returns true if this is an instance of ClassNode.
virtual bool isCollectionNode() const
Returns true if this is an instance of CollectionNode.
bool isExample() const
Returns true if the node type is Example.
bool isIndexNode() const
Returns true if this node was created from something in an index file.
Represents a file that is reachable by QDoc based on its current configuration.
static CodeMarker * marker_