tools/qdoc3/webxmlgenerator.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     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
       
    14 ** this package.
       
    15 **
       
    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.
       
    23 **
       
    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.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /*
       
    43   webxmlgenerator.cpp
       
    44 */
       
    45 
       
    46 #include <QtXml>
       
    47 
       
    48 #include "codemarker.h"
       
    49 #include "pagegenerator.h"
       
    50 #include "webxmlgenerator.h"
       
    51 #include "node.h"
       
    52 #include "separator.h"
       
    53 #include "tree.h"
       
    54 
       
    55 QT_BEGIN_NAMESPACE
       
    56 
       
    57 #define COMMAND_VERSION                 Doc::alias("version")
       
    58 
       
    59 WebXMLGenerator::WebXMLGenerator()
       
    60     : PageGenerator()
       
    61 {
       
    62 }
       
    63 
       
    64 WebXMLGenerator::~WebXMLGenerator()
       
    65 {
       
    66 }
       
    67 
       
    68 void WebXMLGenerator::initializeGenerator(const Config &config)
       
    69 {
       
    70     Generator::initializeGenerator(config);
       
    71 
       
    72     project = config.getString(CONFIG_PROJECT);
       
    73 
       
    74     projectDescription = config.getString(CONFIG_DESCRIPTION);
       
    75     if (projectDescription.isEmpty() && !project.isEmpty())
       
    76         projectDescription = project + " Reference Documentation";
       
    77 
       
    78     projectUrl = config.getString(CONFIG_URL);
       
    79 
       
    80     generateIndex = config.getBool(CONFIG_GENERATEINDEX);
       
    81 }
       
    82 
       
    83 void WebXMLGenerator::terminateGenerator()
       
    84 {
       
    85     PageGenerator::terminateGenerator();
       
    86 }
       
    87 
       
    88 QString WebXMLGenerator::format()
       
    89 {
       
    90     return "WebXML";
       
    91 }
       
    92 
       
    93 QString WebXMLGenerator::fileExtension(const Node * /* node */)
       
    94 {
       
    95     return "xml";
       
    96 }
       
    97 
       
    98 void WebXMLGenerator::generateTree(const Tree *tree, CodeMarker *marker)
       
    99 {
       
   100     tre = tree;
       
   101     moduleClassMap.clear();
       
   102     moduleNamespaceMap.clear();
       
   103     serviceClasses.clear();
       
   104     findAllClasses(tree->root());
       
   105     findAllNamespaces(tree->root());
       
   106 
       
   107     PageGenerator::generateTree(tree, marker);
       
   108 
       
   109     if (generateIndex)
       
   110         tre->generateIndex(outputDir() + "/" + project.toLower() + ".index",
       
   111                            projectUrl, projectDescription, false);
       
   112 }
       
   113 
       
   114 void WebXMLGenerator::startText(const Node *relative, CodeMarker *marker)
       
   115 {
       
   116     inLink = false;
       
   117     inContents = false;
       
   118     inSectionHeading = false;
       
   119     numTableRows = 0;
       
   120     sectionNumber.clear();
       
   121     PageGenerator::startText(relative, marker);
       
   122 }
       
   123 
       
   124 int WebXMLGenerator::generateAtom(QXmlStreamWriter &writer, const Atom *atom,
       
   125                                   const Node *relative, CodeMarker *marker)
       
   126 {
       
   127     Q_UNUSED(writer);
       
   128 
       
   129     int skipAhead = 0;
       
   130 
       
   131     switch (atom->type()) {
       
   132     default:
       
   133         PageGenerator::generateAtom(atom, relative, marker);
       
   134     }
       
   135     return skipAhead;
       
   136 }
       
   137 
       
   138 void WebXMLGenerator::generateClassLikeNode(const InnerNode *inner,
       
   139                                             CodeMarker *marker)
       
   140 {
       
   141     QByteArray data;
       
   142     QXmlStreamWriter writer(&data);
       
   143     writer.setAutoFormatting(true);
       
   144     writer.writeStartDocument();
       
   145     writer.writeStartElement("WebXML");
       
   146     writer.writeStartElement("document");
       
   147 
       
   148     generateIndexSections(writer, inner, marker);
       
   149 
       
   150     writer.writeEndElement(); // document
       
   151     writer.writeEndElement(); // WebXML
       
   152     writer.writeEndDocument();
       
   153 
       
   154     out() << data;
       
   155     out().flush();
       
   156 }
       
   157 
       
   158 void WebXMLGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
       
   159 {
       
   160     QByteArray data;
       
   161     QXmlStreamWriter writer(&data);
       
   162     writer.setAutoFormatting(true);
       
   163     writer.writeStartDocument();
       
   164     writer.writeStartElement("WebXML");
       
   165     writer.writeStartElement("document");
       
   166 
       
   167     generateIndexSections(writer, fake, marker);
       
   168 
       
   169     writer.writeEndElement(); // document
       
   170     writer.writeEndElement(); // WebXML
       
   171     writer.writeEndDocument();
       
   172 
       
   173     out() << data;
       
   174     out().flush();
       
   175 }
       
   176 
       
   177 void WebXMLGenerator::generateIndexSections(QXmlStreamWriter &writer,
       
   178                                  const Node *node, CodeMarker *marker)
       
   179 {
       
   180     if (tre->generateIndexSection(writer, node, true)) {
       
   181 
       
   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()));
       
   187 
       
   188         if (node->type() == Node::Fake) {
       
   189 
       
   190             const FakeNode *fake = static_cast<const FakeNode *>(node);
       
   191 
       
   192             generateRelations(writer, node, marker);
       
   193 
       
   194             if (fake->subType() == Node::Module) {
       
   195                 writer.writeStartElement("generatedlist");
       
   196                 writer.writeAttribute("contents", "classesbymodule");
       
   197 
       
   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
       
   206                 }
       
   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
       
   215                 }
       
   216 
       
   217                 writer.writeEndElement(); // generatedlist
       
   218             }
       
   219         }
       
   220 
       
   221         startText(node, marker);
       
   222 
       
   223         const Atom *atom = node->doc().body().firstAtom();
       
   224         while (atom)
       
   225             atom = addAtomElements(writer, atom, node, marker);
       
   226 
       
   227         QList<Text> alsoList = node->doc().alsoList();
       
   228         supplementAlsoList(node, alsoList);
       
   229 
       
   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();
       
   234                 while (atom)
       
   235                     atom = addAtomElements(writer, atom, node, marker);
       
   236             }
       
   237             writer.writeEndElement(); // see-also
       
   238         }
       
   239 
       
   240         writer.writeEndElement(); // description
       
   241 
       
   242         if (node->isInnerNode()) {
       
   243             const InnerNode *inner = static_cast<const InnerNode *>(node);
       
   244 
       
   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);
       
   248 
       
   249             writer.writeStartElement("related");
       
   250             if (inner->relatedNodes().size() > 0) {
       
   251                 foreach (const Node *child, inner->relatedNodes())
       
   252                     generateIndexSections(writer, child, marker);
       
   253             }
       
   254             writer.writeEndElement(); // related
       
   255         }
       
   256         writer.writeEndElement();
       
   257     }
       
   258 }
       
   259 
       
   260 void WebXMLGenerator::generateInnerNode(const InnerNode *node, CodeMarker *marker)
       
   261 {
       
   262     if (!node->url().isNull())
       
   263         return;
       
   264 
       
   265     if (node->type() == Node::Fake) {
       
   266         const FakeNode *fakeNode = static_cast<const FakeNode *>(node);
       
   267         if (fakeNode->subType() == Node::ExternalPage)
       
   268             return;
       
   269     }
       
   270 
       
   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);
       
   277 	}
       
   278 	endSubPage();
       
   279     }
       
   280 
       
   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 );
       
   286 	++c;
       
   287     }
       
   288 }
       
   289 
       
   290 const Atom *WebXMLGenerator::addAtomElements(QXmlStreamWriter &writer,
       
   291      const Atom *atom, const Node *relative, CodeMarker *marker)
       
   292 {
       
   293     switch (atom->type()) {
       
   294     case Atom::AbstractLeft:
       
   295     case Atom::AbstractRight:
       
   296         break;
       
   297     case Atom::AutoLink:
       
   298         if (!inLink && !inSectionHeading) {
       
   299             const Node *node = findNode(atom, relative, marker);
       
   300             if (node) {
       
   301                 startLink(writer, atom, node, relative);
       
   302                 if (inLink) {
       
   303                     writer.writeCharacters(atom->string());
       
   304                     writer.writeEndElement(); // link
       
   305                     inLink = false;
       
   306                 }
       
   307             } else
       
   308                 writer.writeCharacters(atom->string());
       
   309         } else
       
   310             writer.writeCharacters(atom->string());
       
   311         break;
       
   312     case Atom::BaseName:
       
   313         break;
       
   314     case Atom::BriefLeft:
       
   315 
       
   316         writer.writeStartElement("brief");
       
   317         switch (relative->type()) {
       
   318         case Node::Property:
       
   319             writer.writeCharacters("This property");
       
   320             break;
       
   321         case Node::Variable:
       
   322             writer.writeCharacters("This variable");
       
   323             break;
       
   324         default:
       
   325             break;
       
   326         }
       
   327         if (relative->type() == Node::Property || relative->type() == Node::Variable) {
       
   328             QString str;
       
   329             const Atom *a = atom->next();
       
   330             while (a != 0 && a->type() != Atom::BriefRight) {
       
   331                 if (a->type() == Atom::String || a->type() == Atom::AutoLink)
       
   332                     str += a->string();
       
   333                 a = a->next();
       
   334             }
       
   335             str[0] = str[0].toLower();
       
   336             if (str.right(1) == ".")
       
   337                 str.chop(1);
       
   338 
       
   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 ");
       
   344             else
       
   345                 writer.writeCharacters(" ");
       
   346         }
       
   347         break;
       
   348 
       
   349     case Atom::BriefRight:
       
   350         if (relative->type() == Node::Property || relative->type() == Node::Variable)
       
   351             writer.writeCharacters(".");
       
   352 
       
   353         writer.writeEndElement(); // brief
       
   354         break;
       
   355 
       
   356     case Atom::C:
       
   357         writer.writeStartElement("teletype");
       
   358         if (inLink)
       
   359             writer.writeAttribute("type", "normal");
       
   360         else
       
   361             writer.writeAttribute("type", "highlighted");
       
   362 
       
   363         writer.writeCharacters(plainCode(atom->string()));
       
   364         writer.writeEndElement(); // teletype
       
   365         break;
       
   366 
       
   367     case Atom::Code:
       
   368         writer.writeTextElement("code", trimmedTrailing(plainCode(atom->string())));
       
   369         break;
       
   370 
       
   371 #ifdef QDOC_QML        
       
   372     case Atom::Qml:
       
   373         writer.writeTextElement("qml", trimmedTrailing(plainCode(atom->string())));
       
   374 #endif
       
   375         
       
   376     case Atom::CodeBad:
       
   377         writer.writeTextElement("badcode", trimmedTrailing(plainCode(atom->string())));
       
   378         break;
       
   379 
       
   380     case Atom::CodeNew:
       
   381         writer.writeTextElement("para", "you can rewrite it as");
       
   382         writer.writeTextElement("newcode", trimmedTrailing(plainCode(atom->string())));
       
   383         break;
       
   384 
       
   385     case Atom::CodeOld:
       
   386         writer.writeTextElement("para", "For example, if you have code like");
       
   387         writer.writeTextElement("oldcode", trimmedTrailing(plainCode(atom->string())));
       
   388         break;
       
   389 
       
   390     case Atom::CodeQuoteArgument:
       
   391         if (quoteCommand == "dots") {
       
   392             writer.writeAttribute("indent", atom->string());
       
   393             writer.writeCharacters("...");
       
   394         } else
       
   395             writer.writeCharacters(atom->string());
       
   396         writer.writeEndElement(); // code
       
   397         break;
       
   398 
       
   399     case Atom::CodeQuoteCommand:
       
   400         quoteCommand = atom->string();
       
   401         writer.writeStartElement(quoteCommand);
       
   402         break;
       
   403 
       
   404     case Atom::FootnoteLeft:
       
   405         writer.writeStartElement("footnote");
       
   406         break;
       
   407 
       
   408     case Atom::FootnoteRight:
       
   409         writer.writeEndElement(); // footnote
       
   410         break;
       
   411 /*
       
   412     case Atom::FormatElse:
       
   413         writer.writeStartElement("else");
       
   414         writer.writeEndElement(); // else
       
   415         break;
       
   416 */
       
   417     case Atom::FormatEndif:
       
   418         writer.writeEndElement(); // raw
       
   419         break;
       
   420     case Atom::FormatIf:
       
   421         writer.writeStartElement("raw");
       
   422         writer.writeAttribute("format", atom->string());
       
   423         break;
       
   424     case Atom::FormattingLeft:
       
   425 	{
       
   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");
       
   442         }
       
   443         break;
       
   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>";
       
   451                     skipAhead = 1;
       
   452                 }
       
   453             }
       
   454         }*/
       
   455     case Atom::FormattingRight:
       
   456 	{
       
   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();
       
   473         }
       
   474         if (inLink) {
       
   475             writer.writeEndElement(); // link
       
   476             inLink = false;
       
   477         }
       
   478 	break;
       
   479 /*        if ( atom->string() == ATOM_FORMATTING_LINK ) {
       
   480             if (inLink) {
       
   481                 if ( link.isEmpty() ) {
       
   482                     if (showBrokenLinks)
       
   483                         out() << "</i>";
       
   484                 } else {
       
   485                     out() << "</a>";
       
   486                 }
       
   487             }
       
   488             inLink = false;
       
   489         } else {
       
   490             out() << formattingRightMap()[atom->string()];
       
   491         }*/
       
   492     case Atom::GeneratedList:
       
   493         writer.writeStartElement("generatedlist");
       
   494         writer.writeAttribute("contents", atom->string());
       
   495         writer.writeEndElement(); // generatedlist
       
   496 /*
       
   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]);
       
   516                 }
       
   517                 generateAnnotatedList(relative, marker, editionClasses);
       
   518             }
       
   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;
       
   542                 }
       
   543                 generateAnnotatedList(fake, marker, groupMembersMap);
       
   544             }
       
   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())
       
   553                     list.prepend(node);
       
   554                 foreach (const Node *node, list)
       
   555                     generateBody(node, marker );
       
   556             }
       
   557         }
       
   558         break;
       
   559 */
       
   560         break;
       
   561     case Atom::Image:
       
   562         writer.writeStartElement("image");
       
   563         writer.writeAttribute("href", imageFileName(relative, atom->string()));
       
   564         writer.writeEndElement(); // image
       
   565         break;
       
   566 
       
   567     case Atom::InlineImage:
       
   568         writer.writeStartElement("inlineimage");
       
   569         writer.writeAttribute("href", imageFileName(relative, atom->string()));
       
   570         writer.writeEndElement(); // inlineimage
       
   571         break;
       
   572 
       
   573     case Atom::ImageText:
       
   574         break;
       
   575 
       
   576     case Atom::LegaleseLeft:
       
   577         writer.writeStartElement("legalese");
       
   578         break;
       
   579 
       
   580     case Atom::LegaleseRight:
       
   581         writer.writeEndElement(); // legalese
       
   582         break;
       
   583 
       
   584     case Atom::Link:
       
   585     case Atom::LinkNode:
       
   586         if (!inLink) {
       
   587             const Node *node = findNode(atom, relative, marker);
       
   588             if (node)
       
   589                 startLink(writer, atom, node, relative);
       
   590         }
       
   591         break;
       
   592 
       
   593     case Atom::ListLeft:
       
   594         writer.writeStartElement("list");
       
   595 
       
   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");
       
   602         else {
       
   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");
       
   614         }
       
   615         break;
       
   616 
       
   617     case Atom::ListItemNumber:
       
   618         break;
       
   619 
       
   620     case Atom::ListTagLeft:
       
   621         {
       
   622             writer.writeStartElement("definition");
       
   623 
       
   624             writer.writeTextElement("term", plainCode(
       
   625                 marker->markedUpEnumValue(atom->next()->string(), relative)));
       
   626         }
       
   627         break;
       
   628 
       
   629     case Atom::ListTagRight:
       
   630         writer.writeEndElement(); // definition
       
   631         break;
       
   632 
       
   633     case Atom::ListItemLeft:
       
   634         writer.writeStartElement("item");
       
   635         break;
       
   636 
       
   637     case Atom::ListItemRight:
       
   638         writer.writeEndElement(); // item
       
   639         break;
       
   640 
       
   641     case Atom::ListRight:
       
   642         writer.writeEndElement(); // list
       
   643         break;
       
   644 
       
   645     case Atom::Nop:
       
   646         break;
       
   647 
       
   648     case Atom::ParaLeft:
       
   649         writer.writeStartElement("para");
       
   650         break;
       
   651 
       
   652     case Atom::ParaRight:
       
   653         writer.writeEndElement(); // para
       
   654         break;
       
   655 
       
   656     case Atom::QuotationLeft:
       
   657         writer.writeStartElement("quote");
       
   658         break;
       
   659 
       
   660     case Atom::QuotationRight:
       
   661         writer.writeEndElement(); // quote
       
   662         break;
       
   663 
       
   664     case Atom::RawString:
       
   665         writer.writeCharacters(atom->string());
       
   666         break;
       
   667 
       
   668     case Atom::SectionLeft:
       
   669         writer.writeStartElement("section");
       
   670         writer.writeAttribute("id", Doc::canonicalTitle(Text::sectionHeading(atom).toString()));
       
   671         break;
       
   672 
       
   673     case Atom::SectionRight:
       
   674         writer.writeEndElement(); // section
       
   675         break;
       
   676 
       
   677     case Atom::SectionHeadingLeft:
       
   678         writer.writeStartElement("heading");
       
   679         writer.writeAttribute("level", atom->string()); // + hOffset(relative)
       
   680         inSectionHeading = true;
       
   681         break;
       
   682 
       
   683     case Atom::SectionHeadingRight:
       
   684         writer.writeEndElement(); // heading
       
   685         inSectionHeading = false;
       
   686         break;
       
   687 
       
   688     case Atom::SidebarLeft:
       
   689     case Atom::SidebarRight:
       
   690         break;
       
   691 
       
   692     case Atom::SnippetCommand:
       
   693         writer.writeStartElement(atom->string());
       
   694         break;
       
   695 
       
   696     case Atom::SnippetIdentifier:
       
   697         writer.writeAttribute("identifier", atom->string());
       
   698         writer.writeEndElement(); // snippet
       
   699         break;
       
   700 
       
   701     case Atom::SnippetLocation:
       
   702         writer.writeAttribute("location", atom->string());
       
   703         break;
       
   704 
       
   705     case Atom::String:
       
   706         writer.writeCharacters(atom->string());
       
   707         break;
       
   708 
       
   709     case Atom::TableLeft:
       
   710         writer.writeStartElement("table");
       
   711         if (atom->string().contains("%"))
       
   712             writer.writeAttribute("width", atom->string());
       
   713         break;
       
   714 
       
   715     case Atom::TableRight:
       
   716         writer.writeEndElement(); // table
       
   717         break;
       
   718 
       
   719     case Atom::TableHeaderLeft:
       
   720         writer.writeStartElement("header");
       
   721         break;
       
   722 
       
   723     case Atom::TableHeaderRight:
       
   724         writer.writeEndElement(); // header
       
   725         break;
       
   726 
       
   727     case Atom::TableRowLeft:
       
   728         writer.writeStartElement("row");
       
   729         break;
       
   730 
       
   731     case Atom::TableRowRight:
       
   732         writer.writeEndElement(); // row
       
   733         break;
       
   734 
       
   735     case Atom::TableItemLeft:
       
   736         {
       
   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         }
       
   746         break;
       
   747 
       
   748     case Atom::TableItemRight:
       
   749         writer.writeEndElement(); // item
       
   750         break;
       
   751 
       
   752     case Atom::TableOfContents:
       
   753         writer.writeStartElement("tableofcontents");
       
   754         writer.writeAttribute("details", atom->string());
       
   755         {
       
   756             int numColumns = 1;
       
   757             const Node *node = relative;
       
   758 
       
   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);
       
   765                 pieces.pop_front();
       
   766                 QString path = pieces.join(" ").trimmed();
       
   767                 node = findNode(path, relative, marker);
       
   768                 if (node)
       
   769                     writer.writeAttribute("href", fileName(node));
       
   770             }
       
   771 
       
   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));
       
   777             }
       
   778 
       
   779             if (node)
       
   780                 generateTableOfContents(writer, node, sectioningUnit, numColumns,
       
   781                                         relative);
       
   782         }
       
   783         writer.writeEndElement(); // tableofcontents
       
   784         break;
       
   785 
       
   786     case Atom::Target:
       
   787         writer.writeStartElement("target");
       
   788         writer.writeAttribute("name", Doc::canonicalTitle(atom->string()));
       
   789         writer.writeEndElement(); // target
       
   790         break;
       
   791 
       
   792     case Atom::UnhandledFormat:
       
   793     case Atom::UnknownCommand:
       
   794         writer.writeCharacters(atom->typeString());
       
   795         break;
       
   796     default:
       
   797         break;
       
   798     }
       
   799 
       
   800     if (atom)
       
   801         return atom->next();
       
   802 
       
   803     return 0;
       
   804 }
       
   805 /*
       
   806         QDomElement atomElement = document.createElement(atom->typeString().toLower());
       
   807         QDomText atomValue = document.createTextNode(atom->string());
       
   808         atomElement.appendChild(atomValue);
       
   809         descriptionElement.appendChild(atomElement);
       
   810 */
       
   811 
       
   812 /*
       
   813     ### Warning: findNode() is a modified version of HtmlGenerator::getLink().
       
   814 */
       
   815 const Node *WebXMLGenerator::findNode(const Atom *atom, const Node *relative, CodeMarker *marker)
       
   816 {
       
   817     return findNode(atom->string(), relative, marker);
       
   818 }
       
   819 
       
   820 const Node *WebXMLGenerator::findNode(const QString &title, const Node *relative, CodeMarker *marker)
       
   821 {
       
   822     QString link;
       
   823     if (title.contains(":") &&
       
   824             (title.startsWith("file:")
       
   825              || title.startsWith("http:")
       
   826              || title.startsWith("https:")
       
   827              || title.startsWith("ftp:")
       
   828              || title.startsWith("mailto:"))) {
       
   829 
       
   830         return 0;
       
   831     } else if (title.count('@') == 1) {
       
   832         return 0;
       
   833     } else {
       
   834         QStringList path;
       
   835         if (title.contains('#')) {
       
   836             path = title.split('#');
       
   837         } else {
       
   838             path.append(title);
       
   839         }
       
   840 
       
   841         const Node *node = 0;
       
   842         Atom *targetAtom = 0;
       
   843 
       
   844         QString first = path.first().trimmed();
       
   845         if (first.isEmpty()) {
       
   846             node = relative;
       
   847         } else if (first.endsWith(".html")) {
       
   848             node = tre->root()->findNode(first, Node::Fake);
       
   849         } else {
       
   850             node = marker->resolveTarget(first, tre, relative);
       
   851             if (!node)
       
   852                 node = tre->findFakeNodeByTitle(first);
       
   853             if (!node)
       
   854                 node = tre->findUnambiguousTarget(first, targetAtom);
       
   855         }
       
   856 
       
   857         if (node) {
       
   858             if (!node->url().isEmpty())
       
   859                 return node;
       
   860             else
       
   861                 path.removeFirst();
       
   862         } else {
       
   863             return 0;
       
   864         }
       
   865 
       
   866         while (!path.isEmpty()) {
       
   867             targetAtom = tre->findTarget(path.first(), node);
       
   868             if (targetAtom == 0)
       
   869                 break;
       
   870             path.removeFirst();
       
   871         }
       
   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);
       
   876         }
       
   877 */
       
   878         return node;
       
   879     }
       
   880     return 0;
       
   881 }
       
   882 
       
   883 void WebXMLGenerator::startLink(QXmlStreamWriter &writer, const Atom *atom,
       
   884                                 const Node *node, const Node *relative)
       
   885 {
       
   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);
       
   893             if (targetAtom)
       
   894                 location += "#" + Doc::canonicalTitle(target);
       
   895         }
       
   896         writer.writeAttribute("href", location);
       
   897         QString type = targetType(node);
       
   898         writer.writeAttribute("type", type);
       
   899         switch (node->type()) {
       
   900         case Node::Enum:
       
   901             writer.writeAttribute("enum", tre->fullDocumentName(node));
       
   902             break;
       
   903         case Node::Fake:
       
   904             writer.writeAttribute("page", tre->fullDocumentName(node));
       
   905             break;
       
   906         case Node::Property:
       
   907         {
       
   908             const PropertyNode *propertyNode = static_cast<const PropertyNode *>(node);
       
   909             if (propertyNode->getters().size() > 0)
       
   910                 writer.writeAttribute("getter", tre->fullDocumentName(propertyNode->getters()[0]));
       
   911         }
       
   912         default:
       
   913             ;
       
   914         }
       
   915         inLink = true;
       
   916     }
       
   917 }
       
   918 
       
   919 QString WebXMLGenerator::targetType(const Node *node)
       
   920 {
       
   921     switch (node->type()) {
       
   922         case Node::Namespace:
       
   923             return "namespace";
       
   924             break;
       
   925         case Node::Class:
       
   926             return "class";
       
   927             break;
       
   928         case Node::Fake:
       
   929             return "page";
       
   930             break;
       
   931         case Node::Enum:
       
   932             return "enum";
       
   933             break;
       
   934         case Node::Typedef:
       
   935             return "typedef";
       
   936             break;
       
   937         case Node::Property:
       
   938             return "property";
       
   939             break;
       
   940         case Node::Function:
       
   941             return "function";
       
   942             break;
       
   943         case Node::Variable:
       
   944             return "variable";
       
   945             break;
       
   946         case Node::Target:
       
   947             return "target";
       
   948             break;
       
   949         default:
       
   950             return "";
       
   951     }
       
   952     return "";
       
   953 }
       
   954 
       
   955 void WebXMLGenerator::generateRelations(QXmlStreamWriter &writer, const Node *node, CodeMarker *marker)
       
   956 {
       
   957     if (node && !node->links().empty()) {
       
   958         QPair<QString,QString> linkPair;
       
   959         QPair<QString,QString> anchorPair;
       
   960         const Node *linkNode;
       
   961 
       
   962         foreach (Node::LinkType relation, node->links().keys()) {
       
   963 
       
   964             linkPair = node->links()[relation];
       
   965             linkNode = findNode(linkPair.first, node, marker);
       
   966             
       
   967             if (!linkNode)
       
   968                 linkNode = node;
       
   969 
       
   970             if (linkNode == node)
       
   971                 anchorPair = linkPair;
       
   972             else
       
   973                 anchorPair = anchorForNode(linkNode);
       
   974 
       
   975             writer.writeStartElement("relation");
       
   976             writer.writeAttribute("href", anchorPair.first);
       
   977             writer.writeAttribute("type", targetType(linkNode));
       
   978             
       
   979             switch (relation) {
       
   980             case Node::StartLink:
       
   981                 writer.writeAttribute("meta", "start");
       
   982                 break;
       
   983             case Node::NextLink:
       
   984                 writer.writeAttribute("meta", "next");
       
   985                 break;
       
   986             case Node::PreviousLink:
       
   987                 writer.writeAttribute("meta", "previous");
       
   988                 break;
       
   989             case Node::ContentsLink: 
       
   990                 writer.writeAttribute("meta", "contents");
       
   991                 break;
       
   992             case Node::IndexLink:
       
   993                 writer.writeAttribute("meta", "index");
       
   994                 break;
       
   995             default:
       
   996                 writer.writeAttribute("meta", "");
       
   997             }
       
   998             writer.writeAttribute("description", anchorPair.second);
       
   999             writer.writeEndElement(); // link
       
  1000         }
       
  1001     }
       
  1002 }
       
  1003 
       
  1004 // Classes adapted from HtmlGenerator.
       
  1005 
       
  1006 void WebXMLGenerator::generateTableOfContents(QXmlStreamWriter &writer, const Node *node,
       
  1007                                               Doc::SectioningUnit sectioningUnit,
       
  1008                                               int numColumns, const Node *relative)
       
  1009 
       
  1010 {
       
  1011     if (!node->doc().hasTableOfContents())
       
  1012         return;
       
  1013     QList<Atom *> toc = node->doc().tableOfContents();
       
  1014     if (toc.isEmpty())
       
  1015         return;
       
  1016 
       
  1017     QString nodeName = "";
       
  1018     if (node != relative)
       
  1019         nodeName = node->name();
       
  1020 
       
  1021     QStringList sectionNumber;
       
  1022     int columnSize = 0;
       
  1023 
       
  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) + "%");
       
  1030     }
       
  1031 
       
  1032     // disable nested links in table of contents
       
  1033     inContents = true;
       
  1034     inLink = true;
       
  1035 
       
  1036     for (int i = 0; i < toc.size(); ++i) {
       
  1037         Atom *atom = toc.at(i);
       
  1038 
       
  1039         int nextLevel = atom->string().toInt();
       
  1040         if (nextLevel > (int)sectioningUnit)
       
  1041             continue;
       
  1042 
       
  1043         if (sectionNumber.size() < nextLevel) {
       
  1044             do {
       
  1045                 writer.writeStartElement("list");
       
  1046                 sectionNumber.append("1");
       
  1047             } while (sectionNumber.size() < nextLevel);
       
  1048         } else {
       
  1049             while (sectionNumber.size() > nextLevel) {
       
  1050                 writer.writeEndElement();
       
  1051                 sectionNumber.removeLast();
       
  1052             }
       
  1053             sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1);
       
  1054         }
       
  1055         Text headingText = Text::sectionHeading(atom);
       
  1056 
       
  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");
       
  1063             columnSize = 0;
       
  1064         }
       
  1065 
       
  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
       
  1075 
       
  1076         ++columnSize;
       
  1077     }
       
  1078     while (!sectionNumber.isEmpty()) {
       
  1079         writer.writeEndElement(); // list
       
  1080         sectionNumber.removeLast();
       
  1081     }
       
  1082 
       
  1083     if (numColumns > 1) {
       
  1084         writer.writeEndElement(); // item
       
  1085         writer.writeEndElement(); // row
       
  1086         writer.writeEndElement(); // table
       
  1087     }
       
  1088 
       
  1089     inContents = false;
       
  1090     inLink = false;
       
  1091 }
       
  1092 
       
  1093 void WebXMLGenerator::generateAnnotatedList(QXmlStreamWriter &writer,
       
  1094     const Node *relative, CodeMarker *marker, const QMap<QString, const Node *> &nodeMap)
       
  1095 {
       
  1096     writer.writeStartElement("table");
       
  1097     writer.writeAttribute("width", "100%");
       
  1098 
       
  1099     foreach (QString name, nodeMap.keys()) {
       
  1100         const Node *node = nodeMap[name];
       
  1101 
       
  1102         writer.writeStartElement("row");
       
  1103         writer.writeStartElement("heading");
       
  1104         generateFullName(writer, node, relative, marker);
       
  1105         writer.writeEndElement(); // heading
       
  1106 
       
  1107         writer.writeStartElement("item");
       
  1108         writer.writeCharacters(node->doc().briefText().toString());
       
  1109         writer.writeEndElement(); // item
       
  1110         writer.writeEndElement(); // row
       
  1111     }
       
  1112     writer.writeEndElement(); // table
       
  1113 }
       
  1114 
       
  1115 void WebXMLGenerator::generateFullName(QXmlStreamWriter &writer,
       
  1116     const Node *apparentNode, const Node *relative, CodeMarker *marker,
       
  1117     const Node *actualNode)
       
  1118 {
       
  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
       
  1126 }
       
  1127 
       
  1128 // Classes copied (and slightly adapted) from the HtmlGenerator. These need
       
  1129 // refactoring into a common ancestor class.
       
  1130 
       
  1131 void WebXMLGenerator::findAllClasses(const InnerNode *node)
       
  1132 {
       
  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;
       
  1141 
       
  1142                 QString moduleName = (*c)->moduleName();
       
  1143                 if (!moduleName.isEmpty())
       
  1144                     moduleClassMap[moduleName].insert((*c)->name(), *c);
       
  1145 
       
  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));
       
  1152             }
       
  1153         }
       
  1154         ++c;
       
  1155     }
       
  1156 }
       
  1157 
       
  1158 void WebXMLGenerator::findAllNamespaces(const InnerNode *node)
       
  1159 {
       
  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);
       
  1174                     }
       
  1175                 }
       
  1176             }
       
  1177         }
       
  1178         ++c;
       
  1179     }
       
  1180 }
       
  1181 
       
  1182 const QPair<QString,QString> WebXMLGenerator::anchorForNode(const Node *node)
       
  1183 {
       
  1184     QPair<QString,QString> anchorPair;
       
  1185 
       
  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();
       
  1190     }
       
  1191 
       
  1192     return anchorPair;
       
  1193 }
       
  1194 
       
  1195 QT_END_NAMESPACE