1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the tools applications of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
48 #include "codemarker.h"
49 #include "pagegenerator.h"
50 #include "webxmlgenerator.h"
52 #include "separator.h"
57 #define COMMAND_VERSION Doc::alias("version")
59 WebXMLGenerator::WebXMLGenerator()
64 WebXMLGenerator::~WebXMLGenerator()
68 void WebXMLGenerator::initializeGenerator(const Config
&config
)
70 Generator::initializeGenerator(config
);
72 project
= config
.getString(CONFIG_PROJECT
);
74 projectDescription
= config
.getString(CONFIG_DESCRIPTION
);
75 if (projectDescription
.isEmpty() && !project
.isEmpty())
76 projectDescription
= project
+ " Reference Documentation";
78 projectUrl
= config
.getString(CONFIG_URL
);
80 generateIndex
= config
.getBool(CONFIG_GENERATEINDEX
);
83 void WebXMLGenerator::terminateGenerator()
85 PageGenerator::terminateGenerator();
88 QString
WebXMLGenerator::format()
93 QString
WebXMLGenerator::fileExtension(const Node
* /* node */)
98 void WebXMLGenerator::generateTree(const Tree
*tree
, CodeMarker
*marker
)
101 moduleClassMap
.clear();
102 moduleNamespaceMap
.clear();
103 serviceClasses
.clear();
104 findAllClasses(tree
->root());
105 findAllNamespaces(tree
->root());
107 PageGenerator::generateTree(tree
, marker
);
110 tre
->generateIndex(outputDir() + "/" + project
.toLower() + ".index",
111 projectUrl
, projectDescription
, false);
114 void WebXMLGenerator::startText(const Node
*relative
, CodeMarker
*marker
)
118 inSectionHeading
= false;
120 sectionNumber
.clear();
121 PageGenerator::startText(relative
, marker
);
124 int WebXMLGenerator::generateAtom(QXmlStreamWriter
&writer
, const Atom
*atom
,
125 const Node
*relative
, CodeMarker
*marker
)
131 switch (atom
->type()) {
133 PageGenerator::generateAtom(atom
, relative
, marker
);
138 void WebXMLGenerator::generateClassLikeNode(const InnerNode
*inner
,
142 QXmlStreamWriter
writer(&data
);
143 writer
.setAutoFormatting(true);
144 writer
.writeStartDocument();
145 writer
.writeStartElement("WebXML");
146 writer
.writeStartElement("document");
148 generateIndexSections(writer
, inner
, marker
);
150 writer
.writeEndElement(); // document
151 writer
.writeEndElement(); // WebXML
152 writer
.writeEndDocument();
158 void WebXMLGenerator::generateFakeNode(const FakeNode
*fake
, CodeMarker
*marker
)
161 QXmlStreamWriter
writer(&data
);
162 writer
.setAutoFormatting(true);
163 writer
.writeStartDocument();
164 writer
.writeStartElement("WebXML");
165 writer
.writeStartElement("document");
167 generateIndexSections(writer
, fake
, marker
);
169 writer
.writeEndElement(); // document
170 writer
.writeEndElement(); // WebXML
171 writer
.writeEndDocument();
177 void WebXMLGenerator::generateIndexSections(QXmlStreamWriter
&writer
,
178 const Node
*node
, CodeMarker
*marker
)
180 if (tre
->generateIndexSection(writer
, node
, true)) {
182 // Add documentation to this node if it exists.
183 writer
.writeStartElement("description");
184 writer
.writeAttribute("path", node
->doc().location().filePath());
185 writer
.writeAttribute("line", QString::number(node
->doc().location().lineNo()));
186 writer
.writeAttribute("column", QString::number(node
->doc().location().columnNo()));
188 if (node
->type() == Node::Fake
) {
190 const FakeNode
*fake
= static_cast<const FakeNode
*>(node
);
192 generateRelations(writer
, node
, marker
);
194 if (fake
->subType() == Node::Module
) {
195 writer
.writeStartElement("generatedlist");
196 writer
.writeAttribute("contents", "classesbymodule");
198 if (moduleNamespaceMap
.contains(fake
->name())) {
199 writer
.writeStartElement("section");
200 writer
.writeStartElement("heading");
201 writer
.writeAttribute("level", "1");
202 writer
.writeCharacters("Namespaces");
203 writer
.writeEndElement(); // heading
204 generateAnnotatedList(writer
, fake
, marker
, moduleNamespaceMap
[fake
->name()]);
205 writer
.writeEndElement(); // section
207 if (moduleClassMap
.contains(fake
->name())) {
208 writer
.writeStartElement("section");
209 writer
.writeStartElement("heading");
210 writer
.writeAttribute("level", "1");
211 writer
.writeCharacters("Classes");
212 writer
.writeEndElement(); // heading
213 generateAnnotatedList(writer
, fake
, marker
, moduleClassMap
[fake
->name()]);
214 writer
.writeEndElement(); // section
217 writer
.writeEndElement(); // generatedlist
221 startText(node
, marker
);
223 const Atom
*atom
= node
->doc().body().firstAtom();
225 atom
= addAtomElements(writer
, atom
, node
, marker
);
227 QList
<Text
> alsoList
= node
->doc().alsoList();
228 supplementAlsoList(node
, alsoList
);
230 if (!alsoList
.isEmpty()) {
231 writer
.writeStartElement("see-also");
232 for (int i
= 0; i
< alsoList
.size(); ++i
) {
233 const Atom
*atom
= alsoList
.at(i
).firstAtom();
235 atom
= addAtomElements(writer
, atom
, node
, marker
);
237 writer
.writeEndElement(); // see-also
240 writer
.writeEndElement(); // description
242 if (node
->isInnerNode()) {
243 const InnerNode
*inner
= static_cast<const InnerNode
*>(node
);
245 // Recurse to generate an element for this child node and all its children.
246 foreach (const Node
*child
, inner
->childNodes())
247 generateIndexSections(writer
, child
, marker
);
249 writer
.writeStartElement("related");
250 if (inner
->relatedNodes().size() > 0) {
251 foreach (const Node
*child
, inner
->relatedNodes())
252 generateIndexSections(writer
, child
, marker
);
254 writer
.writeEndElement(); // related
256 writer
.writeEndElement();
260 void WebXMLGenerator::generateInnerNode(const InnerNode
*node
, CodeMarker
*marker
)
262 if (!node
->url().isNull())
265 if (node
->type() == Node::Fake
) {
266 const FakeNode
*fakeNode
= static_cast<const FakeNode
*>(node
);
267 if (fakeNode
->subType() == Node::ExternalPage
)
271 if ( node
->parent() != 0 ) {
272 beginSubPage( node
->location(), fileName(node
) );
273 if ( node
->type() == Node::Namespace
|| node
->type() == Node::Class
) {
274 generateClassLikeNode(node
, marker
);
275 } else if ( node
->type() == Node::Fake
) {
276 generateFakeNode(static_cast<const FakeNode
*>(node
), marker
);
281 NodeList::ConstIterator c
= node
->childNodes().begin();
282 while ( c
!= node
->childNodes().end() ) {
283 if ((*c
)->isInnerNode() && (
284 (*c
)->access() != Node::Private
|| (*c
)->status() == Node::Internal
))
285 generateInnerNode( (const InnerNode
*) *c
, marker
);
290 const Atom
*WebXMLGenerator::addAtomElements(QXmlStreamWriter
&writer
,
291 const Atom
*atom
, const Node
*relative
, CodeMarker
*marker
)
293 switch (atom
->type()) {
294 case Atom::AbstractLeft
:
295 case Atom::AbstractRight
:
298 if (!inLink
&& !inSectionHeading
) {
299 const Node
*node
= findNode(atom
, relative
, marker
);
301 startLink(writer
, atom
, node
, relative
);
303 writer
.writeCharacters(atom
->string());
304 writer
.writeEndElement(); // link
308 writer
.writeCharacters(atom
->string());
310 writer
.writeCharacters(atom
->string());
314 case Atom::BriefLeft
:
316 writer
.writeStartElement("brief");
317 switch (relative
->type()) {
319 writer
.writeCharacters("This property");
322 writer
.writeCharacters("This variable");
327 if (relative
->type() == Node::Property
|| relative
->type() == Node::Variable
) {
329 const Atom
*a
= atom
->next();
330 while (a
!= 0 && a
->type() != Atom::BriefRight
) {
331 if (a
->type() == Atom::String
|| a
->type() == Atom::AutoLink
)
335 str
[0] = str
[0].toLower();
336 if (str
.right(1) == ".")
339 QStringList words
= str
.split(" ");
340 if (!(words
.first() == "contains" || words
.first() == "specifies"
341 || words
.first() == "describes" || words
.first() == "defines"
342 || words
.first() == "holds" || words
.first() == "determines"))
343 writer
.writeCharacters(" holds ");
345 writer
.writeCharacters(" ");
349 case Atom::BriefRight
:
350 if (relative
->type() == Node::Property
|| relative
->type() == Node::Variable
)
351 writer
.writeCharacters(".");
353 writer
.writeEndElement(); // brief
357 writer
.writeStartElement("teletype");
359 writer
.writeAttribute("type", "normal");
361 writer
.writeAttribute("type", "highlighted");
363 writer
.writeCharacters(plainCode(atom
->string()));
364 writer
.writeEndElement(); // teletype
368 writer
.writeTextElement("code", trimmedTrailing(plainCode(atom
->string())));
373 writer
.writeTextElement("qml", trimmedTrailing(plainCode(atom
->string())));
377 writer
.writeTextElement("badcode", trimmedTrailing(plainCode(atom
->string())));
381 writer
.writeTextElement("para", "you can rewrite it as");
382 writer
.writeTextElement("newcode", trimmedTrailing(plainCode(atom
->string())));
386 writer
.writeTextElement("para", "For example, if you have code like");
387 writer
.writeTextElement("oldcode", trimmedTrailing(plainCode(atom
->string())));
390 case Atom::CodeQuoteArgument
:
391 if (quoteCommand
== "dots") {
392 writer
.writeAttribute("indent", atom
->string());
393 writer
.writeCharacters("...");
395 writer
.writeCharacters(atom
->string());
396 writer
.writeEndElement(); // code
399 case Atom::CodeQuoteCommand
:
400 quoteCommand
= atom
->string();
401 writer
.writeStartElement(quoteCommand
);
404 case Atom::FootnoteLeft
:
405 writer
.writeStartElement("footnote");
408 case Atom::FootnoteRight
:
409 writer
.writeEndElement(); // footnote
412 case Atom::FormatElse:
413 writer.writeStartElement("else");
414 writer.writeEndElement(); // else
417 case Atom::FormatEndif
:
418 writer
.writeEndElement(); // raw
421 writer
.writeStartElement("raw");
422 writer
.writeAttribute("format", atom
->string());
424 case Atom::FormattingLeft
:
426 if (atom
->string() == ATOM_FORMATTING_BOLD
)
427 writer
.writeStartElement("bold");
428 else if (atom
->string() == ATOM_FORMATTING_ITALIC
)
429 writer
.writeStartElement("italic");
430 else if (atom
->string() == ATOM_FORMATTING_UNDERLINE
)
431 writer
.writeStartElement("underline");
432 else if (atom
->string() == ATOM_FORMATTING_SUBSCRIPT
)
433 writer
.writeStartElement("subscript");
434 else if (atom
->string() == ATOM_FORMATTING_SUPERSCRIPT
)
435 writer
.writeStartElement("superscript");
436 else if (atom
->string() == ATOM_FORMATTING_TELETYPE
)
437 writer
.writeStartElement("teletype");
438 else if (atom
->string() == ATOM_FORMATTING_PARAMETER
)
439 writer
.writeStartElement("argument");
440 else if (atom
->string() == ATOM_FORMATTING_INDEX
)
441 writer
.writeStartElement("index");
444 /* out() << formattingLeftMap()[atom->string()];
445 if ( atom->string() == ATOM_FORMATTING_PARAMETER ) {
446 if ( atom->next() != 0 && atom->next()->type() == Atom::String ) {
447 QRegExp subscriptRegExp( "([a-z]+)_([0-9n])" );
448 if ( subscriptRegExp.exactMatch(atom->next()->string()) ) {
449 out() << subscriptRegExp.cap( 1 ) << "<sub>"
450 << subscriptRegExp.cap( 2 ) << "</sub>";
455 case Atom::FormattingRight
:
457 if (atom
->string() == ATOM_FORMATTING_BOLD
)
458 writer
.writeEndElement();
459 else if (atom
->string() == ATOM_FORMATTING_ITALIC
)
460 writer
.writeEndElement();
461 else if (atom
->string() == ATOM_FORMATTING_UNDERLINE
)
462 writer
.writeEndElement();
463 else if (atom
->string() == ATOM_FORMATTING_SUBSCRIPT
)
464 writer
.writeEndElement();
465 else if (atom
->string() == ATOM_FORMATTING_SUPERSCRIPT
)
466 writer
.writeEndElement();
467 else if (atom
->string() == ATOM_FORMATTING_TELETYPE
)
468 writer
.writeEndElement();
469 else if (atom
->string() == ATOM_FORMATTING_PARAMETER
)
470 writer
.writeEndElement();
471 else if (atom
->string() == ATOM_FORMATTING_INDEX
)
472 writer
.writeEndElement();
475 writer
.writeEndElement(); // link
479 /* if ( atom->string() == ATOM_FORMATTING_LINK ) {
481 if ( link.isEmpty() ) {
490 out() << formattingRightMap()[atom->string()];
492 case Atom::GeneratedList
:
493 writer
.writeStartElement("generatedlist");
494 writer
.writeAttribute("contents", atom
->string());
495 writer
.writeEndElement(); // generatedlist
497 if (atom->string() == "annotatedclasses") {
498 generateAnnotatedList(relative, marker, nonCompatClasses);
499 } else if (atom->string() == "classes") {
500 generateCompactList(relative, marker, nonCompatClasses);
501 } else if (atom->string().contains("classesbymodule")) {
502 QString arg = atom->string().trimmed();
503 QString moduleName = atom->string().mid(atom->string().indexOf(
504 "classesbymodule") + 15).trimmed();
505 if (moduleClassMap.contains(moduleName))
506 generateAnnotatedList(relative, marker, moduleClassMap[moduleName]);
507 } else if (atom->string().contains("classesbyedition")) {
508 QString arg = atom->string().trimmed();
509 QString editionName = atom->string().mid(atom->string().indexOf(
510 "classesbyedition") + 16).trimmed();
511 if (editionModuleMap.contains(editionName)) {
512 QMap<QString, const Node *> editionClasses;
513 foreach (const QString &moduleName, editionModuleMap[editionName]) {
514 if (moduleClassMap.contains(moduleName))
515 editionClasses.unite(moduleClassMap[moduleName]);
517 generateAnnotatedList(relative, marker, editionClasses);
519 } else if (atom->string() == "classhierarchy") {
520 generateClassHierarchy(relative, marker, nonCompatClasses);
521 } else if (atom->string() == "compatclasses") {
522 generateCompactList(relative, marker, compatClasses);
523 } else if (atom->string() == "functionindex") {
524 generateFunctionIndex(relative, marker);
525 } else if (atom->string() == "legalese") {
526 generateLegaleseList(relative, marker);
527 } else if (atom->string() == "mainclasses") {
528 generateCompactList(relative, marker, mainClasses);
529 } else if (atom->string() == "services") {
530 generateCompactList(relative, marker, serviceClasses);
531 } else if (atom->string() == "overviews") {
532 generateOverviewList(relative, marker);
533 } else if (atom->string() == "namespaces") {
534 generateAnnotatedList(relative, marker, namespaceIndex);
535 } else if (atom->string() == "related") {
536 const FakeNode *fake = static_cast<const FakeNode *>(relative);
537 if (fake && !fake->groupMembers().isEmpty()) {
538 QMap<QString, const Node *> groupMembersMap;
539 foreach (Node *node, fake->groupMembers()) {
540 if (node->type() == Node::Fake)
541 groupMembersMap[fullName(node, relative, marker)] = node;
543 generateAnnotatedList(fake, marker, groupMembersMap);
545 } else if (atom->string() == "relatedinline") {
546 const FakeNode *fake = static_cast<const FakeNode *>(relative);
547 if (fake && !fake->groupMembers().isEmpty()) {
548 // Reverse the list into the original scan order.
549 // Should be sorted. But on what? It may not be a
550 // regular class or page definition.
551 QList<const Node *> list;
552 foreach (const Node *node, fake->groupMembers())
554 foreach (const Node *node, list)
555 generateBody(node, marker );
562 writer
.writeStartElement("image");
563 writer
.writeAttribute("href", imageFileName(relative
, atom
->string()));
564 writer
.writeEndElement(); // image
567 case Atom::InlineImage
:
568 writer
.writeStartElement("inlineimage");
569 writer
.writeAttribute("href", imageFileName(relative
, atom
->string()));
570 writer
.writeEndElement(); // inlineimage
573 case Atom::ImageText
:
576 case Atom::LegaleseLeft
:
577 writer
.writeStartElement("legalese");
580 case Atom::LegaleseRight
:
581 writer
.writeEndElement(); // legalese
587 const Node
*node
= findNode(atom
, relative
, marker
);
589 startLink(writer
, atom
, node
, relative
);
594 writer
.writeStartElement("list");
596 if (atom
->string() == ATOM_LIST_BULLET
)
597 writer
.writeAttribute("type", "bullet");
598 else if (atom
->string() == ATOM_LIST_TAG
)
599 writer
.writeAttribute("type", "definition");
600 else if (atom
->string() == ATOM_LIST_VALUE
)
601 writer
.writeAttribute("type", "enum");
603 writer
.writeAttribute("type", "ordered");
604 if (atom
->string() == ATOM_LIST_UPPERALPHA
)
605 writer
.writeAttribute("start", "A");
606 else if (atom
->string() == ATOM_LIST_LOWERALPHA
)
607 writer
.writeAttribute("start", "a");
608 else if (atom
->string() == ATOM_LIST_UPPERROMAN
)
609 writer
.writeAttribute("start", "I");
610 else if (atom
->string() == ATOM_LIST_LOWERROMAN
)
611 writer
.writeAttribute("start", "i");
612 else // (atom->string() == ATOM_LIST_NUMERIC)
613 writer
.writeAttribute("start", "1");
617 case Atom::ListItemNumber
:
620 case Atom::ListTagLeft
:
622 writer
.writeStartElement("definition");
624 writer
.writeTextElement("term", plainCode(
625 marker
->markedUpEnumValue(atom
->next()->string(), relative
)));
629 case Atom::ListTagRight
:
630 writer
.writeEndElement(); // definition
633 case Atom::ListItemLeft
:
634 writer
.writeStartElement("item");
637 case Atom::ListItemRight
:
638 writer
.writeEndElement(); // item
641 case Atom::ListRight
:
642 writer
.writeEndElement(); // list
649 writer
.writeStartElement("para");
652 case Atom::ParaRight
:
653 writer
.writeEndElement(); // para
656 case Atom::QuotationLeft
:
657 writer
.writeStartElement("quote");
660 case Atom::QuotationRight
:
661 writer
.writeEndElement(); // quote
664 case Atom::RawString
:
665 writer
.writeCharacters(atom
->string());
668 case Atom::SectionLeft
:
669 writer
.writeStartElement("section");
670 writer
.writeAttribute("id", Doc::canonicalTitle(Text::sectionHeading(atom
).toString()));
673 case Atom::SectionRight
:
674 writer
.writeEndElement(); // section
677 case Atom::SectionHeadingLeft
:
678 writer
.writeStartElement("heading");
679 writer
.writeAttribute("level", atom
->string()); // + hOffset(relative)
680 inSectionHeading
= true;
683 case Atom::SectionHeadingRight
:
684 writer
.writeEndElement(); // heading
685 inSectionHeading
= false;
688 case Atom::SidebarLeft
:
689 case Atom::SidebarRight
:
692 case Atom::SnippetCommand
:
693 writer
.writeStartElement(atom
->string());
696 case Atom::SnippetIdentifier
:
697 writer
.writeAttribute("identifier", atom
->string());
698 writer
.writeEndElement(); // snippet
701 case Atom::SnippetLocation
:
702 writer
.writeAttribute("location", atom
->string());
706 writer
.writeCharacters(atom
->string());
709 case Atom::TableLeft
:
710 writer
.writeStartElement("table");
711 if (atom
->string().contains("%"))
712 writer
.writeAttribute("width", atom
->string());
715 case Atom::TableRight
:
716 writer
.writeEndElement(); // table
719 case Atom::TableHeaderLeft
:
720 writer
.writeStartElement("header");
723 case Atom::TableHeaderRight
:
724 writer
.writeEndElement(); // header
727 case Atom::TableRowLeft
:
728 writer
.writeStartElement("row");
731 case Atom::TableRowRight
:
732 writer
.writeEndElement(); // row
735 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());
748 case Atom::TableItemRight
:
749 writer
.writeEndElement(); // item
752 case Atom::TableOfContents
:
753 writer
.writeStartElement("tableofcontents");
754 writer
.writeAttribute("details", atom
->string());
757 const Node
*node
= relative
;
759 Doc::SectioningUnit sectioningUnit
= Doc::Section4
;
760 QStringList params
= atom
->string().split(",");
761 QString columnText
= params
.at(0);
762 QStringList pieces
= columnText
.split(" ", QString::SkipEmptyParts
);
763 if (pieces
.size() >= 2) {
764 columnText
= pieces
.at(0);
766 QString path
= pieces
.join(" ").trimmed();
767 node
= findNode(path
, relative
, marker
);
769 writer
.writeAttribute("href", fileName(node
));
772 if (params
.size() == 2) {
773 numColumns
= qMax(columnText
.toInt(), numColumns
);
774 sectioningUnit
= (Doc::SectioningUnit
)params
.at(1).toInt();
775 writer
.writeAttribute("columns", QString::number(numColumns
));
776 writer
.writeAttribute("unit", QString::number(sectioningUnit
));
780 generateTableOfContents(writer
, node
, sectioningUnit
, numColumns
,
783 writer
.writeEndElement(); // tableofcontents
787 writer
.writeStartElement("target");
788 writer
.writeAttribute("name", Doc::canonicalTitle(atom
->string()));
789 writer
.writeEndElement(); // target
792 case Atom::UnhandledFormat
:
793 case Atom::UnknownCommand
:
794 writer
.writeCharacters(atom
->typeString());
806 QDomElement atomElement = document.createElement(atom->typeString().toLower());
807 QDomText atomValue = document.createTextNode(atom->string());
808 atomElement.appendChild(atomValue);
809 descriptionElement.appendChild(atomElement);
813 ### Warning: findNode() is a modified version of HtmlGenerator::getLink().
815 const Node
*WebXMLGenerator::findNode(const Atom
*atom
, const Node
*relative
, CodeMarker
*marker
)
817 return findNode(atom
->string(), relative
, marker
);
820 const Node
*WebXMLGenerator::findNode(const QString
&title
, const Node
*relative
, CodeMarker
*marker
)
823 if (title
.contains(":") &&
824 (title
.startsWith("file:")
825 || title
.startsWith("http:")
826 || title
.startsWith("https:")
827 || title
.startsWith("ftp:")
828 || title
.startsWith("mailto:"))) {
831 } else if (title
.count('@') == 1) {
835 if (title
.contains('#')) {
836 path
= title
.split('#');
841 const Node
*node
= 0;
842 Atom
*targetAtom
= 0;
844 QString first
= path
.first().trimmed();
845 if (first
.isEmpty()) {
847 } else if (first
.endsWith(".html")) {
848 node
= tre
->root()->findNode(first
, Node::Fake
);
850 node
= marker
->resolveTarget(first
, tre
, relative
);
852 node
= tre
->findFakeNodeByTitle(first
);
854 node
= tre
->findUnambiguousTarget(first
, targetAtom
);
858 if (!node
->url().isEmpty())
866 while (!path
.isEmpty()) {
867 targetAtom
= tre
->findTarget(path
.first(), node
);
872 /* We would ideally treat targets as nodes to be consistent.
873 if (targetAtom && node && node->isInnerNode()) {
874 Node *parentNode = const_cast<Node *>(node);
875 node = new TargetNode(static_cast<InnerNode*>(parentNode), first);
883 void WebXMLGenerator::startLink(QXmlStreamWriter
&writer
, const Atom
*atom
,
884 const Node
*node
, const Node
*relative
)
886 QString location
= tre
->fullDocumentLocation(node
);
887 if (!location
.isEmpty()) {
888 writer
.writeStartElement("link");
889 writer
.writeAttribute("raw", atom
->string());
890 if (atom
->string().contains("#") || node
== relative
) {
891 QString target
= atom
->string().split("#").last();
892 Atom
*targetAtom
= tre
->findTarget(target
, node
);
894 location
+= "#" + Doc::canonicalTitle(target
);
896 writer
.writeAttribute("href", location
);
897 QString type
= targetType(node
);
898 writer
.writeAttribute("type", type
);
899 switch (node
->type()) {
901 writer
.writeAttribute("enum", tre
->fullDocumentName(node
));
904 writer
.writeAttribute("page", tre
->fullDocumentName(node
));
908 const PropertyNode
*propertyNode
= static_cast<const PropertyNode
*>(node
);
909 if (propertyNode
->getters().size() > 0)
910 writer
.writeAttribute("getter", tre
->fullDocumentName(propertyNode
->getters()[0]));
919 QString
WebXMLGenerator::targetType(const Node
*node
)
921 switch (node
->type()) {
922 case Node::Namespace
:
955 void WebXMLGenerator::generateRelations(QXmlStreamWriter
&writer
, const Node
*node
, CodeMarker
*marker
)
957 if (node
&& !node
->links().empty()) {
958 QPair
<QString
,QString
> linkPair
;
959 QPair
<QString
,QString
> anchorPair
;
960 const Node
*linkNode
;
962 foreach (Node::LinkType relation
, node
->links().keys()) {
964 linkPair
= node
->links()[relation
];
965 linkNode
= findNode(linkPair
.first
, node
, marker
);
970 if (linkNode
== node
)
971 anchorPair
= linkPair
;
973 anchorPair
= anchorForNode(linkNode
);
975 writer
.writeStartElement("relation");
976 writer
.writeAttribute("href", anchorPair
.first
);
977 writer
.writeAttribute("type", targetType(linkNode
));
980 case Node::StartLink
:
981 writer
.writeAttribute("meta", "start");
984 writer
.writeAttribute("meta", "next");
986 case Node::PreviousLink
:
987 writer
.writeAttribute("meta", "previous");
989 case Node::ContentsLink
:
990 writer
.writeAttribute("meta", "contents");
992 case Node::IndexLink
:
993 writer
.writeAttribute("meta", "index");
996 writer
.writeAttribute("meta", "");
998 writer
.writeAttribute("description", anchorPair
.second
);
999 writer
.writeEndElement(); // link
1004 // Classes adapted from HtmlGenerator.
1006 void WebXMLGenerator::generateTableOfContents(QXmlStreamWriter
&writer
, const Node
*node
,
1007 Doc::SectioningUnit sectioningUnit
,
1008 int numColumns
, const Node
*relative
)
1011 if (!node
->doc().hasTableOfContents())
1013 QList
<Atom
*> toc
= node
->doc().tableOfContents();
1017 QString nodeName
= "";
1018 if (node
!= relative
)
1019 nodeName
= node
->name();
1021 QStringList sectionNumber
;
1024 if (numColumns
> 1) {
1025 writer
.writeStartElement("table");
1026 writer
.writeAttribute("width", "100%");
1027 writer
.writeStartElement("row");
1028 writer
.writeStartElement("item");
1029 writer
.writeAttribute("width", QString::number((100 + numColumns
- 1) / numColumns
) + "%");
1032 // disable nested links in table of contents
1036 for (int i
= 0; i
< toc
.size(); ++i
) {
1037 Atom
*atom
= toc
.at(i
);
1039 int nextLevel
= atom
->string().toInt();
1040 if (nextLevel
> (int)sectioningUnit
)
1043 if (sectionNumber
.size() < nextLevel
) {
1045 writer
.writeStartElement("list");
1046 sectionNumber
.append("1");
1047 } while (sectionNumber
.size() < nextLevel
);
1049 while (sectionNumber
.size() > nextLevel
) {
1050 writer
.writeEndElement();
1051 sectionNumber
.removeLast();
1053 sectionNumber
.last() = QString::number(sectionNumber
.last().toInt() + 1);
1055 Text headingText
= Text::sectionHeading(atom
);
1057 if (sectionNumber
.size() == 1 && columnSize
> toc
.size() / numColumns
) {
1058 writer
.writeEndElement(); // list
1059 writer
.writeEndElement(); // item
1060 writer
.writeStartElement("item");
1061 writer
.writeAttribute("width", QString::number((100 + numColumns
- 1) / numColumns
) + "%");
1062 writer
.writeStartElement("list");
1066 writer
.writeStartElement("item");
1067 writer
.writeStartElement("para");
1068 writer
.writeStartElement("link");
1069 writer
.writeAttribute("href", nodeName
+ "#" + Doc::canonicalTitle(headingText
.toString()));
1070 writer
.writeAttribute("type", "page");
1071 writer
.writeCharacters(headingText
.toString());
1072 writer
.writeEndElement(); // link
1073 writer
.writeEndElement(); // para
1074 writer
.writeEndElement(); // item
1078 while (!sectionNumber
.isEmpty()) {
1079 writer
.writeEndElement(); // list
1080 sectionNumber
.removeLast();
1083 if (numColumns
> 1) {
1084 writer
.writeEndElement(); // item
1085 writer
.writeEndElement(); // row
1086 writer
.writeEndElement(); // table
1093 void WebXMLGenerator::generateAnnotatedList(QXmlStreamWriter
&writer
,
1094 const Node
*relative
, CodeMarker
*marker
, const QMap
<QString
, const Node
*> &nodeMap
)
1096 writer
.writeStartElement("table");
1097 writer
.writeAttribute("width", "100%");
1099 foreach (QString name
, nodeMap
.keys()) {
1100 const Node
*node
= nodeMap
[name
];
1102 writer
.writeStartElement("row");
1103 writer
.writeStartElement("heading");
1104 generateFullName(writer
, node
, relative
, marker
);
1105 writer
.writeEndElement(); // heading
1107 writer
.writeStartElement("item");
1108 writer
.writeCharacters(node
->doc().briefText().toString());
1109 writer
.writeEndElement(); // item
1110 writer
.writeEndElement(); // row
1112 writer
.writeEndElement(); // table
1115 void WebXMLGenerator::generateFullName(QXmlStreamWriter
&writer
,
1116 const Node
*apparentNode
, const Node
*relative
, CodeMarker
*marker
,
1117 const Node
*actualNode
)
1119 if ( actualNode
== 0 )
1120 actualNode
= apparentNode
;
1121 writer
.writeStartElement("link");
1122 writer
.writeAttribute("href", tre
->fullDocumentLocation(actualNode
));
1123 writer
.writeAttribute("type", targetType(actualNode
));
1124 writer
.writeCharacters(fullName(apparentNode
, relative
, marker
));
1125 writer
.writeEndElement(); // link
1128 // Classes copied (and slightly adapted) from the HtmlGenerator. These need
1129 // refactoring into a common ancestor class.
1131 void WebXMLGenerator::findAllClasses(const InnerNode
*node
)
1133 NodeList::const_iterator c
= node
->childNodes().constBegin();
1134 while (c
!= node
->childNodes().constEnd()) {
1135 if ((*c
)->access() != Node::Private
&& (*c
)->url().isEmpty()) {
1136 if ((*c
)->type() == Node::Class
&& !(*c
)->doc().isEmpty()) {
1137 QString className
= (*c
)->name();
1138 if ((*c
)->parent() && (*c
)->parent()->type() == Node::Namespace
&&
1139 !(*c
)->parent()->name().isEmpty())
1140 className
= (*c
)->parent()->name()+"::"+className
;
1142 QString moduleName
= (*c
)->moduleName();
1143 if (!moduleName
.isEmpty())
1144 moduleClassMap
[moduleName
].insert((*c
)->name(), *c
);
1146 QString serviceName
=
1147 (static_cast<const ClassNode
*>(*c
))->serviceName();
1148 if (!serviceName
.isEmpty())
1149 serviceClasses
.insert(serviceName
, *c
);
1150 } else if ((*c
)->isInnerNode()) {
1151 findAllClasses(static_cast<InnerNode
*>(*c
));
1158 void WebXMLGenerator::findAllNamespaces(const InnerNode
*node
)
1160 NodeList::ConstIterator c
= node
->childNodes().begin();
1161 while (c
!= node
->childNodes().end()) {
1162 if ((*c
)->access() != Node::Private
) {
1163 if ((*c
)->isInnerNode() && (*c
)->url().isEmpty()) {
1164 findAllNamespaces(static_cast<const InnerNode
*>(*c
));
1165 if ((*c
)->type() == Node::Namespace
) {
1166 const NamespaceNode
*nspace
= static_cast<const NamespaceNode
*>(*c
);
1167 // Ensure that the namespace's name is not empty (the root
1168 // namespace has no name).
1169 if (!nspace
->name().isEmpty()) {
1170 namespaceIndex
.insert(nspace
->name(), *c
);
1171 QString moduleName
= (*c
)->moduleName();
1172 if (!moduleName
.isEmpty())
1173 moduleNamespaceMap
[moduleName
].insert((*c
)->name(), *c
);
1182 const QPair
<QString
,QString
> WebXMLGenerator::anchorForNode(const Node
*node
)
1184 QPair
<QString
,QString
> anchorPair
;
1186 anchorPair
.first
= PageGenerator::fileName(node
);
1187 if (node
->type() == Node::Fake
) {
1188 const FakeNode
*fakeNode
= static_cast<const FakeNode
*>(node
);
1189 anchorPair
.second
= fakeNode
->title();