| 1 | /**************************************************************************** | 
|---|
| 2 | ** | 
|---|
| 3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). | 
|---|
| 4 | ** Contact: Qt Software Information (qt-info@nokia.com) | 
|---|
| 5 | ** | 
|---|
| 6 | ** This file is part of the tools applications of the Qt Toolkit. | 
|---|
| 7 | ** | 
|---|
| 8 | ** $QT_BEGIN_LICENSE:LGPL$ | 
|---|
| 9 | ** Commercial Usage | 
|---|
| 10 | ** Licensees holding valid Qt Commercial licenses may use this file in | 
|---|
| 11 | ** accordance with the Qt Commercial License Agreement provided with the | 
|---|
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
|---|
| 13 | ** a written agreement between you and Nokia. | 
|---|
| 14 | ** | 
|---|
| 15 | ** GNU Lesser General Public License Usage | 
|---|
| 16 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
|---|
| 17 | ** General Public License version 2.1 as published by the Free Software | 
|---|
| 18 | ** Foundation and appearing in the file LICENSE.LGPL included in the | 
|---|
| 19 | ** packaging of this file.  Please review the following information to | 
|---|
| 20 | ** ensure the GNU Lesser General Public License version 2.1 requirements | 
|---|
| 21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | 
|---|
| 22 | ** | 
|---|
| 23 | ** In addition, as a special exception, Nokia gives you certain | 
|---|
| 24 | ** additional rights. These rights are described in the Nokia Qt LGPL | 
|---|
| 25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this | 
|---|
| 26 | ** package. | 
|---|
| 27 | ** | 
|---|
| 28 | ** GNU General Public License Usage | 
|---|
| 29 | ** Alternatively, this file may be used under the terms of the GNU | 
|---|
| 30 | ** General Public License version 3.0 as published by the Free Software | 
|---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL included in the | 
|---|
| 32 | ** packaging of this file.  Please review the following information to | 
|---|
| 33 | ** ensure the GNU General Public License version 3.0 requirements will be | 
|---|
| 34 | ** met: http://www.gnu.org/copyleft/gpl.html. | 
|---|
| 35 | ** | 
|---|
| 36 | ** If you are unsure which license is appropriate for your use, please | 
|---|
| 37 | ** contact the sales department at qt-sales@nokia.com. | 
|---|
| 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() == FakeNode::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() == FakeNode::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 | 
|---|