summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xconfigure2
-rw-r--r--src/tools/qdoc/TODO.txt87
-rw-r--r--src/tools/qdoc/atom.cpp387
-rw-r--r--src/tools/qdoc/atom.h237
-rw-r--r--src/tools/qdoc/codechunk.cpp150
-rw-r--r--src/tools/qdoc/codechunk.h123
-rw-r--r--src/tools/qdoc/codemarker.cpp682
-rw-r--r--src/tools/qdoc/codemarker.h192
-rw-r--r--src/tools/qdoc/codeparser.cpp409
-rw-r--r--src/tools/qdoc/codeparser.h107
-rw-r--r--src/tools/qdoc/config.cpp978
-rw-r--r--src/tools/qdoc/config.h199
-rw-r--r--src/tools/qdoc/cppcodemarker.cpp1354
-rw-r--r--src/tools/qdoc/cppcodemarker.h96
-rw-r--r--src/tools/qdoc/cppcodeparser.cpp2502
-rw-r--r--src/tools/qdoc/cppcodeparser.h196
-rw-r--r--src/tools/qdoc/ditaxmlgenerator.cpp6434
-rw-r--r--src/tools/qdoc/ditaxmlgenerator.h543
-rw-r--r--src/tools/qdoc/doc.cpp3393
-rw-r--r--src/tools/qdoc/doc.h198
-rw-r--r--src/tools/qdoc/doc/config/compat.qdocconf31
-rw-r--r--src/tools/qdoc/doc/config/config.pro13
-rw-r--r--src/tools/qdoc/doc/config/images/arrow_down.pngbin0 -> 177 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/bg_l.pngbin0 -> 100 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/bg_l_blank.pngbin0 -> 84 bytes
-rw-r--r--src/tools/qdoc/doc/config/images/bg_ll_blank.pngbin0 -> 320 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/bg_r.pngbin0 -> 96 bytes
-rw-r--r--src/tools/qdoc/doc/config/images/bg_ul_blank.pngbin0 -> 304 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/box_bg.pngbin0 -> 89 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/breadcrumb.pngbin0 -> 134 bytes
-rw-r--r--src/tools/qdoc/doc/config/images/bullet_dn.pngbin0 -> 230 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/bullet_gt.pngbin0 -> 124 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/bullet_sq.pngbin0 -> 74 bytes
-rw-r--r--src/tools/qdoc/doc/config/images/bullet_up.pngbin0 -> 210 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/feedbackground.pngbin0 -> 263 bytes
-rw-r--r--src/tools/qdoc/doc/config/images/header_bg.pngbin0 -> 114 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/horBar.pngbin0 -> 2807 bytes
-rw-r--r--src/tools/qdoc/doc/config/images/page.pngbin0 -> 3102 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/page_bg.pngbin0 -> 84 bytes
-rw-r--r--src/tools/qdoc/doc/config/images/spinner.gifbin0 -> 2037 bytes
-rwxr-xr-xsrc/tools/qdoc/doc/config/images/sprites-combined.pngbin0 -> 62534 bytes
-rw-r--r--src/tools/qdoc/doc/config/macros.qdocconf40
-rw-r--r--src/tools/qdoc/doc/config/qdoc-online.qdocconf2
-rw-r--r--src/tools/qdoc/doc/config/qdoc-project.qdocconf48
-rw-r--r--src/tools/qdoc/doc/config/qdoc.qdocconf2
-rw-r--r--src/tools/qdoc/doc/config/qt-cpp-ignore.qdocconf98
-rw-r--r--src/tools/qdoc/doc/config/qt-defines.qdocconf17
-rw-r--r--src/tools/qdoc/doc/config/qt-html-default-styles.qdocconf32
-rw-r--r--src/tools/qdoc/doc/config/qt-html-online-styles.qdocconf72
-rw-r--r--src/tools/qdoc/doc/config/qt-html-templates-online.qdocconf115
-rw-r--r--src/tools/qdoc/doc/config/qt-html-templates.qdocconf54
-rw-r--r--src/tools/qdoc/doc/config/style/offline.css673
-rw-r--r--src/tools/qdoc/doc/corefeatures.qdoc35
-rw-r--r--src/tools/qdoc/doc/examples/componentset/ProgressBar.qml135
-rw-r--r--src/tools/qdoc/doc/examples/componentset/Switch.qml142
-rw-r--r--src/tools/qdoc/doc/examples/componentset/TabWidget.qml183
-rw-r--r--src/tools/qdoc/doc/examples/componentset/componentset.pro5
-rw-r--r--src/tools/qdoc/doc/examples/componentset/uicomponents.qdoc37
-rw-r--r--src/tools/qdoc/doc/examples/examples.qdoc84
-rw-r--r--src/tools/qdoc/doc/examples/layoutmanagement.qdocinc13
-rw-r--r--src/tools/qdoc/doc/examples/main.cpp54
-rw-r--r--src/tools/qdoc/doc/examples/minimum.qdocconf42
-rw-r--r--src/tools/qdoc/doc/examples/objectmodel.qdocinc11
-rw-r--r--src/tools/qdoc/doc/examples/samples.qdocinc109
-rw-r--r--src/tools/qdoc/doc/examples/signalandslots.qdocinc9
-rw-r--r--src/tools/qdoc/doc/files/compat.qdocconf12
-rw-r--r--src/tools/qdoc/doc/files/qt.qdocconf115
-rw-r--r--src/tools/qdoc/doc/images/happy.gifbin0 -> 11526 bytes
-rw-r--r--src/tools/qdoc/doc/images/happyguy.jpgbin0 -> 53442 bytes
-rw-r--r--src/tools/qdoc/doc/images/qt-logo.pngbin0 -> 5149 bytes
-rw-r--r--src/tools/qdoc/doc/images/training.jpgbin0 -> 8368 bytes
-rw-r--r--src/tools/qdoc/doc/qdoc-guide.qdoc671
-rw-r--r--src/tools/qdoc/doc/qdoc-manual.qdoc8780
-rw-r--r--src/tools/qdoc/editdistance.cpp114
-rw-r--r--src/tools/qdoc/editdistance.h59
-rw-r--r--src/tools/qdoc/generator.cpp1495
-rw-r--r--src/tools/qdoc/generator.h221
-rw-r--r--src/tools/qdoc/helpprojectwriter.cpp772
-rw-r--r--src/tools/qdoc/helpprojectwriter.h111
-rw-r--r--src/tools/qdoc/htmlgenerator.cpp5115
-rw-r--r--src/tools/qdoc/htmlgenerator.h319
-rw-r--r--src/tools/qdoc/jscodemarker.cpp148
-rw-r--r--src/tools/qdoc/jscodemarker.h75
-rw-r--r--src/tools/qdoc/location.cpp398
-rw-r--r--src/tools/qdoc/location.h131
-rw-r--r--src/tools/qdoc/main.cpp481
-rw-r--r--src/tools/qdoc/node.cpp2780
-rw-r--r--src/tools/qdoc/node.h958
-rw-r--r--src/tools/qdoc/openedlist.cpp228
-rw-r--r--src/tools/qdoc/openedlist.h91
-rw-r--r--src/tools/qdoc/pagegenerator.cpp388
-rw-r--r--src/tools/qdoc/pagegenerator.h99
-rw-r--r--src/tools/qdoc/plaincodemarker.cpp137
-rw-r--r--src/tools/qdoc/plaincodemarker.h79
-rw-r--r--src/tools/qdoc/puredocparser.cpp63
-rw-r--r--src/tools/qdoc/puredocparser.h72
-rw-r--r--src/tools/qdoc/qdoc.pro114
-rw-r--r--src/tools/qdoc/qmlcodemarker.cpp302
-rw-r--r--src/tools/qdoc/qmlcodemarker.h86
-rw-r--r--src/tools/qdoc/qmlcodeparser.cpp291
-rw-r--r--src/tools/qdoc/qmlcodeparser.h92
-rw-r--r--src/tools/qdoc/qmlmarkupvisitor.cpp851
-rw-r--r--src/tools/qdoc/qmlmarkupvisitor.h178
-rw-r--r--src/tools/qdoc/qmlparser/qmlparser.pri19
-rw-r--r--src/tools/qdoc/qmlparser/qqmljs.g3016
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsast.cpp931
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsast_p.h2640
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsastfwd_p.h186
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsastvisitor.cpp58
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsastvisitor_p.h329
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsengine_p.cpp161
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsengine_p.h126
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsglobal_p.h69
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsgrammar.cpp1013
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsgrammar_p.h211
-rw-r--r--src/tools/qdoc/qmlparser/qqmljskeywords_p.h860
-rw-r--r--src/tools/qdoc/qmlparser/qqmljslexer.cpp1171
-rw-r--r--src/tools/qdoc/qmlparser/qqmljslexer_p.h248
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h173
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsparser.cpp1817
-rw-r--r--src/tools/qdoc/qmlparser/qqmljsparser_p.h248
-rw-r--r--src/tools/qdoc/qmlvisitor.cpp619
-rw-r--r--src/tools/qdoc/qmlvisitor.h122
-rw-r--r--src/tools/qdoc/quoter.cpp377
-rw-r--r--src/tools/qdoc/quoter.h93
-rw-r--r--src/tools/qdoc/separator.cpp77
-rw-r--r--src/tools/qdoc/separator.h58
-rw-r--r--src/tools/qdoc/text.cpp287
-rw-r--r--src/tools/qdoc/text.h106
-rw-r--r--src/tools/qdoc/tokenizer.cpp771
-rw-r--r--src/tools/qdoc/tokenizer.h182
-rw-r--r--src/tools/qdoc/tr.h72
-rw-r--r--src/tools/qdoc/tree.cpp2358
-rw-r--r--src/tools/qdoc/tree.h174
-rw-r--r--src/tools/qdoc/yyindent.cpp1190
-rw-r--r--src/tools/tools.pro5
136 files changed, 65916 insertions, 2 deletions
diff --git a/configure b/configure
index f29df99ae9..151ddb046f 100755
--- a/configure
+++ b/configure
@@ -7169,7 +7169,7 @@ for file in .projects .projects.3; do
fi
SPEC=$XQMAKESPEC ;;
*/qmake/qmake.pro) continue ;;
- *tools/bootstrap*|*tools/moc*|*tools/rcc*|*tools/uic*) SPEC=$QMAKESPEC ;;
+ *tools/bootstrap*|*tools/moc*|*tools/rcc*|*tools/uic*|*tools/qdoc*) SPEC=$QMAKESPEC ;;
*) if [ "$CFG_NOPROCESS" = "yes" ]; then
continue
else
diff --git a/src/tools/qdoc/TODO.txt b/src/tools/qdoc/TODO.txt
new file mode 100644
index 0000000000..9bf4a2864f
--- /dev/null
+++ b/src/tools/qdoc/TODO.txt
@@ -0,0 +1,87 @@
+ * fix QWSPointerCalibrationData::devPoints and qwsServer
+ * Fix QMenu::addAction(QAction *) overload, "using" etc.
+ * fix space between two tables using <p></p>
+ * qpixmap-qt3.html; remove 8 public functions inherited from QPaintDevice
+ * \variable array
+ * Added support for parameterless macros (e.g. \macro Q_OBJECT).
+ * Made qdoc stricter regarding the data types (e.g. can't use \enum to document a typedef).
+ * Parse QT_MODULE() macro and generate proper warnings for the various editions.
+ * Fix parsing of \image following \value (e.g. qt.html).
+ * Don't turn X11 and similar names into links.
+ * Added automatic links from getters to setters and vice versa.
+ * Support \module and show which module each class is from.
+ * Fix occasional crash caused by misuse of const_cast().
+ * Provide clearer error messages when resolves fail.
+
+
+
+
+CHECK:
+
+ * Identify editions
+ * Automatic \sa getter setter
+ * \macro Q_OBJECT
+
+MUST HAVES:
+
+ * resolve [gs]etters for \sa using base class
+
+ * fix \overload when one is a signal and the other a normal function
+ * use "project" for .dcf files
+ * functions.html: include the types from QtGlobal as well as the functions (whatever that means)
+
+ * nice template function/class syntax
+ * spellchecker: built-in vs. builtin
+
+ * verbose mode for functions that don't exist
+ * No links to Porting Guide sections (e.g. QStringList)
+ * link toggled(bool)
+ * autolink foo(1)
+ * handle using correctly
+ * QObject "reentrant" list: duplicates
+ * operator<< \overload
+ * \compat \overload
+ * qWarning() link
+ * operator<<() autolink
+
+ * get rid of spurious 'global' functions
+ * Make automatic links in code work
+
+ * Fix encoding bug (see Important email from Simon Hausmann)
+ * Make links to QFoo::bar().baz() work
+ * Fix automatic links in \sectionX (e.g. qt4-getting-started.html)
+ * Provide a "List of all properties" page.
+
+ * expand QObjectList -> QList<QObject *>
+ * warning for unnamed parameters in property access functions
+ * \center...\endcenter
+
+LINKS:
+
+ * explanation following nonstandard wording warning
+
+ * omit \overload in operator<< and operator>>
+ * make operator-() unary and binary independent functions (no \overload)
+ * fix \overload
+ * fix \legalese
+ * remove warning for undocumented enum item like QLocale::LastLanguage
+ * improve the \a warnings for overloads; if one overload documents a para, fine
+
+ * implement \sidebar
+
+ * implement \legalesefile
+
+ * show in which module each class is
+ * list namespaces, list header files
+
+
+NICE FEATURES:
+ * implement inheritance tree for each class (as a PNG)
+ * avoid <p>...</p> in table/item cells without relying on horrible kludge
+ * prevent macros from having same name as commands
+ * be smart about enum types Foo::Bar vs. Bar when comparing functions
+ * be smart about const & non-const when comparing functions
+
+OTHER:
+ * make qdoc run faster
+ * make sure \headerfile works even if specified after \relates
diff --git a/src/tools/qdoc/atom.cpp b/src/tools/qdoc/atom.cpp
new file mode 100644
index 0000000000..777240c831
--- /dev/null
+++ b/src/tools/qdoc/atom.cpp
@@ -0,0 +1,387 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qregexp.h>
+#include "atom.h"
+#include "location.h"
+#include <stdio.h>
+
+QT_BEGIN_NAMESPACE
+
+QLatin1String Atom::BOLD_ ("bold");
+QLatin1String Atom::INDEX_ ("index");
+QLatin1String Atom::ITALIC_ ("italic");
+QLatin1String Atom::LINK_ ("link");
+QLatin1String Atom::PARAMETER_ ("parameter");
+QLatin1String Atom::SPAN_ ("span");
+QLatin1String Atom::SUBSCRIPT_ ("subscript");
+QLatin1String Atom::SUPERSCRIPT_ ("superscript");
+QLatin1String Atom::TELETYPE_ ("teletype");
+QLatin1String Atom::UNDERLINE_ ("underline");
+
+QLatin1String Atom::BULLET_ ("bullet");
+QLatin1String Atom::TAG_ ("tag");
+QLatin1String Atom::VALUE_ ("value");
+QLatin1String Atom::LOWERALPHA_ ("loweralpha");
+QLatin1String Atom::LOWERROMAN_ ("lowerroman");
+QLatin1String Atom::NUMERIC_ ("numeric");
+QLatin1String Atom::UPPERALPHA_ ("upperalpha");
+QLatin1String Atom::UPPERROMAN_ ("upperroman");
+
+/*! \class Atom
+ \brief The Atom class is the fundamental unit for representing
+ documents internally.
+
+ Atoms have a \i type and are completed by a \i string whose
+ meaning depends on the \i type. For example, the string
+ \quotation
+ \i italic text looks nicer than \bold bold text
+ \endquotation
+ is represented by the following atoms:
+ \quotation
+ (FormattingLeft, ATOM_FORMATTING_ITALIC)
+ (String, "italic")
+ (FormattingRight, ATOM_FORMATTING_ITALIC)
+ (String, " text is more attractive than ")
+ (FormattingLeft, ATOM_FORMATTING_BOLD)
+ (String, "bold")
+ (FormattingRight, ATOM_FORMATTING_BOLD)
+ (String, " text")
+ \endquotation
+
+ \also Text
+*/
+
+/*! \enum Atom::Type
+
+ \value AbstractLeft
+ \value AbstractRight
+ \value AnnotatedList
+ \value AutoLink
+ \value BaseName
+ \value BriefLeft
+ \value BriefRight
+ \value C
+ \value CaptionLeft
+ \value CaptionRight
+ \value Code
+ \value CodeBad
+ \value CodeNew
+ \value CodeOld
+ \value CodeQuoteArgument
+ \value CodeQuoteCommand
+ \value DivLeft
+ \value DivRight
+ \value EndQmlText
+ \value FormatElse
+ \value FormatEndif
+ \value FormatIf
+ \value FootnoteLeft
+ \value FootnoteRight
+ \value FormattingLeft
+ \value FormattingRight
+ \value GeneratedList
+ \value Image
+ \value ImageText
+ \value ImportantNote
+ \value InlineImage
+ \value LineBreak
+ \value Link
+ \value LinkNode
+ \value ListLeft
+ \value ListItemNumber
+ \value ListTagLeft
+ \value ListTagRight
+ \value ListItemLeft
+ \value ListItemRight
+ \value ListRight
+ \value Nop
+ \value Note
+ \value ParaLeft
+ \value ParaRight
+ \value Qml
+ \value QmlText
+ \value QuotationLeft
+ \value QuotationRight
+ \value RawString
+ \value SectionLeft
+ \value SectionRight
+ \value SectionHeadingLeft
+ \value SectionHeadingRight
+ \value SidebarLeft
+ \value SidebarRight
+ \value SinceList
+ \value String
+ \value TableLeft
+ \value TableRight
+ \value TableHeaderLeft
+ \value TableHeaderRight
+ \value TableRowLeft
+ \value TableRowRight
+ \value TableItemLeft
+ \value TableItemRight
+ \value TableOfContents
+ \value Target
+ \value UnhandledFormat
+ \value UnknownCommand
+*/
+
+static const struct {
+ const char *english;
+ int no;
+} atms[] = {
+ { "AbstractLeft", Atom::AbstractLeft },
+ { "AbstractRight", Atom::AbstractRight },
+ { "AnnotatedList", Atom::AnnotatedList },
+ { "AutoLink", Atom::AutoLink },
+ { "BaseName", Atom::BaseName },
+ { "BriefLeft", Atom::BriefLeft },
+ { "BriefRight", Atom::BriefRight },
+ { "C", Atom::C },
+ { "CaptionLeft", Atom::CaptionLeft },
+ { "CaptionRight", Atom::CaptionRight },
+ { "Code", Atom::Code },
+ { "CodeBad", Atom::CodeBad },
+ { "CodeNew", Atom::CodeNew },
+ { "CodeOld", Atom::CodeOld },
+ { "CodeQuoteArgument", Atom::CodeQuoteArgument },
+ { "CodeQuoteCommand", Atom::CodeQuoteCommand },
+ { "DivLeft", Atom::DivLeft },
+ { "DivRight", Atom::DivRight },
+ { "EndQmlText", Atom::EndQmlText },
+ { "FootnoteLeft", Atom::FootnoteLeft },
+ { "FootnoteRight", Atom::FootnoteRight },
+ { "FormatElse", Atom::FormatElse },
+ { "FormatEndif", Atom::FormatEndif },
+ { "FormatIf", Atom::FormatIf },
+ { "FormattingLeft", Atom::FormattingLeft },
+ { "FormattingRight", Atom::FormattingRight },
+ { "GeneratedList", Atom::GeneratedList },
+ { "GuidLink", Atom::GuidLink},
+ { "Image", Atom::Image },
+ { "ImageText", Atom::ImageText },
+ { "ImportantLeft", Atom::ImportantLeft },
+ { "ImportantRight", Atom::ImportantRight },
+ { "InlineImage", Atom::InlineImage },
+ { "JavaScript", Atom::JavaScript },
+ { "EndJavaScript", Atom::EndJavaScript },
+ { "LegaleseLeft", Atom::LegaleseLeft },
+ { "LegaleseRight", Atom::LegaleseRight },
+ { "LineBreak", Atom::LineBreak },
+ { "Link", Atom::Link },
+ { "LinkNode", Atom::LinkNode },
+ { "ListLeft", Atom::ListLeft },
+ { "ListItemNumber", Atom::ListItemNumber },
+ { "ListTagLeft", Atom::ListTagLeft },
+ { "ListTagRight", Atom::ListTagRight },
+ { "ListItemLeft", Atom::ListItemLeft },
+ { "ListItemRight", Atom::ListItemRight },
+ { "ListRight", Atom::ListRight },
+ { "Nop", Atom::Nop },
+ { "NoteLeft", Atom::NoteLeft },
+ { "NoteRight", Atom::NoteRight },
+ { "ParaLeft", Atom::ParaLeft },
+ { "ParaRight", Atom::ParaRight },
+ { "Qml", Atom::Qml},
+ { "QmlText", Atom::QmlText },
+ { "QuotationLeft", Atom::QuotationLeft },
+ { "QuotationRight", Atom::QuotationRight },
+ { "RawString", Atom::RawString },
+ { "SectionLeft", Atom::SectionLeft },
+ { "SectionRight", Atom::SectionRight },
+ { "SectionHeadingLeft", Atom::SectionHeadingLeft },
+ { "SectionHeadingRight", Atom::SectionHeadingRight },
+ { "SidebarLeft", Atom::SidebarLeft },
+ { "SidebarRight", Atom::SidebarRight },
+ { "SinceList", Atom::SinceList },
+ { "SnippetCommand", Atom::SnippetCommand },
+ { "SnippetIdentifier", Atom::SnippetIdentifier },
+ { "SnippetLocation", Atom::SnippetLocation },
+ { "String", Atom::String },
+ { "TableLeft", Atom::TableLeft },
+ { "TableRight", Atom::TableRight },
+ { "TableHeaderLeft", Atom::TableHeaderLeft },
+ { "TableHeaderRight", Atom::TableHeaderRight },
+ { "TableRowLeft", Atom::TableRowLeft },
+ { "TableRowRight", Atom::TableRowRight },
+ { "TableItemLeft", Atom::TableItemLeft },
+ { "TableItemRight", Atom::TableItemRight },
+ { "TableOfContents", Atom::TableOfContents },
+ { "Target", Atom::Target },
+ { "UnhandledFormat", Atom::UnhandledFormat },
+ { "UnknownCommand", Atom::UnknownCommand },
+ { 0, 0 }
+};
+
+/*! \fn Atom::Atom(Type type, const QString& string)
+
+ Constructs an atom of the specified \a type with the single
+ parameter \a string and does not put the new atom in a list.
+*/
+
+/*! \fn Atom::Atom(Type type, const QString& p1, const QString& p2)
+
+ Constructs an atom of the specified \a type with the two
+ parameters \a p1 and \a p2 and does not put the new atom
+ in a list.
+*/
+
+/*! \fn Atom(Atom *previous, Type type, const QString& string)
+
+ Constructs an atom of the specified \a type with the single
+ parameter \a string and inserts the new atom into the list
+ after the \a previous atom.
+*/
+
+/*! \fn Atom::Atom(Atom* previous, Type type, const QString& p1, const QString& p2)
+
+ Constructs an atom of the specified \a type with the two
+ parameters \a p1 and \a p2 and inserts the new atom into
+ the list after the \a previous atom.
+*/
+
+/*! \fn void Atom::appendChar(QChar ch)
+
+ Appends \a ch to the string parameter of this atom.
+
+ \also string()
+*/
+
+/*! \fn void Atom::appendString(const QString& string)
+
+ Appends \a string to the string parameter of this atom.
+
+ \also string()
+*/
+
+/*! \fn void Atom::chopString()
+
+ \also string()
+*/
+
+/*! \fn Atom *Atom::next()
+ Return the next atom in the atom list.
+ \also type(), string()
+*/
+
+/*!
+ Return the next Atom in the list if it is of Type \a t.
+ Otherwise return 0.
+ */
+const Atom* Atom::next(Type t) const
+{
+ return (next_ && (next_->type() == t)) ? next_ : 0;
+}
+
+/*!
+ Return the next Atom in the list if it is of Type \a t
+ and its string part is \a s. Otherwise return 0.
+ */
+const Atom* Atom::next(Type t, const QString& s) const
+{
+ return (next_ && (next_->type() == t) && (next_->string() == s)) ? next_ : 0;
+}
+
+/*! \fn const Atom *Atom::next() const
+ Return the next atom in the atom list.
+ \also type(), string()
+*/
+
+/*! \fn Type Atom::type() const
+ Return the type of this atom.
+ \also string(), next()
+*/
+
+/*!
+ Return the type of this atom as a string. Return "Invalid" if
+ type() returns an impossible value.
+
+ This is only useful for debugging.
+
+ \also type()
+*/
+QString Atom::typeString() const
+{
+ static bool deja = false;
+
+ if (!deja) {
+ int i = 0;
+ while (atms[i].english != 0) {
+ if (atms[i].no != i)
+ Location::internalError(tr("atom %1 missing").arg(i));
+ i++;
+ }
+ deja = true;
+ }
+
+ int i = (int) type();
+ if (i < 0 || i > (int) Last)
+ return QLatin1String("Invalid");
+ return QLatin1String(atms[i].english);
+}
+
+/*! \fn const QString& Atom::string() const
+
+ Returns the string parameter that together with the type
+ characterizes this atom.
+
+ \also type(), next()
+*/
+
+/*!
+ Dumps this Atom to stderr in printer friendly form.
+ */
+void Atom::dump() const
+{
+ QString str = string();
+ str.replace(QLatin1String("\\"), QLatin1String("\\\\"));
+ str.replace(QLatin1String("\""), QLatin1String("\\\""));
+ str.replace(QLatin1String("\n"), QLatin1String("\\n"));
+ str.replace(QRegExp(QLatin1String("[^\x20-\x7e]")), QLatin1String("?"));
+ if (!str.isEmpty())
+ str = QLatin1String(" \"") + str + QLatin1String("\"");
+ fprintf(stderr,
+ " %-15s%s\n",
+ typeString().toLatin1().data(),
+ str.toLatin1().data());
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/atom.h b/src/tools/qdoc/atom.h
new file mode 100644
index 0000000000..584e8fcd08
--- /dev/null
+++ b/src/tools/qdoc/atom.h
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ atom.h
+*/
+
+#ifndef ATOM_H
+#define ATOM_H
+
+#include <qstringlist.h>
+
+#define QDOC_QML
+
+QT_BEGIN_NAMESPACE
+
+class Atom
+{
+public:
+ enum Type {
+ AbstractLeft,
+ AbstractRight,
+ AnnotatedList,
+ AutoLink,
+ BaseName,
+ BriefLeft,
+ BriefRight,
+ C,
+ CaptionLeft,
+ CaptionRight,
+ Code,
+ CodeBad,
+ CodeNew,
+ CodeOld,
+ CodeQuoteArgument,
+ CodeQuoteCommand,
+ DivLeft,
+ DivRight,
+ EndQmlText,
+ FootnoteLeft,
+ FootnoteRight,
+ FormatElse,
+ FormatEndif,
+ FormatIf,
+ FormattingLeft,
+ FormattingRight,
+ GeneratedList,
+ GuidLink,
+ Image,
+ ImageText,
+ ImportantLeft,
+ ImportantRight,
+ InlineImage,
+ JavaScript,
+ EndJavaScript,
+ LegaleseLeft,
+ LegaleseRight,
+ LineBreak,
+ Link,
+ LinkNode,
+ ListLeft,
+ ListItemNumber,
+ ListTagLeft,
+ ListTagRight,
+ ListItemLeft,
+ ListItemRight,
+ ListRight,
+ Nop,
+ NoteLeft,
+ NoteRight,
+ ParaLeft,
+ ParaRight,
+ Qml,
+ QmlText,
+ QuotationLeft,
+ QuotationRight,
+ RawString,
+ SectionLeft,
+ SectionRight,
+ SectionHeadingLeft,
+ SectionHeadingRight,
+ SidebarLeft,
+ SidebarRight,
+ SinceList,
+ SnippetCommand,
+ SnippetIdentifier,
+ SnippetLocation,
+ String,
+ TableLeft,
+ TableRight,
+ TableHeaderLeft,
+ TableHeaderRight,
+ TableRowLeft,
+ TableRowRight,
+ TableItemLeft,
+ TableItemRight,
+ TableOfContents,
+ Target,
+ UnhandledFormat,
+ UnknownCommand,
+ Last = UnknownCommand
+ };
+
+ Atom(Type type, const QString& string = "")
+ : next_(0), type_(type)
+ {
+ strs << string;
+ }
+
+ Atom(Type type, const QString& p1, const QString& p2)
+ : next_(0), type_(type)
+ {
+ strs << p1;
+ if (!p2.isEmpty())
+ strs << p2;
+ }
+
+ Atom(Atom* previous, Type type, const QString& string = "")
+ : next_(previous->next_), type_(type)
+ {
+ strs << string;
+ previous->next_ = this;
+ }
+
+ Atom(Atom* previous, Type type, const QString& p1, const QString& p2)
+ : next_(previous->next_), type_(type)
+ {
+ strs << p1;
+ if (!p2.isEmpty())
+ strs << p2;
+ previous->next_ = this;
+ }
+
+ void appendChar(QChar ch) { strs[0] += ch; }
+ void appendString(const QString& string) { strs[0] += string; }
+ void chopString() { strs[0].chop(1); }
+ void setString(const QString& string) { strs[0] = string; }
+ Atom* next() { return next_; }
+ void setNext(Atom* newNext) { next_ = newNext; }
+
+ const Atom* next() const { return next_; }
+ const Atom* next(Type t) const;
+ const Atom* next(Type t, const QString& s) const;
+ Type type() const { return type_; }
+ QString typeString() const;
+ const QString& string() const { return strs[0]; }
+ const QString& string(int i) const { return strs[i]; }
+ int count() const { return strs.size(); }
+ void dump() const;
+
+ static QLatin1String BOLD_;
+ static QLatin1String INDEX_;
+ static QLatin1String ITALIC_;
+ static QLatin1String LINK_;
+ static QLatin1String PARAMETER_;
+ static QLatin1String SPAN_;
+ static QLatin1String SUBSCRIPT_;
+ static QLatin1String SUPERSCRIPT_;
+ static QLatin1String TELETYPE_;
+ static QLatin1String UNDERLINE_;
+
+ static QLatin1String BULLET_;
+ static QLatin1String TAG_;
+ static QLatin1String VALUE_;
+ static QLatin1String LOWERALPHA_;
+ static QLatin1String LOWERROMAN_;
+ static QLatin1String NUMERIC_;
+ static QLatin1String UPPERALPHA_;
+ static QLatin1String UPPERROMAN_;
+
+private:
+ Atom* next_;
+ Type type_;
+ QStringList strs;
+};
+
+#define ATOM_FORMATTING_BOLD "bold"
+#define ATOM_FORMATTING_INDEX "index"
+#define ATOM_FORMATTING_ITALIC "italic"
+#define ATOM_FORMATTING_LINK "link"
+#define ATOM_FORMATTING_PARAMETER "parameter"
+#define ATOM_FORMATTING_SPAN "span "
+#define ATOM_FORMATTING_SUBSCRIPT "subscript"
+#define ATOM_FORMATTING_SUPERSCRIPT "superscript"
+#define ATOM_FORMATTING_TELETYPE "teletype"
+#define ATOM_FORMATTING_UNDERLINE "underline"
+
+#define ATOM_LIST_BULLET "bullet"
+#define ATOM_LIST_TAG "tag"
+#define ATOM_LIST_VALUE "value"
+#define ATOM_LIST_LOWERALPHA "loweralpha"
+#define ATOM_LIST_LOWERROMAN "lowerroman"
+#define ATOM_LIST_NUMERIC "numeric"
+#define ATOM_LIST_UPPERALPHA "upperalpha"
+#define ATOM_LIST_UPPERROMAN "upperroman"
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/codechunk.cpp b/src/tools/qdoc/codechunk.cpp
new file mode 100644
index 0000000000..a722bb109e
--- /dev/null
+++ b/src/tools/qdoc/codechunk.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ codechunk.cpp
+*/
+
+#include <qregexp.h>
+#include <qstringlist.h>
+
+#include "codechunk.h"
+
+QT_BEGIN_NAMESPACE
+
+enum { Other, Alnum, Gizmo, Comma, LParen, RParen, RAngle, Colon };
+
+// entries 128 and above are Other
+static const int charCategory[256] = {
+ Other, Other, Other, Other, Other, Other, Other, Other,
+ Other, Other, Other, Other, Other, Other, Other, Other,
+ Other, Other, Other, Other, Other, Other, Other, Other,
+ Other, Other, Other, Other, Other, Other, Other, Other,
+ // ! " # $ % & '
+ Other, Other, Other, Other, Other, Gizmo, Gizmo, Other,
+ // ( ) * + , - . /
+ LParen, RParen, Gizmo, Gizmo, Comma, Other, Other, Gizmo,
+ // 0 1 2 3 4 5 6 7
+ Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum,
+ // 8 9 : ; < = > ?
+ Alnum, Alnum, Colon, Other, Other, Gizmo, RAngle, Gizmo,
+ // @ A B C D E F G
+ Other, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum,
+ // H I J K L M N O
+ Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum,
+ // P Q R S T U V W
+ Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum,
+ // X Y Z [ \ ] ^ _
+ Alnum, Alnum, Alnum, Other, Other, Other, Gizmo, Alnum,
+ // ` a b c d e f g
+ Other, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum,
+ // h i j k l m n o
+ Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum,
+ // p q r s t u v w
+ Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum,
+ // x y z { | } ~
+ Alnum, Alnum, Alnum, LParen, Gizmo, RParen, Other, Other
+};
+
+static const bool needSpace[8][8] = {
+ /* [ a + , ( ) > : */
+ /* [ */ { false, false, false, false, false, true, false, false },
+ /* a */ { false, true, true, false, false, true, false, false },
+ /* + */ { false, true, false, false, false, true, false, true },
+ /* , */ { true, true, true, true, true, true, true, true },
+ /* ( */ { true, true, true, false, true, false, true, true },
+ /* ) */ { true, true, true, false, true, true, true, true },
+ /* > */ { true, true, true, false, true, true, true, false },
+ /* : */ { false, false, true, true, true, true, true, false }
+};
+
+static int category( QChar ch )
+{
+ return charCategory[(int)ch.toLatin1()];
+}
+
+CodeChunk::CodeChunk()
+ : hotspot( -1 )
+{
+}
+
+CodeChunk::CodeChunk( const QString& str )
+ : s( str ), hotspot( -1 )
+{
+}
+
+void CodeChunk::append( const QString& lexeme )
+{
+ if ( !s.isEmpty() && !lexeme.isEmpty() ) {
+ /*
+ Should there be a space or not between the code chunk so far and the
+ new lexeme?
+ */
+ int cat1 = category(s.at(s.size() - 1));
+ int cat2 = category(lexeme[0]);
+ if ( needSpace[cat1][cat2] )
+ s += QLatin1Char( ' ' );
+ }
+ s += lexeme;
+}
+
+void CodeChunk::appendHotspot()
+{
+ /*
+ The first hotspot is the right one.
+ */
+ if ( hotspot == -1 )
+ hotspot = s.length();
+}
+
+QString CodeChunk::toString() const
+{
+ return s;
+}
+
+QStringList CodeChunk::toPath() const
+{
+ QString t = s;
+ t.remove(QRegExp(QLatin1String("<([^<>]|<([^<>]|<[^<>]*>)*>)*>")));
+ return t.split(QLatin1String("::"));
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/codechunk.h b/src/tools/qdoc/codechunk.h
new file mode 100644
index 0000000000..ee30f85a05
--- /dev/null
+++ b/src/tools/qdoc/codechunk.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ codechunk.h
+*/
+
+#ifndef CODECHUNK_H
+#define CODECHUNK_H
+
+#include <qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+// ### get rid of that class
+
+/*
+ The CodeChunk class represents a tiny piece of C++ code.
+
+ The class provides conversion between a list of lexemes and a string. It adds
+ spaces at the right place for consistent style. The tiny pieces of code it
+ represents are data types, enum values, and default parameter values.
+
+ Apart from the piece of code itself, there are two bits of metainformation
+ stored in CodeChunk: the base and the hotspot. The base is the part of the
+ piece that may be a hypertext link. The base of
+
+ QMap<QString, QString>
+
+ is QMap.
+
+ The hotspot is the place the variable name should be inserted in the case of a
+ variable (or parameter) declaration. The base of
+
+ char * []
+
+ is between '*' and '[]'.
+*/
+class CodeChunk
+{
+public:
+ CodeChunk();
+ CodeChunk( const QString& str );
+
+ void append( const QString& lexeme );
+ void appendHotspot();
+
+ bool isEmpty() const { return s.isEmpty(); }
+ QString toString() const;
+ QStringList toPath() const;
+ QString left() const { return s.left(hotspot == -1 ? s.length() : hotspot); }
+ QString right() const { return s.mid(hotspot == -1 ? s.length() : hotspot); }
+
+private:
+ QString s;
+ int hotspot;
+};
+
+inline bool operator==( const CodeChunk& c, const CodeChunk& d ) {
+ return c.toString() == d.toString();
+}
+
+inline bool operator!=( const CodeChunk& c, const CodeChunk& d ) {
+ return !( c == d );
+}
+
+inline bool operator<( const CodeChunk& c, const CodeChunk& d ) {
+ return c.toString() < d.toString();
+}
+
+inline bool operator>( const CodeChunk& c, const CodeChunk& d ) {
+ return d < c;
+}
+
+inline bool operator<=( const CodeChunk& c, const CodeChunk& d ) {
+ return !( c > d );
+}
+
+inline bool operator>=( const CodeChunk& c, const CodeChunk& d ) {
+ return !( c < d );
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/codemarker.cpp b/src/tools/qdoc/codemarker.cpp
new file mode 100644
index 0000000000..791e08062b
--- /dev/null
+++ b/src/tools/qdoc/codemarker.cpp
@@ -0,0 +1,682 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QMetaObject>
+#include "codemarker.h"
+#include "config.h"
+#include "node.h"
+#include <qdebug.h>
+#include <stdio.h>
+
+QT_BEGIN_NAMESPACE
+
+QString CodeMarker::defaultLang;
+QList<CodeMarker *> CodeMarker::markers;
+
+/*!
+ When a code marker constructs itself, it puts itself into
+ the static list of code markers. All the code markers in
+ the static list get initialized in initialize(), which is
+ not called until after the qdoc configuration file has
+ been read.
+ */
+CodeMarker::CodeMarker()
+{
+ markers.prepend(this);
+}
+
+/*!
+ When a code marker destroys itself, it removes itself from
+ the static list of code markers.
+ */
+CodeMarker::~CodeMarker()
+{
+ markers.removeAll(this);
+}
+
+/*!
+ A code market performs no initialization by default. Marker-specific
+ initialization is performed in subclasses.
+ */
+void CodeMarker::initializeMarker(const Config& ) // config
+{
+}
+
+/*!
+ Terminating a code marker is trivial.
+ */
+void CodeMarker::terminateMarker()
+{
+ // nothing.
+}
+
+/*!
+ All the code markers in the static list are initialized
+ here, after the qdoc configuration file has been loaded.
+ */
+void CodeMarker::initialize(const Config& config)
+{
+ defaultLang = config.getString(QLatin1String(CONFIG_LANGUAGE));
+ QList<CodeMarker *>::ConstIterator m = markers.begin();
+ while (m != markers.end()) {
+ (*m)->initializeMarker(config);
+ ++m;
+ }
+}
+
+/*!
+ All the code markers in the static list are terminated here.
+ */
+void CodeMarker::terminate()
+{
+ QList<CodeMarker *>::ConstIterator m = markers.begin();
+ while (m != markers.end()) {
+ (*m)->terminateMarker();
+ ++m;
+ }
+}
+
+CodeMarker *CodeMarker::markerForCode(const QString& code)
+{
+ CodeMarker *defaultMarker = markerForLanguage(defaultLang);
+ if (defaultMarker != 0 && defaultMarker->recognizeCode(code))
+ return defaultMarker;
+
+ QList<CodeMarker *>::ConstIterator m = markers.begin();
+ while (m != markers.end()) {
+ if ((*m)->recognizeCode(code))
+ return *m;
+ ++m;
+ }
+ return defaultMarker;
+}
+
+CodeMarker *CodeMarker::markerForFileName(const QString& fileName)
+{
+ CodeMarker *defaultMarker = markerForLanguage(defaultLang);
+ int dot = -1;
+ while ((dot = fileName.lastIndexOf(QLatin1Char('.'), dot)) != -1) {
+ QString ext = fileName.mid(dot + 1);
+ if (defaultMarker != 0 && defaultMarker->recognizeExtension(ext))
+ return defaultMarker;
+ QList<CodeMarker *>::ConstIterator m = markers.begin();
+ while (m != markers.end()) {
+ if ((*m)->recognizeExtension(ext))
+ return *m;
+ ++m;
+ }
+ --dot;
+ }
+ return defaultMarker;
+}
+
+CodeMarker *CodeMarker::markerForLanguage(const QString& lang)
+{
+ QList<CodeMarker *>::ConstIterator m = markers.begin();
+ while (m != markers.end()) {
+ if ((*m)->recognizeLanguage(lang))
+ return *m;
+ ++m;
+ }
+ return 0;
+}
+
+const Node *CodeMarker::nodeForString(const QString& string)
+{
+ if (sizeof(const Node *) == sizeof(uint)) {
+ return reinterpret_cast<const Node *>(string.toUInt());
+ }
+ else {
+ return reinterpret_cast<const Node *>(string.toULongLong());
+ }
+}
+
+QString CodeMarker::stringForNode(const Node *node)
+{
+ if (sizeof(const Node *) == sizeof(ulong)) {
+ return QString::number(reinterpret_cast<quintptr>(node));
+ }
+ else {
+ return QString::number(reinterpret_cast<qulonglong>(node));
+ }
+}
+
+static const QString samp = QLatin1String("&amp;");
+static const QString slt = QLatin1String("&lt;");
+static const QString sgt = QLatin1String("&gt;");
+static const QString squot = QLatin1String("&quot;");
+
+QString CodeMarker::protect(const QString& str)
+{
+ int n = str.length();
+ QString marked;
+ marked.reserve(n * 2 + 30);
+ const QChar *data = str.constData();
+ for (int i = 0; i != n; ++i) {
+ switch (data[i].unicode()) {
+ case '&': marked += samp; break;
+ case '<': marked += slt; break;
+ case '>': marked += sgt; break;
+ case '"': marked += squot; break;
+ default : marked += data[i];
+ }
+ }
+ return marked;
+}
+
+QString CodeMarker::typified(const QString &string)
+{
+ QString result;
+ QString pendingWord;
+
+ for (int i = 0; i <= string.size(); ++i) {
+ QChar ch;
+ if (i != string.size())
+ ch = string.at(i);
+
+ QChar lower = ch.toLower();
+ if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z'))
+ || ch.digitValue() >= 0 || ch == QLatin1Char('_')
+ || ch == QLatin1Char(':')) {
+ pendingWord += ch;
+ }
+ else {
+ if (!pendingWord.isEmpty()) {
+ bool isProbablyType = (pendingWord != QLatin1String("const"));
+ if (isProbablyType)
+ result += QLatin1String("<@type>");
+ result += pendingWord;
+ if (isProbablyType)
+ result += QLatin1String("</@type>");
+ }
+ pendingWord.clear();
+
+ switch (ch.unicode()) {
+ case '\0':
+ break;
+ case '&':
+ result += QLatin1String("&amp;");
+ break;
+ case '<':
+ result += QLatin1String("&lt;");
+ break;
+ case '>':
+ result += QLatin1String("&gt;");
+ break;
+ default:
+ result += ch;
+ }
+ }
+ }
+ return result;
+}
+
+QString CodeMarker::taggedNode(const Node* node)
+{
+ QString tag;
+ QString name = node->name();
+
+ switch (node->type()) {
+ case Node::Namespace:
+ tag = QLatin1String("@namespace");
+ break;
+ case Node::Class:
+ tag = QLatin1String("@class");
+ break;
+ case Node::Enum:
+ tag = QLatin1String("@enum");
+ break;
+ case Node::Typedef:
+ tag = QLatin1String("@typedef");
+ break;
+ case Node::Function:
+ tag = QLatin1String("@function");
+ break;
+ case Node::Property:
+ tag = QLatin1String("@property");
+ break;
+ case Node::Fake:
+ /*
+ Remove the "QML:" prefix, if present.
+ There shouldn't be any of these "QML:"
+ prefixes in the documentation sources
+ after the switch to using QML module
+ qualifiers, but this code is kept to
+ be backward compatible.
+ */
+ if (node->subType() == Node::QmlClass) {
+ if (node->name().startsWith(QLatin1String("QML:")))
+ name = name.mid(4);
+ }
+ tag = QLatin1String("@property");
+ break;
+ default:
+ tag = QLatin1String("@unknown");
+ break;
+ }
+ return QLatin1Char('<') + tag + QLatin1Char('>') + protect(name)
+ + QLatin1String("</") + tag + QLatin1Char('>');
+}
+
+QString CodeMarker::taggedQmlNode(const Node* node)
+{
+ QString tag;
+ switch (node->type()) {
+ case Node::QmlProperty:
+ tag = QLatin1String("@property");
+ break;
+ case Node::QmlSignal:
+ tag = QLatin1String("@signal");
+ break;
+ case Node::QmlSignalHandler:
+ tag = QLatin1String("@signalhandler");
+ break;
+ case Node::QmlMethod:
+ tag = QLatin1String("@method");
+ break;
+ default:
+ tag = QLatin1String("@unknown");
+ break;
+ }
+ return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name())
+ + QLatin1String("</") + tag + QLatin1Char('>');
+}
+
+QString CodeMarker::linkTag(const Node *node, const QString& body)
+{
+ return QLatin1String("<@link node=\"") + stringForNode(node)
+ + QLatin1String("\">") + body + QLatin1String("</@link>");
+}
+
+QString CodeMarker::sortName(const Node *node, const QString* name)
+{
+ QString nodeName;
+ if (name != 0)
+ nodeName = *name;
+ else
+ nodeName = node->name();
+ int numDigits = 0;
+ for (int i = nodeName.size() - 1; i > 0; --i) {
+ if (nodeName.at(i).digitValue() == -1)
+ break;
+ ++numDigits;
+ }
+
+ // we want 'qint8' to appear before 'qint16'
+ if (numDigits > 0) {
+ for (int i = 0; i < 4 - numDigits; ++i)
+ nodeName.insert(nodeName.size()-numDigits-1, QLatin1Char('0'));
+ }
+
+ if (node->type() == Node::Function) {
+ const FunctionNode *func = static_cast<const FunctionNode *>(node);
+ QString sortNo;
+ if (func->metaness() == FunctionNode::Ctor) {
+ sortNo = QLatin1String("C");
+ }
+ else if (func->metaness() == FunctionNode::Dtor) {
+ sortNo = QLatin1String("D");
+ }
+ else {
+ if (nodeName.startsWith(QLatin1String("operator"))
+ && nodeName.length() > 8
+ && !nodeName[8].isLetterOrNumber())
+ sortNo = QLatin1String("F");
+ else
+ sortNo = QLatin1String("E");
+ }
+ return sortNo + nodeName + QLatin1Char(' ')
+ + QString::number(func->overloadNumber(), 36);
+ }
+
+ if (node->type() == Node::Class)
+ return QLatin1Char('A') + nodeName;
+
+ if (node->type() == Node::Property || node->type() == Node::Variable)
+ return QLatin1Char('E') + nodeName;
+
+ return QLatin1Char('B') + nodeName;
+}
+
+void CodeMarker::insert(FastSection &fastSection,
+ Node *node,
+ SynopsisStyle style,
+ Status status)
+{
+ bool irrelevant = false;
+ bool inheritedMember = false;
+ if (!node->relates()) {
+ if (node->parent() != (const InnerNode*)fastSection.innerNode && !node->parent()->isAbstract()) {
+ if (node->type() != Node::QmlProperty)
+ inheritedMember = true;
+ }
+ }
+
+ if (node->access() == Node::Private) {
+ irrelevant = true;
+ }
+ else if (node->type() == Node::Function) {
+ FunctionNode *func = (FunctionNode *) node;
+ irrelevant = (inheritedMember
+ && (func->metaness() == FunctionNode::Ctor ||
+ func->metaness() == FunctionNode::Dtor));
+ }
+ else if (node->type() == Node::Class || node->type() == Node::Enum
+ || node->type() == Node::Typedef) {
+ irrelevant = (inheritedMember && style != Subpage);
+ if (!irrelevant && style == Detailed && node->type() == Node::Typedef) {
+ const TypedefNode* typedeffe = static_cast<const TypedefNode*>(node);
+ if (typedeffe->associatedEnum())
+ irrelevant = true;
+ }
+ }
+
+ if (!irrelevant) {
+ if (status == Compat) {
+ irrelevant = (node->status() != Node::Compat);
+ }
+ else if (status == Obsolete) {
+ irrelevant = (node->status() != Node::Obsolete);
+ }
+ else {
+ irrelevant = (node->status() == Node::Compat ||
+ node->status() == Node::Obsolete);
+ }
+ }
+
+ if (!irrelevant) {
+ if (!inheritedMember || style == Subpage) {
+ QString key = sortName(node);
+ if (!fastSection.memberMap.contains(key))
+ fastSection.memberMap.insert(key, node);
+ }
+ else {
+ if (node->parent()->type() == Node::Class) {
+ if (fastSection.inherited.isEmpty()
+ || fastSection.inherited.last().first != node->parent()) {
+ QPair<InnerNode *, int> p(node->parent(), 0);
+ fastSection.inherited.append(p);
+ }
+ fastSection.inherited.last().second++;
+ }
+ }
+ }
+}
+
+void CodeMarker::insert(FastSection& fastSection,
+ Node* node,
+ SynopsisStyle style,
+ bool /* includeClassName */)
+{
+ if (node->status() == Node::Compat || node->status() == Node::Obsolete)
+ return;
+
+ bool inheritedMember = false;
+ InnerNode* parent = node->parent();
+ if (parent && (parent->type() == Node::Fake) &&
+ (parent->subType() == Node::QmlPropertyGroup)) {
+ parent = parent->parent();
+ }
+ inheritedMember = (parent != (const InnerNode*)fastSection.innerNode);
+
+ if (!inheritedMember || style == Subpage) {
+ QString key = sortName(node);
+ if (!fastSection.memberMap.contains(key))
+ fastSection.memberMap.insert(key, node);
+ }
+ else {
+ if ((parent->type() == Node::Fake) && (parent->subType() == Node::QmlClass)) {
+ if (fastSection.inherited.isEmpty()
+ || fastSection.inherited.last().first != parent) {
+ QPair<InnerNode*, int> p(parent, 0);
+ fastSection.inherited.append(p);
+ }
+ fastSection.inherited.last().second++;
+ }
+ }
+}
+
+/*!
+ Returns true if \a node represents a reimplemented member function.
+ If it is, then it is inserted in the reimplemented member map in the
+ section \a fs. And, the test is only performed if \a status is \e OK.
+ Otherwise, false is returned.
+ */
+bool CodeMarker::insertReimpFunc(FastSection& fs, Node* node, Status status)
+{
+ if (node->access() == Node::Private)
+ return false;
+
+ const FunctionNode* fn = static_cast<const FunctionNode*>(node);
+ if ((fn->reimplementedFrom() != 0) && (status == Okay)) {
+ bool inherited = (!fn->relates() && (fn->parent() != (const InnerNode*)fs.innerNode));
+ if (!inherited) {
+ QString key = sortName(fn);
+ if (!fs.reimpMemberMap.contains(key)) {
+ fs.reimpMemberMap.insert(key,node);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/*!
+ If \a fs is not empty, convert it to a Section and append
+ the new Section to \a sectionList.
+ */
+void CodeMarker::append(QList<Section>& sectionList, const FastSection& fs, bool includeKeys)
+{
+ if (!fs.isEmpty()) {
+ Section section(fs.name,fs.divClass,fs.singularMember,fs.pluralMember);
+ if (includeKeys) {
+ section.keys = fs.memberMap.keys();
+ }
+ section.members = fs.memberMap.values();
+ section.reimpMembers = fs.reimpMemberMap.values();
+ section.inherited = fs.inherited;
+ sectionList.append(section);
+ }
+}
+
+static QString encode(const QString &string)
+{
+#if 0
+ QString result = string;
+
+ for (int i = string.size() - 1; i >= 0; --i) {
+ uint ch = string.at(i).unicode();
+ if (ch > 0xFF)
+ ch = '?';
+ if ((ch - '0') >= 10 && (ch - 'a') >= 26 && (ch - 'A') >= 26
+ && ch != '/' && ch != '(' && ch != ')' && ch != ',' && ch != '*'
+ && ch != '&' && ch != '_' && ch != '<' && ch != '>' && ch != ':'
+ && ch != '~')
+ result.replace(i, 1, QString("%") + QString("%1").arg(ch, 2, 16));
+ }
+ return result;
+#else
+ return string;
+#endif
+}
+
+QStringList CodeMarker::macRefsForNode(Node *node)
+{
+ QString result = QLatin1String("cpp/");
+ switch (node->type()) {
+ case Node::Class:
+ {
+ const ClassNode *classe = static_cast<const ClassNode *>(node);
+#if 0
+ if (!classe->templateStuff().isEmpty()) {
+ result += QLatin1String("tmplt/");
+ }
+ else
+#endif
+ {
+ result += QLatin1String("cl/");
+ }
+ result += macName(classe); // ### Maybe plainName?
+ }
+ break;
+ case Node::Enum:
+ {
+ QStringList stringList;
+ stringList << encode(result + QLatin1String("tag/") +
+ macName(node));
+ foreach (const QString &enumName, node->doc().enumItemNames()) {
+ // ### Write a plainEnumValue() and use it here
+ stringList << encode(result + QLatin1String("econst/") +
+ macName(node->parent(), enumName));
+ }
+ return stringList;
+ }
+ case Node::Typedef:
+ result += QLatin1String("tdef/") + macName(node);
+ break;
+ case Node::Function:
+ {
+ bool isMacro = false;
+ Q_UNUSED(isMacro)
+ const FunctionNode *func = static_cast<const FunctionNode *>(node);
+
+ // overloads are too clever for the Xcode documentation browser
+ if (func->isOverload())
+ return QStringList();
+
+ if (func->metaness() == FunctionNode::MacroWithParams
+ || func->metaness() == FunctionNode::MacroWithoutParams) {
+ result += QLatin1String("macro/");
+#if 0
+ }
+ else if (!func->templateStuff().isEmpty()) {
+ result += QLatin1String("ftmplt/");
+#endif
+ }
+ else if (func->isStatic()) {
+ result += QLatin1String("clm/");
+ }
+ else if (!func->parent()->name().isEmpty()) {
+ result += QLatin1String("instm/");
+ }
+ else {
+ result += QLatin1String("func/");
+ }
+
+ result += macName(func);
+ if (result.endsWith(QLatin1String("()")))
+ result.chop(2);
+#if 0
+ // this code is too clever for the Xcode documentation
+ // browser and/or pbhelpindexer
+ if (!isMacro) {
+ result += QLatin1Char('/') + QLatin1String(QMetaObject::normalizedSignature(func->returnType().toLatin1().constData())) + "/(";
+ const QList<Parameter> &params = func->parameters();
+ for (int i = 0; i < params.count(); ++i) {
+ QString type = params.at(i).leftType() +
+ params.at(i).rightType();
+ type = QLatin1String(QMetaObject::normalizedSignature(type.toLatin1().constData()));
+ if (i != 0)
+ result += QLatin1Char(',');
+ result += type;
+ }
+ result += QLatin1Char(')');
+ }
+#endif
+ }
+ break;
+ case Node::Variable:
+ result += QLatin1String("data/") + macName(node);
+ break;
+ case Node::Property:
+ {
+ NodeList list = static_cast<const PropertyNode*>(node)->functions();
+ QStringList stringList;
+ foreach (Node* node, list) {
+ stringList += macRefsForNode(node);
+ }
+ return stringList;
+ }
+ case Node::Namespace:
+ case Node::Fake:
+ case Node::Target:
+ default:
+ return QStringList();
+ }
+
+ return QStringList(encode(result));
+}
+
+QString CodeMarker::macName(const Node *node, const QString &name)
+{
+ QString myName = name;
+ if (myName.isEmpty()) {
+ myName = node->name();
+ node = node->parent();
+ }
+
+ if (node->name().isEmpty()) {
+ return QLatin1Char('/') + protect(myName);
+ }
+ else {
+ return plainFullName(node) + QLatin1Char('/') + protect(myName);
+ }
+}
+
+/*!
+ Get the list of documentation sections for the children of
+ the specified QmlClassNode.
+ */
+QList<Section> CodeMarker::qmlSections(const QmlClassNode* ,
+ SynopsisStyle )
+{
+ return QList<Section>();
+}
+
+const Node* CodeMarker::resolveTarget(const QString& ,
+ const Tree* ,
+ const Node* ,
+ const Node* )
+{
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/codemarker.h b/src/tools/qdoc/codemarker.h
new file mode 100644
index 0000000000..894d838a3b
--- /dev/null
+++ b/src/tools/qdoc/codemarker.h
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ codemarker.h
+*/
+
+#ifndef CODEMARKER_H
+#define CODEMARKER_H
+
+#include <qpair.h>
+
+#include "atom.h"
+#include "node.h"
+
+QT_BEGIN_NAMESPACE
+
+class Config;
+class Tree;
+
+struct Section
+{
+ QString name;
+ QString divClass;
+ QString singularMember;
+ QString pluralMember;
+ QStringList keys;
+ NodeList members;
+ NodeList reimpMembers;
+ QList<QPair<InnerNode *, int> > inherited;
+
+ Section() { }
+ Section(const QString& name0,
+ const QString& divClass0,
+ const QString& singularMember0,
+ const QString& pluralMember0)
+ : name(name0),
+ divClass(divClass0),
+ singularMember(singularMember0),
+ pluralMember(pluralMember0) { }
+ void appendMember(Node* node) { members.append(node); }
+ void appendReimpMember(Node* node) { reimpMembers.append(node); }
+};
+
+struct FastSection
+{
+ const InnerNode *innerNode;
+ QString name;
+ QString divClass;
+ QString singularMember;
+ QString pluralMember;
+ QMap<QString, Node *> memberMap;
+ QMap<QString, Node *> reimpMemberMap;
+ QList<QPair<InnerNode *, int> > inherited;
+
+ FastSection(const InnerNode *innerNode0,
+ const QString& name0,
+ const QString& divClass0,
+ const QString& singularMember0,
+ const QString& pluralMember0)
+ : innerNode(innerNode0),
+ name(name0),
+ divClass(divClass0),
+ singularMember(singularMember0),
+ pluralMember(pluralMember0) { }
+ bool isEmpty() const {
+ return (memberMap.isEmpty() &&
+ inherited.isEmpty() &&
+ reimpMemberMap.isEmpty());
+ }
+
+};
+
+class CodeMarker
+{
+public:
+ enum SynopsisStyle { Summary, Detailed, Subpage, Accessors };
+ enum Status { Compat, Obsolete, Okay };
+
+ CodeMarker();
+ virtual ~CodeMarker();
+
+ virtual void initializeMarker(const Config& config);
+ virtual void terminateMarker();
+ virtual bool recognizeCode(const QString& code) = 0;
+ virtual bool recognizeExtension(const QString& ext) = 0;
+ virtual bool recognizeLanguage(const QString& lang) = 0;
+ virtual Atom::Type atomType() const = 0;
+ virtual QString plainName(const Node *node) = 0;
+ virtual QString plainFullName(const Node *node,
+ const Node *relative = 0) = 0;
+ virtual QString markedUpCode(const QString& code,
+ const Node *relative,
+ const Location &location) = 0;
+ virtual QString markedUpSynopsis(const Node *node,
+ const Node *relative,
+ SynopsisStyle style) = 0;
+ virtual QString markedUpQmlItem(const Node* , bool) { return QString(); }
+ virtual QString markedUpName(const Node *node) = 0;
+ virtual QString markedUpFullName(const Node *node,
+ const Node *relative = 0) = 0;
+ virtual QString markedUpEnumValue(const QString &enumValue,
+ const Node *relative) = 0;
+ virtual QString markedUpIncludes(const QStringList& includes) = 0;
+ virtual QString functionBeginRegExp(const QString& funcName) = 0;
+ virtual QString functionEndRegExp(const QString& funcName) = 0;
+ virtual QList<Section> sections(const InnerNode *inner,
+ SynopsisStyle style,
+ Status status) = 0;
+ virtual QList<Section> qmlSections(const QmlClassNode* qmlClassNode,
+ SynopsisStyle style);
+ virtual const Node* resolveTarget(const QString& target,
+ const Tree* tree,
+ const Node* relative,
+ const Node* self = 0);
+ virtual QStringList macRefsForNode(Node* node);
+
+ static void initialize(const Config& config);
+ static void terminate();
+ static CodeMarker *markerForCode(const QString& code);
+ static CodeMarker *markerForFileName(const QString& fileName);
+ static CodeMarker *markerForLanguage(const QString& lang);
+ static const Node *nodeForString(const QString& string);
+ static QString stringForNode(const Node *node);
+
+ QString typified(const QString &string);
+
+protected:
+ virtual QString sortName(const Node *node, const QString* name = 0);
+ QString protect(const QString &string);
+ QString taggedNode(const Node* node);
+ QString taggedQmlNode(const Node* node);
+ QString linkTag(const Node *node, const QString& body);
+ void insert(FastSection &fastSection,
+ Node *node,
+ SynopsisStyle style,
+ Status status);
+ void insert(FastSection& fastSection,
+ Node* node,
+ SynopsisStyle style,
+ bool includeClassName = false);
+ bool insertReimpFunc(FastSection& fs, Node* node, Status status);
+ void append(QList<Section>& sectionList, const FastSection& fastSection, bool includeKeys = false);
+
+private:
+ QString macName(const Node *parent, const QString &name = QString());
+
+ static QString defaultLang;
+ static QList<CodeMarker *> markers;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/codeparser.cpp b/src/tools/qdoc/codeparser.cpp
new file mode 100644
index 0000000000..5173a404f2
--- /dev/null
+++ b/src/tools/qdoc/codeparser.cpp
@@ -0,0 +1,409 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ codeparser.cpp
+*/
+
+#include "codeparser.h"
+#include "node.h"
+#include "tree.h"
+#include "config.h"
+#include "generator.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+#define COMMAND_COMPAT Doc::alias(QLatin1String("compat"))
+#define COMMAND_DEPRECATED Doc::alias(QLatin1String("deprecated")) // ### don't document
+#define COMMAND_INGROUP Doc::alias(QLatin1String("ingroup"))
+#define COMMAND_INMODULE Doc::alias(QLatin1String("inmodule")) // ### don't document
+#define COMMAND_INQMLMODULE Doc::alias(QLatin1String("inqmlmodule"))
+#define COMMAND_INTERNAL Doc::alias(QLatin1String("internal"))
+#define COMMAND_MAINCLASS Doc::alias(QLatin1String("mainclass"))
+#define COMMAND_NONREENTRANT Doc::alias(QLatin1String("nonreentrant"))
+#define COMMAND_OBSOLETE Doc::alias(QLatin1String("obsolete"))
+#define COMMAND_PAGEKEYWORDS Doc::alias(QLatin1String("pagekeywords"))
+#define COMMAND_PRELIMINARY Doc::alias(QLatin1String("preliminary"))
+#define COMMAND_INPUBLICGROUP Doc::alias(QLatin1String("inpublicgroup"))
+#define COMMAND_REENTRANT Doc::alias(QLatin1String("reentrant"))
+#define COMMAND_SINCE Doc::alias(QLatin1String("since"))
+#define COMMAND_SUBTITLE Doc::alias(QLatin1String("subtitle"))
+#define COMMAND_THREADSAFE Doc::alias(QLatin1String("threadsafe"))
+#define COMMAND_TITLE Doc::alias(QLatin1String("title"))
+
+QString CodeParser::currentSubDir_;
+QList<CodeParser *> CodeParser::parsers;
+bool CodeParser::showInternal = false;
+QMap<QString,QString> CodeParser::nameToTitle;
+
+/*!
+ The constructor adds this code parser to the static
+ list of code parsers.
+ */
+CodeParser::CodeParser()
+{
+ parsers.prepend(this);
+}
+
+/*!
+ The destructor removes this code parser from the static
+ list of code parsers.
+ */
+CodeParser::~CodeParser()
+{
+ parsers.removeAll(this);
+}
+
+/*!
+ Initialize the code parser base class.
+ */
+void CodeParser::initializeParser(const Config& config)
+{
+ showInternal = config.getBool(QLatin1String(CONFIG_SHOWINTERNAL));
+}
+
+/*!
+ Terminating a code parser is trivial.
+ */
+void CodeParser::terminateParser()
+{
+ // nothing.
+}
+
+QStringList CodeParser::headerFileNameFilter()
+{
+ return sourceFileNameFilter();
+}
+
+void CodeParser::parseHeaderFile(const Location& location,
+ const QString& filePath,
+ Tree *tree)
+{
+ parseSourceFile(location, filePath, tree);
+}
+
+void CodeParser::doneParsingHeaderFiles(Tree *tree)
+{
+ doneParsingSourceFiles(tree);
+}
+
+/*!
+ All the code parsers in the static list are initialized here,
+ after the qdoc configuration variables have been set.
+ */
+void CodeParser::initialize(const Config& config)
+{
+ QList<CodeParser *>::ConstIterator p = parsers.begin();
+ while (p != parsers.end()) {
+ (*p)->initializeParser(config);
+ ++p;
+ }
+}
+
+/*!
+ All the code parsers in the static list are terminated here.
+ */
+void CodeParser::terminate()
+{
+ QList<CodeParser *>::ConstIterator p = parsers.begin();
+ while (p != parsers.end()) {
+ (*p)->terminateParser();
+ ++p;
+ }
+}
+
+CodeParser *CodeParser::parserForLanguage(const QString& language)
+{
+ QList<CodeParser *>::ConstIterator p = parsers.begin();
+ while (p != parsers.end()) {
+ if ((*p)->language() == language)
+ return *p;
+ ++p;
+ }
+ return 0;
+}
+
+CodeParser *CodeParser::parserForHeaderFile(const QString &filePath)
+{
+ QString fileName = QFileInfo(filePath).fileName();
+
+ QList<CodeParser *>::ConstIterator p = parsers.begin();
+ while (p != parsers.end()) {
+
+ QStringList headerPatterns = (*p)->headerFileNameFilter();
+ foreach (QString pattern, headerPatterns) {
+ QRegExp re(pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (re.exactMatch(fileName))
+ return *p;
+ }
+ ++p;
+ }
+ return 0;
+}
+
+CodeParser *CodeParser::parserForSourceFile(const QString &filePath)
+{
+ QString fileName = QFileInfo(filePath).fileName();
+
+ QList<CodeParser *>::ConstIterator p = parsers.begin();
+ while (p != parsers.end()) {
+
+ QStringList sourcePatterns = (*p)->sourceFileNameFilter();
+ foreach (QString pattern, sourcePatterns) {
+ QRegExp re(pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (re.exactMatch(fileName))
+ return *p;
+ }
+ ++p;
+ }
+ return 0;
+}
+
+/*!
+ Returns the set of strings representing the common metacommands.
+ */
+QSet<QString> CodeParser::commonMetaCommands()
+{
+ return QSet<QString>() << COMMAND_COMPAT
+ << COMMAND_DEPRECATED
+ << COMMAND_INGROUP
+ << COMMAND_INMODULE
+ << COMMAND_INQMLMODULE
+ << COMMAND_INTERNAL
+ << COMMAND_MAINCLASS
+ << COMMAND_NONREENTRANT
+ << COMMAND_OBSOLETE
+ << COMMAND_PAGEKEYWORDS
+ << COMMAND_PRELIMINARY
+ << COMMAND_INPUBLICGROUP
+ << COMMAND_REENTRANT
+ << COMMAND_SINCE
+ << COMMAND_SUBTITLE
+ << COMMAND_THREADSAFE
+ << COMMAND_TITLE;
+}
+
+/*!
+ The topic command has been processed. Now process the other
+ metacommands that were found. These are not the text markup
+ commands.
+ */
+void CodeParser::processCommonMetaCommand(const Location& location,
+ const QString& command,
+ const QString& arg,
+ Node* node,
+ Tree* tree)
+{
+ if (command == COMMAND_COMPAT) {
+ location.warning(tr("\\compat command used, but Qt3 compatibility is no longer supported"));
+ node->setStatus(Node::Compat);
+ }
+ else if (command == COMMAND_DEPRECATED) {
+ node->setStatus(Node::Deprecated);
+ }
+ else if (command == COMMAND_INGROUP) {
+ tree->addToGroup(node, arg);
+ }
+ else if (command == COMMAND_INPUBLICGROUP) {
+ tree->addToPublicGroup(node, arg);
+ }
+ else if (command == COMMAND_INMODULE) {
+ node->setModuleName(arg);
+ }
+ else if (command == COMMAND_INQMLMODULE) {
+ node->setQmlModuleName(arg);
+ tree->addToQmlModule(node,arg);
+ QString qmid = node->qmlModuleIdentifier();
+ QmlClassNode* qcn = static_cast<QmlClassNode*>(node);
+ QmlClassNode::moduleMap.insert(qmid + QLatin1String("::") + node->name(), qcn);
+ }
+ else if (command == COMMAND_MAINCLASS) {
+ node->setStatus(Node::Main);
+ }
+ else if (command == COMMAND_OBSOLETE) {
+ if (node->status() != Node::Compat)
+ node->setStatus(Node::Obsolete);
+ }
+ else if (command == COMMAND_NONREENTRANT) {
+ node->setThreadSafeness(Node::NonReentrant);
+ }
+ else if (command == COMMAND_PRELIMINARY) {
+ node->setStatus(Node::Preliminary);
+ }
+ else if (command == COMMAND_INTERNAL) {
+ if (!showInternal) {
+ node->setAccess(Node::Private);
+ node->setStatus(Node::Internal);
+ }
+ }
+ else if (command == COMMAND_REENTRANT) {
+ node->setThreadSafeness(Node::Reentrant);
+ }
+ else if (command == COMMAND_SINCE) {
+ node->setSince(arg);
+ }
+ else if (command == COMMAND_PAGEKEYWORDS) {
+ node->addPageKeywords(arg);
+ }
+ else if (command == COMMAND_SUBTITLE) {
+ if (node->type() == Node::Fake) {
+ FakeNode *fake = static_cast<FakeNode *>(node);
+ fake->setSubTitle(arg);
+ }
+ else
+ location.warning(tr("Ignored '\\%1'").arg(COMMAND_SUBTITLE));
+ }
+ else if (command == COMMAND_THREADSAFE) {
+ node->setThreadSafeness(Node::ThreadSafe);
+ }
+ else if (command == COMMAND_TITLE) {
+ if (node->type() == Node::Fake) {
+ FakeNode *fake = static_cast<FakeNode *>(node);
+ fake->setTitle(arg);
+ if (fake->subType() == Node::Example) {
+ ExampleNode::exampleNodeMap.insert(fake->title(),static_cast<ExampleNode*>(fake));
+ }
+ nameToTitle.insert(fake->name(),arg);
+ }
+ else
+ location.warning(tr("Ignored '\\%1'").arg(COMMAND_TITLE));
+ }
+}
+
+/*!
+ Find the page title given the page \a name and return it.
+ */
+const QString CodeParser::titleFromName(const QString& name)
+{
+ const QString t = nameToTitle.value(name);
+ return t;
+}
+
+/*!
+ \internal
+ */
+void CodeParser::extractPageLinkAndDesc(const QString& arg,
+ QString* link,
+ QString* desc)
+{
+ QRegExp bracedRegExp(QLatin1String("\\{([^{}]*)\\}(?:\\{([^{}]*)\\})?"));
+
+ if (bracedRegExp.exactMatch(arg)) {
+ *link = bracedRegExp.cap(1);
+ *desc = bracedRegExp.cap(2);
+ if (desc->isEmpty())
+ *desc = *link;
+ }
+ else {
+ int spaceAt = arg.indexOf(QLatin1Char(' '));
+ if (arg.contains(QLatin1String(".html")) && spaceAt != -1) {
+ *link = arg.left(spaceAt).trimmed();
+ *desc = arg.mid(spaceAt).trimmed();
+ }
+ else {
+ *link = arg;
+ *desc = arg;
+ }
+ }
+}
+
+/*!
+ \internal
+ */
+void CodeParser::setLink(Node* node, Node::LinkType linkType, const QString& arg)
+{
+ QString link;
+ QString desc;
+ extractPageLinkAndDesc(arg, &link, &desc);
+ node->setLink(linkType, link, desc);
+}
+
+/*!
+ If the \e {basedir} variable is not set in the qdocconf
+ file, do nothing.
+
+ Otherwise, search for the basedir string string in the
+ \a filePath. It must be found, or else a warning message
+ is output. Extract the subdirectory name that follows the
+ basedir name and create a subdirectory using that name
+ in the output director.
+ */
+void CodeParser::createOutputSubdirectory(const Location& location,
+ const QString& filePath)
+{
+ QString bd = Generator::baseDir();
+ if (!bd.isEmpty()) {
+ int baseIdx = filePath.indexOf(bd);
+ if (baseIdx == -1)
+ location.warning(tr("File path: '%1' does not contain bundle base dir: '%2'")
+ .arg(filePath).arg(bd));
+ else {
+ int subDirIdx = filePath.indexOf(QLatin1Char('/'),baseIdx);
+ if (subDirIdx == -1)
+ location.warning(tr("File path: '%1' has no sub dir after bundle base dir: '%2'")
+ .arg(filePath).arg(bd));
+ else {
+ ++subDirIdx;
+ int fileNameIdx = filePath.indexOf(QLatin1Char('/'),subDirIdx);
+ if (fileNameIdx == -1)
+ location.warning(tr("File path: '%1' has no file name after sub dir: '%2/'")
+ .arg(filePath).arg(filePath.mid(subDirIdx)));
+ else {
+ currentSubDir_ = filePath.mid(subDirIdx,fileNameIdx-subDirIdx);
+ if (currentSubDir_.isEmpty())
+ location.warning(tr("File path: '%1' has no sub dir after bundle base dir: '%2'")
+ .arg(filePath).arg(bd));
+ else {
+ QString subDirPath = Generator::outputDir() + QLatin1Char('/') + currentSubDir_;
+ QDir dirInfo;
+ if (!dirInfo.exists(subDirPath)) {
+ if (!dirInfo.mkpath(subDirPath))
+ location.fatal(tr("Cannot create output sub-directory '%1'").arg(currentSubDir_));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/codeparser.h b/src/tools/qdoc/codeparser.h
new file mode 100644
index 0000000000..f522567ddb
--- /dev/null
+++ b/src/tools/qdoc/codeparser.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ codeparser.h
+*/
+
+#ifndef CODEPARSER_H
+#define CODEPARSER_H
+
+#include <QSet>
+
+#include "node.h"
+
+QT_BEGIN_NAMESPACE
+
+class Config;
+class Node;
+class QString;
+class Tree;
+
+class CodeParser
+{
+public:
+ CodeParser();
+ virtual ~CodeParser();
+
+ virtual void initializeParser(const Config& config);
+ virtual void terminateParser();
+ virtual QString language() = 0;
+ virtual QStringList headerFileNameFilter();
+ virtual QStringList sourceFileNameFilter() = 0;
+ virtual void parseHeaderFile(const Location& location,
+ const QString& filePath, Tree *tree);
+ virtual void parseSourceFile(const Location& location,
+ const QString& filePath, Tree *tree) = 0;
+ virtual void doneParsingHeaderFiles(Tree *tree);
+ virtual void doneParsingSourceFiles(Tree *tree) = 0;
+
+ void createOutputSubdirectory(const Location& location, const QString& filePath);
+
+ static void initialize(const Config& config);
+ static void terminate();
+ static CodeParser *parserForLanguage(const QString& language);
+ static CodeParser *parserForHeaderFile(const QString &filePath);
+ static CodeParser *parserForSourceFile(const QString &filePath);
+ static const QString titleFromName(const QString& name);
+ static void setLink(Node* node, Node::LinkType linkType, const QString& arg);
+ static const QString& currentOutputSubdirectory() { return currentSubDir_; }
+
+protected:
+ QSet<QString> commonMetaCommands();
+ void processCommonMetaCommand(const Location& location,
+ const QString& command, const QString& arg,
+ Node *node, Tree *tree);
+ static void extractPageLinkAndDesc(const QString& arg,
+ QString* link,
+ QString* desc);
+
+private:
+ static QString currentSubDir_;
+ static QList<CodeParser *> parsers;
+ static bool showInternal;
+ static QMap<QString,QString> nameToTitle;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/config.cpp b/src/tools/qdoc/config.cpp
new file mode 100644
index 0000000000..f97b6ca93f
--- /dev/null
+++ b/src/tools/qdoc/config.cpp
@@ -0,0 +1,978 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ config.cpp
+*/
+
+#include <QDir>
+#include <QVariant>
+#include <QFile>
+#include <QTemporaryFile>
+#include <QTextStream>
+#include <qdebug.h>
+#include "config.h"
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ An entry on the MetaStack.
+ */
+class MetaStackEntry
+{
+public:
+ void open();
+ void close();
+
+ QStringList accum;
+ QStringList next;
+};
+
+/*
+ */
+void MetaStackEntry::open()
+{
+ next.append(QString());
+}
+
+/*
+ */
+void MetaStackEntry::close()
+{
+ accum += next;
+ next.clear();
+}
+
+/*
+ ###
+*/
+class MetaStack : private QStack<MetaStackEntry>
+{
+public:
+ MetaStack();
+
+ void process(QChar ch, const Location& location);
+ QStringList getExpanded(const Location& location);
+};
+
+MetaStack::MetaStack()
+{
+ push(MetaStackEntry());
+ top().open();
+}
+
+void MetaStack::process(QChar ch, const Location& location)
+{
+ if (ch == QLatin1Char('{')) {
+ push(MetaStackEntry());
+ top().open();
+ }
+ else if (ch == QLatin1Char('}')) {
+ if (count() == 1)
+ location.fatal(tr("Unexpected '}'"));
+
+ top().close();
+ QStringList suffixes = pop().accum;
+ QStringList prefixes = top().next;
+
+ top().next.clear();
+ QStringList::ConstIterator pre = prefixes.begin();
+ while (pre != prefixes.end()) {
+ QStringList::ConstIterator suf = suffixes.begin();
+ while (suf != suffixes.end()) {
+ top().next << (*pre + *suf);
+ ++suf;
+ }
+ ++pre;
+ }
+ }
+ else if (ch == QLatin1Char(',') && count() > 1) {
+ top().close();
+ top().open();
+ }
+ else {
+ QStringList::Iterator pre = top().next.begin();
+ while (pre != top().next.end()) {
+ *pre += ch;
+ ++pre;
+ }
+ }
+}
+
+QStringList MetaStack::getExpanded(const Location& location)
+{
+ if (count() > 1)
+ location.fatal(tr("Missing '}'"));
+
+ top().close();
+ return top().accum;
+}
+
+QT_STATIC_CONST_IMPL QString Config::dot = QLatin1String(".");
+QString Config::overrideOutputDir;
+QSet<QString> Config::overrideOutputFormats;
+QMap<QString, QString> Config::extractedDirs;
+int Config::numInstances;
+
+/*!
+ \class Config
+ \brief The Config class contains the configuration variables
+ for controlling how qdoc produces documentation.
+
+ Its load() function, reads, parses, and processes a qdocconf file.
+ */
+
+/*!
+ The constructor sets the \a programName and initializes all
+ internal state variables to empty values.
+ */
+Config::Config(const QString& programName)
+ : prog(programName)
+{
+ loc = Location::null;
+ lastLoc = Location::null;
+ locMap.clear();
+ stringValueMap.clear();
+ stringListValueMap.clear();
+ numInstances++;
+}
+
+/*!
+ The destructor has nothing special to do.
+ */
+Config::~Config()
+{
+}
+
+/*!
+ Loads and parses the qdoc configuration file \a fileName.
+ This function calls the other load() function, which does
+ the loading, parsing, and processing of the configuration
+ file.
+
+ Intializes the location variables returned by location()
+ and lastLocation().
+ */
+void Config::load(const QString& fileName)
+{
+ load(Location::null, fileName);
+ if (loc.isEmpty()) {
+ loc = Location(fileName);
+ }
+ else {
+ loc.setEtc(true);
+ }
+ lastLoc = Location::null;
+}
+
+/*!
+ Writes the qdoc configuration data to the named file.
+ The previous contents of the file are overwritten.
+ */
+void Config::unload(const QString& fileName)
+{
+ QStringMultiMap::ConstIterator v = stringValueMap.begin();
+ while (v != stringValueMap.end()) {
+ qDebug() << v.key() << " = " << v.value();
+#if 0
+ if (v.key().startsWith(varDot)) {
+ QString subVar = v.key().mid(varDot.length());
+ int dot = subVar.indexOf(QLatin1Char('.'));
+ if (dot != -1)
+ subVar.truncate(dot);
+ t.insert(subVar,v.value());
+ }
+#endif
+ ++v;
+ }
+ qDebug() << "fileName:" << fileName;
+}
+
+/*!
+ Joins all the strings in \a values into a single string with the
+ individual \a values separated by ' '. Then it inserts the result
+ into the string list map with \a var as the key.
+
+ It also inserts the \a values string list into a separate map,
+ also with \a var as the key.
+ */
+void Config::setStringList(const QString& var, const QStringList& values)
+{
+ stringValueMap[var] = values.join(QLatin1String(" "));
+ stringListValueMap[var] = values;
+}
+
+/*!
+ Looks up the configuarion variable \a var in the string
+ map and returns the boolean value.
+ */
+bool Config::getBool(const QString& var) const
+{
+ return QVariant(getString(var)).toBool();
+}
+
+/*!
+ Looks up the configuration variable \a var in the string list
+ map. Iterates through the string list found, interpreting each
+ string in the list as an integer and adding it to a total sum.
+ Returns the sum.
+ */
+int Config::getInt(const QString& var) const
+{
+ QStringList strs = getStringList(var);
+ QStringList::ConstIterator s = strs.begin();
+ int sum = 0;
+
+ while (s != strs.end()) {
+ sum += (*s).toInt();
+ ++s;
+ }
+ return sum;
+}
+
+/*!
+ Function to return the correct outputdir.
+ outputdir can be set using the qdocconf or the command-line
+ variable -outputdir.
+ */
+QString Config::getOutputDir() const
+{
+ if (overrideOutputDir.isNull())
+ return getString(QLatin1String(CONFIG_OUTPUTDIR));
+ else
+ return overrideOutputDir;
+}
+
+/*!
+ Function to return the correct outputformats.
+ outputformats can be set using the qdocconf or the command-line
+ variable -outputformat.
+ */
+QSet<QString> Config::getOutputFormats() const
+{
+ if (overrideOutputFormats.isEmpty())
+ return getStringSet(QLatin1String(CONFIG_OUTPUTFORMATS));
+ else
+ return overrideOutputFormats;
+}
+
+/*!
+ First, this function looks up the configuration variable \a var
+ in the location map and, if found, sets the internal variable
+ \c{lastLoc} to the Location that \a var maps to.
+
+ Then it looks up the configuration variable \a var in the string
+ map, and returns the string that \a var maps to.
+ */
+QString Config::getString(const QString& var) const
+{
+ if (!locMap[var].isEmpty())
+ (Location&) lastLoc = locMap[var];
+ return stringValueMap[var];
+}
+
+/*!
+ Looks up the configuration variable \a var in the string
+ list map, converts the string list it maps to into a set
+ of strings, and returns the set.
+ */
+QSet<QString> Config::getStringSet(const QString& var) const
+{
+ return QSet<QString>::fromList(getStringList(var));
+}
+
+/*!
+ First, this function looks up the configuration variable \a var
+ in the location map and, if found, sets the internal variable
+ \c{lastLoc} the Location that \a var maps to.
+
+ Then it looks up the configuration variable \a var in the string
+ list map, and returns the string list that \a var maps to.
+ */
+QStringList Config::getStringList(const QString& var) const
+{
+ if (!locMap[var].isEmpty())
+ (Location&) lastLoc = locMap[var];
+ return stringListValueMap[var];
+}
+
+/*!
+ This function should only be called when the configuration
+ variable \a var maps to a string list that contains file paths.
+ It cleans the paths with QDir::cleanPath() before returning
+ them.
+
+ First, this function looks up the configuration variable \a var
+ in the location map and, if found, sets the internal variable
+ \c{lastLoc} the Location that \a var maps to.
+
+ Then it looks up the configuration variable \a var in the string
+ list map, which maps to a string list that contains file paths.
+ These paths might not be clean, so QDir::cleanPath() is called
+ for each one. The string list returned contains cleaned paths.
+ */
+QStringList Config::getCleanPathList(const QString& var) const
+{
+ if (!locMap[var].isEmpty())
+ (Location&) lastLoc = locMap[var];
+ QStringList t;
+ QMap<QString,QStringList>::const_iterator it = stringListValueMap.find(var);
+ if (it != stringListValueMap.end()) {
+ const QStringList& sl = it.value();
+ if (!sl.isEmpty()) {
+ t.reserve(sl.size());
+ for (int i=0; i<sl.size(); ++i) {
+ t.append(QDir::cleanPath(sl[i]));
+ }
+ }
+ }
+ return t;
+}
+
+/*!
+ Calls getRegExpList() with the control variable \a var and
+ iterates through the resulting list of regular expressions,
+ concatening them with some extras characters to form a single
+ QRegExp, which is returned/
+
+ \sa getRegExpList()
+ */
+QRegExp Config::getRegExp(const QString& var) const
+{
+ QString pattern;
+ QList<QRegExp> subRegExps = getRegExpList(var);
+ QList<QRegExp>::ConstIterator s = subRegExps.begin();
+
+ while (s != subRegExps.end()) {
+ if (!(*s).isValid())
+ return *s;
+ if (!pattern.isEmpty())
+ pattern += QLatin1Char('|');
+ pattern += QLatin1String("(?:") + (*s).pattern() + QLatin1Char(')');
+ ++s;
+ }
+ if (pattern.isEmpty())
+ pattern = QLatin1String("$x"); // cannot match
+ return QRegExp(pattern);
+}
+
+/*!
+ Looks up the configuration variable \a var in the string list
+ map, converts the string list to a list of regular expressions,
+ and returns it.
+ */
+QList<QRegExp> Config::getRegExpList(const QString& var) const
+{
+ QStringList strs = getStringList(var);
+ QStringList::ConstIterator s = strs.begin();
+ QList<QRegExp> regExps;
+
+ while (s != strs.end()) {
+ regExps += QRegExp(*s);
+ ++s;
+ }
+ return regExps;
+}
+
+/*!
+ This function is slower than it could be. What it does is
+ find all the keys that begin with \a var + dot and return
+ the matching keys in a set, stripped of the matching prefix
+ and dot.
+ */
+QSet<QString> Config::subVars(const QString& var) const
+{
+ QSet<QString> result;
+ QString varDot = var + QLatin1Char('.');
+ QStringMultiMap::ConstIterator v = stringValueMap.begin();
+ while (v != stringValueMap.end()) {
+ if (v.key().startsWith(varDot)) {
+ QString subVar = v.key().mid(varDot.length());
+ int dot = subVar.indexOf(QLatin1Char('.'));
+ if (dot != -1)
+ subVar.truncate(dot);
+ result.insert(subVar);
+ }
+ ++v;
+ }
+ return result;
+}
+
+/*!
+ Same as subVars(), but in this case we return a string map
+ with the matching keys (stripped of the prefix \a var and
+ mapped to their values. The pairs are inserted into \a t
+ */
+void Config::subVarsAndValues(const QString& var, QStringMultiMap& t) const
+{
+ QString varDot = var + QLatin1Char('.');
+ QStringMultiMap::ConstIterator v = stringValueMap.begin();
+ while (v != stringValueMap.end()) {
+ if (v.key().startsWith(varDot)) {
+ QString subVar = v.key().mid(varDot.length());
+ int dot = subVar.indexOf(QLatin1Char('.'));
+ if (dot != -1)
+ subVar.truncate(dot);
+ t.insert(subVar,v.value());
+ }
+ ++v;
+ }
+}
+
+/*!
+ Builds and returns a list of file pathnames for the file
+ type specified by \a filesVar (e.g. "headers" or "sources").
+ The files are found in the directories specified by
+ \a dirsVar, and they are filtered by \a defaultNameFilter
+ if a better filter can't be constructed from \a filesVar.
+ The directories in \a excludedDirs are avoided. The files
+ in \a excludedFiles are not included in the return list.
+ */
+QStringList Config::getAllFiles(const QString &filesVar,
+ const QString &dirsVar,
+ const QSet<QString> &excludedDirs,
+ const QSet<QString> &excludedFiles)
+{
+ QStringList result = getStringList(filesVar);
+ QStringList dirs = getStringList(dirsVar);
+
+ QString nameFilter = getString(filesVar + dot + QLatin1String(CONFIG_FILEEXTENSIONS));
+
+ QStringList::ConstIterator d = dirs.begin();
+ while (d != dirs.end()) {
+ result += getFilesHere(*d, nameFilter, excludedDirs, excludedFiles);
+ ++d;
+ }
+ return result;
+}
+
+/*!
+ \a fileName is the path of the file to find.
+
+ \a files and \a dirs are the lists where we must find the
+ components of \a fileName.
+
+ \a location is used for obtaining the file and line numbers
+ for report qdoc errors.
+ */
+QString Config::findFile(const Location& location,
+ const QStringList& files,
+ const QStringList& dirs,
+ const QString& fileName,
+ QString& userFriendlyFilePath)
+{
+ if (fileName.isEmpty() || fileName.startsWith(QLatin1Char('/'))) {
+ userFriendlyFilePath = fileName;
+ return fileName;
+ }
+
+ QFileInfo fileInfo;
+ QStringList components = fileName.split(QLatin1Char('?'));
+ QString firstComponent = components.first();
+
+ QStringList::ConstIterator f = files.begin();
+ while (f != files.end()) {
+ if (*f == firstComponent ||
+ (*f).endsWith(QLatin1Char('/') + firstComponent)) {
+ fileInfo.setFile(*f);
+ if (!fileInfo.exists())
+ location.fatal(tr("File '%1' does not exist").arg(*f));
+ break;
+ }
+ ++f;
+ }
+
+ if (fileInfo.fileName().isEmpty()) {
+ QStringList::ConstIterator d = dirs.begin();
+ while (d != dirs.end()) {
+ fileInfo.setFile(QDir(*d), firstComponent);
+ if (fileInfo.exists()) {
+ break;
+ }
+ ++d;
+ }
+ }
+
+ userFriendlyFilePath = QString();
+ if (!fileInfo.exists())
+ return QString();
+
+ QStringList::ConstIterator c = components.begin();
+ for (;;) {
+ bool isArchive = (c != components.end() - 1);
+ QString userFriendly = *c;
+
+ userFriendlyFilePath += userFriendly;
+
+ if (isArchive) {
+ QString extracted = extractedDirs[fileInfo.filePath()];
+ ++c;
+ fileInfo.setFile(QDir(extracted), *c);
+ }
+ else
+ break;
+
+ userFriendlyFilePath += QLatin1Char('?');
+ }
+ return fileInfo.filePath();
+}
+
+/*!
+ */
+QString Config::findFile(const Location& location,
+ const QStringList& files,
+ const QStringList& dirs,
+ const QString& fileBase,
+ const QStringList& fileExtensions,
+ QString& userFriendlyFilePath)
+{
+ QStringList::ConstIterator e = fileExtensions.begin();
+ while (e != fileExtensions.end()) {
+ QString filePath = findFile(location,
+ files,
+ dirs,
+ fileBase + QLatin1Char('.') + *e,
+ userFriendlyFilePath);
+ if (!filePath.isEmpty())
+ return filePath;
+ ++e;
+ }
+ return findFile(location, files, dirs, fileBase, userFriendlyFilePath);
+}
+
+/*!
+ Copies the \a sourceFilePath to the file name constructed by
+ concatenating \a targetDirPath and \a userFriendlySourceFilePath.
+ \a location is for identifying the file and line number where
+ a qdoc error occurred. The constructed output file name is
+ returned.
+ */
+QString Config::copyFile(const Location& location,
+ const QString& sourceFilePath,
+ const QString& userFriendlySourceFilePath,
+ const QString& targetDirPath)
+{
+ QFile inFile(sourceFilePath);
+ if (!inFile.open(QFile::ReadOnly)) {
+ location.fatal(tr("Cannot open input file '%1': %2")
+ .arg(sourceFilePath).arg(inFile.errorString()));
+ return QString();
+ }
+
+ QString outFileName = userFriendlySourceFilePath;
+ int slash = outFileName.lastIndexOf(QLatin1Char('/'));
+ if (slash != -1)
+ outFileName = outFileName.mid(slash);
+
+ QFile outFile(targetDirPath + QLatin1Char('/') + outFileName);
+ if (!outFile.open(QFile::WriteOnly)) {
+ location.fatal(tr("Cannot open output file '%1': %2")
+ .arg(outFile.fileName()).arg(outFile.errorString()));
+ return QString();
+ }
+
+ char buffer[1024];
+ int len;
+ while ((len = inFile.read(buffer, sizeof(buffer))) > 0) {
+ outFile.write(buffer, len);
+ }
+ return outFileName;
+}
+
+/*!
+ Finds the largest unicode digit in \a value in the range
+ 1..7 and returns it.
+ */
+int Config::numParams(const QString& value)
+{
+ int max = 0;
+ for (int i = 0; i != value.length(); i++) {
+ uint c = value[i].unicode();
+ if (c > 0 && c < 8)
+ max = qMax(max, (int)c);
+ }
+ return max;
+}
+
+/*!
+ Removes everything from \a dir. This function is recursive.
+ It doesn't remove \a dir itself, but if it was called
+ recursively, then the caller will remove \a dir.
+ */
+bool Config::removeDirContents(const QString& dir)
+{
+ QDir dirInfo(dir);
+ QFileInfoList entries = dirInfo.entryInfoList();
+
+ bool ok = true;
+
+ QFileInfoList::Iterator it = entries.begin();
+ while (it != entries.end()) {
+ if ((*it).isFile()) {
+ if (!dirInfo.remove((*it).fileName()))
+ ok = false;
+ }
+ else if ((*it).isDir()) {
+ if ((*it).fileName() != QLatin1String(".") && (*it).fileName() != QLatin1String("..")) {
+ if (removeDirContents((*it).absoluteFilePath())) {
+ if (!dirInfo.rmdir((*it).fileName()))
+ ok = false;
+ }
+ else {
+ ok = false;
+ }
+ }
+ }
+ ++it;
+ }
+ return ok;
+}
+
+/*!
+ Returns true if \a ch is a letter, number, '_', '.',
+ '{', '}', or ','.
+ */
+bool Config::isMetaKeyChar(QChar ch)
+{
+ return ch.isLetterOrNumber()
+ || ch == QLatin1Char('_')
+ || ch == QLatin1Char('.')
+ || ch == QLatin1Char('{')
+ || ch == QLatin1Char('}')
+ || ch == QLatin1Char(',');
+}
+
+/*!
+ Load, parse, and process a qdoc configuration file. This
+ function is only called by the other load() function, but
+ this one is recursive, i.e., it calls itself when it sees
+ an \c{include} statement in the qdoc configuration file.
+ */
+void Config::load(Location location, const QString& fileName)
+{
+ QRegExp keySyntax(QLatin1String("\\w+(?:\\.\\w+)*"));
+
+#define SKIP_CHAR() \
+ do { \
+ location.advance(c); \
+ ++i; \
+ c = text.at(i); \
+ cc = c.unicode(); \
+} while (0)
+
+#define SKIP_SPACES() \
+ while (c.isSpace() && cc != '\n') \
+ SKIP_CHAR()
+
+#define PUT_CHAR() \
+ word += c; \
+ SKIP_CHAR();
+
+ if (location.depth() > 16)
+ location.fatal(tr("Too many nested includes"));
+
+ QFile fin(fileName);
+ if (!fin.open(QFile::ReadOnly | QFile::Text)) {
+ fin.setFileName(fileName + QLatin1String(".qdoc"));
+ if (!fin.open(QFile::ReadOnly | QFile::Text))
+ location.fatal(tr("Cannot open file '%1': %2").arg(fileName).arg(fin.errorString()));
+ }
+
+ QTextStream stream(&fin);
+ stream.setCodec("UTF-8");
+ QString text = stream.readAll();
+ text += QLatin1String("\n\n");
+ text += QLatin1Char('\0');
+ fin.close();
+
+ location.push(fileName);
+ location.start();
+
+ int i = 0;
+ QChar c = text.at(0);
+ uint cc = c.unicode();
+ while (i < (int) text.length()) {
+ if (cc == 0)
+ ++i;
+ else if (c.isSpace()) {
+ SKIP_CHAR();
+ }
+ else if (cc == '#') {
+ do {
+ SKIP_CHAR();
+ } while (cc != '\n');
+ }
+ else if (isMetaKeyChar(c)) {
+ Location keyLoc = location;
+ bool plus = false;
+ QString stringValue;
+ QStringList stringListValue;
+ QString word;
+ bool inQuote = false;
+ bool prevWordQuoted = true;
+ bool metWord = false;
+
+ MetaStack stack;
+ do {
+ stack.process(c, location);
+ SKIP_CHAR();
+ } while (isMetaKeyChar(c));
+
+ QStringList keys = stack.getExpanded(location);
+ SKIP_SPACES();
+
+ if (keys.count() == 1 && keys.first() == QLatin1String("include")) {
+ QString includeFile;
+
+ if (cc != '(')
+ location.fatal(tr("Bad include syntax"));
+ SKIP_CHAR();
+ SKIP_SPACES();
+
+ while (!c.isSpace() && cc != '#' && cc != ')') {
+
+ if (cc == '$') {
+ QString var;
+ SKIP_CHAR();
+ while (c.isLetterOrNumber() || cc == '_') {
+ var += c;
+ SKIP_CHAR();
+ }
+ if (!var.isEmpty()) {
+ char *val = getenv(var.toLatin1().data());
+ if (val == 0) {
+ location.fatal(tr("Environment variable '%1' undefined").arg(var));
+ }
+ else {
+ includeFile += QString::fromLatin1(val);
+ }
+ }
+ } else {
+ includeFile += c;
+ SKIP_CHAR();
+ }
+ }
+ SKIP_SPACES();
+ if (cc != ')')
+ location.fatal(tr("Bad include syntax"));
+ SKIP_CHAR();
+ SKIP_SPACES();
+ if (cc != '#' && cc != '\n')
+ location.fatal(tr("Trailing garbage"));
+
+ /*
+ Here is the recursive call.
+ */
+ load(location,
+ QFileInfo(QFileInfo(fileName).dir(), includeFile)
+ .filePath());
+ }
+ else {
+ /*
+ It wasn't an include statement, so it's something else.
+ */
+ if (cc == '+') {
+ plus = true;
+ SKIP_CHAR();
+ }
+ if (cc != '=')
+ location.fatal(tr("Expected '=' or '+=' after key"));
+ SKIP_CHAR();
+ SKIP_SPACES();
+
+ for (;;) {
+ if (cc == '\\') {
+ int metaCharPos;
+
+ SKIP_CHAR();
+ if (cc == '\n') {
+ SKIP_CHAR();
+ }
+ else if (cc > '0' && cc < '8') {
+ word += QChar(c.digitValue());
+ SKIP_CHAR();
+ }
+ else if ((metaCharPos = QString::fromLatin1("abfnrtv").indexOf(c)) != -1) {
+ word += QLatin1Char("\a\b\f\n\r\t\v"[metaCharPos]);
+ SKIP_CHAR();
+ }
+ else {
+ PUT_CHAR();
+ }
+ }
+ else if (c.isSpace() || cc == '#') {
+ if (inQuote) {
+ if (cc == '\n')
+ location.fatal(tr("Unterminated string"));
+ PUT_CHAR();
+ }
+ else {
+ if (!word.isEmpty()) {
+ if (metWord)
+ stringValue += QLatin1Char(' ');
+ stringValue += word;
+ stringListValue << word;
+ metWord = true;
+ word.clear();
+ prevWordQuoted = false;
+ }
+ if (cc == '\n' || cc == '#')
+ break;
+ SKIP_SPACES();
+ }
+ }
+ else if (cc == '"') {
+ if (inQuote) {
+ if (!prevWordQuoted)
+ stringValue += QLatin1Char(' ');
+ stringValue += word;
+ if (!word.isEmpty())
+ stringListValue << word;
+ metWord = true;
+ word.clear();
+ prevWordQuoted = true;
+ }
+ inQuote = !inQuote;
+ SKIP_CHAR();
+ }
+ else if (cc == '$') {
+ QString var;
+ SKIP_CHAR();
+ while (c.isLetterOrNumber() || cc == '_') {
+ var += c;
+ SKIP_CHAR();
+ }
+ if (!var.isEmpty()) {
+ char *val = getenv(var.toLatin1().data());
+ if (val == 0) {
+ location.fatal(tr("Environment variable '%1' undefined").arg(var));
+ }
+ else {
+ word += QString::fromLatin1(val);
+ }
+ }
+ }
+ else {
+ if (!inQuote && cc == '=')
+ location.fatal(tr("Unexpected '='"));
+ PUT_CHAR();
+ }
+ }
+
+ QStringList::ConstIterator key = keys.begin();
+ while (key != keys.end()) {
+ if (!keySyntax.exactMatch(*key))
+ keyLoc.fatal(tr("Invalid key '%1'").arg(*key));
+
+ if (plus) {
+ if (locMap[*key].isEmpty()) {
+ locMap[*key] = keyLoc;
+ }
+ else {
+ locMap[*key].setEtc(true);
+ }
+ if (stringValueMap[*key].isEmpty()) {
+ stringValueMap[*key] = stringValue;
+ }
+ else {
+ stringValueMap[*key] +=
+ QLatin1Char(' ') + stringValue;
+ }
+ stringListValueMap[*key] += stringListValue;
+ }
+ else {
+ locMap[*key] = keyLoc;
+ stringValueMap[*key] = stringValue;
+ stringListValueMap[*key] = stringListValue;
+ }
+ ++key;
+ }
+ }
+ }
+ else {
+ location.fatal(tr("Unexpected character '%1' at beginning of line")
+ .arg(c));
+ }
+ }
+}
+
+QStringList Config::getFilesHere(const QString& dir,
+ const QString& nameFilter,
+ const QSet<QString> &excludedDirs,
+ const QSet<QString> &excludedFiles)
+{
+ QStringList result;
+ if (excludedDirs.contains(dir))
+ return result;
+
+ QDir dirInfo(dir);
+ QStringList fileNames;
+ QStringList::const_iterator fn;
+
+ dirInfo.setNameFilters(nameFilter.split(QLatin1Char(' ')));
+ dirInfo.setSorting(QDir::Name);
+ dirInfo.setFilter(QDir::Files);
+ fileNames = dirInfo.entryList();
+ fn = fileNames.constBegin();
+ while (fn != fileNames.constEnd()) {
+ if (!fn->startsWith(QLatin1Char('~'))) {
+ QString s = dirInfo.filePath(*fn);
+ QString c = QDir::cleanPath(s);
+ if (!excludedFiles.contains(c)) {
+ result.append(c);
+ }
+ }
+ ++fn;
+ }
+
+ dirInfo.setNameFilters(QStringList(QLatin1String("*")));
+ dirInfo.setFilter(QDir::Dirs|QDir::NoDotAndDotDot);
+ fileNames = dirInfo.entryList();
+ fn = fileNames.constBegin();
+ while (fn != fileNames.constEnd()) {
+ result += getFilesHere(dirInfo.filePath(*fn), nameFilter, excludedDirs, excludedFiles);
+ ++fn;
+ }
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/config.h b/src/tools/qdoc/config.h
new file mode 100644
index 0000000000..461e0b969c
--- /dev/null
+++ b/src/tools/qdoc/config.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ config.h
+*/
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include <QMap>
+#include <QSet>
+#include <QStringList>
+
+#include "location.h"
+
+QT_BEGIN_NAMESPACE
+
+typedef QMultiMap<QString, QString> QStringMultiMap;
+
+class Config
+{
+public:
+ Config(const QString& programName);
+ ~Config();
+
+ void load(const QString& fileName);
+ void unload(const QString& fileName);
+ void setStringList(const QString& var, const QStringList& values);
+
+ const QString& programName() const { return prog; }
+ const Location& location() const { return loc; }
+ const Location& lastLocation() const { return lastLoc; }
+ bool getBool(const QString& var) const;
+ int getInt(const QString& var) const;
+ QString getOutputDir() const;
+ QSet<QString> getOutputFormats() const;
+ QString getString(const QString& var) const;
+ QSet<QString> getStringSet(const QString& var) const;
+ QStringList getStringList(const QString& var) const;
+ QStringList getCleanPathList(const QString& var) const;
+ QRegExp getRegExp(const QString& var) const;
+ QList<QRegExp> getRegExpList(const QString& var) const;
+ QSet<QString> subVars(const QString& var) const;
+ void subVarsAndValues(const QString& var, QStringMultiMap& t) const;
+ QStringList getAllFiles(const QString& filesVar,
+ const QString& dirsVar,
+ const QSet<QString> &excludedDirs = QSet<QString>(),
+ const QSet<QString> &excludedFiles = QSet<QString>());
+
+ static QStringList getFilesHere(const QString& dir,
+ const QString& nameFilter,
+ const QSet<QString> &excludedDirs = QSet<QString>(),
+ const QSet<QString> &excludedFiles = QSet<QString>());
+ static QString findFile(const Location& location,
+ const QStringList &files,
+ const QStringList& dirs,
+ const QString& fileName,
+ QString& userFriendlyFilePath);
+ static QString findFile(const Location &location,
+ const QStringList &files,
+ const QStringList &dirs,
+ const QString &fileBase,
+ const QStringList &fileExtensions,
+ QString &userFriendlyFilePath);
+ static QString copyFile(const Location& location,
+ const QString& sourceFilePath,
+ const QString& userFriendlySourceFilePath,
+ const QString& targetDirPath);
+ static int numParams(const QString& value);
+ static bool removeDirContents(const QString& dir);
+
+ QT_STATIC_CONST QString dot;
+
+ static QString overrideOutputDir;
+ static QSet<QString> overrideOutputFormats;
+
+private:
+ static bool isMetaKeyChar(QChar ch);
+ void load(Location location, const QString& fileName);
+
+ QString prog;
+ Location loc;
+ Location lastLoc;
+ QMap<QString, Location> locMap;
+ QMap<QString, QStringList> stringListValueMap;
+ QMap<QString, QString> stringValueMap;
+
+ static QMap<QString, QString> uncompressedFiles;
+ static QMap<QString, QString> extractedDirs;
+ static int numInstances;
+};
+
+#define CONFIG_ALIAS "alias"
+#define CONFIG_BASE "base" // ### don't document for now
+#define CONFIG_BASEDIR "basedir"
+#define CONFIG_CODEINDENT "codeindent"
+#define CONFIG_DEFINES "defines"
+#define CONFIG_DESCRIPTION "description"
+#define CONFIG_EDITION "edition"
+#define CONFIG_ENDHEADER "endheader"
+#define CONFIG_EXAMPLEDIRS "exampledirs"
+#define CONFIG_EXAMPLES "examples"
+#define CONFIG_EXCLUDEDIRS "excludedirs"
+#define CONFIG_EXCLUDEFILES "excludefiles"
+#define CONFIG_EXTRAIMAGES "extraimages"
+#define CONFIG_FALSEHOODS "falsehoods"
+#define CONFIG_FORMATTING "formatting"
+#define CONFIG_GENERATEINDEX "generateindex"
+#define CONFIG_HEADERDIRS "headerdirs"
+#define CONFIG_HEADERS "headers"
+#define CONFIG_HEADERSCRIPTS "headerscripts"
+#define CONFIG_HEADERSTYLES "headerstyles"
+#define CONFIG_IGNOREDIRECTIVES "ignoredirectives"
+#define CONFIG_IGNORETOKENS "ignoretokens"
+#define CONFIG_IMAGEDIRS "imagedirs"
+#define CONFIG_IMAGES "images"
+#define CONFIG_INDEXES "indexes"
+#define CONFIG_LANGUAGE "language"
+#define CONFIG_MACRO "macro"
+#define CONFIG_NATURALLANGUAGE "naturallanguage"
+#define CONFIG_OBSOLETELINKS "obsoletelinks"
+#define CONFIG_OUTPUTDIR "outputdir"
+#define CONFIG_OUTPUTENCODING "outputencoding"
+#define CONFIG_OUTPUTLANGUAGE "outputlanguage"
+#define CONFIG_OUTPUTFORMATS "outputformats"
+#define CONFIG_OUTPUTPREFIXES "outputprefixes"
+#define CONFIG_PROJECT "project"
+#define CONFIG_QHP "qhp"
+#define CONFIG_QUOTINGINFORMATION "quotinginformation"
+#define CONFIG_SCRIPTDIRS "scriptdirs"
+#define CONFIG_SCRIPTS "scripts"
+#define CONFIG_SHOWINTERNAL "showinternal"
+#define CONFIG_SOURCEDIRS "sourcedirs"
+#define CONFIG_SOURCEENCODING "sourceencoding"
+#define CONFIG_SOURCEMODULES "sourcemodules"
+#define CONFIG_SOURCES "sources"
+#define CONFIG_SPURIOUS "spurious"
+#define CONFIG_STYLEDIRS "styledirs"
+#define CONFIG_STYLE "style"
+#define CONFIG_STYLES "styles"
+#define CONFIG_STYLESHEETS "stylesheets"
+#define CONFIG_SYNTAXHIGHLIGHTING "syntaxhighlighting"
+#define CONFIG_TEMPLATEDIR "templatedir"
+#define CONFIG_TABSIZE "tabsize"
+#define CONFIG_TAGFILE "tagfile"
+#define CONFIG_TRANSLATORS "translators" // ### don't document for now
+#define CONFIG_URL "url"
+#define CONFIG_VERSION "version"
+#define CONFIG_VERSIONSYM "versionsym"
+
+#define CONFIG_FILEEXTENSIONS "fileextensions"
+#define CONFIG_IMAGEEXTENSIONS "imageextensions"
+
+#ifdef QDOC_QML
+#define CONFIG_QMLONLY "qmlonly"
+#endif
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/cppcodemarker.cpp b/src/tools/qdoc/cppcodemarker.cpp
new file mode 100644
index 0000000000..cc68865cc0
--- /dev/null
+++ b/src/tools/qdoc/cppcodemarker.cpp
@@ -0,0 +1,1354 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ cppcodemarker.cpp
+*/
+
+#include "atom.h"
+#include "cppcodemarker.h"
+#include "node.h"
+#include "text.h"
+#include "tree.h"
+#include <qdebug.h>
+#include <ctype.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ The constructor does nothing.
+ */
+CppCodeMarker::CppCodeMarker()
+{
+ // nothing.
+}
+
+/*!
+ The destructor does nothing.
+ */
+CppCodeMarker::~CppCodeMarker()
+{
+ // nothing.
+}
+
+/*!
+ Returns true.
+ */
+bool CppCodeMarker::recognizeCode(const QString & /* code */)
+{
+ return true;
+}
+
+/*!
+ Returns true if \a ext is any of a list of file extensions
+ for the C++ language.
+ */
+bool CppCodeMarker::recognizeExtension(const QString& extension)
+{
+ QByteArray ext = extension.toLatin1();
+ return ext == "c" ||
+ ext == "c++" ||
+ ext == "cc" ||
+ ext == "cpp" ||
+ ext == "cxx" ||
+ ext == "ch" ||
+ ext == "h" ||
+ ext == "h++" ||
+ ext == "hh" ||
+ ext == "hpp" ||
+ ext == "hxx";
+}
+
+/*!
+ Returns true if \a lang is either "C" or "Cpp".
+ */
+bool CppCodeMarker::recognizeLanguage(const QString &lang)
+{
+ return lang == QLatin1String("C") || lang == QLatin1String("Cpp");
+}
+
+/*!
+ Returns the type of atom used to represent C++ code in the documentation.
+*/
+Atom::Type CppCodeMarker::atomType() const
+{
+ return Atom::Code;
+}
+
+/*!
+ Returns the \a node name, or "()" if \a node is a
+ Node::Function node.
+ */
+QString CppCodeMarker::plainName(const Node *node)
+{
+ QString name = node->name();
+ if (node->type() == Node::Function)
+ name += QLatin1String("()");
+ return name;
+}
+
+QString CppCodeMarker::plainFullName(const Node *node, const Node *relative)
+{
+ if (node->name().isEmpty()) {
+ return QLatin1String("global");
+ }
+ else {
+ QString fullName;
+ while (node) {
+ fullName.prepend(plainName(node));
+ if (node->parent() == relative ||
+ node->parent()->subType() == Node::Collision ||
+ node->parent()->name().isEmpty())
+ break;
+ fullName.prepend(QLatin1String("::"));
+ node = node->parent();
+ }
+ return fullName;
+ }
+}
+
+QString CppCodeMarker::markedUpCode(const QString &code,
+ const Node *relative,
+ const Location &location)
+{
+ return addMarkUp(code, relative, location);
+}
+
+QString CppCodeMarker::markedUpSynopsis(const Node *node,
+ const Node * /* relative */,
+ SynopsisStyle style)
+{
+ const int MaxEnumValues = 6;
+ const FunctionNode *func;
+ const PropertyNode *property;
+ const VariableNode *variable;
+ const EnumNode *enume;
+ const TypedefNode *typedeff;
+ QString synopsis;
+ QString extra;
+ QString name;
+
+ name = taggedNode(node);
+ if (style != Detailed)
+ name = linkTag(node, name);
+ name = "<@name>" + name + "</@name>";
+
+ if (style == Detailed && !node->parent()->name().isEmpty() &&
+ node->type() != Node::Property)
+ name.prepend(taggedNode(node->parent()) + "::");
+
+ switch (node->type()) {
+ case Node::Namespace:
+ synopsis = "namespace " + name;
+ break;
+ case Node::Class:
+ synopsis = "class " + name;
+ break;
+ case Node::Function:
+ case Node::QmlSignal:
+ case Node::QmlSignalHandler:
+ case Node::QmlMethod:
+ func = (const FunctionNode *) node;
+ if (style != Subpage && !func->returnType().isEmpty())
+ synopsis = typified(func->returnType()) + QLatin1Char(' ');
+ synopsis += name;
+ if (func->metaness() != FunctionNode::MacroWithoutParams) {
+ synopsis += "(";
+ if (!func->parameters().isEmpty()) {
+ //synopsis += QLatin1Char(' ');
+ QList<Parameter>::ConstIterator p = func->parameters().begin();
+ while (p != func->parameters().end()) {
+ if (p != func->parameters().begin())
+ synopsis += ", ";
+ synopsis += typified((*p).leftType());
+ if (style != Subpage && !(*p).name().isEmpty())
+ synopsis +=
+ "<@param>" + protect((*p).name()) + "</@param>";
+ synopsis += protect((*p).rightType());
+ if (style != Subpage && !(*p).defaultValue().isEmpty())
+ synopsis += " = " + protect((*p).defaultValue());
+ ++p;
+ }
+ //synopsis += QLatin1Char(' ');
+ }
+ synopsis += QLatin1Char(')');
+ }
+ if (func->isConst())
+ synopsis += " const";
+
+ if (style == Summary || style == Accessors) {
+ if (func->virtualness() != FunctionNode::NonVirtual)
+ synopsis.prepend("virtual ");
+ if (func->virtualness() == FunctionNode::PureVirtual)
+ synopsis.append(" = 0");
+ }
+ else if (style == Subpage) {
+ if (!func->returnType().isEmpty() && func->returnType() != "void")
+ synopsis += " : " + typified(func->returnType());
+ }
+ else {
+ QStringList bracketed;
+ if (func->isStatic()) {
+ bracketed += "static";
+ }
+ else if (func->virtualness() != FunctionNode::NonVirtual) {
+ if (func->virtualness() == FunctionNode::PureVirtual)
+ bracketed += "pure";
+ bracketed += "virtual";
+ }
+
+ if (func->access() == Node::Protected) {
+ bracketed += "protected";
+ }
+ else if (func->access() == Node::Private) {
+ bracketed += "private";
+ }
+
+ if (func->metaness() == FunctionNode::Signal) {
+ bracketed += "signal";
+ }
+ else if (func->metaness() == FunctionNode::Slot) {
+ bracketed += "slot";
+ }
+ if (!bracketed.isEmpty())
+ extra += " [" + bracketed.join(" ") + QLatin1Char(']');
+ }
+ break;
+ case Node::Enum:
+ enume = static_cast<const EnumNode *>(node);
+ synopsis = "enum " + name;
+ if (style == Summary) {
+ synopsis += " { ";
+
+ QStringList documentedItems = enume->doc().enumItemNames();
+ if (documentedItems.isEmpty()) {
+ foreach (const EnumItem &item, enume->items())
+ documentedItems << item.name();
+ }
+ QStringList omitItems = enume->doc().omitEnumItemNames();
+ foreach (const QString &item, omitItems)
+ documentedItems.removeAll(item);
+
+ if (documentedItems.size() <= MaxEnumValues) {
+ for (int i = 0; i < documentedItems.size(); ++i) {
+ if (i != 0)
+ synopsis += ", ";
+ synopsis += documentedItems.at(i);
+ }
+ }
+ else {
+ for (int i = 0; i < documentedItems.size(); ++i) {
+ if (i < MaxEnumValues-2 || i == documentedItems.size()-1) {
+ if (i != 0)
+ synopsis += ", ";
+ synopsis += documentedItems.at(i);
+ }
+ else if (i == MaxEnumValues - 1) {
+ synopsis += ", ...";
+ }
+ }
+ }
+ if (!documentedItems.isEmpty())
+ synopsis += QLatin1Char(' ');
+ synopsis += QLatin1Char('}');
+ }
+ break;
+ case Node::Typedef:
+ typedeff = static_cast<const TypedefNode *>(node);
+ if (typedeff->associatedEnum()) {
+ synopsis = "flags " + name;
+ }
+ else {
+ synopsis = "typedef " + name;
+ }
+ break;
+ case Node::Property:
+ property = static_cast<const PropertyNode *>(node);
+ synopsis = name + " : " + typified(property->qualifiedDataType());
+ break;
+ case Node::Variable:
+ variable = static_cast<const VariableNode *>(node);
+ if (style == Subpage) {
+ synopsis = name + " : " + typified(variable->dataType());
+ }
+ else {
+ synopsis = typified(variable->leftType()) + QLatin1Char(' ') +
+ name + protect(variable->rightType());
+ }
+ break;
+ default:
+ synopsis = name;
+ }
+
+ if (style == Summary) {
+ if (node->status() == Node::Preliminary) {
+ extra += " (preliminary)";
+ }
+ else if (node->status() == Node::Deprecated) {
+ extra += " (deprecated)";
+ }
+ else if (node->status() == Node::Obsolete) {
+ extra += " (obsolete)";
+ }
+ }
+
+ if (!extra.isEmpty()) {
+ extra.prepend("<@extra>");
+ extra.append("</@extra>");
+ }
+ return synopsis + extra;
+}
+
+/*!
+ */
+QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary)
+{
+ QString name = taggedQmlNode(node);
+ if (summary) {
+ name = linkTag(node,name);
+ } else if (node->type() == Node::QmlProperty) {
+ const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(node);
+ if (pn->isAttached())
+ name.prepend(pn->element() + QLatin1Char('.'));
+ }
+ name = "<@name>" + name + "</@name>";
+ QString synopsis = name;
+ if (node->type() == Node::QmlProperty) {
+ const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(node);
+ synopsis += " : " + typified(pn->dataType());
+ }
+
+ QString extra;
+ if (summary) {
+ if (node->status() == Node::Preliminary) {
+ extra += " (preliminary)";
+ }
+ else if (node->status() == Node::Deprecated) {
+ extra += " (deprecated)";
+ }
+ else if (node->status() == Node::Obsolete) {
+ extra += " (obsolete)";
+ }
+ }
+
+ if (!extra.isEmpty()) {
+ extra.prepend("<@extra>");
+ extra.append("</@extra>");
+ }
+ return synopsis + extra;
+}
+
+QString CppCodeMarker::markedUpName(const Node *node)
+{
+ QString name = linkTag(node, taggedNode(node));
+ if (node->type() == Node::Function)
+ name += "()";
+ return name;
+}
+
+QString CppCodeMarker::markedUpFullName(const Node *node, const Node *relative)
+{
+ if (node->name().isEmpty()) {
+ return "global";
+ }
+ else {
+ QString fullName;
+ for (;;) {
+ fullName.prepend(markedUpName(node));
+ if (node->parent() == relative || node->parent()->name().isEmpty())
+ break;
+ fullName.prepend("<@op>::</@op>");
+ node = node->parent();
+ }
+ return fullName;
+ }
+}
+
+QString CppCodeMarker::markedUpEnumValue(const QString &enumValue,
+ const Node *relative)
+{
+ const Node *node = relative->parent();
+ QString fullName;
+ while (node->parent()) {
+ fullName.prepend(markedUpName(node));
+ if (node->parent() == relative || node->parent()->name().isEmpty())
+ break;
+ fullName.prepend("<@op>::</@op>");
+ node = node->parent();
+ }
+ if (!fullName.isEmpty())
+ fullName.append("<@op>::</@op>");
+ fullName.append(enumValue);
+ return fullName;
+}
+
+QString CppCodeMarker::markedUpIncludes(const QStringList& includes)
+{
+ QString code;
+
+ QStringList::ConstIterator inc = includes.begin();
+ while (inc != includes.end()) {
+ code += "<@preprocessor>#include &lt;<@headerfile>" + *inc + "</@headerfile>&gt;</@preprocessor>\n";
+ ++inc;
+ }
+ return code;
+}
+
+QString CppCodeMarker::functionBeginRegExp(const QString& funcName)
+{
+ return QLatin1Char('^') + QRegExp::escape(funcName) + QLatin1Char('$');
+
+}
+
+QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */)
+{
+ return "^\\}$";
+}
+
+QList<Section> CppCodeMarker::sections(const InnerNode *inner,
+ SynopsisStyle style,
+ Status status)
+{
+ QList<Section> sections;
+
+ if (inner->type() == Node::Class) {
+ const ClassNode *classe = static_cast<const ClassNode *>(inner);
+
+ if (style == Summary) {
+ FastSection privateFunctions(classe,
+ "Private Functions",
+ "",
+ "private function",
+ "private functions");
+ FastSection privateSlots(classe, "Private Slots", "", "private slot", "private slots");
+ FastSection privateTypes(classe, "Private Types", "", "private type", "private types");
+ FastSection protectedFunctions(classe,
+ "Protected Functions",
+ "",
+ "protected function",
+ "protected functions");
+ FastSection protectedSlots(classe,
+ "Protected Slots",
+ "",
+ "protected slot",
+ "protected slots");
+ FastSection protectedTypes(classe,
+ "Protected Types",
+ "",
+ "protected type",
+ "protected types");
+ FastSection protectedVariables(classe,
+ "Protected Variables",
+ "",
+ "protected type",
+ "protected variables");
+ FastSection publicFunctions(classe,
+ "Public Functions",
+ "",
+ "public function",
+ "public functions");
+ FastSection publicSignals(classe, "Signals", "", "signal", "signal");
+ FastSection publicSlots(classe, "Public Slots", "", "public slot", "public slots");
+ FastSection publicTypes(classe, "Public Types", "", "public type", "public types");
+ FastSection publicVariables(classe,
+ "Public Variables",
+ "",
+ "public variable",
+ "public variables");
+ FastSection properties(classe, "Properties", "", "property", "properties");
+ FastSection relatedNonMembers(classe,
+ "Related Non-Members",
+ "",
+ "related non-member",
+ "related non-members");
+ FastSection staticPrivateMembers(classe,
+ "Static Private Members",
+ "",
+ "static private member",
+ "static private members");
+ FastSection staticProtectedMembers(classe,
+ "Static Protected Members",
+ "",
+ "static protected member",
+ "static protected members");
+ FastSection staticPublicMembers(classe,
+ "Static Public Members",
+ "",
+ "static public member",
+ "static public members");
+ FastSection macros(inner, "Macros", "", "macro", "macros");
+
+ NodeList::ConstIterator r = classe->relatedNodes().begin();
+ while (r != classe->relatedNodes().end()) {
+ if ((*r)->type() == Node::Function) {
+ FunctionNode *func = static_cast<FunctionNode *>(*r);
+ if (func->isMacro())
+ insert(macros, *r, style, status);
+ else
+ insert(relatedNonMembers, *r, style, status);
+ }
+ else {
+ insert(relatedNonMembers, *r, style, status);
+ }
+ ++r;
+ }
+
+ QStack<const ClassNode *> stack;
+ stack.push(classe);
+
+ while (!stack.isEmpty()) {
+ const ClassNode *ancestorClass = stack.pop();
+
+ NodeList::ConstIterator c = ancestorClass->childNodes().begin();
+ while (c != ancestorClass->childNodes().end()) {
+ bool isSlot = false;
+ bool isSignal = false;
+ bool isStatic = false;
+ if ((*c)->type() == Node::Function) {
+ const FunctionNode *func = (const FunctionNode *) *c;
+ isSlot = (func->metaness() == FunctionNode::Slot);
+ isSignal = (func->metaness() == FunctionNode::Signal);
+ isStatic = func->isStatic();
+ }
+ else if ((*c)->type() == Node::Variable) {
+ const VariableNode *var = static_cast<const VariableNode *>(*c);
+ isStatic = var->isStatic();
+ }
+
+ switch ((*c)->access()) {
+ case Node::Public:
+ if (isSlot) {
+ insert(publicSlots, *c, style, status);
+ }
+ else if (isSignal) {
+ insert(publicSignals, *c, style, status);
+ }
+ else if (isStatic) {
+ if ((*c)->type() != Node::Variable
+ || !(*c)->doc().isEmpty())
+ insert(staticPublicMembers,*c,style,status);
+ }
+ else if ((*c)->type() == Node::Property) {
+ insert(properties, *c, style, status);
+ }
+ else if ((*c)->type() == Node::Variable) {
+ if (!(*c)->doc().isEmpty())
+ insert(publicVariables, *c, style, status);
+ }
+ else if ((*c)->type() == Node::Function) {
+ if (!insertReimpFunc(publicFunctions,*c,status))
+ insert(publicFunctions, *c, style, status);
+ }
+ else {
+ insert(publicTypes, *c, style, status);
+ }
+ break;
+ case Node::Protected:
+ if (isSlot) {
+ insert(protectedSlots, *c, style, status);
+ }
+ else if (isStatic) {
+ if ((*c)->type() != Node::Variable
+ || !(*c)->doc().isEmpty())
+ insert(staticProtectedMembers,*c,style,status);
+ }
+ else if ((*c)->type() == Node::Variable) {
+ if (!(*c)->doc().isEmpty())
+ insert(protectedVariables,*c,style,status);
+ }
+ else if ((*c)->type() == Node::Function) {
+ if (!insertReimpFunc(protectedFunctions,*c,status))
+ insert(protectedFunctions, *c, style, status);
+ }
+ else {
+ insert(protectedTypes, *c, style, status);
+ }
+ break;
+ case Node::Private:
+ if (isSlot) {
+ insert(privateSlots, *c, style, status);
+ }
+ else if (isStatic) {
+ if ((*c)->type() != Node::Variable
+ || !(*c)->doc().isEmpty())
+ insert(staticPrivateMembers,*c,style,status);
+ }
+ else if ((*c)->type() == Node::Function) {
+ if (!insertReimpFunc(privateFunctions,*c,status))
+ insert(privateFunctions, *c, style, status);
+ }
+ else {
+ insert(privateTypes,*c,style,status);
+ }
+ }
+ ++c;
+ }
+
+ QList<RelatedClass>::ConstIterator r =
+ ancestorClass->baseClasses().begin();
+ while (r != ancestorClass->baseClasses().end()) {
+ stack.prepend((*r).node);
+ ++r;
+ }
+ }
+
+ append(sections, publicTypes);
+ append(sections, properties);
+ append(sections, publicFunctions);
+ append(sections, publicSlots);
+ append(sections, publicSignals);
+ append(sections, publicVariables);
+ append(sections, staticPublicMembers);
+ append(sections, protectedTypes);
+ append(sections, protectedFunctions);
+ append(sections, protectedSlots);
+ append(sections, protectedVariables);
+ append(sections, staticProtectedMembers);
+ append(sections, privateTypes);
+ append(sections, privateFunctions);
+ append(sections, privateSlots);
+ append(sections, staticPrivateMembers);
+ append(sections, relatedNonMembers);
+ append(sections, macros);
+ }
+ else if (style == Detailed) {
+ FastSection memberFunctions(classe,"Member Function Documentation","func","member","members");
+ FastSection memberTypes(classe,"Member Type Documentation","types","member","members");
+ FastSection memberVariables(classe,"Member Variable Documentation","vars","member","members");
+ FastSection properties(classe,"Property Documentation","prop","member","members");
+ FastSection relatedNonMembers(classe,"Related Non-Members","relnonmem","member","members");
+ FastSection macros(classe,"Macro Documentation","macros","member","members");
+
+ NodeList::ConstIterator r = classe->relatedNodes().begin();
+ while (r != classe->relatedNodes().end()) {
+ if ((*r)->type() == Node::Function) {
+ FunctionNode *func = static_cast<FunctionNode *>(*r);
+ if (func->isMacro())
+ insert(macros, *r, style, status);
+ else
+ insert(relatedNonMembers, *r, style, status);
+ }
+ else {
+ insert(relatedNonMembers, *r, style, status);
+ }
+ ++r;
+ }
+
+ NodeList::ConstIterator c = classe->childNodes().begin();
+ while (c != classe->childNodes().end()) {
+ if ((*c)->type() == Node::Enum ||
+ (*c)->type() == Node::Typedef) {
+ insert(memberTypes, *c, style, status);
+ }
+ else if ((*c)->type() == Node::Property) {
+ insert(properties, *c, style, status);
+ }
+ else if ((*c)->type() == Node::Variable) {
+ if (!(*c)->doc().isEmpty())
+ insert(memberVariables, *c, style, status);
+ }
+ else if ((*c)->type() == Node::Function) {
+ FunctionNode *function = static_cast<FunctionNode *>(*c);
+ if (!function->associatedProperty())
+ insert(memberFunctions, function, style, status);
+ }
+ ++c;
+ }
+
+ append(sections, memberTypes);
+ append(sections, properties);
+ append(sections, memberFunctions);
+ append(sections, memberVariables);
+ append(sections, relatedNonMembers);
+ append(sections, macros);
+ }
+ else {
+ FastSection all(classe,"","","member","members");
+
+ QStack<const ClassNode *> stack;
+ stack.push(classe);
+
+ while (!stack.isEmpty()) {
+ const ClassNode *ancestorClass = stack.pop();
+
+ NodeList::ConstIterator c = ancestorClass->childNodes().begin();
+ while (c != ancestorClass->childNodes().end()) {
+ if ((*c)->access() != Node::Private &&
+ (*c)->type() != Node::Property)
+ insert(all, *c, style, status);
+ ++c;
+ }
+
+ QList<RelatedClass>::ConstIterator r =
+ ancestorClass->baseClasses().begin();
+ while (r != ancestorClass->baseClasses().end()) {
+ stack.prepend((*r).node);
+ ++r;
+ }
+ }
+ append(sections, all);
+ }
+ }
+ else {
+ if (style == Summary || style == Detailed) {
+ FastSection namespaces(inner,
+ "Namespaces",
+ style == Detailed ? "nmspace" : "",
+ "namespace",
+ "namespaces");
+ FastSection classes(inner,
+ "Classes",
+ style == Detailed ? "classes" : "",
+ "class",
+ "classes");
+ FastSection types(inner,
+ style == Summary ? "Types" : "Type Documentation",
+ style == Detailed ? "types" : "",
+ "type",
+ "types");
+ FastSection functions(inner,
+ style == Summary ?
+ "Functions" : "Function Documentation",
+ style == Detailed ? "func" : "",
+ "function",
+ "functions");
+ FastSection macros(inner,
+ style == Summary ?
+ "Macros" : "Macro Documentation",
+ style == Detailed ? "macros" : "",
+ "macro",
+ "macros");
+
+ NodeList nodeList = inner->childNodes();
+ nodeList += inner->relatedNodes();
+
+ NodeList::ConstIterator n = nodeList.begin();
+ while (n != nodeList.end()) {
+ switch ((*n)->type()) {
+ case Node::Namespace:
+ insert(namespaces, *n, style, status);
+ break;
+ case Node::Class:
+ insert(classes, *n, style, status);
+ break;
+ case Node::Enum:
+ case Node::Typedef:
+ insert(types, *n, style, status);
+ break;
+ case Node::Function:
+ {
+ FunctionNode *func = static_cast<FunctionNode *>(*n);
+ if (func->isMacro())
+ insert(macros, *n, style, status);
+ else
+ insert(functions, *n, style, status);
+ }
+ break;
+ default:
+ ;
+ }
+ ++n;
+ }
+ append(sections, namespaces);
+ append(sections, classes);
+ append(sections, types);
+ append(sections, functions);
+ append(sections, macros);
+ }
+ }
+
+ return sections;
+}
+
+const Node *CppCodeMarker::resolveTarget(const QString& target,
+ const Tree* tree,
+ const Node* relative,
+ const Node* self)
+{
+ if (target.endsWith("()")) {
+ const FunctionNode *func;
+ QString funcName = target;
+ funcName.chop(2);
+
+ QStringList path = funcName.split("::");
+ if ((func = tree->findFunctionNode(path,
+ relative,
+ Tree::SearchBaseClasses))
+ && func->metaness() != FunctionNode::MacroWithoutParams)
+ return func;
+ }
+ else if (target.contains(QLatin1Char('#'))) {
+ // ### this doesn't belong here; get rid of TargetNode hack
+ int hashAt = target.indexOf(QLatin1Char('#'));
+ QString link = target.left(hashAt);
+ QString ref = target.mid(hashAt + 1);
+ const Node *node;
+ if (link.isEmpty()) {
+ node = relative;
+ }
+ else {
+ QStringList path(link);
+ node = tree->findNode(path, tree->root(), Tree::SearchBaseClasses);
+ }
+ if (node && node->isInnerNode()) {
+ const Atom *atom = node->doc().body().firstAtom();
+ while (atom) {
+ if (atom->type() == Atom::Target && atom->string() == ref) {
+ Node *parentNode = const_cast<Node *>(node);
+ return new TargetNode(static_cast<InnerNode*>(parentNode),
+ ref);
+ }
+ atom = atom->next();
+ }
+ }
+ }
+ else {
+ QStringList path = target.split("::");
+ const Node *node;
+ int flags = Tree::SearchBaseClasses |
+ Tree::SearchEnumValues |
+ Tree::NonFunction;
+ if ((node = tree->findNode(path,
+ relative,
+ flags,
+ self)))
+ return node;
+ }
+ return 0;
+}
+
+static const char * const typeTable[] = {
+ "bool", "char", "double", "float", "int", "long", "short",
+ "signed", "unsigned", "uint", "ulong", "ushort", "uchar", "void",
+ "qlonglong", "qulonglong",
+ "qint", "qint8", "qint16", "qint32", "qint64",
+ "quint", "quint8", "quint16", "quint32", "quint64",
+ "qreal", "cond", 0
+};
+
+static const char * const keywordTable[] = {
+ "and", "and_eq", "asm", "auto", "bitand", "bitor", "break",
+ "case", "catch", "class", "compl", "const", "const_cast",
+ "continue", "default", "delete", "do", "dynamic_cast", "else",
+ "enum", "explicit", "export", "extern", "false", "for", "friend",
+ "goto", "if", "include", "inline", "monitor", "mutable", "namespace",
+ "new", "not", "not_eq", "operator", "or", "or_eq", "private", "protected",
+ "public", "register", "reinterpret_cast", "return", "sizeof",
+ "static", "static_cast", "struct", "switch", "template", "this",
+ "throw", "true", "try", "typedef", "typeid", "typename", "union",
+ "using", "virtual", "volatile", "wchar_t", "while", "xor",
+ "xor_eq", "synchronized",
+ // Qt specific
+ "signals", "slots", "emit", 0
+};
+
+/*
+ @char
+ @class
+ @comment
+ @function
+ @keyword
+ @number
+ @op
+ @preprocessor
+ @string
+ @type
+*/
+
+QString CppCodeMarker::addMarkUp(const QString &in,
+ const Node * /* relative */,
+ const Location & /* location */)
+{
+#define readChar() \
+ ch = (i < (int)code.length()) ? code[i++].cell() : EOF
+
+ QString code = in;
+
+ QMap<QString, int> types;
+ QMap<QString, int> keywords;
+ int j = 0;
+ while (typeTable[j] != 0) {
+ types.insert(QString(typeTable[j]), 0);
+ j++;
+ }
+ j = 0;
+ while (keywordTable[j] != 0) {
+ keywords.insert(QString(keywordTable[j]), 0);
+ j++;
+ }
+
+ QString out("");
+ int braceDepth = 0;
+ int parenDepth = 0;
+ int i = 0;
+ int start = 0;
+ int finish = 0;
+ QChar ch;
+ QRegExp classRegExp("Qt?(?:[A-Z3]+[a-z][A-Za-z]*|t)");
+ QRegExp functionRegExp("q([A-Z][a-z]+)+");
+
+ readChar();
+
+ while (ch != EOF) {
+ QString tag;
+ bool target = false;
+
+ if (ch.isLetter() || ch == '_') {
+ QString ident;
+ do {
+ ident += ch;
+ finish = i;
+ readChar();
+ } while (ch.isLetterOrNumber() || ch == '_');
+
+ if (classRegExp.exactMatch(ident)) {
+ tag = QLatin1String("type");
+ } else if (functionRegExp.exactMatch(ident)) {
+ tag = QLatin1String("func");
+ target = true;
+ } else if (types.contains(ident)) {
+ tag = QLatin1String("type");
+ } else if (keywords.contains(ident)) {
+ tag = QLatin1String("keyword");
+ } else if (braceDepth == 0 && parenDepth == 0) {
+ if (QString(code.unicode() + i - 1, code.length() - (i - 1))
+ .indexOf(QRegExp(QLatin1String("^\\s*\\("))) == 0)
+ tag = QLatin1String("func");
+ target = true;
+ }
+ } else if (ch.isDigit()) {
+ do {
+ finish = i;
+ readChar();
+ } while (ch.isLetterOrNumber() || ch == '.');
+ tag = QLatin1String("number");
+ } else {
+ switch (ch.unicode()) {
+ case '+':
+ case '-':
+ case '!':
+ case '%':
+ case '^':
+ case '&':
+ case '*':
+ case ',':
+ case '.':
+ case '<':
+ case '=':
+ case '>':
+ case '?':
+ case '[':
+ case ']':
+ case '|':
+ case '~':
+ finish = i;
+ readChar();
+ tag = QLatin1String("op");
+ break;
+ case '"':
+ finish = i;
+ readChar();
+
+ while (ch != EOF && ch != '"') {
+ if (ch == '\\')
+ readChar();
+ readChar();
+ }
+ finish = i;
+ readChar();
+ tag = QLatin1String("string");
+ break;
+ case '#':
+ finish = i;
+ readChar();
+ while (ch != EOF && ch != '\n') {
+ if (ch == '\\')
+ readChar();
+ finish = i;
+ readChar();
+ }
+ tag = QLatin1String("preprocessor");
+ break;
+ case '\'':
+ finish = i;
+ readChar();
+
+ while (ch != EOF && ch != '\'') {
+ if (ch == '\\')
+ readChar();
+ readChar();
+ }
+ finish = i;
+ readChar();
+ tag = QLatin1String("char");
+ break;
+ case '(':
+ finish = i;
+ readChar();
+ parenDepth++;
+ break;
+ case ')':
+ finish = i;
+ readChar();
+ parenDepth--;
+ break;
+ case ':':
+ finish = i;
+ readChar();
+ if (ch == ':') {
+ finish = i;
+ readChar();
+ tag = QLatin1String("op");
+ }
+ break;
+ case '/':
+ finish = i;
+ readChar();
+ if (ch == '/') {
+ do {
+ finish = i;
+ readChar();
+ } while (ch != EOF && ch != '\n');
+ tag = QLatin1String("comment");
+ } else if (ch == '*') {
+ bool metAster = false;
+ bool metAsterSlash = false;
+
+ finish = i;
+ readChar();
+
+ while (!metAsterSlash) {
+ if (ch == EOF)
+ break;
+
+ if (ch == '*')
+ metAster = true;
+ else if (metAster && ch == '/')
+ metAsterSlash = true;
+ else
+ metAster = false;
+ finish = i;
+ readChar();
+ }
+ tag = QLatin1String("comment");
+ } else {
+ tag = QLatin1String("op");
+ }
+ break;
+ case '{':
+ finish = i;
+ readChar();
+ braceDepth++;
+ break;
+ case '}':
+ finish = i;
+ readChar();
+ braceDepth--;
+ break;
+ default:
+ finish = i;
+ readChar();
+ }
+ }
+
+ QString text;
+ text = code.mid(start, finish - start);
+ start = finish;
+
+ if (!tag.isEmpty()) {
+ out += QLatin1String("<@") + tag;
+ if (target)
+ out += QLatin1String(" target=\"") + text + QLatin1String("()\"");
+ out += QLatin1Char('>');
+ }
+
+ out += protect(text);
+
+ if (!tag.isEmpty())
+ out += QLatin1String("</@") + tag + QLatin1Char('>');
+ }
+
+ if (start < code.length()) {
+ out += protect(code.mid(start));
+ }
+
+ return out;
+}
+
+/*!
+ This function is for documenting QML properties. It returns
+ the list of documentation sections for the children of the
+ \a qmlClassNode.
+
+ Currently, it only handles QML property groups.
+ */
+QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode,
+ SynopsisStyle style)
+{
+ QList<Section> sections;
+ if (qmlClassNode) {
+ if (style == Summary) {
+ FastSection qmlproperties(qmlClassNode,
+ "Properties",
+ "",
+ "property",
+ "properties");
+ FastSection qmlattachedproperties(qmlClassNode,
+ "Attached Properties",
+ "",
+ "property",
+ "properties");
+ FastSection qmlsignals(qmlClassNode,
+ "Signals",
+ "",
+ "signal",
+ "signals");
+ FastSection qmlsignalhandlers(qmlClassNode,
+ "Signal Handlers",
+ "",
+ "signal handler",
+ "signal handlers");
+ FastSection qmlattachedsignals(qmlClassNode,
+ "Attached Signals",
+ "",
+ "signal",
+ "signals");
+ FastSection qmlmethods(qmlClassNode,
+ "Methods",
+ "",
+ "method",
+ "methods");
+ FastSection qmlattachedmethods(qmlClassNode,
+ "Attached Methods",
+ "",
+ "method",
+ "methods");
+
+ const QmlClassNode* qcn = qmlClassNode;
+ while (qcn != 0) {
+ NodeList::ConstIterator c = qcn->childNodes().begin();
+ while (c != qcn->childNodes().end()) {
+ if ((*c)->subType() == Node::QmlPropertyGroup) {
+ const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c);
+ NodeList::ConstIterator p = qpgn->childNodes().begin();
+ while (p != qpgn->childNodes().end()) {
+ if ((*p)->type() == Node::QmlProperty) {
+ const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*p);
+ if (pn->isAttached())
+ insert(qmlattachedproperties,*p,style,Okay);
+ else
+ insert(qmlproperties,*p,style,Okay);
+ }
+ ++p;
+ }
+ }
+ else if ((*c)->type() == Node::QmlProperty) {
+ const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c);
+ if (pn->qmlPropNodes().isEmpty()) {
+ if (pn->isAttached())
+ insert(qmlattachedproperties,*c,style,Okay);
+ else
+ insert(qmlproperties,*c,style,Okay);
+ }
+ else {
+ NodeList::ConstIterator p = pn->qmlPropNodes().begin();
+ while (p != pn->qmlPropNodes().end()) {
+ if ((*p)->type() == Node::QmlProperty) {
+ const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*p);
+ if (pn->isAttached())
+ insert(qmlattachedproperties,*p,style,Okay);
+ else
+ insert(qmlproperties,*p,style,Okay);
+ }
+ ++p;
+ }
+ }
+ }
+ else if ((*c)->type() == Node::QmlSignal) {
+ const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
+ if (sn->isAttached())
+ insert(qmlattachedsignals,*c,style,Okay);
+ else
+ insert(qmlsignals,*c,style,Okay);
+ }
+ else if ((*c)->type() == Node::QmlSignalHandler) {
+ insert(qmlsignalhandlers,*c,style,Okay);
+ }
+ else if ((*c)->type() == Node::QmlMethod) {
+ const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
+ if (mn->isAttached())
+ insert(qmlattachedmethods,*c,style,Okay);
+ else
+ insert(qmlmethods,*c,style,Okay);
+ }
+ ++c;
+ }
+ if (qcn->qmlBase() != 0) {
+ qcn = static_cast<const QmlClassNode*>(qcn->qmlBase());
+ if (!qcn->isAbstract())
+ qcn = 0;
+ }
+ else
+ qcn = 0;
+ }
+ append(sections,qmlproperties);
+ append(sections,qmlattachedproperties);
+ append(sections,qmlsignals);
+ append(sections,qmlsignalhandlers);
+ append(sections,qmlattachedsignals);
+ append(sections,qmlmethods);
+ append(sections,qmlattachedmethods);
+ }
+ else if (style == Detailed) {
+ FastSection qmlproperties(qmlClassNode, "Property Documentation","qmlprop","member","members");
+ FastSection qmlattachedproperties(qmlClassNode,"Attached Property Documentation","qmlattprop",
+ "member","members");
+ FastSection qmlsignals(qmlClassNode,"Signal Documentation","qmlsig","signal","signals");
+ FastSection qmlsignalhandlers(qmlClassNode,"Signal Handler Documentation","qmlsighan","signal handler","signal handlers");
+ FastSection qmlattachedsignals(qmlClassNode,"Attached Signal Documentation","qmlattsig",
+ "signal","signals");
+ FastSection qmlmethods(qmlClassNode,"Method Documentation","qmlmeth","member","members");
+ FastSection qmlattachedmethods(qmlClassNode,"Attached Method Documentation","qmlattmeth",
+ "member","members");
+ const QmlClassNode* qcn = qmlClassNode;
+ while (qcn != 0) {
+ NodeList::ConstIterator c = qcn->childNodes().begin();
+ while (c != qcn->childNodes().end()) {
+ if ((*c)->subType() == Node::QmlPropertyGroup) {
+ const QmlPropGroupNode* pgn = static_cast<const QmlPropGroupNode*>(*c);
+ if (pgn->isAttached())
+ insert(qmlattachedproperties,*c,style,Okay);
+ else
+ insert(qmlproperties,*c,style,Okay);
+ }
+ else if ((*c)->type() == Node::QmlProperty) {
+ const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(*c);
+ if (pn->isAttached())
+ insert(qmlattachedproperties,*c,style,Okay);
+ else
+ insert(qmlproperties,*c,style,Okay);
+ }
+ else if ((*c)->type() == Node::QmlSignal) {
+ const FunctionNode* sn = static_cast<const FunctionNode*>(*c);
+ if (sn->isAttached())
+ insert(qmlattachedsignals,*c,style,Okay);
+ else
+ insert(qmlsignals,*c,style,Okay);
+ }
+ else if ((*c)->type() == Node::QmlSignalHandler) {
+ insert(qmlsignalhandlers,*c,style,Okay);
+ }
+ else if ((*c)->type() == Node::QmlMethod) {
+ const FunctionNode* mn = static_cast<const FunctionNode*>(*c);
+ if (mn->isAttached())
+ insert(qmlattachedmethods,*c,style,Okay);
+ else
+ insert(qmlmethods,*c,style,Okay);
+ }
+ ++c;
+ }
+ if (qcn->qmlBase() != 0) {
+ qcn = static_cast<const QmlClassNode*>(qcn->qmlBase());
+ if (!qcn->isAbstract())
+ qcn = 0;
+ }
+ else
+ qcn = 0;
+ }
+ append(sections,qmlproperties);
+ append(sections,qmlattachedproperties);
+ append(sections,qmlsignals);
+ append(sections,qmlsignalhandlers);
+ append(sections,qmlattachedsignals);
+ append(sections,qmlmethods);
+ append(sections,qmlattachedmethods);
+ }
+ else {
+ FastSection all(qmlClassNode,"","","member","members");
+
+ const QmlClassNode* current = qmlClassNode;
+ while (current != 0) {
+ NodeList::ConstIterator c = current->childNodes().begin();
+ while (c != current->childNodes().end()) {
+ if ((*c)->subType() == Node::QmlPropertyGroup) {
+ const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c);
+ NodeList::ConstIterator p = qpgn->childNodes().begin();
+ while (p != qpgn->childNodes().end()) {
+ if ((*p)->type() == Node::QmlProperty) {
+ QString key = current->name() + "::" + (*p)->name();
+ key = sortName(*p, &key);
+ if (!all.memberMap.contains(key))
+ all.memberMap.insert(key,*p);
+ //insert(all,*p,style,Okay);
+ }
+ ++p;
+ }
+ }
+ else {
+ QString key = current->name() + "::" + (*c)->name();
+ key = sortName(*c, &key);
+ if (!all.memberMap.contains(key))
+ all.memberMap.insert(key,*c);
+ //insert(all,*c,style,Okay);
+ }
+ ++c;
+ }
+ const FakeNode* fn = current->qmlBase();
+ if (fn) {
+ if (fn->subType() == Node::QmlClass)
+ current = static_cast<const QmlClassNode*>(fn);
+ else {
+ fn->doc().location().warning(tr("Base class of QML class '%1' is ambgiguous")
+ .arg(current->name()));
+ current = 0;
+ }
+ }
+ else
+ current = 0;
+ }
+ append(sections, all, true);
+ }
+ }
+
+ return sections;
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/cppcodemarker.h b/src/tools/qdoc/cppcodemarker.h
new file mode 100644
index 0000000000..b898f9e3bd
--- /dev/null
+++ b/src/tools/qdoc/cppcodemarker.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ cppcodemarker.h
+*/
+
+#ifndef CPPCODEMARKER_H
+#define CPPCODEMARKER_H
+
+#include "codemarker.h"
+
+QT_BEGIN_NAMESPACE
+
+class CppCodeMarker : public CodeMarker
+{
+public:
+ CppCodeMarker();
+ ~CppCodeMarker();
+
+ virtual bool recognizeCode(const QString& code);
+ virtual bool recognizeExtension(const QString& ext);
+ virtual bool recognizeLanguage(const QString& lang);
+ virtual Atom::Type atomType() const;
+ virtual QString plainName(const Node *node);
+ virtual QString plainFullName(const Node *node, const Node *relative);
+ virtual QString markedUpCode(const QString& code,
+ const Node *relative,
+ const Location &location);
+ virtual QString markedUpSynopsis(const Node *node,
+ const Node *relative,
+ SynopsisStyle style);
+ virtual QString markedUpQmlItem(const Node *node, bool summary);
+ virtual QString markedUpName(const Node *node);
+ virtual QString markedUpFullName(const Node *node, const Node *relative);
+ virtual QString markedUpEnumValue(const QString &enumValue, const Node *relative);
+ virtual QString markedUpIncludes(const QStringList& includes);
+ virtual QString functionBeginRegExp(const QString& funcName);
+ virtual QString functionEndRegExp(const QString& funcName);
+ virtual QList<Section> sections(const InnerNode *innerNode,
+ SynopsisStyle style,
+ Status status);
+ virtual QList<Section> qmlSections(const QmlClassNode* qmlClassNode,
+ SynopsisStyle style);
+ virtual const Node* resolveTarget(const QString& target,
+ const Tree* tree,
+ const Node* relative,
+ const Node* self = 0);
+
+private:
+ QString addMarkUp(const QString& protectedCode,
+ const Node *relative,
+ const Location &location);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/cppcodeparser.cpp b/src/tools/qdoc/cppcodeparser.cpp
new file mode 100644
index 0000000000..b83e617ee3
--- /dev/null
+++ b/src/tools/qdoc/cppcodeparser.cpp
@@ -0,0 +1,2502 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ cppcodeparser.cpp
+*/
+
+#include <qfile.h>
+#include <stdio.h>
+#include <errno.h>
+#include "codechunk.h"
+#include "config.h"
+#include "cppcodeparser.h"
+#include "tokenizer.h"
+#include "tree.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/* qmake ignore Q_OBJECT */
+
+#define COMMAND_CLASS Doc::alias("class")
+#define COMMAND_CONTENTSPAGE Doc::alias("contentspage")
+#define COMMAND_DITAMAP Doc::alias("ditamap")
+#define COMMAND_ENUM Doc::alias("enum")
+#define COMMAND_EXAMPLE Doc::alias("example")
+#define COMMAND_EXTERNALPAGE Doc::alias("externalpage")
+#define COMMAND_FILE Doc::alias("file")
+#define COMMAND_FN Doc::alias("fn")
+#define COMMAND_GROUP Doc::alias("group")
+#define COMMAND_HEADERFILE Doc::alias("headerfile")
+#define COMMAND_INDEXPAGE Doc::alias("indexpage")
+#define COMMAND_INHEADERFILE Doc::alias("inheaderfile")
+#define COMMAND_MACRO Doc::alias("macro")
+#define COMMAND_MODULE Doc::alias("module")
+#define COMMAND_NAMESPACE Doc::alias("namespace")
+#define COMMAND_OVERLOAD Doc::alias("overload")
+#define COMMAND_NEXTPAGE Doc::alias("nextpage")
+#define COMMAND_PAGE Doc::alias("page")
+#define COMMAND_PREVIOUSPAGE Doc::alias("previouspage")
+#define COMMAND_PROPERTY Doc::alias("property")
+#define COMMAND_REIMP Doc::alias("reimp")
+#define COMMAND_RELATES Doc::alias("relates")
+#define COMMAND_SERVICE Doc::alias("service")
+#define COMMAND_STARTPAGE Doc::alias("startpage")
+#define COMMAND_TYPEDEF Doc::alias("typedef")
+#define COMMAND_VARIABLE Doc::alias("variable")
+#define COMMAND_QMLABSTRACT Doc::alias("qmlabstract")
+#define COMMAND_QMLCLASS Doc::alias("qmlclass")
+#define COMMAND_QMLPROPERTY Doc::alias("qmlproperty")
+#define COMMAND_QMLATTACHEDPROPERTY Doc::alias("qmlattachedproperty")
+#define COMMAND_QMLINHERITS Doc::alias("inherits")
+#define COMMAND_QMLSIGNAL Doc::alias("qmlsignal")
+#define COMMAND_QMLATTACHEDSIGNAL Doc::alias("qmlattachedsignal")
+#define COMMAND_QMLMETHOD Doc::alias("qmlmethod")
+#define COMMAND_QMLATTACHEDMETHOD Doc::alias("qmlattachedmethod")
+#define COMMAND_QMLDEFAULT Doc::alias("default")
+#define COMMAND_QMLREADONLY Doc::alias("readonly")
+#define COMMAND_QMLBASICTYPE Doc::alias("qmlbasictype")
+#define COMMAND_QMLMODULE Doc::alias("qmlmodule")
+#define COMMAND_AUDIENCE Doc::alias("audience")
+#define COMMAND_CATEGORY Doc::alias("category")
+#define COMMAND_PRODNAME Doc::alias("prodname")
+#define COMMAND_COMPONENT Doc::alias("component")
+#define COMMAND_AUTHOR Doc::alias("author")
+#define COMMAND_PUBLISHER Doc::alias("publisher")
+#define COMMAND_COPYRYEAR Doc::alias("copyryear")
+#define COMMAND_COPYRHOLDER Doc::alias("copyrholder")
+#define COMMAND_PERMISSIONS Doc::alias("permissions")
+#define COMMAND_LIFECYCLEVERSION Doc::alias("lifecycleversion")
+#define COMMAND_LIFECYCLEWSTATUS Doc::alias("lifecyclestatus")
+#define COMMAND_LICENSEYEAR Doc::alias("licenseyear")
+#define COMMAND_LICENSENAME Doc::alias("licensename")
+#define COMMAND_LICENSEDESCRIPTION Doc::alias("licensedescription")
+#define COMMAND_RELEASEDATE Doc::alias("releasedate")
+
+QStringList CppCodeParser::exampleFiles;
+QStringList CppCodeParser::exampleDirs;
+
+/*
+ This is used for fuzzy matching only, which in turn is only used
+ for Qt Jambi.
+*/
+static QString cleanType(const QString &type, const Tree *tree)
+{
+ QString result = type;
+ result.replace("qlonglong", "long long");
+ result.replace("qulonglong", "unsigned long long");
+ result.replace("qreal", "double");
+ result.replace(QRegExp("\\bu(int|short|char|long)\\b"), "unsigned \\1");
+ result.replace("QRgb", "unsigned int");
+ result.replace(" >", ">");
+ result.remove(" const[]");
+ result.replace("QStringList<QString>", "QStringList");
+ result.replace("qint8", "char");
+ result.replace("qint16", "short");
+ result.replace("qint32", "int");
+ result.replace("qint64", "long long");
+ result.replace("quint8", "unsigned char");
+ result.replace("quint16", "unsigned short");
+ result.replace("quint32", "unsigned int");
+ result.replace("quint64", "unsigned long long");
+
+ if (result.contains("QFlags")) {
+ QRegExp regExp("QFlags<(((?:[^<>]+::)*)([^<>:]+))>");
+ int pos = 0;
+ while ((pos = result.indexOf(regExp, pos)) != -1) {
+ // we assume that the path for the associated enum
+ // is the same as for the flag typedef
+ QStringList path = regExp.cap(2).split("::",
+ QString::SkipEmptyParts);
+ const EnumNode *enume = static_cast<const EnumNode *>(
+ tree->findNode(QStringList(path) << regExp.cap(3),
+ Node::Enum));
+ if (enume && enume->flagsType())
+ result.replace(pos, regExp.matchedLength(),
+ (QStringList(path) << enume->flagsType()->name()).join("::"));
+ ++pos;
+ }
+ }
+ if (result.contains("::")) {
+ // remove needless (and needful) class prefixes
+ QRegExp regExp("[A-Za-z0-9_]+::");
+ result.remove(regExp);
+ }
+ return result;
+}
+
+/*!
+ The constructor initializes some regular expressions
+ and calls reset().
+ */
+CppCodeParser::CppCodeParser()
+ : varComment("/\\*\\s*([a-zA-Z_0-9]+)\\s*\\*/"), sep("(?:<[^>]+>)?::")
+{
+ reset(0);
+}
+
+/*!
+ The destructor is trivial.
+ */
+CppCodeParser::~CppCodeParser()
+{
+ // nothing.
+}
+
+/*!
+ The constructor initializes a map of special node types
+ for identifying important nodes. And it initializes
+ some filters for identifying certain kinds of files.
+ */
+void CppCodeParser::initializeParser(const Config &config)
+{
+ CodeParser::initializeParser(config);
+
+ nodeTypeMap.insert(COMMAND_NAMESPACE, Node::Namespace);
+ nodeTypeMap.insert(COMMAND_CLASS, Node::Class);
+ nodeTypeMap.insert(COMMAND_SERVICE, Node::Class);
+ nodeTypeMap.insert(COMMAND_ENUM, Node::Enum);
+ nodeTypeMap.insert(COMMAND_TYPEDEF, Node::Typedef);
+ nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property);
+ nodeTypeMap.insert(COMMAND_VARIABLE, Node::Variable);
+
+ exampleFiles = config.getCleanPathList(CONFIG_EXAMPLES);
+ exampleDirs = config.getCleanPathList(CONFIG_EXAMPLEDIRS);
+ QStringList exampleFilePatterns = config.getStringList(
+ CONFIG_EXAMPLES + Config::dot + CONFIG_FILEEXTENSIONS);
+
+ if (!exampleFilePatterns.isEmpty())
+ exampleNameFilter = exampleFilePatterns.join(" ");
+ else
+ exampleNameFilter = "*.cpp *.h *.js *.xq *.svg *.xml *.ui";
+
+ QStringList exampleImagePatterns = config.getStringList(
+ CONFIG_EXAMPLES + Config::dot + CONFIG_IMAGEEXTENSIONS);
+
+ if (!exampleImagePatterns.isEmpty())
+ exampleImageFilter = exampleImagePatterns.join(" ");
+ else
+ exampleImageFilter = "*.png";
+}
+
+/*!
+ Clear the map of common node types and call
+ the same function in the base class.
+ */
+void CppCodeParser::terminateParser()
+{
+ nodeTypeMap.clear();
+ CodeParser::terminateParser();
+}
+
+/*!
+ Returns "Cpp".
+ */
+QString CppCodeParser::language()
+{
+ return "Cpp";
+}
+
+/*!
+ Returns a list of extensions for header files.
+ */
+QStringList CppCodeParser::headerFileNameFilter()
+{
+ return QStringList() << "*.ch" << "*.h" << "*.h++" << "*.hh" << "*.hpp" << "*.hxx";
+}
+
+/*!
+ Returns a list of extensions for source files, i.e. not
+ header files.
+ */
+QStringList CppCodeParser::sourceFileNameFilter()
+{
+ return QStringList() << "*.c++" << "*.cc" << "*.cpp" << "*.cxx" << "*.mm";
+}
+
+/*!
+ Parse the C++ header file identified by \a filePath
+ and add the parsed contents to the big \a tree. The
+ \a location is used for reporting errors.
+ */
+void CppCodeParser::parseHeaderFile(const Location& location,
+ const QString& filePath,
+ Tree *tree)
+{
+ QFile in(filePath);
+ if (!in.open(QIODevice::ReadOnly)) {
+ location.error(tr("Cannot open C++ header file '%1'").arg(filePath));
+ return;
+ }
+ createOutputSubdirectory(location, filePath);
+
+ reset(tree);
+ Location fileLocation(filePath);
+ Tokenizer fileTokenizer(fileLocation, in);
+ tokenizer = &fileTokenizer;
+ readToken();
+ matchDeclList(tree->root());
+ if (!fileTokenizer.version().isEmpty())
+ tree->setVersion(fileTokenizer.version());
+ in.close();
+
+ if (fileLocation.fileName() == "qiterator.h")
+ parseQiteratorDotH(location, filePath);
+}
+
+/*!
+ Get ready to parse the C++ cpp file identified by \a filePath
+ and add its parsed contents to the big \a tree. \a location is
+ used for reporting errors.
+
+ Call matchDocsAndStuff() to do all the parsing and tree building.
+ */
+void CppCodeParser::parseSourceFile(const Location& location,
+ const QString& filePath,
+ Tree *tree)
+{
+ QFile in(filePath);
+ if (!in.open(QIODevice::ReadOnly)) {
+ location.error(tr("Cannot open C++ source file '%1' (%2)").arg(filePath).arg(strerror(errno)));
+ return;
+ }
+ createOutputSubdirectory(location, filePath);
+
+ reset(tree);
+ Location fileLocation(filePath);
+ Tokenizer fileTokenizer(fileLocation, in);
+ tokenizer = &fileTokenizer;
+ readToken();
+ usedNamespaces.clear();
+ matchDocsAndStuff();
+ in.close();
+}
+
+/*!
+ This is called after all the header files have been parsed.
+ I think the most important thing it does is resolve class
+ inheritance links in the tree. But it also initializes a
+ bunch of stuff.
+ */
+void CppCodeParser::doneParsingHeaderFiles(Tree *tree)
+{
+ tree->resolveInheritance();
+
+ QMapIterator<QString, QString> i(sequentialIteratorClasses);
+ while (i.hasNext()) {
+ i.next();
+ instantiateIteratorMacro(i.key(),
+ i.value(),
+ sequentialIteratorDefinition,
+ tree);
+ }
+ i = mutableSequentialIteratorClasses;
+ while (i.hasNext()) {
+ i.next();
+ instantiateIteratorMacro(i.key(),
+ i.value(),
+ mutableSequentialIteratorDefinition,
+ tree);
+ }
+ i = associativeIteratorClasses;
+ while (i.hasNext()) {
+ i.next();
+ instantiateIteratorMacro(i.key(),
+ i.value(),
+ associativeIteratorDefinition,
+ tree);
+ }
+ i = mutableAssociativeIteratorClasses;
+ while (i.hasNext()) {
+ i.next();
+ instantiateIteratorMacro(i.key(),
+ i.value(),
+ mutableAssociativeIteratorDefinition,
+ tree);
+ }
+ sequentialIteratorDefinition.clear();
+ mutableSequentialIteratorDefinition.clear();
+ associativeIteratorDefinition.clear();
+ mutableAssociativeIteratorDefinition.clear();
+ sequentialIteratorClasses.clear();
+ mutableSequentialIteratorClasses.clear();
+ associativeIteratorClasses.clear();
+ mutableAssociativeIteratorClasses.clear();
+}
+
+/*!
+ This is called after all the source files (i.e., not the
+ header files) have been parsed. It traverses the tree to
+ resolve property links, normalize overload signatures, and
+ do other housekeeping of the tree.
+ */
+void CppCodeParser::doneParsingSourceFiles(Tree *tree)
+{
+ tree->root()->makeUndocumentedChildrenInternal();
+ tree->root()->clearCurrentChildPointers();
+ tree->root()->normalizeOverloads();
+ tree->fixInheritance();
+ tree->resolveProperties();
+}
+
+/*!
+ This function searches the \a tree to find a FunctionNode
+ for a function with the signature \a synopsis. If the
+ \a relative node is provided, the search begins there. If
+ \a fuzzy is true, base classes are searched. The function
+ node is returned, if found.
+ */
+const FunctionNode *CppCodeParser::findFunctionNode(const QString& synopsis,
+ Tree *tree,
+ Node *relative,
+ bool fuzzy)
+{
+ QStringList parentPath;
+ FunctionNode *clone;
+ FunctionNode *func = 0;
+ int flags = fuzzy ? int(Tree::SearchBaseClasses) : 0;
+
+ reset(tree);
+ if (makeFunctionNode(synopsis, &parentPath, &clone)) {
+ func = tree->findFunctionNode(parentPath, clone, relative, flags);
+
+ /*
+ This is necessary because Roberto's parser resolves typedefs.
+ */
+ if (!func && fuzzy) {
+ func = tre->findFunctionNode(parentPath +
+ QStringList(clone->name()),
+ relative,
+ flags);
+ if (!func && clone->name().contains('_')) {
+ QStringList path = parentPath;
+ path << clone->name().split('_');
+ func = tre->findFunctionNode(path, relative, flags);
+ }
+
+ if (func) {
+ NodeList overloads = func->parent()->overloads(func->name());
+ NodeList candidates;
+ for (int i = 0; i < overloads.count(); ++i) {
+ FunctionNode *overload = static_cast<FunctionNode *>(overloads.at(i));
+ if (overload->status() != Node::Compat
+ && overload->parameters().count() == clone->parameters().count()
+ && !overload->isConst() == !clone->isConst())
+ candidates << overload;
+ }
+ if (candidates.count() == 0)
+ return 0;
+
+ /*
+ There's only one function with the correct number
+ of parameters. That must be the one.
+ */
+ if (candidates.count() == 1)
+ return static_cast<FunctionNode *>(candidates.first());
+
+ overloads = candidates;
+ candidates.clear();
+ for (int i = 0; i < overloads.count(); ++i) {
+ FunctionNode *overload = static_cast<FunctionNode *>(overloads.at(i));
+ QList<Parameter> params1 = overload->parameters();
+ QList<Parameter> params2 = clone->parameters();
+
+ int j;
+ for (j = 0; j < params1.count(); ++j) {
+ if (!params2.at(j).name().startsWith(params1.at(j).name()))
+ break;
+ }
+ if (j == params1.count())
+ candidates << overload;
+ }
+
+ /*
+ There are several functions with the correct
+ parameter count, but only one has the correct
+ parameter names.
+ */
+ if (candidates.count() == 1)
+ return static_cast<FunctionNode *>(candidates.first());
+
+ candidates.clear();
+ for (int i = 0; i < overloads.count(); ++i) {
+ FunctionNode *overload = static_cast<FunctionNode *>(overloads.at(i));
+ QList<Parameter> params1 = overload->parameters();
+ QList<Parameter> params2 = clone->parameters();
+
+ int j;
+ for (j = 0; j < params1.count(); ++j) {
+ if (params1.at(j).rightType() != params2.at(j).rightType())
+ break;
+
+ if (cleanType(params1.at(j).leftType(), tree)
+ != cleanType(params2.at(j).leftType(), tree))
+ break;
+ }
+ if (j == params1.count())
+ candidates << overload;
+ }
+
+
+ /*
+ There are several functions with the correct
+ parameter count, but only one has the correct
+ types, loosely compared.
+ */
+ if (candidates.count() == 1)
+ return static_cast<FunctionNode *>(candidates.first());
+
+ return 0;
+ }
+ }
+ delete clone;
+ }
+ return func;
+}
+
+/*!
+ Returns the set of strings reopresenting the topic commands.
+ */
+QSet<QString> CppCodeParser::topicCommands()
+{
+ return QSet<QString>() << COMMAND_CLASS
+ << COMMAND_DITAMAP
+ << COMMAND_ENUM
+ << COMMAND_EXAMPLE
+ << COMMAND_EXTERNALPAGE
+ << COMMAND_FILE
+ << COMMAND_FN
+ << COMMAND_GROUP
+ << COMMAND_HEADERFILE
+ << COMMAND_MACRO
+ << COMMAND_MODULE
+ << COMMAND_NAMESPACE
+ << COMMAND_PAGE
+ << COMMAND_PROPERTY
+ << COMMAND_SERVICE
+ << COMMAND_TYPEDEF
+ << COMMAND_VARIABLE
+ << COMMAND_QMLCLASS
+ << COMMAND_QMLPROPERTY
+ << COMMAND_QMLATTACHEDPROPERTY
+ << COMMAND_QMLSIGNAL
+ << COMMAND_QMLATTACHEDSIGNAL
+ << COMMAND_QMLMETHOD
+ << COMMAND_QMLATTACHEDMETHOD
+ << COMMAND_QMLBASICTYPE
+ << COMMAND_QMLMODULE;
+}
+
+/*!
+ Process the topic \a command in context \a doc with argument \a arg.
+ */
+Node* CppCodeParser::processTopicCommand(const Doc& doc,
+ const QString& command,
+ const QString& arg)
+{
+ if (command == COMMAND_FN) {
+ QStringList parentPath;
+ FunctionNode *func = 0;
+ FunctionNode *clone = 0;
+
+ if (!makeFunctionNode(arg, &parentPath, &clone) &&
+ !makeFunctionNode("void " + arg, &parentPath, &clone)) {
+ doc.location().warning(tr("Invalid syntax in '\\%1'").arg(COMMAND_FN));
+ }
+ else {
+ if (!usedNamespaces.isEmpty()) {
+ foreach (const QString &usedNamespace, usedNamespaces) {
+ QStringList newPath = usedNamespace.split("::") + parentPath;
+ func = tre->findFunctionNode(newPath, clone);
+ if (func)
+ break;
+ }
+ }
+ // Search the root namespace if no match was found.
+ if (func == 0)
+ func = tre->findFunctionNode(parentPath, clone);
+
+ if (func == 0) {
+ if (parentPath.isEmpty() && !lastPath.isEmpty())
+ func = tre->findFunctionNode(lastPath, clone);
+ if (func == 0) {
+ doc.location().warning(tr("Cannot find '%1' in '\\%2'")
+ .arg(clone->name() + "(...)")
+ .arg(COMMAND_FN),
+ tr("I cannot find any function of that name with the "
+ "specified signature. Make sure that the signature "
+ "is identical to the declaration, including 'const' "
+ "qualifiers."));
+ }
+ else {
+ doc.location().warning(tr("Missing '%1::' for '%2' in '\\%3'")
+ .arg(lastPath.join("::"))
+ .arg(clone->name() + "()")
+ .arg(COMMAND_FN));
+ }
+ }
+ else {
+ lastPath = parentPath;
+ }
+ if (func) {
+ func->borrowParameterNames(clone);
+ func->setParentPath(clone->parentPath());
+ }
+ delete clone;
+ }
+ return func;
+ }
+ else if (command == COMMAND_MACRO) {
+ QStringList parentPath;
+ FunctionNode *func = 0;
+
+ if (makeFunctionNode(arg, &parentPath, &func, tre->root())) {
+ if (!parentPath.isEmpty()) {
+ doc.location().warning(tr("Invalid syntax in '\\%1'")
+ .arg(COMMAND_MACRO));
+ delete func;
+ func = 0;
+ }
+ else {
+ func->setMetaness(FunctionNode::MacroWithParams);
+ QList<Parameter> params = func->parameters();
+ for (int i = 0; i < params.size(); ++i) {
+ Parameter &param = params[i];
+ if (param.name().isEmpty() && !param.leftType().isEmpty()
+ && param.leftType() != "...")
+ param = Parameter("", "", param.leftType());
+ }
+ func->setParameters(params);
+ }
+ return func;
+ }
+ else if (QRegExp("[A-Za-z_][A-Za-z0-9_]+").exactMatch(arg)) {
+ func = new FunctionNode(tre->root(), arg);
+ func->setAccess(Node::Public);
+ func->setLocation(doc.location());
+ func->setMetaness(FunctionNode::MacroWithoutParams);
+ }
+ else {
+ doc.location().warning(tr("Invalid syntax in '\\%1'")
+ .arg(COMMAND_MACRO));
+
+ }
+ return func;
+ }
+ else if (nodeTypeMap.contains(command)) {
+ /*
+ The command was neither "fn" nor "macro" .
+ */
+ // ### split(QLatin1Char(' ')) hack is there to support header file syntax
+ QStringList paths = arg.split(QLatin1Char(' '));
+ QStringList path = paths[0].split("::");
+ Node *node = 0;
+ if (!usedNamespaces.isEmpty()) {
+ foreach (const QString &usedNamespace, usedNamespaces) {
+ QStringList newPath = usedNamespace.split("::") + path;
+ node = tre->findNode(newPath, nodeTypeMap[command]);
+ if (node) {
+ path = newPath;
+ break;
+ }
+ }
+ }
+ // Search the root namespace if no match was found.
+ if (node == 0)
+ node = tre->findNode(path, nodeTypeMap[command]);
+
+ if (node == 0) {
+ doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file")
+ .arg(arg).arg(command));
+ lastPath = path;
+
+ }
+ else if (command == COMMAND_SERVICE) {
+ // If the command is "\service", then we need to tag the
+ // class with the actual service name.
+ QStringList args = arg.split(QLatin1Char(' '));
+ if (args.size() > 1) {
+ ClassNode *cnode = static_cast<ClassNode *>(node);
+ cnode->setServiceName(args[1]);
+ cnode->setHideFromMainList(true);
+ }
+ }
+ else if (node->isInnerNode()) {
+ if (path.size() > 1) {
+ path.pop_back();
+ usedNamespaces.insert(path.join("::"));
+ }
+ }
+#if 0
+ /*
+ This code apparently does nothing. After further
+ investigation to verify it is useless, it will
+ be removed.
+ */
+ if (command == COMMAND_CLASS) {
+ if (paths.size() > 1) {
+ if (!paths[1].endsWith(".h")) {
+ ClassNode* cnode = static_cast<ClassNode*>(node);
+ cnode->setQmlElement(paths[1]);
+ }
+ }
+ }
+#endif
+ return node;
+ }
+ else if (command == COMMAND_EXAMPLE) {
+ ExampleNode* en = new ExampleNode(tre->root(), arg);
+ createExampleFileNodes(en);
+ return en;
+ }
+ else if (command == COMMAND_EXTERNALPAGE) {
+ return new FakeNode(tre->root(), arg, Node::ExternalPage, Node::ArticlePage);
+ }
+ else if (command == COMMAND_FILE) {
+ return new FakeNode(tre->root(), arg, Node::File, Node::NoPageType);
+ }
+ else if (command == COMMAND_GROUP) {
+ return new FakeNode(tre->root(), arg, Node::Group, Node::OverviewPage);
+ }
+ else if (command == COMMAND_HEADERFILE) {
+ return new FakeNode(tre->root(), arg, Node::HeaderFile, Node::ApiPage);
+ }
+ else if (command == COMMAND_MODULE) {
+ return new FakeNode(tre->root(), arg, Node::Module, Node::OverviewPage);
+ }
+ else if (command == COMMAND_QMLMODULE) {
+ return new FakeNode(tre->root(), arg, Node::QmlModule, Node::OverviewPage);
+ }
+ else if (command == COMMAND_PAGE) {
+ Node::PageType ptype = Node::ArticlePage;
+ QStringList args = arg.split(QLatin1Char(' '));
+ if (args.size() > 1) {
+ QString t = args[1].toLower();
+ if (t == "howto")
+ ptype = Node::HowToPage;
+ else if (t == "api")
+ ptype = Node::ApiPage;
+ else if (t == "example")
+ ptype = Node::ExamplePage;
+ else if (t == "overview")
+ ptype = Node::OverviewPage;
+ else if (t == "tutorial")
+ ptype = Node::TutorialPage;
+ else if (t == "faq")
+ ptype = Node::FAQPage;
+ else if (t == "ditamap")
+ ptype = Node::DitaMapPage;
+ }
+
+ /*
+ Search for a node with the same name. If there is one,
+ then there is a collision, so create a collision node
+ and make the existing node a child of the collision
+ node, and then create the new Page node and make
+ it a child of the collision node as well. Return the
+ collision node.
+
+ If there is no collision, just create a new Page
+ node and return that one.
+ */
+ NameCollisionNode* ncn = tre->checkForCollision(args[0]);
+ FakeNode* fn = 0;
+ if (ptype == Node::DitaMapPage)
+ fn = new DitaMapNode(tre->root(), args[0]);
+ else
+ fn = new FakeNode(tre->root(), args[0], Node::Page, ptype);
+ if (ncn) {
+ ncn->addCollision(fn);
+ }
+ return fn;
+ }
+ else if (command == COMMAND_DITAMAP) {
+ FakeNode* fn = new DitaMapNode(tre->root(), arg);
+ return fn;
+ }
+ else if (command == COMMAND_QMLCLASS) {
+ const ClassNode* classNode = 0;
+ QStringList names = arg.split(QLatin1Char(' '));
+ if (names.size() > 1) {
+ Node* n = tre->findNode(names[1].split("::"),Node::Class);
+ if (n) {
+ classNode = static_cast<const ClassNode*>(n);
+ }
+ }
+ /*
+ Search for a node with the same name. If there is one,
+ then there is a collision, so create a collision node
+ and make the existing node a child of the collision
+ node, and then create the new QML class node and make
+ it a child of the collision node as well. Return the
+ collision node.
+
+ If there is no collision, just create a new QML class
+ node and return that one.
+ */
+ NameCollisionNode* ncn = tre->checkForCollision(names[0]);
+ QmlClassNode* qcn = new QmlClassNode(tre->root(), names[0], classNode);
+ if (ncn) {
+ ncn->addCollision(qcn);
+ }
+ return qcn;
+ }
+ else if (command == COMMAND_QMLBASICTYPE) {
+ return new QmlBasicTypeNode(tre->root(), arg);
+ }
+ else if ((command == COMMAND_QMLSIGNAL) ||
+ (command == COMMAND_QMLMETHOD) ||
+ (command == COMMAND_QMLATTACHEDSIGNAL) ||
+ (command == COMMAND_QMLATTACHEDMETHOD)) {
+ QString module;
+ QString element;
+ QString type;
+ if (splitQmlMethodArg(doc,arg,type,module,element)) {
+ QmlClassNode* qmlClass = tre->findQmlClassNode(module,element);
+ if (qmlClass) {
+ if (command == COMMAND_QMLSIGNAL)
+ return makeFunctionNode(doc,arg,qmlClass,Node::QmlSignal,false,COMMAND_QMLSIGNAL);
+ else if (command == COMMAND_QMLATTACHEDSIGNAL)
+ return makeFunctionNode(doc,arg,qmlClass,Node::QmlSignal,true,COMMAND_QMLATTACHEDSIGNAL);
+ else if (command == COMMAND_QMLMETHOD)
+ return makeFunctionNode(doc,arg,qmlClass,Node::QmlMethod,false,COMMAND_QMLMETHOD);
+ else if (command == COMMAND_QMLATTACHEDMETHOD)
+ return makeFunctionNode(doc,arg,qmlClass,Node::QmlMethod,true,COMMAND_QMLATTACHEDMETHOD);
+ else
+ return 0; // never get here.
+ }
+ }
+ }
+ return 0;
+}
+
+/*!
+ A QML property argument has the form...
+
+ <type> <element>::<name>
+ <type> <QML-module>::<element>::<name>
+
+ This function splits the argument into one of those
+ two forms. The three part form is the old form, which
+ was used before the creation of QtQuick 2 and Qt
+ Components. A <QML-module> is the QML equivalent of a
+ C++ namespace. So this function splits \a arg on "::"
+ and stores the parts in \a type, \a module, \a element,
+ and \a name, and returns true. If any part other than
+ \a module is not found, a qdoc warning is emitted and
+ false is returned.
+
+ \note The two elements \e{Component} and \e{QtObject} never
+ have a module qualifier.
+ */
+bool CppCodeParser::splitQmlPropertyArg(const Doc& doc,
+ const QString& arg,
+ QString& type,
+ QString& module,
+ QString& element,
+ QString& name)
+{
+ QStringList blankSplit = arg.split(QLatin1Char(' '));
+ if (blankSplit.size() > 1) {
+ type = blankSplit[0];
+ QStringList colonSplit(blankSplit[1].split("::"));
+ if (colonSplit.size() == 3) {
+ module = colonSplit[0];
+ element = colonSplit[1];
+ name = colonSplit[2];
+ return true;
+ }
+ if (colonSplit.size() == 2) {
+ module.clear();
+ element = colonSplit[0];
+ name = colonSplit[1];
+ return true;
+ }
+ QString msg = "Unrecognizable QML module/component qualifier for " + arg;
+ doc.location().warning(tr(msg.toLatin1().data()));
+ }
+ else {
+ QString msg = "Missing property type for " + arg;
+ doc.location().warning(tr(msg.toLatin1().data()));
+ }
+ return false;
+}
+
+/*!
+ A QML signal or method argument has the form...
+
+ <type> <element>::<name>(<param>, <param>, ...)
+ <type> <QML-module>::<element>::<name>(<param>, <param>, ...)
+
+ This function splits the argument into one of those two
+ forms, sets \a module, \a element, and \a name, and returns
+ true. If the argument doesn't match either form, an error
+ message is emitted and false is returned.
+
+ \note The two elements \e{Component} and \e{QtObject} never
+ have a module qualifier.
+ */
+bool CppCodeParser::splitQmlMethodArg(const Doc& doc,
+ const QString& arg,
+ QString& type,
+ QString& module,
+ QString& element)
+{
+ QStringList colonSplit(arg.split("::"));
+ if (colonSplit.size() > 1) {
+ QStringList blankSplit = colonSplit[0].split(QLatin1Char(' '));
+ if (blankSplit.size() > 1) {
+ type = blankSplit[0];
+ if (colonSplit.size() > 2) {
+ module = blankSplit[1];
+ element = colonSplit[1];
+ }
+ else {
+ module.clear();
+ element = blankSplit[1];
+ }
+ }
+ else {
+ type = QString("");
+ if (colonSplit.size() > 2) {
+ module = colonSplit[0];
+ element = colonSplit[1];
+ }
+ else {
+ module.clear();
+ element = colonSplit[0];
+ }
+ }
+ return true;
+ }
+ QString msg = "Unrecognizable QML module/component qualifier for " + arg;
+ doc.location().warning(tr(msg.toLatin1().data()));
+ return false;
+}
+
+/*!
+ Process the topic \a command group with arguments \a args.
+
+ Currently, this function is called only for \e{qmlproperty}
+ and \e{qmlattachedproperty}.
+ */
+Node *CppCodeParser::processTopicCommandGroup(const Doc& doc,
+ const QString& command,
+ const QStringList& args)
+{
+ QmlPropGroupNode* qmlPropGroup = 0;
+ if ((command == COMMAND_QMLPROPERTY) ||
+ (command == COMMAND_QMLATTACHEDPROPERTY)) {
+ QString type;
+ QString module;
+ QString element;
+ QString property;
+ bool attached = (command == COMMAND_QMLATTACHEDPROPERTY);
+ QStringList::ConstIterator arg = args.begin();
+ if (splitQmlPropertyArg(doc,(*arg),type,module,element,property)) {
+ QmlClassNode* qmlClass = tre->findQmlClassNode(module,element);
+ if (qmlClass) {
+ qmlPropGroup = new QmlPropGroupNode(qmlClass,property,attached);
+ }
+ }
+ if (qmlPropGroup) {
+ const ClassNode *correspondingClass = static_cast<const QmlClassNode*>(qmlPropGroup->parent())->classNode();
+ QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlPropGroup,property,type,attached);
+
+ const PropertyNode *correspondingProperty = 0;
+ if (correspondingClass) {
+ correspondingProperty = qmlPropNode->correspondingProperty(tre);
+ }
+ if (correspondingProperty) {
+ bool writableList = type.startsWith("list") && correspondingProperty->dataType().endsWith('*');
+ qmlPropNode->setWritable(writableList || correspondingProperty->isWritable());
+ }
+ ++arg;
+ while (arg != args.end()) {
+ if (splitQmlPropertyArg(doc,(*arg),type,module,element,property)) {
+ QmlPropertyNode* qmlPropNode = new QmlPropertyNode(qmlPropGroup,
+ property,
+ type,
+ attached);
+ if (correspondingProperty) {
+ bool writableList = type.startsWith("list") && correspondingProperty->dataType().endsWith('*');
+ qmlPropNode->setWritable(writableList || correspondingProperty->isWritable());
+ }
+ }
+ ++arg;
+ }
+ }
+ }
+ return qmlPropGroup;
+}
+
+/*!
+ Returns the set of strings representing the common metacommands
+ plus some other metacommands.
+ */
+QSet<QString> CppCodeParser::otherMetaCommands()
+{
+ return commonMetaCommands() << COMMAND_INHEADERFILE
+ << COMMAND_OVERLOAD
+ << COMMAND_REIMP
+ << COMMAND_RELATES
+ << COMMAND_CONTENTSPAGE
+ << COMMAND_NEXTPAGE
+ << COMMAND_PREVIOUSPAGE
+ << COMMAND_INDEXPAGE
+ << COMMAND_STARTPAGE
+ << COMMAND_QMLINHERITS
+ << COMMAND_QMLDEFAULT
+ << COMMAND_QMLREADONLY
+ << COMMAND_QMLABSTRACT;
+}
+
+/*!
+ Process the metacommand \a command in the context of the
+ \a node associated with the topic command and the \a doc.
+ \a arg is the argument to the metacommand.
+ */
+void CppCodeParser::processOtherMetaCommand(const Doc& doc,
+ const QString& command,
+ const QString& arg,
+ Node *node)
+{
+ if (command == COMMAND_INHEADERFILE) {
+ if (node != 0 && node->isInnerNode()) {
+ ((InnerNode *) node)->addInclude(arg);
+ }
+ else {
+ doc.location().warning(tr("Ignored '\\%1'")
+ .arg(COMMAND_INHEADERFILE));
+ }
+ }
+ else if (command == COMMAND_OVERLOAD) {
+ if (node != 0 && node->type() == Node::Function) {
+ ((FunctionNode *) node)->setOverload(true);
+ }
+ else {
+ doc.location().warning(tr("Ignored '\\%1'")
+ .arg(COMMAND_OVERLOAD));
+ }
+ }
+ else if (command == COMMAND_REIMP) {
+ if (node != 0 && node->type() == Node::Function) {
+ FunctionNode *func = (FunctionNode *) node;
+ const FunctionNode *from = func->reimplementedFrom();
+ if (from == 0) {
+ doc.location().warning(
+ tr("Cannot find base function for '\\%1' in %2()")
+ .arg(COMMAND_REIMP).arg(node->name()),
+ tr("The function either doesn't exist in any base class "
+ "with the same signature or it exists but isn't virtual."));
+ }
+ /*
+ Ideally, we would enable this check to warn whenever
+ \reimp is used incorrectly, and only make the node
+ internal if the function is a reimplementation of
+ another function in a base class.
+ */
+ else if (from->access() == Node::Private
+ || from->parent()->access() == Node::Private) {
+ doc.location().warning(tr("'\\%1' in %2() should be '\\internal' because its base function is private or internal")
+ .arg(COMMAND_REIMP).arg(node->name()));
+ }
+
+ func->setReimp(true);
+ }
+ else {
+ doc.location().warning(tr("Ignored '\\%1' in %2")
+ .arg(COMMAND_REIMP)
+ .arg(node->name()));
+ }
+ }
+ else if (command == COMMAND_RELATES) {
+ InnerNode *pseudoParent;
+ if (arg.startsWith(QLatin1Char('<')) || arg.startsWith('"')) {
+ pseudoParent =
+ static_cast<InnerNode *>(tre->findNode(QStringList(arg),
+ Node::Fake));
+ }
+ else {
+ QStringList newPath = arg.split("::");
+ pseudoParent =
+ static_cast<InnerNode*>(tre->findNode(QStringList(newPath),
+ Node::Class));
+ if (!pseudoParent)
+ pseudoParent =
+ static_cast<InnerNode*>(tre->findNode(QStringList(newPath),
+ Node::Namespace));
+ }
+ if (!pseudoParent) {
+ doc.location().warning(tr("Cannot find '%1' in '\\%2'")
+ .arg(arg).arg(COMMAND_RELATES));
+ }
+ else {
+ node->setRelates(pseudoParent);
+ }
+ }
+ else if (command == COMMAND_CONTENTSPAGE) {
+ setLink(node, Node::ContentsLink, arg);
+ }
+ else if (command == COMMAND_NEXTPAGE) {
+ setLink(node, Node::NextLink, arg);
+ }
+ else if (command == COMMAND_PREVIOUSPAGE) {
+ setLink(node, Node::PreviousLink, arg);
+ }
+ else if (command == COMMAND_INDEXPAGE) {
+ setLink(node, Node::IndexLink, arg);
+ }
+ else if (command == COMMAND_STARTPAGE) {
+ setLink(node, Node::StartLink, arg);
+ }
+ else if (command == COMMAND_QMLINHERITS) {
+ if (node->name() == arg)
+ doc.location().warning(tr("%1 tries to inherit itself").arg(arg));
+ else {
+ setLink(node, Node::InheritsLink, arg);
+ if (node->subType() == Node::QmlClass) {
+ QmlClassNode::addInheritedBy(arg,node);
+ }
+ }
+ }
+ else if (command == COMMAND_QMLDEFAULT) {
+ if (node->type() == Node::QmlProperty) {
+ QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
+ qpn->setDefault();
+ }
+ else if (node->type() == Node::Fake && node->subType() == Node::QmlPropertyGroup) {
+ QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node);
+ qpgn->setDefault();
+ }
+ }
+ else if (command == COMMAND_QMLREADONLY) {
+ if (node->type() == Node::QmlProperty) {
+ QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
+ qpn->setReadOnly(1);
+ }
+ else if (node->type() == Node::Fake && node->subType() == Node::QmlPropertyGroup) {
+ QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node);
+ qpgn->setReadOnly(1);
+ NodeList::ConstIterator p = qpgn->childNodes().begin();
+ while (p != qpgn->childNodes().end()) {
+ if ((*p)->type() == Node::QmlProperty) {
+ QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(*p);
+ qpn->setReadOnly(1);
+ }
+ ++p;
+ }
+ }
+ }
+ else if (command == COMMAND_QMLABSTRACT) {
+ if ((node->type() == Node::Fake) && (node->subType() == Node::QmlClass)) {
+ node->setAbstract(true);
+ }
+ }
+ else {
+ processCommonMetaCommand(doc.location(),command,arg,node,tre);
+ }
+}
+
+/*!
+ The topic command has been processed resulting in the \a doc
+ and \a node passed in here. Process the other meta commands,
+ which are found in \a doc, in the context of the topic \a node.
+ */
+void CppCodeParser::processOtherMetaCommands(const Doc& doc, Node *node)
+{
+ const QSet<QString> metaCommands = doc.metaCommandsUsed();
+ QSet<QString>::ConstIterator cmd = metaCommands.begin();
+ while (cmd != metaCommands.end()) {
+ QStringList args = doc.metaCommandArgs(*cmd);
+ QStringList::ConstIterator arg = args.begin();
+ while (arg != args.end()) {
+ processOtherMetaCommand(doc, *cmd, *arg, node);
+ ++arg;
+ }
+ ++cmd;
+ }
+}
+
+/*!
+ Resets the C++ code parser to its default initialized state.
+ */
+void CppCodeParser::reset(Tree *tree)
+{
+ tre = tree;
+ tokenizer = 0;
+ tok = 0;
+ access = Node::Public;
+ metaness = FunctionNode::Plain;
+ lastPath.clear();
+ moduleName = "";
+}
+
+/*!
+ Get the next token from the file being parsed and store it
+ in the token variable.
+ */
+void CppCodeParser::readToken()
+{
+ tok = tokenizer->getToken();
+}
+
+/*!
+ Return the current location in the file being parsed,
+ i.e. the file name, line number, and column number.
+ */
+const Location& CppCodeParser::location()
+{
+ return tokenizer->location();
+}
+
+/*!
+ Return the previous string read from the file being parsed.
+ */
+QString CppCodeParser::previousLexeme()
+{
+ return tokenizer->previousLexeme();
+}
+
+/*!
+ Return the current string string from the file being parsed.
+ */
+QString CppCodeParser::lexeme()
+{
+ return tokenizer->lexeme();
+}
+
+bool CppCodeParser::match(int target)
+{
+ if (tok == target) {
+ readToken();
+ return true;
+ }
+ else
+ return false;
+}
+
+/*!
+ Skip to \a target. If \a target is found before the end
+ of input, return true. Otherwise return false.
+ */
+bool CppCodeParser::skipTo(int target)
+{
+ while ((tok != Tok_Eoi) && (tok != target))
+ readToken();
+ return (tok == target ? true : false);
+}
+
+/*!
+ If the current token is one of the keyword thingees that
+ are used in Qt, skip over it to the next token and return
+ true. Otherwise just return false without reading the
+ next token.
+ */
+bool CppCodeParser::matchCompat()
+{
+ switch (tok) {
+ case Tok_QT_COMPAT:
+ case Tok_QT_COMPAT_CONSTRUCTOR:
+ case Tok_QT_DEPRECATED:
+ case Tok_QT_MOC_COMPAT:
+ case Tok_QT3_SUPPORT:
+ case Tok_QT3_SUPPORT_CONSTRUCTOR:
+ case Tok_QT3_MOC_SUPPORT:
+ readToken();
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool CppCodeParser::matchModuleQualifier(QString& name)
+{
+ bool matches = (lexeme() == QString('.'));
+ if (matches) {
+ do {
+ name += lexeme();
+ readToken();
+ } while ((tok == Tok_Ident) || (lexeme() == QString('.')));
+ }
+ return matches;
+}
+
+bool CppCodeParser::matchTemplateAngles(CodeChunk *dataType)
+{
+ bool matches = (tok == Tok_LeftAngle);
+ if (matches) {
+ int leftAngleDepth = 0;
+ int parenAndBraceDepth = 0;
+ do {
+ if (tok == Tok_LeftAngle) {
+ leftAngleDepth++;
+ }
+ else if (tok == Tok_RightAngle) {
+ leftAngleDepth--;
+ }
+ else if (tok == Tok_LeftParen || tok == Tok_LeftBrace) {
+ ++parenAndBraceDepth;
+ }
+ else if (tok == Tok_RightParen || tok == Tok_RightBrace) {
+ if (--parenAndBraceDepth < 0)
+ return false;
+ }
+
+ if (dataType != 0)
+ dataType->append(lexeme());
+ readToken();
+ } while (leftAngleDepth > 0 && tok != Tok_Eoi);
+ }
+ return matches;
+}
+
+bool CppCodeParser::matchTemplateHeader()
+{
+ readToken();
+ return matchTemplateAngles();
+}
+
+bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var)
+{
+ /*
+ This code is really hard to follow... sorry. The loop is there to match
+ Alpha::Beta::Gamma::...::Omega.
+ */
+ for (;;) {
+ bool virgin = true;
+
+ if (tok != Tok_Ident) {
+ /*
+ There is special processing for 'Foo::operator int()'
+ and such elsewhere. This is the only case where we
+ return something with a trailing gulbrandsen ('Foo::').
+ */
+ if (tok == Tok_operator)
+ return true;
+
+ /*
+ People may write 'const unsigned short' or
+ 'short unsigned const' or any other permutation.
+ */
+ while (match(Tok_const) || match(Tok_volatile))
+ dataType->append(previousLexeme());
+ while (match(Tok_signed) || match(Tok_unsigned) ||
+ match(Tok_short) || match(Tok_long) || match(Tok_int64)) {
+ dataType->append(previousLexeme());
+ virgin = false;
+ }
+ while (match(Tok_const) || match(Tok_volatile))
+ dataType->append(previousLexeme());
+
+ if (match(Tok_Tilde))
+ dataType->append(previousLexeme());
+ }
+
+ if (virgin) {
+ if (match(Tok_Ident))
+ dataType->append(previousLexeme());
+ else if (match(Tok_void) || match(Tok_int) || match(Tok_char) ||
+ match(Tok_double) || match(Tok_Ellipsis))
+ dataType->append(previousLexeme());
+ else
+ return false;
+ }
+ else if (match(Tok_int) || match(Tok_char) || match(Tok_double)) {
+ dataType->append(previousLexeme());
+ }
+
+ matchTemplateAngles(dataType);
+
+ while (match(Tok_const) || match(Tok_volatile))
+ dataType->append(previousLexeme());
+
+ if (match(Tok_Gulbrandsen))
+ dataType->append(previousLexeme());
+ else
+ break;
+ }
+
+ while (match(Tok_Ampersand) || match(Tok_Aster) || match(Tok_const) ||
+ match(Tok_Caret))
+ dataType->append(previousLexeme());
+
+ if (match(Tok_LeftParenAster)) {
+ /*
+ A function pointer. This would be rather hard to handle without a
+ tokenizer hack, because a type can be followed with a left parenthesis
+ in some cases (e.g., 'operator int()'). The tokenizer recognizes '(*'
+ as a single token.
+ */
+ dataType->append(previousLexeme());
+ dataType->appendHotspot();
+ if (var != 0 && match(Tok_Ident))
+ *var = previousLexeme();
+ if (!match(Tok_RightParen) || tok != Tok_LeftParen)
+ return false;
+ dataType->append(previousLexeme());
+
+ int parenDepth0 = tokenizer->parenDepth();
+ while (tokenizer->parenDepth() >= parenDepth0 && tok != Tok_Eoi) {
+ dataType->append(lexeme());
+ readToken();
+ }
+ if (match(Tok_RightParen))
+ dataType->append(previousLexeme());
+ }
+ else {
+ /*
+ The common case: Look for an optional identifier, then for
+ some array brackets.
+ */
+ dataType->appendHotspot();
+
+ if (var != 0) {
+ if (match(Tok_Ident)) {
+ *var = previousLexeme();
+ }
+ else if (match(Tok_Comment)) {
+ /*
+ A neat hack: Commented-out parameter names are
+ recognized by qdoc. It's impossible to illustrate
+ here inside a C-style comment, because it requires
+ an asterslash. It's also impossible to illustrate
+ inside a C++-style comment, because the explanation
+ does not fit on one line.
+ */
+ if (varComment.exactMatch(previousLexeme()))
+ *var = varComment.cap(1);
+ }
+ }
+
+ if (tok == Tok_LeftBracket) {
+ int bracketDepth0 = tokenizer->bracketDepth();
+ while ((tokenizer->bracketDepth() >= bracketDepth0 &&
+ tok != Tok_Eoi) ||
+ tok == Tok_RightBracket) {
+ dataType->append(lexeme());
+ readToken();
+ }
+ }
+ }
+ return true;
+}
+
+bool CppCodeParser::matchParameter(FunctionNode *func)
+{
+ CodeChunk dataType;
+ QString name;
+ CodeChunk defaultValue;
+
+ if (!matchDataType(&dataType, &name))
+ return false;
+ match(Tok_Comment);
+ if (match(Tok_Equal)) {
+ int parenDepth0 = tokenizer->parenDepth();
+
+ while (tokenizer->parenDepth() >= parenDepth0 &&
+ (tok != Tok_Comma ||
+ tokenizer->parenDepth() > parenDepth0) &&
+ tok != Tok_Eoi) {
+ defaultValue.append(lexeme());
+ readToken();
+ }
+ }
+ func->addParameter(Parameter(dataType.toString(),
+ "",
+ name,
+ defaultValue.toString())); // ###
+ return true;
+}
+
+bool CppCodeParser::matchFunctionDecl(InnerNode *parent,
+ QStringList *parentPathPtr,
+ FunctionNode **funcPtr,
+ const QString &templateStuff,
+ Node::Type type,
+ bool attached)
+{
+ CodeChunk returnType;
+ QStringList parentPath;
+ QString name;
+
+ bool compat = false;
+ if (match(Tok_friend))
+ return false;
+ match(Tok_explicit);
+ if (matchCompat())
+ compat = true;
+ bool sta = false;
+ if (match(Tok_static)) {
+ sta = true;
+ if (matchCompat())
+ compat = true;
+ }
+ FunctionNode::Virtualness vir = FunctionNode::NonVirtual;
+ if (match(Tok_virtual)) {
+ vir = FunctionNode::ImpureVirtual;
+ if (matchCompat())
+ compat = true;
+ }
+
+ if (!matchDataType(&returnType)) {
+ if (tokenizer->parsingFnOrMacro()
+ && (match(Tok_Q_DECLARE_FLAGS) ||
+ match(Tok_Q_PROPERTY) ||
+ match(Tok_Q_PRIVATE_PROPERTY)))
+ returnType = CodeChunk(previousLexeme());
+ else {
+ return false;
+ }
+ }
+
+ if (returnType.toString() == "QBool")
+ returnType = CodeChunk("bool");
+
+ if (matchCompat())
+ compat = true;
+
+ if (tok == Tok_operator &&
+ (returnType.toString().isEmpty() ||
+ returnType.toString().endsWith("::"))) {
+ // 'QString::operator const char *()'
+ parentPath = returnType.toString().split(sep);
+ parentPath.removeAll(QString());
+ returnType = CodeChunk();
+ readToken();
+
+ CodeChunk restOfName;
+ if (tok != Tok_Tilde && matchDataType(&restOfName)) {
+ name = "operator " + restOfName.toString();
+ }
+ else {
+ name = previousLexeme() + lexeme();
+ readToken();
+ while (tok != Tok_LeftParen && tok != Tok_Eoi) {
+ name += lexeme();
+ readToken();
+ }
+ }
+ if (tok != Tok_LeftParen) {
+ return false;
+ }
+ }
+ else if (tok == Tok_LeftParen) {
+ // constructor or destructor
+ parentPath = returnType.toString().split(sep);
+ if (!parentPath.isEmpty()) {
+ name = parentPath.last();
+ parentPath.erase(parentPath.end() - 1);
+ }
+ returnType = CodeChunk();
+ }
+ else {
+ while (match(Tok_Ident)) {
+ name = previousLexeme();
+
+ /*
+ This is a hack to let QML module identifiers through.
+ */
+ matchModuleQualifier(name);
+
+ matchTemplateAngles();
+
+ if (match(Tok_Gulbrandsen))
+ parentPath.append(name);
+ else
+ break;
+ }
+
+ if (tok == Tok_operator) {
+ name = lexeme();
+ readToken();
+ while (tok != Tok_Eoi) {
+ name += lexeme();
+ readToken();
+ if (tok == Tok_LeftParen)
+ break;
+ }
+ }
+ if (parent && (tok == Tok_Semicolon ||
+ tok == Tok_LeftBracket ||
+ tok == Tok_Colon)
+ && access != Node::Private) {
+ if (tok == Tok_LeftBracket) {
+ returnType.appendHotspot();
+
+ int bracketDepth0 = tokenizer->bracketDepth();
+ while ((tokenizer->bracketDepth() >= bracketDepth0 &&
+ tok != Tok_Eoi) ||
+ tok == Tok_RightBracket) {
+ returnType.append(lexeme());
+ readToken();
+ }
+ if (tok != Tok_Semicolon) {
+ return false;
+ }
+ }
+ else if (tok == Tok_Colon) {
+ returnType.appendHotspot();
+
+ while (tok != Tok_Semicolon && tok != Tok_Eoi) {
+ returnType.append(lexeme());
+ readToken();
+ }
+ if (tok != Tok_Semicolon) {
+ return false;
+ }
+ }
+
+ VariableNode *var = new VariableNode(parent, name);
+ var->setAccess(access);
+ var->setLocation(location());
+ var->setLeftType(returnType.left());
+ var->setRightType(returnType.right());
+ if (compat)
+ var->setStatus(Node::Compat);
+ var->setStatic(sta);
+ return false;
+ }
+ if (tok != Tok_LeftParen) {
+ return false;
+ }
+ }
+ readToken();
+
+ FunctionNode *func = new FunctionNode(type, parent, name, attached);
+ func->setAccess(access);
+ func->setLocation(location());
+ func->setReturnType(returnType.toString());
+ func->setParentPath(parentPath);
+ func->setTemplateStuff(templateStuff);
+ if (compat)
+ func->setStatus(Node::Compat);
+
+ func->setMetaness(metaness);
+ if (parent) {
+ if (name == parent->name()) {
+ func->setMetaness(FunctionNode::Ctor);
+ } else if (name.startsWith(QLatin1Char('~'))) {
+ func->setMetaness(FunctionNode::Dtor);
+ }
+ }
+ func->setStatic(sta);
+
+ if (tok != Tok_RightParen) {
+ do {
+ if (!matchParameter(func)) {
+ return false;
+ }
+ } while (match(Tok_Comma));
+ }
+ if (!match(Tok_RightParen)) {
+ return false;
+ }
+
+ func->setConst(match(Tok_const));
+
+ if (match(Tok_Equal) && match(Tok_Number))
+ vir = FunctionNode::PureVirtual;
+ func->setVirtualness(vir);
+
+ if (match(Tok_Colon)) {
+ while (tok != Tok_LeftBrace && tok != Tok_Eoi)
+ readToken();
+ }
+
+ if (!match(Tok_Semicolon) && tok != Tok_Eoi) {
+ int braceDepth0 = tokenizer->braceDepth();
+
+ if (!match(Tok_LeftBrace)) {
+ return false;
+ }
+ while (tokenizer->braceDepth() >= braceDepth0 && tok != Tok_Eoi)
+ readToken();
+ match(Tok_RightBrace);
+ }
+ if (parentPathPtr != 0)
+ *parentPathPtr = parentPath;
+ if (funcPtr != 0)
+ *funcPtr = func;
+ return true;
+}
+
+bool CppCodeParser::matchBaseSpecifier(ClassNode *classe, bool isClass)
+{
+ Node::Access access;
+
+ switch (tok) {
+ case Tok_public:
+ access = Node::Public;
+ readToken();
+ break;
+ case Tok_protected:
+ access = Node::Protected;
+ readToken();
+ break;
+ case Tok_private:
+ access = Node::Private;
+ readToken();
+ break;
+ default:
+ access = isClass ? Node::Private : Node::Public;
+ }
+
+ if (tok == Tok_virtual)
+ readToken();
+
+ CodeChunk baseClass;
+ if (!matchDataType(&baseClass))
+ return false;
+
+ tre->addBaseClass(classe,
+ access,
+ baseClass.toPath(),
+ baseClass.toString(),
+ classe->parent());
+ return true;
+}
+
+bool CppCodeParser::matchBaseList(ClassNode *classe, bool isClass)
+{
+ for (;;) {
+ if (!matchBaseSpecifier(classe, isClass))
+ return false;
+ if (tok == Tok_LeftBrace)
+ return true;
+ if (!match(Tok_Comma))
+ return false;
+ }
+}
+
+/*!
+ Parse a C++ class, union, or struct declarion.
+ */
+bool CppCodeParser::matchClassDecl(InnerNode *parent,
+ const QString &templateStuff)
+{
+ bool isClass = (tok == Tok_class);
+ readToken();
+
+ bool compat = matchCompat();
+
+ if (tok != Tok_Ident)
+ return false;
+ while (tok == Tok_Ident)
+ readToken();
+ if (tok != Tok_Colon && tok != Tok_LeftBrace)
+ return false;
+
+ /*
+ So far, so good. We have 'class Foo {' or 'class Foo :'.
+ This is enough to recognize a class definition.
+ */
+ ClassNode *classe = new ClassNode(parent, previousLexeme());
+ classe->setAccess(access);
+ classe->setLocation(location());
+ if (compat)
+ classe->setStatus(Node::Compat);
+ if (!moduleName.isEmpty())
+ classe->setModuleName(moduleName);
+ classe->setTemplateStuff(templateStuff);
+
+ if (match(Tok_Colon) && !matchBaseList(classe, isClass))
+ return false;
+ if (!match(Tok_LeftBrace))
+ return false;
+
+ Node::Access outerAccess = access;
+ access = isClass ? Node::Private : Node::Public;
+ FunctionNode::Metaness outerMetaness = metaness;
+ metaness = FunctionNode::Plain;
+
+ bool matches = (matchDeclList(classe) && match(Tok_RightBrace) &&
+ match(Tok_Semicolon));
+ access = outerAccess;
+ metaness = outerMetaness;
+ return matches;
+}
+
+bool CppCodeParser::matchNamespaceDecl(InnerNode *parent)
+{
+ readToken(); // skip 'namespace'
+ if (tok != Tok_Ident)
+ return false;
+ while (tok == Tok_Ident)
+ readToken();
+ if (tok != Tok_LeftBrace)
+ return false;
+
+ /*
+ So far, so good. We have 'namespace Foo {'.
+ */
+ QString namespaceName = previousLexeme();
+ NamespaceNode *namespasse = 0;
+ if (parent) {
+ namespasse = static_cast<NamespaceNode*>(parent->findNode(namespaceName, Node::Namespace));
+ }
+ if (!namespasse) {
+ namespasse = new NamespaceNode(parent, namespaceName);
+ namespasse->setAccess(access);
+ namespasse->setLocation(location());
+ }
+
+ readToken(); // skip '{'
+ bool matched = matchDeclList(namespasse);
+
+ return matched && match(Tok_RightBrace);
+}
+
+bool CppCodeParser::matchUsingDecl()
+{
+ readToken(); // skip 'using'
+
+ // 'namespace'
+ if (tok != Tok_namespace)
+ return false;
+
+ readToken();
+ // identifier
+ if (tok != Tok_Ident)
+ return false;
+
+ QString name;
+ while (tok == Tok_Ident) {
+ name += lexeme();
+ readToken();
+ if (tok == Tok_Semicolon)
+ break;
+ else if (tok != Tok_Gulbrandsen)
+ return false;
+ name += "::";
+ readToken();
+ }
+
+ /*
+ So far, so good. We have 'using namespace Foo;'.
+ */
+ usedNamespaces.insert(name);
+ return true;
+}
+
+bool CppCodeParser::matchEnumItem(InnerNode *parent, EnumNode *enume)
+{
+ if (!match(Tok_Ident))
+ return false;
+
+ QString name = previousLexeme();
+ CodeChunk val;
+
+ if (match(Tok_Equal)) {
+ while (tok != Tok_Comma && tok != Tok_RightBrace &&
+ tok != Tok_Eoi) {
+ val.append(lexeme());
+ readToken();
+ }
+ }
+
+ if (enume) {
+ QString strVal = val.toString();
+ if (strVal.isEmpty()) {
+ if (enume->items().isEmpty()) {
+ strVal = "0";
+ }
+ else {
+ QString last = enume->items().last().value();
+ bool ok;
+ int n = last.toInt(&ok);
+ if (ok) {
+ if (last.startsWith(QLatin1Char('0')) && last.size() > 1) {
+ if (last.startsWith("0x") || last.startsWith("0X"))
+ strVal = last.left(2) + QString::number(n + 1, 16);
+ else
+ strVal = QLatin1Char('0') + QString::number(n + 1, 8);
+ }
+ else
+ strVal = QString::number(n + 1);
+ }
+ }
+ }
+
+ enume->addItem(EnumItem(name, strVal));
+ }
+ else {
+ VariableNode *var = new VariableNode(parent, name);
+ var->setAccess(access);
+ var->setLocation(location());
+ var->setLeftType("const int");
+ var->setStatic(true);
+ }
+ return true;
+}
+
+bool CppCodeParser::matchEnumDecl(InnerNode *parent)
+{
+ QString name;
+
+ if (!match(Tok_enum))
+ return false;
+ if (match(Tok_Ident))
+ name = previousLexeme();
+ if (tok != Tok_LeftBrace)
+ return false;
+
+ EnumNode *enume = 0;
+
+ if (!name.isEmpty()) {
+ enume = new EnumNode(parent, name);
+ enume->setAccess(access);
+ enume->setLocation(location());
+ }
+
+ readToken();
+
+ if (!matchEnumItem(parent, enume))
+ return false;
+
+ while (match(Tok_Comma)) {
+ if (!matchEnumItem(parent, enume))
+ return false;
+ }
+ return match(Tok_RightBrace) && match(Tok_Semicolon);
+}
+
+bool CppCodeParser::matchTypedefDecl(InnerNode *parent)
+{
+ CodeChunk dataType;
+ QString name;
+
+ if (!match(Tok_typedef))
+ return false;
+ if (!matchDataType(&dataType, &name))
+ return false;
+ if (!match(Tok_Semicolon))
+ return false;
+
+ if (parent && !parent->findNode(name, Node::Typedef)) {
+ TypedefNode *typedeffe = new TypedefNode(parent, name);
+ typedeffe->setAccess(access);
+ typedeffe->setLocation(location());
+ }
+ return true;
+}
+
+bool CppCodeParser::matchProperty(InnerNode *parent)
+{
+ int expected_tok = Tok_LeftParen;
+ if (match(Tok_Q_PRIVATE_PROPERTY)) {
+ expected_tok = Tok_Comma;
+ if (!skipTo(Tok_Comma))
+ return false;
+ }
+ else if (!match(Tok_Q_PROPERTY) &&
+ !match(Tok_Q_OVERRIDE) &&
+ !match(Tok_QDOC_PROPERTY)) {
+ return false;
+ }
+
+ if (!match(expected_tok))
+ return false;
+
+ QString name;
+ CodeChunk dataType;
+ if (!matchDataType(&dataType, &name))
+ return false;
+
+ PropertyNode *property = new PropertyNode(parent, name);
+ property->setAccess(Node::Public);
+ property->setLocation(location());
+ property->setDataType(dataType.toString());
+
+ while (tok != Tok_RightParen && tok != Tok_Eoi) {
+ if (!match(Tok_Ident))
+ return false;
+ QString key = previousLexeme();
+ QString value;
+
+ if (match(Tok_Ident) || match(Tok_Number)) {
+ value = previousLexeme();
+ }
+ else if (match(Tok_LeftParen)) {
+ int depth = 1;
+ while (tok != Tok_Eoi) {
+ if (tok == Tok_LeftParen) {
+ readToken();
+ ++depth;
+ } else if (tok == Tok_RightParen) {
+ readToken();
+ if (--depth == 0)
+ break;
+ } else {
+ readToken();
+ }
+ }
+ value = "?";
+ }
+
+ if (key == "READ")
+ tre->addPropertyFunction(property, value, PropertyNode::Getter);
+ else if (key == "WRITE") {
+ tre->addPropertyFunction(property, value, PropertyNode::Setter);
+ property->setWritable(true);
+ }
+ else if (key == "STORED")
+ property->setStored(value.toLower() == "true");
+ else if (key == "DESIGNABLE") {
+ QString v = value.toLower();
+ if (v == "true")
+ property->setDesignable(true);
+ else if (v == "false")
+ property->setDesignable(false);
+ else {
+ property->setDesignable(false);
+ property->setRuntimeDesFunc(value);
+ }
+ }
+ else if (key == "RESET")
+ tre->addPropertyFunction(property, value, PropertyNode::Resetter);
+ else if (key == "NOTIFY") {
+ tre->addPropertyFunction(property, value, PropertyNode::Notifier);
+ } else if (key == "REVISION") {
+ int revision;
+ bool ok;
+ revision = value.toInt(&ok);
+ if (ok)
+ property->setRevision(revision);
+ else
+ parent->doc().location().warning(tr("Invalid revision number: %1").arg(value));
+ } else if (key == "SCRIPTABLE") {
+ QString v = value.toLower();
+ if (v == "true")
+ property->setScriptable(true);
+ else if (v == "false")
+ property->setScriptable(false);
+ else {
+ property->setScriptable(false);
+ property->setRuntimeScrFunc(value);
+ }
+ }
+ else if (key == "CONSTANT")
+ property->setConstant();
+ else if (key == "FINAL")
+ property->setFinal();
+ }
+ match(Tok_RightParen);
+ return true;
+}
+
+/*!
+ Parse a C++ declaration.
+ */
+bool CppCodeParser::matchDeclList(InnerNode *parent)
+{
+ QString templateStuff;
+ int braceDepth0 = tokenizer->braceDepth();
+ if (tok == Tok_RightBrace) // prevents failure on empty body
+ braceDepth0++;
+
+ while (tokenizer->braceDepth() >= braceDepth0 && tok != Tok_Eoi) {
+ switch (tok) {
+ case Tok_Colon:
+ readToken();
+ break;
+ case Tok_class:
+ case Tok_struct:
+ case Tok_union:
+ matchClassDecl(parent, templateStuff);
+ break;
+ case Tok_namespace:
+ matchNamespaceDecl(parent);
+ break;
+ case Tok_using:
+ matchUsingDecl();
+ break;
+ case Tok_template:
+ templateStuff = matchTemplateHeader();
+ continue;
+ case Tok_enum:
+ matchEnumDecl(parent);
+ break;
+ case Tok_typedef:
+ matchTypedefDecl(parent);
+ break;
+ case Tok_private:
+ readToken();
+ access = Node::Private;
+ metaness = FunctionNode::Plain;
+ break;
+ case Tok_protected:
+ readToken();
+ access = Node::Protected;
+ metaness = FunctionNode::Plain;
+ break;
+ case Tok_public:
+ readToken();
+ access = Node::Public;
+ metaness = FunctionNode::Plain;
+ break;
+ case Tok_signals:
+ case Tok_Q_SIGNALS:
+ readToken();
+ access = Node::Public;
+ metaness = FunctionNode::Signal;
+ break;
+ case Tok_slots:
+ case Tok_Q_SLOTS:
+ readToken();
+ metaness = FunctionNode::Slot;
+ break;
+ case Tok_Q_OBJECT:
+ readToken();
+ break;
+ case Tok_Q_OVERRIDE:
+ case Tok_Q_PROPERTY:
+ case Tok_Q_PRIVATE_PROPERTY:
+ case Tok_QDOC_PROPERTY:
+ matchProperty(parent);
+ break;
+ case Tok_Q_DECLARE_SEQUENTIAL_ITERATOR:
+ readToken();
+ if (match(Tok_LeftParen) && match(Tok_Ident))
+ sequentialIteratorClasses.insert(previousLexeme(),
+ location().fileName());
+ match(Tok_RightParen);
+ break;
+ case Tok_Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR:
+ readToken();
+ if (match(Tok_LeftParen) && match(Tok_Ident))
+ mutableSequentialIteratorClasses.insert(previousLexeme(),
+ location().fileName());
+ match(Tok_RightParen);
+ break;
+ case Tok_Q_DECLARE_ASSOCIATIVE_ITERATOR:
+ readToken();
+ if (match(Tok_LeftParen) && match(Tok_Ident))
+ associativeIteratorClasses.insert(previousLexeme(),
+ location().fileName());
+ match(Tok_RightParen);
+ break;
+ case Tok_Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR:
+ readToken();
+ if (match(Tok_LeftParen) && match(Tok_Ident))
+ mutableAssociativeIteratorClasses.insert(previousLexeme(),
+ location().fileName());
+ match(Tok_RightParen);
+ break;
+ case Tok_Q_DECLARE_FLAGS:
+ readToken();
+ if (match(Tok_LeftParen) && match(Tok_Ident)) {
+ QString flagsType = previousLexeme();
+ if (match(Tok_Comma) && match(Tok_Ident)) {
+ QString enumType = previousLexeme();
+ TypedefNode *flagsNode = new TypedefNode(parent, flagsType);
+ flagsNode->setAccess(access);
+ flagsNode->setLocation(location());
+ EnumNode *enumNode =
+ static_cast<EnumNode*>(parent->findNode(enumType,
+ Node::Enum));
+ if (enumNode)
+ enumNode->setFlagsType(flagsNode);
+ }
+ }
+ match(Tok_RightParen);
+ break;
+ case Tok_QT_MODULE:
+ readToken();
+ if (match(Tok_LeftParen) && match(Tok_Ident))
+ moduleName = previousLexeme();
+ if (!moduleName.startsWith("Qt"))
+ moduleName.prepend("Qt");
+ match(Tok_RightParen);
+ break;
+ default:
+ if (!matchFunctionDecl(parent, 0, 0, templateStuff)) {
+ while (tok != Tok_Eoi &&
+ (tokenizer->braceDepth() > braceDepth0 ||
+ (!match(Tok_Semicolon) &&
+ tok != Tok_public && tok != Tok_protected &&
+ tok != Tok_private)))
+ readToken();
+ }
+ }
+ templateStuff.clear();
+ }
+ return true;
+}
+
+/*!
+ This is called by parseSourceFile() to do the actual parsing
+ and tree building.
+ */
+bool CppCodeParser::matchDocsAndStuff()
+{
+ QSet<QString> topicCommandsAllowed = topicCommands();
+ QSet<QString> otherMetacommandsAllowed = otherMetaCommands();
+ QSet<QString> metacommandsAllowed = topicCommandsAllowed +
+ otherMetacommandsAllowed;
+
+ while (tok != Tok_Eoi) {
+ if (tok == Tok_Doc) {
+ /*
+ lexeme() returns an entire qdoc comment.
+ */
+ QString comment = lexeme();
+ Location start_loc(location());
+ readToken();
+
+ Doc::trimCStyleComment(start_loc,comment);
+ Location end_loc(location());
+
+ /*
+ Doc parses the comment.
+ */
+ Doc doc(start_loc,end_loc,comment,metacommandsAllowed);
+
+ QString topic;
+ QStringList args;
+
+ QSet<QString> topicCommandsUsed = topicCommandsAllowed &
+ doc.metaCommandsUsed();
+
+ /*
+ There should be one topic command in the set,
+ or none. If the set is empty, then the comment
+ should be a function description.
+ */
+ if (topicCommandsUsed.count() > 0) {
+ topic = *topicCommandsUsed.begin();
+ args = doc.metaCommandArgs(topic);
+ }
+
+ NodeList nodes;
+ QList<Doc> docs;
+
+ if (topic.isEmpty()) {
+ QStringList parentPath;
+ FunctionNode *clone;
+ FunctionNode *func = 0;
+
+ if (matchFunctionDecl(0, &parentPath, &clone)) {
+ foreach (const QString &usedNamespace, usedNamespaces) {
+ QStringList newPath = usedNamespace.split("::") + parentPath;
+ func = tre->findFunctionNode(newPath, clone);
+ if (func)
+ break;
+ }
+ if (func == 0)
+ func = tre->findFunctionNode(parentPath, clone);
+
+ if (func) {
+ func->borrowParameterNames(clone);
+ nodes.append(func);
+ docs.append(doc);
+ }
+ delete clone;
+ }
+ else {
+ doc.location().warning(
+ tr("Cannot tie this documentation to anything"),
+ tr("I found a /*! ... */ comment, but there was no "
+ "topic command (e.g., '\\%1', '\\%2') in the "
+ "comment and no function definition following "
+ "the comment.")
+ .arg(COMMAND_FN).arg(COMMAND_PAGE));
+ }
+ }
+ else {
+ /*
+ There is a topic command. Process it.
+ */
+ if ((topic == COMMAND_QMLPROPERTY) ||
+ (topic == COMMAND_QMLATTACHEDPROPERTY)) {
+ Doc nodeDoc = doc;
+ Node *node = processTopicCommandGroup(nodeDoc,topic,args);
+ if (node != 0) {
+ nodes.append(node);
+ docs.append(nodeDoc);
+ }
+ }
+ else {
+ QStringList::ConstIterator a = args.begin();
+ while (a != args.end()) {
+ Doc nodeDoc = doc;
+ Node *node = processTopicCommand(nodeDoc,topic,*a);
+ if (node != 0) {
+ nodes.append(node);
+ docs.append(nodeDoc);
+ }
+ ++a;
+ }
+ }
+ }
+
+ NodeList::Iterator n = nodes.begin();
+ QList<Doc>::Iterator d = docs.begin();
+ while (n != nodes.end()) {
+ processOtherMetaCommands(*d, *n);
+ (*n)->setDoc(*d);
+ if ((*n)->isInnerNode() &&
+ ((InnerNode *)*n)->includes().isEmpty()) {
+ InnerNode *m = static_cast<InnerNode *>(*n);
+ while (m->parent() != tre->root())
+ m = m->parent();
+ if (m == *n)
+ ((InnerNode *)*n)->addInclude((*n)->name());
+ else
+ ((InnerNode *)*n)->setIncludes(m->includes());
+ }
+ ++d;
+ ++n;
+ }
+ }
+ else if (tok == Tok_using) {
+ matchUsingDecl();
+ }
+ else {
+ QStringList parentPath;
+ FunctionNode *clone;
+ FunctionNode *node = 0;
+
+ if (matchFunctionDecl(0, &parentPath, &clone)) {
+ /*
+ The location of the definition is more interesting
+ than that of the declaration. People equipped with
+ a sophisticated text editor can respond to warnings
+ concerning undocumented functions very quickly.
+
+ Signals are implemented in uninteresting files
+ generated by moc.
+ */
+ node = tre->findFunctionNode(parentPath, clone);
+ if (node != 0 && node->metaness() != FunctionNode::Signal)
+ node->setLocation(clone->location());
+ delete clone;
+ }
+ else {
+ if (tok != Tok_Doc)
+ readToken();
+ }
+ }
+ }
+ return true;
+}
+
+/*!
+ This function uses a Tokenizer to parse the function \a signature
+ in an attempt to match it to the signature of a child node of \a root.
+ If a match is found, \a funcPtr is set to point to the matching node
+ and true is returned.
+ */
+bool CppCodeParser::makeFunctionNode(const QString& signature,
+ QStringList* parentPathPtr,
+ FunctionNode** funcPtr,
+ InnerNode* root,
+ Node::Type type,
+ bool attached)
+{
+ Tokenizer* outerTokenizer = tokenizer;
+ int outerTok = tok;
+
+ Location loc;
+ QByteArray latin1 = signature.toLatin1();
+ Tokenizer stringTokenizer(loc, latin1);
+ stringTokenizer.setParsingFnOrMacro(true);
+ tokenizer = &stringTokenizer;
+ readToken();
+
+ bool ok = matchFunctionDecl(root, parentPathPtr, funcPtr, QString(), type, attached);
+ // potential memory leak with funcPtr
+
+ tokenizer = outerTokenizer;
+ tok = outerTok;
+ return ok;
+}
+
+/*!
+ Create a new FunctionNode for a QML method or signal, as
+ specified by \a type, as a child of \a parent. \a sig is
+ the complete signature, and if \a attached is true, the
+ method or signal is "attached". \a qdoctag is the text of
+ the \a type.
+
+ \a parent is the QML class node. The QML module and QML
+ element names have already been consumed to find \a parent.
+ What remains in \a sig is the method signature. The method
+ must be a child of \a parent.
+ */
+FunctionNode* CppCodeParser::makeFunctionNode(const Doc& doc,
+ const QString& sig,
+ InnerNode* parent,
+ Node::Type type,
+ bool attached,
+ QString qdoctag)
+{
+ QStringList pp;
+ FunctionNode* fn = 0;
+ if (!makeFunctionNode(sig,&pp,&fn,parent,type,attached) &&
+ !makeFunctionNode("void "+sig,&pp,&fn,parent,type,attached)) {
+ doc.location().warning(tr("Invalid syntax in '\\%1'").arg(qdoctag));
+ }
+ return fn;
+}
+
+void CppCodeParser::parseQiteratorDotH(const Location &location,
+ const QString &filePath)
+{
+ QFile file(filePath);
+ if (!file.open(QFile::ReadOnly))
+ return;
+
+ QString text = file.readAll();
+ text.remove("\r");
+ text.remove("\\\n");
+ QStringList lines = text.split(QLatin1Char('\n'));
+ lines = lines.filter("Q_DECLARE");
+ lines.replaceInStrings(QRegExp("#define Q[A-Z_]*\\(C\\)"), "");
+
+ if (lines.size() == 4) {
+ sequentialIteratorDefinition = lines[0];
+ mutableSequentialIteratorDefinition = lines[1];
+ associativeIteratorDefinition = lines[2];
+ mutableAssociativeIteratorDefinition = lines[3];
+ }
+ else {
+ location.warning(tr("The qiterator.h hack failed"));
+ }
+}
+
+void CppCodeParser::instantiateIteratorMacro(const QString &container,
+ const QString &includeFile,
+ const QString &macroDef,
+ Tree * /* tree */)
+{
+ QString resultingCode = macroDef;
+ resultingCode.replace(QRegExp("\\bC\\b"), container);
+ resultingCode.remove(QRegExp("\\s*##\\s*"));
+
+ Location loc(includeFile); // hack to get the include file for free
+ QByteArray latin1 = resultingCode.toLatin1();
+ Tokenizer stringTokenizer(loc, latin1);
+ tokenizer = &stringTokenizer;
+ readToken();
+ matchDeclList(tre->root());
+}
+
+void CppCodeParser::createExampleFileNodes(FakeNode *fake)
+{
+ QString examplePath = fake->name();
+ QString proFileName = examplePath + QLatin1Char('/') + examplePath.split(QLatin1Char('/')).last() + ".pro";
+ QString userFriendlyFilePath;
+
+ QString fullPath = Config::findFile(fake->doc().location(),
+ exampleFiles,
+ exampleDirs,
+ proFileName,
+ userFriendlyFilePath);
+
+ if (fullPath.isEmpty()) {
+ QString tmp = proFileName;
+ proFileName = examplePath + QLatin1Char('/') + "qbuild.pro";
+ userFriendlyFilePath.clear();
+ fullPath = Config::findFile(fake->doc().location(),
+ exampleFiles,
+ exampleDirs,
+ proFileName,
+ userFriendlyFilePath);
+ if (fullPath.isEmpty()) {
+ proFileName = examplePath + QLatin1Char('/') + examplePath.split(QLatin1Char('/')).last() + ".qmlproject";
+ userFriendlyFilePath.clear();
+ fullPath = Config::findFile(fake->doc().location(),
+ exampleFiles,
+ exampleDirs,
+ proFileName,
+ userFriendlyFilePath);
+ if (fullPath.isEmpty()) {
+ fake->doc().location().warning(tr("Cannot find file '%1' or '%2'").arg(tmp).arg(proFileName));
+ fake->doc().location().warning(tr("EXAMPLE PATH DOES NOT EXIST: %1").arg(examplePath));
+ return;
+ }
+ }
+ }
+
+ int sizeOfBoringPartOfName = fullPath.size() - proFileName.size();
+ fullPath.truncate(fullPath.lastIndexOf('/'));
+
+ QStringList exampleFiles = Config::getFilesHere(fullPath,exampleNameFilter);
+ QString imagesPath = fullPath + "/images";
+ QStringList imageFiles = Config::getFilesHere(imagesPath,exampleImageFilter);
+ if (!exampleFiles.isEmpty()) {
+ // move main.cpp and to the end, if it exists
+ QString mainCpp;
+ QMutableStringListIterator i(exampleFiles);
+ i.toBack();
+ while (i.hasPrevious()) {
+ QString fileName = i.previous();
+ if (fileName.endsWith("/main.cpp")) {
+ mainCpp = fileName;
+ i.remove();
+ }
+ else if (fileName.contains("/qrc_") || fileName.contains("/moc_")
+ || fileName.contains("/ui_"))
+ i.remove();
+ }
+ if (!mainCpp.isEmpty())
+ exampleFiles.append(mainCpp);
+
+ // add any qmake Qt resource files and qmake project files
+ exampleFiles += Config::getFilesHere(fullPath, "*.qrc *.pro *.qmlproject qmldir");
+ }
+
+ foreach (const QString &exampleFile, exampleFiles)
+ (void) new FakeNode(fake,
+ exampleFile.mid(sizeOfBoringPartOfName),
+ Node::File,
+ Node::NoPageType);
+ foreach (const QString &imageFile, imageFiles) {
+ new FakeNode(fake,
+ imageFile.mid(sizeOfBoringPartOfName),
+ Node::Image,
+ Node::NoPageType);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/cppcodeparser.h b/src/tools/qdoc/cppcodeparser.h
new file mode 100644
index 0000000000..f33ff6430d
--- /dev/null
+++ b/src/tools/qdoc/cppcodeparser.h
@@ -0,0 +1,196 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ cppcodeparser.h
+*/
+
+#ifndef CPPCODEPARSER_H
+#define CPPCODEPARSER_H
+
+#include <qregexp.h>
+
+#include "codeparser.h"
+
+QT_BEGIN_NAMESPACE
+
+class ClassNode;
+class CodeChunk;
+class CppCodeParserPrivate;
+class FunctionNode;
+class InnerNode;
+class Tokenizer;
+
+class CppCodeParser : public CodeParser
+{
+public:
+ CppCodeParser();
+ ~CppCodeParser();
+
+ virtual void initializeParser(const Config& config);
+ virtual void terminateParser();
+ virtual QString language();
+ virtual QStringList headerFileNameFilter();
+ virtual QStringList sourceFileNameFilter();
+ virtual void parseHeaderFile(const Location& location,
+ const QString& filePath,
+ Tree *tree);
+ virtual void parseSourceFile(const Location& location,
+ const QString& filePath,
+ Tree *tree);
+ virtual void doneParsingHeaderFiles(Tree *tree);
+ virtual void doneParsingSourceFiles(Tree *tree);
+
+ const FunctionNode *findFunctionNode(const QString& synopsis,
+ Tree *tree,
+ Node *relative = 0,
+ bool fuzzy = false);
+
+protected:
+ virtual QSet<QString> topicCommands();
+ virtual Node *processTopicCommand(const Doc& doc,
+ const QString& command,
+ const QString& arg);
+#ifdef QDOC_QML
+ // might need to implement this in QsCodeParser as well.
+ virtual Node *processTopicCommandGroup(const Doc& doc,
+ const QString& command,
+ const QStringList& args);
+ bool splitQmlPropertyArg(const Doc& doc,
+ const QString& arg,
+ QString& type,
+ QString& module,
+ QString& element,
+ QString& name);
+ bool splitQmlMethodArg(const Doc& doc,
+ const QString& arg,
+ QString& type,
+ QString& module,
+ QString& element);
+#endif
+ virtual QSet<QString> otherMetaCommands();
+ virtual void processOtherMetaCommand(const Doc& doc,
+ const QString& command,
+ const QString& arg,
+ Node *node);
+ void processOtherMetaCommands(const Doc& doc, Node *node);
+
+private:
+ void reset(Tree *tree);
+ void readToken();
+ const Location& location();
+ QString previousLexeme();
+ QString lexeme();
+ bool match(int target);
+ bool skipTo(int target);
+ bool matchCompat();
+ bool matchModuleQualifier(QString& name);
+ bool matchTemplateAngles(CodeChunk *type = 0);
+ bool matchTemplateHeader();
+ bool matchDataType(CodeChunk *type, QString *var = 0);
+ bool matchParameter(FunctionNode *func);
+ bool matchFunctionDecl(InnerNode *parent,
+ QStringList *parentPathPtr = 0,
+ FunctionNode **funcPtr = 0,
+ const QString &templateStuff = QString(),
+ Node::Type type = Node::Function,
+ bool attached = false);
+ bool matchBaseSpecifier(ClassNode *classe, bool isClass);
+ bool matchBaseList(ClassNode *classe, bool isClass);
+ bool matchClassDecl(InnerNode *parent,
+ const QString &templateStuff = QString());
+ bool matchNamespaceDecl(InnerNode *parent);
+ bool matchUsingDecl();
+ bool matchEnumItem(InnerNode *parent, EnumNode *enume);
+ bool matchEnumDecl(InnerNode *parent);
+ bool matchTypedefDecl(InnerNode *parent);
+ bool matchProperty(InnerNode *parent);
+ bool matchDeclList(InnerNode *parent);
+ bool matchDocsAndStuff();
+ bool makeFunctionNode(const QString &synopsis,
+ QStringList *parentPathPtr,
+ FunctionNode **funcPtr,
+ InnerNode *root = 0,
+ Node::Type type = Node::Function,
+ bool attached = false);
+ FunctionNode* makeFunctionNode(const Doc& doc,
+ const QString& sig,
+ InnerNode* parent,
+ Node::Type type,
+ bool attached,
+ QString qdoctag);
+ void parseQiteratorDotH(const Location &location, const QString &filePath);
+ void instantiateIteratorMacro(const QString &container,
+ const QString &includeFile,
+ const QString &macroDef,
+ Tree *tree);
+ void createExampleFileNodes(FakeNode *fake);
+
+ QMap<QString, Node::Type> nodeTypeMap;
+ Tree *tre;
+ Tokenizer *tokenizer;
+ int tok;
+ Node::Access access;
+ FunctionNode::Metaness metaness;
+ QString moduleName;
+ QStringList lastPath;
+ QRegExp varComment;
+ QRegExp sep;
+
+ QString sequentialIteratorDefinition;
+ QString mutableSequentialIteratorDefinition;
+ QString associativeIteratorDefinition;
+ QString mutableAssociativeIteratorDefinition;
+ QSet<QString> usedNamespaces;
+ QMap<QString, QString> sequentialIteratorClasses;
+ QMap<QString, QString> mutableSequentialIteratorClasses;
+ QMap<QString, QString> associativeIteratorClasses;
+ QMap<QString, QString> mutableAssociativeIteratorClasses;
+
+ static QStringList exampleFiles;
+ static QStringList exampleDirs;
+ QString exampleNameFilter;
+ QString exampleImageFilter;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/ditaxmlgenerator.cpp b/src/tools/qdoc/ditaxmlgenerator.cpp
new file mode 100644
index 0000000000..a4c5cbeea0
--- /dev/null
+++ b/src/tools/qdoc/ditaxmlgenerator.cpp
@@ -0,0 +1,6434 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ ditaxmlgenerator.cpp
+*/
+
+#include "codemarker.h"
+#include "codeparser.h"
+#include "ditaxmlgenerator.h"
+#include "node.h"
+#include "quoter.h"
+#include "separator.h"
+#include "tree.h"
+#include <ctype.h>
+#include <qdebug.h>
+#include <qlist.h>
+#include <qiterator.h>
+#include <qtextcodec.h>
+#include <QUuid>
+
+QT_BEGIN_NAMESPACE
+
+#define COMMAND_VERSION Doc::alias("version")
+int DitaXmlGenerator::id = 0;
+
+/*
+ The strings in this array must appear in the same order as
+ the values in enum DitaXmlGenerator::DitaTag.
+ */
+QString DitaXmlGenerator::ditaTags[] =
+{
+ "",
+ "alt",
+ "apiDesc",
+ "APIMap",
+ "apiName",
+ "apiRelation",
+ "audience",
+ "author",
+ "b",
+ "body",
+ "bodydiv",
+ "brand",
+ "category",
+ "codeblock",
+ "comment",
+ "component",
+ "copyrholder",
+ "copyright",
+ "copyryear",
+ "created",
+ "critdates",
+ "cxxAPIMap",
+ "cxxClass",
+ "cxxClassAbstract",
+ "cxxClassAccessSpecifier",
+ "cxxClassAPIItemLocation",
+ "cxxClassBaseClass",
+ "cxxClassDeclarationFile",
+ "cxxClassDeclarationFileLine",
+ "cxxClassDeclarationFileLineStart",
+ "cxxClassDeclarationFileLineEnd",
+ "cxxClassDefinition",
+ "cxxClassDerivation",
+ "cxxClassDerivationAccessSpecifier",
+ "cxxClassDerivations",
+ "cxxClassDetail",
+ "cxxClassNested",
+ "cxxClassNestedClass",
+ "cxxClassNestedDetail",
+ "cxxDefine",
+ "cxxDefineAccessSpecifier",
+ "cxxDefineAPIItemLocation",
+ "cxxDefineDeclarationFile",
+ "cxxDefineDeclarationFileLine",
+ "cxxDefineDefinition",
+ "cxxDefineDetail",
+ "cxxDefineNameLookup",
+ "cxxDefineParameter",
+ "cxxDefineParameterDeclarationName",
+ "cxxDefineParameters",
+ "cxxDefinePrototype",
+ "cxxDefineReimplemented",
+ "cxxEnumeration",
+ "cxxEnumerationAccessSpecifier",
+ "cxxEnumerationAPIItemLocation",
+ "cxxEnumerationDeclarationFile",
+ "cxxEnumerationDeclarationFileLine",
+ "cxxEnumerationDeclarationFileLineStart",
+ "cxxEnumerationDeclarationFileLineEnd",
+ "cxxEnumerationDefinition",
+ "cxxEnumerationDetail",
+ "cxxEnumerationNameLookup",
+ "cxxEnumerationPrototype",
+ "cxxEnumerationScopedName",
+ "cxxEnumerator",
+ "cxxEnumeratorInitialiser",
+ "cxxEnumeratorNameLookup",
+ "cxxEnumeratorPrototype",
+ "cxxEnumerators",
+ "cxxEnumeratorScopedName",
+ "cxxFunction",
+ "cxxFunctionAccessSpecifier",
+ "cxxFunctionAPIItemLocation",
+ "cxxFunctionConst",
+ "cxxFunctionConstructor",
+ "cxxFunctionDeclarationFile",
+ "cxxFunctionDeclarationFileLine",
+ "cxxFunctionDeclaredType",
+ "cxxFunctionDefinition",
+ "cxxFunctionDestructor",
+ "cxxFunctionDetail",
+ "cxxFunctionNameLookup",
+ "cxxFunctionParameter",
+ "cxxFunctionParameterDeclarationName",
+ "cxxFunctionParameterDeclaredType",
+ "cxxFunctionParameterDefaultValue",
+ "cxxFunctionParameters",
+ "cxxFunctionPrototype",
+ "cxxFunctionPureVirtual",
+ "cxxFunctionReimplemented",
+ "cxxFunctionScopedName",
+ "cxxFunctionStorageClassSpecifierStatic",
+ "cxxFunctionVirtual",
+ "cxxTypedef",
+ "cxxTypedefAccessSpecifier",
+ "cxxTypedefAPIItemLocation",
+ "cxxTypedefDeclarationFile",
+ "cxxTypedefDeclarationFileLine",
+ "cxxTypedefDefinition",
+ "cxxTypedefDetail",
+ "cxxTypedefNameLookup",
+ "cxxTypedefScopedName",
+ "cxxVariable",
+ "cxxVariableAccessSpecifier",
+ "cxxVariableAPIItemLocation",
+ "cxxVariableDeclarationFile",
+ "cxxVariableDeclarationFileLine",
+ "cxxVariableDeclaredType",
+ "cxxVariableDefinition",
+ "cxxVariableDetail",
+ "cxxVariableNameLookup",
+ "cxxVariablePrototype",
+ "cxxVariableReimplemented",
+ "cxxVariableScopedName",
+ "cxxVariableStorageClassSpecifierStatic",
+ "data",
+ "data-about",
+ "dd",
+ "dl",
+ "dlentry",
+ "dt",
+ "entry",
+ "fig",
+ "i",
+ "image",
+ "keyword",
+ "keywords",
+ "li",
+ "link",
+ "linktext",
+ "lq",
+ "map",
+ "mapref",
+ "metadata",
+ "note",
+ "ol",
+ "othermeta",
+ "p",
+ "parameter",
+ "permissions",
+ "ph",
+ "platform",
+ "pre",
+ "prodinfo",
+ "prodname",
+ "prolog",
+ "publisher",
+ "related-links",
+ "resourceid",
+ "revised",
+ "row",
+ "section",
+ "sectiondiv",
+ "shortdesc",
+ "simpletable",
+ "source",
+ "stentry",
+ "sthead",
+ "strow",
+ "sub",
+ "sup",
+ "table",
+ "tbody",
+ "tgroup",
+ "thead",
+ "title",
+ "tm",
+ "topic",
+ "topicmeta",
+ "topicref",
+ "tt",
+ "u",
+ "ul",
+ "unknown",
+ "vrm",
+ "vrmlist",
+ "xref",
+ ""
+};
+
+static bool showBrokenLinks = false;
+
+/*!
+ Quick, dirty, and very ugly. Unescape \a text
+ so QXmlStreamWriter::writeCharacters() can put
+ the escapes back in again!
+ */
+void DitaXmlGenerator::writeCharacters(const QString& text)
+{
+ QString t = text;
+ t = t.replace("&lt;","<");
+ t = t.replace("&gt;",">");
+ t = t.replace("&amp;","&");
+ t = t.replace("&quot;","\"");
+ xmlWriter().writeCharacters(t);
+}
+
+/*!
+ Appends an <xref> element to the current XML stream
+ with the \a href attribute and the \a text.
+ */
+void DitaXmlGenerator::addLink(const QString& href,
+ const QStringRef& text,
+ DitaTag t)
+{
+ if (!href.isEmpty()) {
+ writeStartTag(t);
+ // formathtml
+ writeHrefAttribute(href);
+ writeCharacters(text.toString());
+ writeEndTag(); // </t>
+ }
+ else {
+ writeCharacters(text.toString());
+ }
+}
+
+/*!
+ Push \a t onto the dita tag stack and write the appropriate
+ start tag to the DITA XML file.
+ */
+void DitaXmlGenerator::writeStartTag(DitaTag t)
+{
+ xmlWriter().writeStartElement(ditaTags[t]);
+ tagStack.push(t);
+}
+
+/*!
+ Pop the current DITA tag off the stack, and write the
+ appropriate end tag to the DITA XML file.
+ */
+void DitaXmlGenerator::writeEndTag(DitaTag t)
+{
+ DitaTag top = tagStack.pop();
+ if (t > DT_NONE && top != t)
+ qDebug() << "Expected:" << t << "ACTUAL:" << top;
+ xmlWriter().writeEndElement();
+}
+
+/*!
+ Return the current DITA element tag, the one
+ on top of the stack.
+ */
+DitaXmlGenerator::DitaTag DitaXmlGenerator::currentTag()
+{
+ return tagStack.top();
+}
+
+/*!
+ Write the start tag \c{<apiDesc>}. if \a title is not
+ empty, generate a GUID from it and write the GUID as the
+ value of the \e{id} attribute. Then write \a title as
+ the value of the \e {spectitle} attribute.
+
+ Then if \a outputclass is not empty, write it as the value
+ of the \a outputclass attribute.
+
+ Fiunally, set the section nesting level to 1 and return 1.
+ */
+int DitaXmlGenerator::enterApiDesc(const QString& outputclass, const QString& title)
+{
+ writeStartTag(DT_apiDesc);
+ if (!title.isEmpty()) {
+ writeGuidAttribute(title);
+ xmlWriter().writeAttribute("spectitle",title);
+ }
+ if (!outputclass.isEmpty())
+ xmlWriter().writeAttribute("outputclass",outputclass);
+ sectionNestingLevel = 1;
+ return sectionNestingLevel;
+}
+
+/*!
+ If the section nesting level is 0, output a \c{<section>}
+ element with an \e id attribute generated from \a title and
+ an \e outputclass attribute set to \a outputclass.
+ If \a title is null, no \e id attribute is output.
+ If \a outputclass is empty, no \e outputclass attribute
+ is output.
+
+ Finally, increment the section nesting level and return
+ the new value.
+ */
+int DitaXmlGenerator::enterSection(const QString& outputclass, const QString& title)
+{
+ if (sectionNestingLevel == 0) {
+ writeStartTag(DT_section);
+ if (!title.isEmpty())
+ writeGuidAttribute(title);
+ if (!outputclass.isEmpty())
+ xmlWriter().writeAttribute("outputclass",outputclass);
+ }
+ else if (!title.isEmpty()) {
+ writeStartTag(DT_p);
+ writeGuidAttribute(title);
+ if (!outputclass.isEmpty())
+ xmlWriter().writeAttribute("outputclass",outputclass);
+ writeCharacters(title);
+ writeEndTag(); // </p>
+ }
+ return ++sectionNestingLevel;
+}
+
+/*!
+ If the section nesting level is greater than 0, decrement
+ it. If it becomes 0, output a \c {</section>}. Return the
+ decremented section nesting level.
+ */
+int DitaXmlGenerator::leaveSection()
+{
+ if (sectionNestingLevel > 0) {
+ --sectionNestingLevel;
+ if (sectionNestingLevel == 0)
+ writeEndTag(); // </section> or </apiDesc>
+ }
+ return sectionNestingLevel;
+}
+
+/*!
+ The default constructor.
+ */
+DitaXmlGenerator::DitaXmlGenerator()
+ : inContents(false),
+ inDetailedDescription(false),
+ inLegaleseText(false),
+ inLink(false),
+ inObsoleteLink(false),
+ inSectionHeading(false),
+ inTableHeader(false),
+ inTableBody(false),
+ noLinks(false),
+ obsoleteLinks(false),
+ offlineDocs(true),
+ threeColumnEnumValueTable(true),
+ codeIndent(0),
+ numTableRows(0),
+ divNestingLevel(0),
+ sectionNestingLevel(0),
+ tableColumnCount(0),
+ funcLeftParen("\\S(\\()"),
+ tree_(0),
+ nodeTypeMaps(Node::LastType,0),
+ nodeSubtypeMaps(Node::LastSubtype,0),
+ pageTypeMaps(Node::OnBeyondZebra,0)
+{
+ // nothing yet.
+}
+
+/*!
+ The destructor has nothing to do.
+ */
+DitaXmlGenerator::~DitaXmlGenerator()
+{
+ GuidMaps::iterator i = guidMaps.begin();
+ while (i != guidMaps.end()) {
+ delete i.value();
+ ++i;
+ }
+}
+
+/*!
+ A lot of internal structures are initialized.
+ */
+void DitaXmlGenerator::initializeGenerator(const Config &config)
+{
+ Generator::initializeGenerator(config);
+ obsoleteLinks = config.getBool(QLatin1String(CONFIG_OBSOLETELINKS));
+ setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif");
+
+ style = config.getString(DitaXmlGenerator::format() +
+ Config::dot +
+ DITAXMLGENERATOR_STYLE);
+ postHeader = config.getString(DitaXmlGenerator::format() +
+ Config::dot +
+ DITAXMLGENERATOR_POSTHEADER);
+ postPostHeader = config.getString(DitaXmlGenerator::format() +
+ Config::dot +
+ DITAXMLGENERATOR_POSTPOSTHEADER);
+ footer = config.getString(DitaXmlGenerator::format() +
+ Config::dot +
+ DITAXMLGENERATOR_FOOTER);
+ address = config.getString(DitaXmlGenerator::format() +
+ Config::dot +
+ DITAXMLGENERATOR_ADDRESS);
+ pleaseGenerateMacRef = config.getBool(DitaXmlGenerator::format() +
+ Config::dot +
+ DITAXMLGENERATOR_GENERATEMACREFS);
+
+ project = config.getString(CONFIG_PROJECT);
+ projectDescription = config.getString(CONFIG_DESCRIPTION);
+ if (projectDescription.isEmpty() && !project.isEmpty())
+ projectDescription = project + " Reference Documentation";
+
+ projectUrl = config.getString(CONFIG_URL);
+
+ outputEncoding = config.getString(CONFIG_OUTPUTENCODING);
+ if (outputEncoding.isEmpty())
+ outputEncoding = QLatin1String("ISO-8859-1");
+ outputCodec = QTextCodec::codecForName(outputEncoding.toLocal8Bit());
+
+ naturalLanguage = config.getString(CONFIG_NATURALLANGUAGE);
+ if (naturalLanguage.isEmpty())
+ naturalLanguage = QLatin1String("en");
+
+ config.subVarsAndValues("dita.metadata.default",metadataDefaults);
+ QSet<QString> editionNames = config.subVars(CONFIG_EDITION);
+ QSet<QString>::ConstIterator edition = editionNames.begin();
+ while (edition != editionNames.end()) {
+ QString editionName = *edition;
+ QStringList editionModules = config.getStringList(CONFIG_EDITION +
+ Config::dot +
+ editionName +
+ Config::dot +
+ "modules");
+ QStringList editionGroups = config.getStringList(CONFIG_EDITION +
+ Config::dot +
+ editionName +
+ Config::dot +
+ "groups");
+
+ if (!editionModules.isEmpty())
+ editionModuleMap[editionName] = editionModules;
+ if (!editionGroups.isEmpty())
+ editionGroupMap[editionName] = editionGroups;
+
+ ++edition;
+ }
+
+ stylesheets = config.getStringList(DitaXmlGenerator::format() +
+ Config::dot +
+ DITAXMLGENERATOR_STYLESHEETS);
+ customHeadElements = config.getStringList(DitaXmlGenerator::format() +
+ Config::dot +
+ DITAXMLGENERATOR_CUSTOMHEADELEMENTS);
+ codeIndent = config.getInt(CONFIG_CODEINDENT);
+ version = config.getString(CONFIG_VERSION);
+ vrm = version.split(".");
+}
+
+/*!
+ All this does is call the same function in the base class.
+ */
+void DitaXmlGenerator::terminateGenerator()
+{
+ Generator::terminateGenerator();
+}
+
+/*!
+ Returns "DITAXML".
+ */
+QString DitaXmlGenerator::format()
+{
+ return "DITAXML";
+}
+
+/*!
+ Calls lookupGuid() to get a GUID for \a text, then writes
+ it to the XML stream as an "id" attribute, and returns it.
+ */
+QString DitaXmlGenerator::writeGuidAttribute(QString text)
+{
+ QString guid = lookupGuid(outFileName(),text);
+ xmlWriter().writeAttribute("id",guid);
+ return guid;
+}
+
+
+/*!
+ Write's the GUID for the \a node to the current XML stream
+ as an "id" attribute. If the \a node doesn't yet have a GUID,
+ one is generated.
+ */
+void DitaXmlGenerator::writeGuidAttribute(Node* node)
+{
+ xmlWriter().writeAttribute("id",node->guid());
+}
+
+/*!
+ Looks up \a text in the GUID map. If it finds \a text,
+ it returns the associated GUID. Otherwise it inserts
+ \a text into the map with a new GUID, and it returns
+ the new GUID.
+ */
+QString DitaXmlGenerator::lookupGuid(QString text)
+{
+ QMap<QString, QString>::const_iterator i = name2guidMap.find(text);
+ if (i != name2guidMap.end())
+ return i.value();
+#if 0
+ QString t = QUuid::createUuid().toString();
+ QString guid = "id-" + t.mid(1,t.length()-2);
+#endif
+ QString guid = Node::cleanId(text);
+ name2guidMap.insert(text,guid);
+ return guid;
+}
+
+/*!
+ First, look up the GUID map for \a fileName. If there isn't
+ a GUID map for \a fileName, create one and insert it into
+ the map of GUID maps. Then look up \a text in that GUID map.
+ If \a text is found, return the associated GUID. Otherwise,
+ insert \a text into the GUID map with a new GUID, and return
+ the new GUID.
+ */
+QString DitaXmlGenerator::lookupGuid(const QString& fileName, const QString& text)
+{
+ GuidMap* gm = lookupGuidMap(fileName);
+ GuidMap::const_iterator i = gm->find(text);
+ if (i != gm->end())
+ return i.value();
+#if 0
+ QString t = QUuid::createUuid().toString();
+ QString guid = "id-" + t.mid(1,t.length()-2);
+#endif
+ QString guid = Node::cleanId(text);
+ gm->insert(text,guid);
+ return guid;
+}
+
+/*!
+ Looks up \a fileName in the map of GUID maps. If it finds
+ \a fileName, it returns a pointer to the associated GUID
+ map. Otherwise it creates a new GUID map and inserts it
+ into the map of GUID maps with \a fileName as its key.
+ */
+GuidMap* DitaXmlGenerator::lookupGuidMap(const QString& fileName)
+{
+ GuidMaps::const_iterator i = guidMaps.find(fileName);
+ if (i != guidMaps.end())
+ return i.value();
+ GuidMap* gm = new GuidMap;
+ guidMaps.insert(fileName,gm);
+ return gm;
+}
+
+/*!
+ This is where the DITA XML files are written.
+ \note The file is created in PageGenerator::generateTree().
+ */
+void DitaXmlGenerator::generateTree(const Tree *tree)
+{
+ tree_ = tree;
+ nonCompatClasses.clear();
+ mainClasses.clear();
+ compatClasses.clear();
+ obsoleteClasses.clear();
+ moduleClassMap.clear();
+ moduleNamespaceMap.clear();
+ funcIndex.clear();
+ legaleseTexts.clear();
+ serviceClasses.clear();
+ qmlClasses.clear();
+ findAllClasses(tree->root());
+ findAllFunctions(tree->root());
+ findAllLegaleseTexts(tree->root());
+ findAllNamespaces(tree->root());
+ findAllSince(tree->root());
+
+ PageGenerator::generateTree(tree);
+ writeDitaMap(tree);
+}
+
+void DitaXmlGenerator::startText(const Node* /* relative */,
+ CodeMarker* /* marker */)
+{
+ inLink = false;
+ inContents = false;
+ inSectionHeading = false;
+ inTableHeader = false;
+ numTableRows = 0;
+ threeColumnEnumValueTable = true;
+ link.clear();
+ sectionNumber.clear();
+}
+
+static int countTableColumns(const Atom* t)
+{
+ int result = 0;
+ if (t->type() == Atom::TableHeaderLeft) {
+ while (t->type() == Atom::TableHeaderLeft) {
+ int count = 0;
+ t = t->next();
+ while (t->type() != Atom::TableHeaderRight) {
+ if (t->type() == Atom::TableItemLeft)
+ ++count;
+ t = t->next();
+ }
+ if (count > result)
+ result = count;
+ t = t->next();
+ }
+ }
+ else if (t->type() == Atom::TableRowLeft) {
+ while (t->type() != Atom::TableRowRight) {
+ if (t->type() == Atom::TableItemLeft)
+ ++result;
+ t = t->next();
+ }
+ }
+ return result;
+}
+
+/*!
+ Generate html from an instance of Atom.
+ */
+int DitaXmlGenerator::generateAtom(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker)
+{
+ int skipAhead = 0;
+ QString hx, str;
+ static bool in_para = false;
+ QString guid, hc, attr;
+
+ switch (atom->type()) {
+ case Atom::AbstractLeft:
+ break;
+ case Atom::AbstractRight:
+ break;
+ case Atom::AutoLink:
+ if (!noLinks && !inLink && !inContents && !inSectionHeading) {
+ const Node* node = 0;
+ QString link = getLink(atom, relative, marker, &node);
+ if (!link.isEmpty()) {
+ beginLink(link);
+ generateLink(atom, relative, marker);
+ endLink();
+ }
+ else {
+ writeCharacters(protectEnc(atom->string()));
+ }
+ }
+ else {
+ writeCharacters(protectEnc(atom->string()));
+ }
+ break;
+ case Atom::BaseName:
+ break;
+ case Atom::BriefLeft:
+ //if (relative->type() == Node::Fake) {
+ //skipAhead = skipAtoms(atom, Atom::BriefRight);
+ //break;
+ //}
+ if (inSection()) {
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","brief");
+ }
+ else {
+ noLinks = true;
+ writeStartTag(DT_shortdesc);
+ }
+ if (relative->type() == Node::Property ||
+ relative->type() == Node::Variable) {
+ xmlWriter().writeCharacters("This ");
+ if (relative->type() == Node::Property)
+ xmlWriter().writeCharacters("property");
+ else if (relative->type() == Node::Variable)
+ xmlWriter().writeCharacters("variable");
+ xmlWriter().writeCharacters(" holds ");
+ }
+ if (noLinks) {
+ atom = atom->next();
+ while (atom != 0 && atom->type() != Atom::BriefRight) {
+ if (atom->type() == Atom::String ||
+ atom->type() == Atom::AutoLink)
+ str += atom->string();
+ skipAhead++;
+ atom = atom->next();
+ }
+ str[0] = str[0].toLower();
+ if (str.endsWith(QLatin1Char('.')))
+ str.truncate(str.length() - 1);
+ writeCharacters(str + QLatin1Char('.'));
+ }
+ break;
+ case Atom::BriefRight:
+ // if (relative->type() != Node::Fake)
+ writeEndTag(); // </shortdesc> or </p>
+ noLinks = false;
+ break;
+ case Atom::C:
+ writeStartTag(DT_tt);
+ if (inLink) {
+ writeCharacters(protectEnc(plainCode(atom->string())));
+ }
+ else {
+ writeText(atom->string(), marker, relative);
+ }
+ writeEndTag(); // see writeStartElement() above
+ break;
+ case Atom::Code:
+ {
+ writeStartTag(DT_codeblock);
+ xmlWriter().writeAttribute("outputclass","cpp");
+ QString chars = trimmedTrailing(atom->string());
+ writeText(chars, marker, relative);
+ writeEndTag(); // </codeblock>
+ }
+ break;
+ case Atom::Qml:
+ writeStartTag(DT_codeblock);
+ xmlWriter().writeAttribute("outputclass","qml");
+ writeText(trimmedTrailing(atom->string()), marker, relative);
+ writeEndTag(); // </codeblock>
+ break;
+ case Atom::CodeNew:
+ writeStartTag(DT_p);
+ xmlWriter().writeCharacters("you can rewrite it as");
+ writeEndTag(); // </p>
+ writeStartTag(DT_codeblock);
+ writeText(trimmedTrailing(atom->string()), marker, relative);
+ writeEndTag(); // </codeblock>
+ break;
+ case Atom::CodeOld:
+ writeStartTag(DT_p);
+ xmlWriter().writeCharacters("For example, if you have code like");
+ writeEndTag(); // </p>
+ // fallthrough
+ case Atom::CodeBad:
+ writeStartTag(DT_codeblock);
+ writeCharacters(trimmedTrailing(plainCode(atom->string())));
+ writeEndTag(); // </codeblock>
+ break;
+ case Atom::DivLeft:
+ {
+ bool inStartElement = false;
+ attr = atom->string();
+ DitaTag t = currentTag();
+ if ((t == DT_section) || (t == DT_sectiondiv)) {
+ writeStartTag(DT_sectiondiv);
+ divNestingLevel++;
+ inStartElement = true;
+ }
+ else if ((t == DT_body) || (t == DT_bodydiv)) {
+ writeStartTag(DT_bodydiv);
+ divNestingLevel++;
+ inStartElement = true;
+ }
+ if (!attr.isEmpty()) {
+ if (attr.contains('=')) {
+ int index = 0;
+ int from = 0;
+ QString values;
+ while (index >= 0) {
+ index = attr.indexOf('"',from);
+ if (index >= 0) {
+ ++index;
+ from = index;
+ index = attr.indexOf('"',from);
+ if (index > from) {
+ if (!values.isEmpty())
+ values.append(' ');
+ values += attr.mid(from,index-from);
+ from = index+1;
+ }
+ }
+ }
+ attr = values;
+ }
+ }
+ if (inStartElement)
+ xmlWriter().writeAttribute("outputclass", attr);
+ }
+ break;
+ case Atom::DivRight:
+ if ((currentTag() == DT_sectiondiv) || (currentTag() == DT_bodydiv)) {
+ writeEndTag(); // </sectiondiv>, </bodydiv>, or </p>
+ if (divNestingLevel > 0)
+ --divNestingLevel;
+ }
+ break;
+ case Atom::FootnoteLeft:
+ // ### For now
+ if (in_para) {
+ writeEndTag(); // </p>
+ in_para = false;
+ }
+ xmlWriter().writeCharacters("<!-- ");
+ break;
+ case Atom::FootnoteRight:
+ // ### For now
+ xmlWriter().writeCharacters("-->");
+ break;
+ case Atom::FormatElse:
+ case Atom::FormatEndif:
+ case Atom::FormatIf:
+ break;
+ case Atom::FormattingLeft:
+ {
+ DitaTag t = DT_LAST;
+ if (atom->string() == ATOM_FORMATTING_BOLD)
+ t = DT_b;
+ else if (atom->string() == ATOM_FORMATTING_PARAMETER)
+ t = DT_i;
+ else if (atom->string() == ATOM_FORMATTING_ITALIC)
+ t = DT_i;
+ else if (atom->string() == ATOM_FORMATTING_TELETYPE)
+ t = DT_tt;
+ else if (atom->string().startsWith("span ")) {
+ t = DT_keyword;
+ }
+ else if (atom->string() == ATOM_FORMATTING_UNDERLINE)
+ t = DT_u;
+ else if (atom->string() == ATOM_FORMATTING_INDEX)
+ t = DT_comment;
+ else if (atom->string() == ATOM_FORMATTING_SUBSCRIPT)
+ t = DT_sub;
+ else if (atom->string() == ATOM_FORMATTING_SUPERSCRIPT)
+ t = DT_sup;
+ else
+ qDebug() << "DT_LAST";
+ writeStartTag(t);
+ if (atom->string() == ATOM_FORMATTING_PARAMETER) {
+ if (atom->next() != 0 && atom->next()->type() == Atom::String) {
+ QRegExp subscriptRegExp("([a-z]+)_([0-9n])");
+ if (subscriptRegExp.exactMatch(atom->next()->string())) {
+ xmlWriter().writeCharacters(subscriptRegExp.cap(1));
+ writeStartTag(DT_sub);
+ xmlWriter().writeCharacters(subscriptRegExp.cap(2));
+ writeEndTag(); // </sub>
+ skipAhead = 1;
+ }
+ }
+ }
+ else if (t == DT_keyword) {
+ QString attr = atom->string().mid(5);
+ if (!attr.isEmpty()) {
+ if (attr.contains('=')) {
+ int index = 0;
+ int from = 0;
+ QString values;
+ while (index >= 0) {
+ index = attr.indexOf('"',from);
+ if (index >= 0) {
+ ++index;
+ from = index;
+ index = attr.indexOf('"',from);
+ if (index > from) {
+ if (!values.isEmpty())
+ values.append(' ');
+ values += attr.mid(from,index-from);
+ from = index+1;
+ }
+ }
+ }
+ attr = values;
+ }
+ }
+ xmlWriter().writeAttribute("outputclass", attr);
+ }
+ }
+ break;
+ case Atom::FormattingRight:
+ if (atom->string() == ATOM_FORMATTING_LINK) {
+ endLink();
+ }
+ else {
+ writeEndTag(); // ?
+ }
+ break;
+ case Atom::AnnotatedList:
+ {
+ QList<Node*> values = tree_->groups().values(atom->string());
+ NodeMap nodeMap;
+ for (int i = 0; i < values.size(); ++i) {
+ const Node* n = values.at(i);
+ if ((n->status() != Node::Internal) && (n->access() != Node::Private)) {
+ nodeMap.insert(n->nameForLists(),n);
+ }
+ }
+ generateAnnotatedList(relative, marker, nodeMap);
+ }
+ break;
+ case Atom::GeneratedList:
+ if (atom->string() == "annotatedclasses") {
+ generateAnnotatedList(relative, marker, nonCompatClasses);
+ }
+ else if (atom->string() == "classes") {
+ generateCompactList(relative, marker, nonCompatClasses, true);
+ }
+ else if (atom->string() == "qmlclasses") {
+ generateCompactList(relative, marker, qmlClasses, true);
+ }
+ else if (atom->string().contains("classesbymodule")) {
+ QString arg = atom->string().trimmed();
+ QString moduleName = atom->string().mid(atom->string().indexOf(
+ "classesbymodule") + 15).trimmed();
+ if (moduleClassMap.contains(moduleName))
+ generateAnnotatedList(relative, marker, moduleClassMap[moduleName]);
+ }
+ else if (atom->string().contains("classesbyedition")) {
+
+ QString arg = atom->string().trimmed();
+ QString editionName = atom->string().mid(atom->string().indexOf(
+ "classesbyedition") + 16).trimmed();
+
+ if (editionModuleMap.contains(editionName)) {
+
+ // Add all classes in the modules listed for that edition.
+ NodeMap editionClasses;
+ foreach (const QString &moduleName, editionModuleMap[editionName]) {
+ if (moduleClassMap.contains(moduleName))
+ editionClasses.unite(moduleClassMap[moduleName]);
+ }
+
+ // Add additional groups and remove groups of classes that
+ // should be excluded from the edition.
+
+ QMultiMap <QString, Node *> groups = tree_->groups();
+ foreach (const QString &groupName, editionGroupMap[editionName]) {
+ QList<Node *> groupClasses;
+ if (groupName.startsWith(QLatin1Char('-'))) {
+ groupClasses = groups.values(groupName.mid(1));
+ foreach (const Node *node, groupClasses)
+ editionClasses.remove(node->name());
+ }
+ else {
+ groupClasses = groups.values(groupName);
+ foreach (const Node *node, groupClasses)
+ editionClasses.insert(node->name(), node);
+ }
+ }
+ generateAnnotatedList(relative, marker, editionClasses);
+ }
+ }
+ else if (atom->string() == "classhierarchy") {
+ generateClassHierarchy(relative, marker, nonCompatClasses);
+ }
+ else if (atom->string() == "compatclasses") {
+ generateCompactList(relative, marker, compatClasses, false);
+ }
+ else if (atom->string() == "obsoleteclasses") {
+ generateCompactList(relative, marker, obsoleteClasses, false);
+ }
+ else if (atom->string() == "functionindex") {
+ generateFunctionIndex(relative, marker);
+ }
+ else if (atom->string() == "legalese") {
+ generateLegaleseList(relative, marker);
+ }
+ else if (atom->string() == "mainclasses") {
+ generateCompactList(relative, marker, mainClasses, true);
+ }
+ else if (atom->string() == "services") {
+ generateCompactList(relative, marker, serviceClasses, false);
+ }
+ else if (atom->string() == "overviews") {
+ generateOverviewList(relative, marker);
+ }
+ else if (atom->string() == "namespaces") {
+ generateAnnotatedList(relative, marker, namespaceIndex);
+ }
+ else if (atom->string() == "related") {
+ const FakeNode *fake = static_cast<const FakeNode *>(relative);
+ if (fake && !fake->groupMembers().isEmpty()) {
+ NodeMap groupMembersMap;
+ foreach (const Node *node, fake->groupMembers()) {
+ if (node->type() == Node::Fake)
+ groupMembersMap[fullName(node, relative, marker)] = node;
+ }
+ generateAnnotatedList(fake, marker, groupMembersMap);
+ }
+ }
+ break;
+ case Atom::SinceList:
+ {
+ NewSinceMaps::const_iterator nsmap;
+ nsmap = newSinceMaps.find(atom->string());
+ NewClassMaps::const_iterator ncmap;
+ ncmap = newClassMaps.find(atom->string());
+ NewClassMaps::const_iterator nqcmap;
+ nqcmap = newQmlClassMaps.find(atom->string());
+ if ((nsmap != newSinceMaps.constEnd()) && !nsmap.value().isEmpty()) {
+ QList<Section> sections;
+ QList<Section>::ConstIterator s;
+ for (int i=0; i<LastSinceType; ++i)
+ sections.append(Section(sinceTitle(i),QString(),QString(),QString()));
+
+ NodeMultiMap::const_iterator n = nsmap.value().constBegin();
+ while (n != nsmap.value().constEnd()) {
+ const Node* node = n.value();
+ switch (node->type()) {
+ case Node::Fake:
+ if (node->subType() == Node::QmlClass) {
+ sections[QmlClass].appendMember((Node*)node);
+ }
+ break;
+ case Node::Namespace:
+ sections[Namespace].appendMember((Node*)node);
+ break;
+ case Node::Class:
+ sections[Class].appendMember((Node*)node);
+ break;
+ case Node::Enum:
+ sections[Enum].appendMember((Node*)node);
+ break;
+ case Node::Typedef:
+ sections[Typedef].appendMember((Node*)node);
+ break;
+ case Node::Function: {
+ const FunctionNode* fn = static_cast<const FunctionNode*>(node);
+ if (fn->isMacro())
+ sections[Macro].appendMember((Node*)node);
+ else {
+ Node* p = fn->parent();
+ if (p) {
+ if (p->type() == Node::Class)
+ sections[MemberFunction].appendMember((Node*)node);
+ else if (p->type() == Node::Namespace) {
+ if (p->name().isEmpty())
+ sections[GlobalFunction].appendMember((Node*)node);
+ else
+ sections[NamespaceFunction].appendMember((Node*)node);
+ }
+ else
+ sections[GlobalFunction].appendMember((Node*)node);
+ }
+ else
+ sections[GlobalFunction].appendMember((Node*)node);
+ }
+ break;
+ }
+ case Node::Property:
+ sections[Property].appendMember((Node*)node);
+ break;
+ case Node::Variable:
+ sections[Variable].appendMember((Node*)node);
+ break;
+ case Node::QmlProperty:
+ sections[QmlProperty].appendMember((Node*)node);
+ break;
+ case Node::QmlSignal:
+ sections[QmlSignal].appendMember((Node*)node);
+ break;
+ case Node::QmlSignalHandler:
+ sections[QmlSignalHandler].appendMember((Node*)node);
+ break;
+ case Node::QmlMethod:
+ sections[QmlMethod].appendMember((Node*)node);
+ break;
+ default:
+ break;
+ }
+ ++n;
+ }
+
+ /*
+ First generate the table of contents.
+ */
+ writeStartTag(DT_ul);
+ s = sections.constBegin();
+ while (s != sections.constEnd()) {
+ if (!(*s).members.isEmpty()) {
+ QString li = outFileName() + QLatin1Char('#') + Doc::canonicalTitle((*s).name);
+ writeXrefListItem(li, (*s).name);
+ }
+ ++s;
+ }
+ writeEndTag(); // </ul>
+
+ int idx = 0;
+ s = sections.constBegin();
+ while (s != sections.constEnd()) {
+ if (!(*s).members.isEmpty()) {
+ writeStartTag(DT_p);
+ writeGuidAttribute(Doc::canonicalTitle((*s).name));
+ xmlWriter().writeAttribute("outputclass","h3");
+ writeCharacters(protectEnc((*s).name));
+ writeEndTag(); // </p>
+ if (idx == Class)
+ generateCompactList(0, marker, ncmap.value(), false, QString("Q"));
+ else if (idx == QmlClass)
+ generateCompactList(0, marker, nqcmap.value(), false, QString("Q"));
+ else if (idx == MemberFunction) {
+ ParentMaps parentmaps;
+ ParentMaps::iterator pmap;
+ NodeList::const_iterator i = s->members.constBegin();
+ while (i != s->members.constEnd()) {
+ Node* p = (*i)->parent();
+ pmap = parentmaps.find(p);
+ if (pmap == parentmaps.end())
+ pmap = parentmaps.insert(p,NodeMultiMap());
+ pmap->insert((*i)->name(),(*i));
+ ++i;
+ }
+ pmap = parentmaps.begin();
+ while (pmap != parentmaps.end()) {
+ NodeList nlist = pmap->values();
+ writeStartTag(DT_p);
+ xmlWriter().writeCharacters("Class ");
+ writeStartTag(DT_xref);
+ // formathtml
+ xmlWriter().writeAttribute("href",linkForNode(pmap.key(), 0));
+ QStringList pieces = fullName(pmap.key(), 0, marker).split("::");
+ writeCharacters(protectEnc(pieces.last()));
+ writeEndTag(); // </xref>
+ xmlWriter().writeCharacters(":");
+ writeEndTag(); // </p>
+
+ generateSection(nlist, 0, marker, CodeMarker::Summary);
+ ++pmap;
+ }
+ }
+ else {
+ generateSection(s->members, 0, marker, CodeMarker::Summary);
+ }
+ }
+ ++idx;
+ ++s;
+ }
+ }
+ }
+ break;
+ case Atom::Image:
+ case Atom::InlineImage:
+ {
+ QString fileName = imageFileName(relative, atom->string());
+ QString text;
+ if (atom->next() != 0)
+ text = atom->next()->string();
+ if (fileName.isEmpty()) {
+ QString images = "images";
+ if (!baseDir().isEmpty())
+ images.prepend("../");
+ if (atom->string()[0] != '/')
+ images.append(QLatin1Char('/'));
+ fileName = images + atom->string();
+ }
+ if (relative && (relative->type() == Node::Fake) &&
+ (relative->subType() == Node::Example)) {
+ const ExampleNode* cen = static_cast<const ExampleNode*>(relative);
+ if (cen->imageFileName().isEmpty()) {
+ ExampleNode* en = const_cast<ExampleNode*>(cen);
+ en->setImageFileName(fileName);
+ }
+ }
+
+ if (currentTag() != DT_xref)
+ writeStartTag(DT_fig);
+ writeStartTag(DT_image);
+ writeHrefAttribute(protectEnc(fileName));
+ if (atom->type() == Atom::InlineImage)
+ xmlWriter().writeAttribute("placement","inline");
+ else {
+ xmlWriter().writeAttribute("placement","break");
+ xmlWriter().writeAttribute("align","center");
+ }
+ if (!text.isEmpty()) {
+ writeStartTag(DT_alt);
+ writeCharacters(protectEnc(text));
+ writeEndTag(); // </alt>
+ }
+ writeEndTag(); // </image>
+ if (currentTag() != DT_xref)
+ writeEndTag(); // </fig>
+ }
+ break;
+ case Atom::ImageText:
+ // nothing
+ break;
+ case Atom::ImportantLeft:
+ writeStartTag(DT_note);
+ xmlWriter().writeAttribute("type","important");
+ break;
+ case Atom::ImportantRight:
+ writeEndTag(); // </note>
+ break;
+ case Atom::NoteLeft:
+ writeStartTag(DT_note);
+ xmlWriter().writeAttribute("type","note");
+ break;
+ case Atom::NoteRight:
+ writeEndTag(); // </note>
+ break;
+ case Atom::LegaleseLeft:
+ inLegaleseText = true;
+ break;
+ case Atom::LegaleseRight:
+ inLegaleseText = false;
+ break;
+ case Atom::LineBreak:
+ //xmlWriter().writeEmptyElement("br");
+ break;
+ case Atom::Link:
+ {
+ const Node *node = 0;
+ QString myLink = getLink(atom, relative, marker, &node);
+ if (myLink.isEmpty()) {
+ relative->doc().location().warning(tr("Can't link to '%1' in %2")
+ .arg(atom->string())
+ .arg(marker->plainFullName(relative)));
+ }
+ else if (!inSectionHeading) {
+ beginLink(myLink);
+ }
+#if 0
+ else {
+ //xmlWriter().writeCharacters(atom->string());
+ //qDebug() << "MYLINK:" << myLink << outFileName() << atom->string();
+ }
+#endif
+ skipAhead = 1;
+ }
+ break;
+ case Atom::GuidLink:
+ {
+ beginLink(atom->string());
+ skipAhead = 1;
+ }
+ break;
+ case Atom::LinkNode:
+ {
+ const Node* node = CodeMarker::nodeForString(atom->string());
+ beginLink(linkForNode(node, relative));
+ skipAhead = 1;
+ }
+ break;
+ case Atom::ListLeft:
+ if (in_para) {
+ writeEndTag(); // </p>
+ in_para = false;
+ }
+ if (atom->string() == ATOM_LIST_BULLET) {
+ writeStartTag(DT_ul);
+ }
+ else if (atom->string() == ATOM_LIST_TAG) {
+ writeStartTag(DT_dl);
+ }
+ else if (atom->string() == ATOM_LIST_VALUE) {
+ threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom);
+ if (threeColumnEnumValueTable) {
+ writeStartTag(DT_simpletable);
+ xmlWriter().writeAttribute("outputclass","valuelist");
+ writeStartTag(DT_sthead);
+ writeStartTag(DT_stentry);
+ xmlWriter().writeCharacters("Constant");
+ writeEndTag(); // </stentry>
+ writeStartTag(DT_stentry);
+ xmlWriter().writeCharacters("Value");
+ writeEndTag(); // </stentry>
+ writeStartTag(DT_stentry);
+ xmlWriter().writeCharacters("Description");
+ writeEndTag(); // </stentry>
+ writeEndTag(); // </sthead>
+ }
+ else {
+ writeStartTag(DT_simpletable);
+ xmlWriter().writeAttribute("outputclass","valuelist");
+ writeStartTag(DT_sthead);
+ writeStartTag(DT_stentry);
+ xmlWriter().writeCharacters("Constant");
+ writeEndTag(); // </stentry>
+ writeStartTag(DT_stentry);
+ xmlWriter().writeCharacters("Value");
+ writeEndTag(); // </stentry>
+ writeEndTag(); // </sthead>
+ }
+ }
+ else {
+ writeStartTag(DT_ol);
+ if (atom->string() == ATOM_LIST_UPPERALPHA)
+ xmlWriter().writeAttribute("outputclass","upperalpha");
+ else if (atom->string() == ATOM_LIST_LOWERALPHA)
+ xmlWriter().writeAttribute("outputclass","loweralpha");
+ else if (atom->string() == ATOM_LIST_UPPERROMAN)
+ xmlWriter().writeAttribute("outputclass","upperroman");
+ else if (atom->string() == ATOM_LIST_LOWERROMAN)
+ xmlWriter().writeAttribute("outputclass","lowerroman");
+ else // (atom->string() == ATOM_LIST_NUMERIC)
+ xmlWriter().writeAttribute("outputclass","numeric");
+ if (atom->next() != 0 && atom->next()->string().toInt() != 1) {
+ // I don't think this attribute is supported.
+ xmlWriter().writeAttribute("start",atom->next()->string());
+ }
+ }
+ break;
+ case Atom::ListItemNumber:
+ // nothing
+ break;
+ case Atom::ListTagLeft:
+ if (atom->string() == ATOM_LIST_TAG) {
+ writeStartTag(DT_dt);
+ }
+ else { // (atom->string() == ATOM_LIST_VALUE)
+ writeStartTag(DT_strow);
+ writeStartTag(DT_stentry);
+ writeStartTag(DT_tt);
+ writeCharacters(protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(),
+ relative))));
+ writeEndTag(); // </tt>
+ writeEndTag(); // </stentry>
+ writeStartTag(DT_stentry);
+
+ QString itemValue;
+ if (relative->type() == Node::Enum) {
+ const EnumNode *enume = static_cast<const EnumNode *>(relative);
+ itemValue = enume->itemValue(atom->next()->string());
+ }
+
+ if (itemValue.isEmpty())
+ xmlWriter().writeCharacters("?");
+ else {
+ writeStartTag(DT_tt);
+ writeCharacters(protectEnc(itemValue));
+ writeEndTag(); // </tt>
+ }
+ skipAhead = 1;
+ }
+ break;
+ case Atom::ListTagRight:
+ if (atom->string() == ATOM_LIST_TAG)
+ writeEndTag(); // </dt>
+ break;
+ case Atom::ListItemLeft:
+ if (atom->string() == ATOM_LIST_TAG) {
+ writeStartTag(DT_dd);
+ }
+ else if (atom->string() == ATOM_LIST_VALUE) {
+ if (threeColumnEnumValueTable) {
+ writeEndTag(); // </stentry>
+ writeStartTag(DT_stentry);
+ }
+ }
+ else {
+ writeStartTag(DT_li);
+ }
+ if (matchAhead(atom, Atom::ParaLeft))
+ skipAhead = 1;
+ break;
+ case Atom::ListItemRight:
+ if (atom->string() == ATOM_LIST_TAG) {
+ writeEndTag(); // </dd>
+ }
+ else if (atom->string() == ATOM_LIST_VALUE) {
+ writeEndTag(); // </stentry>
+ writeEndTag(); // </strow>
+ }
+ else {
+ writeEndTag(); // </li>
+ }
+ break;
+ case Atom::ListRight:
+ if (atom->string() == ATOM_LIST_BULLET) {
+ writeEndTag(); // </ul>
+ }
+ else if (atom->string() == ATOM_LIST_TAG) {
+ writeEndTag(); // </dl>
+ }
+ else if (atom->string() == ATOM_LIST_VALUE) {
+ writeEndTag(); // </simpletable>
+ }
+ else {
+ writeEndTag(); // </ol>
+ }
+ break;
+ case Atom::Nop:
+ // nothing
+ break;
+ case Atom::ParaLeft:
+ writeStartTag(DT_p);
+ if (inLegaleseText)
+ xmlWriter().writeAttribute("outputclass","legalese");
+ in_para = true;
+ break;
+ case Atom::ParaRight:
+ endLink();
+ if (in_para) {
+ writeEndTag(); // </p>
+ in_para = false;
+ }
+ break;
+ case Atom::QuotationLeft:
+ writeStartTag(DT_lq);
+ break;
+ case Atom::QuotationRight:
+ writeEndTag(); // </lq>
+ break;
+ case Atom::RawString:
+ if (atom->string() == " ")
+ break;
+ if (atom->string().startsWith(QLatin1Char('&')))
+ writeCharacters(atom->string());
+ else if (atom->string() == "<sup>*</sup>") {
+ writeStartTag(DT_sup);
+ writeCharacters("*");
+ writeEndTag(); // </sup>
+ }
+ else if (atom->string() == "<sup>&reg;</sup>") {
+ writeStartTag(DT_tm);
+ xmlWriter().writeAttribute("tmtype","reg");
+ writeEndTag(); // </tm>
+ }
+ else {
+ writeStartTag(DT_pre);
+ xmlWriter().writeAttribute("outputclass","raw-html");
+ writeCharacters(atom->string());
+ writeEndTag(); // </pre>
+ }
+ break;
+ case Atom::SectionLeft:
+#if 0
+ if (inApiDesc) {
+ writeEndTag(); // </apiDesc>
+ inApiDesc = false;
+ }
+#endif
+ enterSection("details",QString());
+ //writeGuidAttribute(Doc::canonicalTitle(Text::sectionHeading(atom).toString()));
+ break;
+ case Atom::SectionRight:
+ leaveSection();
+ break;
+ case Atom::SectionHeadingLeft:
+ {
+ writeStartTag(DT_p);
+ QString id = Text::sectionHeading(atom).toString();
+ id = stripMarkup(id);
+ id = Doc::canonicalTitle(id);
+ writeGuidAttribute(id);
+ hx = QLatin1Char('h') + QString::number(atom->string().toInt() + hOffset(relative));
+ xmlWriter().writeAttribute("outputclass",hx);
+ inSectionHeading = true;
+ }
+ break;
+ case Atom::SectionHeadingRight:
+ writeEndTag(); // </title> (see case Atom::SectionHeadingLeft)
+ inSectionHeading = false;
+ break;
+ case Atom::SidebarLeft:
+ // nothing
+ break;
+ case Atom::SidebarRight:
+ // nothing
+ break;
+ case Atom::String:
+ if (inLink && !inContents && !inSectionHeading) {
+ generateLink(atom, relative, marker);
+ }
+ else {
+ writeCharacters(atom->string());
+ }
+ break;
+ case Atom::TableLeft:
+ {
+ QString attr;
+ if ((atom->count() > 0) && (atom->string(0) == "borderless"))
+ attr = "borderless";
+ else if ((atom->count() > 1) && (atom->string(1) == "borderless"))
+ attr = "borderless";
+ if (in_para) {
+ writeEndTag(); // </p>
+ in_para = false;
+ }
+ writeStartTag(DT_table);
+ if (!attr.isEmpty())
+ xmlWriter().writeAttribute("outputclass",attr);
+ numTableRows = 0;
+ if (tableColumnCount != 0) {
+ qDebug() << "ERROR: Nested tables!";
+ tableColumnCount = 0;
+ }
+ tableColumnCount = countTableColumns(atom->next());
+ writeStartTag(DT_tgroup);
+ xmlWriter().writeAttribute("cols",QString::number(tableColumnCount));
+ inTableHeader = false;
+ inTableBody = false;
+ }
+ break;
+ case Atom::TableRight:
+ writeEndTag(); // </tbody>
+ writeEndTag(); // </tgroup>
+ writeEndTag(); // </table>
+ inTableHeader = false;
+ inTableBody = false;
+ tableColumnCount = 0;
+ break;
+ case Atom::TableHeaderLeft:
+ if (inTableBody) {
+ writeEndTag(); // </tbody>
+ writeEndTag(); // </tgroup>
+ writeEndTag(); // </table>
+ inTableHeader = false;
+ inTableBody = false;
+ tableColumnCount = 0;
+ writeStartTag(DT_table);
+ numTableRows = 0;
+ tableColumnCount = countTableColumns(atom);
+ writeStartTag(DT_tgroup);
+ xmlWriter().writeAttribute("cols",QString::number(tableColumnCount));
+ }
+ writeStartTag(DT_thead);
+ xmlWriter().writeAttribute("valign","top");
+ writeStartTag(DT_row);
+ xmlWriter().writeAttribute("valign","top");
+ inTableHeader = true;
+ inTableBody = false;
+ break;
+ case Atom::TableHeaderRight:
+ writeEndTag(); // </row>
+ if (matchAhead(atom, Atom::TableHeaderLeft)) {
+ skipAhead = 1;
+ writeStartTag(DT_row);
+ xmlWriter().writeAttribute("valign","top");
+ }
+ else {
+ writeEndTag(); // </thead>
+ inTableHeader = false;
+ inTableBody = true;
+ writeStartTag(DT_tbody);
+ }
+ break;
+ case Atom::TableRowLeft:
+ if (!inTableHeader && !inTableBody) {
+ inTableBody = true;
+ writeStartTag(DT_tbody);
+ }
+ writeStartTag(DT_row);
+ attr = atom->string();
+ if (!attr.isEmpty()) {
+ if (attr.contains('=')) {
+ int index = 0;
+ int from = 0;
+ QString values;
+ while (index >= 0) {
+ index = attr.indexOf('"',from);
+ if (index >= 0) {
+ ++index;
+ from = index;
+ index = attr.indexOf('"',from);
+ if (index > from) {
+ if (!values.isEmpty())
+ values.append(' ');
+ values += attr.mid(from,index-from);
+ from = index+1;
+ }
+ }
+ }
+ attr = values;
+ }
+ xmlWriter().writeAttribute("outputclass", attr);
+ }
+ xmlWriter().writeAttribute("valign","top");
+ break;
+ case Atom::TableRowRight:
+ writeEndTag(); // </row>
+ break;
+ case Atom::TableItemLeft:
+ {
+ QString values;
+ writeStartTag(DT_entry);
+ for (int i=0; i<atom->count(); ++i) {
+ attr = atom->string(i);
+ if (attr.contains('=')) {
+ int index = 0;
+ int from = 0;
+ while (index >= 0) {
+ index = attr.indexOf('"',from);
+ if (index >= 0) {
+ ++index;
+ from = index;
+ index = attr.indexOf('"',from);
+ if (index > from) {
+ if (!values.isEmpty())
+ values.append(' ');
+ values += attr.mid(from,index-from);
+ from = index+1;
+ }
+ }
+ }
+ }
+ else {
+ QStringList spans = attr.split(QLatin1Char(','));
+ if (spans.size() == 2) {
+ if ((spans[0].toInt()>1) || (spans[1].toInt()>1)) {
+ values += "span(" + spans[0] + QLatin1Char(',') + spans[1] + QLatin1Char(')');
+ }
+ }
+ }
+ }
+ if (!values.isEmpty())
+ xmlWriter().writeAttribute("outputclass",values);
+ if (matchAhead(atom, Atom::ParaLeft))
+ skipAhead = 1;
+ }
+ break;
+ case Atom::TableItemRight:
+ if (inTableHeader)
+ writeEndTag(); // </entry>
+ else {
+ writeEndTag(); // </entry>
+ }
+ if (matchAhead(atom, Atom::ParaLeft))
+ skipAhead = 1;
+ break;
+ case Atom::TableOfContents:
+ {
+ int numColumns = 1;
+ const Node* node = relative;
+
+ Doc::Sections sectionUnit = Doc::Section4;
+ QStringList params = atom->string().split(QLatin1Char(','));
+ QString columnText = params.at(0);
+ QStringList pieces = columnText.split(QLatin1Char(' '), QString::SkipEmptyParts);
+ if (pieces.size() >= 2) {
+ columnText = pieces.at(0);
+ pieces.pop_front();
+ QString path = pieces.join(" ").trimmed();
+ node = findNodeForTarget(path, relative, marker, atom);
+ }
+
+ if (params.size() == 2) {
+ numColumns = qMax(columnText.toInt(), numColumns);
+ sectionUnit = (Doc::Sections)params.at(1).toInt();
+ }
+
+ if (node)
+ generateTableOfContents(node,
+ marker,
+ sectionUnit,
+ numColumns,
+ relative);
+ }
+ break;
+ case Atom::Target:
+ if (in_para) {
+ writeEndTag(); // </p>
+ in_para = false;
+ }
+ writeStartTag(DT_p);
+ writeGuidAttribute(Doc::canonicalTitle(atom->string()));
+ xmlWriter().writeAttribute("outputclass","target");
+ //xmlWriter().writeCharacters(protectEnc(atom->string()));
+ writeEndTag(); // </p>
+ break;
+ case Atom::UnhandledFormat:
+ writeStartTag(DT_b);
+ xmlWriter().writeAttribute("outputclass","error");
+ xmlWriter().writeCharacters("<Missing DITAXML>");
+ writeEndTag(); // </b>
+ break;
+ case Atom::UnknownCommand:
+ writeStartTag(DT_b);
+ xmlWriter().writeAttribute("outputclass","error unknown-command");
+ writeCharacters(protectEnc(atom->string()));
+ writeEndTag(); // </b>
+ break;
+ case Atom::QmlText:
+ case Atom::EndQmlText:
+ // don't do anything with these. They are just tags.
+ break;
+ default:
+ // unknownAtom(atom);
+ break;
+ }
+ return skipAhead;
+}
+
+/*!
+ Generate a <cxxClass> element (and all the stuff inside it)
+ for the C++ class represented by \a innerNode. \a marker is
+ for marking up the code. I don't know what that means exactly.
+ */
+void
+DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* marker)
+{
+ QList<Section>::ConstIterator s;
+
+ QString title;
+ QString rawTitle;
+ QString fullTitle;
+ if (inner->type() == Node::Namespace) {
+ const NamespaceNode* nsn = const_cast<NamespaceNode*>(static_cast<const NamespaceNode*>(inner));
+ rawTitle = marker->plainName(inner);
+ fullTitle = marker->plainFullName(inner);
+ title = rawTitle + " Namespace";
+
+ /*
+ Note: Because the C++ specialization we are using
+ has no <cxxNamespace> element, we are using the
+ <cxxClass> element with an outputclass attribute
+ set to "namespace" .
+ */
+ generateHeader(inner, fullTitle);
+ generateBrief(inner, marker); // <shortdesc>
+ writeProlog(inner);
+
+ writeStartTag(DT_cxxClassDetail);
+ writeStartTag(DT_cxxClassDefinition);
+ writeLocation(nsn);
+ writeEndTag(); // <cxxClassDefinition>
+
+ enterApiDesc(QString(),title);
+ Text brief = nsn->doc().briefText(); // zzz
+ if (!brief.isEmpty()) {
+ writeStartTag(DT_p);
+ generateText(brief, nsn, marker);
+ writeEndTag(); // </p>
+ }
+ generateIncludes(nsn, marker);
+ generateStatus(nsn, marker);
+ generateThreadSafeness(nsn, marker);
+ generateSince(nsn, marker);
+
+ enterSection("h2","Detailed Description");
+ generateBody(nsn, marker);
+ generateAlsoList(nsn, marker);
+ leaveSection();
+ leaveSection(); // </apiDesc>
+
+ bool needOtherSection = false;
+ QList<Section> summarySections;
+ summarySections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);
+ if (!summarySections.isEmpty()) {
+ enterSection("redundant",QString());
+ s = summarySections.begin();
+ while (s != summarySections.end()) {
+ if (s->members.isEmpty() && s->reimpMembers.isEmpty()) {
+ if (!s->inherited.isEmpty())
+ needOtherSection = true;
+ }
+ else {
+ QString attr;
+ if (!s->members.isEmpty()) {
+ writeStartTag(DT_p);
+ attr = cleanRef((*s).name).toLower() + " h2";
+ xmlWriter().writeAttribute("outputclass",attr);
+ writeCharacters(protectEnc((*s).name));
+ writeEndTag(); // </title>
+ generateSection(s->members, inner, marker, CodeMarker::Summary);
+ generateSectionInheritedList(*s, inner, marker);
+ }
+ if (!s->reimpMembers.isEmpty()) {
+ QString name = QString("Reimplemented ") + (*s).name;
+ attr = cleanRef(name).toLower() + " h2";
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass",attr);
+ writeCharacters(protectEnc(name));
+ writeEndTag(); // </title>
+ generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
+ generateSectionInheritedList(*s, inner, marker);
+ }
+ }
+ ++s;
+ }
+ if (needOtherSection) {
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","h3");
+ xmlWriter().writeCharacters("Additional Inherited Members");
+ writeEndTag(); // </title>
+ s = summarySections.begin();
+ while (s != summarySections.end()) {
+ if (s->members.isEmpty())
+ generateSectionInheritedList(*s, inner, marker);
+ ++s;
+ }
+ }
+ leaveSection();
+ }
+
+ writeEndTag(); // </cxxClassDetail>
+
+ // not included: <related-links>
+ // not included: <cxxClassNested>
+
+ QList<Section> detailSections;
+ detailSections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
+ s = detailSections.begin();
+ while (s != detailSections.end()) {
+ if ((*s).name == "Classes") {
+ writeNestedClasses((*s),nsn);
+ break;
+ }
+ ++s;
+ }
+
+ s = detailSections.begin();
+ while (s != detailSections.end()) {
+ if ((*s).name == "Function Documentation") {
+ writeFunctions((*s),nsn,marker);
+ }
+ else if ((*s).name == "Type Documentation") {
+ writeEnumerations((*s),marker);
+ writeTypedefs((*s),marker);
+ }
+ else if ((*s).name == "Namespaces") {
+ qDebug() << "Nested namespaces" << outFileName();
+ }
+ else if ((*s).name == "Macro Documentation") {
+ //writeMacros((*s),marker);
+ }
+ ++s;
+ }
+
+ generateLowStatusMembers(inner,marker,CodeMarker::Obsolete);
+ generateLowStatusMembers(inner,marker,CodeMarker::Compat);
+ writeEndTag(); // </cxxClass>
+ }
+ else if (inner->type() == Node::Class) {
+ const ClassNode* cn = const_cast<ClassNode*>(static_cast<const ClassNode*>(inner));
+ rawTitle = marker->plainName(inner);
+ fullTitle = marker->plainFullName(inner);
+ title = rawTitle + " Class";
+
+ generateHeader(inner, fullTitle);
+ generateBrief(inner, marker); // <shortdesc>
+ writeProlog(inner);
+
+ writeStartTag(DT_cxxClassDetail);
+ writeStartTag(DT_cxxClassDefinition);
+ writeStartTag(DT_cxxClassAccessSpecifier);
+ xmlWriter().writeAttribute("value",inner->accessString());
+ writeEndTag(); // <cxxClassAccessSpecifier>
+ if (cn->isAbstract()) {
+ writeStartTag(DT_cxxClassAbstract);
+ xmlWriter().writeAttribute("name","abstract");
+ xmlWriter().writeAttribute("value","abstract");
+ writeEndTag(); // </cxxClassAbstract>
+ }
+ writeDerivations(cn, marker); // <cxxClassDerivations>
+
+ // not included: <cxxClassTemplateParameters>
+
+ writeLocation(cn);
+ writeEndTag(); // <cxxClassDefinition>
+
+ enterApiDesc(QString(),title);
+ Text brief = cn->doc().briefText(); // zzz
+ if (!brief.isEmpty()) {
+ writeStartTag(DT_p);
+ generateText(brief, cn, marker);
+ writeEndTag(); // </p>
+ }
+ generateIncludes(cn, marker);
+ generateStatus(cn, marker);
+ generateInherits(cn, marker);
+ generateInheritedBy(cn, marker);
+ generateThreadSafeness(cn, marker);
+ generateSince(cn, marker);
+ enterSection("h2","Detailed Description");
+ generateBody(cn, marker);
+ generateAlsoList(cn, marker);
+ leaveSection();
+ leaveSection(); // </apiDesc>
+
+ bool needOtherSection = false;
+ QList<Section> summarySections;
+ summarySections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);
+ if (!summarySections.isEmpty()) {
+ enterSection("redundant",QString());
+ s = summarySections.begin();
+ while (s != summarySections.end()) {
+ if (s->members.isEmpty() && s->reimpMembers.isEmpty()) {
+ if (!s->inherited.isEmpty())
+ needOtherSection = true;
+ }
+ else {
+ QString attr;
+ if (!s->members.isEmpty()) {
+ writeStartTag(DT_p);
+ attr = cleanRef((*s).name).toLower() + " h2";
+ xmlWriter().writeAttribute("outputclass",attr);
+ writeCharacters(protectEnc((*s).name));
+ writeEndTag(); // </p>
+ generateSection(s->members, inner, marker, CodeMarker::Summary);
+ generateSectionInheritedList(*s, inner, marker);
+ }
+ if (!s->reimpMembers.isEmpty()) {
+ QString name = QString("Reimplemented ") + (*s).name;
+ attr = cleanRef(name).toLower() + " h2";
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass",attr);
+ writeCharacters(protectEnc(name));
+ writeEndTag(); // </p>
+ generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
+ generateSectionInheritedList(*s, inner, marker);
+ }
+ }
+ ++s;
+ }
+ if (needOtherSection) {
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","h3");
+ xmlWriter().writeCharacters("Additional Inherited Members");
+ writeEndTag(); // </p>
+ s = summarySections.begin();
+ while (s != summarySections.end()) {
+ if (s->members.isEmpty())
+ generateSectionInheritedList(*s, inner, marker);
+ ++s;
+ }
+ }
+ leaveSection();
+ }
+
+ // not included: <example> or <apiImpl>
+
+ writeEndTag(); // </cxxClassDetail>
+
+ // not included: <related-links>
+ // not included: <cxxClassNested>
+
+ QList<Section> detailSections;
+ detailSections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
+ s = detailSections.begin();
+ while (s != detailSections.end()) {
+ if ((*s).name == "Member Function Documentation") {
+ writeFunctions((*s),cn,marker);
+ }
+ else if ((*s).name == "Member Type Documentation") {
+ writeEnumerations((*s),marker);
+ writeTypedefs((*s),marker);
+ }
+ else if ((*s).name == "Member Variable Documentation") {
+ writeDataMembers((*s),marker);
+ }
+ else if ((*s).name == "Property Documentation") {
+ writeProperties((*s),marker);
+ }
+ else if ((*s).name == "Macro Documentation") {
+ //writeMacros((*s),marker);
+ }
+ else if ((*s).name == "Related Non-Members") {
+ QString attribute("related-non-member");
+ writeFunctions((*s),cn,marker,attribute);
+ }
+ ++s;
+ }
+
+ generateLowStatusMembers(inner,marker,CodeMarker::Obsolete);
+ generateLowStatusMembers(inner,marker,CodeMarker::Compat);
+ writeEndTag(); // </cxxClass>
+ }
+ else if ((inner->type() == Node::Fake) && (inner->subType() == Node::HeaderFile)) {
+ const FakeNode* fn = const_cast<FakeNode*>(static_cast<const FakeNode*>(inner));
+ rawTitle = marker->plainName(inner);
+ fullTitle = marker->plainFullName(inner);
+ title = rawTitle;
+
+ /*
+ Note: Because the C++ specialization we are using
+ has no <cxxHeaderFile> element, we are using the
+ <cxxClass> element with an outputclass attribute
+ set to "headerfile" .
+ */
+ generateHeader(inner, fullTitle);
+ generateBrief(inner, marker); // <shortdesc>
+ writeProlog(inner);
+
+ writeStartTag(DT_cxxClassDetail);
+ enterApiDesc(QString(),title);
+ Text brief = fn->doc().briefText(); // zzz
+ if (!brief.isEmpty()) {
+ writeStartTag(DT_p);
+ generateText(brief, fn, marker);
+ writeEndTag(); // </p>
+ }
+ generateIncludes(fn, marker);
+ generateStatus(fn, marker);
+ generateThreadSafeness(fn, marker);
+ generateSince(fn, marker);
+ generateSince(fn, marker);
+ enterSection("h2","Detailed Description");
+ generateBody(fn, marker);
+ generateAlsoList(fn, marker);
+ leaveSection();
+ leaveSection(); // </apiDesc>
+
+ bool needOtherSection = false;
+ QList<Section> summarySections;
+ summarySections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);
+ if (!summarySections.isEmpty()) {
+ enterSection("redundant",QString());
+ s = summarySections.begin();
+ while (s != summarySections.end()) {
+ if (s->members.isEmpty() && s->reimpMembers.isEmpty()) {
+ if (!s->inherited.isEmpty())
+ needOtherSection = true;
+ }
+ else {
+ QString attr;
+ if (!s->members.isEmpty()) {
+ writeStartTag(DT_p);
+ attr = cleanRef((*s).name).toLower() + " h2";
+ xmlWriter().writeAttribute("outputclass",attr);
+ writeCharacters(protectEnc((*s).name));
+ writeEndTag(); // </p>
+ generateSection(s->members, inner, marker, CodeMarker::Summary);
+ generateSectionInheritedList(*s, inner, marker);
+ }
+ if (!s->reimpMembers.isEmpty()) {
+ QString name = QString("Reimplemented ") + (*s).name;
+ attr = cleanRef(name).toLower() + " h2";
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass",attr);
+ writeCharacters(protectEnc(name));
+ writeEndTag(); // </p>
+ generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
+ generateSectionInheritedList(*s, inner, marker);
+ }
+ }
+ ++s;
+ }
+ if (needOtherSection) {
+ enterSection("additional-inherited-members redundant",QString());
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","h3");
+ xmlWriter().writeCharacters("Additional Inherited Members");
+ writeEndTag(); // </p>
+ s = summarySections.begin();
+ while (s != summarySections.end()) {
+ if (s->members.isEmpty())
+ generateSectionInheritedList(*s, inner, marker);
+ ++s;
+ }
+ }
+ leaveSection();
+ }
+
+ writeEndTag(); // </cxxClassDetail>
+
+ // not included: <related-links>
+ // not included: <cxxClassNested>
+
+ QList<Section> detailSections;
+ detailSections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
+ s = detailSections.begin();
+ while (s != detailSections.end()) {
+ if ((*s).name == "Classes") {
+ writeNestedClasses((*s),fn);
+ break;
+ }
+ ++s;
+ }
+
+ s = detailSections.begin();
+ while (s != detailSections.end()) {
+ if ((*s).name == "Function Documentation") {
+ writeFunctions((*s),fn,marker);
+ }
+ else if ((*s).name == "Type Documentation") {
+ writeEnumerations((*s),marker);
+ writeTypedefs((*s),marker);
+ }
+ else if ((*s).name == "Namespaces") {
+ qDebug() << "Nested namespaces" << outFileName();
+ }
+ else if ((*s).name == "Macro Documentation") {
+ //writeMacros((*s),marker);
+ }
+ ++s;
+ }
+ generateLowStatusMembers(inner,marker,CodeMarker::Obsolete);
+ generateLowStatusMembers(inner,marker,CodeMarker::Compat);
+ writeEndTag(); // </cxxClass>
+ }
+ else if ((inner->type() == Node::Fake) && (inner->subType() == Node::QmlClass)) {
+ const QmlClassNode* qcn = const_cast<QmlClassNode*>(static_cast<const QmlClassNode*>(inner));
+ const ClassNode* cn = qcn->classNode();
+ rawTitle = marker->plainName(inner);
+ fullTitle = marker->plainFullName(inner);
+ title = rawTitle + " Element";
+ //QString fullTitle = fake->fullTitle();
+ //QString htmlTitle = fullTitle;
+
+ generateHeader(inner, fullTitle);
+ generateBrief(inner, marker); // <shortdesc>
+ writeProlog(inner);
+
+ writeStartTag(DT_cxxClassDetail);
+ enterApiDesc(QString(),title);
+ Text brief = qcn->doc().briefText(); // zzz
+ if (!brief.isEmpty()) {
+ writeStartTag(DT_p);
+ generateText(brief, qcn, marker);
+ writeEndTag(); // </p>
+ }
+ generateQmlInstantiates(qcn, marker);
+ generateQmlInherits(qcn, marker);
+ generateQmlInheritedBy(qcn, marker);
+ generateSince(qcn, marker);
+ enterSection("h2","Detailed Description");
+ generateBody(qcn, marker);
+ if (cn) {
+ generateQmlText(cn->doc().body(), cn, marker, qcn->name());
+ generateAlsoList(cn, marker);
+ }
+ leaveSection();
+ leaveSection(); // </apiDesc>
+
+ QList<Section> summarySections;
+ summarySections = marker->qmlSections(qcn,CodeMarker::Summary);
+ if (!summarySections.isEmpty()) {
+ enterSection("redundant",QString());
+ s = summarySections.begin();
+ while (s != summarySections.end()) {
+ QString attr;
+ if (!s->members.isEmpty()) {
+ writeStartTag(DT_p);
+ attr = cleanRef((*s).name).toLower() + " h2";
+ xmlWriter().writeAttribute("outputclass",attr);
+ writeCharacters(protectEnc((*s).name));
+ writeEndTag(); // </p>
+ generateQmlSummary(*s,qcn,marker);
+ //generateSection(s->members, inner, marker, CodeMarker::Summary);
+ //generateSectionInheritedList(*s, inner, marker);
+ }
+ ++s;
+ }
+ leaveSection();
+ }
+
+ QList<Section> detailSections;
+ detailSections = marker->qmlSections(qcn,CodeMarker::Detailed);
+ if (!detailSections.isEmpty()) {
+ enterSection("details",QString());
+ s = detailSections.begin();
+ while (s != detailSections.end()) {
+ if (!s->members.isEmpty()) {
+ QString attr;
+ writeStartTag(DT_p);
+ attr = cleanRef((*s).name).toLower() + " h2";
+ xmlWriter().writeAttribute("outputclass",attr);
+ writeCharacters(protectEnc((*s).name));
+ writeEndTag(); // </p>
+ NodeList::ConstIterator m = (*s).members.begin();
+ while (m != (*s).members.end()) {
+ generateDetailedQmlMember(*m, qcn, marker);
+ ++m;
+ }
+ }
+ ++s;
+ }
+ leaveSection();
+ }
+ writeEndTag(); // </cxxClassDetail>
+ writeEndTag(); // </cxxClass>
+ }
+}
+
+
+/*!
+ Write a list item for a \a link with the given \a text.
+ */
+void DitaXmlGenerator::writeXrefListItem(const QString& link, const QString& text)
+{
+ writeStartTag(DT_li);
+ writeStartTag(DT_xref);
+ // formathtml
+ writeHrefAttribute(link);
+ writeCharacters(text);
+ writeEndTag(); // </xref>
+ writeEndTag(); // </li>
+}
+
+/*!
+ Generate the DITA page for a qdoc file that doesn't map
+ to an underlying c++ file.
+ */
+void DitaXmlGenerator::generateFakeNode(const FakeNode* fake, CodeMarker* marker)
+{
+ /*
+ If the fake node is a page node, and if the page type
+ is DITA map page, write the node's contents as a dita
+ map and return without doing anything else.
+ */
+ if (fake->subType() == Node::Page && fake->pageType() == Node::DitaMapPage) {
+ const DitaMapNode* dmn = static_cast<const DitaMapNode*>(fake);
+ writeDitaMap(dmn);
+ return;
+ }
+
+ QList<Section> sections;
+ QList<Section>::const_iterator s;
+ QString fullTitle = fake->fullTitle();
+
+ if (fake->subType() == Node::QmlBasicType) {
+ fullTitle = "QML Basic Type: " + fullTitle;
+ }
+ else if (fake->subType() == Node::Collision) {
+ fullTitle = "Name Collision: " + fullTitle;
+ }
+
+ generateHeader(fake, fullTitle);
+ generateBrief(fake, marker); // <shortdesc>
+ writeProlog(fake);
+
+ writeStartTag(DT_body);
+ enterSection(QString(),QString());
+ if (fake->subType() == Node::Module) {
+ generateStatus(fake, marker);
+ if (moduleNamespaceMap.contains(fake->name())) {
+ enterSection("h2","Namespaces");
+ generateAnnotatedList(fake, marker, moduleNamespaceMap[fake->name()]);
+ leaveSection();
+ }
+ if (moduleClassMap.contains(fake->name())) {
+ enterSection("h2","Classes");
+ generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]);
+ leaveSection();
+ }
+ }
+
+ if (fake->doc().isEmpty()) {
+ if (fake->subType() == Node::File) {
+ Text text;
+ Quoter quoter;
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass", "small-subtitle");
+ text << fake->subTitle();
+ generateText(text, fake, marker);
+ writeEndTag(); // </p>
+ Doc::quoteFromFile(fake->doc().location(), quoter, fake->name());
+ QString code = quoter.quoteTo(fake->location(), "", "");
+ text.clear();
+ text << Atom(Atom::Code, code);
+ generateText(text, fake, marker);
+ }
+ }
+ else {
+ if (fake->subType() == Node::Module) {
+ enterSection("h2","Detailed Description");
+ generateBody(fake, marker);
+ leaveSection();
+ }
+ else {
+ generateBody(fake, marker);
+ }
+ generateAlsoList(fake, marker);
+
+ if ((fake->subType() == Node::QmlModule) && !fake->qmlModuleMembers().isEmpty()) {
+ NodeMap qmlModuleMembersMap;
+ foreach (const Node* node, fake->qmlModuleMembers()) {
+ if (node->type() == Node::Fake && node->subType() == Node::QmlClass)
+ qmlModuleMembersMap[node->name()] = node;
+ }
+ generateAnnotatedList(fake, marker, qmlModuleMembersMap);
+ }
+ else if (!fake->groupMembers().isEmpty()) {
+ NodeMap groupMembersMap;
+ foreach (const Node *node, fake->groupMembers()) {
+ if (node->type() == Node::Class || node->type() == Node::Namespace)
+ groupMembersMap[node->name()] = node;
+ }
+ generateAnnotatedList(fake, marker, groupMembersMap);
+ }
+ }
+ leaveSection(); // </section>
+ writeEndTag(); // </body>
+ writeRelatedLinks(fake, marker);
+ writeEndTag(); // </topic>
+}
+
+/*!
+ This function writes a \e{<link>} element inside a
+ \e{<related-links>} element.
+
+ \sa writeRelatedLinks()
+ */
+void DitaXmlGenerator::writeLink(const Node* node,
+ const QString& text,
+ const QString& role)
+{
+ if (node) {
+ QString link = fileName(node) + QLatin1Char('#') + node->guid();
+ if (link.endsWith("#"))
+ qDebug() << "LINK ENDS WITH #:" << link << outFileName();
+ writeStartTag(DT_link);
+ writeHrefAttribute(link);
+ xmlWriter().writeAttribute("role", role);
+ writeStartTag(DT_linktext);
+ writeCharacters(text);
+ writeEndTag(); // </linktext>
+ writeEndTag(); // </link>
+ }
+}
+
+/*!
+ This function writes a \e{<related-links>} element, which
+ contains the \c{next}, \c{previous}, and \c{start}
+ links for topic pages that have them. Note that the
+ value of the \e role attribute is \c{parent} for the
+ \c{start} link.
+ */
+void DitaXmlGenerator::writeRelatedLinks(const FakeNode* node, CodeMarker* marker)
+{
+ const Node* linkNode = 0;
+ QPair<QString,QString> linkPair;
+ if (node && !node->links().empty()) {
+ writeStartTag(DT_relatedLinks);
+ if (node->links().contains(Node::PreviousLink)) {
+ linkPair = node->links()[Node::PreviousLink];
+ linkNode = findNodeForTarget(linkPair.first, node, marker);
+ writeLink(linkNode, linkPair.second, "previous");
+ }
+ if (node->links().contains(Node::NextLink)) {
+ linkPair = node->links()[Node::NextLink];
+ linkNode = findNodeForTarget(linkPair.first, node, marker);
+ writeLink(linkNode, linkPair.second, "next");
+ }
+ if (node->links().contains(Node::StartLink)) {
+ linkPair = node->links()[Node::StartLink];
+ linkNode = findNodeForTarget(linkPair.first, node, marker);
+ writeLink(linkNode, linkPair.second, "parent");
+ }
+ writeEndTag(); // </related-links>
+ }
+}
+
+/*!
+ Returns "xml" for this subclass of class Generator.
+ */
+QString DitaXmlGenerator::fileExtension(const Node * /* node */) const
+{
+ return "xml";
+}
+
+/*!
+ Writes an XML file header to the current XML stream. This
+ depends on which kind of DITA XML file is being generated,
+ which is determined by the \a node type and subtype and the
+ \a subpage flag. If the \subpage flag is true, a \c{<topic>}
+ header is written, regardless of the type of \a node.
+ */
+void DitaXmlGenerator::generateHeader(const Node* node,
+ const QString& name,
+ bool subpage)
+{
+ if (!node)
+ return;
+
+ DitaTag mainTag = DT_cxxClass;
+ DitaTag nameTag = DT_apiName;
+ QString doctype;
+ QString dtd;
+ QString base;
+ QString version;
+ QString outputclass;
+
+ if (node->type() == Node::Class) {
+ mainTag = DT_cxxClass;
+ nameTag = DT_apiName;
+ dtd = "dtd/cxxClass.dtd";
+ version = "0.7.0";
+ doctype = "<!DOCTYPE " + ditaTags[mainTag] +
+ " PUBLIC \"-//NOKIA//DTD DITA C++ API Class Reference Type v" +
+ version + "//EN\" \"" + dtd + "\">";
+ }
+ else if (node->type() == Node::Namespace) {
+ mainTag = DT_cxxClass;
+ nameTag = DT_apiName;
+ dtd = "dtd/cxxClass.dtd";
+ version = "0.7.0";
+ doctype = "<!DOCTYPE " + ditaTags[mainTag] +
+ " PUBLIC \"-//NOKIA//DTD DITA C++ API Class Reference Type v" +
+ version + "//EN\" \"" + dtd + "\">";
+ outputclass = "namespace";
+ }
+ else if (node->type() == Node::Fake || subpage) {
+ if (node->subType() == Node::HeaderFile) {
+ mainTag = DT_cxxClass;
+ nameTag = DT_apiName;
+ dtd = "dtd/cxxClass.dtd";
+ version = "0.7.0";
+ doctype = "<!DOCTYPE " + ditaTags[mainTag] +
+ " PUBLIC \"-//NOKIA//DTD DITA C++ API Class Reference Type v" +
+ version + "//EN\" \"" + dtd + "\">";
+ outputclass = "headerfile";
+ }
+ else if (node->subType() == Node::QmlClass) {
+ mainTag = DT_cxxClass;
+ nameTag = DT_apiName;
+ dtd = "dtd/cxxClass.dtd";
+ version = "0.7.0";
+ doctype = "<!DOCTYPE " + ditaTags[mainTag] +
+ " PUBLIC \"-//NOKIA//DTD DITA C++ API Class Reference Type v" +
+ version + "//EN\" \"" + dtd + "\">";
+ outputclass = "QML-class";
+ }
+ else {
+ mainTag = DT_topic;
+ nameTag = DT_title;
+ dtd = "dtd/topic.dtd";
+ doctype = "<!DOCTYPE " + ditaTags[mainTag] +
+ " PUBLIC \"-//OASIS//DTD DITA Topic//EN\" \"" + dtd + "\">";
+ switch (node->subType()) {
+ case Node::Page:
+ outputclass = node->pageTypeString();
+ break;
+ case Node::Group:
+ outputclass = "group";
+ break;
+ case Node::Example:
+ outputclass = "example";
+ break;
+ case Node::File:
+ outputclass = "file";
+ break;
+ case Node::Image: // not used
+ outputclass = "image";
+ break;
+ case Node::Module:
+ outputclass = "module";
+ break;
+ case Node::ExternalPage: // not used
+ outputclass = "externalpage";
+ break;
+ default:
+ outputclass = "page";
+ }
+ }
+ }
+
+ xmlWriter().writeDTD(doctype);
+ xmlWriter().writeComment(node->doc().location().fileName());
+ writeStartTag(mainTag);
+ QString id = node->guid();
+ xmlWriter().writeAttribute("id",id);
+ if (!outputclass.isEmpty())
+ xmlWriter().writeAttribute("outputclass",outputclass);
+ writeStartTag(nameTag); // <title> or <apiName>
+ writeCharacters(name);
+ writeEndTag(); // </title> or </apiName>
+}
+
+/*!
+ Outputs the \e brief command as a <shortdesc> element.
+ */
+void DitaXmlGenerator::generateBrief(const Node* node, CodeMarker* marker)
+{
+ Text brief = node->doc().briefText(true); // zzz
+ if (!brief.isEmpty()) {
+ generateText(brief, node, marker);
+ }
+}
+
+/*!
+ Writes the \c {#include ...} required to include the class
+ or namespace in a compilation.
+ */
+void DitaXmlGenerator::generateIncludes(const InnerNode* inner, CodeMarker* marker)
+{
+ if (!inner->includes().isEmpty()) {
+ writeStartTag(DT_codeblock);
+ writeText(marker->markedUpIncludes(inner->includes()), marker, inner);
+ writeEndTag(); // </codeblock>
+ }
+}
+
+/*!
+ zzz
+ Generates a table of contents beginning at \a node.
+ Currently just returns without writing anything.
+ */
+void DitaXmlGenerator::generateTableOfContents(const Node* node,
+ CodeMarker* marker,
+ Doc::Sections sectionUnit,
+ int numColumns,
+ const Node* relative)
+
+{
+ return;
+ if (!node->doc().hasTableOfContents())
+ return;
+ QList<Atom *> toc = node->doc().tableOfContents();
+ if (toc.isEmpty())
+ return;
+
+ QString nodeName = "";
+ if (node != relative)
+ nodeName = node->name();
+
+ QStringList sectionNumber;
+ int columnSize = 0;
+
+ QString tdTag;
+ if (numColumns > 1) {
+ tdTag = "<td>"; /* width=\"" + QString::number((100 + numColumns - 1) / numColumns) + "%\">";*/
+ out() << "<table class=\"toc\">\n<tr class=\"topAlign\">"
+ << tdTag << '\n';
+ }
+
+ // disable nested links in table of contents
+ inContents = true;
+ inLink = true;
+
+ for (int i = 0; i < toc.size(); ++i) {
+ Atom *atom = toc.at(i);
+
+ int nextLevel = atom->string().toInt();
+ if (nextLevel > (int)sectionUnit)
+ continue;
+
+ if (sectionNumber.size() < nextLevel) {
+ do {
+ out() << "<ul>";
+ sectionNumber.append("1");
+ } while (sectionNumber.size() < nextLevel);
+ }
+ else {
+ while (sectionNumber.size() > nextLevel) {
+ out() << "</ul>\n";
+ sectionNumber.removeLast();
+ }
+ sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1);
+ }
+ int numAtoms;
+ Text headingText = Text::sectionHeading(atom);
+
+ if (sectionNumber.size() == 1 && columnSize > toc.size() / numColumns) {
+ out() << "</ul></td>" << tdTag << "<ul>\n";
+ columnSize = 0;
+ }
+ out() << "<li>";
+ out() << "<xref href=\""
+ << nodeName
+ << "#"
+ << Doc::canonicalTitle(headingText.toString())
+ << "\">";
+ generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms);
+ out() << "</xref></li>\n";
+
+ ++columnSize;
+ }
+ while (!sectionNumber.isEmpty()) {
+ out() << "</ul>\n";
+ sectionNumber.removeLast();
+ }
+
+ if (numColumns > 1)
+ out() << "</td></tr></table>\n";
+
+ inContents = false;
+ inLink = false;
+}
+
+/*!
+ zzz
+ Revised for the new doc format.
+ Generates a table of contents beginning at \a node.
+ */
+void DitaXmlGenerator::generateTableOfContents(const Node* node,
+ CodeMarker* marker,
+ QList<Section>* sections)
+{
+ QList<Atom*> toc;
+ if (node->doc().hasTableOfContents())
+ toc = node->doc().tableOfContents();
+ if (toc.isEmpty() && !sections && (node->subType() != Node::Module))
+ return;
+
+ QStringList sectionNumber;
+ int detailsBase = 0;
+
+ // disable nested links in table of contents
+ inContents = true;
+ inLink = true;
+
+ out() << "<div class=\"toc\">\n";
+ out() << "<h3>Contents</h3>\n";
+ sectionNumber.append("1");
+ out() << "<ul>\n";
+
+ if (node->subType() == Node::Module) {
+ if (moduleNamespaceMap.contains(node->name())) {
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\"><xref href=\"#"
+ << registerRef("namespaces")
+ << "\">Namespaces</xref></li>\n";
+ }
+ if (moduleClassMap.contains(node->name())) {
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\"><xref href=\"#"
+ << registerRef("classes")
+ << "\">Classes</xref></li>\n";
+ }
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\"><xref href=\"#"
+ << registerRef("details")
+ << "\">Detailed Description</xref></li>\n";
+ for (int i = 0; i < toc.size(); ++i) {
+ if (toc.at(i)->string().toInt() == 1) {
+ detailsBase = 1;
+ break;
+ }
+ }
+ }
+ else if (sections && (node->type() == Node::Class)) {
+ QList<Section>::ConstIterator s = sections->begin();
+ while (s != sections->end()) {
+ if (!s->members.isEmpty() || !s->reimpMembers.isEmpty()) {
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\"><xref href=\"#"
+ << registerRef((*s).pluralMember)
+ << "\">" << (*s).name
+ << "</xref></li>\n";
+ }
+ ++s;
+ }
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\"><xref href=\"#"
+ << registerRef("details")
+ << "\">Detailed Description</xref></li>\n";
+ for (int i = 0; i < toc.size(); ++i) {
+ if (toc.at(i)->string().toInt() == 1) {
+ detailsBase = 1;
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < toc.size(); ++i) {
+ Atom *atom = toc.at(i);
+ int nextLevel = atom->string().toInt() + detailsBase;
+ if (sectionNumber.size() < nextLevel) {
+ do {
+ sectionNumber.append("1");
+ } while (sectionNumber.size() < nextLevel);
+ }
+ else {
+ while (sectionNumber.size() > nextLevel) {
+ sectionNumber.removeLast();
+ }
+ sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1);
+ }
+ int numAtoms;
+ Text headingText = Text::sectionHeading(atom);
+ QString s = headingText.toString();
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\">";
+ out() << "<xref href=\""
+ << "#"
+ << Doc::canonicalTitle(s)
+ << "\">";
+ generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms);
+ out() << "</xref></li>\n";
+ }
+ while (!sectionNumber.isEmpty()) {
+ sectionNumber.removeLast();
+ }
+ out() << "</ul>\n";
+ out() << "</div>\n";
+ inContents = false;
+ inLink = false;
+}
+
+void DitaXmlGenerator::generateLowStatusMembers(const InnerNode* inner,
+ CodeMarker* marker,
+ CodeMarker::Status status)
+{
+ QString attribute;
+ if (status == CodeMarker::Compat)
+ attribute = "Qt3-support";
+ else if (status == CodeMarker::Obsolete)
+ attribute = "obsolete";
+ else
+ return;
+
+ QList<Section> sections = marker->sections(inner, CodeMarker::Detailed, status);
+ QMutableListIterator<Section> j(sections);
+ while (j.hasNext()) {
+ if (j.next().members.size() == 0)
+ j.remove();
+ }
+ if (sections.isEmpty())
+ return;
+
+ QList<Section>::ConstIterator s = sections.begin();
+ while (s != sections.end()) {
+ if ((*s).name == "Member Function Documentation") {
+ writeFunctions((*s),inner,marker,attribute);
+ }
+ else if ((*s).name == "Member Type Documentation") {
+ writeEnumerations((*s),marker,attribute);
+ writeTypedefs((*s),marker,attribute);
+ }
+ else if ((*s).name == "Member Variable Documentation") {
+ writeDataMembers((*s),marker,attribute);
+ }
+ else if ((*s).name == "Property Documentation") {
+ writeProperties((*s),marker,attribute);
+ }
+ else if ((*s).name == "Macro Documentation") {
+ //writeMacros((*s),marker,attribute);
+ }
+ ++s;
+ }
+}
+
+/*!
+ Write the XML for the class hierarchy to the current XML stream.
+ */
+void DitaXmlGenerator::generateClassHierarchy(const Node* relative,
+ CodeMarker* marker,
+ const QMap<QString,const Node*>& classMap)
+{
+ if (classMap.isEmpty())
+ return;
+
+ NodeMap topLevel;
+ NodeMap::ConstIterator c = classMap.begin();
+ while (c != classMap.end()) {
+ const ClassNode* classe = static_cast<const ClassNode*>(*c);
+ if (classe->baseClasses().isEmpty())
+ topLevel.insert(classe->name(), classe);
+ ++c;
+ }
+
+ QStack<NodeMap > stack;
+ stack.push(topLevel);
+
+ writeStartTag(DT_ul);
+ while (!stack.isEmpty()) {
+ if (stack.top().isEmpty()) {
+ stack.pop();
+ writeEndTag(); // </ul>
+ if (!stack.isEmpty())
+ writeEndTag(); // </li>
+ }
+ else {
+ const ClassNode *child =
+ static_cast<const ClassNode *>(*stack.top().begin());
+ writeStartTag(DT_li);
+ generateFullName(child, relative, marker);
+ writeEndTag(); // </li>
+ stack.top().erase(stack.top().begin());
+
+ NodeMap newTop;
+ foreach (const RelatedClass &d, child->derivedClasses()) {
+ if (d.access != Node::Private && !d.node->doc().isEmpty())
+ newTop.insert(d.node->name(), d.node);
+ }
+ if (!newTop.isEmpty()) {
+ stack.push(newTop);
+ writeStartTag(DT_li);
+ writeStartTag(DT_ul);
+ }
+ }
+ }
+}
+
+/*!
+ Write XML for the contents of the \a nodeMap to the current
+ XML stream.
+ */
+void DitaXmlGenerator::generateAnnotatedList(const Node* relative,
+ CodeMarker* marker,
+ const NodeMap& nodeMap)
+{
+ if (nodeMap.isEmpty())
+ return;
+ writeStartTag(DT_table);
+ xmlWriter().writeAttribute("outputclass","annotated");
+ writeStartTag(DT_tgroup);
+ xmlWriter().writeAttribute("cols","2");
+ writeStartTag(DT_tbody);
+
+ foreach (const QString& name, nodeMap.keys()) {
+ const Node* node = nodeMap[name];
+
+ if (node->status() == Node::Obsolete)
+ continue;
+
+ writeStartTag(DT_row);
+ writeStartTag(DT_entry);
+ writeStartTag(DT_p);
+ generateFullName(node, relative, marker);
+ writeEndTag(); // </p>
+ writeEndTag(); // <entry>
+
+ if (!(node->type() == Node::Fake)) {
+ Text brief = node->doc().trimmedBriefText(name);
+ if (!brief.isEmpty()) {
+ writeStartTag(DT_entry);
+ writeStartTag(DT_p);
+ generateText(brief, node, marker);
+ writeEndTag(); // </p>
+ writeEndTag(); // <entry>
+ }
+ }
+ else {
+ writeStartTag(DT_entry);
+ writeStartTag(DT_p);
+ writeCharacters(protectEnc(node->doc().briefText().toString())); // zzz
+ writeEndTag(); // </p>
+ writeEndTag(); // <entry>
+ }
+ writeEndTag(); // </row>
+ }
+ writeEndTag(); // </tbody>
+ writeEndTag(); // </tgroup>
+ writeEndTag(); // </table>
+}
+
+/*!
+ This function finds the common prefix of the names of all
+ the classes in \a classMap and then generates a compact
+ list of the class names alphabetized on the part of the
+ name not including the common prefix. You can tell the
+ function to use \a comonPrefix as the common prefix, but
+ normally you let it figure it out itself by looking at
+ the name of the first and last classes in \a classMap.
+ */
+void DitaXmlGenerator::generateCompactList(const Node* relative,
+ CodeMarker* marker,
+ const NodeMap& classMap,
+ bool includeAlphabet,
+ QString commonPrefix)
+{
+ const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_'
+
+ if (classMap.isEmpty())
+ return;
+
+ /*
+ If commonPrefix is not empty, then the caller knows what
+ the common prefix is and has passed it in, so just use that
+ one. But if the commonPrefix is empty (it normally is), then
+ compute a common prefix using this simple algorithm. Note we
+ assume the prefix length is 1, i.e. we will have a single
+ character as the common prefix.
+ */
+ int commonPrefixLen = commonPrefix.length();
+ if (commonPrefixLen == 0) {
+ QVector<int> count(26);
+ for (int i=0; i<26; ++i)
+ count[i] = 0;
+
+ NodeMap::const_iterator iter = classMap.begin();
+ while (iter != classMap.end()) {
+ if (!iter.key().contains("::")) {
+ QChar c = iter.key()[0];
+ if ((c >= 'A') && (c <= 'Z')) {
+ int idx = c.unicode() - QChar('A').unicode();
+ ++count[idx];
+ }
+ }
+ ++iter;
+ }
+ int highest = 0;
+ int idx = -1;
+ for (int i=0; i<26; ++i) {
+ if (count[i] > highest) {
+ highest = count[i];
+ idx = i;
+ }
+ }
+ idx += QChar('A').unicode();
+ QChar common(idx);
+ commonPrefix = common;
+ commonPrefixLen = 1;
+
+#if 0
+ /*
+ The algorithm below eventually failed, so it was replaced
+ with the simple (perhaps too simple) algorithm above.
+
+ The caller didn't pass in a common prefix, so get the common
+ prefix by looking at the class names of the first and last
+ classes in the class map. Discard any namespace names and
+ just use the bare class names. For Qt, the prefix is "Q".
+
+ Note that the algorithm used here to derive the common prefix
+ from the first and last classes in alphabetical order (QAccel
+ and QXtWidget in Qt 2.1), fails if either class name does not
+ begin with Q.
+ */
+ QString first;
+ QString last;
+ NodeMap::const_iterator iter = classMap.begin();
+ while (iter != classMap.end()) {
+ if (!iter.key().contains("::")) {
+ first = iter.key();
+ break;
+ }
+ ++iter;
+ }
+
+ if (first.isEmpty())
+ first = classMap.begin().key();
+
+ iter = classMap.end();
+ while (iter != classMap.begin()) {
+ --iter;
+ if (!iter.key().contains("::")) {
+ last = iter.key();
+ break;
+ }
+ }
+
+ if (last.isEmpty())
+ last = classMap.begin().key();
+
+ if (classMap.size() > 1) {
+ while (commonPrefixLen < first.length() + 1 &&
+ commonPrefixLen < last.length() + 1 &&
+ first[commonPrefixLen] == last[commonPrefixLen])
+ ++commonPrefixLen;
+ }
+
+ commonPrefix = first.left(commonPrefixLen);
+#endif
+ }
+
+ /*
+ Divide the data into 37 paragraphs: 0, ..., 9, A, ..., Z,
+ underscore (_). QAccel will fall in paragraph 10 (A) and
+ QXtWidget in paragraph 33 (X). This is the only place where we
+ assume that NumParagraphs is 37. Each paragraph is a NodeMap.
+ */
+ NodeMap paragraph[NumParagraphs+1];
+ QString paragraphName[NumParagraphs+1];
+ QSet<char> usedParagraphNames;
+
+ NodeMap::ConstIterator c = classMap.begin();
+ while (c != classMap.end()) {
+ QStringList pieces = c.key().split("::");
+ QString key;
+ int idx = commonPrefixLen;
+ if (!pieces.last().startsWith(commonPrefix))
+ idx = 0;
+ if (pieces.size() == 1)
+ key = pieces.last().mid(idx).toLower();
+ else
+ key = pieces.last().toLower();
+
+ int paragraphNr = NumParagraphs - 1;
+
+ if (key[0].digitValue() != -1) {
+ paragraphNr = key[0].digitValue();
+ }
+ else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) {
+ paragraphNr = 10 + key[0].unicode() - 'a';
+ }
+
+ paragraphName[paragraphNr] = key[0].toUpper();
+ usedParagraphNames.insert(key[0].toLower().cell());
+ paragraph[paragraphNr].insert(key, c.value());
+ ++c;
+ }
+
+ /*
+ Each paragraph j has a size: paragraph[j].count(). In the
+ discussion, we will assume paragraphs 0 to 5 will have sizes
+ 3, 1, 4, 1, 5, 9.
+
+ We now want to compute the paragraph offset. Paragraphs 0 to 6
+ start at offsets 0, 3, 4, 8, 9, 14, 23.
+ */
+ int paragraphOffset[NumParagraphs + 1]; // 37 + 1
+ paragraphOffset[0] = 0;
+ for (int i=0; i<NumParagraphs; i++) // i = 0..36
+ paragraphOffset[i+1] = paragraphOffset[i] + paragraph[i].count();
+
+ int curParNr = 0;
+ int curParOffset = 0;
+ QMap<QChar,QString> cmap;
+
+ /*
+ Output the alphabet as a row of links.
+ */
+ if (includeAlphabet) {
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","alphabet");
+ for (int i = 0; i < 26; i++) {
+ QChar ch('a' + i);
+ if (usedParagraphNames.contains(char('a' + i))) {
+ writeStartTag(DT_xref);
+ // formathtml
+ QString guid = lookupGuid(outFileName(),QString(ch));
+ QString attr = outFileName() + QString("#%1").arg(guid);
+ xmlWriter().writeAttribute("href", attr);
+ xmlWriter().writeCharacters(QString(ch.toUpper()));
+ writeEndTag(); // </xref>
+ }
+ }
+ writeEndTag(); // </p>
+ }
+
+ /*
+ Output a <p> element to contain all the <dl> elements.
+ */
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","compactlist");
+
+ for (int i=0; i<classMap.count()-1; i++) {
+ while ((curParNr < NumParagraphs) &&
+ (curParOffset == paragraph[curParNr].count())) {
+ ++curParNr;
+ curParOffset = 0;
+ }
+
+ /*
+ Starting a new paragraph means starting a new <dl>.
+ */
+ if (curParOffset == 0) {
+ if (i > 0) {
+ writeEndTag(); // </dlentry>
+ writeEndTag(); // </dl>
+ }
+ writeStartTag(DT_dl);
+ writeStartTag(DT_dlentry);
+ writeStartTag(DT_dt);
+ if (includeAlphabet) {
+ QChar c = paragraphName[curParNr][0].toLower();
+ writeGuidAttribute(QString(c));
+ }
+ xmlWriter().writeAttribute("outputclass","sublist-header");
+ xmlWriter().writeCharacters(paragraphName[curParNr]);
+ writeEndTag(); // </dt>
+ }
+
+ /*
+ Output a <dd> for the current offset in the current paragraph.
+ */
+ writeStartTag(DT_dd);
+ if ((curParNr < NumParagraphs) &&
+ !paragraphName[curParNr].isEmpty()) {
+ NodeMap::Iterator it;
+ it = paragraph[curParNr].begin();
+ for (int i=0; i<curParOffset; i++)
+ ++it;
+
+ /*
+ Previously, we used generateFullName() for this, but we
+ require some special formatting.
+ */
+ writeStartTag(DT_xref);
+ // formathtml
+ writeHrefAttribute(linkForNode(it.value(), relative));
+
+ QStringList pieces;
+ if (it.value()->subType() == Node::QmlClass)
+ pieces << it.value()->name();
+ else
+ pieces = fullName(it.value(), relative, marker).split("::");
+ xmlWriter().writeCharacters(protectEnc(pieces.last()));
+ writeEndTag(); // </xref>
+ if (pieces.size() > 1) {
+ xmlWriter().writeCharacters(" (");
+ generateFullName(it.value()->parent(),relative,marker);
+ xmlWriter().writeCharacters(")");
+ }
+ }
+ writeEndTag(); // </dd>
+ curParOffset++;
+ }
+ writeEndTag(); // </dlentry>
+ writeEndTag(); // </dl>
+ writeEndTag(); // </p>
+}
+
+/*!
+ Write XML for a function index to the current XML stream.
+ */
+void DitaXmlGenerator::generateFunctionIndex(const Node* relative,
+ CodeMarker* marker)
+{
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","alphabet");
+ for (int i = 0; i < 26; i++) {
+ QChar ch('a' + i);
+ writeStartTag(DT_xref);
+ // formathtml
+ QString guid = lookupGuid(outFileName(),QString(ch));
+ QString attr = outFileName() + QString("#%1").arg(guid);
+ xmlWriter().writeAttribute("href", attr);
+ xmlWriter().writeCharacters(QString(ch.toUpper()));
+ writeEndTag(); // </xref>
+
+ }
+ writeEndTag(); // </p>
+
+ char nextLetter = 'a';
+ char currentLetter;
+
+ writeStartTag(DT_ul);
+ QMap<QString, NodeMap >::ConstIterator f = funcIndex.begin();
+ while (f != funcIndex.end()) {
+ writeStartTag(DT_li);
+ currentLetter = f.key()[0].unicode();
+ while (islower(currentLetter) && currentLetter >= nextLetter) {
+ writeStartTag(DT_p);
+ writeGuidAttribute(QString(nextLetter));
+ xmlWriter().writeAttribute("outputclass","target");
+ xmlWriter().writeCharacters(QString(nextLetter));
+ writeEndTag(); // </p>
+ nextLetter++;
+ }
+ xmlWriter().writeCharacters(protectEnc(f.key()));
+ xmlWriter().writeCharacters(":");
+
+ NodeMap::ConstIterator s = (*f).begin();
+ while (s != (*f).end()) {
+ generateFullName((*s)->parent(), relative, marker, *s);
+ ++s;
+ }
+ writeEndTag(); // </li>
+ ++f;
+ }
+ writeEndTag(); // </ul>
+}
+
+/*!
+ Write the legalese texts as XML to the current XML stream.
+ */
+void DitaXmlGenerator::generateLegaleseList(const Node* relative,
+ CodeMarker* marker)
+{
+ QMap<Text, const Node*>::ConstIterator it = legaleseTexts.begin();
+ while (it != legaleseTexts.end()) {
+ Text text = it.key();
+ generateText(text, relative, marker);
+ writeStartTag(DT_ul);
+ do {
+ writeStartTag(DT_li);
+ generateFullName(it.value(), relative, marker);
+ writeEndTag(); // </li>
+ ++it;
+ } while (it != legaleseTexts.end() && it.key() == text);
+ writeEndTag(); //</ul>
+ }
+}
+
+/*!
+ Generate the text for the QML item described by \a node
+ and write it to the current XML stream.
+ */
+void DitaXmlGenerator::generateQmlItem(const Node* node,
+ const Node* relative,
+ CodeMarker* marker,
+ bool summary)
+{
+ QString marked = marker->markedUpQmlItem(node,summary);
+ QRegExp tag("(<[^@>]*>)");
+ if (marked.indexOf(tag) != -1) {
+ QString tmp = protectEnc(marked.mid(tag.pos(1), tag.cap(1).length()));
+ marked.replace(tag.pos(1), tag.cap(1).length(), tmp);
+ }
+ marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"),
+ "<i>\\1<sub>\\2</sub></i>");
+ marked.replace("<@param>", "<i>");
+ marked.replace("</@param>", "</i>");
+
+ marked.replace("<@extra>", "<tt>");
+ marked.replace("</@extra>", "</tt>");
+
+ if (summary) {
+ marked.remove("<@type>");
+ marked.remove("</@type>");
+ }
+ writeText(marked, marker, relative);
+}
+
+/*!
+ Write the XML for the overview list to the current XML stream.
+ */
+void DitaXmlGenerator::generateOverviewList(const Node* relative, CodeMarker* /* marker */)
+{
+ QMap<const FakeNode*, QMap<QString, FakeNode*> > fakeNodeMap;
+ QMap<QString, const FakeNode*> groupTitlesMap;
+ QMap<QString, FakeNode*> uncategorizedNodeMap;
+ QRegExp singleDigit("\\b([0-9])\\b");
+
+ const NodeList children = tree_->root()->childNodes();
+ foreach (Node* child, children) {
+ if (child->type() == Node::Fake && child != relative) {
+ FakeNode* fakeNode = static_cast<FakeNode*>(child);
+
+ // Check whether the page is part of a group or is the group
+ // definition page.
+ QString group;
+ bool isGroupPage = false;
+ if (fakeNode->doc().metaCommandsUsed().contains("group")) {
+ group = fakeNode->doc().metaCommandArgs("group")[0];
+ isGroupPage = true;
+ }
+
+ // there are too many examples; they would clutter the list
+ if (fakeNode->subType() == Node::Example)
+ continue;
+
+ // not interested either in individual (Qt Designer etc.) manual chapters
+ if (fakeNode->links().contains(Node::ContentsLink))
+ continue;
+
+ // Discard external nodes.
+ if (fakeNode->subType() == Node::ExternalPage)
+ continue;
+
+ QString sortKey = fakeNode->fullTitle().toLower();
+ if (sortKey.startsWith("the "))
+ sortKey.remove(0, 4);
+ sortKey.replace(singleDigit, "0\\1");
+
+ if (!group.isEmpty()) {
+ if (isGroupPage) {
+ // If we encounter a group definition page, we add all
+ // the pages in that group to the list for that group.
+ foreach (Node* member, fakeNode->groupMembers()) {
+ if (member->type() != Node::Fake)
+ continue;
+ FakeNode* page = static_cast<FakeNode*>(member);
+ if (page) {
+ QString sortKey = page->fullTitle().toLower();
+ if (sortKey.startsWith("the "))
+ sortKey.remove(0, 4);
+ sortKey.replace(singleDigit, "0\\1");
+ fakeNodeMap[const_cast<const FakeNode*>(fakeNode)].insert(sortKey, page);
+ groupTitlesMap[fakeNode->fullTitle()] = const_cast<const FakeNode*>(fakeNode);
+ }
+ }
+ }
+ else if (!isGroupPage) {
+ // If we encounter a page that belongs to a group then
+ // we add that page to the list for that group.
+ const FakeNode* groupNode =
+ static_cast<const FakeNode*>(tree_->root()->findNode(group, Node::Fake));
+ if (groupNode)
+ fakeNodeMap[groupNode].insert(sortKey, fakeNode);
+ //else
+ // uncategorizedNodeMap.insert(sortKey, fakeNode);
+ }// else
+ // uncategorizedNodeMap.insert(sortKey, fakeNode);
+ }// else
+ // uncategorizedNodeMap.insert(sortKey, fakeNode);
+ }
+ }
+
+ // We now list all the pages found that belong to groups.
+ // If only certain pages were found for a group, but the definition page
+ // for that group wasn't listed, the list of pages will be intentionally
+ // incomplete. However, if the group definition page was listed, all the
+ // pages in that group are listed for completeness.
+
+ if (!fakeNodeMap.isEmpty()) {
+ foreach (const QString& groupTitle, groupTitlesMap.keys()) {
+ const FakeNode* groupNode = groupTitlesMap[groupTitle];
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","h3");
+ writeStartTag(DT_xref);
+ // formathtml
+ xmlWriter().writeAttribute("href",linkForNode(groupNode, relative));
+ writeCharacters(protectEnc(groupNode->fullTitle()));
+ writeEndTag(); // </xref>
+ writeEndTag(); // </p>
+ if (fakeNodeMap[groupNode].count() == 0)
+ continue;
+
+ writeStartTag(DT_ul);
+ foreach (const FakeNode* fakeNode, fakeNodeMap[groupNode]) {
+ QString title = fakeNode->fullTitle();
+ if (title.startsWith("The "))
+ title.remove(0, 4);
+ writeStartTag(DT_li);
+ writeStartTag(DT_xref);
+ // formathtml
+ xmlWriter().writeAttribute("href",linkForNode(fakeNode, relative));
+ writeCharacters(protectEnc(title));
+ writeEndTag(); // </xref>
+ writeEndTag(); // </li>
+ }
+ writeEndTag(); // </ul>
+ }
+ }
+
+ if (!uncategorizedNodeMap.isEmpty()) {
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","h3");
+ xmlWriter().writeCharacters("Miscellaneous");
+ writeEndTag(); // </p>
+ writeStartTag(DT_ul);
+ foreach (const FakeNode *fakeNode, uncategorizedNodeMap) {
+ QString title = fakeNode->fullTitle();
+ if (title.startsWith("The "))
+ title.remove(0, 4);
+ writeStartTag(DT_li);
+ writeStartTag(DT_xref);
+ // formathtml
+ xmlWriter().writeAttribute("href",linkForNode(fakeNode, relative));
+ writeCharacters(protectEnc(title));
+ writeEndTag(); // </xref>
+ writeEndTag(); // </li>
+ }
+ writeEndTag(); // </ul>
+ }
+}
+
+/*!
+ Write the XML for a standard section of a page, e.g.
+ "Public Functions" or "Protected Slots." The section
+ is written too the current XML stream as a table.
+ */
+void DitaXmlGenerator::generateSection(const NodeList& nl,
+ const Node* relative,
+ CodeMarker* marker,
+ CodeMarker::SynopsisStyle style)
+{
+ if (!nl.isEmpty()) {
+ writeStartTag(DT_ul);
+ NodeList::ConstIterator m = nl.begin();
+ while (m != nl.end()) {
+ if ((*m)->access() != Node::Private) {
+ writeStartTag(DT_li);
+ QString marked = getMarkedUpSynopsis(*m, relative, marker, style);
+ writeText(marked, marker, relative);
+ writeEndTag(); // </li>
+ }
+ ++m;
+ }
+ writeEndTag(); // </ul>
+ }
+}
+
+/*!
+ Writes the "inherited from" list to the current XML stream.
+ */
+void DitaXmlGenerator::generateSectionInheritedList(const Section& section,
+ const Node* relative,
+ CodeMarker* marker)
+{
+ if (section.inherited.isEmpty())
+ return;
+ writeStartTag(DT_ul);
+ QList<QPair<InnerNode*,int> >::ConstIterator p = section.inherited.begin();
+ while (p != section.inherited.end()) {
+ writeStartTag(DT_li);
+ QString text;
+ text.setNum((*p).second);
+ text += QLatin1Char(' ');
+ if ((*p).second == 1)
+ text += section.singularMember;
+ else
+ text += section.pluralMember;
+ text += " inherited from ";
+ writeCharacters(text);
+ writeStartTag(DT_xref);
+ // formathtml
+ // zzz
+ text = fileName((*p).first) + QLatin1Char('#');
+ text += DitaXmlGenerator::cleanRef(section.name.toLower());
+ xmlWriter().writeAttribute("href",text);
+ text = protectEnc(marker->plainFullName((*p).first, relative));
+ writeCharacters(text);
+ writeEndTag(); // </xref>
+ writeEndTag(); // </li>
+ ++p;
+ }
+ writeEndTag(); // </ul>
+}
+
+/*!
+ Get the synopsis from the \a node using the \a relative
+ node if needed, and mark up the synopsis using \a marker.
+ Use the style to decide which kind of sysnopsis to build,
+ normally \c Summary or \c Detailed. Return the marked up
+ string.
+ */
+QString DitaXmlGenerator::getMarkedUpSynopsis(const Node* node,
+ const Node* relative,
+ CodeMarker* marker,
+ CodeMarker::SynopsisStyle style)
+{
+ QString marked = marker->markedUpSynopsis(node, relative, style);
+ QRegExp tag("(<[^@>]*>)");
+ if (marked.indexOf(tag) != -1) {
+ QString tmp = protectEnc(marked.mid(tag.pos(1), tag.cap(1).length()));
+ marked.replace(tag.pos(1), tag.cap(1).length(), tmp);
+ }
+ marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"),
+ "<i> \\1<sub>\\2</sub></i>");
+#if 0
+ marked.replace("<@param>","<i>");
+ marked.replace("</@param>","</i>");
+#endif
+ if (style == CodeMarker::Summary) {
+ marked.remove("<@name>"); // was "<b>"
+ marked.remove("</@name>"); // was "</b>"
+ }
+
+ if (style == CodeMarker::Subpage) {
+ QRegExp extraRegExp("<@extra>.*</@extra>");
+ extraRegExp.setMinimal(true);
+ marked.remove(extraRegExp);
+ }
+#if 0
+ else {
+ marked.replace("<@extra>","<tt>");
+ marked.replace("</@extra>","</tt>");
+ }
+#endif
+
+ if (style != CodeMarker::Detailed) {
+ marked.remove("<@type>");
+ marked.remove("</@type>");
+ }
+ return marked;
+}
+
+/*!
+ Renamed from highlightedCode() in the html generator. Writes
+ the \a markedCode to the current XML stream.
+ */
+void DitaXmlGenerator::writeText(const QString& markedCode,
+ CodeMarker* marker,
+ const Node* relative)
+{
+ QString src = markedCode;
+ QString html;
+ QStringRef arg;
+ QStringRef par1;
+
+ const QChar charLangle = '<';
+ const QChar charAt = '@';
+
+ /*
+ First strip out all the extraneous markup. The table
+ below contains the markup we want to keep. Everything
+ else that begins with "<@" or "</@" is stripped out.
+ */
+ static const QString spanTags[] = {
+ "<@link ", "<@link ",
+ "<@type>", "<@type>",
+ "<@headerfile>", "<@headerfile>",
+ "<@func>", "<@func>",
+ "<@func ", "<@func ",
+ "<@param>", "<@param>",
+ "<@extra>", "<@extra>",
+ "</@link>", "</@link>",
+ "</@type>", "</@type>",
+ "</@headerfile>", "</@headerfile>",
+ "</@func>", "</@func>",
+ "</@param>", "</@param>",
+ "</@extra>", "</@extra>"
+ };
+ for (int i = 0, n = src.size(); i < n;) {
+ if (src.at(i) == charLangle) {
+ bool handled = false;
+ for (int k = 0; k != 13; ++k) {
+ const QString & tag = spanTags[2 * k];
+ if (tag == QStringRef(&src, i, tag.length())) {
+ html += spanTags[2 * k + 1];
+ i += tag.length();
+ handled = true;
+ break;
+ }
+ }
+ if (!handled) {
+ ++i;
+ if (src.at(i) == charAt ||
+ (src.at(i) == QLatin1Char('/') && src.at(i + 1) == charAt)) {
+ // drop 'our' unknown tags (the ones still containing '@')
+ while (i < n && src.at(i) != QLatin1Char('>'))
+ ++i;
+ ++i;
+ }
+ else {
+ // retain all others
+ html += charLangle;
+ }
+ }
+ }
+ else {
+ html += src.at(i);
+ ++i;
+ }
+ }
+
+ // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(</@link>)"
+ // replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
+ src = html;
+ html = QString();
+ static const QString markTags[] = {
+ // 0 1 2 3 4 5
+ "link", "type", "headerfile", "func", "param", "extra"
+ };
+
+ for (int i = 0, n = src.size(); i < n;) {
+ if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
+ i += 2;
+ for (int k = 0; k != 6; ++k) {
+ if (parseArg(src, markTags[k], &i, n, &arg, &par1)) {
+ const Node* n = 0;
+ if (k == 0) { // <@link>
+ if (!html.isEmpty()) {
+ writeCharacters(html);
+ html.clear();
+ }
+ n = CodeMarker::nodeForString(par1.toString());
+ QString link = linkForNode(n, relative);
+ addLink(link, arg);
+ }
+ else if (k == 4) { // <@param>
+ if (!html.isEmpty()) {
+ writeCharacters(html);
+ html.clear();
+ }
+ writeStartTag(DT_i);
+ writeCharacters(" " + arg.toString());
+ writeEndTag(); // </i>
+ }
+ else if (k == 5) { // <@extra>
+ if (!html.isEmpty()) {
+ writeCharacters(html);
+ html.clear();
+ }
+ writeStartTag(DT_tt);
+ writeCharacters(arg.toString());
+ writeEndTag(); // </tt>
+ }
+ else {
+ if (!html.isEmpty()) {
+ writeCharacters(html);
+ html.clear();
+ }
+ par1 = QStringRef();
+ QString link;
+ n = marker->resolveTarget(arg.toString(), tree_, relative);
+ if (n && n->subType() == Node::QmlBasicType) {
+ if (relative && relative->subType() == Node::QmlClass) {
+ link = linkForNode(n,relative);
+ addLink(link, arg);
+ }
+ else {
+ writeCharacters(arg.toString());
+ }
+ }
+ else {
+ // (zzz) Is this correct for all cases?
+ link = linkForNode(n,relative);
+ addLink(link, arg);
+ }
+ }
+ break;
+ }
+ }
+ }
+ else {
+ html += src.at(i++);
+ }
+ }
+
+ if (!html.isEmpty()) {
+ writeCharacters(html);
+ }
+}
+
+void DitaXmlGenerator::generateLink(const Atom* atom,
+ const Node* /* relative */,
+ CodeMarker* marker)
+{
+ static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_");
+
+ if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) {
+ // hack for C++: move () outside of link
+ int k = funcLeftParen.pos(1);
+ writeCharacters(protectEnc(atom->string().left(k)));
+ if (link.isEmpty()) {
+ if (showBrokenLinks)
+ writeEndTag(); // </i>
+ }
+ else
+ writeEndTag(); // </xref>
+ inLink = false;
+ writeCharacters(protectEnc(atom->string().mid(k)));
+ }
+ else if (marker->recognizeLanguage("Java")) {
+ // hack for Java: remove () and use <tt> when appropriate
+ bool func = atom->string().endsWith("()");
+ bool tt = (func || atom->string().contains(camelCase));
+ if (tt)
+ writeStartTag(DT_tt);
+ if (func)
+ writeCharacters(protectEnc(atom->string().left(atom->string().length() - 2)));
+ else
+ writeCharacters(protectEnc(atom->string()));
+ writeEndTag(); // </tt>
+ }
+ else
+ writeCharacters(protectEnc(atom->string()));
+}
+
+QString DitaXmlGenerator::cleanRef(const QString& ref)
+{
+ QString clean;
+
+ if (ref.isEmpty())
+ return clean;
+
+ clean.reserve(ref.size() + 20);
+ const QChar c = ref[0];
+ const uint u = c.unicode();
+
+ if ((u >= 'a' && u <= 'z') ||
+ (u >= 'A' && u <= 'Z') ||
+ (u >= '0' && u <= '9')) {
+ clean += c;
+ }
+ else if (u == '~') {
+ clean += "dtor.";
+ }
+ else if (u == '_') {
+ clean += "underscore.";
+ }
+ else {
+ clean += QLatin1Char('A');
+ }
+
+ for (int i = 1; i < (int) ref.length(); i++) {
+ const QChar c = ref[i];
+ const uint u = c.unicode();
+ if ((u >= 'a' && u <= 'z') ||
+ (u >= 'A' && u <= 'Z') ||
+ (u >= '0' && u <= '9') || u == '-' ||
+ u == '_' || u == ':' || u == '.') {
+ clean += c;
+ }
+ else if (c.isSpace()) {
+ clean += QLatin1Char('-');
+ }
+ else if (u == '!') {
+ clean += "-not";
+ }
+ else if (u == '&') {
+ clean += "-and";
+ }
+ else if (u == '<') {
+ clean += "-lt";
+ }
+ else if (u == '=') {
+ clean += "-eq";
+ }
+ else if (u == '>') {
+ clean += "-gt";
+ }
+ else if (u == '#') {
+ clean += QLatin1Char('#');
+ }
+ else {
+ clean += QLatin1Char('-');
+ clean += QString::number((int)u, 16);
+ }
+ }
+ return clean;
+}
+
+QString DitaXmlGenerator::registerRef(const QString& ref)
+{
+ QString clean = DitaXmlGenerator::cleanRef(ref);
+
+ for (;;) {
+ QString& prevRef = refMap[clean.toLower()];
+ if (prevRef.isEmpty()) {
+ prevRef = ref;
+ break;
+ }
+ else if (prevRef == ref)
+ break;
+ clean += QLatin1Char('x');
+ }
+ return clean;
+}
+
+/*!
+ Calls protect() with the \a string. Returns the result.
+ */
+QString DitaXmlGenerator::protectEnc(const QString& string)
+{
+ return protect(string, outputEncoding);
+}
+
+QString DitaXmlGenerator::protect(const QString& string, const QString& ) //outputEncoding)
+{
+#define APPEND(x) \
+ if (xml.isEmpty()) { \
+ xml = string; \
+ xml.truncate(i); \
+} \
+ xml += (x);
+
+ QString xml;
+ int n = string.length();
+
+ for (int i = 0; i < n; ++i) {
+ QChar ch = string.at(i);
+
+ if (ch == QLatin1Char('&')) {
+ APPEND("&amp;");
+ }
+ else if (ch == QLatin1Char('<')) {
+ APPEND("&lt;");
+ }
+ else if (ch == QLatin1Char('>')) {
+ APPEND("&gt;");
+ }
+ else if (ch == QLatin1Char('"')) {
+ APPEND("&quot;");
+ }
+#if 0
+ else if ((outputEncoding == "ISO-8859-1" && ch.unicode() > 0x007F) ||
+ (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) ||
+ (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) {
+ // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator
+ APPEND("&#x");
+ xml += QString::number(ch.unicode(), 16);
+ xml += QLatin1Char(';');
+ }
+#endif
+ else {
+ if (!xml.isEmpty())
+ xml += ch;
+ }
+ }
+
+ if (!xml.isEmpty())
+ return xml;
+ return string;
+
+#undef APPEND
+}
+
+/*!
+ Constructs a file name appropriate for the \a node
+ and returns the file name.
+ */
+QString DitaXmlGenerator::fileBase(const Node* node) const
+{
+ QString result;
+ result = PageGenerator::fileBase(node);
+#if 0
+ if (!node->isInnerNode()) {
+ switch (node->status()) {
+ case Node::Compat:
+ result += "-qt3";
+ break;
+ case Node::Obsolete:
+ result += "-obsolete";
+ break;
+ default:
+ ;
+ }
+ }
+#endif
+ return result;
+}
+
+QString DitaXmlGenerator::guidForNode(const Node* node)
+{
+ switch (node->type()) {
+ case Node::Namespace:
+ case Node::Class:
+ default:
+ break;
+ case Node::Enum:
+ return node->guid();
+ case Node::Typedef:
+ {
+ const TypedefNode* tdn = static_cast<const TypedefNode*>(node);
+ if (tdn->associatedEnum())
+ return guidForNode(tdn->associatedEnum());
+ }
+ return node->guid();
+ case Node::Function:
+ {
+ const FunctionNode* fn = static_cast<const FunctionNode*>(node);
+ if (fn->associatedProperty()) {
+ return guidForNode(fn->associatedProperty());
+ }
+ else {
+ QString ref = fn->name();
+ if (fn->overloadNumber() != 1) {
+ ref += QLatin1Char('-') + QString::number(fn->overloadNumber());
+ }
+ }
+ return fn->guid();
+ }
+ case Node::Fake:
+ if (node->subType() != Node::QmlPropertyGroup)
+ break;
+ case Node::QmlProperty:
+ case Node::Property:
+ return node->guid();
+ case Node::QmlSignal:
+ return node->guid();
+ case Node::QmlSignalHandler:
+ return node->guid();
+ case Node::QmlMethod:
+ return node->guid();
+ case Node::Variable:
+ return node->guid();
+ case Node::Target:
+ return node->guid();
+ }
+ return QString();
+}
+
+/*!
+ Constructs a file name appropriate for the \a node and returns
+ it. If the \a node is not a fake node, or if it is a fake node but
+ it is neither an external page node nor an image node, call the
+ PageGenerator::fileName() function.
+ */
+QString DitaXmlGenerator::fileName(const Node* node)
+{
+ if (node->type() == Node::Fake) {
+ if (static_cast<const FakeNode*>(node)->subType() == Node::ExternalPage)
+ return node->name();
+ if (static_cast<const FakeNode*>(node)->subType() == Node::Image)
+ return node->name();
+ }
+ return PageGenerator::fileName(node);
+}
+
+QString DitaXmlGenerator::linkForNode(const Node* node, const Node* relative)
+{
+ if (node == 0 || node == relative)
+ return QString();
+ if (!node->url().isEmpty())
+ return node->url();
+ if (fileBase(node).isEmpty())
+ return QString();
+ if (node->access() == Node::Private)
+ return QString();
+
+ QString fn = fileName(node);
+ if (node && relative && node->parent() != relative) {
+ if (node->parent()->subType() == Node::QmlClass && relative->subType() == Node::QmlClass) {
+ if (node->parent()->isAbstract()) {
+ /*
+ This is a bit of a hack. What we discover with
+ the three 'if' statements immediately above,
+ is that node's parent is marked \qmlabstract
+ but the link appears in a qdoc comment for a
+ subclass of the node's parent. This means the
+ link should refer to the file for the relative
+ node, not the file for node.
+ */
+ fn = fileName(relative);
+#if DEBUG_ABSTRACT
+ qDebug() << "ABSTRACT:" << node->parent()->name()
+ << node->name() << relative->name()
+ << node->parent()->type() << node->parent()->subType()
+ << relative->type() << relative->subType() << outFileName();
+#endif
+ }
+ }
+ }
+ QString link = fn;
+
+ if (!node->isInnerNode() || node->subType() == Node::QmlPropertyGroup) {
+ QString guid = guidForNode(node);
+ if (relative && fn == fileName(relative) && guid == guidForNode(relative)) {
+ return QString();
+ }
+ link += QLatin1Char('#');
+ link += guid;
+ }
+ /*
+ If the output is going to subdirectories, then if the
+ two nodes will be output to different directories, then
+ the link must go up to the parent directory and then
+ back down into the other subdirectory.
+ */
+ if (node && relative && (node != relative)) {
+ if (node->outputSubdirectory() != relative->outputSubdirectory())
+ link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/')));
+ }
+ return link;
+}
+
+QString DitaXmlGenerator::refForAtom(Atom* atom, const Node* /* node */)
+{
+ if (atom->type() == Atom::SectionLeft)
+ return Doc::canonicalTitle(Text::sectionHeading(atom).toString());
+ if (atom->type() == Atom::Target)
+ return Doc::canonicalTitle(atom->string());
+ return QString();
+}
+
+void DitaXmlGenerator::generateFullName(const Node* apparentNode,
+ const Node* relative,
+ CodeMarker* marker,
+ const Node* actualNode)
+{
+ if (actualNode == 0)
+ actualNode = apparentNode;
+ writeStartTag(DT_xref);
+ // formathtml
+ QString href = linkForNode(actualNode, relative);
+ writeHrefAttribute(href);
+ writeCharacters(protectEnc(fullName(apparentNode, relative, marker)));
+ writeEndTag(); // </xref>
+}
+
+void DitaXmlGenerator::findAllClasses(const InnerNode* node)
+{
+ NodeList::const_iterator c = node->childNodes().constBegin();
+ while (c != node->childNodes().constEnd()) {
+ if ((*c)->access() != Node::Private && (*c)->url().isEmpty()) {
+ if ((*c)->type() == Node::Class && !(*c)->doc().isEmpty()) {
+ QString className = (*c)->name();
+ if ((*c)->parent() &&
+ (*c)->parent()->type() == Node::Namespace &&
+ !(*c)->parent()->name().isEmpty())
+ className = (*c)->parent()->name()+"::"+className;
+
+ if (!(static_cast<const ClassNode *>(*c))->hideFromMainList()) {
+ if ((*c)->status() == Node::Compat) {
+ compatClasses.insert(className, *c);
+ }
+ else if ((*c)->status() == Node::Obsolete) {
+ obsoleteClasses.insert(className, *c);
+ }
+ else {
+ nonCompatClasses.insert(className, *c);
+ if ((*c)->status() == Node::Main)
+ mainClasses.insert(className, *c);
+ }
+ }
+
+ QString moduleName = (*c)->moduleName();
+ if (moduleName == "Qt3SupportLight") {
+ moduleClassMap[moduleName].insert((*c)->name(), *c);
+ moduleName = "Qt3Support";
+ }
+ if (!moduleName.isEmpty())
+ moduleClassMap[moduleName].insert((*c)->name(), *c);
+
+ QString serviceName =
+ (static_cast<const ClassNode *>(*c))->serviceName();
+ if (!serviceName.isEmpty())
+ serviceClasses.insert(serviceName, *c);
+ }
+ else if ((*c)->type() == Node::Fake &&
+ (*c)->subType() == Node::QmlClass &&
+ !(*c)->doc().isEmpty()) {
+ QString qmlClassName = (*c)->name();
+ qmlClasses.insert(qmlClassName,*c);
+ }
+ else if ((*c)->isInnerNode()) {
+ findAllClasses(static_cast<InnerNode *>(*c));
+ }
+ }
+ ++c;
+ }
+}
+
+void DitaXmlGenerator::findAllFunctions(const InnerNode* node)
+{
+ NodeList::ConstIterator c = node->childNodes().begin();
+ while (c != node->childNodes().end()) {
+ if ((*c)->access() != Node::Private) {
+ if ((*c)->isInnerNode() && (*c)->url().isEmpty()) {
+ findAllFunctions(static_cast<const InnerNode*>(*c));
+ }
+ else if ((*c)->type() == Node::Function) {
+ const FunctionNode* func = static_cast<const FunctionNode*>(*c);
+ if ((func->status() > Node::Obsolete) &&
+ !func->isInternal() &&
+ (func->metaness() != FunctionNode::Ctor) &&
+ (func->metaness() != FunctionNode::Dtor)) {
+ funcIndex[(*c)->name()].insert((*c)->parent()->fullDocumentName(), *c);
+ }
+ }
+ }
+ ++c;
+ }
+}
+
+void DitaXmlGenerator::findAllLegaleseTexts(const InnerNode* node)
+{
+ NodeList::ConstIterator c = node->childNodes().begin();
+ while (c != node->childNodes().end()) {
+ if ((*c)->access() != Node::Private) {
+ if (!(*c)->doc().legaleseText().isEmpty())
+ legaleseTexts.insertMulti((*c)->doc().legaleseText(), *c);
+ if ((*c)->isInnerNode())
+ findAllLegaleseTexts(static_cast<const InnerNode *>(*c));
+ }
+ ++c;
+ }
+}
+
+void DitaXmlGenerator::findAllNamespaces(const InnerNode* node)
+{
+ NodeList::ConstIterator c = node->childNodes().begin();
+ while (c != node->childNodes().end()) {
+ if ((*c)->access() != Node::Private) {
+ if ((*c)->isInnerNode() && (*c)->url().isEmpty()) {
+ findAllNamespaces(static_cast<const InnerNode *>(*c));
+ if ((*c)->type() == Node::Namespace) {
+ const NamespaceNode *nspace = static_cast<const NamespaceNode *>(*c);
+ // Ensure that the namespace's name is not empty (the root
+ // namespace has no name).
+ if (!nspace->name().isEmpty()) {
+ namespaceIndex.insert(nspace->name(), *c);
+ QString moduleName = (*c)->moduleName();
+ if (moduleName == "Qt3SupportLight") {
+ moduleNamespaceMap[moduleName].insert((*c)->name(), *c);
+ moduleName = "Qt3Support";
+ }
+ if (!moduleName.isEmpty())
+ moduleNamespaceMap[moduleName].insert((*c)->name(), *c);
+ }
+ }
+ }
+ }
+ ++c;
+ }
+}
+
+/*!
+ We're writing an attribute that indicates that the text
+ data is a heading, hence, h1, h2, h3... etc, and we must
+ decide which number to use.
+ */
+int DitaXmlGenerator::hOffset(const Node* node)
+{
+ switch (node->type()) {
+ case Node::Namespace:
+ case Node::Class:
+ return 2;
+ case Node::Fake:
+ return 1;
+ case Node::Enum:
+ case Node::Typedef:
+ case Node::Function:
+ case Node::Property:
+ default:
+ return 3;
+ }
+}
+
+bool DitaXmlGenerator::isThreeColumnEnumValueTable(const Atom* atom)
+{
+ while (atom != 0 && !(atom->type() == Atom::ListRight && atom->string() == ATOM_LIST_VALUE)) {
+ if (atom->type() == Atom::ListItemLeft && !matchAhead(atom, Atom::ListItemRight))
+ return true;
+ atom = atom->next();
+ }
+ return false;
+}
+
+const Node* DitaXmlGenerator::findNodeForTarget(const QString& target,
+ const Node* relative,
+ CodeMarker* marker,
+ const Atom* atom)
+{
+ const Node* node = 0;
+
+ if (target.isEmpty()) {
+ node = relative;
+ }
+ else if (target.endsWith(".html")) {
+ node = tree_->root()->findNode(target, Node::Fake);
+ }
+ else if (marker) {
+ node = marker->resolveTarget(target, tree_, relative);
+ if (!node)
+ node = tree_->findFakeNodeByTitle(target, relative);
+ if (!node && atom) {
+ node = tree_->findUnambiguousTarget(target, *const_cast<Atom**>(&atom), relative);
+ }
+ }
+
+ if (!node)
+ relative->doc().location().warning(tr("Cannot link to '%1'").arg(target));
+
+ return node;
+}
+
+const QPair<QString,QString> DitaXmlGenerator::anchorForNode(const Node* node)
+{
+ QPair<QString,QString> anchorPair;
+ anchorPair.first = PageGenerator::fileName(node);
+ if (node->type() == Node::Fake) {
+ const FakeNode *fakeNode = static_cast<const FakeNode*>(node);
+ anchorPair.second = fakeNode->title();
+ }
+
+ return anchorPair;
+}
+
+QString DitaXmlGenerator::getLink(const Atom* atom,
+ const Node* relative,
+ CodeMarker* marker,
+ const Node** node)
+{
+ QString link;
+ *node = 0;
+ inObsoleteLink = false;
+
+ if (atom->string().contains(QLatin1Char(':')) &&
+ (atom->string().startsWith("file:")
+ || atom->string().startsWith("http:")
+ || atom->string().startsWith("https:")
+ || atom->string().startsWith("ftp:")
+ || atom->string().startsWith("mailto:"))) {
+
+ link = atom->string();
+ }
+ else {
+ QStringList path;
+ if (atom->string().contains('#'))
+ path = atom->string().split('#');
+ else
+ path.append(atom->string());
+
+ Atom* targetAtom = 0;
+ QString first = path.first().trimmed();
+
+ if (first.isEmpty()) {
+ *node = relative;
+ }
+ else if (first.endsWith(".html")) {
+ *node = tree_->root()->findNode(first, Node::Fake);
+ }
+ else {
+ *node = marker->resolveTarget(first, tree_, relative);
+ if (!*node) {
+ *node = tree_->findFakeNodeByTitle(first, relative);
+ }
+ if (!*node) {
+ *node = tree_->findUnambiguousTarget(first, targetAtom, relative);
+ }
+ }
+
+ if (*node) {
+ if (!(*node)->url().isEmpty()) {
+ return (*node)->url();
+ }
+ else {
+ path.removeFirst();
+ }
+ }
+ else {
+ *node = relative;
+ }
+
+ if (*node && (*node)->status() == Node::Obsolete) {
+ if (relative && (relative->parent() != *node) &&
+ (relative->status() != Node::Obsolete)) {
+ bool porting = false;
+ if (relative->type() == Node::Fake) {
+ const FakeNode* fake = static_cast<const FakeNode*>(relative);
+ if (fake->title().startsWith("Porting"))
+ porting = true;
+ }
+ QString name = marker->plainFullName(relative);
+ if (!porting && !name.startsWith("Q3")) {
+ if (obsoleteLinks) {
+ relative->doc().location().warning(tr("Link to obsolete item '%1' in %2")
+ .arg(atom->string())
+ .arg(name));
+ }
+ inObsoleteLink = true;
+ }
+ }
+ }
+
+ while (!path.isEmpty()) {
+ targetAtom = tree_->findTarget(path.first(), *node);
+ if (targetAtom == 0)
+ break;
+ path.removeFirst();
+ }
+
+ if (path.isEmpty()) {
+ link = linkForNode(*node, relative);
+ if (*node && (*node)->subType() == Node::Image)
+ link = "images/used-in-examples/" + link;
+ if (targetAtom) {
+ if (link.isEmpty())
+ link = outFileName();
+ QString guid = lookupGuid(link,refForAtom(targetAtom,*node));
+ link += QLatin1Char('#') + guid;
+ }
+ else if (!link.isEmpty() && *node && link.endsWith(".xml")) {
+ link += QLatin1Char('#') + (*node)->guid();
+ }
+ }
+ /*
+ If the output is going to subdirectories, then if the
+ two nodes will be output to different directories, then
+ the link must go up to the parent directory and then
+ back down into the other subdirectory.
+ */
+ if (link.startsWith("images/")) {
+ link.prepend(QString("../"));
+ }
+ else if (*node && relative && (*node != relative)) {
+ if ((*node)->outputSubdirectory() != relative->outputSubdirectory()) {
+ link.prepend(QString("../" + (*node)->outputSubdirectory() + QLatin1Char('/')));
+ }
+ }
+ }
+ if (!link.isEmpty() && link[0] == '#') {
+ link.prepend(outFileName());
+ qDebug() << "LOCAL LINK:" << link;
+ }
+ return link;
+}
+
+/*!
+ This function can be called if getLink() returns an empty
+ string.
+ */
+QString DitaXmlGenerator::getDisambiguationLink(const Atom *, CodeMarker *)
+{
+ qDebug() << "Unimplemented function called: "
+ << "QString DitaXmlGenerator::getDisambiguationLink()";
+ return QString();
+}
+
+void DitaXmlGenerator::generateIndex(const QString& fileBase,
+ const QString& url,
+ const QString& title)
+{
+ tree_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index", url, title);
+}
+
+void DitaXmlGenerator::generateStatus(const Node* node, CodeMarker* marker)
+{
+ Text text;
+
+ switch (node->status()) {
+ case Node::Obsolete:
+ if (node->isInnerNode())
+ Generator::generateStatus(node, marker);
+ break;
+ case Node::Compat:
+ if (node->isInnerNode()) {
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
+ << "This "
+ << typeString(node)
+ << " is part of the Qt 3 support library."
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
+ << " It is provided to keep old source code working. "
+ << "We strongly advise against "
+ << "using it in new code. See ";
+
+ const FakeNode *fakeNode = tree_->findFakeNodeByTitle("Porting To Qt 4");
+ Atom *targetAtom = 0;
+ if (fakeNode && node->type() == Node::Class) {
+ QString oldName(node->name());
+ oldName.remove(QLatin1Char('3'));
+ targetAtom = tree_->findTarget(oldName,fakeNode);
+ }
+
+ if (targetAtom) {
+ QString fn = fileName(fakeNode);
+ QString guid = lookupGuid(fn,refForAtom(targetAtom,fakeNode));
+ text << Atom(Atom::GuidLink, fn + QLatin1Char('#') + guid);
+ }
+ else
+ text << Atom(Atom::Link, "Porting to Qt 4");
+
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, "Porting to Qt 4")
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << " for more information."
+ << Atom::ParaRight;
+ }
+ generateText(text, node, marker);
+ break;
+ default:
+ Generator::generateStatus(node, marker);
+ }
+}
+
+void DitaXmlGenerator::beginLink(const QString& link)
+{
+ this->link = link;
+ if (link.isEmpty())
+ return;
+ writeStartTag(DT_xref);
+ // formathtml
+ writeHrefAttribute(link);
+ inLink = true;
+}
+
+void DitaXmlGenerator::endLink()
+{
+ if (inLink) {
+ if (link.isEmpty()) {
+ if (showBrokenLinks)
+ writeEndTag(); // </i>
+ }
+ else {
+ if (inObsoleteLink) {
+ writeStartTag(DT_sup);
+ xmlWriter().writeCharacters("(obsolete)");
+ writeEndTag(); // </sup>
+ }
+ writeEndTag(); // </xref>
+ }
+ }
+ inLink = false;
+ inObsoleteLink = false;
+}
+
+/*!
+ Generates the summary for the \a section. Only used for
+ sections of QML element documentation.
+
+ Currently handles only the QML property group.
+ */
+void DitaXmlGenerator::generateQmlSummary(const Section& section,
+ const Node* relative,
+ CodeMarker* marker)
+{
+ if (!section.members.isEmpty()) {
+ writeStartTag(DT_ul);
+ NodeList::ConstIterator m;
+ m = section.members.begin();
+ while (m != section.members.end()) {
+ writeStartTag(DT_li);
+ generateQmlItem(*m,relative,marker,true);
+ writeEndTag(); // </li>
+ ++m;
+ }
+ writeEndTag(); // </ul>
+ }
+}
+
+/*!
+ Outputs the DITA detailed documentation for a section
+ on a QML element reference page.
+ */
+void DitaXmlGenerator::generateDetailedQmlMember(const Node* node,
+ const InnerNode* relative,
+ CodeMarker* marker)
+{
+ QString marked;
+ const QmlPropertyNode* qpn = 0;
+ if (node->subType() == Node::QmlPropertyGroup) {
+ const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node);
+ NodeList::ConstIterator p = qpgn->childNodes().begin();
+ writeStartTag(DT_ul);
+ while (p != qpgn->childNodes().end()) {
+ if ((*p)->type() == Node::QmlProperty) {
+ qpn = static_cast<const QmlPropertyNode*>(*p);
+ writeStartTag(DT_li);
+ writeGuidAttribute((Node*)qpn);
+ QString attr;
+ int ro = qpn->getReadOnly();
+ if (ro < 0) {
+ if (!qpn->isWritable(tree_))
+ attr = "read-only";
+ }
+ else if (ro > 0)
+ attr = "read-only";
+ if (qpgn->isDefault()) {
+ if (!attr.isEmpty())
+ attr += QLatin1Char(' ');
+ attr += "default";
+ }
+ if (!attr.isEmpty())
+ xmlWriter().writeAttribute("outputclass",attr);
+ generateQmlItem(qpn, relative, marker, false);
+ writeEndTag(); // </li>
+ }
+ ++p;
+ }
+ writeEndTag(); // </ul>
+ }
+ else if (node->type() == Node::QmlProperty) {
+ qpn = static_cast<const QmlPropertyNode*>(node);
+ /*
+ If the QML property node has a single subproperty,
+ override, replace qpn with that override node and
+ proceed as normal.
+ */
+ if (qpn->qmlPropNodes().size() == 1) {
+ Node* n = qpn->qmlPropNodes().at(0);
+ if (n->type() == Node::QmlProperty)
+ qpn = static_cast<const QmlPropertyNode*>(n);
+ }
+ /*
+ Now qpn either has no overrides, or it has more
+ than 1. If it has none, proceed to output as nortmal.
+ */
+ if (qpn->qmlPropNodes().isEmpty()) {
+ writeStartTag(DT_ul);
+ writeStartTag(DT_li);
+ writeGuidAttribute((Node*)qpn);
+ QString attr;
+ int ro = qpn->getReadOnly();
+ if (ro < 0) {
+ const ClassNode* cn = qpn->declarativeCppNode();
+ if (cn && !qpn->isWritable(tree_))
+ attr = "read-only";
+ }
+ else if (ro > 0)
+ attr = "read-only";
+ if (qpn->isDefault()) {
+ if (!attr.isEmpty())
+ attr += QLatin1Char(' ');
+ attr += "default";
+ }
+ if (!attr.isEmpty())
+ xmlWriter().writeAttribute("outputclass",attr);
+ generateQmlItem(qpn, relative, marker, false);
+ writeEndTag(); // </li>
+ writeEndTag(); // </ul>
+ }
+ else {
+ /*
+ The QML property node has multiple override nodes.
+ Process the whole list as we would for a QML property
+ group.
+ */
+ NodeList::ConstIterator p = qpn->qmlPropNodes().begin();
+ writeStartTag(DT_ul);
+ while (p != qpn->qmlPropNodes().end()) {
+ if ((*p)->type() == Node::QmlProperty) {
+ QmlPropertyNode* q = static_cast<QmlPropertyNode*>(*p);
+ writeStartTag(DT_li);
+ writeGuidAttribute((Node*)q);
+ QString attr;
+ int ro = qpn->getReadOnly();
+ if (ro < 0) {
+ if (!qpn->isWritable(tree_))
+ attr = "read-only";
+ }
+ else if (ro > 0)
+ attr = "read-only";
+ if (qpn->isDefault()) {
+ if (!attr.isEmpty())
+ attr += QLatin1Char(' ');
+ attr += "default";
+ }
+ if (!attr.isEmpty())
+ xmlWriter().writeAttribute("outputclass",attr);
+ generateQmlItem(q, relative, marker, false);
+ writeEndTag(); // </li>
+ }
+ ++p;
+ }
+ writeEndTag(); // </ul>
+ }
+ }
+ else if (node->type() == Node::QmlSignal) {
+ Node* n = const_cast<Node*>(node);
+ writeStartTag(DT_ul);
+ writeStartTag(DT_li);
+ writeGuidAttribute(n);
+ marked = getMarkedUpSynopsis(n, relative, marker, CodeMarker::Detailed);
+ writeText(marked, marker, relative);
+ writeEndTag(); // </li>
+ writeEndTag(); // </ul>
+ }
+ else if (node->type() == Node::QmlSignalHandler) {
+ Node* n = const_cast<Node*>(node);
+ writeStartTag(DT_ul);
+ writeStartTag(DT_li);
+ writeGuidAttribute(n);
+ marked = getMarkedUpSynopsis(n, relative, marker, CodeMarker::Detailed);
+ writeText(marked, marker, relative);
+ writeEndTag(); // </li>
+ writeEndTag(); // </ul>
+ }
+ else if (node->type() == Node::QmlMethod) {
+ Node* n = const_cast<Node*>(node);
+ writeStartTag(DT_ul);
+ writeStartTag(DT_li);
+ writeGuidAttribute(n);
+ marked = getMarkedUpSynopsis(n, relative, marker, CodeMarker::Detailed);
+ writeText(marked, marker, relative);
+ writeEndTag(); // </li>
+ writeEndTag(); // </ul>
+ }
+ generateStatus(node, marker);
+ generateBody(node, marker);
+ generateThreadSafeness(node, marker);
+ generateSince(node, marker);
+ generateAlsoList(node, marker);
+}
+
+/*!
+ Output the "Inherits" line for the QML element,
+ if there should be one.
+ */
+void DitaXmlGenerator::generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker)
+{
+ if (!qcn)
+ return;
+ const FakeNode* base = qcn->qmlBase();
+ if (base) {
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","inherits");
+ Text text;
+ text << "[Inherits ";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(base));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, base->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << "]";
+ generateText(text, qcn, marker);
+ writeEndTag(); // </p>
+ }
+}
+
+/*!
+ Output the "Inherit by" list for the QML element,
+ if it is inherited by any other elements.
+ */
+void DitaXmlGenerator::generateQmlInheritedBy(const QmlClassNode* qcn,
+ CodeMarker* marker)
+{
+ if (qcn) {
+ NodeList subs;
+ QmlClassNode::subclasses(qcn->name(),subs);
+ if (!subs.isEmpty()) {
+ Text text;
+ text << Atom::ParaLeft << "Inherited by ";
+ appendSortedQmlNames(text,qcn,subs,marker);
+ text << Atom::ParaRight;
+ generateText(text, qcn, marker);
+ }
+ }
+}
+
+/*!
+ Output the "[Xxx instantiates the C++ class QmlGraphicsXxx]"
+ line for the QML element, if there should be one.
+
+ If there is no class node, or if the class node status
+ is set to Node::Internal, do nothing.
+ */
+void DitaXmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn,
+ CodeMarker* marker)
+{
+ const ClassNode* cn = qcn->classNode();
+ if (cn && (cn->status() != Node::Internal)) {
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","instantiates");
+ Text text;
+ text << "[";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, qcn->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << " instantiates the C++ class ";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, cn->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << "]";
+ generateText(text, qcn, marker);
+ writeEndTag(); // </p>
+ }
+}
+
+/*!
+ Output the "[QmlGraphicsXxx is instantiated by QML element Xxx]"
+ line for the class, if there should be one.
+
+ If there is no QML element, or if the class node status
+ is set to Node::Internal, do nothing.
+ */
+void DitaXmlGenerator::generateInstantiatedBy(const ClassNode* cn,
+ CodeMarker* marker)
+{
+ if (cn && cn->status() != Node::Internal && cn->qmlElement() != 0) {
+ const QmlClassNode* qcn = cn->qmlElement();
+ writeStartTag(DT_p);
+ xmlWriter().writeAttribute("outputclass","instantiated-by");
+ Text text;
+ text << "[";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, cn->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << " is instantiated by QML element ";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, qcn->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << "]";
+ generateText(text, cn, marker);
+ writeEndTag(); // </p>
+ }
+}
+
+/*!
+ Return the full qualification of the node \a n, but without
+ the name of \a n itself. e.g. A::B::C
+ */
+QString DitaXmlGenerator::fullQualification(const Node* n)
+{
+ QString fq;
+ InnerNode* in = n->parent();
+ while (in) {
+ if ((in->type() == Node::Class) ||
+ (in->type() == Node::Namespace)) {
+ if (in->name().isEmpty())
+ break;
+ if (fq.isEmpty())
+ fq = in->name();
+ else
+ fq = in->name() + "::" + fq;
+ }
+ else
+ break;
+ in = in->parent();
+ }
+ return fq;
+}
+
+/*!
+ Outputs the <cxxClassDerivations> element.
+ \code
+ <cxxClassDerivations>
+ <cxxClassDerivation>
+ ...
+ </cxxClassDerivation>
+ ...
+ </cxxClassDerivations>
+ \endcode
+
+ The <cxxClassDerivation> element is:
+
+ \code
+ <cxxClassDerivation>
+ <cxxClassDerivationAccessSpecifier value="public"/>
+ <cxxClassBaseClass href="class_base">Base</cxxClassBaseClass>
+ </cxxClassDerivation>
+ \endcode
+ */
+void DitaXmlGenerator::writeDerivations(const ClassNode* cn, CodeMarker* marker)
+{
+ QList<RelatedClass>::ConstIterator r;
+
+ if (!cn->baseClasses().isEmpty()) {
+ writeStartTag(DT_cxxClassDerivations);
+ r = cn->baseClasses().begin();
+ while (r != cn->baseClasses().end()) {
+ writeStartTag(DT_cxxClassDerivation);
+ writeStartTag(DT_cxxClassDerivationAccessSpecifier);
+ xmlWriter().writeAttribute("value",(*r).accessString());
+ writeEndTag(); // </cxxClassDerivationAccessSpecifier>
+
+ // not included: <cxxClassDerivationVirtual>
+
+ writeStartTag(DT_cxxClassBaseClass);
+ QString attr = fileName((*r).node) + QLatin1Char('#') + (*r).node->guid();
+ xmlWriter().writeAttribute("href",attr);
+ writeCharacters(marker->plainFullName((*r).node));
+ writeEndTag(); // </cxxClassBaseClass>
+
+ // not included: <ClassBaseStruct> or <cxxClassBaseUnion>
+
+ writeEndTag(); // </cxxClassDerivation>
+
+ // not included: <cxxStructDerivation>
+
+ ++r;
+ }
+ writeEndTag(); // </cxxClassDerivations>
+ }
+}
+
+/*!
+ Writes a <cxxXXXAPIItemLocation> element, depending on the
+ type of the node \a n, which can be a class, function, enum,
+ typedef, or property.
+ */
+void DitaXmlGenerator::writeLocation(const Node* n)
+{
+ DitaTag s1, s2, s3a, s3b;
+ s1 = DT_cxxClassAPIItemLocation;
+ s2 = DT_cxxClassDeclarationFile;
+ s3a = DT_cxxClassDeclarationFileLineStart;
+ s3b = DT_cxxClassDeclarationFileLineEnd;
+ if (n->type() == Node::Class || n->type() == Node::Namespace) {
+ s1 = DT_cxxClassAPIItemLocation;
+ s2 = DT_cxxClassDeclarationFile;
+ s3a = DT_cxxClassDeclarationFileLineStart;
+ s3b = DT_cxxClassDeclarationFileLineEnd;
+ }
+ else if (n->type() == Node::Function) {
+ FunctionNode* fn = const_cast<FunctionNode*>(static_cast<const FunctionNode*>(n));
+ if (fn->isMacro()) {
+ s1 = DT_cxxDefineAPIItemLocation;
+ s2 = DT_cxxDefineDeclarationFile;
+ s3a = DT_cxxDefineDeclarationFileLine;
+ s3b = DT_NONE;
+ }
+ else {
+ s1 = DT_cxxFunctionAPIItemLocation;
+ s2 = DT_cxxFunctionDeclarationFile;
+ s3a = DT_cxxFunctionDeclarationFileLine;
+ s3b = DT_NONE;
+ }
+ }
+ else if (n->type() == Node::Enum) {
+ s1 = DT_cxxEnumerationAPIItemLocation;
+ s2 = DT_cxxEnumerationDeclarationFile;
+ s3a = DT_cxxEnumerationDeclarationFileLineStart;
+ s3b = DT_cxxEnumerationDeclarationFileLineEnd;
+ }
+ else if (n->type() == Node::Typedef) {
+ s1 = DT_cxxTypedefAPIItemLocation;
+ s2 = DT_cxxTypedefDeclarationFile;
+ s3a = DT_cxxTypedefDeclarationFileLine;
+ s3b = DT_NONE;
+ }
+ else if ((n->type() == Node::Property) ||
+ (n->type() == Node::Variable)) {
+ s1 = DT_cxxVariableAPIItemLocation;
+ s2 = DT_cxxVariableDeclarationFile;
+ s3a = DT_cxxVariableDeclarationFileLine;
+ s3b = DT_NONE;
+ }
+ writeStartTag(s1);
+ writeStartTag(s2);
+ xmlWriter().writeAttribute("name","filePath");
+ xmlWriter().writeAttribute("value",n->location().filePath());
+ writeEndTag(); // <s2>
+ writeStartTag(s3a);
+ xmlWriter().writeAttribute("name","lineNumber");
+ QString lineNr;
+ xmlWriter().writeAttribute("value",lineNr.setNum(n->location().lineNo()));
+ writeEndTag(); // </s3a>
+ if (s3b != DT_NONE) {
+ writeStartTag(s3b);
+ xmlWriter().writeAttribute("name","lineNumber");
+ QString lineNr;
+ xmlWriter().writeAttribute("value",lineNr.setNum(n->location().lineNo()));
+ writeEndTag(); // </s3b>
+ }
+ writeEndTag(); // </cxx<s1>ApiItemLocation>
+}
+
+/*!
+ Write the <cxxFunction> elements.
+ */
+void DitaXmlGenerator::writeFunctions(const Section& s,
+ const InnerNode* parent,
+ CodeMarker* marker,
+ const QString& attribute)
+{
+ NodeList::ConstIterator m = s.members.begin();
+ while (m != s.members.end()) {
+ if ((*m)->type() == Node::Function) {
+ FunctionNode* fn = const_cast<FunctionNode*>(static_cast<const FunctionNode*>(*m));
+ writeStartTag(DT_cxxFunction);
+ xmlWriter().writeAttribute("id",fn->guid());
+ if (!attribute.isEmpty())
+ xmlWriter().writeAttribute("outputclass",attribute);
+ writeStartTag(DT_apiName);
+ if (fn->metaness() == FunctionNode::Signal)
+ xmlWriter().writeAttribute("outputclass","signal");
+ else if (fn->metaness() == FunctionNode::Slot)
+ xmlWriter().writeAttribute("outputclass","slot");
+ writeCharacters(fn->name());
+ writeEndTag(); // </apiName>
+ generateBrief(fn,marker);
+
+ // not included: <prolog>
+
+ writeStartTag(DT_cxxFunctionDetail);
+ writeStartTag(DT_cxxFunctionDefinition);
+ writeStartTag(DT_cxxFunctionAccessSpecifier);
+ xmlWriter().writeAttribute("value",fn->accessString());
+ writeEndTag(); // <cxxFunctionAccessSpecifier>
+
+ // not included: <cxxFunctionStorageClassSpecifierExtern>
+
+ if (fn->isStatic()) {
+ writeStartTag(DT_cxxFunctionStorageClassSpecifierStatic);
+ xmlWriter().writeAttribute("name","static");
+ xmlWriter().writeAttribute("value","static");
+ writeEndTag(); // <cxxFunctionStorageClassSpecifierStatic>
+ }
+
+ // not included: <cxxFunctionStorageClassSpecifierMutable>,
+
+ if (fn->isConst()) {
+ writeStartTag(DT_cxxFunctionConst);
+ xmlWriter().writeAttribute("name","const");
+ xmlWriter().writeAttribute("value","const");
+ writeEndTag(); // <cxxFunctionConst>
+ }
+
+ // not included: <cxxFunctionExplicit>
+ // <cxxFunctionInline
+
+ if (fn->virtualness() != FunctionNode::NonVirtual) {
+ writeStartTag(DT_cxxFunctionVirtual);
+ xmlWriter().writeAttribute("name","virtual");
+ xmlWriter().writeAttribute("value","virtual");
+ writeEndTag(); // <cxxFunctionVirtual>
+ if (fn->virtualness() == FunctionNode::PureVirtual) {
+ writeStartTag(DT_cxxFunctionPureVirtual);
+ xmlWriter().writeAttribute("name","pure virtual");
+ xmlWriter().writeAttribute("value","pure virtual");
+ writeEndTag(); // <cxxFunctionPureVirtual>
+ }
+ }
+
+ if (fn->name() == parent->name()) {
+ writeStartTag(DT_cxxFunctionConstructor);
+ xmlWriter().writeAttribute("name","constructor");
+ xmlWriter().writeAttribute("value","constructor");
+ writeEndTag(); // <cxxFunctionConstructor>
+ }
+ else if (fn->name()[0] == QChar('~')) {
+ writeStartTag(DT_cxxFunctionDestructor);
+ xmlWriter().writeAttribute("name","destructor");
+ xmlWriter().writeAttribute("value","destructor");
+ writeEndTag(); // <cxxFunctionDestructor>
+ }
+ else {
+ writeStartTag(DT_cxxFunctionDeclaredType);
+ QString src = marker->typified(fn->returnType());
+ replaceTypesWithLinks(fn,parent,marker,src);
+ writeEndTag(); // <cxxFunctionDeclaredType>
+ }
+
+ // not included: <cxxFunctionReturnType>
+
+ QString fq = fullQualification(fn);
+ if (!fq.isEmpty()) {
+ writeStartTag(DT_cxxFunctionScopedName);
+ writeCharacters(fq);
+ writeEndTag(); // <cxxFunctionScopedName>
+ }
+ writeStartTag(DT_cxxFunctionPrototype);
+ writeCharacters(fn->signature(true));
+ writeEndTag(); // <cxxFunctionPrototype>
+
+ QString fnl = fn->signature(false);
+ int idx = fnl.indexOf(' ');
+ if (idx < 0)
+ idx = 0;
+ else
+ ++idx;
+ fnl = fn->parent()->name() + "::" + fnl.mid(idx);
+ writeStartTag(DT_cxxFunctionNameLookup);
+ writeCharacters(fnl);
+ writeEndTag(); // <cxxFunctionNameLookup>
+
+ if (!fn->isInternal() && fn->isReimp() && fn->reimplementedFrom() != 0) {
+ FunctionNode* rfn = (FunctionNode*)fn->reimplementedFrom();
+ if (rfn && !rfn->isInternal()) {
+ writeStartTag(DT_cxxFunctionReimplemented);
+ xmlWriter().writeAttribute("href",rfn->ditaXmlHref());
+ writeCharacters(marker->plainFullName(rfn));
+ writeEndTag(); // </cxxFunctionReimplemented>
+ }
+ }
+ writeParameters(fn,parent,marker);
+ writeLocation(fn);
+ writeEndTag(); // <cxxFunctionDefinition>
+
+ writeApiDesc(fn, marker, QString());
+ // generateAlsoList(inner, marker);
+
+ // not included: <example> or <apiImpl>
+
+ writeEndTag(); // </cxxFunctionDetail>
+ writeEndTag(); // </cxxFunction>
+
+ if (fn->metaness() == FunctionNode::Ctor ||
+ fn->metaness() == FunctionNode::Dtor ||
+ fn->overloadNumber() != 1) {
+ }
+ }
+ ++m;
+ }
+}
+
+static const QString typeTag("type");
+static const QChar charLangle = '<';
+static const QChar charAt = '@';
+
+/*!
+ This function replaces class and enum names with <apiRelation>
+ elements, i.e. links.
+ */
+void DitaXmlGenerator::replaceTypesWithLinks(const Node* n,
+ const InnerNode* parent,
+ CodeMarker* marker,
+ QString& src)
+{
+ QStringRef arg;
+ QStringRef par1;
+ int srcSize = src.size();
+ QString text;
+ for (int i=0; i<srcSize;) {
+ if (src.at(i) == charLangle && src.at(i+1) == charAt) {
+ if (!text.isEmpty()) {
+ writeCharacters(text);
+ text.clear();
+ }
+ i += 2;
+ if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
+ const Node* tn = marker->resolveTarget(arg.toString(), tree_, parent, n);
+ if (tn) {
+ //Do not generate a link from a C++ function to a QML Basic Type (such as int)
+ if (n->type() == Node::Function && tn->subType() == Node::QmlBasicType)
+ writeCharacters(arg.toString());
+ else
+ addLink(linkForNode(tn,parent),arg,DT_apiRelation);
+ }
+ }
+ }
+ else {
+ text += src.at(i++);
+ }
+ }
+ if (!text.isEmpty()) {
+ writeCharacters(text);
+ text.clear();
+ }
+}
+
+/*!
+ This function writes the <cxxFunctionParameters> element.
+ */
+void DitaXmlGenerator::writeParameters(const FunctionNode* fn,
+ const InnerNode* parent,
+ CodeMarker* marker)
+{
+ const QList<Parameter>& parameters = fn->parameters();
+ if (!parameters.isEmpty()) {
+ writeStartTag(DT_cxxFunctionParameters);
+ QList<Parameter>::ConstIterator p = parameters.begin();
+ while (p != parameters.end()) {
+ writeStartTag(DT_cxxFunctionParameter);
+ writeStartTag(DT_cxxFunctionParameterDeclaredType);
+ QString src = marker->typified((*p).leftType());
+ replaceTypesWithLinks(fn,parent,marker,src);
+ //writeCharacters((*p).leftType());
+ if (!(*p).rightType().isEmpty())
+ writeCharacters((*p).rightType());
+ writeEndTag(); // <cxxFunctionParameterDeclaredType>
+ writeStartTag(DT_cxxFunctionParameterDeclarationName);
+ writeCharacters((*p).name());
+ writeEndTag(); // <cxxFunctionParameterDeclarationName>
+
+ // not included: <cxxFunctionParameterDefinitionName>
+
+ if (!(*p).defaultValue().isEmpty()) {
+ writeStartTag(DT_cxxFunctionParameterDefaultValue);
+ writeCharacters((*p).defaultValue());
+ writeEndTag(); // <cxxFunctionParameterDefaultValue>
+ }
+
+ // not included: <apiDefNote>
+
+ writeEndTag(); // <cxxFunctionParameter>
+ ++p;
+ }
+ writeEndTag(); // <cxxFunctionParameters>
+ }
+}
+
+/*!
+ This function writes the enum types.
+ */
+void DitaXmlGenerator::writeEnumerations(const Section& s,
+ CodeMarker* marker,
+ const QString& attribute)
+{
+ NodeList::ConstIterator m = s.members.begin();
+ while (m != s.members.end()) {
+ if ((*m)->type() == Node::Enum) {
+ const EnumNode* en = static_cast<const EnumNode*>(*m);
+ writeStartTag(DT_cxxEnumeration);
+ xmlWriter().writeAttribute("id",en->guid());
+ if (!attribute.isEmpty())
+ xmlWriter().writeAttribute("outputclass",attribute);
+ writeStartTag(DT_apiName);
+ writeCharacters(en->name());
+ writeEndTag(); // </apiName>
+ generateBrief(en,marker);
+
+ // not included <prolog>
+
+ writeStartTag(DT_cxxEnumerationDetail);
+ writeStartTag(DT_cxxEnumerationDefinition);
+ writeStartTag(DT_cxxEnumerationAccessSpecifier);
+ xmlWriter().writeAttribute("value",en->accessString());
+ writeEndTag(); // <cxxEnumerationAccessSpecifier>
+
+ QString fq = fullQualification(en);
+ if (!fq.isEmpty()) {
+ writeStartTag(DT_cxxEnumerationScopedName);
+ writeCharacters(fq);
+ writeEndTag(); // <cxxEnumerationScopedName>
+ }
+ const QList<EnumItem>& items = en->items();
+ if (!items.isEmpty()) {
+ writeStartTag(DT_cxxEnumerationPrototype);
+ writeCharacters(en->name());
+ xmlWriter().writeCharacters(" = { ");
+ QList<EnumItem>::ConstIterator i = items.begin();
+ while (i != items.end()) {
+ writeCharacters((*i).name());
+ if (!(*i).value().isEmpty()) {
+ xmlWriter().writeCharacters(" = ");
+ writeCharacters((*i).value());
+ }
+ ++i;
+ if (i != items.end())
+ xmlWriter().writeCharacters(", ");
+ }
+ xmlWriter().writeCharacters(" }");
+ writeEndTag(); // <cxxEnumerationPrototype>
+ }
+
+ writeStartTag(DT_cxxEnumerationNameLookup);
+ writeCharacters(en->parent()->name() + "::" + en->name());
+ writeEndTag(); // <cxxEnumerationNameLookup>
+
+ // not included: <cxxEnumerationReimplemented>
+
+ if (!items.isEmpty()) {
+ writeStartTag(DT_cxxEnumerators);
+ QList<EnumItem>::ConstIterator i = items.begin();
+ while (i != items.end()) {
+ writeStartTag(DT_cxxEnumerator);
+ writeStartTag(DT_apiName);
+ writeCharacters((*i).name());
+ writeEndTag(); // </apiName>
+
+ QString fq = fullQualification(en->parent());
+ if (!fq.isEmpty()) {
+ writeStartTag(DT_cxxEnumeratorScopedName);
+ writeCharacters(fq + "::" + (*i).name());
+ writeEndTag(); // <cxxEnumeratorScopedName>
+ }
+ writeStartTag(DT_cxxEnumeratorPrototype);
+ writeCharacters((*i).name());
+ writeEndTag(); // <cxxEnumeratorPrototype>
+ writeStartTag(DT_cxxEnumeratorNameLookup);
+ writeCharacters(en->parent()->name() + "::" + (*i).name());
+ writeEndTag(); // <cxxEnumeratorNameLookup>
+
+ if (!(*i).value().isEmpty()) {
+ writeStartTag(DT_cxxEnumeratorInitialiser);
+ if ((*i).value().toInt(0,16) == 0)
+ xmlWriter().writeAttribute("value", "0");
+ else
+ xmlWriter().writeAttribute("value", (*i).value());
+ writeEndTag(); // <cxxEnumeratorInitialiser>
+ }
+
+ // not included: <cxxEnumeratorAPIItemLocation>
+
+ if (!(*i).text().isEmpty()) {
+ writeStartTag(DT_apiDesc);
+ generateText((*i).text(), en, marker);
+ writeEndTag(); // </apiDesc>
+ }
+ writeEndTag(); // <cxxEnumerator>
+ ++i;
+ }
+ writeEndTag(); // <cxxEnumerators>
+ }
+
+ writeLocation(en);
+ writeEndTag(); // <cxxEnumerationDefinition>
+
+ writeApiDesc(en, marker, QString());
+
+ // not included: <example> or <apiImpl>
+
+ writeEndTag(); // </cxxEnumerationDetail>
+
+ // not included: <related-links>
+
+ writeEndTag(); // </cxxEnumeration>
+ }
+ ++m;
+ }
+}
+
+/*!
+ This function writes the output for the \typedef commands.
+ */
+void DitaXmlGenerator::writeTypedefs(const Section& s,
+ CodeMarker* marker,
+ const QString& attribute)
+
+{
+ NodeList::ConstIterator m = s.members.begin();
+ while (m != s.members.end()) {
+ if ((*m)->type() == Node::Typedef) {
+ const TypedefNode* tn = static_cast<const TypedefNode*>(*m);
+ writeStartTag(DT_cxxTypedef);
+ xmlWriter().writeAttribute("id",tn->guid());
+ if (!attribute.isEmpty())
+ xmlWriter().writeAttribute("outputclass",attribute);
+ writeStartTag(DT_apiName);
+ writeCharacters(tn->name());
+ writeEndTag(); // </apiName>
+ generateBrief(tn,marker);
+
+ // not included: <prolog>
+
+ writeStartTag(DT_cxxTypedefDetail);
+ writeStartTag(DT_cxxTypedefDefinition);
+ writeStartTag(DT_cxxTypedefAccessSpecifier);
+ xmlWriter().writeAttribute("value",tn->accessString());
+ writeEndTag(); // <cxxTypedefAccessSpecifier>
+
+ // not included: <cxxTypedefDeclaredType>
+
+ QString fq = fullQualification(tn);
+ if (!fq.isEmpty()) {
+ writeStartTag(DT_cxxTypedefScopedName);
+ writeCharacters(fq);
+ writeEndTag(); // <cxxTypedefScopedName>
+ }
+
+ // not included: <cxxTypedefPrototype>
+
+ writeStartTag(DT_cxxTypedefNameLookup);
+ writeCharacters(tn->parent()->name() + "::" + tn->name());
+ writeEndTag(); // <cxxTypedefNameLookup>
+
+ // not included: <cxxTypedefReimplemented>
+
+ writeLocation(tn);
+ writeEndTag(); // <cxxTypedefDefinition>
+
+ writeApiDesc(tn, marker, QString());
+
+ // not included: <example> or <apiImpl>
+
+ writeEndTag(); // </cxxTypedefDetail>
+
+ // not included: <related-links>
+
+ writeEndTag(); // </cxxTypedef>
+ }
+ ++m;
+ }
+}
+
+/*!
+ This function writes the output for the \property commands.
+ This is the Q_PROPERTYs.
+ */
+void DitaXmlGenerator::writeProperties(const Section& s,
+ CodeMarker* marker,
+ const QString& attribute)
+{
+ NodeList::ConstIterator m = s.members.begin();
+ while (m != s.members.end()) {
+ if ((*m)->type() == Node::Property) {
+ const PropertyNode* pn = static_cast<const PropertyNode*>(*m);
+ writeStartTag(DT_cxxVariable);
+ xmlWriter().writeAttribute("id",pn->guid());
+ if (!attribute.isEmpty())
+ xmlWriter().writeAttribute("outputclass",attribute);
+ writeStartTag(DT_apiName);
+ writeCharacters(pn->name());
+ writeEndTag(); // </apiName>
+ generateBrief(pn,marker);
+
+ // not included: <prolog>
+
+ writeStartTag(DT_cxxVariableDetail);
+ writeStartTag(DT_cxxVariableDefinition);
+ writeStartTag(DT_cxxVariableAccessSpecifier);
+ xmlWriter().writeAttribute("value",pn->accessString());
+ writeEndTag(); // <cxxVariableAccessSpecifier>
+
+ // not included: <cxxVariableStorageClassSpecifierExtern>,
+ // <cxxVariableStorageClassSpecifierStatic>,
+ // <cxxVariableStorageClassSpecifierMutable>,
+ // <cxxVariableConst>, <cxxVariableVolatile>
+
+ if (!pn->qualifiedDataType().isEmpty()) {
+ writeStartTag(DT_cxxVariableDeclaredType);
+ writeCharacters(pn->qualifiedDataType());
+ writeEndTag(); // <cxxVariableDeclaredType>
+ }
+ QString fq = fullQualification(pn);
+ if (!fq.isEmpty()) {
+ writeStartTag(DT_cxxVariableScopedName);
+ writeCharacters(fq);
+ writeEndTag(); // <cxxVariableScopedName>
+ }
+
+ writeStartTag(DT_cxxVariablePrototype);
+ xmlWriter().writeCharacters("Q_PROPERTY(");
+ writeCharacters(pn->qualifiedDataType());
+ xmlWriter().writeCharacters(" ");
+ writeCharacters(pn->name());
+ writePropertyParameter("READ",pn->getters());
+ writePropertyParameter("WRITE",pn->setters());
+ writePropertyParameter("RESET",pn->resetters());
+ writePropertyParameter("NOTIFY",pn->notifiers());
+ if (pn->isDesignable() != pn->designableDefault()) {
+ xmlWriter().writeCharacters(" DESIGNABLE ");
+ if (!pn->runtimeDesignabilityFunction().isEmpty())
+ writeCharacters(pn->runtimeDesignabilityFunction());
+ else
+ xmlWriter().writeCharacters(pn->isDesignable() ? "true" : "false");
+ }
+ if (pn->isScriptable() != pn->scriptableDefault()) {
+ xmlWriter().writeCharacters(" SCRIPTABLE ");
+ if (!pn->runtimeScriptabilityFunction().isEmpty())
+ writeCharacters(pn->runtimeScriptabilityFunction());
+ else
+ xmlWriter().writeCharacters(pn->isScriptable() ? "true" : "false");
+ }
+ if (pn->isWritable() != pn->writableDefault()) {
+ xmlWriter().writeCharacters(" STORED ");
+ xmlWriter().writeCharacters(pn->isStored() ? "true" : "false");
+ }
+ if (pn->isUser() != pn->userDefault()) {
+ xmlWriter().writeCharacters(" USER ");
+ xmlWriter().writeCharacters(pn->isUser() ? "true" : "false");
+ }
+ if (pn->isConstant())
+ xmlWriter().writeCharacters(" CONSTANT");
+ if (pn->isFinal())
+ xmlWriter().writeCharacters(" FINAL");
+ xmlWriter().writeCharacters(")");
+ writeEndTag(); // <cxxVariablePrototype>
+
+ writeStartTag(DT_cxxVariableNameLookup);
+ writeCharacters(pn->parent()->name() + "::" + pn->name());
+ writeEndTag(); // <cxxVariableNameLookup>
+
+ if (pn->overriddenFrom() != 0) {
+ PropertyNode* opn = (PropertyNode*)pn->overriddenFrom();
+ writeStartTag(DT_cxxVariableReimplemented);
+ xmlWriter().writeAttribute("href",opn->ditaXmlHref());
+ writeCharacters(marker->plainFullName(opn));
+ writeEndTag(); // </cxxVariableReimplemented>
+ }
+
+ writeLocation(pn);
+ writeEndTag(); // <cxxVariableDefinition>
+
+ writeApiDesc(pn, marker, QString());
+
+ // not included: <example> or <apiImpl>
+
+ writeEndTag(); // </cxxVariableDetail>
+
+ // not included: <related-links>
+
+ writeEndTag(); // </cxxVariable>
+ }
+ ++m;
+ }
+}
+
+/*!
+ This function outputs the nodes resulting from \variable commands.
+ */
+void DitaXmlGenerator::writeDataMembers(const Section& s,
+ CodeMarker* marker,
+ const QString& attribute)
+{
+ NodeList::ConstIterator m = s.members.begin();
+ while (m != s.members.end()) {
+ if ((*m)->type() == Node::Variable) {
+ const VariableNode* vn = static_cast<const VariableNode*>(*m);
+ writeStartTag(DT_cxxVariable);
+ xmlWriter().writeAttribute("id",vn->guid());
+ if (!attribute.isEmpty())
+ xmlWriter().writeAttribute("outputclass",attribute);
+ writeStartTag(DT_apiName);
+ writeCharacters(vn->name());
+ writeEndTag(); // </apiName>
+ generateBrief(vn,marker);
+
+ // not included: <prolog>
+
+ writeStartTag(DT_cxxVariableDetail);
+ writeStartTag(DT_cxxVariableDefinition);
+ writeStartTag(DT_cxxVariableAccessSpecifier);
+ xmlWriter().writeAttribute("value",vn->accessString());
+ writeEndTag(); // <cxxVariableAccessSpecifier>
+
+ // not included: <cxxVAriableStorageClassSpecifierExtern>
+
+ if (vn->isStatic()) {
+ writeStartTag(DT_cxxVariableStorageClassSpecifierStatic);
+ xmlWriter().writeAttribute("name","static");
+ xmlWriter().writeAttribute("value","static");
+ writeEndTag(); // <cxxVariableStorageClassSpecifierStatic>
+ }
+
+ // not included: <cxxVAriableStorageClassSpecifierMutable>,
+ // <cxxVariableConst>, <cxxVariableVolatile>
+
+ writeStartTag(DT_cxxVariableDeclaredType);
+ writeCharacters(vn->leftType());
+ if (!vn->rightType().isEmpty())
+ writeCharacters(vn->rightType());
+ writeEndTag(); // <cxxVariableDeclaredType>
+
+ QString fq = fullQualification(vn);
+ if (!fq.isEmpty()) {
+ writeStartTag(DT_cxxVariableScopedName);
+ writeCharacters(fq);
+ writeEndTag(); // <cxxVariableScopedName>
+ }
+
+ writeStartTag(DT_cxxVariablePrototype);
+ writeCharacters(vn->leftType() + QLatin1Char(' '));
+ //writeCharacters(vn->parent()->name() + "::" + vn->name());
+ writeCharacters(vn->name());
+ if (!vn->rightType().isEmpty())
+ writeCharacters(vn->rightType());
+ writeEndTag(); // <cxxVariablePrototype>
+
+ writeStartTag(DT_cxxVariableNameLookup);
+ writeCharacters(vn->parent()->name() + "::" + vn->name());
+ writeEndTag(); // <cxxVariableNameLookup>
+
+ // not included: <cxxVariableReimplemented>
+
+ writeLocation(vn);
+ writeEndTag(); // <cxxVariableDefinition>
+
+ writeApiDesc(vn, marker, QString());
+
+ // not included: <example> or <apiImpl>
+
+ writeEndTag(); // </cxxVariableDetail>
+
+ // not included: <related-links>
+
+ writeEndTag(); // </cxxVariable>
+ }
+ ++m;
+ }
+}
+
+/*!
+ This function writes a \macro as a <cxxDefine>.
+ */
+void DitaXmlGenerator::writeMacros(const Section& s,
+ CodeMarker* marker,
+ const QString& attribute)
+{
+ NodeList::ConstIterator m = s.members.begin();
+ while (m != s.members.end()) {
+ if ((*m)->type() == Node::Function) {
+ const FunctionNode* fn = static_cast<const FunctionNode*>(*m);
+ if (fn->isMacro()) {
+ writeStartTag(DT_cxxDefine);
+ xmlWriter().writeAttribute("id",fn->guid());
+ if (!attribute.isEmpty())
+ xmlWriter().writeAttribute("outputclass",attribute);
+ writeStartTag(DT_apiName);
+ writeCharacters(fn->name());
+ writeEndTag(); // </apiName>
+ generateBrief(fn,marker);
+
+ // not included: <prolog>
+
+ writeStartTag(DT_cxxDefineDetail);
+ writeStartTag(DT_cxxDefineDefinition);
+ writeStartTag(DT_cxxDefineAccessSpecifier);
+ xmlWriter().writeAttribute("value",fn->accessString());
+ writeEndTag(); // <cxxDefineAccessSpecifier>
+
+ writeStartTag(DT_cxxDefinePrototype);
+ xmlWriter().writeCharacters("#define ");
+ writeCharacters(fn->name());
+ if (fn->metaness() == FunctionNode::MacroWithParams) {
+ QStringList params = fn->parameterNames();
+ if (!params.isEmpty()) {
+ xmlWriter().writeCharacters("(");
+ for (int i = 0; i < params.size(); ++i) {
+ if (params[i].isEmpty())
+ xmlWriter().writeCharacters("...");
+ else
+ writeCharacters(params[i]);
+ if ((i+1) < params.size())
+ xmlWriter().writeCharacters(", ");
+ }
+ xmlWriter().writeCharacters(")");
+ }
+ }
+ writeEndTag(); // <cxxDefinePrototype>
+
+ writeStartTag(DT_cxxDefineNameLookup);
+ writeCharacters(fn->name());
+ writeEndTag(); // <cxxDefineNameLookup>
+
+ if (fn->reimplementedFrom() != 0) {
+ FunctionNode* rfn = (FunctionNode*)fn->reimplementedFrom();
+ writeStartTag(DT_cxxDefineReimplemented);
+ xmlWriter().writeAttribute("href",rfn->ditaXmlHref());
+ writeCharacters(marker->plainFullName(rfn));
+ writeEndTag(); // </cxxDefineReimplemented>
+ }
+
+ if (fn->metaness() == FunctionNode::MacroWithParams) {
+ QStringList params = fn->parameterNames();
+ if (!params.isEmpty()) {
+ writeStartTag(DT_cxxDefineParameters);
+ for (int i = 0; i < params.size(); ++i) {
+ writeStartTag(DT_cxxDefineParameter);
+ writeStartTag(DT_cxxDefineParameterDeclarationName);
+ writeCharacters(params[i]);
+ writeEndTag(); // <cxxDefineParameterDeclarationName>
+
+ // not included: <apiDefNote>
+
+ writeEndTag(); // <cxxDefineParameter>
+ }
+ writeEndTag(); // <cxxDefineParameters>
+ }
+ }
+
+ writeLocation(fn);
+ writeEndTag(); // <cxxDefineDefinition>
+
+ writeApiDesc(fn, marker, QString());
+
+ // not included: <example> or <apiImpl>
+
+ writeEndTag(); // </cxxDefineDetail>
+
+ // not included: <related-links>
+
+ writeEndTag(); // </cxxDefine>
+ }
+ }
+ ++m;
+ }
+}
+
+/*!
+ This function writes one parameter of a Q_PROPERTY macro.
+ The property is identified by \a tag ("READ" "WRIE" etc),
+ and it is found in the 'a nlist.
+ */
+void DitaXmlGenerator::writePropertyParameter(const QString& tag, const NodeList& nlist)
+{
+ NodeList::const_iterator n = nlist.begin();
+ while (n != nlist.end()) {
+ xmlWriter().writeCharacters(" ");
+ writeCharacters(tag);
+ xmlWriter().writeCharacters(" ");
+ writeCharacters((*n)->name());
+ ++n;
+ }
+}
+
+/*!
+ Calls beginSubPage() in the base class to open the file.
+ Then creates a new XML stream writer using the IO device
+ from opened file and pushes the XML writer onto a stackj.
+ Creates the file named \a fileName in the output directory.
+ Attaches a QTextStream to the created file, which is written
+ to all over the place using out(). Finally, it sets some
+ parameters in the XML writer and calls writeStartDocument().
+
+ It also ensures that a GUID map is created for the output file.
+ */
+void DitaXmlGenerator::beginSubPage(const InnerNode* node,
+ const QString& fileName)
+{
+ PageGenerator::beginSubPage(node,fileName);
+ (void) lookupGuidMap(fileName);
+ QXmlStreamWriter* writer = new QXmlStreamWriter(out().device());
+ xmlWriterStack.push(writer);
+ writer->setAutoFormatting(true);
+ writer->setAutoFormattingIndent(4);
+ writer->writeStartDocument();
+ clearSectionNesting();
+}
+
+/*!
+ Calls writeEndDocument() and then pops the XML stream writer
+ off the stack and deletes it. Then it calls endSubPage() in
+ the base class to close the device.
+ */
+void DitaXmlGenerator::endSubPage()
+{
+ if (inSection())
+ qDebug() << "Missing </section> in" << outFileName() << sectionNestingLevel;
+ xmlWriter().writeEndDocument();
+ delete xmlWriterStack.pop();
+ PageGenerator::endSubPage();
+}
+
+/*!
+ Returns a reference to the XML stream writer currently in use.
+ There is one XML stream writer open for each XML file being
+ written, and they are kept on a stack. The one on top of the
+ stack is the one being written to at the moment.
+ */
+QXmlStreamWriter& DitaXmlGenerator::xmlWriter()
+{
+ return *xmlWriterStack.top();
+}
+
+/*!
+ Writes the \e {<apiDesc>} element for \a node to the current XML
+ stream using the code \a marker and the \a title.
+ */
+void DitaXmlGenerator::writeApiDesc(const Node* node,
+ CodeMarker* marker,
+ const QString& title)
+{
+ if (!node->doc().isEmpty()) {
+ inDetailedDescription = true;
+ enterApiDesc(QString(),title);
+ generateBody(node, marker);
+ generateAlsoList(node, marker);
+ leaveSection();
+ }
+ inDetailedDescription = false;
+}
+
+/*!
+ Write the nested class elements.
+ */
+void DitaXmlGenerator::writeNestedClasses(const Section& s,
+ const Node* n)
+{
+ if (s.members.isEmpty())
+ return;
+ writeStartTag(DT_cxxClassNested);
+ writeStartTag(DT_cxxClassNestedDetail);
+
+ NodeList::ConstIterator m = s.members.begin();
+ while (m != s.members.end()) {
+ if ((*m)->type() == Node::Class) {
+ writeStartTag(DT_cxxClassNestedClass);
+ QString link = linkForNode((*m), n);
+ xmlWriter().writeAttribute("href", link);
+ QString name = n->name() + "::" + (*m)->name();
+ writeCharacters(name);
+ writeEndTag(); // <cxxClassNestedClass>
+ }
+ ++m;
+ }
+ writeEndTag(); // <cxxClassNestedDetail>
+ writeEndTag(); // <cxxClassNested>
+}
+
+/*!
+ Recursive writing of DITA XML files from the root \a node.
+ */
+void
+DitaXmlGenerator::generateInnerNode(const InnerNode* node)
+{
+ if (!node->url().isNull())
+ return;
+
+ if (node->type() == Node::Fake) {
+ const FakeNode *fakeNode = static_cast<const FakeNode *>(node);
+ if (fakeNode->subType() == Node::ExternalPage)
+ return;
+ if (fakeNode->subType() == Node::Image)
+ return;
+ if (fakeNode->subType() == Node::QmlPropertyGroup)
+ return;
+ if (fakeNode->subType() == Node::Page) {
+ if (node->count() > 0)
+ qDebug("PAGE %s HAS CHILDREN", qPrintable(fakeNode->title()));
+ }
+ }
+
+ /*
+ Obtain a code marker for the source file.
+ */
+ CodeMarker *marker = CodeMarker::markerForFileName(node->location().filePath());
+
+ if (node->parent() != 0) {
+ beginSubPage(node, fileName(node));
+ if (node->type() == Node::Namespace || node->type() == Node::Class) {
+ generateClassLikeNode(node, marker);
+ }
+ else if (node->type() == Node::Fake) {
+ if (node->subType() == Node::HeaderFile)
+ generateClassLikeNode(node, marker);
+ else if (node->subType() == Node::QmlClass)
+ generateClassLikeNode(node, marker);
+ else
+ generateFakeNode(static_cast<const FakeNode*>(node), marker);
+ }
+ endSubPage();
+ }
+
+ NodeList::ConstIterator c = node->childNodes().begin();
+ while (c != node->childNodes().end()) {
+ if ((*c)->isInnerNode() && (*c)->access() != Node::Private)
+ generateInnerNode((const InnerNode*) *c);
+ ++c;
+ }
+}
+
+/*!
+ Returns true if \a format is "XML" or "HTML" .
+ */
+bool DitaXmlGenerator::canHandleFormat(const QString& format)
+{
+ return (format == "HTML") || (format == this->format());
+}
+
+/*!
+ If the node multimap \a nmm contains nodes mapped to \a key,
+ if any of the nodes mapped to \a key has the same href as the
+ \a node, return true. Otherwise, return false.
+ */
+bool DitaXmlGenerator::isDuplicate(NodeMultiMap* nmm, const QString& key, Node* node)
+{
+ QList<Node*> matches = nmm->values(key);
+ if (!matches.isEmpty()) {
+ for (int i=0; i<matches.size(); ++i) {
+ if (matches[i] == node)
+ return true;
+ if (fileName(node) == fileName(matches[i]))
+ return true;
+ }
+ }
+ return false;
+}
+/*!
+ Collect all the nodes in the tree according to their type or subtype.
+
+ type: Class
+ type: Namespace
+
+ subtype: Example
+ subtype: External page
+ subtype: Group
+ subtype: Header file
+ subtype: Module
+ subtype: Page
+ subtype: QML basic type
+ subtype: QML class
+ subtype: QML module
+ */
+void DitaXmlGenerator::collectNodesByTypeAndSubtype(const InnerNode* parent)
+{
+ //qDebug() << "START";
+ const NodeList& children = parent->childNodes();
+ if (children.size() == 0)
+ return;
+
+ bool related;
+ QString message;
+ for (int i=0; i<children.size(); ++i) {
+ Node* child = children[i];
+ if (!child || child->isInternal() || child->doc().isEmpty())
+ continue;
+ if (child->relates()) {
+ related = true;
+ message = child->relates()->name();
+ }
+ else {
+ related = false;
+ message = "has documentation but no \\relates command";
+ }
+ switch (child->type()) {
+ case Node::Namespace:
+ //qDebug() << "NODE: Namespace" << "TITLE:" << child->name()
+ // << "FILE:" << fileName(child);
+ if (!isDuplicate(nodeTypeMaps[Node::Namespace],child->name(),child))
+ nodeTypeMaps[Node::Namespace]->insert(child->name(),child);
+ break;
+ case Node::Class:
+ //qDebug() << "NODE: Class" << "TITLE:" << child->name()
+ // << "FILE:" << fileName(child);
+ if (!isDuplicate(nodeTypeMaps[Node::Class],child->name(),child))
+ nodeTypeMaps[Node::Class]->insert(child->name(),child);
+ break;
+ case Node::Fake:
+ //qDebug() << "NODE: Fake";
+ switch (child->subType()) {
+ case Node::Example:
+ //qDebug() << "FAKE NODE: Example" << "TITLE:" << child->title()
+ // << "FILE:" << fileName(child);
+ if (!isDuplicate(nodeSubtypeMaps[Node::Example],child->title(),child))
+ nodeSubtypeMaps[Node::Example]->insert(child->title(),child);
+ break;
+ case Node::HeaderFile:
+ //qDebug() << "FAKE NODE: Header file" << "TITLE:" << child->title()
+ // << "FILE:" << fileName(child);
+ if (!isDuplicate(nodeSubtypeMaps[Node::HeaderFile],child->title(),child))
+ nodeSubtypeMaps[Node::HeaderFile]->insert(child->title(),child);
+ break;
+ case Node::File:
+ //qDebug() << "FAKE NODE: File";
+ break;
+ case Node::Image:
+ //qDebug() << "FAKE NODE: Image";
+ break;
+ case Node::Group:
+ //qDebug() << "FAKE NODE: Group" << "TITLE:" << child->title()
+ // << "FILE:" << fileName(child);
+ if (!isDuplicate(nodeSubtypeMaps[Node::Group],child->title(),child))
+ nodeSubtypeMaps[Node::Group]->insert(child->title(),child);
+ break;
+ case Node::Module:
+ //qDebug() << "FAKE NODE: Module" << "TITLE:" << child->title()
+ // << "FILE:" << fileName(child);
+ if (!isDuplicate(nodeSubtypeMaps[Node::Module],child->title(),child))
+ nodeSubtypeMaps[Node::Module]->insert(child->title(),child);
+ break;
+ case Node::Page:
+ //qDebug() << "FAKE NODE: Page" << "PAGE TYPE:" << child->pageTypeString()
+ // << "TITLE:" << child->title()
+ // << "FILE:" << fileName(child);
+ if (!isDuplicate(pageTypeMaps[child->pageType()],child->title(),child))
+ pageTypeMaps[child->pageType()]->insert(child->title(),child);
+ break;
+ case Node::ExternalPage:
+ //qDebug() << "FAKE NODE: External page" << "TITLE:" << child->title()
+ // << "FILE:" << fileName(child);
+ if (!isDuplicate(nodeSubtypeMaps[Node::ExternalPage],child->title(),child))
+ nodeSubtypeMaps[Node::ExternalPage]->insert(child->title(),child);
+ break;
+ case Node::QmlClass:
+ //qDebug() << "FAKE NODE: QML class" << "TITLE:" << child->title() << "FILE:"
+ // << fileName(child);
+ if (!isDuplicate(nodeSubtypeMaps[Node::QmlClass],child->title(),child))
+ nodeSubtypeMaps[Node::QmlClass]->insert(child->title(),child);
+ break;
+ case Node::QmlPropertyGroup:
+ //qDebug() << "FAKE NODE: QML property group";
+ break;
+ case Node::QmlBasicType:
+ //qDebug() << "FAKE NODE: QML basic type" << "TITLE:" << child->title()
+ // << "FILE:" << fileName(child);
+ if (!isDuplicate(nodeSubtypeMaps[Node::QmlBasicType],child->title(),child))
+ nodeSubtypeMaps[Node::QmlBasicType]->insert(child->title(),child);
+ break;
+ case Node::QmlModule:
+ //qDebug() << "FAKE NODE: QML module" << "TITLE:" << child->title()
+ // << "FILE:" << fileName(child);
+ if (!isDuplicate(nodeSubtypeMaps[Node::QmlModule],child->title(),child))
+ nodeSubtypeMaps[Node::QmlModule]->insert(child->title(),child);
+ break;
+ case Node::Collision:
+ //qDebug() << "FAKE NODE: Collision";
+ break;
+ default:
+ break;
+ }
+ break;
+ case Node::Enum:
+ if (!related)
+ child->location().warning(tr("Global enum, %1, %2").arg(child->name()).arg(message));
+ break;
+ case Node::Typedef:
+ if (!related)
+ child->location().warning(tr("Global typedef, %1, %2").arg(child->name()).arg(message));
+ break;
+ case Node::Function:
+ if (!related) {
+ const FunctionNode* fn = static_cast<const FunctionNode*>(child);
+ if (fn->isMacro())
+ child->location().warning(tr("Global macro, %1, %2").arg(child->name()).arg(message));
+ else
+ child->location().warning(tr("Global function, %1(), %2").arg(child->name()).arg(message));
+ }
+ break;
+ case Node::Property:
+ break;
+ case Node::Variable:
+ if (!related)
+ child->location().warning(tr("Global variable, %1, %2").arg(child->name()).arg(message));
+ break;
+ case Node::Target:
+ break;
+ case Node::QmlProperty:
+ if (!related)
+ child->location().warning(tr("Global QML property, %1, %2").arg(child->name()).arg(message));
+ break;
+ case Node::QmlSignal:
+ if (!related)
+ child->location().warning(tr("Global QML, signal, %1 %2").arg(child->name()).arg(message));
+ break;
+ case Node::QmlSignalHandler:
+ if (!related)
+ child->location().warning(tr("Global QML signal handler, %1, %2").arg(child->name()).arg(message));
+ break;
+ case Node::QmlMethod:
+ if (!related)
+ child->location().warning(tr("Global QML method, %1, %2").arg(child->name()).arg(message));
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*!
+ Creates the DITA map for the qdoc run. The map is written
+ to the file \e{qt.ditamap" in the DITA XML output directory.
+ */
+void DitaXmlGenerator::writeDitaMap(const Tree *tree)
+{
+ beginSubPage(tree->root(),"qt.ditamap");
+
+ QString doctype;
+ doctype = "<!DOCTYPE map PUBLIC \"-//OASIS//DTD DITA Map//EN\" \"map.dtd\">";
+ // doctype = "<!DOCTYPE cxxAPIMap PUBLIC \"-//NOKIA//DTD DITA C++ API Map Reference Type v0.6.0//EN\" \"dtd/cxxAPIMap.dtd\">";
+
+ xmlWriter().writeDTD(doctype);
+ writeStartTag(DT_map);
+ //xmlWriter().writeAttribute("id","Qt-DITA-Map");
+ //xmlWriter().writeAttribute("title","Qt DITA Map");
+ writeStartTag(DT_topicmeta);
+ writeStartTag(DT_shortdesc);
+ xmlWriter().writeCharacters("The top level map for the Qt documentation");
+ writeEndTag(); // </shortdesc>
+ writeEndTag(); // </topicmeta>
+ GuidMaps::iterator i = guidMaps.begin();
+ while (i != guidMaps.end()) {
+ writeStartTag(DT_topicref);
+ if (i.key() != "qt.ditamap")
+ xmlWriter().writeAttribute("href",i.key());
+ writeEndTag(); // </topicref>
+ ++i;
+ }
+ endSubPage();
+
+ for (unsigned i=0; i<Node::LastType; ++i)
+ nodeTypeMaps[i] = new NodeMultiMap;
+ for (unsigned i=0; i<Node::LastSubtype; ++i)
+ nodeSubtypeMaps[i] = new NodeMultiMap;
+ for (unsigned i=0; i<Node::OnBeyondZebra; ++i)
+ pageTypeMaps[i] = new NodeMultiMap;
+ collectNodesByTypeAndSubtype(tree->root());
+#if 0
+ for (unsigned i=0; i<Node::LastType; ++i) {
+ if (nodeTypeMaps[i] && nodeTypeMaps[i]->size() > 0)
+ qDebug() << "NODE TYPE:" << Node::nodeTypeString(i) << nodeTypeMaps[i]->size();
+ }
+ for (unsigned i=1; i<Node::LastSubtype; ++i) {
+ if (nodeSubtypeMaps[i] && nodeSubtypeMaps[i]->size() > 0)
+ qDebug() << "NODE SUBTYPE:" << Node::nodeSubtypeString(i) << nodeSubtypeMaps[i]->size();
+ }
+ for (unsigned i=1; i<Node::OnBeyondZebra; ++i) {
+ if (pageTypeMaps[i] && pageTypeMaps[i]->size() > 0)
+ qDebug() << "PAGE TYPE:" << Node::pageTypeString(i) << pageTypeMaps[i]->size();
+ }
+#endif
+ beginSubPage(tree->root(),"test.ditamap");
+
+ doctype = "<!DOCTYPE map PUBLIC \"-//OASIS//DTD DITA Map//EN\" \"map.dtd\">";
+ xmlWriter().writeDTD(doctype);
+ writeStartTag(DT_map);
+ writeStartTag(DT_topicmeta);
+ writeStartTag(DT_shortdesc);
+ xmlWriter().writeCharacters("The top level map for the Qt documentation");
+ writeEndTag(); // </shortdesc>
+ writeEndTag(); // </topicmeta>
+
+ writeTopicrefs(pageTypeMaps[Node::OverviewPage], "overviews");
+ writeTopicrefs(pageTypeMaps[Node::HowToPage], "howtos");
+ writeTopicrefs(pageTypeMaps[Node::TutorialPage], "tutorials");
+ writeTopicrefs(pageTypeMaps[Node::FAQPage], "faqs");
+ writeTopicrefs(pageTypeMaps[Node::ArticlePage], "articles");
+ writeTopicrefs(nodeSubtypeMaps[Node::Example], "examples");
+ writeTopicrefs(nodeSubtypeMaps[Node::QmlClass], "QML classes");
+ writeTopicrefs(nodeTypeMaps[Node::Class], "C++ classes");
+ writeTopicrefs(nodeTypeMaps[Node::Namespace], "C++ namespaces");
+ writeTopicrefs(nodeSubtypeMaps[Node::HeaderFile], "header files");
+ writeTopicrefs(nodeSubtypeMaps[Node::Module], "modules");
+ writeTopicrefs(nodeSubtypeMaps[Node::Group], "groups");
+ writeTopicrefs(nodeSubtypeMaps[Node::QmlModule], "QML modules");
+ writeTopicrefs(nodeSubtypeMaps[Node::QmlBasicType], "QML basic types");
+
+ endSubPage();
+
+ for (unsigned i=0; i<Node::LastType; ++i)
+ delete nodeTypeMaps[i];
+ for (unsigned i=0; i<Node::LastSubtype; ++i)
+ delete nodeSubtypeMaps[i];
+ for (unsigned i=0; i<Node::OnBeyondZebra; ++i)
+ delete pageTypeMaps[i];
+}
+
+/*!
+ Creates the DITA map from the topicrefs in \a node,
+ which is a DitaMapNode.
+ */
+void DitaXmlGenerator::writeDitaMap(const DitaMapNode* node)
+{
+ beginSubPage(node,node->name());
+
+ QString doctype;
+ doctype = "<!DOCTYPE map PUBLIC \"-//OASIS//DTD DITA Map//EN\" \"map.dtd\">";
+ // doctype = "<!DOCTYPE cxxAPIMap PUBLIC \"-//NOKIA//DTD DITA C++ API Map Reference Type v0.6.0//EN\" \"dtd/cxxAPIMap.dtd\">";
+
+ xmlWriter().writeDTD(doctype);
+ writeStartTag(DT_map);
+ writeStartTag(DT_topicmeta);
+ writeStartTag(DT_shortdesc);
+ xmlWriter().writeCharacters(node->title());
+ writeEndTag(); // </shortdesc>
+ writeEndTag(); // </topicmeta>
+ const DitaRefList map = node->map();
+ writeDitaRefs(map);
+ endSubPage();
+}
+
+/*!
+ Write the \a ditarefs to the current output file.
+ */
+void DitaXmlGenerator::writeDitaRefs(const DitaRefList& ditarefs)
+{
+ foreach (DitaRef* t, ditarefs) {
+ if (t->isMapRef())
+ writeStartTag(DT_mapref);
+ else
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("navtitle",t->navtitle());
+ if (t->href().isEmpty()) {
+ const FakeNode* fn = tree_->findFakeNodeByTitle(t->navtitle());
+ if (fn)
+ xmlWriter().writeAttribute("href",fileName(fn));
+ }
+ else
+ xmlWriter().writeAttribute("href",t->href());
+ if (t->subrefs() && !t->subrefs()->isEmpty())
+ writeDitaRefs(*(t->subrefs()));
+ writeEndTag(); // </topicref> or </mapref>
+ }
+}
+
+void DitaXmlGenerator::writeTopicrefs(NodeMultiMap* nmm, const QString& navtitle)
+{
+ if (!nmm || nmm->isEmpty())
+ return;
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("navtitle",navtitle);
+ NodeMultiMap::iterator i = nmm->begin();
+ while (i != nmm->end()) {
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("navtitle",i.key());
+ xmlWriter().writeAttribute("href",fileName(i.value()));
+ switch (i.value()->type()) {
+ case Node::Fake: {
+ const FakeNode* fn = static_cast<const FakeNode*>(i.value());
+ switch (fn->subType()) {
+ case Node::Group: {
+ const NodeList& members = fn->groupMembers();
+ for (int j=0; j<members.size(); ++j) {
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("navtitle",members[j]->name());
+ xmlWriter().writeAttribute("href",fileName(members[j]));
+ writeEndTag(); // </topicref>
+ }
+ break;
+ }
+ case Node::QmlModule: {
+ const NodeList& members = fn->qmlModuleMembers();
+ for (int j=0; j<members.size(); ++j) {
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("navtitle",members[j]->name());
+ xmlWriter().writeAttribute("href",fileName(members[j]));
+ writeEndTag(); // </topicref>
+ }
+ break;
+ }
+ case Node::Example: {
+ const ExampleNode* en = static_cast<const ExampleNode*>(fn);
+ if (!en->imageFileName().isEmpty()) {
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("navtitle","image");
+ xmlWriter().writeAttribute("href",en->imageFileName());
+ writeEndTag(); // </topicref>
+ }
+ const NodeList& files = en->childNodes();
+ for (int j=0; j<files.size(); ++j) {
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("href",files[j]->name());
+ writeEndTag(); // </topicref>
+ }
+ break;
+ }
+ case Node::Module: {
+ if (moduleNamespaceMap.contains(fn->name())) {
+ const NodeMap& nodeMap = moduleNamespaceMap[fn->name()];
+ foreach (const QString& name, nodeMap.keys()) {
+ const Node* node = nodeMap[name];
+ if (node->status() == Node::Obsolete ||
+ node->isInternal() ||
+ node->access() == Node::Private ||
+ node->doc().isEmpty())
+ continue;
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("navtitle",node->name());
+ xmlWriter().writeAttribute("href",fileName(node));
+ writeEndTag(); // </topicref>
+ }
+ }
+ if (moduleClassMap.contains(fn->name())) {
+ const NodeMap& nodeMap = moduleClassMap[fn->name()];
+ foreach (const QString& name, nodeMap.keys()) {
+ const Node* node = nodeMap[name];
+ if (node->status() == Node::Obsolete ||
+ node->isInternal() ||
+ node->access() == Node::Private ||
+ node->doc().isEmpty())
+ continue;
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("navtitle",node->name());
+ xmlWriter().writeAttribute("href",fileName(node));
+ writeEndTag(); // </topicref>
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case Node::Namespace: {
+ const NamespaceNode* nn = static_cast<const NamespaceNode*>(i.value());
+ const NodeList& c = nn->childNodes();
+ for (int j=0; j<c.size(); ++j) {
+ if (c[j]->isInternal() || c[j]->access() == Node::Private || c[j]->doc().isEmpty())
+ continue;
+ if (c[j]->type() == Node::Class) {
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("navtitle",c[j]->name());
+ xmlWriter().writeAttribute("href",fileName(c[j]));
+ writeEndTag(); // </topicref>
+ }
+ }
+ break;
+ }
+ case Node::Class: {
+ const NamespaceNode* nn = static_cast<const NamespaceNode*>(i.value());
+ const NodeList& c = nn->childNodes();
+ for (int j=0; j<c.size(); ++j) {
+ if (c[j]->isInternal() || c[j]->access() == Node::Private || c[j]->doc().isEmpty())
+ continue;
+ if (c[j]->type() == Node::Class) {
+ writeStartTag(DT_topicref);
+ xmlWriter().writeAttribute("navtitle",c[j]->name());
+ xmlWriter().writeAttribute("href",fileName(c[j]));
+ writeEndTag(); // </topicref>
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ writeEndTag(); // </topicref>
+ ++i;
+ }
+ writeEndTag(); // </topicref>
+}
+
+
+/*!
+ Looks up the tag name for \a t in the map of metadata
+ values for the current topic in \a inner. If a value
+ for the tag is found, the element is written with the
+ found value. Otherwise if \a force is set, an empty
+ element is written using the tag.
+
+ Returns true or false depending on whether it writes
+ an element using the tag \a t.
+
+ \note If \a t is found in the metadata map, it is erased.
+ i.e. Once you call this function for a particular \a t,
+ you consume \a t.
+ */
+bool DitaXmlGenerator::writeMetadataElement(const InnerNode* inner,
+ DitaXmlGenerator::DitaTag t,
+ bool force)
+{
+ QString s = getMetadataElement(inner,t);
+ if (s.isEmpty() && !force)
+ return false;
+ writeStartTag(t);
+ if (!s.isEmpty())
+ xmlWriter().writeCharacters(s);
+ writeEndTag();
+ return true;
+}
+
+
+/*!
+ Looks up the tag name for \a t in the map of metadata
+ values for the current topic in \a inner. If one or more
+ value sfor the tag are found, the elements are written.
+ Otherwise nothing is written.
+
+ Returns true or false depending on whether it writes
+ at least one element using the tag \a t.
+
+ \note If \a t is found in the metadata map, it is erased.
+ i.e. Once you call this function for a particular \a t,
+ you consume \a t.
+ */
+bool DitaXmlGenerator::writeMetadataElements(const InnerNode* inner,
+ DitaXmlGenerator::DitaTag t)
+{
+ QStringList s = getMetadataElements(inner,t);
+ if (s.isEmpty())
+ return false;
+ for (int i=0; i<s.size(); ++i) {
+ writeStartTag(t);
+ xmlWriter().writeCharacters(s[i]);
+ writeEndTag();
+ }
+ return true;
+}
+
+/*!
+ Looks up the tag name for \a t in the map of metadata
+ values for the current topic in \a inner. If a value
+ for the tag is found, the value is returned.
+
+ \note If \a t is found in the metadata map, it is erased.
+ i.e. Once you call this function for a particular \a t,
+ you consume \a t.
+ */
+QString DitaXmlGenerator::getMetadataElement(const InnerNode* inner, DitaXmlGenerator::DitaTag t)
+{
+ QString s = Generator::getMetadataElement(inner, ditaTags[t]);
+ if (s.isEmpty())
+ s = metadataDefault(t);
+ return s;
+}
+
+/*!
+ Looks up the tag name for \a t in the map of metadata
+ values for the current topic in \a inner. If values
+ for the tag are found, they are returned in a string
+ list.
+
+ \note If \a t is found in the metadata map, all the
+ pairs having the key \a t are erased. i.e. Once you
+ all this function for a particular \a t, you consume
+ \a t.
+ */
+QStringList DitaXmlGenerator::getMetadataElements(const InnerNode* inner,
+ DitaXmlGenerator::DitaTag t)
+{
+ QStringList s = Generator::getMetadataElements(inner,ditaTags[t]);
+ if (s.isEmpty())
+ s.append(metadataDefault(t));
+ return s;
+}
+
+/*!
+ Returns the value of key \a t or an empty string
+ if \a t is not found in the map.
+ */
+QString DitaXmlGenerator::metadataDefault(DitaTag t) const
+{
+ return metadataDefaults.value(ditaTags[t]);
+}
+
+/*!
+ Writes the <prolog> element for the \a inner node
+ using the \a marker. The <prolog> element contains
+ the <metadata> element, plus some others. This
+ function writes one or more of these elements:
+
+ \list
+ \o <audience> *
+ \o <author> *
+ \o <brand> not used
+ \o <category> *
+ \o <compomnent> *
+ \o <copyrholder> *
+ \o <copyright> *
+ \o <created> not used
+ \o <copyryear> *
+ \o <critdates> not used
+ \o <keyword> not used
+ \o <keywords> not used
+ \o <metadata> *
+ \o <othermeta> *
+ \o <permissions> *
+ \o <platform> not used
+ \o <prodinfo> *
+ \o <prodname> *
+ \o <prolog> *
+ \o <publisher> *
+ \o <resourceid> not used
+ \o <revised> not used
+ \o <source> not used
+ \o <tm> not used
+ \o <unknown> not used
+ \o <vrm> *
+ \o <vrmlist> *
+ \endlist
+
+ \node * means the tag has been used.
+
+ */
+void
+DitaXmlGenerator::writeProlog(const InnerNode* inner)
+{
+ if (!inner)
+ return;
+ writeStartTag(DT_prolog);
+ writeMetadataElements(inner,DT_author);
+ writeMetadataElement(inner,DT_publisher);
+ QString s = getMetadataElement(inner,DT_copyryear);
+ QString t = getMetadataElement(inner,DT_copyrholder);
+ writeStartTag(DT_copyright);
+ writeStartTag(DT_copyryear);
+ if (!s.isEmpty())
+ xmlWriter().writeAttribute("year",s);
+ writeEndTag(); // </copyryear>
+ writeStartTag(DT_copyrholder);
+ if (!s.isEmpty())
+ xmlWriter().writeCharacters(t);
+ writeEndTag(); // </copyrholder>
+ writeEndTag(); // </copyright>
+ s = getMetadataElement(inner,DT_permissions);
+ writeStartTag(DT_permissions);
+ xmlWriter().writeAttribute("view",s);
+ writeEndTag(); // </permissions>
+ writeStartTag(DT_metadata);
+ QStringList sl = getMetadataElements(inner,DT_audience);
+ if (!sl.isEmpty()) {
+ for (int i=0; i<sl.size(); ++i) {
+ writeStartTag(DT_audience);
+ xmlWriter().writeAttribute("type",sl[i]);
+ writeEndTag(); // </audience>
+ }
+ }
+ if (!writeMetadataElement(inner,DT_category,false)) {
+ writeStartTag(DT_category);
+ QString category = "Page";
+ if (inner->type() == Node::Class)
+ category = "Class reference";
+ else if (inner->type() == Node::Namespace)
+ category = "Namespace";
+ else if (inner->type() == Node::Fake) {
+ if (inner->subType() == Node::QmlClass)
+ category = "QML Reference";
+ else if (inner->subType() == Node::QmlBasicType)
+ category = "QML Basic Type";
+ else if (inner->subType() == Node::HeaderFile)
+ category = "Header File";
+ else if (inner->subType() == Node::Module)
+ category = "Module";
+ else if (inner->subType() == Node::File)
+ category = "Example Source File";
+ else if (inner->subType() == Node::Example)
+ category = "Example";
+ else if (inner->subType() == Node::Image)
+ category = "Image";
+ else if (inner->subType() == Node::Group)
+ category = "Group";
+ else if (inner->subType() == Node::Page)
+ category = "Page";
+ else if (inner->subType() == Node::ExternalPage)
+ category = "External Page"; // Is this necessary?
+ }
+ xmlWriter().writeCharacters(category);
+ writeEndTag(); // </category>
+ }
+ if (vrm.size() > 0) {
+ writeStartTag(DT_prodinfo);
+ if (!writeMetadataElement(inner,DT_prodname,false)) {
+ writeStartTag(DT_prodname);
+ xmlWriter().writeCharacters(projectDescription);
+ writeEndTag(); // </prodname>
+ }
+ writeStartTag(DT_vrmlist);
+ writeStartTag(DT_vrm);
+ if (vrm.size() > 0)
+ xmlWriter().writeAttribute("version",vrm[0]);
+ if (vrm.size() > 1)
+ xmlWriter().writeAttribute("release",vrm[1]);
+ if (vrm.size() > 2)
+ xmlWriter().writeAttribute("modification",vrm[2]);
+ writeEndTag(); // <vrm>
+ writeEndTag(); // <vrmlist>
+ if (!writeMetadataElement(inner,DT_component,false)) {
+ QString component = inner->moduleName();
+ if (!component.isEmpty()) {
+ writeStartTag(DT_component);
+ xmlWriter().writeCharacters(component);
+ writeEndTag(); // </component>
+ }
+ }
+ writeEndTag(); // </prodinfo>
+ }
+ const QStringMultiMap& metaTagMap = inner->doc().metaTagMap();
+ QMapIterator<QString, QString> i(metaTagMap);
+ while (i.hasNext()) {
+ i.next();
+ writeStartTag(DT_othermeta);
+ xmlWriter().writeAttribute("name",i.key());
+ xmlWriter().writeAttribute("content",i.value());
+ writeEndTag(); // </othermeta>
+ }
+ writeEndTag(); // </metadata>
+ writeEndTag(); // </prolog>
+}
+
+/*!
+ This function should be called to write the \a href attribute
+ if the href could be an \e http or \e ftp link. If \a href is
+ one or the other, a \e scope attribute is also writen, with
+ value \e external.
+ */
+void DitaXmlGenerator::writeHrefAttribute(const QString& href)
+{
+ xmlWriter().writeAttribute("href", href);
+ if (href.startsWith("http:") || href.startsWith("ftp:") ||
+ href.startsWith("https:") || href.startsWith("mailto:"))
+ xmlWriter().writeAttribute("scope", "external");
+}
+
+/*!
+ Strips the markup tags from \a src, when we are trying to
+ create an \e{id} attribute. Returns the stripped text.
+ */
+QString DitaXmlGenerator::stripMarkup(const QString& src) const
+{
+ QString text;
+ const QChar charAt = '@';
+ const QChar charSlash = '/';
+ const QChar charLangle = '<';
+ const QChar charRangle = '>';
+
+ int n = src.size();
+ int i = 0;
+ while (i < n) {
+ if (src.at(i) == charLangle) {
+ ++i;
+ if (src.at(i) == charAt || (src.at(i) == charSlash && src.at(i+1) == charAt)) {
+ while (i < n && src.at(i) != charRangle)
+ ++i;
+ ++i;
+ }
+ else {
+ text += charLangle;
+ }
+ }
+ else
+ text += src.at(i++);
+ }
+ return text;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/ditaxmlgenerator.h b/src/tools/qdoc/ditaxmlgenerator.h
new file mode 100644
index 0000000000..ba96265b48
--- /dev/null
+++ b/src/tools/qdoc/ditaxmlgenerator.h
@@ -0,0 +1,543 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DITAXMLGENERATOR_H
+#define DITAXMLGENERATOR_H
+
+#include <qmap.h>
+#include <qregexp.h>
+#include <QXmlStreamWriter>
+#include "codemarker.h"
+#include "config.h"
+#include "pagegenerator.h"
+
+QT_BEGIN_NAMESPACE
+
+typedef QMap<QString, QString> GuidMap;
+typedef QMap<QString, GuidMap*> GuidMaps;
+
+class DitaXmlGenerator : public PageGenerator
+{
+public:
+ enum SinceType {
+ Namespace,
+ Class,
+ MemberFunction,
+ NamespaceFunction,
+ GlobalFunction,
+ Macro,
+ Enum,
+ Typedef,
+ Property,
+ Variable,
+ QmlClass,
+ QmlProperty,
+ QmlSignal,
+ QmlSignalHandler,
+ QmlMethod,
+ LastSinceType
+ };
+
+ enum DitaTag {
+ DT_NONE,
+ DT_alt,
+ DT_apiDesc,
+ DT_APIMap,
+ DT_apiName,
+ DT_apiRelation,
+ DT_audience,
+ DT_author,
+ DT_b,
+ DT_body,
+ DT_bodydiv,
+ DT_brand,
+ DT_category,
+ DT_codeblock,
+ DT_comment,
+ DT_component,
+ DT_copyrholder,
+ DT_copyright,
+ DT_copyryear,
+ DT_created,
+ DT_critdates,
+ DT_cxxAPIMap,
+ DT_cxxClass,
+ DT_cxxClassAbstract,
+ DT_cxxClassAccessSpecifier,
+ DT_cxxClassAPIItemLocation,
+ DT_cxxClassBaseClass,
+ DT_cxxClassDeclarationFile,
+ DT_cxxClassDeclarationFileLine,
+ DT_cxxClassDeclarationFileLineStart,
+ DT_cxxClassDeclarationFileLineEnd,
+ DT_cxxClassDefinition,
+ DT_cxxClassDerivation,
+ DT_cxxClassDerivationAccessSpecifier,
+ DT_cxxClassDerivations,
+ DT_cxxClassDetail,
+ DT_cxxClassNested,
+ DT_cxxClassNestedClass,
+ DT_cxxClassNestedDetail,
+ DT_cxxDefine,
+ DT_cxxDefineAccessSpecifier,
+ DT_cxxDefineAPIItemLocation,
+ DT_cxxDefineDeclarationFile,
+ DT_cxxDefineDeclarationFileLine,
+ DT_cxxDefineDefinition,
+ DT_cxxDefineDetail,
+ DT_cxxDefineNameLookup,
+ DT_cxxDefineParameter,
+ DT_cxxDefineParameterDeclarationName,
+ DT_cxxDefineParameters,
+ DT_cxxDefinePrototype,
+ DT_cxxDefineReimplemented,
+ DT_cxxEnumeration,
+ DT_cxxEnumerationAccessSpecifier,
+ DT_cxxEnumerationAPIItemLocation,
+ DT_cxxEnumerationDeclarationFile,
+ DT_cxxEnumerationDeclarationFileLine,
+ DT_cxxEnumerationDeclarationFileLineStart,
+ DT_cxxEnumerationDeclarationFileLineEnd,
+ DT_cxxEnumerationDefinition,
+ DT_cxxEnumerationDetail,
+ DT_cxxEnumerationNameLookup,
+ DT_cxxEnumerationPrototype,
+ DT_cxxEnumerationScopedName,
+ DT_cxxEnumerator,
+ DT_cxxEnumeratorInitialiser,
+ DT_cxxEnumeratorNameLookup,
+ DT_cxxEnumeratorPrototype,
+ DT_cxxEnumerators,
+ DT_cxxEnumeratorScopedName,
+ DT_cxxFunction,
+ DT_cxxFunctionAccessSpecifier,
+ DT_cxxFunctionAPIItemLocation,
+ DT_cxxFunctionConst,
+ DT_cxxFunctionConstructor,
+ DT_cxxFunctionDeclarationFile,
+ DT_cxxFunctionDeclarationFileLine,
+ DT_cxxFunctionDeclaredType,
+ DT_cxxFunctionDefinition,
+ DT_cxxFunctionDestructor,
+ DT_cxxFunctionDetail,
+ DT_cxxFunctionNameLookup,
+ DT_cxxFunctionParameter,
+ DT_cxxFunctionParameterDeclarationName,
+ DT_cxxFunctionParameterDeclaredType,
+ DT_cxxFunctionParameterDefaultValue,
+ DT_cxxFunctionParameters,
+ DT_cxxFunctionPrototype,
+ DT_cxxFunctionPureVirtual,
+ DT_cxxFunctionReimplemented,
+ DT_cxxFunctionScopedName,
+ DT_cxxFunctionStorageClassSpecifierStatic,
+ DT_cxxFunctionVirtual,
+ DT_cxxTypedef,
+ DT_cxxTypedefAccessSpecifier,
+ DT_cxxTypedefAPIItemLocation,
+ DT_cxxTypedefDeclarationFile,
+ DT_cxxTypedefDeclarationFileLine,
+ DT_cxxTypedefDefinition,
+ DT_cxxTypedefDetail,
+ DT_cxxTypedefNameLookup,
+ DT_cxxTypedefScopedName,
+ DT_cxxVariable,
+ DT_cxxVariableAccessSpecifier,
+ DT_cxxVariableAPIItemLocation,
+ DT_cxxVariableDeclarationFile,
+ DT_cxxVariableDeclarationFileLine,
+ DT_cxxVariableDeclaredType,
+ DT_cxxVariableDefinition,
+ DT_cxxVariableDetail,
+ DT_cxxVariableNameLookup,
+ DT_cxxVariablePrototype,
+ DT_cxxVariableReimplemented,
+ DT_cxxVariableScopedName,
+ DT_cxxVariableStorageClassSpecifierStatic,
+ DT_data,
+ DT_dataabout,
+ DT_dd,
+ DT_dl,
+ DT_dlentry,
+ DT_dt,
+ DT_entry,
+ DT_fig,
+ DT_i,
+ DT_image,
+ DT_keyword,
+ DT_keywords,
+ DT_li,
+ DT_link,
+ DT_linktext,
+ DT_lq,
+ DT_map,
+ DT_mapref,
+ DT_metadata,
+ DT_note,
+ DT_ol,
+ DT_othermeta,
+ DT_p,
+ DT_parameter,
+ DT_permissions,
+ DT_ph,
+ DT_platform,
+ DT_pre,
+ DT_prodinfo,
+ DT_prodname,
+ DT_prolog,
+ DT_publisher,
+ DT_relatedLinks,
+ DT_resourceid,
+ DT_revised,
+ DT_row,
+ DT_section,
+ DT_sectiondiv,
+ DT_shortdesc,
+ DT_simpletable,
+ DT_source,
+ DT_stentry,
+ DT_sthead,
+ DT_strow,
+ DT_sub,
+ DT_sup,
+ DT_table,
+ DT_tbody,
+ DT_tgroup,
+ DT_thead,
+ DT_title,
+ DT_tm,
+ DT_topic,
+ DT_topicmeta,
+ DT_topicref,
+ DT_tt,
+ DT_u,
+ DT_ul,
+ DT_unknown,
+ DT_vrm,
+ DT_vrmlist,
+ DT_xref,
+ DT_LAST
+ };
+
+public:
+ DitaXmlGenerator();
+ ~DitaXmlGenerator();
+
+ virtual void initializeGenerator(const Config& config);
+ virtual void terminateGenerator();
+ virtual QString format();
+ virtual bool canHandleFormat(const QString& format);
+ virtual void generateTree(const Tree *tree);
+ virtual void generateDisambiguationPages() { }
+
+ QString protectEnc(const QString& string);
+ static QString protect(const QString& string, const QString& encoding = "ISO-8859-1");
+ static QString cleanRef(const QString& ref);
+ static QString sinceTitle(int i) { return sinceTitles[i]; }
+
+protected:
+ virtual void startText(const Node* relative, CodeMarker* marker);
+ virtual int generateAtom(const Atom* atom,
+ const Node* relative,
+ CodeMarker* marker);
+ virtual void generateClassLikeNode(const InnerNode* inner, CodeMarker* marker);
+ virtual void generateFakeNode(const FakeNode* fake, CodeMarker* marker);
+ virtual QString fileExtension(const Node* node) const;
+ virtual QString guidForNode(const Node* node);
+ virtual QString linkForNode(const Node* node, const Node* relative);
+ virtual QString refForAtom(Atom* atom, const Node* node);
+
+ void writeXrefListItem(const QString& link, const QString& text);
+ QString fullQualification(const Node* n);
+
+ void writeCharacters(const QString& text);
+ void writeDerivations(const ClassNode* cn, CodeMarker* marker);
+ void writeLocation(const Node* n);
+ void writeFunctions(const Section& s,
+ const InnerNode* parent,
+ CodeMarker* marker,
+ const QString& attribute = QString());
+ void writeNestedClasses(const Section& s, const Node* n);
+ void replaceTypesWithLinks(const Node* n,
+ const InnerNode* parent,
+ CodeMarker* marker,
+ QString& src);
+ void writeParameters(const FunctionNode* fn, const InnerNode* parent, CodeMarker* marker);
+ void writeEnumerations(const Section& s,
+ CodeMarker* marker,
+ const QString& attribute = QString());
+ void writeTypedefs(const Section& s,
+ CodeMarker* marker,
+ const QString& attribute = QString());
+ void writeDataMembers(const Section& s,
+ CodeMarker* marker,
+ const QString& attribute = QString());
+ void writeProperties(const Section& s,
+ CodeMarker* marker,
+ const QString& attribute = QString());
+ void writeMacros(const Section& s,
+ CodeMarker* marker,
+ const QString& attribute = QString());
+ void writePropertyParameter(const QString& tag, const NodeList& nlist);
+ void writeRelatedLinks(const FakeNode* fake, CodeMarker* marker);
+ void writeLink(const Node* node, const QString& tex, const QString& role);
+ void writeProlog(const InnerNode* inner);
+ bool writeMetadataElement(const InnerNode* inner,
+ DitaXmlGenerator::DitaTag t,
+ bool force=true);
+ bool writeMetadataElements(const InnerNode* inner, DitaXmlGenerator::DitaTag t);
+ void writeHrefAttribute(const QString& href);
+ QString getMetadataElement(const InnerNode* inner, DitaXmlGenerator::DitaTag t);
+ QStringList getMetadataElements(const InnerNode* inner, DitaXmlGenerator::DitaTag t);
+
+private:
+ enum SubTitleSize { SmallSubTitle, LargeSubTitle };
+
+ const QPair<QString,QString> anchorForNode(const Node* node);
+ const Node* findNodeForTarget(const QString& target,
+ const Node* relative,
+ CodeMarker* marker,
+ const Atom* atom = 0);
+ void generateHeader(const Node* node,
+ const QString& name,
+ bool subpage = false);
+ void generateBrief(const Node* node, CodeMarker* marker);
+ void generateIncludes(const InnerNode* inner, CodeMarker* marker);
+ void generateTableOfContents(const Node* node,
+ CodeMarker* marker,
+ Doc::Sections sectioningUnit,
+ int numColumns,
+ const Node* relative = 0);
+ void generateTableOfContents(const Node* node,
+ CodeMarker* marker,
+ QList<Section>* sections = 0);
+ void generateLowStatusMembers(const InnerNode* inner,
+ CodeMarker* marker,
+ CodeMarker::Status status);
+ QString generateLowStatusMemberFile(const InnerNode* inner,
+ CodeMarker* marker,
+ CodeMarker::Status status);
+ void generateClassHierarchy(const Node* relative,
+ CodeMarker* marker,
+ const NodeMap& classMap);
+ void generateAnnotatedList(const Node* relative,
+ CodeMarker* marker,
+ const NodeMap& nodeMap);
+ void generateCompactList(const Node* relative,
+ CodeMarker* marker,
+ const NodeMap& classMap,
+ bool includeAlphabet,
+ QString commonPrefix = QString());
+ void generateFunctionIndex(const Node* relative, CodeMarker* marker);
+ void generateLegaleseList(const Node* relative, CodeMarker* marker);
+ void generateOverviewList(const Node* relative, CodeMarker* marker);
+
+ void generateQmlSummary(const Section& section,
+ const Node* relative,
+ CodeMarker* marker);
+ void generateQmlItem(const Node* node,
+ const Node* relative,
+ CodeMarker* marker,
+ bool summary);
+ void generateDetailedQmlMember(const Node* node,
+ const InnerNode* relative,
+ CodeMarker* marker);
+ void generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker);
+ void generateQmlInheritedBy(const QmlClassNode* qcn, CodeMarker* marker);
+ void generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker);
+ void generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker);
+
+ void generateSection(const NodeList& nl,
+ const Node* relative,
+ CodeMarker* marker,
+ CodeMarker::SynopsisStyle style);
+ QString getMarkedUpSynopsis(const Node* node,
+ const Node* relative,
+ CodeMarker* marker,
+ CodeMarker::SynopsisStyle style);
+ void generateSectionInheritedList(const Section& section,
+ const Node* relative,
+ CodeMarker* marker);
+ void writeText(const QString& markedCode,
+ CodeMarker* marker,
+ const Node* relative);
+
+ void generateFullName(const Node* apparentNode,
+ const Node* relative,
+ CodeMarker* marker,
+ const Node* actualNode = 0);
+ void generateLink(const Atom* atom,
+ const Node* relative,
+ CodeMarker* marker);
+ void generateStatus(const Node* node, CodeMarker* marker);
+
+ QString registerRef(const QString& ref);
+ virtual QString fileBase(const Node *node) const;
+ QString fileName(const Node *node);
+ void findAllClasses(const InnerNode *node);
+ void findAllFunctions(const InnerNode *node);
+ void findAllLegaleseTexts(const InnerNode *node);
+ void findAllNamespaces(const InnerNode *node);
+ static int hOffset(const Node *node);
+ static bool isThreeColumnEnumValueTable(const Atom *atom);
+ QString getLink(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker,
+ const Node **node);
+ QString getDisambiguationLink(const Atom* atom, CodeMarker* marker);
+ virtual void generateIndex(const QString& fileBase,
+ const QString& url,
+ const QString& title);
+#ifdef GENERATE_MAC_REFS
+ void generateMacRef(const Node* node, CodeMarker* marker);
+#endif
+ void beginLink(const QString& link);
+ void endLink();
+ QString writeGuidAttribute(QString text);
+ void writeGuidAttribute(Node* node);
+ QString lookupGuid(QString text);
+ QString lookupGuid(const QString& fileName, const QString& text);
+ GuidMap* lookupGuidMap(const QString& fileName);
+ virtual void beginSubPage(const InnerNode* node, const QString& fileName);
+ virtual void endSubPage();
+ virtual void generateInnerNode(const InnerNode* node);
+ QXmlStreamWriter& xmlWriter();
+ void writeApiDesc(const Node* node, CodeMarker* marker, const QString& title);
+ void addLink(const QString& href, const QStringRef& text, DitaTag t = DT_xref);
+ void writeDitaMap(const Tree* tree);
+ void writeDitaMap(const DitaMapNode* node);
+ void writeStartTag(DitaTag t);
+ void writeEndTag(DitaTag t=DT_NONE);
+ DitaTag currentTag();
+ void clearSectionNesting() { sectionNestingLevel = 0; }
+ int enterApiDesc(const QString& outputclass, const QString& title);
+ int enterSection(const QString& outputclass, const QString& title);
+ int leaveSection();
+ bool inSection() const { return (sectionNestingLevel > 0); }
+ int currentSectionNestingLevel() const { return sectionNestingLevel; }
+ QString metadataDefault(DitaTag t) const;
+ QString stripMarkup(const QString& src) const;
+ void collectNodesByTypeAndSubtype(const InnerNode* parent);
+ void writeDitaRefs(const DitaRefList& ditarefs);
+ void writeTopicrefs(NodeMultiMap* nmm, const QString& navtitle);
+ bool isDuplicate(NodeMultiMap* nmm, const QString& key, Node* node);
+
+private:
+ /*
+ These flags indicate which elements the generator
+ is currently outputting.
+ */
+ bool inContents;
+ bool inDetailedDescription;
+ bool inLegaleseText;
+ bool inLink;
+ bool inObsoleteLink;
+ bool inSectionHeading;
+ bool inTableHeader;
+ bool inTableBody;
+
+ bool noLinks;
+ bool obsoleteLinks;
+ bool offlineDocs;
+ bool threeColumnEnumValueTable;
+
+ int codeIndent;
+ int numTableRows;
+ int divNestingLevel;
+ int sectionNestingLevel;
+ int tableColumnCount;
+
+ QString link;
+ QStringList sectionNumber;
+ QRegExp funcLeftParen;
+ QString style;
+ QString postHeader;
+ QString postPostHeader;
+ QString footer;
+ QString address;
+ bool pleaseGenerateMacRef;
+ QString project;
+ QString projectDescription;
+ QString projectUrl;
+ QString navigationLinks;
+ QString version;
+ QStringList vrm;
+ QStringList stylesheets;
+ QStringList customHeadElements;
+ const Tree* tree_;
+ QMap<QString, QString> refMap;
+ QMap<QString, QString> name2guidMap;
+ GuidMaps guidMaps;
+ QMap<QString, NodeMap > moduleClassMap;
+ QMap<QString, NodeMap > moduleNamespaceMap;
+ NodeMap nonCompatClasses;
+ NodeMap mainClasses;
+ NodeMap compatClasses;
+ NodeMap obsoleteClasses;
+ NodeMap namespaceIndex;
+ NodeMap serviceClasses;
+#ifdef QDOC_QML
+ NodeMap qmlClasses;
+#endif
+ QMap<QString, NodeMap > funcIndex;
+ QMap<Text, const Node*> legaleseTexts;
+ static int id;
+ static QString ditaTags[];
+ QStack<QXmlStreamWriter*> xmlWriterStack;
+ QStack<DitaTag> tagStack;
+ QStringMultiMap metadataDefaults;
+ QVector<NodeMultiMap*> nodeTypeMaps;
+ QVector<NodeMultiMap*> nodeSubtypeMaps;
+ QVector<NodeMultiMap*> pageTypeMaps;
+};
+
+#define DITAXMLGENERATOR_ADDRESS "address"
+#define DITAXMLGENERATOR_FOOTER "footer"
+#define DITAXMLGENERATOR_GENERATEMACREFS "generatemacrefs" // ### document me
+#define DITAXMLGENERATOR_POSTHEADER "postheader"
+#define DITAXMLGENERATOR_POSTPOSTHEADER "postpostheader"
+#define DITAXMLGENERATOR_STYLE "style"
+#define DITAXMLGENERATOR_STYLESHEETS "stylesheets"
+#define DITAXMLGENERATOR_CUSTOMHEADELEMENTS "customheadelements"
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/doc.cpp b/src/tools/qdoc/doc.cpp
new file mode 100644
index 0000000000..7572799eba
--- /dev/null
+++ b/src/tools/qdoc/doc.cpp
@@ -0,0 +1,3393 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "config.h"
+#include "doc.h"
+#include "codemarker.h"
+#include "editdistance.h"
+#include "openedlist.h"
+#include "quoter.h"
+#include "text.h"
+#include "tokenizer.h"
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qhash.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <ctype.h>
+#include <limits.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QSet<QString>, null_Set_QString)
+Q_GLOBAL_STATIC(TopicList, nullTopicList)
+Q_GLOBAL_STATIC(QStringList, null_QStringList)
+Q_GLOBAL_STATIC(QList<Text>, null_QList_Text)
+//Q_GLOBAL_STATIC(QStringMap, null_QStringMap)
+Q_GLOBAL_STATIC(QStringMultiMap, null_QStringMultiMap)
+
+struct Macro
+{
+ QString defaultDef;
+ Location defaultDefLocation;
+ QStringMap otherDefs;
+ int numParams;
+};
+
+enum {
+ CMD_A,
+ CMD_ABSTRACT,
+ CMD_ANNOTATEDLIST,
+ CMD_B,
+ CMD_BADCODE,
+ CMD_BASENAME,
+ CMD_BOLD,
+ CMD_BRIEF,
+ CMD_C,
+ CMD_CAPTION,
+ CMD_CHAPTER,
+ CMD_CODE,
+ CMD_CODELINE,
+ CMD_DIV,
+ CMD_DOTS,
+ CMD_E,
+ CMD_ELSE,
+ CMD_ENDABSTRACT,
+ CMD_ENDCHAPTER,
+ CMD_ENDCODE,
+ CMD_ENDDIV,
+ CMD_ENDFOOTNOTE,
+ CMD_ENDIF,
+ CMD_ENDLEGALESE,
+ CMD_ENDLINK,
+ CMD_ENDLIST,
+ CMD_ENDMAPREF,
+ CMD_ENDOMIT,
+ CMD_ENDPART,
+ CMD_ENDQUOTATION,
+ CMD_ENDRAW,
+ CMD_ENDSECTION1,
+ CMD_ENDSECTION2,
+ CMD_ENDSECTION3,
+ CMD_ENDSECTION4,
+ CMD_ENDSIDEBAR,
+ CMD_ENDTABLE,
+ CMD_ENDTOPICREF,
+ CMD_EXPIRE,
+ CMD_FOOTNOTE,
+ CMD_GENERATELIST,
+ CMD_GRANULARITY,
+ CMD_HEADER,
+ CMD_I,
+ CMD_IF,
+ CMD_IMAGE,
+ CMD_IMPORTANT,
+ CMD_INCLUDE,
+ CMD_INLINEIMAGE,
+ CMD_INDEX,
+ CMD_KEYWORD,
+ CMD_L,
+ CMD_LEGALESE,
+ CMD_LI,
+ CMD_LINK,
+ CMD_LIST,
+ CMD_MAPREF,
+ CMD_META,
+ CMD_NEWCODE,
+ CMD_NOTE,
+ CMD_O,
+ CMD_OLDCODE,
+ CMD_OMIT,
+ CMD_OMITVALUE,
+ CMD_OVERLOAD,
+ CMD_PART,
+ CMD_PRINTLINE,
+ CMD_PRINTTO,
+ CMD_PRINTUNTIL,
+ CMD_QUOTATION,
+ CMD_QUOTEFILE,
+ CMD_QUOTEFROMFILE,
+ CMD_QUOTEFUNCTION,
+ CMD_RAW,
+ CMD_ROW,
+ CMD_SA,
+ CMD_SECTION1,
+ CMD_SECTION2,
+ CMD_SECTION3,
+ CMD_SECTION4,
+ CMD_SIDEBAR,
+ CMD_SINCELIST,
+ CMD_SKIPLINE,
+ CMD_SKIPTO,
+ CMD_SKIPUNTIL,
+ CMD_SNIPPET,
+ CMD_SPAN,
+ CMD_SUB,
+ CMD_SUP,
+ CMD_TABLE,
+ CMD_TABLEOFCONTENTS,
+ CMD_TARGET,
+ CMD_TOPICREF,
+ CMD_TT,
+ CMD_UNDERLINE,
+ CMD_UNICODE,
+ CMD_VALUE,
+ CMD_WARNING,
+ CMD_QML,
+ CMD_ENDQML,
+ CMD_CPP,
+ CMD_ENDCPP,
+ CMD_QMLTEXT,
+ CMD_ENDQMLTEXT,
+ CMD_CPPTEXT,
+ CMD_ENDCPPTEXT,
+ CMD_JS,
+ CMD_ENDJS,
+ NOT_A_CMD
+};
+
+static struct {
+ const char *english;
+ int no;
+ QString *alias;
+} cmds[] = {
+ { "a", CMD_A, 0 },
+ { "abstract", CMD_ABSTRACT, 0 },
+ { "annotatedlist", CMD_ANNOTATEDLIST, 0 },
+ { "b", CMD_B, 0 },
+ { "badcode", CMD_BADCODE, 0 },
+ { "basename", CMD_BASENAME, 0 }, // ### don't document for now
+ { "bold", CMD_BOLD, 0 },
+ { "brief", CMD_BRIEF, 0 },
+ { "c", CMD_C, 0 },
+ { "caption", CMD_CAPTION, 0 },
+ { "chapter", CMD_CHAPTER, 0 },
+ { "code", CMD_CODE, 0 },
+ { "codeline", CMD_CODELINE, 0},
+ { "div", CMD_DIV, 0 },
+ { "dots", CMD_DOTS, 0 },
+ { "e", CMD_E, 0 },
+ { "else", CMD_ELSE, 0 },
+ { "endabstract", CMD_ENDABSTRACT, 0 },
+ { "endchapter", CMD_ENDCHAPTER, 0 },
+ { "endcode", CMD_ENDCODE, 0 },
+ { "enddiv", CMD_ENDDIV, 0 },
+ { "endfootnote", CMD_ENDFOOTNOTE, 0 },
+ { "endif", CMD_ENDIF, 0 },
+ { "endlegalese", CMD_ENDLEGALESE, 0 },
+ { "endlink", CMD_ENDLINK, 0 },
+ { "endlist", CMD_ENDLIST, 0 },
+ { "endmapref", CMD_ENDMAPREF, 0 },
+ { "endomit", CMD_ENDOMIT, 0 },
+ { "endpart", CMD_ENDPART, 0 },
+ { "endquotation", CMD_ENDQUOTATION, 0 },
+ { "endraw", CMD_ENDRAW, 0 },
+ { "endsection1", CMD_ENDSECTION1, 0 }, // ### don't document for now
+ { "endsection2", CMD_ENDSECTION2, 0 }, // ### don't document for now
+ { "endsection3", CMD_ENDSECTION3, 0 }, // ### don't document for now
+ { "endsection4", CMD_ENDSECTION4, 0 }, // ### don't document for now
+ { "endsidebar", CMD_ENDSIDEBAR, 0 },
+ { "endtable", CMD_ENDTABLE, 0 },
+ { "endtopicref", CMD_ENDTOPICREF, 0 },
+ { "expire", CMD_EXPIRE, 0 },
+ { "footnote", CMD_FOOTNOTE, 0 },
+ { "generatelist", CMD_GENERATELIST, 0 },
+ { "granularity", CMD_GRANULARITY, 0 }, // ### don't document for now
+ { "header", CMD_HEADER, 0 },
+ { "i", CMD_I, 0 },
+ { "if", CMD_IF, 0 },
+ { "image", CMD_IMAGE, 0 },
+ { "important", CMD_IMPORTANT, 0 },
+ { "include", CMD_INCLUDE, 0 },
+ { "inlineimage", CMD_INLINEIMAGE, 0 },
+ { "index", CMD_INDEX, 0 }, // ### don't document for now
+ { "keyword", CMD_KEYWORD, 0 },
+ { "l", CMD_L, 0 },
+ { "legalese", CMD_LEGALESE, 0 },
+ { "li", CMD_LI, 0 },
+ { "link", CMD_LINK, 0 },
+ { "list", CMD_LIST, 0 },
+ { "mapref", CMD_MAPREF, 0 },
+ { "meta", CMD_META, 0 },
+ { "newcode", CMD_NEWCODE, 0 },
+ { "note", CMD_NOTE, 0 },
+ { "o", CMD_O, 0 },
+ { "oldcode", CMD_OLDCODE, 0 },
+ { "omit", CMD_OMIT, 0 },
+ { "omitvalue", CMD_OMITVALUE, 0 },
+ { "overload", CMD_OVERLOAD, 0 },
+ { "part", CMD_PART, 0 },
+ { "printline", CMD_PRINTLINE, 0 },
+ { "printto", CMD_PRINTTO, 0 },
+ { "printuntil", CMD_PRINTUNTIL, 0 },
+ { "quotation", CMD_QUOTATION, 0 },
+ { "quotefile", CMD_QUOTEFILE, 0 },
+ { "quotefromfile", CMD_QUOTEFROMFILE, 0 },
+ { "quotefunction", CMD_QUOTEFUNCTION, 0 },
+ { "raw", CMD_RAW, 0 },
+ { "row", CMD_ROW, 0 },
+ { "sa", CMD_SA, 0 },
+ { "section1", CMD_SECTION1, 0 },
+ { "section2", CMD_SECTION2, 0 },
+ { "section3", CMD_SECTION3, 0 },
+ { "section4", CMD_SECTION4, 0 },
+ { "sidebar", CMD_SIDEBAR, 0 },
+ { "sincelist", CMD_SINCELIST, 0 },
+ { "skipline", CMD_SKIPLINE, 0 },
+ { "skipto", CMD_SKIPTO, 0 },
+ { "skipuntil", CMD_SKIPUNTIL, 0 },
+ { "snippet", CMD_SNIPPET, 0 },
+ { "span", CMD_SPAN, 0 },
+ { "sub", CMD_SUB, 0 },
+ { "sup", CMD_SUP, 0 },
+ { "table", CMD_TABLE, 0 },
+ { "tableofcontents", CMD_TABLEOFCONTENTS, 0 },
+ { "target", CMD_TARGET, 0 },
+ { "topicref", CMD_TOPICREF, 0 },
+ { "tt", CMD_TT, 0 },
+ { "underline", CMD_UNDERLINE, 0 },
+ { "unicode", CMD_UNICODE, 0 },
+ { "value", CMD_VALUE, 0 },
+ { "warning", CMD_WARNING, 0 },
+ { "qml", CMD_QML, 0 },
+ { "endqml", CMD_ENDQML, 0 },
+ { "cpp", CMD_CPP, 0 },
+ { "endcpp", CMD_ENDCPP, 0 },
+ { "qmltext", CMD_QMLTEXT, 0 },
+ { "endqmltext", CMD_ENDQMLTEXT, 0 },
+ { "cpptext", CMD_CPPTEXT, 0 },
+ { "endcpptext", CMD_ENDCPPTEXT, 0 },
+ { "js", CMD_JS, 0 },
+ { "endjs", CMD_ENDJS, 0 },
+ { 0, 0, 0 }
+};
+
+typedef QHash<QString, int> QHash_QString_int;
+typedef QHash<QString, Macro> QHash_QString_Macro;
+
+Q_GLOBAL_STATIC(QStringMap, aliasMap)
+Q_GLOBAL_STATIC(QHash_QString_int, cmdHash)
+Q_GLOBAL_STATIC(QHash_QString_Macro, macroHash)
+
+class DocPrivateExtra
+{
+public:
+ QString baseName;
+ Doc::Sections granularity;
+ Doc::Sections section; // ###
+ QList<Atom*> tableOfContents;
+ QList<int> tableOfContentsLevels;
+ QList<Atom*> keywords;
+ QList<Atom*> targets;
+ QStringMultiMap metaMap;
+
+ DocPrivateExtra()
+ : granularity(Doc::Part) { }
+};
+
+struct Shared // ### get rid of
+{
+ Shared()
+ : count(1) { }
+ void ref() { ++count; }
+ bool deref() { return (--count == 0); }
+
+ int count;
+};
+
+static QString cleanLink(const QString &link)
+{
+ int colonPos = link.indexOf(':');
+ if ((colonPos == -1) ||
+ (!link.startsWith("file:") && !link.startsWith("mailto:")))
+ return link;
+ return link.mid(colonPos + 1).simplified();
+}
+
+class DocPrivate : public Shared
+{
+public:
+ DocPrivate(const Location& start = Location::null,
+ const Location& end = Location::null,
+ const QString& source = "");
+ ~DocPrivate();
+
+ void addAlso(const Text& also);
+ void constructExtra();
+ bool isEnumDocSimplifiable() const;
+
+ // ### move some of this in DocPrivateExtra
+ Location start_loc;
+ Location end_loc;
+ QString src;
+ Text text;
+ QSet<QString> params;
+ QList<Text> alsoList;
+ QStringList enumItemList;
+ QStringList omitEnumItemList;
+ QSet<QString> metacommandsUsed;
+ QCommandMap metaCommandMap;
+ bool hasLegalese : 1;
+ bool hasSectioningUnits : 1;
+ DocPrivateExtra *extra;
+ TopicList topics;
+ DitaRefList ditamap_;
+};
+
+DocPrivate::DocPrivate(const Location& start,
+ const Location& end,
+ const QString& source)
+ : start_loc(start),
+ end_loc(end),
+ src(source),
+ hasLegalese(false),
+ hasSectioningUnits(false),
+ extra(0)
+{
+ // nothing.
+}
+
+/*!
+ If the doc is a ditamap, the destructor deletes each element
+ in the ditamap structure. These were allocated as needed.
+ */
+DocPrivate::~DocPrivate()
+{
+ delete extra;
+ foreach (DitaRef* t, ditamap_) {
+ delete t;
+ }
+}
+
+void DocPrivate::addAlso(const Text& also)
+{
+ alsoList.append(also);
+}
+
+void DocPrivate::constructExtra()
+{
+ if (extra == 0)
+ extra = new DocPrivateExtra;
+}
+
+bool DocPrivate::isEnumDocSimplifiable() const
+{
+ bool justMetColon = false;
+ int numValueTables = 0;
+
+ const Atom *atom = text.firstAtom();
+ while (atom) {
+ if (atom->type() == Atom::AutoLink || atom->type() == Atom::String) {
+ justMetColon = atom->string().endsWith(QLatin1Char(':'));
+ }
+ else if ((atom->type() == Atom::ListLeft) &&
+ (atom->string() == ATOM_LIST_VALUE)) {
+ if (justMetColon || numValueTables > 0)
+ return false;
+ ++numValueTables;
+ }
+ atom = atom->next();
+ }
+ return true;
+}
+
+class DocParser
+{
+public:
+ void parse(const QString &source,
+ DocPrivate *docPrivate,
+ const QSet<QString> &metaCommandSet,
+ const QSet<QString>& possibleTopics);
+
+ static int endCmdFor(int cmd);
+ static QString cmdName(int cmd);
+ static QString endCmdName(int cmd);
+ static QString untabifyEtc(const QString& str);
+ static int indentLevel(const QString& str);
+ static QString unindent(int level, const QString& str);
+ static QString slashed(const QString& str);
+
+ static int tabSize;
+ static QStringList exampleFiles;
+ static QStringList exampleDirs;
+ static QStringList sourceFiles;
+ static QStringList sourceDirs;
+ static bool quoting;
+
+private:
+ Location& location();
+ QString detailsUnknownCommand(const QSet<QString>& metaCommandSet,
+ const QString& str);
+ void checkExpiry(const QString& date);
+ void insertBaseName(const QString &baseName);
+ void insertTarget(const QString& target, bool keyword);
+ void include(const QString& fileName, const QString& identifier);
+ void startFormat(const QString& format, int cmd);
+ bool openCommand(int cmd);
+ bool closeCommand(int endCmd);
+ void startSection(Doc::Sections unit, int cmd);
+ void endSection(int unit, int endCmd);
+ void parseAlso();
+ void append(Atom::Type type, const QString& string = "");
+ void append(Atom::Type type, const QString& p1, const QString& p2);
+ void appendChar(QChar ch);
+ void appendWord(const QString &word);
+ void appendToCode(const QString &code);
+ void appendToCode(const QString &code, Atom::Type defaultType);
+ void startNewPara();
+ void enterPara(Atom::Type leftType = Atom::ParaLeft,
+ Atom::Type rightType = Atom::ParaRight,
+ const QString& string = "");
+ void leavePara();
+ void leaveValue();
+ void leaveValueList();
+ void leaveTableRow();
+ CodeMarker *quoteFromFile();
+ void expandMacro(const QString& name, const QString& def, int numParams);
+ QString expandMacroToString(const QString &name, const QString &def, int numParams);
+ Doc::Sections getSectioningUnit();
+ QString getArgument(bool verbatim = false);
+ QString getBracedArgument(bool verbatim);
+ QString getOptionalArgument();
+ QString getRestOfLine();
+ QString getMetaCommandArgument(const QString &cmdStr);
+ QString getUntilEnd(int cmd);
+ QString getCode(int cmd, CodeMarker *marker);
+ QString getUnmarkedCode(int cmd);
+
+ bool isBlankLine();
+ bool isLeftBraceAhead();
+ void skipSpacesOnLine();
+ void skipSpacesOrOneEndl();
+ void skipAllSpaces();
+ void skipToNextPreprocessorCommand();
+
+ QStack<int> openedInputs;
+
+ QString in;
+ int pos;
+ int len;
+ Location cachedLoc;
+ int cachedPos;
+
+ DocPrivate* priv;
+ enum ParagraphState {
+ OutsideParagraph,
+ InSingleLineParagraph,
+ InMultiLineParagraph
+ };
+ ParagraphState paraState;
+ bool inTableHeader;
+ bool inTableRow;
+ bool inTableItem;
+ bool indexStartedPara; // ### rename
+ Atom::Type pendingParaLeftType;
+ Atom::Type pendingParaRightType;
+ QString pendingParaString;
+
+ int braceDepth;
+ int minIndent;
+ Doc::Sections currentSection;
+ QMap<QString, Location> targetMap;
+ QMap<int, QString> pendingFormats;
+ QStack<int> openedCommands;
+ QStack<OpenedList> openedLists;
+ Quoter quoter;
+ QStack<DitaRef*> ditarefs_;
+};
+
+int DocParser::tabSize;
+QStringList DocParser::exampleFiles;
+QStringList DocParser::exampleDirs;
+QStringList DocParser::sourceFiles;
+QStringList DocParser::sourceDirs;
+bool DocParser::quoting;
+
+/*!
+ Parse the \a source string to build a Text data structure
+ in \a docPrivate. The Text data structure is a linked list
+ of Atoms.
+
+ \a metaCommandSet is the set of metacommands that may be
+ found in \a source. These metacommands are not markup text
+ commands. They are topic commands and related metacommands.
+ */
+void DocParser::parse(const QString& source,
+ DocPrivate *docPrivate,
+ const QSet<QString>& metaCommandSet,
+ const QSet<QString>& possibleTopics)
+{
+ in = source;
+ pos = 0;
+ len = in.length();
+ cachedLoc = docPrivate->start_loc;
+ cachedPos = 0;
+ priv = docPrivate;
+ priv->text << Atom::Nop;
+ priv->topics.clear();
+
+ paraState = OutsideParagraph;
+ inTableHeader = false;
+ inTableRow = false;
+ inTableItem = false;
+ indexStartedPara = false;
+ pendingParaLeftType = Atom::Nop;
+ pendingParaRightType = Atom::Nop;
+
+ braceDepth = 0;
+ minIndent = INT_MAX;
+ currentSection = Doc::NoSection;
+ openedCommands.push(CMD_OMIT);
+ quoter.reset();
+
+ CodeMarker *marker = 0;
+ Atom *currentLinkAtom = 0;
+ QString p1, p2;
+ QStack<bool> preprocessorSkipping;
+ int numPreprocessorSkipping = 0;
+
+ while (pos < len) {
+ QChar ch = in.at(pos);
+
+ switch (ch.unicode()) {
+ case '\\':
+ {
+ QString cmdStr;
+ pos++;
+ while (pos < len) {
+ ch = in.at(pos);
+ if (ch.isLetterOrNumber()) {
+ cmdStr += ch;
+ pos++;
+ }
+ else {
+ break;
+ }
+ }
+ if (cmdStr.isEmpty()) {
+ if (pos < len) {
+ enterPara();
+ if (in.at(pos).isSpace()) {
+ skipAllSpaces();
+ appendChar(QLatin1Char(' '));
+ }
+ else {
+ appendChar(in.at(pos++));
+ }
+ }
+ }
+ else {
+ int cmd = cmdHash()->value(cmdStr,NOT_A_CMD);
+ switch (cmd) {
+ case CMD_A:
+ enterPara();
+ p1 = getArgument();
+ append(Atom::FormattingLeft,ATOM_FORMATTING_PARAMETER);
+ append(Atom::String, p1);
+ append(Atom::FormattingRight,ATOM_FORMATTING_PARAMETER);
+ priv->params.insert(p1);
+ break;
+ case CMD_ABSTRACT:
+ if (openCommand(cmd)) {
+ leavePara();
+ append(Atom::AbstractLeft);
+ }
+ break;
+ case CMD_BADCODE:
+ leavePara();
+ append(Atom::CodeBad,getCode(CMD_BADCODE, marker));
+ break;
+ case CMD_BASENAME:
+ leavePara();
+ insertBaseName(getArgument());
+ break;
+ case CMD_BOLD:
+ location().warning(tr("'\\bold' is deprecated. Use '\\b'"));
+ case CMD_B:
+ startFormat(ATOM_FORMATTING_BOLD, cmd);
+ break;
+ case CMD_BRIEF:
+ leavePara();
+ enterPara(Atom::BriefLeft, Atom::BriefRight);
+ break;
+ case CMD_C:
+ enterPara();
+ p1 = untabifyEtc(getArgument(true));
+ marker = CodeMarker::markerForCode(p1);
+ append(Atom::C, marker->markedUpCode(p1, 0, location()));
+ break;
+ case CMD_CAPTION:
+ leavePara();
+ enterPara(Atom::CaptionLeft, Atom::CaptionRight);
+ break;
+ case CMD_CHAPTER:
+ startSection(Doc::Chapter, cmd);
+ break;
+ case CMD_CODE:
+ leavePara();
+ append(Atom::Code, getCode(CMD_CODE, 0));
+ break;
+ case CMD_QML:
+ leavePara();
+ append(Atom::Qml, getCode(CMD_QML, CodeMarker::markerForLanguage(QLatin1String("QML"))));
+ break;
+ case CMD_QMLTEXT:
+ append(Atom::QmlText);
+ break;
+ case CMD_JS:
+ leavePara();
+ append(Atom::JavaScript, getCode(CMD_JS, CodeMarker::markerForLanguage(QLatin1String("JavaScript"))));
+ break;
+ case CMD_DIV:
+ leavePara();
+ p1 = getArgument(true);
+ append(Atom::DivLeft, p1);
+ openedCommands.push(cmd);
+ break;
+ case CMD_ENDDIV:
+ leavePara();
+ append(Atom::DivRight);
+ closeCommand(cmd);
+ break;
+ case CMD_CODELINE:
+ {
+ if (!quoting) {
+ if (priv->text.lastAtom()->type() == Atom::Code
+ && priv->text.lastAtom()->string().endsWith("\n\n"))
+ priv->text.lastAtom()->chopString();
+ appendToCode("\n");
+ }
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ append(Atom::CodeQuoteArgument, " ");
+ }
+ }
+ break;
+ case CMD_DOTS:
+ {
+ if (!quoting) {
+ if (priv->text.lastAtom()->type() == Atom::Code
+ && priv->text.lastAtom()->string().endsWith("\n\n"))
+ priv->text.lastAtom()->chopString();
+
+ QString arg = getOptionalArgument();
+ int indent = 4;
+ if (!arg.isEmpty())
+ indent = arg.toInt();
+ for (int i = 0; i < indent; ++i)
+ appendToCode(" ");
+ appendToCode("...\n");
+ }
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ QString arg = getOptionalArgument();
+ if (arg.isEmpty())
+ arg = "4";
+ append(Atom::CodeQuoteArgument, arg);
+ }
+ }
+ break;
+ case CMD_ELSE:
+ if (preprocessorSkipping.size() > 0) {
+ if (preprocessorSkipping.top()) {
+ --numPreprocessorSkipping;
+ }
+ else {
+ ++numPreprocessorSkipping;
+ }
+ preprocessorSkipping.top() = !preprocessorSkipping.top();
+ (void)getRestOfLine(); // ### should ensure that it's empty
+ if (numPreprocessorSkipping)
+ skipToNextPreprocessorCommand();
+ }
+ else {
+ location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_ELSE)));
+ }
+ break;
+ case CMD_ENDABSTRACT:
+ if (closeCommand(cmd)) {
+ leavePara();
+ append(Atom::AbstractRight);
+ }
+ break;
+ case CMD_ENDCHAPTER:
+ endSection(Doc::Chapter, cmd);
+ break;
+ case CMD_ENDCODE:
+ closeCommand(cmd);
+ break;
+ case CMD_ENDQML:
+ closeCommand(cmd);
+ break;
+ case CMD_ENDQMLTEXT:
+ append(Atom::EndQmlText);
+ break;
+ case CMD_ENDJS:
+ closeCommand(cmd);
+ break;
+ case CMD_ENDFOOTNOTE:
+ if (closeCommand(cmd)) {
+ leavePara();
+ append(Atom::FootnoteRight);
+ paraState = InMultiLineParagraph; // ###
+ }
+ break;
+ case CMD_ENDIF:
+ if (preprocessorSkipping.count() > 0) {
+ if (preprocessorSkipping.pop())
+ --numPreprocessorSkipping;
+ (void)getRestOfLine(); // ### should ensure that it's empty
+ if (numPreprocessorSkipping)
+ skipToNextPreprocessorCommand();
+ }
+ else {
+ location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_ENDIF)));
+ }
+ break;
+ case CMD_ENDLEGALESE:
+ if (closeCommand(cmd)) {
+ leavePara();
+ append(Atom::LegaleseRight);
+ }
+ break;
+ case CMD_ENDLINK:
+ if (closeCommand(cmd)) {
+ if (priv->text.lastAtom()->type() == Atom::String
+ && priv->text.lastAtom()->string().endsWith(QLatin1Char(' ')))
+ priv->text.lastAtom()->chopString();
+ append(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ }
+ break;
+ case CMD_ENDLIST:
+ if (closeCommand(cmd)) {
+ leavePara();
+ if (openedLists.top().isStarted()) {
+ append(Atom::ListItemRight,
+ openedLists.top().styleString());
+ append(Atom::ListRight,
+ openedLists.top().styleString());
+ }
+ openedLists.pop();
+ }
+ break;
+ case CMD_ENDMAPREF:
+ case CMD_ENDTOPICREF:
+ if (closeCommand(cmd)) {
+ ditarefs_.pop(); // zzz
+ }
+ break;
+ case CMD_ENDOMIT:
+ closeCommand(cmd);
+ break;
+ case CMD_ENDPART:
+ endSection(Doc::Part, cmd);
+ break;
+ case CMD_ENDQUOTATION:
+ if (closeCommand(cmd)) {
+ leavePara();
+ append(Atom::QuotationRight);
+ }
+ break;
+ case CMD_ENDRAW:
+ location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_ENDRAW)));
+ break;
+ case CMD_ENDSECTION1:
+ endSection(Doc::Section1, cmd);
+ break;
+ case CMD_ENDSECTION2:
+ endSection(Doc::Section2, cmd);
+ break;
+ case CMD_ENDSECTION3:
+ endSection(Doc::Section3, cmd);
+ break;
+ case CMD_ENDSECTION4:
+ endSection(Doc::Section4, cmd);
+ break;
+ case CMD_ENDSIDEBAR:
+ if (closeCommand(cmd)) {
+ leavePara();
+ append(Atom::SidebarRight);
+ }
+ break;
+ case CMD_ENDTABLE:
+ if (closeCommand(cmd)) {
+ leaveTableRow();
+ append(Atom::TableRight);
+ }
+ break;
+ case CMD_EXPIRE:
+ checkExpiry(getArgument());
+ break;
+ case CMD_FOOTNOTE:
+ if (openCommand(cmd)) {
+ enterPara();
+ append(Atom::FootnoteLeft);
+ paraState = OutsideParagraph; // ###
+ }
+ break;
+ case CMD_ANNOTATEDLIST:
+ append(Atom::AnnotatedList, getArgument());
+ break;
+ case CMD_SINCELIST:
+ append(Atom::SinceList, getRestOfLine().simplified());
+ break;
+ case CMD_GENERATELIST:
+ append(Atom::GeneratedList, getArgument());
+ break;
+ case CMD_GRANULARITY:
+ priv->constructExtra();
+ priv->extra->granularity = getSectioningUnit();
+ break;
+ case CMD_HEADER:
+ if (openedCommands.top() == CMD_TABLE) {
+ leaveTableRow();
+ append(Atom::TableHeaderLeft);
+ inTableHeader = true;
+ }
+ else {
+ if (openedCommands.contains(CMD_TABLE)) {
+ location().warning(tr("Cannot use '\\%1' within '\\%2'")
+ .arg(cmdName(CMD_HEADER))
+ .arg(cmdName(openedCommands.top())));
+ }
+ else {
+ location().warning(tr("Cannot use '\\%1' outside of '\\%2'")
+ .arg(cmdName(CMD_HEADER))
+ .arg(cmdName(CMD_TABLE)));
+ }
+ }
+ break;
+ case CMD_I:
+ location().warning(tr("'\\i' is deprecated. Use '\\e' for italic or '\\li' for list item"));
+ case CMD_E:
+ startFormat(ATOM_FORMATTING_ITALIC, cmd);
+ break;
+ case CMD_IF:
+ preprocessorSkipping.push(!Tokenizer::isTrue(getRestOfLine()));
+ if (preprocessorSkipping.top())
+ ++numPreprocessorSkipping;
+ if (numPreprocessorSkipping)
+ skipToNextPreprocessorCommand();
+ break;
+ case CMD_IMAGE:
+ leaveValueList();
+ append(Atom::Image, getArgument());
+ append(Atom::ImageText, getRestOfLine());
+ break;
+ case CMD_IMPORTANT:
+ leavePara();
+ enterPara(Atom::ImportantLeft, Atom::ImportantRight);
+ break;
+ case CMD_INCLUDE:
+ {
+ QString fileName = getArgument();
+ QString identifier = getRestOfLine();
+ include(fileName, identifier);
+ }
+ break;
+ case CMD_INLINEIMAGE:
+ enterPara();
+ append(Atom::InlineImage, getArgument());
+ append(Atom::ImageText, getRestOfLine());
+ append(Atom::String, " ");
+ break;
+ case CMD_INDEX:
+ if (paraState == OutsideParagraph) {
+ enterPara();
+ indexStartedPara = true;
+ }
+ else {
+ const Atom *last = priv->text.lastAtom();
+ if (indexStartedPara &&
+ (last->type() != Atom::FormattingRight ||
+ last->string() != ATOM_FORMATTING_INDEX))
+ indexStartedPara = false;
+ }
+ startFormat(ATOM_FORMATTING_INDEX, cmd);
+ break;
+ case CMD_KEYWORD:
+ insertTarget(getRestOfLine(),true);
+ break;
+ case CMD_L:
+ enterPara();
+ if (isLeftBraceAhead()) {
+ p1 = getArgument();
+ append(Atom::Link, p1);
+ if (isLeftBraceAhead()) {
+ currentLinkAtom = priv->text.lastAtom();
+ startFormat(ATOM_FORMATTING_LINK, cmd);
+ }
+ else {
+ append(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ append(Atom::String, cleanLink(p1));
+ append(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ }
+ }
+ else {
+ p1 = getArgument();
+ append(Atom::Link, p1);
+ append(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ append(Atom::String, cleanLink(p1));
+ append(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ }
+ break;
+ case CMD_LEGALESE:
+ leavePara();
+ if (openCommand(cmd))
+ append(Atom::LegaleseLeft);
+ docPrivate->hasLegalese = true;
+ break;
+ case CMD_LINK:
+ if (openCommand(cmd)) {
+ enterPara();
+ p1 = getArgument();
+ append(Atom::Link, p1);
+ append(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ skipSpacesOrOneEndl();
+ }
+ break;
+ case CMD_LIST:
+ if (openCommand(cmd)) {
+ leavePara();
+ openedLists.push(OpenedList(location(),
+ getOptionalArgument()));
+ }
+ break;
+ case CMD_TOPICREF:
+ case CMD_MAPREF:
+ if (openCommand(cmd)) {
+ DitaRef* t = 0;
+ if (cmd == CMD_MAPREF)
+ t = new MapRef();
+ else
+ t = new TopicRef();
+ t->setNavtitle(getArgument(true));
+ if (cmd == CMD_MAPREF)
+ t->setHref(getArgument());
+ else
+ t->setHref(getOptionalArgument());
+ if (ditarefs_.isEmpty())
+ priv->ditamap_.append(t);
+ else
+ ditarefs_.top()->appendSubref(t);
+ ditarefs_.push(t);
+ }
+ break;
+ case CMD_META:
+ priv->constructExtra();
+ p1 = getArgument();
+ priv->extra->metaMap.insert(p1, getArgument());
+ break;
+ case CMD_NEWCODE:
+ location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_NEWCODE)));
+ break;
+ case CMD_NOTE:
+ leavePara();
+ enterPara(Atom::NoteLeft, Atom::NoteRight);
+ break;
+ case CMD_O:
+ location().warning(tr("'\\o' is deprecated. Use '\\li'"));
+ case CMD_LI:
+ leavePara();
+ if (openedCommands.top() == CMD_LIST) {
+ if (openedLists.top().isStarted()) {
+ append(Atom::ListItemRight,
+ openedLists.top().styleString());
+ }
+ else {
+ append(Atom::ListLeft,
+ openedLists.top().styleString());
+ }
+ openedLists.top().next();
+ append(Atom::ListItemNumber,
+ openedLists.top().numberString());
+ append(Atom::ListItemLeft,
+ openedLists.top().styleString());
+ enterPara();
+ }
+ else if (openedCommands.top() == CMD_TABLE) {
+ p1 = "1,1";
+ p2 = "";
+ if (isLeftBraceAhead()) {
+ p1 = getArgument();
+ if (isLeftBraceAhead()) {
+ p2 = getArgument();
+ }
+ }
+
+ if (!inTableHeader && !inTableRow) {
+ location().warning(tr("Missing '\\%1' or '\\%1' before '\\%3'")
+ .arg(cmdName(CMD_HEADER))
+ .arg(cmdName(CMD_ROW))
+ .arg(cmdName(CMD_LI)));
+ append(Atom::TableRowLeft);
+ inTableRow = true;
+ }
+ else if (inTableItem) {
+ append(Atom::TableItemRight);
+ inTableItem = false;
+ }
+
+ append(Atom::TableItemLeft, p1, p2);
+ inTableItem = true;
+ }
+ else {
+ location().warning(tr("Command '\\%1' outside of '\\%2' and '\\%3'")
+ .arg(cmdName(cmd))
+ .arg(cmdName(CMD_LIST))
+ .arg(cmdName(CMD_TABLE)));
+ }
+ break;
+ case CMD_OLDCODE:
+ leavePara();
+ append(Atom::CodeOld, getCode(CMD_OLDCODE, marker));
+ append(Atom::CodeNew, getCode(CMD_NEWCODE, marker));
+ break;
+ case CMD_OMIT:
+ getUntilEnd(cmd);
+ break;
+ case CMD_OMITVALUE:
+ p1 = getArgument();
+ if (!priv->enumItemList.contains(p1))
+ priv->enumItemList.append(p1);
+ if (!priv->omitEnumItemList.contains(p1))
+ priv->omitEnumItemList.append(p1);
+ break;
+ case CMD_PART:
+ startSection(Doc::Part, cmd);
+ break;
+ case CMD_PRINTLINE:
+ leavePara();
+ if (!quoting)
+ appendToCode(quoter.quoteLine(location(), cmdStr,
+ getRestOfLine()));
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ append(Atom::CodeQuoteArgument, getRestOfLine());
+ }
+ break;
+ case CMD_PRINTTO:
+ leavePara();
+ if (!quoting)
+ appendToCode(quoter.quoteTo(location(), cmdStr,
+ getRestOfLine()));
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ append(Atom::CodeQuoteArgument, getRestOfLine());
+ }
+ break;
+ case CMD_PRINTUNTIL:
+ leavePara();
+ if (!quoting)
+ appendToCode(quoter.quoteUntil(location(), cmdStr,
+ getRestOfLine()));
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ append(Atom::CodeQuoteArgument, getRestOfLine());
+ }
+ break;
+ case CMD_QUOTATION:
+ if (openCommand(cmd)) {
+ leavePara();
+ append(Atom::QuotationLeft);
+ }
+ break;
+ case CMD_QUOTEFILE:
+ {
+ leavePara();
+ QString fileName = getArgument();
+ Doc::quoteFromFile(location(), quoter, fileName);
+ if (!quoting) {
+ append(Atom::Code,
+ quoter.quoteTo(location(), cmdStr, ""));
+ quoter.reset();
+ }
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ append(Atom::CodeQuoteArgument, fileName);
+ }
+ break;
+ }
+ case CMD_QUOTEFROMFILE:
+ leavePara();
+ if (!quoting)
+ quoteFromFile();
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ append(Atom::CodeQuoteArgument, getArgument());
+ }
+ break;
+ case CMD_QUOTEFUNCTION:
+ leavePara();
+ marker = quoteFromFile();
+ p1 = getRestOfLine();
+ if (!quoting) {
+ quoter.quoteTo(location(), cmdStr,
+ slashed(marker->functionBeginRegExp(p1)));
+ append(Atom::Code,
+ quoter.quoteUntil(location(), cmdStr,
+ slashed(marker->functionEndRegExp(p1))));
+ quoter.reset();
+ }
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ append(Atom::CodeQuoteArgument, slashed(marker->functionEndRegExp(p1)));
+ }
+ break;
+ case CMD_RAW:
+ leavePara();
+ p1 = getRestOfLine();
+ if (p1.isEmpty())
+ location().warning(tr("Missing format name after '\\%1")
+ .arg(cmdName(CMD_RAW)));
+ append(Atom::FormatIf, p1);
+ append(Atom::RawString, untabifyEtc(getUntilEnd(cmd)));
+ append(Atom::FormatElse);
+ append(Atom::FormatEndif);
+ break;
+ case CMD_ROW:
+ if (openedCommands.top() == CMD_TABLE) {
+ p1.clear();
+ if (isLeftBraceAhead())
+ p1 = getArgument(true);
+ leaveTableRow();
+ append(Atom::TableRowLeft,p1);
+ inTableRow = true;
+ }
+ else {
+ if (openedCommands.contains(CMD_TABLE)) {
+ location().warning(tr("Cannot use '\\%1' within '\\%2'")
+ .arg(cmdName(CMD_ROW))
+ .arg(cmdName(openedCommands.top())));
+ }
+ else {
+ location().warning(tr("Cannot use '\\%1' outside of '\\%2'")
+ .arg(cmdName(CMD_ROW))
+ .arg(cmdName(CMD_TABLE)));
+ }
+ }
+ break;
+ case CMD_SA:
+ parseAlso();
+ break;
+ case CMD_SECTION1:
+ startSection(Doc::Section1, cmd);
+ break;
+ case CMD_SECTION2:
+ startSection(Doc::Section2, cmd);
+ break;
+ case CMD_SECTION3:
+ startSection(Doc::Section3, cmd);
+ break;
+ case CMD_SECTION4:
+ startSection(Doc::Section4, cmd);
+ break;
+ case CMD_SIDEBAR:
+ if (openCommand(cmd)) {
+ leavePara();
+ append(Atom::SidebarLeft);
+ }
+ break;
+ case CMD_SKIPLINE:
+ leavePara();
+ if (!quoting)
+ quoter.quoteLine(location(),
+ cmdStr,
+ getRestOfLine());
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ append(Atom::CodeQuoteArgument, getRestOfLine());
+ }
+ break;
+ case CMD_SKIPTO:
+ leavePara();
+ if (!quoting)
+ quoter.quoteTo(location(),
+ cmdStr,
+ getRestOfLine());
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ append(Atom::CodeQuoteArgument, getRestOfLine());
+ }
+ break;
+ case CMD_SKIPUNTIL:
+ leavePara();
+ if (!quoting)
+ quoter.quoteUntil(location(),
+ cmdStr,
+ getRestOfLine());
+ else {
+ append(Atom::CodeQuoteCommand, cmdStr);
+ append(Atom::CodeQuoteArgument, getRestOfLine());
+ }
+ break;
+ case CMD_SPAN:
+ p1 = ATOM_FORMATTING_SPAN + getArgument(true);
+ startFormat(p1, cmd);
+ break;
+ case CMD_SNIPPET:
+ leavePara();
+ {
+ QString snippet = getArgument();
+ QString identifier = getRestOfLine();
+ if (quoting) {
+ append(Atom::SnippetCommand, cmdStr);
+ append(Atom::SnippetLocation, snippet);
+ append(Atom::SnippetIdentifier, identifier);
+ }
+ else {
+ marker = Doc::quoteFromFile(location(),quoter,snippet);
+ appendToCode(quoter.quoteSnippet(location(), identifier), marker->atomType());
+ }
+ }
+ break;
+ case CMD_SUB:
+ startFormat(ATOM_FORMATTING_SUBSCRIPT, cmd);
+ break;
+ case CMD_SUP:
+ startFormat(ATOM_FORMATTING_SUPERSCRIPT, cmd);
+ break;
+ case CMD_TABLE:
+ //p1 = getRestOfLine();
+ p1 = getOptionalArgument();
+ p2 = getOptionalArgument();
+ if (openCommand(cmd)) {
+ leavePara();
+ append(Atom::TableLeft, p1, p2);
+ inTableHeader = false;
+ inTableRow = false;
+ inTableItem = false;
+ }
+ break;
+ case CMD_TABLEOFCONTENTS:
+ p1 = "1";
+ if (isLeftBraceAhead())
+ p1 = getArgument();
+ p1 += ",";
+ p1 += QString::number((int)getSectioningUnit());
+ append(Atom::TableOfContents, p1);
+ break;
+ case CMD_TARGET:
+ insertTarget(getRestOfLine(),false);
+ break;
+ case CMD_TT:
+ startFormat(ATOM_FORMATTING_TELETYPE, cmd);
+ break;
+ case CMD_UNDERLINE:
+ startFormat(ATOM_FORMATTING_UNDERLINE, cmd);
+ break;
+ case CMD_UNICODE:
+ enterPara();
+ p1 = getArgument();
+ {
+ bool ok;
+ uint unicodeChar = p1.toUInt(&ok, 0);
+ if (!ok ||
+ (unicodeChar == 0x0000) ||
+ (unicodeChar > 0xFFFE)) {
+ location().warning(tr("Invalid Unicode character '%1' specified "
+ "with '%2'")
+ .arg(p1, cmdName(CMD_UNICODE)));
+ }
+ else {
+ append(Atom::String, QChar(unicodeChar));
+ }
+ }
+ break;
+ case CMD_VALUE:
+ leaveValue();
+ if (openedLists.top().style() == OpenedList::Value) {
+ p1 = getArgument();
+ if (!priv->enumItemList.contains(p1))
+ priv->enumItemList.append(p1);
+
+ openedLists.top().next();
+ append(Atom::ListTagLeft, ATOM_LIST_VALUE);
+ append(Atom::String, p1);
+ append(Atom::ListTagRight, ATOM_LIST_VALUE);
+ append(Atom::ListItemLeft, ATOM_LIST_VALUE);
+
+ skipSpacesOrOneEndl();
+ if (isBlankLine())
+ append(Atom::Nop);
+ }
+ else {
+ // ### problems
+ }
+ break;
+ case CMD_WARNING:
+ leavePara();
+ enterPara();
+ append(Atom::FormattingLeft, ATOM_FORMATTING_BOLD);
+ append(Atom::String, "Warning:");
+ append(Atom::FormattingRight, ATOM_FORMATTING_BOLD);
+ append(Atom::String, " ");
+ break;
+ case CMD_OVERLOAD:
+ priv->metacommandsUsed.insert(cmdStr);
+ p1.clear();
+ if (!isBlankLine())
+ p1 = getRestOfLine();
+ if (!p1.isEmpty()) {
+ append(Atom::ParaLeft);
+ append(Atom::String, "This function overloads ");
+ append(Atom::AutoLink,p1);
+ append(Atom::String, ".");
+ append(Atom::ParaRight);
+ }
+ else {
+ append(Atom::ParaLeft);
+ append(Atom::String,"This is an overloaded function.");
+ append(Atom::ParaRight);
+ p1 = getMetaCommandArgument(cmdStr);
+ }
+ priv->metaCommandMap[cmdStr].append(p1);
+ break;
+ case NOT_A_CMD:
+ if (metaCommandSet.contains(cmdStr)) {
+ priv->metacommandsUsed.insert(cmdStr);
+ QString arg = getMetaCommandArgument(cmdStr);
+ priv->metaCommandMap[cmdStr].append(arg);
+ if (possibleTopics.contains(cmdStr)) {
+ priv->topics.append(Topic(cmdStr,arg));
+ }
+ }
+ else if (macroHash()->contains(cmdStr)) {
+ const Macro &macro = macroHash()->value(cmdStr);
+ int numPendingFi = 0;
+ QStringMap::ConstIterator d;
+ d = macro.otherDefs.begin();
+ while (d != macro.otherDefs.end()) {
+ append(Atom::FormatIf, d.key());
+ expandMacro(cmdStr, *d, macro.numParams);
+ ++d;
+
+ if (d == macro.otherDefs.end()) {
+ append(Atom::FormatEndif);
+ }
+ else {
+ append(Atom::FormatElse);
+ numPendingFi++;
+ }
+ }
+ while (numPendingFi-- > 0)
+ append(Atom::FormatEndif);
+
+ if (!macro.defaultDef.isEmpty()) {
+ if (!macro.otherDefs.isEmpty()) {
+ macro.defaultDefLocation.warning(
+ tr("Macro cannot have both "
+ "format-specific and qdoc- "
+ "syntax definitions"));
+ }
+ else {
+ location().push(macro.defaultDefLocation.filePath());
+ in.insert(pos, expandMacroToString(cmdStr, macro.defaultDef, macro.numParams));
+ len = in.length();
+ openedInputs.push(pos + macro.defaultDef.length());
+ }
+ }
+ }
+ else {
+ location().warning(
+ tr("Unknown command '\\%1'").arg(cmdStr),
+ detailsUnknownCommand(metaCommandSet,cmdStr));
+ enterPara();
+ append(Atom::UnknownCommand, cmdStr);
+ }
+ }
+ }
+ }
+ break;
+ case '{':
+ enterPara();
+ appendChar('{');
+ braceDepth++;
+ pos++;
+ break;
+ case '}':
+ {
+ braceDepth--;
+ pos++;
+
+ QMap<int, QString>::Iterator f = pendingFormats.find(braceDepth);
+ if (f == pendingFormats.end()) {
+ enterPara();
+ appendChar('}');
+ }
+ else {
+ append(Atom::FormattingRight, *f);
+ if (*f == ATOM_FORMATTING_INDEX) {
+ if (indexStartedPara)
+ skipAllSpaces();
+ }
+ else if (*f == ATOM_FORMATTING_LINK) {
+ // hack for C++ to support links like
+ // \l{QString::}{count()}
+ if (currentLinkAtom &&
+ currentLinkAtom->string().endsWith("::")) {
+ QString suffix = Text::subText(currentLinkAtom,
+ priv->text.lastAtom()).toString();
+ currentLinkAtom->appendString(suffix);
+ }
+ currentLinkAtom = 0;
+ }
+ pendingFormats.erase(f);
+ }
+ }
+ break;
+ default:
+ {
+ bool newWord;
+ switch (priv->text.lastAtom()->type()) {
+ case Atom::ParaLeft:
+ newWord = true;
+ break;
+ default:
+ newWord = false;
+ }
+
+ if (paraState == OutsideParagraph) {
+ if (ch.isSpace()) {
+ ++pos;
+ newWord = false;
+ }
+ else {
+ enterPara();
+ newWord = true;
+ }
+ }
+ else {
+ if (ch.isSpace()) {
+ ++pos;
+ if ((ch == '\n') &&
+ (paraState == InSingleLineParagraph ||
+ isBlankLine())) {
+ leavePara();
+ newWord = false;
+ }
+ else {
+ appendChar(' ');
+ newWord = true;
+ }
+ }
+ else {
+ newWord = true;
+ }
+ }
+
+ if (newWord) {
+ int startPos = pos;
+ int numInternalUppercase = 0;
+ int numLowercase = 0;
+ int numStrangeSymbols = 0;
+
+ while (pos < len) {
+ unsigned char latin1Ch = in.at(pos).toLatin1();
+ if (islower(latin1Ch)) {
+ ++numLowercase;
+ ++pos;
+ }
+ else if (isupper(latin1Ch)) {
+ if (pos > startPos)
+ ++numInternalUppercase;
+ ++pos;
+ }
+ else if (isdigit(latin1Ch)) {
+ if (pos > startPos) {
+ ++pos;
+ }
+ else {
+ break;
+ }
+ }
+ else if (latin1Ch == '_' || latin1Ch == '@') {
+ ++numStrangeSymbols;
+ ++pos;
+ }
+ else if (latin1Ch == ':' && pos < len - 1
+ && in.at(pos + 1) == QLatin1Char(':')) {
+ ++numStrangeSymbols;
+ pos += 2;
+ }
+ else if (latin1Ch == '(') {
+ if (pos > startPos) {
+ if (pos < len - 1 &&
+ in.at(pos + 1) == QLatin1Char(')')) {
+ ++numStrangeSymbols;
+ pos += 2;
+ break;
+ }
+ else {
+ // ### handle functions with signatures
+ // and function calls
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ if (pos == startPos) {
+ if (!ch.isSpace()) {
+ appendChar(ch);
+ ++pos;
+ }
+ }
+ else {
+ QString word = in.mid(startPos, pos - startPos);
+ // is word a C++ symbol or an English word?
+ if ((numInternalUppercase >= 1 && numLowercase >= 2)
+ || numStrangeSymbols >= 1) {
+ append(Atom::AutoLink, word);
+ }
+ else {
+ appendWord(word);
+ }
+ }
+ }
+ }
+ }
+ }
+ leaveValueList();
+
+ // for compatibility
+ if (openedCommands.top() == CMD_LEGALESE) {
+ append(Atom::LegaleseRight);
+ openedCommands.pop();
+ }
+
+ if (openedCommands.top() != CMD_OMIT) {
+ location().warning(tr("Missing '\\%1'").arg(endCmdName(openedCommands.top())));
+ }
+ else if (preprocessorSkipping.count() > 0) {
+ location().warning(tr("Missing '\\%1'").arg(cmdName(CMD_ENDIF)));
+ }
+
+ if (currentSection > Doc::NoSection) {
+ append(Atom::SectionRight, QString::number(currentSection));
+ currentSection = Doc::NoSection;
+ }
+
+ if (priv->extra && priv->extra->granularity < priv->extra->section)
+ priv->extra->granularity = priv->extra->section;
+ priv->text.stripFirstAtom();
+}
+
+Location &DocParser::location()
+{
+ while (!openedInputs.isEmpty() && openedInputs.top() <= pos) {
+ cachedLoc.pop();
+ cachedPos = openedInputs.pop();
+ }
+ while (cachedPos < pos)
+ cachedLoc.advance(in.at(cachedPos++));
+ return cachedLoc;
+}
+
+QString DocParser::detailsUnknownCommand(const QSet<QString> &metaCommandSet,
+ const QString &str)
+{
+ QSet<QString> commandSet = metaCommandSet;
+ int i = 0;
+ while (cmds[i].english != 0) {
+ commandSet.insert(*cmds[i].alias);
+ i++;
+ }
+
+ if (aliasMap()->contains(str))
+ return tr("The command '\\%1' was renamed '\\%2' by the configuration"
+ " file. Use the new name.")
+ .arg(str).arg((*aliasMap())[str]);
+
+ QString best = nearestName(str, commandSet);
+ if (best.isEmpty())
+ return QString();
+ return tr("Maybe you meant '\\%1'?").arg(best);
+}
+
+void DocParser::checkExpiry(const QString& date)
+{
+ QRegExp ymd("(\\d{4})(?:-(\\d{2})(?:-(\\d{2})))");
+
+ if (ymd.exactMatch(date)) {
+ int y = ymd.cap(1).toInt();
+ int m = ymd.cap(2).toInt();
+ int d = ymd.cap(3).toInt();
+
+ if (m == 0)
+ m = 1;
+ if (d == 0)
+ d = 1;
+ QDate expiryDate(y, m, d);
+ if (expiryDate.isValid()) {
+ int days = expiryDate.daysTo(QDate::currentDate());
+ if (days == 0) {
+ location().warning(tr("Documentation expires today"));
+ }
+ else if (days == 1) {
+ location().warning(tr("Documentation expired yesterday"));
+ }
+ else if (days >= 2) {
+ location().warning(tr("Documentation expired %1 days ago")
+ .arg(days));
+ }
+ }
+ else {
+ location().warning(tr("Date '%1' invalid").arg(date));
+ }
+ }
+ else {
+ location().warning(tr("Date '%1' not in YYYY-MM-DD format")
+ .arg(date));
+ }
+}
+
+void DocParser::insertBaseName(const QString &baseName)
+{
+ priv->constructExtra();
+ if (currentSection == priv->extra->section) {
+ priv->extra->baseName = baseName;
+ }
+ else {
+ Atom *atom = priv->text.firstAtom();
+ Atom *sectionLeft = 0;
+
+ int delta = currentSection - priv->extra->section;
+
+ while (atom != 0) {
+ if (atom->type() == Atom::SectionLeft &&
+ atom->string().toInt() == delta)
+ sectionLeft = atom;
+ atom = atom->next();
+ }
+ if (sectionLeft != 0)
+ (void) new Atom(sectionLeft, Atom::BaseName, baseName);
+ }
+}
+
+void DocParser::insertTarget(const QString &target, bool keyword)
+{
+ if (targetMap.contains(target)) {
+ location().warning(tr("Duplicate target name '%1'").arg(target));
+ targetMap[target].warning(tr("(The previous occurrence is here)"));
+ }
+ else {
+ targetMap.insert(target, location());
+ append(Atom::Target, target);
+ priv->constructExtra();
+ if (keyword)
+ priv->extra->keywords.append(priv->text.lastAtom());
+ else
+ priv->extra->targets.append(priv->text.lastAtom());
+ }
+}
+
+void DocParser::include(const QString& fileName, const QString& identifier)
+{
+ if (location().depth() > 16)
+ location().fatal(tr("Too many nested '\\%1's")
+ .arg(cmdName(CMD_INCLUDE)));
+
+ QString userFriendlyFilePath;
+ // ### use current directory?
+ QString filePath = Config::findFile(location(),
+ sourceFiles,
+ sourceDirs,
+ fileName,
+ userFriendlyFilePath);
+ if (filePath.isEmpty()) {
+ location().warning(tr("Cannot find qdoc include file '%1'").arg(fileName));
+ }
+ else {
+ QFile inFile(filePath);
+ if (!inFile.open(QFile::ReadOnly)) {
+ location().warning(tr("Cannot open qdoc include file '%1'")
+ .arg(userFriendlyFilePath));
+ }
+ else {
+ location().push(userFriendlyFilePath);
+
+ QTextStream inStream(&inFile);
+ QString includedStuff = inStream.readAll();
+ inFile.close();
+
+ if (identifier.isEmpty()) {
+ in.insert(pos, includedStuff);
+ len = in.length();
+ openedInputs.push(pos + includedStuff.length());
+ }
+ else {
+ QStringList lineBuffer = includedStuff.split(QLatin1Char('\n'));
+ int i = 0;
+ int startLine = -1;
+ while (i < lineBuffer.size()) {
+ if (lineBuffer[i].startsWith("//!")) {
+ if (lineBuffer[i].contains(identifier)) {
+ startLine = i+1;
+ break;
+ }
+ }
+ ++i;
+ }
+ if (startLine < 0) {
+ location().warning(tr("Cannot find '%1' in '%2'")
+ .arg(identifier)
+ .arg(userFriendlyFilePath));
+ return;
+
+ }
+ QString result;
+ i = startLine;
+ do {
+ if (lineBuffer[i].startsWith("//!")) {
+ if (i<lineBuffer.size()) {
+ if (lineBuffer[i].contains(identifier)) {
+ break;
+ }
+ }
+ }
+ else
+ result += lineBuffer[i] + QLatin1Char('\n');
+ ++i;
+ } while (i < lineBuffer.size());
+ if (result.isEmpty()) {
+ location().warning(tr("Empty qdoc snippet '%1' in '%2'")
+ .arg(identifier)
+ .arg(userFriendlyFilePath));
+ }
+ else {
+ in.insert(pos, result);
+ len = in.length();
+ openedInputs.push(pos + result.length());
+ }
+ }
+ }
+ }
+}
+
+void DocParser::startFormat(const QString& format, int cmd)
+{
+ enterPara();
+
+ QMap<int, QString>::ConstIterator f = pendingFormats.begin();
+ while (f != pendingFormats.end()) {
+ if (*f == format) {
+ location().warning(tr("Cannot nest '\\%1' commands")
+ .arg(cmdName(cmd)));
+ return;
+ }
+ ++f;
+ }
+
+ append(Atom::FormattingLeft, format);
+
+ if (isLeftBraceAhead()) {
+ skipSpacesOrOneEndl();
+ pendingFormats.insert(braceDepth, format);
+ ++braceDepth;
+ ++pos;
+ }
+ else {
+ append(Atom::String, getArgument());
+ append(Atom::FormattingRight, format);
+ if (format == ATOM_FORMATTING_INDEX && indexStartedPara) {
+ skipAllSpaces();
+ indexStartedPara = false;
+ }
+ }
+}
+
+bool DocParser::openCommand(int cmd)
+{
+ int outer = openedCommands.top();
+ bool ok = true;
+
+ if (cmd != CMD_LINK) {
+ if (outer == CMD_LIST) {
+ ok = (cmd == CMD_FOOTNOTE || cmd == CMD_LIST);
+ }
+ else if (outer == CMD_ABSTRACT) {
+ ok = (cmd == CMD_LIST ||
+ cmd == CMD_QUOTATION ||
+ cmd == CMD_TABLE);
+ }
+ else if (outer == CMD_SIDEBAR) {
+ ok = (cmd == CMD_LIST ||
+ cmd == CMD_QUOTATION ||
+ cmd == CMD_SIDEBAR);
+ }
+ else if (outer == CMD_QUOTATION) {
+ ok = (cmd == CMD_LIST);
+ }
+ else if (outer == CMD_TABLE) {
+ ok = (cmd == CMD_LIST ||
+ cmd == CMD_FOOTNOTE ||
+ cmd == CMD_QUOTATION);
+ }
+ else if (outer == CMD_FOOTNOTE || outer == CMD_LINK) {
+ ok = false;
+ }
+ else if (outer == CMD_TOPICREF)
+ ok = (cmd == CMD_TOPICREF || cmd == CMD_MAPREF);
+ else if (outer == CMD_MAPREF)
+ ok = false;
+ }
+
+ if (ok) {
+ openedCommands.push(cmd);
+ }
+ else {
+ location().warning(tr("Can't use '\\%1' in '\\%2'").arg(cmdName(cmd)).arg(cmdName(outer)));
+ }
+ return ok;
+}
+
+bool DocParser::closeCommand(int endCmd)
+{
+ if (endCmdFor(openedCommands.top()) == endCmd && openedCommands.size() > 1) {
+ openedCommands.pop();
+ return true;
+ }
+ else {
+ bool contains = false;
+ QStack<int> opened2 = openedCommands;
+ while (opened2.size() > 1) {
+ if (endCmdFor(opened2.top()) == endCmd) {
+ contains = true;
+ break;
+ }
+ opened2.pop();
+ }
+
+ if (contains) {
+ while (endCmdFor(openedCommands.top()) != endCmd && openedCommands.size() > 1) {
+ location().warning(tr("Missing '\\%1' before '\\%2'")
+ .arg(endCmdName(openedCommands.top()))
+ .arg(cmdName(endCmd)));
+ openedCommands.pop();
+ }
+ }
+ else {
+ location().warning(tr("Unexpected '\\%1'").arg(cmdName(endCmd)));
+ }
+ return false;
+ }
+}
+
+void DocParser::startSection(Doc::Sections unit, int cmd)
+{
+ leaveValueList();
+
+ if (currentSection == Doc::NoSection) {
+ currentSection = (Doc::Sections) (unit);
+ priv->constructExtra();
+ priv->extra->section = currentSection;
+ }
+ else
+ endSection(unit,cmd);
+
+ append(Atom::SectionLeft, QString::number(unit));
+ priv->constructExtra();
+ priv->extra->tableOfContents.append(priv->text.lastAtom());
+ priv->extra->tableOfContentsLevels.append(unit);
+ enterPara(Atom::SectionHeadingLeft,
+ Atom::SectionHeadingRight,
+ QString::number(unit));
+ currentSection = unit;
+
+}
+
+void DocParser::endSection(int , int) // (int unit, int endCmd)
+{
+ leavePara();
+ append(Atom::SectionRight, QString::number(currentSection));
+ currentSection = (Doc::NoSection);
+}
+
+void DocParser::parseAlso()
+{
+ leavePara();
+ skipSpacesOnLine();
+ while (pos < len && in[pos] != '\n') {
+ QString target;
+ QString str;
+
+ if (in[pos] == '{') {
+ target = getArgument();
+ skipSpacesOnLine();
+ if (in[pos] == '{') {
+ str = getArgument();
+
+ // hack for C++ to support links like \l{QString::}{count()}
+ if (target.endsWith("::"))
+ target += str;
+ }
+ else {
+ str = target;
+ }
+#ifdef QDOC2_COMPAT
+ }
+ else if (in[pos] == '\\' && in.mid(pos, 5) == "\\link") {
+ pos += 6;
+ target = getArgument();
+ int endPos = in.indexOf("\\endlink", pos);
+ if (endPos != -1) {
+ str = in.mid(pos, endPos - pos).trimmed();
+ pos = endPos + 8;
+ }
+#endif
+ }
+ else {
+ target = getArgument();
+ str = cleanLink(target);
+ }
+
+ Text also;
+ also << Atom(Atom::Link, target)
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << str
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ priv->addAlso(also);
+
+ skipSpacesOnLine();
+ if (pos < len && in[pos] == ',') {
+ pos++;
+ skipSpacesOrOneEndl();
+ }
+ else if (in[pos] != '\n') {
+ location().warning(tr("Missing comma in '\\%1'").arg(cmdName(CMD_SA)));
+ }
+ }
+}
+
+//static bool debug = false;
+#if 0
+if (type == Atom::DivLeft)
+debug = true;
+if (debug)
+qDebug() << type << string;
+if (type == Atom::DivRight)
+debug = false;
+#endif
+
+void DocParser::append(Atom::Type type, const QString &string)
+{
+ Atom::Type lastType = priv->text.lastAtom()->type();
+ if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n")))
+ priv->text.lastAtom()->chopString();
+ priv->text << Atom(type, string);
+}
+
+void DocParser::append(Atom::Type type, const QString& p1, const QString& p2)
+{
+ Atom::Type lastType = priv->text.lastAtom()->type();
+ if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n")))
+ priv->text.lastAtom()->chopString();
+ priv->text << Atom(type, p1, p2);
+}
+
+void DocParser::appendChar(QChar ch)
+{
+ if (priv->text.lastAtom()->type() != Atom::String)
+ append(Atom::String);
+ Atom *atom = priv->text.lastAtom();
+ if (ch == QLatin1Char(' ')) {
+ if (!atom->string().endsWith(QLatin1Char(' ')))
+ atom->appendChar(QLatin1Char(' '));
+ }
+ else
+ atom->appendChar(ch);
+}
+
+void DocParser::appendWord(const QString &word)
+{
+ if (priv->text.lastAtom()->type() != Atom::String) {
+ append(Atom::String, word);
+ }
+ else
+ priv->text.lastAtom()->appendString(word);
+}
+
+void DocParser::appendToCode(const QString& markedCode)
+{
+ Atom::Type lastType = priv->text.lastAtom()->type();
+#ifdef QDOC_QML
+ if (lastType != Atom::Qml && lastType != Atom::Code && lastType != Atom::JavaScript)
+ append(Atom::Qml);
+#else
+ if (lastType != Atom::Code)
+ append(Atom::Code);
+#endif
+ priv->text.lastAtom()->appendString(markedCode);
+}
+
+void DocParser::appendToCode(const QString &markedCode, Atom::Type defaultType)
+{
+ Atom::Type lastType = priv->text.lastAtom()->type();
+ if (lastType != Atom::Qml && lastType != Atom::Code && lastType != Atom::JavaScript)
+ append(defaultType, markedCode);
+ else
+ priv->text.lastAtom()->appendString(markedCode);
+}
+
+void DocParser::startNewPara()
+{
+ leavePara();
+ enterPara();
+}
+
+void DocParser::enterPara(Atom::Type leftType,
+ Atom::Type rightType,
+ const QString& string)
+{
+ if (paraState == OutsideParagraph) {
+
+ if ((priv->text.lastAtom()->type() != Atom::ListItemLeft) &&
+ (priv->text.lastAtom()->type() != Atom::DivLeft)) {
+ leaveValueList();
+ }
+
+ append(leftType, string);
+ indexStartedPara = false;
+ pendingParaLeftType = leftType;
+ pendingParaRightType = rightType;
+ pendingParaString = string;
+ if (leftType == Atom::SectionHeadingLeft) {
+ paraState = InSingleLineParagraph;
+ }
+ else {
+ paraState = InMultiLineParagraph;
+ }
+ skipSpacesOrOneEndl();
+ }
+}
+
+void DocParser::leavePara()
+{
+ if (paraState != OutsideParagraph) {
+ if (!pendingFormats.isEmpty()) {
+ location().warning(tr("Missing '}'"));
+ pendingFormats.clear();
+ }
+
+ if (priv->text.lastAtom()->type() == pendingParaLeftType) {
+ priv->text.stripLastAtom();
+ }
+ else {
+ if (priv->text.lastAtom()->type() == Atom::String &&
+ priv->text.lastAtom()->string().endsWith(QLatin1Char(' '))) {
+ priv->text.lastAtom()->chopString();
+ }
+ append(pendingParaRightType, pendingParaString);
+ }
+ paraState = OutsideParagraph;
+ indexStartedPara = false;
+ pendingParaRightType = Atom::Nop;
+ pendingParaString = "";
+ }
+}
+
+void DocParser::leaveValue()
+{
+ leavePara();
+ if (openedLists.isEmpty()) {
+ openedLists.push(OpenedList(OpenedList::Value));
+ append(Atom::ListLeft, ATOM_LIST_VALUE);
+ }
+ else {
+ if (priv->text.lastAtom()->type() == Atom::Nop)
+ priv->text.stripLastAtom();
+ append(Atom::ListItemRight, ATOM_LIST_VALUE);
+ }
+}
+
+void DocParser::leaveValueList()
+{
+ leavePara();
+ if (!openedLists.isEmpty() &&
+ (openedLists.top().style() == OpenedList::Value)) {
+ if (priv->text.lastAtom()->type() == Atom::Nop)
+ priv->text.stripLastAtom();
+ append(Atom::ListItemRight, ATOM_LIST_VALUE);
+ append(Atom::ListRight, ATOM_LIST_VALUE);
+ openedLists.pop();
+ }
+}
+
+void DocParser::leaveTableRow()
+{
+ if (inTableItem) {
+ leavePara();
+ append(Atom::TableItemRight);
+ inTableItem = false;
+ }
+ if (inTableHeader) {
+ append(Atom::TableHeaderRight);
+ inTableHeader = false;
+ }
+ if (inTableRow) {
+ append(Atom::TableRowRight);
+ inTableRow = false;
+ }
+}
+
+CodeMarker *DocParser::quoteFromFile()
+{
+ return Doc::quoteFromFile(location(), quoter, getArgument());
+}
+
+void DocParser::expandMacro(const QString &name,
+ const QString &def,
+ int numParams)
+{
+ if (numParams == 0) {
+ append(Atom::RawString, def);
+ }
+ else {
+ QStringList args;
+ QString rawString;
+
+ for (int i = 0; i < numParams; i++) {
+ if (numParams == 1 || isLeftBraceAhead()) {
+ args << getArgument(true);
+ }
+ else {
+ location().warning(tr("Macro '\\%1' invoked with too few"
+ " arguments (expected %2, got %3)")
+ .arg(name).arg(numParams).arg(i));
+ break;
+ }
+ }
+
+ int j = 0;
+ while (j < def.size()) {
+ int paramNo;
+ if (((paramNo = def[j].unicode()) >= 1) &&
+ (paramNo <= numParams)) {
+ if (!rawString.isEmpty()) {
+ append(Atom::RawString, rawString);
+ rawString = "";
+ }
+ append(Atom::String, args[paramNo - 1]);
+ j += 1;
+ }
+ else {
+ rawString += def[j++];
+ }
+ }
+ if (!rawString.isEmpty())
+ append(Atom::RawString, rawString);
+ }
+}
+
+QString DocParser::expandMacroToString(const QString &name, const QString &def, int numParams)
+{
+ if (numParams == 0) {
+ return def;
+ }
+ else {
+ QStringList args;
+ QString rawString;
+
+ for (int i = 0; i < numParams; i++) {
+ if (numParams == 1 || isLeftBraceAhead()) {
+ args << getArgument(true);
+ }
+ else {
+ location().warning(tr("Macro '\\%1' invoked with too few"
+ " arguments (expected %2, got %3)")
+ .arg(name).arg(numParams).arg(i));
+ break;
+ }
+ }
+
+ int j = 0;
+ while (j < def.size()) {
+ int paramNo;
+ if (((paramNo = def[j].unicode()) >= 1) &&
+ (paramNo <= numParams)) {
+ rawString += args[paramNo - 1];
+ j += 1;
+ }
+ else {
+ rawString += def[j++];
+ }
+ }
+ return rawString;
+ }
+}
+
+Doc::Sections DocParser::getSectioningUnit()
+{
+ QString name = getOptionalArgument();
+
+ if (name == "part") {
+ return Doc::Part;
+ }
+ else if (name == "chapter") {
+ return Doc::Chapter;
+ }
+ else if (name == "section1") {
+ return Doc::Section1;
+ }
+ else if (name == "section2") {
+ return Doc::Section2;
+ }
+ else if (name == "section3") {
+ return Doc::Section3;
+ }
+ else if (name == "section4") {
+ return Doc::Section4;
+ }
+ else if (name.isEmpty()) {
+ return Doc::NoSection;
+ }
+ else {
+ location().warning(tr("Invalid section '%1'").arg(name));
+ return Doc::NoSection;
+ }
+}
+
+/*!
+ Gets an argument that is enclosed in braces and returns it
+ without the enclosing braces. On entry, the current character
+ is the left brace. On exit, the current character is the one
+ that comes afterr the right brace.
+
+ If \a verbatim is true, extra whitespace is retained in the
+ returned string. Otherwise, extr whitespace is removed.
+ */
+QString DocParser::getBracedArgument(bool verbatim)
+{
+ QString arg;
+ int delimDepth = 0;
+ if (pos < (int) in.length() && in[pos] == '{') {
+ pos++;
+ while (pos < (int) in.length() && delimDepth >= 0) {
+ switch (in[pos].unicode()) {
+ case '{':
+ delimDepth++;
+ arg += QLatin1Char('{');
+ pos++;
+ break;
+ case '}':
+ delimDepth--;
+ if (delimDepth >= 0)
+ arg += QLatin1Char('}');
+ pos++;
+ break;
+ case '\\':
+ if (verbatim) {
+ arg += in[pos];
+ pos++;
+ }
+ else {
+ pos++;
+ if (pos < (int) in.length()) {
+ if (in[pos].isLetterOrNumber())
+ break;
+ arg += in[pos];
+ if (in[pos].isSpace()) {
+ skipAllSpaces();
+ }
+ else {
+ pos++;
+ }
+ }
+ }
+ break;
+ default:
+ arg += in[pos];
+ pos++;
+ }
+ }
+ if (delimDepth > 0)
+ location().warning(tr("Missing '}'"));
+ }
+ return arg;
+}
+
+/*!
+ Typically, an argument ends at the next white-space. However,
+ braces can be used to group words:
+
+ {a few words}
+
+ Also, opening and closing parentheses have to match. Thus,
+
+ printf("%d\n", x)
+
+ is an argument too, although it contains spaces. Finally,
+ trailing punctuation is not included in an argument, nor is 's.
+*/
+QString DocParser::getArgument(bool verbatim)
+{
+ skipSpacesOrOneEndl();
+
+ int delimDepth = 0;
+ int startPos = pos;
+ QString arg = getBracedArgument(verbatim);
+ if (arg.isEmpty()) {
+ while ((pos < in.length()) &&
+ ((delimDepth > 0) || ((delimDepth == 0) && !in[pos].isSpace()))) {
+ switch (in[pos].unicode()) {
+ case '(':
+ case '[':
+ case '{':
+ delimDepth++;
+ arg += in[pos];
+ pos++;
+ break;
+ case ')':
+ case ']':
+ case '}':
+ delimDepth--;
+ if (pos == startPos || delimDepth >= 0) {
+ arg += in[pos];
+ pos++;
+ }
+ break;
+ case '\\':
+ if (verbatim) {
+ arg += in[pos];
+ pos++;
+ }
+ else {
+ pos++;
+ if (pos < (int) in.length()) {
+ if (in[pos].isLetterOrNumber())
+ break;
+ arg += in[pos];
+ if (in[pos].isSpace()) {
+ skipAllSpaces();
+ }
+ else {
+ pos++;
+ }
+ }
+ }
+ break;
+ default:
+ arg += in[pos];
+ pos++;
+ }
+ }
+ if ((arg.length() > 1) &&
+ (QString(".,:;!?").indexOf(in[pos - 1]) != -1) &&
+ !arg.endsWith("...")) {
+ arg.truncate(arg.length() - 1);
+ pos--;
+ }
+ if (arg.length() > 2 && in.mid(pos - 2, 2) == "'s") {
+ arg.truncate(arg.length() - 2);
+ pos -= 2;
+ }
+ }
+ return arg.simplified();
+}
+
+QString DocParser::getOptionalArgument()
+{
+ skipSpacesOrOneEndl();
+ if (pos + 1 < (int) in.length() && in[pos] == '\\' &&
+ in[pos + 1].isLetterOrNumber()) {
+ return "";
+ }
+ else {
+ return getArgument();
+ }
+}
+
+QString DocParser::getRestOfLine()
+{
+ QString t;
+
+ skipSpacesOnLine();
+
+ bool trailingSlash = false;
+
+ do {
+ int begin = pos;
+
+ while (pos < in.size() && in[pos] != '\n') {
+ if (in[pos] == '\\' && !trailingSlash) {
+ trailingSlash = true;
+ ++pos;
+ while ((pos < in.size()) &&
+ in[pos].isSpace() &&
+ (in[pos] != '\n'))
+ ++pos;
+ }
+ else {
+ trailingSlash = false;
+ ++pos;
+ }
+ }
+
+ if (!t.isEmpty())
+ t += " ";
+ t += in.mid(begin, pos - begin).simplified();
+
+ if (trailingSlash) {
+ t.chop(1);
+ t = t.simplified();
+ }
+ if (pos < in.size())
+ ++pos;
+ } while (pos < in.size() && trailingSlash);
+
+ return t;
+}
+
+/*!
+ The metacommand argument is normally the remaining text to
+ the right of the metacommand itself. The extra blanks are
+ stripped and the argument string is returned.
+ */
+QString DocParser::getMetaCommandArgument(const QString &cmdStr)
+{
+ skipSpacesOnLine();
+
+ int begin = pos;
+ int parenDepth = 0;
+
+ while (pos < in.size() && (in[pos] != '\n' || parenDepth > 0)) {
+ if (in.at(pos) == '(')
+ ++parenDepth;
+ else if (in.at(pos) == ')')
+ --parenDepth;
+
+ ++pos;
+ }
+ if (pos == in.size() && parenDepth > 0) {
+ pos = begin;
+ location().warning(tr("Unbalanced parentheses in '%1'").arg(cmdStr));
+ }
+
+ QString t = in.mid(begin, pos - begin).simplified();
+ skipSpacesOnLine();
+ return t;
+}
+
+QString DocParser::getUntilEnd(int cmd)
+{
+ int endCmd = endCmdFor(cmd);
+ QRegExp rx("\\\\" + cmdName(endCmd) + "\\b");
+ QString t;
+ int end = rx.indexIn(in, pos);
+
+ if (end == -1) {
+ location().warning(tr("Missing '\\%1'").arg(cmdName(endCmd)));
+ pos = in.length();
+ }
+ else {
+ t = in.mid(pos, end - pos);
+ pos = end + rx.matchedLength();
+ }
+ return t;
+}
+
+QString DocParser::getCode(int cmd, CodeMarker *marker)
+{
+ QString code = untabifyEtc(getUntilEnd(cmd));
+ int indent = indentLevel(code);
+ if (indent < minIndent)
+ minIndent = indent;
+ code = unindent(minIndent, code);
+ if (!marker)
+ marker = CodeMarker::markerForCode(code);
+ return marker->markedUpCode(code, 0, location());
+}
+
+/*!
+ Was used only for generating doxygen output.
+ */
+QString DocParser::getUnmarkedCode(int cmd)
+{
+ QString code = getUntilEnd(cmd);
+ return code;
+}
+
+bool DocParser::isBlankLine()
+{
+ int i = pos;
+
+ while (i < len && in[i].isSpace()) {
+ if (in[i] == '\n')
+ return true;
+ i++;
+ }
+ return false;
+}
+
+bool DocParser::isLeftBraceAhead()
+{
+ int numEndl = 0;
+ int i = pos;
+
+ while (i < len && in[i].isSpace() && numEndl < 2) {
+ // ### bug with '\\'
+ if (in[i] == '\n')
+ numEndl++;
+ i++;
+ }
+ return numEndl < 2 && i < len && in[i] == '{';
+}
+
+/*!
+ Skips to the next non-space character or EOL.
+ */
+void DocParser::skipSpacesOnLine()
+{
+ while ((pos < in.length()) &&
+ in[pos].isSpace() &&
+ (in[pos].unicode() != '\n'))
+ ++pos;
+}
+
+/*!
+ Skips spaces and on EOL.
+ */
+void DocParser::skipSpacesOrOneEndl()
+{
+ int firstEndl = -1;
+ while (pos < (int) in.length() && in[pos].isSpace()) {
+ QChar ch = in[pos];
+ if (ch == '\n') {
+ if (firstEndl == -1) {
+ firstEndl = pos;
+ }
+ else {
+ pos = firstEndl;
+ break;
+ }
+ }
+ pos++;
+ }
+}
+
+void DocParser::skipAllSpaces()
+{
+ while (pos < len && in[pos].isSpace())
+ pos++;
+}
+
+void DocParser::skipToNextPreprocessorCommand()
+{
+ QRegExp rx("\\\\(?:" + cmdName(CMD_IF) + QLatin1Char('|') +
+ cmdName(CMD_ELSE) + QLatin1Char('|') +
+ cmdName(CMD_ENDIF) + ")\\b");
+ int end = rx.indexIn(in, pos + 1); // ### + 1 necessary?
+
+ if (end == -1)
+ pos = in.length();
+ else
+ pos = end;
+}
+
+int DocParser::endCmdFor(int cmd)
+{
+ switch (cmd) {
+ case CMD_ABSTRACT:
+ return CMD_ENDABSTRACT;
+ case CMD_BADCODE:
+ return CMD_ENDCODE;
+ case CMD_CHAPTER:
+ return CMD_ENDCHAPTER;
+ case CMD_CODE:
+ return CMD_ENDCODE;
+ case CMD_DIV:
+ return CMD_ENDDIV;
+ case CMD_QML:
+ return CMD_ENDQML;
+ case CMD_QMLTEXT:
+ return CMD_ENDQMLTEXT;
+ case CMD_JS:
+ return CMD_ENDJS;
+ case CMD_FOOTNOTE:
+ return CMD_ENDFOOTNOTE;
+ case CMD_LEGALESE:
+ return CMD_ENDLEGALESE;
+ case CMD_LINK:
+ return CMD_ENDLINK;
+ case CMD_LIST:
+ return CMD_ENDLIST;
+ case CMD_NEWCODE:
+ return CMD_ENDCODE;
+ case CMD_OLDCODE:
+ return CMD_NEWCODE;
+ case CMD_OMIT:
+ return CMD_ENDOMIT;
+ case CMD_PART:
+ return CMD_ENDPART;
+ case CMD_QUOTATION:
+ return CMD_ENDQUOTATION;
+ case CMD_RAW:
+ return CMD_ENDRAW;
+ case CMD_SECTION1:
+ return CMD_ENDSECTION1;
+ case CMD_SECTION2:
+ return CMD_ENDSECTION2;
+ case CMD_SECTION3:
+ return CMD_ENDSECTION3;
+ case CMD_SECTION4:
+ return CMD_ENDSECTION4;
+ case CMD_SIDEBAR:
+ return CMD_ENDSIDEBAR;
+ case CMD_TABLE:
+ return CMD_ENDTABLE;
+ case CMD_TOPICREF:
+ return CMD_ENDTOPICREF;
+ case CMD_MAPREF:
+ return CMD_ENDMAPREF;
+ default:
+ return cmd;
+ }
+}
+
+QString DocParser::cmdName(int cmd)
+{
+ return *cmds[cmd].alias;
+}
+
+QString DocParser::endCmdName(int cmd)
+{
+ return cmdName(endCmdFor(cmd));
+}
+
+QString DocParser::untabifyEtc(const QString& str)
+{
+ QString result;
+ result.reserve(str.length());
+ int column = 0;
+
+ for (int i = 0; i < str.length(); i++) {
+ const QChar c = str.at(i);
+ if (c == QLatin1Char('\r'))
+ continue;
+ if (c == QLatin1Char('\t')) {
+ result += " " + (column % tabSize);
+ column = ((column / tabSize) + 1) * tabSize;
+ continue;
+ }
+ if (c == QLatin1Char('\n')) {
+ while (result.endsWith(QLatin1Char(' ')))
+ result.chop(1);
+ result += c;
+ column = 0;
+ continue;
+ }
+ result += c;
+ column++;
+ }
+
+ while (result.endsWith("\n\n"))
+ result.truncate(result.length() - 1);
+ while (result.startsWith(QLatin1Char('\n')))
+ result = result.mid(1);
+
+ return result;
+}
+
+int DocParser::indentLevel(const QString& str)
+{
+ int minIndent = INT_MAX;
+ int column = 0;
+
+ for (int i = 0; i < (int) str.length(); i++) {
+ if (str[i] == '\n') {
+ column = 0;
+ }
+ else {
+ if (str[i] != ' ' && column < minIndent)
+ minIndent = column;
+ column++;
+ }
+ }
+ return minIndent;
+}
+
+QString DocParser::unindent(int level, const QString& str)
+{
+ if (level == 0)
+ return str;
+
+ QString t;
+ int column = 0;
+
+ for (int i = 0; i < (int) str.length(); i++) {
+ if (str[i] == QLatin1Char('\n')) {
+ t += '\n';
+ column = 0;
+ }
+ else {
+ if (column >= level)
+ t += str[i];
+ column++;
+ }
+ }
+ return t;
+}
+
+QString DocParser::slashed(const QString& str)
+{
+ QString result = str;
+ result.replace(QLatin1Char('/'), "\\/");
+ return QLatin1Char('/') + result + QLatin1Char('/');
+}
+
+#define COMMAND_BRIEF Doc::alias("brief")
+#define COMMAND_QMLBRIEF Doc::alias("qmlbrief")
+
+Doc::Doc(const Location& start_loc,
+ const Location& end_loc,
+ const QString& source,
+ const QSet<QString>& metaCommandSet)
+{
+ priv = new DocPrivate(start_loc,end_loc,source);
+ DocParser parser;
+ parser.parse(source,priv,metaCommandSet,QSet<QString>());
+}
+
+/*!
+ Parse the qdoc comment \a source. Build up a list of all the topic
+ commands found including their arguments. This constructor is used
+ when there can be more than one topic command in theqdoc comment.
+ Normally, there is only one topic command in a qdoc comment, but in
+ QML documentation, there is the case where the qdoc \e{qmlproperty}
+ command can appear multiple times in a qdoc comment.
+ */
+Doc::Doc(const Location& start_loc,
+ const Location& end_loc,
+ const QString& source,
+ const QSet<QString>& metaCommandSet,
+ const QSet<QString>& topics)
+{
+ priv = new DocPrivate(start_loc,end_loc,source);
+ DocParser parser;
+ parser.parse(source,priv,metaCommandSet,topics);
+}
+
+Doc::Doc(const Doc& doc)
+ : priv(0)
+{
+ operator=(doc);
+}
+
+Doc::~Doc()
+{
+ if (priv && priv->deref())
+ delete priv;
+}
+
+Doc &Doc::operator=(const Doc& doc)
+{
+ if (doc.priv)
+ doc.priv->ref();
+ if (priv && priv->deref())
+ delete priv;
+ priv = doc.priv;
+ return *this;
+}
+
+void Doc::renameParameters(const QStringList &oldNames,
+ const QStringList &newNames)
+{
+ if (priv && oldNames != newNames) {
+ detach();
+
+ priv->params = newNames.toSet();
+
+ Atom *atom = priv->text.firstAtom();
+ while (atom) {
+ if (atom->type() == Atom::FormattingLeft
+ && atom->string() == ATOM_FORMATTING_PARAMETER) {
+ atom = atom->next();
+ if (!atom)
+ return;
+ int index = oldNames.indexOf(atom->string());
+ if (index != -1 && index < newNames.count())
+ atom->setString(newNames.at(index));
+ }
+ atom = atom->next();
+ }
+ }
+}
+
+void Doc::simplifyEnumDoc()
+{
+ if (priv) {
+ if (priv->isEnumDocSimplifiable()) {
+ detach();
+
+ Text newText;
+
+ Atom *atom = priv->text.firstAtom();
+ while (atom) {
+ if ((atom->type() == Atom::ListLeft) &&
+ (atom->string() == ATOM_LIST_VALUE)) {
+ while (atom && ((atom->type() != Atom::ListRight) ||
+ (atom->string() != ATOM_LIST_VALUE)))
+ atom = atom->next();
+ if (atom)
+ atom = atom->next();
+ }
+ else {
+ newText << *atom;
+ atom = atom->next();
+ }
+ }
+ priv->text = newText;
+ }
+ }
+}
+
+void Doc::setBody(const Text &text)
+{
+ detach();
+ priv->text = text;
+}
+
+/*!
+ Returns the starting location of a qdoc comment.
+ */
+const Location &Doc::location() const
+{
+ static const Location dummy;
+ return priv == 0 ? dummy : priv->start_loc;
+}
+
+const QString &Doc::source() const
+{
+ static QString null;
+ return priv == 0 ? null : priv->src;
+}
+
+bool Doc::isEmpty() const
+{
+ return priv == 0 || priv->src.isEmpty();
+}
+
+const Text& Doc::body() const
+{
+ static const Text dummy;
+ return priv == 0 ? dummy : priv->text;
+}
+
+Text Doc::briefText(bool inclusive) const
+{
+ return body().subText(Atom::BriefLeft, Atom::BriefRight, 0, inclusive);
+}
+
+Text Doc::trimmedBriefText(const QString &className) const
+{
+ QString classNameOnly = className;
+ if (className.contains("::"))
+ classNameOnly = className.split("::").last();
+
+ Text originalText = briefText();
+ Text resultText;
+ const Atom *atom = originalText.firstAtom();
+ if (atom) {
+ QString briefStr;
+ QString whats;
+ bool standardWording = true;
+
+ /*
+ This code is really ugly. The entire \brief business
+ should be rethought.
+ */
+ while (atom) {
+ if (atom->type() == Atom::AutoLink || atom->type() == Atom::String) {
+ briefStr += atom->string();
+ }
+ atom = atom->next();
+ }
+
+ QStringList w = briefStr.split(QLatin1Char(' '));
+ if (!w.isEmpty() && w.first() == "Returns") {
+ }
+ else {
+ if (!w.isEmpty() && w.first() == "The")
+ w.removeFirst();
+ else {
+ location().warning(
+ tr("Nonstandard wording in '\\%1' text for '%2' (expected 'The')")
+ .arg(COMMAND_BRIEF).arg(className));
+ standardWording = false;
+ }
+
+ if (!w.isEmpty() && (w.first() == className || w.first() == classNameOnly))
+ w.removeFirst();
+ else {
+ location().warning(
+ tr("Nonstandard wording in '\\%1' text for '%2' (expected '%3')")
+ .arg(COMMAND_BRIEF).arg(className).arg(className));
+ standardWording = false;
+ }
+
+ if (!w.isEmpty() && ((w.first() == "class") ||
+ (w.first() == "function") ||
+ (w.first() == "macro") ||
+ (w.first() == "widget") ||
+ (w.first() == "namespace") ||
+ (w.first() == "header")))
+ w.removeFirst();
+ else {
+ location().warning(
+ tr("Nonstandard wording in '\\%1' text for '%2' ("
+ "expected 'class', 'function', 'macro', 'widget', "
+ "'namespace' or 'header')")
+ .arg(COMMAND_BRIEF).arg(className));
+ standardWording = false;
+ }
+
+ if (!w.isEmpty() && (w.first() == "is" || w.first() == "provides"))
+ w.removeFirst();
+
+ if (!w.isEmpty() && (w.first() == "a" || w.first() == "an"))
+ w.removeFirst();
+ }
+
+ whats = w.join(" ");
+
+ if (whats.endsWith(QLatin1Char('.')))
+ whats.truncate(whats.length() - 1);
+
+ if (whats.isEmpty()) {
+ location().warning(
+ tr("Nonstandard wording in '\\%1' text for '%2' (expected more text)")
+ .arg(COMMAND_BRIEF).arg(className));
+ standardWording = false;
+ }
+ else
+ whats[0] = whats[0].toUpper();
+
+ // ### move this once \brief is abolished for properties
+ if (standardWording)
+ resultText << whats;
+ }
+ return resultText;
+}
+
+Text Doc::legaleseText() const
+{
+ if (priv == 0 || !priv->hasLegalese)
+ return Text();
+ else
+ return body().subText(Atom::LegaleseLeft, Atom::LegaleseRight);
+}
+
+const QString& Doc::baseName() const
+{
+ static QString null;
+ if (priv == 0 || priv->extra == 0) {
+ return null;
+ }
+ else {
+ return priv->extra->baseName;
+ }
+}
+
+Doc::Sections Doc::granularity() const
+{
+ if (priv == 0 || priv->extra == 0) {
+ return DocPrivateExtra().granularity;
+ }
+ else {
+ return priv->extra->granularity;
+ }
+}
+
+const QSet<QString> &Doc::parameterNames() const
+{
+ return priv == 0 ? *null_Set_QString() : priv->params;
+}
+
+const QStringList &Doc::enumItemNames() const
+{
+ return priv == 0 ? *null_QStringList() : priv->enumItemList;
+}
+
+const QStringList &Doc::omitEnumItemNames() const
+{
+ return priv == 0 ? *null_QStringList() : priv->omitEnumItemList;
+}
+
+const QSet<QString> &Doc::metaCommandsUsed() const
+{
+ return priv == 0 ? *null_Set_QString() : priv->metacommandsUsed;
+}
+
+/*!
+ Returns a reference to the list of topic commands used in the
+ current qdoc comment. Normally there is only one, but there
+ can be multiple \e{qmlproperty} commands, for example.
+ */
+const TopicList& Doc::topicsUsed() const
+{
+ return priv == 0 ? *nullTopicList() : priv->topics;
+}
+
+QStringList Doc::metaCommandArgs(const QString& metacommand) const
+{
+ return priv == 0 ? QStringList() : priv->metaCommandMap.value(metacommand);
+}
+
+const QList<Text> &Doc::alsoList() const
+{
+ return priv == 0 ? *null_QList_Text() : priv->alsoList;
+}
+
+bool Doc::hasTableOfContents() const
+{
+ return priv && priv->extra && !priv->extra->tableOfContents.isEmpty();
+}
+
+bool Doc::hasKeywords() const
+{
+ return priv && priv->extra && !priv->extra->keywords.isEmpty();
+}
+
+bool Doc::hasTargets() const
+{
+ return priv && priv->extra && !priv->extra->targets.isEmpty();
+}
+
+const QList<Atom *> &Doc::tableOfContents() const
+{
+ priv->constructExtra();
+ return priv->extra->tableOfContents;
+}
+
+const QList<int> &Doc::tableOfContentsLevels() const
+{
+ priv->constructExtra();
+ return priv->extra->tableOfContentsLevels;
+}
+
+const QList<Atom *> &Doc::keywords() const
+{
+ priv->constructExtra();
+ return priv->extra->keywords;
+}
+
+const QList<Atom *> &Doc::targets() const
+{
+ priv->constructExtra();
+ return priv->extra->targets;
+}
+
+const QStringMultiMap &Doc::metaTagMap() const
+{
+ return priv && priv->extra ? priv->extra->metaMap : *null_QStringMultiMap();
+}
+
+void Doc::initialize(const Config& config)
+{
+ DocParser::tabSize = config.getInt(CONFIG_TABSIZE);
+ DocParser::exampleFiles = config.getCleanPathList(CONFIG_EXAMPLES);
+ DocParser::exampleDirs = config.getCleanPathList(CONFIG_EXAMPLEDIRS);
+ DocParser::sourceFiles = config.getCleanPathList(CONFIG_SOURCES);
+ DocParser::sourceDirs = config.getCleanPathList(CONFIG_SOURCEDIRS);
+ DocParser::quoting = config.getBool(CONFIG_QUOTINGINFORMATION);
+
+ QmlClassNode::qmlOnly = config.getBool(CONFIG_QMLONLY);
+
+ QStringMap reverseAliasMap;
+
+ QSet<QString> commands = config.subVars(CONFIG_ALIAS);
+ QSet<QString>::ConstIterator c = commands.begin();
+ while (c != commands.end()) {
+ QString alias = config.getString(CONFIG_ALIAS + Config::dot + *c);
+ if (reverseAliasMap.contains(alias)) {
+ config.lastLocation().warning(tr("Command name '\\%1' cannot stand"
+ " for both '\\%2' and '\\%3'")
+ .arg(alias)
+ .arg(reverseAliasMap[alias])
+ .arg(*c));
+ }
+ else {
+ reverseAliasMap.insert(alias, *c);
+ }
+ aliasMap()->insert(*c, alias);
+ ++c;
+ }
+
+ int i = 0;
+ while (cmds[i].english) {
+ cmds[i].alias = new QString(alias(cmds[i].english));
+ cmdHash()->insert(*cmds[i].alias, cmds[i].no);
+
+ if (cmds[i].no != i)
+ Location::internalError(tr("command %1 missing").arg(i));
+ i++;
+ }
+
+ QSet<QString> macroNames = config.subVars(CONFIG_MACRO);
+ QSet<QString>::ConstIterator n = macroNames.begin();
+ while (n != macroNames.end()) {
+ QString macroDotName = CONFIG_MACRO + Config::dot + *n;
+ Macro macro;
+ macro.numParams = -1;
+ macro.defaultDef = config.getString(macroDotName);
+ if (!macro.defaultDef.isEmpty()) {
+ macro.defaultDefLocation = config.lastLocation();
+ macro.numParams = Config::numParams(macro.defaultDef);
+ }
+ bool silent = false;
+
+ QSet<QString> formats = config.subVars(macroDotName);
+ QSet<QString>::ConstIterator f = formats.begin();
+ while (f != formats.end()) {
+ QString def = config.getString(macroDotName + Config::dot + *f);
+ if (!def.isEmpty()) {
+ macro.otherDefs.insert(*f, def);
+ int m = Config::numParams(def);
+ if (macro.numParams == -1) {
+ macro.numParams = m;
+ }
+ else if (macro.numParams != m) {
+ if (!silent) {
+ QString other = tr("default");
+ if (macro.defaultDef.isEmpty())
+ other = macro.otherDefs.begin().key();
+ config.lastLocation().warning(tr("Macro '\\%1' takes"
+ " inconsistent number"
+ " of arguments (%2"
+ " %3, %4 %5)")
+ .arg(*n)
+ .arg(*f)
+ .arg(m)
+ .arg(other)
+ .arg(macro.numParams));
+ silent = true;
+ }
+ if (macro.numParams < m)
+ macro.numParams = m;
+ }
+ }
+ ++f;
+ }
+
+ if (macro.numParams != -1)
+ macroHash()->insert(*n, macro);
+ ++n;
+ }
+}
+
+void Doc::terminate()
+{
+ DocParser::exampleFiles.clear();
+ DocParser::exampleDirs.clear();
+ DocParser::sourceFiles.clear();
+ DocParser::sourceDirs.clear();
+ aliasMap()->clear();
+ cmdHash()->clear();
+ macroHash()->clear();
+
+ int i = 0;
+ while (cmds[i].english) {
+ delete cmds[i].alias;
+ cmds[i].alias = 0;
+ ++i;
+ }
+}
+
+QString Doc::alias(const QString &english)
+{
+ return aliasMap()->value(english, english);
+}
+
+/*!
+ Trims the deadwood out of \a str. i.e., this function
+ cleans up \a str.
+ */
+void Doc::trimCStyleComment(Location& location, QString& str)
+{
+ QString cleaned;
+ Location m = location;
+ bool metAsterColumn = true;
+ int asterColumn = location.columnNo() + 1;
+ int i;
+
+ for (i = 0; i < (int) str.length(); i++) {
+ if (m.columnNo() == asterColumn) {
+ if (str[i] != '*')
+ break;
+ cleaned += ' ';
+ metAsterColumn = true;
+ }
+ else {
+ if (str[i] == '\n') {
+ if (!metAsterColumn)
+ break;
+ metAsterColumn = false;
+ }
+ cleaned += str[i];
+ }
+ m.advance(str[i]);
+ }
+ if (cleaned.length() == str.length())
+ str = cleaned;
+
+ for (int i = 0; i < 3; i++)
+ location.advance(str[i]);
+ str = str.mid(3, str.length() - 5);
+}
+
+CodeMarker *Doc::quoteFromFile(const Location &location,
+ Quoter &quoter,
+ const QString &fileName)
+{
+ quoter.reset();
+
+ QString code;
+
+ QString userFriendlyFilePath;
+ QString filePath = Config::findFile(location,
+ DocParser::exampleFiles,
+ DocParser::exampleDirs,
+ fileName, userFriendlyFilePath);
+ if (filePath.isEmpty()) {
+ location.warning(tr("Cannot find file to quote from: '%1'").arg(fileName));
+ }
+ else {
+ QFile inFile(filePath);
+ if (!inFile.open(QFile::ReadOnly)) {
+ location.warning(tr("Cannot open file to quote from: '%1'").arg(userFriendlyFilePath));
+ }
+ else {
+ QTextStream inStream(&inFile);
+ code = DocParser::untabifyEtc(inStream.readAll());
+ }
+ }
+
+ QString dirPath = QFileInfo(filePath).path();
+ CodeMarker *marker = CodeMarker::markerForFileName(fileName);
+ quoter.quoteFromFile(userFriendlyFilePath,
+ code,
+ marker->markedUpCode(code, 0, location));
+ return marker;
+}
+
+QString Doc::canonicalTitle(const QString &title)
+{
+ // The code below is equivalent to the following chunk, but _much_
+ // faster (accounts for ~10% of total running time)
+ //
+ // QRegExp attributeExpr("[^A-Za-z0-9]+");
+ // QString result = title.toLower();
+ // result.replace(attributeExpr, " ");
+ // result = result.simplified();
+ // result.replace(QLatin1Char(' '), QLatin1Char('-'));
+
+ QString result;
+ result.reserve(title.size());
+
+ bool dashAppended = false;
+ bool begun = false;
+ int lastAlnum = 0;
+ for (int i = 0; i != title.size(); ++i) {
+ uint c = title.at(i).unicode();
+ if (c >= 'A' && c <= 'Z')
+ c -= 'A' - 'a';
+ bool alnum = (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
+ if (alnum) {
+ result += QLatin1Char(c);
+ begun = true;
+ dashAppended = false;
+ lastAlnum = result.size();
+ }
+ else if (!dashAppended) {
+ if (begun)
+ result += QLatin1Char('-');
+ dashAppended = true;
+ }
+ }
+ result.truncate(lastAlnum);
+ return result;
+}
+
+void Doc::detach()
+{
+ if (!priv) {
+ priv = new DocPrivate;
+ return;
+ }
+ if (priv->count == 1)
+ return;
+
+ --priv->count;
+
+ DocPrivate *newPriv = new DocPrivate(*priv);
+ newPriv->count = 1;
+ if (priv->extra)
+ newPriv->extra = new DocPrivateExtra(*priv->extra);
+
+ priv = newPriv;
+}
+
+/*!
+ The destructor deletes all the sub-TopicRefs.
+ */
+TopicRef::~TopicRef()
+{
+ foreach (DitaRef* t, subrefs_) {
+ delete t;
+ }
+}
+
+/*!
+ Returns a reference to the structure that will be used
+ for generating a DITA mao.
+ */
+const DitaRefList& Doc::ditamap() const { return priv->ditamap_; }
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/doc.h b/src/tools/qdoc/doc.h
new file mode 100644
index 0000000000..d3fd2dbb4d
--- /dev/null
+++ b/src/tools/qdoc/doc.h
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ doc.h
+*/
+
+#ifndef DOC_H
+#define DOC_H
+
+#include <QSet>
+#include <QString>
+#include <QMap>
+
+#include "location.h"
+
+QT_BEGIN_NAMESPACE
+
+class Atom;
+class CodeMarker;
+class Config;
+class DocPrivate;
+class Quoter;
+class Text;
+class FakeNode;
+class DitaRef;
+
+typedef QMap<QString, QStringList> QCommandMap;
+typedef QMap<QString, QString> QStringMap;
+typedef QMultiMap<QString, QString> QStringMultiMap;
+
+struct Topic
+{
+ QString topic;
+ QString args;
+ Topic(QString& t, QString a) : topic(t), args(a) { }
+};
+typedef QList<Topic> TopicList;
+
+typedef QList<DitaRef*> DitaRefList;
+
+class DitaRef
+{
+public:
+ DitaRef() { }
+ virtual ~DitaRef() { }
+
+ const QString& navtitle() const { return navtitle_; }
+ const QString& href() const { return href_; }
+ void setNavtitle(const QString& t) { navtitle_ = t; }
+ void setHref(const QString& t) { href_ = t; }
+ virtual bool isMapRef() const = 0;
+ virtual const DitaRefList* subrefs() const { return 0; }
+ virtual void appendSubref(DitaRef* ) { }
+
+private:
+ QString navtitle_;
+ QString href_;
+};
+
+class TopicRef : public DitaRef
+{
+public:
+ TopicRef() { }
+ ~TopicRef();
+
+ virtual bool isMapRef() const { return false; }
+ virtual const DitaRefList* subrefs() const { return &subrefs_; }
+ virtual void appendSubref(DitaRef* t) { subrefs_.append(t); }
+
+private:
+ DitaRefList subrefs_;
+};
+
+class MapRef : public DitaRef
+{
+public:
+ MapRef() { }
+ ~MapRef() { }
+
+ virtual bool isMapRef() const { return true; }
+};
+
+class Doc
+{
+public:
+ // the order is important
+ enum Sections {
+ NoSection = -2,
+ Part = -1,
+ Chapter = 1,
+ Section1 = 1,
+ Section2 = 2,
+ Section3 = 3,
+ Section4 = 4
+ };
+
+ Doc() : priv(0) {}
+ Doc(const Location &start_loc,
+ const Location &end_loc,
+ const QString &source,
+ const QSet<QString> &metaCommandSet);
+ Doc(const Location& start_loc,
+ const Location& end_loc,
+ const QString& source,
+ const QSet<QString>& metaCommandSet,
+ const QSet<QString>& topics);
+ Doc(const Doc &doc);
+ ~Doc();
+
+ Doc& operator=( const Doc& doc );
+
+ void renameParameters(const QStringList &oldNames,
+ const QStringList &newNames);
+ void simplifyEnumDoc();
+ void setBody(const Text &body);
+ const DitaRefList& ditamap() const;
+
+ const Location &location() const;
+ bool isEmpty() const;
+ const QString& source() const;
+ const Text& body() const;
+ Text briefText(bool inclusive = false) const;
+ Text trimmedBriefText(const QString &className) const;
+ Text legaleseText() const;
+ const QString& baseName() const;
+ Sections granularity() const;
+ const QSet<QString> &parameterNames() const;
+ const QStringList &enumItemNames() const;
+ const QStringList &omitEnumItemNames() const;
+ const QSet<QString> &metaCommandsUsed() const;
+ const TopicList& topicsUsed() const;
+ QStringList metaCommandArgs( const QString& metaCommand ) const;
+ const QList<Text> &alsoList() const;
+ bool hasTableOfContents() const;
+ bool hasKeywords() const;
+ bool hasTargets() const;
+ const QList<Atom *> &tableOfContents() const;
+ const QList<int> &tableOfContentsLevels() const;
+ const QList<Atom *> &keywords() const;
+ const QList<Atom *> &targets() const;
+ const QStringMultiMap &metaTagMap() const;
+
+ static void initialize( const Config &config );
+ static void terminate();
+ static QString alias( const QString &english );
+ static void trimCStyleComment( Location& location, QString& str );
+ static CodeMarker *quoteFromFile(const Location &location,
+ Quoter &quoter,
+ const QString &fileName);
+ static QString canonicalTitle(const QString &title);
+
+private:
+ void detach();
+ DocPrivate *priv;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/doc/config/compat.qdocconf b/src/tools/qdoc/doc/config/compat.qdocconf
new file mode 100644
index 0000000000..0b59629ec3
--- /dev/null
+++ b/src/tools/qdoc/doc/config/compat.qdocconf
@@ -0,0 +1,31 @@
+alias.i = e
+alias.include = input
+
+macro.0 = "\\\\0"
+macro.b = "\\\\b"
+macro.n = "\\\\n"
+macro.r = "\\\\r"
+macro.i = "\\o"
+macro.i11 = "\\o{1,1}"
+macro.i12 = "\\o{1,2}"
+macro.i13 = "\\o{1,3}"
+macro.i14 = "\\o{1,4}"
+macro.i15 = "\\o{1,5}"
+macro.i16 = "\\o{1,6}"
+macro.i17 = "\\o{1,7}"
+macro.i18 = "\\o{1,8}"
+macro.i19 = "\\o{1,9}"
+macro.i21 = "\\o{2,1}"
+macro.i31 = "\\o{3,1}"
+macro.i41 = "\\o{4,1}"
+macro.i51 = "\\o{5,1}"
+macro.i61 = "\\o{6,1}"
+macro.i71 = "\\o{7,1}"
+macro.i81 = "\\o{8,1}"
+macro.i91 = "\\o{9,1}"
+macro.img = "\\image"
+macro.endquote = "\\endquotation"
+macro.relatesto = "\\relates"
+
+spurious = "Missing comma in .*" \
+ "Missing pattern .*"
diff --git a/src/tools/qdoc/doc/config/config.pro b/src/tools/qdoc/doc/config/config.pro
new file mode 100644
index 0000000000..ee7aea8a04
--- /dev/null
+++ b/src/tools/qdoc/doc/config/config.pro
@@ -0,0 +1,13 @@
+SOURCES = config.pro \
+ compat.qdocconf \
+ qdoc-online.qdocconf \
+ qt-defines.qdocconf \
+ qt-html-templates.qdocconf \
+ qdoc-project.qdocconf \
+ qt-html-default-styles.qdocconf \
+ qdoc.qdocconf \
+ qt-html-online-styles.qdocconf \
+ macros.qdocconf \
+ qt-cpp-ignore.qdocconf \
+ qt-html-templates-online.qdocconf
+
diff --git a/src/tools/qdoc/doc/config/images/arrow_down.png b/src/tools/qdoc/doc/config/images/arrow_down.png
new file mode 100644
index 0000000000..9d01e97f6a
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/arrow_down.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/bg_l.png b/src/tools/qdoc/doc/config/images/bg_l.png
new file mode 100755
index 0000000000..90b1da10b9
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/bg_l.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/bg_l_blank.png b/src/tools/qdoc/doc/config/images/bg_l_blank.png
new file mode 100755
index 0000000000..5a9673d81b
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/bg_l_blank.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/bg_ll_blank.png b/src/tools/qdoc/doc/config/images/bg_ll_blank.png
new file mode 100644
index 0000000000..95a1c45e04
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/bg_ll_blank.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/bg_r.png b/src/tools/qdoc/doc/config/images/bg_r.png
new file mode 100755
index 0000000000..f0fb121dea
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/bg_r.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/bg_ul_blank.png b/src/tools/qdoc/doc/config/images/bg_ul_blank.png
new file mode 100644
index 0000000000..70512614cc
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/bg_ul_blank.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/box_bg.png b/src/tools/qdoc/doc/config/images/box_bg.png
new file mode 100755
index 0000000000..3322f923f8
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/box_bg.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/breadcrumb.png b/src/tools/qdoc/doc/config/images/breadcrumb.png
new file mode 100755
index 0000000000..0ded5514d2
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/breadcrumb.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/bullet_dn.png b/src/tools/qdoc/doc/config/images/bullet_dn.png
new file mode 100644
index 0000000000..f7762472e2
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/bullet_dn.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/bullet_gt.png b/src/tools/qdoc/doc/config/images/bullet_gt.png
new file mode 100755
index 0000000000..7561b4edc4
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/bullet_gt.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/bullet_sq.png b/src/tools/qdoc/doc/config/images/bullet_sq.png
new file mode 100755
index 0000000000..a84845e3c7
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/bullet_sq.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/bullet_up.png b/src/tools/qdoc/doc/config/images/bullet_up.png
new file mode 100644
index 0000000000..7de2f06954
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/bullet_up.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/feedbackground.png b/src/tools/qdoc/doc/config/images/feedbackground.png
new file mode 100755
index 0000000000..3a38d995d7
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/feedbackground.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/header_bg.png b/src/tools/qdoc/doc/config/images/header_bg.png
new file mode 100644
index 0000000000..a436aa61ef
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/header_bg.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/horBar.png b/src/tools/qdoc/doc/config/images/horBar.png
new file mode 100755
index 0000000000..100fe91c6c
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/horBar.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/page.png b/src/tools/qdoc/doc/config/images/page.png
new file mode 100644
index 0000000000..1db151bd31
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/page.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/page_bg.png b/src/tools/qdoc/doc/config/images/page_bg.png
new file mode 100755
index 0000000000..9b3bd999df
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/page_bg.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/spinner.gif b/src/tools/qdoc/doc/config/images/spinner.gif
new file mode 100644
index 0000000000..1ed786f2ec
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/spinner.gif
Binary files differ
diff --git a/src/tools/qdoc/doc/config/images/sprites-combined.png b/src/tools/qdoc/doc/config/images/sprites-combined.png
new file mode 100755
index 0000000000..3a48b21f6b
--- /dev/null
+++ b/src/tools/qdoc/doc/config/images/sprites-combined.png
Binary files differ
diff --git a/src/tools/qdoc/doc/config/macros.qdocconf b/src/tools/qdoc/doc/config/macros.qdocconf
new file mode 100644
index 0000000000..2dbc9c1f91
--- /dev/null
+++ b/src/tools/qdoc/doc/config/macros.qdocconf
@@ -0,0 +1,40 @@
+macro.aacute.HTML = "&aacute;"
+macro.Aring.HTML = "&Aring;"
+macro.aring.HTML = "&aring;"
+macro.Auml.HTML = "&Auml;"
+macro.author = "\\bold{Author:}"
+macro.br.HTML = "<br />"
+macro.BR.HTML = "<br />"
+macro.copyright.HTML = "&copy;"
+macro.eacute.HTML = "&eacute;"
+macro.gui = "\\bold"
+macro.hr.HTML = "<hr />"
+macro.iacute.HTML = "&iacute;"
+macro.key = "\\bold"
+macro.menu = "\\bold"
+macro.note = "\\bold{Note:}"
+macro.oslash.HTML = "&oslash;"
+macro.ouml.HTML = "&ouml;"
+macro.QA = "\\e{Qt Assistant}"
+macro.QD = "\\e{Qt Designer}"
+macro.QL = "\\e{Qt Linguist}"
+macro.QQV = "\\e{Qt QML Viewer}"
+macro.param = "\\e"
+macro.raisedaster.HTML = "<sup>*</sup>"
+macro.rarrow.HTML = "&rarr;"
+macro.reg.HTML = "<sup>&reg;</sup>"
+macro.return = "Returns"
+macro.starslash = "\\c{*/}"
+macro.begincomment = "\\c{/*}"
+macro.endcomment = "\\c{*/}"
+macro.uuml.HTML = "&uuml;"
+macro.mdash.HTML = "&mdash;"
+macro.pi.HTML = "&Pi;"
+macro.beginqdoc.HTML = "/*!"
+macro.endqdoc.HTML = "*/"
+
+macro.beginfloatleft.HTML = "<div style=\"float: left; margin-right: 2em\">"
+macro.beginfloatright.HTML = "<div style=\"float: right; margin-left: 2em\">"
+macro.endfloat.HTML = "</div>"
+macro.clearfloat.HTML = "<br style=\"clear: both\" />"
+macro.emptyspan.HTML = "<span></span>"
diff --git a/src/tools/qdoc/doc/config/qdoc-online.qdocconf b/src/tools/qdoc/doc/config/qdoc-online.qdocconf
new file mode 100644
index 0000000000..7fd8ed59f4
--- /dev/null
+++ b/src/tools/qdoc/doc/config/qdoc-online.qdocconf
@@ -0,0 +1,2 @@
+include(qdoc-project.qdocconf)
+include(qt-html-templates-online.qdocconf)
diff --git a/src/tools/qdoc/doc/config/qdoc-project.qdocconf b/src/tools/qdoc/doc/config/qdoc-project.qdocconf
new file mode 100644
index 0000000000..d85058cd6a
--- /dev/null
+++ b/src/tools/qdoc/doc/config/qdoc-project.qdocconf
@@ -0,0 +1,48 @@
+include(compat.qdocconf)
+include(macros.qdocconf)
+include(qt-cpp-ignore.qdocconf)
+include(qt-defines.qdocconf)
+
+indexes = $$MODULE_BUILD_TREE/doc/html/qt.index
+
+sourceencoding = UTF-8
+outputencoding = UTF-8
+naturallanguage = en_US
+
+project = QDoc
+description = QDoc3 Manual
+url = http://doc.qt.nokia.com/qdoc
+
+sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
+headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
+examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp *.qml *.qdoc *.qdocconf *.qdocinc"
+examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng"
+
+sourcedirs = ..
+
+exampledirs = .. \
+ ../examples \
+ ../../../../examples \
+ config
+
+imagedirs = ../../../doc/src/templates/images \
+ images
+
+outputdir = $$MODULE_BUILD_TREE/tools/qdoc3/doc/html
+tagfile = $$MODULE_BUILD_TREE/tools/qdoc3/doc/html/qdoc.tags
+
+qhp.projects = QDoc
+
+qhp.QDoc.file = qdoc.qhp
+qhp.QDoc.namespace = com.trolltech.qdoc
+qhp.QDoc.virtualFolder = qdoc
+qhp.QDoc.indexTitle = QDoc Manual - Table of Contents
+qhp.QDoc.indexRoot =
+
+qhp.QDoc.filterAttributes = qdoc qtrefdoc
+qhp.QDoc.customFilters.QDoc.name = QDoc
+qhp.QDoc.customFilters.QDoc.filterAttributes = qdoc
+qhp.QDoc.subprojects = overviews
+qhp.QDoc.subprojects.overviews.title = Overviews
+qhp.QDoc.subprojects.overviews.indexTitle = All Overviews and HOWTOs
+qhp.QDoc.subprojects.overviews.selectors = fake:page,group,module
diff --git a/src/tools/qdoc/doc/config/qdoc.qdocconf b/src/tools/qdoc/doc/config/qdoc.qdocconf
new file mode 100644
index 0000000000..c238abef88
--- /dev/null
+++ b/src/tools/qdoc/doc/config/qdoc.qdocconf
@@ -0,0 +1,2 @@
+include(qdoc-project.qdocconf)
+include(qt-html-templates.qdocconf)
diff --git a/src/tools/qdoc/doc/config/qt-cpp-ignore.qdocconf b/src/tools/qdoc/doc/config/qt-cpp-ignore.qdocconf
new file mode 100644
index 0000000000..21efcf9940
--- /dev/null
+++ b/src/tools/qdoc/doc/config/qt-cpp-ignore.qdocconf
@@ -0,0 +1,98 @@
+Cpp.ignoretokens = QAXFACTORY_EXPORT \
+ QDESIGNER_COMPONENTS_LIBRARY \
+ QDESIGNER_EXTENSION_LIBRARY \
+ QDESIGNER_SDK_LIBRARY \
+ QDESIGNER_SHARED_LIBRARY \
+ QDESIGNER_UILIB_LIBRARY \
+ QM_EXPORT_CANVAS \
+ QM_EXPORT_DNS \
+ QM_EXPORT_DOM \
+ QM_EXPORT_FTP \
+ QM_EXPORT_HTTP \
+ QM_EXPORT_ICONVIEW \
+ QM_EXPORT_NETWORK \
+ QM_EXPORT_OPENGL \
+ QM_EXPORT_OPENVG \
+ QM_EXPORT_SQL \
+ QM_EXPORT_TABLE \
+ QM_EXPORT_WORKSPACE \
+ QM_EXPORT_XML \
+ QT_ASCII_CAST_WARN \
+ QT_ASCII_CAST_WARN_CONSTRUCTOR \
+ QT_BEGIN_HEADER \
+ QT_DESIGNER_STATIC \
+ QT_END_HEADER \
+ QT_FASTCALL \
+ QT_WIDGET_PLUGIN_EXPORT \
+ Q_COMPAT_EXPORT \
+ Q_CORE_EXPORT \
+ Q_CORE_EXPORT_INLINE \
+ Q_EXPLICIT \
+ Q_EXPORT \
+ Q_EXPORT_CODECS_CN \
+ Q_EXPORT_CODECS_JP \
+ Q_EXPORT_CODECS_KR \
+ Q_EXPORT_PLUGIN \
+ Q_GFX_INLINE \
+ Q_AUTOTEST_EXPORT \
+ Q_GUI_EXPORT \
+ Q_GUI_EXPORT_INLINE \
+ Q_GUI_EXPORT_STYLE_CDE \
+ Q_GUI_EXPORT_STYLE_COMPACT \
+ Q_GUI_EXPORT_STYLE_MAC \
+ Q_GUI_EXPORT_STYLE_MOTIF \
+ Q_GUI_EXPORT_STYLE_MOTIFPLUS \
+ Q_GUI_EXPORT_STYLE_PLATINUM \
+ Q_GUI_EXPORT_STYLE_POCKETPC \
+ Q_GUI_EXPORT_STYLE_SGI \
+ Q_GUI_EXPORT_STYLE_WINDOWS \
+ Q_GUI_EXPORT_STYLE_WINDOWSXP \
+ QHELP_EXPORT \
+ Q_INLINE_TEMPLATE \
+ Q_INTERNAL_WIN_NO_THROW \
+ Q_LOCATION_EXPORT \
+ Q_NETWORK_EXPORT \
+ Q_OPENGL_EXPORT \
+ Q_OPENVG_EXPORT \
+ Q_OUTOFLINE_TEMPLATE \
+ Q_SQL_EXPORT \
+ Q_SVG_EXPORT \
+ Q_SCRIPT_EXPORT \
+ Q_SCRIPTTOOLS_EXPORT \
+ Q_TESTLIB_EXPORT \
+ Q_XML_EXPORT \
+ Q_XMLSTREAM_EXPORT \
+ Q_XMLPATTERNS_EXPORT \
+ QDBUS_EXPORT \
+ Q_DBUS_EXPORT \
+ QT_BEGIN_NAMESPACE \
+ QT_BEGIN_INCLUDE_NAMESPACE \
+ QT_END_NAMESPACE \
+ QT_END_INCLUDE_NAMESPACE \
+ PHONON_EXPORT \
+ Q_DECLARATIVE_EXPORT \
+ Q_GADGET \
+ QWEBKIT_EXPORT \
+ Q_INVOKABLE
+Cpp.ignoredirectives = Q_DECLARE_HANDLE \
+ Q_DECLARE_INTERFACE \
+ Q_DECLARE_METATYPE \
+ Q_DECLARE_OPERATORS_FOR_FLAGS \
+ Q_DECLARE_PRIVATE \
+ Q_DECLARE_PUBLIC \
+ Q_DECLARE_SHARED \
+ Q_DECLARE_TR_FUNCTIONS \
+ Q_DECLARE_TYPEINFO \
+ Q_DISABLE_COPY \
+ QT_FORWARD_DECLARE_CLASS \
+ Q_DUMMY_COMPARISON_OPERATOR \
+ Q_ENUMS \
+ Q_FLAGS \
+ Q_INTERFACES \
+ __attribute__ \
+ K_DECLARE_PRIVATE \
+ PHONON_OBJECT \
+ PHONON_HEIR \
+ Q_PRIVATE_PROPERTY \
+ Q_DECLARE_PRIVATE_D \
+ Q_CLASSINFO
diff --git a/src/tools/qdoc/doc/config/qt-defines.qdocconf b/src/tools/qdoc/doc/config/qt-defines.qdocconf
new file mode 100644
index 0000000000..50a355f04c
--- /dev/null
+++ b/src/tools/qdoc/doc/config/qt-defines.qdocconf
@@ -0,0 +1,17 @@
+defines = Q_QDOC \
+ QT_.*_SUPPORT \
+ QT_.*_LIB \
+ QT_COMPAT \
+ QT_KEYPAD_NAVIGATION \
+ QT_NO_EGL \
+ QT3_SUPPORT \
+ Q_WS_.* \
+ Q_OS_.* \
+ Q_BYTE_ORDER \
+ QT_DEPRECATED \
+ Q_NO_USING_KEYWORD \
+ __cplusplus
+
+versionsym = QT_VERSION_STR
+
+codeindent = 1
diff --git a/src/tools/qdoc/doc/config/qt-html-default-styles.qdocconf b/src/tools/qdoc/doc/config/qt-html-default-styles.qdocconf
new file mode 100644
index 0000000000..b2e39d02f5
--- /dev/null
+++ b/src/tools/qdoc/doc/config/qt-html-default-styles.qdocconf
@@ -0,0 +1,32 @@
+# Define the location of the templates to use. Style sheets and scripts are
+# specified relative to the template directory and will be copied into
+# subdirectories of the output directory.
+
+HTML.templatedir = .
+
+HTML.stylesheets = style/offline.css
+
+HTML.scripts =
+
+# Files not referenced in any qdoc file (last four needed by qtdemo)
+# See also qhp.Qt.extraFiles
+extraimages.HTML = qt-logo.png \
+ arrow_down.png \
+ breadcrumb.png \
+ bullet_gt.png \
+ bullet_dn.png \
+ bullet_sq.png \
+ bullet_up.png \
+ horBar.png \
+ sprites-combined.png
+
+# Include the style sheets and scripts used.
+
+HTML.headerstyles = \
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/offline.css\" />\n"
+
+HTML.headerscripts =
+
+HTML.endheader = \
+ "</head>\n" \
+ "<body>\n"
diff --git a/src/tools/qdoc/doc/config/qt-html-online-styles.qdocconf b/src/tools/qdoc/doc/config/qt-html-online-styles.qdocconf
new file mode 100644
index 0000000000..4ffd6ca65f
--- /dev/null
+++ b/src/tools/qdoc/doc/config/qt-html-online-styles.qdocconf
@@ -0,0 +1,72 @@
+# Define the location of the templates to use. Style sheets and scripts are
+# specified relative to the template directory and will be copied into
+# subdirectories of the output directory.
+
+HTML.templatedir = .
+
+HTML.stylesheets = style/narrow.css \
+ style/style.css \
+ style/style_ie6.css \
+ style/style_ie7.css \
+ style/style_ie8.css \
+ style/superfish.css
+
+# Adding jquery and functions - providing online tools and search features
+HTML.scripts = scripts/functions.js \
+ scripts/narrow.js \
+ scripts/superfish.js \
+ scripts/jquery.js
+
+
+# Files not referenced in any qdoc file.
+# See also qhp.Qt.extraFiles
+extraimages.HTML = qt-logo.png \
+ bg_l.png \
+ bg_l_blank.png \
+ bg_ll_blank.png \
+ bg_ul_blank.png \
+ header_bg.png \
+ bg_r.png \
+ box_bg.png \
+ breadcrumb.png \
+ bullet_gt.png \
+ bullet_dn.png \
+ bullet_sq.png \
+ bullet_up.png \
+ arrow_down.png \
+ feedbackground.png \
+ horBar.png \
+ page.png \
+ page_bg.png \
+ sprites-combined.png \
+ spinner.gif
+
+# Include the style sheets and scripts used.
+
+HTML.headerstyles = \
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/style.css\" />\n" \
+ " <script src=\"scripts/jquery.js\" type=\"text/javascript\"></script>\n" \
+ " <script src=\"scripts/functions.js\" type=\"text/javascript\"></script>\n" \
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/superfish.css\" />\n" \
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"style/narrow.css\" />\n" \
+ " <!--[if IE]>\n" \
+ "<meta name=\"MSSmartTagsPreventParsing\" content=\"true\">\n" \
+ "<meta http-equiv=\"imagetoolbar\" content=\"no\">\n" \
+ "<![endif]-->\n" \
+ "<!--[if lt IE 7]>\n" \
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style_ie6.css\">\n" \
+ "<![endif]-->\n" \
+ "<!--[if IE 7]>\n" \
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style_ie7.css\">\n" \
+ "<![endif]-->\n" \
+ "<!--[if IE 8]>\n" \
+ "<link rel=\"stylesheet\" type=\"text/css\" href=\"style/style_ie8.css\">\n" \
+ "<![endif]-->\n\n"
+
+HTML.headerscripts = \
+ "<script src=\"scripts/superfish.js\" type=\"text/javascript\"></script>\n" \
+ "<script src=\"scripts/narrow.js\" type=\"text/javascript\"></script>\n\n"
+
+HTML.endheader = \
+ "</head>\n" \
+ "<body class=\"\" onload=\"CheckEmptyAndLoadList();\">\n"
diff --git a/src/tools/qdoc/doc/config/qt-html-templates-online.qdocconf b/src/tools/qdoc/doc/config/qt-html-templates-online.qdocconf
new file mode 100644
index 0000000000..af186f0568
--- /dev/null
+++ b/src/tools/qdoc/doc/config/qt-html-templates-online.qdocconf
@@ -0,0 +1,115 @@
+include(qt-html-online-styles.qdocconf)
+
+HTML.postheader = \
+ " <div class=\"header\" id=\"qtdocheader\">\n" \
+ " <div class=\"content\"> \n" \
+ " <div id=\"nav-logo\">\n" \
+ " <a href=\"index.html\">Home</a></div>\n" \
+ " <a href=\"index.html\" class=\"qtref\"><span>QDoc Reference Documentation</span></a>\n" \
+ " <div id=\"narrowsearch\"></div>\n" \
+ " <div id=\"nav-topright\">\n" \
+ " <ul>\n" \
+ " <li class=\"nav-topright-home\"><a href=\"http://qt.nokia.com/\">Qt HOME</a></li>\n" \
+ " <li class=\"nav-topright-dev\"><a href=\"http://developer.qt.nokia.com/\">DEV</a></li>\n" \
+ " <li class=\"nav-topright-labs\"><a href=\"http://labs.qt.nokia.com/blogs/\">LABS</a></li>\n" \
+ " <li class=\"nav-topright-doc nav-topright-doc-active\"><a href=\"http://doc.qt.nokia.com/\">\n" \
+ " DOC</a></li>\n" \
+ " <li class=\"nav-topright-blog\"><a href=\"http://blog.qt.nokia.com/\">BLOG</a></li>\n" \
+ " </ul>\n" \
+ " </div>\n" \
+ " <div id=\"shortCut\">\n" \
+ " <ul>\n" \
+ " <li class=\"shortCut-topleft-inactive\"><span><a href=\"index.html\">Qt 4.7</a></span></li>\n" \
+ " <li class=\"shortCut-topleft-active\"><a href=\"http://doc.qt.nokia.com\">ALL VERSIONS" \
+ " </a></li>\n" \
+ " </ul>\n" \
+ " </div>\n" \
+ " </div>\n" \
+ " </div>\n" \
+ " <div class=\"wrapper\">\n" \
+ " <div class=\"hd\">\n" \
+ " <span></span>\n" \
+ " </div>\n" \
+ " <div class=\"bd group\">\n" \
+ " <div class=\"wrap\">\n" \
+ " <div class=\"toolbar\">\n" \
+ " <div class=\"breadcrumb toolblock\">\n" \
+ " <ul>\n" \
+ " <li class=\"first\"><a href=\"index.html\">Home</a></li>\n" \
+ " <!-- Breadcrumbs go here -->\n"
+
+HTML.postpostheader = \
+ " </ul>\n" \
+ " </div>\n" \
+ " <div class=\"toolbuttons toolblock\">\n" \
+ " <ul>\n" \
+ " <li id=\"smallA\" class=\"t_button\">A</li>\n" \
+ " <li id=\"medA\" class=\"t_button active\">A</li>\n" \
+ " <li id=\"bigA\" class=\"t_button\">A</li>\n" \
+ " <li id=\"print\" class=\"t_button\"><a href=\"javascript:this.print();\">\n" \
+ " <span>Print</span></a></li>\n" \
+ " </ul>\n" \
+ " </div>\n" \
+ " </div>\n" \
+ " <div class=\"content mainContent\">\n"
+
+HTML.footer = \
+ " </div>\n" \
+ " </div>\n" \
+ " </div> \n" \
+ " <div class=\"ft\">\n" \
+ " <span></span>\n" \
+ " </div>\n" \
+ " </div> \n" \
+ " <div class=\"footer\">\n" \
+ " <p>\n" \
+ " <acronym title=\"Copyright\">&copy;</acronym> 2012 Nokia Corporation and/or its\n" \
+ " subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation \n" \
+ " in Finland and/or other countries worldwide.</p>\n" \
+ " <p>\n" \
+ " All other trademarks are property of their respective owners. <a title=\"Privacy Policy\"\n" \
+ " href=\"http://qt.nokia.com/about/privacy-policy\">Privacy Policy</a></p>\n" \
+ " <br />\n" \
+ " <p>\n" \
+ " Licensees holding valid Qt Commercial licenses may use this document in accordance with the" \
+ " Qt Commercial License Agreement provided with the Software or, alternatively, in accordance" \
+ " with the terms contained in a written agreement between you and Nokia.</p>\n" \
+ " <p>\n" \
+ " Alternatively, this document may be used under the terms of the <a href=\"http://www.gnu.org/licenses/fdl.html\">GNU\n" \
+ " Free Documentation License version 1.3</a>\n" \
+ " as published by the Free Software Foundation.</p>\n" \
+ " </div>\n"
+
+
+# Files not referenced in any qdoc file.
+# See also extraimages.HTML
+qhp.QDoc.extraFiles = index.html \
+ images/bg_l.png \
+ images/bg_l_blank.png \
+ images/bg_ll_blank.png \
+ images/bg_ul_blank.png \
+ images/header_bg.png \
+ images/bg_r.png \
+ images/box_bg.png \
+ images/breadcrumb.png \
+ images/bullet_gt.png \
+ images/bullet_dn.png \
+ images/bullet_sq.png \
+ images/bullet_up.png \
+ images/arrow_down.png \
+ images/feedbackground.png \
+ images/horBar.png \
+ images/page.png \
+ images/page_bg.png \
+ images/sprites-combined.png \
+ images/spinner.gif \
+ scripts/functions.js \
+ scripts/jquery.js \
+ scripts/narrow.js \
+ scripts/superfish.js \
+ style/narrow.css \
+ style/superfish.css \
+ style/style_ie6.css \
+ style/style_ie7.css \
+ style/style_ie8.css \
+ style/style.css
diff --git a/src/tools/qdoc/doc/config/qt-html-templates.qdocconf b/src/tools/qdoc/doc/config/qt-html-templates.qdocconf
new file mode 100644
index 0000000000..2e15140945
--- /dev/null
+++ b/src/tools/qdoc/doc/config/qt-html-templates.qdocconf
@@ -0,0 +1,54 @@
+include(qt-html-default-styles.qdocconf)
+
+HTML.postheader = \
+ "<div class=\"header\" id=\"qtdocheader\">\n" \
+ " <div class=\"content\"> \n" \
+ " <a href=\"index.html\" class=\"qtref\"><span>QDoc Reference Documentation</span></a>\n" \
+ " </div>\n" \
+ " <div class=\"breadcrumb toolblock\">\n" \
+ " <ul>\n" \
+ " <li class=\"first\"><a href=\"index.html\">Home</a></li>\n" \
+ " <!-- Breadcrumbs go here -->\n"
+
+HTML.postpostheader = \
+ " </ul>\n" \
+ " </div>\n" \
+ "</div>\n" \
+ "<div class=\"content mainContent\">\n"
+
+HTML.footer = \
+ " <div class=\"ft\">\n" \
+ " <span></span>\n" \
+ " </div>\n" \
+ "</div> \n" \
+ "<div class=\"footer\">\n" \
+ " <p>\n" \
+ " <acronym title=\"Copyright\">&copy;</acronym> 2012 Nokia Corporation and/or its\n" \
+ " subsidiaries. Nokia, Qt and their respective logos are trademarks of Nokia Corporation \n" \
+ " in Finland and/or other countries worldwide.</p>\n" \
+ " <p>\n" \
+ " All other trademarks are property of their respective owners. <a title=\"Privacy Policy\"\n" \
+ " href=\"http://qt.nokia.com/about/privacy-policy\">Privacy Policy</a></p>\n" \
+ " <br />\n" \
+ " <p>\n" \
+ " Licensees holding valid Qt Commercial licenses may use this document in accordance with the" \
+ " Qt Commercial License Agreement provided with the Software or, alternatively, in accordance" \
+ " with the terms contained in a written agreement between you and Nokia.</p>\n" \
+ " <p>\n" \
+ " Alternatively, this document may be used under the terms of the <a href=\"http://www.gnu.org/licenses/fdl.html\">GNU\n" \
+ " Free Documentation License version 1.3</a>\n" \
+ " as published by the Free Software Foundation.</p>\n" \
+ "</div>\n" \
+
+# Files not referenced in any qdoc file.
+# See also extraimages.HTML
+qhp.QDoc.extraFiles = index.html \
+ images/arrow_down.png \
+ images/breadcrumb.png \
+ images/bullet_gt.png \
+ images/bullet_dn.png \
+ images/bullet_sq.png \
+ images/bullet_up.png \
+ images/horBar.png \
+ images/sprites-combined.png \
+ style/offline.css
diff --git a/src/tools/qdoc/doc/config/style/offline.css b/src/tools/qdoc/doc/config/style/offline.css
new file mode 100644
index 0000000000..3689ee8d40
--- /dev/null
+++ b/src/tools/qdoc/doc/config/style/offline.css
@@ -0,0 +1,673 @@
+@media screen
+{
+
+/* basic elements */
+ html
+ {
+ color: #000000;
+ background: #FFFFFF;
+ }
+ table
+ {
+ border-collapse: collapse;
+ border-spacing: 0;
+ }
+ fieldset, img
+ {
+ border: 0;
+ max-width:100%;
+ }
+ address, caption, cite, code, dfn, em, strong, th, var, optgroup
+ {
+ font-style: inherit;
+ font-weight: inherit;
+ }
+ del, ins
+ {
+ text-decoration: none;
+ }
+ li
+ {
+ list-style: none;
+ }
+ ol li
+ {
+ list-style: decimal;
+ }
+ caption, th
+ {
+ text-align: left;
+ }
+ h1, h2, h3, h4, h5, h6
+ {
+ font-size: 100%;
+ }
+ q:before, q:after
+ {
+ content: '';
+ }
+ abbr, acronym
+ {
+ border: 0;
+ font-variant: normal;
+ }
+ sup, sub
+ {
+ vertical-align: baseline;
+ }
+ tt, .qmlreadonly span, .qmldefault span
+ {
+ word-spacing:0.5em;
+ }
+ legend
+ {
+ color: #000000;
+ }
+ strong
+ {
+ font-weight: bold;
+ }
+ em
+ {
+ font-style: italic;
+ }
+
+ body
+ {
+ margin-left: 0.5em;
+ margin-right: 0.5em;
+ }
+ a
+ {
+ color: #00732F;
+ text-decoration: none;
+ }
+ hr
+ {
+ background-color: #E6E6E6;
+ border: 1px solid #E6E6E6;
+ height: 1px;
+ width: 100%;
+ text-align: left;
+ margin: 1.5em 0 1.5em 0;
+ }
+
+ pre
+ {
+ border: 1px solid #DDDDDD;
+ -moz-border-radius: 0.7em 0.7em 0.7em 0.7em;
+ -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em;
+ border-radius: 0.7em 0.7em 0.7em 0.7em;
+ margin: 0 1.5em 1em 1em;
+ padding: 1em 1em 1em 1em;
+ overflow-x: auto;
+ }
+ table, pre
+ {
+ -moz-border-radius: 0.7em 0.7em 0.7em 0.7em;
+ -webkit-border-radius: 0.7em 0.7em 0.7em 0.7em;
+ border-radius: 0.7em 0.7em 0.7em 0.7em;
+ background-color: #F6F6F6;
+ border: 1px solid #E6E6E6;
+ border-collapse: separate;
+ margin-bottom: 2.5em;
+ }
+ pre {
+ font-size: 90%;
+ display: block;
+ overflow:hidden;
+ }
+ thead
+ {
+ margin-top: 0.5em;
+ font-weight: bold
+ }
+ th
+ {
+ padding: 0.5em 1.5em 0.5em 1.5em;
+ background-color: #E1E1E1;
+ border-left: 1px solid #E6E6E6;
+ }
+ td
+ {
+ padding: 0.25em 1.5em 0.25em 2em;
+ }
+
+ td.rightAlign
+ {
+ padding: 0.25em 0.5em 0.25em 1em;
+ }
+ table tr.odd
+ {
+ border-left: 1px solid #E6E6E6;
+ background-color: #F6F6F6;
+ color: #66666E;
+ }
+ table tr.even
+ {
+ border-left: 1px solid #E6E6E6;
+ background-color: #ffffff;
+ color: #66666E;
+ }
+
+ div.float-left
+ {
+ float: left; margin-right: 2em
+ }
+ div.float-right
+ {
+ float: right; margin-left: 2em
+ }
+
+ span.comment
+ {
+ color: #008B00;
+ font-style: italic
+ }
+ span.string, span.char
+ {
+ color: #000084;
+ }
+ span.number
+ {
+ color: #a46200;
+ }
+ span.operator
+ {
+ color: #202020;
+ }
+ span.keyword
+ {
+ color: #840000;
+ }
+ span.name
+ {
+ color: black
+ }
+ span.type
+ {
+ font-weight: bold
+ }
+ span.type a:visited
+ {
+ color: #0F5300;
+ }
+ span.preprocessor
+ {
+ color: #404040
+ }
+/* end basic elements */
+
+/* font style elements */
+ .heading
+ {
+ font-weight: bold;
+ font-size: 125%;
+ }
+ .subtitle
+ {
+ font-size: 110%
+ }
+ .small-subtitle
+ {
+ font-size: 100%
+ }
+ .red
+ {
+ color:red;
+ }
+/* end font style elements */
+
+/* global settings*/
+ .header, .footer
+ {
+ display: block;
+ clear: both;
+ overflow: hidden;
+ }
+/* end global settings*/
+
+/* header elements */
+ .header .qtref
+ {
+ color: #00732F;
+ font-weight: bold;
+ font-size: 130%;
+ }
+
+ .header .content
+ {
+ margin-bottom: 0.5em
+ }
+
+ .naviNextPrevious
+ {
+ display: none
+ }
+ .header .breadcrumb
+ {
+ font-size: 90%;
+ padding: 0.5em 0 0.5em 1em;
+ margin: 0;
+ background-color: #fafafa;
+ height: 1.35em;
+ border-bottom: 1px solid #d1d1d1;
+ }
+
+ .header .breadcrumb ul
+ {
+ margin: 0;
+ padding: 0;
+ }
+
+ .header .content
+ {
+ word-wrap: break-word;
+ }
+
+ .header .breadcrumb ul li
+ {
+ float: left;
+ background: url(../images/breadcrumb.png) no-repeat 0 3px;
+ padding-left: 1.5em;
+ margin-left: 1.5em;
+ }
+
+ .header .breadcrumb ul li.last
+ {
+ font-weight: normal;
+ }
+
+ .header .breadcrumb ul li a
+ {
+ color: #00732F;
+ }
+
+ .header .breadcrumb ul li.first
+ {
+ background-image: none;
+ padding-left: 0;
+ margin-left: 0;
+ }
+
+ .header .content ol li {
+ background: none;
+ margin-bottom: 1.0em;
+ margin-left: 1.2em;
+ padding-left: 0
+ }
+
+ .header .content li
+ {
+ background: url(../images/bullet_sq.png) no-repeat 0 5px;
+ margin-bottom: 1em;
+ padding-left: 1.2em;
+ }
+
+/* end header elements */
+
+/* content elements */
+ .content h1
+ {
+ font-weight: bold;
+ font-size: 150%
+ }
+
+ .content h2
+ {
+ font-weight: bold;
+ font-size: 135%;
+ width: 100%;
+ }
+ .content h3
+ {
+ font-weight: bold;
+ font-size: 120%;
+ width: 100%;
+ }
+ .content table p
+ {
+ margin: 0
+ }
+ .content ul
+ {
+ padding-left: 2.5em;
+ }
+ .content li
+ {
+ padding-top: 0.25em;
+ padding-bottom: 0.25em;
+ }
+ .content ul img {
+ vertical-align: middle;
+ }
+
+ .content a:visited
+ {
+ color: #4c0033;
+ text-decoration: none;
+ }
+
+ .content a:visited:hover
+ {
+ color: #4c0033;
+ text-decoration: underline;
+ }
+
+ a:hover
+ {
+ color: #4c0033;
+ text-decoration: underline;
+ }
+ descr p a
+ {
+ text-decoration: underline;
+ }
+
+ .descr p a:visited
+ {
+ text-decoration: underline;
+ }
+
+ .alphaChar{
+ width:95%;
+ background-color:#F6F6F6;
+ border:1px solid #E6E6E6;
+ -moz-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ font-size:12pt;
+ padding-left:10px;
+ margin-top:10px;
+ margin-bottom:10px;
+ }
+ .flowList{
+ /*vertical-align:top;*/
+ /*margin:20px auto;*/
+
+ column-count:3;
+ -webkit-column-count:3;
+ -moz-column-count:3;
+/*
+ column-width:100%;
+ -webkit-column-width:200px;
+ -col-column-width:200px;
+*/
+ column-gap:41px;
+ -webkit-column-gap:41px;
+ -moz-column-gap:41px;
+
+ column-rule: 1px dashed #ccc;
+ -webkit-column-rule: 1px dashed #ccc;
+ -moz-column-rule: 1px dashed #ccc;
+ }
+
+ .flowList dl{
+ }
+ .flowList dd{
+ /*display:inline-block;*/
+ margin-left:10px;
+ min-width:250px;
+ line-height: 1.5;
+ min-width:100%;
+ min-height:15px;
+ }
+
+ .flowList dd a{
+ }
+
+ .content .flowList p{
+ padding:0px;
+ }
+
+ .content .alignedsummary
+ {
+ margin: 15px;
+ }
+
+
+ .qmltype
+ {
+ text-align: center;
+ font-size: 120%;
+ }
+ .qmlreadonly
+ {
+ padding-left: 5px;
+ float: right;
+ color: #254117;
+ }
+
+ .qmldefault
+ {
+ padding-left: 5px;
+ float: right;
+ color: red;
+ }
+
+ .qmldoc
+ {
+ }
+
+ .generic .alphaChar{
+ margin-top:5px;
+ }
+
+ .generic .odd .alphaChar{
+ background-color: #F6F6F6;
+ }
+
+ .generic .even .alphaChar{
+ background-color: #FFFFFF;
+ }
+
+ .memItemRight{
+ padding: 0.25em 1.5em 0.25em 0;
+ }
+ .highlightedCode
+ {
+ margin: 1.0em;
+ }
+ .annotated td {
+ padding: 0.25em 0.5em 0.25em 0.5em;
+ }
+
+ .header .content .toc ul
+ {
+ padding-left: 0px;
+ }
+
+ .content .toc h3 {
+ border-bottom: 0px;
+ margin-top: 0px;
+ }
+
+ .content .toc h3 a:hover {
+ color: #00732F;
+ text-decoration: none;
+ }
+
+ .content .toc .level2
+ {
+ margin-left: 1.5em;
+ }
+
+ .content .toc .level3
+ {
+ margin-left: 3.0em;
+ }
+
+ .content ul li
+ {
+ background: url(../images/bullet_sq.png) no-repeat 0 0.7em;
+ padding-left: 1em
+ }
+
+ .content .toc li
+ {
+ background: url(../images/bullet_dn.png) no-repeat 0 5px;
+ padding-left: 1em
+ }
+
+ .relpage
+ {
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ border: 1px solid #DDDDDD;
+ padding: 25px 25px;
+ clear: both;
+ }
+ .relpage ul
+ {
+ float: none;
+ padding: 1.5em;
+ }
+
+ h3.fn, span.fn
+ {
+ -moz-border-radius:7px 7px 7px 7px;
+ -webkit-border-radius:7px 7px 7px 7px;
+ border-radius:7px 7px 7px 7px;
+ background-color: #F6F6F6;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #E6E6E6;
+ font-weight: bold;
+ word-spacing:3px;
+ padding:3px 5px;
+ }
+
+ .functionIndex {
+ font-size:12pt;
+ word-spacing:10px;
+ margin-bottom:10px;
+ background-color: #F6F6F6;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #E6E6E6;
+ -moz-border-radius: 7px 7px 7px 7px;
+ -webkit-border-radius: 7px 7px 7px 7px;
+ border-radius: 7px 7px 7px 7px;
+ width:100%;
+ }
+
+ .centerAlign
+ {
+ text-align:center;
+ }
+
+ .rightAlign
+ {
+ text-align:right;
+ }
+
+ .leftAlign
+ {
+ text-align:left;
+ }
+
+ .topAlign{
+ vertical-align:top
+ }
+
+ .functionIndex a{
+ display:inline-block;
+ }
+
+/* end content elements */
+/* footer elements */
+
+ .footer
+ {
+ color: #393735;
+ font-size: 0.75em;
+ text-align: center;
+ padding-top: 1.5em;
+ padding-bottom: 1em;
+ background-color: #E6E7E8;
+ margin: 0;
+ }
+ .footer p
+ {
+ margin: 0.25em
+ }
+ .small
+ {
+ font-size: 0.5em;
+ }
+/* end footer elements */
+
+ .item {
+ float: left;
+ position: relative;
+ width: 100%;
+ overflow: hidden;
+ }
+
+
+ .item .primary {
+ margin-right: 220px;
+ position: relative;
+ }
+
+ .item hr {
+ margin-left: -220px;
+ }
+
+ .item .secondary {
+ float: right;
+ width: 200px;
+ position: relative;
+ }
+
+ .item .cols {
+ clear: both;
+ display: block;
+ }
+
+ .item .cols .col {
+ float: left;
+ margin-left: 1.5%;
+ }
+
+ .item .cols .col.first {
+ margin-left: 0;
+ }
+
+ .item .cols.two .col {
+ width: 45%;
+ }
+
+ .item .box {
+ margin: 0 0 10px 0;
+ }
+
+ .item .box h3 {
+ margin: 0 0 10px 0;
+ }
+
+ .cols.unclear {
+ clear:none;
+ }
+}
+
+/* end of screen media */
+
+/* start of print media */
+
+@media print
+{
+ input, textarea, .header, .footer, .toolbar, .feedback, .wrapper .hd, .wrapper .bd .sidebar, .wrapper .ft, #feedbackBox, #blurpage, .toc, .breadcrumb, .toolbar, .floatingResult
+ {
+ display: none;
+ background: none;
+ }
+ .content
+ {
+ background: none;
+ display: block;
+ width: 100%; margin: 0; float: none;
+ }
+}
+/* end of print media */
diff --git a/src/tools/qdoc/doc/corefeatures.qdoc b/src/tools/qdoc/doc/corefeatures.qdoc
new file mode 100644
index 0000000000..6d31cacda2
--- /dev/null
+++ b/src/tools/qdoc/doc/corefeatures.qdoc
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page corefeatures.html
+ \title Core Features
+
+ \input examples/signalandslots.qdocinc
+ \input examples/objectmodel.qdocinc
+ \input examples/layoutmanagement.qdocinc
+*/
diff --git a/src/tools/qdoc/doc/examples/componentset/ProgressBar.qml b/src/tools/qdoc/doc/examples/componentset/ProgressBar.qml
new file mode 100644
index 0000000000..fc6d6a644f
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/componentset/ProgressBar.qml
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+/*!
+ \qmlclass ProgressBar
+ \inqmlmodule UIComponents 1.0
+ \brief A component that shows the progress of an event
+
+ A ProgressBar shows the linear progress of an event as its \l value.
+ The range is specified using the \l {minimum} and the \l{maximum} values.
+
+ The ProgressBar component is part of the \l {UI Components} module.
+
+ This documentation is part of the \l{componentset}{UIComponents} example.
+*/
+Item {
+ id: progressbar
+
+ /*!
+ The minumum value of the ProgressBar range.
+ The \l value must not be less than this value.
+ */
+ property int minimum: 0
+
+ /*!
+ The maximum value of the ProgressBar range.
+ The \l value must not be more than this value.
+ */
+ property int maximum: 100
+
+ /*!
+ The value of the progress.
+ */
+ property int value: 0
+
+ /*!
+ \qmlproperty color ProgressBar::color
+ The color of the ProgressBar's gradient. Must bind to a color type.
+
+ \omit
+ The "\qmlproperty <type> <property name>" is needed because
+ property alias need to have their types manually entered.
+
+ QDoc will not publish the documentation within omit and endomit.
+ \endomit
+
+ \sa secondcolor
+ */
+ property alias color: gradient1.color
+
+ /*!
+ \qmlproperty color ProgressBar::secondcolor
+ The second color of the ProgressBar's gradient.
+ Must bind to a color type.
+
+ \omit
+ The "\qmlproperty <type> <property name>" is needed because
+ property alias need to have their types manually entered.
+
+ QDoc will not publish the documentation within omit and endomit.
+ \endomit
+
+ \sa color
+ */
+ property alias secondColor: gradient2.color
+
+ width: 250; height: 23
+ clip: true
+
+ Rectangle {
+ id: highlight
+
+ /*!
+ An internal documentation comment. The widthDest property is not
+ a public API and therefore will not be exposed.
+ */
+ property int widthDest: ((progressbar.width * (value - minimum)) / (maximum - minimum) - 6)
+
+ width: highlight.widthDest
+ Behavior on width { SmoothedAnimation { velocity: 1200 } }
+
+ anchors { left: parent.left; top: parent.top; bottom: parent.bottom; margins: 3 }
+ radius: 1
+ gradient: Gradient {
+ GradientStop { id: gradient1; position: 0.0 }
+ GradientStop { id: gradient2; position: 1.0 }
+ }
+
+ }
+ Text {
+ anchors { right: highlight.right; rightMargin: 6; verticalCenter: parent.verticalCenter }
+ color: "white"
+ font.bold: true
+ text: Math.floor((value - minimum) / (maximum - minimum) * 100) + '%'
+ }
+}
diff --git a/src/tools/qdoc/doc/examples/componentset/Switch.qml b/src/tools/qdoc/doc/examples/componentset/Switch.qml
new file mode 100644
index 0000000000..31153d6252
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/componentset/Switch.qml
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+/*!
+ \qmlclass ToggleSwitch
+ \inqmlmodule UIComponents 1.0
+ \brief A component that can be turned on or off
+
+ A toggle switch has two states: an \c on and an \c off state. The \c off
+ state is when the \l on property is set to \c false.
+
+ The ToggleSwitch component is part of the \l {UI Components} module.
+
+ This documentation is part of the \l{componentset}{UIComponents} example.
+
+*/
+Item {
+ id: toggleswitch
+ width: background.width; height: background.height
+
+ /*!
+ Indicates the state of the switch. If \c false, then the switch is in
+ the \c off state.
+
+ \omit
+ The \qmlproperty <type> <propertyname> is not necessary as QDoc
+ will associate this property to the ToggleSwitch
+
+ QDoc will not publish the documentation within omit and endomit.
+ \endomit
+ */
+ property bool on: false
+
+
+ /*!
+ A method to toggle the switch. If the switch is \c on, the toggling it
+ will turn it \c off. Toggling a switch in the \c off position will
+ turn it \c on.
+ */
+ function toggle() {
+ if (toggleswitch.state == "on")
+ toggleswitch.state = "off";
+ else
+ toggleswitch.state = "on";
+ }
+
+
+ /*!
+ \internal
+
+ An internal function to synchronize the switch's internals. This
+ function is not for public access. The \internal command will
+ prevent QDoc from publishing this comment in the public API.
+ */
+ function releaseSwitch() {
+ if (knob.x == 1) {
+ if (toggleswitch.state == "off") return;
+ }
+ if (knob.x == 78) {
+ if (toggleswitch.state == "on") return;
+ }
+ toggle();
+ }
+
+ Rectangle {
+ id: background
+ width: 130; height: 48
+ radius: 48
+ color: "lightsteelblue"
+ MouseArea { anchors.fill: parent; onClicked: toggle() }
+ }
+
+ Rectangle {
+ id: knob
+ width: 48; height: 48
+ radius: width
+ color: "lightblue"
+
+ MouseArea {
+ anchors.fill: parent
+ drag.target: knob; drag.axis: Drag.XAxis; drag.minimumX: 1; drag.maximumX: 78
+ onClicked: toggle()
+ onReleased: releaseSwitch()
+ }
+ }
+
+ states: [
+ State {
+ name: "on"
+ PropertyChanges { target: knob; x: 78 }
+ PropertyChanges { target: toggleswitch; on: true }
+ },
+ State {
+ name: "off"
+ PropertyChanges { target: knob; x: 1 }
+ PropertyChanges { target: toggleswitch; on: false }
+ }
+ ]
+
+ transitions: Transition {
+ NumberAnimation { properties: "x"; easing.type: Easing.InOutQuad; duration: 200 }
+ }
+}
diff --git a/src/tools/qdoc/doc/examples/componentset/TabWidget.qml b/src/tools/qdoc/doc/examples/componentset/TabWidget.qml
new file mode 100644
index 0000000000..eb64979fb2
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/componentset/TabWidget.qml
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
+** the names of its contributors may be used to endorse or promote
+** products derived from this software without specific prior written
+** permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 1.0
+
+/*!
+ \qmlclass TabWidget
+ \inqmlmodule UIComponents 1.0
+ \brief A widget that places its children as tabs
+
+ A TabWidget places its children as tabs in a view. Selecting
+ a tab involves selecting the tab at the top.
+
+ The TabWidget component is part of the \l {UI Components} module.
+
+ This documentation is part of the \l{componentset}{UIComponents} example.
+
+ \section1 Adding Tabs
+
+ To add a tab, declare the tab as a child of the TabWidget.
+
+ \code
+ TabWidget {
+ id: tabwidget
+
+ Rectangle {
+ id: tab1
+ color: "red"
+ //... omitted
+ }
+ Rectangle {
+ id: tab2
+ color: "blue"
+ //... omitted
+ }
+
+ }
+ \endcode
+
+*/
+Item {
+ id: tabWidget
+
+ /*!
+ \internal
+
+ Setting the default property to stack.children means any child items
+ of the TabWidget are actually added to the 'stack' item's children.
+
+ See the \l{"Property Binding in QML"}
+ documentation for details on default properties.
+
+ This is an implementation detail, not meant for public knowledge. Putting
+ the \internal command at the beginning will cause QDoc to not publish this
+ documentation in the public API page.
+
+ Normally, a property alias needs to have a
+ "\qmlproperty <type> <propertyname>" to assign the alias a type.
+
+ */
+ default property alias content: stack.children
+
+
+ /*!
+ The currently active tab in the TabWidget.
+ */
+ property int current: 0
+
+ /*!
+ A sample \c{read-only} property.
+ A contrived property to demonstrate QDoc's ability to detect
+ read-only properties.
+
+ The signature is:
+ \code
+ readonly property int sampleReadOnlyProperty: 0
+ \endcode
+
+ Note that the property must be initialized to a value.
+
+ */
+ readonly property int sampleReadOnlyProperty: 0
+
+ /*!
+ \internal
+
+ This handler is an implementation
+ detail. The \c{\internal} command will prevent QDoc from publishing this
+ documentation on the public API.
+ */
+ onCurrentChanged: setOpacities()
+ Component.onCompleted: setOpacities()
+
+ /*!
+ \internal
+
+ An internal function to set the opacity.
+ The \internal command will prevent QDoc from publishing this
+ documentation on the public API.
+ */
+ function setOpacities() {
+ for (var i = 0; i < stack.children.length; ++i) {
+ stack.children[i].opacity = (i == current ? 1 : 0)
+ }
+ }
+
+ Row {
+ id: header
+
+ Repeater {
+ model: stack.children.length
+ delegate: Rectangle {
+ width: tabWidget.width / stack.children.length; height: 36
+
+ Rectangle {
+ width: parent.width; height: 1
+ anchors { bottom: parent.bottom; bottomMargin: 1 }
+ color: "#acb2c2"
+ }
+ BorderImage {
+ anchors { fill: parent; leftMargin: 2; topMargin: 5; rightMargin: 1 }
+ border { left: 7; right: 7 }
+ source: "tab.png"
+ visible: tabWidget.current == index
+ }
+ Text {
+ horizontalAlignment: Qt.AlignHCenter; verticalAlignment: Qt.AlignVCenter
+ anchors.fill: parent
+ text: stack.children[index].title
+ elide: Text.ElideRight
+ font.bold: tabWidget.current == index
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: tabWidget.current = index
+ }
+ }
+ }
+ }
+
+ Item {
+ id: stack
+ width: tabWidget.width
+ anchors.top: header.bottom; anchors.bottom: tabWidget.bottom
+ }
+}
diff --git a/src/tools/qdoc/doc/examples/componentset/componentset.pro b/src/tools/qdoc/doc/examples/componentset/componentset.pro
new file mode 100644
index 0000000000..5b44737c2d
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/componentset/componentset.pro
@@ -0,0 +1,5 @@
+SOURCES = componentset.pro \
+ ProgressBar.qml \
+ Switch.qml \
+ TabWidget.qml \
+ uicomponents.qdoc
diff --git a/src/tools/qdoc/doc/examples/componentset/uicomponents.qdoc b/src/tools/qdoc/doc/examples/componentset/uicomponents.qdoc
new file mode 100644
index 0000000000..10c23c7c0f
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/componentset/uicomponents.qdoc
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmlmodule UIComponents 1.0
+ \title UI Components
+ \brief Basic set of QML Components
+
+ This is a listing of a list of QML components. These files are available
+ for general import and they are based off the \l{Qt Quick Code Samples}.
+
+ This module is part of the \l{componentset}{UIComponents} example.
+*/
diff --git a/src/tools/qdoc/doc/examples/examples.qdoc b/src/tools/qdoc/doc/examples/examples.qdoc
new file mode 100644
index 0000000000..69ea11afe6
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/examples.qdoc
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example componentset
+ \title QML Documentation Example
+
+ This example demonstrates one of the ways to document QML components.
+
+ In particular, there are sample components that are documented with QDoc
+ commands comments. There are documentation comments for the QML components
+ and their public interfaces. The components are grouped into a module, the
+ \l {UI Components} module.
+
+ The \l{componentset/uicomponents.qdoc}{uicomponents.qdoc} file generates
+ the overview page for the \l {UI Components} module page.
+
+ The generated documentation is available in the \l {UI Components} module.
+
+ \section1 QML Class
+
+ The components use the \l{qmlclass-command}{\\qmlclass} to document the
+ component. In addition, they have the \l{inmodule-command}{\\inmodule}
+ command in order for QDoc to associate them to the \c UIComponents module.
+
+ QDoc uses the \l{brief-command}{\\brief} command to place a basic
+ description when listing the component.
+
+ \section1 Properties, Signals, Handlers, and Methods
+
+ The components have their properties, signals, handlers, and methods
+ defined in their respective QML files. QDoc associates the properties and
+ methods to the components, therefore, you only need to place the
+ documentation above the property, method, or signal.
+
+ To document the type of a \e {property alias}, you must use the
+ \l{qmlproperty-command}{\\qmlproperty} command to specify the data type.
+
+ \code
+ \qmlproperty int anAliasedProperty
+ An aliased property of type int.
+ \endcode
+
+ \section2 Internal Documentation
+
+ You may declare that a documentation is for internal use by placing the
+ \l{internal-command}{\\internal} command after the beginning QDoc comment
+ \begincomment. QDoc will prevent the internal documentation from appearing
+ in the public API.
+
+ If you wish to omit certain parts of the documentation, you may use the
+ \l{omit-command}{\\omit} and \l{omit-command}{\\endomit} command.
+
+ \section1 Components with C++ Implementation
+
+ This example only demonstrates the documentation for components in QML
+ files, but the regular \l{qml-documentation}{QML commands} may be placed
+ inside C++ classes to define the public API of the component.
+
+*/
diff --git a/src/tools/qdoc/doc/examples/layoutmanagement.qdocinc b/src/tools/qdoc/doc/examples/layoutmanagement.qdocinc
new file mode 100644
index 0000000000..01f8acf363
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/layoutmanagement.qdocinc
@@ -0,0 +1,13 @@
+\section1 Layout Classes
+
+The Qt layout system provides a simple and powerful way of specifying
+the layout of child widgets.
+
+By specifying the logical layout once, you get the following benefits:
+
+\list
+ \o Positioning of child widgets.
+ \o Sensible default sizes for windows.
+ \o Sensible minimum sizes for windows.
+ \o ...
+\endlist
diff --git a/src/tools/qdoc/doc/examples/main.cpp b/src/tools/qdoc/doc/examples/main.cpp
new file mode 100644
index 0000000000..b721c7fcf4
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/main.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QPushButton>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ QPushButton hello("Hello world!");
+ hello.resize(100, 30);
+
+ hello.show();
+ return app.exec();
+}
diff --git a/src/tools/qdoc/doc/examples/minimum.qdocconf b/src/tools/qdoc/doc/examples/minimum.qdocconf
new file mode 100644
index 0000000000..1dcff501c0
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/minimum.qdocconf
@@ -0,0 +1,42 @@
+# QDoc is a tool that constantly evolves to suit our needs,
+# and there are some compatibility issues between old and new
+# practices. For that reason, any QDoc configuration file needs to
+# include compat.qdocconf.
+
+#include(compat.qdocconf)
+
+
+# The outputdir variable specifies the directory
+# where QDoc will put the generated documentation.
+
+outputdir = html
+
+
+# The headerdirs variable specifies the directories
+# containing the header files associated
+# with the .cpp source files used in the documentation.
+
+headerdirs = .
+
+
+# The sourcedirs variable specifies the
+# directories containing the .cpp or .qdoc
+# files used in the documentation.
+
+#sourcedirs = .
+
+
+# The exampledirs variable specifies the directories containing
+# the source code of the example files.
+
+exampledirs = .
+
+
+# The imagedirs variable specifies the
+# directories containing the images used in the documentation.
+
+imagedirs = ./images
+
+
+
+
diff --git a/src/tools/qdoc/doc/examples/objectmodel.qdocinc b/src/tools/qdoc/doc/examples/objectmodel.qdocinc
new file mode 100644
index 0000000000..02b5991c4d
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/objectmodel.qdocinc
@@ -0,0 +1,11 @@
+\section1 Qt Object Model
+
+The standard C++ object model provides very efficient runtime support
+for the object paradigm. But its static nature is inflexibile in
+certain problem domains. Graphical user interface programming is a
+domain that requires both runtime efficiency and a high level of
+flexibility. Qt provides this, by combining the speed of C++ with the
+flexibility of the Qt Object Model.
+
+...
+
diff --git a/src/tools/qdoc/doc/examples/samples.qdocinc b/src/tools/qdoc/doc/examples/samples.qdocinc
new file mode 100644
index 0000000000..58213210f2
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/samples.qdocinc
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [qvector3d-class]
+/*!
+ \class QVector3D
+ \brief The QVector3D class represents a vector or vertex in 3D space.
+ \since 4.6
+ \ingroup painting-3D
+
+ Vectors are one of the main building blocks of 3D representation and
+ drawing. They consist of three coordinates, traditionally called
+ x, y, and z.
+
+ The QVector3D class can also be used to represent vertices in 3D space.
+ We therefore do not need to provide a separate vertex class.
+
+ \bold{Note:} By design values in the QVector3D instance are stored as \c float.
+ This means that on platforms where the \c qreal arguments to QVector3D
+ functions are represented by \c double values, it is possible to
+ lose precision.
+
+ \sa QVector2D, QVector4D, QQuaternion
+*/
+//! [qvector3d-class]
+
+//! [qvector3d-function]
+/*!
+ \fn QVector3D::QVector3D(const QPoint& point)
+
+ Constructs a vector with x and y coordinates from a 2D \a point, and a
+ z coordinate of 0.
+*/
+//! [qvector3d-function]
+
+//! [sample-page]
+/*!
+ \page generic-guide.html
+ \title Generic QDoc Guide
+ \nextpage Creating QDoc Configuration Files
+ There are three essential materials for generating documentation with qdoc:
+
+ \list
+ \o \c qdoc binary
+ \o \c qdocconf configuration files
+ \o \c Documentation in \c C++, \c QML, and \c .qdoc files
+ \endlist
+*/
+//! [sample-page]
+
+//! [sample-faq]
+/*!
+ \page altruism-faq.html faq
+ \title Altruism Frequently Asked Questions
+
+ \brief All the questions about altruism, answered.
+
+ ...
+*/
+//! [sample-faq]
+
+//! [sample-example]
+/*!
+ \title UI Components: Tab Widget Example
+ \example declarative/ui-components/tabwidget
+
+ This example shows how to create a tab widget. It also demonstrates how
+ \l {Property aliases}{property aliases} and
+ \l {Introduction to the QML Language#Default Properties}{default properties} can be used to collect and
+ assemble the child items declared within an \l Item.
+
+ \image qml-tabwidget-example.png
+*/
+//! [sample-example]
+
+//! [sample-overview]
+/*!
+ \page overview-qt-technology.html overview
+ \title Overview of a Qt Technology
+
+ \brief provides a technology never seen before.
+
+*/
+//! [sample-overview]
+
diff --git a/src/tools/qdoc/doc/examples/signalandslots.qdocinc b/src/tools/qdoc/doc/examples/signalandslots.qdocinc
new file mode 100644
index 0000000000..e14ede1441
--- /dev/null
+++ b/src/tools/qdoc/doc/examples/signalandslots.qdocinc
@@ -0,0 +1,9 @@
+\section1 Signals and Slots
+
+Signals and slots are used for communication between objects. The signals and
+slots mechanism is a central feature of Qt and probably the part that differs
+most from the features provided by other frameworks.
+
+\section2 Introduction
+
+In GUI programming, when we ...
diff --git a/src/tools/qdoc/doc/files/compat.qdocconf b/src/tools/qdoc/doc/files/compat.qdocconf
new file mode 100644
index 0000000000..3e7ea6c891
--- /dev/null
+++ b/src/tools/qdoc/doc/files/compat.qdocconf
@@ -0,0 +1,12 @@
+alias.include = input
+
+macro.0 = "\\\\0"
+macro.b = "\\\\b"
+macro.n = "\\\\n"
+macro.r = "\\\\r"
+macro.img = "\\image"
+macro.endquote = "\\endquotation"
+macro.relatesto = "\\relates"
+
+spurious = "Missing comma in .*" \
+ "Missing pattern .*"
diff --git a/src/tools/qdoc/doc/files/qt.qdocconf b/src/tools/qdoc/doc/files/qt.qdocconf
new file mode 100644
index 0000000000..377f0f14c1
--- /dev/null
+++ b/src/tools/qdoc/doc/files/qt.qdocconf
@@ -0,0 +1,115 @@
+include(compat.qdocconf)
+include(macros.qdocconf)
+include(qt-cpp-ignore.qdocconf)
+include(qt-html-templates.qdocconf)
+include(qt-defines.qdocconf)
+
+project = Qt
+versionsym =
+version = %VERSION%
+description = Qt Reference Documentation
+url = http://qt.nokia.com/doc/4.7
+
+edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \
+ QtXmlPatterns QtTest
+edition.Desktop.modules = QtCore QtDBus QtGui QtNetwork QtOpenGL QtScript QtScriptTools QtSql QtSvg \
+ QtWebKit QtXml QtXmlPatterns Qt3Support QtHelp \
+ QtDesigner QtAssistant QAxContainer Phonon \
+ QAxServer QtUiTools QtTest QtDBus
+edition.DesktopLight.modules = QtCore QtDBus QtGui Qt3SupportLight QtTest
+edition.DesktopLight.groups = -graphicsview-api
+
+qhp.projects = Qt
+
+qhp.Qt.file = qt.qhp
+qhp.Qt.namespace = com.trolltech.qt.474
+qhp.Qt.virtualFolder = qdoc
+qhp.Qt.indexTitle = Qt Reference Documentation
+qhp.Qt.indexRoot =
+
+# Files not referenced in any qdoc file (last four are needed by qtdemo)
+# See also extraimages.HTML
+qhp.Qt.extraFiles = classic.css \
+ images/qt-logo.png \
+ images/taskmenuextension-example.png \
+ images/coloreditorfactoryimage.png \
+ images/dynamiclayouts-example.png \
+ images/stylesheet-coffee-plastique.png
+
+qhp.Qt.filterAttributes = qt 4.7.4 qtrefdoc
+qhp.Qt.customFilters.Qt.name = Qt 4.7.4
+qhp.Qt.customFilters.Qt.filterAttributes = qt 4.7.4
+qhp.Qt.subprojects = classes overviews examples
+qhp.Qt.subprojects.classes.title = Classes
+qhp.Qt.subprojects.classes.indexTitle = Qt's Classes
+qhp.Qt.subprojects.classes.selectors = class fake:headerfile
+qhp.Qt.subprojects.classes.sortPages = true
+qhp.Qt.subprojects.overviews.title = Overviews
+qhp.Qt.subprojects.overviews.indexTitle = All Overviews and HOWTOs
+qhp.Qt.subprojects.overviews.selectors = fake:page,group,module
+qhp.Qt.subprojects.examples.title = Tutorials and Examples
+qhp.Qt.subprojects.examples.indexTitle = Qt Examples
+qhp.Qt.subprojects.examples.selectors = fake:example
+
+language = Cpp
+
+headerdirs = $QTDIR/src \
+ $QTDIR/extensions/activeqt \
+ $QTDIR/tools/assistant/lib \
+ $QTDIR/tools/assistant/compat/lib \
+ $QTDIR/tools/designer/src/uitools \
+ $QTDIR/tools/designer/src/lib/extension \
+ $QTDIR/tools/designer/src/lib/sdk \
+ $QTDIR/tools/designer/src/lib/uilib \
+ $QTDIR/tools/qtestlib/src \
+ $QTDIR/tools/qdbus/src
+sourcedirs = $QTDIR/src \
+ $QTDIR/doc/src \
+ $QTDIR/extensions/activeqt \
+ $QTDIR/tools/assistant/lib \
+ $QTDIR/tools/assistant/compat/lib \
+ $QTDIR/tools/designer/src/uitools \
+ $QTDIR/tools/designer/src/lib/extension \
+ $QTDIR/tools/designer/src/lib/sdk \
+ $QTDIR/tools/designer/src/lib/uilib \
+ $QTDIR/tools/qtestlib/src \
+ $QTDIR/tools/qdbus
+
+excludedirs = $QTDIR/src/3rdparty/clucene \
+ $QTDIR/src/3rdparty/des \
+ $QTDIR/src/3rdparty/freetype \
+ $QTDIR/src/3rdparty/harfbuzz \
+ $QTDIR/src/3rdparty/kdebase \
+ $QTDIR/src/3rdparty/libjpeg \
+ $QTDIR/src/3rdparty/libmng \
+ $QTDIR/src/3rdparty/libpng \
+ $QTDIR/src/3rdparty/libtiff \
+ $QTDIR/src/3rdparty/md4 \
+ $QTDIR/src/3rdparty/md5 \
+ $QTDIR/src/3rdparty/patches \
+ $QTDIR/src/3rdparty/sha1 \
+ $QTDIR/src/3rdparty/sqlite \
+ $QTDIR/src/3rdparty/webkit/JavaScriptCore \
+ $QTDIR/src/3rdparty/webkit/WebCore \
+ $QTDIR/src/3rdparty/wintab \
+ $QTDIR/src/3rdparty/zlib \
+ $QTDIR/doc/src/snippets \
+ $QTDIR/src/3rdparty/phonon/gstreamer \
+ $QTDIR/src/3rdparty/phonon/ds9 \
+ $QTDIR/src/3rdparty/phonon/qt7 \
+ $QTDIR/src/3rdparty/phonon/waveout
+
+sources.fileextensions = "*.cpp *.qdoc *.mm"
+examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp"
+
+exampledirs = $QTDIR/doc/src \
+ $QTDIR/examples \
+ $QTDIR/examples/tutorials \
+ $QTDIR \
+ $QTDIR/qmake/examples \
+ $QTDIR/src/3rdparty/webkit/WebKit/qt/docs
+imagedirs = $QTDIR/doc/src/images \
+ $QTDIR/examples
+outputdir = $QTDIR/doc/html
+tagfile = $QTDIR/doc/html/qt.tags
+base = file:$QTDIR/doc/html
diff --git a/src/tools/qdoc/doc/images/happy.gif b/src/tools/qdoc/doc/images/happy.gif
new file mode 100644
index 0000000000..a4597f6fa8
--- /dev/null
+++ b/src/tools/qdoc/doc/images/happy.gif
Binary files differ
diff --git a/src/tools/qdoc/doc/images/happyguy.jpg b/src/tools/qdoc/doc/images/happyguy.jpg
new file mode 100644
index 0000000000..e8604793c2
--- /dev/null
+++ b/src/tools/qdoc/doc/images/happyguy.jpg
Binary files differ
diff --git a/src/tools/qdoc/doc/images/qt-logo.png b/src/tools/qdoc/doc/images/qt-logo.png
new file mode 100644
index 0000000000..14ddf2a028
--- /dev/null
+++ b/src/tools/qdoc/doc/images/qt-logo.png
Binary files differ
diff --git a/src/tools/qdoc/doc/images/training.jpg b/src/tools/qdoc/doc/images/training.jpg
new file mode 100644
index 0000000000..c2ce5c3b21
--- /dev/null
+++ b/src/tools/qdoc/doc/images/training.jpg
Binary files differ
diff --git a/src/tools/qdoc/doc/qdoc-guide.qdoc b/src/tools/qdoc/doc/qdoc-guide.qdoc
new file mode 100644
index 0000000000..704e03b7c7
--- /dev/null
+++ b/src/tools/qdoc/doc/qdoc-guide.qdoc
@@ -0,0 +1,671 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+ \page qdoc-guide.html
+ \title Getting Started with QDoc
+ \nextpage Creating QDoc Configuration Files
+
+ Qt uses QDoc to generate its documentation set into HTML and DITA XML
+ formats. QDoc uses a set of configuration files to generate documentation
+ from QDoc comments. The comments have types called
+ \l{writing-topic-commands}{topics} that determine whether a comment is a
+ class documentation or a property documentation. A comment may also have
+ \l{writing-markup}{mark up} to enhance the layout and formatting of the
+ final output.
+
+ There are three essential materials for generating documentation with qdoc:
+ \list
+ \o \c QDoc binary
+ \o \c qdocconf configuration files
+ \o \c Documentation in \c C++, \c QML, and \c .qdoc files
+ \endlist
+
+ This section intends to cover the basic necessities for creating a
+ documentation set. Additionally, the guide presents special considerations
+ and options to documenting non-C++ API documentation as well as QML
+ documentation. Finally, the guide will provide a sample project
+ documentation and a QML component documentation.
+
+ For specific QDoc information, consult the
+ \l{Table of Contents}{QDoc Manual}.
+ \section1 Chapters
+
+ \list 1
+ \o \l{Creating QDoc Configuration Files}
+ \o \l{Writing Documentation}
+ \o \l{Categories of Documentation}
+ \o \l{Configuration File Example}
+ \o \l{QML Documentation Example}
+ \endlist
+
+*/
+
+/*!
+ \page qdoc-guide-conf.html
+ \title Creating QDoc Configuration Files
+ \previouspage Getting Started with QDoc
+ \nextpage Writing Documentation
+ To generate documentation, QDoc uses configuration files, with the
+ \c qdocconf extension, to store configuration settings.
+
+ The \l{The QDoc Configuration File} article covers the various configuration
+ variables in greater detail.
+
+ \section1 QDoc Configuration Files
+ QDoc's configuration settings can reside in a single \e qdocconf file, but
+ can also be in other qdocconf files. The \c {include(<filepath>)} command
+ allows configuration files to include other configuration files.
+
+ QDoc has two outputs, HTML documentation and documentation in DITA XML
+ format. The main distinction between the two outputs is that HTML
+ documentation needs to have its HTML styling information in the
+ configuration files. DITA XML documentation does not, and a separate process
+ can style the documentation in DITA at a later time. DITA XML is therefore
+ more flexible in allowing different styles to apply to the same information.
+
+ To run qdoc, the project configuration file is supplied as an argument.
+ \code
+ qdoc3 project.qdocconf
+ \endcode
+
+ The project configuration contains information that qdoc uses to create the
+ documentation.
+
+ \section2 Project Information
+
+ QDoc uses the \c project information to generate the documentation.
+ \code
+ project = QDoc Project
+ description = Sample QDoc project
+ \endcode
+
+ \target qdoc-input-output-dir
+ \section2 Input and Output Directories
+
+ Specifying the path to the source directories allow QDoc to find sources and
+ generate documentation.
+
+ \code
+ sourcedirs = <path to source code>
+ exampledirs = <path to examples directory>
+ imagedirs = <path to image directory>
+
+ sources.fileextensions = "*.cpp *.qdoc *.mm *.qml"
+ headers.fileextensions = "*.h *.ch *.h++ *.hh *.hpp *.hxx"
+ examples.fileextensions = "*.cpp *.h *.js *.xq *.svg *.xml *.ui *.qhp *.qhcp *.qml"
+ examples.imageextensions = "*.png *.jpeg *.jpg *.gif *.mng"
+ \endcode
+
+ QDoc will process headers and sources from the ones specified in the
+ \c fileextensions variable.
+
+ Likewise, QDoc needs the path to the output directory. The \c outputformats
+ variable determines the type of documentation. These variables should be
+ in separate configuration files to modularize the documentation build.
+ \code
+ outputdir = $SAMPLE_PROJECT/doc/html
+ outputformats = HTML
+ \endcode
+
+ QDoc can resolve the paths relative to the qdocconf file as well as
+ environment variables.
+
+ \note During each QDoc run, the output directory is deleted.
+ \section2 Extra Files
+
+ QDoc will output generated documentation into the directory specified in
+ the \l{Input and Output Directories}{output} directory. It is also possible
+ to specify extra files that QDoc should export.
+
+ \code
+ extraimages.HTML = extraImage.png \
+ extraImage2.png
+ \endcode
+
+ The \c extraImage.png and the \c extraImage2.png files will be copied to the
+ HTML output directory.
+
+ \section2 Qt Help Framework Configuration
+
+ QDoc will also export a \l{Qt Help Project} file, in a \c qhp file.
+ The qhp file is then used by the \c qhelpgenerator to package the
+ documentation into a \c qch file. Qt Creator and Qt Assistant reads the qch
+ file to display the documentation.
+
+ The \l {Creating Help Project Files} article covers the configuration
+ options.
+
+ \section2 HTML Configuration
+
+ QDoc has an HTML generator that will export a set of documentation into
+ HTML files using various configuration settings. QDoc will place the
+ generated documentation into the directory specified by the \c outputdir
+ variable.
+
+ \code
+ outputformats = HTML
+ outputdir = <path to output directory>
+ \endcode
+
+ QDoc needs to know where the styles and templates for generating HTML
+ are located. Typically, the templates directory contains a \c scripts,
+ \c images, and a \c style directory, containing scripts and CSS files.
+
+ \code
+ HTML.templatedir = <path to templates>
+ \endcode
+
+ The main configuration variables are:
+ \code
+ HTML.postheader
+ HTML.postpostheader
+ HTML.postheader
+ HTML.footer
+
+ HTML.headerstyles
+ HTML.stylesheets = style.css \
+ style1.css
+
+ HTML.scripts = script.js
+ \endcode
+
+ The \c{HTML.headerstyles} variable inserts the style information into the
+ HTML file and the \c{HTML.stylesheets} specifies which files QDoc should
+ copy into the output directory. As well, QDoc will embed the string
+ in the \c postheader, \c footer, and related variables into each HTML file.
+
+ The \l {HTML Specific Configuration Variables} article outlines the usage
+ of each variable.
+
+ \section2 DITA XML Configuration
+
+ DITA XML output is enabled using the \c outputformats variable. Unlike HTML
+ documentation, QDoc does not need HTML style templates for generating
+ documentation in DITA XML format.
+
+ \code
+ outputformats = DITAXML
+ outputdir
+ \endcode
+
+ \section2 Qt Index Reference
+ Documentation projects can link to Qt APIs and other articles by specifying
+ the path to the \c qt.index file. When qdoc generates the Qt Reference
+ Documentation, it will also generate an index file, containing the URLs to
+ the articles. Other projects can use the links in the index file so that
+ they can link to other articles and API documentation within Qt.
+
+ \code
+ indexes = $QT_INSTALL_DOCS/html/qt.index $OTHER_PROJECT/html/qt.index
+ \endcode
+ It is possible to specify multiple index files from several projects.
+
+ \section1 Macros and Other Configurations
+
+ Macros for substituting HTML characters exist and are helpful for generating
+ specific HTML-valid characters.
+
+ \code
+ macro.pi.HTML = "&Pi;"
+ \endcode
+ The snippet code will replace any instances of \c{\\pi} with \c &Pi; in the
+ HTML file, which will appear as the Greek \pi symbol when viewed in
+ browsers.
+
+ There is quite a long list of macros for inserting text and
+ \l{alias-variable}{aliases} available.
+
+ \section2 QML Additions
+
+ QDoc is able to parse QML files for QDoc comments. QDoc will parse files
+ with the QML extension, \c{.qml}, if the extension type is included in the
+ \l{Input and Output Directories}{fileextensions} variable.
+
+ Also, the generated HTML files can have a prefix, specified in the QDoc
+ configuration file.
+ \code
+ outputprefixes = QML
+ outputprefixes.QML = qml-components-
+ \endcode
+ The outputprefixes will, for example, prefix QML components HTML filenames.
+ \code
+ files:
+ qml-components-button.html
+ qml-components-scrollbar.html
+ \endcode
+
+*/
+
+/*!
+ \page qdoc-guide-writing.html
+ \title Writing Documentation
+ \previouspage Creating QDoc Configuration Files
+ \nextpage Categories of Documentation
+
+ \section1 QDoc Comments
+ Documentation is contained within qdoc \e comments, delimited by
+ \beginqdoc and \endqdoc comments. Note that these are valid comments
+ in C++, QML, and JavaScript.
+
+ QDoc will parse C++ and QML files to look for qdoc comments. To explicitly
+ omit a certain file type, omit it from the
+ \l{Input and Output Directories}{configuration} file.
+
+ \section1 QDoc Commands
+
+ QDoc uses \e commands to retrieve information about the documentation. \c
+ Topic commands determine the type of documentation element, the \c context
+ commands provide hints and information about a topic, and \c markup commands
+ provide information on how QDoc should format a piece of documentation.
+
+ \target writing-topic-commands
+ \section2 QDoc Topics
+ Each qdoc comment must have a \e topic type. A topic distinguishes it from
+ other topics. To specify a topic type, use one of the several
+ \l{Topic Commands}{topic commands}.
+
+ QDoc will collect similar topics and create a page for each one. For
+ example, all the enumerations, properties, functions, and class description
+ of a particular C++ class will reside in one page. A generic page is
+ specified using the \l{page-command}{\\page} command and the filename is the
+ argument.
+
+ Example of topic commands:
+ \list
+ \o \l{enum-command}{\\enum} - for enumeration documentation
+ \o \l{class-command}{\\class} - for C++ class documentation
+ \o \l{qmlclass-command}{\\qmlclass} - for QML component documentation
+ \o \l{page-command}{\\page} - for creating a page.
+ \endlist
+
+ The \l{page-command}{\\page} command is for creating articles that are not
+ part of source documentation. The command can also accept two arguments: the
+ file name of the article and the documentation type. The possible types are:
+ \list
+ \o \c howto
+ \o \c overview
+ \o \c tutorial
+ \o \c faq
+ \o \c article - \e default when there is no type
+ \endlist
+
+ \snippet examples/samples.qdocinc sample-faq
+
+ The \l{Topic Commands} page has information on all of the available topic
+ commands.
+
+ \target writing-context
+ \section2 Topic Contexts
+
+ Context commands give QDoc a hint about the \e context of the topic. For
+ example, if a C++ function is obsolete, then it should be marked obsolete
+ with the \l{obsolete-command}{\\obsolete} command. Likewise,
+ \l{nextpage-command}{page navigation} and \l{title-command}{page title} 
+ give extra page information to QDoc.
+
+ QDoc will create additional links or pages for these contexts. For example,
+ a group is created using the \l{group-command}{\\group} command and the
+ members have the \l{ingroup-command}{\\ingroup} command. The group name is
+ supplied as an argument.
+
+ The \l{Context Commands} page has a listing of all the available context
+ commands.
+
+ \target writing-markup
+ \section2 Documentation Markup
+
+ QDoc can provide \e markup to content similar to other markup or
+ documentation tools. QDoc can mark a section of text in \bold{bold} when
+ the text is marked up with the \l{bold-command}{\\bold} command.
+
+ \code
+ \bold{This} text will be in \bold{bold}.
+ \endcode
+
+ The \l{Markup Commands} page has a full listing of the available markup
+ commands.
+
+ \section1 Anatomy of Documentation
+
+ Essentially, for QDoc to create a page, there must be some essential
+ ingredients present.
+
+ \list
+ \o Assign a topic to a QDoc comment - A comment could be a page, a
+ property documentation, a class documentation, or any of the available
+ \l{Topic Commands}{topic commands}.
+
+ \o Give the topic a context - QDoc can associate certain topics to other
+ pages such as associating obsolete functions when the documentation is
+ marked with \l{obsolete-command}{\\obsolete}.
+
+ \o Mark sections of the document with
+ \l{Markup Commands}{markup commands} - QDoc can create layouts and
+ format the documentation for the documentation.
+ \endlist
+
+ In Qt, the \l{QVector3D} class was documented with the following QDoc
+ comment:
+ \snippet examples/samples.qdocinc qvector3d-class
+
+ It has a constructor, \l{QVector3D::QVector3D()}, which was documented with
+ the following QDoc comment:
+ \snippet examples/samples.qdocinc qvector3d-function
+
+ The different comments may reside in different files and QDoc will collect
+ them depending on their topic and their context. The resulting documentation
+ from the snippets are generated into the \l{QVector3D} class documentation.
+
+ Note that if the documentation immediately precedes the function or class
+ in the source code, then it does not need to have a topic. QDoc will assume
+ that the documentation above the code is the documentation for that code.
+
+ An article is created using \l{page-command}{\\page} command. The first
+ argument is the HTML file that QDoc will create. The topic is supplemented
+ with context commands, the \l{title-command}{\\title} and
+ \l{nextpage-command}{\\nextpage} commands. There are several other
+ QDoc commands such as the \l{list-command}{\\list} command.
+ \snippet examples/samples.qdocinc sample-page
+
+ The section on \l{QDoc Topics}{topic commands} gives an overview on several
+ other topic types.
+
+
+*/
+
+/*!
+ \page qdoc-categories.html
+ \title Categories of Documentation
+ \previouspage Writing Documentation
+ \nextpage Configuration File Example
+ \brief Describes the different types such as How-To's, Tutorials, Overviews,
+ Examples, and Class Documentation.
+
+ There are several types of predefined documentation \e categories or
+ \e types:
+ \list
+ \o How-To's
+ \o Tutorial
+ \o Overview
+ \o Article
+ \o FAQ (Frequently Asked Questions)
+ \o C++ API Documentation
+ \o QML Component Documentation
+ \o Code Example
+ \endlist
+
+ QDoc has the ability to format a page depending on the type. Further,
+ stylesheets can provide additional control on the display of each category.
+
+ \section1 API Documentation
+ QDoc excels in the creation of API documentation given a set of source code
+ and documentation in QDoc comments. Specifically, QDoc is aware of Qt's
+ architecture and can validate the existence of Qt C++ class, function, or
+ property documentation. QDoc gives warnings and errors if it cannot
+ associate a documentation with a code entity or if a code entity does not
+ have documentation.
+
+ In general, every Qt code entity such as properties, classes, methods,
+ signals, and enumerations have a corresponding
+ \l{qdoc-topics}{topic command}. QDoc will associate the documentation to the
+ source using C++ naming rules.
+
+ QDoc will parse the header files (typically \c .h files) to build a tree of
+ the class structures. Then QDoc will parse the source files and
+ documentation files to attach documentation to the class structure.
+ Afterwards, QDoc will generate a page for the class.
+
+ \note QDoc uses the header files to inform itself about the class and will
+ not properly process QDoc comments in header files.
+
+ \keyword qml-documentation
+ \section2 Documenting QML Components
+
+ In the world of \l{Qt Quick}{QML}, there are additional entities we need to
+ document such as QML signals, attached properties, and QML methods.
+ Internally, they use Qt technologies, however, QML API documentation
+ requires different layout and naming conventions from the Qt C++ API
+ documentation.
+
+ A list of QML related QDoc commands:
+ \list
+ \o \l{qmlattachedproperty-command}{\\qmlattachedproperty}
+ \o \l{qmlattachedsignal-command}{\\qmlattachedsignal}
+ \o \l{qmlbasictype-command}{\\qmlbasictype}
+ \o \l{qmlclass-command}{\\qmlclass} - creates a QML component documentation
+ \o \l{qmlmethod-command}{\\qmlmethod}
+ \o \l{qmlproperty-command}{\\qmlproperty}
+ \o \l{qmlsignal-command}{\\qmlsignal}
+ \o \l{inherits-command}{\\inherits}
+ \o \l{qmlmodule-command}{\\qmlmodule}
+ \o \l{inqmlmodule-command}{\\inqmlmodule}
+
+ \endlist
+
+ \note Remember to enable QML parsing by including the \c{*.qml} filetype in
+ the \l{qdoc-input-output-dir}{fileextension} variable.
+
+ Essentially, to create an API documentation of a QML component, create
+ a QDoc comment with a \l{qmlclass-command}{\\qmlclass} command. Similar to
+ C++ API documentation, QML API are documented using their corresponding QDoc
+ commands.
+
+ \section3 QML Parser
+
+ You may either document a QML component rom a C++ class or from a QML file.
+ QDoc supports both types and can parse both C++ and QML files.
+
+ In a QML file, you may simply place the QDoc comment above the property,
+ signal, handler, or method. QDoc will collect the comments and form the API
+ documentation. Additionally, QDoc can detect
+ \l{qml-property-aliases}{property-aliases}, but the property type must be
+ manually declared using the \l{qmlproperty-command}{\\qmlproperty} command.
+
+ QML components in C++ classes have their documentation above their property
+ or method documentation. However, the QML commands must be used instead of
+ the C++ documentation topic commands. Instead of the \c {\\class}
+ command, use the \l{qmlclass-command}{\\qmlclass} command.
+
+ \section3 QML Modules
+
+ A component belongs to a component \e set or a \e module. The module
+ may include all the related components for a platform or contain a certain
+ version of \l{Qt Quick}. For example, the Qt Quick 2 \l{QML Elements} belong
+ to the QtQuick2 module while there is also a QtQuick1 module for the older
+ elements introduced in Qt 4.
+
+ Modules affect the way Qdoc link and relate the components. The
+ \l{qmlclass-command}{\\qmlclass} topic command must have an
+ \l{inqmlmodule-command}{\\inqmlmodule} context command to relate the
+ component to a module. Similarly, a \l{qmlmodule-command}{\\qmlmodule} topic
+ command must exist in a separate \c .qdoc file to create the overview page
+ for the module. The overview page will list the related components.
+
+ The links to the components, must therefore, also contain the module name.
+ For example, if a component called \c TabWidget is in the \c UIComponents
+ module, it must be linked as \c {UIComponents::TabWidget}.
+
+ The \l{componentset}{UIComponents} example demonstrates proper usage of
+ QDoc commands to document QML components and QML modules.
+
+ \section3 Read-only and Internal QML Properties
+
+ QDoc detects QML properties that are marked as \c readonly. Note that the
+ property must be initialized with a value.
+
+ \code
+ readonly property int sampleReadOnlyProperty: 0
+ \endcode
+ For example, the example \l{TabWidget} component has a fictitious read-only
+ property \c sampleReadOnlyProperty. Its declaration has the \c readonly
+ identifier and it has an initial value.
+
+ Properties and signals that are not meant for the public interface may
+ be marked with the \l{internal-command}{\\internal} command. QDoc will not
+ publish the documentation in the generated outputs.
+
+ \section1 Articles & Overviews
+ Articles and overviews are a style of writing best used for providing
+ summary detail on a topic or concept. It may introduce a technology or
+ discuss how a concept may be applied, but without discussing exact steps
+ in too much detail. However, this type of content could provide the entry
+ point for readers to find instructional and reference materials that do,
+ such as tutorials, examples and class documentation. An example of an
+ overview might be a product page, such as a top level discussion of
+ QtQuick, individual modules, design principles, or tools.
+
+ To signify that a document is an article, you append the article keyword
+ to the \\page command:
+
+ \snippet examples/samples.qdocinc sample-overview
+
+ The \l{writing-topic-commands}{writing topic commands} section has a listing
+ of the available \\page command arguments.
+
+ \section1 Tutorials, How-To's, FAQ's
+
+ Tutorials, How-To's, and FAQ's are all instructional material, in that they
+ instruct or prescribe to the reader. Tutorials are content designed to guide
+ the reader along a progressive learning path for a concept or technology.
+ How-To's and FAQ's (\e{Frequently Asked Questions}) provide guidance by
+ presenting material in the form of answers to commonly asked topics.
+ How-To's and FAQ's are designed for easy reference and are not necessarily
+ presented in a linear progression.
+
+ To create these types, mark the pages by providing a \c type argument to the
+ \l{page-command}{\\page} command. The \c type argument is the second
+ argument, with the file name being the first.
+ \snippet examples/samples.qdocinc sample-faq
+
+ The \l{writing-topic-commands}{writing topic commands} section has a listing
+ of the available \\page command arguments.
+
+ \section1 Code Examples
+ Examples are an effective way to demonstrate practical usage of a given
+ technology or concept. When it comes to middleware this is usually in the
+ form of an application using simple code and clear explanations of what the
+ code is doing. Any module, API, project, pattern etc. should have at least
+ one good example.
+
+ An example may have an accompanying tutorial. The tutorial instructs and
+ describes the code, while the code example is the code content that users
+ may study. Code examples may have accompanying text that are not in the
+ tutorial.
+
+ QDoc will create a page containing the example code with a description
+ using the \l{example-command}{\\example} command.
+
+ \snippet examples/samples.qdocinc sample-example
+
+ QDoc will use the directory specified in the input
+ \l{Input and Output Directories}{exampledirs} variable to find the Qt
+ Project (\c .pro) file to generate the example files. The generated HTML
+ will have the filename, \c {declarative-ui-components-tabwidget.html}. QDoc
+ will also list all of the example code. For reference, view QDoc's generated
+ page for the \l{UI Components: Tab Widget Example}{Tab Widget} example.
+
+ \note The example's project file must be the same as the
+ directory name.
+*/
+
+/*!
+ \example config
+ \title Configuration File Example
+ \previouspage Categories of Documentation
+ \brief configuration files for the QDoc Manual and QDoc Guide
+
+ The QDoc Manual uses these \c qdocconf files to generate the QDoc Guide and
+ the \l{Table of Contents}{QDoc Manual}.
+
+ \note The configuration files are similar to the Qt Reference Documentation
+ and the QDoc Manual do not use all of the variables. The variables are
+ included to demonstrate a full project scenario.
+
+ \section1 Macros and other Definitions
+ \list
+ \o \l{config/compat.qdocconf}
+ \o \l{config/macros.qdocconf}
+ \o \l{config/qt-cpp-ignore.qdocconf}
+ \o \l{config/qt-defines.qdocconf}
+ \endlist
+
+ QDoc allows macros to help with aliasing and for inputting special HTML
+ characters within the documentation. Macros are a form of workarounds if
+ QDoc is unable to resolve formatting issues such as when QDoc should
+ disregard QDoc comments in documentation paragraphs.
+
+ QDoc is also aware of the common C++ and Qt preprocessors and can decide
+ which documentation to generate according to the definitions in the
+ configuration files.
+
+ \section1 Project Information
+ \list
+ \o \l{config/qdoc-online.qdocconf}
+ \o \l{config/qdoc.qdocconf}
+ \o \l{config/qdoc-project.qdocconf}
+ \endlist
+
+ These configuration files dictate how QDoc will generate the project.
+ Depending which configuration file QDoc processes, the formatting and the
+ information about the project will be different. If QDoc processes
+ \c{qdoc-online.qdocconf}, QDoc will generate the HTML version of the manual
+ will have the style suitable for online viewing.
+
+ Additionally, the settings for creating the
+ \l{The Qt Help Framework}{Qt Help File} is in the configuration.
+
+ \note The project file uses variables used during Qt's
+ \l{Configuration Options for Qt}{configuration} step.
+
+ \section1 HTML Styles
+ \list
+ \o \l{config/qt-html-default-styles.qdocconf}
+ \o \l{config/qt-html-online-styles.qdocconf}
+ \o \l{config/qt-html-templates-online.qdocconf}
+ \o \l{config/qt-html-templates.qdocconf}
+ \endlist
+
+ These files indicate which styles QDoc should use for the HTML formats.
+ Typically, there are two templates, one for online viewing and one for
+ offline. Qt Creator is able to fit more content in a page with the offline
+ template. The templates store HTML information as strings and QDoc will copy
+ the template to each HTML page.
+
+ \section1 Project File
+ \list
+ \o \l{config/config.pro}
+ \endlist
+
+ Every example page (such as this one) needs a Qt project file. QDoc will
+ use the project file to determine which files are part of the example. QDoc
+ will then create a page listing all the files that are part of the example.
+
+ \note the directory name of the example and the name of the project file
+ must match. The example directory is found using the
+ \l{qdoc-input-output-dir}{exampledirs} variable.
+*/
+
diff --git a/src/tools/qdoc/doc/qdoc-manual.qdoc b/src/tools/qdoc/doc/qdoc-manual.qdoc
new file mode 100644
index 0000000000..f3e01658fd
--- /dev/null
+++ b/src/tools/qdoc/doc/qdoc-manual.qdoc
@@ -0,0 +1,8780 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms
+** and conditions contained in a signed written agreement between you
+** and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page index.html
+ \nextpage Introduction to QDoc
+
+ \title Table of Contents
+
+ \list
+ \o \l {Introduction to QDoc}
+ \o \l {Getting Started with QDoc}
+ \o \l {Command Index}
+ \o \l {Topic Commands}
+ \o \l {Context Commands}
+ \list
+ \o \l {Document Navigation}
+ \o \l {Reporting Status}
+ \o \l {Thread Support}
+ \o \l {Relating Things}
+ \o \l {Grouping Things}
+ \o \l {Naming Things}
+ \endlist
+ \o \l{Markup Commands}
+ \list
+ \o \l {Text Markup}
+ \o \l {Document Structure}
+ \o \l {Including Code Inline}
+ \o \l {Including External Code}
+ \o \l {Creating Links}
+ \o \l {Including Images}
+ \o \l {Tables and Lists}
+ \o \l {Special Content}
+ \o \l {Miscellaneous}
+ \endlist
+ \o \l {The QDoc Configuration File}
+ \list
+ \o \l {Generic Configuration Variables}
+ \o \l {Creating Help Project Files}
+ \o \l {C++ Specific Configuration Variables}
+ \o \l {HTML Specific Configuration Variables}
+ \o \l {Supporting Derived Projects}
+ \o \l {Compatibility Issues}
+ \o \l {qt.qdocconf}
+ \o \l {minimum.qdocconf}
+ \o \l {Generating DITA XML Output}
+ \endlist
+ \endlist
+
+*/
+
+/*!
+ \page 01-qdoc-manual.html
+ \contentspage Table of Contents
+ \previouspage Table of Contents
+ \nextpage Command Index
+
+ \title Introduction to QDoc
+
+ QDoc is a tool used by Qt Developers to generate documentation for
+ software projects. It works by extracting \e {qdoc comments} from
+ project source files and then formatting these comments as HTML
+ pages or DITA XML documents, etc. QDoc finds qdoc comments in \c
+ {.cpp} files and in \c {.qdoc} files. QDoc does not look for qdoc
+ comments in \c {.h} files. A qdoc comment always begins with an
+ exclamation mark \bold{!} e.g.:
+
+ \code
+ / *!
+ \class QObject
+ \brief The QObject class is the base class of all Qt objects.
+
+ \ingroup objectmodel
+
+ \reentrant
+
+ QObject is the heart of the Qt \l{Object Model}. The
+ central feature in this model is a very powerful mechanism
+ for seamless object communication called \l{signals and
+ slots}. You can connect a signal to a slot with connect()
+ and destroy the connection with disconnect(). To avoid
+ never ending notification loops you can temporarily block
+ signals with blockSignals(). The protected functions
+ connectNotify() and disconnectNotify() make it possible to
+ track connections.
+
+ QObjects organize themselves in \l {Object Trees &
+ Ownership} {object trees}. When you create a QObject with
+ another object as parent, the object will automatically
+ add itself to the parent's children() list. The parent
+ takes ownership of the object; i.e., it will automatically
+ delete its children in its destructor. You can look for an
+ object by name and optionally type using findChild() or
+ findChildren().
+
+ Every object has an objectName() and its class name can be
+ found via the corresponding metaObject() (see
+ QMetaObject::className()). You can determine whether the
+ object's class inherits another class in the QObject
+ inheritance hierarchy by using the inherits() function.
+
+ ....
+ * /
+ \endcode
+
+ From the qdoc comment above, QDoc generates the now famous HTML
+ page \l {http://doc.qt.nokia.com/qobject.html#details}
+ {QObject Class Reference}.
+
+ This manual explains how to use the QDoc commands in qdoc comments
+ to embed good documentation in your source files. It also explains
+ how to make a \l {The QDoc Configuration File} {QDoc configuration
+ file}, which you will pass to QDoc on the command line.
+
+ \section1 Running QDoc
+
+ The current name of the QDoc program is \c {qdoc3}. To run qdoc3
+ from the command line, give it the name of a configuration file:
+
+ \quotation
+ \c {$ ../../bin/qdoc3 ./config.qdocconf}
+ \endquotation
+
+ QDoc recognizes the \c {.qdocconf} suffix as a \l{The QDoc
+ Configuration File} {QDoc configuration file}. The configuration
+ file is where you tell QDoc where to find the project source
+ files, header files, and \c {.qdoc} files. It is also where you
+ tell QDoc what kind of output to generate (HTML, DITA XML,...),
+ and where to put the generated documentation. The configuration
+ file also contains other information for QDoc.
+
+ See \l{The QDoc Configuration File} for a instructions on how to
+ build a Qdoc configuration file.
+
+ \section1 How QDoc Works
+
+ QDoc begins by reading the configuarion file you specified on the
+ command line. It stores all the variables from the configuration
+ file for later use. One of the first variables it uses is \c
+ {outputformats}. This variable tells QDoc which output generators
+ it will run. The default value is \e {HTML}, so if you don't set
+ \c {outputformats} in your configuration file, QDoc will generate
+ HTML output. That's usually what you will want anyway, but you can
+ also specify \e {DITAXML} to get DITA XML output instead.
+
+ Next, QDoc uses the values of the \l
+ {22-qdoc-configuration-generalvariables.html#headerdirs-variable}
+ {headerdirs} variable and/or the \l
+ {22-qdoc-configuration-generalvariables.html#headers-variable}
+ {headers} variable to find and parse all the header files for your
+ project. QDoc does \e not scan header files for qdoc comments. It
+ parses the header files to build a master tree of all the items
+ that should be documented (i.e. the items that QDoc should find
+ qdoc comments for).
+
+ After parsing all the header files and building the master tree of
+ items to be documented, QDoc uses the value of the \l
+ {22-qdoc-configuration-generalvariables.html#sourcedirs-variable}
+ {sourcedirs} variable and/or the value of the \l
+ {22-qdoc-configuration-generalvariables.html#sources-variable}
+ {sources} variable to find and parse all the \c {.cpp} and \c
+ {.qdoc} files for your project. These are the files QDoc scans for
+ \e {qdoc comments}. Remember that a qdoc comment begins with
+ an exclamation mark, i.e. \bold {/*!} .
+
+ For each qdoc comment it finds, it searches the master tree for
+ the item where the documentation belongs. The it interprets the
+ qdoc commands in the comment and stores the interpreted commands
+ and the comment text in the tree node for the item.
+
+ Finally, QDoc traverses the master tree. For each node, if the
+ node has stored documentation, QDoc calls the output generator
+ specified by the \c {outputformats} variable to format and write
+ the documentation in the directory specified in the configuration
+ file in the \l
+ {22-qdoc-configuration-generalvariables.html#outputdir-variable}
+ {outputdir} variable.
+
+ \section1 Command Types
+
+ QDoc interprets three types of commands:
+
+ \list
+ \o \l {Topic Commands}
+ \o \l {Context Commands}
+ \o \l {Markup Commands}
+ \endlist
+
+ Topic commands identify the elememt you are documenting, e.g. a C++
+ class, function, or type, an example, or an extra page of text
+ that doesn't map to an underlying C++ elememnt.
+
+ Context commands tell QDoc how the element being documented
+ relates to other documented elememnts, e.g. next and previous page
+ links or inclusion in page groups or library modules. Context
+ commands can also provide information about the documented element
+ that QDoc can't get from the source files, e.g. whether the
+ element is thread-safe, an overloaded or reimplemented function,
+ or that it has been deprecated.
+
+ Markup commands tell QDoc how text and image elements in the
+ document should be rendered, or about the document's outline
+ structure.
+*/
+
+/*!
+ \page 03-qdoc-commands-markup.html
+ \contentspage Table of Contents
+ \previouspage Naming Things
+ \nextpage Text Markup
+
+ \title Markup Commands
+
+ The markup commands indicate the generated documentation's visual
+ appearance and logical structure.
+
+ \list
+ \o \l {04-qdoc-commands-textmarkup.html#a-command} {\\a}
+ \o \l {11-qdoc-commands-specialcontent.html#abstract-command} {\\abstract}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#annotatedlist-command} {\\annotatedlist}
+ \o \l {06-qdoc-commands-includecodeinline.html#badcode-command} {\\badcode}
+ \o \l {04-qdoc-commands-textmarkup.html#bold-command} {\\bold}
+ \o \l {11-qdoc-commands-specialcontent.html#brief-command} {\\brief}
+ \o \l {04-qdoc-commands-textmarkup.html#c-command} {\\c}
+ \o \l {09-qdoc-commands-includingimages.html#caption-command} {\\caption}
+ \o \l {05-qdoc-commands-documentstructure.html#chapter-command} {\\chapter}
+ \o \l {06-qdoc-commands-includecodeinline.html#code-command} {\\code}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#codeline-command} {\\codeline}
+ \o \l {04-qdoc-commands-textmarkup.html#div-command} {\\div}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#dots-command} {\\dots}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#else-command} {\\else}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#endif-command} {\\endif}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#expire-command} {\\expire}
+ \o \l {11-qdoc-commands-specialcontent.html#footnote-command} {\\footnote}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#generatelist-command} {\\generatelist}
+ \o \l {10-qdoc-commands-tablesandlists.html#header-command} {\\header}
+ \o \l {04-qdoc-commands-textmarkup.html#i-command} {\\i}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#if-command} {\\if}
+ \o \l {09-qdoc-commands-includingimages.html#image-command} {\\image}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#include-command} {\\include}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#include-command} {\\input}
+ \o \l {09-qdoc-commands-includingimages.html#inlineimage-command} {\\inlineimage}
+ \o \l {08-qdoc-commands-creatinglinks.html#keyword-command} {\\keyword}
+ \o \l {08-qdoc-commands-creatinglinks.html#l-command} {\\l}
+ \o \l {11-qdoc-commands-specialcontent.html#legalese-command} {\\legalese}
+ \o \l {10-qdoc-commands-tablesandlists.html#list-command} {\\list}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#meta-command} {\\meta}
+ \o \l {06-qdoc-commands-includecodeinline.html#newcode-command} {\\newcode}
+ \o \l {10-qdoc-commands-tablesandlists.html#o-command} {\\o}
+ \o \l {06-qdoc-commands-includecodeinline.html#oldcode-command} {\\oldcode}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#omit-command} {\\omit}
+ \o \l {05-qdoc-commands-documentstructure.html#part-command} {\\part}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#printline-command} {\\printline}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#printto-command} {\\printto}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#printuntil-command} {\\printuntil}
+ \o \l {11-qdoc-commands-specialcontent.html#quotation-command} {\\quotation}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#quotefile-command} {\\quotefile}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#quotefromfile-command} {\\quotefromfile}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#raw-command} {\\raw}
+ \o \l {10-qdoc-commands-tablesandlists.html#row-command} {\\row}
+ \o \l {08-qdoc-commands-creatinglinks.html#sa-command} {\\sa}
+ \o \l {05-qdoc-commands-documentstructure.html#sectionOne-command} {\\section1}
+ \o \l {05-qdoc-commands-documentstructure.html#sectionTwo-command} {\\section2}
+ \o \l {05-qdoc-commands-documentstructure.html#sectionThree-command} {\\section3}
+ \o \l {05-qdoc-commands-documentstructure.html#sectionFour-command} {\\section4}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#skipline-command} {\\skipline}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#skipto-command} {\\skipto}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#skipuntil-command} {\\skipuntil}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#snippet-command} {\\snippet}
+ \o \l {04-qdoc-commands-textmarkup.html#span-command} {\\span}
+ \o \l {04-qdoc-commands-textmarkup.html#sub-command} {\\sub}
+ \o \l {04-qdoc-commands-textmarkup.html#sup-command} {\\sup}
+ \o \l {10-qdoc-commands-tablesandlists.html#table-command} {\\table}
+ \o \l {11-qdoc-commands-specialcontent.html#tableofcontents-command} {\\tableofcontents}
+ \o \l {08-qdoc-commands-creatinglinks.html#target-command} {\\target}
+ \o \l {04-qdoc-commands-textmarkup.html#tt-command} {\\tt}
+ \o \l {04-qdoc-commands-textmarkup.html#underline-command} {\\underline}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#raw-command} {\\unicode}
+ \o \l {11-qdoc-commands-specialcontent.html#warning-command} {\\warning}
+ \o \l {04-qdoc-commands-textmarkup.html#backslash-command} {\\\\}
+ \endlist
+*/
+
+/*!
+ \page 04-qdoc-commands-textmarkup.html
+ \contentspage Table of Contents
+ \previouspage Markup Commands
+ \nextpage Document Structure
+
+ \title Text Markup
+
+ The text formatting commands indicate how text is to be rendered.
+
+ \target a-command
+ \section1 \\a (parameter marker)
+
+ The \\a command tells QDoc the next word is a formal parameter name.
+
+ A warning is emitted when a formal parameter is not documented or
+ is misspelled, so when you document a function you should mention
+ each formal parameter by name in the function description,
+ preceded by the \\a command. The parameter name is then rendered
+ in italics.
+
+ \code
+ / *!
+ Constructs a line edit containing the text
+ \a contents. The \a parent parameter is sent
+ to the QWidget constructor.
+ * /
+
+ QLineEdit::QLineEdit(const QString &contents, QWidget *parent) :QWidget(parent)
+ {
+ ...
+ }
+
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \bold {QLineEdit::QLineEdit ( const QString &
+ contents, QWidget *parent )}
+
+ Constructs a line edit containing the text \a contents.
+ The \a parent parameter is sent to the QWidget constructor.
+ \endquotation
+
+ You can enclose the formal parameter name in curly brackets, if
+ you want to, but it isn't necessary.
+
+ \target c-command
+ \section1 \\c (code font)
+
+ The \\c command is used for rendering variable names, user-defined
+ class names, and C++ keywords (e.g. \c int and \c for) in the code
+ font.
+
+ The command renders its argument using a typewriter font. For
+ example:
+
+ \code
+ / *!
+ The \c AnalogClock class provides a clock widget with hour
+ and minute hands that is automatically updated every
+ few seconds.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The \c AnalogClock class provides a clock widget with hour
+ and minute hands that is automatically updated every
+ few seconds.
+ \endquotation
+
+ If the text to be rendered in the code font contains spaces, enclose the
+ entire text in curly brackets.
+
+ \code
+ \c {QLineEdit::QLineEdit(const QString &contents, QWidget *parent) :QWidget(parent)}
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \c {QLineEdit::QLineEdit(const QString &contents, QWidget *parent) :QWidget(parent)}
+ \endquotation
+
+ The \\c command accepts the special character \c \ within its
+ argument, i.e. it renders it as a normal character. So if you want
+ to use nested commands, you must use the \l {tt-command} {teletype
+ (\\tt)} command instead.
+
+ See also \l {tt-command} {\\tt} and \l {code-command} {\\code}.
+
+ \target div-command
+ \section1 \\div
+
+ The \\div and \\enddiv commands delimit a large or small block of
+ text (which may include other QDoc commands) to which special
+ formatting attributes should be applied.
+
+ An argument must be provided in curly braces, as in the qdoc
+ comment shown below. The argument is not interpreted but is used
+ as attribute(s) of the tag that is ultimately output by qdoc.
+
+ For example, we might want to render an inline image so that it
+ floats to the right of the current block of text:
+
+ \code
+ / *!
+ \div {class="float-right"}
+ \inlineimage qml-column.png
+ \enddiv
+
+ * /
+ \endcode
+
+ If qdoc is generating HTML, it will translate these commands to:
+
+ \code
+ <div class="float-right"><p><img src="images/qml-column.png" /></p></div>
+ \endcode
+
+ For HTML, the attribute value \e {float-right} then will refer to
+ a clause in the style.css file. which in this case could be:
+
+ \code
+ div.float-right
+ {
+ float: right; margin-left: 2em
+ }
+ \endcode
+
+ If qdoc is generating DITA XML, it will translate the commands to:
+
+ \code
+ <sectiondiv outputclass="float-right">
+ <p>
+ <fig>
+ <image href="images/qml-column.png" placement="inline"/>
+ </fig>
+ </p>
+ </sectiondiv>
+ \endcode
+
+ Your DITA XML publishing program must then recognize the \e
+ {outputclass} attribute value.
+
+ \note The \bold {\\div} command can be nested.
+
+ Below is an example taken from the index.qdoc file used to
+ generate index.html for Qt 4.7:
+
+ \code
+ \div {class="indexbox guide"}
+ \div {class="heading"}
+ Qt Developer Guide
+ \enddiv
+ \div {class="indexboxcont indexboxbar"}
+ \div {class="section indexIcon"} \emptyspan
+ \enddiv
+ \div {class="section"}
+ Qt is a cross-platform application and UI
+ framework. Using Qt, you can write web-enabled
+ applications once and deploy them across desktop,
+ mobile and embedded operating systems without
+ rewriting the source code.
+ \enddiv
+ \div {class="section sectionlist"}
+ \list
+ \o \l{Getting Started Guides} {Getting started}
+ \o \l{Installation} {Installation}
+ \o \l{how-to-learn-qt.html} {How to learn Qt}
+ \o \l{tutorials.html} {Tutorials}
+ \o \l{Qt Examples} {Examples}
+ \o \l{qt4-7-intro.html} {What's new in Qt 4.7}
+ \endlist
+ \enddiv
+ \enddiv
+ \enddiv
+ \endcode
+
+ When all the class attribute values are defined as they are in the
+ style.css file that is used for rendering the Qt 4.7 documentation,
+ the above example is rendered as:
+
+ \div {class="indexbox guide"}
+ \div {class="heading"}
+ Qt Developer Guide
+ \enddiv
+ \div {class="indexboxcont indexboxbar"}
+ \div {class="section indexIcon"} \emptyspan
+ \enddiv
+ \div {class="section"}
+ Qt is a cross-platform application and UI
+ framework. Using Qt, you can write web-enabled
+ applications once and deploy them across desktop,
+ mobile and embedded operating systems without
+ rewriting the source code.
+ \enddiv
+ \div {class="section sectionlist"}
+ \list
+ \o \l{Getting Started Guides} {Getting started}
+ \o \l{Installation} {Installation}
+ \o \l{how-to-learn-qt.html} {How to learn Qt}
+ \o \l{tutorials.html} {Tutorials}
+ \o \l{Qt Examples} {Examples}
+ \o \l{qt4-7-intro.html} {What's new in Qt 4.7}
+ \endlist
+ \enddiv
+ \enddiv
+ \enddiv
+
+ When generating DITA XML, qdoc outputs the nested \e {div} commands as:
+
+ \code
+ <sectiondiv outputclass="indexbox guide">
+ <sectiondiv outputclass="heading">
+ <p>Qt Developer Guide</p>
+ </sectiondiv>
+ <sectiondiv outputclass="indexboxcont indexboxbar">
+ <sectiondiv outputclass="section indexIcon"/>
+ <sectiondiv outputclass="section">
+ <p>Qt is a cross-platform application and UI
+ framework. Using Qt, you can write
+ web-enabled applications once and deploy
+ them across desktop, mobile and embedded
+ operating systems without rewriting the
+ source code.
+ </p>
+ </sectiondiv>
+ <sectiondiv outputclass="section sectionlist">
+ <ul>
+ <li>
+ <xref href="gettingstarted.xml#id-606ee7a8-219b-47b7-8f94-91bc8c76e54c">Getting started</xref>
+ </li>
+ <li>
+ <xref href="installation.xml#id-075c20e2-aa1e-4f88-a316-a46517e50443">Installation</xref>
+ </li>
+ <li>
+ <xref href="how-to-learn-qt.xml#id-49f509b5-52f9-4cd9-9921-74217b9a5182">How to learn Qt</xref>
+ </li>
+ <li>
+ <xref href="tutorials.xml#id-a737f955-a904-455f-b4aa-0dc69ed5a64f">Tutorials</xref>
+ </li>
+ <li>
+ <xref href="all-examples.xml#id-98d95159-d65b-4706-b08f-13d80080448d">Examples</xref>
+ </li>
+ <li>
+ <xref href="qt4-7-intro.xml#id-519ae0e3-4242-4c2a-b2be-e05d1e95f177">What's new in Qt 4.7</xref>
+ </li>
+ </ul>
+ </sectiondiv>
+ </sectiondiv>
+ </sectiondiv>
+ \endcode
+
+ Your DITA XML publishing program must recognize the values of the
+ \e {outputclass} attribute.
+
+ See also \l {span-command} {\\span}.
+
+ \target span -command
+ \section1 \\span
+
+ The \\span command is for applying special formatting
+ attributes to a small block of text.
+
+ Two arguments must be provided, each argument in curly braces, as
+ shown in the qdoc comment below. The first argument is not
+ interpreted but is used as the formatting attribute(s) of the tag
+ that is ultimately output by qdoc. The second argument is the text
+ to be rendered with the special formatting attributes.
+
+ For example, we might want to render the first word of each
+ element in a numeric list in blue.
+
+ \code
+ / *!
+ Global variables with complex types:
+ \list 1
+ \o \span {class="variableName"} {mutableComplex1} in globals.cpp at line 14
+ \o \span {class="variableName"} {mutableComplex2} in globals.cpp at line 15
+ \o \span {class="variableName"} {constComplex1} in globals.cpp at line 16
+ \o \span {class="variableName"} {constComplex2} in globals.cpp at line 17
+ \endlist
+ * /
+ \endcode
+
+ Class \e {variableName} refers to a clause in your style.css.
+
+ \code
+ .variableName
+ {
+ font-family: courier;
+ color: blue
+ }
+ \endcode
+
+ Using the \e {variableName} clause shown above, the example is rendered as:
+
+ Global variables with complex types:
+ \list 1
+ \o \span {class="variableName"} {mutableComplex1} in globals.cpp at line 14
+ \o \span {class="variableName"} {mutableComplex2} in globals.cpp at line 15
+ \o \span {class="variableName"} {constComplex1} in globals.cpp at line 16
+ \o \span {class="variableName"} {constComplex2} in globals.cpp at line 17
+ \endlist
+
+ \note The \bold span command does not cause a new paragraph to be
+ started.
+
+ See also \l {div-command} {\\div}.
+
+ \target tt-command
+ \section1 \\tt (teletype font)
+
+ The \\tt command renders its argument in a monospace font. This
+ command behaves just like the \l {c-command} {\\c} command, except
+ that \\tt allows you to nest QDoc commands within the argument
+ (e.g. \l {i-command} {\\i}, \l {bold-command} {\\bold} and \l
+ {underline-command} {\\underline}).
+
+ \code
+ / *!
+ After \c setupUi() populates the main container with
+ child widgets it scans the main container's list of
+ slots for names with the form
+ \tt{on_\e{objectName}_\e{signalName}().}
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ After \c setupUi() populates the main container with
+ child widgets it scans the main container's list of
+ slots for names with the form
+ \tt{on_\e{objectName}_\e{signalName}().}
+ \endquotation
+
+ If the text to be rendered in the code font contains spaces, enclose the
+ entire text in curly brackets.
+
+ \code
+ \tt {QLineEdit::QLineEdit(const QString &contents, QWidget *parent) :QWidget(parent)}
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \tt {QLineEdit::QLineEdit(const QString &contents, QWidget *parent) :QWidget(parent)}
+ \endquotation
+
+ See also \l {c-command} {\\c}.
+
+ \target bold-command
+ \section1 \\bold
+
+ The \\bold command renders its argument in bold font.
+
+ \code
+ / *!
+ This is regular text; \bold {this text is
+ rendered using the \\bold command}.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ This is regular text; \bold {this text is rendered using
+ the \\bold command}.
+ \endquotation
+
+ \target i-command
+ \section1 \\i (italics)
+
+ The \\i command renders its argument in italics.
+
+ \warning If \\i doesn't work and you get some strange error
+ meesages from qdoc3 about using \\o outside of tables and lists,
+ use \bold{\\e} for italics instead of \\i. For more information,
+ see the relevant explanation in the section on \l
+ {26-qdoc-commands-compatibility.html#i-versus-e} {compatibility
+ issues}.
+
+ If the argument contains spaces or other punctuation, enclose the
+ argument in curly brackets.
+
+ \code
+ / *!
+ Here, we render \i {a few words} in italic.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ Here, we render \e {a few words} in italic.
+ \endquotation
+
+ If you want to use other QDoc commands within an argument that
+ contains spaces, you always need to enclose the argument with
+ braces. But QDoc is smart enough to count parentheses [3], so you
+ don't need braces in cases like this:
+
+ \code
+ / *!
+ An argument can sometimes contain whitespaces,
+ for example: \i QPushButton(tr("A Brand New Button"))
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ An argument can sometimes contain whitespaces,
+ for example: \e QPushButton(tr("A Brand New Button"))
+ \endquotation
+
+ Finally, trailing punctuation is not included in an argument [4],
+ nor is 's [5]
+
+ \raw HTML
+ <table align="center" cellpadding="2"
+ cellspacing="1" border="0">
+ <tr valign="top" bgcolor="#a2c511">
+ <th></th>
+ <th>QDoc Syntax</th>
+ <th>Generated Documentation</th>
+ </tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td>1</td>
+ <td>A variation of a command button is a \e menu
+ button.</td>
+ <td>A variation of a command button is a <i>menu</i>
+ button.</td>
+ </tr>
+
+ <tr valign="top" bgcolor="#c0c0c0">
+ <td>2</td>
+ <td>The QPushButton widget provides a
+ \e {command button}.</td>
+ <td>The QPushButton widget provides a
+ <i>command button</i>.</td>
+ </tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td>3</td>
+ <td>Another class of buttons are option buttons
+ \e (see QRadioButton).</td>
+ <td>Another class of buttons are option buttons
+ <i> (see QRadioButton)</i>.</td>
+ </tr>
+
+ <tr valign="top" bgcolor="#c0c0c0">
+ <td>4</td>
+ <td>A push button emits the signal \e clicked().</td>
+ <td>A push button emits the signal <i>clicked</i>().</td>
+ </tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td>5</td>
+ <td>The \e QPushButton's checked property is
+ false by default.</td>
+ <td>The <i>QPushButton</i>'s checked property is
+ false by default.</td>
+ </tr>
+
+ </table>
+ \endraw
+
+ \target sub-command
+ \section1 \\sub
+
+ The \\sub command renders its argument lower than the baseline of
+ the regular text, using a smaller font.
+
+ \code
+ / *!
+ Definition (Range): Consider the sequence
+ {x\sub n}\sub {n > 1} . The set
+
+ {x\sub 2, x\sub 3, x\sub 4, ...} = {x\sub n ; n = 2, 3, 4, ...}
+
+ is called the range of the sequence.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ Definition (Range): Consider the sequence
+ {x\sub n}\sub {n > 1} . The set
+
+ {x\sub 2, x\sub 3, x\sub 4, ...} = {x\sub n ; n = 2, 3, 4, ...}
+
+ is called the range of the sequence.
+ \endquotation
+
+ If the argument contains spaces or other punctuation, enclose the
+ argument in curly brackets.
+
+ \target sup-command
+ \section1 \\sup
+
+ The \\sup command renders its argument higher than
+ the baseline of the regular text, using a smaller font.
+
+ \code
+ / *!
+ The series
+
+ 1 + a + a\sup 2 + a\sup 3 + a\sup 4 + ...
+
+ is called the \i {geometric series}.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The series
+
+ 1 + a + a\sup 2 + a\sup 3 + a\sup 4 + ...
+
+ is called the \e {geometric series}.
+ \endquotation
+
+ If the argument contains spaces or other punctuation, enclose the
+ argument in curly brackets.
+
+ \target underline-command
+ \section1 \\underline
+
+ The \\underline command renders its argument underlined.
+
+ \code
+ / *!
+ The \underline {F}ile menu gives the users the possibility
+ to open, and edit, an existing file, save a new or modified
+ file, and exit the application.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The \underline {F}ile menu gives the users the possibility
+ to open, and edit, an existing file, save a new or modified
+ file, and exit the application.
+ \endquotation
+
+ If the argument contains spaces or other punctuation, enclose the
+ argument in curly brackets.
+
+ \target backslash-command
+ \section1 \\\\ (double backslash)
+
+ The \\\\ command expands to a single backslash.
+
+ QDoc commands always start with a backslash alone. To display an
+ actual backslash in the text you need to type two of the kind. If
+ you want to display two backslashes, you need to type four, and so
+ forth.
+
+ \code
+ / *!
+ The \\\\ command is useful if you want a
+ backslash to appear verbatim, for example,
+ writing C:\\windows\\home\\.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The \\\\ command is useful if you want a
+ backslash to appear verbatim, for example,
+ writing C:\\windows\\home\\.
+ \endquotation
+
+ However, if you want your text to appear in a typewriter font as
+ well, you can use the \l {c-command} {\\c} command instead, which
+ accepts and renders the backslash as any other character. For
+ example:
+
+ \code
+ / *!
+ The \\c command is useful if you want a
+ backslash to appear verbatim, and the word
+ that contains it written in a typewriter font,
+ like this: \c {C:\windows\home\}.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The \\c command is useful if you want a
+ backslash to appear verbatim, and the word
+ that contains it written in a typewriter font,
+ like this: \c {C:\windows\home\}.
+ \endquotation
+
+*/
+
+/*!
+ \page 05-qdoc-commands-documentstructure.html
+ \previouspage Text Markup
+ \contentspage Table of Contents
+ \nextpage Including Code Inline
+
+ \title Document Structure
+
+ The document structuring commands are for dividing your document
+ into sections. QDoc supports six kinds of sections: \c \part, \c
+ \chapter, \c \section1, \c \section2, \c \section3 and \c
+ \section4. The \c \section1..4 commands are the most useful. The
+ correspond to the traditional section, subsection, etc used in
+ outlining.
+
+ \target part-command
+ \section1 \\part
+
+ The \\part command is intended for use in a large document, like a
+ book.
+
+ In general a document structuring command considers everything
+ that follows it until the first line break as its argument. The
+ argument is rendered as the unit's title. If the title needs to be
+ spanned over several lines, make sure that each line (except the
+ last one) is ended with a backslash.
+
+ In total, there are six levels of sections in QDoc: \c \part, \c
+ \chapter, \c \section1, \c \section2, \c \section3 and \c
+ \section4. \c \section1 to \c \section4 correspond to the
+ traditional section, subsection, subsubsection and
+ subsubsubsection.
+
+ There is a strict ordering of the section units:
+
+ \code
+ part
+ |
+ chapter
+ |
+ section1
+ |
+ section2
+ |
+ section3
+ |
+ section4
+ \endcode
+
+ For example, a \c section1 unit can only appear as the top level
+ section or inside a \c chapter unit. Skipping a section unit, for
+ example from \c part to \c section1, is not allowed.
+
+ You can \e begin with either of the three: \c part, \c chapter or
+ \c section1.
+
+
+ \code
+ / *!
+ \part Basic Qt
+
+ This is the first part.
+
+
+ \chapter Getting Started
+
+ This is the first part's first chapter.
+
+
+ \section1 Hello Qt
+
+ This is the first chapter's first section.
+
+
+ \section1 Making Connections
+
+ This is the first chapter's second section.
+
+
+ \section1 Using the Reference Documentation
+
+ This is the first chapter's third section.
+
+
+ \chapter Creating Dialogs
+
+ This is the first part's second chapter.
+
+
+ \section1 Subclassing QDialog
+
+ This is the second chapter's first section.
+
+ ...
+
+
+ \part Intermediate Qt
+
+ This is the second part.
+
+
+ \chapter Layout Management
+
+ This is the second part's first chapter.
+
+
+ \section1 Basic Layouts
+
+ This is the first chapter's first section.
+
+ ...
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \raw HTML
+ <a name="Basic Qt">
+ <h1>Basic Qt</h1>
+ </a>
+ <p>This is the first part.</p>
+
+ <a name="Getting started">
+ <h2>Getting Started</h2>
+ </a>
+ This is the first part's first chapter.</p>
+
+ <a name="Hello Qt">
+ <h3>Hello Qt</h3>
+ </a>
+ <p>This is the first chapter's first section.</p>
+
+ <a name="Making Connections">
+ <h3>Making Connections</h3>
+ </a>
+ <p>This is the first chapter's second section.</p>
+
+ <a name="Using the Reference Documentation">
+ <h3>Using the Reference Documentation</h3>
+ </a>
+ <p>This is the first chapter's third section.</p>
+
+ <a name="Creating Dialogs">
+ <h2>Creating Dialogs</h2>
+ </a>
+ <p>This is the first part's second chapter.</p>
+
+ <a name="Subclassing QDialog">
+ <h3>Subclassing QDialog</h3>
+ </a>
+ <p>This is the second chapter's first section.</p>
+
+ ...
+
+ <a name="Intermediate Qt">
+ <h1>Intermediate Qt</h1>
+ </a>
+ <p>This is the second part.</p>
+
+ <a name="Layout Management">
+ <h2>Layout Management</h2>
+ </a>
+ <p>This is the second part's first chapter.</p>
+
+ <a name="Basic Layouts">
+ <h3>Basic Layouts</h3>
+ </a>
+ <p>This is the first chapter's first section.</p>
+
+ ...
+
+ \endraw
+ \endquotation
+
+ Each section is a logical unit in the document. The section
+ heading appears in the automatically generated table of contents
+ that normally appears in the upper righthand corner of the page.
+
+ \target chapter-command
+ \section1 \\chapter
+
+ The \\chapter command is intended for use in
+ larger documents, and divides the document into chapters.
+
+ See \l{part} {\\part} for an explanation of the various
+ section units, command argument and rendering.
+
+ \target sectionOne-command
+ \section1 \\section1
+
+ The \\section1 command starts a new section.
+
+ See \l{part} {\\part} for an explanation of the various
+ section units, command argument and rendering.
+
+ \target sectionTwo-command
+ \section1 \\section2
+
+ The \\section2 command starts a new section.
+
+ See \l{part} {\\part} for an explanation of the various
+ section units, command argument and rendering.
+
+ \target sectionThree-command
+ \section1 \\section3
+
+ The \\section3 command starts a new section.
+
+ See \l{part} {\\part} for an explanation of the various
+ section units, command argument and rendering.
+
+ \target sectionFour-command
+ \section1 \\section4
+
+ The \\section4 command starts a new section.
+
+ See \l{part} {\\part} for an explanation of the various
+ section units, command argument and rendering.
+
+*/
+
+/*!
+ \page 06-qdoc-commands-includecodeinline.html
+ \previouspage Document Structure
+ \contentspage Table of Contents
+ \nextpage Including External Code
+
+ \title Including Code Inline
+
+ The following commands are used to render source code without
+ formatting. The source code begins on a new line, rendered in the
+ code.
+
+ \bold{Note:} Although all these commands are for rendering C++
+ code, the
+ \l{07-0-qdoc-commands-includingexternalcode.html#snippet-command}
+ {\\snippet} and
+ \l{07-0-qdoc-commands-includingexternalcode.html#codeline-command}
+ {\\codeline} commands are preferred over the others. These
+ commands allow equivalent code snippets for other Qt language
+ bindings to be substituted for the C++ snippets in the
+ documentation.
+
+ \target code-command
+ \section1 \\code
+
+ The \\code and \\endcode commands enclose a snippet of source code.
+
+ \note The \l {c-command} {\\c} command can be used for short code
+ fragments within a sentence. The \\code command is for longer code
+ snippets. It renders the code verbatim in a separate paragraph in
+ the code font.
+
+ When processing any of the \\code, \l {badcode-command}
+ {\\badcode}, \l {newcode-command} {\\newcode} or \l
+ {oldcode-command} {\\oldcode} commands, QDoc removes all
+ indentation that is common for the verbatim code blocks within a
+ \c{/}\c{*!} ... \c{*}\c{/} comment before it adds the standard
+ indentation. For that reason the recommended style is to use 8
+ spaces for the verbatim code contained within these commands
+
+ \note This doesn't apply to externally quoted code using the \l
+ {quotefromfile-command} {\\quotefromfile} or \l
+ {quotefile-command} {\\quotefile} command.
+
+ \code
+ / *!
+ \code
+ #include <QApplication>
+ #include <QPushButton>
+
+ int main(int argc, char *argv[])
+ {
+ ...
+ }
+ \ endcode
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \code
+ #include <QApplication>
+ #include <QPushButton>
+
+ int main(int argc, char *argv[])
+ {
+ ...
+ }
+ \endcode
+
+ Other QDoc commands are disabled within \\code... \\endcode, and
+ the special character '\\' is accepted and rendered like the rest
+ of the code.
+
+ To include code snippets from an external file, use the
+ \l{07-0-qdoc-commands-includingexternalcode.html#snippet-command}
+ {\\snippet} and
+ \l{07-0-qdoc-commands-includingexternalcode.html#codeline-command}
+ {\\codeline} commands.
+
+ See also \l {c-command} {\\c}, \l
+ {07-0-qdoc-commands-includingexternalcode.html#quotefromfile-command}
+ {\\quotefromfile}, \l {badcode-command} {\\badcode}, \l
+ {newcode-command} {\\newcode} and \l {oldcode-command}
+ {\\oldcode}.
+
+ \target badcode-command
+ \section1 \\badcode
+
+ The \\badcode and \\endcode commands delimit a snippet of code
+ that doesn't compile or is wrong for some other reason.
+
+ The \\badcode command is similar to the \l {code-command} {\\code}
+ command, but it renders the code snippet using a grey font instead
+ of black.
+
+ Like the \l {code-command} {\\code} command, this command begins
+ its code snippet on a new line rendered in the code font and with
+ the standard indentation.
+
+ \code
+ / *!
+ The statement below is rendered using the
+ regular \\code command:
+
+ \code
+ statusbar()->message(tr("Host %1 found").arg(hostName));
+ \ endcode
+
+ While the following statement is rendered using
+ the \\badcode command:
+
+ \badcode
+ statusbar()->message(tr("Host" + hostName + " found"));
+ \ endcode
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The statement below is rendered using the
+ regular \\code command:
+
+ \code
+ statusbar()->message(tr("Host %1 found").arg(hostName));
+ \endcode
+
+ While the following statement is rendered using
+ the \\badcode command:
+
+ \badcode
+ statusbar()->message(tr("Host" + hostName + " found"));
+ \endcode
+ \endquotation
+
+ Other QDoc commands are disabled within \\badcode... \\endcode,
+ and the special character '\\' is accepted and rendered like the
+ rest of the code.
+
+ See also \l {code-command} {\\code}, \l {newcode-command}
+ {\\newcode} and \l {oldcode-command} {\\oldcode}.
+
+ \target newcode-command
+ \section1 \\newcode
+
+ The \\newcode, \\oldcode, and \\endcode commands enable you to
+ show how to port a snippet of code to a new version of an API.
+
+ The \\newcode command, and its companion the \\oldcode command, is
+ a convenience combination of the \l {code-command} {\\code} and \l
+ {badcode-command} {\\badcode} commands: The combination provides a
+ text relating the two code snippets to each other. The command
+ requires a preceding \\oldcode statement.
+
+ Like the \l {code-command} {\\code} and \l {badcode-command}
+ {\\badcode} commands, the \\newcode command renders its code on a
+ new line in the documentation using a typewriter font and the
+ standard indentation.
+
+ \code
+ / *!
+ \oldcode
+ if (printer->setup(parent))
+ ...
+ \newcode
+ QPrintDialog dialog(printer, parent);
+ if (dialog.exec())
+ ...
+ \ endcode
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \oldcode
+ if (printer->setup(parent))
+ ...
+ \newcode
+ QPrintDialog dialog(printer, parent);
+ if (dialog.exec())
+ ...
+ \endcode
+ \endquotation
+
+ Other QDoc commands are disabled within \\oldcode ... \\endcode,
+ and the '\\' character doesn't need to be escaped.
+
+ \target oldcode-command
+ \section1 \\oldcode
+
+ The \\oldcode command requires a corresponding
+ \\newcode statement; otherwise QDoc fails to parse the command
+ and emits a warning.
+
+ See also \l {newcode-command} {\\newcode} and \l {badcode-command} {\\badcode}.
+
+ \target qml-command
+ \section1 \\qml
+
+ The \\qml and \\endqml commands enclose a snippet of QML source
+ code. Currently, QDoc handles \\qml and \\endqml exactly the same
+ as \\code and \\endcode.
+
+ \code
+ / *!
+ \qml
+ import QtQuick 1.0
+
+ Row {
+ Rectangle {
+ width: 100; height: 100
+ color: "blue"
+ transform: Translate { y: 20 }
+ }
+ Rectangle {
+ width: 100; height: 100
+ color: "red"
+ transform: Translate { y: -20 }
+ }
+ }
+ \endqml
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \qml
+ import QtQuick 1.0
+
+ Row {
+ Rectangle {
+ width: 100; height: 100
+ color: "blue"
+ transform: Translate { y: 20 }
+ }
+ Rectangle {
+ width: 100; height: 100
+ color: "red"
+ transform: Translate { y: -20 }
+ }
+ }
+ \endqml
+*/
+
+/*!
+ \page 07-0-qdoc-commands-includingexternalcode.html
+ \previouspage Including Code Inline
+ \contentspage Table of Contents
+ \nextpage Creating Links
+
+ \title Including External Code
+
+ The following commands enable you to include code snippets from
+ external files. You can make QDoc include the complete contents of
+ a file, or you can quote specific parts of the file and skip
+ others. The typical use of the latter is to quote a file chunk by
+ chunk.
+
+ \bold{Note:} Although all these commands are for rendering C++
+ code, the
+ \l{07-0-qdoc-commands-includingexternalcode.html#snippet-command}
+ {\\snippet} and
+ \l{07-0-qdoc-commands-includingexternalcode.html#codeline-command}
+ {\\codeline} commands are preferred over the others. These
+ commands allow equivalent code snippets for other Qt language
+ bindings to be substituted for the C++ snippets in the
+ documentation.
+
+ \target quotefile-command
+ \section1 \\quotefile
+
+ The \\quotefile command expands to the complete contents of the
+ file given as argument.
+
+ The command considers the rest of the line as part of its
+ argument, make sure to follow the file name with a line break.
+
+ The file's contents is rendered in a separate paragraph, using a
+ typewriter font and the standard indentation. The code is shown
+ verbatim.
+
+ \code
+ / *!
+ This is a simple "Hello world" example:
+
+ \quotefile examples/main.cpp
+
+ It contains only the bare minimum you need
+ to get a Qt application up and running.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ This is a simple "Hello world" example:
+
+ \quotefile examples/main.cpp
+
+ It contains only the bare minimum you need to get a Qt
+ application up and running.
+ \endquotation
+
+ See also \l {quotefromfile-command} {\\quotefromfile} and
+ \l {code-command} {\\code}.
+
+
+ \target quotefromfile-command
+ \section1 \\quotefromfile
+
+ The \\quotefromfile command opens the file given as argument for
+ quoting.
+
+ The command considers the rest of the line as part of its
+ argument, make sure to follow the file name with a line break.
+
+ The command is intended for use when quoting parts from file with
+ the walkthrough commands: \l {printline-command} {\\printline}, \l
+ {printto-command} {\\printto}, \l {printuntil-command}
+ {\\printuntil}, \l {skipline-command} {\\skipline}, \l
+ {skipto-command} {\\skipto}, \l {skipuntil-command}
+ {\\skipuntil}. This enables you to quote specific portions of a
+ file.
+
+ \code
+ / *!
+ The whole application is contained within
+ the \c main() function:
+
+ \quotefromfile examples/main.cpp
+
+ \skipto main
+ \printuntil app(argc, argv)
+
+ First we create a QApplication object using
+ the \c argc and \c argv parameters.
+
+ \skipto QPushButton
+ \printuntil resize
+
+ Then we create a QPushButton, and give it a reasonable
+ size using the QWidget::resize() function.
+
+ ...
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The whole application is contained within
+ the \c main() function:
+
+ \quotefromfile examples/main.cpp
+
+ \skipto main
+ \printuntil app(argc, argv)
+
+ First we create a QApplication object using the \c argc
+ and \c argv parameters.
+
+ \skipto QPushButton
+ \printuntil resize
+
+ Then we create a QPushButton, and give it a reasonable
+ size using the QWidget::resize() function.
+
+ ...
+ \endquotation
+
+ (\l {Example File} {The complete example file...})
+
+ QDoc remembers which file it's quoting, and the current position
+ within that file (see \l {file} {\\printline} for more
+ information). There is no need to "close" the file.
+
+ Earlier we called this command \\quotefile. For more information,
+ see the \l
+ {26-qdoc-commands-compatibility.html#quotefromfile-versus-quotefile}
+ {compatibility} section.
+
+ See also \l {quotefile-command} {\\quotefile}, \l {code-command}
+ {\\code} and \l {dots} {\\dots}.
+
+ \target printline-command
+ \section1 \\printline
+
+ The \\printline command expands to the line from the current
+ position to the next non-blank line of the current souce file.
+
+ To ensure that the documentation remains synchronized with the
+ source file, a substring of the line must be specified as an
+ argument to the command. Note that the command considers the rest
+ of the line as part of its argument, make sure to follow the
+ substring with a line break.
+
+ The line from the source file is rendered as a separate paragraph,
+ using a typewriter font and the standard indentation. The code is
+ shown verbatim.
+
+ \code
+ / *!
+ There has to be exactly one QApplication object
+ in every GUI application that uses Qt.
+
+ \quotefromfile examples/main.cpp
+
+ \printline QApplication
+
+ This line includes the QApplication class
+ definition. QApplication manages various
+ application-wide resources, such as the
+ default font and cursor.
+
+ \printline QPushButton
+
+ This line includes the QPushButton class
+ definition. The QPushButton widget provides a command
+ button.
+
+ \printline main
+
+ The main function...
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ There has to be exactly one QApplication object
+ in every GUI application that uses Qt.
+
+ \quotefromfile examples/main.cpp
+
+ \skipto QApplication
+ \printline QApplication
+
+ This line includes the QApplication class
+ definition. QApplication manages various
+ application-wide resources, such as the
+ default font and cursor.
+
+ \printline QPushButton
+
+ This line includes the QPushButton class
+ definition. The QPushButton widget provides a command
+ button.
+
+ \printline main
+
+ The main function...
+ \endquotation
+
+ (\l {Example File} {The complete example file...})
+
+ \target file
+
+ QDoc reads the file sequentially. To move the current position
+ forward you can use either of the \l {skipline-command}
+ {\\skip...} commands. To move the current position backward, you
+ can use the \l {quotefromfile-command} {\\quotefromfile} command
+ again.
+
+ \target substring
+
+ If the substring argument is surrounded by slashes it is
+ interpreted as a \l {regular expression}.
+
+ \code
+ / *!
+ \quotefromfile widgets/scribble/mainwindow.cpp
+
+ \skipto closeEvent
+ \printuntil /^\}/
+
+ Close events are sent to widgets that the users want to
+ close, usually by clicking \c File|Exit or by clicking
+ the \c X title bar button. By reimplementing the event
+ handler, we can intercept attempts to close the
+ application.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \quotefromfile widgets/scribble/mainwindow.cpp
+
+ \skipto closeEvent
+ \printuntil /^\}/
+
+ Close events are sent to widgets that the users want to
+ close, usually by clicking \c File|Exit or by clicking
+ the \c X title bar button. By reimplementing the event
+ handler, we can intercept attempts to close the
+ application.
+ \endquotation
+
+ (\l {widgets/scribble} {The complete example file...})
+
+ The regular expression \c /^\}/ makes QDoc print until the first
+ '}' character occurring at the beginning of the line without
+ indentation. /.../ encloses the regular expression, and '^' means
+ the beginning of the line. The '}' character must be escaped since
+ it is a special character in regular expressions.
+
+ QDoc will emit a warning if the specified substring or regular
+ expression cannot be located, i.e. if the source code has changed.
+
+ See also \l {printto-command} {\\printto} and \l
+ {printuntil-command} {\\printuntil}.
+
+ \target printto-command
+ \section1 \\printto
+
+ The \\printto command expands to all the lines from the current
+ position up to and \e excluding the next line containing a given
+ substring.
+
+ The command considers the rest of the line as part of its
+ argument, make sure to follow the substring with a line break. The
+ command also follows the same conventions for \l {file}
+ {positioning} and \l {substring} {argument} as the \l
+ {printline-command} {\\printline} command.
+
+ The lines from the source file are rendered in a separate
+ paragraph, using a typewriter font and the standard
+ indentation. The code is shown verbatim.
+
+ \code
+ / *!
+ The whole application is contained within the
+ \c main() function:
+
+ \quotefromfile examples/main.cpp
+ \printto hello
+
+ First we create a QApplication object using the \c argc and
+ \c argv parameters...
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The whole application is contained within the
+ \c main() function:
+
+ \quotefromfile examples/main.cpp
+ \skipto main
+ \printto hello
+
+ First we create a QApplication object using the \c argc
+ and \c argv parameters...
+ \endquotation
+
+ (\l {Example File} {The complete example file...})
+
+ See also \l {printline-command} {\\printline} and \l
+ {printuntil-command} {\\printuntil}.
+
+ \target printuntil-command
+ \section1 \\printuntil
+
+ The \\printuntil command expands to all the lines from the current
+ position up to and \e including the next line containing a given
+ substring.
+
+ The command considers the rest of the line as part of its
+ argument, make sure to follow the substring with a line break. The
+ command also follows the same conventions for \l {file}
+ {positioning} and \l {substring} {argument} as the \l
+ {printline-command} {\\printline} command.
+
+ The lines from the source file are rendered in a separate
+ paragraph, using a typewriter font and the standard
+ indentation. The code is shown verbatim.
+
+ \code
+ / *!
+ The whole application is contained within the
+ \c main() function:
+
+ \quotefromfile examples/main.cpp
+ \skipto main
+ \printuntil hello
+
+ First we create a QApplication object using the
+ \c argc and \c argv parameters, then we create
+ a QPushButton.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The whole application is contained within the
+ \c main() function:
+
+ \quotefromfile examples/main.cpp
+ \skipto main
+ \printuntil hello
+
+ First we create a \l
+ {http://qt.nokia.com/doc/4.0/qapplication} {QApplication}
+ object using the \c argc and \c argv parameters, then we
+ create a \l
+ {http://qt.nokia.com/doc/4.0/qpushbutton} {QPushButton}.
+ \endquotation
+
+ (\l {Example File} {The complete example file...})
+
+ See also \l {printline-command} {\\printline} and \l
+ {printto-command} {\\printto}.
+
+ \target skipline-command
+ \section1 \\skipline
+
+ The \\skipline command ignores the next non-blank line in the
+ current source file.
+
+ Doc reads the file sequentially, and the \\skipline command is
+ used to move the current position (omitting a line of the source
+ file). See the remark about \l {file} {file positioning} above.
+
+ The command considers the rest of the line as part of its
+ argument, make sure to follow the substring with a line break. The
+ command also follows the same conventions for \l {substring}
+ {argument} as the \l {printline-command} {\\printline} command,
+ and it is used in conjunction with the \l {quotefromfile-command}
+ {\\quotefromfile} command.
+
+ \code
+ / *!
+ QPushButton is a GUI push button that the user
+ can press and release.
+
+ \quotefromfile examples/main.cpp
+ \skipline QApplication
+ \printline QPushButton
+
+ This line includes the QPushButton class
+ definition. For each class that is part of the
+ public Qt API, there exists a header file of
+ the same name that contains its definition.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \l
+ QPushButton is a GUI push button that the user
+ can press and release.
+
+ \quotefromfile examples/main.cpp
+ \skipto QApplication
+ \skipline QApplication
+ \printline QPushButton
+
+ This line includes the QPushButton class
+ definition. For each class that is part of the public
+ Qt API, there exists a header file of the same name
+ that contains its definition.
+ \endquotation
+
+ (\l {Example File} {The complete example file...})
+
+ See also \l {skipto-command} {\\skipto}, \l {skipuntil-command}
+ {\\skipuntil} and \l {dots} {\\dots}.
+
+ \target skipto-command
+ \section1 \\skipto
+
+ The \\skipto command ignores all the lines from the current
+ position up to and \e excluding the next line containing a given
+ substring.
+
+ QDoc reads the file sequentially, and the \\skipto command is used
+ to move the current position (omitting one or several lines of the
+ source file). See the remark about \l {file} {file positioning}
+ above.
+
+ The command considers the rest of the line as part of its
+ argument, make sure to follow the substring with a line break.
+
+ The command also follows the same conventions for \l {substring}
+ {argument} as the \l {printline-command} {\\printline} command,
+ and it is used in conjunction with the \l {quotefromfile-command}
+ {\\quotefromfile} command.
+
+ \code
+ / *!
+ The whole application is contained within
+ the \c main() function:
+
+ \quotefromfile examples/main.cpp
+ \skipto main
+ \printuntil }
+
+ First we create a QApplication object. There
+ has to be exactly one such object in
+ every GUI application that uses Qt. Then
+ we create a QPushButton, resize it to a reasonable
+ size...
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The whole application is contained within
+ the \c main() function:
+
+ \quotefromfile examples/main.cpp
+ \skipto main
+ \printuntil }
+
+ First we create a QApplication object. There has to be
+ exactly one such object in every GUI application that
+ uses Qt. Then we create a QPushButton, resize it to a
+ reasonable size ...
+ \endquotation
+
+ (\l {Example File} {The complete example file...})
+
+ See also \l {skipline-command} {\\skipline}, \l
+ {skipuntil-command} {\\skipuntil} and \l {dots} {\\dots}.
+
+ \target skipuntil-command
+ \section1 \\skipuntil
+
+ The \\skipuntil command ignores all the lines from the current
+ position up to and \e including the next line containing a given
+ substring.
+
+ QDoc reads the file sequentially, and the \\skipuntil command is
+ used to move the current position (omitting one or several lines
+ of the source file). See the remark about \l {file} {file
+ positioning} above.
+
+ The command considers the rest of the line as part of its
+ argument, make sure to follow the substring with a line break.
+
+ The command also follows the same conventions for \l {substring}
+ {argument} as the \l {printline-command} {\\printline} command,
+ and it is used in conjunction with the \l {quotefromfile-command}
+ {\\quotefromfile} command.
+
+ \code
+ / *!
+ The first thing we did in the \c main() function
+ was to create a QApplication object \c app.
+
+ \quotefromfile examples/main.cpp
+ \skipuntil show
+ \dots
+ \printuntil }
+
+ In the end we must remember to make \c main() pass the
+ control to Qt. QCoreApplication::exec() will return when
+ the application exits...
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ The first thing we did in the \c main() function was to
+ create a QApplication object \c app.
+
+ \quotefromfile examples/main.cpp
+ \skipuntil show
+ \dots
+ \printuntil }
+
+ In the end we must remember to make \c main() pass the
+ control to Qt. QCoreApplication::exec()
+ will return when the application exits...
+ \endquotation
+
+ (\l {Example File} {The complete example file...})
+
+ See also \l {skipline-command} {\\skipline}, \l {skipto-command}
+ {\\skipto} and \l {dots} {\\dots}.
+
+ \target dots-command
+ \section1 \\dots
+
+ The \\dots command indicates that parts of the source file have
+ been omitted when quoting a file.
+
+ The command is used in conjunction with the \l
+ {quotefromfile-command} {\\quotefromfile} command, and should be
+ stated on its own line. The dots are rendered on a new line, using
+ a typewriter font.
+
+ \code
+ / *!
+ \quotefromfile examples/main.cpp
+ \skipto main
+ \printuntil {
+ \dots
+ \skipuntil exec
+ \printline }
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotefromfile examples/main.cpp
+ \skipto main
+ \printuntil {
+ \dots
+ \skipuntil exec
+ \printline }
+
+ (\l {Example File} {The complete example file...})
+
+ The default indentation is 4 spaces, but this can be adjusted
+ using the command's optional argument.
+
+ \code
+ / *!
+ \dots 0
+ \dots
+ \dots 8
+ \dots 12
+ \dots 16
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \dots 0
+ \dots
+ \dots 8
+ \dots 12
+ \dots 16
+
+ See also \l {skipline-command} {\\skipline}, \l {skipto-command}
+ {\\skipto} and \l {skipuntil-command} {\\skipuntil}.
+
+ \target snippet-command
+ \section1 \\snippet
+
+ The \\snippet command causes a code snippet to be included
+ verbatim as preformatted text, which may be syntax highlighted.
+
+ Each code snippet are referenced by the file that holds it and by
+ a unique identifier for that file. Snippet files are typically
+ stored in a \c{snippets} directory inside the documentation
+ directory (e.g., \c{$QTDIR/doc/src/snippets}).
+
+ For example, the following documentation references a snippet in a
+ file residing in a subdirectory of the documentation directory:
+
+ \code
+ \snippet snippets/textdocument-resources/main.cpp Adding a resource
+ \endcode
+
+ The text following the file name is the unique identifier for the
+ snippet. This is used to delimit the quoted code in the relevant
+ snippet file as shown in the following example that corresponds to
+ the above \c{\\snippet} command:
+
+ \dots
+ \code
+ QImage image(64, 64, QImage::Format_RGB32);
+ image.fill(qRgb(255, 160, 128));
+
+ //! [Adding a resource]
+ document->addResource(QTextDocument::ImageResource,
+ QUrl("mydata://image.png"), QVariant(image));
+ //! [Adding a resource]
+ \endcode
+ \dots
+
+ \target codeline-command
+ \section1 \\codeline
+
+ The \\codeline command inserts a blank line of preformatted
+ text. It is used to insert gaps between snippets without closing
+ the current preformatted text area and opening a new one.
+
+*/
+
+/*!
+ \page 07-1-example.html
+ \previouspage Including External Code
+ \contentspage Table of Contents
+
+ \title Example File
+
+ \quotefile examples/main.cpp
+*/
+
+/*!
+ \page 08-qdoc-commands-creatinglinks.html
+ \previouspage Including External Code
+ \contentspage Table of Contents
+ \nextpage Including Images
+
+ \title Creating Links
+
+ These commands are for creating hyperlinks to classes, functions,
+ examples, and other targets.
+
+ \target l-command
+ \section1 \\l (link)
+
+ The \\l link command is used to create a hyperlink to many
+ different kinds of targets. The command's general syntax is:
+
+ \code
+ \l {link target} {link text}
+ \endcode
+
+ \code
+ / *!
+ Read the \l {http://qt.nokia.com/doc/4.0/}
+ {Qt's Reference Documentation} carefully.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ Read the \l {http://qt.nokia.com/doc/4.0/}
+ {Qt's Reference Documentation} carefully.
+ \endquotation
+
+ If the link target is equivalent to the link text, the second
+ argument can be omitted.
+
+ For example, if you have documentation like:
+
+ \code
+ / *!
+ \target assertions
+
+ Assertions make some statement about the text at the
+ point where they occur in the regexp but they do not
+ match any characters.
+
+ ...
+
+ Regexps are built up from expressions, quantifiers, and
+ \l {assertions} {assertions}.
+ * /
+ \endcode
+
+ You can simplify this as follows:
+
+ \code
+ / *!
+ \target assertions
+
+ Assertions make some statement about the text at the
+ point where they occur in the regexp but they do not
+ match any characters.
+
+ ...
+
+ Regexps are built up from expressions, quantifiers, and
+ \l assertions.
+ * /
+ \endcode
+
+ For the one-parameter version the braces can often be omitted.
+ The \\l command supports several kinds of links:
+
+ \list
+
+ \o \c {\l QWidget} - The name of a class documented with the \l
+ {class-command} {\\class} command.
+
+ \o \c {\l QWidget::sizeHint()} - The name of a member function,
+ documented with or without an \l {fn-command} {\\fn} command.
+
+ \o \c {\l <QtGlobal>} - The subject of a \l {headerfile-command}
+ {\\headerfile} command.
+
+ \o \c {\l widgets/wiggly} - The relative path used in an \l
+ {example-command} {\\example} command.
+
+ \o \c {\l {QWidget Class Reference}} - The title used in a
+ \l {title-command} {\\title} command.
+
+ \o \c {\l {Introduction to QDoc}}- The text from one of the
+ \l{part-command} {\\part}, \l{chapter} {\\chapter} or \l
+ {sectionOne-command} {\\section} commands.
+
+ \o \c {\l fontmatching} - The argument of a \l {target-command}
+ {\\target} command.
+
+ \o \c {\l {Shared Classes}} - A keyword named in a \l
+ {keyword-command} {\\keyword} command.
+
+ \o \c {\l network.html} - The file name used in a \l
+ {page-command} {\\page} command.
+
+ \o \c {\l http://qt.nokia.com/} - A URL.
+
+ \endlist
+
+ QDoc also tries to make a link out of any words that don't
+ resemble any normal English words, for example Qt class names or
+ functions, like QWidget or QWidget::sizeHint(). In these cases,
+ the \\l command can actually be omitted, but by using the command,
+ you ensure that QDoc will emit a warning if it cannot find the
+ link target. In addition, if you only want the function name to
+ appear in the link, you can use the following syntax:
+
+ \list
+ \o \c {\l {QWidget::} {sizeHint()}}
+ \endlist
+
+ QDoc renders this as:
+
+ \quotation
+ \l {QWidget::} {sizeHint()}
+ \endquotation
+
+ See also \l {sa-command} {\\sa}, \l {target-command} {\\target}
+ and \l {keyword-command} {\\keyword}.
+
+
+ \target sa-command
+ \section1 \\sa (see also)
+
+ The \\sa command defines a list of links that will be rendered in
+ a separate "See also" section at the bottom of the documentation
+ unit.
+
+ The command takes a comma-separated list of links as its
+ argument. If the line ends with a comma, you can continue
+ the list on the next line. The general syntax is:
+
+ \code
+ \sa {the first link}, {the second link},
+ {the third link}, ...
+ \endcode
+
+ QDoc will automatically try to generate "See also" links
+ interconnecting a property's various functions. For example, a
+ setVisible() function will automatically get a link to visible()
+ and vice versa.
+
+ In general, QDoc will generate "See also" links that interconnect
+ the functions that access the same property. It recognizes four
+ different syntax versions:
+
+ \list
+ \o \c property()
+ \o \c setProperty()
+ \o \c isProperty()
+ \o \c hasProperty()
+ \endlist
+
+ The \\sa command supports the same kind of links as the \l
+ {l-command} {\\l} command.
+
+ \code
+ / *!
+ Appends the actions \a actions to this widget's
+ list of actions.
+
+ \sa removeAction(), QMenu, addAction()
+ * /
+ void QWidget::addActions(QList<QAction *> actions)
+ {
+ ...
+ }
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \bold {void QWidget::addActions ( QList<QAction*>
+ \e actions )}
+
+ Appends the actions \e actions to this widget's list of
+ actions.
+
+ See also \l {QWidget::removeAction()} {removeAction()},
+ \l QMenu, and \l {QWidget::addAction()} {addAction()}.
+ \endquotation
+
+ See also \l {l-command} {\\l}, \l {target-command} {\\target} and
+ \l {keyword-command} {\\keyword}.
+
+
+ \target target-command
+ \section1 \\target
+
+ The \\target command names a place in the documentation that you
+ can link to using the \l {l-command} {\\l (link)} and \l
+ {sa-command} {\\sa (see also)} commands.
+
+ The text up to the line break becomes the target name. Be sure to
+ follow the target name with a line break. Curly brackets are not
+ required around the target name, but they may be required when the
+ target name is used in a link cammand. See below.
+
+ \code
+ / *!
+ \target capturing parentheses
+ \section1 Capturing Text
+
+ Parentheses allow us to group elements together so that
+ we can quantify and capture them.
+
+ ...
+ * /
+ \endcode
+
+ The target name \e{capturing parentheses} can be linked from
+ within the same document containing the target in two ways:
+
+ \list
+ \o \c {\l {capturing parentheses}} (from within the same qdoc comment)
+ \o \c {\l qregexp.html#capturing-parentheses} (from elsewhere in the same document)
+ \endlist
+
+ \note The brackets in the link example are required because the
+ target name contains spaces.
+
+ From other documents, the target name can be linked this way:
+
+ \list
+ \o \c {\l http://doc.qt.nokia.com/4.0/qregexp.html#capturing-parentheses}
+ \endlist
+
+ See also \l {l-command} {\\l}, \l {sa-command} {\\sa} and \l
+ {keyword-command} {\\keyword}.
+
+ \target keyword-command
+ \section1 \\keyword
+
+ The \\keyword command names a place in the documentation that you
+ can link to using the \l {l-command} {\\l (link)} and \l
+ {sa-command} {\\sa (see also)} commands.
+
+ The \\keyword command is like the \l {target-command} {\\target}
+ command, but stronger. A keyword can be linked from anywhere using
+ a simple syntax.
+
+ Keywords must be unique over all the documents processed during
+ the QDoc run. The command uses the rest of the line as its
+ argument. Be sure to follow the keyword with a line break.
+
+
+ \code
+ / *!
+ \class QRegExp
+ \reentrant
+ \brief The QRegExp class provides pattern
+ matching using regular expressions.
+ \ingroup tools
+ \ingroup misc
+ \ingroup shared
+ \mainclass
+
+ \keyword regular expression
+
+ Regular expressions, or "regexps", provide a way to
+ find patterns within text.
+
+ ...
+ * /
+ \endcode
+
+ The location marked with the keyword can be linked with:
+
+ \code
+ / *!
+ When a string is surrounded by slashes, it is
+ interpreted as a \l {regular expression}.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ When a string is surrounded by slashes, it's
+ interpreted as a \l {regular expression}.
+ \endquotation
+
+ If the keyword text contains spaces, the brackets are required.
+
+ See also \l {l-command} {\\l (link)}, \l {sa-command} {\\sa (see
+ also)} and \l {target-command} {\\target}.
+
+*/
+
+/*!
+ \page 09-qdoc-commands-includingimages.html
+ \previouspage Creating Links
+ \contentspage Table of Contents
+ \nextpage Tables and Lists
+
+ \title Including Images
+
+ The graphic commands makes it possible to include images in the
+ documentation. The images can be rendered as separate paragraphs,
+ or within running text.
+
+ \target image-command
+ \section1 \\image
+
+ The \\image command expands to the image specified by its first
+ argument, and renders it centered as a separate paragraph.
+
+ The \\image command replaces the old \\img command. For more
+ information, see the \l
+ {26-qdoc-commands-compatibility.html#image-versus-img}
+ {compatibility} section.
+
+ The command takes two arguments. The first argument is the name of
+ the image file. The second argument is optional and is a simple
+ description of the image, equivalent to the HTML alt="" in an image
+ tag. The description is used for tooltips, and for when a browser
+ doesn't support images, like the Lynx text browser.
+
+ The remaining text \e{after} the file name is the optional,
+ description argument. Be sure to follow the file name or the
+ description with a line break. Curly brackets are required if the
+ description argument spans multiple lines.
+
+ \code
+ / *!
+ Qt is a C++ toolkit for cross-platform GUI application development.
+
+ \image happyguy.jpg "Happy guy"
+
+ Qt provides single-source portability across Microsoft
+ Windows, Mac OS X, Linux, and all major commercial Unix
+ variants. It is also available for embedded devices.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ Qt is a C++ toolkit for cross-platform GUI application development.
+
+ \image happyguy.jpg image "Happy guy"
+
+ Qt provides single-source portability across Microsoft
+ Windows, Mac OS X, Linux, and all major commercial Unix
+ variants. It is also available for embedded devices.
+ \endquotation
+
+ See also \l {inlineimage-command} {\\inlineimage} and \l
+ {caption-command} {\\caption}.
+
+ \target inlineimage-command
+ \section1 \\inlineimage
+
+ The \\inlineimage command expands to the image specified by its
+ argument. The image is rendered inline with the rest of the text.
+
+ The command takes two arguments. The first argument is the name of
+ the image file. The second argument is optional and is a simple
+ description of the image, equivalent to the HTML alt="" in an image
+ tag. The description is used for tooltips, and for when a browser
+ doesn't support images, like the Lynx text browser.
+
+ The most common use of the \\inlineimage command is in lists and
+ tables. Here is an example of including inline images in a list:
+
+ \code
+ / *!
+ \list 1
+ \o \inlineimage happy.gif Oh so happy!
+ \o \inlineimage happy.gif Oh so happy!
+ \o \inlineimage happy.gif Oh so happy!
+ \endlist
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \list 1
+ \o \inlineimage happy.gif Oh so happy!
+ \o \inlineimage happy.gif Oh so happy!
+ \o \inlineimage happy.gif Oh so happy!
+ \endlist
+
+ Here is an example of including inline images in a table:
+
+ \code
+ / *!
+ \table
+ \header
+ \o Qt
+ \o Qt Creator
+ \row
+ \o \inlineimage happy.gif Oh so happy!
+ \o \inlineimage happy.gif Oh so happy!
+ \row
+ \o \inlineimage happy.gif Oh so happy!
+ \o \inlineimage happy.gif Oh so happy!
+ \endtable
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \raw HTML
+ <table align="center" cellpadding="2"
+ cellspacing="1" border="0">
+ <tr valign="top" bgcolor="#a2c511">
+ <th>Qt</th>
+ <th>Qt Creator</th>
+ </tr>
+ <tr valign="top" bgcolor="#f0f0f0">
+ <td><img src="images/happy.gif" alt="Oh so happy!" />
+ </td>
+ <td><img src="images/happy.gif" alt="Oh so happy!" />
+ </td>
+ </tr>
+ <tr valign="top" bgcolor="#f0f0f0">
+ <td><img src="images/happy.gif" alt="Oh so happy!"/>
+ </td>
+ <td><img src="images/happy.gif" alt="Oh so happy!" />
+ </td>
+ </tr>
+ </table>
+ \endraw
+
+ The command can also be used to insert an image inline with the
+ text.
+
+ \code
+ / *!
+ \inlineimage training.jpg Qt Training
+ The Qt Programming course is offered as a
+ five day Open Enrollment Course. The classes
+ are open to the public. While the course is open
+ to anyone who wants to learn, attendees should
+ have significant experience in C++ development
+ to derive maximum benefit from the course.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \inlineimage training.jpg Qt Training
+ The Qt Programming course is offered as a
+ five day Open Enrollment Course. The classes
+ are open to the public. While the course is open
+ to anyone who wants to learn, attendees should
+ have significant experience in C++ development
+ to derive maximum benefit from the course.
+ \endquotation
+
+ See also \l {image-command} {\\image} and \l {caption-command} {\\caption}.
+
+ \target caption-command
+ \section1 \\caption
+
+ The \\caption command provides a caption for an image.
+
+ The command takes all the text up to the end of the paragraph to
+ be the caption. Experiment until you get the effect you want.
+
+ \code
+ / *!
+ \table 100%
+ \row
+ \o \image windowsvista-pushbutton.png
+ \caption The QPushButton widget provides a command button.
+ \o \image windowsvista-toolbutton.png
+ \caption The QToolButton class provides a quick-access button to commands
+ or options, usually used inside a QToolBar.
+ \endtable
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \table 100%
+ \row
+ \o \image windowsvista-pushbutton.png
+ \caption The QPushButton widget provides a command button.
+ \o \image windowsvista-toolbutton.png
+ \caption The QToolButton class provides a quick-access button to commands
+ or options, usually used inside a QToolBar.
+ \endtable
+
+ See also \l {image-command} {\\image} and \l {inlineimage-command}
+ {\\inlineimage}
+*/
+
+/*!
+ \page 10-qdoc-commands-tablesandlists.html
+ \previouspage Including Images
+ \contentspage Table of Contents
+ \nextpage Special Content
+
+ \title Tables and Lists
+
+ These commands enable creating lists and tables. A list is
+ rendered left aligned as a separate paragraph. A table is rendered
+ centered as a separate paragraph. The table width depends on the
+ width of its contents.
+
+ \target table-command
+ \section1 \\table
+
+ The \\table and \\endtable commands delimit the contents of a
+ table.
+
+ The command accepts a single argument specifying the table's width
+ as a percentage of the page width:
+
+ \code
+ / *!
+ \table 100 %
+
+ ...
+
+ \endtable
+ * /
+ \endcode
+
+ The code above ensures that the table will fill all available
+ space. If the table's width is smaller than 100 %, the table will
+ be centered in the generated documentation.
+
+ A table can contain headers, rows and columns. A row starts with a
+ \l {row-command} {\\row} command and consists of cells, which
+ starts with a \l {o-command} {\\o} command. There is also a \l
+ {header-command} {\\header} command which is a special kind of row
+ with a special formatting.
+
+ \code
+ / *!
+ \table
+ \header
+ \o Qt Core Feature
+ \o Brief Description
+ \row
+ \o \l {Signal and Slots}
+ \o Signals and slots are used for communication
+ between objects.
+ \row
+ \o \l {Layout Management}
+ \o The Qt layout system provides a simple
+ and powerful way of specifying the layout
+ of child widgets.
+ \row
+ \o \l {Drag and Drop}
+ \o Drag and drop provides a simple visual
+ mechanism which users can use to transfer
+ information between and within applications.
+ \endtable
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \raw HTML
+ <table align="center" cellpadding="2"
+ cellspacing="1" border="0">
+ <tr valign="top" bgcolor="#a2c511">
+ <th>Qt Core Feature</th>
+ <th>Brief Description</th>
+ </tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td>
+ <a href="http://qt.nokia.com/doc/4.0/signalsandslots.html">
+ Signals and Slots</a>
+ </td>
+ <td>Signals and slots are used for communication
+ between objects.</td>
+ </tr>
+
+ <tr valign="top" bgcolor="#c0c0c0">
+ <td>
+ <a href=http://qt.nokia.com/doc/4.0/layout.html">
+ Layout Management</a></td>
+ <td>The Qt layout system provides a simple
+ and powerful way of specifying the layout
+ of child widgets.</td>
+ </tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td>
+ <a href=http://qt.nokia.com/doc/4.0/dnd.html">
+ Drag and Drop</a></td>
+ <td>Drag and drop provides a simple visual
+ mechanism which users can use to transfer
+ information between and within applications.</td>
+ </tr>
+
+ </table>
+ \endraw
+
+ You can also make cells span several rows and columns. For
+ example:
+
+ \code
+ / *!
+ \table
+ \header
+ \o {3,1} This header cell spans three columns
+ but only one row.
+ \row
+ \o {2, 1} This table cell spans two columns
+ but only one row
+ \o {1, 2} This table cell spans only one column,
+ but two rows.
+ \row
+ \o A regular table cell
+ \o A regular table cell
+ \endtable
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \raw HTML
+ <table align="center" cellpadding="2" cellspacing="1"
+ border="0">
+
+ <tr valign="top" bgcolor="#a2c511">
+ <th colspan="3" rowspan=" 1">
+ This header cell spans three columns but only one row
+ </th>
+ </tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td colspan="2" rowspan=" 1">
+ This table cell spans two columns but only one row
+ </td>
+ <td rowspan=" 2">
+ This table cell spans only one column, but two rows.
+ </td>
+ </tr>
+
+ <tr valign="top" bgcolor="#c0c0c0">
+ <td>A regular table cell</td>
+ <td>A regular table cell</td>
+ </tr>
+
+ </table>
+ \endraw
+
+ See also \l {header-command} {\\header}, \l {row-command} {\\row} and \l {o-command} {\\o}.
+
+ \target header-command
+ \section1 \\header
+
+ The \\header command indicates that the following table cells are
+ the current table's column headers.
+
+ The command can only be used within the \l{table-command}
+ {\\table...\\endtable} commands. A header can contain several
+ cells. A cell is created with the \l {o-command} {\\o} command.
+
+ A header cell's text is centered within the table cell and
+ rendered using a bold font.
+
+ \code
+ / *!
+ \table
+ \header
+ \o Qt Core Feature
+ \o Brief Description
+ \row
+ \o \l {Signal and Slots}
+ \o Signals and slots are used for communication
+ between objects.
+ \endtable
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \raw HTML
+ <table align="center" cellpadding="2"
+ cellspacing="1" border="0">
+ <tr valign="top" bgcolor="#a2c511">
+ <th>Qt Core Feature</th>
+ <th>Brief Description</th>
+ </tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td>
+ <a href="http://qt.nokia.com/doc/4.0/signalsandslots.html">
+ Signals and Slots</a>
+ </td>
+ <td>Signals and slots are used for communication
+ between objects.</td>
+ </tr>
+ </table>
+ \endraw
+
+ See also \l {table-command} {\\table}, \l {row-command} {\\row} and \l {o-command} {\\o}.
+
+ \target row-command
+ \section1 \\row
+
+ The \\row command begins a new row in a table. The \l {o-command}
+ {\\o items} that belong in the new row will immediately follow the
+ \\row.
+
+ The command can only be used within the \l{table-command}
+ {\\table...\\endtable} commands. A row can contain several
+ cells. A cell is created with the \l {o-command} {\\o} command.
+
+ The background cell color of each row alternates between two
+ shades of grey, making it easier to distinguish the rows from each
+ other. The cells' contents is left aligned.
+
+ \code
+ / *!
+ \table
+ \header
+ \o Qt Core Feature
+ \o Brief Description
+ \row
+ \o \l {Signal and Slots}
+ \o Signals and slots are used for communication
+ between objects.
+ \row
+ \o \l {Layout Management}
+ \o The Qt layout system provides a simple
+ and powerful way of specifying the layout
+ of child widgets.
+ \row
+ \o \l {Drag and Drop}
+ \o Drag and drop provides a simple visual
+ mechanism which users can use to transfer
+ information between and within applications.
+ \endtable
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \raw HTML
+ <table align="center" cellpadding="2"
+ cellspacing="1" border="0">
+ <tr valign="top" bgcolor="#a2c511">
+ <th>Qt Core Feature</th>
+ <th>Brief Description</th>
+ </tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td>
+ <a href="http://qt.nokia.com/doc/4.0/signalsandslots.html">
+ Signals and Slots</a>
+ </td>
+ <td>Signals and slots are used for communication
+ between objects.</td>
+ </tr>
+
+ <tr valign="top" bgcolor="#c0c0c0">
+ <td>
+ <a href=http://qt.nokia.com/doc/4.0/layout.html">
+ Layout Management</a></td>
+ <td>The Qt layout system provides a simple
+ and powerful way of specifying the layout
+ of child widgets.</td>
+ </tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td>
+ <a href=http://qt.nokia.com/doc/4.0/dnd.html">
+ Drag and Drop</a></td>
+ <td>Drag and drop provides a simple visual
+ mechanism which users can use to transfer
+ information between and within applications.</td>
+ </tr>
+
+ </table>
+ \endraw
+
+ See also \l {table-command} {\\table}, \l {header-command}
+ {\\header} and \l {o-command} {\\o}.
+
+ \target value-command
+ \section1 \\value
+
+ The \\value command starts the documentation of a C++ enum item.
+
+ The command's first argument is the enum item. Then follows its
+ associated description. The description argument ends at the next
+ blank line or \\value. The arguments are rendered within a table.
+
+ The documentation will be located in the associated class, header
+ file or namespace documentation. See the \l {enum-command}
+ {\\enum} documentation for an example.
+
+ See also \l {enum-command} {\\enum} and \l {omitvalue-command} {\\omitvalue}.
+
+ \target omitvalue-command
+ \section1 \\omitvalue
+
+ The \\omitvalue command excludes a C++ enum item from the
+ documentation.
+
+ The command's only argument is the name of the enum item that will
+ be omitted. See the \l {enum-command} {\\enum} documentation for
+ an example.
+
+ See also \l {enum-command} {\\enum} and \l {value-command}
+ {\\value}.
+
+ \target list-command
+ \section1 \\list
+
+ The \\list and \\endlist commands delimit a list of items.
+
+ Create each list item with the \l {o-command} {\\o} command. A
+ list always contains one or more items. Lists can be nested. For
+ example:
+
+ \code
+ / *!
+ \list
+ \o Qt Reference Documentation: Getting Started
+ \list
+ \o How to Learn Qt
+ \o Installation
+ \list
+ \o Qt/X11
+ \o Qt/Windows
+ \o Qt/Mac
+ \o Qt/Embedded
+ \endlist
+ \o Tutorial and Examples
+ \endlist
+ \endlist
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \list
+ \o Qt Reference Documentation: Getting Started
+ \list
+ \o How to Learn Qt
+ \o Installation
+ \list
+ \o Qt/X11
+ \o Qt/Windows
+ \o Qt/Mac
+ \o Qt/Embedded
+ \endlist
+ \o Tutorial and Examples
+ \endlist
+ \endlist
+
+ The \\list command takes an optional argument providing
+ alternative appearances for the list items.
+
+ \code
+ / *!
+ \list
+ \o How to Learn Qt
+ \o Installation
+ \o Tutorial and Examples
+ \endlist
+ * /
+ \endcode
+
+ QDoc renders the list items with bullets (the default):
+
+ \list
+ \o How to Learn Qt
+ \o Installation
+ \o Tutorial and Examples
+ \endlist
+
+ \warning There appears to be a bug in qdoc3 here. If you include
+ any of the argument types, you get a numeric list. We're looking
+ into it.
+
+ If you provide 'A' as an argument to the \\list command, the
+ bullets are replaced with characters in alphabetical order:
+
+ \list A
+ \o How to Learn Qt
+ \o Installation
+ \o Tutorial and Examples
+ \endlist
+
+ If you replace 'A' with '1', the list items are numbered in
+ ascending order:
+
+ \list 1
+ \o How to Learn Qt
+ \o Installation
+ \o Tutorial and Examples
+
+ \endlist
+
+ If you provide 'i' as the argument, the bullets are replaced with
+ roman numerals:
+
+ \list i
+ \o How to Learn Qt
+ \o Installation
+ \o Tutorial and Examples
+ \endlist
+
+ Finally, you can make the list items appear with roman numbers
+ following in ascending order if you provide 'I' as the optional
+ argument:
+
+ \list I
+ \o How to Learn Qt
+ \o Installation
+ \o Tutorial and Examples
+ \endlist
+
+ You can also make the listing start at any character or number by
+ simply provide the number or character you want to start at. For
+ example:
+
+ \code
+ / *!
+ \list G
+ \o How to Learn Qt
+ \o Installation
+ \o Tutorial and Examples
+ \endlist
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \list G
+ \o How to Learn Qt
+ \o Installation
+ \o Tutorial and Examples
+ \endlist
+
+ See also \l {o-command} {\\o}.
+
+ \target o-command
+ \section1 \\o (cell, item)
+
+ The \\o command announce a table or list item.
+
+ Earlier we used the \l {i-command} {\\i} command for this
+ purpose. For more information see the \l
+ {26-qdoc-commands-compatibility.html#o-versus-i} {compatibility}
+ section.
+
+ The command can only be used within the \l{table-command}
+ {\\table...\\endtable} or \l{list-command} {\\list... \\endlist}
+ commands.
+
+ It considers everything until the next occurrence of the \\o
+ command, or the currently applicable \l {table-command}
+ {\\endtable} or \l {list-command} {\\endlist} command, as its
+ argument. For examples, see \l {table-command} {\\table} and \l
+ {list-command} {\\list}.
+
+ If the command is used within a table, you can in addition specify
+ how many rows or columns the item should span.
+
+ \code
+ / *!
+ \table
+ \header
+ \o {3,1} This header cell spans three columns
+ but only one row.
+ \row
+ \o {2, 1} This table item spans two columns
+ but only one row
+ \o {1, 2} This table item spans only one column,
+ but two rows.
+ \row
+ \o A regular table item
+ \o A regular table item
+ \endtable
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \raw HTML
+ <table align="center" cellpadding="2" cellspacing="1"
+ border="0">
+
+ <tr valign="top" bgcolor="#a2c511">
+ <th colspan="3" rowspan=" 1">
+ This header cell spans three columns but only one row
+ </th>
+ </tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td colspan="2" rowspan=" 1">
+ This table item spans two columns but only one row
+ </td>
+ <td rowspan=" 2">
+ This table item spans only one column, but two rows.
+ </td>
+ </tr>
+
+ <tr valign="top" bgcolor="#c0c0c0">
+ <td>A regular table item</td>
+ <td>A regular table item</td>
+ </tr>
+
+ </table>
+ \endraw
+
+ If not specified, the item will span one column and one row.
+
+ See also \l {table-command} {\\table}, \l {header-command}
+ {\\header}, \l {list-command} {\\list} and \l {o-command} {\\o}.
+
+*/
+
+/*!
+ \page 11-qdoc-commands-specialcontent.html
+ \previouspage Tables and Lists
+ \contentspage Table of Contents
+ \nextpage Miscellaneous
+
+ \title Special Content
+
+ The document contents commands identify parts of the documentation,
+ i.e. parts with a special rendering, conceptual meaning or
+ function.
+
+ \target abstract-command
+ \section1 \\abstract
+
+ The \\abstract and \\endabstract commands delimit a
+ document's abstract section.
+
+ The abstract section is rendered as an indented italicized
+ paragraph.
+
+ \warning The \bold{\\abstract} and \bold{\\endabstract} commands
+ have not been implemented. The abstract section is rendered as a
+ regular HTML paragraph.
+
+ \target quotation-command
+ \section1 \\quotation
+
+ The \\quotation and \\endquotation commands delimit a long quotation.
+
+ The text in the delimited block is surrounded by
+ \bold{<blockquote>} and \bold{</blockquote>} in the html output,
+ e.g.:
+
+ \code
+ / *!
+ While the prospect of a significantly broader market is
+ good news for Firstlogic, the notion also posed some
+ challenges. Dave Dobson, director of technology for the La
+ Crosse, Wisconsin-based company, said:
+
+ \quotation
+ As our solutions were being adopted into new
+ environments, we saw an escalating need for easier
+ integration with a wider range of enterprise
+ applications.
+ \endquotation
+ * /
+ \endcode
+
+ The text in the \bold{\\quotation} block will appear in the generated HTML as:
+
+ \code
+ <blockquote>
+ <p>As our solutions were being adopted into new environments,
+ we saw an escalating need for easier integration with a wider
+ range of enterprise applications.</p>
+ </blockquote>
+ \endcode
+
+ The built-in style sheet for most browsers will render the
+ contents of the <blockquote> tag with left and right
+ indentations. The example above would be rendered as:
+
+ \quotation
+ As our solutions were being adopted into new
+ environments, we saw an escalating need for easier
+ integration with a wider range of enterprise
+ applications.
+ \endquotation
+
+ But you can redefine the \bold{<blockquote>} tag in your style.css file.
+
+ This command replaces the old \\quote command. For more
+ information see the \l
+ {26-qdoc-commands-compatibility.html#quotation-versus-quote}
+ {compatibility} section.
+
+ \target footnote-command
+ \section1 \\footnote
+
+ The \\footnote and \\endfootnote commands delimit a footnote.
+
+ The footnote is rendered at the bottom of the page.
+
+ \warning The \bold{\\footnote} and \bold{\\endfootnote} commands
+ have not been implemented. The footnote is rendered as a regular
+ HTML paragraph.
+
+ \target tableofcontents-command
+ \section1 \\tableofcontents
+
+ The \\tableofcontents command has been disabled because QDoc
+ now generates a table of contents automatically.
+
+ The automatically generated table of contents appears in the upper
+ righthand corner of the page.
+
+ \target brief-command
+ \section1 \\brief
+
+ The \\brief command introduces a one-sentence description of a
+ class, namespace, header file, property or variable.
+
+ The brief text is used to introduce the documentation of the
+ associated object, and in lists generated using the \l
+ {generatelist-command} {\\generatelist} command and the \l
+ {annotatedlist-command} {\\annotatedlist} command.
+
+ The \\brief command can be used in two significant different ways:
+ \l {brief class} {One for classes, namespaces and header files},
+ and \l {brief-property} {one for properties and variables}.
+
+ \target brief-property
+
+ When the \\brief command is used to describe a property or a
+ variable, the brief text must be a sentence fragment starting with
+ "whether" (for a boolean property or variable) or starting with
+ "the" (for any other property or variable).
+
+ For example the boolean QWidget::isWindow property:
+
+ \code
+ / *!
+ \property QWidget::isActiveWindow
+ \brief whether this widget's window is the active window
+
+ The active window is the window that contains the widget that
+ has keyboard focus.
+
+ When popup windows are visible, this property is true
+ for both the active window \e and for the popup.
+
+ \sa activateWindow(), QApplication::activeWindow()
+ * /
+ \endcode
+
+ and the QWidget::geometry property
+
+ \code
+ / *!
+ \property QWidget::geometry
+ \brief the geometry of the widget relative to its parent and
+ excluding the window frame
+
+ When changing the geometry, the widget, if visible,
+ receives a move event (moveEvent()) and/or a resize
+ event (resizeEvent()) immediately.
+
+ ...
+
+ \sa frameGeometry(), rect(), ...
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \raw HTML
+ <h3>geometry :
+ <a href="http://qt.nokia.com/doc/4.0/qrect.html">QRect</a>
+ </h3>
+ \endraw
+
+ This property holds the geometry of the widget relative
+ to its parent and excluding the window frame.
+
+ ...
+
+ Access functions:
+ \list
+ \o \bold {const QRect & geometry () const}
+ \o \bold {void setGeometry ( int x, int y, int w, int h )}
+ \o \bold {void setGeometry ( const QRect & )}
+ \endlist
+
+ See also \l
+ {QWidget::frameGeometry()} {frameGeometry()}, \l
+ {QWidget::rect()} {rect()}, ...
+ \endquotation
+
+ \target brief class
+
+ When the \\brief command is used to describe a class, the brief
+ text should be a complete sentence and must start like this:
+
+ \code
+ The <classname> class is|provides|contains|specifies...
+ \endcode
+
+ \warning The brief statement is used as the first paragraph of the
+ detailed description. Do not repeat the sentence.
+
+ \code
+ / *!
+ \class PreviewWindow
+ \brief The PreviewWindow class is a custom widget
+ displaying the names of its currently set
+ window flags in a read-only text editor.
+
+ The PreviewWindow class inherits QWidget. The widget
+ displays the names of its window flags set with the
+ setWindowFlags() function. It is also provided with a
+ QPushButton that closes the window.
+
+ ...
+
+ \sa QWidget
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \raw HTML
+ <h1>PreviewWindow Class Reference</h1>
+ \endraw
+
+ The PreviewWindow class is a custom widget displaying
+ the names of its currently set window flags in a
+ read-only text editor. \l {preview window} {More...}
+
+ \raw HTML
+ <h3>Properties</h3>
+ \endraw
+
+ \list
+ \o 52 properties inherited from QWidget
+ \o 1 property inherited from QObject
+ \endlist
+
+ \raw HTML
+ <h3>Public Functions</h3>
+ \endraw
+
+ \list
+ \o \l {constructor} {PreviewWindow}(QWidget *parent = 0)
+ \o void \l {function} {setWindowFlags}(Qt::WindowFlags flags)
+ \endlist
+
+ \list
+ \o 183 public functions inherited from QWidget
+ \o 28 public functions inherited from QObject
+ \endlist
+
+ \raw HTML
+ <h3>Public Slots</h3>
+ \endraw
+
+ \list
+ \o 17 public slots inherited from QWidget
+ \o 1 public slot inherited from QObject
+ \endlist
+
+ \raw HTML
+ <h3>Additional Inherited Members</h3>
+ \endraw
+
+ \list
+ \o 1 signal inherited from QWidget
+ \o 1 signal inherited from QObject
+ \o 4 static public members inherited from QWidget
+ \o 4 static public members inherited from QObject
+ \o 39 protected functions inherited from QWidget
+ \o 7 protected functions inherited from QObject
+ \endlist
+
+ \target preview window
+
+ \raw HTML
+ <hr />
+ <h2>Detailed Description</h2>
+ \endraw
+
+ The PreviewWindow class is a custom widget displaying
+ the names of its currently set window flags in a
+ read-only text editor.
+
+ The PreviewWindow class inherits QWidget. The widget
+ displays the names of its window flags set with the \l
+ {function} {setWindowFlags()} function. It is also
+ provided with a QPushButton that closes the window.
+
+ ...
+
+ See also QWidget.
+
+ \raw HTML
+ <hr />
+ <h2>Member Function Documentation</h2>
+ \endraw
+
+ \target constructor
+ \raw HTML
+ <h3>PreviewWindow(QWidget *parent = 0)</h3>
+ \endraw
+
+ Constructs a preview window widget with \e parent.
+
+ \target function
+ \raw HTML
+ <h3>setWindowFlags(Qt::WindowFlags flags)</h3>
+ \endraw
+
+ Sets the widgets flags using the
+ QWidget::setWindowFlags() function.
+
+ Then runs through the available window flags,
+ creating a text that contains the names of the flags
+ that matches the flags parameter, displaying
+ the text in the widgets text editor.
+ \endquotation
+
+ Using \\brief in a \l{namespace-command}{\\namespace}:
+
+ \code
+ / *!
+ \namespace Qt
+
+ \brief The Qt namespace contains miscellaneous identifiers
+ used throughout the Qt library.
+ * /
+ \endcode
+
+ Using \\brief in a \l{headerfile-command}{\\headerfile}:
+
+ \code
+ / *!
+ \headerfile <QtGlobal>
+ \title Global Qt Declarations
+
+ \brief The <QtGlobal> header file provides basic
+ declarations and is included by all other Qt headers.
+
+ \sa <QtAlgorithms>
+ * /
+ \endcode
+
+ See also \l{property-command} {\\property}, \l{class-command}
+ {\\class}, \l{namespace-command} {\\namespace} and
+ \l{headerfile-command} {\\headerfile}.
+
+ \target legalese-command
+ \section1 \\legalese
+
+ The \\legalese and \\endlegalese commands delimit a licence agreement.
+
+ In the generated HTML, the delimited text is surrounded by a \bold
+ {<div class="LegaleseLeft">} and \bold {</div>} tags.
+
+ For example, here is a license agreement enclosed in \\legalese
+ and \\endlegalese:
+
+ \code
+ / *!
+ \legalese
+ Copyright 1996 Daniel Dardailler.
+
+ Permission to use, copy, modify, distribute, and sell this
+ software for any purpose is hereby granted without fee,
+ provided that the above copyright notice appear in all
+ copies and that both that copyright notice and this
+ permission notice appear in supporting documentation, and
+ that the name of Daniel Dardailler not be used in
+ advertising or publicity pertaining to distribution of the
+ software without specific, written prior permission. Daniel
+ Dardailler makes no representations about the suitability of
+ this software for any purpose. It is provided "as is"
+ without express or implied warranty.
+
+ Modifications Copyright 1999 Matt Koss, under the same
+ license as above.
+ \endlegalese
+ * /
+ \endcode
+
+ It will appear in the generated HTML as:
+
+ \code
+ <div class="LegaleseLeft">
+ <p>Copyright 1996 Daniel Dardailler.</p>
+ <p>Permission to use, copy, modify, distribute, and sell
+ this software for any purpose is hereby granted without fee,
+ provided that the above copyright notice appear in all
+ copies and that both that copyright notice and this
+ permission notice appear in supporting documentation, and
+ that the name of Daniel Dardailler not be used in
+ advertising or publicity pertaining to distribution of the
+ software without specific, written prior permission. Daniel
+ Dardailler makes no representations about the suitability of
+ this software for any purpose. It is provided "as is"
+ without express or implied warranty.</p>
+
+ <p>Modifications Copyright 1999 Matt Koss, under the same
+ license as above.</p>
+ </div>
+ \endcode
+
+ If the \\endlegalese command is omitted, QDoc will process the
+ \\legalese command but considers the rest of the documentation
+ page as the license agreement.
+
+ Ideally, the license text is located with the licensed code.
+
+ Elsewhere, the documentation identified as \e{\\legalese} command
+ can be accumulated using \l {generatelist-command} {\\generatelist}
+ with \c {legalese-command} as the argument. This is useful for
+ generating an overview of the license agreements associated with
+ the source code.
+
+ \target warning-command
+ \section1 \\warning
+
+ The \\warning command prepends "Warning:" to the command's
+ argument, in bold font.
+
+ \code
+ / *!
+ Qt::HANDLE is a platform-specific handle type
+ for system objects. This is equivalent to
+ \c{void *} on Windows and Mac OS X, and to
+ \c{unsigned long} on X11.
+
+ \warning Using this type is not portable.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ Qt::HANDLE is a platform-specific handle type
+ for system objects. This is equivalent to
+ \c{void *} on Windows and Mac OS X, and to
+ \c{unsigned long} on X11.
+
+ \warning Using this type is not portable.
+ \endquotation
+
+*/
+
+/*!
+ \page 12-0-qdoc-commands-miscellaneous.html
+ \previouspage Special Content
+ \contentspage Table of Contents
+ \nextpage The QDoc Configuration File
+
+ \title Miscellaneous
+
+ These commands provide miscellaneous functions connected to the
+ visual appearance of the documentation, and to the process of
+ generating the documentation.
+
+ \target expire-command
+ \section1 \\expire
+
+ The \\expire command allows you to define an expiration
+ date for your documentation.
+
+ When using the \\expire command, QDoc will emit a warning when the
+ current date is larger than the specified date. The command
+ accepts one argument; the argument's format is yyyy-mm-dd. For
+ example:
+
+ \code
+ / *!
+ \page porting.html
+
+ \title Porting to Qt 3.x
+
+ \expire 2004-12-31
+
+ This document describes porting applications from Qt
+ 2.x to Qt 3.x.
+
+ The Qt 3.x series is not binary compatible with the
+ 2.x series.
+ ...
+ * /
+ \endcode
+
+ If you run QDoc on 4 July 2005, it will emit the warning
+
+ \quotation
+ porting.qdoc:6: Documentation expired 185 days ago
+ \endquotation
+
+
+ \target annotatedlist-command
+ \section1 \\annotatedlist
+
+ The \\annotatedlist command expands to a list of the members of a
+ group, each member listed with its \e {brief} text. Below is an
+ example from the Qt Reference Documentation:
+
+ \code
+ / *!
+ ...
+ \section1 Drag and Drop Classes
+
+ These classes deal with drag and drop and the necessary mime type
+ encoding and decoding.
+
+ \annotatedlist draganddrop
+
+ * /
+ \endcode
+
+ This generates a list of all the classes in the \e{draganddrop} group.
+ A class in the \e{draganddrop} group will have the \\ingroup command
+ in its \\class or \\qmlclass comment.
+
+
+ \target generatelist-command
+ \section1 \\generatelist
+
+ The \\generatelist command expands to a list of various
+ documentation or links to documentation. Below is an example from
+ the Qt Reference Documentation:
+
+ \code
+ / *!
+ \page classes.html
+ \title All Classes
+
+ For a shorter list that only includes the most
+ frequently used classes, see \l{Qt's Main Classes}. For
+ a list of Qt 3 support classes, see \l{Qt3Support
+ Classes}.
+
+ \generatelist classes
+ * /
+ \endcode
+
+ This generates the \l {All Classes} page. The command accepts the
+ following arguments:
+
+ \target table example
+ \section2 \c annotatedclasses
+
+ The \c annotatedclasses argument provides a table containing the
+ names of all the classes, and a description of each class. Each
+ class name is a link to the class's reference documentation. For
+ example:
+
+ \table
+ \row
+ \o QDial
+ \o Rounded range control (like a speedometer or potentiometer)
+ \row
+ \o QDialog
+ \o The base class of dialog windows
+ \row
+ \o QDir
+ \o Access to directory structures and their contents
+ \endtable
+
+ A C++ class is documented with the \l {class-command} {\\class}
+ command. The annotation for the class is taken from the argument
+ of the class comment's \l {brief-command} {\\brief} command.
+
+ \target list example
+ \section2 \c classes
+
+ The \c classes argument provides a complete alphabetical list of
+ the classes. Each class name is a link to the class's reference
+ documentation. This command is uded to generate the \l
+ {classes.html} {All Classes} page this way:
+
+ \code
+ / *!
+ \page classes.html
+ \title All Classes
+ \ingroup classlists
+
+ \brief If you know the name of the class you want, find it here.
+
+ This is a list of all Qt classes. For a list of the classes
+ provided for compatibility with Qt3, see \l{Qt3 Support
+ Classes}. For classes that have been deprecated, see the
+ \l{Obsolete Classes} list.
+
+ \generatelist classes
+ * /
+ \endcode
+
+ A C++ class is documented with the \l {class-command} {\\class}
+ command.
+
+ \section2 \c classesbymodule
+
+ When this argument is used, a second argument is required, which
+ specifies the module whose classes are to be listed. QDoc
+ generates a table containing those classes. Each class is listed
+ with the text of its \l{brief-command} {\\brief} command.
+
+ This command is used to generate the \l {phonon-module.html}
+ {Phonon Module} page this way.
+
+ \code
+ / *!
+ \page phonon-module.html
+ \module Phonon
+ \title Phonon Module
+ \ingroup modules
+
+ \brief The Phonon module contains namespaces and classes for multimedia functionality.
+
+ \generatelist{classesbymodule Phonon}
+
+ ...
+
+ * /
+ \endcode
+
+ Each class that is a member of the specified module must be marked
+ with the \l {inmodule-command} {\\inmodule} command in its \\class
+ comment.
+
+ \section2 \c compatclasses
+
+ The \c compatclasses argument generates a list in alphabetical
+ order of the support classes. It is normally used only to
+ generate the \l {compatclasses.html} {Qt3 Support Classes} page
+ this way:
+
+ \code
+ / *!
+ \page compatclasses.html
+ \title Qt3 Support Classes
+ \ingroup classlists
+
+ \brief These classes ease the porting of code from Qt 3 to Qt 4.
+
+ These are the classes that Qt provides for compatibility with Qt
+ 3. Most of these are provided by the Qt3Support module.
+
+ \generatelist compatclasses
+ * /
+ \endcode
+
+ A support class is identified in the \\class comment with the \l
+ {compat-command} {\\compat} command.
+
+ \section2 \c functionindex
+
+ The \c functionindex argument provides a complete alphabetical
+ list of all the documented member functions. It is normally used
+ only to generate the \l {functions.html} {Qt function index} page
+ this way:
+
+ \code
+ / *!
+ \page functions.html
+ \title All Functions
+ \ingroup funclists
+
+ \brief All documented Qt functions listed alphabetically with a
+ link to where each one is declared.
+
+ This is the list of all documented member functions and global
+ functions in the Qt API. Each function has a link to the
+ class or header file where it is declared and documented.
+
+ \generatelist functionindex
+ * /
+ \endcode
+
+ \section2 \c legalese
+
+ The \c legalese argument tells QDoc to generate a complete list of
+ licenses in the documentation. Each license is identified using
+ the \l {legalese-command} {\\legalese} command. This command is
+ used to generate the \l {licenses.html} {Qt license information}
+ page this way:
+
+ \code
+ / *!
+ \page licenses.html
+ \title Other Licenses Used in Qt
+ \ingroup licensing
+ \brief Information about other licenses used for Qt components and third-party code.
+
+ Qt contains some code that is not provided under the
+ \l{GNU General Public License (GPL)},
+ \l{GNU Lesser General Public License (LGPL)} or the
+ \l{Qt Commercial Edition}{Qt Commercial License Agreement}, but rather under
+ specific licenses from the original authors. Some pieces of code were developed
+ by Nokia and others originated from third parties.
+ This page lists the licenses used, names the authors, and links
+ to the places where it is used.
+
+ Nokia gratefully acknowledges these and other contributions
+ to Qt. We recommend that programs that use Qt also acknowledge
+ these contributions, and quote these license statements in an
+ appendix to the documentation.
+
+ See also: \l{Licenses for Fonts Used in Qt for Embedded Linux}
+
+ \generatelist legalese
+ * /
+ \endcode
+
+ \section2 \c mainclasses
+
+ The \c mainclasses argument tells QDoc to generate an alphabetical
+ list of the main classes. A class is marked as a main class by
+ including a \l {mainclass-command} {\\mainclass} command in the
+ \\class comment.
+
+ \note The Qt documentation no longer includes a main classes page,
+ but you can generate one for your main classes if you want it.
+
+ \section2 \c overviews
+
+ The \c overviews argument is used to tell QDoc to generate a list
+ by concatenating the contents of all the \l {group-command}
+ {\\group} pages. Qt uses it to generate the \l {overviews.html}
+ {overviews} page this way:
+
+ \code
+ / *!
+ \page overviews.html
+
+ \title All Overviews and HOWTOs
+
+ \generatelist overviews
+ * /
+ \endcode
+
+ \section2 \c related
+
+ The \c related argument is used in combination with the \l
+ {group-command} {\\group} and \l {ingroup-command} {\\ingroup}
+ commands to list all the overviews related to a specified
+ group. For example, the page for the \l {Programming with Qt}
+ {Programming with Qt} page is generated this way:
+
+ \code
+ / *!
+ \group qt-basic-concepts
+ \title Programming with Qt
+
+ \brief The basic architecture of the Qt cross-platform application and UI framework.
+
+ Qt is a cross-platform application and UI framework for
+ writing web-enabled applications for desktop, mobile, and
+ embedded operating systems. This page contains links to
+ articles and overviews explaining key components and
+ techniuqes used in Qt development.
+
+ \generatelist {related}
+ * /
+ \endcode
+
+ Each page listed on this group page contains the command:
+
+ \code
+ \ingroup qt-basic-concepts
+ \endcode
+
+ \section2 \c service
+
+ The \c service argument tells QDoc to generate an alphabetical
+ list of the services. Each service name is a link to the service's
+ reference documentation.
+
+ A service is identified with the \l {service-command} {\\service}
+ command.
+
+ \note This command and the \l {service-command} {\\service}
+ command are not used in the Qt documentation.
+
+ \target if-command
+ \section1 \\if
+
+ The \\if command and the corresponding \\endif command
+ enclose parts of a QDoc comment that only will be included if
+ the condition specified by the command's argument is true.
+
+ The command reads the rest of the line and parses it as an C++ #if
+ statement.
+
+ \code
+ / *!
+ \if defined(opensourceedition)
+
+ \bold{Note:} This edition is for the development of
+ \l{Qt Open Source Edition} {Free and Open Source}
+ software only; see \l{Qt Commercial Editions}.
+
+ \endif
+ * /
+ \endcode
+
+ This QDoc comment will only be rendered if the \c
+ opensourceedition preprocessor symbol is defined, and specified in
+ the \l {defines-variable} {defines} variable in the configuration
+ file to make QDoc process the code within #ifdef and #endif:
+
+ \code
+ defines = opensourceedition
+ \endcode
+
+ You can also define the preprocessor symbol manually on the
+ command line. For more information see the documentation of the \l
+ {defines-variable} {defines} variable.
+
+ See also \l{endif-command} {\\endif}, \l{else-command} {\\else},
+ \l {defines-variable} {defines} and \l {falsehoods-variable}
+ {falsehoods}.
+
+ \target endif-command
+ \section1 \\endif
+
+ The \\endif command and the corresponding \\if command
+ enclose parts of a QDoc comment that will be included if
+ the condition specified by the \l {if-command} {\\if} command's
+ argument is true.
+
+ For more information, see the documentation of the \l {if-command}
+ {\\if} command.
+
+ See also \l{if-command} {\\if}, \l{else-command} {\\else}, \l
+ {defines-variable} {defines} and \l {falsehoods-variable}
+ {falsehoods}.
+
+ \target else-command
+ \section1 \\else
+
+ The \\else command specifies an alternative if the
+ condition in the \l {if-command} {\\if} command is false.
+
+ The \\else command can only be used within \l {if-command}
+ {\\if...\\endif} commands, but is useful when there is only two
+ alternatives.
+
+ \code
+ / *!
+ The Qt 3 support library is provided to keep old
+ source code working.
+
+ In addition to the \c Qt3Support classes, Qt 4 provides
+ compatibility functions when it's possible for an old
+ API to cohabit with the new one.
+
+ \if !defined(QT3_SUPPORT)
+ \if defined(QT3_SUPPORTWARNINGS)
+ The compiler emits a warning when a
+ compatibility function is called. (This works
+ only with GCC 3.2+ and MSVC 7.)
+ \else
+ To use the Qt 3 support library, you need to
+ have the line QT += qt3support in your .pro
+ file (qmake automatically define the
+ QT3_SUPPORT symbol, turning on compatibility
+ function support).
+
+ You can also define the symbol manually (e.g.,
+ if you don't want to link against the \c
+ Qt3Support library), or you can define \c
+ QT3_SUPPORT_WARNINGS instead, telling the
+ compiler to emit a warning when a compatibility
+ function is called. (This works only with GCC
+ 3.2+ and MSVC 7.)
+ \endif
+ \endif
+ * /
+ \endcode
+
+ If the \c QT3_SUPPORT is defined, the comment will be rendered
+ like this:
+
+ \quotation
+ The Qt 3 support library is provided to keep old source
+ code working.
+
+ In addition to the Qt3Support classes, Qt 4 provides
+ compatibility functions when it's possible for an old
+ API to cohabit with the new one.
+ \endquotation
+
+ If \c QT3_SUPPORT is not defined but \c QT3_SUPPORT_WARNINGS is
+ defined, the comment will be rendered like this:
+
+ \quotation
+ The Qt 3 support library is provided to keep old source
+ code working.
+
+ In addition to the Qt3Support classes, Qt 4 provides
+ compatibility functions when it's possible for an old
+ API to cohabit with the new one.
+
+ The compiler emits a warning when a compatibility
+ function is called. (This works only with GCC 3.2+ and
+ MSVC 7.)
+ \endquotation
+
+ If none of the symbols are defined, the comment will be
+ rendered as
+
+ \quotation
+ The Qt 3 support library is provided to keep old
+ source code working.
+
+ In addition to the \c Qt3Support classes, Qt 4 provides
+ compatibility functions when it's possible for an old
+ API to cohabit with the new one.
+
+ To use the Qt 3 support library, you need to have the
+ line QT += qt3support in your .pro file (qmake
+ automatically define the QT3_SUPPORT symbol, turning on
+ compatibility function support).
+
+ You can also define the symbol manually (e.g., if you
+ don't want to link against the \c Qt3Support library),
+ or you can define \c QT3_SUPPORT_WARNINGS instead,
+ telling the compiler to emit a warning when a
+ compatibility function is called. (This works only with
+ GCC 3.2+ and MSVC 7.)
+ \endquotation
+
+ See also \l{if-command} {\\if}, \l{endif-command} {\\endif}, \l
+ {defines-variable} {defines} and \l {falsehoods-variable}
+ {falsehoods}.
+
+ \target include-command
+ \section1 \\include
+
+ The \\include command sends all or part of the file specified by
+ its first argument to the QDoc input stream to be processed as a
+ qdoc comment snippet. This command is often assigned the alias,
+ \e {input}, in the QDoc configuration file, e.g. \e {alias.include
+ = input}.
+
+ The command is useful when some snippet of commands and text is to
+ be used in multiple places in the documentation. In that case,
+ move the snippet into a separate file and use the \\include
+ command wherever you want to insert the snippet into the
+ documentation. To prevent QDoc from reading the file as a
+ stand-alone page of documentation, we recommend that you use the
+ \c .qdocinc extension for these \e {include} files.
+
+ The command can have either one or two arguments. The first
+ argument is always a file name. The contents of the file must be
+ QDoc input, i.e. a sequence of QDoc commands and text, but without
+ the enclosing qdoc comment \c{/}\c{*!} ... \c{*}\c{/} delimeters.
+ If you want to include the entire named file, don't use the second
+ argument. If you want to include only part of the file, see the
+ \l{2-argument-form}{two argument form} below. Here is an example
+ of the one argument form:
+
+ \code
+ / *!
+ \page corefeatures.html
+ \title Core Features
+
+ \include examples/signalandslots.qdocinc
+ \include examples/objectmodel.qdocinc
+ \include examples/layoutmanagement.qdocinc
+ * /
+ \endcode
+
+ Here are links to the \c .qdocinc files used above:
+ \l{signalandslots.qdocinc}, \l{objectmodel.qdocinc},
+ \l{layoutmanagement.qdocinc}. QDoc renders this page
+ \l{corefeatures.html} {as shown here}.
+
+ \target 2-argument-form}
+ \section2 \\include filename snippet-identifier
+
+ It is kind of a pain to make a separate \c .qdocinc file for every
+ QDoc include snippet you want to use in multiple places in the
+ documentation, especially given that you probably have to put the
+ copyright/license notice in every one of these files. So if you
+ have lots of these include snippets, you can put them all in a
+ single file if you want, and surround each one with:
+ \code
+ //! [snippet-id1]
+
+ QDoc commands and text...
+
+ //! [snippet-id1]
+
+ //! [snippet-id2]
+
+ More QDoc commands and text...
+
+ //! [snippet-id2]
+ \endcode
+
+ Then you can use the two-argument form of the command:
+
+ \code
+ \input examples/signalandslots.qdocinc snippet-id2
+ \input examples/objectmodel.qdocinc another-snippet-id
+ \endcode
+
+ It works as expected. The sequence of QDoc commands and text found
+ between the two tags with the same name as the second argument is
+ sent to the QDoc input stream. You can even nest these snippets,
+ although it's not clear why you would want to do that.
+
+ \target meta-command
+ \section1 \\meta
+
+ The \\meta command is mainly used for including metadata in DITA
+ XML files. It is also used when generating HTML output for specifying
+ the \e maintainer(s) of a C++ class.
+
+ The command has two arguments: The first argument is the name of the
+ metadata attribute you wish to set, and the second argument is the
+ value for the attribute. Each argument should be enclosed in curly
+ brackets, as shown in this example:
+
+ \code
+ / *!
+ \class QWidget
+ \brief The QWidget class is the base class of all user interface objects.
+
+ \ingroup basicwidgets
+
+ \meta {technology} {User Interface}
+ \meta {platform} {OS X 10.6}
+ \meta {platform} {Symbian}
+ \meta {platform} {MeeGo}
+ \meta {audience} {user}
+ \meta {audience} {programmer}
+ \meta {audience} {designer}
+ * /
+ \endcode
+
+ When running QDoc to generate HTML, the example above will have no
+ effect on the generated output, but if you run QDoc to generate
+ DITA XML, the example will generate the following:
+
+ \code
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!DOCTYPE cxxClass PUBLIC "-//NOKIA//DTD DITA C++ API Class Reference Type v0.6.0//EN" "dtd/cxxClass.dtd">
+ <!--qwidget.cpp-->
+ <cxxClass id="id-9a14268e-6b09-4eee-b940-21a00a0961df">
+ <apiName>QWidget</apiName>
+ <shortdesc>the QWidget class is the base class of all user interface objects.</shortdesc>
+ <prolog>
+ <author>Qt Development Frameworks</author>
+ <publisher>Nokia</publisher>
+ <copyright>
+ <copyryear year="2011"/>
+ <copyrholder>Nokia</copyrholder>
+ </copyright>
+ <permissions view="all"/>
+ <metadata>
+ <audience type="designer"/>
+ <audience type="programmer"/>
+ <audience type="user"/>
+ <category>Class reference</category>
+ <prodinfo>
+ <prodname>Qt Reference Documentation</prodname>
+ <vrmlist>
+ <vrm version="4" release="7" modification="3"/>
+ </vrmlist>
+ <component>QtGui</component>
+ </prodinfo>
+ <othermeta name="platform" content="MeeGo"/>
+ <othermeta name="platform" content="Symbian"/>
+ <othermeta name="platform" content="OS X 10.6"/>
+ <othermeta name="technology" content="User Interface"/>
+ </metadata>
+ </prolog>
+ \endcode
+
+ In the example output, several values have been set using defualt
+ values obtained from the QDoc configuration file. See \l
+ {Generating DITA XML Output} for details.
+
+ \target omit-command
+ \section1 \\omit
+
+ The \\omit command and the correspondning \\endomit command
+ delimit parts of the documentation that you want QDoc to skip. For
+ example:
+
+ \code
+ / *!
+ \table
+ \row
+ \o Basic Widgets
+ \o Basic GUI widgets such as buttons, comboboxes
+ and scrollbars.
+
+ \omit
+ \row
+ \o Component Model
+ \o Interfaces and helper classes for the Qt
+ Component Model.
+ \endomit
+
+ \row
+ \o Database Classes
+ \o Database related classes, e.g. for SQL databases.
+ \endtable
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \raw HTML
+ <table align="center" cellpadding="2"
+ cellspacing="1" border="0">
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td>Basic Widgets</td>
+ <td>Basic GUI widgets such as buttons, comboboxes
+ and scrollbars.</td>
+ </tr>
+
+ <tr valign="top" bgcolor="#c0c0c0">
+ <td>Database Classes</td>
+ <td>Database related classes, e.g. for SQL databases.</td>
+ </tr>
+ </table>
+ \endraw
+
+ \target raw-command
+ \section1 \\raw \span {class="newStuff"} {(avoid)}
+
+ The \\raw command and the corresponding
+ \\endraw command delimit a block of raw mark-up language code.
+
+ \note Avoid using this command if possible, because it generates
+ DITA XML code that causes problems. If you are trying to generate
+ special table or list behavior, try to get the behavior you want
+ using the \l {span-command} {\\span} and \l {div-command} {\\div}
+ commands in your \l {table-command} {\\table} or \l {list-command}
+ {\\list}.
+
+ The command takes an argument specifying the code's format;
+ currently the only supported format is HTML.
+
+ The \\raw command is useful if you want some special HTML effects
+ in your documentation.
+
+ \code
+ / *!
+ Qt has some predefined QColor objects.
+
+ \raw HTML
+ <style type="text/css" id="colorstyles">
+ #color-blue { background-color: #0000ff; color: #ffffff }
+ #color-darkBlue { background-color: #000080; color: #ffffff }
+ #color-cyan { background-color: #00ffff; color: #000000 }
+ </style>
+
+ <p>
+ <tt id="color-blue">Blue(#0000ff)</tt>,
+ <tt id="color-darkBlue">dark blue(#000080)</tt> and
+ <tt id="color-cyan">cyan(#00ffff)</tt>.
+ </p>
+ \endraw
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ Qt has some predefined QColor objects.
+
+ \raw HTML
+ <style type="text/css" id="colorstyles">
+ #color-blue { background-color: #0000ff; color: #ffffff }
+ #color-darkBlue { background-color: #000080; color: #ffffff }
+ #color-cyan { background-color: #00ffff; color: #000000 }
+ </style>
+
+ <p>
+ <tt id="color-blue">Blue(#0000ff)</tt>,
+ <tt id="color-darkBlue">dark blue(#000080)</tt> and
+ <tt id="color-cyan">cyan(#00ffff)</tt>.
+ </p>
+ \endraw
+ \endquotation
+
+ \note But you can achieve the exact same thing using qdoc
+ commands. In this case, all you have to do is include the color
+ styles in your style.css file. Then you can write:
+
+ \code
+ \tt {\span {id="color-blue"} {Blue(#0000ff)}},
+ \tt {\span {id="color-darkBlue"} {dark blue(#000080)}} and
+ \tt {\span {id="color-cyan"} {cyan(#00ffff)}}.
+ \endcode
+
+ ...which is rendered again as:
+
+ \tt {\span {id="color-blue"} {Blue(#0000ff)}},
+ \tt {\span {id="color-darkBlue"} {dark blue(#000080)}} and
+ \tt {\span {id="color-cyan"} {cyan(#00ffff)}}.
+
+ \target unicode-command
+ \section1 \\unicode
+
+ The \\unicode command allows you to insert an arbitrary Unicode
+ character in the document.
+
+ The command takes an argument specifying the character as an
+ integer. By default, base 10 is assumed, unless a '0x' or '0'
+ prefix is specified (for base 16 and 8, respectively). For
+ example:
+
+ \code
+ O G\unicode{0xEA}nio e as Rosas
+
+ \unicode 0xC0 table en famille avec 15 \unicode 0x20AC par jour
+
+ \unicode 0x3A3 \e{a}\sub{\e{i}}
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ O G\unicode{0xEA}nio e as Rosas
+
+ \unicode 0xC0 table en famille avec 15 \unicode 0x20AC par jour
+
+ \unicode 0x3A3 \e{a}\sub{\e{i}}
+ \endquotation
+*/
+
+/*!
+ \page 12-1-signalandslots.html
+ \previouspage Miscellaneous
+ \contentspage Table of Contents
+
+ \title signalandslots.qdocinc
+
+ \quotefile examples/signalandslots.qdocinc
+*/
+
+/*!
+ \page 12-2-objectmodel.html
+ \previouspage Miscellaneous
+ \contentspage Table of Contents
+
+ \title objectmodel.qdocinc
+
+ \quotefile examples/objectmodel.qdocinc
+*/
+
+/*!
+ \page 12-3-layoutmanagement.html
+ \previouspage Miscellaneous
+ \contentspage Table of Contents
+
+ \title layoutmanagement.qdocinc
+
+ \quotefile examples/layoutmanagement.qdocinc
+*/
+
+/*!
+ \page 13-qdoc-commands-topics.html
+ \previouspage Command Index
+ \contentspage Table of Contents
+ \nextpage Context Commands
+
+ \title Topic Commands
+
+ A topic command tells QDoc which source code element is being
+ documented. Some topic commands allow you to create documentation
+ pages that aren't tied to any underlying source code element.
+
+ When QDoc processes a QDoc comment, it tries to connect the
+ comment to an element in the source code by first looking for a
+ topic command that names the source code element. If there is no
+ topic command, QDoc tries to connect the comment to the source
+ code element that immediately follows the comment. If it can't do
+ either of these and if there is no topic command that indicates
+ the comment does not have an underlying source code element (e.g.
+ \l{page-command} {\\page}), then the comment is discarded.
+
+ \target topic argument
+
+ The name of the entity being documented is usually the only
+ argument for a topic command. Use the complete name. Sometimes
+ there can be a second parameter in the argument. See e.g. \l
+ {page-command} {\\page}.
+
+ \code
+ \enum QComboBox::InsertPolicy
+ \endcode
+
+ The \l {fn-command} {\\fn} command is a special case. For the \l
+ {fn-command} {\\fn} command, use the function's signature
+ including the class qualifier.
+
+ \code
+ \fn void QGraphicsWidget::setWindowFlags(Qt::WindowFlags wFlags)
+ \endcode
+
+ A topic command can appear anywhere in a comment but must stand
+ alone on its own line. Best practice is to let the topic commend
+ be the first line of the comment. If the argument spans several
+ lines, make sure that each line (except the last one) is ended
+ with a backslash. In addition QDoc counts parentheses, which means
+ that if it encounters a '(' it considers everything until the
+ closing ')' as its argument.
+
+ If a topic command is repeated with different arguments, the
+ same documentation will appear for both the units.
+
+ \code
+ / *!
+ \fn void PreviewWindow::setWindowFlags()
+ \fn void ControllerWindow::setWindowFlags()
+
+ Sets the widgets flags using the QWidget::setWindowFlags()
+ function.
+
+ Then runs through the available window flags, creating a text
+ that contains the names of the flags that matches the flags
+ parameter, displaying the text in the widgets text editor.
+ * /
+ \endcode
+
+ The \c PreviewWindow::setWindowFlags() and \c
+ ControllerWindow::setWindowFlags() functions will get the same
+ documentation.
+
+ \target class-command
+ \section1 \\class
+
+ The \\class command is for documenting a C++ class. The argument
+ is the complete name of the class. The command tells QDoc that a
+ class is part of the public API, and lets you enter a detailed
+ description.
+
+ \code
+ / *!
+ \class QMap::iterator
+
+ \brief The QMap::iterator class provides an STL-style
+ non-const iterator for QMap and QMultiMap.
+
+ QMap features both \l{STL-style iterators} and
+ \l{Java-style iterators}. The STL-style iterators ...
+ * /
+ \endcode
+
+ The HTML documentation for the named class is written to a
+ \c{.html} file named from the class name, in lower case, and with
+ the double colon qulifier(s) replaced with '-'. For example, the
+ documentation for the \c QMap::Iterator class is written to \c
+ qmap-iterator.html.
+
+ \target framework
+
+ The file contains the class description from the \\class comment,
+ plus the documentation generated from QDoc comments for all the
+ class members, i.e. a list of the class's types, properties,
+ functions, signals, and slots.
+
+ In addition to the detailed description of the class, the \\class
+ comment typically contains a \l {brief-command} {\\brief} command
+ and one or more \l{Markup Commands}. See the \\class command for
+ any of the Qt class for examples. Here is a very simple example:
+
+ \code
+ / *!
+ \class PreviewWindow
+ \brief The PreviewWindow class is a custom widget
+ displaying the names of its currently set
+ window flags in a read-only text editor.
+
+ \ingroup miscellaneous
+
+ The PreviewWindow class inherits QWidget. The widget
+ displays the names of its window flags set with the \l
+ {function} {setWindowFlags()} function. It is also
+ provided with a QPushButton that closes the window.
+
+ ...
+
+ \sa QWidget
+ * /
+ \endcode
+
+ The way QDoc renders this \\class will depend a lot on your \c
+ {style.css} file, but the general outline of the class reference
+ page will look like this:
+
+ \quotation
+ \raw HTML
+ <h1>PreviewWindow Class Reference</h1>
+ \endraw
+
+ The PreviewWindow class is a custom widget displaying
+ the names of its currently set window flags in a
+ read-only text editor. \l {preview window} {More...}
+
+ \raw HTML
+ <h3>Properties</h3>
+ \endraw
+
+ \list
+ \o 52 properties inherited from QWidget
+ \o 1 property inherited from QObject
+ \endlist
+
+ \raw HTML
+ <h3>Public Functions</h3>
+ \endraw
+
+ \list
+ \o \l {constructor} {PreviewWindow}(QWidget *parent = 0)
+ \o void \l {function} {setWindowFlags}(Qt::WindowFlags flags)
+ \endlist
+
+ \list
+ \o 183 public functions inherited from QWidget
+ \o 28 public functions inherited from QObject
+ \endlist
+
+ \raw HTML
+ <h3>Public Slots</h3>
+ \endraw
+
+ \list
+ \o 17 public slots inherited from QWidget
+ \o 1 public slot inherited from QObject
+ \endlist
+
+ \raw HTML
+ <h3>Additional Inherited Members</h3>
+ \endraw
+
+ \list
+ \o 1 signal inherited from QWidget
+ \o 1 signal inherited from QObject
+ \o 4 static public members inherited from QWidget
+ \o 4 static public members inherited from QObject
+ \o 39 protected functions inherited from QWidget
+ \o 7 protected functions inherited from QObject
+ \endlist
+
+ \target preview window
+
+ \raw HTML
+ <hr />
+ <h2>Detailed Description</h2>
+ \endraw
+
+ The PreviewWindow class is a custom widget displaying
+ the names of its currently set window flags in a
+ read-only text editor.
+
+ The PreviewWindow class inherits QWidget. The widget
+ displays the names of its window flags set with the \l
+ {function} {setWindowFlags()} function. It is also
+ provided with a QPushButton that closes the window.
+
+ ...
+
+ See also QWidget.
+
+ \raw HTML
+ <hr />
+ <h2>Member Function Documentation</h2>
+ \endraw
+
+ \target constructor
+ \raw HTML
+ <h3>PreviewWindow(QWidget *parent = 0)</h3>
+ \endraw
+
+ Constructs a preview window widget with \e parent.
+
+ \target function
+ \raw HTML
+ <h3>setWindowFlags(Qt::WindowFlags flags)</h3>
+ \endraw
+
+ Sets the widgets flags using the
+ QWidget::setWindowFlags() function.
+
+ Then runs through the available window flags,
+ creating a text that contains the names of the flags
+ that matches the flags parameter, displaying
+ the text in the widgets text editor.
+ \endquotation
+
+ \target enum-command
+ \section1 \\enum
+
+ The \\enum command is for documenting a C++ enum type. The
+ argument is the full name of the enum type.
+
+ The enum values are documented in the \\enum comment using the \l
+ {value-command} {\\value} command. If an enum value is not
+ documented with \\value, QDoc emits a warning. These warnings can
+ be avoided using the \l {omitvalue-command} {\\omitvalue} command
+ to tell QDoc that an enum value should not be documented. The enum
+ documentation will be included on the class reference page, header
+ file page, or namespace page where the enum type is defined. For
+ example, consider the enum type \c {Corner} in the Qt namespace:
+
+ \code
+ enum Corner {
+ TopLeftCorner = 0x00000,
+ TopRightCorner = 0x00001,
+ BottomLeftCorner = 0x00002,
+ BottomRightCorner = 0x00003
+ #if defined(QT3_SUPPORT) && !defined(Q_MOC_RUN)
+ ,TopLeft = TopLeftCorner,
+ TopRight = TopRightCorner,
+ BottomLeft = BottomLeftCorner,
+ BottomRight = BottomRightCorner
+ #endif
+ };
+ \endcode
+
+ This enum can be cocumented this way:
+
+ \code
+ / *!
+ \enum Qt::Corner
+
+ This enum type specifies a corner in a rectangle:
+
+ \value TopLeftCorner
+ The top-left corner of the rectangle.
+ \value TopRightCorner
+ The top-right corner of the rectangle.
+ \value BottomLeftCorner
+ The bottom-left corner of the rectangle.
+ \value BottomRightCorner
+ The bottom-right corner of the rectangle.
+
+ \omitvalue TopLeft
+ \omitvalue TopRight
+ \omitvalue BottomLeft
+ \omitvalue BottomRight
+ * /
+ \endcode
+
+ Note the inclusion of the namespace qualifier. QDoc will render
+ this enum type in \c {qt.html} like this:
+
+ \quotation
+ \raw HTML
+ <h3 class="fn"><a name="Corner-enum"></a>enum Qt::Corner</h3>
+
+ <p>This enum type specifies a corner in a rectangle:</p>
+
+ <table border="1" cellpadding="2" cellspacing="1" width="100%">
+ <tr>
+ <th width="25%">Constant</th>
+ <th width="15%">Value</th>
+ <th width="60%">Description</th>
+ </tr>
+
+ <tr>
+ <td valign="top"><tt>Qt::TopLeftCorner</tt></td>
+ <td align="center" valign="top"><tt>0x00000</tt></td>
+ <td valign="top">The top-left corner of the rectangle.</td>
+ </tr>
+
+ <tr>
+ <td valign="top"><tt>Qt::TopRightCorner</tt></td>
+ <td align="center" valign="top"><tt>0x00001</tt></td>
+ <td valign="top">The top-right corner of the rectangle.</td>
+ </tr>
+
+ <tr>
+ <td valign="top"><tt>Qt::BottomLeftCorner</tt></td>
+ <td align="center" valign="top"><tt>0x00002</tt></td>
+ <td valign="top">The bottom-left corner of the rectangle.</td>
+ </tr>
+
+ <tr>
+ <td valign="top"><tt>Qt::BottomRightCorner</tt></td>
+ <td align="center" valign="top"><tt>0x00003</tt></td>
+ <td valign="top">The bottom-right corner of the rectangle.</td>
+ </tr>
+
+ </table>
+ \endraw
+ \endquotation
+
+ See also \l {value-command} {\\value} and \l {omitvalue-command} {\\omitvalue}.
+
+ \target example-command
+ \section1 \\example
+
+ The \\example command is for documenting an example. The argument
+ is the example's path relative to omne of the paths listed in the
+ \l {exampledirs-variable} {exampledirs} variable in the QDoc
+ configuration file.
+
+ The documentation page will be output to \c {path-to-example}.html.
+ QDoc will add a list of all the example's source files at the top
+ of the page.
+
+ For example, if \l {exampledirs-variable} {exampledirs} contains
+ \c $QTDIR/examples/widgets/imageviewer, then
+
+ \code
+ / *!
+ \example widgets/imageviewer
+ \title ImageViewer Example
+ \subtitle
+
+ The example shows how to combine QLabel and QScrollArea
+ to display an image.
+
+ ...
+ * /
+ \endcode
+
+ QDoc renders this example in widgets-imageviewer.html:
+
+ \quotation
+ \raw HTML
+ <center><h1>Image Viewer Example</h1></center>
+ \endraw
+
+ Files:
+ \list
+ \o \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-imageviewer-cpp.html}
+ {widgets/imageviewer/imageviewer.cpp}
+ \o \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-imageviewer-h.html}
+ {widgets/imageviewer/imageviewer.h}
+ \o \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-main-cpp.html}
+ {widgets/imageviewer/main.cpp}
+ \endlist
+
+ The example shows how to combine QLabel and QScrollArea
+ to display an image.
+
+ ...
+ \endquotation
+
+ \target externalpage-command
+ \section1 \\externalpage
+
+ The \\externalpage command assigns a title to an external URL.
+
+ \code
+ / *!
+ \externalpage http://doc.qt.nokia.com/index.html
+ \title Qt Documentation Site
+ * /
+ \endcode
+
+ This allows you to include a link to the external page in your
+ documentation this way:
+
+ \code
+ / *!
+ At the \l {Qt Documentation Site} you can find the latest
+ documentation for Qt, Qt Creator, the Qt SDK and much more.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ At the \l {http://doc.qt.nokia.com/index.html}{Qt Documentation Site}
+ you can find the latest documentation for Qt, Qt Creator, the Qt SDK
+ and much more.
+ \endquotation
+
+ To achieve the same result without using the \\externalpage
+ command, you would have to hard code the address into your
+ documentation:
+
+ \code
+ / *!
+ At the \l {http://doc.qt.nokia.com/index.html}{Qt Documentation Site}
+ you can find the latest documentation for Qt, Qt Creator, the Qt SDK
+ and much more.
+ * /
+ \endcode
+
+ The \\externalpage command makes it easier to maintain the
+ documentation. If the address changes, you only need to change the
+ argument of the \\externalpage command.
+
+ \target fn-command
+ \section1 \\fn (function)
+
+ The \\fn command is for documenting a function. The argument is
+ the function's signature, including its return type, const-ness,
+ and list of formal arguments with types. If the named function
+ doesn't exist, QDoc emits a warning.
+
+ \note The \\fn command is QDoc's default command, i.e. when no
+ topic command can be found in a QDoc comment, QDoc tries to tie
+ the documentation to the following code as if it is the
+ documentation for a function. Hence, it is normally not necessary
+ to include this command when documenting a function, if the
+ function's QDoc comment is written immediately above the function
+ implementation in the \c .cpp file. But it must be present when
+ documenting an inline function in the \c .cpp file that is
+ implemented in the \c .h file.
+
+ \code
+ / *!
+ \fn bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const
+
+ Returns true if this toolbar is dockable in the given
+ \a area; otherwise returns false.
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \raw HTML
+ <h3>bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const
+ </h3>
+ \endraw
+
+ Returns true if this toolbar is dockable in the given
+ \a area; otherwise returns false.
+ \endquotation
+
+ See also \l {overload-command} {\\overload}.
+
+ \target group-command
+ \section1 \\group
+
+ The \\group command creates a separate page that lists the classes
+ belonging to the group. The argument is the group name.
+
+ A class is included in a group by using the \l {ingroup-command}
+ {\\ingroup} command. Overview pages can also be related to a group
+ using the same command, but the list of overview pages must be
+ requested explicitly using the \l {generatelist-command}
+ {\\generatelist} command (see example below).
+
+ The \\group command is typically followed by a \l {title-command}
+ {\\title} command and a short introduction to the group. The
+ HTML page for the group is written to a \c {.html} file put in
+ <lower-case>\e{group}.html.
+
+ Each class name is listed as a link to the class reference page
+ followed by the text from the class's \l {brief-command} {\\brief}
+ texts.
+
+ \code
+ / *!
+ \group io
+
+ \title Input/Output and Networking
+
+ These classes are used to handle input and output to
+ and from external devices, processes, files etc. as
+ well as manipulating files and directories.
+ * /
+ \endcode
+
+ QDoc generates a group page in \c{io.html} that will look
+ like this:
+
+ \quotation
+ \raw HTML
+
+ <h1>Input/Output and Networking</h1>
+
+ <p>These classes are used to handle input and output
+ to and from external devices, processes, files etc. as
+ well as manipulating files and directories.</p>
+
+ <p>
+ <table width="100%">
+ <tr valign="top" bgcolor="#e0e0e0">
+ <td><b>
+ <a href="http://qt.nokia.com/doc/4.0/qabstractsocket.html">QAbstractSocket</a>
+ </b></td>
+ <td>
+ The base functionality common to all socket types
+ </td></tr>
+
+ <tr valign="top" bgcolor="#e0e0e0">
+ <td><b>
+ <a href="http://qt.nokia.com/doc/4.0/qbuffer.html">QBuffer</a>
+ </b></td>
+ <td>
+ QIODevice interface for a QByteArray
+ </td></tr>
+
+ <tr valign="top" bgcolor="#e0e0e0">
+ <td><b>
+ <a href="http://qt.nokia.com/doc/4.0/qclipboard.html">QClipboard</a>
+ </b></td>
+ <td>
+ Access to the window system clipboard
+ </td></tr>
+ </table>
+ \endraw
+ \endquotation
+
+ Note that overview pages related to the group, must be listed
+ explicitly using the \l {generatelist-command} {\\generatelist}
+ command with the \c related argument.
+
+ \code
+ / *!
+ \group architecture
+
+ \title Architecture
+
+ These documents describe aspects of Qt's architecture
+ and design, including overviews of core Qt features and
+ technologies.
+
+ \generatelist{related}
+ * /
+ \endcode
+
+ See also \l {ingroup-command} {\\ingroup} and \l
+ {generatelist-command} {\\generatelist}.
+
+ \target headerfile-command
+ \section1 \\headerfile
+
+ The \\headerfile command is for documenting the global functions,
+ types and macros that are declared in a header file but not in a
+ namespace. The argument is the name of the header file. The HTML
+ page is written to a \c {.html} file constructed from the header
+ file aregument.
+
+ The documentation for a function, type, or macro that is declared
+ in the header file being documented is included in the header file
+ page using the \l {relates-command} {\\relates} command.
+
+ If the argument doesn't exist as a header file, the \\headerfile
+ command creates a documentation page for the header file anyway.
+
+ \code
+ / *!
+ \headerfile <QtAlgorithms>
+
+ \title Generic Algorithms
+
+ \brief The <QtAlgorithms> header file provides
+ generic template-based algorithms.
+
+ Qt provides a number of global template functions in \c
+ <QtAlgorithms> that work on containers and perform
+ well-know algorithms.
+ * /
+ \endcode
+
+ QDoc generates a header file page \c{qtalgorithms.html} that looks
+ like this:
+
+ \quotation
+ \raw HTML
+ <center><h1>&lt;QtAlgorithms&gt; -
+ Generic Algorithms</h1></center>
+ <p>The <QtAlgorithms> header file provides generic
+ template-based algorithms.
+ <a href="13-qdoc-commands-topics.html#header-command">More...</a>
+ </p>
+
+ <h3>Functions</h3>
+ <ul>
+ <li>RandomAccessIterator
+ <a href="http://qt.nokia.com/doc/4.0/qlineedit.html#EchoMode-enum">qBinaryFind</a></b>
+ (RandomAccessIterator begin, RandomAccessIterator end,
+ const T & value)</li>
+ <li>...</li></ul>
+ <hr />
+ \endraw
+
+ \target header
+
+ \raw HTML
+ <h2>Detailed Description</h2>
+ <p>The <QtAlgorithms> header file provides generic
+ template-based algorithms. </p>
+ \endraw
+
+ Qt provides a number of global template functions in \c
+ <QtAlgorithms> that work on containers and perform
+ well-know algorithms.
+
+ ...
+ \endquotation
+
+ \target macro-command
+ \section1 \\macro
+
+ The \\macro command is for documententin a C++ macro. The argument
+ is the macro in one of three styles: function-like macros like
+ Q_ASSERT(), declaration-style macros like Q_PROPERTY(), and macros
+ without parentheses like Q_OBJECT.
+
+ The \\macro comment must contain a \l {relates-command}
+ {\\relates} command that attaches the macro comment to a class,
+ header file, or namespace. Otherwise, the documentation will be
+ lost. Here are three example macro comments followed by what they
+ might look like in \c {qtglobal.html} or \c {qobject.html}:
+
+ \code
+ / *!
+ \macro void Q_ASSERT(bool test)
+ \relates <QtGlobal>
+
+ Prints a warning message containing the source code
+ file name and line number if \a test is false.
+
+ ...
+
+ \sa Q_ASSERT_X(), qFatal(), {Debugging Techniques}
+ * /
+ \endcode
+
+ \quotation
+ \raw HTML
+ <h3>void Q_ASSERT ( bool <i>test</i> )</h3>
+ \endraw
+
+ Prints a warning message containing the source code
+ file name and line number if \a test is false.
+
+ ...
+
+ See also Q_ASSERT_X(), qFatal() and \l {Debugging Techniques}.
+
+ \endquotation
+
+ \code
+ / *!
+ \macro Q_PROPERTY(...)
+ \relates QObject
+
+ This macro declares a QObject property. The syntax is:
+
+ ...
+
+ \sa {Qt's Property System}
+ * /
+ \endcode
+
+ \quotation
+ \raw HTML
+ <h3>Q_PROPERTY ( ... )</h3>
+ \endraw
+
+ This macro declares a QObject property. The syntax is:
+
+ ...
+
+ See also \l {Qt's Property System}.
+ \endquotation
+
+ \code
+ / *!
+ \macro Q_OBJECT
+ \relates QObject
+
+ The Q_OBJECT macro must appear in the private section
+ of a class definition that declares its own signals and
+ slots or that uses other services provided by Qt's
+ meta-object system.
+
+ ...
+
+ \sa {Meta-Object System}, {Signals and Slots}, {Qt's
+ Property System}
+ * /
+ \endcode
+
+ \quotation
+ \raw HTML
+ <h3>Q_OBJECT</h3>
+ \endraw
+
+ The Q_OBJECT macro must appear in the private section
+ of a class definition that declares its own signals and
+ slots or that uses other services provided by Qt's
+ meta-object system.
+
+ ...
+
+ See also \l {Meta-Object System}, \l {Signals &
+ Slots} and \l {Qt's Property System}.
+ \endquotation
+
+ \target module-command
+ \section1 \\module
+
+ The \\module creates a page that lists the classes belonging to
+ the module specified by the command's argument. A class included
+ in the module by including the \l {inmodule-command} {\\inmodule}
+ command in the \\class comment.
+
+ The \\module command is typically followed by a \l {title-command}
+ {\\title} and a \l {brief-command} {\\brief} command. Each class
+ is listed as a link to the class reference page followed by the
+ text from the class's \l {brief-command} {\\brief} command. For
+ example:
+
+ \code
+ / *!
+ \module QtNetwork
+
+ \title QtNetwork Module
+
+ \brief The QtNetwork module offers classes that allow
+ you to write TCP/IP clients and servers.
+
+ The network module provides classes to make network
+ programming easier and portable. It offers both
+ high-level classes such as QNetworkAccessManager that
+ implements application-level protocols, and
+ lower-level classes such as QTcpSocket, QTcpServer, and
+ QUdpSocket.
+ * /
+ \endcode
+
+ QDoc renders this in \c {qtnetwork.html} like this:
+
+ \quotation
+ \raw HTML
+ <h1><center>QtNetwork Module</center></h1>
+ \endraw
+
+ The QtNetwork module offers classes that allow you to
+ write TCP/IP clients and servers.\l {module
+ details} {More...}
+
+ \raw HTML
+ <p>
+ <table width="100%">
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td><b>
+ <a href="http://qt.nokia.com/doc/4.0/qabstractsocket.html">QAbstractSocket</a>
+ </b></td>
+ <td>
+ The base functionality common to all socket types
+ </td></tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td><b>
+ <a href="http://qt.nokia.com/doc/4.0/qftp.html">QFtp</a>
+ </b></td>
+ <td>
+ Implementation of the FTP protocol
+ </td></tr>
+
+ <tr valign="top" bgcolor="#d0d0d0">
+ <td>...</td>
+ <td>...</td>
+ </tr>
+ </table>
+
+ <p><hr /></p>
+ \endraw
+
+ \target module details
+
+ \raw HTML
+ <h2>Detailed Description</h2>
+
+ <p>
+ The QtNetwork module offers classes that allow you to
+ write TCP/IP clients and servers.
+ </p>
+
+ <p>
+ The network module provides classes to make network
+ programming easier and portable. It offers both
+ high-level classes such as QNetworkAccessManager that
+ implements application-level protocols, and
+ lower-level classes such as QTcpSocket, QTcpServer, and
+ QUdpSocket.
+ </p>
+ \endraw
+
+ ...
+
+ \endquotation
+
+ See also \l {inmodule-command} {\\inmodule}
+
+ \target namespace-command
+ \section1 \\namespace
+
+ The \\namespace command is for documenting the contents of the C++
+ namespace named as its argument. The documentation outline QDoc
+ generates for a namespace is similar to the outline it generates
+ for a C++ class.
+
+ \code
+ / *!
+ \namespace Qt
+
+ \brief The Qt namespace contains miscellaneous
+ identifiers used throughout the Qt library.
+ * /
+ \endcode
+
+ QDoc renders this in \c{qt.html} like this:
+
+ \quotation
+ \raw HTML
+ <center><h1>Qt Namespace Reference</h1></center>
+ <p>The Qt namespace contains miscellaneous
+ identifiers used throughout the Qt library.
+ <a href="13-qdoc-commands-topics.html#name">More...</a>
+ </p>
+
+ <pre>#include &lt;Qt&gt;</pre>
+ <ul>
+ <li>
+ <a href="http://qt.nokia.com/doc/4.0/qt-qt3.html">
+ Qt 3 support members</a></li>
+ </ul>
+
+
+ <h3>Types</h3>
+ <ul>
+ <li>flags
+ <a href="http://qt.nokia.com/doc/4.0/qt.html#AlignmentFlag-enum">Alignment</a></b></li>
+ <li>...</li></ul>
+ <hr />
+ \endraw
+
+ \target name
+
+ \raw HTML
+ <h2>Detailed Description</h2>
+ <p>The Qt namespace contains miscellaneous identifiers
+ used throughout the Qt library.</p>
+ \endraw
+
+ ...
+ \endquotation
+
+ \target page-command
+ \section1 \\page
+
+ The \\page command is for creating a stand-alone documentation
+ page. The argument can consist of two parts separated by a
+ space. The first part is the name of the file where QDoc should
+ store the page. The second part, if present, is a word that
+ specifies the page type. Currently, the second part can be one of
+ the following list of words:
+
+ \list
+
+ \o faq - A frequently asked question.
+
+ \o howto - A user guide for how to use some component of the
+ software.
+
+ \o example - A page that describes a working example.
+
+ \o overview - For text pages that provide an overview of some
+ important subject.
+
+ \o tutorial - For text pages that are part of a tutorial.
+
+ \o api - This is the type of page used for C++ class references
+ and QML element references, etc. You should never use this one for
+ the pages you write, because this one is reserved for qdoc.
+
+ \endlist
+
+ The page title is set using the \l {title-command} {\\title}
+ command.
+
+ \code
+ / *!
+ \page aboutqt.html
+
+ \title About Qt
+
+ Qt is a C++ toolkit for cross-platform GUI
+ application development. Qt provides single-source
+ portability across Microsoft Windows, Mac OS X, Linux,
+ and all major commercial Unix variants.
+
+ Qt provides application developers with all the
+ functionality needed to build applications with
+ state-of-the-art graphical user interfaces. Qt is fully
+ object-oriented, easily extensible, and allows true
+ component programming.
+
+ ...
+ * /
+ \endcode
+
+ QDoc renders this page in \c {aboutqt.html}.
+
+ \target property-command
+ \section1 \\property
+
+ The \\property command is for documenting a Qt property. The
+ argument is the full property name.
+
+ A property is defined using the Q_PROPERTY() macro. The macro
+ takes as arguments the property's name and its set, reset and get
+ functions.
+
+ \code
+ Q_PROPERTY(QString state READ state WRITE setState)
+ \endcode
+
+ The set, reset and get functions don't need to be documented,
+ documenting the property is sufficient. QDoc will generate a list
+ of the access function that will appear in the property
+ documentation which in turn will be located in the documentation
+ of the class that defines the property.
+
+ The \\property command comment typically includes a \l
+ {brief-command} {\\brief} command. Forproperties the \l
+ {brief-command} {\\brief} command's argument is a sentence
+ fragment that will be included in a one line description of the
+ property. The command follows the same rules for the \l
+ {brief-property} {description} as the \l {variable-command}
+ {\\variable} command.
+
+ \code
+ / *!
+ \property QPushButton::flat
+ \brief whether the border is disabled
+
+ This property's default is false.
+ * /
+ \endcode
+
+ QDoc includes this in \c {qpushbutton.html} like this:
+
+ \quotation
+ \raw HTML
+ <h3>flat : bool</h3>
+ \endraw
+
+ This property holds whether the border is disabled.
+
+ This property's default is false.
+
+ Access functions:
+
+ \list
+ \o \bold { bool isFlat () const}
+ \o \bold { void setFlat ( bool )}
+ \endlist
+
+ \endquotation
+
+ \code
+ / *!
+ \property QWidget::width
+ \brief the width of the widget excluding any window frame
+
+ See the \l {Window Geometry} documentation for an
+ overview of window geometry.
+
+ \sa geometry, height, size
+ * /
+ \endcode
+
+ QDoc includes this in \c {qwidget.html} like this:
+
+ \quotation
+ \raw HTML
+ <h3>width : const int</h3>
+ \endraw
+
+ This property holds the width of the widget excluding
+ any window frame.
+
+ See the \l {Window Geometry} documentation for an
+ overview of window geometry.
+
+ Access functions:
+
+ \list
+ \o \bold { int width () const}
+ \endlist
+
+ See also \l{QWidget::geometry} {geometry},
+ \l{QWidget::height} {height}, and \l{QWidget::size} {size}.
+ \endquotation
+
+ \target service-command
+ \section1 \\service
+
+ The \\service command tells QDoc that a class is a service class
+ and names the service. The command takes two arguments, the name
+ of the class and the name of the service. Currently, this command
+ is not used in the Qt documentation.
+
+ \code
+ / *!
+ \service TimeService Time
+ ...
+ * /
+ class TimeService : public QCopObjectService
+ {
+ ...
+ }
+ \endcode
+
+ See also \l {class-command} {\\class} and \l
+ {generatelist-command} {\\generatelist}.
+
+ \target qmlattachedproperty-command
+ \section1 \\qmlattachedproperty
+
+ The \\qmlattachedproperty command is for documenting a QML
+ property that will be attached to some QML element type. See
+ \l{http://doc.qt.nokia.com/4.7/qdeclarativeintroduction.html#attached-properties}
+ {Attached Properties}. The argument is the rest of the line. The
+ argument text should be the property type, followed by the QML
+ element name where the property is being declared, the \c{::}
+ qualifier, and finally the property name. If we have a QML
+ attached property named \c isCurrentItem in QML element \c ListView,
+ and the property has type \c {bool}, the \\qmlattachedproperty for
+ it would look like this:
+
+ \code
+ / *!
+ \qmlattachedproperty bool ListView::isCurrentItem
+ This attached property is true if this delegate is the current
+ item; otherwise false.
+
+ It is attached to each instance of the delegate.
+
+ This property may be used to adjust the appearance of the current
+ item, for example:
+
+ \snippet doc/src/snippets/declarative/listview/listview.qml isCurrentItem
+ * /
+ \endcode
+
+ QDoc includes this attached property on the QML reference page for the
+ \l{http://doc.qt.nokia.com/4.7/qml-listview.html#isCurrentItem-prop}
+ {ListView} element.
+
+ \target qmlattachedsignal-command
+ \section1 \\qmlattachedsignal
+
+ The \\qmlattachedsignal command is for documenting an attachable
+ \l{http://doc.qt.nokia.com/4.7/qdeclarativeintroduction.html#signal-handlers}
+ {signal handler}. The \\qmlattachedsignal command is used just like
+ the \l{qmlsignal-command} {\\qmlsignal} command.
+
+ The argument is the rest of the line. It should be the name of the
+ QML element where the signal handler is declared, the \c{::}
+ qualifier, and finally the signal handler name. If we have a QML
+ attached signal handler named \c onAdd() in the \c GridView
+ element, the \\qmlattachedsignal for it would look like this:
+
+ \code
+ / *!
+ \qmlattachedsignal GridView::onAdd()
+ This attached handler is called immediately after an item is
+ added to the view.
+ * /
+ \endcode
+
+ QDoc includes this documentation on the QML reference page for the
+ \l{http://doc.qt.nokia.com/4.7/qml-gridview.html#onAdd-signal}
+ {GridView} element.
+
+ \target qmlbasictype-command
+ \section1 \\qmlbasictype
+
+ The \\qmlbasictype command is for documenting a basic type for QML.
+ The argument is the type name. The type must be included in the
+ QML basic types group using the \l{ingroup-command}{\\ingroup}
+ command as shown below. This will cause QDoc to include the
+ documentation for the type on the
+ \l{http://doc.qt.nokia.com/4.7/qdeclarativebasictypes.html}
+ {QML Basic Types} page. The \l{brief-command} {\\brief} command
+ is also required, because it appears on the
+ \l{http://doc.qt.nokia.com/4.7/qdeclarativebasictypes.html}
+ {QML Basic Types} page as well.
+
+ \code
+ / *!
+ \qmlbasictype int
+ \ingroup qmlbasictypes
+
+ \brief An integer is a whole number, e.g. 0, 10, or -20.
+
+ An integer is a whole number, e.g. 0, 10, or -20. The possible
+ \c int values range from around -2000000000 to around
+ 2000000000, although most elements will only accept a reduced
+ range (which they mention in their documentation).
+
+ Example:
+ \qml
+ Item { width: 100; height: 200 }
+ \endqml
+
+ \sa {QML Basic Types}
+ * /
+ \endcode
+
+ QDoc outputs this as \l{http://doc.qt.nokia.com/4.7/qml-int.html}
+ {qml-int.html}.
+
+ \target qmlclass-command
+ \section1 \\qmlclass
+
+ The \\qmlclass command is for documenting a QML element that is
+ instantiated by a C++ class. The command has two arguments. The
+ first argument is the name of the QML element. The second argument
+ is the name of the C++ class that instantiates the QML element.
+
+ \code
+ / *!
+ \qmlclass Transform QGraphicsTransform
+ \ingroup qml-transform-elements
+ \since 4.7
+ \brief The Transform elements provide a way of building
+ advanced transformations on Items.
+
+ The Transform element is a base type which cannot be
+ instantiated directly. The following concrete Transform types
+ are available:
+
+ \list
+ \o \l Rotation
+ \o \l Scale
+ \o \l Translate
+ \endlist
+
+ The Transform elements let you create and control advanced
+ transformations that can be configured independently using
+ specialized properties.
+
+ You can assign any number of Transform elements to an \l
+ Item. Each Transform is applied in order, one at a time.
+
+ * /
+ \endcode
+
+ This example generates the
+ \l {http://doc.qt.nokia.com/4.7/qml-transform.html} {QML Transform
+ Element} page. The \\qmlclass comment should include the \l
+ {since-command} {\\since} command, because all QML elements are
+ new. It should also include the \l{brief-command} {\\brief}
+ command. And since every QML element is a member of a group of QML
+ elements, it should also include one or more \l{ingroup-command}
+ {\\ingroup} commands.
+
+ \target qmlmethod-command
+ \section1 \\qmlmethod
+
+ The \\qmlmethod command is for documenting a QML method. The
+ argument is the complete method signature, including return
+ type and parameter names and types.
+
+ \code
+ / *!
+ \qmlmethod void TextInput::select(int start, int end)
+
+ Causes the text from \a start to \a end to be selected.
+
+ If either start or end is out of range, the selection is not changed.
+
+ After calling this, selectionStart will become the lesser and
+ selectionEnd will become the greater (regardless of the order
+ passed to this method).
+
+ \sa selectionStart, selectionEnd
+ * /
+ \endcode
+
+ QDoc includes this documentation on the element refence page for the
+ \l{http://doc.qt.nokia.com/4.7/qml-textinput.html#select-method}
+ {TextInput} element.
+
+ \target qmlproperty-command
+ \section1 \\qmlproperty
+
+ The \\qmlproperty command is for documenting a QML property. The
+ argument is the rest of the line. The argument text should be the
+ property type, followed by the QML element name, the \c{::}
+ qualifier, and finally the property name. If we have a QML
+ property named \c x in QML element \c Translate, and the property
+ has type \c {real}, the \\qmlproperty for it would look like this:
+
+ \code
+ / *!
+ \qmlproperty real Translate::x
+
+ The translation along the X axis.
+ * /
+ \endcode
+
+ QDoc includes this QML property on the QML reference page for the
+ \l {http://doc.qt.nokia.com/4.7/qml-translate.html} {Translate}
+ element.
+
+ \target qmlsignal-command
+ \section1 \\qmlsignal
+
+ The \\qmlsignal command is for documenting a
+ \l{http://doc.qt.nokia.com/4.7/qdeclarativeintroduction.html#signal-handlers}
+ {signal handler}.
+ The argument is the rest of the line. It should be the QML element where the
+ signal handler is declared, the \c{::} qualifier, and finally the signal
+ handler name. If we have a QML signal handler named \c onAdd() in QML
+ element \c MouseArea, the \\qmlsignal for it would look like this:
+
+ \code
+ / *!
+ \qmlsignal MouseArea::onEntered()
+
+ This handler is called when the mouse enters the mouse area.
+
+ By default the onEntered handler is only called while a button is
+ pressed. Setting hoverEnabled to true enables handling of
+ onEntered when no mouse button is pressed.
+
+ \sa hoverEnabled
+ * /
+ \endcode
+
+ QDoc includes this documentation on the QML reference page for the
+ \l{http://doc.qt.nokia.com/4.7/qml-mousearea.html#onEntered-signal}
+ {MouseArea} element.
+
+ \target qmlmodule-command
+ \section1 \\qmlmodule
+
+ Insert the \c{\\qmlmodule} command to create a \c QML module page. A QML
+ module is a collection of QML components or any related material. This
+ command is similar to the \l{group-command}.
+
+ A QML class may belong to a module by inserting the
+ \l{inqmlmodule-command}{\\inqmlmodule} command as a topic command.
+ Every member of a group must be linked to using the module name and two
+ colons (\c{::}).
+
+ \code
+ A link to the UI Component's TabWidget is \l {UIComponent::TabWidget}.
+ \endcode
+
+ QDoc will generate a page for the module with a listing of the members
+ of the module.
+
+ \code
+ \qmlmodule ClickableComponents
+
+ This is a list of the Clickable Components set. A Clickable component
+ responds to a \c clicked() event.
+ \endcode
+
+ The \l{componentset}{UIComponents} example demonstrates proper usage of
+ QDoc commands to document QML components and QML modules.
+
+ \target inqmlmodule-command
+ \section1 \\inqmlmodule
+
+ A QML class may belong to a \l{qmlmodule-command}{QML module} by inserting
+ the \l{inqmlmodule-command}{\\inqmlmodule} command as a topic command.
+ Every member of a group must be linked to using the module name and two
+ colons (\c{::}).
+
+ \code
+ \qmlclass ClickableButton
+ \inqmlmodule ClickableComponents
+
+ A clickable button that responds to the \c click() event.
+ \endcode
+
+ To link to the \c ClickableButton, use the
+ \c{\l ClickableComponents::ClickableButton} format.
+
+ The \l{componentset}{UIComponents} example demonstrates proper usage of
+ QDoc commands to document QML components and QML modules.
+
+ \target typedef-command
+ \section1 \\typedef
+
+ The \\typedef command is for documenting a C++ typedef. The
+ argument is the name of the typedef. The documentation for
+ the typedef will be included in the refernece documentation
+ for the class, namespace, or header file in which the typedef
+ is declared. To relat the \\typedef to a class, namespace, or
+ header file, the \\typedef comment must contain a
+ \l {relates-command} {\\relates} command.
+
+ \code
+ / *!
+ \typedef QObjectList
+ \relates QObject
+
+ Synonym for QList<QObject>.
+ * /
+ \endcode
+
+ QDoc includes this in \c {qobject.html} as:
+
+ \quotation
+ \raw HTML
+ <h3>typedef QObjectList</h3>
+ \endraw
+
+ Synonym for QList<QObject>.
+ \endquotation
+
+ Another, although more rare, example:
+
+ \code
+ / *!
+ \typedef QMsgHandler
+ \relates QtGlobal
+
+ This is a typedef for a pointer to a function with the
+ following signature:
+
+ \code
+ void myMsgHandler(QtMsgType, const char *);
+ \ endcode
+
+ \sa QtMsgType, qInstallMsgHandler()
+ * /
+ \endcode
+
+ QDoc includes this in \c {qtglobal.html} as:
+
+ \quotation
+ \raw HTML
+ <h3>typedef QtMsgHandler</h3>
+ \endraw
+
+ This is a typedef for a pointer to a function with the
+ following signature:
+
+ \raw HTML
+ <tt>
+ <pre> void myMsgHandler(QtMsgType, const char *);</pre>
+ </tt>
+ \endraw
+
+ See also QtMsgType and qInstallMsgHandler().
+ \endquotation
+
+ Other typedefs are located on the reference page for the class
+ that defines them.
+
+ \code
+ / *!
+ \typedef QLinkedList::Iterator
+
+ Qt-style synonym for QList::iterator.
+ * /
+ \endcode
+
+ QDoc includes this one on the reference page for class QLinkedList as:
+
+ \quotation
+ \raw HTML
+ <h3>typedef QLinkedList::Iterator</h3>
+ \endraw
+
+ Qt-style synonym for QList::iterator.
+ \endquotation
+
+ \target variable-command
+ \section1 \\variable
+
+ The \\variable command is for documenting a class member variable
+ or a constant. The argument is the variable or constant name. The
+ \\variable command comment includes a \l {brief-command} {\\brief}
+ command. QDoc generates the documentation based on the text from
+ \\brief command.
+
+ The documentation will be located in the in the associated class,
+ header file or namespace documentation.
+
+ In case of a member variable:
+
+ \code
+ / *!
+ \variable QStyleOption::palette
+ \brief the palette that should be used when painting
+ the control
+ * /
+ \endcode
+
+ QDoc includes this in qstyleoption.html as:
+
+ \quotation
+ \raw HTML
+ <h3>
+ <a href="http://qt.nokia.com/doc/4.0/qpalette.html">
+ QPalette
+ </a>
+ QStyleOption::palette
+ </h3>
+ \endraw
+
+ This variable holds the palette that should be used
+ when painting the control.
+ \endquotation
+
+ You can also document constants with the \\variable command. For
+ example, suppose you have the \c Type and \c UserType constants in
+ the QTreeWidgetItem class:
+
+ \code
+ enum { Type = 0, UserType = 1000 };
+ \endcode
+
+ For these, the \\vaqriable command can be used this way:
+
+ \code
+ / *!
+ \variable QTreeWidgetItem::Type
+
+ The default type for tree widget items.
+
+ \sa UserType, type()
+ * /
+ \endcode
+ \code
+ / *!
+ \variable QTreeWidgetItem::UserType
+
+ The minimum value for custom types. Values below
+ UserType are reserved by Qt.
+
+ \sa Type, type()
+ * /
+ \endcode
+
+ QDoc includes these in qtreewidget.html as:
+
+ \quotation
+ \raw HTML
+ <h3>
+ const int QTreeWidgetItem::Type
+ </h3>
+ \endraw
+
+ The default type for tree widget items.
+
+ See also \l {QTreeWidgetItem::UserType} {UserType} and \l
+ {QTreeWidgetItem::type()} {type()}.
+
+ \raw HTML
+ <h3>
+ const int QTreeWidgetItem::UserType
+ </h3>
+ \endraw
+
+ The minimum value for custom types. Values below
+ UserType are reserved by Qt.
+
+ See also \l {QTreeWidgetItem::Type} {Type} and
+ \l{QTreeWidgetItem::type()} {type()}.
+
+ \endquotation
+*/
+
+/*!
+ \page 14-qdoc-commands-contextcommands.html
+ \previouspage Topic Commands
+ \contentspage Table of Contents
+ \nextpage Document Navigation
+
+ \title Context Commands
+
+ The context commands provide information about the element being
+ documented that QDoc can't deduce on its own. e.g. Is a class
+ thread-safe? Is a function reentrant? Which module is the class a
+ member of? Context commands can appear anywhere in a QDoc comment,
+ but they are normally placed near the top of the comment, just
+ below the \l {Topic Commands} {topic} command.
+
+ \list
+ \o \l {16-qdoc-commands-status.html#compat-command}{\\compat},
+ \o \l {15-qdoc-commands-navigation.html#contentspage-command}{\\contentspage},
+ \o \l {15-qdoc-commands-navigation.html#indexpage-command}{\\indexpage},
+ \o \l {19-qdoc-commands-grouping.html#ingroup-command}{\\ingroup},
+ \o \l {18-qdoc-commands-relating.html#inherits-command}{\\inherits},
+ \o \l {19-qdoc-commands-grouping.html#inmodule-command}{\\inmodule},
+ \o \l {16-qdoc-commands-status.html#internal-command}{\\internal},
+ \o \l {19-qdoc-commands-grouping.html#mainclass-command}{\\mainclass},
+ \o \l {15-qdoc-commands-navigation.html#nextpage-command}{\\nextpage},
+ \o \l {17-qdoc-commands-thread.html#nonreentrant-command}{\\nonreentrant},
+ \o \l {16-qdoc-commands-status.html#obsolete-command}{\\obsolete},
+ \o \l {18-qdoc-commands-relating.html#overload-command}{\\overload},
+ \o \l {16-qdoc-commands-status.html#preliminary-command}{\\preliminary},
+ \o \l {15-qdoc-commands-navigation.html#previouspage-command}{\\previouspage},
+ \o \l {17-qdoc-commands-thread.html#reentrant-command}{\\reentrant},
+ \o \l {18-qdoc-commands-relating.html#reimp-command}{\\reimp},
+ \o \l {18-qdoc-commands-relating.html#relates-command}{\\relates},
+ \o \l {16-qdoc-commands-status.html#since-command}{\\since},
+ \o \l {15-qdoc-commands-navigation.html#startpage-command}{\\startpage},
+ \o \l {20-qdoc-commands-namingthings.html#subtitle-command}{\\subtitle}
+ \o \l {17-qdoc-commands-thread.html#threadsafe-command}{\\threadsafe},
+ \o \l {20-qdoc-commands-namingthings.html#title-command}{\\title}
+ \endlist
+
+*/
+
+/*!
+ \page 15-qdoc-commands-navigation.html
+ \previouspage Context Commands
+ \contentspage Table of Contents
+ \nextpage Reporting Status
+
+ \title Document Navigation
+
+ The navigation commands are for linking the pages of a document in
+ a meaningful sequence. Below is a sequence of QDoc comments that
+ shows a typical use of the navigation commands.
+
+ \section1 Example
+
+ \code
+ / *!
+ \page basicqt.html
+ \contentspage {Basic Qt} {Contents}
+ \nextpage Getting Started
+
+ \indexpage Index
+ \startpage Basic Qt
+
+ \title Basic Qt
+
+ The Qt toolkit is a C++ class library and a set of tools for
+ building multiplatform GUI programs using a "write once,
+ compile anywhere approach".
+
+ Table of contents:
+
+ \list
+ \o \l {Getting Started}
+ \o \l {Creating Dialogs}
+ \o \l {Creating Main Windows}
+ \endlist
+ * /
+
+ / *!
+ \page gettingstarted.html
+ \previouspage Basic Qt
+ \contentspage {Basic Qt} {Contents}
+ \nextpage Creating Dialogs
+
+ \indexpage Index
+ \startpage Basic Qt
+
+ \title Getting Started
+
+ This chapter shows how to combine basic C++ with the
+ functionality provided by Qt to create a few small graphical
+ interface (GUI) applications.
+ * /
+
+ / *!
+ \page creatingdialogs.html
+ \previouspage Getting Started
+ \contentspage {Basic Qt} {Contents}
+
+ \indexpage Index
+ \startpage Basic Qt
+
+ \title Creating Dialogs
+
+ This chapter will teach you how to create dialog boxes using Qt.
+ * /
+
+ / *!
+ \page index.html
+
+ \indexpage Index
+ \startpage Basic Qt
+
+ \title Index
+
+ \list
+ \o \l {Basic Qt}
+ \o \l {Creating Dialogs}
+ \o \l {Getting Started}
+ \endlist
+ * /
+ \endcode
+
+ QDoc renders the "Getting Started" page in \c{creatingdialogs.html}:
+
+ \quotation
+ \raw HTML
+ <table border="0" cellpadding="0" cellspacing="5" width="100%">
+
+ <tr>
+ <p>
+ [Previous: <a href="15-qdoc-commands-navigation.html#deadlink">
+ Basic Qt</a>]
+ [<a href="15-qdoc-commands-navigation.html#deadlink">Contents</a>]
+ [Next: <a href="15-qdoc-commands-navigation.html#deadlink">
+ Creating Dialogs</a>]
+ </p>
+
+ <h1 align="center">Getting Started<br /></h1>
+
+ <p>
+ This chapter shows how to combine basic C++ with the
+ functionality provided by Qt to create a few small graphical
+ interface (GUI) applications.
+ </p>
+
+ <p>
+ [Previous: <a href="15-qdoc-commands-navigation.html#deadlink">
+ Basic Qt</a>]
+ [<a href="15-qdoc-commands-navigation.html#deadlink">Contents</a>]
+ [Next: <a href="15-qdoc-commands-navigation.html#deadlink">
+ Creating Dialogs</a>]
+ </p>
+
+ </table>
+ \endraw
+ \endquotation
+
+ The \l {indexpage-command} {\\indexpage} and \l
+ {startpage-command} {\\startpage} commands create links to the
+ page's index page and start page. These links can be used by
+ browsers and search engines.
+
+ The index page is typically an alphabetical list of the document's
+ titles and topics, while the start page is the page considered by
+ the author to be the starting point of a multipage document.
+
+ The links are included in the generated HTML source code but have
+ no visual effect on the documentation:
+
+ \code
+ <head>
+ ...
+ <link rel="index" href="index.html" />
+ <link rel="start" href="basicqt.html" />
+ ...
+ </head>
+ \endcode
+
+ \section1 Commands
+
+ \target previouspage-command
+ \section2 \\previouspage
+
+ The \\previouspage command links the current page to the previous
+ page in a sequence.a The command has two arguments, each enclosed
+ by curly braces: The first is the link target, i.e. the title of
+ the previous page, the second is the link text. If the page's
+ title is equivalent to the link text, the second argument can be
+ omitted.
+
+ The command must stand alone on its own line.
+
+ \target nextpage-command
+ \section2 \\nextpage
+
+ The \\nextpage command links the current page to the next page in
+ a sequence. The command follows the same syntax and argument
+ convention as the \l {previouspage-command} {\\previouspage}
+ command.
+
+ \target startpage-command
+ \section2 \\startpage
+
+ The \\startpage command specifies the first page of a sequence of
+ pages. The command must stand alone on its own line, and its
+ unique argument is the title of the first document.
+
+ QDoc will generate a link to the start page and include it in the
+ generated HTML file, but this has no visual effect on the
+ documentation. The generated link type tells browsers and search
+ engines which document is considered by the author to be the
+ starting point of the collection.
+
+ \target contentspage-command
+ \section2 \\contentspage
+
+ The \\contentspage command links the current page to a table of
+ contents page. The command follows the same syntax and argument
+ convention as the \l {previouspage-command} {\\previouspage}
+ command.
+
+ \target indexpage-command
+ \section2 \\indexpage
+
+ The \\indexpage command specifies an index page for the current
+ document. The command must stand alone on its own line, and its
+ unique argument is the title of the index document.
+
+ QDoc will generate a link to the index page and include it in the
+ generated HTML file, but this has no visual effect on the
+ documentation. The generated link type tells browsers and search
+ engines which document is considered by the author to be the
+ index page of the collection.
+*/
+
+/*!
+ \page 16-qdoc-commands-status.html
+ \previouspage Document Navigation
+ \contentspage Table of Contents
+ \nextpage Thread Support
+
+ \title Reporting Status
+
+ These commands are for indicating that a documented element is
+ still under development, is becoming obsolete, is provided for
+ compatibility reasons, or is simply not to be included in the
+ public interface. The \l {since-command}{\\since} command is for
+ including information about the version when a function or class
+ first appeared.
+
+ \target compat-command
+ \section1 \\compat
+
+ The \\compat command is for indicating that a class or function is
+ part of the support library provided to keep old source code
+ working.
+
+ The command must stand on its own line.
+
+ Usually an equivalent function or class is provided as an
+ alternative.
+
+ If the command is used in the documentation of a class, the
+ command expands to a warning that the referenced class is part of
+ the support library. The warning is located at the top of the
+ documentation page.
+
+ \code
+ / *!
+ \class MyQt3SupportClass
+ \compat
+ * /
+ \endcode
+
+ QDoc renders this at the top of the MyQt3SupportClass class
+ reference page.
+
+ \quotation
+ \bold {This class is part of the Qt 3 support
+ library.} It is provided to keep old source code
+ working. We strongly advise against using it in new
+ code. See the \l
+ {http://qt.nokia.com/doc/4.0/porting4.html} {Porting
+ Guide} for more information.
+ \endquotation
+
+ If the command is used when documenting a function, QDoc will
+ create and link to a separate page documenting Qt 3 support
+ members when generating the reference documentation for the
+ associated class.
+
+ \code
+ / *!
+ \fn MyClass::MyQt3SupportMemberFunction
+ \compat
+
+ Use MyNewFunction() instead.
+ * /
+ \endcode
+
+ QDoc renders this in \c{myclass-qt3.html} as:
+
+ \quotation
+ \raw HTML
+ <h1>Qt 3 Support Members for MyClass</h1>
+ \endraw
+
+ \bold {The following class members are part of the Qt 3
+ support layer.} They are provided to help you port old code to
+ Qt 4. We advise against using them in new code.
+
+ ...
+
+ \list
+ \o void MyQt3SupportMemberFunction()
+ \o ...
+ \endlist
+
+ \raw HTML
+ <hr />
+ <h2>Member Function Documentation</h2>
+ <h3>void MyQt3SupportMemberFunction ()</h3>
+ <p>Use MyNewFunction() instead.</p>
+ \endraw
+ ...
+ \endquotation
+
+ \target default-command
+ \section1 \\default
+
+ The \\default command is for marking a QML property as the
+ \l {http://doc.qt.nokia.com/4.7/qdeclarativeintroduction.html#default-properties}
+ {default property}. The word \span {class="newStuff"} {default} is shown in red in
+ the documentation of the property.
+
+ \code
+ / *!
+ \qmlproperty list<Change> State::changes
+ This property holds the changes to apply for this state
+ \default
+
+ By default these changes are applied against the default state. If the state
+ extends another state, then the changes are applied against the state being
+ extended.
+ * /
+ \endcode
+
+ See how QDoc renders this property on the reference page for the
+ \l {http://doc.qt.nokia.com/4.7/qml-state.html#changes-prop} {State}
+ element.
+
+ \target obsolete-command
+ \section1 \\obsolete
+
+ The \\obsolete command is for indicating that a function is being
+ deprecated, and it should no longer be used in new code. There is
+ no guarantee for how long it will remain in the library.
+
+ The command must stand on its own line.
+
+ When generating the reference documentation for a class, QDoc will
+ create and link to a separate page documenting its obsolete
+ functions. Usually an equivalent function is provided as an
+ alternative.
+
+ \code
+ / *!
+ \fn MyClass::MyObsoleteFunction
+ \obsolete
+
+ Use MyNewFunction() instead.
+ * /
+ \endcode
+
+ QDoc renders this in \c{myclass-obsolete.html} as:
+
+ \quotation
+ \raw HTML
+ <h1>Obsolete Members for MyClass</h1>
+ \endraw
+
+ \bold {The following class members are obsolete.} They are
+ provided to keep old source code working. We strongly advise
+ against using them in new code.
+
+ ...
+
+ \list
+ \o void MyObsoleteFunction() \c (obsolete)
+ \o ...
+ \endlist
+
+ \raw HTML
+ <hr />
+ <h2>Member Function Documentation</h2>
+ <h3>void MyObsoleteFunction ()</h3>
+ <p>Use MyNewFunction() instead.</p>
+ \endraw
+ ...
+ \endquotation
+
+ \target internal-command
+ \section1 \\internal
+
+ The \\internal command indicates that the referenced
+ function is not part of the public interface.
+
+ The command must stand on its own line.
+
+ QDoc ignores the documentation as well as the documented item,
+ when generating the associated class reference documenation.
+
+ \code
+ / *!
+ \internal
+
+ Tries to find the decimal separator. If it can't find
+ it and the thousand delimiter is != '.' it will try to
+ find a '.';
+ * /
+ int QDoubleSpinBoxPrivate::findDelimiter
+ (const QString &str, int index) const
+ {
+ int dotindex = str.indexOf(delimiter, index);
+ if (dotindex == -1 && thousand != dot && delimiter != dot)
+ dotindex = str.indexOf(dot, index);
+ return dotindex;
+ }
+ \endcode
+
+ This function will not be included in the documentation.
+
+ \target preliminary-command
+ \section1 \\preliminary
+
+ The \\preliminary command is for indicating that a referenced
+ function is still under development.
+
+ The command must stand on its own line.
+
+ The \\preliminary command expands to a notification in the
+ function documentation, and marks the function as preliminary when
+ it appears in lists.
+
+ \code
+ / *!
+ \preliminary
+
+ Returns information about the joining properties of the
+ character (needed for certain languages such as
+ Arabic).
+ * /
+ QChar::Joining QChar::joining() const
+ {
+ return ::joining(*this);
+ }
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \raw HTML
+ <h3>
+ <a href="http://qt.nokia.com/doc/4.0/qchar.html#Joining-enum">Joining</a>
+ QChar::joining () const</h3>
+ \endraw
+
+ \bold {This function is under development and
+ subject to change.}
+
+ Returns information about the joining properties of the
+ character (needed for certain languages such as
+ Arabic).
+ \endquotation
+
+ And the function's entry in QChar's list of functions will be
+ rendered as:
+
+ \quotation
+ \list
+ \o ...
+ \o Joining
+ \l {http://qt.nokia.com/doc/4.0/qchar.html#Joining-enum}
+ {joining}()
+ const \c (preliminary)
+ \o ...
+ \endlist
+ \endquotation
+
+ \target since-command
+ \section1 \\since
+
+ The \\since command tells in which minor release
+ the associated functionality was added.
+
+ \code
+ / *!
+ \since 4.1
+
+ Returns an icon for \a standardIcon.
+
+ ...
+
+ \sa standardIconImplementation(), standardPixmap()
+ * /
+ QIcon QStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const
+ {
+ }
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \raw HTML
+ <h3>QIcon QStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const</h3>
+ \endraw
+
+ This function was introduced in Qt version 4.1
+
+ Returns an icon for \a standardIcon.
+
+ ...
+
+ See also \l {QStyle::standardIconImplementation()}
+ {standardIconImplementation()} and \l
+ {QStyle::standardPixmap()} {standardPixmap()}.
+ \endquotation
+
+ QDoc generates the "Qt" reference from the \l
+ {25-qdoc-configuration-derivedprojects.html#project} {\c project}
+ configuration variable. For that reason this reference will change
+ according to the current documentation project.
+
+ See also \l {25-qdoc-configuration-derivedprojects.html#project}
+ {\c project}.
+*/
+
+/*!
+ \page 17-qdoc-commands-thread.html
+ \previouspage Reporting Status
+ \contentspage Table of Contents
+ \nextpage Relating Things
+
+ \title Thread Support
+
+ The thread support commands are for specifying the level of
+ support for multithreaded programming in a class or function.
+ There are three levels of support: \c threadsafe, \c reentrant and
+ \c nonreentrant.
+
+ The default is \c nonreentrant which means that the associated
+ class or function cannot be called by multiple threads. \c
+ Reentrant and \c threadsafe are levels primarily used for classes.
+
+ \c Reentrant means that all the functions in the referenced class
+ can be called simultaneously by multiple threads, provided that
+ each invocation of the functions reference unique data. While \c
+ threadsafe means that all the functions in the referenced class
+ can be called simultaneously by multiple threads even when each
+ invocation references shared data.
+
+ When a class is marked \l {reentrant-command} {\\reentrant} or \l
+ {threadsafe-command} {\\threadsafe}, functions in that class can
+ be marked \c nonreentrant using the \l {nonreentrant-command}
+ {\\nonreentrant} command.
+
+ \section1 Example
+
+ \target reentrant-example
+ \code
+ / *!
+ \class QLocale
+ \brief The QLocale class converts between numbers and their
+ string representations in various languages.
+
+ \reentrant
+ \ingroup i18n
+ \ingroup text
+ \mainclass
+
+ QLocale is initialized with a language/country pair in its
+ constructor and offers number-to-string and string-to-number
+ conversion functions similar to those in QString.
+
+ ...
+ * /
+
+ / *!
+ \nonreentrant
+
+ Sets the global default locale to \a locale. These values are
+ used when a QLocale object is constructed with no
+ arguments. If this function is not called, the system's locale
+ is used.
+
+ \warning In a multithreaded application, the default locale
+ should be set at application startup, before any non-GUI
+ threads are created.
+
+ \sa system() c()
+ * /
+ void QLocale::setDefault(const QLocale &locale)
+ {
+ default_d = locale.d;
+ }
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \raw HTML
+ <h1><center>QLocale Class Reference</center></h1>
+ \endraw
+
+ The QLocale class converts between numbers and their string
+ representations in various languages. More...
+
+ \code
+ #include <QLocale>
+ \endcode
+
+ \bold {Note:} All the functions in this class are \l
+ {threads.html#reentrant} {reentrant}, except \l
+ {QLocale::setDefault()} {setDefault()}.
+
+ ...
+
+ \raw HTML
+ <hr />
+ <h2>Member Type Documentation</h2>
+ \endraw
+
+ ...
+
+ \raw HTML
+ <h3>void QLocale::setDefault ( const QLocale & locale ) </h3>
+ \endraw
+
+ Sets the global default locale to locale. These values are
+ used when a QLocale object is constructed with no
+ arguments. If this function is not called, the system's locale
+ is used.
+
+ \warning In a multithreaded application, the default locale
+ should be set at application startup, before any non-GUI
+ threads are created.
+
+ \warning This function is not reentrant.
+
+ See also \l {QLocale::system()} {system()} and \l
+ {QLocale::c()} {c()}.
+
+ ...
+ \endquotation
+
+ As shown above, QDoc generates a notification when a class is
+ declared reentrant, and lists the exceptions (the declared
+ nonreentrant functions). A link to the general documentation on \l
+ {threads.html#reentrant} {reentrancy and thread-safety} is
+ included. In addition a warning, "\bold Warning: This function is
+ not reentrant.", is generated in the nonreentrant functions'
+ documentation.
+
+ QDoc will generate the same notification and warnings when a class
+ is declared threadsafe.
+
+ For more information see the general documentation on \l
+ {threads.html#reentrant} {reentrancy and thread-safety}.
+
+ \section1 Commands
+
+ \target threadsafe-command
+ \section2 \\threadsafe
+
+ The \\threadsafe command includes a line in the documentation to
+ indicate that the associated class or function is \e threadsafe
+ and can be called simultaneously by multiple threads, even when
+ separate invocations reference shared data.
+
+ The command must stand on its own line.
+
+ The documentation generated from this command will be similar to
+ the what is generated for the \l {reentrant-command} {\\reentrant}
+ command. See the example above in the \l {reentrant-example}
+ {introduction}.
+
+ See also \l{reentrant-command} {\\reentrant} and
+ \l{nonreentrant-command} {\\nonreentrant}.
+
+ \target reentrant-command
+ \section2 \\reentrant
+
+ The \\reentrant command indicates that the associated class or
+ function can be called simultaneously by multiple threads,
+ provided that each invocation references its own data. See the \l
+ {reentrant-example} {example} above.
+
+ The command must stand on its own line.
+
+ See also \l{nonreentrant-command} {\\nonreentrant} and
+ \l{threadsafe-command} {\\threadsafe}.
+
+ \target nonreentrant-command
+ \section2 \\nonreentrant
+
+ The \\nonreentrant command indicates that the associated class or
+ function cannot be called by multiple threads. Nonreentrant is the
+ default case.
+
+ The command must stand on its own line.
+
+ When a class is marked \l {reentrant-command} {\\reentrant} or \l
+ {threadsafe-command} {\\threadsafe}, functions in that class can
+ be marked \c nonreentrant using this command in the \l{fn-command}
+ {\\fn} comment of the functions to be excluded.
+
+ See also \l{reentrant-command} {\\reentrant} and
+ \l{threadsafe-command} {\\threadsafe}.
+*/
+
+/*!
+ \page 18-qdoc-commands-relating.html
+ \previouspage Thread Support
+ \contentspage Table of Contents
+ \nextpage Grouping Things
+
+ \title Relating Things
+
+ The relating commands are for specifying how one documented
+ element relates to another documented element. e.g., This function
+ is an overload of another function, or this function is a
+ reimplementation of another function, or this typedef is \e
+ related to some class or header file. There is also a command
+ for documenting that a QML element inherits some other QML
+ element.
+
+ \section1 Commands
+
+ \target inherits-command
+ \section2 \\inherits
+
+ The \\inherits command is for documenting that one QML element
+ inherits some other QML element. It must be included in the
+ inheriting element's \l{qmlclass-command}{\\qmlclass} comment.
+ The argument is the name of the inherited QML element.
+
+ \code
+ / *!
+ \qmlclass PauseAnimation QQuickPauseAnimation
+ \ingroup qml-animation-transition
+ \since 4.7
+ \inherits Animation
+ \brief The PauseAnimation element provides a pause for an animation.
+
+ When used in a SequentialAnimation, PauseAnimation is a step
+ when nothing happens, for a specified duration.
+
+ A 500ms animation sequence, with a 100ms pause between two animations:
+
+ SequentialAnimation {
+ NumberAnimation { ... duration: 200 }
+ PauseAnimation { duration: 100 }
+ NumberAnimation { ... duration: 200 }
+ }
+
+ \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}
+ * /
+ \endcode
+
+ QDoc includes this line on the reference page for the
+ \l{http://doc.qt.nokia.com/4.7/qml-pauseanimation.html} {PauseAnimation}
+ element:
+
+ \quotation
+ Inherits \l{http://doc.qt.nokia.com/4.7/qml-animation.html} {Animation}
+ \endquotation
+
+ \target overload-command
+ \section2 \\overload
+
+ The \\overload command is for indicating that a function is a
+ secondary overload of its name.
+
+ The command must stand on its own line.
+
+ For a function name that is overloaded (except constructors), QDoc
+ expects one primary version of the function, and all the others
+ marked with the \bold {\\overload command}. The primary version
+ should be fully documented. Each overload can have whatever extra
+ documentation you want to add for just that overloaded version.
+
+ From Qt 4.5, you can include the function name plus '()' as a
+ parameter to the \bold{\\overload} command, which will include a
+ standard \e{This function overloads...} line of text with a link
+ to the documentation for the primary version of the function.
+
+ \code
+ / *!
+ \overload addAction()
+
+ This convenience function creates a new action with an
+ \a icon and some \a text. The function adds the newly
+ created action to the menu's list of actions, and
+ returns it.
+
+ \sa QWidget::addAction()
+ * /
+ QAction *QMenu::addAction(const QIcon &icon, const QString &text)
+ {
+ QAction *ret = new QAction(icon, text, this);
+ addAction(ret);
+ return ret;
+ }
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \raw HTML
+ <h3><a href="http://qt.nokia.com/doc/4.0/qaction.html">QAction</a>
+ * QMenu::addAction ( const QIcon & <i>icon</i>,
+ const QString & <i>text</i> )
+ </h3>
+ \endraw
+
+ This function overloads \l {http://qt.nokia.com/doc/4.0/qwidget.html#addAction} {addAction()}
+
+ This convenience function creates a new action with an
+ \e icon and some \e text. The function adds the newly
+ created action to the menu's list of actions, and
+ returns it.
+
+ See also
+ \l {http://qt.nokia.com/doc/4.0/qwidget.html#addAction}
+ {QWidget::addAction}().
+ \endquotation
+
+ If you don't include the function name with the \bold{\\overlaod}
+ command, then instead of the "This function overloads..." line
+ with the link to the documentation for the primary version, you
+ get the old standard line:
+
+ \quotation
+ This is an overloaded member function, provided for
+ convenience.
+ \endquotation.
+
+ \target reimp-command
+ \section2 \\reimp
+
+ The \\reimp command is for indicating that a function is a
+ reimplementation of a virtual function.
+
+ The command must stand on its own line.
+
+ QDoc will omit the reimplemented function from the class
+ reference.
+
+ \code
+ / *!
+ \reimp
+ * /
+ void QToolButton::nextCheckState()
+ {
+ Q_D(QToolButton);
+ if (!d->defaultAction)
+ QAbstractButton::nextCheckState();
+ else
+ d->defaultAction->trigger();
+ }
+ \endcode
+
+ This function will not be included in the documentation. Instead,
+ a link to the base function QAbstractButton::nextCheckState() will
+ appear in the documentation.
+
+ \target relates-command
+ \section2 \\relates
+
+ The \\relates command is for including the documentation of a
+ global element to some class or header file. The argument is a
+ class name or header file.
+
+ \code
+ / *!
+ \relates QChar
+
+ Reads a char from the stream \a in into char \a chr.
+
+ \sa {Format of the QDataStream operators}
+ * /
+ QDataStream &operator>>(QDataStream &in, QChar &chr)
+ {
+ quint16 u;
+ in >> u;
+ chr.unicode() = ushort(u);
+ return in;
+ }
+ \endcode
+
+ The documentation for this function will be included on the reference page
+ for class QChra.
+*/
+
+/*!
+ \page 19-qdoc-commands-grouping.html
+ \previouspage Relating Things
+ \contentspage Table of Contents
+ \nextpage Naming Things
+
+ \title Grouping Things
+
+ The grouping commands relate classes to defined groups and
+ modules. The groups are used when generating lists of related
+ classes in the documentation, while the modules are elements of
+ Qt's structure.
+
+ \section1 Commands
+
+ \target mainclass-command
+ \section2 \\mainclass
+
+ The \\mainclass command relates the documented class to
+ a group called mainclasses.
+
+ The command must stand on its own line.
+
+ \code
+ / *!
+ \class QWidget qwidget.h
+ \brief The QWidget class is the base class of
+ all user interface objects.
+
+ \mainclass
+
+ ...
+ * /
+ \endcode
+
+ This will include the QWidget class in the \e mainclasses
+ group, which means, for example, that the class will appear on the
+ list created by calling the \l {generatelist-command}
+ {\\generatelist} command with the \c mainclasses argument:
+
+ \l http://qt.nokia.com/doc/4.0/mainclasses.html
+
+ \note The Qt documentation no longer includes the \e mainclasses
+ page.
+
+ See also \l {generatelist-command} {\\generatelist}.
+
+ \target ingroup-command
+ \section2 \\ingroup
+
+ The \\ingroup command indicates that the given
+ overview or documented class belongs to a certain group of
+ related docmentation.
+
+ A class or overview may belong to many groups.
+
+ The \\ingroup command's argument is a group name, but note
+ that the command considers the rest of the line as part of
+ its argument. Make sure that the group name is followed by
+ a linebreak.
+
+ \code
+ / *!
+ \class QDir
+ \brief The QDir class provides access to directory
+ structures and their contents.
+
+ \ingroup io
+ ...
+ * /
+ \endcode
+
+ This will include the QDir class in the \c io group, which means,
+ for example, that QDir will appear on the list created by calling
+ the \l {group-command} {\\group} command with the \c io argument.
+
+ To list overviews that are related to a certain group, you must
+ generate the list explicitly using the \l {generatelist-command}
+ {\\generatelist} command with the \c related argument.
+
+ See also \l {group-command} {\\group}.
+
+ \target inmodule-command
+ \section2 \\inmodule
+
+ The \\inmodule command relates a class to the module specified by
+ the command's argument.
+
+ For the basic classes in Qt, a class's module is determined by its
+ location, i.e. its directory. However, for extensions, like
+ ActiveQt and Qt Designer, a class must be related to a module
+ explicitly.
+
+ The command's argument is a module name, but note that the command
+ considers the rest of the line as part of its argument. Make sure
+ that the module name is followed by a linebreak.
+
+ \code
+ /*!
+ \class QDesignerTaskMenuExtension
+ \inmodule QtDesigner
+ * /
+ \endcode
+
+ This ensures that the QDesignerTaskMenuExtension class is included
+ in the \c QtDesigner module, which means, for example, that the
+ class will appear on the list created by calling the \l
+ {generatelist-command} {\\generatelist} command with the \c
+ {{classesbymodule QtDesigner}} argument.
+
+ See also \l {module-command} {\\module} and \l
+ {generatelist-command} {\\generatelist}.
+*/
+
+/*!
+ \page 20-qdoc-commands-namingthings.html
+ \previouspage Grouping Things
+ \contentspage Table of Contents
+ \nextpage Markup Commands
+
+ \title Naming Things
+
+ In general, a title command considers everything that follows it
+ until the first line break as its argument. If the title is so
+ long it must span multiple lines, end each line (except the last
+ one) with a backslash.
+
+ \section1 Commands
+
+ \target title-command
+ \section2 \\title
+
+ The \\title command sets the title for a documentation page, or
+ allows you to override it.
+
+ \code
+ / *!
+ \page signalandslots.html
+
+ \title Signals & Slots
+
+ Signals and slots are used for communication between
+ objects. The signals and slots mechanism is a central
+ feature of Qt and probably the part that differs most
+ from the features provided by other frameworks.
+
+ ...
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \raw HTML
+ <h1><center>Signal and Slots</center></h1>
+ \endraw
+
+ Signals and slots are used for communication between
+ objects. The signals and slots mechanism is a central
+ feature of Qt and probably the part that differs most
+ from the features provided by other frameworks.
+ ...
+ \endquotation
+ See also \l {subtitle-command} {\\subtitle}.
+
+ \target subtitle-command
+ \section2 \\subtitle
+
+ The \\subtitle command sets a subtitle for a documentation page.
+
+ \code
+ / *!
+ \page qtopiacore-overview.html
+
+ \title Qtopia Core
+ \subtitle Qt for Embedded Linux
+
+ Qt/Embedded, the embedded Linux port of Qt, is a
+ complete and self-contained C++ GUI and platform
+ development tool for Linux-based embedded development.
+ ...
+ * /
+ \endcode
+
+ QDoc renders this as:
+
+ \quotation
+ \raw HTML
+ <h1><center>Qtopia Core</center></h1>
+ <h2><center>Qt for Embedded Linux</center></h2>
+ \endraw
+
+ Qt/Embedded, the embedded Linux port of Qt, is a
+ complete and self-contained C++ GUI and platform
+ development tool for Linux-based embedded development.
+ ...
+ \endquotation
+
+ See also \l {title-command} {\\title}.
+
+*/
+
+/*!
+ \page 21-0-qdoc-configuration.html
+ \previouspage Miscellaneous
+ \contentspage Table of Contents
+ \nextpage Generic Configuration Variables
+
+ \title The QDoc Configuration File
+
+ Before running QDoc, you must create a QDoc configuration file to
+ tell QDoc where to find the source files that contain the QDoc
+ comments. The pathname to your configuration file is passed to
+ QDoc on the command line:
+
+ \quotation
+ \c {/current/dir$ ../../bin/qdoc3 ./config.qdocconf}
+ \endquotation
+
+ \section1 General Description
+
+ The configuration file is a list of entries of the form \e
+ {"variable = value"}. Using the configuration variables, you can
+ define where QDoc should find the various source files, images and
+ examples, where to put generated documentation etc. The
+ configuration file can also contain directives like \c
+ include. For an example, see the \l minimum.qdocconf file.
+
+ You can also use configuration variables to get QDoc to support
+ \l{Supporting Derived Projects} {derived projects}, i.e QDoc can
+ generate links in your project's documentation to elements in the
+ Qt online documentation. See the \l {Supporting Derived projects}
+ section.
+
+ The value of a configuration variable can be set using either '='
+ or '+='. The difference is that '=' overrides the previous value,
+ while '+=' adds a new value to the current one.
+
+ Some configuration variables accept a list of strings as their
+ value, e.g.
+ \l {22-qdoc-configuration-generalvariables.html#sourcedirs-variable}
+ {\c{sourcedirs}}, while others accept only a single string. Double
+ quotes around a value string are optional, but including them allows
+ you to use special characters like '=' and ' \" ' within the valuem
+ string, e.g.:
+
+ \code
+ HTML.postheader = "<a href=\"index.html\">Home</a>"
+ \endcode
+
+ If an entry spans many lines, use a backslash at the end of every
+ line but the last:
+
+ \code
+ sourcedirs = kernel \
+ tools \
+ widgets
+ \endcode
+
+ \section1 Configuration Variables
+
+ \section1 Variable List
+
+ \list
+ \o \l {22-qdoc-configuration-generalvariables.html#alias-variable} {alias}
+ \o \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoredirectives-variable} {Cpp.ignoredirectives}
+ \o \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoretokens-variable} {Cpp.ignoretokens}
+ \o \l {23-qdoc-configuration-cppvariables.html#basedir-variable} {basedir} \span {class="newStuff"} {(experimental)}
+ \o \l {22-qdoc-configuration-generalvariables.html#defines-variable} {defines}
+ \o \l {22-qdoc-configuration-generalvariables.html#edition-variable} {edition}
+ \o \l {22-qdoc-configuration-generalvariables.html#exampledirs-variable} {exampledirs}
+ \o \l {22-qdoc-configuration-generalvariables.html#examples-variable} {examples}
+ \o \l {22-qdoc-configuration-generalvariables.html#examples.fileextensions-variable} {examples.fileextensions}
+ \o \l {22-qdoc-configuration-generalvariables.html#excludedirs-variable} {excludedirs}
+ \o \l {22-qdoc-configuration-generalvariables.html#excludefiles-variable} {excludefiles}
+ \o \l {22-qdoc-configuration-generalvariables.html#extraimages-variable} {extraimages}
+ \o \l {22-qdoc-configuration-generalvariables.html#falsehoods-variable} {falsehoods}
+ \o \l {22-qdoc-configuration-generalvariables.html#headerdirs-variable} {headerdirs}
+ \o \l {22-qdoc-configuration-generalvariables.html#headers-variable} {headers}
+ \o \l {22-qdoc-configuration-generalvariables.html#headers.fileextensions-variable} {headers.fileextensions}
+ \o \l {24-qdoc-configuration-htmlvariables.html#HTML.footer-variable} {HTML.footer}
+ \o \l {24-qdoc-configuration-htmlvariables.html#HTML.postheader-variable} {HTML.postheader}
+ \o \l {24-qdoc-configuration-htmlvariables.html#HTML.style-variable} {HTML.style}
+ \o \l {22-qdoc-configuration-generalvariables.html#imagedirs-variable} {imagedirs}
+ \o \l {22-qdoc-configuration-generalvariables.html#images-variable} {images}
+ \o \l {22-qdoc-configuration-generalvariables.html#images.fileextensions-variable} {images.fileextensions}
+ \o \l {22-qdoc-configuration-generalvariables.html#language-variable} {language}
+ \o \l {22-qdoc-configuration-generalvariables.html#macro-variable} {macro}
+ \o \l {22-qdoc-configuration-generalvariables.html#outputdir-variable} {outputdir}
+ \o \l {22-qdoc-configuration-generalvariables.html#outputformats-variable} {outputformats}
+ \o \l {22-qdoc-configuration-generalvariables.html#sourcedirs-variable} {sourcedirs}
+ \o \l {22-qdoc-configuration-generalvariables.html#sources-variable} {sources}
+ \o \l {22-qdoc-configuration-generalvariables.html#sources.fileextensions-variable} {sources.fileextensions}
+ \o \l {22-qdoc-configuration-generalvariables.html#spurious-variable} {spurious}
+ \o \l {22-qdoc-configuration-generalvariables.html#tabsize-variable} {tabsize}
+ \o \l {22-qdoc-configuration-generalvariables.html#version-variable} {version}
+ \o \l {22-qdoc-configuration-generalvariables.html#versionsym-variable} {versionsym}
+ \endlist
+
+ \section1 Categories
+
+ \list
+ \o \l {Generic Configuration Variables}
+ \o \l {C++ Specific Configuration Variables}
+ \o \l {HTML Specific Configuration Variables}
+ \endlist
+
+ \section1 Configuration File Examples
+
+ \list
+ \o A minimum configuration file: \l minimum.qdocconf
+ \o The Qt configuration file: \l qt.qdocconf
+ \endlist
+*/
+
+/*!
+ \page 21-1-minimum-qdocconf.html
+ \previouspage qt.qdocconf
+ \contentspage Table of Contents
+ \nextpage Generating DITA XML Output
+
+ \title minimum.qdocconf
+
+ \quotefile examples/minimum.qdocconf
+*/
+
+/*!
+ \page 21-2-qt-qdocconf.html
+ \previouspage Compatibility Issues
+ \contentspage Table of Contents
+ \nextpage minimum.qdocconf
+
+ \title qt.qdocconf
+
+ \quotefile files/qt.qdocconf
+*/
+
+/*!
+ \page 21-3-qt-dita-xml-output.html
+ \previouspage minimum.qdocconf
+ \contentspage Table of Contents
+ \nextpage Table of Contents
+
+ \title Generating DITA XML Output
+
+ QDoc can generate \l {http://dita.xml.org} {DITA XML output}.
+
+ In your confifiguration file, set your \c {outputformats} variable
+ to \c {DITAXML}, and send the output to an appropriate directory:
+
+ \code
+ outputdir = $QTDIR/doc/ditaxml
+ outputformats = DITAXML
+ \endcode
+
+ And include these macros in your configuration file to prevent
+ QDoc from doing some escaping that doesn't validate in XML:
+
+ \code
+ macro.aacute.DITAXML = "&aacute;"
+ macro.Aring.DITAXML = "&Aring;"
+ macro.aring.DITAXML = "&aring;"
+ macro.Auml.DITAXML = "&Auml;"
+ macro.br.DITAXML = " "
+ macro.BR.DITAXML = " "
+ macro.copyright.DITAXML = "&copy;"
+ macro.eacute.DITAXML = "&eacute;"
+ macro.hr.DITAXML = " "
+ macro.iacute.DITAXML = "&iacute;"
+ macro.oslash.DITAXML = "&oslash;"
+ macro.ouml.DITAXML = "&ouml;"
+ macro.raisedaster.DITAXML = "<sup>*</sup>"
+ macro.rarrow.DITAXML = "&rarr;"
+ macro.reg.DITAXML = "<sup>&reg;</sup>"
+ macro.uuml.DITAXML = "&uuml;"
+ macro.mdash.DITAXML = "&mdash;"
+ macro.emptyspan.DITAXML = " "
+ \endcode
+
+ You can also set default values for some of the tags in the DITA
+ \c {<prolog>} and \c {<metadata>} elements:
+
+ \code
+ dita.metadata.default.author = Qt Development Frameworks
+ dita.metadata.default.permissions = all
+ dita.metadata.default.publisher = Nokia
+ dita.metadata.default.copyryear = 2011
+ dita.metadata.default.copyrholder = Nokia
+ dita.metadata.default.audience = programmer
+ \endcode
+
+ See the \l {12-0-qdoc-commands-miscellaneous.html#meta-command}
+ {\\meta} command for more details on DITA metadata.
+
+*/
+
+/*!
+ \page 22-qdoc-configuration-generalvariables.html
+ \previouspage The QDoc Configuration File
+ \contentspage Table of Contents
+ \nextpage Creating Help Project Files
+
+ \title Generic Configuration Variables
+
+ With the general QDoc configuration variables, you can define
+ where QDoc will find the various source files it needs to generate
+ the documentation, as well as the directory to put the generated
+ documentation. You can also do some minor manipulation of QDoc
+ itself, controlling its output and processing behavior.
+
+ \target alias-variable
+ \section1 alias
+
+ The \c alias variable renames a QDoc command.
+
+ The general syntax is \tt {alias.\e{original-command-name} = \e
+ temporary-command-name}.
+
+ \code
+ alias.i = e
+ \endcode
+
+ This renames the built-in command \\i (italics) to \\e. The \c
+ alias variable is often used for compatibility reasons; for more
+ information see the \l {Compatibility Issues} {compatibility
+ section}.
+
+ See also \l {macro-variable} {macro}.
+
+ \target codeindent-variable
+ \section1 codeindent
+
+ The \c codeindent variable specifies the level of indentation that
+ QDoc uses when writing code snippets.
+
+ QDoc originally used a hard-coded value of four spaces for code
+ indentation to ensure that code snippets could be easily
+ distinguished from surrounding text. Since we can use \l{HTML
+ Specific Configuration Variables#HTML.stylesheets} {stylesheets}
+ to adjust the appearance of certain types of HTML elements, this
+ level of indentation is not always required.
+
+ \target basedir-variable \span {class="newStuff"} {(experimental)}
+ \section1 basedir
+
+ The \c basedir variable tells QDoc two things. First, the fact that
+ it is set it tells QDoc to the put the output files in subdirectories
+ of the output directory. Second, the value of basedir is the name of
+ the bundle directory for your project. .e.g. if you are working with
+ the Qt5 bundle, you will have checked out the bundle into some root
+ subdirectory (the base directory), and that root directory might
+ very well be \e {qt5}
+
+ Then in your qdocconf file, you would assign to the basedir variable:
+
+ \code
+ basedir = qt5
+ \endcode
+
+ Now, QDoc knows to scan the file path of each source file it parses,
+ looking for \e qt5. For example, this file would be:
+
+ \code
+ ~/depot/qt5/qtdoc/tools/qdoc3/doc/qdoc-manual.qdoc
+ \endcode
+
+ QDoc scans the path for the basedir \e{qt5} and the next subdirectory
+ \e{qtdoc} becomes one of the subdirectories in the output directory.
+ The HTML output file created from this file will be stored in the
+ \e{qtdoc} subdirectory.
+
+ \note This is an experimental command. It is currently used only by
+ the Qt documentation group. If you use it, be advised that you might
+ find some broken links in your HTML output due to remaining problems
+ with cross-subdirectory linking.
+
+ \target defines-variable
+ \section1 defines
+
+ The \c defines variable specifies the C++ preprocessor symbols
+ that QDoc will recognize and respond to.
+
+ When a preprocessor symbol is specified using the \c defines
+ variable, you can also use the \l {if-command} {\\if} command to
+ enclose documentation that only will be included if the
+ preprocessor symbol is defined.
+
+ The values of the variable are regular expressions (see QRegExp
+ for details). By default, no symbol is defined, meaning that code
+ protected with #ifdef...#endif will be ignored.
+
+ \code
+ defines = Q_QDOC \
+ QT_.*_SUPPORT \
+ QT_.*_LIB \
+ QT_COMPAT \
+ QT3_SUPPORT \
+ Q_WS_.* \
+ Q_OS_.* \
+ Q_BYTE_ORDER \
+ __cplusplus
+ \endcode
+
+ This ensures that QDoc will process the code that requires these
+ symbols to be defined. For example:
+
+ \code
+ #ifdef Q_WS_WIN
+ HDC getDC() const;
+ void releaseDC(HDC) const;
+ #endif
+ \endcode
+
+ Since the Q_WS_.* regular expression (specified using the \c
+ defines variable) matches Q_WS_WIN, QDoc will process the code
+ within #ifdef and #endif in our example.
+
+ You can also define preprocessor symbols manually on the command
+ line using the -D option. For example:
+
+ \code
+ currentdirectory$ qdoc3 -Dconsoleedition qt.qdocconf
+ \endcode
+
+ In this case the -D option ensures that the \c consoleedition
+ preprocessor symbol is defined when QDoc processes the source
+ files defined in the qt.qdocconf file.
+
+ See also \l {falsehoods-variable} {falsehoods} and \l {if-command} {\\if}.
+
+ \target edition-variable
+ \section1 edition
+
+ The \c edition variable specifies which modules are included in
+ each edition of a package, and provides QDoc with information to
+ provide class lists for each edition.
+
+ This feature is mostly used when providing documentation for Qt
+ packages.
+
+ The \c edition variable is always used with a particular edition
+ name to define the modules for that edition:
+
+ \code
+ edition.Console = QtCore QtNetwork QtSql QtXml
+ edition.Desktop = QtCore QtGui QtNetwork QtOpenGL QtSql QtXml \
+ QtDesigner QtAssistant Qt3Support QAxContainer \
+ QAxServer
+ edition.DesktopLight = QtCore QtGui Qt3SupportLight
+ \endcode
+
+ In the above examples, the \c Console edition only includes the
+ contents of four modules. Only the classes from these modules will
+ be used when the \l{Miscellaneous#generatelist-command}
+ {generatelist} command is used to generate a list of classes for
+ this edition:
+
+ \code
+ \generatelist{classesbyedition Console}
+ \endcode
+
+ \target exampledirs-variable
+ \section1 exampledirs
+
+ The \c exampledirs variable specifies the directories containing
+ the source code of the example files.
+
+ The \l {examples-variable} {examples} {examples} and \l
+ {exampledirs-variable} {exampledirs} variables are used by the \l
+ {quotefromfile-command} {\\quotefromfile}, \l {quotefile-command}
+ {\\quotefile} and \l {example-command} {\\example} commands. If
+ both the \l {examples-variable} {examples} and \l
+ {exampledirs-variable} {exampledirs} variables are defined, QDoc
+ will search in both, first in \l {examples-variable} {examples}
+ then in \l {exampledirs-variable} {exampledirs}.
+
+ QDoc will search through the directories in the specified order,
+ and accept the first matching file it finds. It will only search
+ in the specified directories, \e not in subdirectories.
+
+ \code
+ exampledirs = $QTDIR/doc/src \
+ $QTDIR/examples \
+ $QTDIR \
+ $QTDIR/qmake/examples
+
+ examples = $QTDIR/examples/widgets/analogclock/analogclock.cpp
+ \endcode
+
+ When processing
+
+ \code
+ \quotefromfile widgets/calculator/calculator.cpp
+ \endcode
+
+ QDoc will then see if there exists a file called \c calculator.cpp
+ listed as a value in the \l {examples} {\c examples} variable. If
+ it doesn't, it will search in the \c exampledirs variable, and
+ first see if there exists a file called
+
+ \code
+ $QTDIR/doc/src/widgets/calculator/calculator.cpp
+ \endcode
+
+ If it doesn't, QDoc will continue looking for a file called
+
+ \code
+ $QTDIR/examples/widgets/calculator/calculator.cpp
+ \endcode
+
+ and so forth.
+
+ See also \l examples.
+
+ \target examples-variable
+ \section1 examples
+
+ The \c examples variable allows you to specify individual example
+ files in addition to those located in the directories specified by
+ the \l {exampledirs-variable} {\c exampledirs} variable.
+
+ The \c examples and \l {exampledirs-variable} {\c exampledirs}
+ variables are used by the \l {quotefromfile-command}
+ {\\quotefromfile}, \l {quotefile-command} {\\quotefile} and \l
+ {example} {\\example} commands. If both the \c examples and \l
+ {exampledirs-variable} {\c exampledirs} variables are defined,
+ QDoc will search in both, first in \c examples then in \l
+ {exampledirs-variable} {\c exampledirs}.
+
+ QDoc will search through the values listed for the \c examples
+ variable, in the specified order, and accept the first one it
+ finds.
+
+ For an extensive example, see the \l {exampledirs-variable} {\c
+ exampledirs} command. But note that if you know the file is listed
+ in the \c examples variable, you don't need to specify its path:
+
+ \code
+ \quotefromfile calculator.cpp
+ \endcode
+
+ See also \l {exampledirs-variable} {exampledirs}.
+
+ \target examples.fileextensions-variable
+ \section1 examples.fileextensions
+
+ The \c examples.fileextensions variable specifies the file
+ extensions that qdoc will look for when collecting example files
+ for display in the documentation.
+
+ The default extensions are *.cpp, *.h, *.js, *.xq, *.svg, *.xml
+ and *.ui.
+
+ The extensions are given as standard wildcard expressions. You
+ can add a file extension to the filter using '+='. For example:
+
+ \code
+ examples.fileextensions += *.qrc
+ \endcode
+
+ See also \l{headers.fileextensions}.
+
+ \target excludedirs-variable
+ \section1 excludedirs
+
+ The \c excludedirs variable is for listing directories that should \e{not}
+ be processed by qdoc, even if the same directories are included by the
+ \l {sourcedirs-variable} {sourcedirs} or \l {headerdirs-variable} {headerdirs}
+ variables.
+
+ For example in \l qt.qdocconf
+
+ \code
+ excludedirs = $QTDIR/extensions/activeqt \
+ $QTDIR/extensions/motif \
+ $QTDIR/tools/designer/src/lib/extension \
+ $QTDIR/tools/designer/src/lib/sdk \
+ $QTDIR/tools/designer/src/lib/uilib
+ \endcode
+
+ When executed, QDoc will exclude the listed directories from
+ further consideration. Files in these directories will not be
+ read by qdoc.
+
+ See also \l {excludefiles-variable} {excludefiles}.
+
+ \target excludefiles-variable
+ \section1 excludefiles
+
+ The \c excludefiles variable allows you to specify individual files
+ that should \e{not} be processed by qdoc.
+
+ \code
+ excludefiles += $QT_CORE_SOURCES/../../src/widgets/kernel/qwidget.h \
+ $QT_CORE_SOURCES/../../src/widgets/kernel/qwidget.cpp
+ \endcode
+
+ If you include the above in your qdocconf file for qtbase, there
+ will be no qwidget.html generated for html and no qwidget.xml
+ generated for DITA XML.
+
+ See also \l {excludedirs-variable} {excludedirs}.
+
+ \target extraimages-variable
+ \section1 extraimages
+
+ The \c extraimages variable tells QDoc to incorporate specific
+ images in the generated documentation.
+
+ QDoc will not recognize images used within HTML (or any other
+ markup language). If we want the images to be copied from the
+ directories specified by \l {imagedirs} {\c imagedirs} (the images
+ in question must be located in these directories) to the output
+ directory, we must specify the images using the \c extraimages
+ variable.
+
+ The general syntax is \tt {extraimages.\e{format} = \e image}. The
+ file extension is optional.
+
+ For example, in \l qt.qdocconf we use a couple of images within
+ the HTML.postheader variable which value is pure HTML. For that
+ reason, these images are specified using the \c extraimages
+ variable:
+
+ \code
+ extraimages.HTML = qt-logo
+ \endcode
+
+ See also \l images and \l imagedirs.
+
+ \target falsehoods-variable
+ \section1 falsehoods
+
+ The \c falsehoods variable defines the truth value of specified
+ preprocessor symbols as false.
+
+ If this variable is not set for a preprocessor symbol, QDoc
+ assumes its truth value is true. The exception is '0', which value
+ always is false.
+
+ QDoc will recognize, and is able to evaluate, the following
+ preprocessor syntax:
+
+ \code
+ #ifdef NOTYET
+ ...
+ #endif
+
+ #if defined (NOTYET)
+ ...
+ #end if
+ \endcode
+
+ However, faced with unknown syntax like
+
+ \code
+ #if NOTYET
+ ...
+ #endif
+ \endcode
+
+ QDoc will evaluate it as true by default, \e unless the
+ preprocessor symbol is specified within the \c falsehoods variable
+ entry:
+
+ \code
+ falsehoods = NOTYET
+ \endcode
+
+ See also \l defines.
+
+ \target generateindex-variable
+ \section1 generateindex
+
+ The \c generateindex variable contains a boolean value that
+ specifies whether to generate an index file when HTML
+ documentation is generated.
+
+ By default, an index file is always generated with HTML
+ documentation, so this variable is typically only used when
+ disabling this feature (by setting the value to \c false) or when
+ enabling index generation for the WebXML output (by setting the
+ value to \c true).
+
+ \target headerdirs-variable
+ \section1 headerdirs
+
+ The \c headerdirs variable specifies the directories containing
+ the header files associated with the \c .cpp source files used in
+ the documentation.
+
+ \code
+ headerdirs = $QTDIR/src \
+ $QTDIR/extensions/activeqt \
+ $QTDIR/extensions/motif \
+ $QTDIR/tools/designer/src/lib/extension \
+ $QTDIR/tools/designer/src/lib/sdk \
+ $QTDIR/tools/designer/src/lib/uilib
+ \endcode
+
+ When executed, the first thing QDoc will do is to read through the
+ headers specified in the \l {headers} {\c headers} variable, and
+ the ones located in the directories specified in the \c headerdir
+ variable (including all subdirectories), building an internal
+ structure of the classes and their functions.
+
+ Then it will read through the sources specified in the \l
+ {sources-variable} {\c sources}, and the ones located in the
+ directories specified in the \l {sourcedirs-variable} {\c
+ sourcedirs} varible (including all subdirectories), merging the
+ documentation with the structure it retrieved from the header
+ files.
+
+ If both the \c headers and \c headerdirs variables are defined,
+ QDoc will read through both, first \l {headers} {\c headers} then
+ \c headerdirs.
+
+ In the specified directories, QDoc will only read the files with
+ the fileextensions specified in the \l {headers.fileextensions}
+ {\c headers.fileextensions} variable. The default extensions are
+ *.ch, *.h, *.h++, *.hh, *.hpp and *.hxx". The files specified by
+ \l {headers} {\c headers} will be read independent of their
+ fileextensions.
+
+ See also \l headers and \l headers.fileextensions.
+
+ \target headers-variable
+ \section1 headers
+
+ The \c headers variable allows you to specify individual header
+ files in addition to those located in the directories specified by
+ the \l {headerdirs} {\c headerdirs} variable.
+
+ \code
+ headers = $QTDIR/src/gui/widgets/qlineedit.h \
+ $QTDIR/src/gui/widgets/qpushbutton.h
+ \endcode
+
+ When processing the \c headers variable, QDoc behaves in the same
+ way as it does when processing the \l {headerdirs} {\c headerdirs}
+ variable. For more information, see the \l {headerdirs} {\c
+ headerdirs} variable.
+
+ See also \l headerdirs.
+
+ \target headers.fileextensions-variable
+ \section1 headers.fileextensions
+
+ The \c headers.fileextensions variable specify the extension used
+ by the headers.
+
+ When processing the header files specified in the \l {headerdirs}
+ {\c headerdirs} variable, QDoc will only read the files with the
+ fileextensions specified in the \c headers.fileextensions
+ variable. In this way QDoc avoid spending time reading irrelevant
+ files.
+
+ The default extensions are *.ch, *.h, *.h++, *.hh, *.hpp and
+ *.hxx.
+
+ The extensions are given as standard wildcard expressions. You
+ can add a file extension to the filter using '+='. For example:
+
+ \code
+ header.fileextensions += *.H
+ \endcode
+
+ \warning The above assignment may not work as described.
+
+ See also \l headerdirs.
+
+ \target imagedirs-variable
+ \section1 imagedirs
+
+ The \c imagedirs variable specifies the directories containing the
+ images used in the documentation.
+
+ The \l {images} {\c images} and \c imagedirs variables are used by
+ the \l {image-command} {\\image} and \l {inlineimage-command}
+ {\\inlineimage} commands. If both the \l {images} {\c images} and
+ \c imagedirs variables are defined, QDoc will search in both,
+ first in \l {images} {\c images} then in \c imagedirs.
+
+ QDoc will search through the directories in the specified order,
+ and accept the first matching file it finds. It will only search
+ in the specified directories, \e not in subdirectories.
+
+ \code
+ imagedirs = $QTDIR/doc/src/images \
+ $QTDIR/examples
+
+ images = $QTDIR/doc/src/images/calculator-example.png
+ \endcode
+
+ When processing
+
+ \code
+ \image calculator-example.png
+ \endcode
+
+ QDoc will then see if there exists a file called
+ calculator-example.png listed as a value in the \c images
+ variable. If it doesn't, it will search in the \c imagedirs
+ variable, and first see if there exists a file called
+
+ \code
+ $QTDIR/doc/src/images/calculator-example.png
+ \endcode
+
+ If it doesn't, QDoc will look for a file called
+
+ \code
+ $QTDIR/examples/calculator-example.png
+ \endcode
+
+ You can filter the images in an image directory using the \l
+ {images.fileextensions} {\c images.fileextensions} variable. The
+ general idea behind the \l {images.fileextensions} {\c images.fileextensions}
+ variable is to enable different image format for different output format.
+
+ \warning The \l {images.fileextensions} {\c images.fileextensions}
+ variable's functionality is preliminay since QDoc at this point
+ only support HTML.
+
+ See also \l images and \l images.fileextensions.
+
+ \target images-variable
+ \section1 images
+
+ The \c images variable allows you to specify individual image
+ files in addition to those located in the directories specified by
+ the \l {imagedirs} {\c imagedirs} variable.
+
+ \code
+ images = $QTDIR/doc/src/images/calculator-example.png
+ \endcode
+
+ When processing the \c images variable, QDoc behaves in the same
+ way as it does when processing the \l {imagedirs} {\c imagedirs}
+ variable. For more information, see the \l {imagedirs} {\c
+ imagedirs} variable.
+
+ See also \l imagedirs and \l images.fileextensions.
+
+ \target images.fileextensions-variable
+ \section1 images.fileextensions
+
+ The images.fileextensions variable filters the files within an
+ image directory.
+
+ The variable's values (the extensions) are given as standard
+ wildcard expressions. The general syntax is: \tt
+ {images.fileextensions.\e{format} = *.\e{extension}}.
+
+ The idea is to enable different image format for different output
+ format.
+
+ \code
+ images.fileextensions.HTML = *.png
+ images.fileextensions.LOUT = *.eps
+ \endcode
+
+ Then, when processing the \l {image-command} {\\image} and \l
+ {inlineimage-command} {\\inlineimage} commands, QDoc will only
+ search for files with extensions specified in the output format's
+ associated image extension variable.
+
+ \warning This is preliminary functionality since QDoc at this
+ point only support HTML.
+
+ The default extensions for HTML are *.png, *.jpg, *.jpeg and
+ *.gif.
+
+ You can add a file extension to the filter using '+='. For
+ example:
+
+ \code
+ images.fileextensions.HTML += *.eps
+ \endcode
+
+ See also \l imagedirs and \l images.
+
+ \target language-variable
+ \section1 language
+
+ The \c language variable specifies the language of the source code
+ that is used in the documentation.
+
+ Currently, C++ is the only language that QDoc understands. It is
+ also the default language, and doesn't really need to be
+ specified. But for example in \l qt.qdocconf:
+
+ \code
+ language = Cpp
+ \endcode
+
+ identifies the language of the Qt source code as C++.
+
+ \target macro-variable
+ \section1 macro
+
+ The \c macro variable is used to create your own simple QDoc
+ commands. The syntax is \tt {macro.\e{command} = \e{definition}},
+ where the definition is written using QDoc syntax.
+
+ A macro variable can be restricted for use in one type of output
+ generation. By appending \c {.HTML} to the macro name, for
+ example, the macro is only used when generating HTML output. By
+ appending \c {.DITAXML} to the macro name, the macro is only used
+ when generating DITA XML.
+
+ \code
+ macro.gui = "\\bold"
+ macro.raisedaster.HTML = "<sup>*</sup>"
+ \endcode
+
+ The first macro defines the \\gui command to render its argument
+ using a bold font. The second macro defines the \\raisedaster
+ command to render a superscript asterisk, but only when generating
+ HTML.
+
+ See also \l {alias-variable} {alias}.
+
+ \target naturallanguage-variable
+ \section1 naturallanguage
+
+ The \c naturallanguage variable specifies the natural language
+ used for the documentation generated by qdoc.
+
+ \code
+ naturallanguage = zh-Hans
+ \endcode
+
+ By default, the natural language is \c en for compatibility with
+ legacy documentation.
+
+ qdoc will add the natural language information to the HTML it
+ generates, using the \c lang and \c xml:lang attributes.
+
+ See also \l {sourceencoding-variable} {sourceencoding},
+ \l {outputencoding-variable} {outputencoding},
+ \l{http://www.w3.org/TR/xhtml1/#C_7}
+ {C.7. The lang and xml:lang Attributes} and
+ \l{http://www.w3.org/TR/i18n-html-tech-lang/#ri20040429.113217290}
+ {Best Practice 13: Using Hans and Hant codes}.
+
+ \target outputdir-variable
+ \section1 outputdir
+
+ The \c outputdir variable specifies the directory where QDoc will
+ put the generated documentation.
+
+ In qt.qdocconf:
+
+ \code
+ outputdir = $QTDIR/doc/html
+ \endcode
+
+ locates the generated Qt reference documentation in
+ $QTDIR/doc/html. For example, the documentation of the QWidget
+ class is located in
+
+ \code
+ $QTDIR/doc/html/qwidget.html
+ \endcode
+
+ The associated images will be put in an \c images subdirectory.
+
+ \warning When running QDoc multiple times using the same output
+ directory, all files from the previous run will be lost.
+
+ \target outputencoding-variable
+ \section1 outputencoding
+
+ The \c outputencoding variable specifies the encoding used for the
+ documentation generated by qdoc.
+
+ \code
+ outputencoding = UTF-8
+ \endcode
+
+ By default, the output encoding is \c ISO-8859-1 (Latin1) for
+ compatibility with legacy documentation. When generating
+ documentation for some languages, particularly non-European
+ languages, this is not sufficient and an encoding such as UTF-8 is
+ required.
+
+ qdoc will encode HTML using this encoding and generate the correct
+ declarations to indicate to browsers which encoding is being
+ used. The \l naturallanguage configuration variable should also be
+ specified to provide browsers with a complete set of character
+ encoding and language information.
+
+ See also \l outputencoding and \l naturallanguage.
+
+ \target outputformats-variable
+ \section1 outputformats
+
+ The \c outputformats variable specifies the format of
+ the generated documentation.
+
+ Currently, QDoc only supports the HTML format. It is also
+ the default format, and doesn't need to be specified.
+
+ \target outputprefixes
+ \section1 outputprefixes
+
+ The \c outputprefixes variable specifies a mapping between types of files
+ and the prefixes to prepend to the HTML file names in the generated
+ documentation.
+
+ \code
+ outputprefixes = QML
+ outputprefixes.QML = qt-components-
+ \endcode
+
+ By default, files containing the API documentation for QML elements
+ or components are prefixed with "qml-". In the above example, the
+ prefix "qt-components-" is used instead.
+
+ \target qhp-variable
+ \section1 qhp
+
+ The \c qhp variable is used to define the information to be
+ written out to Qt Help Project (\c{qhp}) files.
+
+ See the \l{Creating Help Project Files} chapter for information
+ about this process.
+
+ \target sourcedirs-variable
+ \section1 sourcedirs
+
+ The \c sourcedirs variable specifies the directories containing
+ the \c .cpp or \c .qdoc files used in the documentation.
+
+ For example in \l qt.qdocconf
+
+ \code
+ sourcedirs = $QTDIR/src \
+ $QTDIR/doc/src \
+ $QTDIR/extensions/activeqt \
+ $QTDIR/extensions/motif \
+ $QTDIR/tools/designer/src/lib/extension \
+ $QTDIR/tools/designer/src/lib/sdk \
+ $QTDIR/tools/designer/src/lib/uilib
+ \endcode
+
+ When executed, the first thing QDoc will do is to read through the
+ headers specified in the \l {header-command} {\c header} variable,
+ and the ones located in the directories specified in the \c
+ headerdir variable (including all subdirectories), building an
+ internal structure of the classes and their functions.
+
+ Then it will read through the sources specified in the \l
+ {sources} {\c sources}, and the ones located in the directories
+ specified in the \l {sourcedirs} {\c sourcedirs} varible
+ (including all subdirectories), merging the documentation with the
+ structure it retrieved from the header files.
+
+ If both the \c sources and \c sourcedirs variables are defined,
+ QDoc will read through both, first \l {sources} {\c sources} then
+ \c sourcedirs.
+
+ In the specified directories, QDoc will only read the files with
+ the fileextensions specified in the \l {sources.fileextensions}
+ {\c sources.fileextensions} variable. The default extensions are
+ *.c++, *.cc, *.cpp and *.cxx. The files specified by \l {sources}
+ {\c sources} will be read independent of their fileextensions.
+
+ See also \l {sources-variable} {sources} and
+ \l {sources.fileextensions-variable} {sources.fileextensions}.
+
+ \target sourceencoding-variable
+ \section1 sourceencoding
+
+ The \c sourceencoding variable specifies the encoding used for the
+ source code and documentation.
+
+ \code
+ sourceencoding = UTF-8
+ \endcode
+
+ By default, the source encoding is \c ISO-8859-1 (Latin1) for
+ compatibility with legacy documentation. For some languages,
+ particularly non-European languages, this is not sufficient and an
+ encoding such as UTF-8 is required.
+
+ Although qdoc will use the encoding to read source and
+ documentation files, limitations of C++ compilers may prevent you
+ from using non-ASCII characters in source code comments. In cases
+ like these, it is possible to write API documentation completely
+ in documentation files.
+
+ See also \l {naturallanguage-variable} {naturallanguage} and
+ \l {outputencoding-variable} {outputencoding}.
+
+ \target sources-variable
+ \section1 sources
+
+ The \c sources variable allows you to specify individual source
+ files in addition to those located in the directories specified by
+ the \l {sourcedirs-variable} {sourcedirs} variable.
+
+ \code
+ sources = $QTDIR/src/gui/widgets/qlineedit.cpp \
+ $QTDIR/src/gui/widgets/qpushbutton.cpp
+ \endcode
+
+ When processing the \c sources variable, QDoc behaves in the same
+ way as it does when processing the \l {sourcedirs-variable}
+ {sourcedirs} variable. For more information, see the \l
+ {sourcedirs-variable} {sourcedirs} variable.
+
+ See also \l {sourcedirs-variable} {sourcedirs}.
+
+ \target sources.fileextensions-variable
+ \section1 sources.fileextensions
+
+ The \c sources.fileextensions variable filters the files within a
+ source directory.
+
+ When processing the source files specified in the \l {sourcedirs}
+ {\c sourcedirs} variable, QDoc will only read the files with the
+ fileextensions specified in the \c sources.fileextensions
+ variable. In this way QDoc avoid spending time reading irrelevant
+ files.
+
+ The default extensions are *.c++, *.cc, *.cpp and *.cxx.
+
+ The extensions are given as standard wildcard expressions. You
+ can add a file extension to the filter using '+='. For example:
+
+ \code
+ sources.fileextensions += *.CC
+ \endcode
+
+ \warning The above assignment may not work as described.
+
+ See also \l {sourcedirs-variable} {sourcedirs} and \l
+ (sources-variable} {sources}.
+
+
+ \target spurious-variable
+ \section1 spurious
+
+ The \c spurious variable excludes specified QDoc warnings from the
+ output. The warnings are specified using standard wildcard
+ expressions.
+
+ \code
+ spurious = "Cannot find .*" \
+ "Missing .*"
+ \endcode
+
+ makes sure that warnings matching either of these expressions,
+ will not be part of the output when running QDoc. For example
+ would the following warning be omitted from the output:
+
+ \code
+ qt-4.0/src/opengl/qgl_mac.cpp:156: Missing parameter name
+ \endcode
+
+ \target syntaxhighlighting
+ \section1 syntaxhighlighting
+
+ The \c syntaxhighlighting variable specifies whether QDoc should
+ perform syntax highlighting on source code quoted in the
+ documentation it generates.
+
+ \code
+ syntaxhighlighting = true
+ \endcode
+
+ will enable syntax highlighting for all supported programming
+ languages.
+
+ \target tabsize-variable
+ \section1 tabsize
+
+ The \c tabsize variable defines the size of a tab character.
+
+ \code
+ tabsize = 4
+ \endcode
+
+ will give the tab character the size of 4 spaces. The default
+ value of the variable is 8, and doesn't need to be specified.
+
+ \target tagfile-variable
+ \section1 tagfile
+
+ The \c tagfile variable specifies the Doxygen tag file to be
+ written when HTML is generated.
+
+ \target version-variable
+ \section1 version
+
+ The \c version variable specifies the version number of the
+ documented software.
+
+ \code
+ version = 4.0.1
+ \endcode
+
+ When a version number is specified (using the \tt{\l version} or
+ \tt {\l versionsym} variables in a \c .qdocconf file), it is
+ accessible through the corresponding \\version command for use in
+ the documentation.
+
+ \warning The \\version command's functionality is not fully
+ implemented; currently it only works within raw HTML code.
+
+ See also \l versionsym.
+
+ \target versionsym-variable
+ \section1 versionsym
+
+ The \c versionsym variable specifies a C++ preprocessor symbol
+ that defines the version number of the documented software.
+
+ For example in \l qt.qdocconf:
+
+ \code
+ versionsym = QT_VERSION_STR
+ \endcode
+
+ QT_VERSION_STR is defined in qglobal.h as follows
+
+ \code
+ #define QT_VERSION_STR "4.0.1"
+ \endcode
+
+ When a version number is specified (using the \tt{\l version} or
+ \tt {\l versionsym} variables in a \c .qdocconf file), it is
+ accessible through the corresponding \\version command for use in
+ the documentation.
+
+ \warning The \\version command's functionality is not fully
+ implemented; currently it only works within raw HTML code.
+
+ See also \l {version} {\\version}.
+*/
+
+/*!
+ \page 22-creating-help-project-files.html
+ \previouspage Generic Configuration Variables
+ \contentspage Table of Contents
+ \nextpage C++ Specific Configuration Variables
+
+ \title Creating Help Project Files
+
+ \section1 Overview
+
+ Starting with Qt 4.4, Qt Assistant uses a different system for managing
+ Qt documentation that requires QDoc to generate inventories of files in a
+ format that is similar to the old style DCF format, but with additional
+ features.
+
+ Instead of hard-coding information about the documentation sets for Qt,
+ QDoc allows configuration variables to be used to specify which pages are
+ to be used in each documentation set it generates. These are specified as
+ subvariables of the \c qch variable with each set declared using a unique
+ identifier as a subvariable.
+
+ For example, the configuration file for the Qt documentation defines a
+ \c Qt documentation set by specifying information about the set as
+ subvariables with the \c{qhp.Qt} prefix:
+
+ \code
+ qhp.Qt.file = qt.qhp
+ qhp.Qt.namespace = com.trolltech.qt.440
+ qhp.Qt.virtualFolder = qdoc
+ qhp.Qt.indexTitle = Qt Reference Documentation
+ qhp.Qt.indexRoot =
+ qhp.Qt.extraFiles = classic.css images/qt-logo.png
+ qhp.Qt.filterAttributes = qt 4.4.0 qtrefdoc
+ qhp.Qt.customFilters.Qt.name = Qt 4.4.0
+ qhp.Qt.customFilters.Qt.filterAttributes = qt 4.4.0
+ qhp.Qt.subprojects = classes overviews examples
+ qhp.Qt.subprojects.classes.title = Classes
+ qhp.Qt.subprojects.classes.indexTitle = Qt's Classes
+ qhp.Qt.subprojects.classes.selectors = class
+ qhp.Qt.subprojects.overviews.title = Overviews
+ qhp.Qt.subprojects.overviews.indexTitle = All Overviews and HOWTOs
+ qhp.Qt.subprojects.overviews.selectors = fake:page,group,module
+ qhp.Qt.subprojects.examples.title = Tutorials and Examples
+ qhp.Qt.subprojects.examples.indexTitle = Qt Examples
+ qhp.Qt.subprojects.examples.selectors = fake:example
+ \endcode
+
+ To create a table of contents for a manual, create a subproject with
+ a \c{type} property and set it to \c{manual}. The page in the documentation
+ referred to by the \c{indexTitle} property must contain a list of links
+ that acts as a table of contents for the whole manual. QDoc will take the
+ information in this list and create a table of contents for the subproject.
+
+ For example, the configuration file for Qt Creator defines only one
+ subproject for its documentation, including all the documentation in a
+ single manual:
+
+ \code
+ qhp.QtCreator.subprojects = manual
+ qhp.QtCreator.subprojects.manual.title = Qt Creator Manual
+ qhp.QtCreator.subprojects.manual.indexTitle = Qt Creator Manual
+ qhp.QtCreator.subprojects.manual.type = manual
+ \endcode
+
+ In this example, the page entitled "Qt Creator Manual" contains a nested
+ list of links to pages in the documentation which is duplicated in
+ Qt Assistant's Contents tab.
+*/
+
+/*!
+ \page 23-qdoc-configuration-cppvariables.html
+ \previouspage Creating Help Project Files
+ \contentspage Table of Contents
+ \nextpage HTML Specific Configuration Variables
+
+ \title C++ Specific Configuration Variables
+
+ The C++ specific configuration variables are provided to avoid
+ erroneous documentation due to non-standard C++ constructs.
+
+ \target Cpp.ignoredirectives-variable
+ \section1 Cpp.ignoredirectives
+
+ The \c Cpp.ignoredirectives variable makes QDoc ignore the
+ specified non-standard constructs, within C++ source code.
+
+ If not specified by the \tt {\l Cpp.ignoretokens} or \tt {\l
+ Cpp.ignoredirectives} variables, non-standard constructs
+ (typically macros) can result in erroneous documentation.
+
+ In \l qt.qdocconf:
+
+ \code
+ Cpp.ignoredirectives = Q_DECLARE_INTERFACE \
+ Q_DECLARE_OPERATORS_FOR_FLAGS \
+ Q_DECLARE_PRIVATE \
+ Q_DECLARE_PUBLIC \
+ Q_DISABLE_COPY \
+ Q_DUMMY_COMPARISON_OPERATOR \
+ Q_ENUMS \
+ Q_FLAGS \
+ Q_INTERFACES \
+ __attribute__
+ \endcode
+
+ makes sure that when processing the code below, for example, QDoc
+ will simply ignore the 'Q_ENUMS' and 'Q_FLAGS' expressions:
+
+ \code
+ class Q_CORE_EXPORT Qt {
+ Q_OBJECT
+ Q_ENUMS(Orientation TextFormat BackgroundMode
+ DateFormat ScrollBarPolicy FocusPolicy
+ ContextMenuPolicy CaseSensitivity
+ LayoutDirection ArrowType)
+ Q_ENUMS(ToolButtonStyle)
+ Q_FLAGS(Alignment)
+ Q_FLAGS(Orientations)
+ Q_FLAGS(DockWidgetAreas)
+
+ public:
+ ...
+ };
+ \endcode
+
+ The Q_OBJECT macro, however, is an exception: QDoc recognizes this
+ particular non-standard construct, so there is no need specifying
+ it using the \tt {\l Cpp.ignoredirectives} variable.
+
+ Regarding the Q_CORE_EXPORT macro; see the documentation of the
+ \tt {\l Cpp.ignoretokens} variable.
+
+ See also \l Cpp.ignoretokens.
+
+ \target Cpp.ignoretokens-variable
+ \section1 Cpp.ignoretokens
+
+ The \c Cpp.ignoretokens variable makes QDoc ignore the specified
+ non-standard constructs, within C++ source code.
+
+ If not specified by the \tt {\l Cpp.ignoretokens} or \tt {\l
+ Cpp.ignoredirectives} variables, non-standard constructs
+ (typically macros) can result in erroneous documentation.
+
+ In \l qt.qdocconf:
+
+ \code
+ Cpp.ignoretokens = QAXFACTORY_EXPORT \
+ QM_EXPORT_CANVAS \
+ ...
+ Q_COMPAT_EXPORT \
+ Q_CORE_EXPORT \
+ Q_EXPLICIT \
+ Q_EXPORT \
+ ...
+ Q_XML_EXPORT
+ \endcode
+
+ makes sure that when processing the code below, for example, QDoc
+ will simply ignore the 'Q_CORE_EXPORT' expression:
+
+ \code
+ class Q_CORE_EXPORT Qt {
+ Q_OBJECT
+ Q_ENUMS(Orientation TextFormat BackgroundMode
+ DateFormat ScrollBarPolicy FocusPolicy
+ ContextMenuPolicy CaseSensitivity
+ LayoutDirection ArrowType)
+ Q_ENUMS(ToolButtonStyle)
+ Q_FLAGS(Alignment)
+ Q_FLAGS(Orientations)
+ Q_FLAGS(DockWidgetAreas)
+ public:
+ ...
+ };
+ \endcode
+
+ Regarding the Q_OBJECT, Q_ENUMS and Q_FLAGS macros; see the
+ documentation of the \tt {\l Cpp.ignoredirectives} variable.
+
+ See also \l Cpp.ignoredirectives.
+*/
+
+/*!
+ \page 24-qdoc-configuration-htmlvariables.html
+ \previouspage C++ Specific Configuration Variables
+ \contentspage Table of Contents
+ \nextpage Supporting Derived Projects
+
+ \title HTML Specific Configuration Variables
+
+ The HTML specific configuration variables define the generated
+ documentation's style, or define the contents of the
+ documentation's footer or postheader. The format of the variable
+ values are raw HTML.
+
+ \target HTML.footer-variable
+ \section1 HTML.footer
+
+ The \c HTML.footer variable defines the content of the generated
+ HTML documentation's footer.
+
+ The footer is rendered at the bottom of the generated
+ documentation page.
+
+ The variable's value is given as raw HTML code enclosed by
+ quotation marks. Note that if the value spans several lines, each
+ line needs to be enclosed by quotation marks.
+
+ For example in \l qt.qdocconf:
+
+ \code
+ HTML.footer = "<p /><address><hr /><div align=\"center\">\n" \
+ ...
+ "</tr></table></div></address>"
+ \endcode
+
+ The complete variable entry in \l qt.qdocconf provides the
+ standard footer of the \l {http://qt.nokia.com/doc/4.0/index.html}
+ {Qt Reference Documentation}.
+
+ \target HTML.postheader-variable
+ \section1 HTML.postheader
+
+ The \c HTML.postheader variable defines the content of the
+ generated HTML documentation's postheader.
+
+ The header is rendered at the top of the generated documentation
+ page.
+
+ The variable's value is given as raw HTML enclosed by quotation
+ marks. Note that if the value spans several lines, each line needs
+ to be enclosed by quotation marks.
+
+ For example in \l qt.qdocconf:
+
+ \code
+ HTML.postheader = "<table border=\"0\"..." \
+ ...
+ "<img src=\"images/qt-logo.png\" \
+ "align=\"right\" width=\"203\" height=\"32\""\
+ "border=\"0\" />" \
+ "</td></tr>" \
+ "</table>"
+ \endcode
+
+ The complete variable entry in \l qt.qdocconf provides the
+ standard header of the \l {http://doc.qt.nokia.com/}
+ {Qt Reference Documentation}.
+
+ \target HTML.style-variable
+ \section1 HTML.style
+
+ The HTML.style variable defines the style for
+ the generated HTML documentation.
+
+ The variable's value is given as raw HTML enclosed by quotation
+ marks. Note that if the value spans several lines, each line needs
+ to be enclosed by quotation marks.
+
+ For example in \l qt.qdocconf:
+
+ \code
+ HTML.style = "h3.fn,span.fn" \
+ "{ margin-left: 1cm; text-indent: -1cm; }\n" \
+ "a:link { color: #004faf; text-decoration: none }\n" \
+ "a:visited" \
+ "{ color: #672967; text-decoration: none }\n" \
+ "td.postheader { font-family: sans-serif }\n" \
+ "tr.address { font-family: sans-serif }\n" \
+ "body { background: #ffffff; color: black; }"
+ \endcode
+
+ provides the HTML style for the \l
+ {http://qt.nokia.com/doc/4.0/index.html} {Qt Reference
+ Documentation}.
+
+ \target HTML.stylesheets-variable
+ \section1 HTML.stylesheets
+
+ The HTML.stylesheets variable defines a list of stylesheets
+ to use for the generated HTML documentation.
+
+ Using separate stylesheets for the documentation makes it easier
+ to customize and experiment with the style used once the contents
+ has been generated. Typically, it is only necessary to define a
+ single stylesheet for any set of documentation; for example:
+
+ \code
+ HTML.stylesheets = classic.css
+ \endcode
+
+ QDoc expects to find stylesheets in the directory containing the
+ \l qt.qdocconf file, and it will copy those specified to the output
+ directory alongside the HTML pages.
+
+*/
+
+/*!
+ \page 25-qdoc-configuration-derivedprojects.html
+ \previouspage HTML Specific Configuration Variables
+ \contentspage Table of Contents
+ \nextpage Compatibility Issues
+
+ \title Supporting Derived Projects
+
+ Some configuration variables allow you to use QDoc to support
+ Qt-based projects; i.e allow your project to contain links to the
+ online Qt documentation. This means that QDoc will be able to
+ create links to the class reference documentation, without any
+ explicit linking command.
+
+ \target description-variable
+ \section1 description
+
+ The description variable holds a short description of the
+ associated project.
+
+ See also \l project.
+
+ \target indexes-variable
+ \section1 indexes
+
+ The \c indexes variable lists the index files that will be used to
+ generate references.
+
+ For example. to make a derived Qt project contain links to the Qt
+ Reference documentation, you need to specify the associated index
+ file:
+
+ \code
+ indexes = $QTDIR/doc/html/qt.index
+ \endcode
+
+ See also \l project and \l url.
+
+ \target project-variable
+ \section1 project
+
+ The \c project variable provides a name for the project associated
+ with the \c .qdocconf file.
+
+ The project's name is used to form a file name for the associated
+ project's \e index file.
+
+ \code
+ project = QtCreator
+ \endcode
+
+ This will cause an index file called \c qtcreator.index to be
+ created.
+
+ See also \l description and \l indexes.
+
+ \target url-variable
+ \section1 url
+
+ The \c url variable holds the base URL for the reference
+ documentation associated with the current project.
+
+ The URL is stored in the generated index file for the
+ project. When we use the index on its own, QDoc will use this as
+ the base URL when constructing links to classes, functions, and
+ other things listed in the index.
+
+ \code
+ project = Qt
+ description = Qt Reference Documentation
+ url = http://doc.qt.nokia.com/4.7
+
+ ...
+ \endcode
+
+ This makes sure that whenever \c qt.index is used to generate
+ references to for example Qt classes, the base URL is \c
+ http://doc.qt.nokia.com/4.7.
+
+ See also \l indexes.
+
+ \target howto
+ \section1 How to Support Derived Projects
+
+ This feature makes use of the comprehensive indexes generated by
+ QDoc when it creates the Qt reference documentation.
+
+ For example, \l qt.qdocconf (the configuration file for Qt)
+ contains the following variable definitions:
+
+ \code
+ project = Qt
+ description = Qt Reference Documentation
+ url = http://doc.qt.nokia.com/4.7
+
+ ...
+ \endcode
+
+ The \l project variable name is used to form a file name for the
+ index file; in this case the \c qt.index file is created. The \l
+ url is stored in the index file. Later, when we use the index on
+ its own, QDoc will use this as the base URL when constructing
+ links to classes, functions, and other things listed in the index.
+
+ In a mini-project, you can use an index file by defining an \l
+ indexes configuration variable in your \c .qdocconf file.
+
+ For example, you can create a \c qtcreator.qdocconf file to help you
+ check the Qt Creator documentation:
+
+ \code
+ include($QTDIR/tools/qdoc3/test/compat.qdocconf)
+
+ project = QtCreator
+ description = Qt Creator Class Documentation
+ url = http://doc.qt.nokia.com/qtcreator-2.2
+
+ indexes = $QTDIR/doc/html/qt.index
+
+ outputdir = html
+
+ headerdirs = src
+ sourcedirs = src \
+ examples
+ sources.fileextensions = "*.cpp *.qdoc *.doc"
+
+ exampledirs = examples
+ \endcode
+
+ The code above requires that you run QDoc from the directory that
+ contains this file. You need to include the compat.qdocconf
+ file for compatibility reasons; this is further explained in the
+ \l {Compatibility Issues} section.
+
+ \bold {To resolve the actual links to Qt classes, the
+ mini-project's \c .qdocconf file needs to assign a value to the \l
+ indexes variable; \c $QTDIR/doc/html/qt.index makes sure that you
+ always use the updated index file for the Qt documentation.}
+
+ The only disadvantages with this approach are the extra file that
+ QDoc has to generate and the time it takes to do so. Reading the
+ index back again later isn't instantaneous either, but it's
+ quicker than processing all the Qt classes each time you need to
+ write a new document.
+*/
+
+/*!
+ \page 26-qdoc-commands-compatibility.html
+ \previouspage Supporting Derived Projects
+ \contentspage Table of Contents
+ \nextpage qt.qdocconf
+
+ \title Compatibility Issues
+
+ \section1 General Description
+
+ \target reason
+
+ Because QDoc evolves to suit our documentation needs, there can be
+ some compatibility issues when converting to a new version.
+
+ To allow you to proceed at your own speed when converting your
+ qdoc comments to use new qdoc commands and formats, the ability to
+ include a configuration file called \c {compat.qdocconf} is
+ provided.
+
+ A \c {compat.qdocconf} file is a separate configuration file,
+ which you include in your main configuration file. It typically
+ contains the mappings from old qdoc commands to new ones using
+ \l {alias} and
+ \l {22-qdoc-configuration-generalvariables.html#macro-variable}
+ {macro} configuration variables.
+
+ \section1 Qt Compatibility
+
+ In Qt's documentation there still exist occurrences of old
+ commands, and the Qt \l {qt.qdocconf} {configuration file} needs to
+ include the compat.qdocconf file tailored for Qt. For more
+ detailed information about the commands creating compatibility
+ issues, see the \l {Command Comments} {command comments}.
+
+ \section1 Qt's current compat.qdocconf file
+
+ \quotefile files/compat.qdocconf
+
+ \section1 Command Comments
+
+ \table
+ \header
+ \o New Command
+ \o Old Command
+ \o Description
+
+ \row
+ \o \\i \target i-versus-e
+ \o \\e
+ \o Earlier we
+ used the \\i command to indicate a list or table item, and
+ the \\e command for rendering in italic. Now we want the
+ \\i command to render in italic discarding the
+ \\e command name.
+
+ \bold {We still need to use the \\e command to render in
+ italic in new documentation for \l {reason} {compatibility
+ reasons}}.
+
+ \row
+ \o \\include \target include-versus-input
+ \o \\input
+ \o The \\include command was previously used to quote the
+ complete contents of a source file, now we want to use the
+ command to include separate documentation.
+ That is the functionality of the old \\input command
+ which name we want to discard.
+
+ \bold {We still need to use the \\input command to include
+ plain text in new documentation for \l
+ {reason} {compatibility reasons}}.
+
+ \row
+ \o \\quotefile \target quotefile-versus-include
+ \o \\include
+ \o Earlier, we have used the \\quotefile command to
+ quote from file, i.e. quote parts from file, and the
+ \\include command to quote the entire file. Since we now want
+ \\include to include separate documentation, we change the use of
+ \\quotefile to quote a complete source file.
+
+ \bold {We still need to use the \\include command to quote
+ the entire contents of a source file in new documentation
+ for \l {reason} {compatibility reasons}}.
+
+ \row
+ \o \\quotefromfile \target quotefromfile-versus-quotefile
+ \o \\quotefile
+ \o Earlier, we have used the \\quotefile command to
+ quote from file, i.e. quote parts from file. Since we now want
+ that command to quote an entire file, we introduce the new
+ \\quotefromfile command to quote from file.
+
+ \bold {Use \l {quotefromfile-command} {\\quotefromfile} to quote
+ parts from a source file in new documentation}.
+
+ \row
+ \o \\o \target o-versus-i
+ \o \\i
+ \o Earlier we used the \\i command to indicate list items
+ and table items. Since we now want the \\i command to render
+ in italic instead, we introduce the new \\o command for
+ this purpose.
+
+ \bold {Use \l {o-command} {\\o} to indicate list and table items in
+ new documentation}.
+
+ \row
+ \o \\quotation \target quotation-versus-quote
+ \o \\quote
+ \o These commands are equivalent, and represent a simple name
+ change.
+
+ \bold {Use \l {quotation} {\\quotation} in new
+ documentation}.
+
+ \row
+ \o \\image \target image-versus-img
+ \o \\img
+ \o These commands are equivalent, and represent a simple name
+ change.
+
+ \bold {Use \l {image-command} {\\image} in new documentation}.
+
+ \endtable
+*/
+
+/*!
+ \page 27-qdoc-commmands-alphabetical.html
+ \previouspage Introduction to QDoc
+ \contentspage Table of Contents
+ \nextpage Topic Commands
+
+ \title Command Index
+
+ This is a complete, alphabetized list of the QDoc commands.
+
+ \list
+
+ \o \l {04-qdoc-commands-textmarkup.html#a-command} {\\a}
+ \o \l {11-qdoc-commands-specialcontent.html#abstract-command} {\\abstract}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#annotatedlist-command} {\\annotatedlist} \span {class="newStuff"} {(new 03/11/11)}
+ \o \l {23-qdoc-configuration-cppvariables.html#basedir-variable} {basedir} \span {class="newStuff"} {(experimental)}
+ \o \l {06-qdoc-commands-includecodeinline.html#badcode-command} {\\badcode}
+ \o \l {04-qdoc-commands-textmarkup.html#bold-command} {\\bold}
+ \o \l {11-qdoc-commands-specialcontent.html#brief-command} {\\brief}
+ \o \l {04-qdoc-commands-textmarkup.html#c-command} {\\c}
+ \o \l {09-qdoc-commands-includingimages.html#caption-command} {\\caption}
+ \o \l {05-qdoc-commands-documentstructure.html#chapter-command} {\\chapter}
+ \o \l {13-qdoc-commands-topics.html#class-command} {\\class}
+ \o \l {06-qdoc-commands-includecodeinline.html#code-command} {\\code}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#codeline-command} {\\codeline},
+ \o \l {16-qdoc-commands-status.html#compat-command} {\\compat}
+ \o \l {15-qdoc-commands-navigation.html#contentspage-command} {\\contentspage}
+ \o \l {16-qdoc-commands-status.html#default-command} {\\default}
+ \o \l {04-qdoc-commands-textmarkup.html#div-command} {\\div}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#dots-command} {\\dots}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#else-command} {\\else}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#endif-command} {\\endif}
+ \o \l {13-qdoc-commands-topics.html#enum-command} {\\enum}
+ \o \l {13-qdoc-commands-topics.html#example-command} {\\example}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#expire-command} {\\expire}
+ \o \l {13-qdoc-commands-topics.html#externalpage-command} {\\externalpage}
+ \o \l {13-qdoc-commands-topics.html#fn-command} {\\fn}
+ \o \l {11-qdoc-commands-specialcontent.html#footnote-command} {\\footnote}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#generatelist-command} {\\generatelist}
+ \o \l {13-qdoc-commands-topics.html#group-command} {\\group}
+ \o \l {10-qdoc-commands-tablesandlists.html#header-command} {\\header}
+ \o \l {13-qdoc-commands-topics.html#headerfile-command} {\\headerfile}
+ \o \l {04-qdoc-commands-textmarkup.html#i-command} {\\i}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#if-command} {\\if}
+ \o \l {09-qdoc-commands-includingimages.html#image-command} {\\image}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#include-command} {\\include}
+ \o \l {15-qdoc-commands-navigation.html#indexpage-command} {\\indexpage}
+ \o \l {19-qdoc-commands-grouping.html#ingroup-command} {\\ingroup}
+ \o \l {18-qdoc-commands-relating.html#inherits-command}{\\inherits}
+ \o \l {19-qdoc-commands-grouping.html#inmodule-command} {\\inmodule}
+ \o \l {09-qdoc-commands-includingimages.html#inlineimage-command} {\\inlineimage}
+ \o \l {16-qdoc-commands-status.html#internal-command} {\\internal}
+ \o \l {08-qdoc-commands-creatinglinks.html#keyword-command} {\\keyword}
+ \o \l {08-qdoc-commands-creatinglinks.html#l-command} {\\l}
+ \o \l {11-qdoc-commands-specialcontent.html#legalese-command} {\\legalese}
+ \o \l {10-qdoc-commands-tablesandlists.html#list-command} {\\list}
+ \o \l {13-qdoc-commands-topics.html#macro-command} {\\macro}
+ \o \l {19-qdoc-commands-grouping.html#mainclass-command} {\\mainclass}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#meta-command} {\\meta}
+ \o \l {13-qdoc-commands-topics.html#module-command} {\\module}
+ \o \l {13-qdoc-commands-topics.html#namespace-command} {\\namespace}
+ \o \l {15-qdoc-commands-navigation.html#nextpage-command} {\\nextpage}
+ \o \l {06-qdoc-commands-includecodeinline.html#newcode-command} {\\newcode}
+ \o \l {17-qdoc-commands-thread.html#nonreentrant-command} {\\nonreentrant}
+ \o \l {10-qdoc-commands-tablesandlists.html#o-command} {\\o}
+ \o \l {16-qdoc-commands-status.html#obsolete-command} {\\obsolete}
+ \o \l {06-qdoc-commands-includecodeinline.html#oldcode-command} {\\oldcode}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#omit-command} {\\omit}
+ \o \l {10-qdoc-commands-tablesandlists.html#omitvalue-command} {\\omitvalue}
+ \o \l {18-qdoc-commands-relating.html#overload-command} {\\overload}
+ \o \l {13-qdoc-commands-topics.html#page-command} {\\page}
+ \o \l {05-qdoc-commands-documentstructure.html#part-command} {\\part}
+ \o \l {16-qdoc-commands-status.html#preliminary-command} {\\preliminary}
+ \o \l {15-qdoc-commands-navigation.html#previouspage-command} {\\previouspage}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#printline-command} {\\printline}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#printto-command} {\\printto}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#printuntil-command} {\\printuntil}
+ \o \l {13-qdoc-commands-topics.html#property-command} {\\property}
+ \o \l {13-qdoc-commands-topics.html#qmlattachedproperty-command} {\\qmlattachedproperty}
+ \o \l {13-qdoc-commands-topics.html#qmlattachedsignal-command} {\\qmlattachedsignal}
+ \o \l {13-qdoc-commands-topics.html#qmlbasictype-command} {\\qmlbasictype}
+ \o \l {13-qdoc-commands-topics.html#qmlclass-command} {\\qmlclass}
+ \o \l {13-qdoc-commands-topics.html#qmlmethod-command} {\\qmlmethod}
+ \o \l {13-qdoc-commands-topics.html#qmlproperty-command} {\\qmlproperty}
+ \o \l {13-qdoc-commands-topics.html#qmlsignal-command} {\\qmlsignal}
+ \o \l {13-qdoc-commands-topics.html#qmlmodule-command} {\\qmlmodule}
+ \o \l {13-qdoc-commands-topics.html#inqmlmodule-command} {\\inqmlmodule}
+ \o \l {11-qdoc-commands-specialcontent.html#quotation-command} {\\quotation}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#quotefile-command} {\\quotefile}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#quotefromfile-command} {\\quotefromfile}
+ \o \l {12-0-qdoc-commands-miscellaneous.html#raw-command} {\\raw} \span {class="newStuff"} {(avoid)}
+ \o \l {17-qdoc-commands-thread.html#reentrant-command} {\\reentrant}
+ \o \l {18-qdoc-commands-relating.html#reimp-command} {\\reimp}
+ \o \l {18-qdoc-commands-relating.html#relates-command} {\\relates}
+ \o \l {10-qdoc-commands-tablesandlists.html#row-command} {\\row}
+ \o \l {08-qdoc-commands-creatinglinks.html#sa-command} {\\sa}
+ \o \l {05-qdoc-commands-documentstructure.html#sectionOne-command} {\\section1}
+ \o \l {05-qdoc-commands-documentstructure.html#sectionTwo-command} {\\section2}
+ \o \l {05-qdoc-commands-documentstructure.html#sectionThree-command} {\\section3}
+ \o \l {05-qdoc-commands-documentstructure.html#sectionFour-command} {\\section4}
+ \o \l {13-qdoc-commands-topics.html#service-command} {\\service}
+ \o \l {16-qdoc-commands-status.html#since-command} {\\since}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#skipline-command} {\\skipline}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#skipto-command} {\\skipto}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#skipuntil-command} {\\skipuntil}
+ \o \l {07-0-qdoc-commands-includingexternalcode.html#snippet-command} {\\snippet},
+ \o \l {04-qdoc-commands-textmarkup.html#span-command} {\\span}
+ \o \l {15-qdoc-commands-navigation.html#startpage-command} {\\startpage}
+ \o \l {04-qdoc-commands-textmarkup.html#sub-command} {\\sub}
+ \o \l {20-qdoc-commands-namingthings.html#subtitle-command} {\\subtitle}
+ \o \l {04-qdoc-commands-textmarkup.html#sup-command} {\\sup}
+ \o \l {10-qdoc-commands-tablesandlists.html#table-command} {\\table}
+ \o \l {11-qdoc-commands-specialcontent.html#tableofcontents-command} {\\tableofcontents}
+ \o \l {08-qdoc-commands-creatinglinks.html#target-command} {\\target}
+ \o \l {17-qdoc-commands-thread.html#threadsafe-command} {\\threadsafe}
+ \o \l {20-qdoc-commands-namingthings.html#title-command} {\\title}
+ \o \l {04-qdoc-commands-textmarkup.html#tt-command} {\\tt}
+ \o \l {13-qdoc-commands-topics.html#typedef-command} {\\typedef}
+ \o \l {04-qdoc-commands-textmarkup.html#underline-command} {\\underline}
+ \o \l {13-qdoc-commands-topics.html#variable-command} {\\variable}
+ \o \l {10-qdoc-commands-tablesandlists.html#value-command} {\\value}
+ \o \l {11-qdoc-commands-specialcontent.html#warning-command} {\\warning}
+ \endlist
+*/
+
+/*!
+ \externalpage http://qt.nokia.com/about
+ \title About Qt
+*/
diff --git a/src/tools/qdoc/editdistance.cpp b/src/tools/qdoc/editdistance.cpp
new file mode 100644
index 0000000000..8e14deddc1
--- /dev/null
+++ b/src/tools/qdoc/editdistance.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ editdistance.cpp
+*/
+
+#include "editdistance.h"
+
+QT_BEGIN_NAMESPACE
+
+int editDistance( const QString& s, const QString& t )
+{
+#define D( i, j ) d[(i) * n + (j)]
+ int i;
+ int j;
+ int m = s.length() + 1;
+ int n = t.length() + 1;
+ int *d = new int[m * n];
+ int result;
+
+ for ( i = 0; i < m; i++ )
+ D( i, 0 ) = i;
+ for ( j = 0; j < n; j++ )
+ D( 0, j ) = j;
+ for ( i = 1; i < m; i++ ) {
+ for ( j = 1; j < n; j++ ) {
+ if ( s[i - 1] == t[j - 1] ) {
+ D( i, j ) = D( i - 1, j - 1 );
+ } else {
+ int x = D( i - 1, j );
+ int y = D( i - 1, j - 1 );
+ int z = D( i, j - 1 );
+ D( i, j ) = 1 + qMin( qMin(x, y), z );
+ }
+ }
+ }
+ result = D( m - 1, n - 1 );
+ delete[] d;
+ return result;
+#undef D
+}
+
+QString nearestName( const QString& actual, const QSet<QString>& candidates )
+{
+ if (actual.isEmpty())
+ return "";
+
+ int deltaBest = 10000;
+ int numBest = 0;
+ QString best;
+
+ QSet<QString>::ConstIterator c = candidates.begin();
+ while ( c != candidates.end() ) {
+ if ( (*c)[0] == actual[0] ) {
+ int delta = editDistance( actual, *c );
+ if ( delta < deltaBest ) {
+ deltaBest = delta;
+ numBest = 1;
+ best = *c;
+ } else if ( delta == deltaBest ) {
+ numBest++;
+ }
+ }
+ ++c;
+ }
+
+ if ( numBest == 1 && deltaBest <= 2 &&
+ actual.length() + best.length() >= 5 ) {
+ return best;
+ } else {
+ return "";
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/editdistance.h b/src/tools/qdoc/editdistance.h
new file mode 100644
index 0000000000..d8e8fe29aa
--- /dev/null
+++ b/src/tools/qdoc/editdistance.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ editdistance.h
+*/
+
+#ifndef EDITDISTANCE_H
+#define EDITDISTANCE_H
+
+#include <QSet>
+#include <QString>
+
+QT_BEGIN_NAMESPACE
+
+int editDistance( const QString& s, const QString& t );
+QString nearestName( const QString& actual, const QSet<QString>& candidates );
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/generator.cpp b/src/tools/qdoc/generator.cpp
new file mode 100644
index 0000000000..c990413234
--- /dev/null
+++ b/src/tools/qdoc/generator.cpp
@@ -0,0 +1,1495 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ generator.cpp
+*/
+#include <qdir.h>
+#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
+#include <qdebug.h>
+#endif
+#include <qdebug.h>
+#include "codemarker.h"
+#include "config.h"
+#include "doc.h"
+#include "editdistance.h"
+#include "generator.h"
+#include "node.h"
+#include "openedlist.h"
+#include "quoter.h"
+#include "separator.h"
+#include "tokenizer.h"
+#include "ditaxmlgenerator.h"
+
+QT_BEGIN_NAMESPACE
+
+QList<Generator *> Generator::generators;
+QMap<QString, QMap<QString, QString> > Generator::fmtLeftMaps;
+QMap<QString, QMap<QString, QString> > Generator::fmtRightMaps;
+QMap<QString, QStringList> Generator::imgFileExts;
+QSet<QString> Generator::outputFormats;
+QStringList Generator::imageFiles;
+QStringList Generator::imageDirs;
+QStringList Generator::exampleDirs;
+QStringList Generator::exampleImgExts;
+QStringList Generator::scriptFiles;
+QStringList Generator::scriptDirs;
+QStringList Generator::styleFiles;
+QStringList Generator::styleDirs;
+QString Generator::outDir_;
+QString Generator::baseDir_;
+QString Generator::project;
+QHash<QString, QString> Generator::outputPrefixes;
+
+QString Generator::sinceTitles[] =
+{
+ " New Namespaces",
+ " New Classes",
+ " New Member Functions",
+ " New Functions in Namespaces",
+ " New Global Functions",
+ " New Macros",
+ " New Enum Types",
+ " New Typedefs",
+ " New Properties",
+ " New Variables",
+ " New QML Elements",
+ " New QML Properties",
+ " New QML Signals",
+ " New QML Signal Handlers",
+ " New QML Methods",
+ ""
+};
+
+static void singularPlural(Text& text, const NodeList& nodes)
+{
+ if (nodes.count() == 1)
+ text << " is";
+ else
+ text << " are";
+}
+
+Generator::Generator()
+ : amp("&amp;"),
+ lt("&lt;"),
+ gt("&gt;"),
+ quot("&quot;"),
+ tag("</?@[^>]*>")
+{
+ generators.prepend(this);
+}
+
+Generator::~Generator()
+{
+ generators.removeAll(this);
+}
+
+void Generator::initializeGenerator(const Config & /* config */)
+{
+}
+
+void Generator::terminateGenerator()
+{
+}
+
+void Generator::initialize(const Config &config)
+{
+ outputFormats = config.getOutputFormats();
+ if (!outputFormats.isEmpty()) {
+ outDir_ = config.getOutputDir();
+ baseDir_ = config.getString(CONFIG_BASEDIR);
+ if (!baseDir_.isEmpty())
+ config.location().warning(tr("\"basedir\" specified in config file. "
+ "All output will be in module directories of the output directory"));
+ if (outDir_.isEmpty())
+ config.lastLocation().fatal(tr("No output directory specified in configuration file or on the command line"));
+
+ QDir dirInfo;
+ if (dirInfo.exists(outDir_)) {
+ if (!Config::removeDirContents(outDir_))
+ config.lastLocation().error(tr("Cannot empty output directory '%1'").arg(outDir_));
+ }
+ else {
+ if (!dirInfo.mkpath(outDir_))
+ config.lastLocation().fatal(tr("Cannot create output directory '%1'").arg(outDir_));
+ }
+
+ if (!dirInfo.mkdir(outDir_ + "/images"))
+ config.lastLocation().fatal(tr("Cannot create output directory '%1'")
+ .arg(outDir_ + "/images"));
+ if (!dirInfo.mkdir(outDir_ + "/images/used-in-examples"))
+ config.lastLocation().fatal(tr("Cannot create output directory '%1'")
+ .arg(outDir_ + "/images/used-in-examples"));
+ if (!dirInfo.mkdir(outDir_ + "/scripts"))
+ config.lastLocation().fatal(tr("Cannot create output directory '%1'")
+ .arg(outDir_ + "/scripts"));
+ if (!dirInfo.mkdir(outDir_ + "/style"))
+ config.lastLocation().fatal(tr("Cannot create output directory '%1'")
+ .arg(outDir_ + "/style"));
+ }
+
+ imageFiles = config.getCleanPathList(CONFIG_IMAGES);
+ imageDirs = config.getCleanPathList(CONFIG_IMAGEDIRS);
+ scriptFiles = config.getCleanPathList(CONFIG_SCRIPTS);
+ scriptDirs = config.getCleanPathList(CONFIG_SCRIPTDIRS);
+ styleFiles = config.getCleanPathList(CONFIG_STYLES);
+ styleDirs = config.getCleanPathList(CONFIG_STYLEDIRS);
+ exampleDirs = config.getCleanPathList(CONFIG_EXAMPLEDIRS);
+ exampleImgExts = config.getStringList(CONFIG_EXAMPLES + Config::dot +
+ CONFIG_IMAGEEXTENSIONS);
+
+ QString imagesDotFileExtensions =
+ CONFIG_IMAGES + Config::dot + CONFIG_FILEEXTENSIONS;
+ QSet<QString> formats = config.subVars(imagesDotFileExtensions);
+ QSet<QString>::ConstIterator f = formats.begin();
+ while (f != formats.end()) {
+ imgFileExts[*f] = config.getStringList(imagesDotFileExtensions +
+ Config::dot + *f);
+ ++f;
+ }
+
+ QList<Generator *>::ConstIterator g = generators.begin();
+ while (g != generators.end()) {
+ if (outputFormats.contains((*g)->format())) {
+ (*g)->initializeGenerator(config);
+ QStringList extraImages =
+ config.getCleanPathList(CONFIG_EXTRAIMAGES+Config::dot+(*g)->format());
+ QStringList::ConstIterator e = extraImages.begin();
+ while (e != extraImages.end()) {
+ QString userFriendlyFilePath;
+ QString filePath = Config::findFile(config.lastLocation(),
+ imageFiles,
+ imageDirs,
+ *e,
+ imgFileExts[(*g)->format()],
+ userFriendlyFilePath);
+ if (!filePath.isEmpty())
+ Config::copyFile(config.lastLocation(),
+ filePath,
+ userFriendlyFilePath,
+ (*g)->outputDir() +
+ "/images");
+ ++e;
+ }
+
+ // Documentation template handling
+ QString templateDir = config.getString(
+ (*g)->format() + Config::dot + CONFIG_TEMPLATEDIR);
+
+ if (!templateDir.isEmpty()) {
+ QStringList noExts;
+ QStringList searchDirs = QStringList() << templateDir;
+ QStringList scripts =
+ config.getCleanPathList((*g)->format()+Config::dot+CONFIG_SCRIPTS);
+ e = scripts.begin();
+ while (e != scripts.end()) {
+ QString userFriendlyFilePath;
+ QString filePath = Config::findFile(config.lastLocation(),
+ scriptFiles,
+ searchDirs,
+ *e,
+ noExts,
+ userFriendlyFilePath);
+ if (!filePath.isEmpty())
+ Config::copyFile(config.lastLocation(),
+ filePath,
+ userFriendlyFilePath,
+ (*g)->outputDir() +
+ "/scripts");
+ ++e;
+ }
+
+ QStringList styles =
+ config.getCleanPathList((*g)->format()+Config::dot+CONFIG_STYLESHEETS);
+ e = styles.begin();
+ while (e != styles.end()) {
+ QString userFriendlyFilePath;
+ QString filePath = Config::findFile(config.lastLocation(),
+ styleFiles,
+ searchDirs,
+ *e,
+ noExts,
+ userFriendlyFilePath);
+ if (!filePath.isEmpty())
+ Config::copyFile(config.lastLocation(),
+ filePath,
+ userFriendlyFilePath,
+ (*g)->outputDir() +
+ "/style");
+ ++e;
+ }
+ }
+ }
+ ++g;
+ }
+
+ QRegExp secondParamAndAbove("[\2-\7]");
+ QSet<QString> formattingNames = config.subVars(CONFIG_FORMATTING);
+ QSet<QString>::ConstIterator n = formattingNames.begin();
+ while (n != formattingNames.end()) {
+ QString formattingDotName = CONFIG_FORMATTING + Config::dot + *n;
+
+ QSet<QString> formats = config.subVars(formattingDotName);
+ QSet<QString>::ConstIterator f = formats.begin();
+ while (f != formats.end()) {
+ QString def = config.getString(formattingDotName +
+ Config::dot + *f);
+ if (!def.isEmpty()) {
+ int numParams = Config::numParams(def);
+ int numOccs = def.count("\1");
+
+ if (numParams != 1) {
+ config.lastLocation().warning(tr("Formatting '%1' must "
+ "have exactly one "
+ "parameter (found %2)")
+ .arg(*n).arg(numParams));
+ }
+ else if (numOccs > 1) {
+ config.lastLocation().fatal(tr("Formatting '%1' must "
+ "contain exactly one "
+ "occurrence of '\\1' "
+ "(found %2)")
+ .arg(*n).arg(numOccs));
+ }
+ else {
+ int paramPos = def.indexOf("\1");
+ fmtLeftMaps[*f].insert(*n, def.left(paramPos));
+ fmtRightMaps[*f].insert(*n, def.mid(paramPos + 1));
+ }
+ }
+ ++f;
+ }
+ ++n;
+ }
+
+ project = config.getString(CONFIG_PROJECT);
+
+ QStringList prefixes = config.getStringList(CONFIG_OUTPUTPREFIXES);
+ if (!prefixes.isEmpty()) {
+ foreach (QString prefix, prefixes)
+ outputPrefixes[prefix] = config.getString(
+ CONFIG_OUTPUTPREFIXES + Config::dot + prefix);
+ } else
+ outputPrefixes[QLatin1String("QML")] = QLatin1String("qml-");
+}
+
+void Generator::terminate()
+{
+ QList<Generator *>::ConstIterator g = generators.begin();
+ while (g != generators.end()) {
+ if (outputFormats.contains((*g)->format()))
+ (*g)->terminateGenerator();
+ ++g;
+ }
+
+ fmtLeftMaps.clear();
+ fmtRightMaps.clear();
+ imgFileExts.clear();
+ imageFiles.clear();
+ imageDirs.clear();
+ outDir_ = "";
+ QmlClassNode::terminate();
+ ExampleNode::terminate();
+}
+
+Generator *Generator::generatorForFormat(const QString& format)
+{
+ QList<Generator *>::ConstIterator g = generators.begin();
+ while (g != generators.end()) {
+ if ((*g)->format() == format)
+ return *g;
+ ++g;
+ }
+ return 0;
+}
+
+void Generator::startText(const Node * /* relative */,
+ CodeMarker * /* marker */)
+{
+}
+
+void Generator::endText(const Node * /* relative */,
+ CodeMarker * /* marker */)
+{
+}
+
+int Generator::generateAtom(const Atom * /* atom */,
+ const Node * /* relative */,
+ CodeMarker * /* marker */)
+{
+ return 0;
+}
+
+void Generator::generateClassLikeNode(const InnerNode * /* classe */,
+ CodeMarker * /* marker */)
+{
+}
+
+void Generator::generateFakeNode(const FakeNode * /* fake */,
+ CodeMarker * /* marker */)
+{
+}
+
+bool Generator::generateText(const Text& text,
+ const Node *relative,
+ CodeMarker *marker)
+{
+ bool result = false;
+ if (text.firstAtom() != 0) {
+ int numAtoms = 0;
+ startText(relative, marker);
+ generateAtomList(text.firstAtom(),
+ relative,
+ marker,
+ true,
+ numAtoms);
+ endText(relative, marker);
+ result = true;
+ }
+ return result;
+}
+
+#ifdef QDOC_QML
+/*!
+ Extract sections of markup text surrounded by \e qmltext
+ and \e endqmltext and output them.
+ */
+bool Generator::generateQmlText(const Text& text,
+ const Node *relative,
+ CodeMarker *marker,
+ const QString& /* qmlName */ )
+{
+ const Atom* atom = text.firstAtom();
+ bool result = false;
+
+ if (atom != 0) {
+ startText(relative, marker);
+ while (atom) {
+ if (atom->type() != Atom::QmlText)
+ atom = atom->next();
+ else {
+ atom = atom->next();
+ while (atom && (atom->type() != Atom::EndQmlText)) {
+ int n = 1 + generateAtom(atom, relative, marker);
+ while (n-- > 0)
+ atom = atom->next();
+ }
+ }
+ }
+ endText(relative, marker);
+ result = true;
+ }
+ return result;
+}
+#endif
+
+void Generator::generateBody(const Node *node, CodeMarker *marker)
+{
+ bool quiet = false;
+
+ if (node->type() == Node::Fake) {
+ const FakeNode *fake = static_cast<const FakeNode *>(node);
+ if (fake->subType() == Node::Example) {
+ generateExampleFiles(fake, marker);
+ }
+ else if ((fake->subType() == Node::File) || (fake->subType() == Node::Image)) {
+ quiet = true;
+ }
+ }
+ if (node->doc().isEmpty()) {
+ if (!quiet && !node->isReimp()) { // ### might be unnecessary
+ node->location().warning(tr("No documentation for '%1'")
+ .arg(marker->plainFullName(node)));
+ }
+ }
+ else {
+ if (node->type() == Node::Function) {
+ const FunctionNode *func = static_cast<const FunctionNode *>(node);
+ if (func->reimplementedFrom() != 0)
+ generateReimplementedFrom(func, marker);
+ }
+
+ if (!generateText(node->doc().body(), node, marker)) {
+ if (node->isReimp())
+ return;
+ }
+
+ if (node->type() == Node::Enum) {
+ const EnumNode *enume = (const EnumNode *) node;
+
+ QSet<QString> definedItems;
+ QList<EnumItem>::ConstIterator it = enume->items().begin();
+ while (it != enume->items().end()) {
+ definedItems.insert((*it).name());
+ ++it;
+ }
+
+ QSet<QString> documentedItems = enume->doc().enumItemNames().toSet();
+ QSet<QString> allItems = definedItems + documentedItems;
+ if (allItems.count() > definedItems.count() ||
+ allItems.count() > documentedItems.count()) {
+ QSet<QString>::ConstIterator a = allItems.begin();
+ while (a != allItems.end()) {
+ if (!definedItems.contains(*a)) {
+ QString details;
+ QString best = nearestName(*a, definedItems);
+ if (!best.isEmpty() && !documentedItems.contains(best))
+ details = tr("Maybe you meant '%1'?").arg(best);
+
+ node->doc().location().warning(
+ tr("No such enum item '%1' in %2").arg(*a).arg(marker->plainFullName(node)),
+ details);
+ }
+ else if (!documentedItems.contains(*a)) {
+ node->doc().location().warning(
+ tr("Undocumented enum item '%1' in %2").arg(*a).arg(marker->plainFullName(node)));
+ }
+ ++a;
+ }
+ }
+ }
+ else if (node->type() == Node::Function) {
+ const FunctionNode *func = static_cast<const FunctionNode *>(node);
+ QSet<QString> definedParams;
+ QList<Parameter>::ConstIterator p = func->parameters().begin();
+ while (p != func->parameters().end()) {
+ if ((*p).name().isEmpty() && (*p).leftType() != QLatin1String("...")
+ && func->name() != QLatin1String("operator++")
+ && func->name() != QLatin1String("operator--")) {
+ node->doc().location().warning(tr("Missing parameter name"));
+ }
+ else {
+ definedParams.insert((*p).name());
+ }
+ ++p;
+ }
+
+ QSet<QString> documentedParams = func->doc().parameterNames();
+ QSet<QString> allParams = definedParams + documentedParams;
+ if (allParams.count() > definedParams.count()
+ || allParams.count() > documentedParams.count()) {
+ QSet<QString>::ConstIterator a = allParams.begin();
+ while (a != allParams.end()) {
+ if (!definedParams.contains(*a)) {
+ QString details;
+ QString best = nearestName(*a, definedParams);
+ if (!best.isEmpty())
+ details = tr("Maybe you meant '%1'?").arg(best);
+
+ node->doc().location().warning(
+ tr("No such parameter '%1' in %2").arg(*a).arg(marker->plainFullName(node)),
+ details);
+ }
+ else if (!(*a).isEmpty() && !documentedParams.contains(*a)) {
+ bool needWarning = (func->status() > Node::Obsolete);
+ if (func->overloadNumber() > 1) {
+ FunctionNode *primaryFunc =
+ func->parent()->findFunctionNode(func->name());
+ if (primaryFunc) {
+ foreach (const Parameter &param,
+ primaryFunc->parameters()) {
+ if (param.name() == *a) {
+ needWarning = false;
+ break;
+ }
+ }
+ }
+ }
+ if (needWarning && !func->isReimp())
+ node->doc().location().warning(
+ tr("Undocumented parameter '%1' in %2")
+ .arg(*a).arg(marker->plainFullName(node)));
+ }
+ ++a;
+ }
+ }
+ /*
+ Something like this return value check should
+ be implemented at some point.
+ */
+ if (func->status() > Node::Obsolete && func->returnType() == "bool"
+ && func->reimplementedFrom() == 0 && !func->isOverload()) {
+ QString body = func->doc().body().toString();
+ if (!body.contains("return", Qt::CaseInsensitive))
+ node->doc().location().warning(tr("Undocumented return value"));
+ }
+ }
+ }
+
+ if (node->type() == Node::Fake) {
+ const FakeNode *fake = static_cast<const FakeNode *>(node);
+ if (fake->subType() == Node::File) {
+ Text text;
+ Quoter quoter;
+ Doc::quoteFromFile(fake->doc().location(), quoter, fake->name());
+ QString code = quoter.quoteTo(fake->location(), "", "");
+ CodeMarker *codeMarker = CodeMarker::markerForFileName(fake->name());
+ text << Atom(codeMarker->atomType(), code);
+ generateText(text, fake, codeMarker);
+ }
+ }
+}
+
+void Generator::generateAlsoList(const Node *node, CodeMarker *marker)
+{
+ QList<Text> alsoList = node->doc().alsoList();
+ supplementAlsoList(node, alsoList);
+
+ if (!alsoList.isEmpty()) {
+ Text text;
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
+ << "See also "
+ << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD);
+
+ for (int i = 0; i < alsoList.size(); ++i)
+ text << alsoList.at(i) << separator(i, alsoList.size());
+
+ text << Atom::ParaRight;
+ generateText(text, node, marker);
+ }
+}
+
+/*!
+ Generate a list of maintainers in the output
+ */
+void Generator::generateMaintainerList(const InnerNode* node, CodeMarker* marker)
+{
+ QStringList sl = getMetadataElements(node,"maintainer");
+
+ if (!sl.isEmpty()) {
+ Text text;
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
+ << "Maintained by: "
+ << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD);
+
+ for (int i = 0; i < sl.size(); ++i)
+ text << sl.at(i) << separator(i, sl.size());
+
+ text << Atom::ParaRight;
+ generateText(text, node, marker);
+ }
+}
+
+void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker)
+{
+ QList<RelatedClass>::ConstIterator r;
+ int index;
+
+ if (!classe->baseClasses().isEmpty()) {
+ Text text;
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
+ << "Inherits: "
+ << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD);
+
+ r = classe->baseClasses().begin();
+ index = 0;
+ while (r != classe->baseClasses().end()) {
+ text << Atom(Atom::LinkNode, CodeMarker::stringForNode((*r).node))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, (*r).dataTypeWithTemplateArgs)
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+
+ if ((*r).access == Node::Protected) {
+ text << " (protected)";
+ }
+ else if ((*r).access == Node::Private) {
+ text << " (private)";
+ }
+ text << separator(index++, classe->baseClasses().count());
+ ++r;
+ }
+ text << Atom::ParaRight;
+ generateText(text, classe, marker);
+ }
+}
+
+#ifdef QDOC_QML
+/*!
+ */
+void Generator::generateQmlInherits(const QmlClassNode* , CodeMarker* )
+{
+ // stub.
+}
+#endif
+
+void Generator::generateInheritedBy(const ClassNode *classe,
+ CodeMarker *marker)
+{
+ if (!classe->derivedClasses().isEmpty()) {
+ Text text;
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
+ << "Inherited by: "
+ << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD);
+
+ appendSortedNames(text, classe, classe->derivedClasses(), marker);
+ text << Atom::ParaRight;
+ generateText(text, classe, marker);
+ }
+}
+
+/*!
+ This function is called when the documentation for an
+ example is being formatted. It outputs the list of source
+ files comprising the example, and the list of images used
+ by the example. The images are copied into a subtree of
+ \c{...doc/html/images/used-in-examples/...}
+ */
+void Generator::generateFileList(const FakeNode* fake,
+ CodeMarker* marker,
+ Node::SubType subtype,
+ const QString& tag)
+{
+ int count = 0;
+ Text text;
+ OpenedList openedList(OpenedList::Bullet);
+
+ text << Atom::ParaLeft << tag << Atom::ParaRight
+ << Atom(Atom::ListLeft, openedList.styleString());
+
+ foreach (const Node* child, fake->childNodes()) {
+ if (child->subType() == subtype) {
+ ++count;
+ QString file = child->name();
+ if (subtype == Node::Image) {
+ if (!file.isEmpty()) {
+ QDir dirInfo;
+ QString userFriendlyFilePath;
+ QString srcPath = Config::findFile(fake->location(),
+ QStringList(),
+ exampleDirs,
+ file,
+ exampleImgExts,
+ userFriendlyFilePath);
+ userFriendlyFilePath.truncate(userFriendlyFilePath.lastIndexOf('/'));
+
+ QString imgOutDir = outDir_ + "/images/used-in-examples/" + userFriendlyFilePath;
+ if (!dirInfo.mkpath(imgOutDir))
+ fake->location().fatal(tr("Cannot create output directory '%1'")
+ .arg(imgOutDir));
+
+ QString imgOutName = Config::copyFile(fake->location(),
+ srcPath,
+ file,
+ imgOutDir);
+ }
+
+ }
+
+ openedList.next();
+ text << Atom(Atom::ListItemNumber, openedList.numberString())
+ << Atom(Atom::ListItemLeft, openedList.styleString())
+ << Atom::ParaLeft
+ << Atom(Atom::Link, file)
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << file
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << Atom::ParaRight
+ << Atom(Atom::ListItemRight, openedList.styleString());
+ }
+ }
+ text << Atom(Atom::ListRight, openedList.styleString());
+ if (count > 0)
+ generateText(text, fake, marker);
+}
+
+void Generator::generateExampleFiles(const FakeNode *fake, CodeMarker *marker)
+{
+ if (fake->childNodes().isEmpty())
+ return;
+ generateFileList(fake, marker, Node::File, QString("Files:"));
+ generateFileList(fake, marker, Node::Image, QString("Images:"));
+}
+
+QString Generator::indent(int level, const QString& markedCode)
+{
+ if (level == 0)
+ return markedCode;
+
+ QString t;
+ int column = 0;
+
+ int i = 0;
+ while (i < (int) markedCode.length()) {
+ if (markedCode.at(i) == QLatin1Char('\n')) {
+ column = 0;
+ }
+ else {
+ if (column == 0) {
+ for (int j = 0; j < level; j++)
+ t += QLatin1Char(' ');
+ }
+ column++;
+ }
+ t += markedCode.at(i++);
+ }
+ return t;
+}
+
+QString Generator::plainCode(const QString& markedCode)
+{
+ QString t = markedCode;
+ t.replace(tag, QString());
+ t.replace(quot, QLatin1String("\""));
+ t.replace(gt, QLatin1String(">"));
+ t.replace(lt, QLatin1String("<"));
+ t.replace(amp, QLatin1String("&"));
+ return t;
+}
+
+QString Generator::typeString(const Node *node)
+{
+ switch (node->type()) {
+ case Node::Namespace:
+ return "namespace";
+ case Node::Class:
+ return "class";
+ case Node::Fake:
+ {
+ switch (node->subType()) {
+ case Node::QmlClass:
+ return "element";
+ case Node::QmlPropertyGroup:
+ return "property group";
+ case Node::QmlBasicType:
+ return "type";
+ default:
+ return "documentation";
+ }
+ }
+ case Node::Enum:
+ return "enum";
+ case Node::Typedef:
+ return "typedef";
+ case Node::Function:
+ return "function";
+ case Node::Property:
+ return "property";
+ default:
+ return "documentation";
+ }
+}
+
+/*!
+ Returns a relative path name for an image.
+ */
+QString Generator::imageFileName(const Node *relative, const QString& fileBase)
+{
+ QString userFriendlyFilePath;
+ QString filePath = Config::findFile(
+ relative->doc().location(), imageFiles, imageDirs, fileBase,
+ imgFileExts[format()], userFriendlyFilePath);
+
+ if (filePath.isEmpty())
+ return QString();
+
+ QString path = Config::copyFile(relative->doc().location(),
+ filePath,
+ userFriendlyFilePath,
+ outputDir() + QLatin1String("/images"));
+ QString images = "images";
+ if (path[0] != '/')
+ images.append(QLatin1Char('/'));
+ return images + path;
+}
+
+void Generator::setImageFileExtensions(const QStringList& extensions)
+{
+ imgFileExts[format()] = extensions;
+}
+
+void Generator::unknownAtom(const Atom *atom)
+{
+ Location::internalError(tr("unknown atom type '%1' in %2 generator")
+ .arg(atom->typeString()).arg(format()));
+}
+
+bool Generator::matchAhead(const Atom *atom, Atom::Type expectedAtomType)
+{
+ return atom->next() != 0 && atom->next()->type() == expectedAtomType;
+}
+
+void Generator::supplementAlsoList(const Node *node, QList<Text> &alsoList)
+{
+ if (node->type() == Node::Function) {
+ const FunctionNode *func = static_cast<const FunctionNode *>(node);
+ if (func->overloadNumber() == 1) {
+ QString alternateName;
+ const FunctionNode *alternateFunc = 0;
+
+ if (func->name().startsWith("set") && func->name().size() >= 4) {
+ alternateName = func->name()[3].toLower();
+ alternateName += func->name().mid(4);
+ alternateFunc = func->parent()->findFunctionNode(alternateName);
+
+ if (!alternateFunc) {
+ alternateName = "is" + func->name().mid(3);
+ alternateFunc = func->parent()->findFunctionNode(alternateName);
+ if (!alternateFunc) {
+ alternateName = "has" + func->name().mid(3);
+ alternateFunc = func->parent()->findFunctionNode(alternateName);
+ }
+ }
+ }
+ else if (!func->name().isEmpty()) {
+ alternateName = "set";
+ alternateName += func->name()[0].toUpper();
+ alternateName += func->name().mid(1);
+ alternateFunc = func->parent()->findFunctionNode(alternateName);
+ }
+
+ if (alternateFunc && alternateFunc->access() != Node::Private) {
+ int i;
+ for (i = 0; i < alsoList.size(); ++i) {
+ if (alsoList.at(i).toString().contains(alternateName))
+ break;
+ }
+
+ if (i == alsoList.size()) {
+ alternateName += "()";
+
+ Text also;
+ also << Atom(Atom::Link, alternateName)
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << alternateName
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ alsoList.prepend(also);
+ }
+ }
+ }
+ }
+}
+
+QMap<QString, QString>& Generator::formattingLeftMap()
+{
+ return fmtLeftMaps[format()];
+}
+
+QMap<QString, QString>& Generator::formattingRightMap()
+{
+ return fmtRightMaps[format()];
+}
+
+/*
+ Trims trailimng whitespace off the \a string and returns
+ the trimmed string.
+ */
+QString Generator::trimmedTrailing(const QString& string)
+{
+ QString trimmed = string;
+ while (trimmed.length() > 0 && trimmed[trimmed.length() - 1].isSpace())
+ trimmed.truncate(trimmed.length() - 1);
+ return trimmed;
+}
+
+void Generator::generateStatus(const Node *node, CodeMarker *marker)
+{
+ Text text;
+
+ switch (node->status()) {
+ case Node::Commendable:
+ case Node::Main:
+ break;
+ case Node::Preliminary:
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
+ << "This "
+ << typeString(node)
+ << " is under development and is subject to change."
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
+ << Atom::ParaRight;
+ break;
+ case Node::Deprecated:
+ text << Atom::ParaLeft;
+ if (node->isInnerNode())
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD);
+ text << "This " << typeString(node) << " is deprecated.";
+ if (node->isInnerNode())
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD);
+ text << Atom::ParaRight;
+ break;
+ case Node::Obsolete:
+ text << Atom::ParaLeft;
+ if (node->isInnerNode())
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD);
+ text << "This " << typeString(node) << " is obsolete.";
+ if (node->isInnerNode())
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD);
+ text << " It is provided to keep old source code working. "
+ << "We strongly advise against "
+ << "using it in new code." << Atom::ParaRight;
+ break;
+ case Node::Compat:
+ // reimplemented in HtmlGenerator subclass
+ if (node->isInnerNode()) {
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
+ << "This "
+ << typeString(node)
+ << " is part of the Qt 3 compatibility layer."
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
+ << " It is provided to keep old source code working. "
+ << "We strongly advise against "
+ << "using it in new code. See "
+ << Atom(Atom::AutoLink, "Porting to Qt 4")
+ << " for more information."
+ << Atom::ParaRight;
+ }
+ break;
+ case Node::Internal:
+ default:
+ break;
+ }
+ generateText(text, node, marker);
+}
+
+void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker)
+{
+ Text text;
+ Text theStockLink;
+ Node::ThreadSafeness threadSafeness = node->threadSafeness();
+
+ Text rlink;
+ rlink << Atom(Atom::Link,"reentrant")
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << "reentrant"
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+
+ Text tlink;
+ tlink << Atom(Atom::Link,"thread-safe")
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << "thread-safe"
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+
+ switch (threadSafeness) {
+ case Node::UnspecifiedSafeness:
+ break;
+ case Node::NonReentrant:
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
+ << "Warning:"
+ << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD)
+ << " This "
+ << typeString(node)
+ << " is not "
+ << rlink
+ << "."
+ << Atom::ParaRight;
+ break;
+ case Node::Reentrant:
+ case Node::ThreadSafe:
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
+ << "Note:"
+ << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD)
+ << " ";
+
+ if (node->isInnerNode()) {
+ const InnerNode* innerNode = static_cast<const InnerNode*>(node);
+ text << "All functions in this "
+ << typeString(node)
+ << " are ";
+ if (threadSafeness == Node::ThreadSafe)
+ text << tlink;
+ else
+ text << rlink;
+
+ bool exceptions = false;
+ NodeList reentrant;
+ NodeList threadsafe;
+ NodeList nonreentrant;
+ NodeList::ConstIterator c = innerNode->childNodes().begin();
+ while (c != innerNode->childNodes().end()) {
+
+ if ((*c)->status() != Node::Obsolete){
+ switch ((*c)->threadSafeness()) {
+ case Node::Reentrant:
+ reentrant.append(*c);
+ if (threadSafeness == Node::ThreadSafe)
+ exceptions = true;
+ break;
+ case Node::ThreadSafe:
+ threadsafe.append(*c);
+ if (threadSafeness == Node::Reentrant)
+ exceptions = true;
+ break;
+ case Node::NonReentrant:
+ nonreentrant.append(*c);
+ exceptions = true;
+ break;
+ default:
+ break;
+ }
+ }
+ ++c;
+ }
+ if (!exceptions)
+ text << ".";
+ else if (threadSafeness == Node::Reentrant) {
+ if (nonreentrant.isEmpty()) {
+ if (!threadsafe.isEmpty()) {
+ text << ", but ";
+ appendFullNames(text,threadsafe,innerNode,marker);
+ singularPlural(text,threadsafe);
+ text << " also " << tlink << ".";
+ }
+ else
+ text << ".";
+ }
+ else {
+ text << ", except for ";
+ appendFullNames(text,nonreentrant,innerNode,marker);
+ text << ", which";
+ singularPlural(text,nonreentrant);
+ text << " nonreentrant.";
+ if (!threadsafe.isEmpty()) {
+ text << " ";
+ appendFullNames(text,threadsafe,innerNode,marker);
+ singularPlural(text,threadsafe);
+ text << " " << tlink << ".";
+ }
+ }
+ }
+ else { // thread-safe
+ if (!nonreentrant.isEmpty() || !reentrant.isEmpty()) {
+ text << ", except for ";
+ if (!reentrant.isEmpty()) {
+ appendFullNames(text,reentrant,innerNode,marker);
+ text << ", which";
+ singularPlural(text,reentrant);
+ text << " only " << rlink;
+ if (!nonreentrant.isEmpty())
+ text << ", and ";
+ }
+ if (!nonreentrant.isEmpty()) {
+ appendFullNames(text,nonreentrant,innerNode,marker);
+ text << ", which";
+ singularPlural(text,nonreentrant);
+ text << " nonreentrant.";
+ }
+ text << ".";
+ }
+ }
+ }
+ else {
+ text << "This " << typeString(node) << " is ";
+ if (threadSafeness == Node::ThreadSafe)
+ text << tlink;
+ else
+ text << rlink;
+ text << ".";
+ }
+ text << Atom::ParaRight;
+ }
+ generateText(text,node,marker);
+}
+
+void Generator::generateSince(const Node *node, CodeMarker *marker)
+{
+ if (!node->since().isEmpty()) {
+ Text text;
+ text << Atom::ParaLeft
+ << "This "
+ << typeString(node);
+ if (node->type() == Node::Enum)
+ text << " was introduced or modified in ";
+ else
+ text << " was introduced in ";
+
+ QStringList since = node->since().split(QLatin1Char(' '));
+ if (since.count() == 1) {
+ // Handle legacy use of \since <version>.
+ if (project.isEmpty())
+ text << "version";
+ else
+ text << project;
+ text << " " << since[0];
+ } else {
+ // Reconstruct the <project> <version> string.
+ text << " " << since.join(" ");
+ }
+
+ text << "." << Atom::ParaRight;
+ generateText(text, node, marker);
+ }
+}
+
+void Generator::generateReimplementedFrom(const FunctionNode *func,
+ CodeMarker *marker)
+{
+ if (func->reimplementedFrom() != 0) {
+ const FunctionNode *from = func->reimplementedFrom();
+ if (from->access() != Node::Private &&
+ from->parent()->access() != Node::Private) {
+ Text text;
+ text << Atom::ParaLeft << "Reimplemented from ";
+ QString fullName = from->parent()->name() + "::" + from->name() + "()";
+ appendFullName(text, from->parent(), fullName, from);
+ text << "." << Atom::ParaRight;
+ generateText(text, func, marker);
+ }
+ }
+}
+
+const Atom *Generator::generateAtomList(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker,
+ bool generate,
+ int &numAtoms)
+{
+ while (atom) {
+ if (atom->type() == Atom::FormatIf) {
+ int numAtoms0 = numAtoms;
+ bool rightFormat = canHandleFormat(atom->string());
+ atom = generateAtomList(atom->next(),
+ relative,
+ marker,
+ generate && rightFormat,
+ numAtoms);
+ if (!atom)
+ return 0;
+
+ if (atom->type() == Atom::FormatElse) {
+ ++numAtoms;
+ atom = generateAtomList(atom->next(),
+ relative,
+ marker,
+ generate && !rightFormat,
+ numAtoms);
+ if (!atom)
+ return 0;
+ }
+
+ if (atom->type() == Atom::FormatEndif) {
+ if (generate && numAtoms0 == numAtoms) {
+ relative->location().warning(tr("Output format %1 not handled %2")
+ .arg(format()).arg(outFileName()));
+ Atom unhandledFormatAtom(Atom::UnhandledFormat, format());
+ generateAtomList(&unhandledFormatAtom,
+ relative,
+ marker,
+ generate,
+ numAtoms);
+ }
+ atom = atom->next();
+ }
+ }
+ else if (atom->type() == Atom::FormatElse ||
+ atom->type() == Atom::FormatEndif) {
+ return atom;
+ }
+ else {
+ int n = 1;
+ if (generate) {
+ n += generateAtom(atom, relative, marker);
+ numAtoms += n;
+ }
+ while (n-- > 0)
+ atom = atom->next();
+ }
+ }
+ return 0;
+}
+
+void Generator::appendFullName(Text& text,
+ const Node *apparentNode,
+ const Node *relative,
+ CodeMarker *marker,
+ const Node *actualNode)
+{
+ if (actualNode == 0)
+ actualNode = apparentNode;
+ text << Atom(Atom::LinkNode, CodeMarker::stringForNode(actualNode))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, marker->plainFullName(apparentNode, relative))
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+}
+
+void Generator::appendFullName(Text& text,
+ const Node *apparentNode,
+ const QString& fullName,
+ const Node *actualNode)
+{
+ if (actualNode == 0)
+ actualNode = apparentNode;
+ text << Atom(Atom::LinkNode, CodeMarker::stringForNode(actualNode))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, fullName)
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+}
+
+void Generator::appendFullNames(Text& text,
+ const NodeList& nodes,
+ const Node* relative,
+ CodeMarker* marker)
+{
+ NodeList::ConstIterator n = nodes.begin();
+ int index = 0;
+ while (n != nodes.end()) {
+ appendFullName(text,*n,relative,marker);
+ text << comma(index++,nodes.count());
+ ++n;
+ }
+}
+
+void Generator::appendSortedNames(Text& text,
+ const ClassNode *classe,
+ const QList<RelatedClass> &classes,
+ CodeMarker *marker)
+{
+ QList<RelatedClass>::ConstIterator r;
+ QMap<QString,Text> classMap;
+ int index = 0;
+
+ r = classes.begin();
+ while (r != classes.end()) {
+ if ((*r).node->access() == Node::Public &&
+ (*r).node->status() != Node::Internal
+ && !(*r).node->doc().isEmpty()) {
+ Text className;
+ appendFullName(className, (*r).node, classe, marker);
+ classMap[className.toString().toLower()] = className;
+ }
+ ++r;
+ }
+
+ QStringList classNames = classMap.keys();
+ classNames.sort();
+
+ foreach (const QString &className, classNames) {
+ text << classMap[className];
+ text << separator(index++, classNames.count());
+ }
+}
+
+void Generator::appendSortedQmlNames(Text& text,
+ const Node* base,
+ const NodeList& subs,
+ CodeMarker *marker)
+{
+ QMap<QString,Text> classMap;
+ int index = 0;
+
+ for (int i = 0; i < subs.size(); ++i) {
+ Text t;
+ if (!base->isQtQuickNode() || !subs[i]->isQtQuickNode() ||
+ (base->qmlModuleIdentifier() == subs[i]->qmlModuleIdentifier())) {
+ appendFullName(t, subs[i], base, marker);
+ classMap[t.toString().toLower()] = t;
+ }
+ }
+
+ QStringList names = classMap.keys();
+ names.sort();
+
+ foreach (const QString &name, names) {
+ text << classMap[name];
+ text << separator(index++, names.count());
+ }
+}
+
+int Generator::skipAtoms(const Atom *atom, Atom::Type type) const
+{
+ int skipAhead = 0;
+ atom = atom->next();
+ while (atom != 0 && atom->type() != type) {
+ skipAhead++;
+ atom = atom->next();
+ }
+ return skipAhead;
+}
+
+QString Generator::fullName(const Node *node,
+ const Node *relative,
+ CodeMarker *marker) const
+{
+ if (node->type() == Node::Fake) {
+ const FakeNode* fn = static_cast<const FakeNode *>(node);
+#if 0
+ // Removed for QTBUG-22870
+ if (!fn->qmlModuleIdentifier().isEmpty())
+ return fn->qmlModuleIdentifier() + QLatin1Char(' ') + fn->title();
+#endif
+ return fn->title();
+ }
+ else if (node->type() == Node::Class &&
+ !(static_cast<const ClassNode *>(node))->serviceName().isEmpty())
+ return (static_cast<const ClassNode *>(node))->serviceName();
+ else
+ return marker->plainFullName(node, relative);
+}
+
+QString Generator::outputPrefix(const QString &nodeType)
+{
+ return outputPrefixes[nodeType];
+}
+
+/*!
+ Looks up the tag \a t in the map of metadata values for the
+ current topic in \a inner. If a value for the tag is found,
+ the value is returned.
+
+ \note If \a t is found in the metadata map, it is erased.
+ i.e. Once you call this function for a particular \a t,
+ you consume \a t.
+ */
+QString Generator::getMetadataElement(const InnerNode* inner, const QString& t)
+{
+ QString s;
+ QStringMultiMap& metaTagMap = const_cast<QStringMultiMap&>(inner->doc().metaTagMap());
+ QStringMultiMap::iterator i = metaTagMap.find(t);
+ if (i != metaTagMap.end()) {
+ s = i.value();
+ metaTagMap.erase(i);
+ }
+ return s;
+}
+
+/*!
+ Looks up the tag \a t in the map of metadata values for the
+ current topic in \a inner. If values for the tag are found,
+ they are returned in a string list.
+
+ \note If \a t is found in the metadata map, all the pairs
+ having the key \a t are erased. i.e. Once you call this
+ function for a particular \a t, you consume \a t.
+ */
+QStringList Generator::getMetadataElements(const InnerNode* inner, const QString& t)
+{
+ QStringList s;
+ QStringMultiMap& metaTagMap = const_cast<QStringMultiMap&>(inner->doc().metaTagMap());
+ s = metaTagMap.values(t);
+ if (!s.isEmpty())
+ metaTagMap.remove(t);
+ return s;
+}
+
+/*!
+ For generating the "New Classes... in 4.6" section on the
+ What's New in 4.6" page.
+ */
+void Generator::findAllSince(const InnerNode *node)
+{
+ NodeList::const_iterator child = node->childNodes().constBegin();
+
+ // Traverse the tree, starting at the node supplied.
+
+ while (child != node->childNodes().constEnd()) {
+
+ QString sinceString = (*child)->since();
+
+ if (((*child)->access() != Node::Private) && !sinceString.isEmpty()) {
+
+ // Insert a new entry into each map for each new since string found.
+ NewSinceMaps::iterator nsmap = newSinceMaps.find(sinceString);
+ if (nsmap == newSinceMaps.end())
+ nsmap = newSinceMaps.insert(sinceString,NodeMultiMap());
+
+ NewClassMaps::iterator ncmap = newClassMaps.find(sinceString);
+ if (ncmap == newClassMaps.end())
+ ncmap = newClassMaps.insert(sinceString,NodeMap());
+
+ NewClassMaps::iterator nqcmap = newQmlClassMaps.find(sinceString);
+ if (nqcmap == newQmlClassMaps.end())
+ nqcmap = newQmlClassMaps.insert(sinceString,NodeMap());
+
+ if ((*child)->type() == Node::Function) {
+ // Insert functions into the general since map.
+ FunctionNode *func = static_cast<FunctionNode *>(*child);
+ if ((func->status() > Node::Obsolete) &&
+ (func->metaness() != FunctionNode::Ctor) &&
+ (func->metaness() != FunctionNode::Dtor)) {
+ nsmap.value().insert(func->name(),(*child));
+ }
+ }
+ else if ((*child)->url().isEmpty()) {
+ if ((*child)->type() == Node::Class && !(*child)->doc().isEmpty()) {
+ // Insert classes into the since and class maps.
+ QString className = (*child)->name();
+ if ((*child)->parent() &&
+ (*child)->parent()->type() == Node::Namespace &&
+ !(*child)->parent()->name().isEmpty())
+ className = (*child)->parent()->name()+"::"+className;
+
+ nsmap.value().insert(className,(*child));
+ ncmap.value().insert(className,(*child));
+ }
+ else if ((*child)->subType() == Node::QmlClass) {
+ // Insert QML elements into the since and element maps.
+ QString className = (*child)->name();
+ if ((*child)->parent() &&
+ (*child)->parent()->type() == Node::Namespace &&
+ !(*child)->parent()->name().isEmpty())
+ className = (*child)->parent()->name()+"::"+className;
+
+ nsmap.value().insert(className,(*child));
+ nqcmap.value().insert(className,(*child));
+ }
+ else if ((*child)->type() == Node::QmlProperty) {
+ // Insert QML properties into the since map.
+ QString propertyName = (*child)->name();
+ nsmap.value().insert(propertyName,(*child));
+ }
+ }
+ else {
+ // Insert external documents into the general since map.
+ QString name = (*child)->name();
+ if ((*child)->parent() &&
+ (*child)->parent()->type() == Node::Namespace &&
+ !(*child)->parent()->name().isEmpty())
+ name = (*child)->parent()->name()+"::"+name;
+
+ nsmap.value().insert(name,(*child));
+ }
+
+ // Find child nodes with since commands.
+ if ((*child)->isInnerNode()) {
+ findAllSince(static_cast<InnerNode *>(*child));
+ }
+ }
+ ++child;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/generator.h b/src/tools/qdoc/generator.h
new file mode 100644
index 0000000000..4021a85f61
--- /dev/null
+++ b/src/tools/qdoc/generator.h
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ generator.h
+*/
+
+#ifndef GENERATOR_H
+#define GENERATOR_H
+
+#include <qlist.h>
+#include <qmap.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include "node.h"
+#include "text.h"
+
+QT_BEGIN_NAMESPACE
+
+typedef QMap<QString, const Node*> NodeMap;
+typedef QMultiMap<QString, Node*> NodeMultiMap;
+typedef QMap<QString, NodeMultiMap> NewSinceMaps;
+typedef QMap<Node*, NodeMultiMap> ParentMaps;
+typedef QMap<QString, NodeMap> NewClassMaps;
+
+class ClassNode;
+class Config;
+class CodeMarker;
+class FakeNode;
+class FunctionNode;
+class InnerNode;
+class Location;
+class NamespaceNode;
+class Node;
+class Tree;
+
+class Generator
+{
+public:
+ Generator();
+ virtual ~Generator();
+
+ virtual void initializeGenerator(const Config &config);
+ virtual void terminateGenerator();
+ virtual QString format() = 0;
+ virtual bool canHandleFormat(const QString &format) { return format == this->format(); }
+ virtual void generateTree(const Tree *tree) = 0;
+
+ static void initialize(const Config& config);
+ static void terminate();
+ static Generator *generatorForFormat(const QString& format);
+ static const QString& outputDir() { return outDir_; }
+ static const QString& baseDir() { return baseDir_; }
+
+protected:
+ virtual void startText(const Node *relative, CodeMarker *marker);
+ virtual void endText(const Node *relative, CodeMarker *marker);
+ virtual int generateAtom(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker);
+ virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker);
+ virtual void generateFakeNode(const FakeNode *fake, CodeMarker *marker);
+
+ virtual bool generateText(const Text& text,
+ const Node *relative,
+ CodeMarker *marker);
+ virtual bool generateQmlText(const Text& text,
+ const Node *relative,
+ CodeMarker *marker,
+ const QString& qmlName);
+ virtual void generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker);
+ virtual void generateBody(const Node *node, CodeMarker *marker);
+ virtual void generateAlsoList(const Node *node, CodeMarker *marker);
+ virtual void generateMaintainerList(const InnerNode* node, CodeMarker* marker);
+ virtual void generateInherits(const ClassNode *classe,
+ CodeMarker *marker);
+ virtual void generateInheritedBy(const ClassNode *classe,
+ CodeMarker *marker);
+
+ void generateThreadSafeness(const Node *node, CodeMarker *marker);
+ void generateSince(const Node *node, CodeMarker *marker);
+ void generateStatus(const Node *node, CodeMarker *marker);
+ const Atom* generateAtomList(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker,
+ bool generate,
+ int& numGeneratedAtoms);
+ void generateFileList(const FakeNode* fake,
+ CodeMarker* marker,
+ Node::SubType subtype,
+ const QString& tag);
+ void generateExampleFiles(const FakeNode *fake, CodeMarker *marker);
+
+ virtual int skipAtoms(const Atom *atom, Atom::Type type) const;
+ virtual QString fullName(const Node *node,
+ const Node *relative,
+ CodeMarker *marker) const;
+
+ virtual QString outFileName() { return QString(); }
+
+ QString indent(int level, const QString& markedCode);
+ QString plainCode(const QString& markedCode);
+ virtual QString typeString(const Node *node);
+ virtual QString imageFileName(const Node *relative, const QString& fileBase);
+ void setImageFileExtensions(const QStringList& extensions);
+ void unknownAtom(const Atom *atom);
+ QMap<QString, QString> &formattingLeftMap();
+ QMap<QString, QString> &formattingRightMap();
+ QMap<QString, QStringList> editionModuleMap;
+ QMap<QString, QStringList> editionGroupMap;
+
+ static QString trimmedTrailing(const QString &string);
+ static bool matchAhead(const Atom *atom, Atom::Type expectedAtomType);
+ static void supplementAlsoList(const Node *node, QList<Text> &alsoList);
+ static QString outputPrefix(const QString &nodeType);
+
+ QString getMetadataElement(const InnerNode* inner, const QString& t);
+ QStringList getMetadataElements(const InnerNode* inner, const QString& t);
+ void findAllSince(const InnerNode *node);
+
+private:
+ void generateReimplementedFrom(const FunctionNode *func,
+ CodeMarker *marker);
+ void appendFullName(Text& text,
+ const Node *apparentNode,
+ const Node *relative,
+ CodeMarker *marker,
+ const Node *actualNode = 0);
+ void appendFullName(Text& text,
+ const Node *apparentNode,
+ const QString& fullName,
+ const Node *actualNode);
+ void appendFullNames(Text& text,
+ const NodeList& nodes,
+ const Node* relative,
+ CodeMarker* marker);
+ void appendSortedNames(Text& text,
+ const ClassNode *classe,
+ const QList<RelatedClass> &classes,
+ CodeMarker *marker);
+
+protected:
+ void appendSortedQmlNames(Text& text,
+ const Node* base,
+ const NodeList& subs,
+ CodeMarker *marker);
+
+ static QString sinceTitles[];
+ NewSinceMaps newSinceMaps;
+ NewClassMaps newClassMaps;
+ NewClassMaps newQmlClassMaps;
+
+private:
+ QString amp;
+ QString lt;
+ QString gt;
+ QString quot;
+ QRegExp tag;
+
+ static QList<Generator *> generators;
+ static QMap<QString, QMap<QString, QString> > fmtLeftMaps;
+ static QMap<QString, QMap<QString, QString> > fmtRightMaps;
+ static QMap<QString, QStringList> imgFileExts;
+ static QSet<QString> outputFormats;
+ static QStringList imageFiles;
+ static QStringList imageDirs;
+ static QStringList exampleDirs;
+ static QStringList exampleImgExts;
+ static QStringList scriptFiles;
+ static QStringList scriptDirs;
+ static QStringList styleFiles;
+ static QStringList styleDirs;
+ static QString outDir_;
+ static QString baseDir_;
+ static QString project;
+ static QHash<QString, QString> outputPrefixes;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/helpprojectwriter.cpp b/src/tools/qdoc/helpprojectwriter.cpp
new file mode 100644
index 0000000000..096877211d
--- /dev/null
+++ b/src/tools/qdoc/helpprojectwriter.cpp
@@ -0,0 +1,772 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QHash>
+#include <QMap>
+
+#include "atom.h"
+#include "helpprojectwriter.h"
+#include "htmlgenerator.h"
+#include "config.h"
+#include "node.h"
+#include "tree.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+HelpProjectWriter::HelpProjectWriter(const Config &config, const QString &defaultFileName)
+{
+ // The output directory should already have been checked by the calling
+ // generator.
+ outputDir = config.getOutputDir();
+
+ QStringList names = config.getStringList(CONFIG_QHP + Config::dot + "projects");
+
+ foreach (const QString &projectName, names) {
+ HelpProject project;
+ project.name = projectName;
+
+ QString prefix = CONFIG_QHP + Config::dot + projectName + Config::dot;
+ project.helpNamespace = config.getString(prefix + "namespace");
+ project.virtualFolder = config.getString(prefix + "virtualFolder");
+ project.fileName = config.getString(prefix + "file");
+ if (project.fileName.isEmpty())
+ project.fileName = defaultFileName;
+ project.extraFiles = config.getStringSet(prefix + "extraFiles");
+ project.indexTitle = config.getString(prefix + "indexTitle");
+ project.indexRoot = config.getString(prefix + "indexRoot");
+ project.filterAttributes = config.getStringList(prefix + "filterAttributes").toSet();
+ QSet<QString> customFilterNames = config.subVars(prefix + "customFilters");
+ foreach (const QString &filterName, customFilterNames) {
+ QString name = config.getString(prefix + "customFilters" + Config::dot + filterName + Config::dot + "name");
+ QSet<QString> filters = config.getStringList(prefix + "customFilters" + Config::dot + filterName + Config::dot + "filterAttributes").toSet();
+ project.customFilters[name] = filters;
+ }
+ //customFilters = config.defs.
+
+ foreach (QString name, config.getStringSet(prefix + "excluded"))
+ project.excluded.insert(name.replace("\\", "/"));
+
+ foreach (const QString &name, config.getStringList(prefix + "subprojects")) {
+ SubProject subproject;
+ QString subprefix = prefix + "subprojects" + Config::dot + name + Config::dot;
+ subproject.title = config.getString(subprefix + "title");
+ subproject.indexTitle = config.getString(subprefix + "indexTitle");
+ subproject.sortPages = config.getBool(subprefix + "sortPages");
+ subproject.type = config.getString(subprefix + "type");
+ readSelectors(subproject, config.getStringList(subprefix + "selectors"));
+ project.subprojects[name] = subproject;
+ }
+
+ if (project.subprojects.isEmpty()) {
+ SubProject subproject;
+ readSelectors(subproject, config.getStringList(prefix + "selectors"));
+ project.subprojects[""] = subproject;
+ }
+
+ projects.append(project);
+ }
+}
+
+void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList &selectors)
+{
+ QHash<QString, Node::Type> typeHash;
+ typeHash["namespace"] = Node::Namespace;
+ typeHash["class"] = Node::Class;
+ typeHash["fake"] = Node::Fake;
+ typeHash["enum"] = Node::Enum;
+ typeHash["typedef"] = Node::Typedef;
+ typeHash["function"] = Node::Function;
+ typeHash["property"] = Node::Property;
+ typeHash["variable"] = Node::Variable;
+ typeHash["target"] = Node::Target;
+#ifdef QDOC_QML
+ typeHash["qmlproperty"] = Node::QmlProperty;
+ typeHash["qmlsignal"] = Node::QmlSignal;
+ typeHash["qmlsignalhandler"] = Node::QmlSignalHandler;
+ typeHash["qmlmethod"] = Node::QmlMethod;
+#endif
+
+ QHash<QString, Node::SubType> subTypeHash;
+ subTypeHash["example"] = Node::Example;
+ subTypeHash["headerfile"] = Node::HeaderFile;
+ subTypeHash["file"] = Node::File;
+ subTypeHash["group"] = Node::Group;
+ subTypeHash["module"] = Node::Module;
+ subTypeHash["page"] = Node::Page;
+ subTypeHash["externalpage"] = Node::ExternalPage;
+#ifdef QDOC_QML
+ subTypeHash["qmlclass"] = Node::QmlClass;
+ subTypeHash["qmlpropertygroup"] = Node::QmlPropertyGroup;
+ subTypeHash["qmlbasictype"] = Node::QmlBasicType;
+#endif
+
+ QSet<Node::SubType> allSubTypes = QSet<Node::SubType>::fromList(subTypeHash.values());
+
+ foreach (const QString &selector, selectors) {
+ QStringList pieces = selector.split(QLatin1Char(':'));
+ if (pieces.size() == 1) {
+ QString lower = selector.toLower();
+ if (typeHash.contains(lower))
+ subproject.selectors[typeHash[lower]] = allSubTypes;
+ } else if (pieces.size() >= 2) {
+ QString lower = pieces[0].toLower();
+ pieces = pieces[1].split(QLatin1Char(','));
+ if (typeHash.contains(lower)) {
+ QSet<Node::SubType> subTypes;
+ for (int i = 0; i < pieces.size(); ++i) {
+ QString lower = pieces[i].toLower();
+ if (subTypeHash.contains(lower))
+ subTypes.insert(subTypeHash[lower]);
+ }
+ subproject.selectors[typeHash[lower]] = subTypes;
+ }
+ }
+ }
+}
+
+void HelpProjectWriter::addExtraFile(const QString &file)
+{
+ for (int i = 0; i < projects.size(); ++i)
+ projects[i].extraFiles.insert(file);
+}
+
+void HelpProjectWriter::addExtraFiles(const QSet<QString> &files)
+{
+ for (int i = 0; i < projects.size(); ++i)
+ projects[i].extraFiles.unite(files);
+}
+
+/*
+ Returns a list of strings describing the keyword details for a given node.
+
+ The first string is the human-readable name to be shown in Assistant.
+ The second string is a unique identifier.
+ The third string is the location of the documentation for the keyword.
+*/
+QStringList HelpProjectWriter::keywordDetails(const Node *node) const
+{
+ QStringList details;
+
+ if (node->type() == Node::QmlProperty) {
+ // "name"
+ details << node->name();
+ // "id"
+ details << node->parent()->parent()->name()+"::"+node->name();
+ }
+ else if (node->parent() && !node->parent()->name().isEmpty()) {
+ // "name"
+ if (node->type() == Node::Enum || node->type() == Node::Typedef)
+ details << node->parent()->name()+"::"+node->name();
+ else
+ details << node->name();
+ // "id"
+ details << node->parent()->name()+"::"+node->name();
+ }
+ else if (node->type() == Node::Fake) {
+ const FakeNode *fake = static_cast<const FakeNode *>(node);
+ if (fake->subType() == Node::QmlClass) {
+ details << (QmlClassNode::qmlOnly ? fake->name() : fake->fullTitle());
+ details << "QML." + fake->name();
+ }
+ else {
+ details << fake->fullTitle();
+ details << fake->fullTitle();
+ }
+ }
+ else {
+ details << node->name();
+ details << node->name();
+ }
+ details << HtmlGenerator::fullDocumentLocation(node,true);
+ return details;
+}
+
+bool HelpProjectWriter::generateSection(HelpProject &project,
+ QXmlStreamWriter & /* writer */,
+ const Node *node)
+{
+ if (!node->url().isEmpty())
+ return false;
+
+ if (node->access() == Node::Private || node->status() == Node::Internal)
+ return false;
+
+ if (node->name().isEmpty())
+ return true;
+
+ QString docPath = node->doc().location().filePath();
+ if (!docPath.isEmpty() && project.excluded.contains(docPath))
+ return false;
+
+ QString objName;
+ if (node->type() == Node::Fake) {
+ const FakeNode *fake = static_cast<const FakeNode *>(node);
+ objName = fake->fullTitle();
+ }
+ else
+ objName = node->fullDocumentName();
+
+ // Only add nodes to the set for each subproject if they match a selector.
+ // Those that match will be listed in the table of contents.
+
+ foreach (const QString &name, project.subprojects.keys()) {
+ SubProject subproject = project.subprojects[name];
+ // No selectors: accept all nodes.
+ if (subproject.selectors.isEmpty()) {
+ project.subprojects[name].nodes[objName] = node;
+ }
+ else if (subproject.selectors.contains(node->type())) {
+ // Accept only the node types in the selectors hash.
+ if (node->type() != Node::Fake)
+ project.subprojects[name].nodes[objName] = node;
+ else {
+ // Accept only fake nodes with subtypes contained in the selector's
+ // mask.
+ const FakeNode *fakeNode = static_cast<const FakeNode *>(node);
+ if (subproject.selectors[node->type()].contains(fakeNode->subType()) &&
+ fakeNode->subType() != Node::ExternalPage &&
+ !fakeNode->fullTitle().isEmpty()) {
+
+ project.subprojects[name].nodes[objName] = node;
+ }
+ }
+ }
+ }
+
+ switch (node->type()) {
+
+ case Node::Class:
+ project.keywords.append(keywordDetails(node));
+ project.files.insert(HtmlGenerator::fullDocumentLocation(node,true));
+ break;
+
+ case Node::Namespace:
+ project.keywords.append(keywordDetails(node));
+ project.files.insert(HtmlGenerator::fullDocumentLocation(node,true));
+ break;
+
+ case Node::Enum:
+ project.keywords.append(keywordDetails(node));
+ {
+ const EnumNode *enumNode = static_cast<const EnumNode*>(node);
+ foreach (const EnumItem &item, enumNode->items()) {
+ QStringList details;
+
+ if (enumNode->itemAccess(item.name()) == Node::Private)
+ continue;
+
+ if (!node->parent()->name().isEmpty()) {
+ details << node->parent()->name()+"::"+item.name(); // "name"
+ details << node->parent()->name()+"::"+item.name(); // "id"
+ } else {
+ details << item.name(); // "name"
+ details << item.name(); // "id"
+ }
+ details << HtmlGenerator::fullDocumentLocation(node,true);
+ project.keywords.append(details);
+ }
+ }
+ break;
+
+ case Node::Property:
+ case Node::QmlProperty:
+ case Node::QmlSignal:
+ case Node::QmlSignalHandler:
+ case Node::QmlMethod:
+ project.keywords.append(keywordDetails(node));
+ break;
+
+ case Node::Function:
+ {
+ const FunctionNode *funcNode = static_cast<const FunctionNode *>(node);
+
+ // Only insert keywords for non-constructors. Constructors are covered
+ // by the classes themselves.
+
+ if (funcNode->metaness() != FunctionNode::Ctor)
+ project.keywords.append(keywordDetails(node));
+
+ // Insert member status flags into the entries for the parent
+ // node of the function, or the node it is related to.
+ // Since parent nodes should have already been inserted into
+ // the set of files, we only need to ensure that related nodes
+ // are inserted.
+
+ if (node->relates()) {
+ project.memberStatus[node->relates()].insert(node->status());
+ project.files.insert(HtmlGenerator::fullDocumentLocation(node->relates(),true));
+ } else if (node->parent())
+ project.memberStatus[node->parent()].insert(node->status());
+ }
+ break;
+
+ case Node::Typedef:
+ {
+ const TypedefNode *typedefNode = static_cast<const TypedefNode *>(node);
+ QStringList typedefDetails = keywordDetails(node);
+ const EnumNode *enumNode = typedefNode->associatedEnum();
+ // Use the location of any associated enum node in preference
+ // to that of the typedef.
+ if (enumNode)
+ typedefDetails[2] = HtmlGenerator::fullDocumentLocation(enumNode,true);
+
+ project.keywords.append(typedefDetails);
+ }
+ break;
+
+ case Node::Variable:
+ {
+ QString location = HtmlGenerator::fullDocumentLocation(node,true);
+ project.files.insert(location.left(location.lastIndexOf(QLatin1Char('#'))));
+ project.keywords.append(keywordDetails(node));
+ }
+ break;
+
+ // Fake nodes (such as manual pages) contain subtypes, titles and other
+ // attributes.
+ case Node::Fake: {
+ const FakeNode *fakeNode = static_cast<const FakeNode*>(node);
+ if (fakeNode->subType() != Node::ExternalPage &&
+ !fakeNode->fullTitle().isEmpty()) {
+
+ if (fakeNode->subType() != Node::File) {
+ if (fakeNode->doc().hasKeywords()) {
+ foreach (const Atom *keyword, fakeNode->doc().keywords()) {
+ if (!keyword->string().isEmpty()) {
+ QStringList details;
+ details << keyword->string()
+ << keyword->string()
+ << HtmlGenerator::fullDocumentLocation(node,true) +
+ QLatin1Char('#') + Doc::canonicalTitle(keyword->string());
+ project.keywords.append(details);
+ } else
+ fakeNode->doc().location().warning(
+ tr("Bad keyword in %1").arg(HtmlGenerator::fullDocumentLocation(node,true))
+ );
+ }
+ }
+ project.keywords.append(keywordDetails(node));
+ }
+ /*
+ if (fakeNode->doc().hasTableOfContents()) {
+ foreach (const Atom *item, fakeNode->doc().tableOfContents()) {
+ QString title = Text::sectionHeading(item).toString();
+ if (!title.isEmpty()) {
+ QStringList details;
+ details << title
+ << title
+ << HtmlGenerator::fullDocumentLocation(node,true) +
+ QLatin1Char('#') + Doc::canonicalTitle(title);
+ project.keywords.append(details);
+ } else
+ fakeNode->doc().location().warning(
+ tr("Bad contents item in %1").arg(HtmlGenerator::fullDocumentLocation(node,true)));
+ }
+ }
+*/
+ project.files.insert(HtmlGenerator::fullDocumentLocation(node,true));
+ }
+ break;
+ }
+ default:
+ ;
+ }
+
+ // Add all images referenced in the page to the set of files to include.
+ const Atom *atom = node->doc().body().firstAtom();
+ while (atom) {
+ if (atom->type() == Atom::Image || atom->type() == Atom::InlineImage) {
+ // Images are all placed within a single directory regardless of
+ // whether the source images are in a nested directory structure.
+ QStringList pieces = atom->string().split(QLatin1Char('/'));
+ project.files.insert("images/" + pieces.last());
+ }
+ atom = atom->next();
+ }
+
+ return true;
+}
+
+void HelpProjectWriter::generateSections(HelpProject &project,
+ QXmlStreamWriter &writer, const Node *node)
+{
+ if (!generateSection(project, writer, node))
+ return;
+
+ if (node->isInnerNode()) {
+ const InnerNode *inner = static_cast<const InnerNode *>(node);
+
+ // Ensure that we don't visit nodes more than once.
+ QMap<QString, const Node*> childMap;
+ foreach (const Node *node, inner->childNodes()) {
+ if (node->access() == Node::Private)
+ continue;
+ if (node->type() == Node::Fake) {
+ /*
+ Don't visit QML property group nodes,
+ but visit their children, which are all
+ QML property nodes.
+ */
+ if (node->subType() == Node::QmlPropertyGroup) {
+ const InnerNode* inner = static_cast<const InnerNode*>(node);
+ foreach (const Node* n, inner->childNodes()) {
+ if (n->access() == Node::Private)
+ continue;
+ childMap[n->fullDocumentName()] = n;
+ }
+ }
+ else
+ childMap[static_cast<const FakeNode *>(node)->fullTitle()] = node;
+ }
+ else {
+ if (node->type() == Node::Function) {
+ const FunctionNode *funcNode = static_cast<const FunctionNode *>(node);
+ if (funcNode->isOverload())
+ continue;
+ }
+ childMap[node->fullDocumentName()] = node;
+ }
+ }
+
+ foreach (const Node *child, childMap)
+ generateSections(project, writer, child);
+ }
+}
+
+void HelpProjectWriter::generate(const Tree *tre)
+{
+ this->tree = tre;
+ for (int i = 0; i < projects.size(); ++i)
+ generateProject(projects[i]);
+}
+
+void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer,
+ const Node *node)
+{
+ QString href = HtmlGenerator::fullDocumentLocation(node,true);
+ QString objName = node->name();
+
+ switch (node->type()) {
+
+ case Node::Class:
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", href);
+ if (node->parent() && !node->parent()->name().isEmpty())
+ writer.writeAttribute("title", tr("%1::%2 Class Reference").arg(node->parent()->name()).arg(objName));
+ else
+ writer.writeAttribute("title", tr("%1 Class Reference").arg(objName));
+
+ // Write subsections for all members, obsolete members and Qt 3
+ // members.
+ if (!project.memberStatus[node].isEmpty()) {
+ QString membersPath = href.left(href.size()-5) + "-members.html";
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", membersPath);
+ writer.writeAttribute("title", tr("List of all members"));
+ writer.writeEndElement(); // section
+ project.files.insert(membersPath);
+ }
+ if (project.memberStatus[node].contains(Node::Compat)) {
+ QString compatPath = href.left(href.size()-5) + "-qt3.html";
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", compatPath);
+ writer.writeAttribute("title", tr("Qt 3 support members"));
+ writer.writeEndElement(); // section
+ project.files.insert(compatPath);
+ }
+ if (project.memberStatus[node].contains(Node::Obsolete)) {
+ QString obsoletePath = href.left(href.size()-5) + "-obsolete.html";
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", obsoletePath);
+ writer.writeAttribute("title", tr("Obsolete members"));
+ writer.writeEndElement(); // section
+ project.files.insert(obsoletePath);
+ }
+
+ writer.writeEndElement(); // section
+ break;
+
+ case Node::Namespace:
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", href);
+ writer.writeAttribute("title", objName);
+ writer.writeEndElement(); // section
+ break;
+
+ case Node::Fake: {
+ // Fake nodes (such as manual pages) contain subtypes, titles and other
+ // attributes.
+ const FakeNode *fakeNode = static_cast<const FakeNode*>(node);
+
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", href);
+ writer.writeAttribute("title", fakeNode->fullTitle());
+
+ if ((fakeNode->subType() == Node::HeaderFile) || (fakeNode->subType() == Node::QmlClass)) {
+ // Write subsections for all members, obsolete members and Qt 3
+ // members.
+ if (!project.memberStatus[node].isEmpty() || (fakeNode->subType() == Node::QmlClass)) {
+ QString membersPath = href.left(href.size()-5) + "-members.html";
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", membersPath);
+ writer.writeAttribute("title", tr("List of all members"));
+ writer.writeEndElement(); // section
+ project.files.insert(membersPath);
+ }
+ if (project.memberStatus[node].contains(Node::Compat)) {
+ QString compatPath = href.left(href.size()-5) + "-qt3.html";
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", compatPath);
+ writer.writeAttribute("title", tr("Qt 3 support members"));
+ writer.writeEndElement(); // section
+ project.files.insert(compatPath);
+ }
+ if (project.memberStatus[node].contains(Node::Obsolete)) {
+ QString obsoletePath = href.left(href.size()-5) + "-obsolete.html";
+ writer.writeStartElement("section");
+ writer.writeAttribute("ref", obsoletePath);
+ writer.writeAttribute("title", tr("Obsolete members"));
+ writer.writeEndElement(); // section
+ project.files.insert(obsoletePath);
+ }
+ }
+
+ writer.writeEndElement(); // section
+ }
+ break;
+ default:
+ ;
+ }
+}
+
+void HelpProjectWriter::generateProject(HelpProject &project)
+{
+ const Node *rootNode;
+ if (!project.indexRoot.isEmpty())
+ rootNode = tree->findFakeNodeByTitle(project.indexRoot);
+ else
+ rootNode = tree->root();
+
+ if (!rootNode)
+ return;
+
+ project.files.clear();
+ project.keywords.clear();
+
+ QFile file(outputDir + QDir::separator() + project.fileName);
+ if (!file.open(QFile::WriteOnly | QFile::Text))
+ return;
+
+ QXmlStreamWriter writer(&file);
+ writer.setAutoFormatting(true);
+ writer.writeStartDocument();
+ writer.writeStartElement("QtHelpProject");
+ writer.writeAttribute("version", "1.0");
+
+ // Write metaData, virtualFolder and namespace elements.
+ writer.writeTextElement("namespace", project.helpNamespace);
+ writer.writeTextElement("virtualFolder", project.virtualFolder);
+
+ // Write customFilter elements.
+ QHash<QString, QSet<QString> >::ConstIterator it;
+ for (it = project.customFilters.begin(); it != project.customFilters.end(); ++it) {
+ writer.writeStartElement("customFilter");
+ writer.writeAttribute("name", it.key());
+ foreach (const QString &filter, it.value())
+ writer.writeTextElement("filterAttribute", filter);
+ writer.writeEndElement(); // customFilter
+ }
+
+ // Start the filterSection.
+ writer.writeStartElement("filterSection");
+
+ // Write filterAttribute elements.
+ foreach (const QString &filterName, project.filterAttributes)
+ writer.writeTextElement("filterAttribute", filterName);
+
+ writer.writeStartElement("toc");
+ writer.writeStartElement("section");
+ const Node* node = tree->findFakeNodeByTitle(project.indexTitle);
+ if (node == 0)
+ node = tree->findNode(QStringList("index.html"));
+ QString indexPath;
+ if (node)
+ indexPath = HtmlGenerator::fullDocumentLocation(node,true);
+ else
+ indexPath = "index.html";
+ writer.writeAttribute("ref", indexPath);
+ writer.writeAttribute("title", project.indexTitle);
+ project.files.insert(HtmlGenerator::fullDocumentLocation(rootNode));
+
+ generateSections(project, writer, rootNode);
+
+ foreach (const QString &name, project.subprojects.keys()) {
+ SubProject subproject = project.subprojects[name];
+
+ if (subproject.type == QLatin1String("manual")) {
+
+ const FakeNode *indexPage = tree->findFakeNodeByTitle(subproject.indexTitle);
+ if (indexPage) {
+ Text indexBody = indexPage->doc().body();
+ const Atom *atom = indexBody.firstAtom();
+ QStack<int> sectionStack;
+ bool inItem = false;
+
+ while (atom) {
+ switch (atom->type()) {
+ case Atom::ListLeft:
+ sectionStack.push(0);
+ break;
+ case Atom::ListRight:
+ if (sectionStack.pop() > 0)
+ writer.writeEndElement(); // section
+ break;
+ case Atom::ListItemLeft:
+ inItem = true;
+ break;
+ case Atom::ListItemRight:
+ inItem = false;
+ break;
+ case Atom::Link:
+ if (inItem) {
+ if (sectionStack.top() > 0)
+ writer.writeEndElement(); // section
+
+ const FakeNode *page = tree->findFakeNodeByTitle(atom->string());
+ writer.writeStartElement("section");
+ QString indexPath = HtmlGenerator::fullDocumentLocation(page,true);
+ writer.writeAttribute("ref", indexPath);
+ writer.writeAttribute("title", atom->string());
+ project.files.insert(indexPath);
+
+ sectionStack.top() += 1;
+ }
+ break;
+ default:
+ ;
+ }
+
+ if (atom == indexBody.lastAtom())
+ break;
+ atom = atom->next();
+ }
+ } else
+ rootNode->doc().location().warning(
+ tr("Failed to find index: %1").arg(subproject.indexTitle)
+ );
+
+ } else {
+
+ if (!name.isEmpty()) {
+ writer.writeStartElement("section");
+ QString indexPath = HtmlGenerator::fullDocumentLocation(tree->findFakeNodeByTitle(subproject.indexTitle),true);
+ writer.writeAttribute("ref", indexPath);
+ writer.writeAttribute("title", subproject.title);
+ project.files.insert(indexPath);
+ }
+ if (subproject.sortPages) {
+ QStringList titles = subproject.nodes.keys();
+ titles.sort();
+ foreach (const QString &title, titles) {
+ writeNode(project, writer, subproject.nodes[title]);
+ }
+ } else {
+ // Find a contents node and navigate from there, using the NextLink values.
+ QSet<QString> visited;
+
+ foreach (const Node *node, subproject.nodes) {
+ QString nextTitle = node->links().value(Node::NextLink).first;
+ if (!nextTitle.isEmpty() &&
+ node->links().value(Node::ContentsLink).first.isEmpty()) {
+
+ FakeNode *nextPage = const_cast<FakeNode *>(tree->findFakeNodeByTitle(nextTitle));
+
+ // Write the contents node.
+ writeNode(project, writer, node);
+
+ while (nextPage) {
+ writeNode(project, writer, nextPage);
+ nextTitle = nextPage->links().value(Node::NextLink).first;
+ if (nextTitle.isEmpty() || visited.contains(nextTitle))
+ break;
+ nextPage = const_cast<FakeNode *>(tree->findFakeNodeByTitle(nextTitle));
+ visited.insert(nextTitle);
+ }
+ break;
+ }
+ }
+ }
+
+ if (!name.isEmpty())
+ writer.writeEndElement(); // section
+ }
+ }
+
+ writer.writeEndElement(); // section
+ writer.writeEndElement(); // toc
+
+ writer.writeStartElement("keywords");
+ foreach (const QStringList &details, project.keywords) {
+ writer.writeStartElement("keyword");
+ writer.writeAttribute("name", details[0]);
+ writer.writeAttribute("id", details[1]);
+ writer.writeAttribute("ref", details[2]);
+ writer.writeEndElement(); //keyword
+ }
+ writer.writeEndElement(); // keywords
+
+ writer.writeStartElement("files");
+ foreach (const QString &usedFile, project.files) {
+ if (!usedFile.isEmpty())
+ writer.writeTextElement("file", usedFile);
+ }
+ foreach (const QString &usedFile, project.extraFiles)
+ writer.writeTextElement("file", usedFile);
+ writer.writeEndElement(); // files
+
+ writer.writeEndElement(); // filterSection
+ writer.writeEndElement(); // QtHelpProject
+ writer.writeEndDocument();
+ file.close();
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/helpprojectwriter.h b/src/tools/qdoc/helpprojectwriter.h
new file mode 100644
index 0000000000..8725f6275e
--- /dev/null
+++ b/src/tools/qdoc/helpprojectwriter.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HELPPROJECTWRITER_H
+#define HELPPROJECTWRITER_H
+
+#include <QString>
+#include <QXmlStreamReader>
+#include <QXmlStreamWriter>
+
+#include "config.h"
+#include "node.h"
+
+QT_BEGIN_NAMESPACE
+
+class Tree;
+typedef QPair<QString, const Node*> QStringNodePair;
+
+struct SubProject
+{
+ QString title;
+ QString indexTitle;
+ QHash<Node::Type, QSet<FakeNode::SubType> > selectors;
+ bool sortPages;
+ QString type;
+ QHash<QString, const Node *> nodes;
+};
+
+struct HelpProject
+{
+ QString name;
+ QString helpNamespace;
+ QString virtualFolder;
+ QString fileName;
+ QString indexRoot;
+ QString indexTitle;
+ QList<QStringList> keywords;
+ QSet<QString> files;
+ QSet<QString> extraFiles;
+ QSet<QString> filterAttributes;
+ QHash<QString, QSet<QString> > customFilters;
+ QSet<QString> excluded;
+ QMap<QString, SubProject> subprojects;
+ QHash<const Node *, QSet<Node::Status> > memberStatus;
+};
+
+class HelpProjectWriter
+{
+public:
+ HelpProjectWriter(const Config &config, const QString &defaultFileName);
+ void addExtraFile(const QString &file);
+ void addExtraFiles(const QSet<QString> &files);
+ void generate(const Tree *tre);
+
+private:
+ void generateProject(HelpProject &project);
+ void generateSections(HelpProject &project, QXmlStreamWriter &writer,
+ const Node *node);
+ bool generateSection(HelpProject &project, QXmlStreamWriter &writer,
+ const Node *node);
+ QStringList keywordDetails(const Node *node) const;
+ void writeNode(HelpProject &project, QXmlStreamWriter &writer, const Node *node);
+ void readSelectors(SubProject &subproject, const QStringList &selectors);
+
+ const Tree *tree;
+
+ QString outputDir;
+ QList<HelpProject> projects;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp
new file mode 100644
index 0000000000..dd3a0fcbfc
--- /dev/null
+++ b/src/tools/qdoc/htmlgenerator.cpp
@@ -0,0 +1,5115 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ htmlgenerator.cpp
+*/
+
+#include "codemarker.h"
+#include "codeparser.h"
+#include "helpprojectwriter.h"
+#include "htmlgenerator.h"
+#include "node.h"
+#include "separator.h"
+#include "tree.h"
+#include <ctype.h>
+#include <qdebug.h>
+#include <qlist.h>
+#include <qiterator.h>
+#include <qtextcodec.h>
+#include <QUuid>
+
+QT_BEGIN_NAMESPACE
+
+#define COMMAND_VERSION Doc::alias("version")
+int HtmlGenerator::id = 0;
+bool HtmlGenerator::debugging_on = false;
+
+QString HtmlGenerator::divNavTop = "";
+
+static bool showBrokenLinks = false;
+
+static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)");
+static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)(</@func>)");
+static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)");
+static QRegExp spanTag("</@(?:comment|preprocessor|string|char|number|op|type|name|keyword)>");
+static QRegExp unknownTag("</?@[^>]*>");
+
+static void addLink(const QString &linkTarget,
+ const QStringRef &nestedStuff,
+ QString *res)
+{
+ if (!linkTarget.isEmpty()) {
+ *res += "<a href=\"";
+ *res += linkTarget;
+ *res += "\">";
+ *res += nestedStuff;
+ *res += "</a>";
+ }
+ else {
+ *res += nestedStuff;
+ }
+}
+
+
+HtmlGenerator::HtmlGenerator()
+ : helpProjectWriter(0),
+ inLink(false),
+ inObsoleteLink(false),
+ inContents(false),
+ inSectionHeading(false),
+ inTableHeader(false),
+ numTableRows(0),
+ threeColumnEnumValueTable(true),
+ funcLeftParen("\\S(\\()"),
+ myTree(0),
+ obsoleteLinks(false)
+{
+}
+
+/*!
+ The destructor deletes the instance of HelpProjectWriter.
+ */
+HtmlGenerator::~HtmlGenerator()
+{
+ if (helpProjectWriter)
+ delete helpProjectWriter;
+}
+
+void HtmlGenerator::initializeGenerator(const Config &config)
+{
+ static const struct {
+ const char *key;
+ const char *left;
+ const char *right;
+ } defaults[] = {
+ { ATOM_FORMATTING_BOLD, "<b>", "</b>" },
+ { ATOM_FORMATTING_INDEX, "<!--", "-->" },
+ { ATOM_FORMATTING_ITALIC, "<i>", "</i>" },
+ { ATOM_FORMATTING_PARAMETER, "<i>", "</i>" },
+ { ATOM_FORMATTING_SUBSCRIPT, "<sub>", "</sub>" },
+ { ATOM_FORMATTING_SUPERSCRIPT, "<sup>", "</sup>" },
+ { ATOM_FORMATTING_TELETYPE, "<tt>", "</tt>" },
+ { ATOM_FORMATTING_UNDERLINE, "<u>", "</u>" },
+ { 0, 0, 0 }
+ };
+
+ Generator::initializeGenerator(config);
+ obsoleteLinks = config.getBool(QLatin1String(CONFIG_OBSOLETELINKS));
+ setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif");
+ int i = 0;
+ while (defaults[i].key) {
+ formattingLeftMap().insert(defaults[i].key, defaults[i].left);
+ formattingRightMap().insert(defaults[i].key, defaults[i].right);
+ i++;
+ }
+
+ style = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ CONFIG_STYLE);
+ endHeader = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ CONFIG_ENDHEADER);
+ postHeader = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_POSTHEADER);
+ postPostHeader = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_POSTPOSTHEADER);
+ footer = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_FOOTER);
+ address = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_ADDRESS);
+ pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_GENERATEMACREFS);
+ noBreadCrumbs = config.getBool(HtmlGenerator::format() +
+ Config::dot +
+ HTMLGENERATOR_NOBREADCRUMBS);
+
+ project = config.getString(CONFIG_PROJECT);
+
+ projectDescription = config.getString(CONFIG_DESCRIPTION);
+ if (projectDescription.isEmpty() && !project.isEmpty())
+ projectDescription = project + " Reference Documentation";
+
+ projectUrl = config.getString(CONFIG_URL);
+
+ outputEncoding = config.getString(CONFIG_OUTPUTENCODING);
+ if (outputEncoding.isEmpty())
+ outputEncoding = QLatin1String("ISO-8859-1");
+ outputCodec = QTextCodec::codecForName(outputEncoding.toLocal8Bit());
+
+ naturalLanguage = config.getString(CONFIG_NATURALLANGUAGE);
+ if (naturalLanguage.isEmpty())
+ naturalLanguage = QLatin1String("en");
+
+ QSet<QString> editionNames = config.subVars(CONFIG_EDITION);
+ QSet<QString>::ConstIterator edition = editionNames.begin();
+ while (edition != editionNames.end()) {
+ QString editionName = *edition;
+ QStringList editionModules = config.getStringList(CONFIG_EDITION +
+ Config::dot +
+ editionName +
+ Config::dot +
+ "modules");
+ QStringList editionGroups = config.getStringList(CONFIG_EDITION +
+ Config::dot +
+ editionName +
+ Config::dot +
+ "groups");
+
+ if (!editionModules.isEmpty())
+ editionModuleMap[editionName] = editionModules;
+ if (!editionGroups.isEmpty())
+ editionGroupMap[editionName] = editionGroups;
+
+ ++edition;
+ }
+
+ codeIndent = config.getInt(CONFIG_CODEINDENT);
+
+ helpProjectWriter = new HelpProjectWriter(config,
+ project.toLower() +
+ ".qhp");
+
+ // Documentation template handling
+ headerScripts = config.getString(HtmlGenerator::format() + Config::dot +
+ CONFIG_HEADERSCRIPTS);
+ headerStyles = config.getString(HtmlGenerator::format() +
+ Config::dot +
+ CONFIG_HEADERSTYLES);
+
+ QString prefix = CONFIG_QHP + Config::dot + "Qt" + Config::dot;
+ manifestDir = "qthelp://" + config.getString(prefix + "namespace");
+ manifestDir += QLatin1Char('/') + config.getString(prefix + "virtualFolder") + QLatin1Char('/');
+
+ /*
+ If the output files will be in subdirectores in the output
+ directory, change the references to files in the style and
+ scripts subdirectories that appear in the headerscipts and
+ headerstyles string so that they link to the correct files,
+ whic means prepending "../" to each
+ */
+ if (!baseDir().isEmpty()) {
+ headerScripts = headerScripts.replace("style/","../style/");
+ headerScripts = headerScripts.replace("scripts/","../scripts/");
+ headerStyles = headerStyles.replace("style/","../style/");
+ headerStyles = headerStyles.replace("scripts/","../scripts/");
+ }
+}
+
+void HtmlGenerator::terminateGenerator()
+{
+ Generator::terminateGenerator();
+}
+
+QString HtmlGenerator::format()
+{
+ return "HTML";
+}
+
+/*!
+ This is where the HTML files are written.
+ \note The HTML file generation is done in the base class,
+ PageGenerator::generateTree().
+ */
+void HtmlGenerator::generateTree(const Tree *tree)
+{
+ myTree = tree;
+ nonCompatClasses.clear();
+ mainClasses.clear();
+ compatClasses.clear();
+ obsoleteClasses.clear();
+ moduleClassMap.clear();
+ moduleNamespaceMap.clear();
+ funcIndex.clear();
+ legaleseTexts.clear();
+ serviceClasses.clear();
+ qmlClasses.clear();
+ findAllClasses(tree->root());
+ findAllFunctions(tree->root());
+ findAllLegaleseTexts(tree->root());
+ findAllNamespaces(tree->root());
+ findAllSince(tree->root());
+
+ PageGenerator::generateTree(tree);
+ reportOrphans(tree->root());
+ generateDisambiguationPages();
+
+ QString fileBase = project.toLower().simplified().replace(" ", "-");
+ generateIndex(fileBase, projectUrl, projectDescription);
+ generatePageIndex(outputDir() + QLatin1Char('/') + fileBase + ".pageindex");
+
+ helpProjectWriter->generate(myTree);
+ generateManifestFiles();
+}
+
+void HtmlGenerator::startText(const Node * /* relative */,
+ CodeMarker * /* marker */)
+{
+ inLink = false;
+ inContents = false;
+ inSectionHeading = false;
+ inTableHeader = false;
+ numTableRows = 0;
+ threeColumnEnumValueTable = true;
+ link.clear();
+ sectionNumber.clear();
+}
+
+/*!
+ Generate html from an instance of Atom.
+ */
+int HtmlGenerator::generateAtom(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker)
+{
+ int skipAhead = 0;
+ static bool in_para = false;
+
+ switch (atom->type()) {
+ case Atom::AbstractLeft:
+ if (relative)
+ relative->doc().location().warning(tr("\abstract is not implemented."));
+ else
+ Location::information(tr("\abstract is not implemented."));
+ break;
+ case Atom::AbstractRight:
+ break;
+ case Atom::AutoLink:
+ if (!inLink && !inContents && !inSectionHeading) {
+ const Node *node = 0;
+ QString link = getLink(atom, relative, marker, &node);
+ if (!link.isEmpty()) {
+ beginLink(link, node, relative, marker);
+ generateLink(atom, relative, marker);
+ endLink();
+ }
+ else {
+ out() << protectEnc(atom->string());
+ }
+ }
+ else {
+ out() << protectEnc(atom->string());
+ }
+ break;
+ case Atom::BaseName:
+ break;
+ case Atom::BriefLeft:
+ if (relative->type() == Node::Fake) {
+ if (relative->subType() != Node::Example) {
+ skipAhead = skipAtoms(atom, Atom::BriefRight);
+ break;
+ }
+ }
+
+ out() << "<p>";
+ if (relative->type() == Node::Property ||
+ relative->type() == Node::Variable) {
+ QString str;
+ atom = atom->next();
+ while (atom != 0 && atom->type() != Atom::BriefRight) {
+ if (atom->type() == Atom::String ||
+ atom->type() == Atom::AutoLink)
+ str += atom->string();
+ skipAhead++;
+ atom = atom->next();
+ }
+ str[0] = str[0].toLower();
+ if (str.endsWith(QLatin1Char('.')))
+ str.truncate(str.length() - 1);
+ out() << "This ";
+ if (relative->type() == Node::Property)
+ out() << "property";
+ else
+ out() << "variable";
+ QStringList words = str.split(QLatin1Char(' '));
+ if (!(words.first() == "contains" || words.first() == "specifies"
+ || words.first() == "describes" || words.first() == "defines"
+ || words.first() == "holds" || words.first() == "determines"))
+ out() << " holds ";
+ else
+ out() << ' ';
+ out() << str << '.';
+ }
+ break;
+ case Atom::BriefRight:
+ if (relative->type() != Node::Fake)
+ out() << "</p>\n";
+ break;
+ case Atom::C:
+ // This may at one time have been used to mark up C++ code but it is
+ // now widely used to write teletype text. As a result, text marked
+ // with the \c command is not passed to a code marker.
+ out() << formattingLeftMap()[ATOM_FORMATTING_TELETYPE];
+ if (inLink) {
+ out() << protectEnc(plainCode(atom->string()));
+ }
+ else {
+ out() << protectEnc(plainCode(atom->string()));
+ }
+ out() << formattingRightMap()[ATOM_FORMATTING_TELETYPE];
+ break;
+ case Atom::CaptionLeft:
+ out() << "<p class=\"figCaption\">";
+ in_para = true;
+ break;
+ case Atom::CaptionRight:
+ endLink();
+ if (in_para) {
+ out() << "</p>\n";
+ in_para = false;
+ }
+ break;
+ case Atom::Code:
+ out() << "<pre class=\"cpp\">"
+ << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
+ marker,relative))
+ << "</pre>\n";
+ break;
+#ifdef QDOC_QML
+ case Atom::Qml:
+ out() << "<pre class=\"qml\">"
+ << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
+ marker,relative))
+ << "</pre>\n";
+ break;
+ case Atom::JavaScript:
+ out() << "<pre class=\"js\">"
+ << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
+ marker,relative))
+ << "</pre>\n";
+ break;
+#endif
+ case Atom::CodeNew:
+ out() << "<p>you can rewrite it as</p>\n"
+ << "<pre class=\"cpp\">"
+ << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
+ marker,relative))
+ << "</pre>\n";
+ break;
+ case Atom::CodeOld:
+ out() << "<p>For example, if you have code like</p>\n";
+ // fallthrough
+ case Atom::CodeBad:
+ out() << "<pre class=\"cpp\">"
+ << trimmedTrailing(protectEnc(plainCode(indent(codeIndent,atom->string()))))
+ << "</pre>\n";
+ break;
+ case Atom::DivLeft:
+ out() << "<div";
+ if (!atom->string().isEmpty())
+ out() << ' ' << atom->string();
+ out() << '>';
+ break;
+ case Atom::DivRight:
+ out() << "</div>";
+ break;
+ case Atom::FootnoteLeft:
+ // ### For now
+ if (in_para) {
+ out() << "</p>\n";
+ in_para = false;
+ }
+ out() << "<!-- ";
+ break;
+ case Atom::FootnoteRight:
+ // ### For now
+ out() << "-->";
+ break;
+ case Atom::FormatElse:
+ case Atom::FormatEndif:
+ case Atom::FormatIf:
+ break;
+ case Atom::FormattingLeft:
+ if (atom->string().startsWith("span ")) {
+ out() << '<' + atom->string() << '>';
+ }
+ else
+ out() << formattingLeftMap()[atom->string()];
+ if (atom->string() == ATOM_FORMATTING_PARAMETER) {
+ if (atom->next() != 0 && atom->next()->type() == Atom::String) {
+ QRegExp subscriptRegExp("([a-z]+)_([0-9n])");
+ if (subscriptRegExp.exactMatch(atom->next()->string())) {
+ out() << subscriptRegExp.cap(1) << "<sub>"
+ << subscriptRegExp.cap(2) << "</sub>";
+ skipAhead = 1;
+ }
+ }
+ }
+ break;
+ case Atom::FormattingRight:
+ if (atom->string() == ATOM_FORMATTING_LINK) {
+ endLink();
+ }
+ else if (atom->string().startsWith("span ")) {
+ out() << "</span>";
+ }
+ else {
+ out() << formattingRightMap()[atom->string()];
+ }
+ break;
+ case Atom::AnnotatedList:
+ {
+ QList<Node*> values = myTree->groups().values(atom->string());
+ NodeMap nodeMap;
+ for (int i = 0; i < values.size(); ++i) {
+ const Node* n = values.at(i);
+ if ((n->status() != Node::Internal) && (n->access() != Node::Private)) {
+ nodeMap.insert(n->nameForLists(),n);
+ }
+ }
+ generateAnnotatedList(relative, marker, nodeMap);
+ }
+ break;
+ case Atom::GeneratedList:
+ if (atom->string() == "annotatedclasses") {
+ generateAnnotatedList(relative, marker, nonCompatClasses);
+ }
+ else if (atom->string() == "classes") {
+ generateCompactList(relative, marker, nonCompatClasses, true);
+ }
+ else if (atom->string() == "qmlclasses") {
+ generateCompactList(relative, marker, qmlClasses, true);
+ }
+ else if (atom->string().contains("classesbymodule")) {
+ QString arg = atom->string().trimmed();
+ QString moduleName = atom->string().mid(atom->string().indexOf(
+ "classesbymodule") + 15).trimmed();
+ if (moduleClassMap.contains(moduleName))
+ generateAnnotatedList(relative, marker, moduleClassMap[moduleName]);
+ }
+ else if (atom->string().contains("classesbyedition")) {
+
+ QString arg = atom->string().trimmed();
+ QString editionName = atom->string().mid(atom->string().indexOf(
+ "classesbyedition") + 16).trimmed();
+
+ if (editionModuleMap.contains(editionName)) {
+
+ // Add all classes in the modules listed for that edition.
+ NodeMap editionClasses;
+ foreach (const QString &moduleName, editionModuleMap[editionName]) {
+ if (moduleClassMap.contains(moduleName))
+ editionClasses.unite(moduleClassMap[moduleName]);
+ }
+
+ // Add additional groups and remove groups of classes that
+ // should be excluded from the edition.
+
+ QMultiMap <QString, Node *> groups = myTree->groups();
+ foreach (const QString &groupName, editionGroupMap[editionName]) {
+ QList<Node *> groupClasses;
+ if (groupName.startsWith(QLatin1Char('-'))) {
+ groupClasses = groups.values(groupName.mid(1));
+ foreach (const Node *node, groupClasses)
+ editionClasses.remove(node->name());
+ }
+ else {
+ groupClasses = groups.values(groupName);
+ foreach (const Node *node, groupClasses)
+ editionClasses.insert(node->name(), node);
+ }
+ }
+ generateAnnotatedList(relative, marker, editionClasses);
+ }
+ }
+ else if (atom->string() == "classhierarchy") {
+ generateClassHierarchy(relative, marker, nonCompatClasses);
+ }
+ else if (atom->string() == "compatclasses") {
+ generateCompactList(relative, marker, compatClasses, false);
+ }
+ else if (atom->string() == "obsoleteclasses") {
+ generateCompactList(relative, marker, obsoleteClasses, false);
+ }
+ else if (atom->string() == "functionindex") {
+ generateFunctionIndex(relative, marker);
+ }
+ else if (atom->string() == "legalese") {
+ generateLegaleseList(relative, marker);
+ }
+ else if (atom->string() == "mainclasses") {
+ generateCompactList(relative, marker, mainClasses, true);
+ }
+ else if (atom->string() == "services") {
+ generateCompactList(relative, marker, serviceClasses, false);
+ }
+ else if (atom->string() == "overviews") {
+ generateOverviewList(relative, marker);
+ }
+ else if (atom->string() == "namespaces") {
+ generateAnnotatedList(relative, marker, namespaceIndex);
+ }
+ else if (atom->string() == "related") {
+ const FakeNode *fake = static_cast<const FakeNode *>(relative);
+ if (fake && !fake->groupMembers().isEmpty()) {
+ NodeMap groupMembersMap;
+ foreach (const Node *node, fake->groupMembers()) {
+ if (node->type() == Node::Fake)
+ groupMembersMap[fullName(node, relative, marker)] = node;
+ }
+ generateAnnotatedList(fake, marker, groupMembersMap);
+ }
+ }
+ else if (atom->string() == "relatedinline") {
+ const FakeNode *fake = static_cast<const FakeNode *>(relative);
+ if (fake && !fake->groupMembers().isEmpty()) {
+ // Reverse the list into the original scan order.
+ // Should be sorted. But on what? It may not be a
+ // regular class or page definition.
+ QList<const Node *> list;
+ foreach (const Node *node, fake->groupMembers())
+ list.prepend(node);
+ foreach (const Node *node, list)
+ generateBody(node, marker);
+ }
+ }
+ break;
+ case Atom::SinceList:
+ {
+ NewSinceMaps::const_iterator nsmap;
+ nsmap = newSinceMaps.find(atom->string());
+ NewClassMaps::const_iterator ncmap;
+ ncmap = newClassMaps.find(atom->string());
+ NewClassMaps::const_iterator nqcmap;
+ nqcmap = newQmlClassMaps.find(atom->string());
+
+ if ((nsmap != newSinceMaps.constEnd()) && !nsmap.value().isEmpty()) {
+ QList<Section> sections;
+ QList<Section>::ConstIterator s;
+
+ for (int i=0; i<LastSinceType; ++i)
+ sections.append(Section(sinceTitle(i),QString(),QString(),QString()));
+
+ NodeMultiMap::const_iterator n = nsmap.value().constBegin();
+
+ while (n != nsmap.value().constEnd()) {
+
+ const Node* node = n.value();
+ switch (node->type()) {
+ case Node::Fake:
+ if (node->subType() == Node::QmlClass) {
+ sections[QmlClass].appendMember((Node*)node);
+ }
+ break;
+ case Node::Namespace:
+ sections[Namespace].appendMember((Node*)node);
+ break;
+ case Node::Class:
+ sections[Class].appendMember((Node*)node);
+ break;
+ case Node::Enum:
+ sections[Enum].appendMember((Node*)node);
+ break;
+ case Node::Typedef:
+ sections[Typedef].appendMember((Node*)node);
+ break;
+ case Node::Function: {
+ const FunctionNode* fn = static_cast<const FunctionNode*>(node);
+ if (fn->isMacro())
+ sections[Macro].appendMember((Node*)node);
+ else {
+ Node* p = fn->parent();
+ if (p) {
+ if (p->type() == Node::Class)
+ sections[MemberFunction].appendMember((Node*)node);
+ else if (p->type() == Node::Namespace) {
+ if (p->name().isEmpty())
+ sections[GlobalFunction].appendMember((Node*)node);
+ else
+ sections[NamespaceFunction].appendMember((Node*)node);
+ }
+ else
+ sections[GlobalFunction].appendMember((Node*)node);
+ }
+ else
+ sections[GlobalFunction].appendMember((Node*)node);
+ }
+ break;
+ }
+ case Node::Property:
+ sections[Property].appendMember((Node*)node);
+ break;
+ case Node::Variable:
+ sections[Variable].appendMember((Node*)node);
+ break;
+ case Node::QmlProperty:
+ sections[QmlProperty].appendMember((Node*)node);
+ break;
+ case Node::QmlSignal:
+ sections[QmlSignal].appendMember((Node*)node);
+ break;
+ case Node::QmlSignalHandler:
+ sections[QmlSignalHandler].appendMember((Node*)node);
+ break;
+ case Node::QmlMethod:
+ sections[QmlMethod].appendMember((Node*)node);
+ break;
+ default:
+ break;
+ }
+ ++n;
+ }
+
+ /*
+ First generate the table of contents.
+ */
+ out() << "<ul>\n";
+ s = sections.constBegin();
+ while (s != sections.constEnd()) {
+ if (!(*s).members.isEmpty()) {
+
+ out() << "<li>"
+ << "<a href=\"#"
+ << Doc::canonicalTitle((*s).name)
+ << "\">"
+ << (*s).name
+ << "</a></li>\n";
+ }
+ ++s;
+ }
+ out() << "</ul>\n";
+
+ int idx = 0;
+ s = sections.constBegin();
+ while (s != sections.constEnd()) {
+ if (!(*s).members.isEmpty()) {
+ out() << "<a name=\""
+ << Doc::canonicalTitle((*s).name)
+ << "\"></a>\n";
+ out() << "<h3>" << protectEnc((*s).name) << "</h3>\n";
+ if (idx == Class)
+ generateCompactList(0, marker, ncmap.value(), false, QString("Q"));
+ else if (idx == QmlClass)
+ generateCompactList(0, marker, nqcmap.value(), false, QString("Q"));
+ else if (idx == MemberFunction) {
+ ParentMaps parentmaps;
+ ParentMaps::iterator pmap;
+ NodeList::const_iterator i = s->members.constBegin();
+ while (i != s->members.constEnd()) {
+ Node* p = (*i)->parent();
+ pmap = parentmaps.find(p);
+ if (pmap == parentmaps.end())
+ pmap = parentmaps.insert(p,NodeMultiMap());
+ pmap->insert((*i)->name(),(*i));
+ ++i;
+ }
+ pmap = parentmaps.begin();
+ while (pmap != parentmaps.end()) {
+ NodeList nlist = pmap->values();
+ out() << "<p>Class ";
+
+ out() << "<a href=\""
+ << linkForNode(pmap.key(), 0)
+ << "\">";
+ QStringList pieces = fullName(pmap.key(), 0, marker).split("::");
+ out() << protectEnc(pieces.last());
+ out() << "</a>" << ":</p>\n";
+
+ generateSection(nlist, 0, marker, CodeMarker::Summary);
+ out() << "<br/>";
+ ++pmap;
+ }
+ }
+ else
+ generateSection(s->members, 0, marker, CodeMarker::Summary);
+ }
+ ++idx;
+ ++s;
+ }
+ }
+ }
+ break;
+ case Atom::Image:
+ case Atom::InlineImage:
+ {
+ QString fileName = imageFileName(relative, atom->string());
+ QString text;
+ if (atom->next() != 0)
+ text = atom->next()->string();
+ if (atom->type() == Atom::Image)
+ out() << "<p class=\"centerAlign\">";
+ if (fileName.isEmpty()) {
+ out() << "<font color=\"red\">[Missing image "
+ << protectEnc(atom->string()) << "]</font>";
+ }
+ else {
+ QString prefix = "";
+ if (!baseDir().isEmpty())
+ prefix = "../";
+ out() << "<img src=\"" << protectEnc(prefix + fileName) << '"';
+ if (!text.isEmpty())
+ out() << " alt=\"" << protectEnc(text) << '"';
+ else
+ out() << " alt=\"\"";
+ out() << " />";
+ helpProjectWriter->addExtraFile(fileName);
+ if ((relative->type() == Node::Fake) &&
+ (relative->subType() == Node::Example)) {
+ const ExampleNode* cen = static_cast<const ExampleNode*>(relative);
+ if (cen->imageFileName().isEmpty()) {
+ ExampleNode* en = const_cast<ExampleNode*>(cen);
+ en->setImageFileName(fileName);
+ }
+ }
+ }
+ if (atom->type() == Atom::Image)
+ out() << "</p>";
+ }
+ break;
+ case Atom::ImageText:
+ break;
+ case Atom::ImportantLeft:
+ out() << "<p>";
+ out() << formattingLeftMap()[ATOM_FORMATTING_BOLD];
+ out() << "Important: ";
+ out() << formattingRightMap()[ATOM_FORMATTING_BOLD];
+ break;
+ case Atom::ImportantRight:
+ out() << "</p>";
+ break;
+ case Atom::NoteLeft:
+ out() << "<p>";
+ out() << formattingLeftMap()[ATOM_FORMATTING_BOLD];
+ out() << "Note: ";
+ out() << formattingRightMap()[ATOM_FORMATTING_BOLD];
+ break;
+ case Atom::NoteRight:
+ out() << "</p>";
+ break;
+ case Atom::LegaleseLeft:
+ out() << "<div class=\"LegaleseLeft\">";
+ break;
+ case Atom::LegaleseRight:
+ out() << "</div>";
+ break;
+ case Atom::LineBreak:
+ out() << "<br/>";
+ break;
+ case Atom::Link:
+ {
+ const Node *node = 0;
+ QString myLink = getLink(atom, relative, marker, &node);
+ if (myLink.isEmpty()) {
+ myLink = getDisambiguationLink(atom, marker);
+ if (myLink.isEmpty()) {
+ relative->doc().location().warning(tr("Can't create link to '%1'")
+ .arg(atom->string()));
+ }
+ else
+ node = 0;
+ }
+ beginLink(myLink, node, relative, marker);
+ skipAhead = 1;
+ }
+ break;
+ case Atom::LinkNode:
+ {
+ const Node *node = CodeMarker::nodeForString(atom->string());
+ beginLink(linkForNode(node, relative), node, relative, marker);
+ skipAhead = 1;
+ }
+ break;
+ case Atom::ListLeft:
+ if (in_para) {
+ out() << "</p>\n";
+ in_para = false;
+ }
+ if (atom->string() == ATOM_LIST_BULLET) {
+ out() << "<ul>\n";
+ }
+ else if (atom->string() == ATOM_LIST_TAG) {
+ out() << "<dl>\n";
+ }
+ else if (atom->string() == ATOM_LIST_VALUE) {
+ threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom);
+ if (threeColumnEnumValueTable) {
+ out() << "<table class=\"valuelist\">";
+ if (++numTableRows % 2 == 1)
+ out() << "<tr valign=\"top\" class=\"odd\">";
+ else
+ out() << "<tr valign=\"top\" class=\"even\">";
+
+ out() << "<th class=\"tblConst\">Constant</th>"
+ << "<th class=\"tblval\">Value</th>"
+ << "<th class=\"tbldscr\">Description</th></tr>\n";
+ }
+ else {
+ out() << "<table class=\"valuelist\">"
+ << "<tr><th class=\"tblConst\">Constant</th><th class=\"tblVal\">Value</th></tr>\n";
+ }
+ }
+ else {
+ out() << "<ol class=";
+ if (atom->string() == ATOM_LIST_UPPERALPHA) {
+ out() << "\"A\"";
+ } /* why type? changed to */
+ else if (atom->string() == ATOM_LIST_LOWERALPHA) {
+ out() << "\"a\"";
+ }
+ else if (atom->string() == ATOM_LIST_UPPERROMAN) {
+ out() << "\"I\"";
+ }
+ else if (atom->string() == ATOM_LIST_LOWERROMAN) {
+ out() << "\"i\"";
+ }
+ else { // (atom->string() == ATOM_LIST_NUMERIC)
+ out() << "\"1\"";
+ }
+ if (atom->next() != 0 && atom->next()->string().toInt() != 1)
+ out() << " start=\"" << atom->next()->string() << '"';
+ out() << ">\n";
+ }
+ break;
+ case Atom::ListItemNumber:
+ break;
+ case Atom::ListTagLeft:
+ if (atom->string() == ATOM_LIST_TAG) {
+ out() << "<dt>";
+ }
+ else { // (atom->string() == ATOM_LIST_VALUE)
+ // ### Trenton
+
+ out() << "<tr><td class=\"topAlign\"><tt>"
+ << protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(),
+ relative)))
+ << "</tt></td><td class=\"topAlign\">";
+
+ QString itemValue;
+ if (relative->type() == Node::Enum) {
+ const EnumNode *enume = static_cast<const EnumNode *>(relative);
+ itemValue = enume->itemValue(atom->next()->string());
+ }
+
+ if (itemValue.isEmpty())
+ out() << '?';
+ else
+ out() << "<tt>" << protectEnc(itemValue) << "</tt>";
+
+ skipAhead = 1;
+ }
+ break;
+ case Atom::ListTagRight:
+ if (atom->string() == ATOM_LIST_TAG)
+ out() << "</dt>\n";
+ break;
+ case Atom::ListItemLeft:
+ if (atom->string() == ATOM_LIST_TAG) {
+ out() << "<dd>";
+ }
+ else if (atom->string() == ATOM_LIST_VALUE) {
+ if (threeColumnEnumValueTable) {
+ out() << "</td><td class=\"topAlign\">";
+ if (matchAhead(atom, Atom::ListItemRight))
+ out() << "&nbsp;";
+ }
+ }
+ else {
+ out() << "<li>";
+ }
+ if (matchAhead(atom, Atom::ParaLeft))
+ skipAhead = 1;
+ break;
+ case Atom::ListItemRight:
+ if (atom->string() == ATOM_LIST_TAG) {
+ out() << "</dd>\n";
+ }
+ else if (atom->string() == ATOM_LIST_VALUE) {
+ out() << "</td></tr>\n";
+ }
+ else {
+ out() << "</li>\n";
+ }
+ break;
+ case Atom::ListRight:
+ if (atom->string() == ATOM_LIST_BULLET) {
+ out() << "</ul>\n";
+ }
+ else if (atom->string() == ATOM_LIST_TAG) {
+ out() << "</dl>\n";
+ }
+ else if (atom->string() == ATOM_LIST_VALUE) {
+ out() << "</table>\n";
+ }
+ else {
+ out() << "</ol>\n";
+ }
+ break;
+ case Atom::Nop:
+ break;
+ case Atom::ParaLeft:
+ out() << "<p>";
+ in_para = true;
+ break;
+ case Atom::ParaRight:
+ endLink();
+ if (in_para) {
+ out() << "</p>\n";
+ in_para = false;
+ }
+ //if (!matchAhead(atom, Atom::ListItemRight) && !matchAhead(atom, Atom::TableItemRight))
+ // out() << "</p>\n";
+ break;
+ case Atom::QuotationLeft:
+ out() << "<blockquote>";
+ break;
+ case Atom::QuotationRight:
+ out() << "</blockquote>\n";
+ break;
+ case Atom::RawString:
+ out() << atom->string();
+ break;
+ case Atom::SectionLeft:
+ out() << "<a name=\"" << Doc::canonicalTitle(Text::sectionHeading(atom).toString())
+ << "\"></a>" << divNavTop << '\n';
+ break;
+ case Atom::SectionRight:
+ break;
+ case Atom::SectionHeadingLeft:
+ out() << "<h" + QString::number(atom->string().toInt() + hOffset(relative)) + QLatin1Char('>');
+ inSectionHeading = true;
+ break;
+ case Atom::SectionHeadingRight:
+ out() << "</h" + QString::number(atom->string().toInt() + hOffset(relative)) + ">\n";
+ inSectionHeading = false;
+ break;
+ case Atom::SidebarLeft:
+ break;
+ case Atom::SidebarRight:
+ break;
+ case Atom::String:
+ if (inLink && !inContents && !inSectionHeading) {
+ generateLink(atom, relative, marker);
+ }
+ else {
+ out() << protectEnc(atom->string());
+ }
+ break;
+ case Atom::TableLeft:
+ {
+ QString p1, p2;
+ QString attr = "generic";
+ QString width;
+ if (in_para) {
+ out() << "</p>\n";
+ in_para = false;
+ }
+ if (atom->count() > 0) {
+ p1 = atom->string(0);
+ if (atom->count() > 1)
+ p2 = atom->string(1);
+ }
+ if (!p1.isEmpty()) {
+ if (p1 == "borderless")
+ attr = p1;
+ else if (p1.contains("%"))
+ width = p1;
+ }
+ if (!p2.isEmpty()) {
+ if (p2 == "borderless")
+ attr = p2;
+ else if (p2.contains("%"))
+ width = p2;
+ }
+ out() << "<table class=\"" << attr << "\"";
+ if (!width.isEmpty())
+ out() << " width=\"" << width << "\">";
+ out() << "\n ";
+ numTableRows = 0;
+ }
+ break;
+ case Atom::TableRight:
+ out() << "</table>\n";
+ break;
+ case Atom::TableHeaderLeft:
+ out() << "<thead><tr class=\"qt-style\">";
+ inTableHeader = true;
+ break;
+ case Atom::TableHeaderRight:
+ out() << "</tr>";
+ if (matchAhead(atom, Atom::TableHeaderLeft)) {
+ skipAhead = 1;
+ out() << "\n<tr class=\"qt-style\">";
+ }
+ else {
+ out() << "</thead>\n";
+ inTableHeader = false;
+ }
+ break;
+ case Atom::TableRowLeft:
+ if (!atom->string().isEmpty())
+ out() << "<tr " << atom->string() << '>';
+ else if (++numTableRows % 2 == 1)
+ out() << "<tr valign=\"top\" class=\"odd\">";
+ else
+ out() << "<tr valign=\"top\" class=\"even\">";
+ break;
+ case Atom::TableRowRight:
+ out() << "</tr>\n";
+ break;
+ case Atom::TableItemLeft:
+ {
+ if (inTableHeader)
+ out() << "<th ";
+ else
+ out() << "<td ";
+
+ for (int i=0; i<atom->count(); ++i) {
+ if (i > 0)
+ out() << ' ';
+ QString p = atom->string(i);
+ if (p.contains('=')) {
+ out() << p;
+ }
+ else {
+ QStringList spans = p.split(",");
+ if (spans.size() == 2) {
+ if (spans.at(0) != "1")
+ out() << " colspan=\"" << spans.at(0) << '"';
+ if (spans.at(1) != "1")
+ out() << " rowspan=\"" << spans.at(1) << '"';
+ }
+ }
+ }
+ if (inTableHeader)
+ out() << '>';
+ else {
+ out() << '>';
+ //out() << "><p>";
+ }
+ if (matchAhead(atom, Atom::ParaLeft))
+ skipAhead = 1;
+ }
+ break;
+ case Atom::TableItemRight:
+ if (inTableHeader)
+ out() << "</th>";
+ else {
+ out() << "</td>";
+ //out() << "</p></td>";
+ }
+ if (matchAhead(atom, Atom::ParaLeft))
+ skipAhead = 1;
+ break;
+ case Atom::TableOfContents:
+ break;
+ case Atom::Target:
+ out() << "<a name=\"" << Doc::canonicalTitle(atom->string()) << "\"></a>";
+ break;
+ case Atom::UnhandledFormat:
+ out() << "<b class=\"redFont\">&lt;Missing HTML&gt;</b>";
+ break;
+ case Atom::UnknownCommand:
+ out() << "<b class=\"redFont\"><code>\\" << protectEnc(atom->string())
+ << "</code></b>";
+ break;
+#ifdef QDOC_QML
+ case Atom::QmlText:
+ case Atom::EndQmlText:
+ // don't do anything with these. They are just tags.
+ break;
+#endif
+ default:
+ unknownAtom(atom);
+ }
+ return skipAhead;
+}
+
+/*!
+ Generate a reference page for a C++ class.
+ */
+void HtmlGenerator::generateClassLikeNode(const InnerNode *inner,
+ CodeMarker *marker)
+{
+ QList<Section> sections;
+ QList<Section>::ConstIterator s;
+
+ const ClassNode *classe = 0;
+
+ QString title;
+ QString rawTitle;
+ QString fullTitle;
+ if (inner->type() == Node::Namespace) {
+ rawTitle = marker->plainName(inner);
+ fullTitle = marker->plainFullName(inner);
+ title = rawTitle + " Namespace";
+ }
+ else if (inner->type() == Node::Class) {
+ classe = static_cast<const ClassNode *>(inner);
+ rawTitle = marker->plainName(inner);
+ fullTitle = marker->plainFullName(inner);
+ title = rawTitle + " Class";
+ }
+
+ Text subtitleText;
+ if (rawTitle != fullTitle)
+ subtitleText << "(" << Atom(Atom::AutoLink, fullTitle) << ")"
+ << Atom(Atom::LineBreak);
+
+ generateHeader(title, inner, marker);
+ sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay);
+ generateTableOfContents(inner,marker,&sections);
+ generateTitle(title, subtitleText, SmallSubTitle, inner, marker);
+ generateBrief(inner, marker);
+ generateIncludes(inner, marker);
+ generateStatus(inner, marker);
+ if (classe) {
+ generateInherits(classe, marker);
+ generateInheritedBy(classe, marker);
+ if (classe->qmlElement() != 0)
+ generateInstantiatedBy(classe,marker);
+ }
+ generateThreadSafeness(inner, marker);
+ generateSince(inner, marker);
+
+ out() << "<ul>\n";
+
+ QString membersLink = generateListOfAllMemberFile(inner, marker);
+ if (!membersLink.isEmpty())
+ out() << "<li><a href=\"" << membersLink << "\">"
+ << "List of all members, including inherited members</a></li>\n";
+
+ QString obsoleteLink = generateLowStatusMemberFile(inner,
+ marker,
+ CodeMarker::Obsolete);
+ if (!obsoleteLink.isEmpty())
+ out() << "<li><a href=\"" << obsoleteLink << "\">"
+ << "Obsolete members</a></li>\n";
+
+ QString compatLink = generateLowStatusMemberFile(inner,
+ marker,
+ CodeMarker::Compat);
+ if (!compatLink.isEmpty())
+ out() << "<li><a href=\"" << compatLink << "\">"
+ << "Qt 3 support members</a></li>\n";
+
+ out() << "</ul>\n";
+
+ bool needOtherSection = false;
+
+ /*
+ sections is built above for the call to generateTableOfContents().
+ */
+ s = sections.begin();
+ while (s != sections.end()) {
+ if (s->members.isEmpty() && s->reimpMembers.isEmpty()) {
+ if (!s->inherited.isEmpty())
+ needOtherSection = true;
+ }
+ else {
+ if (!s->members.isEmpty()) {
+ // out() << "<hr />\n";
+ out() << "<a name=\""
+ << registerRef((*s).name.toLower())
+ << "\"></a>" << divNavTop << "\n";
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+ generateSection(s->members, inner, marker, CodeMarker::Summary);
+ }
+ if (!s->reimpMembers.isEmpty()) {
+ QString name = QString("Reimplemented ") + (*s).name;
+ // out() << "<hr />\n";
+ out() << "<a name=\""
+ << registerRef(name.toLower())
+ << "\"></a>" << divNavTop << "\n";
+ out() << "<h2>" << protectEnc(name) << "</h2>\n";
+ generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary);
+ }
+
+ if (!s->inherited.isEmpty()) {
+ out() << "<ul>\n";
+ generateSectionInheritedList(*s, inner, marker);
+ out() << "</ul>\n";
+ }
+ }
+ ++s;
+ }
+
+ if (needOtherSection) {
+ out() << "<h3>Additional Inherited Members</h3>\n"
+ "<ul>\n";
+
+ s = sections.begin();
+ while (s != sections.end()) {
+ if (s->members.isEmpty() && !s->inherited.isEmpty())
+ generateSectionInheritedList(*s, inner, marker);
+ ++s;
+ }
+ out() << "</ul>\n";
+ }
+
+ out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << '\n';
+
+ if (!inner->doc().isEmpty()) {
+ generateExtractionMark(inner, DetailedDescriptionMark);
+ //out() << "<hr />\n"
+ out() << "<div class=\"descr\">\n" // QTBUG-9504
+ << "<h2>" << "Detailed Description" << "</h2>\n";
+ generateBody(inner, marker);
+ out() << "</div>\n"; // QTBUG-9504
+ generateAlsoList(inner, marker);
+ generateMaintainerList(inner, marker);
+ generateExtractionMark(inner, EndMark);
+ }
+
+ sections = marker->sections(inner, CodeMarker::Detailed, CodeMarker::Okay);
+ s = sections.begin();
+ while (s != sections.end()) {
+ //out() << "<hr />\n";
+ if (!(*s).divClass.isEmpty())
+ out() << "<div class=\"" << (*s).divClass << "\">\n"; // QTBUG-9504
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+
+ NodeList::ConstIterator m = (*s).members.begin();
+ while (m != (*s).members.end()) {
+ if ((*m)->access() != Node::Private) { // ### check necessary?
+ if ((*m)->type() != Node::Class)
+ generateDetailedMember(*m, inner, marker);
+ else {
+ out() << "<h3> class ";
+ generateFullName(*m, inner, marker);
+ out() << "</h3>";
+ generateBrief(*m, marker, inner);
+ }
+
+ QStringList names;
+ names << (*m)->name();
+ if ((*m)->type() == Node::Function) {
+ const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m);
+ if (func->metaness() == FunctionNode::Ctor ||
+ func->metaness() == FunctionNode::Dtor ||
+ func->overloadNumber() != 1)
+ names.clear();
+ }
+ else if ((*m)->type() == Node::Property) {
+ const PropertyNode *prop = reinterpret_cast<const PropertyNode *>(*m);
+ if (!prop->getters().isEmpty() &&
+ !names.contains(prop->getters().first()->name()))
+ names << prop->getters().first()->name();
+ if (!prop->setters().isEmpty())
+ names << prop->setters().first()->name();
+ if (!prop->resetters().isEmpty())
+ names << prop->resetters().first()->name();
+ }
+ else if ((*m)->type() == Node::Enum) {
+ const EnumNode *enume = reinterpret_cast<const EnumNode*>(*m);
+ if (enume->flagsType())
+ names << enume->flagsType()->name();
+
+ foreach (const QString &enumName,
+ enume->doc().enumItemNames().toSet() -
+ enume->doc().omitEnumItemNames().toSet())
+ names << plainCode(marker->markedUpEnumValue(enumName,
+ enume));
+ }
+ }
+ ++m;
+ }
+ if (!(*s).divClass.isEmpty())
+ out() << "</div>\n"; // QTBUG-9504
+ ++s;
+ }
+ generateFooter(inner);
+}
+
+/*!
+ We delayed generation of the disambiguation pages until now, after
+ all the other pages have been generated. We do this because we might
+ encounter a link command that tries to link to a target on a QML
+ component page, but the link doesn't specify the module identifer
+ for the component, and the component name without a module
+ identifier is ambiguous. When such a link is found, qdoc can't find
+ the target, so it appends the target to the NameCollisionNode. After
+ the tree has been traversed and all these ambiguous links have been
+ added to the name collision nodes, this function is called. The list
+ of collision nodes is traversed here, and the disambiguation page for
+ each collision is generated. The disambiguation page will not only
+ disambiguate links to the component pages, but it will also disambiguate
+ links to properties, section headers, etc.
+ */
+void HtmlGenerator::generateDisambiguationPages()
+{
+ if (collisionNodes.isEmpty())
+ return;
+ for (int i=0; i<collisionNodes.size(); ++i) {
+ NameCollisionNode* ncn = collisionNodes.at(i);
+ ncn->clearCurrentChild();
+ beginSubPage(ncn, PageGenerator::fileName(ncn));
+ QString fullTitle = "Name Collision: " + ncn->fullTitle();
+ QString htmlTitle = fullTitle;
+ CodeMarker* marker = CodeMarker::markerForFileName(ncn->location().filePath());
+ if (ncn->isQmlNode()) {
+ // Replace the marker with a QML code marker.
+ if (ncn->isQmlNode())
+ marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
+ }
+
+ generateHeader(htmlTitle, ncn, marker);
+ if (!fullTitle.isEmpty())
+ out() << "<h1 class=\"title\">" << protectEnc(fullTitle) << "</h1>\n";
+ const NodeList& nl = ncn->childNodes();
+ NodeMap nm;
+ NodeList::ConstIterator it = nl.begin();
+ while (it != nl.end()) {
+ QString t = (*it)->qmlModuleIdentifier() + " " + protectEnc(fullTitle);
+ nm.insertMulti(t,(*it));
+ ++it;
+ }
+ generateAnnotatedList(ncn, marker, nm, true);
+
+ const QMap<QString,QString>& targets = ncn->linkTargets();
+ if (!targets.isEmpty()) {
+ QMap<QString,QString>::ConstIterator t = targets.begin();
+ while (t != targets.end()) {
+ out() << "<a name=\"" << Doc::canonicalTitle(t.key()) << "\"></a>";
+ out() << "<h2 class=\"title\">" << protectEnc(t.key()) << "</h2>\n";
+ out() << "<ul>\n";
+ it = nl.begin();
+ while (it != nl.end()) {
+ InnerNode* n = static_cast<InnerNode*>(*it);
+ Node* p = n->findNode(t.key());
+ if (p) {
+ QString link = linkForNode(p,0);
+ QString label = n->qmlModuleIdentifier() + "::" + n->name() + "::" + p->name();
+ out() << "<li>";
+ out() << "<a href=\"" << link << "\">";
+ out() << protectEnc(label) << "</a>";
+ out() << "</li>\n";
+ }
+ ++it;
+ }
+ out() << "</ul>\n";
+ ++t;
+ }
+ }
+
+ generateFooter(ncn);
+ endSubPage();
+ }
+}
+
+/*!
+ Generate the HTML page for an entity that doesn't map
+ to any underlying parsable C++ class or QML component.
+ */
+void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker)
+{
+ /*
+ If the fake node is a page node, and if the page type
+ is DITA map page, write the node's contents as a dita
+ map and return without doing anything else.
+ */
+ if (fake->subType() == Node::Page && fake->pageType() == Node::DitaMapPage) {
+ const DitaMapNode* dmn = static_cast<const DitaMapNode*>(fake);
+ writeDitaMap(dmn);
+ return;
+ }
+
+ SubTitleSize subTitleSize = LargeSubTitle;
+ QList<Section> sections;
+ QList<Section>::const_iterator s;
+ QString fullTitle = fake->fullTitle();
+ QString htmlTitle = fullTitle;
+
+ if (fake->subType() == Node::File && !fake->subTitle().isEmpty()) {
+ subTitleSize = SmallSubTitle;
+ htmlTitle += " (" + fake->subTitle() + ")";
+ }
+ else if (fake->subType() == Node::QmlBasicType) {
+ fullTitle = "QML Basic Type: " + fullTitle;
+ htmlTitle = fullTitle;
+
+ // Replace the marker with a QML code marker.
+ marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
+ }
+
+ generateHeader(htmlTitle, fake, marker);
+ /*
+ Generate the TOC for the new doc format.
+ Don't generate a TOC for the home page.
+ */
+ const QmlClassNode* qml_cn = 0;
+ if (fake->subType() == Node::QmlClass) {
+ qml_cn = static_cast<const QmlClassNode*>(fake);
+ sections = marker->qmlSections(qml_cn,CodeMarker::Summary);
+ generateTableOfContents(fake,marker,&sections);
+
+ // Replace the marker with a QML code marker.
+ marker = CodeMarker::markerForLanguage(QLatin1String("QML"));
+ }
+ else if (fake->subType() != Node::Collision && fake->name() != QString("index.html"))
+ generateTableOfContents(fake,marker,0);
+
+ generateTitle(fullTitle,
+ Text() << fake->subTitle(),
+ subTitleSize,
+ fake,
+ marker);
+
+ if (fake->subType() == Node::Module) {
+ // Generate brief text and status for modules.
+ generateBrief(fake, marker);
+ generateStatus(fake, marker);
+ generateSince(fake, marker);
+
+ if (moduleNamespaceMap.contains(fake->name())) {
+ out() << "<a name=\"" << registerRef("namespaces") << "\"></a>" << divNavTop << '\n';
+ out() << "<h2>Namespaces</h2>\n";
+ generateAnnotatedList(fake, marker, moduleNamespaceMap[fake->name()]);
+ }
+ if (moduleClassMap.contains(fake->name())) {
+ out() << "<a name=\"" << registerRef("classes") << "\"></a>" << divNavTop << '\n';
+ out() << "<h2>Classes</h2>\n";
+ generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]);
+ }
+ }
+ else if (fake->subType() == Node::HeaderFile) {
+ // Generate brief text and status for modules.
+ generateBrief(fake, marker);
+ generateStatus(fake, marker);
+ generateSince(fake, marker);
+
+ out() << "<ul>\n";
+
+ QString membersLink = generateListOfAllMemberFile(fake, marker);
+ if (!membersLink.isEmpty())
+ out() << "<li><a href=\"" << membersLink << "\">"
+ << "List of all members, including inherited members</a></li>\n";
+
+ QString obsoleteLink = generateLowStatusMemberFile(fake,
+ marker,
+ CodeMarker::Obsolete);
+ if (!obsoleteLink.isEmpty())
+ out() << "<li><a href=\"" << obsoleteLink << "\">"
+ << "Obsolete members</a></li>\n";
+
+ QString compatLink = generateLowStatusMemberFile(fake,
+ marker,
+ CodeMarker::Compat);
+ if (!compatLink.isEmpty())
+ out() << "<li><a href=\"" << compatLink << "\">"
+ << "Qt 3 support members</a></li>\n";
+
+ out() << "</ul>\n";
+ }
+ else if (fake->subType() == Node::QmlClass) {
+ const_cast<FakeNode*>(fake)->setCurrentChild();
+ const ClassNode* cn = qml_cn->classNode();
+ generateBrief(qml_cn, marker);
+ generateQmlInherits(qml_cn, marker);
+ generateQmlInheritedBy(qml_cn, marker);
+ generateQmlInstantiates(qml_cn, marker);
+ generateSince(qml_cn, marker);
+
+ QString allQmlMembersLink = generateAllQmlMembersFile(qml_cn, marker);
+ if (!allQmlMembersLink.isEmpty()) {
+ out() << "<ul>\n";
+ out() << "<li><a href=\"" << allQmlMembersLink << "\">"
+ << "List of all members, including inherited members</a></li>\n";
+ out() << "</ul>\n";
+ }
+
+ s = sections.begin();
+ while (s != sections.end()) {
+ out() << "<a name=\"" << registerRef((*s).name.toLower())
+ << "\"></a>" << divNavTop << "\n";
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+ generateQmlSummary(*s,fake,marker);
+ ++s;
+ }
+
+ generateExtractionMark(fake, DetailedDescriptionMark);
+ out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << '\n';
+ out() << "<h2>" << "Detailed Description" << "</h2>\n";
+ generateBody(fake, marker);
+ if (cn)
+ generateQmlText(cn->doc().body(), cn, marker, fake->name());
+ generateAlsoList(fake, marker);
+ generateExtractionMark(fake, EndMark);
+ //out() << "<hr />\n";
+
+ sections = marker->qmlSections(qml_cn,CodeMarker::Detailed);
+ s = sections.begin();
+ while (s != sections.end()) {
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+ NodeList::ConstIterator m = (*s).members.begin();
+ while (m != (*s).members.end()) {
+ generateDetailedQmlMember(*m, fake, marker);
+ out() << "<br/>\n";
+ ++m;
+ }
+ ++s;
+ }
+ generateFooter(fake);
+ const_cast<FakeNode*>(fake)->clearCurrentChild();
+ return;
+ }
+
+ sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay);
+ s = sections.begin();
+ while (s != sections.end()) {
+ out() << "<a name=\"" << registerRef((*s).name) << "\"></a>" << divNavTop << '\n';
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+ generateSectionList(*s, fake, marker, CodeMarker::Summary);
+ ++s;
+ }
+
+ Text brief = fake->doc().briefText();
+ if (fake->subType() == Node::Module && !brief.isEmpty()) {
+ generateExtractionMark(fake, DetailedDescriptionMark);
+ out() << "<a name=\"" << registerRef("details") << "\"></a>" << divNavTop << '\n';
+ out() << "<div class=\"descr\">\n"; // QTBUG-9504
+ out() << "<h2>" << "Detailed Description" << "</h2>\n";
+ }
+ else {
+ generateExtractionMark(fake, DetailedDescriptionMark);
+ out() << "<div class=\"descr\"> <a name=\"" << registerRef("details") << "\"></a>\n"; // QTBUG-9504
+ }
+
+ generateBody(fake, marker);
+ out() << "</div>\n"; // QTBUG-9504
+ generateAlsoList(fake, marker);
+ generateExtractionMark(fake, EndMark);
+
+ if ((fake->subType() == Node::Group) && !fake->groupMembers().isEmpty()) {
+ NodeMap groupMembersMap;
+ foreach (const Node *node, fake->groupMembers()) {
+ if (node->type() == Node::Class || node->type() == Node::Namespace)
+ groupMembersMap[node->name()] = node;
+ }
+ generateAnnotatedList(fake, marker, groupMembersMap);
+ }
+ else if ((fake->subType() == Node::QmlModule) && !fake->qmlModuleMembers().isEmpty()) {
+ NodeMap qmlModuleMembersMap;
+ foreach (const Node* node, fake->qmlModuleMembers()) {
+ if (node->type() == Node::Fake && node->subType() == Node::QmlClass)
+ qmlModuleMembersMap[node->name()] = node;
+ }
+ generateAnnotatedList(fake, marker, qmlModuleMembersMap);
+ }
+
+ sections = marker->sections(fake, CodeMarker::Detailed, CodeMarker::Okay);
+ s = sections.begin();
+ while (s != sections.end()) {
+ //out() << "<hr />\n";
+ out() << "<h2>" << protectEnc((*s).name) << "</h2>\n";
+
+ NodeList::ConstIterator m = (*s).members.begin();
+ while (m != (*s).members.end()) {
+ generateDetailedMember(*m, fake, marker);
+ ++m;
+ }
+ ++s;
+ }
+ generateFooter(fake);
+}
+
+/*!
+ Returns "html" for this subclass of Generator.
+ */
+QString HtmlGenerator::fileExtension(const Node * /* node */) const
+{
+ return "html";
+}
+
+/*!
+ Output breadcrumb list in the html file.
+ */
+void HtmlGenerator::generateBreadCrumbs(const QString &title,
+ const Node *node,
+ CodeMarker *marker)
+{
+ if (noBreadCrumbs)
+ return;
+
+ Text breadcrumbs;
+ if (node->type() == Node::Class) {
+ const ClassNode *cn = static_cast<const ClassNode *>(node);
+ QString name = node->moduleName();
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::Link, QLatin1String("All Modules"))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, QLatin1String("Modules"))
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << Atom(Atom::ListItemRight);
+ if (!name.isEmpty())
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::AutoLink, name)
+ << Atom(Atom::ListItemRight);
+ if (!cn->name().isEmpty())
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::String, protectEnc(cn->name()))
+ << Atom(Atom::ListItemRight);
+ }
+ else if (node->type() == Node::Fake) {
+ const FakeNode* fn = static_cast<const FakeNode*>(node);
+ if (node->subType() == Node::Module) {
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::Link, QLatin1String("All Modules"))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, QLatin1String("Modules"))
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << Atom(Atom::ListItemRight);
+ QString name = node->name();
+ if (!name.isEmpty())
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::String, protectEnc(name))
+ << Atom(Atom::ListItemRight);
+ }
+ else if (node->subType() == Node::Group) {
+ if (fn->name() == QString("modules"))
+ breadcrumbs << Atom(Atom::String, QLatin1String("Modules"));
+ else
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::String, protectEnc(title))
+ << Atom(Atom::ListItemRight);
+ }
+ else if (node->subType() == Node::Page) {
+ if (fn->name() == QString("qdeclarativeexamples.html")) {
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::Link, QLatin1String("Qt Examples"))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, QLatin1String("Examples"))
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << Atom(Atom::ListItemRight);
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::AutoLink, QLatin1String("QML Examples & Demos"))
+ << Atom(Atom::ListItemRight);
+ }
+ else if (fn->name().startsWith("examples-")) {
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::Link, QLatin1String("Qt Examples"))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, QLatin1String("Examples"))
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << Atom(Atom::ListItemRight);
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::String, protectEnc(title))
+ << Atom(Atom::ListItemRight);
+ }
+ else if (fn->name() == QString("namespaces.html"))
+ breadcrumbs << Atom(Atom::String, QLatin1String("Namespaces"));
+ else
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::String, protectEnc(title))
+ << Atom(Atom::ListItemRight);
+ }
+ else if (node->subType() == Node::QmlClass) {
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::AutoLink, QLatin1String("Basic QML Types"))
+ << Atom(Atom::ListItemRight);
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::String, protectEnc(title))
+ << Atom(Atom::ListItemRight);
+ }
+ else if (node->subType() == Node::Example) {
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::Link, QLatin1String("Qt Examples"))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, QLatin1String("Examples"))
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << Atom(Atom::ListItemRight);
+ QStringList sl = fn->name().split('/');
+ if (sl.contains("declarative"))
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::AutoLink, QLatin1String("QML Examples & Demos"))
+ << Atom(Atom::ListItemRight);
+ else {
+ QString name = protectEnc("examples-" + sl.at(0) + ".html"); // this generates an empty link
+ QString t = CodeParser::titleFromName(name);
+ }
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::String, protectEnc(title))
+ << Atom(Atom::ListItemRight);
+ }
+ }
+ else if (node->type() == Node::Namespace) {
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::Link, QLatin1String("All Namespaces"))
+ << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, QLatin1String("Namespaces"))
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << Atom(Atom::ListItemRight);
+ breadcrumbs << Atom(Atom::ListItemLeft)
+ << Atom(Atom::String, protectEnc(title))
+ << Atom(Atom::ListItemRight);
+ }
+
+ generateText(breadcrumbs, node, marker);
+}
+
+void HtmlGenerator::generateHeader(const QString& title,
+ const Node *node,
+ CodeMarker *marker)
+{
+ out() << QString("<?xml version=\"1.0\" encoding=\"%1\"?>\n").arg(outputEncoding);
+ out() << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
+ out() << QString("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"%1\" lang=\"%1\">\n").arg(naturalLanguage);
+ out() << "<head>\n";
+ out() << " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
+ if (node && !node->doc().location().isEmpty())
+ out() << "<!-- " << node->doc().location().fileName() << " -->\n";
+
+ QString shortVersion = myTree->version();
+ if (shortVersion.count(QChar('.')) == 2)
+ shortVersion.truncate(shortVersion.lastIndexOf(QChar('.')));
+ if (!project.isEmpty())
+ shortVersion = project + QLatin1String(" ") + shortVersion + QLatin1String(": ");
+ else
+ shortVersion = QLatin1String("Qt ") + shortVersion + QLatin1String(": ");
+
+ // Generating page title
+ out() << " <title>" << shortVersion << protectEnc(title) << "</title>\n";
+
+ // Include style sheet and script links.
+ out() << headerStyles;
+ out() << headerScripts;
+ out() << endHeader;
+
+#ifdef GENERATE_MAC_REFS
+ if (mainPage)
+ generateMacRef(node, marker);
+#endif
+
+ out() << QString(postHeader).replace("\\" + COMMAND_VERSION, myTree->version());
+ generateBreadCrumbs(title,node,marker);
+ out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, myTree->version());
+
+ navigationLinks.clear();
+
+ if (node && !node->links().empty()) {
+ QPair<QString,QString> linkPair;
+ QPair<QString,QString> anchorPair;
+ const Node *linkNode;
+
+ if (node->links().contains(Node::PreviousLink)) {
+ linkPair = node->links()[Node::PreviousLink];
+ linkNode = findNodeForTarget(linkPair.first, node, marker);
+ if (!linkNode || linkNode == node)
+ anchorPair = linkPair;
+ else
+ anchorPair = anchorForNode(linkNode);
+
+ out() << " <link rel=\"prev\" href=\""
+ << anchorPair.first << "\" />\n";
+
+ navigationLinks += "[Previous: <a href=\"" + anchorPair.first + "\">";
+ if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
+ navigationLinks += protect(anchorPair.second);
+ else
+ navigationLinks += protect(linkPair.second);
+ navigationLinks += "</a>]\n";
+ }
+ if (node->links().contains(Node::NextLink)) {
+ linkPair = node->links()[Node::NextLink];
+ linkNode = findNodeForTarget(linkPair.first, node, marker);
+ if (!linkNode || linkNode == node)
+ anchorPair = linkPair;
+ else
+ anchorPair = anchorForNode(linkNode);
+
+ out() << " <link rel=\"next\" href=\""
+ << anchorPair.first << "\" />\n";
+
+ navigationLinks += "[Next: <a href=\"" + anchorPair.first + "\">";
+ if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty())
+ navigationLinks += protect(anchorPair.second);
+ else
+ navigationLinks += protect(linkPair.second);
+ navigationLinks += "</a>]\n";
+ }
+ if (node->links().contains(Node::StartLink)) {
+ linkPair = node->links()[Node::StartLink];
+ linkNode = findNodeForTarget(linkPair.first, node, marker);
+ if (!linkNode || linkNode == node)
+ anchorPair = linkPair;
+ else
+ anchorPair = anchorForNode(linkNode);
+ out() << " <link rel=\"start\" href=\""
+ << anchorPair.first << "\" />\n";
+ }
+ }
+
+ if (node && !node->links().empty())
+ out() << "<p class=\"naviNextPrevious headerNavi\">\n" << navigationLinks << "</p><p/>\n";
+}
+
+void HtmlGenerator::generateTitle(const QString& title,
+ const Text &subTitle,
+ SubTitleSize subTitleSize,
+ const Node *relative,
+ CodeMarker *marker)
+{
+ if (!title.isEmpty())
+ out() << "<h1 class=\"title\">" << protectEnc(title) << "</h1>\n";
+ if (!subTitle.isEmpty()) {
+ out() << "<span";
+ if (subTitleSize == SmallSubTitle)
+ out() << " class=\"small-subtitle\">";
+ else
+ out() << " class=\"subtitle\">";
+ generateText(subTitle, relative, marker);
+ out() << "</span>\n";
+ }
+}
+
+void HtmlGenerator::generateFooter(const Node *node)
+{
+ if (node && !node->links().empty())
+ out() << "<p class=\"naviNextPrevious footerNavi\">\n" << navigationLinks << "</p>\n";
+
+ out() << QString(footer).replace("\\" + COMMAND_VERSION, myTree->version())
+ << QString(address).replace("\\" + COMMAND_VERSION, myTree->version());
+
+ out() << "</body>\n";
+ out() << "</html>\n";
+}
+
+void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker,
+ const Node *relative)
+{
+ Text brief = node->doc().briefText();
+ if (!brief.isEmpty()) {
+ generateExtractionMark(node, BriefMark);
+ out() << "<p>";
+ generateText(brief, node, marker);
+
+ if (!relative || node == relative)
+ out() << " <a href=\"#";
+ else
+ out() << " <a href=\"" << linkForNode(node, relative) << '#';
+ out() << registerRef("details") << "\">More...</a></p>\n";
+
+
+ generateExtractionMark(node, EndMark);
+ }
+}
+
+void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker)
+{
+ if (!inner->includes().isEmpty()) {
+ out() << "<pre class=\"cpp\">"
+ << trimmedTrailing(highlightedCode(indent(codeIndent,
+ marker->markedUpIncludes(inner->includes())),
+ marker,inner))
+ << "</pre>";
+ }
+}
+
+/*!
+ Revised for the new doc format.
+ Generates a table of contents beginning at \a node.
+ */
+void HtmlGenerator::generateTableOfContents(const Node *node,
+ CodeMarker *marker,
+ QList<Section>* sections)
+{
+ QList<Atom*> toc;
+ if (node->doc().hasTableOfContents())
+ toc = node->doc().tableOfContents();
+ if (toc.isEmpty() && !sections && (node->subType() != Node::Module))
+ return;
+
+ QStringList sectionNumber;
+ int detailsBase = 0;
+
+ // disable nested links in table of contents
+ inContents = true;
+ inLink = true;
+
+ out() << "<div class=\"toc\">\n";
+ out() << "<h3><a name=\"toc\">Contents</a></h3>\n";
+ sectionNumber.append("1");
+ out() << "<ul>\n";
+
+ if (node->subType() == Node::Module) {
+ if (moduleNamespaceMap.contains(node->name())) {
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\"><a href=\"#"
+ << registerRef("namespaces")
+ << "\">Namespaces</a></li>\n";
+ }
+ if (moduleClassMap.contains(node->name())) {
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\"><a href=\"#"
+ << registerRef("classes")
+ << "\">Classes</a></li>\n";
+ }
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\"><a href=\"#"
+ << registerRef("details")
+ << "\">Detailed Description</a></li>\n";
+ for (int i = 0; i < toc.size(); ++i) {
+ if (toc.at(i)->string().toInt() == 1) {
+ detailsBase = 1;
+ break;
+ }
+ }
+ }
+ else if (sections && ((node->type() == Node::Class) ||
+ (node->type() == Node::Namespace) ||
+ (node->subType() == Node::QmlClass))) {
+ QList<Section>::ConstIterator s = sections->begin();
+ while (s != sections->end()) {
+ if (!s->members.isEmpty() || !s->reimpMembers.isEmpty()) {
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\"><a href=\"#"
+ << registerRef((*s).pluralMember)
+ << "\">" << (*s).name
+ << "</a></li>\n";
+ }
+ ++s;
+ }
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\"><a href=\"#"
+ << registerRef("details")
+ << "\">Detailed Description</a></li>\n";
+ for (int i = 0; i < toc.size(); ++i) {
+ if (toc.at(i)->string().toInt() == 1) {
+ detailsBase = 1;
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < toc.size(); ++i) {
+ Atom *atom = toc.at(i);
+ int nextLevel = atom->string().toInt() + detailsBase;
+ if (nextLevel >= 0) {
+ if (sectionNumber.size() < nextLevel) {
+ do {
+ sectionNumber.append("1");
+ } while (sectionNumber.size() < nextLevel);
+ }
+ else {
+ while (sectionNumber.size() > nextLevel) {
+ sectionNumber.removeLast();
+ }
+ sectionNumber.last() = QString::number(sectionNumber.last().toInt() + 1);
+ }
+ }
+ int numAtoms;
+ Text headingText = Text::sectionHeading(atom);
+ QString s = headingText.toString();
+ out() << "<li class=\"level"
+ << sectionNumber.size()
+ << "\">";
+ out() << "<a href=\""
+ << '#'
+ << Doc::canonicalTitle(s)
+ << "\">";
+ generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms);
+ out() << "</a></li>\n";
+ }
+ while (!sectionNumber.isEmpty()) {
+ sectionNumber.removeLast();
+ }
+ out() << "</ul>\n";
+ out() << "</div>\n";
+ inContents = false;
+ inLink = false;
+}
+
+QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner,
+ CodeMarker *marker)
+{
+ QList<Section> sections;
+ QList<Section>::ConstIterator s;
+
+ sections = marker->sections(inner,
+ CodeMarker::Subpage,
+ CodeMarker::Okay);
+ if (sections.isEmpty())
+ return QString();
+
+ QString fileName = fileBase(inner) + "-members." + fileExtension(inner);
+ beginSubPage(inner, fileName);
+ QString title = "List of All Members for " + inner->name();
+ generateHeader(title, inner, marker);
+ generateTitle(title, Text(), SmallSubTitle, inner, marker);
+ out() << "<p>This is the complete list of members for ";
+ generateFullName(inner, 0, marker);
+ out() << ", including inherited members.</p>\n";
+
+ Section section = sections.first();
+ generateSectionList(section, 0, marker, CodeMarker::Subpage);
+
+ generateFooter();
+ endSubPage();
+ return fileName;
+}
+
+/*!
+ This function creates an html page on which are listed all
+ the members of QML class \a qml_cn, including the inherited
+ members. The \a marker is used for formatting stuff.
+ */
+QString HtmlGenerator::generateAllQmlMembersFile(const QmlClassNode* qml_cn,
+ CodeMarker* marker)
+{
+ QList<Section> sections;
+ QList<Section>::ConstIterator s;
+
+ sections = marker->qmlSections(qml_cn,CodeMarker::Subpage);
+ if (sections.isEmpty())
+ return QString();
+
+ QString fileName = fileBase(qml_cn) + "-members." + fileExtension(qml_cn);
+ beginSubPage(qml_cn, fileName);
+ QString title = "List of All Members for " + qml_cn->name();
+ generateHeader(title, qml_cn, marker);
+ generateTitle(title, Text(), SmallSubTitle, qml_cn, marker);
+ out() << "<p>This is the complete list of members for ";
+ generateFullName(qml_cn, 0, marker);
+ out() << ", including inherited members.</p>\n";
+
+ Section section = sections.first();
+ generateSectionList(section, 0, marker, CodeMarker::Subpage);
+
+ generateFooter();
+ endSubPage();
+ return fileName;
+}
+
+QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner,
+ CodeMarker *marker,
+ CodeMarker::Status status)
+{
+ QList<Section> sections = marker->sections(inner,
+ CodeMarker::Summary,
+ status);
+ QMutableListIterator<Section> j(sections);
+ while (j.hasNext()) {
+ if (j.next().members.size() == 0)
+ j.remove();
+ }
+ if (sections.isEmpty())
+ return QString();
+
+ int i;
+
+ QString title;
+ QString fileName;
+
+ if (status == CodeMarker::Compat) {
+ title = "Qt 3 Support Members for " + inner->name();
+ fileName = fileBase(inner) + "-qt3." + fileExtension(inner);
+ }
+ else {
+ title = "Obsolete Members for " + inner->name();
+ fileName = fileBase(inner) + "-obsolete." + fileExtension(inner);
+ }
+
+ beginSubPage(inner, fileName);
+ generateHeader(title, inner, marker);
+ generateTitle(title, Text(), SmallSubTitle, inner, marker);
+
+ if (status == CodeMarker::Compat) {
+ out() << "<p><b>The following class members are part of the "
+ "<a href=\"qt3support.html\">Qt 3 support layer</a>.</b> "
+ "They are provided to help you port old code to Qt 4. We advise against "
+ "using them in new code.</p>\n";
+ }
+ else {
+ out() << "<p><b>The following class members are obsolete.</b> "
+ << "They are provided to keep old source code working. "
+ << "We strongly advise against using them in new code.</p>\n";
+ }
+
+ out() << "<p><ul><li><a href=\""
+ << linkForNode(inner, 0) << "\">"
+ << protectEnc(inner->name())
+ << " class reference</a></li></ul></p>\n";
+
+ for (i = 0; i < sections.size(); ++i) {
+ out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n";
+ generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary);
+ }
+
+ sections = marker->sections(inner, CodeMarker::Detailed, status);
+ for (i = 0; i < sections.size(); ++i) {
+ //out() << "<hr />\n";
+ out() << "<h2>" << protectEnc(sections.at(i).name) << "</h2>\n";
+
+ NodeList::ConstIterator m = sections.at(i).members.begin();
+ while (m != sections.at(i).members.end()) {
+ if ((*m)->access() != Node::Private)
+ generateDetailedMember(*m, inner, marker);
+ ++m;
+ }
+ }
+
+ generateFooter();
+ endSubPage();
+ return fileName;
+}
+
+void HtmlGenerator::generateClassHierarchy(const Node *relative,
+ CodeMarker *marker,
+ const QMap<QString,const Node*> &classMap)
+{
+ if (classMap.isEmpty())
+ return;
+
+ NodeMap topLevel;
+ NodeMap::ConstIterator c = classMap.begin();
+ while (c != classMap.end()) {
+ const ClassNode *classe = static_cast<const ClassNode *>(*c);
+ if (classe->baseClasses().isEmpty())
+ topLevel.insert(classe->name(), classe);
+ ++c;
+ }
+
+ QStack<NodeMap > stack;
+ stack.push(topLevel);
+
+ out() << "<ul>\n";
+ while (!stack.isEmpty()) {
+ if (stack.top().isEmpty()) {
+ stack.pop();
+ out() << "</ul>\n";
+ }
+ else {
+ const ClassNode *child =
+ static_cast<const ClassNode *>(*stack.top().begin());
+ out() << "<li>";
+ generateFullName(child, relative, marker);
+ out() << "</li>\n";
+ stack.top().erase(stack.top().begin());
+
+ NodeMap newTop;
+ foreach (const RelatedClass &d, child->derivedClasses()) {
+ if (d.access != Node::Private && !d.node->doc().isEmpty())
+ newTop.insert(d.node->name(), d.node);
+ }
+ if (!newTop.isEmpty()) {
+ stack.push(newTop);
+ out() << "<ul>\n";
+ }
+ }
+ }
+}
+
+void HtmlGenerator::generateAnnotatedList(const Node *relative,
+ CodeMarker *marker,
+ const NodeMap &nodeMap,
+ bool allOdd)
+{
+ out() << "<table class=\"annotated\">\n";
+
+ int row = 0;
+ foreach (const QString &name, nodeMap.keys()) {
+ const Node *node = nodeMap[name];
+
+ if (node->status() == Node::Obsolete)
+ continue;
+
+ if (allOdd || (++row % 2 == 1))
+ out() << "<tr class=\"odd topAlign\">";
+ else
+ out() << "<tr class=\"even topAlign\">";
+ out() << "<td class=\"tblName\"><p>";
+ generateFullName(node, relative, marker);
+ out() << "</p></td>";
+
+ if (!(node->type() == Node::Fake)) {
+ Text brief = node->doc().trimmedBriefText(name);
+ if (!brief.isEmpty()) {
+ out() << "<td class=\"tblDescr\"><p>";
+ generateText(brief, node, marker);
+ out() << "</p></td>";
+ }
+ }
+ else {
+ out() << "<td class=\"tblDescr\"><p>";
+ out() << protectEnc(node->doc().briefText().toString());
+ out() << "</p></td>";
+ }
+ out() << "</tr>\n";
+ }
+ out() << "</table>\n";
+}
+
+/*!
+ This function finds the common prefix of the names of all
+ the classes in \a classMap and then generates a compact
+ list of the class names alphabetized on the part of the
+ name not including the common prefix. You can tell the
+ function to use \a comonPrefix as the common prefix, but
+ normally you let it figure it out itself by looking at
+ the name of the first and last classes in \a classMap.
+ */
+void HtmlGenerator::generateCompactList(const Node *relative,
+ CodeMarker *marker,
+ const NodeMap &classMap,
+ bool includeAlphabet,
+ QString commonPrefix)
+{
+ const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_'
+
+ if (classMap.isEmpty())
+ return;
+
+ /*
+ If commonPrefix is not empty, then the caller knows what
+ the common prefix is and has passed it in, so just use that
+ one. But if the commonPrefix is empty (it normally is), then
+ compute a common prefix using this simple algorithm. Note we
+ assume the prefix length is 1, i.e. we will have a single
+ character as the common prefix.
+ */
+ int commonPrefixLen = commonPrefix.length();
+ if (commonPrefixLen == 0) {
+ QVector<int> count(26);
+ for (int i=0; i<26; ++i)
+ count[i] = 0;
+
+ NodeMap::const_iterator iter = classMap.begin();
+ while (iter != classMap.end()) {
+ if (!iter.key().contains("::")) {
+ QChar c = iter.key()[0];
+ if ((c >= 'A') && (c <= 'Z')) {
+ int idx = c.unicode() - QChar('A').unicode();
+ ++count[idx];
+ }
+ }
+ ++iter;
+ }
+ int highest = 0;
+ int idx = -1;
+ for (int i=0; i<26; ++i) {
+ if (count[i] > highest) {
+ highest = count[i];
+ idx = i;
+ }
+ }
+ idx += QChar('A').unicode();
+ QChar common(idx);
+ commonPrefix = common;
+ commonPrefixLen = 1;
+
+#if 0
+ /*
+ The algorithm below eventually failed, so it was replaced
+ with the simple (perhaps too simple) algorithm above.
+
+ The caller didn't pass in a common prefix, so get the common
+ prefix by looking at the class names of the first and last
+ classes in the class map. Discard any namespace names and
+ just use the bare class names. For Qt, the prefix is "Q".
+
+ Note that the algorithm used here to derive the common prefix
+ from the first and last classes in alphabetical order (QAccel
+ and QXtWidget in Qt 2.1), fails if either class name does not
+ begin with Q.
+ */
+ QString first;
+ QString last;
+ NodeMap::const_iterator iter = classMap.begin();
+ while (iter != classMap.end()) {
+ if (!iter.key().contains("::")) {
+ first = iter.key();
+ break;
+ }
+ ++iter;
+ }
+
+ if (first.isEmpty())
+ first = classMap.begin().key();
+
+ iter = classMap.end();
+ while (iter != classMap.begin()) {
+ --iter;
+ if (!iter.key().contains("::")) {
+ last = iter.key();
+ break;
+ }
+ }
+
+ if (last.isEmpty())
+ last = classMap.begin().key();
+
+ if (classMap.size() > 1) {
+ while (commonPrefixLen < first.length() + 1 &&
+ commonPrefixLen < last.length() + 1 &&
+ first[commonPrefixLen] == last[commonPrefixLen])
+ ++commonPrefixLen;
+ }
+
+ commonPrefix = first.left(commonPrefixLen);
+#endif
+ }
+
+ /*
+ Divide the data into 37 paragraphs: 0, ..., 9, A, ..., Z,
+ underscore (_). QAccel will fall in paragraph 10 (A) and
+ QXtWidget in paragraph 33 (X). This is the only place where we
+ assume that NumParagraphs is 37. Each paragraph is a NodeMap.
+ */
+ NodeMap paragraph[NumParagraphs+1];
+ QString paragraphName[NumParagraphs+1];
+ QSet<char> usedParagraphNames;
+
+ NodeMap::ConstIterator c = classMap.begin();
+ while (c != classMap.end()) {
+ QStringList pieces = c.key().split("::");
+ QString key;
+ int idx = commonPrefixLen;
+ if (!pieces.last().startsWith(commonPrefix))
+ idx = 0;
+ if (pieces.size() == 1)
+ key = pieces.last().mid(idx).toLower();
+ else
+ key = pieces.last().toLower();
+
+ int paragraphNr = NumParagraphs - 1;
+
+ if (key[0].digitValue() != -1) {
+ paragraphNr = key[0].digitValue();
+ }
+ else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) {
+ paragraphNr = 10 + key[0].unicode() - 'a';
+ }
+
+ paragraphName[paragraphNr] = key[0].toUpper();
+ usedParagraphNames.insert(key[0].toLower().cell());
+ paragraph[paragraphNr].insert(key, c.value());
+ ++c;
+ }
+
+ /*
+ Each paragraph j has a size: paragraph[j].count(). In the
+ discussion, we will assume paragraphs 0 to 5 will have sizes
+ 3, 1, 4, 1, 5, 9.
+
+ We now want to compute the paragraph offset. Paragraphs 0 to 6
+ start at offsets 0, 3, 4, 8, 9, 14, 23.
+ */
+ int paragraphOffset[NumParagraphs + 1]; // 37 + 1
+ paragraphOffset[0] = 0;
+ for (int i=0; i<NumParagraphs; i++) // i = 0..36
+ paragraphOffset[i+1] = paragraphOffset[i] + paragraph[i].count();
+
+ /*
+ Output the alphabet as a row of links.
+ */
+ if (includeAlphabet) {
+ out() << "<p class=\"centerAlign functionIndex\"><b>";
+ for (int i = 0; i < 26; i++) {
+ QChar ch('a' + i);
+ if (usedParagraphNames.contains(char('a' + i)))
+ out() << QString("<a href=\"#%1\">%2</a>&nbsp;").arg(ch).arg(ch.toUpper());
+ }
+ out() << "</b></p>\n";
+ }
+
+ /*
+ Output a <div> element to contain all the <dl> elements.
+ */
+ out() << "<div class=\"flowListDiv\">\n";
+ numTableRows = 0;
+
+ int curParNr = 0;
+ int curParOffset = 0;
+
+ for (int i=0; i<classMap.count(); i++) {
+ while ((curParNr < NumParagraphs) &&
+ (curParOffset == paragraph[curParNr].count())) {
+ ++curParNr;
+ curParOffset = 0;
+ }
+
+ /*
+ Starting a new paragraph means starting a new <dl>.
+ */
+ if (curParOffset == 0) {
+ if (i > 0)
+ out() << "</dl>\n";
+ if (++numTableRows % 2 == 1)
+ out() << "<dl class=\"flowList odd\">";
+ else
+ out() << "<dl class=\"flowList even\">";
+ out() << "<dt class=\"alphaChar\">";
+ if (includeAlphabet) {
+ QChar c = paragraphName[curParNr][0].toLower();
+ out() << QString("<a name=\"%1\"></a>").arg(c);
+ }
+ out() << "<b>"
+ << paragraphName[curParNr]
+ << "</b>";
+ out() << "</dt>\n";
+ }
+
+ /*
+ Output a <dd> for the current offset in the current paragraph.
+ */
+ out() << "<dd>";
+ if ((curParNr < NumParagraphs) &&
+ !paragraphName[curParNr].isEmpty()) {
+ NodeMap::Iterator it;
+ it = paragraph[curParNr].begin();
+ for (int i=0; i<curParOffset; i++)
+ ++it;
+
+ /*
+ Previously, we used generateFullName() for this, but we
+ require some special formatting.
+ */
+ out() << "<a href=\"" << linkForNode(it.value(), relative) << "\">";
+
+ QStringList pieces;
+ if (it.value()->subType() == Node::QmlClass)
+ pieces << it.value()->name();
+ else
+ pieces = fullName(it.value(), relative, marker).split("::");
+ out() << protectEnc(pieces.last());
+ out() << "</a>";
+ if (pieces.size() > 1) {
+ out() << " (";
+ generateFullName(it.value()->parent(), relative, marker);
+ out() << ')';
+ }
+ }
+ out() << "</dd>\n";
+ curParOffset++;
+ }
+ if (classMap.count() > 0)
+ out() << "</dl>\n";
+
+ out() << "</div>\n";
+}
+
+void HtmlGenerator::generateFunctionIndex(const Node *relative,
+ CodeMarker *marker)
+{
+ out() << "<p class=\"centerAlign functionIndex\"><b>";
+ for (int i = 0; i < 26; i++) {
+ QChar ch('a' + i);
+ out() << QString("<a href=\"#%1\">%2</a>&nbsp;").arg(ch).arg(ch.toUpper());
+ }
+ out() << "</b></p>\n";
+
+ char nextLetter = 'a';
+ char currentLetter;
+
+#if 1
+ out() << "<ul>\n";
+#endif
+ QMap<QString, NodeMap >::ConstIterator f = funcIndex.begin();
+ while (f != funcIndex.end()) {
+#if 1
+ out() << "<li>";
+#else
+ out() << "<p>";
+#endif
+ out() << protectEnc(f.key()) << ':';
+
+ currentLetter = f.key()[0].unicode();
+ while (islower(currentLetter) && currentLetter >= nextLetter) {
+ out() << QString("<a name=\"%1\"></a>").arg(nextLetter);
+ nextLetter++;
+ }
+
+ NodeMap::ConstIterator s = (*f).begin();
+ while (s != (*f).end()) {
+ out() << ' ';
+ generateFullName((*s)->parent(), relative, marker, *s);
+ ++s;
+ }
+#if 1
+ out() << "</li>";
+#else
+ out() << "</p>";
+#endif
+ out() << '\n';
+ ++f;
+ }
+#if 1
+ out() << "</ul>\n";
+#endif
+}
+
+void HtmlGenerator::generateLegaleseList(const Node *relative,
+ CodeMarker *marker)
+{
+ QMap<Text, const Node *>::ConstIterator it = legaleseTexts.begin();
+ while (it != legaleseTexts.end()) {
+ Text text = it.key();
+ //out() << "<hr />\n";
+ generateText(text, relative, marker);
+ out() << "<ul>\n";
+ do {
+ out() << "<li>";
+ generateFullName(it.value(), relative, marker);
+ out() << "</li>\n";
+ ++it;
+ } while (it != legaleseTexts.end() && it.key() == text);
+ out() << "</ul>\n";
+ }
+}
+
+void HtmlGenerator::generateQmlItem(const Node *node,
+ const Node *relative,
+ CodeMarker *marker,
+ bool summary)
+{
+ QString marked = marker->markedUpQmlItem(node,summary);
+ QRegExp templateTag("(<[^@>]*>)");
+ if (marked.indexOf(templateTag) != -1) {
+ QString contents = protectEnc(marked.mid(templateTag.pos(1),
+ templateTag.cap(1).length()));
+ marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
+ contents);
+ }
+ marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"),
+ "<i>\\1<sub>\\2</sub></i>");
+ marked.replace("<@param>", "<i>");
+ marked.replace("</@param>", "</i>");
+
+ if (summary)
+ marked.replace("@name>", "b>");
+
+ marked.replace("<@extra>", "<tt>");
+ marked.replace("</@extra>", "</tt>");
+
+ if (summary) {
+ marked.remove("<@type>");
+ marked.remove("</@type>");
+ }
+ out() << highlightedCode(marked, marker, relative, false, node);
+}
+
+void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */)
+{
+ QMap<const FakeNode *, QMap<QString, FakeNode *> > fakeNodeMap;
+ QMap<QString, const FakeNode *> groupTitlesMap;
+ QMap<QString, FakeNode *> uncategorizedNodeMap;
+ QRegExp singleDigit("\\b([0-9])\\b");
+
+ const NodeList children = myTree->root()->childNodes();
+ foreach (Node *child, children) {
+ if (child->type() == Node::Fake && child != relative) {
+ FakeNode *fakeNode = static_cast<FakeNode *>(child);
+
+ // Check whether the page is part of a group or is the group
+ // definition page.
+ QString group;
+ bool isGroupPage = false;
+ if (fakeNode->doc().metaCommandsUsed().contains("group")) {
+ group = fakeNode->doc().metaCommandArgs("group")[0];
+ isGroupPage = true;
+ }
+
+ // there are too many examples; they would clutter the list
+ if (fakeNode->subType() == Node::Example)
+ continue;
+
+ // not interested either in individual (Qt Designer etc.) manual chapters
+ if (fakeNode->links().contains(Node::ContentsLink))
+ continue;
+
+ // Discard external nodes.
+ if (fakeNode->subType() == Node::ExternalPage)
+ continue;
+
+ QString sortKey = fakeNode->fullTitle().toLower();
+ if (sortKey.startsWith("the "))
+ sortKey.remove(0, 4);
+ sortKey.replace(singleDigit, "0\\1");
+
+ if (!group.isEmpty()) {
+ if (isGroupPage) {
+ // If we encounter a group definition page, we add all
+ // the pages in that group to the list for that group.
+ foreach (Node *member, fakeNode->groupMembers()) {
+ if (member->type() != Node::Fake)
+ continue;
+ FakeNode *page = static_cast<FakeNode *>(member);
+ if (page) {
+ QString sortKey = page->fullTitle().toLower();
+ if (sortKey.startsWith("the "))
+ sortKey.remove(0, 4);
+ sortKey.replace(singleDigit, "0\\1");
+ fakeNodeMap[const_cast<const FakeNode *>(fakeNode)].insert(sortKey, page);
+ groupTitlesMap[fakeNode->fullTitle()] = const_cast<const FakeNode *>(fakeNode);
+ }
+ }
+ }
+ else if (!isGroupPage) {
+ // If we encounter a page that belongs to a group then
+ // we add that page to the list for that group.
+ const FakeNode *groupNode = static_cast<const FakeNode *>(myTree->root()->findNode(group, Node::Fake));
+ if (groupNode)
+ fakeNodeMap[groupNode].insert(sortKey, fakeNode);
+ //else
+ // uncategorizedNodeMap.insert(sortKey, fakeNode);
+ }// else
+ // uncategorizedNodeMap.insert(sortKey, fakeNode);
+ }// else
+ // uncategorizedNodeMap.insert(sortKey, fakeNode);
+ }
+ }
+
+ // We now list all the pages found that belong to groups.
+ // If only certain pages were found for a group, but the definition page
+ // for that group wasn't listed, the list of pages will be intentionally
+ // incomplete. However, if the group definition page was listed, all the
+ // pages in that group are listed for completeness.
+
+ if (!fakeNodeMap.isEmpty()) {
+ foreach (const QString &groupTitle, groupTitlesMap.keys()) {
+ const FakeNode *groupNode = groupTitlesMap[groupTitle];
+ out() << QString("<h3><a href=\"%1\">%2</a></h3>\n").arg(
+ linkForNode(groupNode, relative)).arg(
+ protectEnc(groupNode->fullTitle()));
+
+ if (fakeNodeMap[groupNode].count() == 0)
+ continue;
+
+ out() << "<ul>\n";
+
+ foreach (const FakeNode *fakeNode, fakeNodeMap[groupNode]) {
+ QString title = fakeNode->fullTitle();
+ if (title.startsWith("The "))
+ title.remove(0, 4);
+ out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">"
+ << protectEnc(title) << "</a></li>\n";
+ }
+ out() << "</ul>\n";
+ }
+ }
+
+ if (!uncategorizedNodeMap.isEmpty()) {
+ out() << QString("<h3>Miscellaneous</h3>\n");
+ out() << "<ul>\n";
+ foreach (const FakeNode *fakeNode, uncategorizedNodeMap) {
+ QString title = fakeNode->fullTitle();
+ if (title.startsWith("The "))
+ title.remove(0, 4);
+ out() << "<li><a href=\"" << linkForNode(fakeNode, relative) << "\">"
+ << protectEnc(title) << "</a></li>\n";
+ }
+ out() << "</ul>\n";
+ }
+}
+
+void HtmlGenerator::generateSection(const NodeList& nl,
+ const Node *relative,
+ CodeMarker *marker,
+ CodeMarker::SynopsisStyle style)
+{
+ bool alignNames = true;
+ if (!nl.isEmpty()) {
+ bool twoColumn = false;
+ if (style == CodeMarker::Subpage) {
+ alignNames = false;
+ twoColumn = (nl.count() >= 16);
+ }
+ else if (nl.first()->type() == Node::Property) {
+ twoColumn = (nl.count() >= 5);
+ alignNames = false;
+ }
+ if (alignNames) {
+ out() << "<table class=\"alignedsummary\">\n";
+ }
+ else {
+ if (twoColumn)
+ out() << "<table class=\"propsummary\">\n"
+ << "<tr><td class=\"topAlign\">";
+ out() << "<ul>\n";
+ }
+
+ int i = 0;
+ NodeList::ConstIterator m = nl.begin();
+ while (m != nl.end()) {
+ if ((*m)->access() == Node::Private) {
+ ++m;
+ continue;
+ }
+
+ if (alignNames) {
+ out() << "<tr><td class=\"memItemLeft rightAlign topAlign\"> ";
+ }
+ else {
+ if (twoColumn && i == (int) (nl.count() + 1) / 2)
+ out() << "</ul></td><td class=\"topAlign\"><ul>\n";
+ out() << "<li class=\"fn\">";
+ }
+
+ generateSynopsis(*m, relative, marker, style, alignNames);
+ if (alignNames)
+ out() << "</td></tr>\n";
+ else
+ out() << "</li>\n";
+ i++;
+ ++m;
+ }
+ if (alignNames)
+ out() << "</table>\n";
+ else {
+ out() << "</ul>\n";
+ if (twoColumn)
+ out() << "</td></tr>\n</table>\n";
+ }
+ }
+}
+
+void HtmlGenerator::generateSectionList(const Section& section,
+ const Node *relative,
+ CodeMarker *marker,
+ CodeMarker::SynopsisStyle style)
+{
+ bool alignNames = true;
+ if (!section.members.isEmpty()) {
+ bool twoColumn = false;
+ if (style == CodeMarker::Subpage) {
+ alignNames = false;
+ twoColumn = (section.members.count() >= 16);
+ }
+ else if (section.members.first()->type() == Node::Property) {
+ twoColumn = (section.members.count() >= 5);
+ alignNames = false;
+ }
+ if (alignNames) {
+ out() << "<table class=\"alignedsummary\">\n";
+ }
+ else {
+ if (twoColumn)
+ out() << "<table class=\"propsummary\">\n"
+ << "<tr><td class=\"topAlign\">";
+ out() << "<ul>\n";
+ }
+
+ int i = 0;
+ NodeList::ConstIterator m = section.members.begin();
+ while (m != section.members.end()) {
+ if ((*m)->access() == Node::Private) {
+ ++m;
+ continue;
+ }
+
+ if (alignNames) {
+ out() << "<tr><td class=\"memItemLeft topAlign rightAlign\"> ";
+ }
+ else {
+ if (twoColumn && i == (int) (section.members.count() + 1) / 2)
+ out() << "</ul></td><td class=\"topAlign\"><ul>\n";
+ out() << "<li class=\"fn\">";
+ }
+
+ QString prefix;
+ if (!section.keys.isEmpty()) {
+ prefix = section.keys.at(i).mid(1);
+ prefix = prefix.left(section.keys.at(i).indexOf("::")+1);
+ }
+ generateSynopsis(*m, relative, marker, style, alignNames, &prefix);
+ if (alignNames)
+ out() << "</td></tr>\n";
+ else
+ out() << "</li>\n";
+ i++;
+ ++m;
+ }
+ if (alignNames)
+ out() << "</table>\n";
+ else {
+ out() << "</ul>\n";
+ if (twoColumn)
+ out() << "</td></tr>\n</table>\n";
+ }
+ }
+
+ if (style == CodeMarker::Summary && !section.inherited.isEmpty()) {
+ out() << "<ul>\n";
+ generateSectionInheritedList(section, relative, marker);
+ out() << "</ul>\n";
+ }
+}
+
+void HtmlGenerator::generateSectionInheritedList(const Section& section,
+ const Node *relative,
+ CodeMarker *marker)
+{
+ QList<QPair<InnerNode *, int> >::ConstIterator p = section.inherited.begin();
+ while (p != section.inherited.end()) {
+ out() << "<li class=\"fn\">";
+ out() << (*p).second << ' ';
+ if ((*p).second == 1) {
+ out() << section.singularMember;
+ }
+ else {
+ out() << section.pluralMember;
+ }
+ out() << " inherited from <a href=\"" << fileName((*p).first)
+ << '#' << HtmlGenerator::cleanRef(section.name.toLower()) << "\">"
+ << protectEnc(marker->plainFullName((*p).first, relative))
+ << "</a></li>\n";
+ ++p;
+ }
+}
+
+void HtmlGenerator::generateSynopsis(const Node *node,
+ const Node *relative,
+ CodeMarker *marker,
+ CodeMarker::SynopsisStyle style,
+ bool alignNames,
+ const QString* prefix)
+{
+ QString marked = marker->markedUpSynopsis(node, relative, style);
+
+ if (prefix)
+ marked.prepend(*prefix);
+ QRegExp templateTag("(<[^@>]*>)");
+ if (marked.indexOf(templateTag) != -1) {
+ QString contents = protectEnc(marked.mid(templateTag.pos(1),
+ templateTag.cap(1).length()));
+ marked.replace(templateTag.pos(1), templateTag.cap(1).length(),
+ contents);
+ }
+ marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"),
+ "<i>\\1<sub>\\2</sub></i>");
+ marked.replace("<@param>", "<i> ");
+ marked.replace("</@param>", "</i>");
+
+ if (style == CodeMarker::Summary) {
+ marked.remove("<@name>"); // was "<b>"
+ marked.remove("</@name>"); // was "</b>"
+ }
+
+ if (style == CodeMarker::Subpage) {
+ QRegExp extraRegExp("<@extra>.*</@extra>");
+ extraRegExp.setMinimal(true);
+ marked.remove(extraRegExp);
+ } else {
+ marked.replace("<@extra>", "<tt>");
+ marked.replace("</@extra>", "</tt>");
+ }
+
+ if (style != CodeMarker::Detailed) {
+ marked.remove("<@type>");
+ marked.remove("</@type>");
+ }
+
+ out() << highlightedCode(marked, marker, relative, alignNames);
+}
+
+QString HtmlGenerator::highlightedCode(const QString& markedCode,
+ CodeMarker* marker,
+ const Node* relative,
+ bool alignNames,
+ const Node* self)
+{
+ QString src = markedCode;
+ QString html;
+ QStringRef arg;
+ QStringRef par1;
+
+ const QChar charLangle = '<';
+ const QChar charAt = '@';
+
+ static const QString typeTag("type");
+ static const QString headerTag("headerfile");
+ static const QString funcTag("func");
+ static const QString linkTag("link");
+
+ // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(</@link>)"
+ bool done = false;
+ for (int i = 0, srcSize = src.size(); i < srcSize;) {
+ if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
+ if (alignNames && !done) {
+ html += "</td><td class=\"memItemRight bottomAlign\">";
+ done = true;
+ }
+ i += 2;
+ if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) {
+ html += "<b>";
+ const Node* n = CodeMarker::nodeForString(par1.toString());
+ QString link = linkForNode(n, relative);
+ addLink(link, arg, &html);
+ html += "</b>";
+ }
+ else {
+ html += charLangle;
+ html += charAt;
+ }
+ }
+ else {
+ html += src.at(i++);
+ }
+ }
+
+ // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)"
+ src = html;
+ html = QString();
+ for (int i = 0, srcSize = src.size(); i < srcSize;) {
+ if (src.at(i) == charLangle && src.at(i + 1) == charAt) {
+ i += 2;
+ if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
+
+ const Node* n = marker->resolveTarget(par1.toString(),
+ myTree,
+ relative);
+ QString link = linkForNode(n, relative);
+ addLink(link, arg, &html);
+ par1 = QStringRef();
+ }
+ else {
+ html += charLangle;
+ html += charAt;
+ }
+ }
+ else {
+ html += src.at(i++);
+ }
+ }
+
+ // replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)" tags
+ src = html;
+ html = QString();
+
+ for (int i=0, srcSize=src.size(); i<srcSize;) {
+ if (src.at(i) == charLangle && src.at(i+1) == charAt) {
+ i += 2;
+ bool handled = false;
+ if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) {
+ par1 = QStringRef();
+ const Node* n = marker->resolveTarget(arg.toString(), myTree, relative, self);
+ html += QLatin1String("<span class=\"type\">");
+ if (n && n->subType() == Node::QmlBasicType) {
+ if (relative && relative->subType() == Node::QmlClass)
+ addLink(linkForNode(n,relative), arg, &html);
+ else
+ html += arg.toString();
+ }
+ else
+ addLink(linkForNode(n,relative), arg, &html);
+ html += QLatin1String("</span>");
+ handled = true;
+ }
+ else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) {
+ par1 = QStringRef();
+ const Node* n = marker->resolveTarget(arg.toString(), myTree, relative);
+ addLink(linkForNode(n,relative), arg, &html);
+ handled = true;
+ }
+ else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) {
+ par1 = QStringRef();
+ const Node* n = marker->resolveTarget(arg.toString(), myTree, relative);
+ addLink(linkForNode(n,relative), arg, &html);
+ handled = true;
+ }
+
+ if (!handled) {
+ html += charLangle;
+ html += charAt;
+ }
+ }
+ else {
+ html += src.at(i++);
+ }
+ }
+
+ // replace all
+ // "<@comment>" -> "<span class=\"comment\">";
+ // "<@preprocessor>" -> "<span class=\"preprocessor\">";
+ // "<@string>" -> "<span class=\"string\">";
+ // "<@char>" -> "<span class=\"char\">";
+ // "<@number>" -> "<span class=\"number\">";
+ // "<@op>" -> "<span class=\"operator\">";
+ // "<@type>" -> "<span class=\"type\">";
+ // "<@name>" -> "<span class=\"name\">";
+ // "<@keyword>" -> "<span class=\"keyword\">";
+ // "</@(?:comment|preprocessor|string|char|number|op|type|name|keyword)>" -> "</span>"
+ src = html;
+ html = QString();
+ static const QString spanTags[] = {
+ "<@comment>", "<span class=\"comment\">",
+ "<@preprocessor>", "<span class=\"preprocessor\">",
+ "<@string>", "<span class=\"string\">",
+ "<@char>", "<span class=\"char\">",
+ "<@number>", "<span class=\"number\">",
+ "<@op>", "<span class=\"operator\">",
+ "<@type>", "<span class=\"type\">",
+ "<@name>", "<span class=\"name\">",
+ "<@keyword>", "<span class=\"keyword\">",
+ "</@comment>", "</span>",
+ "</@preprocessor>", "</span>",
+ "</@string>", "</span>",
+ "</@char>", "</span>",
+ "</@number>", "</span>",
+ "</@op>", "</span>",
+ "</@type>", "</span>",
+ "</@name>", "</span>",
+ "</@keyword>", "</span>",
+ };
+ // Update the upper bound of k in the following code to match the length
+ // of the above array.
+ for (int i = 0, n = src.size(); i < n;) {
+ if (src.at(i) == charLangle) {
+ bool handled = false;
+ for (int k = 0; k != 18; ++k) {
+ const QString & tag = spanTags[2 * k];
+ if (tag == QStringRef(&src, i, tag.length())) {
+ html += spanTags[2 * k + 1];
+ i += tag.length();
+ handled = true;
+ break;
+ }
+ }
+ if (!handled) {
+ ++i;
+ if (src.at(i) == charAt ||
+ (src.at(i) == QLatin1Char('/') && src.at(i + 1) == charAt)) {
+ // drop 'our' unknown tags (the ones still containing '@')
+ while (i < n && src.at(i) != QLatin1Char('>'))
+ ++i;
+ ++i;
+ }
+ else {
+ // retain all others
+ html += charLangle;
+ }
+ }
+ }
+ else {
+ html += src.at(i);
+ ++i;
+ }
+ }
+ return html;
+}
+
+void HtmlGenerator::generateLink(const Atom* atom,
+ const Node* /* relative */,
+ CodeMarker* marker)
+{
+ static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_");
+
+ if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) {
+ // hack for C++: move () outside of link
+ int k = funcLeftParen.pos(1);
+ out() << protectEnc(atom->string().left(k));
+ if (link.isEmpty()) {
+ if (showBrokenLinks)
+ out() << "</i>";
+ } else {
+ out() << "</a>";
+ }
+ inLink = false;
+ out() << protectEnc(atom->string().mid(k));
+ } else {
+ out() << protectEnc(atom->string());
+ }
+}
+
+QString HtmlGenerator::cleanRef(const QString& ref)
+{
+ QString clean;
+
+ if (ref.isEmpty())
+ return clean;
+
+ clean.reserve(ref.size() + 20);
+ const QChar c = ref[0];
+ const uint u = c.unicode();
+
+ if ((u >= 'a' && u <= 'z') ||
+ (u >= 'A' && u <= 'Z') ||
+ (u >= '0' && u <= '9')) {
+ clean += c;
+ } else if (u == '~') {
+ clean += "dtor.";
+ } else if (u == '_') {
+ clean += "underscore.";
+ } else {
+ clean += "A";
+ }
+
+ for (int i = 1; i < (int) ref.length(); i++) {
+ const QChar c = ref[i];
+ const uint u = c.unicode();
+ if ((u >= 'a' && u <= 'z') ||
+ (u >= 'A' && u <= 'Z') ||
+ (u >= '0' && u <= '9') || u == '-' ||
+ u == '_' || u == ':' || u == '.') {
+ clean += c;
+ } else if (c.isSpace()) {
+ clean += "-";
+ } else if (u == '!') {
+ clean += "-not";
+ } else if (u == '&') {
+ clean += "-and";
+ } else if (u == '<') {
+ clean += "-lt";
+ } else if (u == '=') {
+ clean += "-eq";
+ } else if (u == '>') {
+ clean += "-gt";
+ } else if (u == '#') {
+ clean += QLatin1Char('#');
+ } else {
+ clean += "-";
+ clean += QString::number((int)u, 16);
+ }
+ }
+ return clean;
+}
+
+QString HtmlGenerator::registerRef(const QString& ref)
+{
+ QString clean = HtmlGenerator::cleanRef(ref);
+
+ for (;;) {
+ QString& prevRef = refMap[clean.toLower()];
+ if (prevRef.isEmpty()) {
+ prevRef = ref;
+ break;
+ } else if (prevRef == ref) {
+ break;
+ }
+ clean += "x";
+ }
+ return clean;
+}
+
+QString HtmlGenerator::protectEnc(const QString &string)
+{
+ return protect(string, outputEncoding);
+}
+
+QString HtmlGenerator::protect(const QString &string, const QString &outputEncoding)
+{
+#define APPEND(x) \
+ if (html.isEmpty()) { \
+ html = string; \
+ html.truncate(i); \
+} \
+ html += (x);
+
+ QString html;
+ int n = string.length();
+
+ for (int i = 0; i < n; ++i) {
+ QChar ch = string.at(i);
+
+ if (ch == QLatin1Char('&')) {
+ APPEND("&amp;");
+ } else if (ch == QLatin1Char('<')) {
+ APPEND("&lt;");
+ } else if (ch == QLatin1Char('>')) {
+ APPEND("&gt;");
+ } else if (ch == QLatin1Char('"')) {
+ APPEND("&quot;");
+ } else if ((outputEncoding == "ISO-8859-1" && ch.unicode() > 0x007F)
+ || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/'))
+ || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) {
+ // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator
+ APPEND("&#x");
+ html += QString::number(ch.unicode(), 16);
+ html += QLatin1Char(';');
+ } else {
+ if (!html.isEmpty())
+ html += ch;
+ }
+ }
+
+ if (!html.isEmpty())
+ return html;
+ return string;
+
+#undef APPEND
+}
+
+QString HtmlGenerator::fileBase(const Node *node) const
+{
+ QString result;
+
+ result = PageGenerator::fileBase(node);
+
+ if (!node->isInnerNode()) {
+ switch (node->status()) {
+ case Node::Compat:
+ result += "-qt3";
+ break;
+ case Node::Obsolete:
+ result += "-obsolete";
+ break;
+ default:
+ ;
+ }
+ }
+ return result;
+}
+
+QString HtmlGenerator::fileName(const Node *node)
+{
+ if (node->type() == Node::Fake) {
+ if (static_cast<const FakeNode *>(node)->subType() == Node::ExternalPage)
+ return node->name();
+ if (static_cast<const FakeNode *>(node)->subType() == Node::Image)
+ return node->name();
+ }
+ return PageGenerator::fileName(node);
+}
+
+QString HtmlGenerator::refForNode(const Node *node)
+{
+ const FunctionNode *func;
+ const TypedefNode *typedeffe;
+ QString ref;
+
+ switch (node->type()) {
+ case Node::Namespace:
+ case Node::Class:
+ default:
+ break;
+ case Node::Enum:
+ ref = node->name() + "-enum";
+ break;
+ case Node::Typedef:
+ typedeffe = static_cast<const TypedefNode *>(node);
+ if (typedeffe->associatedEnum()) {
+ return refForNode(typedeffe->associatedEnum());
+ }
+ else {
+ ref = node->name() + "-typedef";
+ }
+ break;
+ case Node::Function:
+ func = static_cast<const FunctionNode *>(node);
+ if (func->associatedProperty()) {
+ return refForNode(func->associatedProperty());
+ }
+ else {
+ ref = func->name();
+ if (func->overloadNumber() != 1)
+ ref += "-" + QString::number(func->overloadNumber());
+ }
+ break;
+ case Node::Fake:
+ if (node->subType() != Node::QmlPropertyGroup)
+ break;
+ case Node::QmlProperty:
+ case Node::Property:
+ ref = node->name() + "-prop";
+ break;
+ case Node::QmlSignal:
+ ref = node->name() + "-signal";
+ break;
+ case Node::QmlSignalHandler:
+ ref = node->name() + "-signal-handler";
+ break;
+ case Node::QmlMethod:
+ ref = node->name() + "-method";
+ break;
+ case Node::Variable:
+ ref = node->name() + "-var";
+ break;
+ case Node::Target:
+ return protectEnc(node->name());
+ }
+ return registerRef(ref);
+}
+
+#define DEBUG_ABSTRACT 0
+
+/*!
+ Construct the link string for the \a node and return it.
+ The \a relative node is use to decide the link we are
+ generating is in the same file as the target. Note the
+ relative node can be 0, which pretty much guarantees
+ that the link and the target aren't in the same file.
+ */
+QString HtmlGenerator::linkForNode(const Node *node, const Node *relative)
+{
+ if (node == 0 || node == relative)
+ return QString();
+ if (!node->url().isEmpty())
+ return node->url();
+ if (fileBase(node).isEmpty())
+ return QString();
+ if (node->access() == Node::Private)
+ return QString();
+
+ QString fn = fileName(node);
+ if (node && relative && node->parent() != relative) {
+ if (node->parent()->subType() == Node::QmlClass && relative->subType() == Node::QmlClass) {
+ if (node->parent()->isAbstract()) {
+ /*
+ This is a bit of a hack. What we discover with
+ the three 'if' statements immediately above,
+ is that node's parent is marked \qmlabstract
+ but the link appears in a qdoc comment for a
+ subclass of the node's parent. This means the
+ link should refer to the file for the relative
+ node, not the file for node.
+ */
+ fn = fileName(relative);
+#if DEBUG_ABSTRACT
+ qDebug() << "ABSTRACT:" << node->parent()->name()
+ << node->name() << relative->name()
+ << node->parent()->type() << node->parent()->subType()
+ << relative->type() << relative->subType() << outFileName();
+#endif
+ }
+ }
+ }
+ QString link = fn;
+
+ if (!node->isInnerNode() || node->subType() == Node::QmlPropertyGroup) {
+ QString ref = refForNode(node);
+ if (relative && fn == fileName(relative) && ref == refForNode(relative))
+ return QString();
+
+ link += QLatin1Char('#');
+ link += ref;
+ }
+ /*
+ If the output is going to subdirectories, then if the
+ two nodes will be output to different directories, then
+ the link must go up to the parent directory and then
+ back down into the other subdirectory.
+ */
+ if (node && relative && (node != relative)) {
+ if (node->outputSubdirectory() != relative->outputSubdirectory())
+ link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/')));
+ }
+ return link;
+}
+
+QString HtmlGenerator::refForAtom(Atom *atom, const Node * /* node */)
+{
+ if (atom->type() == Atom::SectionLeft) {
+ return Doc::canonicalTitle(Text::sectionHeading(atom).toString());
+ }
+ else if (atom->type() == Atom::Target) {
+ return Doc::canonicalTitle(atom->string());
+ }
+ else {
+ return QString();
+ }
+}
+
+void HtmlGenerator::generateFullName(const Node *apparentNode,
+ const Node *relative,
+ CodeMarker *marker,
+ const Node *actualNode)
+{
+ if (actualNode == 0)
+ actualNode = apparentNode;
+ out() << "<a href=\"" << linkForNode(actualNode, relative);
+ if (true || relative == 0 || relative->status() != actualNode->status()) {
+ switch (actualNode->status()) {
+ case Node::Obsolete:
+ out() << "\" class=\"obsolete";
+ break;
+ case Node::Compat:
+ out() << "\" class=\"compat";
+ break;
+ default:
+ ;
+ }
+ }
+ out() << "\">";
+ out() << protectEnc(fullName(apparentNode, relative, marker));
+ out() << "</a>";
+}
+
+void HtmlGenerator::generateDetailedMember(const Node *node,
+ const InnerNode *relative,
+ CodeMarker *marker)
+{
+ const EnumNode *enume;
+
+#ifdef GENERATE_MAC_REFS
+ generateMacRef(node, marker);
+#endif
+ generateExtractionMark(node, MemberMark);
+ if (node->type() == Node::Enum
+ && (enume = static_cast<const EnumNode *>(node))->flagsType()) {
+#ifdef GENERATE_MAC_REFS
+ generateMacRef(enume->flagsType(), marker);
+#endif
+ out() << "<h3 class=\"flags\">";
+ out() << "<a name=\"" + refForNode(node) + "\"></a>";
+ generateSynopsis(enume, relative, marker, CodeMarker::Detailed);
+ out() << "<br/>";
+ generateSynopsis(enume->flagsType(),
+ relative,
+ marker,
+ CodeMarker::Detailed);
+ out() << "</h3>\n";
+ }
+ else {
+ out() << "<h3 class=\"fn\">";
+ out() << "<a name=\"" + refForNode(node) + "\"></a>";
+ generateSynopsis(node, relative, marker, CodeMarker::Detailed);
+ out() << "</h3>" << divNavTop << '\n';
+ }
+
+ generateStatus(node, marker);
+ generateBody(node, marker);
+ generateThreadSafeness(node, marker);
+ generateSince(node, marker);
+
+ if (node->type() == Node::Property) {
+ const PropertyNode *property = static_cast<const PropertyNode *>(node);
+ Section section;
+
+ section.members += property->getters();
+ section.members += property->setters();
+ section.members += property->resetters();
+
+ if (!section.members.isEmpty()) {
+ out() << "<p><b>Access functions:</b></p>\n";
+ generateSectionList(section, node, marker, CodeMarker::Accessors);
+ }
+
+ Section notifiers;
+ notifiers.members += property->notifiers();
+
+ if (!notifiers.members.isEmpty()) {
+ out() << "<p><b>Notifier signal:</b></p>\n";
+ //out() << "<p>This signal is emitted when the property value is changed.</p>\n";
+ generateSectionList(notifiers, node, marker, CodeMarker::Accessors);
+ }
+ }
+ else if (node->type() == Node::Enum) {
+ const EnumNode *enume = static_cast<const EnumNode *>(node);
+ if (enume->flagsType()) {
+ out() << "<p>The " << protectEnc(enume->flagsType()->name())
+ << " type is a typedef for "
+ << "<a href=\"qflags.html\">QFlags</a>&lt;"
+ << protectEnc(enume->name())
+ << "&gt;. It stores an OR combination of "
+ << protectEnc(enume->name())
+ << " values.</p>\n";
+ }
+ }
+ generateAlsoList(node, marker);
+ generateExtractionMark(node, EndMark);
+}
+
+void HtmlGenerator::findAllClasses(const InnerNode *node)
+{
+ NodeList::const_iterator c = node->childNodes().constBegin();
+ while (c != node->childNodes().constEnd()) {
+ if ((*c)->access() != Node::Private && (*c)->url().isEmpty()) {
+ if ((*c)->type() == Node::Class && !(*c)->doc().isEmpty()) {
+ QString className = (*c)->name();
+ if ((*c)->parent() &&
+ (*c)->parent()->type() == Node::Namespace &&
+ !(*c)->parent()->name().isEmpty())
+ className = (*c)->parent()->name()+"::"+className;
+
+ if (!(static_cast<const ClassNode *>(*c))->hideFromMainList()) {
+ if ((*c)->status() == Node::Compat) {
+ compatClasses.insert(className, *c);
+ }
+ else if ((*c)->status() == Node::Obsolete) {
+ obsoleteClasses.insert(className, *c);
+ }
+ else {
+ nonCompatClasses.insert(className, *c);
+ if ((*c)->status() == Node::Main)
+ mainClasses.insert(className, *c);
+ }
+ }
+
+ QString moduleName = (*c)->moduleName();
+ if (moduleName == "Qt3SupportLight") {
+ moduleClassMap[moduleName].insert((*c)->name(), *c);
+ moduleName = "Qt3Support";
+ }
+ if (!moduleName.isEmpty())
+ moduleClassMap[moduleName].insert((*c)->name(), *c);
+
+ QString serviceName =
+ (static_cast<const ClassNode *>(*c))->serviceName();
+ if (!serviceName.isEmpty())
+ serviceClasses.insert(serviceName, *c);
+ }
+ else if ((*c)->type() == Node::Fake &&
+ (*c)->subType() == Node::QmlClass &&
+ !(*c)->doc().isEmpty()) {
+ QString qmlClassName = (*c)->name();
+ /*
+ Remove the "QML:" prefix, if present.
+ It shouldn't be present anymore.
+ */
+ if (qmlClassName.startsWith(QLatin1String("QML:")))
+ qmlClasses.insert(qmlClassName.mid(4),*c);
+ else
+ qmlClasses.insert(qmlClassName,*c);
+ }
+ else if ((*c)->isInnerNode()) {
+ findAllClasses(static_cast<InnerNode *>(*c));
+ }
+ }
+ ++c;
+ }
+}
+
+void HtmlGenerator::findAllFunctions(const InnerNode *node)
+{
+ NodeList::ConstIterator c = node->childNodes().begin();
+ while (c != node->childNodes().end()) {
+ if ((*c)->access() != Node::Private) {
+ if ((*c)->isInnerNode() && (*c)->url().isEmpty()) {
+ findAllFunctions(static_cast<const InnerNode *>(*c));
+ }
+ else if ((*c)->type() == Node::Function) {
+ const FunctionNode *func = static_cast<const FunctionNode *>(*c);
+ if ((func->status() > Node::Obsolete) &&
+ !func->isInternal() &&
+ (func->metaness() != FunctionNode::Ctor) &&
+ (func->metaness() != FunctionNode::Dtor)) {
+ funcIndex[(*c)->name()].insert((*c)->parent()->fullDocumentName(), *c);
+ }
+ }
+ }
+ ++c;
+ }
+}
+
+void HtmlGenerator::findAllLegaleseTexts(const InnerNode *node)
+{
+ NodeList::ConstIterator c = node->childNodes().begin();
+ while (c != node->childNodes().end()) {
+ if ((*c)->access() != Node::Private) {
+ if (!(*c)->doc().legaleseText().isEmpty())
+ legaleseTexts.insertMulti((*c)->doc().legaleseText(), *c);
+ if ((*c)->isInnerNode())
+ findAllLegaleseTexts(static_cast<const InnerNode *>(*c));
+ }
+ ++c;
+ }
+}
+
+void HtmlGenerator::findAllNamespaces(const InnerNode *node)
+{
+ NodeList::ConstIterator c = node->childNodes().begin();
+ while (c != node->childNodes().end()) {
+ if ((*c)->access() != Node::Private) {
+ if ((*c)->isInnerNode() && (*c)->url().isEmpty()) {
+ findAllNamespaces(static_cast<const InnerNode *>(*c));
+ if ((*c)->type() == Node::Namespace) {
+ const NamespaceNode *nspace = static_cast<const NamespaceNode *>(*c);
+ // Ensure that the namespace's name is not empty (the root
+ // namespace has no name).
+ if (!nspace->name().isEmpty()) {
+ namespaceIndex.insert(nspace->name(), *c);
+ QString moduleName = (*c)->moduleName();
+ if (moduleName == "Qt3SupportLight") {
+ moduleNamespaceMap[moduleName].insert((*c)->name(), *c);
+ moduleName = "Qt3Support";
+ }
+ if (!moduleName.isEmpty())
+ moduleNamespaceMap[moduleName].insert((*c)->name(), *c);
+ }
+ }
+ }
+ }
+ ++c;
+ }
+}
+
+int HtmlGenerator::hOffset(const Node *node)
+{
+ switch (node->type()) {
+ case Node::Namespace:
+ case Node::Class:
+ return 2;
+ case Node::Fake:
+ return 1;
+ case Node::Enum:
+ case Node::Typedef:
+ case Node::Function:
+ case Node::Property:
+ default:
+ return 3;
+ }
+}
+
+bool HtmlGenerator::isThreeColumnEnumValueTable(const Atom *atom)
+{
+ while (atom != 0 && !(atom->type() == Atom::ListRight && atom->string() == ATOM_LIST_VALUE)) {
+ if (atom->type() == Atom::ListItemLeft && !matchAhead(atom, Atom::ListItemRight))
+ return true;
+ atom = atom->next();
+ }
+ return false;
+}
+
+const Node *HtmlGenerator::findNodeForTarget(const QString &target,
+ const Node *relative,
+ CodeMarker *marker,
+ const Atom *atom)
+{
+ const Node *node = 0;
+
+ if (target.isEmpty()) {
+ node = relative;
+ }
+ else if (target.endsWith(".html")) {
+ node = myTree->root()->findNode(target, Node::Fake);
+ }
+ else if (marker) {
+ node = marker->resolveTarget(target, myTree, relative);
+ if (!node) {
+ node = myTree->findFakeNodeByTitle(target, relative);
+ }
+ if (!node && atom) {
+ node = myTree->findUnambiguousTarget(target, *const_cast<Atom**>(&atom), relative);
+ }
+ }
+
+ if (!node)
+ relative->doc().location().warning(tr("Cannot link to '%1'").arg(target));
+ return node;
+}
+
+const QPair<QString,QString> HtmlGenerator::anchorForNode(const Node *node)
+{
+ QPair<QString,QString> anchorPair;
+
+ anchorPair.first = PageGenerator::fileName(node);
+ if (node->type() == Node::Fake) {
+ const FakeNode *fakeNode = static_cast<const FakeNode*>(node);
+ anchorPair.second = fakeNode->title();
+ }
+
+ return anchorPair;
+}
+
+QString HtmlGenerator::getLink(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker,
+ const Node** node)
+{
+ QString link;
+ *node = 0;
+ inObsoleteLink = false;
+
+ if (atom->string().contains(":") &&
+ (atom->string().startsWith("file:")
+ || atom->string().startsWith("http:")
+ || atom->string().startsWith("https:")
+ || atom->string().startsWith("ftp:")
+ || atom->string().startsWith("mailto:"))) {
+
+ link = atom->string();
+ }
+ else {
+ QStringList path;
+ if (atom->string().contains('#')) {
+ path = atom->string().split('#');
+ }
+ else {
+ path.append(atom->string());
+ }
+
+ Atom *targetAtom = 0;
+ QString first = path.first().trimmed();
+ if (first.isEmpty()) {
+ *node = relative;
+ }
+ else if (first.endsWith(".html")) {
+ *node = myTree->root()->findNode(first, Node::Fake);
+ }
+ else {
+ *node = marker->resolveTarget(first, myTree, relative);
+ if (!*node) {
+ *node = myTree->findFakeNodeByTitle(first, relative);
+ }
+ if (!*node) {
+ *node = myTree->findUnambiguousTarget(first, targetAtom, relative);
+ }
+ }
+ if (*node) {
+ if (!(*node)->url().isEmpty()) {
+ return (*node)->url();
+ }
+ else {
+ path.removeFirst();
+ }
+ }
+ else {
+ *node = relative;
+ }
+
+ if (*node) {
+ if ((*node)->status() == Node::Obsolete) {
+ if (relative) {
+ if (relative->parent() != *node) {
+ if (relative->status() != Node::Obsolete) {
+ bool porting = false;
+ if (relative->type() == Node::Fake) {
+ const FakeNode* fake = static_cast<const FakeNode*>(relative);
+ if (fake->title().startsWith("Porting"))
+ porting = true;
+ }
+ QString name = marker->plainFullName(relative);
+ if (!porting && !name.startsWith("Q3")) {
+ if (obsoleteLinks) {
+ relative->doc().location().warning(tr("Link to obsolete item '%1' in %2")
+ .arg(atom->string())
+ .arg(name));
+ }
+ inObsoleteLink = true;
+ }
+ }
+ }
+ }
+ else {
+ qDebug() << "Link to Obsolete entity"
+ << (*node)->name() << "no relative";
+ }
+ }
+ }
+
+ /*
+ This loop really only makes sense if *node is not 0.
+ In that case, The node *node points to represents a
+ qdoc page, so the link will ultimately point to some
+ target on that page. This loop finds that target on
+ the page that *node represents. targetAtom is that
+ target.
+ */
+ while (!path.isEmpty()) {
+ targetAtom = myTree->findTarget(path.first(), *node);
+ if (targetAtom == 0)
+ break;
+ path.removeFirst();
+ }
+
+ /*
+ Given that *node is not null, we now cconstruct a link
+ to the page that *node represents, and then if there is
+ a target on that page, we connect the target to the link
+ with '#'.
+ */
+ if (path.isEmpty()) {
+ link = linkForNode(*node, relative);
+ if (*node && (*node)->subType() == Node::Image)
+ link = "images/used-in-examples/" + link;
+ if (targetAtom)
+ link += QLatin1Char('#') + refForAtom(targetAtom, *node);
+ }
+ /*
+ If the output is going to subdirectories, then if the
+ two nodes will be output to different directories, then
+ the link must go up to the parent directory and then
+ back down into the other subdirectory.
+ */
+ if (link.startsWith("images/")) {
+ link.prepend(QString("../"));
+ }
+ else if (*node && relative && (*node != relative)) {
+ if ((*node)->outputSubdirectory() != relative->outputSubdirectory()) {
+ link.prepend(QString("../" + (*node)->outputSubdirectory() + QLatin1Char('/')));
+ }
+ }
+ }
+ return link;
+}
+
+/*!
+ This function can be called if getLink() returns an empty
+ string. It tests the \a atom string to see if it is a link
+ of the form <element> :: <name>, where <element> is a QML
+ element or component without a module qualifier. If so, it
+ constructs a link to the <name> clause on the disambiguation
+ page for <element> and returns that link string. It also
+ adds the <name> as a target in the NameCollisionNode for
+ <element>. These clauses are then constructed when the
+ disambiguation page is actually generated.
+ */
+QString HtmlGenerator::getDisambiguationLink(const Atom *atom, CodeMarker *)
+{
+ QString link;
+ if (!atom->string().contains("::"))
+ return link;
+ QStringList path = atom->string().split("::");
+ NameCollisionNode* ncn = myTree->findCollisionNode(path[0]);
+ if (ncn) {
+ QString label;
+ if (atom->next() && atom->next()->next()) {
+ if (atom->next()->type() == Atom::FormattingLeft &&
+ atom->next()->next()->type() == Atom::String)
+ label = atom->next()->next()->string();
+ }
+ ncn->addLinkTarget(path[1],label);
+ link = fileName(ncn);
+ link += QLatin1Char('#');
+ link += Doc::canonicalTitle(path[1]);
+ }
+ return link;
+}
+
+void HtmlGenerator::generateIndex(const QString &fileBase,
+ const QString &url,
+ const QString &title)
+{
+ myTree->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index", url, title);
+}
+
+void HtmlGenerator::generateStatus(const Node *node, CodeMarker *marker)
+{
+ Text text;
+
+ switch (node->status()) {
+ case Node::Obsolete:
+ if (node->isInnerNode())
+ Generator::generateStatus(node, marker);
+ break;
+ case Node::Compat:
+ if (node->isInnerNode()) {
+ text << Atom::ParaLeft
+ << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
+ << "This "
+ << typeString(node)
+ << " is part of the Qt 3 support library."
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
+ << " It is provided to keep old source code working. "
+ << "We strongly advise against "
+ << "using it in new code. See ";
+
+ const FakeNode *fakeNode = myTree->findFakeNodeByTitle("Porting To Qt 4");
+ Atom *targetAtom = 0;
+ if (fakeNode && node->type() == Node::Class) {
+ QString oldName(node->name());
+ oldName.remove(QLatin1Char('3'));
+ targetAtom = myTree->findTarget(oldName,
+ fakeNode);
+ }
+
+ if (targetAtom) {
+ text << Atom(Atom::Link, linkForNode(fakeNode, node) + QLatin1Char('#') +
+ refForAtom(targetAtom, fakeNode));
+ }
+ else
+ text << Atom(Atom::Link, "Porting to Qt 4");
+
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
+ << Atom(Atom::String, "Porting to Qt 4")
+ << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
+ << " for more information."
+ << Atom::ParaRight;
+ }
+ generateText(text, node, marker);
+ break;
+ default:
+ Generator::generateStatus(node, marker);
+ }
+}
+
+#ifdef GENERATE_MAC_REFS
+/*
+ No longer valid.
+ */
+void HtmlGenerator::generateMacRef(const Node *node, CodeMarker *marker)
+{
+ if (!pleaseGenerateMacRef || marker == 0)
+ return;
+
+ QStringList macRefs = marker->macRefsForNode(node);
+ foreach (const QString &macRef, macRefs)
+ out() << "<a name=\"" << "//apple_ref/" << macRef << "\"></a>\n";
+}
+#endif
+
+void HtmlGenerator::beginLink(const QString &link,
+ const Node *node,
+ const Node *relative,
+ CodeMarker *marker)
+{
+ Q_UNUSED(marker)
+ Q_UNUSED(relative)
+
+ this->link = link;
+ if (link.isEmpty()) {
+ if (showBrokenLinks)
+ out() << "<i>";
+ }
+ else if (node == 0 ||
+ (relative != 0 && node->status() == relative->status())) {
+ out() << "<a href=\"" << link << "\">";
+ }
+ else {
+ switch (node->status()) {
+ case Node::Obsolete:
+ out() << "<a href=\"" << link << "\" class=\"obsolete\">";
+ break;
+ case Node::Compat:
+ out() << "<a href=\"" << link << "\" class=\"compat\">";
+ break;
+ default:
+ out() << "<a href=\"" << link << "\">";
+ }
+ }
+ inLink = true;
+}
+
+void HtmlGenerator::endLink()
+{
+ if (inLink) {
+ if (link.isEmpty()) {
+ if (showBrokenLinks)
+ out() << "</i>";
+ }
+ else {
+ if (inObsoleteLink) {
+ out() << "<sup>(obsolete)</sup>";
+ }
+ out() << "</a>";
+ }
+ }
+ inLink = false;
+ inObsoleteLink = false;
+}
+
+/*!
+ Generates the summary for the \a section. Only used for
+ sections of QML element documentation.
+
+ Currently handles only the QML property group.
+ */
+void HtmlGenerator::generateQmlSummary(const Section& section,
+ const Node *relative,
+ CodeMarker *marker)
+{
+ if (!section.members.isEmpty()) {
+ out() << "<ul>\n";
+ NodeList::ConstIterator m;
+ m = section.members.begin();
+ while (m != section.members.end()) {
+ out() << "<li class=\"fn\">";
+ generateQmlItem(*m,relative,marker,true);
+ out() << "</li>\n";
+ ++m;
+ }
+ out() << "</ul>\n";
+ }
+}
+
+/*!
+ Outputs the html detailed documentation for a section
+ on a QML element reference page.
+ */
+void HtmlGenerator::generateDetailedQmlMember(const Node *node,
+ const InnerNode *relative,
+ CodeMarker *marker)
+{
+ const QmlPropertyNode* qpn = 0;
+#ifdef GENERATE_MAC_REFS
+ generateMacRef(node, marker);
+#endif
+ generateExtractionMark(node, MemberMark);
+ out() << "<div class=\"qmlitem\">";
+ if (node->subType() == Node::QmlPropertyGroup) {
+ const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node);
+ NodeList::ConstIterator p = qpgn->childNodes().begin();
+ out() << "<div class=\"qmlproto\">";
+ out() << "<table class=\"qmlname\">";
+ while (p != qpgn->childNodes().end()) {
+ if ((*p)->type() == Node::QmlProperty) {
+ qpn = static_cast<const QmlPropertyNode*>(*p);
+ out() << "<tr valign=\"top\" class=\"odd\">";
+ out() << "<td class=\"tblQmlPropNode\"><p>";
+ out() << "<a name=\"" + refForNode(qpn) + "\"></a>";
+
+ int ro = qpn->getReadOnly();
+ if (ro < 0) {
+ if (!qpn->isWritable(myTree)) {
+ out() << "<span class=\"qmlreadonly\">read-only</span>";
+ }
+ }
+ else if (ro > 0) {
+ out() << "<span class=\"qmlreadonly\">read-only</span>";
+ }
+ if (qpgn->isDefault())
+ out() << "<span class=\"qmldefault\">default</span>";
+ generateQmlItem(qpn, relative, marker, false);
+ out() << "</p></td></tr>";
+ }
+ ++p;
+ }
+ out() << "</table>";
+ out() << "</div>";
+ }
+ else if (node->type() == Node::QmlProperty) {
+ qpn = static_cast<const QmlPropertyNode*>(node);
+ /*
+ If the QML property node has a single subproperty,
+ override, replace qpn with that override node and
+ proceed as normal.
+ */
+ if (qpn->qmlPropNodes().size() == 1) {
+ Node* n = qpn->qmlPropNodes().at(0);
+ if (n->type() == Node::QmlProperty)
+ qpn = static_cast<const QmlPropertyNode*>(n);
+ }
+ /*
+ Now qpn either has no overrides, or it has more
+ than 1. If it has none, proceed to output as nortmal.
+ */
+ if (qpn->qmlPropNodes().isEmpty()) {
+ out() << "<div class=\"qmlproto\">";
+ out() << "<table class=\"qmlname\">";
+ out() << "<tr valign=\"top\" class=\"odd\">";
+ out() << "<td class=\"tblQmlPropNode\"><p>";
+ out() << "<a name=\"" + refForNode(qpn) + "\"></a>";
+ int ro = qpn->getReadOnly();
+ if (ro < 0) {
+ const ClassNode* cn = qpn->declarativeCppNode();
+ if (cn && !qpn->isWritable(myTree)) {
+ out() << "<span class=\"qmlreadonly\">read-only</span>";
+ }
+ }
+ else if (ro > 0) {
+ out() << "<span class=\"qmlreadonly\">read-only</span>";
+ }
+ if (qpn->isDefault())
+ out() << "<span class=\"qmldefault\">default</span>";
+ generateQmlItem(qpn, relative, marker, false);
+ out() << "</p></td></tr>";
+ out() << "</table>";
+ out() << "</div>";
+ }
+ else {
+ /*
+ The QML property node has multiple override nodes.
+ Process the whole list as we would for a QML property
+ group.
+ */
+ NodeList::ConstIterator p = qpn->qmlPropNodes().begin();
+ out() << "<div class=\"qmlproto\">";
+ out() << "<table class=\"qmlname\">";
+ while (p != qpn->qmlPropNodes().end()) {
+ if ((*p)->type() == Node::QmlProperty) {
+ QmlPropertyNode* q = static_cast<QmlPropertyNode*>(*p);
+ out() << "<tr valign=\"top\" class=\"odd\">";
+ out() << "<td class=\"tblQmlPropNode\"><p>";
+ out() << "<a name=\"" + refForNode(q) + "\"></a>";
+
+ int ro = qpn->getReadOnly();
+ if (ro < 0) {
+ if (!qpn->isWritable(myTree)) {
+ out() << "<span class=\"qmlreadonly\">read-only</span>";
+ }
+ }
+ else if (ro > 0) {
+ out() << "<span class=\"qmlreadonly\">read-only</span>";
+ }
+ if (qpn->isDefault())
+ out() << "<span class=\"qmldefault\">default</span>";
+ generateQmlItem(q, relative, marker, false);
+ out() << "</p></td></tr>";
+ }
+ ++p;
+ }
+ out() << "</table>";
+ out() << "</div>";
+ }
+ }
+ else if (node->type() == Node::QmlSignal) {
+ const FunctionNode* qsn = static_cast<const FunctionNode*>(node);
+ out() << "<div class=\"qmlproto\">";
+ out() << "<table class=\"qmlname\">";
+ out() << "<tr valign=\"top\" class=\"odd\">";
+ out() << "<td class=\"tblQmlFuncNode\"><p>";
+ out() << "<a name=\"" + refForNode(qsn) + "\"></a>";
+ generateSynopsis(qsn,relative,marker,CodeMarker::Detailed,false);
+ out() << "</p></td></tr>";
+ out() << "</table>";
+ out() << "</div>";
+ }
+ else if (node->type() == Node::QmlSignalHandler) {
+ const FunctionNode* qshn = static_cast<const FunctionNode*>(node);
+ out() << "<div class=\"qmlproto\">";
+ out() << "<table class=\"qmlname\">";
+ out() << "<tr valign=\"top\" class=\"odd\">";
+ out() << "<td class=\"tblQmlFuncNode\"><p>";
+ out() << "<a name=\"" + refForNode(qshn) + "\"></a>";
+ generateSynopsis(qshn,relative,marker,CodeMarker::Detailed,false);
+ out() << "</p></td></tr>";
+ out() << "</table>";
+ out() << "</div>";
+ }
+ else if (node->type() == Node::QmlMethod) {
+ const FunctionNode* qmn = static_cast<const FunctionNode*>(node);
+ out() << "<div class=\"qmlproto\">";
+ out() << "<table class=\"qmlname\">";
+ out() << "<tr valign=\"top\" class=\"odd\">";
+ out() << "<td class=\"tblQmlFuncNode\"><p>";
+ out() << "<a name=\"" + refForNode(qmn) + "\"></a>";
+ generateSynopsis(qmn,relative,marker,CodeMarker::Detailed,false);
+ out() << "</p></td></tr>";
+ out() << "</table>";
+ out() << "</div>";
+ }
+ out() << "<div class=\"qmldoc\">";
+ generateStatus(node, marker);
+ generateBody(node, marker);
+ generateThreadSafeness(node, marker);
+ generateSince(node, marker);
+ generateAlsoList(node, marker);
+ out() << "</div>";
+ out() << "</div>";
+ generateExtractionMark(node, EndMark);
+}
+
+/*!
+ Output the "Inherits" line for the QML element,
+ if there should be one.
+ */
+void HtmlGenerator::generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker)
+{
+ if (!qcn)
+ return;
+ const FakeNode* base = qcn->qmlBase();
+ if (base) {
+ Text text;
+ text << Atom::ParaLeft << "Inherits ";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(base));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, base->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << Atom::ParaRight;
+ generateText(text, qcn, marker);
+ }
+}
+
+/*!
+ Output the "Inherit by" list for the QML element,
+ if it is inherited by any other elements.
+ */
+void HtmlGenerator::generateQmlInheritedBy(const QmlClassNode* qcn, CodeMarker* marker)
+{
+ if (qcn) {
+ NodeList subs;
+ QmlClassNode::subclasses(qcn->name(),subs);
+ if (!subs.isEmpty()) {
+ Text text;
+ text << Atom::ParaLeft << "Inherited by ";
+ appendSortedQmlNames(text,qcn,subs,marker);
+ text << Atom::ParaRight;
+ generateText(text, qcn, marker);
+ }
+ }
+}
+
+/*!
+ Output the "[Xxx instantiates the C++ class QmlGraphicsXxx]"
+ line for the QML element, if there should be one.
+
+ If there is no class node, or if the class node status
+ is set to Node::Internal, do nothing.
+ */
+void HtmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker)
+{
+ const ClassNode* cn = qcn->classNode();
+ if (cn && (cn->status() != Node::Internal)) {
+ Text text;
+ text << Atom::ParaLeft;
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ QString name = qcn->name();
+ /*
+ Remove the "QML:" prefix, if present.
+ It shouldn't be present anymore.
+ */
+ if (name.startsWith(QLatin1String("QML:")))
+ name = name.mid(4); // remove the "QML:" prefix
+ text << Atom(Atom::String, name);
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << " instantiates the C++ class ";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, cn->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << Atom::ParaRight;
+ generateText(text, qcn, marker);
+ }
+}
+
+/*!
+ Output the "[QmlGraphicsXxx is instantiated by QML element Xxx]"
+ line for the class, if there should be one.
+
+ If there is no QML element, or if the class node status
+ is set to Node::Internal, do nothing.
+ */
+void HtmlGenerator::generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker)
+{
+ if (cn && cn->status() != Node::Internal && cn->qmlElement() != 0) {
+ const QmlClassNode* qcn = cn->qmlElement();
+ Text text;
+ text << Atom::ParaLeft;
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, cn->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << " is instantiated by QML element ";
+ text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn));
+ text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK);
+ text << Atom(Atom::String, qcn->name());
+ text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
+ text << Atom::ParaRight;
+ generateText(text, cn, marker);
+ }
+}
+
+/*!
+ Generate the <page> element for the given \a node using the \a writer.
+ Return true if a <page> element was written; otherwise return false.
+ */
+bool HtmlGenerator::generatePageElement(QXmlStreamWriter& writer,
+ const Node* node,
+ CodeMarker* marker) const
+{
+ if (node->pageType() == Node::NoPageType)
+ return false;
+ if (node->name().isEmpty())
+ return true;
+ if (node->access() == Node::Private)
+ return false;
+
+ QString guid = QUuid::createUuid().toString();
+ QString title;
+ QString rawTitle;
+ QString fullTitle;
+ QStringList pageWords;
+ QXmlStreamAttributes attributes;
+
+ QString url = node->outputSubdirectory();
+ if (!url.isEmpty())
+ url.append(QLatin1Char('/'));
+ url.append(PageGenerator::fileName(node));
+
+ writer.writeStartElement("page");
+
+ if (node->isInnerNode()) {
+ const InnerNode* inner = static_cast<const InnerNode*>(node);
+ if (!inner->pageKeywords().isEmpty())
+ pageWords << inner->pageKeywords();
+
+ switch (node->type()) {
+ case Node::Fake:
+ {
+ const FakeNode* fake = static_cast<const FakeNode*>(node);
+ title = fake->fullTitle();
+ pageWords << title;
+ break;
+ }
+ case Node::Class:
+ {
+ title = node->name() + " Class";
+ pageWords << node->name() << "class" << "reference";
+ break;
+ }
+ case Node::Namespace:
+ {
+ rawTitle = marker->plainName(inner);
+ fullTitle = marker->plainFullName(inner);
+ title = rawTitle + " Namespace";
+ pageWords << rawTitle << "namespace" << "reference";
+ break;
+ }
+ default:
+ title = node->name();
+ pageWords << title;
+ break;
+ }
+ }
+ else {
+ switch (node->type()) {
+ case Node::Enum:
+ {
+ title = node->name() + " Enum";
+ pageWords << node->name() << "enum" << "type";
+ url += QLatin1Char('#') + node->name() + "-enum";
+ break;
+ }
+ case Node::Function:
+ {
+ title = node->name() + " Function";
+ pageWords << node->name() << "function";
+ url += QLatin1Char('#') + node->name();
+ break;
+ }
+ case Node::Property:
+ {
+ title = node->name() + " Property";
+ pageWords << node->name() << "property";
+ url += QLatin1Char('#') + node->name() + "-prop";
+ break;
+ }
+ case Node::Typedef:
+ {
+ title = node->name() + " Type";
+ pageWords << node->name() << "typedef" << "type";
+ url += QLatin1Char('#') + node->name();
+ break;
+ }
+ default:
+ title = node->name();
+ pageWords << title;
+ break;
+ }
+
+ Node* parent = node->parent();
+ if (parent && ((parent->type() == Node::Class) ||
+ (parent->type() == Node::Namespace))) {
+ pageWords << parent->name();
+ }
+ }
+
+ writer.writeAttribute("id",guid);
+ writer.writeStartElement("pageWords");
+ writer.writeCharacters(pageWords.join(" "));
+
+ writer.writeEndElement();
+ writer.writeStartElement("pageTitle");
+ writer.writeCharacters(title);
+ writer.writeEndElement();
+ writer.writeStartElement("pageUrl");
+ writer.writeCharacters(url);
+ writer.writeEndElement();
+ writer.writeStartElement("pageType");
+ QString ptype = "Article";
+ switch (node->pageType()) {
+ case Node::ApiPage:
+ ptype = "APIPage";
+ break;
+ case Node::ArticlePage:
+ ptype = "Article";
+ break;
+ case Node::ExamplePage:
+ ptype = "Example";
+ break;
+ case Node::HowToPage:
+ ptype = "HowTo";
+ break;
+ case Node::OverviewPage:
+ ptype = "Overview";
+ break;
+ case Node::TutorialPage:
+ ptype = "Tutorial";
+ break;
+ case Node::FAQPage:
+ ptype = "FAQ";
+ break;
+ default:
+ break;
+ }
+ writer.writeCharacters(ptype);
+ writer.writeEndElement();
+ writer.writeEndElement();
+
+ if (node->type() == Node::Fake && node->doc().hasTableOfContents()) {
+ QList<Atom*> toc = node->doc().tableOfContents();
+ if (!toc.isEmpty()) {
+ for (int i = 0; i < toc.size(); ++i) {
+ Text headingText = Text::sectionHeading(toc.at(i));
+ QString s = headingText.toString();
+ writer.writeStartElement("page");
+ guid = QUuid::createUuid().toString();
+ QString internalUrl = url + QLatin1Char('#') + Doc::canonicalTitle(s);
+ writer.writeAttribute("id",guid);
+ writer.writeStartElement("pageWords");
+ writer.writeCharacters(pageWords.join(" "));
+ writer.writeCharacters(" ");
+ writer.writeCharacters(s);
+ writer.writeEndElement();
+ writer.writeStartElement("pageTitle");
+ writer.writeCharacters(s);
+ writer.writeEndElement();
+ writer.writeStartElement("pageUrl");
+ writer.writeCharacters(internalUrl);
+ writer.writeEndElement();
+ writer.writeStartElement("pageType");
+ writer.writeCharacters("Article");
+ writer.writeEndElement();
+ writer.writeEndElement();
+ }
+ }
+ }
+ return true;
+}
+
+/*!
+ Traverse the tree recursively and generate the <keyword>
+ elements.
+ */
+void HtmlGenerator::generatePageElements(QXmlStreamWriter& writer, const Node* node, CodeMarker* marker) const
+{
+ if (generatePageElement(writer, node, marker)) {
+
+ if (node->isInnerNode()) {
+ const InnerNode *inner = static_cast<const InnerNode *>(node);
+
+ // Recurse to write an element for this child node and all its children.
+ foreach (const Node *child, inner->childNodes())
+ generatePageElements(writer, child, marker);
+ }
+ }
+}
+
+/*!
+ Outputs the file containing the index used for searching the html docs.
+ */
+void HtmlGenerator::generatePageIndex(const QString& fileName) const
+{
+ QFile file(fileName);
+ if (!file.open(QFile::WriteOnly | QFile::Text))
+ return ;
+
+ CodeMarker *marker = CodeMarker::markerForFileName(fileName);
+
+ QXmlStreamWriter writer(&file);
+ writer.setAutoFormatting(true);
+ writer.writeStartDocument();
+ writer.writeStartElement("qtPageIndex");
+
+ generatePageElements(writer, myTree->root(), marker);
+
+ writer.writeEndElement(); // qtPageIndex
+ writer.writeEndDocument();
+ file.close();
+}
+
+void HtmlGenerator::generateExtractionMark(const Node *node, ExtractionMarkType markType)
+{
+ if (markType != EndMark) {
+ out() << "<!-- $$$" + node->name();
+ if (markType == MemberMark) {
+ if (node->type() == Node::Function) {
+ const FunctionNode *func = static_cast<const FunctionNode *>(node);
+ if (!func->associatedProperty()) {
+ if (func->overloadNumber() == 1)
+ out() << "[overload1]";
+ out() << "$$$" + func->name() + func->rawParameters().remove(' ');
+ }
+ } else if (node->type() == Node::Property) {
+ out() << "-prop";
+ const PropertyNode *prop = static_cast<const PropertyNode *>(node);
+ const NodeList &list = prop->functions();
+ foreach (const Node *propFuncNode, list) {
+ if (propFuncNode->type() == Node::Function) {
+ const FunctionNode *func = static_cast<const FunctionNode *>(propFuncNode);
+ out() << "$$$" + func->name() + func->rawParameters().remove(' ');
+ }
+ }
+ } else if (node->type() == Node::Enum) {
+ const EnumNode *enumNode = static_cast<const EnumNode *>(node);
+ foreach (const EnumItem &item, enumNode->items())
+ out() << "$$$" + item.name();
+ }
+ } else if (markType == BriefMark) {
+ out() << "-brief";
+ } else if (markType == DetailedDescriptionMark) {
+ out() << "-description";
+ }
+ out() << " -->\n";
+ } else {
+ out() << "<!-- @@@" + node->name() + " -->\n";
+ }
+}
+
+/*!
+ Returns the full document location for HTML-based documentation.
+ */
+QString HtmlGenerator::fullDocumentLocation(const Node *node, bool subdir)
+{
+ if (!node)
+ return "";
+ if (!node->url().isEmpty())
+ return node->url();
+
+ QString parentName;
+ QString anchorRef;
+ QString fdl = "";
+
+ /*
+ If the output is being sent to subdirectories of the
+ output directory, and if the subdir parameter is set,
+ prepend the subdirectory name + '/' to the result.
+ */
+ if (subdir) {
+ fdl = node->outputSubdirectory();
+ if (!fdl.isEmpty())
+ fdl.append(QLatin1Char('/'));
+ }
+ if (node->type() == Node::Namespace) {
+
+ // The root namespace has no name - check for this before creating
+ // an attribute containing the location of any documentation.
+
+ if (!node->fileBase().isEmpty())
+ parentName = node->fileBase() + ".html";
+ else
+ return "";
+ }
+ else if (node->type() == Node::Fake) {
+ if ((node->subType() == Node::QmlClass) ||
+ (node->subType() == Node::QmlBasicType)) {
+ QString fb = node->fileBase();
+ if (fb.startsWith(Generator::outputPrefix(QLatin1String("QML"))))
+ return fb + ".html";
+ else {
+ QString mq = "";
+ if (!node->qmlModuleName().isEmpty()) {
+ mq = node->qmlModuleIdentifier().replace(QChar('.'),QChar('-'));
+ mq = mq.toLower() + "-";
+ }
+ return fdl+ Generator::outputPrefix(QLatin1String("QML")) + mq +
+ node->fileBase() + QLatin1String(".html");
+ }
+ }
+ else
+ parentName = node->fileBase() + ".html";
+ }
+ else if (node->fileBase().isEmpty())
+ return "";
+
+ Node *parentNode = 0;
+
+ if ((parentNode = node->relates())) {
+ parentName = fullDocumentLocation(node->relates());
+ }
+ else if ((parentNode = node->parent())) {
+ if (parentNode->subType() == Node::QmlPropertyGroup) {
+ parentNode = parentNode->parent();
+ parentName = fullDocumentLocation(parentNode);
+ }
+ else
+ parentName = fullDocumentLocation(node->parent());
+ }
+
+ switch (node->type()) {
+ case Node::Class:
+ case Node::Namespace:
+ if (parentNode && !parentNode->name().isEmpty()) {
+ parentName.remove(".html");
+ parentName += QLatin1Char('-')
+ + node->fileBase().toLower() + ".html";
+ } else {
+ parentName = node->fileBase() + ".html";
+ }
+ break;
+ case Node::Function:
+ {
+ /*
+ Functions can be destructors, overloaded, or
+ have associated properties.
+ */
+ const FunctionNode *functionNode =
+ static_cast<const FunctionNode *>(node);
+
+ if (functionNode->metaness() == FunctionNode::Dtor)
+ anchorRef = "#dtor." + functionNode->name().mid(1);
+
+ else if (functionNode->associatedProperty())
+ return fullDocumentLocation(functionNode->associatedProperty());
+
+ else if (functionNode->overloadNumber() > 1)
+ anchorRef = QLatin1Char('#') + functionNode->name()
+ + "-" + QString::number(functionNode->overloadNumber());
+ else
+ anchorRef = QLatin1Char('#') + functionNode->name();
+ }
+
+ /*
+ Use node->name() instead of node->fileBase() as
+ the latter returns the name in lower-case. For
+ HTML anchors, we need to preserve the case.
+ */
+ break;
+ case Node::Enum:
+ anchorRef = QLatin1Char('#') + node->name() + "-enum";
+ break;
+ case Node::Typedef:
+ anchorRef = QLatin1Char('#') + node->name() + "-typedef";
+ break;
+ case Node::Property:
+ anchorRef = QLatin1Char('#') + node->name() + "-prop";
+ break;
+ case Node::QmlProperty:
+ anchorRef = QLatin1Char('#') + node->name() + "-prop";
+ break;
+ case Node::QmlSignal:
+ anchorRef = QLatin1Char('#') + node->name() + "-signal";
+ break;
+ case Node::QmlSignalHandler:
+ anchorRef = QLatin1Char('#') + node->name() + "-signal-handler";
+ break;
+ case Node::QmlMethod:
+ anchorRef = QLatin1Char('#') + node->name() + "-method";
+ break;
+ case Node::Variable:
+ anchorRef = QLatin1Char('#') + node->name() + "-var";
+ break;
+ case Node::Target:
+ anchorRef = QLatin1Char('#') + Doc::canonicalTitle(node->name());
+ break;
+ case Node::Fake:
+ {
+ /*
+ Use node->fileBase() for fake nodes because they are represented
+ by pages whose file names are lower-case.
+ */
+ parentName = node->fileBase();
+ parentName.replace(QLatin1Char('/'), "-").replace(".", "-");
+ parentName += ".html";
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Various objects can be compat (deprecated) or obsolete.
+ if (node->type() != Node::Class && node->type() != Node::Namespace) {
+ switch (node->status()) {
+ case Node::Compat:
+ parentName.replace(".html", "-qt3.html");
+ break;
+ case Node::Obsolete:
+ parentName.replace(".html", "-obsolete.html");
+ break;
+ default:
+ ;
+ }
+ }
+
+ return fdl + parentName.toLower() + anchorRef;
+}
+
+/*!
+ This function outputs one or more manifest files in XML.
+ They are used by Creator.
+ */
+void HtmlGenerator::generateManifestFiles()
+{
+ generateManifestFile("examples", "example");
+ generateManifestFile("demos", "demo");
+ ExampleNode::exampleNodeMap.clear();
+}
+
+/*!
+ This function is called by generaqteManiferstFile(), once
+ for each manifest file to be generated. \a manifest is the
+ type of manifest file.
+ */
+void HtmlGenerator::generateManifestFile(QString manifest, QString element)
+{
+ if (ExampleNode::exampleNodeMap.isEmpty())
+ return;
+ QString fileName = manifest +"-manifest.xml";
+ QFile file(outputDir() + QLatin1Char('/') + fileName);
+ if (!file.open(QFile::WriteOnly | QFile::Text))
+ return ;
+ bool demos = false;
+ if (manifest == "demos")
+ demos = true;
+
+ bool proceed = false;
+ ExampleNodeMap::Iterator i = ExampleNode::exampleNodeMap.begin();
+ while (i != ExampleNode::exampleNodeMap.end()) {
+ const ExampleNode* en = i.value();
+ if (demos) {
+ if (en->name().startsWith("demos")) {
+ proceed = true;
+ break;
+ }
+ }
+ else if (!en->name().startsWith("demos")) {
+ proceed = true;
+ break;
+ }
+ ++i;
+ }
+ if (!proceed)
+ return;
+
+ QXmlStreamWriter writer(&file);
+ writer.setAutoFormatting(true);
+ writer.writeStartDocument();
+ writer.writeStartElement("instructionals");
+ writer.writeAttribute("module", project);
+ writer.writeStartElement(manifest);
+
+ i = ExampleNode::exampleNodeMap.begin();
+ while (i != ExampleNode::exampleNodeMap.end()) {
+ const ExampleNode* en = i.value();
+ if (demos) {
+ if (!en->name().startsWith("demos")) {
+ ++i;
+ continue;
+ }
+ }
+ else if (en->name().startsWith("demos")) {
+ ++i;
+ continue;
+ }
+ writer.writeStartElement(element);
+ writer.writeAttribute("name", en->title());
+ QString docUrl = manifestDir + en->fileBase() + ".html";
+ writer.writeAttribute("docUrl", docUrl);
+ foreach (const Node* child, en->childNodes()) {
+ if (child->subType() == Node::File) {
+ QString file = child->name();
+ if (file.endsWith(".pro") || file.endsWith(".qmlproject")) {
+ if (file.startsWith("demos/"))
+ file = file.mid(6);
+ writer.writeAttribute("projectPath", file);
+ break;
+ }
+ }
+ }
+ if (!en->imageFileName().isEmpty())
+ writer.writeAttribute("imageUrl", manifestDir + en->imageFileName());
+ writer.writeStartElement("description");
+ Text brief = en->doc().briefText();
+ if (!brief.isEmpty())
+ writer.writeCDATA(brief.toString());
+ else
+ writer.writeCDATA(QString("No description available"));
+ writer.writeEndElement(); // description
+ QStringList tags = en->title().toLower().split(QLatin1Char(' '));
+ if (!tags.isEmpty()) {
+ writer.writeStartElement("tags");
+ bool wrote_one = false;
+ for (int n=0; n<tags.size(); ++n) {
+ QString tag = tags.at(n);
+ if (tag.at(0).isDigit())
+ continue;
+ if (tag.at(0) == '-')
+ continue;
+ if (tag.startsWith("example"))
+ continue;
+ if (tag.startsWith("chapter"))
+ continue;
+ if (tag.endsWith(QLatin1Char(':')))
+ tag.chop(1);
+ if (n>0 && wrote_one)
+ writer.writeCharacters(",");
+ writer.writeCharacters(tag);
+ wrote_one = true;
+ }
+ writer.writeEndElement(); // tags
+ }
+
+ QString ename = en->name().mid(en->name().lastIndexOf('/')+1);
+ QSet<QString> usedNames;
+ foreach (const Node* child, en->childNodes()) {
+ if (child->subType() == Node::File) {
+ QString file = child->name();
+ QString fileName = file.mid(file.lastIndexOf('/')+1);
+ QString baseName = fileName;
+ if ((fileName.count(QChar('.')) > 0) &&
+ (fileName.endsWith(".cpp") ||
+ fileName.endsWith(".h") ||
+ fileName.endsWith(".qml")))
+ baseName.truncate(baseName.lastIndexOf(QChar('.')));
+ if (baseName.toLower() == ename) {
+ if (!usedNames.contains(fileName)) {
+ writer.writeStartElement("fileToOpen");
+ if (file.startsWith("demos/"))
+ file = file.mid(6);
+ writer.writeCharacters(file);
+ writer.writeEndElement(); // fileToOpen
+ usedNames.insert(fileName);
+ }
+ }
+ else if (fileName.toLower().endsWith("main.cpp") ||
+ fileName.toLower().endsWith("main.qml")) {
+ if (!usedNames.contains(fileName)) {
+ writer.writeStartElement("fileToOpen");
+ if (file.startsWith("demos/"))
+ file = file.mid(6);
+ writer.writeCharacters(file);
+ writer.writeEndElement(); // fileToOpen
+ usedNames.insert(fileName);
+ }
+ }
+ }
+ }
+ writer.writeEndElement(); // example
+ ++i;
+ }
+
+ writer.writeEndElement(); // examples
+ writer.writeEndElement(); // instructionals
+ writer.writeEndDocument();
+ file.close();
+}
+
+/*!
+ Find global entities that have documentation but no
+ \e{relates} comand. Report these as errors if they
+ are not also marked \e {internal}.
+
+ type: Class
+ type: Namespace
+
+ subtype: Example
+ subtype: External page
+ subtype: Group
+ subtype: Header file
+ subtype: Module
+ subtype: Page
+ subtype: QML basic type
+ subtype: QML class
+ subtype: QML module
+ */
+void HtmlGenerator::reportOrphans(const InnerNode* parent)
+{
+ const NodeList& children = parent->childNodes();
+ if (children.size() == 0)
+ return;
+
+ bool related;
+ QString message;
+ for (int i=0; i<children.size(); ++i) {
+ Node* child = children[i];
+ if (!child || child->isInternal() || child->doc().isEmpty())
+ continue;
+ if (child->relates()) {
+ related = true;
+ message = child->relates()->name();
+ }
+ else {
+ related = false;
+ message = "has documentation but no \\relates command";
+ }
+ switch (child->type()) {
+ case Node::Namespace:
+ break;
+ case Node::Class:
+ break;
+ case Node::Fake:
+ switch (child->subType()) {
+ case Node::Example:
+ break;
+ case Node::HeaderFile:
+ break;
+ case Node::File:
+ break;
+ case Node::Image:
+ break;
+ case Node::Group:
+ break;
+ case Node::Module:
+ break;
+ case Node::Page:
+ break;
+ case Node::ExternalPage:
+ break;
+ case Node::QmlClass:
+ break;
+ case Node::QmlPropertyGroup:
+ break;
+ case Node::QmlBasicType:
+ break;
+ case Node::QmlModule:
+ break;
+ case Node::Collision:
+ break;
+ default:
+ break;
+ }
+ break;
+ case Node::Enum:
+ if (!related)
+ child->location().warning(tr("Global enum, %1, %2").arg(child->name()).arg(message));
+ break;
+ case Node::Typedef:
+ if (!related)
+ child->location().warning(tr("Global typedef, %1, %2").arg(child->name()).arg(message));
+ break;
+ case Node::Function:
+ if (!related) {
+ const FunctionNode* fn = static_cast<const FunctionNode*>(child);
+ if (fn->isMacro())
+ child->location().warning(tr("Global macro, %1, %2").arg(child->name()).arg(message));
+ else
+ child->location().warning(tr("Global function, %1(), %2").arg(child->name()).arg(message));
+ }
+ break;
+ case Node::Property:
+ break;
+ case Node::Variable:
+ if (!related)
+ child->location().warning(tr("Global variable, %1, %2").arg(child->name()).arg(message));
+ break;
+ case Node::Target:
+ break;
+ case Node::QmlProperty:
+ if (!related)
+ child->location().warning(tr("Global QML property, %1, %2").arg(child->name()).arg(message));
+ break;
+ case Node::QmlSignal:
+ if (!related)
+ child->location().warning(tr("Global QML, signal, %1 %2").arg(child->name()).arg(message));
+ break;
+ case Node::QmlSignalHandler:
+ if (!related)
+ child->location().warning(tr("Global QML signal handler, %1, %2").arg(child->name()).arg(message));
+ break;
+ case Node::QmlMethod:
+ if (!related)
+ child->location().warning(tr("Global QML method, %1, %2").arg(child->name()).arg(message));
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/*!
+ Returns a reference to the XML stream writer currently in use.
+ There is one XML stream writer open for each XML file being
+ written, and they are kept on a stack. The one on top of the
+ stack is the one being written to at the moment. In the HTML
+ output generator, it is perhaps impossible for there to ever
+ be more than one writer open.
+ */
+QXmlStreamWriter& HtmlGenerator::xmlWriter()
+{
+ return *xmlWriterStack.top();
+}
+
+/*!
+ This function is only called for writing ditamaps.
+
+ Calls beginSubPage() in the base class to open the file.
+ Then creates a new XML stream writer using the IO device
+ from opened file and pushes the XML writer onto a stackj.
+ Creates the file named \a fileName in the output directory.
+ Attaches a QTextStream to the created file, which is written
+ to all over the place using out(). Finally, it sets some
+ parameters in the XML writer and calls writeStartDocument().
+
+ It also ensures that a GUID map is created for the output file.
+ */
+void HtmlGenerator::beginDitamapPage(const InnerNode* node, const QString& fileName)
+{
+ PageGenerator::beginSubPage(node,fileName);
+ QXmlStreamWriter* writer = new QXmlStreamWriter(out().device());
+ xmlWriterStack.push(writer);
+ writer->setAutoFormatting(true);
+ writer->setAutoFormattingIndent(4);
+ writer->writeStartDocument();
+}
+
+/*!
+ This function is only called for writing ditamaps.
+
+ Calls writeEndDocument() and then pops the XML stream writer
+ off the stack and deletes it. Then it calls endSubPage() in
+ the base class to close the device.
+ */
+void HtmlGenerator::endDitamapPage()
+{
+ xmlWriter().writeEndDocument();
+ delete xmlWriterStack.pop();
+ PageGenerator::endSubPage();
+}
+
+/*!
+ This function is only called for writing ditamaps.
+
+ Creates the DITA map from the topicrefs in \a node,
+ which is a DitaMapNode.
+ */
+void HtmlGenerator::writeDitaMap(const DitaMapNode* node)
+{
+ beginDitamapPage(node,node->name());
+
+ QString doctype = "<!DOCTYPE map PUBLIC \"-//OASIS//DTD DITA Map//EN\" \"map.dtd\">";
+
+ xmlWriter().writeDTD(doctype);
+ xmlWriter().writeStartElement("map");
+ xmlWriter().writeStartElement("topicmeta");
+ xmlWriter().writeStartElement("shortdesc");
+ xmlWriter().writeCharacters(node->title());
+ xmlWriter().writeEndElement(); // </shortdesc>
+ xmlWriter().writeEndElement(); // </topicmeta>
+ DitaRefList map = node->map();
+ writeDitaRefs(map);
+ endDitamapPage();
+}
+
+/*!
+ Write the \a ditarefs to the current output file.
+ */
+void HtmlGenerator::writeDitaRefs(const DitaRefList& ditarefs)
+{
+ foreach (DitaRef* t, ditarefs) {
+ if (t->isMapRef())
+ xmlWriter().writeStartElement("mapref");
+ else
+ xmlWriter().writeStartElement("topicref");
+ xmlWriter().writeAttribute("navtitle",t->navtitle());
+ if (t->href().isEmpty()) {
+ const FakeNode* fn = myTree->findFakeNodeByTitle(t->navtitle());
+ if (fn)
+ xmlWriter().writeAttribute("href",fileName(fn));
+ }
+ else
+ xmlWriter().writeAttribute("href",t->href());
+ if (t->subrefs() && !t->subrefs()->isEmpty())
+ writeDitaRefs(*(t->subrefs()));
+ xmlWriter().writeEndElement(); // </topicref> or </mapref>
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/htmlgenerator.h b/src/tools/qdoc/htmlgenerator.h
new file mode 100644
index 0000000000..24c5fb7179
--- /dev/null
+++ b/src/tools/qdoc/htmlgenerator.h
@@ -0,0 +1,319 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ htmlgenerator.h
+*/
+
+#ifndef HTMLGENERATOR_H
+#define HTMLGENERATOR_H
+
+#include <qmap.h>
+#include <qregexp.h>
+#include <QXmlStreamWriter>
+#include "codemarker.h"
+#include "config.h"
+#include "pagegenerator.h"
+
+QT_BEGIN_NAMESPACE
+
+class HelpProjectWriter;
+
+class HtmlGenerator : public PageGenerator
+{
+public:
+ enum SinceType {
+ Namespace,
+ Class,
+ MemberFunction,
+ NamespaceFunction,
+ GlobalFunction,
+ Macro,
+ Enum,
+ Typedef,
+ Property,
+ Variable,
+ QmlClass,
+ QmlProperty,
+ QmlSignal,
+ QmlSignalHandler,
+ QmlMethod,
+ LastSinceType
+ };
+
+public:
+ HtmlGenerator();
+ ~HtmlGenerator();
+
+ virtual void initializeGenerator(const Config& config);
+ virtual void terminateGenerator();
+ virtual QString format();
+ virtual void generateTree(const Tree *tree);
+ virtual void generateDisambiguationPages();
+ void generateManifestFiles();
+
+ QString protectEnc(const QString &string);
+ static QString protect(const QString &string, const QString &encoding = "ISO-8859-1");
+ static QString cleanRef(const QString& ref);
+ static QString sinceTitle(int i) { return sinceTitles[i]; }
+ static QString fullDocumentLocation(const Node *node, bool subdir = false);
+
+protected:
+ virtual void startText(const Node *relative, CodeMarker *marker);
+ virtual int generateAtom(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker);
+ virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker);
+ virtual void generateFakeNode(const FakeNode *fake, CodeMarker *marker);
+ virtual QString fileExtension(const Node *node) const;
+ virtual QString refForNode(const Node *node);
+ virtual QString linkForNode(const Node *node, const Node *relative);
+ virtual QString refForAtom(Atom *atom, const Node *node);
+
+ void generateManifestFile(QString manifest, QString element);
+
+private:
+ enum SubTitleSize { SmallSubTitle, LargeSubTitle };
+ enum ExtractionMarkType {
+ BriefMark,
+ DetailedDescriptionMark,
+ MemberMark,
+ EndMark
+ };
+
+ const QPair<QString,QString> anchorForNode(const Node *node);
+ const Node *findNodeForTarget(const QString &target,
+ const Node *relative,
+ CodeMarker *marker,
+ const Atom *atom = 0);
+ void generateBreadCrumbs(const QString& title,
+ const Node *node,
+ CodeMarker *marker);
+ void generateHeader(const QString& title,
+ const Node *node = 0,
+ CodeMarker *marker = 0);
+ void generateTitle(const QString& title,
+ const Text &subTitle,
+ SubTitleSize subTitleSize,
+ const Node *relative,
+ CodeMarker *marker);
+ void generateFooter(const Node *node = 0);
+ void generateBrief(const Node *node,
+ CodeMarker *marker,
+ const Node *relative = 0);
+ void generateIncludes(const InnerNode *inner, CodeMarker *marker);
+ void generateTableOfContents(const Node *node,
+ CodeMarker *marker,
+ QList<Section>* sections = 0);
+ QString generateListOfAllMemberFile(const InnerNode *inner,
+ CodeMarker *marker);
+ QString generateAllQmlMembersFile(const QmlClassNode* qml_cn,
+ CodeMarker* marker);
+ QString generateLowStatusMemberFile(const InnerNode *inner,
+ CodeMarker *marker,
+ CodeMarker::Status status);
+ void generateClassHierarchy(const Node *relative,
+ CodeMarker *marker,
+ const NodeMap &classMap);
+ void generateAnnotatedList(const Node *relative,
+ CodeMarker *marker,
+ const NodeMap &nodeMap,
+ bool allOdd = false);
+ void generateCompactList(const Node *relative,
+ CodeMarker *marker,
+ const NodeMap &classMap,
+ bool includeAlphabet,
+ QString commonPrefix = QString());
+ void generateFunctionIndex(const Node *relative, CodeMarker *marker);
+ void generateLegaleseList(const Node *relative, CodeMarker *marker);
+ void generateOverviewList(const Node *relative, CodeMarker *marker);
+ void generateSectionList(const Section& section,
+ const Node *relative,
+ CodeMarker *marker,
+ CodeMarker::SynopsisStyle style);
+ void generateQmlSummary(const Section& section,
+ const Node *relative,
+ CodeMarker *marker);
+ void generateQmlItem(const Node *node,
+ const Node *relative,
+ CodeMarker *marker,
+ bool summary);
+ void generateDetailedQmlMember(const Node *node,
+ const InnerNode *relative,
+ CodeMarker *marker);
+ void generateQmlInherits(const QmlClassNode* qcn, CodeMarker* marker);
+ void generateQmlInheritedBy(const QmlClassNode* qcn, CodeMarker* marker);
+ void generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker);
+ void generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker);
+
+ void generateSection(const NodeList& nl,
+ const Node *relative,
+ CodeMarker *marker,
+ CodeMarker::SynopsisStyle style);
+ void generateSynopsis(const Node *node,
+ const Node *relative,
+ CodeMarker *marker,
+ CodeMarker::SynopsisStyle style,
+ bool alignNames = false,
+ const QString* prefix = 0);
+ void generateSectionInheritedList(const Section& section,
+ const Node *relative,
+ CodeMarker *marker);
+ QString highlightedCode(const QString& markedCode,
+ CodeMarker* marker,
+ const Node* relative,
+ bool alignNames = false,
+ const Node* self = 0);
+
+ void generateFullName(const Node *apparentNode,
+ const Node *relative,
+ CodeMarker *marker,
+ const Node *actualNode = 0);
+ void generateDetailedMember(const Node *node,
+ const InnerNode *relative,
+ CodeMarker *marker);
+ void generateLink(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker);
+ void generateStatus(const Node *node, CodeMarker *marker);
+
+ QString registerRef(const QString& ref);
+ virtual QString fileBase(const Node *node) const;
+ QString fileName(const Node *node);
+ void findAllClasses(const InnerNode *node);
+ void findAllFunctions(const InnerNode *node);
+ void findAllLegaleseTexts(const InnerNode *node);
+ void findAllNamespaces(const InnerNode *node);
+ static int hOffset(const Node *node);
+ static bool isThreeColumnEnumValueTable(const Atom *atom);
+ QString getLink(const Atom *atom,
+ const Node *relative,
+ CodeMarker *marker,
+ const Node** node);
+ QString getDisambiguationLink(const Atom* atom, CodeMarker* marker);
+ virtual void generateIndex(const QString &fileBase,
+ const QString &url,
+ const QString &title);
+#ifdef GENERATE_MAC_REFS
+ void generateMacRef(const Node *node, CodeMarker *marker);
+#endif
+ void beginLink(const QString &link,
+ const Node *node,
+ const Node *relative,
+ CodeMarker *marker);
+ void endLink();
+ bool generatePageElement(QXmlStreamWriter& writer,
+ const Node* node,
+ CodeMarker* marker) const;
+ void generatePageElements(QXmlStreamWriter& writer,
+ const Node* node,
+ CodeMarker* marker) const;
+ void generatePageIndex(const QString& fileName) const;
+ void generateExtractionMark(const Node *node, ExtractionMarkType markType);
+ void reportOrphans(const InnerNode* parent);
+
+ void beginDitamapPage(const InnerNode* node, const QString& fileName);
+ void endDitamapPage();
+ void writeDitaMap(const DitaMapNode* node);
+ void writeDitaRefs(const DitaRefList& ditarefs);
+ QXmlStreamWriter& xmlWriter();
+
+ QMap<QString, QString> refMap;
+ int codeIndent;
+ HelpProjectWriter *helpProjectWriter;
+ bool inLink;
+ bool inObsoleteLink;
+ bool inContents;
+ bool inSectionHeading;
+ bool inTableHeader;
+ int numTableRows;
+ bool threeColumnEnumValueTable;
+ QString link;
+ QStringList sectionNumber;
+ QRegExp funcLeftParen;
+ QString style;
+ QString headerScripts;
+ QString headerStyles;
+ QString endHeader;
+ QString postHeader;
+ QString postPostHeader;
+ QString footer;
+ QString address;
+ bool pleaseGenerateMacRef;
+ bool noBreadCrumbs;
+ QString project;
+ QString projectDescription;
+ QString projectUrl;
+ QString navigationLinks;
+ QString manifestDir;
+ QStringList stylesheets;
+ QStringList customHeadElements;
+ const Tree *myTree;
+ bool obsoleteLinks;
+ QMap<QString, NodeMap > moduleClassMap;
+ QMap<QString, NodeMap > moduleNamespaceMap;
+ NodeMap nonCompatClasses;
+ NodeMap mainClasses;
+ NodeMap compatClasses;
+ NodeMap obsoleteClasses;
+ NodeMap namespaceIndex;
+ NodeMap serviceClasses;
+ NodeMap qmlClasses;
+ QMap<QString, NodeMap > funcIndex;
+ QMap<Text, const Node *> legaleseTexts;
+ QStack<QXmlStreamWriter*> xmlWriterStack;
+ static int id;
+public:
+ static bool debugging_on;
+ static QString divNavTop;
+};
+
+#define HTMLGENERATOR_ADDRESS "address"
+#define HTMLGENERATOR_FOOTER "footer"
+#define HTMLGENERATOR_GENERATEMACREFS "generatemacrefs" // ### document me
+#define HTMLGENERATOR_POSTHEADER "postheader"
+#define HTMLGENERATOR_POSTPOSTHEADER "postpostheader"
+#define HTMLGENERATOR_NOBREADCRUMBS "nobreadcrumbs"
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/tools/qdoc/jscodemarker.cpp b/src/tools/qdoc/jscodemarker.cpp
new file mode 100644
index 0000000000..87dec52189
--- /dev/null
+++ b/src/tools/qdoc/jscodemarker.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ jscodemarker.cpp
+*/
+
+#include "qqmljsast_p.h"
+#include "qqmljsengine_p.h"
+#include "qqmljslexer_p.h"
+#include "qqmljsparser_p.h"
+
+#include "atom.h"
+#include "node.h"
+#include "jscodemarker.h"
+#include "qmlmarkupvisitor.h"
+#include "text.h"
+#include "tree.h"
+
+QT_BEGIN_NAMESPACE
+
+JsCodeMarker::JsCodeMarker()
+{
+}
+
+JsCodeMarker::~JsCodeMarker()
+{
+}
+
+/*!
+ Returns true if the \a code is recognized by the parser.
+ */
+bool JsCodeMarker::recognizeCode(const QString &code)
+{
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ QQmlJS::Parser parser(&engine);
+
+ QString newCode = code;
+ QList<QQmlJS::AST::SourceLocation> pragmas = extractPragmas(newCode);
+ lexer.setCode(newCode, 1);
+
+ return parser.parseProgram();
+}
+
+/*!
+ Returns true if \a ext is any of a list of file extensions
+ for the QML language.
+ */
+bool JsCodeMarker::recognizeExtension(const QString &ext)
+{
+ return ext == "js" || ext == "json";
+}
+
+/*!
+ Returns true if the \a language is recognized. We recognize JavaScript,
+ ECMAScript and JSON.
+ */
+bool JsCodeMarker::recognizeLanguage(const QString &language)
+{
+ return language == "JavaScript" || language == "ECMAScript" || language == "JSON";
+}
+
+/*!
+ Returns the type of atom used to represent JavaScript code in the documentation.
+*/
+Atom::Type JsCodeMarker::atomType() const
+{
+ return Atom::JavaScript;
+}
+
+QString JsCodeMarker::markedUpCode(const QString &code,
+ const Node *relative,
+ const Location &location)
+{
+ return addMarkUp(code, relative, location);
+}
+
+QString JsCodeMarker::addMarkUp(const QString &code,
+ const Node * /* relative */,
+ const Location &location)
+{
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+
+ QString newCode = code;
+ QList<QQmlJS::AST::SourceLocation> pragmas = extractPragmas(newCode);
+ lexer.setCode(newCode, 1);
+
+ QQmlJS::Parser parser(&engine);
+ QString output;
+
+ if (parser.parseProgram()) {
+ QQmlJS::AST::Node *ast = parser.rootNode();
+ // Pass the unmodified code to the visitor so that pragmas and other
+ // unhandled source text can be output.
+ QmlMarkupVisitor visitor(code, pragmas, &engine);
+ QQmlJS::AST::Node::accept(ast, &visitor);
+ output = visitor.markedUpCode();
+ } else {
+ location.warning(tr("Unable to parse JavaScript: \"%1\" at line %2, column %3").arg(
+ parser.errorMessage()).arg(parser.errorLineNumber()).arg(
+ parser.errorColumnNumber()));
+ output = protect(code);
+ }
+
+ return output;
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/jscodemarker.h b/src/tools/qdoc/jscodemarker.h
new file mode 100644
index 0000000000..2b1064e7b8
--- /dev/null
+++ b/src/tools/qdoc/jscodemarker.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ jscodemarker.h
+*/
+
+#ifndef JSCODEMARKER_H
+#define JSCODEMARKER_H
+
+#include "qmlcodemarker.h"
+
+QT_BEGIN_NAMESPACE
+
+class JsCodeMarker : public QmlCodeMarker
+{
+public:
+ JsCodeMarker();
+ ~JsCodeMarker();
+
+ virtual bool recognizeCode(const QString &code);
+ virtual bool recognizeExtension(const QString &ext);
+ virtual bool recognizeLanguage(const QString &language);
+ virtual Atom::Type atomType() const;
+
+ virtual QString markedUpCode(const QString &code,
+ const Node *relative,
+ const Location &location);
+
+private:
+ QString addMarkUp(const QString &code, const Node *relative,
+ const Location &location);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/location.cpp b/src/tools/qdoc/location.cpp
new file mode 100644
index 0000000000..9cea232555
--- /dev/null
+++ b/src/tools/qdoc/location.cpp
@@ -0,0 +1,398 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtDebug>
+#include "config.h"
+#include "location.h"
+
+#include <qregexp.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <stdio.h>
+
+QT_BEGIN_NAMESPACE
+
+QT_STATIC_CONST_IMPL Location Location::null;
+
+int Location::tabSize;
+QString Location::programName;
+QRegExp *Location::spuriousRegExp = 0;
+
+/*!
+ \class Location
+
+ \brief The Location class keeps track of where we are in a file.
+
+ It maintains a stack of file positions. A file position
+ consists of the file path, line number, and column number.
+ The location is used for printing error messages that are
+ tied to a location in a file.
+ */
+
+/*!
+ Constructs an empty location.
+ */
+Location::Location()
+ : stk(0), stkTop(&stkBottom), stkDepth(0), etcetera(false)
+{
+ // nothing.
+}
+
+/*!
+ Constructs a location with (fileName, 1, 1) on its file
+ position stack.
+ */
+Location::Location(const QString& fileName)
+ : stk(0), stkTop(&stkBottom), stkDepth(0), etcetera(false)
+{
+ push(fileName);
+}
+
+/*!
+ The copy constructor copies the contents of \a other into
+ this Location using the assignment operator.
+ */
+Location::Location(const Location& other)
+ : stk(0), stkTop(&stkBottom), stkDepth(0), etcetera(false)
+{
+ *this = other;
+}
+
+/*!
+ The assignment operator does a deep copy of the entire
+ state of \a other into this Location.
+ */
+Location& Location::operator=(const Location& other)
+{
+ QStack<StackEntry> *oldStk = stk;
+
+ stkBottom = other.stkBottom;
+ if (other.stk == 0) {
+ stk = 0;
+ stkTop = &stkBottom;
+ }
+ else {
+ stk = new QStack<StackEntry>(*other.stk);
+ stkTop = &stk->top();
+ }
+ stkDepth = other.stkDepth;
+ etcetera = other.etcetera;
+ delete oldStk;
+ return *this;
+}
+
+/*!
+ If the file position on top of the stack has a line number
+ less than 1, set its line number to 1 and its column number
+ to 1. Otherwise, do nothing.
+ */
+void Location::start()
+{
+ if (stkTop->lineNo < 1) {
+ stkTop->lineNo = 1;
+ stkTop->columnNo = 1;
+ }
+}
+
+/*!
+ Advance the current file position, using \a ch to decide how to do
+ that. If \a ch is a \c{'\\n'}, increment the current line number and
+ set the column number to 1. If \ch is a \c{'\\t'}, increment to the
+ next tab column. Otherwise, increment the column number by 1.
+
+ The current file position is the one on top of the position stack.
+ */
+void Location::advance(QChar ch)
+{
+ if (ch == QLatin1Char('\n')) {
+ stkTop->lineNo++;
+ stkTop->columnNo = 1;
+ }
+ else if (ch == QLatin1Char('\t')) {
+ stkTop->columnNo =
+ 1 + tabSize * (stkTop->columnNo + tabSize-1) / tabSize;
+ }
+ else {
+ stkTop->columnNo++;
+ }
+}
+
+/*!
+ Pushes \a filePath onto the file position stack. The current
+ file position becomes (\a filePath, 1, 1).
+
+ \sa pop()
+*/
+void Location::push(const QString& filePath)
+{
+ if (stkDepth++ >= 1) {
+ if (stk == 0)
+ stk = new QStack<StackEntry>;
+ stk->push(StackEntry());
+ stkTop = &stk->top();
+ }
+
+ stkTop->filePath = filePath;
+ stkTop->lineNo = INT_MIN;
+ stkTop->columnNo = 1;
+}
+
+/*!
+ Pops the top of the internal stack. The current file position
+ becomes the next one in the new top of stack.
+
+ \sa push()
+*/
+void Location::pop()
+{
+ if (--stkDepth == 0) {
+ stkBottom = StackEntry();
+ }
+ else {
+ stk->pop();
+ if (stk->isEmpty()) {
+ delete stk;
+ stk = 0;
+ stkTop = &stkBottom;
+ }
+ else {
+ stkTop = &stk->top();
+ }
+ }
+}
+
+/*! \fn bool Location::isEmpty() const
+
+ Returns true if there is no file name set yet; returns false
+ otherwise. The functions filePath(), lineNo() and columnNo()
+ must not be called on an empty Location object.
+ */
+
+/*! \fn const QString& Location::filePath() const
+ Returns the current path and file name.
+ Must not be called on an empty Location object.
+
+ \sa lineNo(), columnNo()
+ */
+
+/*!
+ Returns the file name part of the file path, ie the
+ current file. Must not be called on an empty Location
+ object.
+ */
+QString Location::fileName() const
+{
+ QString fp = filePath();
+ return fp.mid(fp.lastIndexOf('/') + 1);
+}
+
+/*! \fn int Location::lineNo() const
+ Returns the current line number.
+ Must not be called on an empty Location object.
+
+ \sa filePath(), columnNo()
+*/
+
+/*! \fn int Location::columnNo() const
+ Returns the current column number.
+ Must not be called on an empty Location object.
+
+ \sa filePath(), lineNo()
+*/
+
+/*!
+ Writes \a message and \a detals to stderr as a formatted
+ warning message.
+ */
+void Location::warning(const QString& message, const QString& details) const
+{
+ emitMessage(Warning, message, details);
+}
+
+/*!
+ Writes \a message and \a detals to stderr as a formatted
+ error message.
+ */
+void Location::error(const QString& message, const QString& details) const
+{
+ emitMessage(Error, message, details);
+}
+
+/*!
+ Writes \a message and \a detals to stderr as a formatted
+ error message and then exits the program.
+ */
+void Location::fatal(const QString& message, const QString& details) const
+{
+ emitMessage(Error, message, details);
+ information(message);
+ information(details);
+ information("Aborting");
+ exit(EXIT_FAILURE);
+}
+
+/*!
+ Gets several parameters from the \a config, including
+ tab size, program name, and a regular expression that
+ appears to be used for matching certain error messages
+ so that emitMessage() can avoid printing them.
+ */
+void Location::initialize(const Config& config)
+{
+ tabSize = config.getInt(CONFIG_TABSIZE);
+ programName = config.programName();
+
+ QRegExp regExp = config.getRegExp(CONFIG_SPURIOUS);
+ if (regExp.isValid()) {
+ spuriousRegExp = new QRegExp(regExp);
+ }
+ else {
+ config.lastLocation().warning(tr("Invalid regular expression '%1'")
+ .arg(regExp.pattern()));
+ }
+}
+
+/*!
+ Apparently, all this does is delete the regular expression
+ used for intercepting certain error messages that should
+ not be emitted by emitMessage().
+ */
+void Location::terminate()
+{
+ delete spuriousRegExp;
+ spuriousRegExp = 0;
+}
+
+/*!
+ Prints \a message to \c stdout followed by a \c{'\n'}.
+ */
+void Location::information(const QString& message)
+{
+ printf("%s\n", message.toLatin1().data());
+ fflush(stdout);
+}
+
+/*!
+ Report a program bug, including the \a hint.
+ */
+void Location::internalError(const QString& hint)
+{
+ Location::null.fatal(tr("Internal error (%1)").arg(hint),
+ tr("There is a bug in %1. Seek advice from your local"
+ " %2 guru.")
+ .arg(programName).arg(programName));
+}
+
+/*!
+ Formats \a message and \a details into a single string
+ and outputs that string to \c stderr. \a type specifies
+ whether the \a message is an error or a warning.
+ */
+void Location::emitMessage(MessageType type,
+ const QString& message,
+ const QString& details) const
+{
+ if (type == Warning &&
+ spuriousRegExp != 0 &&
+ spuriousRegExp->exactMatch(message))
+ return;
+
+ QString result = message;
+ if (!details.isEmpty())
+ result += "\n[" + details + QLatin1Char(']');
+ result.replace("\n", "\n ");
+ if (type == Error)
+ result.prepend(tr("error: "));
+ result.prepend(toString());
+ fprintf(stderr, "%s\n", result.toLatin1().data());
+ fflush(stderr);
+}
+
+/*!
+ Converts the location to a string to be prepended to error
+ messages.
+ */
+QString Location::toString() const
+{
+ QString str;
+
+ if (isEmpty()) {
+ str = programName;
+ }
+ else {
+ Location loc2 = *this;
+ loc2.setEtc(false);
+ loc2.pop();
+ if (!loc2.isEmpty()) {
+ QString blah = tr("In file included from ");
+ for (;;) {
+ str += blah;
+ str += loc2.top();
+ loc2.pop();
+ if (loc2.isEmpty())
+ break;
+ str += tr(",");
+ str += QLatin1Char('\n');
+ blah.fill(' ');
+ }
+ str += tr(":");
+ str += QLatin1Char('\n');
+ }
+ str += top();
+ }
+ str += QLatin1String(": ");
+ return str;
+}
+
+QString Location::top() const
+{
+ QString str = filePath();
+ if (lineNo() >= 1) {
+ str += QLatin1Char(':');
+ str += QString::number(lineNo());
+ }
+ if (etc())
+ str += QLatin1String(" (etc.)");
+ return str;
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/location.h b/src/tools/qdoc/location.h
new file mode 100644
index 0000000000..1e1333f782
--- /dev/null
+++ b/src/tools/qdoc/location.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ location.h
+*/
+
+#ifndef LOCATION_H
+#define LOCATION_H
+
+#include <qstack.h>
+
+#include "tr.h"
+
+#define QDOC_QML
+
+QT_BEGIN_NAMESPACE
+
+class Config;
+class QRegExp;
+
+class Location
+{
+public:
+ Location();
+ Location(const QString& filePath);
+ Location(const Location& other);
+ ~Location() { delete stk; }
+
+ Location& operator=(const Location& other);
+
+ void start();
+ void advance(QChar ch);
+ void advanceLines(int n) { stkTop->lineNo += n; stkTop->columnNo = 1; }
+
+ void push(const QString& filePath);
+ void pop();
+ void setEtc(bool etc) { etcetera = etc; }
+ void setLineNo(int no) { stkTop->lineNo = no; }
+ void setColumnNo(int no) { stkTop->columnNo = no; }
+
+ bool isEmpty() const { return stkDepth == 0; }
+ int depth() const { return stkDepth; }
+ const QString& filePath() const { return stkTop->filePath; }
+ QString fileName() const;
+ int lineNo() const { return stkTop->lineNo; }
+ int columnNo() const { return stkTop->columnNo; }
+ bool etc() const { return etcetera; }
+ void warning(const QString& message,
+ const QString& details = QString()) const;
+ void error(const QString& message,
+ const QString& details = QString()) const;
+ void fatal(const QString& message,
+ const QString& details = QString()) const;
+
+ QT_STATIC_CONST Location null;
+
+ static void initialize(const Config& config);
+ static void terminate();
+ static void information(const QString& message);
+ static void internalError(const QString& hint);
+
+private:
+ enum MessageType { Warning, Error };
+
+ struct StackEntry
+ {
+ QString filePath;
+ int lineNo;
+ int columnNo;
+ };
+
+ void emitMessage(MessageType type,
+ const QString& message,
+ const QString& details) const;
+ QString toString() const;
+ QString top() const;
+
+private:
+ StackEntry stkBottom;
+ QStack<StackEntry> *stk;
+ StackEntry *stkTop;
+ int stkDepth;
+ bool etcetera;
+
+ static int tabSize;
+ static QString programName;
+ static QRegExp *spuriousRegExp;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/main.cpp b/src/tools/qdoc/main.cpp
new file mode 100644
index 0000000000..11a54b4d38
--- /dev/null
+++ b/src/tools/qdoc/main.cpp
@@ -0,0 +1,481 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ main.cpp
+*/
+
+#include <qglobal.h>
+#include <stdlib.h>
+#include "codemarker.h"
+#include "codeparser.h"
+#include "config.h"
+#include "cppcodemarker.h"
+#include "cppcodeparser.h"
+#include "ditaxmlgenerator.h"
+#include "doc.h"
+#include "htmlgenerator.h"
+#include "plaincodemarker.h"
+#include "puredocparser.h"
+#include "tokenizer.h"
+#include "tree.h"
+
+#ifdef HAVE_DECLARATIVE
+#include "jscodemarker.h"
+#include "qmlcodemarker.h"
+#include "qmlcodeparser.h"
+#endif
+
+#include <qdebug.h>
+
+#include "qtranslator.h"
+#ifndef QT_BOOTSTRAPPED
+# include "qcoreapplication.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*
+ The default indent for code is 4.
+ The default value for false is 0.
+ The default language is c++.
+ The default output format is html.
+ The default tab size is 8.
+ And those are all the default values for configuration variables.
+ */
+static const struct {
+ const char *key;
+ const char *value;
+} defaults[] = {
+ { CONFIG_CODEINDENT, "4" },
+ { CONFIG_FALSEHOODS, "0" },
+ { CONFIG_LANGUAGE, "Cpp" },
+ { CONFIG_OUTPUTFORMATS, "HTML" },
+ { CONFIG_TABSIZE, "8" },
+ { 0, 0 }
+};
+
+static bool highlighting = false;
+static bool showInternal = false;
+static bool obsoleteLinks = false;
+static QStringList defines;
+static QHash<QString, Tree *> trees;
+
+/*!
+ Print the help message to \c stdout.
+ */
+static void printHelp()
+{
+ Location::information(tr("Usage: qdoc [options] file1.qdocconf ...\n"
+ "Options:\n"
+ " -help "
+ "Display this information and exit\n"
+ " -version "
+ "Display version of qdoc and exit\n"
+ " -D<name> "
+ "Define <name> as a macro while parsing sources\n"
+ " -highlighting "
+ "Turn on syntax highlighting (makes qdoc run slower)\n"
+ " -showinternal "
+ "Include stuff marked internal\n"
+ " -obsoletelinks "
+ "Report links from obsolete items to non-obsolete items\n"
+ " -outputdir "
+ "Specify output directory, overrides setting in qdocconf file\n"
+ " -outputformat "
+ "Specify output format, overrides setting in qdocconf file") );
+}
+
+/*!
+ Prints the qdoc version number to stdout.
+ */
+static void printVersion()
+{
+ QString s = tr("qdoc version %1").arg(QT_VERSION_STR);
+ Location::information(s);
+}
+
+/*!
+ Processes the qdoc config file \a fileName. This is the
+ controller for all of qdoc.
+ */
+static void processQdocconfFile(const QString &fileName)
+{
+#ifndef QT_NO_TRANSLATION
+ QList<QTranslator *> translators;
+#endif
+
+ /*
+ The Config instance represents the configuration data for qdoc.
+ All the other classes are initialized with the config. Here we
+ initialize the configuration with some default values.
+ */
+ Config config(tr("qdoc"));
+ int i = 0;
+ while (defaults[i].key) {
+ config.setStringList(defaults[i].key,
+ QStringList() << defaults[i].value);
+ ++i;
+ }
+ config.setStringList(CONFIG_SYNTAXHIGHLIGHTING, QStringList(highlighting ? "true" : "false"));
+ config.setStringList(CONFIG_SHOWINTERNAL,
+ QStringList(showInternal ? "true" : "false"));
+ config.setStringList(CONFIG_OBSOLETELINKS,
+ QStringList(obsoleteLinks ? "true" : "false"));
+
+ /*
+ With the default configuration values in place, load
+ the qdoc configuration file. Note that the configuration
+ file may include other configuration files.
+
+ The Location class keeps track of the current location
+ in the file being processed, mainly for error reporting
+ purposes.
+ */
+ Location::initialize(config);
+ config.load(fileName);
+
+ QStringList sourceModules;
+ sourceModules = config.getStringList(CONFIG_SOURCEMODULES);
+ Location sourceModulesLocation = config.lastLocation();
+
+ if (!sourceModules.isEmpty()) {
+ Location::information(tr("qdoc will generate documentation for the modules found in the sourcemodules variable."));
+ foreach (const QString& sourceModule, sourceModules) {
+ QString qdocconf = sourceModule;
+ if (!qdocconf.endsWith(".qdocconf"))
+ qdocconf += "/doc/config/module.qdocconf";
+ QFile f(qdocconf);
+ if (!f.exists()) {
+ sourceModulesLocation.warning(tr("Can't find module's qdoc config file '%1'").arg(qdocconf));
+ }
+ else {
+ Location::information(tr(" Including: %1").arg(qdocconf));
+ config.load(qdocconf);
+ }
+ }
+ }
+
+ /*
+ Add the defines to the configuration variables.
+ */
+ QStringList defs = defines + config.getStringList(CONFIG_DEFINES);
+ config.setStringList(CONFIG_DEFINES,defs);
+ Location::terminate();
+
+ QString prevCurrentDir = QDir::currentPath();
+ QString dir = QFileInfo(fileName).path();
+ if (!dir.isEmpty())
+ QDir::setCurrent(dir);
+
+ /*
+ Initialize all the classes and data structures with the
+ qdoc configuration.
+ */
+ Location::initialize(config);
+ Tokenizer::initialize(config);
+ Doc::initialize(config);
+ CodeMarker::initialize(config);
+ CodeParser::initialize(config);
+ Generator::initialize(config);
+
+#ifndef QT_NO_TRANSLATION
+ /*
+ Load the language translators, if the configuration specifies any.
+ */
+ QStringList fileNames = config.getStringList(CONFIG_TRANSLATORS);
+ QStringList::Iterator fn = fileNames.begin();
+ while (fn != fileNames.end()) {
+ QTranslator *translator = new QTranslator(0);
+ if (!translator->load(*fn))
+ config.lastLocation().error(tr("Cannot load translator '%1'")
+ .arg(*fn));
+ QCoreApplication::instance()->installTranslator(translator);
+ translators.append(translator);
+ ++fn;
+ }
+#endif
+
+ //QSet<QString> outputLanguages = config.getStringSet(CONFIG_OUTPUTLANGUAGES);
+
+ /*
+ Get the source language (Cpp) from the configuration
+ and the location in the configuration file where the
+ source language was set.
+ */
+ QString lang = config.getString(CONFIG_LANGUAGE);
+ Location langLocation = config.lastLocation();
+
+ /*
+ Initialize the tree where all the parsed sources will be stored.
+ The tree gets built as the source files are parsed, and then the
+ documentation output is generated by traversing the tree.
+ */
+ Tree *tree = new Tree;
+ tree->setVersion(config.getString(CONFIG_VERSION));
+
+ /*
+ By default, the only output format is HTML.
+ */
+ QSet<QString> outputFormats = config.getOutputFormats();
+ Location outputFormatsLocation = config.lastLocation();
+
+ /*
+ Read some XML indexes containing definitions from other documentation sets.
+ */
+ QStringList indexFiles = config.getStringList(CONFIG_INDEXES);
+ tree->readIndexes(indexFiles);
+
+ QSet<QString> excludedDirs;
+ QSet<QString> excludedFiles;
+ QSet<QString> headers;
+ QSet<QString> sources;
+ QStringList headerList;
+ QStringList sourceList;
+ QStringList excludedDirsList;
+ QStringList excludedFilesList;
+
+ excludedDirsList = config.getCleanPathList(CONFIG_EXCLUDEDIRS);
+ foreach (const QString &excludeDir, excludedDirsList) {
+ QString p = QDir::fromNativeSeparators(excludeDir);
+ excludedDirs.insert(p);
+ }
+
+ excludedFilesList = config.getCleanPathList(CONFIG_EXCLUDEFILES);
+ foreach (const QString& excludeFile, excludedFilesList) {
+ QString p = QDir::fromNativeSeparators(excludeFile);
+ excludedFiles.insert(p);
+ }
+
+ headerList = config.getAllFiles(CONFIG_HEADERS,CONFIG_HEADERDIRS,excludedDirs,excludedFiles);
+ headers = QSet<QString>::fromList(headerList);
+
+ sourceList = config.getAllFiles(CONFIG_SOURCES,CONFIG_SOURCEDIRS,excludedDirs,excludedFiles);
+ sources = QSet<QString>::fromList(sourceList);
+
+ /*
+ Parse each header file in the set using the appropriate parser and add it
+ to the big tree.
+ */
+ QSet<CodeParser *> usedParsers;
+
+ QSet<QString>::ConstIterator h = headers.begin();
+ while (h != headers.end()) {
+ CodeParser *codeParser = CodeParser::parserForHeaderFile(*h);
+ if (codeParser) {
+ codeParser->parseHeaderFile(config.location(), *h, tree);
+ usedParsers.insert(codeParser);
+ }
+ ++h;
+ }
+
+ foreach (CodeParser *codeParser, usedParsers)
+ codeParser->doneParsingHeaderFiles(tree);
+
+ usedParsers.clear();
+ /*
+ Parse each source text file in the set using the appropriate parser and
+ add it to the big tree.
+ */
+ QSet<QString>::ConstIterator s = sources.begin();
+ while (s != sources.end()) {
+ CodeParser *codeParser = CodeParser::parserForSourceFile(*s);
+ if (codeParser) {
+ codeParser->parseSourceFile(config.location(), *s, tree);
+ usedParsers.insert(codeParser);
+ }
+ ++s;
+ }
+
+ foreach (CodeParser *codeParser, usedParsers)
+ codeParser->doneParsingSourceFiles(tree);
+
+ /*
+ Now the big tree has been built from all the header and
+ source files. Resolve all the class names, function names,
+ targets, URLs, links, and other stuff that needs resolving.
+ */
+ tree->resolveGroups();
+ tree->resolveQmlModules();
+ tree->resolveTargets(tree->root());
+ tree->resolveCppToQmlLinks();
+ tree->resolveQmlInheritance();
+
+ /*
+ The tree is built and all the stuff that needed resolving
+ has been resolved. Now traverse the tree and generate the
+ documentation output. More than one output format can be
+ requested. The tree is traversed for each one.
+ */
+ QSet<QString>::ConstIterator of = outputFormats.begin();
+ while (of != outputFormats.end()) {
+ Generator* generator = Generator::generatorForFormat(*of);
+ if (generator == 0)
+ outputFormatsLocation.fatal(tr("Unknown output format '%1'").arg(*of));
+ generator->generateTree(tree);
+ ++of;
+ }
+
+ /*
+ Generate the XML tag file, if it was requested.
+ */
+ QString tagFile = config.getString(CONFIG_TAGFILE);
+ if (!tagFile.isEmpty()) {
+ tree->generateTagFile(tagFile);
+ }
+
+ tree->setVersion("");
+ Generator::terminate();
+ CodeParser::terminate();
+ CodeMarker::terminate();
+ Doc::terminate();
+ Tokenizer::terminate();
+ Location::terminate();
+ QDir::setCurrent(prevCurrentDir);
+
+#ifndef QT_NO_TRANSLATION
+ qDeleteAll(translators);
+#endif
+#ifdef DEBUG_SHUTDOWN_CRASH
+ qDebug() << "main(): Delete tree";
+#endif
+ delete tree;
+#ifdef DEBUG_SHUTDOWN_CRASH
+ qDebug() << "main(): Tree deleted";
+#endif
+}
+
+QT_END_NAMESPACE
+
+int main(int argc, char **argv)
+{
+ QT_USE_NAMESPACE
+
+#ifndef QT_BOOTSTRAPPED
+ QCoreApplication app(argc, argv);
+#endif
+
+ /*
+ Create code parsers for the languages to be parsed,
+ and create a tree for C++.
+ */
+ CppCodeParser cppParser;
+#ifdef HAVE_DECLARATIVE
+ QmlCodeParser qmlParser;
+#endif
+ PureDocParser docParser;
+
+ /*
+ Create code markers for plain text, C++,
+ javascript, and QML.
+ */
+ PlainCodeMarker plainMarker;
+ CppCodeMarker cppMarker;
+#ifdef HAVE_DECLARATIVE
+ JsCodeMarker jsMarker;
+ QmlCodeMarker qmlMarker;
+#endif
+
+ HtmlGenerator htmlGenerator;
+ DitaXmlGenerator ditaxmlGenerator;
+
+ QStringList qdocFiles;
+ QString opt;
+ int i = 1;
+
+ while (i < argc) {
+ opt = argv[i++];
+
+ if (opt == "-help") {
+ printHelp();
+ return EXIT_SUCCESS;
+ }
+ else if (opt == "-version") {
+ printVersion();
+ return EXIT_SUCCESS;
+ }
+ else if (opt == "--") {
+ while (i < argc)
+ qdocFiles.append(argv[i++]);
+ }
+ else if (opt.startsWith("-D")) {
+ QString define = opt.mid(2);
+ defines += define;
+ }
+ else if (opt == "-highlighting") {
+ highlighting = true;
+ }
+ else if (opt == "-showinternal") {
+ showInternal = true;
+ }
+ else if (opt == "-obsoletelinks") {
+ obsoleteLinks = true;
+ }
+ else if (opt == "-outputdir") {
+ Config::overrideOutputDir = argv[i];
+ i++;
+ }
+ else if (opt == "-outputformat") {
+ Config::overrideOutputFormats.insert(argv[i]);
+ i++;
+ }
+ else {
+ qdocFiles.append(opt);
+ }
+ }
+
+ if (qdocFiles.isEmpty()) {
+ printHelp();
+ return EXIT_FAILURE;
+ }
+
+ /*
+ Main loop.
+ */
+ foreach (QString qf, qdocFiles) {
+ //qDebug() << "PROCESSING:" << qf;
+ processQdocconfFile(qf);
+ }
+
+ qDeleteAll(trees);
+ return EXIT_SUCCESS;
+}
+
diff --git a/src/tools/qdoc/node.cpp b/src/tools/qdoc/node.cpp
new file mode 100644
index 0000000000..13c51c721d
--- /dev/null
+++ b/src/tools/qdoc/node.cpp
@@ -0,0 +1,2780 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "node.h"
+#include "tree.h"
+#include "codemarker.h"
+#include "codeparser.h"
+#include <QUuid>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+ExampleNodeMap ExampleNode::exampleNodeMap;
+QStringMap Node::operators_;
+
+/*!
+ \class Node
+ \brief The Node class is a node in the Tree.
+
+ A Node represents a class or function or something else
+ from the source code..
+ */
+
+/*!
+ When this Node is destroyed, if it has a parent Node, it
+ removes itself from the parent node's child list.
+ */
+Node::~Node()
+{
+ if (parent_)
+ parent_->removeChild(this);
+ if (relatesTo_)
+ relatesTo_->removeRelated(this);
+}
+
+/*!
+ Sets this Node's Doc to \a doc. If \a replace is false and
+ this Node already has a Doc, a warning is reported that the
+ Doc is being overridden, and it reports where the previous
+ Doc was found. If \a replace is true, the Doc is replaced
+ silently.
+ */
+void Node::setDoc(const Doc& doc, bool replace)
+{
+ if (!d.isEmpty() && !replace) {
+ doc.location().warning(tr("Overrides a previous doc"));
+ d.location().warning(tr("(The previous doc is here)"));
+ }
+ d = doc;
+}
+
+/*!
+ Construct a node with the given \a type and having the
+ given \a parent and \a name. The new node is added to the
+ parent's child list.
+ */
+Node::Node(Type type, InnerNode *parent, const QString& name)
+ : nodeType_(type),
+ access_(Public),
+ safeness_(UnspecifiedSafeness),
+ pageType_(NoPageType),
+ status_(Commendable),
+ parent_(parent),
+ relatesTo_(0),
+ name_(name)
+{
+ if (parent_)
+ parent_->addChild(this);
+ outSubDir_ = CodeParser::currentOutputSubdirectory();
+ if (operators_.isEmpty()) {
+ operators_.insert("++","inc");
+ operators_.insert("--","dec");
+ operators_.insert("==","eq");
+ operators_.insert("!=","ne");
+ operators_.insert("<<","lt-lt");
+ operators_.insert(">>","gt-gt");
+ operators_.insert("+=","plus-assign");
+ operators_.insert("-=","minus-assign");
+ operators_.insert("*=","mult-assign");
+ operators_.insert("/=","div-assign");
+ operators_.insert("%=","mod-assign");
+ operators_.insert("&=","bitwise-and-assign");
+ operators_.insert("|=","bitwise-or-assign");
+ operators_.insert("^=","bitwise-xor-assign");
+ operators_.insert("<<=","bitwise-left-shift-assign");
+ operators_.insert(">>=","bitwise-right-shift-assign");
+ operators_.insert("||","logical-or");
+ operators_.insert("&&","logical-and");
+ operators_.insert("()","call");
+ operators_.insert("[]","subscript");
+ operators_.insert("->","pointer");
+ operators_.insert("->*","pointer-star");
+ operators_.insert("+","plus");
+ operators_.insert("-","minus");
+ operators_.insert("*","mult");
+ operators_.insert("/","div");
+ operators_.insert("%","mod");
+ operators_.insert("|","bitwise-or");
+ operators_.insert("&","bitwise-and");
+ operators_.insert("^","bitwise-xor");
+ operators_.insert("!","not");
+ operators_.insert("~","bitwise-not");
+ operators_.insert("<=","lt-eq");
+ operators_.insert(">=","gt-eq");
+ operators_.insert("<","lt");
+ operators_.insert(">","gt");
+ operators_.insert("=","assign");
+ operators_.insert(",","comma");
+ operators_.insert("delete[]","delete-array");
+ operators_.insert("delete","delete");
+ operators_.insert("new[]","new-array");
+ operators_.insert("new","new");
+ }
+}
+
+/*!
+ Returns the node's URL.
+ */
+QString Node::url() const
+{
+ return url_;
+}
+
+/*!
+ Sets the node's URL to \a url
+ */
+void Node::setUrl(const QString &url)
+{
+ url_ = url;
+}
+
+/*!
+ Returns this node's page type as a string, for use as an
+ attribute value in XML or HTML.
+ */
+QString Node::pageTypeString() const
+{
+ return pageTypeString(pageType_);
+}
+
+/*!
+ Returns the page type \a t as a string, for use as an
+ attribute value in XML or HTML.
+ */
+QString Node::pageTypeString(unsigned t)
+{
+ switch ((PageType)t) {
+ case Node::ApiPage:
+ return "api";
+ case Node::ArticlePage:
+ return "article";
+ case Node::ExamplePage:
+ return "example";
+ case Node::HowToPage:
+ return "howto";
+ case Node::OverviewPage:
+ return "overview";
+ case Node::TutorialPage:
+ return "tutorial";
+ case Node::FAQPage:
+ return "faq";
+ case Node::DitaMapPage:
+ return "ditamap";
+ default:
+ return "article";
+ }
+}
+
+/*!
+ Returns this node's type as a string for use as an
+ attribute value in XML or HTML.
+ */
+QString Node::nodeTypeString() const
+{
+ return nodeTypeString(type());
+}
+
+/*!
+ Returns the node type \a t as a string for use as an
+ attribute value in XML or HTML.
+ */
+QString Node::nodeTypeString(unsigned t)
+{
+ switch ((Type)t) {
+ case Namespace:
+ return "namespace";
+ case Class:
+ return "class";
+ case Fake:
+ return "fake";
+ case Enum:
+ return "enum";
+ case Typedef:
+ return "typedef";
+ case Function:
+ return "function";
+ case Property:
+ return "property";
+ case Variable:
+ return "variable";
+ case Target:
+ return "target";
+ case QmlProperty:
+ return "QML property";
+ case QmlSignal:
+ return "QML signal";
+ case QmlSignalHandler:
+ return "QML signal handler";
+ case QmlMethod:
+ return "QML method";
+ default:
+ break;
+ }
+ return "";
+}
+
+/*!
+ Returns this node's subtype as a string for use as an
+ attribute value in XML or HTML. This is only useful
+ in the case where the node type is Fake.
+ */
+QString Node::nodeSubtypeString() const
+{
+ return nodeSubtypeString(subType());
+}
+
+/*!
+ Returns the node subtype \a t as a string for use as an
+ attribute value in XML or HTML. This is only useful
+ in the case where the node type is Fake.
+ */
+QString Node::nodeSubtypeString(unsigned t)
+{
+ switch ((SubType)t) {
+ case Example:
+ return "example";
+ case HeaderFile:
+ return "header file";
+ case File:
+ return "file";
+ case Image:
+ return "image";
+ case Group:
+ return "group";
+ case Module:
+ return "module";
+ case Page:
+ return "page";
+ case ExternalPage:
+ return "external page";
+ case QmlClass:
+ return "QML class";
+ case QmlPropertyGroup:
+ return "QML property group";
+ case QmlBasicType:
+ return "QML basic type";
+ case QmlModule:
+ return "QML module";
+ case DitaMap:
+ return "ditamap";
+ case Collision:
+ return "collision";
+ case NoSubType:
+ default:
+ break;
+ }
+ return "";
+}
+
+/*!
+ Set the page type according to the string \a t.
+ */
+void Node::setPageType(const QString& t)
+{
+ if ((t == "API") || (t == "api"))
+ pageType_ = ApiPage;
+ else if (t == "howto")
+ pageType_ = HowToPage;
+ else if (t == "overview")
+ pageType_ = OverviewPage;
+ else if (t == "tutorial")
+ pageType_ = TutorialPage;
+ else if (t == "howto")
+ pageType_ = HowToPage;
+ else if (t == "article")
+ pageType_ = ArticlePage;
+ else if (t == "example")
+ pageType_ = ExamplePage;
+ else if (t == "ditamap")
+ pageType_ = DitaMapPage;
+}
+
+/*!
+ Sets the pointer to the node that this node relates to.
+ */
+void Node::setRelates(InnerNode *pseudoParent)
+{
+ if (relatesTo_) {
+ relatesTo_->removeRelated(this);
+ }
+ relatesTo_ = pseudoParent;
+ pseudoParent->related_.append(this);
+}
+
+/*!
+ This function creates a pair that describes a link.
+ The pair is composed from \a link and \a desc. The
+ \a linkType is the map index the pair is filed under.
+ */
+void Node::setLink(LinkType linkType, const QString &link, const QString &desc)
+{
+ QPair<QString,QString> linkPair;
+ linkPair.first = link;
+ linkPair.second = desc;
+ linkMap[linkType] = linkPair;
+}
+
+/*!
+ Sets the information about the project and version a node was introduced
+ in. The string is simplified, removing excess whitespace before being
+ stored.
+*/
+void Node::setSince(const QString &since)
+{
+ sinc = since.simplified();
+}
+
+/*!
+ Returns a string representing the access specifier.
+ */
+QString Node::accessString() const
+{
+ switch (access_) {
+ case Protected:
+ return "protected";
+ case Private:
+ return "private";
+ case Public:
+ default:
+ break;
+ }
+ return "public";
+}
+
+/*!
+ Extract a class name from the type \a string and return it.
+ */
+QString Node::extractClassName(const QString &string) const
+{
+ QString result;
+ for (int i=0; i<=string.size(); ++i) {
+ QChar ch;
+ if (i != string.size())
+ ch = string.at(i);
+
+ QChar lower = ch.toLower();
+ if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) ||
+ ch.digitValue() >= 0 ||
+ ch == QLatin1Char('_') ||
+ ch == QLatin1Char(':')) {
+ result += ch;
+ }
+ else if (!result.isEmpty()) {
+ if (result != QLatin1String("const"))
+ return result;
+ result.clear();
+ }
+ }
+ return result;
+}
+
+/*!
+ Returns a string representing the access specifier.
+ */
+QString RelatedClass::accessString() const
+{
+ switch (access) {
+ case Node::Protected:
+ return "protected";
+ case Node::Private:
+ return "private";
+ case Node::Public:
+ default:
+ break;
+ }
+ return "public";
+}
+
+/*!
+ Returns the inheritance status.
+ */
+Node::Status Node::inheritedStatus() const
+{
+ Status parentStatus = Commendable;
+ if (parent_)
+ parentStatus = parent_->inheritedStatus();
+ return (Status)qMin((int)status_, (int)parentStatus);
+}
+
+/*!
+ Returns the thread safeness value for whatever this node
+ represents. But if this node has a parent and the thread
+ safeness value of the parent is the same as the thread
+ safeness value of this node, what is returned is the
+ value \c{UnspecifiedSafeness}. Why?
+ */
+Node::ThreadSafeness Node::threadSafeness() const
+{
+ if (parent_ && safeness_ == parent_->inheritedThreadSafeness())
+ return UnspecifiedSafeness;
+ return safeness_;
+}
+
+/*!
+ If this node has a parent, the parent's thread safeness
+ value is returned. Otherwise, this node's thread safeness
+ value is returned. Why?
+ */
+Node::ThreadSafeness Node::inheritedThreadSafeness() const
+{
+ if (parent_ && safeness_ == UnspecifiedSafeness)
+ return parent_->inheritedThreadSafeness();
+ return safeness_;
+}
+
+/*!
+ Returns the sanitized file name without the path.
+ If the the file is an html file, the html suffix
+ is removed. Why?
+ */
+QString Node::fileBase() const
+{
+ QString base = name();
+ if (base.endsWith(".html"))
+ base.chop(5);
+ base.replace(QRegExp("[^A-Za-z0-9]+"), " ");
+ base = base.trimmed();
+ base.replace(QLatin1Char(' '), QLatin1Char('-'));
+ return base.toLower();
+}
+
+/*!
+ Returns this node's Universally Unique IDentifier as a
+ QString. Creates the UUID first, if it has not been created.
+ */
+QString Node::guid() const
+{
+ if (uuid.isEmpty())
+ uuid = idForNode();
+ return uuid;
+}
+
+#if 0
+// fossil
+QUuid quuid = QUuid::createUuid();
+QString t = quuid.toString();
+uuid = "id-" + t.mid(1,t.length()-2);
+#endif
+
+/*!
+ Composes a string to be used as an href attribute in DITA
+ XML. It is composed of the file name and the UUID separated
+ by a '#'. If this node is a class node, the file name is
+ taken from this node; if this node is a function node, the
+ file name is taken from the parent node of this node.
+ */
+QString Node::ditaXmlHref()
+{
+ QString href;
+ if ((type() == Function) ||
+ (type() == Property) ||
+ (type() == Variable)) {
+ href = parent()->fileBase();
+ }
+ else {
+ href = fileBase();
+ }
+ if (!href.endsWith(".xml"))
+ href += ".xml";
+ return href + QLatin1Char('#') + guid();
+}
+
+/*!
+ If this node is a QML class node, return a pointer to it.
+ If it is a child of a QML class node, return a pointer to
+ the QML class node. Otherwise, return 0;
+ */
+const QmlClassNode* Node::qmlClassNode() const
+{
+ if (isQmlNode()) {
+ const Node* n = this;
+ while (n && n->subType() != Node::QmlClass)
+ n = n->parent();
+ if (n && n->subType() == Node::QmlClass)
+ return static_cast<const QmlClassNode*>(n);
+ }
+ return 0;
+}
+
+/*!
+ If this node is a QML node, find its QML class node,
+ and return a pointer to the C++ class node from the
+ QML class node. That pointer will be null if the QML
+ class node is a component. It will be non-null if
+ the QML class node is a QML element.
+ */
+const ClassNode* Node::declarativeCppNode() const
+{
+ const QmlClassNode* qcn = qmlClassNode();
+ if (qcn)
+ return qcn->classNode();
+ return 0;
+}
+
+/*!
+ \class InnerNode
+ */
+
+/*!
+ The inner node destructor deletes the children and removes
+ this node from its related nodes.
+ */
+InnerNode::~InnerNode()
+{
+ deleteChildren();
+ removeFromRelated();
+}
+
+/*!
+ Find the node in this node's children that has the
+ given \a name. If this node is a QML class node, be
+ sure to also look in the children of its property
+ group nodes. Return the matching node or 0.
+ */
+Node *InnerNode::findNode(const QString& name)
+{
+ Node *node = childMap.value(name);
+ if (node && node->subType() != QmlPropertyGroup)
+ return node;
+ if ((type() == Fake) && (subType() == QmlClass)) {
+ for (int i=0; i<children.size(); ++i) {
+ Node* n = children.at(i);
+ if (n->subType() == QmlPropertyGroup) {
+ node = static_cast<InnerNode*>(n)->findNode(name);
+ if (node)
+ return node;
+ }
+ }
+ }
+ return primaryFunctionMap.value(name);
+}
+void InnerNode::findNodes(const QString& name, QList<Node*>& n)
+{
+ n.clear();
+ Node* node = 0;
+ QList<Node*> nodes = childMap.values(name);
+ /*
+ <sigh> If this node's child map contains no nodes named
+ name, then if this node is a QML class, seach each of its
+ property group nodes for a node named name. If a match is
+ found, append it to the output list and return immediately.
+ */
+ if (nodes.isEmpty()) {
+ if ((type() == Fake) && (subType() == QmlClass)) {
+ for (int i=0; i<children.size(); ++i) {
+ node = children.at(i);
+ if (node->subType() == QmlPropertyGroup) {
+ node = static_cast<InnerNode*>(node)->findNode(name);
+ if (node) {
+ n.append(node);
+ return;
+ }
+ }
+ }
+ }
+ }
+ else {
+ /*
+ If the childMap does contain one or more nodes named
+ name, traverse the list of matching nodes. Append each
+ matching node that is not a property group node to the
+ output list. Search each property group node for a node
+ named name and append that node to the output list.
+ This is overkill, I think, but should produce a useful
+ list.
+ */
+ for (int i=0; i<nodes.size(); ++i) {
+ node = nodes.at(i);
+ if (node->subType() != QmlPropertyGroup)
+ n.append(node);
+ else {
+ node = static_cast<InnerNode*>(node)->findNode(name);
+ if (node)
+ n.append(node);
+ }
+ }
+ }
+ if (!n.isEmpty())
+ return;
+ node = primaryFunctionMap.value(name);
+ if (node)
+ n.append(node);
+}
+
+/*!
+ Find the node in this node's children that has the given \a name. If
+ this node is a QML class node, be sure to also look in the children
+ of its property group nodes. Return the matching node or 0.
+
+ If \a qml is true, only match a node for which node->isQmlNode()
+ returns true. If \a qml is false, only match a node for which
+ node->isQmlNode() returns false.
+ */
+Node* InnerNode::findNode(const QString& name, bool qml)
+{
+ QList<Node*> nodes = childMap.values(name);
+ if (!nodes.isEmpty()) {
+ for (int i=0; i<nodes.size(); ++i) {
+ Node* node = nodes.at(i);
+ if (!qml) {
+ if (!node->isQmlNode())
+ return node;
+ }
+ else if (node->isQmlNode() && (node->subType() != QmlPropertyGroup))
+ return node;
+ }
+ }
+ if (qml && (type() == Fake) && (subType() == QmlClass)) {
+ for (int i=0; i<children.size(); ++i) {
+ Node* node = children.at(i);
+ if (node->subType() == QmlPropertyGroup) {
+ node = static_cast<InnerNode*>(node)->findNode(name);
+ if (node)
+ return node;
+ }
+ }
+ }
+ return primaryFunctionMap.value(name);
+}
+
+/*!
+ Same as the other findNode(), but if the node with the
+ specified \a name is not of the specified \a type, return
+ 0.
+ */
+Node *InnerNode::findNode(const QString& name, Type type)
+{
+ if (type == Function) {
+ return primaryFunctionMap.value(name);
+ }
+ else {
+ Node *node = childMap.value(name);
+ if (node && node->type() == type) {
+ return node;
+ }
+ else {
+ return 0;
+ }
+ }
+}
+
+/*!
+ Find the function node in this node for the function named \a name.
+ */
+FunctionNode *InnerNode::findFunctionNode(const QString& name)
+{
+ return static_cast<FunctionNode *>(primaryFunctionMap.value(name));
+}
+
+/*!
+ Find the function node in this node that has the same name as \a clone.
+ */
+FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone)
+{
+ QMap<QString, Node *>::ConstIterator c =
+ primaryFunctionMap.find(clone->name());
+ if (c != primaryFunctionMap.end()) {
+ if (isSameSignature(clone, (FunctionNode *) *c)) {
+ return (FunctionNode *) *c;
+ }
+ else if (secondaryFunctionMap.contains(clone->name())) {
+ const NodeList& secs = secondaryFunctionMap[clone->name()];
+ NodeList::ConstIterator s = secs.begin();
+ while (s != secs.end()) {
+ if (isSameSignature(clone, (FunctionNode *) *s))
+ return (FunctionNode *) *s;
+ ++s;
+ }
+ }
+ }
+ return 0;
+}
+
+/*!
+ Returns the list of keys from the primary function map.
+ */
+QStringList InnerNode::primaryKeys()
+{
+ QStringList t;
+ QMap<QString, Node*>::iterator i = primaryFunctionMap.begin();
+ while (i != primaryFunctionMap.end()) {
+ t.append(i.key());
+ ++i;
+ }
+ return t;
+}
+
+/*!
+ Returns the list of keys from the secondary function map.
+ */
+QStringList InnerNode::secondaryKeys()
+{
+ QStringList t;
+ QMap<QString, NodeList>::iterator i = secondaryFunctionMap.begin();
+ while (i != secondaryFunctionMap.end()) {
+ t.append(i.key());
+ ++i;
+ }
+ return t;
+}
+
+/*!
+ */
+void InnerNode::setOverload(const FunctionNode *func, bool overlode)
+{
+ Node *node = (Node *) func;
+ Node *&primary = primaryFunctionMap[func->name()];
+
+ if (secondaryFunctionMap.contains(func->name())) {
+ NodeList& secs = secondaryFunctionMap[func->name()];
+ if (overlode) {
+ if (primary == node) {
+ primary = secs.first();
+ secs.erase(secs.begin());
+ secs.append(node);
+ }
+ else {
+ secs.removeAll(node);
+ secs.append(node);
+ }
+ }
+ else {
+ if (primary != node) {
+ secs.removeAll(node);
+ secs.prepend(primary);
+ primary = node;
+ }
+ }
+ }
+}
+
+/*!
+ Mark all child nodes that have no documentation as having
+ private access and internal status. qdoc will then ignore
+ them for documentation purposes.
+
+ \note Exception: Name collision nodes are not marked
+ private/internal.
+ */
+void InnerNode::makeUndocumentedChildrenInternal()
+{
+ foreach (Node *child, childNodes()) {
+ if (child->doc().isEmpty()) {
+ if (child->subType() != Node::Collision) {
+ child->setAccess(Node::Private);
+ child->setStatus(Node::Internal);
+ }
+ }
+ }
+}
+
+/*!
+ In each child node that is a collision node,
+ clear the current child pointer.
+ */
+void InnerNode::clearCurrentChildPointers()
+{
+ foreach (Node* child, childNodes()) {
+ if (child->subType() == Collision) {
+ child->clearCurrentChild();
+ }
+ }
+}
+
+/*!
+ */
+void InnerNode::normalizeOverloads()
+{
+ QMap<QString, Node *>::Iterator p1 = primaryFunctionMap.begin();
+ while (p1 != primaryFunctionMap.end()) {
+ FunctionNode *primaryFunc = (FunctionNode *) *p1;
+ if (secondaryFunctionMap.contains(primaryFunc->name()) &&
+ (primaryFunc->status() != Commendable ||
+ primaryFunc->access() == Private)) {
+
+ NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
+ NodeList::ConstIterator s = secs.begin();
+ while (s != secs.end()) {
+ FunctionNode *secondaryFunc = (FunctionNode *) *s;
+
+ // Any non-obsolete, non-compatibility, non-private functions
+ // (i.e, visible functions) are preferable to the primary
+ // function.
+
+ if (secondaryFunc->status() == Commendable &&
+ secondaryFunc->access() != Private) {
+
+ *p1 = secondaryFunc;
+ int index = secondaryFunctionMap[primaryFunc->name()].indexOf(secondaryFunc);
+ secondaryFunctionMap[primaryFunc->name()].replace(index, primaryFunc);
+ break;
+ }
+ ++s;
+ }
+ }
+ ++p1;
+ }
+
+ QMap<QString, Node *>::ConstIterator p = primaryFunctionMap.begin();
+ while (p != primaryFunctionMap.end()) {
+ FunctionNode *primaryFunc = (FunctionNode *) *p;
+ if (primaryFunc->isOverload())
+ primaryFunc->ove = false;
+ if (secondaryFunctionMap.contains(primaryFunc->name())) {
+ NodeList& secs = secondaryFunctionMap[primaryFunc->name()];
+ NodeList::ConstIterator s = secs.begin();
+ while (s != secs.end()) {
+ FunctionNode *secondaryFunc = (FunctionNode *) *s;
+ if (!secondaryFunc->isOverload())
+ secondaryFunc->ove = true;
+ ++s;
+ }
+ }
+ ++p;
+ }
+
+ NodeList::ConstIterator c = childNodes().begin();
+ while (c != childNodes().end()) {
+ if ((*c)->isInnerNode())
+ ((InnerNode *) *c)->normalizeOverloads();
+ ++c;
+ }
+}
+
+/*!
+ */
+void InnerNode::removeFromRelated()
+{
+ while (!related_.isEmpty()) {
+ Node *p = static_cast<Node *>(related_.takeFirst());
+
+ if (p != 0 && p->relates() == this) p->clearRelated();
+ }
+}
+
+/*!
+ Deletes all this node's children.
+ */
+void InnerNode::deleteChildren()
+{
+ NodeList childrenCopy = children; // `children` will be changed in ~Node()
+ qDeleteAll(childrenCopy);
+}
+
+/*! \fn bool InnerNode::isInnerNode() const
+ Returns true because this is an inner node.
+ */
+
+/*!
+ */
+const Node *InnerNode::findNode(const QString& name) const
+{
+ InnerNode *that = (InnerNode *) this;
+ return that->findNode(name);
+}
+
+/*!
+ If \a qml is true, only match a node for which node->isQmlNode()
+ returns true. If \a qml is false, only match a node for which
+ node->isQmlNode() returns false.
+ */
+const Node* InnerNode::findNode(const QString& name, bool qml) const
+{
+ InnerNode*that = (InnerNode*) this;
+ return that->findNode(name, qml);
+}
+
+/*!
+ */
+const Node *InnerNode::findNode(const QString& name, Type type) const
+{
+ InnerNode *that = (InnerNode *) this;
+ return that->findNode(name, type);
+}
+
+/*!
+ Find the function node in this node that has the given \a name.
+ */
+const FunctionNode *InnerNode::findFunctionNode(const QString& name) const
+{
+ InnerNode *that = (InnerNode *) this;
+ return that->findFunctionNode(name);
+}
+
+/*!
+ Find the function node in this node that has the same name as \a clone.
+ */
+const FunctionNode *InnerNode::findFunctionNode(const FunctionNode *clone) const
+{
+ InnerNode *that = (InnerNode *) this;
+ return that->findFunctionNode(clone);
+}
+
+/*!
+ */
+const EnumNode *InnerNode::findEnumNodeForValue(const QString &enumValue) const
+{
+ foreach (const Node *node, enumChildren) {
+ const EnumNode *enume = static_cast<const EnumNode *>(node);
+ if (enume->hasItem(enumValue))
+ return enume;
+ }
+ return 0;
+}
+
+/*!
+ Returnds the sequence number of the function node \a func
+ in the list of overloaded functions for a class, such that
+ all the functions have the same name as the \a func.
+ */
+int InnerNode::overloadNumber(const FunctionNode *func) const
+{
+ Node *node = (Node *) func;
+ if (primaryFunctionMap[func->name()] == node) {
+ return 1;
+ }
+ else {
+ return secondaryFunctionMap[func->name()].indexOf(node) + 2;
+ }
+}
+
+/*!
+ Returns the number of member functions of a class such that
+ the functions are all named \a funcName.
+ */
+int InnerNode::numOverloads(const QString& funcName) const
+{
+ if (primaryFunctionMap.contains(funcName)) {
+ return secondaryFunctionMap[funcName].count() + 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+/*!
+ Returns a node list containing all the member functions of
+ some class such that the functions overload the name \a funcName.
+ */
+NodeList InnerNode::overloads(const QString &funcName) const
+{
+ NodeList result;
+ Node *primary = primaryFunctionMap.value(funcName);
+ if (primary) {
+ result << primary;
+ result += secondaryFunctionMap[funcName];
+ }
+ return result;
+}
+
+/*!
+ Construct an inner node (i.e., not a leaf node) of the
+ given \a type and having the given \a parent and \a name.
+ */
+InnerNode::InnerNode(Type type, InnerNode *parent, const QString& name)
+ : Node(type, parent, name)
+{
+ switch (type) {
+ case Class:
+ case Namespace:
+ setPageType(ApiPage);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ Appends an \a include file to the list of include files.
+ */
+void InnerNode::addInclude(const QString& include)
+{
+ inc.append(include);
+}
+
+/*!
+ Sets the list of include files to \a includes.
+ */
+void InnerNode::setIncludes(const QStringList& includes)
+{
+ inc = includes;
+}
+
+/*!
+ f1 is always the clone
+ */
+bool InnerNode::isSameSignature(const FunctionNode *f1, const FunctionNode *f2)
+{
+ if (f1->parameters().count() != f2->parameters().count())
+ return false;
+ if (f1->isConst() != f2->isConst())
+ return false;
+
+ QList<Parameter>::ConstIterator p1 = f1->parameters().begin();
+ QList<Parameter>::ConstIterator p2 = f2->parameters().begin();
+ while (p2 != f2->parameters().end()) {
+ if ((*p1).hasType() && (*p2).hasType()) {
+ if ((*p1).rightType() != (*p2).rightType())
+ return false;
+
+ QString t1 = p1->leftType();
+ QString t2 = p2->leftType();
+
+ if (t1.length() < t2.length())
+ qSwap(t1, t2);
+
+ /*
+ ### hack for C++ to handle superfluous
+ "Foo::" prefixes gracefully
+ */
+ if (t1 != t2 && t1 != (f2->parent()->name() + "::" + t2))
+ return false;
+ }
+ ++p1;
+ ++p2;
+ }
+ return true;
+}
+
+/*!
+ Adds the \a child to this node's child list.
+ */
+void InnerNode::addChild(Node *child)
+{
+ children.append(child);
+ if ((child->type() == Function) || (child->type() == QmlMethod)) {
+ FunctionNode *func = (FunctionNode *) child;
+ if (!primaryFunctionMap.contains(func->name())) {
+ primaryFunctionMap.insert(func->name(), func);
+ }
+ else {
+ NodeList &secs = secondaryFunctionMap[func->name()];
+ secs.append(func);
+ }
+ }
+ else {
+ if (child->type() == Enum)
+ enumChildren.append(child);
+ childMap.insertMulti(child->name(), child);
+ }
+}
+
+/*!
+ */
+void InnerNode::removeChild(Node *child)
+{
+ children.removeAll(child);
+ enumChildren.removeAll(child);
+ if (child->type() == Function) {
+ QMap<QString, Node *>::Iterator prim =
+ primaryFunctionMap.find(child->name());
+ NodeList& secs = secondaryFunctionMap[child->name()];
+ if (prim != primaryFunctionMap.end() && *prim == child) {
+ if (secs.isEmpty()) {
+ primaryFunctionMap.remove(child->name());
+ }
+ else {
+ primaryFunctionMap.insert(child->name(), secs.takeFirst());
+ }
+ }
+ else {
+ secs.removeAll(child);
+ }
+ }
+ QMap<QString, Node *>::Iterator ent = childMap.find(child->name());
+ while (ent != childMap.end() && ent.key() == child->name()) {
+ if (*ent == child) {
+ childMap.erase(ent);
+ break;
+ }
+ ++ent;
+ }
+}
+
+/*!
+ Find the module (QtCore, QtGui, etc.) to which the class belongs.
+ We do this by obtaining the full path to the header file's location
+ and examine everything between "src/" and the filename. This is
+ semi-dirty because we are assuming a particular directory structure.
+
+ This function is only really useful if the class's module has not
+ been defined in the header file with a QT_MODULE macro or with an
+ \inmodule command in the documentation.
+*/
+QString Node::moduleName() const
+{
+ if (!mod.isEmpty())
+ return mod;
+
+ QString path = location().filePath();
+ QString pattern = QString("src") + QDir::separator();
+ int start = path.lastIndexOf(pattern);
+
+ if (start == -1)
+ return "";
+
+ QString moduleDir = path.mid(start + pattern.size());
+ int finish = moduleDir.indexOf(QDir::separator());
+
+ if (finish == -1)
+ return "";
+
+ QString moduleName = moduleDir.left(finish);
+
+ if (moduleName == "corelib")
+ return "QtCore";
+ else if (moduleName == "uitools")
+ return "QtUiTools";
+ else if (moduleName == "gui")
+ return "QtGui";
+ else if (moduleName == "network")
+ return "QtNetwork";
+ else if (moduleName == "opengl")
+ return "QtOpenGL";
+ else if (moduleName == "qt3support")
+ return "Qt3Support";
+ else if (moduleName == "svg")
+ return "QtSvg";
+ else if (moduleName == "sql")
+ return "QtSql";
+ else if (moduleName == "qtestlib")
+ return "QtTest";
+ else if (moduleDir.contains("webkit"))
+ return "QtWebKit";
+ else if (moduleName == "xml")
+ return "QtXml";
+ else
+ return "";
+}
+
+/*!
+ */
+void InnerNode::removeRelated(Node *pseudoChild)
+{
+ related_.removeAll(pseudoChild);
+}
+
+/*!
+ \class LeafNode
+ */
+
+/*!
+ Returns false because this is a LeafNode.
+ */
+bool LeafNode::isInnerNode() const
+{
+ return false;
+}
+
+/*!
+ Constructs a leaf node named \a name of the specified
+ \a type. The new leaf node becomes a child of \a parent.
+ */
+LeafNode::LeafNode(Type type, InnerNode *parent, const QString& name)
+ : Node(type, parent, name)
+{
+ switch (type) {
+ case Enum:
+ case Function:
+ case Typedef:
+ case Variable:
+ case QmlProperty:
+ case QmlSignal:
+ case QmlSignalHandler:
+ case QmlMethod:
+ setPageType(ApiPage);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ This constructor should only be used when this node's parent
+ is meant to be \a parent, but this node is not to be listed
+ as a child of \a parent. It is currently only used for the
+ documentation case where a \e{qmlproperty} command is used
+ to override the QML definition of a QML property.
+ */
+LeafNode::LeafNode(InnerNode* parent, Type type, const QString& name)
+ : Node(type, 0, name)
+{
+ setParent(parent);
+ switch (type) {
+ case Enum:
+ case Function:
+ case Typedef:
+ case Variable:
+ case QmlProperty:
+ case QmlSignal:
+ case QmlSignalHandler:
+ case QmlMethod:
+ setPageType(ApiPage);
+ break;
+ default:
+ break;
+ }
+}
+
+
+/*!
+ \class NamespaceNode
+ */
+
+/*!
+ Constructs a namespace node.
+ */
+NamespaceNode::NamespaceNode(InnerNode *parent, const QString& name)
+ : InnerNode(Namespace, parent, name)
+{
+ setPageType(ApiPage);
+}
+
+/*!
+ \class ClassNode
+ \brief This class represents a C++ class.
+ */
+
+/*!
+ Constructs a class node. A class node will generate an API page.
+ */
+ClassNode::ClassNode(InnerNode *parent, const QString& name)
+ : InnerNode(Class, parent, name)
+{
+ hidden = false;
+ abstract = false;
+ qmlelement = 0;
+ setPageType(ApiPage);
+}
+
+/*!
+ */
+void ClassNode::addBaseClass(Access access,
+ ClassNode *node,
+ const QString &dataTypeWithTemplateArgs)
+{
+ bases.append(RelatedClass(access, node, dataTypeWithTemplateArgs));
+ node->derived.append(RelatedClass(access, this));
+}
+
+/*!
+ */
+void ClassNode::fixBaseClasses()
+{
+ int i;
+ i = 0;
+ QSet<ClassNode *> found;
+
+ // Remove private and duplicate base classes.
+ while (i < bases.size()) {
+ ClassNode* bc = bases.at(i).node;
+ if (bc->access() == Node::Private || found.contains(bc)) {
+ RelatedClass rc = bases.at(i);
+ bases.removeAt(i);
+ ignoredBases.append(rc);
+ const QList<RelatedClass> &bb = bc->baseClasses();
+ for (int j = bb.size() - 1; j >= 0; --j)
+ bases.insert(i, bb.at(j));
+ }
+ else {
+ ++i;
+ }
+ found.insert(bc);
+ }
+
+ i = 0;
+ while (i < derived.size()) {
+ ClassNode* dc = derived.at(i).node;
+ if (dc->access() == Node::Private) {
+ derived.removeAt(i);
+ const QList<RelatedClass> &dd = dc->derivedClasses();
+ for (int j = dd.size() - 1; j >= 0; --j)
+ derived.insert(i, dd.at(j));
+ }
+ else {
+ ++i;
+ }
+ }
+}
+
+/*!
+ Search the child list to find the property node with the
+ specified \a name.
+ */
+const PropertyNode *ClassNode::findPropertyNode(const QString &name) const
+{
+ const Node *n = findNode(name, Node::Property);
+
+ if (n)
+ return static_cast<const PropertyNode*>(n);
+
+ const PropertyNode *pn = 0;
+
+ const QList<RelatedClass> &bases = baseClasses();
+ if (!bases.isEmpty()) {
+ for (int i = 0; i < bases.size(); ++i) {
+ const ClassNode *cn = bases[i].node;
+ pn = cn->findPropertyNode(name);
+ if (pn)
+ break;
+ }
+ }
+ const QList<RelatedClass>& ignoredBases = ignoredBaseClasses();
+ if (!ignoredBases.isEmpty()) {
+ for (int i = 0; i < ignoredBases.size(); ++i) {
+ const ClassNode *cn = ignoredBases[i].node;
+ pn = cn->findPropertyNode(name);
+ if (pn)
+ break;
+ }
+ }
+
+ return pn;
+}
+
+/*!
+ This function does a recursive search of this class node's
+ base classes looking for one that has a QML element. If it
+ finds one, it returns the pointer to that QML element. If
+ it doesn't find one, it returns null.
+ */
+const QmlClassNode* ClassNode::findQmlBaseNode() const
+{
+ const QmlClassNode* result = 0;
+ const QList<RelatedClass>& bases = baseClasses();
+
+ if (!bases.isEmpty()) {
+ for (int i = 0; i < bases.size(); ++i) {
+ const ClassNode* cn = bases[i].node;
+ if (cn && cn->qmlElement()) {
+ return cn->qmlElement();
+ }
+ }
+ for (int i = 0; i < bases.size(); ++i) {
+ const ClassNode* cn = bases[i].node;
+ if (cn) {
+ result = cn->findQmlBaseNode();
+ if (result != 0) {
+ return result;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*!
+ \class FakeNode
+ */
+
+/*!
+ The type of a FakeNode is Fake, and it has a \a subtype,
+ which specifies the type of FakeNode. The page type for
+ the page index is set here.
+ */
+FakeNode::FakeNode(InnerNode* parent, const QString& name, SubType subtype, Node::PageType ptype)
+ : InnerNode(Fake, parent, name), nodeSubtype_(subtype)
+{
+ switch (subtype) {
+ case Page:
+ setPageType(ptype);
+ break;
+ case DitaMap:
+ setPageType(ptype);
+ break;
+ case Module:
+ case QmlModule:
+ case Group:
+ setPageType(OverviewPage);
+ break;
+ case QmlClass:
+ case QmlBasicType:
+ setPageType(ApiPage);
+ break;
+ case Example:
+ setPageType(ExamplePage);
+ break;
+ case Collision:
+ setPageType(ptype);
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ Returns the fake node's title. This is used for the page title.
+*/
+QString FakeNode::title() const
+{
+ return title_;
+}
+
+/*!
+ Returns the fake node's full title, which is usually
+ just title(), but for some SubType values is different
+ from title()
+ */
+QString FakeNode::fullTitle() const
+{
+ if (nodeSubtype_ == File) {
+ if (title().isEmpty())
+ return name().mid(name().lastIndexOf('/') + 1) + " Example File";
+ else
+ return title();
+ }
+ else if (nodeSubtype_ == Image) {
+ if (title().isEmpty())
+ return name().mid(name().lastIndexOf('/') + 1) + " Image File";
+ else
+ return title();
+ }
+ else if ((nodeSubtype_ == HeaderFile) || (nodeSubtype_ == Collision)) {
+ if (title().isEmpty())
+ return name();
+ else
+ return name() + " - " + title();
+ }
+ else {
+ return title();
+ }
+}
+
+/*!
+ Returns the subtitle.
+ */
+QString FakeNode::subTitle() const
+{
+ if (!subtitle_.isEmpty())
+ return subtitle_;
+
+ if ((nodeSubtype_ == File) || (nodeSubtype_ == Image)) {
+ if (title().isEmpty() && name().contains(QLatin1Char('/')))
+ return name();
+ }
+ return QString();
+}
+
+/*!
+ The constructor calls the FakeNode constructor with
+ \a parent, \a name, and Node::Example.
+ */
+ExampleNode::ExampleNode(InnerNode* parent, const QString& name)
+ : FakeNode(parent, name, Node::Example, Node::ExamplePage)
+{
+ // nothing
+}
+
+/*!
+ \class EnumNode
+ */
+
+/*!
+ The constructor for the node representing an enum type
+ has a \a parent class and an enum type \a name.
+ */
+EnumNode::EnumNode(InnerNode *parent, const QString& name)
+ : LeafNode(Enum, parent, name), ft(0)
+{
+}
+
+/*!
+ Add \a item to the enum type's item list.
+ */
+void EnumNode::addItem(const EnumItem& item)
+{
+ itms.append(item);
+ names.insert(item.name());
+}
+
+/*!
+ Returns the access level of the enumeration item named \a name.
+ Apparently it is private if it has been omitted by qdoc's
+ omitvalue command. Otherwise it is public.
+ */
+Node::Access EnumNode::itemAccess(const QString &name) const
+{
+ if (doc().omitEnumItemNames().contains(name))
+ return Private;
+ return Public;
+}
+
+/*!
+ Returns the enum value associated with the enum \a name.
+ */
+QString EnumNode::itemValue(const QString &name) const
+{
+ foreach (const EnumItem &item, itms) {
+ if (item.name() == name)
+ return item.value();
+ }
+ return QString();
+}
+
+/*!
+ \class TypedefNode
+ */
+
+/*!
+ */
+TypedefNode::TypedefNode(InnerNode *parent, const QString& name)
+ : LeafNode(Typedef, parent, name), ae(0)
+{
+}
+
+/*!
+ */
+void TypedefNode::setAssociatedEnum(const EnumNode *enume)
+{
+ ae = enume;
+}
+
+/*!
+ \class Parameter
+ \brief The class Parameter contains one parameter.
+
+ A parameter can be a function parameter or a macro
+ parameter.
+ */
+
+/*!
+ Constructs this parameter from the left and right types
+ \a leftType and rightType, the parameter \a name, and the
+ \a defaultValue. In practice, \a rightType is not used,
+ and I don't know what is was meant for.
+ */
+Parameter::Parameter(const QString& leftType,
+ const QString& rightType,
+ const QString& name,
+ const QString& defaultValue)
+ : lef(leftType), rig(rightType), nam(name), def(defaultValue)
+{
+}
+
+/*!
+ The standard copy constructor copies the strings from \a p.
+ */
+Parameter::Parameter(const Parameter& p)
+ : lef(p.lef), rig(p.rig), nam(p.nam), def(p.def)
+{
+}
+
+/*!
+ Assigning Parameter \a p to this Parameter copies the
+ strings across.
+ */
+Parameter& Parameter::operator=(const Parameter& p)
+{
+ lef = p.lef;
+ rig = p.rig;
+ nam = p.nam;
+ def = p.def;
+ return *this;
+}
+
+/*!
+ Reconstructs the text describing the parameter and
+ returns it. If \a value is true, the default value
+ will be included, if there is one.
+ */
+QString Parameter::reconstruct(bool value) const
+{
+ QString p = lef + rig;
+ if (!p.endsWith(QChar('*')) && !p.endsWith(QChar('&')) && !p.endsWith(QChar(' ')))
+ p += QLatin1Char(' ');
+ p += nam;
+ if (value && !def.isEmpty())
+ p += " = " + def;
+ return p;
+}
+
+
+/*!
+ \class FunctionNode
+ */
+
+/*!
+ Construct a function node for a C++ function. It's parent
+ is \a parent, and it's name is \a name.
+ */
+FunctionNode::FunctionNode(InnerNode *parent, const QString& name)
+ : LeafNode(Function, parent, name),
+ met(Plain),
+ vir(NonVirtual),
+ con(false),
+ sta(false),
+ ove(false),
+ reimp(false),
+ attached_(false),
+ rf(0),
+ ap(0)
+{
+ // nothing.
+}
+
+/*!
+ Construct a function node for a QML method or signal, specified
+ by \a type. It's parent is \a parent, and it's name is \a name.
+ If \a attached is true, it is an attached method or signal.
+ */
+FunctionNode::FunctionNode(Type type, InnerNode *parent, const QString& name, bool attached)
+ : LeafNode(type, parent, name),
+ met(Plain),
+ vir(NonVirtual),
+ con(false),
+ sta(false),
+ ove(false),
+ reimp(false),
+ attached_(attached),
+ rf(0),
+ ap(0)
+{
+ // nothing.
+}
+
+/*!
+ Sets the \a virtualness of this function. If the \a virtualness
+ is PureVirtual, and if the parent() is a ClassNode, set the parent's
+ \e abstract flag to true.
+ */
+void FunctionNode::setVirtualness(Virtualness virtualness)
+{
+ vir = virtualness;
+ if ((virtualness == PureVirtual) && parent() &&
+ (parent()->type() == Node::Class))
+ parent()->setAbstract(true);
+}
+
+/*!
+ */
+void FunctionNode::setOverload(bool overlode)
+{
+ parent()->setOverload(this, overlode);
+ ove = overlode;
+}
+
+/*!
+ Sets the function node's reimplementation flag to \a r.
+ When \a r is true, it is supposed to mean that this function
+ is a reimplementation of a virtual function in a base class,
+ but it really just means the \e reimp command was seen in the
+ qdoc comment.
+ */
+void FunctionNode::setReimp(bool r)
+{
+ reimp = r;
+}
+
+/*!
+ */
+void FunctionNode::addParameter(const Parameter& parameter)
+{
+ params.append(parameter);
+}
+
+/*!
+ */
+void FunctionNode::borrowParameterNames(const FunctionNode *source)
+{
+ QList<Parameter>::Iterator t = params.begin();
+ QList<Parameter>::ConstIterator s = source->params.begin();
+ while (s != source->params.end() && t != params.end()) {
+ if (!(*s).name().isEmpty())
+ (*t).setName((*s).name());
+ ++s;
+ ++t;
+ }
+}
+
+/*!
+ If this function is a reimplementation, \a from points
+ to the FunctionNode of the function being reimplemented.
+ */
+void FunctionNode::setReimplementedFrom(FunctionNode *from)
+{
+ rf = from;
+ from->rb.append(this);
+}
+
+/*!
+ Sets the "associated" property to \a property. The function
+ might be the setter or getter for a property, for example.
+ */
+void FunctionNode::setAssociatedProperty(PropertyNode *property)
+{
+ ap = property;
+}
+
+/*!
+ Returns the overload number for this function obtained
+ from the parent.
+ */
+int FunctionNode::overloadNumber() const
+{
+ return parent()->overloadNumber(this);
+}
+
+/*!
+ Returns the number of times this function name has been
+ overloaded, obtained from the parent.
+ */
+int FunctionNode::numOverloads() const
+{
+ return parent()->numOverloads(name());
+}
+
+/*!
+ Returns the list of parameter names.
+ */
+QStringList FunctionNode::parameterNames() const
+{
+ QStringList names;
+ QList<Parameter>::ConstIterator p = parameters().begin();
+ while (p != parameters().end()) {
+ names << (*p).name();
+ ++p;
+ }
+ return names;
+}
+
+/*!
+ Returns a raw list of parameters. If \a names is true, the
+ names are included. If \a values is true, the default values
+ are included, if any are present.
+ */
+QString FunctionNode::rawParameters(bool names, bool values) const
+{
+ QString raw;
+ foreach (const Parameter &parameter, parameters()) {
+ raw += parameter.leftType() + parameter.rightType();
+ if (names)
+ raw += parameter.name();
+ if (values)
+ raw += parameter.defaultValue();
+ }
+ return raw;
+}
+
+/*!
+ Returns the list of reconstructed parameters. If \a values
+ is true, the default values are included, if any are present.
+ */
+QStringList FunctionNode::reconstructParams(bool values) const
+{
+ QStringList params;
+ QList<Parameter>::ConstIterator p = parameters().begin();
+ while (p != parameters().end()) {
+ params << (*p).reconstruct(values);
+ ++p;
+ }
+ return params;
+}
+
+/*!
+ Reconstructs and returns the function's signature. If \a values
+ is true, the default values of the parameters are included, if
+ present.
+ */
+QString FunctionNode::signature(bool values) const
+{
+ QString s;
+ if (!returnType().isEmpty())
+ s = returnType() + QLatin1Char(' ');
+ s += name() + QLatin1Char('(');
+ QStringList params = reconstructParams(values);
+ int p = params.size();
+ if (p > 0) {
+ for (int i=0; i<p; i++) {
+ s += params[i];
+ if (i < (p-1))
+ s += ", ";
+ }
+ }
+ s += QLatin1Char(')');
+ return s;
+}
+
+/*!
+ Returns true if the node's status is Internal, or if its
+ parent is a class with internal status.
+ */
+bool FunctionNode::isInternal() const
+{
+ if (status() == Internal)
+ return true;
+ if (parent() && parent()->status() == Internal)
+ return true;
+ if (relates() && relates()->status() == Internal)
+ return true;
+ return false;
+}
+
+/*!
+ Print some debugging stuff.
+ */
+void FunctionNode::debug() const
+{
+ qDebug("QML METHOD %s rt %s pp %s",
+ qPrintable(name()), qPrintable(rt), qPrintable(pp.join(" ")));
+}
+
+/*!
+ \class PropertyNode
+
+ This class describes one instance of using the Q_PROPERTY macro.
+ */
+
+/*!
+ The constructor sets the \a parent and the \a name, but
+ everything else is set to default values.
+ */
+PropertyNode::PropertyNode(InnerNode *parent, const QString& name)
+ : LeafNode(Property, parent, name),
+ sto(Trool_Default),
+ des(Trool_Default),
+ scr(Trool_Default),
+ wri(Trool_Default),
+ usr(Trool_Default),
+ cst(false),
+ fnl(false),
+ rev(-1),
+ overrides(0)
+{
+ // nothing.
+}
+
+/*!
+ Sets this property's \e {overridden from} property to
+ \a baseProperty, which indicates that this property
+ overrides \a baseProperty. To begin with, all the values
+ in this property are set to the corresponding values in
+ \a baseProperty.
+
+ We probably should ensure that the constant and final
+ attributes are not being overridden improperly.
+ */
+void PropertyNode::setOverriddenFrom(const PropertyNode* baseProperty)
+{
+ for (int i = 0; i < NumFunctionRoles; ++i) {
+ if (funcs[i].isEmpty())
+ funcs[i] = baseProperty->funcs[i];
+ }
+ if (sto == Trool_Default)
+ sto = baseProperty->sto;
+ if (des == Trool_Default)
+ des = baseProperty->des;
+ if (scr == Trool_Default)
+ scr = baseProperty->scr;
+ if (wri == Trool_Default)
+ wri = baseProperty->wri;
+ if (usr == Trool_Default)
+ usr = baseProperty->usr;
+ overrides = baseProperty;
+}
+
+/*!
+ */
+QString PropertyNode::qualifiedDataType() const
+{
+ if (setters().isEmpty() && resetters().isEmpty()) {
+ if (type_.contains(QLatin1Char('*')) || type_.contains(QLatin1Char('&'))) {
+ // 'QWidget *' becomes 'QWidget *' const
+ return type_ + " const";
+ }
+ else {
+ /*
+ 'int' becomes 'const int' ('int const' is
+ correct C++, but looks wrong)
+ */
+ return "const " + type_;
+ }
+ }
+ else {
+ return type_;
+ }
+}
+
+/*! Converts the \a boolean value to an enum representation
+ of the boolean type, which includes an enum value for the
+ \e {default value} of the item, i.e. true, false, or default.
+ */
+PropertyNode::Trool PropertyNode::toTrool(bool boolean)
+{
+ return boolean ? Trool_True : Trool_False;
+}
+
+/*!
+ Converts the enum \a troolean back to a boolean value.
+ If \a troolean is neither the true enum value nor the
+ false enum value, the boolean value returned is
+ \a defaultValue.
+
+ Note that runtimeDesignabilityFunction() should be called
+ first. If that function returns the name of a function, it
+ means the function must be called at runtime to determine
+ whether the property is Designable.
+ */
+bool PropertyNode::fromTrool(Trool troolean, bool defaultValue)
+{
+ switch (troolean) {
+ case Trool_True:
+ return true;
+ case Trool_False:
+ return false;
+ default:
+ return defaultValue;
+ }
+}
+
+/*!
+ \class TargetNode
+ */
+
+/*!
+ */
+TargetNode::TargetNode(InnerNode *parent, const QString& name)
+ : LeafNode(Target, parent, name)
+{
+}
+
+/*!
+ Returns false because this is a TargetNode.
+ */
+bool TargetNode::isInnerNode() const
+{
+ return false;
+}
+
+bool QmlClassNode::qmlOnly = false;
+QMultiMap<QString,Node*> QmlClassNode::inheritedBy;
+QMap<QString, QmlClassNode*> QmlClassNode::moduleMap;
+
+/*!
+ Constructs a Qml class node (i.e. a Fake node with the
+ subtype QmlClass. The new node has the given \a parent
+ and \a name and is associated with the C++ class node
+ specified by \a cn which may be null if the the Qml
+ class node is not associated with a C++ class node.
+ */
+QmlClassNode::QmlClassNode(InnerNode *parent,
+ const QString& name,
+ const ClassNode* cn)
+ : FakeNode(parent, name, QmlClass, Node::ApiPage),
+ abstract(false),
+ cnode_(cn),
+ base_(0)
+{
+ int i = 0;
+ if (name.startsWith("QML:")) {
+ qDebug() << "BOGUS:" << name;
+ i = 4;
+ }
+ setTitle(name.mid(i));
+}
+
+/*!
+ I made this so I could print a debug message here.
+ */
+QmlClassNode::~QmlClassNode()
+{
+#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
+ qDebug() << "Deleting QmlClassNode:" << name();
+#endif
+}
+
+/*!
+ Clear the static maps so that subsequent runs don't try to use
+ contents from a previous run.
+ */
+void QmlClassNode::terminate()
+{
+ inheritedBy.clear();
+ moduleMap.clear();
+}
+
+/*!
+ The base file name for this kind of node has "qml_"
+ prepended to it.
+
+ But not yet. Still testing.
+ */
+QString QmlClassNode::fileBase() const
+{
+ return Node::fileBase();
+}
+
+/*!
+ Record the fact that QML class \a base is inherited by
+ QML class \a sub.
+ */
+void QmlClassNode::addInheritedBy(const QString& base, Node* sub)
+{
+ if (inheritedBy.find(base,sub) == inheritedBy.end()) {
+ inheritedBy.insert(base,sub);
+ }
+#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
+ qDebug() << "QmlClassNode::addInheritedBy(): insert" << base << sub->name() << inheritedBy.size();
+#endif
+}
+
+/*!
+ Loads the list \a subs with the nodes of all the subclasses of \a base.
+ */
+void QmlClassNode::subclasses(const QString& base, NodeList& subs)
+{
+ subs.clear();
+ if (inheritedBy.count(base) > 0) {
+ subs = inheritedBy.values(base);
+#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES
+ qDebug() << "QmlClassNode::subclasses():" << inheritedBy.count(base) << base
+ << "subs:" << subs.size() << "total size:" << inheritedBy.size();
+#endif
+ }
+}
+
+/*! \fn QString QmlClassNode::qmlModuleIdentifier() const
+ This function is called to get a string that is used either
+ as a prefix for the file name to use for QML element or
+ component reference page, or as a qualifier to prefix a
+ reference to a QML element or comnponent. The string that
+ is returned is the concatenation of the QML module name
+ and its version number. e.g., if an element or component
+ is defined to be in the QML module QtQuick 1, its module
+ identifier is "QtQuick1". See setQmlModuleName().
+ */
+
+/*!
+ This function splits \a arg on the blank character to get a
+ QML module name and version number. It stores these separately.
+ The version number is not required.
+ */
+void Node::setQmlModuleName(const QString& arg)
+{
+ QStringList blankSplit = arg.split(QLatin1Char(' '));
+ qmlModuleName_ = blankSplit[0];
+ if (blankSplit.size() > 1)
+ qmlModuleVersion_ = blankSplit[1];
+}
+
+/*!
+ The name of this QML class node might be the same as the
+ name of some other QML class node. If so, then this node's
+ parent will be a NameCollisionNode.This function sets the
+ NameCollisionNode's current child to this node. This is
+ important when outputing the documentation for this node,
+ when, for example, the documentation contains a link to
+ the page being output. We don't want to generate a link
+ to the disambiguation page if we can avoid it, and to be
+ able to avoid it, the NameCollisionNode must maintain the
+ current child pointer. That's the purpose of this function.
+ */
+void QmlClassNode::setCurrentChild()
+{
+ if (parent()) {
+ InnerNode* n = parent();
+ if (n->subType() == Node::Collision)
+ n->setCurrentChild(this);
+ }
+}
+
+/*!
+ */
+void QmlClassNode::clearCurrentChild()
+{
+ if (parent()) {
+ InnerNode* n = parent();
+ if (n->subType() == Node::Collision)
+ n->clearCurrentChild();
+ }
+}
+
+/*!
+ Most QML elements don't have an \\inherits command in their
+ \\qmlclass command. This leaves qdoc bereft, when it tries
+ to output the line in the documentation that specifies the
+ QML element that a QML element inherits.
+ */
+void QmlClassNode::resolveInheritance(const Tree* tree)
+{
+ if (!links().empty() && links().contains(Node::InheritsLink)) {
+ QPair<QString,QString> linkPair;
+ linkPair = links()[Node::InheritsLink];
+ QStringList strList = linkPair.first.split("::");
+ const Node* n = tree->findNode(strList,Node::Fake);
+ if (n && (n->subType() == Node::QmlClass || n->subType() == Node::Collision)) {
+ base_ = static_cast<const FakeNode*>(n);
+ if (base_ && base_->subType() == Node::QmlClass) {
+ return;
+ }
+ }
+ if (base_ && base_->subType() == Node::Collision) {
+ const NameCollisionNode* ncn = static_cast<const NameCollisionNode*>(base_);
+ const NodeList& children = ncn->childNodes();
+ for (int i=0; i<importList_.size(); ++i) {
+ QString qmid = importList_.at(i).first + importList_.at(i).second;
+ for (int j=0; j<children.size(); ++j) {
+ if (qmid == children.at(j)->qmlModuleIdentifier()) {
+ base_ = static_cast<const FakeNode*>(children.at(j));
+ return;
+ }
+ }
+ }
+ QString qmid = qmlModuleIdentifier();
+ for (int k=0; k<children.size(); ++k) {
+ if (qmid == children.at(k)->qmlModuleIdentifier()) {
+ base_ = static_cast<const QmlClassNode*>(children.at(k));
+ return;
+ }
+ }
+ }
+ if (base_)
+ return;
+ }
+ if (cnode_) {
+ const QmlClassNode* qcn = cnode_->findQmlBaseNode();
+ if (qcn != 0)
+ base_ = qcn;
+ }
+ return;
+}
+
+/*!
+ Constructs a Qml basic type node (i.e. a Fake node with
+ the subtype QmlBasicType. The new node has the given
+ \a parent and \a name.
+ */
+QmlBasicTypeNode::QmlBasicTypeNode(InnerNode *parent,
+ const QString& name)
+ : FakeNode(parent, name, QmlBasicType, Node::ApiPage)
+{
+ setTitle(name);
+}
+
+/*!
+ Constructor for the Qml property group node. \a parent is
+ always a QmlClassNode.
+ */
+QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent,
+ const QString& name,
+ bool attached)
+ : FakeNode(parent, name, QmlPropertyGroup, Node::ApiPage),
+ isdefault_(false),
+ attached_(attached),
+ readOnly_(-1)
+{
+ // nothing.
+}
+
+/*!
+ Constructor for the QML property node, when the \a parent
+ is QML property group node. This constructor is only used
+ for creating QML property nodes for QML elements, i.e.
+ not for creating QML property nodes for QML components.
+ Hopefully, this constructor will become obsolete, so don't
+ use it unless one of the other two constructors can't be
+ used.
+ */
+QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent,
+ const QString& name,
+ const QString& type,
+ bool attached)
+ : LeafNode(QmlProperty, parent, name),
+ type_(type),
+ sto(Trool_Default),
+ des(Trool_Default),
+ isdefault_(false),
+ attached_(attached),
+ readOnly_(-1)
+{
+ setPageType(ApiPage);
+}
+
+/*!
+ Constructor for the QML property node, when the \a parent
+ is a QML class node.
+ */
+QmlPropertyNode::QmlPropertyNode(QmlClassNode *parent,
+ const QString& name,
+ const QString& type,
+ bool attached)
+ : LeafNode(QmlProperty, parent, name),
+ type_(type),
+ sto(Trool_Default),
+ des(Trool_Default),
+ isdefault_(false),
+ attached_(attached),
+ readOnly_(-1)
+{
+ setPageType(ApiPage);
+}
+
+/*!
+ Constructor for the QML property node, when the \a parent
+ is a QML property node. Strictly speaking, this is not the
+ way QML property nodes were originally meant to be built,
+ because this constructor has another QML property node as
+ its parent. But this constructor is useful for documenting
+ QML properties in QML components, i.e., when you override
+ the definition of a property with the \e{qmlproperty}
+ command. It actually uses the parent of \a parent as the
+ parent.
+ */
+QmlPropertyNode::QmlPropertyNode(QmlPropertyNode* parent,
+ const QString& name,
+ const QString& type,
+ bool attached)
+ : LeafNode(parent->parent(), QmlProperty, name),
+ type_(type),
+ sto(Trool_Default),
+ des(Trool_Default),
+ isdefault_(false),
+ attached_(attached),
+ readOnly_(-1)
+{
+ setPageType(ApiPage);
+}
+
+/*!
+ I don't know what this is.
+ */
+QmlPropertyNode::Trool QmlPropertyNode::toTrool(bool boolean)
+{
+ return boolean ? Trool_True : Trool_False;
+}
+
+/*!
+ I don't know what this is either.
+ */
+bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue)
+{
+ switch (troolean) {
+ case Trool_True:
+ return true;
+ case Trool_False:
+ return false;
+ default:
+ return defaultValue;
+ }
+}
+
+/*!
+ Returns true if a QML property or attached property is
+ read-only. The algorithm for figuring this out is long
+ amd tedious and almost certainly will break. It currently
+ doesn't work for qmlproperty bool PropertyChanges::explicit,
+ because the tokenizer gets confused on "explicit".
+ */
+bool QmlPropertyNode::isWritable(const Tree* tree) const
+{
+ if (wri != Trool_Default)
+ return fromTrool(wri, false);
+
+ const PropertyNode *pn = correspondingProperty(tree);
+ if (pn)
+ return pn->isWritable();
+ else {
+ location().warning(tr("Can't determine read-only status of QML property %1; writable assumed.").arg(name()));
+ return true;
+ }
+}
+
+const PropertyNode *QmlPropertyNode::correspondingProperty(const Tree *tree) const
+{
+ const PropertyNode *pn;
+
+ Node* n = parent();
+ while (n && n->subType() != Node::QmlClass)
+ n = n->parent();
+ if (n) {
+ const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n);
+ const ClassNode* cn = qcn->classNode();
+ if (cn) {
+ QStringList dotSplit = name().split(QChar('.'));
+ pn = cn->findPropertyNode(dotSplit[0]);
+ if (pn) {
+ if (dotSplit.size() > 1) {
+ // Find the C++ property corresponding to the QML property in
+ // the property group, <group>.<property>.
+
+ QStringList path(extractClassName(pn->qualifiedDataType()));
+ const Node* nn = tree->findNode(path,Class);
+ if (nn) {
+ const ClassNode* cn = static_cast<const ClassNode*>(nn);
+ const PropertyNode *pn2 = cn->findPropertyNode(dotSplit[1]);
+ if (pn2)
+ return pn2; // Return the property for the QML property.
+ else
+ return pn; // Return the property for the QML group.
+ }
+ }
+ else
+ return pn;
+ }
+ else {
+ pn = cn->findPropertyNode(dotSplit[0]);
+ if (pn)
+ return pn;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*! \class NameCollisionNode
+
+ An instance of this node is inserted in the tree
+ whenever qdoc discovers that two nodes have the
+ same name.
+ */
+
+/*!
+ Constructs a name collision node containing \a child
+ as its first child. The parent of \a child becomes
+ this node's parent.
+ */
+NameCollisionNode::NameCollisionNode(InnerNode* child)
+ : FakeNode(child->parent(), child->name(), Collision, Node::NoPageType)
+{
+ setTitle("Name Collisions For: " + child->name());
+ addCollision(child);
+ current = 0;
+}
+
+/*!
+ Add a collision to this collision node. \a child has
+ the same name as the other children in this collision
+ node. \a child becomes the current child.
+ */
+void NameCollisionNode::addCollision(InnerNode* child)
+{
+ if (child) {
+ if (child->parent())
+ child->parent()->removeChild(child);
+ child->setParent((InnerNode*)this);
+ children.append(child);
+ }
+}
+
+/*!
+ The destructor does nothing.
+ */
+NameCollisionNode::~NameCollisionNode()
+{
+ // nothing.
+}
+
+/*! \fn const InnerNode* NameCollisionNode::currentChild() const
+ Returns a pointer to the current child, which may be 0.
+ */
+
+/*! \fn void NameCollisionNode::setCurrentChild(InnerNode* child)
+ Sets the current child to \a child. The current child is
+ valid only within the file where it is defined.
+ */
+
+/*! \fn void NameCollisionNode::clearCurrentChild()
+ Sets the current child to 0. This should be called at the
+ end of each file, because the current child is only valid
+ within the file where the child is defined.
+ */
+
+/*!
+ Returns true if this collision node's current node is a QML node.
+ */
+bool NameCollisionNode::isQmlNode() const
+{
+ if (current)
+ return current->isQmlNode();
+ return false;
+}
+
+/*!
+ Find any of this collision node's children that has type \a t
+ and subtype \a st and return a pointer to it.
+*/
+const InnerNode* NameCollisionNode::findAny(Node::Type t, Node::SubType st) const
+{
+ if (current) {
+ if (current->type() == t && current->subType() == st)
+ return current;
+ }
+ const NodeList& cn = childNodes();
+ NodeList::ConstIterator i = cn.begin();
+ while (i != cn.end()) {
+ if ((*i)->type() == t && (*i)->subType() == st)
+ return static_cast<const InnerNode*>(*i);
+ ++i;
+ }
+ return 0;
+}
+
+/*!
+ This node is a name collision node. Find a child of this node
+ such that the child's QML module identifier matches origin's
+ QML module identifier. Return the matching node, or return this
+ node if there is no matching node.
+ */
+const Node* NameCollisionNode::applyModuleIdentifier(const Node* origin) const
+{
+ if (origin && !origin->qmlModuleIdentifier().isEmpty()) {
+ const NodeList& cn = childNodes();
+ NodeList::ConstIterator i = cn.begin();
+ while (i != cn.end()) {
+ if ((*i)->type() == Node::Fake && (*i)->subType() == Node::QmlClass) {
+ if (origin->qmlModuleIdentifier() == (*i)->qmlModuleIdentifier())
+ return (*i);
+ }
+ ++i;
+ }
+ }
+ return this;
+}
+
+/*!
+ Construct the full document name for this node and return it.
+ */
+QString Node::fullDocumentName() const
+{
+ QStringList pieces;
+ const Node* n = this;
+
+ do {
+ if (!n->name().isEmpty() &&
+ ((n->type() != Node::Fake) || (n->subType() != Node::QmlPropertyGroup)))
+ pieces.insert(0, n->name());
+
+ if ((n->type() == Node::Fake) && (n->subType() != Node::QmlPropertyGroup)) {
+ if ((n->subType() == Node::QmlClass) && !n->qmlModuleName().isEmpty())
+ pieces.insert(0, n->qmlModuleIdentifier());
+ break;
+ }
+
+ // Examine the parent node if one exists.
+ if (n->parent())
+ n = n->parent();
+ else
+ break;
+ } while (true);
+
+ // Create a name based on the type of the ancestor node.
+ QString concatenator = "::";
+ if ((n->type() == Node::Fake) && (n->subType() != Node::QmlClass))
+ concatenator = QLatin1Char('#');
+
+ return pieces.join(concatenator);
+}
+
+/*!
+ Returns the \a str as an NCName, which means the name can
+ be used as the value of an \e id attribute. Search for NCName
+ on the internet for details of what can be an NCName.
+ */
+QString Node::cleanId(QString str)
+{
+ QString clean;
+ QString name = str.simplified();
+
+ if (name.isEmpty())
+ return clean;
+
+ name = name.replace("::","-");
+ name = name.replace(" ","-");
+ name = name.replace("()","-call");
+
+ clean.reserve(name.size() + 20);
+ if (!str.startsWith("id-"))
+ clean = "id-";
+ const QChar c = name[0];
+ const uint u = c.unicode();
+
+ if ((u >= 'a' && u <= 'z') ||
+ (u >= 'A' && u <= 'Z') ||
+ (u >= '0' && u <= '9')) {
+ clean += c;
+ }
+ else if (u == '~') {
+ clean += "dtor.";
+ }
+ else if (u == '_') {
+ clean += "underscore.";
+ }
+ else {
+ clean += QLatin1Char('a');
+ }
+
+ for (int i = 1; i < (int) name.length(); i++) {
+ const QChar c = name[i];
+ const uint u = c.unicode();
+ if ((u >= 'a' && u <= 'z') ||
+ (u >= 'A' && u <= 'Z') ||
+ (u >= '0' && u <= '9') || u == '-' ||
+ u == '_' || u == '.') {
+ clean += c;
+ }
+ else if (c.isSpace() || u == ':' ) {
+ clean += QLatin1Char('-');
+ }
+ else if (u == '!') {
+ clean += "-not";
+ }
+ else if (u == '&') {
+ clean += "-and";
+ }
+ else if (u == '<') {
+ clean += "-lt";
+ }
+ else if (u == '=') {
+ clean += "-eq";
+ }
+ else if (u == '>') {
+ clean += "-gt";
+ }
+ else if (u == '#') {
+ clean += "-hash";
+ }
+ else if (u == '(') {
+ clean += "-";
+ }
+ else if (u == ')') {
+ clean += "-";
+ }
+ else {
+ clean += QLatin1Char('-');
+ clean += QString::number((int)u, 16);
+ }
+ }
+ return clean;
+}
+
+/*!
+ Creates a string that can be used as a UUID for the node,
+ depending on the type and subtype of the node. Uniquenss
+ is not guaranteed, but it is expected that strings created
+ here will be unique within an XML document. Hence, the
+ returned string can be used as the value of an \e id
+ attribute.
+ */
+QString Node::idForNode() const
+{
+ const FunctionNode* func;
+ const TypedefNode* tdn;
+ QString str;
+
+ switch (type()) {
+ case Node::Namespace:
+ str = "namespace-" + fullDocumentName();
+ break;
+ case Node::Class:
+ str = "class-" + fullDocumentName();
+ break;
+ case Node::Enum:
+ str = "enum-" + name();
+ break;
+ case Node::Typedef:
+ tdn = static_cast<const TypedefNode*>(this);
+ if (tdn->associatedEnum()) {
+ return tdn->associatedEnum()->idForNode();
+ }
+ else {
+ str = "typedef-" + name();
+ }
+ break;
+ case Node::Function:
+ func = static_cast<const FunctionNode*>(this);
+ if (func->associatedProperty()) {
+ return func->associatedProperty()->idForNode();
+ }
+ else {
+ if (func->name().startsWith("operator")) {
+ str = "";
+ /*
+ The test below should probably apply to all
+ functions, but for now, overloaded operators
+ are the only ones that produce duplicate id
+ attributes in the DITA XML files.
+ */
+ if (relatesTo_)
+ str = "nonmember-";
+ QString op = func->name().mid(8);
+ if (!op.isEmpty()) {
+ int i = 0;
+ while (i<op.size() && op.at(i) == ' ')
+ ++i;
+ if (i>0 && i<op.size()) {
+ op = op.mid(i);
+ }
+ if (!op.isEmpty()) {
+ i = 0;
+ while (i < op.size()) {
+ const QChar c = op.at(i);
+ const uint u = c.unicode();
+ if ((u >= 'a' && u <= 'z') ||
+ (u >= 'A' && u <= 'Z') ||
+ (u >= '0' && u <= '9'))
+ break;
+ ++i;
+ }
+ str += "operator-";
+ if (i>0) {
+ QString tail = op.mid(i);
+ op = op.left(i);
+ if (operators_.contains(op)) {
+ str += operators_.value(op);
+ if (!tail.isEmpty())
+ str += "-" + tail;
+ }
+ else
+ qDebug() << "qdoc3 internal error: Operator missing from operators_ map:" << op;
+ }
+ else {
+ str += op;
+ }
+ }
+ }
+ }
+ else if (parent_) {
+ if (parent_->type() == Class)
+ str = "class-member-" + func->name();
+ else if (parent_->type() == Namespace)
+ str = "namespace-member-" + func->name();
+ else if (parent_->type() == Fake) {
+ if (parent_->subType() == QmlClass)
+ str = "qml-method-" + func->name();
+ else
+ qDebug() << "qdoc3 internal error: Node subtype not handled:"
+ << parent_->subType() << func->name();
+ }
+ else
+ qDebug() << "qdoc3 internal error: Node type not handled:"
+ << parent_->type() << func->name();
+
+ }
+ if (func->overloadNumber() != 1)
+ str += QLatin1Char('-') + QString::number(func->overloadNumber());
+ }
+ break;
+ case Node::Fake:
+ {
+ switch (subType()) {
+ case Node::QmlClass:
+ str = "qml-class-" + name();
+ break;
+ case Node::QmlPropertyGroup:
+ str = "qml-property-" + name();
+ break;
+ case Node::Page:
+ case Node::Group:
+ case Node::Module:
+ case Node::HeaderFile:
+ str = title();
+ if (str.isEmpty()) {
+ str = name();
+ if (str.endsWith(".html"))
+ str.remove(str.size()-5,5);
+ }
+ str.replace("/","-");
+ break;
+ case Node::File:
+ str = name();
+ str.replace("/","-");
+ break;
+ case Node::Example:
+ str = name();
+ str.replace("/","-");
+ break;
+ case Node::QmlBasicType:
+ str = "qml-basic-type-" + name();
+ break;
+ case Node::QmlModule:
+ str = "qml-module-" + name();
+ break;
+ case Node::Collision:
+ str = title();
+ str.replace(": ","-");
+ break;
+ default:
+ qDebug() << "ERROR: A case was not handled in Node::idForNode():"
+ << "subType():" << subType() << "type():" << type();
+ break;
+ }
+ }
+ break;
+ case Node::QmlProperty:
+ str = "qml-property-" + name();
+ break;
+ case Node::Property:
+ str = "property-" + name();
+ break;
+ case Node::QmlSignal:
+ str = "qml-signal-" + name();
+ break;
+ case Node::QmlSignalHandler:
+ str = "qml-signal-handler-" + name();
+ break;
+ case Node::QmlMethod:
+ str = "qml-method-" + name();
+ break;
+ case Node::Variable:
+ str = "var-" + name();
+ break;
+ case Node::Target:
+ str = name();
+ break;
+ default:
+ qDebug() << "ERROR: A case was not handled in Node::idForNode():"
+ << "type():" << type() << "subType():" << subType();
+ break;
+ }
+ if (str.isEmpty()) {
+ qDebug() << "ERROR: A link text was empty in Node::idForNode():"
+ << "type():" << type() << "subType():" << subType()
+ << "name():" << name()
+ << "title():" << title();
+ }
+ else {
+ str = cleanId(str);
+ }
+ return str;
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/node.h b/src/tools/qdoc/node.h
new file mode 100644
index 0000000000..440b22dc04
--- /dev/null
+++ b/src/tools/qdoc/node.h
@@ -0,0 +1,958 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ node.h
+*/
+
+#ifndef NODE_H
+#define NODE_H
+
+#include <qdir.h>
+#include <qmap.h>
+#include <qpair.h>
+#include <qstringlist.h>
+
+#include "codechunk.h"
+#include "doc.h"
+#include "location.h"
+#include "text.h"
+
+QT_BEGIN_NAMESPACE
+
+class Node;
+class ClassNode;
+class InnerNode;
+class ClassNode;
+class ExampleNode;
+class QmlClassNode;
+class Tree;
+
+typedef QMap<QString, const Node*> NodeMap;
+typedef QMultiMap<QString, Node*> NodeMultiMap;
+typedef QMultiMap<QString, const ExampleNode*> ExampleNodeMap;
+typedef QList<QPair<QString,QString> > ImportList;
+
+class Node
+{
+public:
+ enum Type {
+ Namespace,
+ Class,
+ Fake,
+ Enum,
+ Typedef,
+ Function,
+ Property,
+ Variable,
+ Target,
+ QmlProperty,
+ QmlSignal,
+ QmlSignalHandler,
+ QmlMethod,
+ LastType
+ };
+
+ enum SubType {
+ NoSubType,
+ Example,
+ HeaderFile,
+ File,
+ Image,
+ Group,
+ Module,
+ Page,
+ ExternalPage,
+ QmlClass,
+ QmlPropertyGroup,
+ QmlBasicType,
+ QmlModule,
+ DitaMap,
+ Collision,
+ LastSubtype
+ };
+
+ enum Access { Public, Protected, Private };
+
+ enum Status {
+ Compat,
+ Obsolete,
+ Deprecated,
+ Preliminary,
+ Commendable,
+ Main,
+ Internal
+ }; // don't reorder this enum
+
+ enum ThreadSafeness {
+ UnspecifiedSafeness,
+ NonReentrant,
+ Reentrant,
+ ThreadSafe
+ };
+
+ enum LinkType {
+ StartLink,
+ NextLink,
+ PreviousLink,
+ ContentsLink,
+ IndexLink,
+ InheritsLink /*,
+ GlossaryLink,
+ CopyrightLink,
+ ChapterLink,
+ SectionLink,
+ SubsectionLink,
+ AppendixLink */
+ };
+
+ enum PageType {
+ NoPageType,
+ ApiPage,
+ ArticlePage,
+ ExamplePage,
+ HowToPage,
+ OverviewPage,
+ TutorialPage,
+ FAQPage,
+ DitaMapPage,
+ OnBeyondZebra
+ };
+
+ virtual ~Node();
+
+ void setAccess(Access access) { access_ = access; }
+ void setLocation(const Location& location) { loc = location; }
+ void setDoc(const Doc& doc, bool replace = false);
+ void setStatus(Status status) { status_ = status; }
+ void setThreadSafeness(ThreadSafeness safeness) { safeness_ = safeness; }
+ void setSince(const QString &since);
+ void setRelates(InnerNode* pseudoParent);
+ void setModuleName(const QString &module) { mod = module; }
+ void setLink(LinkType linkType, const QString &link, const QString &desc);
+ void setUrl(const QString &url);
+ void setTemplateStuff(const QString &templateStuff) { templateStuff_ = templateStuff; }
+ void setPageType(PageType t) { pageType_ = t; }
+ void setPageType(const QString& t);
+ void setParent(InnerNode* n) { parent_ = n; }
+
+ virtual bool isInnerNode() const = 0;
+ virtual bool isReimp() const { return false; }
+ virtual bool isFunction() const { return false; }
+ virtual bool isQmlNode() const { return false; }
+ virtual bool isInternal() const { return false; }
+ virtual bool isQtQuickNode() const { return false; }
+ virtual bool isAbstract() const { return false; }
+ virtual void setAbstract(bool ) { }
+ virtual QString title() const { return QString(); }
+ Type type() const { return nodeType_; }
+ virtual SubType subType() const { return NoSubType; }
+ InnerNode* parent() const { return parent_; }
+ InnerNode* relates() const { return relatesTo_; }
+ const QString& name() const { return name_; }
+ QMap<LinkType, QPair<QString,QString> > links() const { return linkMap; }
+ QString moduleName() const;
+ QString url() const;
+ virtual QString nameForLists() const { return name_; }
+
+ Access access() const { return access_; }
+ QString accessString() const;
+ const Location& location() const { return loc; }
+ const Doc& doc() const { return d; }
+ Status status() const { return status_; }
+ Status inheritedStatus() const;
+ ThreadSafeness threadSafeness() const;
+ ThreadSafeness inheritedThreadSafeness() const;
+ QString since() const { return sinc; }
+ QString templateStuff() const { return templateStuff_; }
+ PageType pageType() const { return pageType_; }
+ QString pageTypeString() const;
+ QString nodeTypeString() const;
+ QString nodeSubtypeString() const;
+ virtual void addPageKeywords(const QString& ) { }
+
+ void clearRelated() { relatesTo_ = 0; }
+
+ virtual QString fileBase() const;
+ QString guid() const;
+ QString ditaXmlHref();
+ QString extractClassName(const QString &string) const;
+ virtual QString qmlModuleName() const { return qmlModuleName_; }
+ virtual QString qmlModuleVersion() const { return qmlModuleVersion_; }
+ virtual QString qmlModuleIdentifier() const { return qmlModuleName_ + qmlModuleVersion_; }
+ virtual void setQmlModuleName(const QString& );
+ virtual const ClassNode* classNode() const { return 0; }
+ virtual void clearCurrentChild() { }
+ virtual const ImportList* importList() const { return 0; }
+ virtual void setImportList(const ImportList& ) { }
+ virtual const Node* applyModuleIdentifier(const Node* ) const { return 0; }
+ const QmlClassNode* qmlClassNode() const;
+ const ClassNode* declarativeCppNode() const;
+ const QString& outputSubdirectory() const { return outSubDir_; }
+ QString fullDocumentName() const;
+ static QString cleanId(QString str);
+ QString idForNode() const;
+
+ static QString pageTypeString(unsigned t);
+ static QString nodeTypeString(unsigned t);
+ static QString nodeSubtypeString(unsigned t);
+
+protected:
+ Node(Type type, InnerNode* parent, const QString& name);
+
+private:
+
+#ifdef Q_WS_WIN
+ Type nodeType_;
+ Access access_;
+ ThreadSafeness safeness_;
+ PageType pageType_;
+ Status status_;
+#else
+ Type nodeType_ : 4;
+ Access access_ : 2;
+ ThreadSafeness safeness_ : 2;
+ PageType pageType_ : 4;
+ Status status_ : 3;
+#endif
+ InnerNode* parent_;
+ InnerNode* relatesTo_;
+ QString name_;
+ Location loc;
+ Doc d;
+ QMap<LinkType, QPair<QString, QString> > linkMap;
+ QString mod;
+ QString url_;
+ QString sinc;
+ QString templateStuff_;
+ mutable QString uuid;
+ QString outSubDir_;
+ QString qmlModuleName_;
+ QString qmlModuleVersion_;
+ static QStringMap operators_;
+};
+
+class FunctionNode;
+class EnumNode;
+class NameCollisionNode;
+
+typedef QList<Node*> NodeList;
+typedef QMap<QString, const Node*> NodeMap;
+typedef QMultiMap<QString, Node*> NodeMultiMap;
+
+class InnerNode : public Node
+{
+public:
+ virtual ~InnerNode();
+
+ Node* findNode(const QString& name);
+ Node* findNode(const QString& name, bool qml);
+ Node* findNode(const QString& name, Type type);
+ void findNodes(const QString& name, QList<Node*>& n);
+ FunctionNode* findFunctionNode(const QString& name);
+ FunctionNode* findFunctionNode(const FunctionNode* clone);
+ void addInclude(const QString &include);
+ void setIncludes(const QStringList &includes);
+ void setOverload(const FunctionNode* func, bool overlode);
+ void normalizeOverloads();
+ void makeUndocumentedChildrenInternal();
+ void clearCurrentChildPointers();
+ void deleteChildren();
+ void removeFromRelated();
+
+ virtual bool isInnerNode() const { return true; }
+ const Node* findNode(const QString& name) const;
+ const Node* findNode(const QString& name, bool qml) const;
+ const Node* findNode(const QString& name, Type type) const;
+ const FunctionNode* findFunctionNode(const QString& name) const;
+ const FunctionNode* findFunctionNode(const FunctionNode* clone) const;
+ const EnumNode* findEnumNodeForValue(const QString &enumValue) const;
+ const NodeList & childNodes() const { return children; }
+ const NodeList & relatedNodes() const { return related_; }
+ int count() const { return children.size(); }
+ int overloadNumber(const FunctionNode* func) const;
+ int numOverloads(const QString& funcName) const;
+ NodeList overloads(const QString &funcName) const;
+ const QStringList& includes() const { return inc; }
+
+ QStringList primaryKeys();
+ QStringList secondaryKeys();
+ const QStringList& pageKeywords() const { return pageKeywds; }
+ virtual void addPageKeywords(const QString& t) { pageKeywds << t; }
+ virtual void setCurrentChild() { }
+ virtual void setCurrentChild(InnerNode* ) { }
+
+protected:
+ InnerNode(Type type, InnerNode* parent, const QString& name);
+
+private:
+ friend class Node;
+ friend class NameCollisionNode;
+
+ static bool isSameSignature(const FunctionNode* f1, const FunctionNode* f2);
+ void addChild(Node* child);
+ void removeRelated(Node* pseudoChild);
+ void removeChild(Node* child);
+
+ QStringList pageKeywds;
+ QStringList inc;
+ NodeList children;
+ NodeList enumChildren;
+ NodeList related_;
+ QMap<QString, Node*> childMap;
+ QMap<QString, Node*> primaryFunctionMap;
+ QMap<QString, NodeList> secondaryFunctionMap;
+};
+
+class LeafNode : public Node
+{
+public:
+ LeafNode();
+ virtual ~LeafNode() { }
+
+ virtual bool isInnerNode() const;
+
+protected:
+ LeafNode(Type type, InnerNode* parent, const QString& name);
+ LeafNode(InnerNode* parent, Type type, const QString& name);
+};
+
+class NamespaceNode : public InnerNode
+{
+public:
+ NamespaceNode(InnerNode* parent, const QString& name);
+ virtual ~NamespaceNode() { }
+};
+
+class ClassNode;
+
+struct RelatedClass
+{
+ RelatedClass() { }
+ RelatedClass(Node::Access access0,
+ ClassNode* node0,
+ const QString& dataTypeWithTemplateArgs0 = "")
+ : access(access0),
+ node(node0),
+ dataTypeWithTemplateArgs(dataTypeWithTemplateArgs0) { }
+ QString accessString() const;
+
+ Node::Access access;
+ ClassNode* node;
+ QString dataTypeWithTemplateArgs;
+};
+
+class PropertyNode;
+
+class ClassNode : public InnerNode
+{
+public:
+ ClassNode(InnerNode* parent, const QString& name);
+ virtual ~ClassNode() { }
+
+ void addBaseClass(Access access,
+ ClassNode* node,
+ const QString &dataTypeWithTemplateArgs = "");
+ void fixBaseClasses();
+
+ const QList<RelatedClass> &baseClasses() const { return bases; }
+ const QList<RelatedClass> &derivedClasses() const { return derived; }
+ const QList<RelatedClass> &ignoredBaseClasses() const { return ignoredBases; }
+
+ bool hideFromMainList() const { return hidden; }
+ void setHideFromMainList(bool value) { hidden = value; }
+
+ QString serviceName() const { return sname; }
+ void setServiceName(const QString& value) { sname = value; }
+ const QmlClassNode* qmlElement() const { return qmlelement; }
+ void setQmlElement(QmlClassNode* qcn) { qmlelement = qcn; }
+ virtual bool isAbstract() const { return abstract; }
+ virtual void setAbstract(bool b) { abstract = b; }
+ const PropertyNode* findPropertyNode(const QString& name) const;
+ const QmlClassNode* findQmlBaseNode() const;
+
+private:
+ QList<RelatedClass> bases;
+ QList<RelatedClass> derived;
+ QList<RelatedClass> ignoredBases;
+ bool hidden;
+ bool abstract;
+ QString sname;
+ QmlClassNode* qmlelement;
+};
+
+class FakeNode : public InnerNode
+{
+public:
+
+ FakeNode(InnerNode* parent,
+ const QString& name,
+ SubType subType,
+ PageType ptype);
+ virtual ~FakeNode() { }
+
+ void setTitle(const QString &title) { title_ = title; }
+ void setSubTitle(const QString &subTitle) { subtitle_ = subTitle; }
+ void addGroupMember(Node* node) { nodeList.append(node); }
+ void addQmlModuleMember(Node* node) { nodeList.append(node); }
+
+ SubType subType() const { return nodeSubtype_; }
+ virtual QString title() const;
+ virtual QString fullTitle() const;
+ virtual QString subTitle() const;
+ virtual QString imageFileName() const { return QString(); }
+ const NodeList& groupMembers() const { return nodeList; }
+ const NodeList& qmlModuleMembers() const { return nodeList; }
+ virtual QString nameForLists() const { return title(); }
+ virtual void setImageFileName(const QString& ) { }
+
+protected:
+ SubType nodeSubtype_;
+ QString title_;
+ QString subtitle_;
+ NodeList nodeList; // used for groups and QML modules.
+};
+
+class NameCollisionNode : public FakeNode
+{
+public:
+ NameCollisionNode(InnerNode* child);
+ ~NameCollisionNode();
+ const InnerNode* currentChild() const { return current; }
+ virtual void setCurrentChild(InnerNode* child) { current = child; }
+ virtual void clearCurrentChild() { current = 0; }
+ virtual bool isQmlNode() const;
+ virtual const Node* applyModuleIdentifier(const Node* origin) const;
+ const InnerNode* findAny(Node::Type t, Node::SubType st) const;
+ void addCollision(InnerNode* child);
+ const QMap<QString,QString>& linkTargets() const { return targets; }
+ void addLinkTarget(const QString& t, const QString& v) { targets.insert(t,v); }
+
+private:
+ InnerNode* current;
+ QMap<QString,QString> targets;
+};
+
+class ExampleNode : public FakeNode
+{
+public:
+ ExampleNode(InnerNode* parent, const QString& name);
+ virtual ~ExampleNode() { }
+ virtual QString imageFileName() const { return imageFileName_; }
+ virtual void setImageFileName(const QString& ifn) { imageFileName_ = ifn; }
+
+ static void terminate() { exampleNodeMap.clear(); }
+
+public:
+ static ExampleNodeMap exampleNodeMap;
+
+private:
+ QString imageFileName_;
+};
+
+class QmlClassNode : public FakeNode
+{
+public:
+ QmlClassNode(InnerNode* parent,
+ const QString& name,
+ const ClassNode* cn);
+ virtual ~QmlClassNode();
+ virtual bool isQmlNode() const { return true; }
+ virtual bool isQtQuickNode() const { return (qmlModuleName() == QLatin1String("QtQuick")); }
+ virtual const ClassNode* classNode() const { return cnode_; }
+ virtual QString fileBase() const;
+ virtual void setCurrentChild();
+ virtual void clearCurrentChild();
+ virtual const ImportList* importList() const { return &importList_; }
+ virtual void setImportList(const ImportList& il) { importList_ = il; }
+ virtual bool isAbstract() const { return abstract; }
+ virtual void setAbstract(bool b) { abstract = b; }
+ const FakeNode* qmlBase() const { return base_; }
+ void resolveInheritance(const Tree* tree);
+ static void addInheritedBy(const QString& base, Node* sub);
+ static void subclasses(const QString& base, NodeList& subs);
+ static void terminate();
+
+public:
+ static bool qmlOnly;
+ static QMultiMap<QString,Node*> inheritedBy;
+ static QMap<QString, QmlClassNode*> moduleMap;
+
+private:
+ bool abstract;
+ const ClassNode* cnode_;
+ const FakeNode* base_;
+ ImportList importList_;
+};
+
+class QmlBasicTypeNode : public FakeNode
+{
+public:
+ QmlBasicTypeNode(InnerNode* parent,
+ const QString& name);
+ virtual ~QmlBasicTypeNode() { }
+ virtual bool isQmlNode() const { return true; }
+};
+
+class QmlPropGroupNode : public FakeNode
+{
+public:
+ QmlPropGroupNode(QmlClassNode* parent,
+ const QString& name,
+ bool attached);
+ virtual ~QmlPropGroupNode() { }
+ virtual bool isQmlNode() const { return true; }
+ virtual bool isQtQuickNode() const { return parent()->isQtQuickNode(); }
+ virtual QString qmlModuleName() const { return parent()->qmlModuleName(); }
+ virtual QString qmlModuleVersion() const { return parent()->qmlModuleVersion(); }
+ virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); }
+
+ const QString& element() const { return parent()->name(); }
+ void setDefault() { isdefault_ = true; }
+ void setReadOnly(int ro) { readOnly_ = ro; }
+ int getReadOnly() const { return readOnly_; }
+ bool isDefault() const { return isdefault_; }
+ bool isAttached() const { return attached_; }
+ bool isReadOnly() const { return (readOnly_ > 0); }
+
+private:
+ bool isdefault_;
+ bool attached_;
+ int readOnly_;
+};
+
+class QmlPropertyNode;
+
+class QmlPropertyNode : public LeafNode
+{
+public:
+ QmlPropertyNode(QmlClassNode *parent,
+ const QString& name,
+ const QString& type,
+ bool attached);
+ QmlPropertyNode(QmlPropGroupNode* parent,
+ const QString& name,
+ const QString& type,
+ bool attached);
+ QmlPropertyNode(QmlPropertyNode* parent,
+ const QString& name,
+ const QString& type,
+ bool attached);
+ virtual ~QmlPropertyNode() { }
+
+ void setDataType(const QString& dataType) { type_ = dataType; }
+ void setStored(bool stored) { sto = toTrool(stored); }
+ void setDesignable(bool designable) { des = toTrool(designable); }
+ void setWritable(bool writable) { wri = toTrool(writable); }
+
+ const QString &dataType() const { return type_; }
+ QString qualifiedDataType() const { return type_; }
+ void setDefault() { isdefault_ = true; }
+ void setReadOnly(int ro) { readOnly_ = ro; }
+ int getReadOnly() const { return readOnly_; }
+ bool isDefault() const { return isdefault_; }
+ bool isStored() const { return fromTrool(sto,true); }
+ bool isDesignable() const { return fromTrool(des,false); }
+ bool isWritable(const Tree* tree) const;
+ bool isAttached() const { return attached_; }
+ bool isReadOnly() const { return (readOnly_ > 0); }
+ virtual bool isQmlNode() const { return true; }
+ virtual bool isQtQuickNode() const { return parent()->isQtQuickNode(); }
+ virtual QString qmlModuleName() const { return parent()->qmlModuleName(); }
+ virtual QString qmlModuleVersion() const { return parent()->qmlModuleVersion(); }
+ virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); }
+
+ const PropertyNode *correspondingProperty(const Tree *tree) const;
+
+ const QString& element() const { return static_cast<QmlPropGroupNode*>(parent())->element(); }
+ void appendQmlPropNode(QmlPropertyNode* p) { qmlPropNodes_.append(p); }
+ const NodeList& qmlPropNodes() const { return qmlPropNodes_; }
+
+private:
+ enum Trool { Trool_True, Trool_False, Trool_Default };
+
+ static Trool toTrool(bool boolean);
+ static bool fromTrool(Trool troolean, bool defaultValue);
+
+ QString type_;
+ Trool sto;
+ Trool des;
+ Trool wri;
+ bool isdefault_;
+ bool attached_;
+ int readOnly_;
+ NodeList qmlPropNodes_;
+};
+
+class EnumItem
+{
+public:
+ EnumItem() { }
+ EnumItem(const QString& name, const QString& value)
+ : nam(name), val(value) { }
+ EnumItem(const QString& name, const QString& value, const Text &txt)
+ : nam(name), val(value), txt(txt) { }
+
+ const QString& name() const { return nam; }
+ const QString& value() const { return val; }
+ const Text &text() const { return txt; }
+
+private:
+ QString nam;
+ QString val;
+ Text txt;
+};
+
+class TypedefNode;
+
+class EnumNode : public LeafNode
+{
+public:
+ EnumNode(InnerNode* parent, const QString& name);
+ virtual ~EnumNode() { }
+
+ void addItem(const EnumItem& item);
+ void setFlagsType(TypedefNode* typedeff);
+ bool hasItem(const QString &name) const { return names.contains(name); }
+
+ const QList<EnumItem>& items() const { return itms; }
+ Access itemAccess(const QString& name) const;
+ const TypedefNode* flagsType() const { return ft; }
+ QString itemValue(const QString &name) const;
+
+private:
+ QList<EnumItem> itms;
+ QSet<QString> names;
+ const TypedefNode* ft;
+};
+
+class TypedefNode : public LeafNode
+{
+public:
+ TypedefNode(InnerNode* parent, const QString& name);
+ virtual ~TypedefNode() { }
+
+ const EnumNode* associatedEnum() const { return ae; }
+
+private:
+ void setAssociatedEnum(const EnumNode* enume);
+
+ friend class EnumNode;
+
+ const EnumNode* ae;
+};
+
+inline void EnumNode::setFlagsType(TypedefNode* typedeff)
+{
+ ft = typedeff;
+ typedeff->setAssociatedEnum(this);
+}
+
+
+class Parameter
+{
+public:
+ Parameter() {}
+ Parameter(const QString& leftType,
+ const QString& rightType = "",
+ const QString& name = "",
+ const QString& defaultValue = "");
+ Parameter(const Parameter& p);
+
+ Parameter& operator=(const Parameter& p);
+
+ void setName(const QString& name) { nam = name; }
+
+ bool hasType() const { return lef.length() + rig.length() > 0; }
+ const QString& leftType() const { return lef; }
+ const QString& rightType() const { return rig; }
+ const QString& name() const { return nam; }
+ const QString& defaultValue() const { return def; }
+
+ QString reconstruct(bool value = false) const;
+
+private:
+ QString lef;
+ QString rig;
+ QString nam;
+ QString def;
+};
+
+class PropertyNode;
+
+class FunctionNode : public LeafNode
+{
+public:
+ enum Metaness {
+ Plain,
+ Signal,
+ Slot,
+ Ctor,
+ Dtor,
+ MacroWithParams,
+ MacroWithoutParams,
+ Native };
+ enum Virtualness { NonVirtual, ImpureVirtual, PureVirtual };
+
+ FunctionNode(InnerNode* parent, const QString &name);
+ FunctionNode(Type type, InnerNode* parent, const QString &name, bool attached);
+ virtual ~FunctionNode() { }
+
+ void setReturnType(const QString& returnType) { rt = returnType; }
+ void setParentPath(const QStringList& parentPath) { pp = parentPath; }
+ void setMetaness(Metaness metaness) { met = metaness; }
+ void setVirtualness(Virtualness virtualness);
+ void setConst(bool conste) { con = conste; }
+ void setStatic(bool statique) { sta = statique; }
+ void setOverload(bool overlode);
+ void setReimp(bool r);
+ void addParameter(const Parameter& parameter);
+ inline void setParameters(const QList<Parameter>& parameters);
+ void borrowParameterNames(const FunctionNode* source);
+ void setReimplementedFrom(FunctionNode* from);
+
+ const QString& returnType() const { return rt; }
+ Metaness metaness() const { return met; }
+ bool isMacro() const {
+ return met == MacroWithParams || met == MacroWithoutParams;
+ }
+ Virtualness virtualness() const { return vir; }
+ bool isConst() const { return con; }
+ bool isStatic() const { return sta; }
+ bool isOverload() const { return ove; }
+ bool isReimp() const { return reimp; }
+ bool isFunction() const { return true; }
+ int overloadNumber() const;
+ int numOverloads() const;
+ const QList<Parameter>& parameters() const { return params; }
+ QStringList parameterNames() const;
+ QString rawParameters(bool names = false, bool values = false) const;
+ const FunctionNode* reimplementedFrom() const { return rf; }
+ const QList<FunctionNode*> &reimplementedBy() const { return rb; }
+ const PropertyNode* associatedProperty() const { return ap; }
+ const QStringList& parentPath() const { return pp; }
+
+ QStringList reconstructParams(bool values = false) const;
+ QString signature(bool values = false) const;
+ const QString& element() const { return parent()->name(); }
+ bool isAttached() const { return attached_; }
+ virtual bool isInternal() const;
+ virtual bool isQmlNode() const {
+ return ((type() == QmlSignal) ||
+ (type() == QmlMethod) ||
+ (type() == QmlSignalHandler));
+ }
+ virtual bool isQtQuickNode() const { return parent()->isQtQuickNode(); }
+ virtual QString qmlModuleName() const { return parent()->qmlModuleName(); }
+ virtual QString qmlModuleVersion() const { return parent()->qmlModuleVersion(); }
+ virtual QString qmlModuleIdentifier() const { return parent()->qmlModuleIdentifier(); }
+
+ void debug() const;
+
+private:
+ void setAssociatedProperty(PropertyNode* property);
+
+ friend class InnerNode;
+ friend class PropertyNode;
+
+ QString rt;
+ QStringList pp;
+#ifdef Q_WS_WIN
+ Metaness met;
+ Virtualness vir;
+#else
+ Metaness met : 4;
+ Virtualness vir : 2;
+#endif
+ bool con : 1;
+ bool sta : 1;
+ bool ove : 1;
+ bool reimp: 1;
+ bool attached_: 1;
+ QList<Parameter> params;
+ const FunctionNode* rf;
+ const PropertyNode* ap;
+ QList<FunctionNode*> rb;
+};
+
+class PropertyNode : public LeafNode
+{
+public:
+ enum FunctionRole { Getter, Setter, Resetter, Notifier };
+ enum { NumFunctionRoles = Notifier + 1 };
+
+ PropertyNode(InnerNode* parent, const QString& name);
+ virtual ~PropertyNode() { }
+
+ void setDataType(const QString& dataType) { type_ = dataType; }
+ void addFunction(FunctionNode* function, FunctionRole role);
+ void addSignal(FunctionNode* function, FunctionRole role);
+ void setStored(bool stored) { sto = toTrool(stored); }
+ void setDesignable(bool designable) { des = toTrool(designable); }
+ void setScriptable(bool scriptable) { scr = toTrool(scriptable); }
+ void setWritable(bool writable) { wri = toTrool(writable); }
+ void setUser(bool user) { usr = toTrool(user); }
+ void setOverriddenFrom(const PropertyNode* baseProperty);
+ void setRuntimeDesFunc(const QString& rdf) { runtimeDesFunc = rdf; }
+ void setRuntimeScrFunc(const QString& scrf) { runtimeScrFunc = scrf; }
+ void setConstant() { cst = true; }
+ void setFinal() { fnl = true; }
+ void setRevision(int revision) { rev = revision; }
+
+ const QString &dataType() const { return type_; }
+ QString qualifiedDataType() const;
+ NodeList functions() const;
+ NodeList functions(FunctionRole role) const { return funcs[(int)role]; }
+ NodeList getters() const { return functions(Getter); }
+ NodeList setters() const { return functions(Setter); }
+ NodeList resetters() const { return functions(Resetter); }
+ NodeList notifiers() const { return functions(Notifier); }
+ bool isStored() const { return fromTrool(sto, storedDefault()); }
+ bool isDesignable() const { return fromTrool(des, designableDefault()); }
+ bool isScriptable() const { return fromTrool(scr, scriptableDefault()); }
+ const QString& runtimeDesignabilityFunction() const { return runtimeDesFunc; }
+ const QString& runtimeScriptabilityFunction() const { return runtimeScrFunc; }
+ bool isWritable() const { return fromTrool(wri, writableDefault()); }
+ bool isUser() const { return fromTrool(usr, userDefault()); }
+ bool isConstant() const { return cst; }
+ bool isFinal() const { return fnl; }
+ const PropertyNode* overriddenFrom() const { return overrides; }
+
+ bool storedDefault() const { return true; }
+ bool userDefault() const { return false; }
+ bool designableDefault() const { return !setters().isEmpty(); }
+ bool scriptableDefault() const { return true; }
+ bool writableDefault() const { return !setters().isEmpty(); }
+
+private:
+ enum Trool { Trool_True, Trool_False, Trool_Default };
+
+ static Trool toTrool(bool boolean);
+ static bool fromTrool(Trool troolean, bool defaultValue);
+
+ QString type_;
+ QString runtimeDesFunc;
+ QString runtimeScrFunc;
+ NodeList funcs[NumFunctionRoles];
+ Trool sto;
+ Trool des;
+ Trool scr;
+ Trool wri;
+ Trool usr;
+ bool cst;
+ bool fnl;
+ int rev;
+ const PropertyNode* overrides;
+};
+
+inline void FunctionNode::setParameters(const QList<Parameter> &parameters)
+{
+ params = parameters;
+}
+
+inline void PropertyNode::addFunction(FunctionNode* function, FunctionRole role)
+{
+ funcs[(int)role].append(function);
+ function->setAssociatedProperty(this);
+}
+
+inline void PropertyNode::addSignal(FunctionNode* function, FunctionRole role)
+{
+ funcs[(int)role].append(function);
+}
+
+inline NodeList PropertyNode::functions() const
+{
+ NodeList list;
+ for (int i = 0; i < NumFunctionRoles; ++i)
+ list += funcs[i];
+ return list;
+}
+
+class VariableNode : public LeafNode
+{
+public:
+ VariableNode(InnerNode* parent, const QString &name);
+ virtual ~VariableNode() { }
+
+ void setLeftType(const QString &leftType) { lt = leftType; }
+ void setRightType(const QString &rightType) { rt = rightType; }
+ void setStatic(bool statique) { sta = statique; }
+
+ const QString &leftType() const { return lt; }
+ const QString &rightType() const { return rt; }
+ QString dataType() const { return lt + rt; }
+ bool isStatic() const { return sta; }
+
+private:
+ QString lt;
+ QString rt;
+ bool sta;
+};
+
+inline VariableNode::VariableNode(InnerNode* parent, const QString &name)
+ : LeafNode(Variable, parent, name), sta(false)
+{
+ // nothing.
+}
+
+class TargetNode : public LeafNode
+{
+public:
+ TargetNode(InnerNode* parent, const QString& name);
+ virtual ~TargetNode() { }
+
+ virtual bool isInnerNode() const;
+};
+
+class DitaMapNode : public FakeNode
+{
+public:
+ DitaMapNode(InnerNode* parent, const QString& name)
+ : FakeNode(parent, name, Node::Page, Node::DitaMapPage) { }
+ virtual ~DitaMapNode() { }
+
+ const DitaRefList& map() const { return doc().ditamap(); }
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/openedlist.cpp b/src/tools/qdoc/openedlist.cpp
new file mode 100644
index 0000000000..9fa93f0d28
--- /dev/null
+++ b/src/tools/qdoc/openedlist.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ openedlist.cpp
+*/
+
+#include <qregexp.h>
+
+#include "atom.h"
+#include "openedlist.h"
+
+QT_BEGIN_NAMESPACE
+
+static const char roman[] = "m\2d\5c\2l\5x\2v\5i";
+
+OpenedList::OpenedList( Style style )
+ : sty( style ), ini( 1 ), nex( 0 )
+{
+}
+
+OpenedList::OpenedList( const Location& location, const QString& hint )
+ : sty( Bullet ), ini( 1 )
+{
+ QRegExp hintSyntax( "(\\W*)([0-9]+|[A-Z]+|[a-z]+)(\\W*)" );
+
+ if ( hintSyntax.exactMatch(hint) ) {
+ bool ok;
+ int asNumeric = hint.toInt( &ok );
+ int asRoman = fromRoman( hintSyntax.cap(2) );
+ int asAlpha = fromAlpha( hintSyntax.cap(2) );
+
+ if ( ok ) {
+ sty = Numeric;
+ ini = asNumeric;
+ } else if ( asRoman > 0 && asRoman != 100 && asRoman != 500 ) {
+ sty = ( hint == hint.toLower() ) ? LowerRoman : UpperRoman;
+ ini = asRoman;
+ } else {
+ sty = ( hint == hint.toLower() ) ? LowerAlpha : UpperAlpha;
+ ini = asAlpha;
+ }
+ pref = hintSyntax.cap( 1 );
+ suff = hintSyntax.cap( 3 );
+ } else if ( !hint.isEmpty() ) {
+ location.warning( tr("Unrecognized list style '%1'").arg(hint) );
+ }
+ nex = ini - 1;
+}
+
+QString OpenedList::styleString() const
+{
+ switch ( style() ) {
+ case Bullet:
+ default:
+ return ATOM_LIST_BULLET;
+ case Tag:
+ return ATOM_LIST_TAG;
+ case Value:
+ return ATOM_LIST_VALUE;
+ case Numeric:
+ return ATOM_LIST_NUMERIC;
+ case UpperAlpha:
+ return ATOM_LIST_UPPERALPHA;
+ case LowerAlpha:
+ return ATOM_LIST_LOWERALPHA;
+ case UpperRoman:
+ return ATOM_LIST_UPPERROMAN;
+ case LowerRoman:
+ return ATOM_LIST_LOWERROMAN;
+ }
+}
+
+QString OpenedList::numberString() const
+{
+ return QString::number( number() );
+ /*
+ switch ( style() ) {
+ case Numeric:
+ return QString::number( number() );
+ case UpperAlpha:
+ return toAlpha( number() ).toUpper();
+ case LowerAlpha:
+ return toAlpha( number() );
+ case UpperRoman:
+ return toRoman( number() ).toUpper();
+ case LowerRoman:
+ return toRoman( number() );
+ case Bullet:
+ default:
+ return "*";
+ }*/
+}
+
+QString OpenedList::toAlpha( int n )
+{
+ QString str;
+
+ while ( n > 0 ) {
+ n--;
+ str.prepend( (n % 26) + 'a' );
+ n /= 26;
+ }
+ return str;
+}
+
+int OpenedList::fromAlpha( const QString& str )
+{
+ int n = 0;
+ int u;
+
+ for ( int i = 0; i < (int) str.length(); i++ ) {
+ u = str[i].toLower().unicode();
+ if ( u >= 'a' && u <= 'z' ) {
+ n *= 26;
+ n += u - 'a' + 1;
+ } else {
+ return 0;
+ }
+ }
+ return n;
+}
+
+QString OpenedList::toRoman( int n )
+{
+ /*
+ See p. 30 of Donald E. Knuth's "TeX: The Program".
+ */
+ QString str;
+ int j = 0;
+ int k;
+ int u;
+ int v = 1000;
+
+ for ( ;; ) {
+ while ( n >= v ) {
+ str += roman[j];
+ n -= v;
+ }
+
+ if ( n <= 0 )
+ break;
+
+ k = j + 2;
+ u = v / roman[k - 1];
+ if ( roman[k - 1] == 2 ) {
+ k += 2;
+ u /= 5;
+ }
+ if ( n + u >= v ) {
+ str += roman[k];
+ n += u;
+ } else {
+ j += 2;
+ v /= roman[j - 1];
+ }
+ }
+ return str;
+}
+
+int OpenedList::fromRoman( const QString& str )
+{
+ int n = 0;
+ int j;
+ int u;
+ int v = 0;
+
+ for ( int i = str.length() - 1; i >= 0; i-- ) {
+ j = 0;
+ u = 1000;
+ while ( roman[j] != 'i' && roman[j] != str[i].toLower() ) {
+ j += 2;
+ u /= roman[j - 1];
+ }
+ if ( u < v ) {
+ n -= u;
+ } else {
+ n += u;
+ }
+ v = u;
+ }
+
+ if ( str.toLower() == toRoman(n) ) {
+ return n;
+ } else {
+ return 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/openedlist.h b/src/tools/qdoc/openedlist.h
new file mode 100644
index 0000000000..7150ca60c7
--- /dev/null
+++ b/src/tools/qdoc/openedlist.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ openedlist.h
+*/
+
+#ifndef OPENEDLIST_H
+#define OPENEDLIST_H
+
+#include <qstring.h>
+
+#include "location.h"
+
+QT_BEGIN_NAMESPACE
+
+class OpenedList
+{
+public:
+ enum Style { Bullet, Tag, Value, Numeric, UpperAlpha, LowerAlpha,
+ UpperRoman, LowerRoman };
+
+ OpenedList()
+ : sty( Bullet ), ini( 1 ), nex( 0 ) { }
+ OpenedList( Style style );
+ OpenedList( const Location& location, const QString& hint );
+
+ void next() { nex++; }
+
+ bool isStarted() const { return nex >= ini; }
+ Style style() const { return sty; }
+ QString styleString() const;
+ int number() const { return nex; }
+ QString numberString() const;
+ QString prefix() const { return pref; }
+ QString suffix() const { return suff; }
+
+private:
+ static QString toAlpha( int n );
+ static int fromAlpha( const QString& str );
+ static QString toRoman( int n );
+ static int fromRoman( const QString& str );
+
+ Style sty;
+ int ini;
+ int nex;
+ QString pref;
+ QString suff;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/pagegenerator.cpp b/src/tools/qdoc/pagegenerator.cpp
new file mode 100644
index 0000000000..d8c3babe2e
--- /dev/null
+++ b/src/tools/qdoc/pagegenerator.cpp
@@ -0,0 +1,388 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ pagegenerator.cpp
+*/
+
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qdebug.h>
+#include "codemarker.h"
+#include "pagegenerator.h"
+#include "tree.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Nothing to do in the constructor.
+ */
+PageGenerator::PageGenerator()
+ : outputCodec(0)
+{
+ // nothing.
+}
+
+/*!
+ The destructor
+ */
+PageGenerator::~PageGenerator()
+{
+ while (!outStreamStack.isEmpty())
+ endSubPage();
+}
+
+bool PageGenerator::parseArg(const QString& src,
+ const QString& tag,
+ int* pos,
+ int n,
+ QStringRef* contents,
+ QStringRef* par1,
+ bool debug)
+{
+#define SKIP_CHAR(c) \
+ if (debug) \
+ qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \
+ if (i >= n || src[i] != c) { \
+ if (debug) \
+ qDebug() << " char '" << c << "' not found"; \
+ return false; \
+} \
+ ++i;
+
+
+#define SKIP_SPACE \
+ while (i < n && src[i] == ' ') \
+ ++i;
+
+ int i = *pos;
+ int j = i;
+
+ // assume "<@" has been parsed outside
+ //SKIP_CHAR('<');
+ //SKIP_CHAR('@');
+
+ if (tag != QStringRef(&src, i, tag.length())) {
+ if (0 && debug)
+ qDebug() << "tag " << tag << " not found at " << i;
+ return false;
+ }
+
+ if (debug)
+ qDebug() << "haystack:" << src << "needle:" << tag << "i:" <<i;
+
+ // skip tag
+ i += tag.length();
+
+ // parse stuff like: linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)");
+ if (par1) {
+ SKIP_SPACE;
+ // read parameter name
+ j = i;
+ while (i < n && src[i].isLetter())
+ ++i;
+ if (src[i] == '=') {
+ if (debug)
+ qDebug() << "read parameter" << QString(src.data() + j, i - j);
+ SKIP_CHAR('=');
+ SKIP_CHAR('"');
+ // skip parameter name
+ j = i;
+ while (i < n && src[i] != '"')
+ ++i;
+ *par1 = QStringRef(&src, j, i - j);
+ SKIP_CHAR('"');
+ SKIP_SPACE;
+ } else {
+ if (debug)
+ qDebug() << "no optional parameter found";
+ }
+ }
+ SKIP_SPACE;
+ SKIP_CHAR('>');
+
+ // find contents up to closing "</@tag>
+ j = i;
+ for (; true; ++i) {
+ if (i + 4 + tag.length() > n)
+ return false;
+ if (src[i] != '<')
+ continue;
+ if (src[i + 1] != '/')
+ continue;
+ if (src[i + 2] != '@')
+ continue;
+ if (tag != QStringRef(&src, i + 3, tag.length()))
+ continue;
+ if (src[i + 3 + tag.length()] != '>')
+ continue;
+ break;
+ }
+
+ *contents = QStringRef(&src, j, i - j);
+
+ i += tag.length() + 4;
+
+ *pos = i;
+ if (debug)
+ qDebug() << " tag " << tag << " found: pos now: " << i;
+ return true;
+#undef SKIP_CHAR
+}
+
+/*!
+ This function is recursive.
+ */
+void PageGenerator::generateTree(const Tree *tree)
+{
+ generateInnerNode(tree->root());
+}
+
+QString PageGenerator::fileBase(const Node *node) const
+{
+ if (node->relates())
+ node = node->relates();
+ else if (!node->isInnerNode())
+ node = node->parent();
+ if (node->subType() == Node::QmlPropertyGroup) {
+ node = node->parent();
+ }
+
+ QString base = node->doc().baseName();
+ if (!base.isEmpty())
+ return base;
+
+ const Node *p = node;
+
+ forever {
+ const Node *pp = p->parent();
+ base.prepend(p->name());
+ if (!p->qmlModuleIdentifier().isEmpty())
+ base.prepend(p->qmlModuleIdentifier()+QChar('-'));
+ /*
+ To avoid file name conflicts in the html directory,
+ we prepend a prefix (by default, "qml-") to the file name of QML
+ element doc files.
+ */
+ if ((p->subType() == Node::QmlClass) ||
+ (p->subType() == Node::QmlBasicType)) {
+ base.prepend(outputPrefix(QLatin1String("QML")));
+ }
+ if (!pp || pp->name().isEmpty() || pp->type() == Node::Fake)
+ break;
+ base.prepend(QLatin1Char('-'));
+ p = pp;
+ }
+ if (node->type() == Node::Fake) {
+ if (node->subType() == Node::Collision) {
+ const NameCollisionNode* ncn = static_cast<const NameCollisionNode*>(node);
+ if (ncn->currentChild())
+ return fileBase(ncn->currentChild());
+ base.prepend("collision-");
+ }
+#ifdef QDOC2_COMPAT
+ if (base.endsWith(".html"))
+ base.truncate(base.length() - 5);
+#endif
+ }
+
+ // the code below is effectively equivalent to:
+ // base.replace(QRegExp("[^A-Za-z0-9]+"), " ");
+ // base = base.trimmed();
+ // base.replace(QLatin1Char(' '), QLatin1Char('-'));
+ // base = base.toLower();
+ // as this function accounted for ~8% of total running time
+ // we optimize a bit...
+
+ QString res;
+ // +5 prevents realloc in fileName() below
+ res.reserve(base.size() + 5);
+ bool begun = false;
+ for (int i = 0; i != base.size(); ++i) {
+ QChar c = base.at(i);
+ uint u = c.unicode();
+ if (u >= 'A' && u <= 'Z')
+ u -= 'A' - 'a';
+ if ((u >= 'a' && u <= 'z') || (u >= '0' && u <= '9')) {
+ res += QLatin1Char(u);
+ begun = true;
+ }
+ else if (begun) {
+ res += QLatin1Char('-');
+ begun = false;
+ }
+ }
+ while (res.endsWith(QLatin1Char('-')))
+ res.chop(1);
+ return res;
+}
+
+/*!
+ If the \a node has a URL, return the URL as the file name.
+ Otherwise, construct the file name from the fileBase() and
+ the fileExtension(), and return the constructed name.
+ */
+QString PageGenerator::fileName(const Node* node) const
+{
+ if (!node->url().isEmpty())
+ return node->url();
+
+ QString name = fileBase(node);
+ name += QLatin1Char('.');
+ name += fileExtension(node);
+ return name;
+}
+
+/*!
+ Return the current output file name.
+ */
+QString PageGenerator::outFileName()
+{
+ return QFileInfo(static_cast<QFile*>(out().device())->fileName()).fileName();
+}
+
+/*!
+ Creates the file named \a fileName in the output directory.
+ Attaches a QTextStream to the created file, which is written
+ to all over the place using out().
+ */
+void PageGenerator::beginSubPage(const InnerNode* node, const QString& fileName)
+{
+ QString path = outputDir() + QLatin1Char('/');
+ if (!node->outputSubdirectory().isEmpty())
+ path += node->outputSubdirectory() + QLatin1Char('/');
+ path += fileName;
+ QFile* outFile = new QFile(path);
+ if (!outFile->open(QFile::WriteOnly))
+ node->location().fatal(tr("Cannot open output file '%1'").arg(outFile->fileName()));
+ QTextStream* out = new QTextStream(outFile);
+
+ if (outputCodec)
+ out->setCodec(outputCodec);
+ outStreamStack.push(out);
+}
+
+/*!
+ Flush the text stream associated with the subpage, and
+ then pop it off the text stream stack and delete it.
+ This terminates output of the subpage.
+ */
+void PageGenerator::endSubPage()
+{
+ outStreamStack.top()->flush();
+ delete outStreamStack.top()->device();
+ delete outStreamStack.pop();
+}
+
+/*!
+ Used for writing to the current output stream. Returns a
+ reference to the crrent output stream, which is then used
+ with the \c {<<} operator for writing.
+ */
+QTextStream &PageGenerator::out()
+{
+ return *outStreamStack.top();
+}
+
+/*!
+ Recursive writing of HTML files from the root \a node.
+
+ \note NameCollisionNodes are skipped here and processed
+ later. See HtmlGenerator::generateDisambiguationPages()
+ for more on this.
+ */
+void
+PageGenerator::generateInnerNode(const InnerNode* node)
+{
+ if (!node->url().isNull())
+ return;
+
+ if (node->type() == Node::Fake) {
+ const FakeNode *fakeNode = static_cast<const FakeNode *>(node);
+ if (fakeNode->subType() == Node::ExternalPage)
+ return;
+ if (fakeNode->subType() == Node::Image)
+ return;
+ if (fakeNode->subType() == Node::QmlPropertyGroup)
+ return;
+ if (fakeNode->subType() == Node::Page) {
+ if (node->count() > 0)
+ qDebug("PAGE %s HAS CHILDREN", qPrintable(fakeNode->title()));
+ }
+ }
+
+ /*
+ Obtain a code marker for the source file.
+ */
+ CodeMarker *marker = CodeMarker::markerForFileName(node->location().filePath());
+
+ if (node->parent() != 0) {
+ /*
+ Skip name collision nodes here and process them
+ later in generateDisambiguationPages(). Each one
+ is appended to a list for later.
+ */
+ if ((node->type() == Node::Fake) && (node->subType() == Node::Collision)) {
+ const NameCollisionNode* ncn = static_cast<const NameCollisionNode*>(node);
+ collisionNodes.append(const_cast<NameCollisionNode*>(ncn));
+ }
+ else {
+ beginSubPage(node, fileName(node));
+ if (node->type() == Node::Namespace || node->type() == Node::Class) {
+ generateClassLikeNode(node, marker);
+ }
+ else if (node->type() == Node::Fake) {
+ generateFakeNode(static_cast<const FakeNode *>(node), marker);
+ }
+ endSubPage();
+ }
+ }
+
+ NodeList::ConstIterator c = node->childNodes().begin();
+ while (c != node->childNodes().end()) {
+ if ((*c)->isInnerNode() && (*c)->access() != Node::Private) {
+ generateInnerNode((const InnerNode *) *c);
+ }
+ ++c;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/pagegenerator.h b/src/tools/qdoc/pagegenerator.h
new file mode 100644
index 0000000000..da0d32d2ff
--- /dev/null
+++ b/src/tools/qdoc/pagegenerator.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ pagegenerator.h
+*/
+
+#ifndef PAGEGENERATOR_H
+#define PAGEGENERATOR_H
+
+#include <QStack>
+#include <qtextstream.h>
+#include "generator.h"
+#include "location.h"
+
+QT_BEGIN_NAMESPACE
+
+class QTextCodec;
+class ClassNode;
+class InnerNode;
+class NamespaceNode;
+class NameCollisionNode;
+
+class PageGenerator : public Generator
+{
+public:
+ PageGenerator();
+ ~PageGenerator();
+
+ virtual void generateTree(const Tree *tree);
+ virtual void generateDisambiguationPages() { }
+
+protected:
+ virtual QString fileBase(const Node* node) const;
+ virtual QString fileExtension(const Node* node) const = 0;
+ QString fileName(const Node* node) const;
+ QString outFileName();
+ virtual void beginSubPage(const InnerNode* node, const QString& fileName);
+ virtual void endSubPage();
+ virtual void generateInnerNode(const InnerNode *node);
+ QTextStream& out();
+
+ QString naturalLanguage;
+ QString outputEncoding;
+ QTextCodec* outputCodec;
+ bool parseArg(const QString& src,
+ const QString& tag,
+ int* pos,
+ int n,
+ QStringRef* contents,
+ QStringRef* par1 = 0,
+ bool debug = false);
+
+protected:
+ QStack<QTextStream*> outStreamStack;
+ QList<NameCollisionNode*> collisionNodes;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/plaincodemarker.cpp b/src/tools/qdoc/plaincodemarker.cpp
new file mode 100644
index 0000000000..a8b2277056
--- /dev/null
+++ b/src/tools/qdoc/plaincodemarker.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "plaincodemarker.h"
+
+QT_BEGIN_NAMESPACE
+
+PlainCodeMarker::PlainCodeMarker()
+{
+}
+
+PlainCodeMarker::~PlainCodeMarker()
+{
+}
+
+bool PlainCodeMarker::recognizeCode( const QString& /* code */ )
+{
+ return true;
+}
+
+bool PlainCodeMarker::recognizeExtension( const QString& /* ext */ )
+{
+ return true;
+}
+
+bool PlainCodeMarker::recognizeLanguage( const QString& /* lang */ )
+{
+ return false;
+}
+
+Atom::Type PlainCodeMarker::atomType() const
+{
+ return Atom::Code;
+}
+
+QString PlainCodeMarker::plainName( const Node * /* node */ )
+{
+ return "";
+}
+
+QString PlainCodeMarker::plainFullName(const Node * /* node */, const Node * /* relative */)
+{
+ return "";
+}
+
+QString PlainCodeMarker::markedUpCode( const QString& code,
+ const Node * /* relative */,
+ const Location & /* location */ )
+{
+ return protect( code );
+}
+
+QString PlainCodeMarker::markedUpSynopsis( const Node * /* node */,
+ const Node * /* relative */,
+ SynopsisStyle /* style */ )
+{
+ return "foo";
+}
+
+QString PlainCodeMarker::markedUpName( const Node * /* node */ )
+{
+ return "";
+}
+
+QString PlainCodeMarker::markedUpFullName( const Node * /* node */,
+ const Node * /* relative */ )
+{
+ return "";
+}
+
+QString PlainCodeMarker::markedUpEnumValue(const QString & /* enumValue */,
+ const Node * /* relative */)
+{
+ return "";
+}
+
+QString PlainCodeMarker::markedUpIncludes( const QStringList& /* includes */ )
+{
+ return "";
+}
+
+QString PlainCodeMarker::functionBeginRegExp( const QString& /* funcName */ )
+{
+ return "";
+}
+
+QString PlainCodeMarker::functionEndRegExp( const QString& /* funcName */ )
+{
+ return "";
+}
+
+QList<Section> PlainCodeMarker::sections(const InnerNode * /* innerNode */,
+ SynopsisStyle /* style */,
+ Status /* status */)
+{
+ return QList<Section>();
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/plaincodemarker.h b/src/tools/qdoc/plaincodemarker.h
new file mode 100644
index 0000000000..0a46e2d4d4
--- /dev/null
+++ b/src/tools/qdoc/plaincodemarker.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ plaincodemarker.h
+*/
+
+#ifndef PLAINCODEMARKER_H
+#define PLAINCODEMARKER_H
+
+#include "codemarker.h"
+
+QT_BEGIN_NAMESPACE
+
+class PlainCodeMarker : public CodeMarker
+{
+public:
+ PlainCodeMarker();
+ ~PlainCodeMarker();
+
+ bool recognizeCode( const QString& code );
+ bool recognizeExtension( const QString& ext );
+ bool recognizeLanguage( const QString& lang );
+ Atom::Type atomType() const;
+ QString plainName( const Node *node );
+ QString plainFullName( const Node *node, const Node *relative );
+ QString markedUpCode( const QString& code, const Node *relative, const Location &location );
+ QString markedUpSynopsis( const Node *node, const Node *relative,
+ SynopsisStyle style );
+ QString markedUpName( const Node *node );
+ QString markedUpFullName( const Node *node, const Node *relative );
+ QString markedUpEnumValue(const QString &enumValue, const Node *relative);
+ QString markedUpIncludes( const QStringList& includes );
+ QString functionBeginRegExp( const QString& funcName );
+ QString functionEndRegExp( const QString& funcName );
+ QList<Section> sections(const InnerNode *innerNode, SynopsisStyle style, Status status);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/puredocparser.cpp b/src/tools/qdoc/puredocparser.cpp
new file mode 100644
index 0000000000..2303591974
--- /dev/null
+++ b/src/tools/qdoc/puredocparser.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ puredocparser.cpp
+*/
+
+#include "puredocparser.h"
+
+QT_BEGIN_NAMESPACE
+
+PureDocParser::PureDocParser()
+{
+}
+
+PureDocParser::~PureDocParser()
+{
+}
+
+QStringList PureDocParser::sourceFileNameFilter()
+{
+ return QStringList("*.qdoc");
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/puredocparser.h b/src/tools/qdoc/puredocparser.h
new file mode 100644
index 0000000000..80efadf6a4
--- /dev/null
+++ b/src/tools/qdoc/puredocparser.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ puredocparser.h
+*/
+
+#ifndef PUREDOCPARSER_H
+#define PUREDOCPARSER_H
+
+#include <QSet>
+
+#include "cppcodeparser.h"
+#include "location.h"
+
+QT_BEGIN_NAMESPACE
+
+class Config;
+class Node;
+class QString;
+class Tree;
+
+class PureDocParser : public CppCodeParser
+{
+public:
+ PureDocParser();
+ virtual ~PureDocParser();
+
+ virtual QStringList sourceFileNameFilter();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/qdoc.pro b/src/tools/qdoc/qdoc.pro
new file mode 100644
index 0000000000..fca5a3daf4
--- /dev/null
+++ b/src/tools/qdoc/qdoc.pro
@@ -0,0 +1,114 @@
+TEMPLATE = app
+TARGET = qdoc
+
+DESTDIR = ../../../bin
+DEFINES += QDOC2_COMPAT
+
+include(../bootstrap/bootstrap.pri)
+DEFINES -= QT_NO_CAST_FROM_ASCII
+DEFINES += QT_NO_TRANSLATION
+
+INCLUDEPATH += $$QT_SOURCE_TREE/src/tools/qdoc \
+ $$QT_SOURCE_TREE/src/tools/qdoc/qmlparser
+DEPENDPATH += $$QT_SOURCE_TREE/src/tools/qdoc \
+ $$QT_SOURCE_TREE/src/tools/qdoc/qmlparser
+
+# Increase the stack size on MSVC to 4M to avoid a stack overflow
+win32-msvc*:{
+ QMAKE_LFLAGS += /STACK:4194304
+}
+
+HEADERS += atom.h \
+ codechunk.h \
+ codemarker.h \
+ codeparser.h \
+ config.h \
+ cppcodemarker.h \
+ cppcodeparser.h \
+ ditaxmlgenerator.h \
+ doc.h \
+ editdistance.h \
+ generator.h \
+ helpprojectwriter.h \
+ htmlgenerator.h \
+ location.h \
+ node.h \
+ openedlist.h \
+ pagegenerator.h \
+ plaincodemarker.h \
+ puredocparser.h \
+ quoter.h \
+ separator.h \
+ text.h \
+ tokenizer.h \
+ tr.h \
+ tree.h
+SOURCES += atom.cpp \
+ codechunk.cpp \
+ codemarker.cpp \
+ codeparser.cpp \
+ config.cpp \
+ cppcodemarker.cpp \
+ cppcodeparser.cpp \
+ ditaxmlgenerator.cpp \
+ doc.cpp \
+ editdistance.cpp \
+ generator.cpp \
+ helpprojectwriter.cpp \
+ htmlgenerator.cpp \
+ location.cpp \
+ main.cpp \
+ node.cpp \
+ openedlist.cpp \
+ pagegenerator.cpp \
+ plaincodemarker.cpp \
+ puredocparser.cpp \
+ quoter.cpp \
+ separator.cpp \
+ text.cpp \
+ tokenizer.cpp \
+ tree.cpp \
+ yyindent.cpp
+
+### QML/JS Parser ###
+
+DEFINES += HAVE_DECLARATIVE
+include(qmlparser/qmlparser.pri)
+
+HEADERS += jscodemarker.h \
+ qmlcodemarker.h \
+ qmlcodeparser.h \
+ qmlmarkupvisitor.h \
+ qmlvisitor.h
+
+SOURCES += jscodemarker.cpp \
+ qmlcodemarker.cpp \
+ qmlcodeparser.cpp \
+ qmlmarkupvisitor.cpp \
+ qmlvisitor.cpp
+
+### Documentation for qdoc3 ###
+
+qtPrepareTool(QDOC, qdoc3)
+qtPrepareTool(QHELPGENERATOR, qhelpgenerator)
+
+equals(QMAKE_DIR_SEP, /) {
+ QDOC = QT_BUILD_TREE=$$QT_BUILD_TREE QT_SOURCE_TREE=$$QT_SOURCE_TREE $$QDOC
+} else {
+ QDOC = set QT_BUILD_TREE=$$QT_BUILD_TREE&& set QT_SOURCE_TREE=$$QT_SOURCE_TREE&& $$QDOC
+ QDOC = $$replace(QDOC, "/", "\\")
+}
+
+html-docs.commands = cd \"$$QT_BUILD_TREE/doc\" && $$QDOC $$QT_SOURCE_TREE/tools/qdoc3/doc/config/qdoc.qdocconf
+html-docs.files = $$QT_BUILD_TREE/doc/html
+
+qch-docs.commands = cd \"$$QT_BUILD_TREE/doc\" && $$QHELPGENERATOR $$QT_BUILD_TREE/tools/qdoc3/doc/html/qdoc.qhp -o $$QT_BUILD_TREE/tools/qdoc3/doc/qch/qdoc.qch
+qch-docs.files = $$QT_BUILD_TREE/tools/qdoc3/doc/qch
+qch-docs.path = $$[QT_INSTALL_DOCS]
+qch-docs.CONFIG += no_check_exist directory
+
+QMAKE_EXTRA_TARGETS += html-docs qch-docs
+
+target.path = $$[QT_HOST_BINS]
+INSTALLS += target
+load(qt_targets)
diff --git a/src/tools/qdoc/qmlcodemarker.cpp b/src/tools/qdoc/qmlcodemarker.cpp
new file mode 100644
index 0000000000..26483cc0d8
--- /dev/null
+++ b/src/tools/qdoc/qmlcodemarker.cpp
@@ -0,0 +1,302 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ qmlcodemarker.cpp
+*/
+
+#include "qqmljsast_p.h"
+#include "qqmljsastfwd_p.h"
+#include "qqmljsengine_p.h"
+#include "qqmljslexer_p.h"
+#include "qqmljsparser_p.h"
+
+#include "atom.h"
+#include "node.h"
+#include "qmlcodemarker.h"
+#include "qmlmarkupvisitor.h"
+#include "text.h"
+#include "tree.h"
+
+QT_BEGIN_NAMESPACE
+
+QmlCodeMarker::QmlCodeMarker()
+{
+}
+
+QmlCodeMarker::~QmlCodeMarker()
+{
+}
+
+/*!
+ Returns true if the \a code is recognized by the parser.
+ */
+bool QmlCodeMarker::recognizeCode(const QString &code)
+{
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+ QQmlJS::Parser parser(&engine);
+
+ QString newCode = code;
+ extractPragmas(newCode);
+ lexer.setCode(newCode, 1);
+
+ return parser.parse();
+}
+
+/*!
+ Returns true if \a ext is any of a list of file extensions
+ for the QML language.
+ */
+bool QmlCodeMarker::recognizeExtension(const QString &ext)
+{
+ return ext == "qml";
+}
+
+/*!
+ Returns true if the \a language is recognized. Only "QML" is
+ recognized by this marker.
+ */
+bool QmlCodeMarker::recognizeLanguage(const QString &language)
+{
+ return language == "QML";
+}
+
+/*!
+ Returns the type of atom used to represent QML code in the documentation.
+*/
+Atom::Type QmlCodeMarker::atomType() const
+{
+ return Atom::Qml;
+}
+
+/*!
+ Returns the name of the \a node. Method names include are returned with a
+ trailing set of parentheses.
+ */
+QString QmlCodeMarker::plainName(const Node *node)
+{
+ QString name = node->name();
+ if (node->type() == Node::QmlMethod)
+ name += "()";
+ return name;
+}
+
+QString QmlCodeMarker::plainFullName(const Node *node, const Node *relative)
+{
+ if (node->name().isEmpty()) {
+ return "global";
+ }
+ else {
+ QString fullName;
+ while (node) {
+ fullName.prepend(plainName(node));
+ if (node->parent() == relative ||
+ node->parent()->subType() == Node::Collision ||
+ node->parent()->name().isEmpty())
+ break;
+ fullName.prepend("::");
+ node = node->parent();
+ }
+ return fullName;
+ }
+}
+
+QString QmlCodeMarker::markedUpCode(const QString &code,
+ const Node *relative,
+ const Location &location)
+{
+ return addMarkUp(code, relative, location);
+}
+
+QString QmlCodeMarker::markedUpName(const Node *node)
+{
+ QString name = linkTag(node, taggedNode(node));
+ if (node->type() == Node::QmlMethod)
+ name += "()";
+ return name;
+}
+
+QString QmlCodeMarker::markedUpFullName(const Node *node, const Node *relative)
+{
+ if (node->name().isEmpty()) {
+ return "global";
+ }
+ else {
+ QString fullName;
+ for (;;) {
+ fullName.prepend(markedUpName(node));
+ if (node->parent() == relative || node->parent()->name().isEmpty())
+ break;
+ fullName.prepend("<@op>::</@op>");
+ node = node->parent();
+ }
+ return fullName;
+ }
+}
+
+QString QmlCodeMarker::markedUpIncludes(const QStringList& includes)
+{
+ QString code;
+
+ QStringList::ConstIterator inc = includes.begin();
+ while (inc != includes.end()) {
+ code += "import " + *inc + QLatin1Char('\n');
+ ++inc;
+ }
+ Location location;
+ return addMarkUp(code, 0, location);
+}
+
+QString QmlCodeMarker::functionBeginRegExp(const QString& funcName)
+{
+ return "^" + QRegExp::escape("function " + funcName) + "$";
+
+}
+
+QString QmlCodeMarker::functionEndRegExp(const QString& /* funcName */)
+{
+ return "^\\}$";
+}
+
+QString QmlCodeMarker::addMarkUp(const QString &code,
+ const Node * /* relative */,
+ const Location &location)
+{
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer lexer(&engine);
+
+ QString newCode = code;
+ QList<QQmlJS::AST::SourceLocation> pragmas = extractPragmas(newCode);
+ lexer.setCode(newCode, 1);
+
+ QQmlJS::Parser parser(&engine);
+ QString output;
+
+ if (parser.parse()) {
+ QQmlJS::AST::UiProgram *ast = parser.ast();
+ // Pass the unmodified code to the visitor so that pragmas and other
+ // unhandled source text can be output.
+ QmlMarkupVisitor visitor(code, pragmas, &engine);
+ QQmlJS::AST::Node::accept(ast, &visitor);
+ output = visitor.markedUpCode();
+ } else {
+ location.warning(tr("Unable to parse QML snippet: \"%1\" at line %2, column %3").arg(
+ parser.errorMessage()).arg(parser.errorLineNumber()).arg(
+ parser.errorColumnNumber()));
+ output = protect(code);
+ }
+
+ return output;
+}
+
+/*
+ Copied and pasted from
+ src/declarative/qml/qqmlscriptparser.cpp.
+*/
+static void replaceWithSpace(QString &str, int idx, int n)
+{
+ QChar *data = str.data() + idx;
+ const QChar space(QLatin1Char(' '));
+ for (int ii = 0; ii < n; ++ii)
+ *data++ = space;
+}
+
+/*
+ Copied and pasted from
+ src/declarative/qml/qqmlscriptparser.cpp then modified to
+ return a list of removed pragmas.
+
+ Searches for ".pragma <value>" declarations within \a script.
+ Currently supported pragmas are: library
+*/
+QList<QQmlJS::AST::SourceLocation> QmlCodeMarker::extractPragmas(QString &script)
+{
+ const QString pragma(QLatin1String("pragma"));
+ const QString library(QLatin1String("library"));
+ QList<QQmlJS::AST::SourceLocation> removed;
+
+ QQmlJS::Lexer l(0);
+ l.setCode(script, 0);
+
+ int token = l.lex();
+
+ while (true) {
+ if (token != QQmlJSGrammar::T_DOT)
+ return removed;
+
+ int startOffset = l.tokenOffset();
+ int startLine = l.tokenStartLine();
+ int startColumn = l.tokenStartColumn();
+
+ token = l.lex();
+
+ if (token != QQmlJSGrammar::T_IDENTIFIER ||
+ l.tokenStartLine() != startLine ||
+ script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
+ return removed;
+
+ token = l.lex();
+
+ if (token != QQmlJSGrammar::T_IDENTIFIER ||
+ l.tokenStartLine() != startLine)
+ return removed;
+
+ QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ token = l.lex();
+ if (l.tokenStartLine() == startLine)
+ return removed;
+
+ if (pragmaValue == QLatin1String("library")) {
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+ removed.append(
+ QQmlJS::AST::SourceLocation(
+ startOffset, endOffset - startOffset,
+ startLine, startColumn));
+ } else
+ return removed;
+ }
+ return removed;
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/qmlcodemarker.h b/src/tools/qdoc/qmlcodemarker.h
new file mode 100644
index 0000000000..4bcebb43ba
--- /dev/null
+++ b/src/tools/qdoc/qmlcodemarker.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ qmlcodemarker.h
+*/
+
+#ifndef QMLCODEMARKER_H
+#define QMLCODEMARKER_H
+
+#include "qqmljsastfwd_p.h"
+#include "cppcodemarker.h"
+
+QT_BEGIN_NAMESPACE
+
+class QmlCodeMarker : public CppCodeMarker
+{
+public:
+ QmlCodeMarker();
+ ~QmlCodeMarker();
+
+ virtual bool recognizeCode(const QString &code);
+ virtual bool recognizeExtension(const QString &ext);
+ virtual bool recognizeLanguage(const QString &language);
+ virtual Atom::Type atomType() const;
+ virtual QString plainName(const Node *node);
+ virtual QString plainFullName(const Node *node, const Node *relative);
+ virtual QString markedUpCode(const QString &code,
+ const Node *relative,
+ const Location &location);
+
+ virtual QString markedUpName(const Node *node);
+ virtual QString markedUpFullName(const Node *node, const Node *relative);
+ virtual QString markedUpIncludes(const QStringList &includes);
+ virtual QString functionBeginRegExp(const QString &funcName);
+ virtual QString functionEndRegExp(const QString &funcName);
+
+ /* Copied from src/declarative/qml/qdeclarativescriptparser.cpp */
+ QList<QQmlJS::AST::SourceLocation> extractPragmas(QString &script);
+
+private:
+ QString addMarkUp(const QString &code, const Node *relative,
+ const Location &location);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/qmlcodeparser.cpp b/src/tools/qdoc/qmlcodeparser.cpp
new file mode 100644
index 0000000000..23b8af8567
--- /dev/null
+++ b/src/tools/qdoc/qmlcodeparser.cpp
@@ -0,0 +1,291 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ qmlcodeparser.cpp
+*/
+
+#include "qqmljsast_p.h"
+#include "qqmljsastvisitor_p.h"
+
+#include "qmlcodeparser.h"
+#include "node.h"
+#include "tree.h"
+#include "config.h"
+#include "qmlvisitor.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+#define COMMAND_STARTPAGE Doc::alias("startpage")
+#define COMMAND_VARIABLE Doc::alias("variable")
+
+#define COMMAND_DEPRECATED Doc::alias("deprecated")
+#define COMMAND_INGROUP Doc::alias("ingroup")
+#define COMMAND_INTERNAL Doc::alias("internal")
+#define COMMAND_OBSOLETE Doc::alias("obsolete")
+#define COMMAND_PAGEKEYWORDS Doc::alias("pagekeywords")
+#define COMMAND_PRELIMINARY Doc::alias("preliminary")
+#define COMMAND_SINCE Doc::alias("since")
+
+#define COMMAND_QMLABSTRACT Doc::alias("qmlabstract")
+#define COMMAND_QMLCLASS Doc::alias("qmlclass")
+#define COMMAND_QMLMODULE Doc::alias("qmlmodule")
+#define COMMAND_QMLPROPERTY Doc::alias("qmlproperty")
+#define COMMAND_QMLATTACHEDPROPERTY Doc::alias("qmlattachedproperty")
+#define COMMAND_QMLINHERITS Doc::alias("inherits")
+#define COMMAND_INQMLMODULE Doc::alias("inqmlmodule")
+#define COMMAND_QMLSIGNAL Doc::alias("qmlsignal")
+#define COMMAND_QMLATTACHEDSIGNAL Doc::alias("qmlattachedsignal")
+#define COMMAND_QMLMETHOD Doc::alias("qmlmethod")
+#define COMMAND_QMLATTACHEDMETHOD Doc::alias("qmlattachedmethod")
+#define COMMAND_QMLDEFAULT Doc::alias("default")
+#define COMMAND_QMLREADONLY Doc::alias("readonly")
+#define COMMAND_QMLBASICTYPE Doc::alias("qmlbasictype")
+#define COMMAND_QMLMODULE Doc::alias("qmlmodule")
+
+QmlCodeParser::QmlCodeParser()
+{
+}
+
+QmlCodeParser::~QmlCodeParser()
+{
+}
+
+/*!
+ Initializes the code parser base class. The \a config argument
+ is passed to the initialization functions in the base class.
+
+ Also creates a lexer and parser from QQmlJS.
+ */
+void QmlCodeParser::initializeParser(const Config &config)
+{
+ CodeParser::initializeParser(config);
+
+ lexer = new QQmlJS::Lexer(&engine);
+ parser = new QQmlJS::Parser(&engine);
+}
+
+/*!
+ Deletes the lexer and parser created by the constructor.
+ */
+void QmlCodeParser::terminateParser()
+{
+ delete lexer;
+ delete parser;
+}
+
+/*!
+ Returns "QML".
+ */
+QString QmlCodeParser::language()
+{
+ return "QML";
+}
+
+/*!
+ Returns a filter string of "*.qml".
+ */
+QStringList QmlCodeParser::sourceFileNameFilter()
+{
+ return QStringList("*.qml");
+}
+
+/*!
+ Parses the source file at \a filePath, creating nodes as
+ needed and inserting them into the \a tree. \a location is
+ used for error reporting.
+
+ If it can't open the file at \a filePath, it reports an
+ error and returns without doing anything.
+ */
+void QmlCodeParser::parseSourceFile(const Location& location,
+ const QString& filePath,
+ Tree *tree)
+{
+ QFile in(filePath);
+ if (!in.open(QIODevice::ReadOnly)) {
+ location.error(tr("Cannot open QML file '%1'").arg(filePath));
+ return;
+ }
+ createOutputSubdirectory(location, filePath);
+
+ QString document = in.readAll();
+ in.close();
+
+ Location fileLocation(filePath);
+
+ QString newCode = document;
+ extractPragmas(newCode);
+ lexer->setCode(newCode, 1);
+
+ QSet<QString> topicCommandsAllowed = topicCommands();
+ QSet<QString> otherMetacommandsAllowed = otherMetaCommands();
+ QSet<QString> metacommandsAllowed = topicCommandsAllowed + otherMetacommandsAllowed;
+
+ if (parser->parse()) {
+ QQmlJS::AST::UiProgram *ast = parser->ast();
+ QmlDocVisitor visitor(filePath,
+ newCode,
+ &engine,
+ tree,
+ metacommandsAllowed,
+ topicCommandsAllowed);
+ QQmlJS::AST::Node::accept(ast, &visitor);
+ }
+ foreach (const QQmlJS::DiagnosticMessage &msg, parser->diagnosticMessages()) {
+ qDebug().nospace() << qPrintable(filePath) << ':' << msg.loc.startLine
+ << ": QML syntax error at col " << msg.loc.startColumn
+ << ": " << qPrintable(msg.message);
+ }
+}
+
+/*!
+ This function is called when the parser finishes parsing
+ the file, but in this case the function does nothing.
+ */
+void QmlCodeParser::doneParsingSourceFiles(Tree *)
+{
+}
+
+/*!
+ Returns the set of strings representing the topic commands.
+ */
+QSet<QString> QmlCodeParser::topicCommands()
+{
+ return QSet<QString>() << COMMAND_VARIABLE
+ << COMMAND_QMLCLASS
+ << COMMAND_QMLPROPERTY
+ << COMMAND_QMLATTACHEDPROPERTY
+ << COMMAND_QMLSIGNAL
+ << COMMAND_QMLATTACHEDSIGNAL
+ << COMMAND_QMLMETHOD
+ << COMMAND_QMLATTACHEDMETHOD
+ << COMMAND_QMLBASICTYPE;
+}
+
+/*!
+ Returns the set of strings representing the common metacommands
+ plus some other metacommands.
+ */
+QSet<QString> QmlCodeParser::otherMetaCommands()
+{
+ return commonMetaCommands() << COMMAND_STARTPAGE
+ << COMMAND_QMLINHERITS
+ << COMMAND_QMLDEFAULT
+ << COMMAND_QMLREADONLY
+ << COMMAND_DEPRECATED
+ << COMMAND_INGROUP
+ << COMMAND_INTERNAL
+ << COMMAND_OBSOLETE
+ << COMMAND_PRELIMINARY
+ << COMMAND_SINCE
+ << COMMAND_QMLABSTRACT
+ << COMMAND_INQMLMODULE;
+
+}
+
+/*!
+ Copy and paste from src/declarative/qml/qdeclarativescriptparser.cpp.
+ This function blanks out the section of the \a str beginning at \a idx
+ and running for \a n characters.
+*/
+static void replaceWithSpace(QString &str, int idx, int n)
+{
+ QChar *data = str.data() + idx;
+ const QChar space(QLatin1Char(' '));
+ for (int ii = 0; ii < n; ++ii)
+ *data++ = space;
+}
+
+/*!
+ Copy & paste from src/declarative/qml/qdeclarativescriptparser.cpp,
+ then modified to return no values.
+
+ Searches for ".pragma <value>" declarations within \a script.
+ Currently supported pragmas are: library
+*/
+void QmlCodeParser::extractPragmas(QString &script)
+{
+ const QString pragma(QLatin1String("pragma"));
+ const QString library(QLatin1String("library"));
+
+ QQmlJS::Lexer l(0);
+ l.setCode(script, 0);
+
+ int token = l.lex();
+
+ while (true) {
+ if (token != QQmlJSGrammar::T_DOT)
+ return;
+
+ int startOffset = l.tokenOffset();
+ int startLine = l.tokenStartLine();
+
+ token = l.lex();
+
+ if (token != QQmlJSGrammar::T_IDENTIFIER ||
+ l.tokenStartLine() != startLine ||
+ script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
+ return;
+
+ token = l.lex();
+
+ if (token != QQmlJSGrammar::T_IDENTIFIER ||
+ l.tokenStartLine() != startLine)
+ return;
+
+ QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
+ int endOffset = l.tokenLength() + l.tokenOffset();
+
+ token = l.lex();
+ if (l.tokenStartLine() == startLine)
+ return;
+
+ if (pragmaValue == QLatin1String("library"))
+ replaceWithSpace(script, startOffset, endOffset - startOffset);
+ else
+ return;
+ }
+ return;
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/qmlcodeparser.h b/src/tools/qdoc/qmlcodeparser.h
new file mode 100644
index 0000000000..295c6a80ef
--- /dev/null
+++ b/src/tools/qdoc/qmlcodeparser.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ qmlcodeparser.h
+*/
+
+#ifndef QMLCODEPARSER_H
+#define QMLCODEPARSER_H
+
+#include <QSet>
+#include "qqmljsengine_p.h"
+#include "qqmljslexer_p.h"
+#include "qqmljsparser_p.h"
+
+#include "codeparser.h"
+
+QT_BEGIN_NAMESPACE
+
+class Config;
+class Node;
+class QString;
+class Tree;
+
+class QmlCodeParser : public CodeParser
+{
+public:
+ QmlCodeParser();
+ virtual ~QmlCodeParser();
+
+ virtual void initializeParser(const Config& config);
+ virtual void terminateParser();
+ virtual QString language();
+ virtual QStringList sourceFileNameFilter();
+ virtual void parseSourceFile(const Location& location,
+ const QString& filePath, Tree *tree);
+ virtual void doneParsingSourceFiles(Tree *tree);
+
+ /* Copied from src/declarative/qml/qdeclarativescriptparser.cpp */
+ void extractPragmas(QString &script);
+
+protected:
+ virtual QSet<QString> topicCommands();
+ virtual QSet<QString> otherMetaCommands();
+
+private:
+ QQmlJS::Engine engine;
+ QQmlJS::Lexer *lexer;
+ QQmlJS::Parser *parser;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/qmlmarkupvisitor.cpp b/src/tools/qdoc/qmlmarkupvisitor.cpp
new file mode 100644
index 0000000000..0b1883723f
--- /dev/null
+++ b/src/tools/qdoc/qmlmarkupvisitor.cpp
@@ -0,0 +1,851 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QStringList>
+#include <QtGlobal>
+#include "qqmljsast_p.h"
+#include "qqmljsastfwd_p.h"
+#include "qqmljsengine_p.h"
+
+#include "qmlmarkupvisitor.h"
+
+QT_BEGIN_NAMESPACE
+
+QmlMarkupVisitor::QmlMarkupVisitor(const QString &source,
+ const QList<QQmlJS::AST::SourceLocation> &pragmas,
+ QQmlJS::Engine *engine)
+{
+ this->source = source;
+ this->engine = engine;
+
+ cursor = 0;
+ extraIndex = 0;
+
+ // Merge the lists of locations of pragmas and comments in the source code.
+ int i = 0;
+ int j = 0;
+ while (i < engine->comments().length() && j < pragmas.length()) {
+ if (engine->comments()[i].offset < pragmas[j].offset) {
+ extraTypes.append(Comment);
+ extraLocations.append(engine->comments()[i]);
+ ++i;
+ } else {
+ extraTypes.append(Pragma);
+ extraLocations.append(engine->comments()[j]);
+ ++j;
+ }
+ }
+
+ while (i < engine->comments().length()) {
+ extraTypes.append(Comment);
+ extraLocations.append(engine->comments()[i]);
+ ++i;
+ }
+
+ while (j < pragmas.length()) {
+ extraTypes.append(Pragma);
+ extraLocations.append(pragmas[j]);
+ ++j;
+ }
+}
+
+QmlMarkupVisitor::~QmlMarkupVisitor()
+{
+}
+
+// The protect() function is a copy of the one from CppCodeMarker.
+
+static const QString samp = QLatin1String("&amp;");
+static const QString slt = QLatin1String("&lt;");
+static const QString sgt = QLatin1String("&gt;");
+static const QString squot = QLatin1String("&quot;");
+
+QString QmlMarkupVisitor::protect(const QString& str)
+{
+ int n = str.length();
+ QString marked;
+ marked.reserve(n * 2 + 30);
+ const QChar *data = str.constData();
+ for (int i = 0; i != n; ++i) {
+ switch (data[i].unicode()) {
+ case '&': marked += samp; break;
+ case '<': marked += slt; break;
+ case '>': marked += sgt; break;
+ case '"': marked += squot; break;
+ default : marked += data[i];
+ }
+ }
+ return marked;
+}
+
+QString QmlMarkupVisitor::markedUpCode()
+{
+ if (int(cursor) < source.length())
+ addExtra(cursor, source.length());
+
+ return output;
+}
+
+void QmlMarkupVisitor::addExtra(quint32 start, quint32 finish)
+{
+ if (extraIndex >= extraLocations.length()) {
+ QString extra = source.mid(start, finish - start);
+ if (extra.trimmed().isEmpty())
+ output += extra;
+ else
+ output += protect(extra); // text that should probably have been caught by the parser
+
+ cursor = finish;
+ return;
+ }
+
+ while (extraIndex < extraLocations.length()) {
+ if (extraTypes[extraIndex] == Comment) {
+ if (extraLocations[extraIndex].offset - 2 >= start)
+ break;
+ } else {
+ if (extraLocations[extraIndex].offset >= start)
+ break;
+ }
+ extraIndex++;
+ }
+
+ quint32 i = start;
+ while (i < finish && extraIndex < extraLocations.length()) {
+ quint32 j = extraLocations[extraIndex].offset - 2;
+ if (i <= j && j < finish) {
+ if (i < j)
+ output += protect(source.mid(i, j - i));
+
+ quint32 l = extraLocations[extraIndex].length;
+ if (extraTypes[extraIndex] == Comment) {
+ if (source.mid(j, 2) == QLatin1String("/*"))
+ l += 4;
+ else
+ l += 2;
+ output += QLatin1String("<@comment>");
+ output += protect(source.mid(j, l));
+ output += QLatin1String("</@comment>");
+ } else
+ output += protect(source.mid(j, l));
+
+ extraIndex++;
+ i = j + l;
+ } else
+ break;
+ }
+
+ QString extra = source.mid(i, finish - i);
+ if (extra.trimmed().isEmpty())
+ output += extra;
+ else
+ output += protect(extra); // text that should probably have been caught by the parser
+
+ cursor = finish;
+}
+
+void QmlMarkupVisitor::addMarkedUpToken(
+ QQmlJS::AST::SourceLocation &location, const QString &tagName,
+ const QHash<QString, QString> &attributes)
+{
+ if (!location.isValid())
+ return;
+
+ if (cursor < location.offset)
+ addExtra(cursor, location.offset);
+ else if (cursor > location.offset)
+ return;
+
+ output += QString(QLatin1String("<@%1")).arg(tagName);
+ foreach (const QString &key, attributes)
+ output += QString(QLatin1String(" %1=\"%2\"")).arg(key).arg(attributes[key]);
+ output += QString(QLatin1String(">%2</@%3>")).arg(protect(sourceText(location)), tagName);
+ cursor += location.length;
+}
+
+QString QmlMarkupVisitor::sourceText(QQmlJS::AST::SourceLocation &location)
+{
+ return source.mid(location.offset, location.length);
+}
+
+void QmlMarkupVisitor::addVerbatim(QQmlJS::AST::SourceLocation first,
+ QQmlJS::AST::SourceLocation last)
+{
+ if (!first.isValid())
+ return;
+
+ quint32 start = first.begin();
+ quint32 finish;
+ if (last.isValid())
+ finish = last.end();
+ else
+ finish = first.end();
+
+ if (cursor < start)
+ addExtra(cursor, start);
+ else if (cursor > start)
+ return;
+
+ QString text = source.mid(start, finish - start);
+ output += protect(text);
+ cursor = finish;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UiImport *uiimport)
+{
+ addVerbatim(uiimport->importToken);
+ if (!uiimport->importUri)
+ addMarkedUpToken(uiimport->fileNameToken, QLatin1String("headerfile"));
+ return false;
+}
+
+void QmlMarkupVisitor::endVisit(QQmlJS::AST::UiImport *uiimport)
+{
+ addVerbatim(uiimport->versionToken);
+ addVerbatim(uiimport->asToken);
+ addMarkedUpToken(uiimport->importIdToken, QLatin1String("headerfile"));
+ addVerbatim(uiimport->semicolonToken);
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UiPublicMember *member)
+{
+ if (member->type == QQmlJS::AST::UiPublicMember::Property) {
+ addVerbatim(member->defaultToken);
+ addVerbatim(member->readonlyToken);
+ addVerbatim(member->propertyToken);
+ addVerbatim(member->typeModifierToken);
+ addMarkedUpToken(member->typeToken, QLatin1String("type"));
+ addMarkedUpToken(member->identifierToken, QLatin1String("name"));
+ addVerbatim(member->colonToken);
+ if (member->binding)
+ QQmlJS::AST::Node::accept(member->binding, this);
+ else if (member->statement)
+ QQmlJS::AST::Node::accept(member->statement, this);
+ } else {
+ addVerbatim(member->propertyToken);
+ addVerbatim(member->typeModifierToken);
+ addMarkedUpToken(member->typeToken, QLatin1String("type"));
+ //addVerbatim(member->identifierToken);
+ QQmlJS::AST::Node::accept(member->parameters, this);
+ }
+ addVerbatim(member->semicolonToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UiObjectInitializer *initializer)
+{
+ addVerbatim(initializer->lbraceToken, initializer->lbraceToken);
+ return true;
+}
+
+void QmlMarkupVisitor::endVisit(QQmlJS::AST::UiObjectInitializer *initializer)
+{
+ addVerbatim(initializer->rbraceToken, initializer->rbraceToken);
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UiObjectBinding *binding)
+{
+ QQmlJS::AST::Node::accept(binding->qualifiedId, this);
+ addVerbatim(binding->colonToken);
+ QQmlJS::AST::Node::accept(binding->qualifiedTypeNameId, this);
+ QQmlJS::AST::Node::accept(binding->initializer, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UiScriptBinding *binding)
+{
+ QQmlJS::AST::Node::accept(binding->qualifiedId, this);
+ addVerbatim(binding->colonToken);
+ QQmlJS::AST::Node::accept(binding->statement, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UiArrayBinding *binding)
+{
+ QQmlJS::AST::Node::accept(binding->qualifiedId, this);
+ addVerbatim(binding->colonToken);
+ addVerbatim(binding->lbracketToken);
+ QQmlJS::AST::Node::accept(binding->members, this);
+ addVerbatim(binding->rbracketToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UiArrayMemberList *list)
+{
+ for (QQmlJS::AST::UiArrayMemberList *it = list; it; it = it->next) {
+ QQmlJS::AST::Node::accept(it->member, this);
+ //addVerbatim(it->commaToken);
+ }
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UiQualifiedId *id)
+{
+ addMarkedUpToken(id->identifierToken, QLatin1String("name"));
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ThisExpression *expression)
+{
+ addVerbatim(expression->thisToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::IdentifierExpression *identifier)
+{
+ addMarkedUpToken(identifier->identifierToken, QLatin1String("name"));
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::NullExpression *null)
+{
+ addMarkedUpToken(null->nullToken, QLatin1String("number"));
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::TrueLiteral *literal)
+{
+ addMarkedUpToken(literal->trueToken, QLatin1String("number"));
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::FalseLiteral *literal)
+{
+ addMarkedUpToken(literal->falseToken, QLatin1String("number"));
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::NumericLiteral *literal)
+{
+ addMarkedUpToken(literal->literalToken, QLatin1String("number"));
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::StringLiteral *literal)
+{
+ addMarkedUpToken(literal->literalToken, QLatin1String("string"));
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::RegExpLiteral *literal)
+{
+ addVerbatim(literal->literalToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ArrayLiteral *literal)
+{
+ addVerbatim(literal->lbracketToken);
+ QQmlJS::AST::Node::accept(literal->elements, this);
+ addVerbatim(literal->rbracketToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ObjectLiteral *literal)
+{
+ addVerbatim(literal->lbraceToken);
+ return true;
+}
+
+void QmlMarkupVisitor::endVisit(QQmlJS::AST::ObjectLiteral *literal)
+{
+ addVerbatim(literal->rbraceToken);
+}
+
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ElementList *list)
+{
+ for (QQmlJS::AST::ElementList *it = list; it; it = it->next) {
+ QQmlJS::AST::Node::accept(it->expression, this);
+ //addVerbatim(it->commaToken);
+ }
+ QQmlJS::AST::Node::accept(list->elision, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::Elision *elision)
+{
+ addVerbatim(elision->commaToken, elision->commaToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::PropertyNameAndValueList *list)
+{
+ QQmlJS::AST::Node::accept(list->name, this);
+ addVerbatim(list->colonToken, list->colonToken);
+ QQmlJS::AST::Node::accept(list->value, this);
+ addVerbatim(list->commaToken, list->commaToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ArrayMemberExpression *expression)
+{
+ QQmlJS::AST::Node::accept(expression->base, this);
+ addVerbatim(expression->lbracketToken);
+ QQmlJS::AST::Node::accept(expression->expression, this);
+ addVerbatim(expression->rbracketToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::FieldMemberExpression *expression)
+{
+ QQmlJS::AST::Node::accept(expression->base, this);
+ addVerbatim(expression->dotToken);
+ addMarkedUpToken(expression->identifierToken, QLatin1String("name"));
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::NewMemberExpression *expression)
+{
+ addVerbatim(expression->newToken);
+ QQmlJS::AST::Node::accept(expression->base, this);
+ addVerbatim(expression->lparenToken);
+ QQmlJS::AST::Node::accept(expression->arguments, this);
+ addVerbatim(expression->rparenToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::NewExpression *expression)
+{
+ addVerbatim(expression->newToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ArgumentList *list)
+{
+ addVerbatim(list->commaToken, list->commaToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::PostIncrementExpression *expression)
+{
+ addVerbatim(expression->incrementToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::PostDecrementExpression *expression)
+{
+ addVerbatim(expression->decrementToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::DeleteExpression *expression)
+{
+ addVerbatim(expression->deleteToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::VoidExpression *expression)
+{
+ addVerbatim(expression->voidToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::TypeOfExpression *expression)
+{
+ addVerbatim(expression->typeofToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::PreIncrementExpression *expression)
+{
+ addVerbatim(expression->incrementToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::PreDecrementExpression *expression)
+{
+ addVerbatim(expression->decrementToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UnaryPlusExpression *expression)
+{
+ addVerbatim(expression->plusToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UnaryMinusExpression *expression)
+{
+ addVerbatim(expression->minusToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::TildeExpression *expression)
+{
+ addVerbatim(expression->tildeToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::NotExpression *expression)
+{
+ addVerbatim(expression->notToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::BinaryExpression *expression)
+{
+ QQmlJS::AST::Node::accept(expression->left, this);
+ addMarkedUpToken(expression->operatorToken, QLatin1String("op"));
+ QQmlJS::AST::Node::accept(expression->right, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ConditionalExpression *expression)
+{
+ QQmlJS::AST::Node::accept(expression->expression, this);
+ addVerbatim(expression->questionToken);
+ QQmlJS::AST::Node::accept(expression->ok, this);
+ addVerbatim(expression->colonToken);
+ QQmlJS::AST::Node::accept(expression->ko, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::Expression *expression)
+{
+ QQmlJS::AST::Node::accept(expression->left, this);
+ addVerbatim(expression->commaToken);
+ QQmlJS::AST::Node::accept(expression->right, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::Block *block)
+{
+ addVerbatim(block->lbraceToken);
+ return true;
+}
+
+void QmlMarkupVisitor::endVisit(QQmlJS::AST::Block *block)
+{
+ addVerbatim(block->rbraceToken);
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::VariableStatement *statement)
+{
+ addVerbatim(statement->declarationKindToken);
+ QQmlJS::AST::Node::accept(statement->declarations, this);
+ addVerbatim(statement->semicolonToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::VariableDeclarationList *list)
+{
+ for (QQmlJS::AST::VariableDeclarationList *it = list; it; it = it->next) {
+ QQmlJS::AST::Node::accept(it->declaration, this);
+ addVerbatim(it->commaToken);
+ }
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::VariableDeclaration *declaration)
+{
+ addMarkedUpToken(declaration->identifierToken, QLatin1String("name"));
+ QQmlJS::AST::Node::accept(declaration->expression, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::EmptyStatement *statement)
+{
+ addVerbatim(statement->semicolonToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ExpressionStatement *statement)
+{
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->semicolonToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::IfStatement *statement)
+{
+ addMarkedUpToken(statement->ifToken, QLatin1String("keyword"));
+ addVerbatim(statement->lparenToken);
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->rparenToken);
+ QQmlJS::AST::Node::accept(statement->ok, this);
+ if (statement->ko) {
+ addMarkedUpToken(statement->elseToken, QLatin1String("keyword"));
+ QQmlJS::AST::Node::accept(statement->ko, this);
+ }
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::DoWhileStatement *statement)
+{
+ addMarkedUpToken(statement->doToken, QLatin1String("keyword"));
+ QQmlJS::AST::Node::accept(statement->statement, this);
+ addMarkedUpToken(statement->whileToken, QLatin1String("keyword"));
+ addVerbatim(statement->lparenToken);
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->rparenToken);
+ addVerbatim(statement->semicolonToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::WhileStatement *statement)
+{
+ addMarkedUpToken(statement->whileToken, QLatin1String("keyword"));
+ addVerbatim(statement->lparenToken);
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->rparenToken);
+ QQmlJS::AST::Node::accept(statement->statement, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ForStatement *statement)
+{
+ addMarkedUpToken(statement->forToken, QLatin1String("keyword"));
+ addVerbatim(statement->lparenToken);
+ QQmlJS::AST::Node::accept(statement->initialiser, this);
+ addVerbatim(statement->firstSemicolonToken);
+ QQmlJS::AST::Node::accept(statement->condition, this);
+ addVerbatim(statement->secondSemicolonToken);
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->rparenToken);
+ QQmlJS::AST::Node::accept(statement->statement, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::LocalForStatement *statement)
+{
+ addMarkedUpToken(statement->forToken, QLatin1String("keyword"));
+ addVerbatim(statement->lparenToken);
+ addMarkedUpToken(statement->varToken, QLatin1String("keyword"));
+ QQmlJS::AST::Node::accept(statement->declarations, this);
+ addVerbatim(statement->firstSemicolonToken);
+ QQmlJS::AST::Node::accept(statement->condition, this);
+ addVerbatim(statement->secondSemicolonToken);
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->rparenToken);
+ QQmlJS::AST::Node::accept(statement->statement, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ForEachStatement *statement)
+{
+ addMarkedUpToken(statement->forToken, QLatin1String("keyword"));
+ addVerbatim(statement->lparenToken);
+ QQmlJS::AST::Node::accept(statement->initialiser, this);
+ addVerbatim(statement->inToken);
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->rparenToken);
+ QQmlJS::AST::Node::accept(statement->statement, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::LocalForEachStatement *statement)
+{
+ addMarkedUpToken(statement->forToken, QLatin1String("keyword"));
+ addVerbatim(statement->lparenToken);
+ addMarkedUpToken(statement->varToken, QLatin1String("keyword"));
+ QQmlJS::AST::Node::accept(statement->declaration, this);
+ addVerbatim(statement->inToken);
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->rparenToken);
+ QQmlJS::AST::Node::accept(statement->statement, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ContinueStatement *statement)
+{
+ addMarkedUpToken(statement->continueToken, QLatin1String("keyword"));
+ addMarkedUpToken(statement->identifierToken, QLatin1String("name"));
+ addVerbatim(statement->semicolonToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::BreakStatement *statement)
+{
+ addMarkedUpToken(statement->breakToken, QLatin1String("keyword"));
+ addMarkedUpToken(statement->identifierToken, QLatin1String("name"));
+ addVerbatim(statement->semicolonToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ReturnStatement *statement)
+{
+ addMarkedUpToken(statement->returnToken, QLatin1String("keyword"));
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->semicolonToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::WithStatement *statement)
+{
+ addMarkedUpToken(statement->withToken, QLatin1String("keyword"));
+ addVerbatim(statement->lparenToken);
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->rparenToken);
+ QQmlJS::AST::Node::accept(statement->statement, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::CaseBlock *block)
+{
+ addVerbatim(block->lbraceToken);
+ return true;
+}
+
+void QmlMarkupVisitor::endVisit(QQmlJS::AST::CaseBlock *block)
+{
+ addVerbatim(block->rbraceToken, block->rbraceToken);
+}
+
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::SwitchStatement *statement)
+{
+ addMarkedUpToken(statement->switchToken, QLatin1String("keyword"));
+ addVerbatim(statement->lparenToken);
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->rparenToken);
+ QQmlJS::AST::Node::accept(statement->block, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::CaseClause *clause)
+{
+ addMarkedUpToken(clause->caseToken, QLatin1String("keyword"));
+ QQmlJS::AST::Node::accept(clause->expression, this);
+ addVerbatim(clause->colonToken);
+ QQmlJS::AST::Node::accept(clause->statements, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::DefaultClause *clause)
+{
+ addMarkedUpToken(clause->defaultToken, QLatin1String("keyword"));
+ addVerbatim(clause->colonToken, clause->colonToken);
+ return true;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::LabelledStatement *statement)
+{
+ addMarkedUpToken(statement->identifierToken, QLatin1String("name"));
+ addVerbatim(statement->colonToken);
+ QQmlJS::AST::Node::accept(statement->statement, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::ThrowStatement *statement)
+{
+ addMarkedUpToken(statement->throwToken, QLatin1String("keyword"));
+ QQmlJS::AST::Node::accept(statement->expression, this);
+ addVerbatim(statement->semicolonToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::Catch *c)
+{
+ addMarkedUpToken(c->catchToken, QLatin1String("keyword"));
+ addVerbatim(c->lparenToken);
+ addMarkedUpToken(c->identifierToken, QLatin1String("name"));
+ addVerbatim(c->rparenToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::Finally *f)
+{
+ addMarkedUpToken(f->finallyToken, QLatin1String("keyword"));
+ QQmlJS::AST::Node::accept(f->statement, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::TryStatement *statement)
+{
+ addMarkedUpToken(statement->tryToken, QLatin1String("keyword"));
+ QQmlJS::AST::Node::accept(statement->statement, this);
+ QQmlJS::AST::Node::accept(statement->catchExpression, this);
+ QQmlJS::AST::Node::accept(statement->finallyExpression, this);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::FunctionExpression *expression)
+{
+ addMarkedUpToken(expression->functionToken, QLatin1String("keyword"));
+ addMarkedUpToken(expression->identifierToken, QLatin1String("name"));
+ addVerbatim(expression->lparenToken);
+ QQmlJS::AST::Node::accept(expression->formals, this);
+ addVerbatim(expression->rparenToken);
+ addVerbatim(expression->lbraceToken);
+ QQmlJS::AST::Node::accept(expression->body, this);
+ addVerbatim(expression->rbraceToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::FunctionDeclaration *declaration)
+{
+ addMarkedUpToken(declaration->functionToken, QLatin1String("keyword"));
+ addMarkedUpToken(declaration->identifierToken, QLatin1String("name"));
+ addVerbatim(declaration->lparenToken);
+ QQmlJS::AST::Node::accept(declaration->formals, this);
+ addVerbatim(declaration->rparenToken);
+ addVerbatim(declaration->lbraceToken);
+ QQmlJS::AST::Node::accept(declaration->body, this);
+ addVerbatim(declaration->rbraceToken);
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::FormalParameterList *list)
+{
+ addVerbatim(list->commaToken);
+ addMarkedUpToken(list->identifierToken, QLatin1String("name"));
+ return false;
+}
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::DebuggerStatement *statement)
+{
+ addVerbatim(statement->debuggerToken);
+ addVerbatim(statement->semicolonToken);
+ return true;
+}
+
+// Elements and items are represented by UiObjectDefinition nodes.
+
+bool QmlMarkupVisitor::visit(QQmlJS::AST::UiObjectDefinition *definition)
+{
+ QHash<QString, QString> attributes;
+ addMarkedUpToken(definition->qualifiedTypeNameId->identifierToken, QLatin1String("type"));
+ QQmlJS::AST::Node::accept(definition->initializer, this);
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/qmlmarkupvisitor.h b/src/tools/qdoc/qmlmarkupvisitor.h
new file mode 100644
index 0000000000..e6b8aee8b8
--- /dev/null
+++ b/src/tools/qdoc/qmlmarkupvisitor.h
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLVISITOR_H
+#define QMLVISITOR_H
+
+#include <QString>
+#include "qqmljsastvisitor_p.h"
+#include "node.h"
+#include "tree.h"
+
+QT_BEGIN_NAMESPACE
+
+class QmlMarkupVisitor : public QQmlJS::AST::Visitor
+{
+public:
+ enum ExtraType{
+ Comment,
+ Pragma
+ };
+
+ QmlMarkupVisitor(const QString &code,
+ const QList<QQmlJS::AST::SourceLocation> &pragmas,
+ QQmlJS::Engine *engine);
+ virtual ~QmlMarkupVisitor();
+
+ QString markedUpCode();
+
+ virtual bool visit(QQmlJS::AST::UiImport *);
+ virtual void endVisit(QQmlJS::AST::UiImport *);
+
+ virtual bool visit(QQmlJS::AST::UiPublicMember *);
+ virtual bool visit(QQmlJS::AST::UiObjectDefinition *);
+
+ virtual bool visit(QQmlJS::AST::UiObjectInitializer *);
+ virtual void endVisit(QQmlJS::AST::UiObjectInitializer *);
+
+ virtual bool visit(QQmlJS::AST::UiObjectBinding *);
+ virtual bool visit(QQmlJS::AST::UiScriptBinding *);
+ virtual bool visit(QQmlJS::AST::UiArrayBinding *);
+ virtual bool visit(QQmlJS::AST::UiArrayMemberList *);
+ virtual bool visit(QQmlJS::AST::UiQualifiedId *);
+
+ virtual bool visit(QQmlJS::AST::ThisExpression *);
+ virtual bool visit(QQmlJS::AST::IdentifierExpression *);
+ virtual bool visit(QQmlJS::AST::NullExpression *);
+ virtual bool visit(QQmlJS::AST::TrueLiteral *);
+ virtual bool visit(QQmlJS::AST::FalseLiteral *);
+ virtual bool visit(QQmlJS::AST::NumericLiteral *);
+ virtual bool visit(QQmlJS::AST::StringLiteral *);
+ virtual bool visit(QQmlJS::AST::RegExpLiteral *);
+ virtual bool visit(QQmlJS::AST::ArrayLiteral *);
+
+ virtual bool visit(QQmlJS::AST::ObjectLiteral *);
+ virtual void endVisit(QQmlJS::AST::ObjectLiteral *);
+
+ virtual bool visit(QQmlJS::AST::ElementList *);
+ virtual bool visit(QQmlJS::AST::Elision *);
+ virtual bool visit(QQmlJS::AST::PropertyNameAndValueList *);
+ virtual bool visit(QQmlJS::AST::ArrayMemberExpression *);
+ virtual bool visit(QQmlJS::AST::FieldMemberExpression *);
+ virtual bool visit(QQmlJS::AST::NewMemberExpression *);
+ virtual bool visit(QQmlJS::AST::NewExpression *);
+ virtual bool visit(QQmlJS::AST::ArgumentList *);
+ virtual bool visit(QQmlJS::AST::PostIncrementExpression *);
+ virtual bool visit(QQmlJS::AST::PostDecrementExpression *);
+ virtual bool visit(QQmlJS::AST::DeleteExpression *);
+ virtual bool visit(QQmlJS::AST::VoidExpression *);
+ virtual bool visit(QQmlJS::AST::TypeOfExpression *);
+ virtual bool visit(QQmlJS::AST::PreIncrementExpression *);
+ virtual bool visit(QQmlJS::AST::PreDecrementExpression *);
+ virtual bool visit(QQmlJS::AST::UnaryPlusExpression *);
+ virtual bool visit(QQmlJS::AST::UnaryMinusExpression *);
+ virtual bool visit(QQmlJS::AST::TildeExpression *);
+ virtual bool visit(QQmlJS::AST::NotExpression *);
+ virtual bool visit(QQmlJS::AST::BinaryExpression *);
+ virtual bool visit(QQmlJS::AST::ConditionalExpression *);
+ virtual bool visit(QQmlJS::AST::Expression *);
+
+ virtual bool visit(QQmlJS::AST::Block *);
+ virtual void endVisit(QQmlJS::AST::Block *);
+
+ virtual bool visit(QQmlJS::AST::VariableStatement *);
+ virtual bool visit(QQmlJS::AST::VariableDeclarationList *);
+ virtual bool visit(QQmlJS::AST::VariableDeclaration *);
+ virtual bool visit(QQmlJS::AST::EmptyStatement *);
+ virtual bool visit(QQmlJS::AST::ExpressionStatement *);
+ virtual bool visit(QQmlJS::AST::IfStatement *);
+ virtual bool visit(QQmlJS::AST::DoWhileStatement *);
+ virtual bool visit(QQmlJS::AST::WhileStatement *);
+ virtual bool visit(QQmlJS::AST::ForStatement *);
+ virtual bool visit(QQmlJS::AST::LocalForStatement *);
+ virtual bool visit(QQmlJS::AST::ForEachStatement *);
+ virtual bool visit(QQmlJS::AST::LocalForEachStatement *);
+ virtual bool visit(QQmlJS::AST::ContinueStatement *);
+ virtual bool visit(QQmlJS::AST::BreakStatement *);
+ virtual bool visit(QQmlJS::AST::ReturnStatement *);
+ virtual bool visit(QQmlJS::AST::WithStatement *);
+
+ virtual bool visit(QQmlJS::AST::CaseBlock *);
+ virtual void endVisit(QQmlJS::AST::CaseBlock *);
+
+ virtual bool visit(QQmlJS::AST::SwitchStatement *);
+ virtual bool visit(QQmlJS::AST::CaseClause *);
+ virtual bool visit(QQmlJS::AST::DefaultClause *);
+ virtual bool visit(QQmlJS::AST::LabelledStatement *);
+ virtual bool visit(QQmlJS::AST::ThrowStatement *);
+ virtual bool visit(QQmlJS::AST::TryStatement *);
+ virtual bool visit(QQmlJS::AST::Catch *);
+ virtual bool visit(QQmlJS::AST::Finally *);
+ virtual bool visit(QQmlJS::AST::FunctionDeclaration *);
+ virtual bool visit(QQmlJS::AST::FunctionExpression *);
+ virtual bool visit(QQmlJS::AST::FormalParameterList *);
+ virtual bool visit(QQmlJS::AST::DebuggerStatement *);
+
+protected:
+ QString protect(const QString &string);
+
+private:
+ typedef QHash<QString, QString> StringHash;
+ void addExtra(quint32 start, quint32 finish);
+ void addMarkedUpToken(QQmlJS::AST::SourceLocation &location,
+ const QString &text,
+ const StringHash &attributes = StringHash());
+ void addVerbatim(QQmlJS::AST::SourceLocation first,
+ QQmlJS::AST::SourceLocation last = QQmlJS::AST::SourceLocation());
+ QString sourceText(QQmlJS::AST::SourceLocation &location);
+
+ QQmlJS::Engine *engine;
+ QList<ExtraType> extraTypes;
+ QList<QQmlJS::AST::SourceLocation> extraLocations;
+ QString source;
+ QString output;
+ quint32 cursor;
+ int extraIndex;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/qmlparser/qmlparser.pri b/src/tools/qdoc/qmlparser/qmlparser.pri
new file mode 100644
index 0000000000..6be85ba85a
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qmlparser.pri
@@ -0,0 +1,19 @@
+HEADERS += \
+ $$PWD/qqmljsast_p.h \
+ $$PWD/qqmljsastfwd_p.h \
+ $$PWD/qqmljsastvisitor_p.h \
+ $$PWD/qqmljsengine_p.h \
+ $$PWD/qqmljsgrammar_p.h \
+ $$PWD/qqmljslexer_p.h \
+ $$PWD/qqmljsmemorypool_p.h \
+ $$PWD/qqmljsparser_p.h \
+ $$PWD/qqmljsglobal_p.h \
+ $$PWD/qqmljskeywords_p.h
+
+SOURCES += \
+ $$PWD/qqmljsast.cpp \
+ $$PWD/qqmljsastvisitor.cpp \
+ $$PWD/qqmljsengine_p.cpp \
+ $$PWD/qqmljsgrammar.cpp \
+ $$PWD/qqmljslexer.cpp \
+ $$PWD/qqmljsparser.cpp
diff --git a/src/tools/qdoc/qmlparser/qqmljs.g b/src/tools/qdoc/qmlparser/qqmljs.g
new file mode 100644
index 0000000000..746fcb24df
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljs.g
@@ -0,0 +1,3016 @@
+----------------------------------------------------------------------------
+--
+-- Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+-- Contact: http://www.qt-project.org/
+--
+-- This file is part of the QtQml module of the Qt Toolkit.
+--
+-- $QT_BEGIN_LICENSE:LGPL-ONLY$
+-- GNU Lesser General Public License Usage
+-- This file may be used under the terms of the GNU Lesser
+-- General Public License version 2.1 as published by the Free Software
+-- Foundation and appearing in the file LICENSE.LGPL included in the
+-- packaging of this file. Please review the following information to
+-- ensure the GNU Lesser General Public License version 2.1 requirements
+-- will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+--
+-- If you have questions regarding the use of this file, please contact
+-- us via http://www.qt-project.org/.
+--
+-- $QT_END_LICENSE$
+--
+----------------------------------------------------------------------------
+
+%parser QQmlJSGrammar
+%decl qqmljsparser_p.h
+%impl qdeclarativejsparser.cpp
+%expect 2
+%expect-rr 2
+
+%token T_AND "&" T_AND_AND "&&" T_AND_EQ "&="
+%token T_BREAK "break" T_CASE "case" T_CATCH "catch"
+%token T_COLON ":" T_COMMA "," T_CONTINUE "continue"
+%token T_DEFAULT "default" T_DELETE "delete" T_DIVIDE_ "/"
+%token T_DIVIDE_EQ "/=" T_DO "do" T_DOT "."
+%token T_ELSE "else" T_EQ "=" T_EQ_EQ "=="
+%token T_EQ_EQ_EQ "===" T_FINALLY "finally" T_FOR "for"
+%token T_FUNCTION "function" T_GE ">=" T_GT ">"
+%token T_GT_GT ">>" T_GT_GT_EQ ">>=" T_GT_GT_GT ">>>"
+%token T_GT_GT_GT_EQ ">>>=" T_IDENTIFIER "identifier" T_IF "if"
+%token T_IN "in" T_INSTANCEOF "instanceof" T_LBRACE "{"
+%token T_LBRACKET "[" T_LE "<=" T_LPAREN "("
+%token T_LT "<" T_LT_LT "<<" T_LT_LT_EQ "<<="
+%token T_MINUS "-" T_MINUS_EQ "-=" T_MINUS_MINUS "--"
+%token T_NEW "new" T_NOT "!" T_NOT_EQ "!="
+%token T_NOT_EQ_EQ "!==" T_NUMERIC_LITERAL "numeric literal" T_OR "|"
+%token T_OR_EQ "|=" T_OR_OR "||" T_PLUS "+"
+%token T_PLUS_EQ "+=" T_PLUS_PLUS "++" T_QUESTION "?"
+%token T_RBRACE "}" T_RBRACKET "]" T_REMAINDER "%"
+%token T_REMAINDER_EQ "%=" T_RETURN "return" T_RPAREN ")"
+%token T_SEMICOLON ";" T_AUTOMATIC_SEMICOLON T_STAR "*"
+%token T_STAR_EQ "*=" T_STRING_LITERAL "string literal"
+%token T_PROPERTY "property" T_SIGNAL "signal" T_READONLY "readonly"
+%token T_SWITCH "switch" T_THIS "this" T_THROW "throw"
+%token T_TILDE "~" T_TRY "try" T_TYPEOF "typeof"
+%token T_VAR "var" T_VOID "void" T_WHILE "while"
+%token T_WITH "with" T_XOR "^" T_XOR_EQ "^="
+%token T_NULL "null" T_TRUE "true" T_FALSE "false"
+%token T_CONST "const"
+%token T_DEBUGGER "debugger"
+%token T_RESERVED_WORD "reserved word"
+%token T_MULTILINE_STRING_LITERAL "multiline string literal"
+%token T_COMMENT "comment"
+
+--- context keywords.
+%token T_PUBLIC "public"
+%token T_IMPORT "import"
+%token T_AS "as"
+%token T_ON "on"
+
+%token T_ERROR
+
+--- feed tokens
+%token T_FEED_UI_PROGRAM
+%token T_FEED_UI_OBJECT_MEMBER
+%token T_FEED_JS_STATEMENT
+%token T_FEED_JS_EXPRESSION
+%token T_FEED_JS_SOURCE_ELEMENT
+%token T_FEED_JS_PROGRAM
+
+%nonassoc SHIFT_THERE
+%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY
+%nonassoc REDUCE_HERE
+
+%start TopLevel
+
+/./****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QtDebug>
+#include <QtCore/QCoreApplication>
+
+#include <string.h>
+
+#include "qqmljsengine_p.h"
+#include "qqmljslexer_p.h"
+#include "qqmljsast_p.h"
+#include "qqmljsmemorypool_p.h"
+
+./
+
+/:/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+#ifndef QDECLARATIVEJSPARSER_P_H
+#define QDECLARATIVEJSPARSER_P_H
+
+#include "qqmljsglobal_p.h"
+#include "qqmljsgrammar_p.h"
+#include "qqmljsast_p.h"
+#include "qqmljsengine_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Engine;
+
+class QML_PARSER_EXPORT Parser: protected $table
+{
+public:
+ union Value {
+ int ival;
+ double dval;
+ AST::ArgumentList *ArgumentList;
+ AST::CaseBlock *CaseBlock;
+ AST::CaseClause *CaseClause;
+ AST::CaseClauses *CaseClauses;
+ AST::Catch *Catch;
+ AST::DefaultClause *DefaultClause;
+ AST::ElementList *ElementList;
+ AST::Elision *Elision;
+ AST::ExpressionNode *Expression;
+ AST::Finally *Finally;
+ AST::FormalParameterList *FormalParameterList;
+ AST::FunctionBody *FunctionBody;
+ AST::FunctionDeclaration *FunctionDeclaration;
+ AST::Node *Node;
+ AST::PropertyName *PropertyName;
+ AST::PropertyNameAndValueList *PropertyNameAndValueList;
+ AST::SourceElement *SourceElement;
+ AST::SourceElements *SourceElements;
+ AST::Statement *Statement;
+ AST::StatementList *StatementList;
+ AST::Block *Block;
+ AST::VariableDeclaration *VariableDeclaration;
+ AST::VariableDeclarationList *VariableDeclarationList;
+
+ AST::UiProgram *UiProgram;
+ AST::UiImportList *UiImportList;
+ AST::UiImport *UiImport;
+ AST::UiParameterList *UiParameterList;
+ AST::UiPublicMember *UiPublicMember;
+ AST::UiObjectDefinition *UiObjectDefinition;
+ AST::UiObjectInitializer *UiObjectInitializer;
+ AST::UiObjectBinding *UiObjectBinding;
+ AST::UiScriptBinding *UiScriptBinding;
+ AST::UiArrayBinding *UiArrayBinding;
+ AST::UiObjectMember *UiObjectMember;
+ AST::UiObjectMemberList *UiObjectMemberList;
+ AST::UiArrayMemberList *UiArrayMemberList;
+ AST::UiQualifiedId *UiQualifiedId;
+ };
+
+public:
+ Parser(Engine *engine);
+ ~Parser();
+
+ // parse a UI program
+ bool parse() { return parse(T_FEED_UI_PROGRAM); }
+ bool parseStatement() { return parse(T_FEED_JS_STATEMENT); }
+ bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); }
+ bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); }
+ bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); }
+ bool parseProgram() { return parse(T_FEED_JS_PROGRAM); }
+
+ AST::UiProgram *ast() const
+ { return AST::cast<AST::UiProgram *>(program); }
+
+ AST::Statement *statement() const
+ {
+ if (! program)
+ return 0;
+
+ return program->statementCast();
+ }
+
+ AST::ExpressionNode *expression() const
+ {
+ if (! program)
+ return 0;
+
+ return program->expressionCast();
+ }
+
+ AST::UiObjectMember *uiObjectMember() const
+ {
+ if (! program)
+ return 0;
+
+ return program->uiObjectMemberCast();
+ }
+
+ AST::Node *rootNode() const
+ { return program; }
+
+ QList<DiagnosticMessage> diagnosticMessages() const
+ { return diagnostic_messages; }
+
+ inline DiagnosticMessage diagnosticMessage() const
+ {
+ foreach (const DiagnosticMessage &d, diagnostic_messages) {
+ if (! d.kind == DiagnosticMessage::Warning)
+ return d;
+ }
+
+ return DiagnosticMessage();
+ }
+
+ inline QString errorMessage() const
+ { return diagnosticMessage().message; }
+
+ inline int errorLineNumber() const
+ { return diagnosticMessage().loc.startLine; }
+
+ inline int errorColumnNumber() const
+ { return diagnosticMessage().loc.startColumn; }
+
+protected:
+ bool parse(int startToken);
+
+ void reallocateStack();
+
+ inline Value &sym(int index)
+ { return sym_stack [tos + index - 1]; }
+
+ inline QStringRef &stringRef(int index)
+ { return string_stack [tos + index - 1]; }
+
+ inline AST::SourceLocation &loc(int index)
+ { return location_stack [tos + index - 1]; }
+
+ AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
+
+protected:
+ Engine *driver;
+ MemoryPool *pool;
+ int tos;
+ int stack_size;
+ Value *sym_stack;
+ int *state_stack;
+ AST::SourceLocation *location_stack;
+ QStringRef *string_stack;
+
+ AST::Node *program;
+
+ // error recovery
+ enum { TOKEN_BUFFER_SIZE = 3 };
+
+ struct SavedToken {
+ int token;
+ double dval;
+ AST::SourceLocation loc;
+ QStringRef spell;
+ };
+
+ double yylval;
+ QStringRef yytokenspell;
+ AST::SourceLocation yylloc;
+ AST::SourceLocation yyprevlloc;
+
+ SavedToken token_buffer[TOKEN_BUFFER_SIZE];
+ SavedToken *first_token;
+ SavedToken *last_token;
+
+ QList<DiagnosticMessage> diagnostic_messages;
+};
+
+} // end of namespace QQmlJS
+
+
+:/
+
+
+/.
+
+#include "qqmljsparser_p.h"
+#include <QVarLengthArray>
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+using namespace QQmlJS;
+
+QT_QML_BEGIN_NAMESPACE
+
+void Parser::reallocateStack()
+{
+ if (! stack_size)
+ stack_size = 128;
+ else
+ stack_size <<= 1;
+
+ sym_stack = reinterpret_cast<Value*> (realloc(sym_stack, stack_size * sizeof(Value)));
+ state_stack = reinterpret_cast<int*> (realloc(state_stack, stack_size * sizeof(int)));
+ location_stack = reinterpret_cast<AST::SourceLocation*> (realloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
+ string_stack = reinterpret_cast<QStringRef*> (realloc(string_stack, stack_size * sizeof(QStringRef)));
+}
+
+Parser::Parser(Engine *engine):
+ driver(engine),
+ pool(engine->pool()),
+ tos(0),
+ stack_size(0),
+ sym_stack(0),
+ state_stack(0),
+ location_stack(0),
+ string_stack(0),
+ first_token(0),
+ last_token(0)
+{
+}
+
+Parser::~Parser()
+{
+ if (stack_size) {
+ free(sym_stack);
+ free(state_stack);
+ free(location_stack);
+ free(string_stack);
+ }
+}
+
+static inline AST::SourceLocation location(Lexer *lexer)
+{
+ AST::SourceLocation loc;
+ loc.offset = lexer->tokenOffset();
+ loc.length = lexer->tokenLength();
+ loc.startLine = lexer->tokenStartLine();
+ loc.startColumn = lexer->tokenStartColumn();
+ return loc;
+}
+
+AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
+{
+ QVarLengthArray<QStringRef, 4> nameIds;
+ QVarLengthArray<AST::SourceLocation, 4> locations;
+
+ AST::ExpressionNode *it = expr;
+ while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
+ nameIds.append(m->name);
+ locations.append(m->identifierToken);
+ it = m->base;
+ }
+
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) {
+ AST::UiQualifiedId *q = new (pool) AST::UiQualifiedId(idExpr->name);
+ q->identifierToken = idExpr->identifierToken;
+
+ AST::UiQualifiedId *currentId = q;
+ for (int i = nameIds.size() - 1; i != -1; --i) {
+ currentId = new (pool) AST::UiQualifiedId(currentId, nameIds[i]);
+ currentId->identifierToken = locations[i];
+ }
+
+ return currentId->finish();
+ }
+
+ return 0;
+}
+
+bool Parser::parse(int startToken)
+{
+ Lexer *lexer = driver->lexer();
+ bool hadErrors = false;
+ int yytoken = -1;
+ int action = 0;
+
+ token_buffer[0].token = startToken;
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ tos = -1;
+ program = 0;
+
+ do {
+ if (++tos == stack_size)
+ reallocateStack();
+
+ state_stack[tos] = action;
+
+ _Lcheck_token:
+ if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) {
+ yyprevlloc = yylloc;
+
+ if (first_token == last_token) {
+ yytoken = lexer->lex();
+ yylval = lexer->tokenValue();
+ yytokenspell = lexer->tokenSpell();
+ yylloc = location(lexer);
+ } else {
+ yytoken = first_token->token;
+ yylval = first_token->dval;
+ yytokenspell = first_token->spell;
+ yylloc = first_token->loc;
+ ++first_token;
+ }
+ }
+
+ action = t_action(action, yytoken);
+ if (action > 0) {
+ if (action != ACCEPT_STATE) {
+ yytoken = -1;
+ sym(1).dval = yylval;
+ stringRef(1) = yytokenspell;
+ loc(1) = yylloc;
+ } else {
+ --tos;
+ return ! hadErrors;
+ }
+ } else if (action < 0) {
+ const int r = -action - 1;
+ tos -= rhs[r];
+
+ switch (r) {
+./
+
+--------------------------------------------------------------------------------------------------------
+-- Declarative UI
+--------------------------------------------------------------------------------------------------------
+
+TopLevel: T_FEED_UI_PROGRAM UiProgram ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_STATEMENT Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_EXPRESSION Expression ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_SOURCE_ELEMENT SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_UI_OBJECT_MEMBER UiObjectMember ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+TopLevel: T_FEED_JS_PROGRAM Program ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+./
+
+UiProgram: UiImportListOpt UiRootMember ;
+/.
+case $rule_number: {
+ sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiImportList,
+ sym(2).UiObjectMemberList->finish());
+} break;
+./
+
+UiImportListOpt: Empty ;
+UiImportListOpt: UiImportList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).UiImportList->finish();
+} break;
+./
+
+UiImportList: UiImport ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImport);
+} break;
+./
+
+UiImportList: UiImportList UiImport ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImportList, sym(2).UiImport);
+} break;
+./
+
+ImportId: MemberExpression ;
+
+UiImport: UiImportHead T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->semicolonToken = loc(2);
+} break;
+./
+
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->semicolonToken = loc(3);
+} break;
+./
+
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_NUMERIC_LITERAL T_AS JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->asToken = loc(3);
+ sym(1).UiImport->importIdToken = loc(4);
+ sym(1).UiImport->importId = stringRef(4);
+ sym(1).UiImport->semicolonToken = loc(5);
+} break;
+./
+
+UiImport: UiImportHead T_AS JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiImport: UiImportHead T_AS JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ sym(1).UiImport->asToken = loc(2);
+ sym(1).UiImport->importIdToken = loc(3);
+ sym(1).UiImport->importId = stringRef(3);
+ sym(1).UiImport->semicolonToken = loc(4);
+} break;
+./
+
+
+UiImportHead: T_IMPORT ImportId ;
+/.
+case $rule_number: {
+ AST::UiImport *node = 0;
+
+ if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
+ node = new (pool) AST::UiImport(importIdLiteral->value);
+ node->fileNameToken = loc(2);
+ } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
+ node = new (pool) AST::UiImport(qualifiedId);
+ node->fileNameToken = loc(2);
+ }
+
+ sym(1).Node = node;
+
+ if (node) {
+ node->importToken = loc(1);
+ } else {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id or a string literal")));
+
+ return false; // ### remove me
+ }
+} break;
+./
+
+Empty: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+UiRootMember: UiObjectDefinition ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
+} break;
+./
+
+UiObjectMemberList: UiObjectMember ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
+} break;
+./
+
+UiObjectMemberList: UiObjectMemberList UiObjectMember ;
+/.
+case $rule_number: {
+ AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList(
+ sym(1).UiObjectMemberList, sym(2).UiObjectMember);
+ sym(1).Node = node;
+} break;
+./
+
+UiArrayMemberList: UiObjectDefinition ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember);
+} break;
+./
+
+UiArrayMemberList: UiArrayMemberList T_COMMA UiObjectDefinition ;
+/.
+case $rule_number: {
+ AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList(
+ sym(1).UiArrayMemberList, sym(3).UiObjectMember);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectInitializer: T_LBRACE T_RBRACE ;
+/.
+case $rule_number: {
+ AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectInitializer: T_LBRACE UiObjectMemberList T_RBRACE ;
+/.
+case $rule_number: {
+ AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer(sym(2).UiObjectMemberList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectDefinition: UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId,
+ sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiObjectDefinition ;
+
+UiObjectMember: UiQualifiedId T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::UiArrayBinding *node = new (pool) AST::UiArrayBinding(
+ sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish());
+ node->colonToken = loc(2);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiQualifiedId T_COLON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
+ sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: UiQualifiedId T_ON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
+ sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ node->hasOnToken = true;
+ sym(1).Node = node;
+} break;
+./
+
+UiScriptStatement: Block ;
+UiScriptStatement: EmptyStatement ;
+UiScriptStatement: ExpressionStatement ;
+UiScriptStatement: IfStatement ;
+UiScriptStatement: WithStatement ;
+UiScriptStatement: SwitchStatement ;
+UiScriptStatement: TryStatement ;
+
+UiObjectMember: UiQualifiedId T_COLON UiScriptStatement ;
+/.
+case $rule_number:
+{
+ AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding(
+ sym(1).UiQualifiedId, sym(3).Statement);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiPropertyType: T_VAR ;
+UiPropertyType: T_RESERVED_WORD ;
+UiPropertyType: T_IDENTIFIER ;
+
+UiParameterListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+UiParameterListOpt: UiParameterList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).UiParameterList->finish ();
+} break;
+./
+
+UiParameterList: UiPropertyType JsIdentifier ;
+/.
+case $rule_number: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(stringRef(1), stringRef(2));
+ node->propertyTypeToken = loc(1);
+ node->identifierToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UiParameterList: UiParameterList T_COMMA UiPropertyType JsIdentifier ;
+/.
+case $rule_number: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, stringRef(3), stringRef(4));
+ node->commaToken = loc(2);
+ node->identifierToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_LPAREN UiParameterListOpt T_RPAREN T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2));
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->parameters = sym(4).UiParameterList;
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_SIGNAL T_IDENTIFIER T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2));
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6));
+ node->typeModifier = stringRef(2);
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3));
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_AUTOMATIC_SEMICOLON ;
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4));
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3),
+ sym(5).Statement);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_READONLY T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4),
+ sym(6).Statement);
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_DEFAULT T_PROPERTY UiPropertyType JsIdentifier T_COLON UiScriptStatement ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4),
+ sym(6).Statement);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY T_IDENTIFIER T_LT UiPropertyType T_GT JsIdentifier T_COLON T_LBRACKET UiArrayMemberList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6));
+ node->typeModifier = stringRef(2);
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6));
+ propertyName->identifierToken = loc(6);
+ propertyName->next = 0;
+
+ AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(
+ propertyName, sym(9).UiArrayMemberList->finish());
+ binding->colonToken = loc(7);
+ binding->lbracketToken = loc(8);
+ binding->rbracketToken = loc(10);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: T_PROPERTY UiPropertyType JsIdentifier T_COLON UiQualifiedId UiObjectInitializer ;
+/.
+case $rule_number: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3));
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3));
+ propertyName->identifierToken = loc(3);
+ propertyName->next = 0;
+
+ AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
+ propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer);
+ binding->colonToken = loc(4);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+./
+
+UiObjectMember: FunctionDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+} break;
+./
+
+UiObjectMember: VariableStatement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+} break;
+./
+
+JsIdentifier: T_IDENTIFIER;
+
+JsIdentifier: T_PROPERTY ;
+JsIdentifier: T_SIGNAL ;
+JsIdentifier: T_READONLY ;
+JsIdentifier: T_ON ;
+
+--------------------------------------------------------------------------------------------------------
+-- Expressions
+--------------------------------------------------------------------------------------------------------
+
+PrimaryExpression: T_THIS ;
+/.
+case $rule_number: {
+ AST::ThisExpression *node = new (pool) AST::ThisExpression();
+ node->thisToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: JsIdentifier ;
+/.
+case $rule_number: {
+ AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_NULL ;
+/.
+case $rule_number: {
+ AST::NullExpression *node = new (pool) AST::NullExpression();
+ node->nullToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_TRUE ;
+/.
+case $rule_number: {
+ AST::TrueLiteral *node = new (pool) AST::TrueLiteral();
+ node->trueToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_FALSE ;
+/.
+case $rule_number: {
+ AST::FalseLiteral *node = new (pool) AST::FalseLiteral();
+ node->falseToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_NUMERIC_LITERAL ;
+/.
+case $rule_number: {
+ AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_MULTILINE_STRING_LITERAL ;
+/.case $rule_number:./
+
+PrimaryExpression: T_STRING_LITERAL ;
+/.
+case $rule_number: {
+ AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1));
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_DIVIDE_ ;
+/:
+#define J_SCRIPT_REGEXPLITERAL_RULE1 $rule_number
+:/
+/.
+case $rule_number: {
+ bool rx = lexer->scanRegExp(Lexer::NoPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false; // ### remove me
+ }
+
+ loc(1).length = lexer->tokenLength();
+ yylloc = loc(1); // adjust the location of the current token
+
+ AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
+ driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_DIVIDE_EQ ;
+/:
+#define J_SCRIPT_REGEXPLITERAL_RULE2 $rule_number
+:/
+/.
+case $rule_number: {
+ bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false;
+ }
+
+ loc(1).length = lexer->tokenLength();
+ yylloc = loc(1); // adjust the location of the current token
+
+ AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
+ driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET Elision T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_COMMA T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
+ (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACKET ElementList T_COMMA Elision T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
+ sym(4).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+-- PrimaryExpression: T_LBRACE T_RBRACE ;
+-- /.
+-- case $rule_number: {
+-- sym(1).Node = new (pool) AST::ObjectLiteral();
+-- } break;
+-- ./
+
+PrimaryExpression: T_LBRACE PropertyNameAndValueListOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::ObjectLiteral *node = 0;
+ if (sym(2).Node)
+ node = new (pool) AST::ObjectLiteral(
+ sym(2).PropertyNameAndValueList->finish ());
+ else
+ node = new (pool) AST::ObjectLiteral();
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LBRACE PropertyNameAndValueList T_COMMA T_RBRACE ;
+/.
+case $rule_number: {
+ AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral(
+ sym(2).PropertyNameAndValueList->finish ());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PrimaryExpression: T_LPAREN Expression T_RPAREN ;
+/.
+case $rule_number: {
+ AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression);
+ node->lparenToken = loc(1);
+ node->rparenToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+UiQualifiedId: MemberExpression ;
+/.
+case $rule_number: {
+ if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
+ QLatin1String("Ignored annotation")));
+
+ sym(1).Expression = mem->base;
+ }
+
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false; // ### recover
+ }
+} break;
+./
+
+ElementList: AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression);
+} break;
+./
+
+ElementList: Elision AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression);
+} break;
+./
+
+ElementList: ElementList T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList,
+ (AST::Elision *) 0, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ElementList: ElementList T_COMMA Elision AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(),
+ sym(4).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+Elision: T_COMMA ;
+/.
+case $rule_number: {
+ AST::Elision *node = new (pool) AST::Elision();
+ node->commaToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Elision: Elision T_COMMA ;
+/.
+case $rule_number: {
+ AST::Elision *node = new (pool) AST::Elision(sym(1).Elision);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyNameAndValueList: PropertyName T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList(
+ sym(1).PropertyName, sym(3).Expression);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyNameAndValueList: PropertyNameAndValueList T_COMMA PropertyName T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList(
+ sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression);
+ node->commaToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_IDENTIFIER %prec SHIFT_THERE ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_SIGNAL ;
+/.case $rule_number:./
+
+PropertyName: T_PROPERTY ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_STRING_LITERAL ;
+/.
+case $rule_number: {
+ AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: T_NUMERIC_LITERAL ;
+/.
+case $rule_number: {
+ AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+PropertyName: ReservedIdentifier ;
+/.
+case $rule_number: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+ReservedIdentifier: T_BREAK ;
+ReservedIdentifier: T_CASE ;
+ReservedIdentifier: T_CATCH ;
+ReservedIdentifier: T_CONTINUE ;
+ReservedIdentifier: T_DEFAULT ;
+ReservedIdentifier: T_DELETE ;
+ReservedIdentifier: T_DO ;
+ReservedIdentifier: T_ELSE ;
+ReservedIdentifier: T_FALSE ;
+ReservedIdentifier: T_FINALLY ;
+ReservedIdentifier: T_FOR ;
+ReservedIdentifier: T_FUNCTION ;
+ReservedIdentifier: T_IF ;
+ReservedIdentifier: T_IN ;
+ReservedIdentifier: T_INSTANCEOF ;
+ReservedIdentifier: T_NEW ;
+ReservedIdentifier: T_NULL ;
+ReservedIdentifier: T_RETURN ;
+ReservedIdentifier: T_SWITCH ;
+ReservedIdentifier: T_THIS ;
+ReservedIdentifier: T_THROW ;
+ReservedIdentifier: T_TRUE ;
+ReservedIdentifier: T_TRY ;
+ReservedIdentifier: T_TYPEOF ;
+ReservedIdentifier: T_VAR ;
+ReservedIdentifier: T_VOID ;
+ReservedIdentifier: T_WHILE ;
+ReservedIdentifier: T_CONST ;
+ReservedIdentifier: T_DEBUGGER ;
+ReservedIdentifier: T_RESERVED_WORD ;
+ReservedIdentifier: T_WITH ;
+
+PropertyIdentifier: JsIdentifier ;
+PropertyIdentifier: ReservedIdentifier ;
+
+MemberExpression: PrimaryExpression ;
+MemberExpression: FunctionExpression ;
+
+MemberExpression: MemberExpression T_LBRACKET Expression T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+MemberExpression: MemberExpression T_DOT PropertyIdentifier ;
+/.
+case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+MemberExpression: T_NEW MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList);
+ node->newToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+NewExpression: MemberExpression ;
+
+NewExpression: T_NEW NewExpression ;
+/.
+case $rule_number: {
+ AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression);
+ node->newToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: MemberExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_LPAREN ArgumentListOpt T_RPAREN ;
+/.
+case $rule_number: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_LBRACKET Expression T_RBRACKET ;
+/.
+case $rule_number: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CallExpression: CallExpression T_DOT PropertyIdentifier ;
+/.
+case $rule_number: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+ArgumentListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ArgumentListOpt: ArgumentList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).ArgumentList->finish();
+} break;
+./
+
+ArgumentList: AssignmentExpression ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression);
+} break;
+./
+
+ArgumentList: ArgumentList T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LeftHandSideExpression: NewExpression ;
+LeftHandSideExpression: CallExpression ;
+PostfixExpression: LeftHandSideExpression ;
+
+PostfixExpression: LeftHandSideExpression T_PLUS_PLUS ;
+/.
+case $rule_number: {
+ AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression);
+ node->incrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+PostfixExpression: LeftHandSideExpression T_MINUS_MINUS ;
+/.
+case $rule_number: {
+ AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression);
+ node->decrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: PostfixExpression ;
+
+UnaryExpression: T_DELETE UnaryExpression ;
+/.
+case $rule_number: {
+ AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression);
+ node->deleteToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_VOID UnaryExpression ;
+/.
+case $rule_number: {
+ AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression);
+ node->voidToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_TYPEOF UnaryExpression ;
+/.
+case $rule_number: {
+ AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression);
+ node->typeofToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_PLUS_PLUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression);
+ node->incrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_MINUS_MINUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression);
+ node->decrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_PLUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression);
+ node->plusToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_MINUS UnaryExpression ;
+/.
+case $rule_number: {
+ AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression);
+ node->minusToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_TILDE UnaryExpression ;
+/.
+case $rule_number: {
+ AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression);
+ node->tildeToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+UnaryExpression: T_NOT UnaryExpression ;
+/.
+case $rule_number: {
+ AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression);
+ node->notToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: UnaryExpression ;
+
+MultiplicativeExpression: MultiplicativeExpression T_STAR UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Mul, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: MultiplicativeExpression T_DIVIDE_ UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Div, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+MultiplicativeExpression: MultiplicativeExpression T_REMAINDER UnaryExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Mod, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AdditiveExpression: MultiplicativeExpression ;
+
+AdditiveExpression: AdditiveExpression T_PLUS MultiplicativeExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Add, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AdditiveExpression: AdditiveExpression T_MINUS MultiplicativeExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Sub, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: AdditiveExpression ;
+
+ShiftExpression: ShiftExpression T_LT_LT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::LShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: ShiftExpression T_GT_GT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::RShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ShiftExpression: ShiftExpression T_GT_GT_GT AdditiveExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::URShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: ShiftExpression ;
+
+RelationalExpression: RelationalExpression T_LT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_GT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_LE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_GE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_INSTANCEOF ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpression: RelationalExpression T_IN ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::In, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: ShiftExpression ;
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_LT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_GT ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_LE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_GE ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+RelationalExpressionNotIn: RelationalExpressionNotIn T_INSTANCEOF ShiftExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: RelationalExpression ;
+
+EqualityExpression: EqualityExpression T_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_NOT_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_EQ_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpression: EqualityExpression T_NOT_EQ_EQ RelationalExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: RelationalExpressionNotIn ;
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ RelationalExpressionNotIn;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_EQ_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+EqualityExpressionNotIn: EqualityExpressionNotIn T_NOT_EQ_EQ RelationalExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseANDExpression: EqualityExpression ;
+
+BitwiseANDExpression: BitwiseANDExpression T_AND EqualityExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseANDExpressionNotIn: EqualityExpressionNotIn ;
+
+BitwiseANDExpressionNotIn: BitwiseANDExpressionNotIn T_AND EqualityExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseXORExpression: BitwiseANDExpression ;
+
+BitwiseXORExpression: BitwiseXORExpression T_XOR BitwiseANDExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseXORExpressionNotIn: BitwiseANDExpressionNotIn ;
+
+BitwiseXORExpressionNotIn: BitwiseXORExpressionNotIn T_XOR BitwiseANDExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseORExpression: BitwiseXORExpression ;
+
+BitwiseORExpression: BitwiseORExpression T_OR BitwiseXORExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BitwiseORExpressionNotIn: BitwiseXORExpressionNotIn ;
+
+BitwiseORExpressionNotIn: BitwiseORExpressionNotIn T_OR BitwiseXORExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalANDExpression: BitwiseORExpression ;
+
+LogicalANDExpression: LogicalANDExpression T_AND_AND BitwiseORExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalANDExpressionNotIn: BitwiseORExpressionNotIn ;
+
+LogicalANDExpressionNotIn: LogicalANDExpressionNotIn T_AND_AND BitwiseORExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalORExpression: LogicalANDExpression ;
+
+LogicalORExpression: LogicalORExpression T_OR_OR LogicalANDExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LogicalORExpressionNotIn: LogicalANDExpressionNotIn ;
+
+LogicalORExpressionNotIn: LogicalORExpressionNotIn T_OR_OR LogicalANDExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ConditionalExpression: LogicalORExpression ;
+
+ConditionalExpression: LogicalORExpression T_QUESTION AssignmentExpression T_COLON AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+ConditionalExpressionNotIn: LogicalORExpressionNotIn ;
+
+ConditionalExpressionNotIn: LogicalORExpressionNotIn T_QUESTION AssignmentExpressionNotIn T_COLON AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentExpression: ConditionalExpression ;
+
+AssignmentExpression: LeftHandSideExpression AssignmentOperator AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentExpressionNotIn: ConditionalExpressionNotIn ;
+
+AssignmentExpressionNotIn: LeftHandSideExpression AssignmentOperator AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+AssignmentOperator: T_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::Assign;
+} break;
+./
+
+AssignmentOperator: T_STAR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceMul;
+} break;
+./
+
+AssignmentOperator: T_DIVIDE_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceDiv;
+} break;
+./
+
+AssignmentOperator: T_REMAINDER_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceMod;
+} break;
+./
+
+AssignmentOperator: T_PLUS_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceAdd;
+} break;
+./
+
+AssignmentOperator: T_MINUS_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceSub;
+} break;
+./
+
+AssignmentOperator: T_LT_LT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceLeftShift;
+} break;
+./
+
+AssignmentOperator: T_GT_GT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceRightShift;
+} break;
+./
+
+AssignmentOperator: T_GT_GT_GT_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceURightShift;
+} break;
+./
+
+AssignmentOperator: T_AND_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceAnd;
+} break;
+./
+
+AssignmentOperator: T_XOR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceXor;
+} break;
+./
+
+AssignmentOperator: T_OR_EQ ;
+/.
+case $rule_number: {
+ sym(1).ival = QSOperator::InplaceOr;
+} break;
+./
+
+Expression: AssignmentExpression ;
+
+Expression: Expression T_COMMA AssignmentExpression ;
+/.
+case $rule_number: {
+ AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ExpressionOpt: Expression ;
+
+ExpressionNotIn: AssignmentExpressionNotIn ;
+
+ExpressionNotIn: ExpressionNotIn T_COMMA AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionNotInOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+ExpressionNotInOpt: ExpressionNotIn ;
+
+Statement: Block ;
+Statement: VariableStatement ;
+Statement: EmptyStatement ;
+Statement: ExpressionStatement ;
+Statement: IfStatement ;
+Statement: IterationStatement ;
+Statement: ContinueStatement ;
+Statement: BreakStatement ;
+Statement: ReturnStatement ;
+Statement: WithStatement ;
+Statement: LabelledStatement ;
+Statement: SwitchStatement ;
+Statement: ThrowStatement ;
+Statement: TryStatement ;
+Statement: DebuggerStatement ;
+
+
+Block: T_LBRACE StatementListOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::Block *node = new (pool) AST::Block(sym(2).StatementList);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+StatementList: Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::StatementList(sym(1).Statement);
+} break;
+./
+
+StatementList: StatementList Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement);
+} break;
+./
+
+StatementListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+StatementListOpt: StatementList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).StatementList->finish ();
+} break;
+./
+
+VariableStatement: VariableDeclarationKind VariableDeclarationList T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+VariableStatement: VariableDeclarationKind VariableDeclarationList T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(
+ sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+ node->declarationKindToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationKind: T_CONST ;
+/.
+case $rule_number: {
+ sym(1).ival = T_CONST;
+} break;
+./
+
+VariableDeclarationKind: T_VAR ;
+/.
+case $rule_number: {
+ sym(1).ival = T_VAR;
+} break;
+./
+
+VariableDeclarationList: VariableDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
+} break;
+./
+
+VariableDeclarationList: VariableDeclarationList T_COMMA VariableDeclaration ;
+/.
+case $rule_number: {
+ AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList(
+ sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationListNotIn: VariableDeclarationNotIn ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
+} break;
+./
+
+VariableDeclarationListNotIn: VariableDeclarationListNotIn T_COMMA VariableDeclarationNotIn ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+} break;
+./
+
+VariableDeclaration: JsIdentifier InitialiserOpt ;
+/.
+case $rule_number: {
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+VariableDeclarationNotIn: JsIdentifier InitialiserNotInOpt ;
+/.
+case $rule_number: {
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Initialiser: T_EQ AssignmentExpression ;
+/.
+case $rule_number: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+./
+
+InitialiserOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+InitialiserOpt: Initialiser ;
+
+InitialiserNotIn: T_EQ AssignmentExpressionNotIn ;
+/.
+case $rule_number: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+./
+
+InitialiserNotInOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+InitialiserNotInOpt: InitialiserNotIn ;
+
+EmptyStatement: T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::EmptyStatement *node = new (pool) AST::EmptyStatement();
+ node->semicolonToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+ExpressionStatement: Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ExpressionStatement: Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement T_ELSE Statement ;
+/.
+case $rule_number: {
+ AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->elseToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+IfStatement: T_IF T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+
+IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+IterationStatement: T_DO Statement T_WHILE T_LPAREN Expression T_RPAREN T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
+ node->doToken = loc(1);
+ node->whileToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_WHILE T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement);
+ node->whileToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN ExpressionNotInOpt T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression,
+ sym(5).Expression, sym(7).Expression, sym(9).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->firstSemicolonToken = loc(4);
+ node->secondSemicolonToken = loc(6);
+ node->rparenToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationListNotIn T_SEMICOLON ExpressionOpt T_SEMICOLON ExpressionOpt T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::LocalForStatement *node = new (pool) AST::LocalForStatement(
+ sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(8).Expression, sym(10).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->firstSemicolonToken = loc(5);
+ node->secondSemicolonToken = loc(7);
+ node->rparenToken = loc(9);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN LeftHandSideExpression T_IN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression,
+ sym(5).Expression, sym(7).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->inToken = loc(4);
+ node->rparenToken = loc(6);
+ sym(1).Node = node;
+} break;
+./
+
+IterationStatement: T_FOR T_LPAREN T_VAR VariableDeclarationNotIn T_IN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement(
+ sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->inToken = loc(5);
+ node->rparenToken = loc(7);
+ sym(1).Node = node;
+} break;
+./
+
+ContinueStatement: T_CONTINUE T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ContinueStatement: T_CONTINUE T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
+ node->continueToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ContinueStatement: T_CONTINUE JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ContinueStatement: T_CONTINUE JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
+ node->continueToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+BreakStatement: T_BREAK T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+BreakStatement: T_BREAK T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
+ node->breakToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+BreakStatement: T_BREAK JsIdentifier T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+BreakStatement: T_BREAK JsIdentifier T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
+ node->breakToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+ReturnStatement: T_RETURN ExpressionOpt T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ReturnStatement: T_RETURN ExpressionOpt T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression);
+ node->returnToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+WithStatement: T_WITH T_LPAREN Expression T_RPAREN Statement ;
+/.
+case $rule_number: {
+ AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement);
+ node->withToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+SwitchStatement: T_SWITCH T_LPAREN Expression T_RPAREN CaseBlock ;
+/.
+case $rule_number: {
+ AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock);
+ node->switchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+CaseBlock: T_LBRACE CaseClausesOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+CaseBlock: T_LBRACE CaseClausesOpt DefaultClause CaseClausesOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(5);
+ sym(1).Node = node;
+} break;
+./
+
+CaseClauses: CaseClause ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause);
+} break;
+./
+
+CaseClauses: CaseClauses CaseClause ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause);
+} break;
+./
+
+CaseClausesOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+CaseClausesOpt: CaseClauses ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).CaseClauses->finish ();
+} break;
+./
+
+CaseClause: T_CASE Expression T_COLON StatementListOpt ;
+/.
+case $rule_number: {
+ AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList);
+ node->caseToken = loc(1);
+ node->colonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+DefaultClause: T_DEFAULT T_COLON StatementListOpt ;
+/.
+case $rule_number: {
+ AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList);
+ node->defaultToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LabelledStatement: T_SIGNAL T_COLON Statement ;
+/.case $rule_number:./
+
+LabelledStatement: T_PROPERTY T_COLON Statement ;
+/.
+case $rule_number: {
+ AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+LabelledStatement: T_IDENTIFIER T_COLON Statement ;
+/.
+case $rule_number: {
+ AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+ThrowStatement: T_THROW Expression T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+ThrowStatement: T_THROW Expression T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
+ node->throwToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Catch ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Finally ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+TryStatement: T_TRY Block Catch Finally ;
+/.
+case $rule_number: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+Catch: T_CATCH T_LPAREN JsIdentifier T_RPAREN Block ;
+/.
+case $rule_number: {
+ AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block);
+ node->catchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->identifierToken = loc(3);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+./
+
+Finally: T_FINALLY Block ;
+/.
+case $rule_number: {
+ AST::Finally *node = new (pool) AST::Finally(sym(2).Block);
+ node->finallyToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+DebuggerStatement: T_DEBUGGER T_AUTOMATIC_SEMICOLON ; -- automatic semicolon
+DebuggerStatement: T_DEBUGGER T_SEMICOLON ;
+/.
+case $rule_number: {
+ AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
+ node->debuggerToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+./
+
+FunctionDeclaration: T_FUNCTION JsIdentifier T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+FunctionExpression: T_FUNCTION IdentifierOpt T_LPAREN FormalParameterListOpt T_RPAREN T_LBRACE FunctionBodyOpt T_RBRACE ;
+/.
+case $rule_number: {
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ if (! stringRef(2).isNull())
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterList: JsIdentifier ;
+/.
+case $rule_number: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterList: FormalParameterList T_COMMA JsIdentifier ;
+/.
+case $rule_number: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3));
+ node->commaToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+./
+
+FormalParameterListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+FormalParameterListOpt: FormalParameterList ;
+/.
+case $rule_number: {
+ sym(1).Node = sym(1).FormalParameterList->finish ();
+} break;
+./
+
+FunctionBodyOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+FunctionBodyOpt: FunctionBody ;
+
+FunctionBody: SourceElements ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ());
+} break;
+./
+
+Program: Empty ;
+
+Program: SourceElements ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ());
+} break;
+./
+
+SourceElements: SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement);
+} break;
+./
+
+SourceElements: SourceElements SourceElement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement);
+} break;
+./
+
+SourceElement: Statement ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement);
+} break;
+./
+
+SourceElement: FunctionDeclaration ;
+/.
+case $rule_number: {
+ sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration);
+} break;
+./
+
+IdentifierOpt: ;
+/.
+case $rule_number: {
+ stringRef(1) = QStringRef();
+} break;
+./
+
+IdentifierOpt: JsIdentifier ;
+
+PropertyNameAndValueListOpt: ;
+/.
+case $rule_number: {
+ sym(1).Node = 0;
+} break;
+./
+
+PropertyNameAndValueListOpt: PropertyNameAndValueList ;
+
+/.
+ } // switch
+ action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT);
+ } // if
+ } while (action != 0);
+
+ if (first_token == last_token) {
+ const int errorState = state_stack[tos];
+
+ // automatic insertion of `;'
+ if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken)) {
+ SavedToken &tk = token_buffer[0];
+ tk.token = yytoken;
+ tk.dval = yylval;
+ tk.spell = yytokenspell;
+ tk.loc = yylloc;
+
+ yylloc = yyprevlloc;
+ yylloc.offset += yylloc.length;
+ yylloc.startColumn += yylloc.length;
+ yylloc.length = 0;
+
+ //const QString msg = qApp->translate("QQmlParser", "Missing `;'");
+ //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg));
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ yytoken = T_SEMICOLON;
+ yylval = 0;
+
+ action = errorState;
+
+ goto _Lcheck_token;
+ }
+
+ hadErrors = true;
+
+ token_buffer[0].token = yytoken;
+ token_buffer[0].dval = yylval;
+ token_buffer[0].spell = yytokenspell;
+ token_buffer[0].loc = yylloc;
+
+ token_buffer[1].token = yytoken = lexer->lex();
+ token_buffer[1].dval = yylval = lexer->tokenValue();
+ token_buffer[1].spell = yytokenspell = lexer->tokenSpell();
+ token_buffer[1].loc = yylloc = location(lexer);
+
+ if (t_action(errorState, yytoken)) {
+ QString msg;
+ int token = token_buffer[0].token;
+ if (token < 0 || token >= TERMINAL_COUNT)
+ msg = qApp->translate("QQmlParser", "Syntax error");
+ else
+ msg = qApp->translate("QQmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+
+ static int tokens[] = {
+ T_PLUS,
+ T_EQ,
+
+ T_COMMA,
+ T_COLON,
+ T_SEMICOLON,
+
+ T_RPAREN, T_RBRACKET, T_RBRACE,
+
+ T_NUMERIC_LITERAL,
+ T_IDENTIFIER,
+
+ T_LPAREN, T_LBRACKET, T_LBRACE,
+
+ EOF_SYMBOL
+ };
+
+ for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) {
+ int a = t_action(errorState, *tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = *tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[2];
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ for (int tk = 1; tk < TERMINAL_COUNT; ++tk) {
+ if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM ||
+ tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION ||
+ tk == T_FEED_JS_SOURCE_ELEMENT)
+ continue;
+
+ int a = t_action(errorState, tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = qApp->translate("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ const QString msg = qApp->translate("QQmlParser", "Syntax error");
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ }
+
+ return false;
+}
+
+QT_QML_END_NAMESPACE
+
+
+./
+/:
+QT_QML_END_NAMESPACE
+
+
+
+#endif // QDECLARATIVEJSPARSER_P_H
+:/
diff --git a/src/tools/qdoc/qmlparser/qqmljsast.cpp b/src/tools/qdoc/qmlparser/qqmljsast.cpp
new file mode 100644
index 0000000000..d0b984fc9e
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsast.cpp
@@ -0,0 +1,931 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmljsast_p.h"
+
+#include "qqmljsastvisitor_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS { namespace AST {
+
+void Node::accept(Visitor *visitor)
+{
+ if (visitor->preVisit(this)) {
+ accept0(visitor);
+ }
+ visitor->postVisit(this);
+}
+
+void Node::accept(Node *node, Visitor *visitor)
+{
+ if (node)
+ node->accept(visitor);
+}
+
+ExpressionNode *Node::expressionCast()
+{
+ return 0;
+}
+
+BinaryExpression *Node::binaryExpressionCast()
+{
+ return 0;
+}
+
+Statement *Node::statementCast()
+{
+ return 0;
+}
+
+UiObjectMember *Node::uiObjectMemberCast()
+{
+ return 0;
+}
+
+ExpressionNode *ExpressionNode::expressionCast()
+{
+ return this;
+}
+
+BinaryExpression *BinaryExpression::binaryExpressionCast()
+{
+ return this;
+}
+
+Statement *Statement::statementCast()
+{
+ return this;
+}
+
+UiObjectMember *UiObjectMember::uiObjectMemberCast()
+{
+ return this;
+}
+
+void NestedExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+ visitor->endVisit(this);
+}
+
+void ThisExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void IdentifierExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NullExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void TrueLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void FalseLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void StringLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NumericLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void RegExpLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArrayLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ accept(elision, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ObjectLiteral::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(properties, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ElementList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ElementList *it = this; it; it = it->next) {
+ accept(it->elision, visitor);
+ accept(it->expression, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void Elision::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ // ###
+ }
+
+ visitor->endVisit(this);
+}
+
+void PropertyNameAndValueList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (PropertyNameAndValueList *it = this; it; it = it->next) {
+ accept(it->name, visitor);
+ accept(it->value, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void IdentifierPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void StringLiteralPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void NumericLiteralPropertyName::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArrayMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FieldMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NewMemberExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(arguments, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NewExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CallExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ accept(arguments, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ArgumentList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (ArgumentList *it = this; it; it = it->next) {
+ accept(it->expression, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void PostIncrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PostDecrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(base, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DeleteExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void VoidExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TypeOfExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PreIncrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void PreDecrementExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UnaryPlusExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UnaryMinusExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TildeExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void NotExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void BinaryExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(left, visitor);
+ accept(right, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ConditionalExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(ok, visitor);
+ accept(ko, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Expression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(left, visitor);
+ accept(right, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Block::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void StatementList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (StatementList *it = this; it; it = it->next) {
+ accept(it->statement, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarations, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableDeclarationList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (VariableDeclarationList *it = this; it; it = it->next) {
+ accept(it->declaration, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void VariableDeclaration::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void EmptyStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ExpressionStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void IfStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(ok, visitor);
+ accept(ko, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DoWhileStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void WhileStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ForStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(initialiser, visitor);
+ accept(condition, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LocalForStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declarations, visitor);
+ accept(condition, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ForEachStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(initialiser, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LocalForEachStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ContinueStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void BreakStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void ReturnStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void WithStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void SwitchStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(block, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseBlock::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(clauses, visitor);
+ accept(defaultClause, visitor);
+ accept(moreClauses, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseClauses::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (CaseClauses *it = this; it; it = it->next) {
+ accept(it->clause, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void CaseClause::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DefaultClause::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void LabelledStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void ThrowStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(expression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void TryStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(catchExpression, visitor);
+ accept(finallyExpression, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Catch::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Finally::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionDeclaration::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(formals, visitor);
+ accept(body, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionExpression::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(formals, visitor);
+ accept(body, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void FormalParameterList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ // ###
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionBody::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void Program::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(elements, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void SourceElements::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (SourceElements *it = this; it; it = it->next) {
+ accept(it->element, visitor);
+ }
+ }
+
+ visitor->endVisit(this);
+}
+
+void FunctionSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(declaration, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void StatementSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void DebuggerStatement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiProgram::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(imports, visitor);
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiPublicMember::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(statement, visitor);
+ accept(binding, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectDefinition::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedTypeNameId, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectInitializer::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(qualifiedTypeNameId, visitor);
+ accept(initializer, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiScriptBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(statement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiArrayBinding::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(qualifiedId, visitor);
+ accept(members, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiObjectMemberList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiObjectMemberList *it = this; it; it = it->next)
+ accept(it->member, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiArrayMemberList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ for (UiArrayMemberList *it = this; it; it = it->next)
+ accept(it->member, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiQualifiedId::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiImport::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(importUri, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiImportList::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(import, visitor);
+ accept(next, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+void UiSourceElement::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(sourceElement, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
+} } // namespace QQmlJS::AST
+
+QT_QML_END_NAMESPACE
+
+
diff --git a/src/tools/qdoc/qmlparser/qqmljsast_p.h b/src/tools/qdoc/qmlparser/qqmljsast_p.h
new file mode 100644
index 0000000000..f85eb4ca5f
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsast_p.h
@@ -0,0 +1,2640 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSAST_P_H
+#define QQMLJSAST_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqmljsastvisitor_p.h"
+#include "qqmljsglobal_p.h"
+#include "qqmljsmemorypool_p.h"
+
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+#define QQMLJS_DECLARE_AST_NODE(name) \
+ enum { K = Kind_##name };
+
+namespace QSOperator // ### rename
+{
+
+enum Op {
+ Add,
+ And,
+ InplaceAnd,
+ Assign,
+ BitAnd,
+ BitOr,
+ BitXor,
+ InplaceSub,
+ Div,
+ InplaceDiv,
+ Equal,
+ Ge,
+ Gt,
+ In,
+ InplaceAdd,
+ InstanceOf,
+ Le,
+ LShift,
+ InplaceLeftShift,
+ Lt,
+ Mod,
+ InplaceMod,
+ Mul,
+ InplaceMul,
+ NotEqual,
+ Or,
+ InplaceOr,
+ RShift,
+ InplaceRightShift,
+ StrictEqual,
+ StrictNotEqual,
+ Sub,
+ URShift,
+ InplaceURightShift,
+ InplaceXor
+};
+
+} // namespace QSOperator
+
+namespace QQmlJS {
+
+namespace AST {
+
+template <typename _T1, typename _T2>
+_T1 cast(_T2 *ast)
+{
+ if (ast && ast->kind == static_cast<_T1>(0)->K)
+ return static_cast<_T1>(ast);
+
+ return 0;
+}
+
+class QML_PARSER_EXPORT Node: public Managed
+{
+public:
+ enum Kind {
+ Kind_Undefined,
+
+ Kind_ArgumentList,
+ Kind_ArrayLiteral,
+ Kind_ArrayMemberExpression,
+ Kind_BinaryExpression,
+ Kind_Block,
+ Kind_BreakStatement,
+ Kind_CallExpression,
+ Kind_CaseBlock,
+ Kind_CaseClause,
+ Kind_CaseClauses,
+ Kind_Catch,
+ Kind_ConditionalExpression,
+ Kind_ContinueStatement,
+ Kind_DebuggerStatement,
+ Kind_DefaultClause,
+ Kind_DeleteExpression,
+ Kind_DoWhileStatement,
+ Kind_ElementList,
+ Kind_Elision,
+ Kind_EmptyStatement,
+ Kind_Expression,
+ Kind_ExpressionStatement,
+ Kind_FalseLiteral,
+ Kind_FieldMemberExpression,
+ Kind_Finally,
+ Kind_ForEachStatement,
+ Kind_ForStatement,
+ Kind_FormalParameterList,
+ Kind_FunctionBody,
+ Kind_FunctionDeclaration,
+ Kind_FunctionExpression,
+ Kind_FunctionSourceElement,
+ Kind_IdentifierExpression,
+ Kind_IdentifierPropertyName,
+ Kind_IfStatement,
+ Kind_LabelledStatement,
+ Kind_LocalForEachStatement,
+ Kind_LocalForStatement,
+ Kind_NewExpression,
+ Kind_NewMemberExpression,
+ Kind_NotExpression,
+ Kind_NullExpression,
+ Kind_NumericLiteral,
+ Kind_NumericLiteralPropertyName,
+ Kind_ObjectLiteral,
+ Kind_PostDecrementExpression,
+ Kind_PostIncrementExpression,
+ Kind_PreDecrementExpression,
+ Kind_PreIncrementExpression,
+ Kind_Program,
+ Kind_PropertyName,
+ Kind_PropertyNameAndValueList,
+ Kind_RegExpLiteral,
+ Kind_ReturnStatement,
+ Kind_SourceElement,
+ Kind_SourceElements,
+ Kind_StatementList,
+ Kind_StatementSourceElement,
+ Kind_StringLiteral,
+ Kind_StringLiteralPropertyName,
+ Kind_SwitchStatement,
+ Kind_ThisExpression,
+ Kind_ThrowStatement,
+ Kind_TildeExpression,
+ Kind_TrueLiteral,
+ Kind_TryStatement,
+ Kind_TypeOfExpression,
+ Kind_UnaryMinusExpression,
+ Kind_UnaryPlusExpression,
+ Kind_VariableDeclaration,
+ Kind_VariableDeclarationList,
+ Kind_VariableStatement,
+ Kind_VoidExpression,
+ Kind_WhileStatement,
+ Kind_WithStatement,
+ Kind_NestedExpression,
+
+ Kind_UiArrayBinding,
+ Kind_UiImport,
+ Kind_UiImportList,
+ Kind_UiObjectBinding,
+ Kind_UiObjectDefinition,
+ Kind_UiObjectInitializer,
+ Kind_UiObjectMemberList,
+ Kind_UiArrayMemberList,
+ Kind_UiProgram,
+ Kind_UiParameterList,
+ Kind_UiPublicMember,
+ Kind_UiQualifiedId,
+ Kind_UiScriptBinding,
+ Kind_UiSourceElement
+ };
+
+ inline Node()
+ : kind(Kind_Undefined) {}
+
+ // NOTE: node destructors are never called,
+ // instead we block free the memory
+ // (see the NodePool class)
+ virtual ~Node() {}
+
+ virtual ExpressionNode *expressionCast();
+ virtual BinaryExpression *binaryExpressionCast();
+ virtual Statement *statementCast();
+ virtual UiObjectMember *uiObjectMemberCast();
+
+ void accept(Visitor *visitor);
+ static void accept(Node *node, Visitor *visitor);
+
+ inline static void acceptChild(Node *node, Visitor *visitor)
+ { return accept(node, visitor); } // ### remove
+
+ virtual void accept0(Visitor *visitor) = 0;
+ virtual SourceLocation firstSourceLocation() const = 0;
+ virtual SourceLocation lastSourceLocation() const = 0;
+
+// attributes
+ int kind;
+};
+
+class QML_PARSER_EXPORT ExpressionNode: public Node
+{
+public:
+ ExpressionNode() {}
+
+ virtual ExpressionNode *expressionCast();
+};
+
+class QML_PARSER_EXPORT Statement: public Node
+{
+public:
+ Statement() {}
+
+ virtual Statement *statementCast();
+};
+
+class QML_PARSER_EXPORT NestedExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NestedExpression)
+
+ NestedExpression(ExpressionNode *expression)
+ : expression(expression)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lparenToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ThisExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ThisExpression)
+
+ ThisExpression() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return thisToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return thisToken; }
+
+// attributes
+ SourceLocation thisToken;
+};
+
+class QML_PARSER_EXPORT IdentifierExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(IdentifierExpression)
+
+ IdentifierExpression(const QStringRef &n):
+ name (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return identifierToken; }
+
+// attributes
+ QStringRef name;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT NullExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NullExpression)
+
+ NullExpression() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return nullToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return nullToken; }
+
+// attributes
+ SourceLocation nullToken;
+};
+
+class QML_PARSER_EXPORT TrueLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TrueLiteral)
+
+ TrueLiteral() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return trueToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return trueToken; }
+
+// attributes
+ SourceLocation trueToken;
+};
+
+class QML_PARSER_EXPORT FalseLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FalseLiteral)
+
+ FalseLiteral() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return falseToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return falseToken; }
+
+// attributes
+ SourceLocation falseToken;
+};
+
+class QML_PARSER_EXPORT NumericLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NumericLiteral)
+
+ NumericLiteral(double v):
+ value(v) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ double value;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT StringLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(StringLiteral)
+
+ StringLiteral(const QStringRef &v):
+ value (v) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ QStringRef value;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT RegExpLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(RegExpLiteral)
+
+ RegExpLiteral(const QStringRef &p, int f):
+ pattern (p), flags (f) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return literalToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return literalToken; }
+
+// attributes:
+ QStringRef pattern;
+ int flags;
+ SourceLocation literalToken;
+};
+
+class QML_PARSER_EXPORT ArrayLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ArrayLiteral)
+
+ ArrayLiteral(Elision *e):
+ elements (0), elision (e)
+ { kind = K; }
+
+ ArrayLiteral(ElementList *elts):
+ elements (elts), elision (0)
+ { kind = K; }
+
+ ArrayLiteral(ElementList *elts, Elision *e):
+ elements (elts), elision (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbracketToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+// attributes
+ ElementList *elements;
+ Elision *elision;
+ SourceLocation lbracketToken;
+ SourceLocation commaToken;
+ SourceLocation rbracketToken;
+};
+
+class QML_PARSER_EXPORT ObjectLiteral: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ObjectLiteral)
+
+ ObjectLiteral():
+ properties (0) { kind = K; }
+
+ ObjectLiteral(PropertyNameAndValueList *plist):
+ properties (plist) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ PropertyNameAndValueList *properties;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT Elision: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Elision)
+
+ Elision():
+ next (this) { kind = K; }
+
+ Elision(Elision *previous)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return commaToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : commaToken; }
+
+ inline Elision *finish ()
+ {
+ Elision *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ Elision *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT ElementList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ElementList)
+
+ ElementList(Elision *e, ExpressionNode *expr):
+ elision (e), expression (expr), next (this)
+ { kind = K; }
+
+ ElementList(ElementList *previous, Elision *e, ExpressionNode *expr):
+ elision (e), expression (expr)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ inline ElementList *finish ()
+ {
+ ElementList *front = next;
+ next = 0;
+ return front;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (elision)
+ return elision->firstSourceLocation();
+ return expression->firstSourceLocation();
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (next)
+ return next->lastSourceLocation();
+ return expression->lastSourceLocation();
+ }
+
+// attributes
+ Elision *elision;
+ ExpressionNode *expression;
+ ElementList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT PropertyName: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PropertyName)
+
+ PropertyName() { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return propertyNameToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return propertyNameToken; }
+
+// attributes
+ SourceLocation propertyNameToken;
+};
+
+class QML_PARSER_EXPORT PropertyNameAndValueList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PropertyNameAndValueList)
+
+ PropertyNameAndValueList(PropertyName *n, ExpressionNode *v):
+ name (n), value (v), next (this)
+ { kind = K; }
+
+ PropertyNameAndValueList(PropertyNameAndValueList *previous, PropertyName *n, ExpressionNode *v):
+ name (n), value (v)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return name->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (next)
+ return next->lastSourceLocation();
+ return value->lastSourceLocation();
+ }
+
+ inline PropertyNameAndValueList *finish ()
+ {
+ PropertyNameAndValueList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ PropertyName *name;
+ ExpressionNode *value;
+ PropertyNameAndValueList *next;
+ SourceLocation colonToken;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT IdentifierPropertyName: public PropertyName
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(IdentifierPropertyName)
+
+ IdentifierPropertyName(const QStringRef &n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ QStringRef id;
+};
+
+class QML_PARSER_EXPORT StringLiteralPropertyName: public PropertyName
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(StringLiteralPropertyName)
+
+ StringLiteralPropertyName(const QStringRef &n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ QStringRef id;
+};
+
+class QML_PARSER_EXPORT NumericLiteralPropertyName: public PropertyName
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NumericLiteralPropertyName)
+
+ NumericLiteralPropertyName(double n):
+ id (n) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ double id;
+};
+
+class QML_PARSER_EXPORT ArrayMemberExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ArrayMemberExpression)
+
+ ArrayMemberExpression(ExpressionNode *b, ExpressionNode *e):
+ base (b), expression (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+// attributes
+ ExpressionNode *base;
+ ExpressionNode *expression;
+ SourceLocation lbracketToken;
+ SourceLocation rbracketToken;
+};
+
+class QML_PARSER_EXPORT FieldMemberExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FieldMemberExpression)
+
+ FieldMemberExpression(ExpressionNode *b, const QStringRef &n):
+ base (b), name (n)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return identifierToken; }
+
+ // attributes
+ ExpressionNode *base;
+ QStringRef name;
+ SourceLocation dotToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT NewMemberExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NewMemberExpression)
+
+ NewMemberExpression(ExpressionNode *b, ArgumentList *a):
+ base (b), arguments (a)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return newToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+ // attributes
+ ExpressionNode *base;
+ ArgumentList *arguments;
+ SourceLocation newToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT NewExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NewExpression)
+
+ NewExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return newToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation newToken;
+};
+
+class QML_PARSER_EXPORT CallExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(CallExpression)
+
+ CallExpression(ExpressionNode *b, ArgumentList *a):
+ base (b), arguments (a)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rparenToken; }
+
+// attributes
+ ExpressionNode *base;
+ ArgumentList *arguments;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ArgumentList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ArgumentList)
+
+ ArgumentList(ExpressionNode *e):
+ expression (e), next (this)
+ { kind = K; }
+
+ ArgumentList(ArgumentList *previous, ExpressionNode *e):
+ expression (e)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return expression->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (next)
+ return next->lastSourceLocation();
+ return expression->lastSourceLocation();
+ }
+
+ inline ArgumentList *finish ()
+ {
+ ArgumentList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ ExpressionNode *expression;
+ ArgumentList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT PostIncrementExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PostIncrementExpression)
+
+ PostIncrementExpression(ExpressionNode *b):
+ base (b) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return incrementToken; }
+
+// attributes
+ ExpressionNode *base;
+ SourceLocation incrementToken;
+};
+
+class QML_PARSER_EXPORT PostDecrementExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PostDecrementExpression)
+
+ PostDecrementExpression(ExpressionNode *b):
+ base (b) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return base->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return decrementToken; }
+
+// attributes
+ ExpressionNode *base;
+ SourceLocation decrementToken;
+};
+
+class QML_PARSER_EXPORT DeleteExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(DeleteExpression)
+
+ DeleteExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return deleteToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation deleteToken;
+};
+
+class QML_PARSER_EXPORT VoidExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(VoidExpression)
+
+ VoidExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return voidToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation voidToken;
+};
+
+class QML_PARSER_EXPORT TypeOfExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TypeOfExpression)
+
+ TypeOfExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return typeofToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation typeofToken;
+};
+
+class QML_PARSER_EXPORT PreIncrementExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PreIncrementExpression)
+
+ PreIncrementExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return incrementToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation incrementToken;
+};
+
+class QML_PARSER_EXPORT PreDecrementExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(PreDecrementExpression)
+
+ PreDecrementExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return decrementToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation decrementToken;
+};
+
+class QML_PARSER_EXPORT UnaryPlusExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UnaryPlusExpression)
+
+ UnaryPlusExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return plusToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation plusToken;
+};
+
+class QML_PARSER_EXPORT UnaryMinusExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UnaryMinusExpression)
+
+ UnaryMinusExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return minusToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation minusToken;
+};
+
+class QML_PARSER_EXPORT TildeExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TildeExpression)
+
+ TildeExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return tildeToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation tildeToken;
+};
+
+class QML_PARSER_EXPORT NotExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(NotExpression)
+
+ NotExpression(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return notToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation notToken;
+};
+
+class QML_PARSER_EXPORT BinaryExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(BinaryExpression)
+
+ BinaryExpression(ExpressionNode *l, int o, ExpressionNode *r):
+ left (l), op (o), right (r)
+ { kind = K; }
+
+ virtual BinaryExpression *binaryExpressionCast();
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return left->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return right->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *left;
+ int op;
+ ExpressionNode *right;
+ SourceLocation operatorToken;
+};
+
+class QML_PARSER_EXPORT ConditionalExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ConditionalExpression)
+
+ ConditionalExpression(ExpressionNode *e, ExpressionNode *t, ExpressionNode *f):
+ expression (e), ok (t), ko (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return expression->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return ko->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ ExpressionNode *ok;
+ ExpressionNode *ko;
+ SourceLocation questionToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT Expression: public ExpressionNode // ### rename
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Expression)
+
+ Expression(ExpressionNode *l, ExpressionNode *r):
+ left (l), right (r) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return left->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return right->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *left;
+ ExpressionNode *right;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT Block: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Block)
+
+ Block(StatementList *slist):
+ statements (slist) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+ // attributes
+ StatementList *statements;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT StatementList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(StatementList)
+
+ StatementList(Statement *stmt):
+ statement (stmt), next (this)
+ { kind = K; }
+
+ StatementList(StatementList *previous, Statement *stmt):
+ statement (stmt)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return statement->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : statement->lastSourceLocation(); }
+
+ inline StatementList *finish ()
+ {
+ StatementList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ Statement *statement;
+ StatementList *next;
+};
+
+class QML_PARSER_EXPORT VariableStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(VariableStatement)
+
+ VariableStatement(VariableDeclarationList *vlist):
+ declarations (vlist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return declarationKindToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ VariableDeclarationList *declarations;
+ SourceLocation declarationKindToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT VariableDeclaration: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(VariableDeclaration)
+
+ VariableDeclaration(const QStringRef &n, ExpressionNode *e):
+ name (n), expression (e), readOnly(false)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return expression ? expression->lastSourceLocation() : identifierToken; }
+
+// attributes
+ QStringRef name;
+ ExpressionNode *expression;
+ bool readOnly;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT VariableDeclarationList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(VariableDeclarationList)
+
+ VariableDeclarationList(VariableDeclaration *decl):
+ declaration (decl), next (this)
+ { kind = K; }
+
+ VariableDeclarationList(VariableDeclarationList *previous, VariableDeclaration *decl):
+ declaration (decl)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return declaration->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (next)
+ return next->lastSourceLocation();
+ return declaration->lastSourceLocation();
+ }
+
+ inline VariableDeclarationList *finish (bool readOnly)
+ {
+ VariableDeclarationList *front = next;
+ next = 0;
+ if (readOnly) {
+ VariableDeclarationList *vdl;
+ for (vdl = front; vdl != 0; vdl = vdl->next)
+ vdl->declaration->readOnly = true;
+ }
+ return front;
+ }
+
+// attributes
+ VariableDeclaration *declaration;
+ VariableDeclarationList *next;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT EmptyStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(EmptyStatement)
+
+ EmptyStatement() { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return semicolonToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT ExpressionStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ExpressionStatement)
+
+ ExpressionStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return expression->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT IfStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(IfStatement)
+
+ IfStatement(ExpressionNode *e, Statement *t, Statement *f = 0):
+ expression (e), ok (t), ko (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return ifToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (ko)
+ return ko->lastSourceLocation();
+
+ return ok->lastSourceLocation();
+ }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *ok;
+ Statement *ko;
+ SourceLocation ifToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation elseToken;
+};
+
+class QML_PARSER_EXPORT DoWhileStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(DoWhileStatement)
+
+ DoWhileStatement(Statement *stmt, ExpressionNode *e):
+ statement (stmt), expression (e)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return doToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ Statement *statement;
+ ExpressionNode *expression;
+ SourceLocation doToken;
+ SourceLocation whileToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT WhileStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(WhileStatement)
+
+ WhileStatement(ExpressionNode *e, Statement *stmt):
+ expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return whileToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation whileToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ForStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ForStatement)
+
+ ForStatement(ExpressionNode *i, ExpressionNode *c, ExpressionNode *e, Statement *stmt):
+ initialiser (i), condition (c), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *initialiser;
+ ExpressionNode *condition;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation firstSemicolonToken;
+ SourceLocation secondSemicolonToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT LocalForStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(LocalForStatement)
+
+ LocalForStatement(VariableDeclarationList *vlist, ExpressionNode *c, ExpressionNode *e, Statement *stmt):
+ declarations (vlist), condition (c), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ VariableDeclarationList *declarations;
+ ExpressionNode *condition;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation varToken;
+ SourceLocation firstSemicolonToken;
+ SourceLocation secondSemicolonToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ForEachStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ForEachStatement)
+
+ ForEachStatement(ExpressionNode *i, ExpressionNode *e, Statement *stmt):
+ initialiser (i), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *initialiser;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation inToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT LocalForEachStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(LocalForEachStatement)
+
+ LocalForEachStatement(VariableDeclaration *v, ExpressionNode *e, Statement *stmt):
+ declaration (v), expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return forToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ VariableDeclaration *declaration;
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation forToken;
+ SourceLocation lparenToken;
+ SourceLocation varToken;
+ SourceLocation inToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT ContinueStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ContinueStatement)
+
+ ContinueStatement(const QStringRef &l = QStringRef()):
+ label (l) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return continueToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ QStringRef label;
+ SourceLocation continueToken;
+ SourceLocation identifierToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT BreakStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(BreakStatement)
+
+ BreakStatement(const QStringRef &l):
+ label (l) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return breakToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+ // attributes
+ QStringRef label;
+ SourceLocation breakToken;
+ SourceLocation identifierToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT ReturnStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ReturnStatement)
+
+ ReturnStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return returnToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ ExpressionNode *expression;
+ SourceLocation returnToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT WithStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(WithStatement)
+
+ WithStatement(ExpressionNode *e, Statement *stmt):
+ expression (e), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return withToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ ExpressionNode *expression;
+ Statement *statement;
+ SourceLocation withToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT CaseBlock: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(CaseBlock)
+
+ CaseBlock(CaseClauses *c, DefaultClause *d = 0, CaseClauses *r = 0):
+ clauses (c), defaultClause (d), moreClauses (r)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ CaseClauses *clauses;
+ DefaultClause *defaultClause;
+ CaseClauses *moreClauses;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT SwitchStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(SwitchStatement)
+
+ SwitchStatement(ExpressionNode *e, CaseBlock *b):
+ expression (e), block (b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return switchToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return block->rbraceToken; }
+
+// attributes
+ ExpressionNode *expression;
+ CaseBlock *block;
+ SourceLocation switchToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT CaseClause: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(CaseClause)
+
+ CaseClause(ExpressionNode *e, StatementList *slist):
+ expression (e), statements (slist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return caseToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statements ? statements->lastSourceLocation() : colonToken; }
+
+// attributes
+ ExpressionNode *expression;
+ StatementList *statements;
+ SourceLocation caseToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT CaseClauses: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(CaseClauses)
+
+ CaseClauses(CaseClause *c):
+ clause (c), next (this)
+ { kind = K; }
+
+ CaseClauses(CaseClauses *previous, CaseClause *c):
+ clause (c)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return clause->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : clause->lastSourceLocation(); }
+
+ inline CaseClauses *finish ()
+ {
+ CaseClauses *front = next;
+ next = 0;
+ return front;
+ }
+
+//attributes
+ CaseClause *clause;
+ CaseClauses *next;
+};
+
+class QML_PARSER_EXPORT DefaultClause: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(DefaultClause)
+
+ DefaultClause(StatementList *slist):
+ statements (slist)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return defaultToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statements ? statements->lastSourceLocation() : colonToken; }
+
+// attributes
+ StatementList *statements;
+ SourceLocation defaultToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT LabelledStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(LabelledStatement)
+
+ LabelledStatement(const QStringRef &l, Statement *stmt):
+ label (l), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ QStringRef label;
+ Statement *statement;
+ SourceLocation identifierToken;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT ThrowStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(ThrowStatement)
+
+ ThrowStatement(ExpressionNode *e):
+ expression (e) { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return throwToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+ // attributes
+ ExpressionNode *expression;
+ SourceLocation throwToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT Catch: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Catch)
+
+ Catch(const QStringRef &n, Block *stmt):
+ name (n), statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return catchToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ QStringRef name;
+ Block *statement;
+ SourceLocation catchToken;
+ SourceLocation lparenToken;
+ SourceLocation identifierToken;
+ SourceLocation rparenToken;
+};
+
+class QML_PARSER_EXPORT Finally: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Finally)
+
+ Finally(Block *stmt):
+ statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return finallyToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement ? statement->lastSourceLocation() : finallyToken; }
+
+// attributes
+ Block *statement;
+ SourceLocation finallyToken;
+};
+
+class QML_PARSER_EXPORT TryStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(TryStatement)
+
+ TryStatement(Statement *stmt, Catch *c, Finally *f):
+ statement (stmt), catchExpression (c), finallyExpression (f)
+ { kind = K; }
+
+ TryStatement(Statement *stmt, Finally *f):
+ statement (stmt), catchExpression (0), finallyExpression (f)
+ { kind = K; }
+
+ TryStatement(Statement *stmt, Catch *c):
+ statement (stmt), catchExpression (c), finallyExpression (0)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return tryToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (finallyExpression)
+ return finallyExpression->statement->rbraceToken;
+ else if (catchExpression)
+ return catchExpression->statement->rbraceToken;
+
+ return statement->lastSourceLocation();
+ }
+
+// attributes
+ Statement *statement;
+ Catch *catchExpression;
+ Finally *finallyExpression;
+ SourceLocation tryToken;
+};
+
+class QML_PARSER_EXPORT FunctionExpression: public ExpressionNode
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FunctionExpression)
+
+ FunctionExpression(const QStringRef &n, FormalParameterList *f, FunctionBody *b):
+ name (n), formals (f), body (b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return functionToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ QStringRef name;
+ FormalParameterList *formals;
+ FunctionBody *body;
+ SourceLocation functionToken;
+ SourceLocation identifierToken;
+ SourceLocation lparenToken;
+ SourceLocation rparenToken;
+ SourceLocation lbraceToken;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT FunctionDeclaration: public FunctionExpression
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FunctionDeclaration)
+
+ FunctionDeclaration(const QStringRef &n, FormalParameterList *f, FunctionBody *b):
+ FunctionExpression(n, f, b)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+};
+
+class QML_PARSER_EXPORT FormalParameterList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FormalParameterList)
+
+ FormalParameterList(const QStringRef &n):
+ name (n), next (this)
+ { kind = K; }
+
+ FormalParameterList(FormalParameterList *previous, const QStringRef &n):
+ name (n)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : identifierToken; }
+
+ inline FormalParameterList *finish ()
+ {
+ FormalParameterList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ QStringRef name;
+ FormalParameterList *next;
+ SourceLocation commaToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT SourceElement: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(SourceElement)
+
+ inline SourceElement()
+ { kind = K; }
+};
+
+class QML_PARSER_EXPORT SourceElements: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(SourceElements)
+
+ SourceElements(SourceElement *elt):
+ element (elt), next (this)
+ { kind = K; }
+
+ SourceElements(SourceElements *previous, SourceElement *elt):
+ element (elt)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return element->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : element->lastSourceLocation(); }
+
+ inline SourceElements *finish ()
+ {
+ SourceElements *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ SourceElement *element;
+ SourceElements *next;
+};
+
+class QML_PARSER_EXPORT FunctionBody: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FunctionBody)
+
+ FunctionBody(SourceElements *elts):
+ elements (elts)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return elements ? elements->firstSourceLocation() : SourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return elements ? elements->lastSourceLocation() : SourceLocation(); }
+
+// attributes
+ SourceElements *elements;
+};
+
+class QML_PARSER_EXPORT Program: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(Program)
+
+ Program(SourceElements *elts):
+ elements (elts)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return elements ? elements->firstSourceLocation() : SourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return elements ? elements->lastSourceLocation() : SourceLocation(); }
+
+// attributes
+ SourceElements *elements;
+};
+
+class QML_PARSER_EXPORT FunctionSourceElement: public SourceElement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(FunctionSourceElement)
+
+ FunctionSourceElement(FunctionDeclaration *f):
+ declaration (f)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return declaration->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return declaration->lastSourceLocation(); }
+
+// attributes
+ FunctionDeclaration *declaration;
+};
+
+class QML_PARSER_EXPORT StatementSourceElement: public SourceElement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(StatementSourceElement)
+
+ StatementSourceElement(Statement *stmt):
+ statement (stmt)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return statement->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+// attributes
+ Statement *statement;
+};
+
+class QML_PARSER_EXPORT DebuggerStatement: public Statement
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(DebuggerStatement)
+
+ DebuggerStatement()
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return debuggerToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ SourceLocation debuggerToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiQualifiedId: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiQualifiedId)
+
+ UiQualifiedId(const QStringRef &name)
+ : next(this), name(name)
+ { kind = K; }
+
+ UiQualifiedId(UiQualifiedId *previous, const QStringRef &name)
+ : name(name)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ UiQualifiedId *finish()
+ {
+ UiQualifiedId *head = next;
+ next = 0;
+ return head;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : identifierToken; }
+
+// attributes
+ UiQualifiedId *next;
+ QStringRef name;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT UiImport: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiImport)
+
+ UiImport(const QStringRef &fileName)
+ : fileName(fileName), importUri(0)
+ { kind = K; }
+
+ UiImport(UiQualifiedId *uri)
+ : importUri(uri)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return importToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return semicolonToken; }
+
+// attributes
+ QStringRef fileName;
+ UiQualifiedId *importUri;
+ QStringRef importId;
+ SourceLocation importToken;
+ SourceLocation fileNameToken;
+ SourceLocation versionToken;
+ SourceLocation asToken;
+ SourceLocation importIdToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiImportList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiImportList)
+
+ UiImportList(UiImport *import)
+ : import(import),
+ next(this)
+ { kind = K; }
+
+ UiImportList(UiImportList *previous, UiImport *import)
+ : import(import)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ UiImportList *finish()
+ {
+ UiImportList *head = next;
+ next = 0;
+ return head;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return import->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : import->lastSourceLocation(); }
+
+// attributes
+ UiImport *import;
+ UiImportList *next;
+};
+
+class QML_PARSER_EXPORT UiObjectMember: public Node
+{
+public:
+ virtual SourceLocation firstSourceLocation() const = 0;
+ virtual SourceLocation lastSourceLocation() const = 0;
+
+ virtual UiObjectMember *uiObjectMemberCast();
+};
+
+class QML_PARSER_EXPORT UiObjectMemberList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiObjectMemberList)
+
+ UiObjectMemberList(UiObjectMember *member)
+ : next(this), member(member)
+ { kind = K; }
+
+ UiObjectMemberList(UiObjectMemberList *previous, UiObjectMember *member)
+ : member(member)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return member->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : member->lastSourceLocation(); }
+
+ UiObjectMemberList *finish()
+ {
+ UiObjectMemberList *head = next;
+ next = 0;
+ return head;
+ }
+
+// attributes
+ UiObjectMemberList *next;
+ UiObjectMember *member;
+};
+
+class QML_PARSER_EXPORT UiProgram: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiProgram)
+
+ UiProgram(UiImportList *imports, UiObjectMemberList *members)
+ : imports(imports), members(members)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (imports)
+ return imports->firstSourceLocation();
+ else if (members)
+ return members->firstSourceLocation();
+ return SourceLocation();
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (members)
+ return members->lastSourceLocation();
+ else if (imports)
+ return imports->lastSourceLocation();
+ return SourceLocation();
+ }
+
+// attributes
+ UiImportList *imports;
+ UiObjectMemberList *members;
+};
+
+class QML_PARSER_EXPORT UiArrayMemberList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiArrayMemberList)
+
+ UiArrayMemberList(UiObjectMember *member)
+ : next(this), member(member)
+ { kind = K; }
+
+ UiArrayMemberList(UiArrayMemberList *previous, UiObjectMember *member)
+ : member(member)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return member->firstSourceLocation(); }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : member->lastSourceLocation(); }
+
+ UiArrayMemberList *finish()
+ {
+ UiArrayMemberList *head = next;
+ next = 0;
+ return head;
+ }
+
+// attributes
+ UiArrayMemberList *next;
+ UiObjectMember *member;
+ SourceLocation commaToken;
+};
+
+class QML_PARSER_EXPORT UiObjectInitializer: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiObjectInitializer)
+
+ UiObjectInitializer(UiObjectMemberList *members)
+ : members(members)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return lbraceToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbraceToken; }
+
+// attributes
+ SourceLocation lbraceToken;
+ UiObjectMemberList *members;
+ SourceLocation rbraceToken;
+};
+
+class QML_PARSER_EXPORT UiParameterList: public Node
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiParameterList)
+
+ UiParameterList(const QStringRef &t, const QStringRef &n):
+ type (t), name (n), next (this)
+ { kind = K; }
+
+ UiParameterList(UiParameterList *previous, const QStringRef &t, const QStringRef &n):
+ type (t), name (n)
+ {
+ kind = K;
+ next = previous->next;
+ previous->next = this;
+ }
+
+ virtual void accept0(Visitor *) {}
+
+ virtual SourceLocation firstSourceLocation() const
+ { return propertyTypeToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return next ? next->lastSourceLocation() : identifierToken; }
+
+ inline UiParameterList *finish ()
+ {
+ UiParameterList *front = next;
+ next = 0;
+ return front;
+ }
+
+// attributes
+ QStringRef type;
+ QStringRef name;
+ UiParameterList *next;
+ SourceLocation commaToken;
+ SourceLocation propertyTypeToken;
+ SourceLocation identifierToken;
+};
+
+class QML_PARSER_EXPORT UiPublicMember: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiPublicMember)
+
+ UiPublicMember(const QStringRef &memberType,
+ const QStringRef &name)
+ : type(Property), memberType(memberType), name(name), statement(0), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
+ { kind = K; }
+
+ UiPublicMember(const QStringRef &memberType,
+ const QStringRef &name,
+ Statement *statement)
+ : type(Property), memberType(memberType), name(name), statement(statement), binding(0), isDefaultMember(false), isReadonlyMember(false), parameters(0)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (defaultToken.isValid())
+ return defaultToken;
+ else if (readonlyToken.isValid())
+ return readonlyToken;
+
+ return propertyToken;
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (binding)
+ return binding->lastSourceLocation();
+ if (statement)
+ return statement->lastSourceLocation();
+
+ return semicolonToken;
+ }
+
+// attributes
+ enum { Signal, Property } type;
+ QStringRef typeModifier;
+ QStringRef memberType;
+ QStringRef name;
+ Statement *statement; // initialized with a JS expression
+ UiObjectMember *binding; // initialized with a QML object or array.
+ bool isDefaultMember;
+ bool isReadonlyMember;
+ UiParameterList *parameters;
+ SourceLocation defaultToken;
+ SourceLocation readonlyToken;
+ SourceLocation propertyToken;
+ SourceLocation typeModifierToken;
+ SourceLocation typeToken;
+ SourceLocation identifierToken;
+ SourceLocation colonToken;
+ SourceLocation semicolonToken;
+};
+
+class QML_PARSER_EXPORT UiObjectDefinition: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiObjectDefinition)
+
+ UiObjectDefinition(UiQualifiedId *qualifiedTypeNameId,
+ UiObjectInitializer *initializer)
+ : qualifiedTypeNameId(qualifiedTypeNameId), initializer(initializer)
+ { kind = K; }
+
+ virtual void accept0(Visitor *visitor);
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedTypeNameId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return initializer->rbraceToken; }
+
+// attributes
+ UiQualifiedId *qualifiedTypeNameId;
+ UiObjectInitializer *initializer;
+};
+
+class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiSourceElement)
+
+ UiSourceElement(Node *sourceElement)
+ : sourceElement(sourceElement)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ return funDecl->firstSourceLocation();
+ else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
+ return varStmt->firstSourceLocation();
+
+ return SourceLocation();
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ {
+ if (FunctionDeclaration *funDecl = cast<FunctionDeclaration *>(sourceElement))
+ return funDecl->lastSourceLocation();
+ else if (VariableStatement *varStmt = cast<VariableStatement *>(sourceElement))
+ return varStmt->lastSourceLocation();
+
+ return SourceLocation();
+ }
+
+ virtual void accept0(Visitor *visitor);
+
+
+// attributes
+ Node *sourceElement;
+};
+
+class QML_PARSER_EXPORT UiObjectBinding: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiObjectBinding)
+
+ UiObjectBinding(UiQualifiedId *qualifiedId,
+ UiQualifiedId *qualifiedTypeNameId,
+ UiObjectInitializer *initializer)
+ : qualifiedId(qualifiedId),
+ qualifiedTypeNameId(qualifiedTypeNameId),
+ initializer(initializer),
+ hasOnToken(false)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ {
+ if (hasOnToken && qualifiedTypeNameId)
+ return qualifiedTypeNameId->identifierToken;
+
+ return qualifiedId->identifierToken;
+ }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return initializer->rbraceToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ UiQualifiedId *qualifiedTypeNameId;
+ UiObjectInitializer *initializer;
+ SourceLocation colonToken;
+ bool hasOnToken;
+};
+
+class QML_PARSER_EXPORT UiScriptBinding: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiScriptBinding)
+
+ UiScriptBinding(UiQualifiedId *qualifiedId,
+ Statement *statement)
+ : qualifiedId(qualifiedId),
+ statement(statement)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return statement->lastSourceLocation(); }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ Statement *statement;
+ SourceLocation colonToken;
+};
+
+class QML_PARSER_EXPORT UiArrayBinding: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiArrayBinding)
+
+ UiArrayBinding(UiQualifiedId *qualifiedId,
+ UiArrayMemberList *members)
+ : qualifiedId(qualifiedId),
+ members(members)
+ { kind = K; }
+
+ virtual SourceLocation firstSourceLocation() const
+ { return qualifiedId->identifierToken; }
+
+ virtual SourceLocation lastSourceLocation() const
+ { return rbracketToken; }
+
+ virtual void accept0(Visitor *visitor);
+
+// attributes
+ UiQualifiedId *qualifiedId;
+ UiArrayMemberList *members;
+ SourceLocation colonToken;
+ SourceLocation lbracketToken;
+ SourceLocation rbracketToken;
+};
+
+} } // namespace AST
+
+
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/qmlparser/qqmljsastfwd_p.h b/src/tools/qdoc/qmlparser/qqmljsastfwd_p.h
new file mode 100644
index 0000000000..dec1cbc599
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsastfwd_p.h
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSAST_FWD_P_H
+#define QQMLJSAST_FWD_P_H
+
+#include "qqmljsglobal_p.h"
+
+#include <QtCore/qglobal.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS { namespace AST {
+
+class SourceLocation
+{
+public:
+ SourceLocation(quint32 offset = 0, quint32 length = 0, quint32 line = 0, quint32 column = 0)
+ : offset(offset), length(length),
+ startLine(line), startColumn(column)
+ { }
+
+ bool isValid() const { return length != 0; }
+
+ quint32 begin() const { return offset; }
+ quint32 end() const { return offset + length; }
+
+// attributes
+ // ### encode
+ quint32 offset;
+ quint32 length;
+ quint32 startLine;
+ quint32 startColumn;
+};
+
+class Visitor;
+class Node;
+class ExpressionNode;
+class Statement;
+class ThisExpression;
+class IdentifierExpression;
+class NullExpression;
+class TrueLiteral;
+class FalseLiteral;
+class NumericLiteral;
+class StringLiteral;
+class RegExpLiteral;
+class ArrayLiteral;
+class ObjectLiteral;
+class ElementList;
+class Elision;
+class PropertyNameAndValueList;
+class PropertyName;
+class IdentifierPropertyName;
+class StringLiteralPropertyName;
+class NumericLiteralPropertyName;
+class ArrayMemberExpression;
+class FieldMemberExpression;
+class NewMemberExpression;
+class NewExpression;
+class CallExpression;
+class ArgumentList;
+class PostIncrementExpression;
+class PostDecrementExpression;
+class DeleteExpression;
+class VoidExpression;
+class TypeOfExpression;
+class PreIncrementExpression;
+class PreDecrementExpression;
+class UnaryPlusExpression;
+class UnaryMinusExpression;
+class TildeExpression;
+class NotExpression;
+class BinaryExpression;
+class ConditionalExpression;
+class Expression; // ### rename
+class Block;
+class StatementList;
+class VariableStatement;
+class VariableDeclarationList;
+class VariableDeclaration;
+class EmptyStatement;
+class ExpressionStatement;
+class IfStatement;
+class DoWhileStatement;
+class WhileStatement;
+class ForStatement;
+class LocalForStatement;
+class ForEachStatement;
+class LocalForEachStatement;
+class ContinueStatement;
+class BreakStatement;
+class ReturnStatement;
+class WithStatement;
+class SwitchStatement;
+class CaseBlock;
+class CaseClauses;
+class CaseClause;
+class DefaultClause;
+class LabelledStatement;
+class ThrowStatement;
+class TryStatement;
+class Catch;
+class Finally;
+class FunctionDeclaration;
+class FunctionExpression;
+class FormalParameterList;
+class FunctionBody;
+class Program;
+class SourceElements;
+class SourceElement;
+class FunctionSourceElement;
+class StatementSourceElement;
+class DebuggerStatement;
+class NestedExpression;
+
+// ui elements
+class UiProgram;
+class UiImportList;
+class UiImport;
+class UiPublicMember;
+class UiObjectDefinition;
+class UiObjectInitializer;
+class UiObjectBinding;
+class UiScriptBinding;
+class UiSourceElement;
+class UiArrayBinding;
+class UiObjectMember;
+class UiObjectMemberList;
+class UiArrayMemberList;
+class UiQualifiedId;
+
+} } // namespace AST
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/qmlparser/qqmljsastvisitor.cpp b/src/tools/qdoc/qmlparser/qqmljsastvisitor.cpp
new file mode 100644
index 0000000000..2d854dc735
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsastvisitor.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmljsastvisitor_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS { namespace AST {
+
+Visitor::Visitor()
+{
+}
+
+Visitor::~Visitor()
+{
+}
+
+} } // namespace QQmlJS::AST
+
+QT_QML_END_NAMESPACE
diff --git a/src/tools/qdoc/qmlparser/qqmljsastvisitor_p.h b/src/tools/qdoc/qmlparser/qqmljsastvisitor_p.h
new file mode 100644
index 0000000000..991580309d
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsastvisitor_p.h
@@ -0,0 +1,329 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSASTVISITOR_P_H
+#define QQMLJSASTVISITOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqmljsastfwd_p.h"
+#include "qqmljsglobal_p.h"
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS { namespace AST {
+
+class QML_PARSER_EXPORT Visitor
+{
+public:
+ Visitor();
+ virtual ~Visitor();
+
+ virtual bool preVisit(Node *) { return true; }
+ virtual void postVisit(Node *) {}
+
+ // Ui
+ virtual bool visit(UiProgram *) { return true; }
+ virtual bool visit(UiImportList *) { return true; }
+ virtual bool visit(UiImport *) { return true; }
+ virtual bool visit(UiPublicMember *) { return true; }
+ virtual bool visit(UiSourceElement *) { return true; }
+ virtual bool visit(UiObjectDefinition *) { return true; }
+ virtual bool visit(UiObjectInitializer *) { return true; }
+ virtual bool visit(UiObjectBinding *) { return true; }
+ virtual bool visit(UiScriptBinding *) { return true; }
+ virtual bool visit(UiArrayBinding *) { return true; }
+ virtual bool visit(UiObjectMemberList *) { return true; }
+ virtual bool visit(UiArrayMemberList *) { return true; }
+ virtual bool visit(UiQualifiedId *) { return true; }
+
+ virtual void endVisit(UiProgram *) {}
+ virtual void endVisit(UiImportList *) {}
+ virtual void endVisit(UiImport *) {}
+ virtual void endVisit(UiPublicMember *) {}
+ virtual void endVisit(UiSourceElement *) {}
+ virtual void endVisit(UiObjectDefinition *) {}
+ virtual void endVisit(UiObjectInitializer *) {}
+ virtual void endVisit(UiObjectBinding *) {}
+ virtual void endVisit(UiScriptBinding *) {}
+ virtual void endVisit(UiArrayBinding *) {}
+ virtual void endVisit(UiObjectMemberList *) {}
+ virtual void endVisit(UiArrayMemberList *) {}
+ virtual void endVisit(UiQualifiedId *) {}
+
+ // QQmlJS
+ virtual bool visit(ThisExpression *) { return true; }
+ virtual void endVisit(ThisExpression *) {}
+
+ virtual bool visit(IdentifierExpression *) { return true; }
+ virtual void endVisit(IdentifierExpression *) {}
+
+ virtual bool visit(NullExpression *) { return true; }
+ virtual void endVisit(NullExpression *) {}
+
+ virtual bool visit(TrueLiteral *) { return true; }
+ virtual void endVisit(TrueLiteral *) {}
+
+ virtual bool visit(FalseLiteral *) { return true; }
+ virtual void endVisit(FalseLiteral *) {}
+
+ virtual bool visit(StringLiteral *) { return true; }
+ virtual void endVisit(StringLiteral *) {}
+
+ virtual bool visit(NumericLiteral *) { return true; }
+ virtual void endVisit(NumericLiteral *) {}
+
+ virtual bool visit(RegExpLiteral *) { return true; }
+ virtual void endVisit(RegExpLiteral *) {}
+
+ virtual bool visit(ArrayLiteral *) { return true; }
+ virtual void endVisit(ArrayLiteral *) {}
+
+ virtual bool visit(ObjectLiteral *) { return true; }
+ virtual void endVisit(ObjectLiteral *) {}
+
+ virtual bool visit(ElementList *) { return true; }
+ virtual void endVisit(ElementList *) {}
+
+ virtual bool visit(Elision *) { return true; }
+ virtual void endVisit(Elision *) {}
+
+ virtual bool visit(PropertyNameAndValueList *) { return true; }
+ virtual void endVisit(PropertyNameAndValueList *) {}
+
+ virtual bool visit(NestedExpression *) { return true; }
+ virtual void endVisit(NestedExpression *) {}
+
+ virtual bool visit(IdentifierPropertyName *) { return true; }
+ virtual void endVisit(IdentifierPropertyName *) {}
+
+ virtual bool visit(StringLiteralPropertyName *) { return true; }
+ virtual void endVisit(StringLiteralPropertyName *) {}
+
+ virtual bool visit(NumericLiteralPropertyName *) { return true; }
+ virtual void endVisit(NumericLiteralPropertyName *) {}
+
+ virtual bool visit(ArrayMemberExpression *) { return true; }
+ virtual void endVisit(ArrayMemberExpression *) {}
+
+ virtual bool visit(FieldMemberExpression *) { return true; }
+ virtual void endVisit(FieldMemberExpression *) {}
+
+ virtual bool visit(NewMemberExpression *) { return true; }
+ virtual void endVisit(NewMemberExpression *) {}
+
+ virtual bool visit(NewExpression *) { return true; }
+ virtual void endVisit(NewExpression *) {}
+
+ virtual bool visit(CallExpression *) { return true; }
+ virtual void endVisit(CallExpression *) {}
+
+ virtual bool visit(ArgumentList *) { return true; }
+ virtual void endVisit(ArgumentList *) {}
+
+ virtual bool visit(PostIncrementExpression *) { return true; }
+ virtual void endVisit(PostIncrementExpression *) {}
+
+ virtual bool visit(PostDecrementExpression *) { return true; }
+ virtual void endVisit(PostDecrementExpression *) {}
+
+ virtual bool visit(DeleteExpression *) { return true; }
+ virtual void endVisit(DeleteExpression *) {}
+
+ virtual bool visit(VoidExpression *) { return true; }
+ virtual void endVisit(VoidExpression *) {}
+
+ virtual bool visit(TypeOfExpression *) { return true; }
+ virtual void endVisit(TypeOfExpression *) {}
+
+ virtual bool visit(PreIncrementExpression *) { return true; }
+ virtual void endVisit(PreIncrementExpression *) {}
+
+ virtual bool visit(PreDecrementExpression *) { return true; }
+ virtual void endVisit(PreDecrementExpression *) {}
+
+ virtual bool visit(UnaryPlusExpression *) { return true; }
+ virtual void endVisit(UnaryPlusExpression *) {}
+
+ virtual bool visit(UnaryMinusExpression *) { return true; }
+ virtual void endVisit(UnaryMinusExpression *) {}
+
+ virtual bool visit(TildeExpression *) { return true; }
+ virtual void endVisit(TildeExpression *) {}
+
+ virtual bool visit(NotExpression *) { return true; }
+ virtual void endVisit(NotExpression *) {}
+
+ virtual bool visit(BinaryExpression *) { return true; }
+ virtual void endVisit(BinaryExpression *) {}
+
+ virtual bool visit(ConditionalExpression *) { return true; }
+ virtual void endVisit(ConditionalExpression *) {}
+
+ virtual bool visit(Expression *) { return true; }
+ virtual void endVisit(Expression *) {}
+
+ virtual bool visit(Block *) { return true; }
+ virtual void endVisit(Block *) {}
+
+ virtual bool visit(StatementList *) { return true; }
+ virtual void endVisit(StatementList *) {}
+
+ virtual bool visit(VariableStatement *) { return true; }
+ virtual void endVisit(VariableStatement *) {}
+
+ virtual bool visit(VariableDeclarationList *) { return true; }
+ virtual void endVisit(VariableDeclarationList *) {}
+
+ virtual bool visit(VariableDeclaration *) { return true; }
+ virtual void endVisit(VariableDeclaration *) {}
+
+ virtual bool visit(EmptyStatement *) { return true; }
+ virtual void endVisit(EmptyStatement *) {}
+
+ virtual bool visit(ExpressionStatement *) { return true; }
+ virtual void endVisit(ExpressionStatement *) {}
+
+ virtual bool visit(IfStatement *) { return true; }
+ virtual void endVisit(IfStatement *) {}
+
+ virtual bool visit(DoWhileStatement *) { return true; }
+ virtual void endVisit(DoWhileStatement *) {}
+
+ virtual bool visit(WhileStatement *) { return true; }
+ virtual void endVisit(WhileStatement *) {}
+
+ virtual bool visit(ForStatement *) { return true; }
+ virtual void endVisit(ForStatement *) {}
+
+ virtual bool visit(LocalForStatement *) { return true; }
+ virtual void endVisit(LocalForStatement *) {}
+
+ virtual bool visit(ForEachStatement *) { return true; }
+ virtual void endVisit(ForEachStatement *) {}
+
+ virtual bool visit(LocalForEachStatement *) { return true; }
+ virtual void endVisit(LocalForEachStatement *) {}
+
+ virtual bool visit(ContinueStatement *) { return true; }
+ virtual void endVisit(ContinueStatement *) {}
+
+ virtual bool visit(BreakStatement *) { return true; }
+ virtual void endVisit(BreakStatement *) {}
+
+ virtual bool visit(ReturnStatement *) { return true; }
+ virtual void endVisit(ReturnStatement *) {}
+
+ virtual bool visit(WithStatement *) { return true; }
+ virtual void endVisit(WithStatement *) {}
+
+ virtual bool visit(SwitchStatement *) { return true; }
+ virtual void endVisit(SwitchStatement *) {}
+
+ virtual bool visit(CaseBlock *) { return true; }
+ virtual void endVisit(CaseBlock *) {}
+
+ virtual bool visit(CaseClauses *) { return true; }
+ virtual void endVisit(CaseClauses *) {}
+
+ virtual bool visit(CaseClause *) { return true; }
+ virtual void endVisit(CaseClause *) {}
+
+ virtual bool visit(DefaultClause *) { return true; }
+ virtual void endVisit(DefaultClause *) {}
+
+ virtual bool visit(LabelledStatement *) { return true; }
+ virtual void endVisit(LabelledStatement *) {}
+
+ virtual bool visit(ThrowStatement *) { return true; }
+ virtual void endVisit(ThrowStatement *) {}
+
+ virtual bool visit(TryStatement *) { return true; }
+ virtual void endVisit(TryStatement *) {}
+
+ virtual bool visit(Catch *) { return true; }
+ virtual void endVisit(Catch *) {}
+
+ virtual bool visit(Finally *) { return true; }
+ virtual void endVisit(Finally *) {}
+
+ virtual bool visit(FunctionDeclaration *) { return true; }
+ virtual void endVisit(FunctionDeclaration *) {}
+
+ virtual bool visit(FunctionExpression *) { return true; }
+ virtual void endVisit(FunctionExpression *) {}
+
+ virtual bool visit(FormalParameterList *) { return true; }
+ virtual void endVisit(FormalParameterList *) {}
+
+ virtual bool visit(FunctionBody *) { return true; }
+ virtual void endVisit(FunctionBody *) {}
+
+ virtual bool visit(Program *) { return true; }
+ virtual void endVisit(Program *) {}
+
+ virtual bool visit(SourceElements *) { return true; }
+ virtual void endVisit(SourceElements *) {}
+
+ virtual bool visit(FunctionSourceElement *) { return true; }
+ virtual void endVisit(FunctionSourceElement *) {}
+
+ virtual bool visit(StatementSourceElement *) { return true; }
+ virtual void endVisit(StatementSourceElement *) {}
+
+ virtual bool visit(DebuggerStatement *) { return true; }
+ virtual void endVisit(DebuggerStatement *) {}
+};
+
+} } // namespace AST
+
+QT_QML_END_NAMESPACE
+
+#endif // QQMLJSASTVISITOR_P_H
diff --git a/src/tools/qdoc/qmlparser/qqmljsengine_p.cpp b/src/tools/qdoc/qmlparser/qqmljsengine_p.cpp
new file mode 100644
index 0000000000..459ba8d7dc
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsengine_p.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmljsengine_p.h"
+#include "qqmljsglobal_p.h"
+
+#include <qnumeric.h>
+#include <QHash>
+#include <QDebug>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+static int toDigit(char c)
+{
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+ else if ((c >= 'a') && (c <= 'z'))
+ return 10 + c - 'a';
+ else if ((c >= 'A') && (c <= 'Z'))
+ return 10 + c - 'A';
+ return -1;
+}
+
+double integerFromString(const char *buf, int size, int radix)
+{
+ if (size == 0)
+ return qSNaN();
+
+ double sign = 1.0;
+ int i = 0;
+ if (buf[0] == '+') {
+ ++i;
+ } else if (buf[0] == '-') {
+ sign = -1.0;
+ ++i;
+ }
+
+ if (((size-i) >= 2) && (buf[i] == '0')) {
+ if (((buf[i+1] == 'x') || (buf[i+1] == 'X'))
+ && (radix < 34)) {
+ if ((radix != 0) && (radix != 16))
+ return 0;
+ radix = 16;
+ i += 2;
+ } else {
+ if (radix == 0) {
+ radix = 8;
+ ++i;
+ }
+ }
+ } else if (radix == 0) {
+ radix = 10;
+ }
+
+ int j = i;
+ for ( ; i < size; ++i) {
+ int d = toDigit(buf[i]);
+ if ((d == -1) || (d >= radix))
+ break;
+ }
+ double result;
+ if (j == i) {
+ if (!qstrcmp(buf, "Infinity"))
+ result = qInf();
+ else
+ result = qSNaN();
+ } else {
+ result = 0;
+ double multiplier = 1;
+ for (--i ; i >= j; --i, multiplier *= radix)
+ result += toDigit(buf[i]) * multiplier;
+ }
+ result *= sign;
+ return result;
+}
+
+double integerFromString(const QString &str, int radix)
+{
+ QByteArray ba = str.trimmed().toLatin1();
+ return integerFromString(ba.constData(), ba.size(), radix);
+}
+
+
+Engine::Engine()
+ : _lexer(0)
+{ }
+
+Engine::~Engine()
+{ }
+
+void Engine::setCode(const QString &code)
+{ _code = code; }
+
+void Engine::addComment(int pos, int len, int line, int col)
+{ if (len > 0) _comments.append(QQmlJS::AST::SourceLocation(pos, len, line, col)); }
+
+QList<QQmlJS::AST::SourceLocation> Engine::comments() const
+{ return _comments; }
+
+Lexer *Engine::lexer() const
+{ return _lexer; }
+
+void Engine::setLexer(Lexer *lexer)
+{ _lexer = lexer; }
+
+MemoryPool *Engine::pool()
+{ return &_pool; }
+
+QStringRef Engine::newStringRef(const QString &text)
+{
+ const int pos = _extraCode.length();
+ _extraCode += text;
+ return _extraCode.midRef(pos, text.length());
+}
+
+QStringRef Engine::newStringRef(const QChar *chars, int size)
+{ return newStringRef(QString(chars, size)); }
+
+} // end of namespace QQmlJS
+
+QT_QML_END_NAMESPACE
diff --git a/src/tools/qdoc/qmlparser/qqmljsengine_p.h b/src/tools/qdoc/qmlparser/qqmljsengine_p.h
new file mode 100644
index 0000000000..3cb78de4eb
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsengine_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSENGINE_P_H
+#define QQMLJSENGINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqmljsglobal_p.h"
+#include "qqmljsastfwd_p.h"
+#include "qqmljsmemorypool_p.h"
+
+#include <QString>
+#include <QSet>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Lexer;
+class MemoryPool;
+
+class QML_PARSER_EXPORT DiagnosticMessage
+{
+public:
+ enum Kind { Warning, Error };
+
+ DiagnosticMessage()
+ : kind(Error) {}
+
+ DiagnosticMessage(Kind kind, const AST::SourceLocation &loc, const QString &message)
+ : kind(kind), loc(loc), message(message) {}
+
+ bool isWarning() const
+ { return kind == Warning; }
+
+ bool isError() const
+ { return kind == Error; }
+
+ Kind kind;
+ AST::SourceLocation loc;
+ QString message;
+};
+
+class QML_PARSER_EXPORT Engine
+{
+ Lexer *_lexer;
+ MemoryPool _pool;
+ QList<AST::SourceLocation> _comments;
+ QString _extraCode;
+ QString _code;
+
+public:
+ Engine();
+ ~Engine();
+
+ void setCode(const QString &code);
+
+ void addComment(int pos, int len, int line, int col);
+ QList<AST::SourceLocation> comments() const;
+
+ Lexer *lexer() const;
+ void setLexer(Lexer *lexer);
+
+ MemoryPool *pool();
+
+ inline QStringRef midRef(int position, int size) { return _code.midRef(position, size); }
+
+ QStringRef newStringRef(const QString &s);
+ QStringRef newStringRef(const QChar *chars, int size);
+};
+
+double integerFromString(const char *buf, int size, int radix);
+
+} // end of namespace QQmlJS
+
+QT_QML_END_NAMESPACE
+
+#endif // QQMLJSENGINE_P_H
diff --git a/src/tools/qdoc/qmlparser/qqmljsglobal_p.h b/src/tools/qdoc/qmlparser/qqmljsglobal_p.h
new file mode 100644
index 0000000000..81c90310ad
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsglobal_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QQMLJSGLOBAL_P_H
+#define QQMLJSGLOBAL_P_H
+
+#include <QtCore/qglobal.h>
+
+#ifdef QT_CREATOR
+# define QT_QML_BEGIN_NAMESPACE
+# define QT_QML_END_NAMESPACE
+
+# ifdef QDECLARATIVEJS_BUILD_DIR
+# define QML_PARSER_EXPORT Q_DECL_EXPORT
+# elif QML_BUILD_STATIC_LIB
+# define QML_PARSER_EXPORT
+# else
+# define QML_PARSER_EXPORT Q_DECL_IMPORT
+# endif // QQMLJS_BUILD_DIR
+
+#else // !QT_CREATOR
+# define QT_QML_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
+# define QT_QML_END_NAMESPACE QT_END_NAMESPACE
+# if defined(QT_BUILD_QMLDEVTOOLS_LIB) || defined(QT_QMLDEVTOOLS_LIB)
+ // QmlDevTools is a static library
+# define QML_PARSER_EXPORT
+# else
+# define QML_PARSER_EXPORT Q_AUTOTEST_EXPORT
+# endif
+#endif // QT_CREATOR
+
+#endif // QQMLJSGLOBAL_P_H
diff --git a/src/tools/qdoc/qmlparser/qqmljsgrammar.cpp b/src/tools/qdoc/qmlparser/qqmljsgrammar.cpp
new file mode 100644
index 0000000000..f69f809ee3
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsgrammar.cpp
@@ -0,0 +1,1013 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// This file was generated by qlalr - DO NOT EDIT!
+#include "qqmljsgrammar_p.h"
+
+QT_BEGIN_NAMESPACE
+
+const char *const QQmlJSGrammar::spell [] = {
+ "end of file", "&", "&&", "&=", "break", "case", "catch", ":", ",", "continue",
+ "default", "delete", "/", "/=", "do", ".", "else", "=", "==", "===",
+ "finally", "for", "function", ">=", ">", ">>", ">>=", ">>>", ">>>=", "identifier",
+ "if", "in", "instanceof", "{", "[", "<=", "(", "<", "<<", "<<=",
+ "-", "-=", "--", "new", "!", "!=", "!==", "numeric literal", "|", "|=",
+ "||", "+", "+=", "++", "?", "}", "]", "%", "%=", "return",
+ ")", ";", 0, "*", "*=", "string literal", "property", "signal", "readonly", "switch",
+ "this", "throw", "~", "try", "typeof", "var", "void", "while", "with", "^",
+ "^=", "null", "true", "false", "const", "debugger", "reserved word", "multiline string literal", "comment", "public",
+ "import", "as", "on", 0, 0, 0, 0, 0, 0, 0,
+ 0, 0};
+
+const short QQmlJSGrammar::lhs [] = {
+ 102, 102, 102, 102, 102, 102, 103, 109, 109, 112,
+ 112, 114, 113, 113, 113, 113, 113, 113, 113, 113,
+ 116, 111, 110, 119, 119, 120, 120, 121, 121, 118,
+ 107, 107, 107, 107, 123, 123, 123, 123, 123, 123,
+ 123, 107, 131, 131, 131, 132, 132, 133, 133, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 117, 117, 117, 117,
+ 117, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+ 136, 136, 136, 136, 136, 136, 136, 136, 136, 122,
+ 138, 138, 138, 138, 137, 137, 140, 140, 142, 142,
+ 142, 142, 142, 142, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 144, 144, 115, 115, 115,
+ 115, 115, 147, 147, 148, 148, 148, 148, 146, 146,
+ 149, 149, 150, 150, 151, 151, 151, 152, 152, 152,
+ 152, 152, 152, 152, 152, 152, 152, 153, 153, 153,
+ 153, 154, 154, 154, 155, 155, 155, 155, 156, 156,
+ 156, 156, 156, 156, 156, 157, 157, 157, 157, 157,
+ 157, 158, 158, 158, 158, 158, 159, 159, 159, 159,
+ 159, 160, 160, 161, 161, 162, 162, 163, 163, 164,
+ 164, 165, 165, 166, 166, 167, 167, 168, 168, 169,
+ 169, 170, 170, 171, 171, 141, 141, 172, 172, 173,
+ 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
+ 173, 105, 105, 174, 174, 175, 175, 176, 176, 104,
+ 104, 104, 104, 104, 104, 104, 104, 104, 104, 104,
+ 104, 104, 104, 104, 124, 185, 185, 184, 184, 135,
+ 135, 186, 186, 187, 187, 189, 189, 188, 190, 193,
+ 191, 191, 194, 192, 192, 125, 126, 126, 127, 127,
+ 177, 177, 177, 177, 177, 177, 177, 178, 178, 178,
+ 178, 179, 179, 179, 179, 180, 180, 128, 129, 195,
+ 195, 198, 198, 196, 196, 199, 197, 181, 181, 181,
+ 182, 182, 130, 130, 130, 200, 201, 183, 183, 134,
+ 145, 205, 205, 202, 202, 203, 203, 206, 108, 108,
+ 207, 207, 106, 106, 204, 204, 139, 139, 208};
+
+const short QQmlJSGrammar::rhs [] = {
+ 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
+ 2, 1, 2, 2, 3, 3, 5, 5, 4, 4,
+ 2, 0, 1, 1, 2, 1, 3, 2, 3, 2,
+ 1, 5, 4, 4, 1, 1, 1, 1, 1, 1,
+ 1, 3, 1, 1, 1, 0, 1, 2, 4, 6,
+ 6, 3, 3, 7, 7, 4, 4, 5, 5, 5,
+ 6, 6, 10, 6, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 3, 3, 4, 5, 3, 4, 3, 1,
+ 1, 2, 3, 4, 1, 2, 3, 5, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,
+ 3, 5, 1, 2, 4, 4, 4, 3, 0, 1,
+ 1, 3, 1, 1, 1, 2, 2, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 1, 3, 3,
+ 3, 1, 3, 3, 1, 3, 3, 3, 1, 3,
+ 3, 3, 3, 3, 3, 1, 3, 3, 3, 3,
+ 3, 1, 3, 3, 3, 3, 1, 3, 3, 3,
+ 3, 1, 3, 1, 3, 1, 3, 1, 3, 1,
+ 3, 1, 3, 1, 3, 1, 3, 1, 3, 1,
+ 3, 1, 5, 1, 5, 1, 3, 1, 3, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 3, 0, 1, 1, 3, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 3, 1, 2, 0, 1, 3,
+ 3, 1, 1, 1, 3, 1, 3, 2, 2, 2,
+ 0, 1, 2, 0, 1, 1, 2, 2, 7, 5,
+ 7, 7, 5, 9, 10, 7, 8, 2, 2, 3,
+ 3, 2, 2, 3, 3, 3, 3, 5, 5, 3,
+ 5, 1, 2, 0, 1, 4, 3, 3, 3, 3,
+ 3, 3, 3, 3, 4, 5, 2, 2, 2, 8,
+ 8, 1, 3, 0, 1, 0, 1, 1, 1, 1,
+ 1, 2, 1, 1, 0, 1, 0, 1, 2};
+
+const short QQmlJSGrammar::action_default [] = {
+ 0, 0, 22, 0, 0, 0, 22, 0, 175, 242,
+ 206, 214, 210, 154, 226, 202, 3, 139, 73, 155,
+ 218, 222, 143, 172, 153, 158, 138, 192, 179, 0,
+ 80, 81, 76, 345, 67, 347, 0, 0, 0, 0,
+ 78, 0, 0, 74, 77, 71, 0, 0, 68, 70,
+ 69, 79, 72, 0, 75, 0, 0, 168, 0, 0,
+ 155, 174, 157, 156, 0, 0, 0, 170, 171, 169,
+ 173, 0, 203, 0, 0, 0, 0, 193, 0, 0,
+ 0, 0, 0, 0, 183, 0, 0, 0, 177, 178,
+ 176, 181, 185, 184, 182, 180, 195, 194, 196, 0,
+ 211, 0, 207, 0, 0, 149, 136, 148, 137, 105,
+ 106, 107, 132, 108, 133, 109, 110, 111, 112, 113,
+ 114, 115, 116, 117, 118, 119, 120, 121, 134, 122,
+ 123, 124, 125, 126, 127, 128, 129, 130, 131, 135,
+ 0, 0, 147, 243, 150, 0, 151, 0, 152, 146,
+ 0, 239, 232, 230, 237, 238, 236, 235, 241, 234,
+ 233, 231, 240, 227, 0, 215, 0, 0, 219, 0,
+ 0, 223, 0, 0, 149, 141, 0, 140, 0, 145,
+ 159, 0, 346, 334, 335, 0, 332, 0, 333, 0,
+ 336, 250, 257, 256, 264, 252, 0, 253, 337, 0,
+ 344, 254, 255, 260, 258, 341, 338, 343, 261, 0,
+ 272, 0, 0, 0, 0, 345, 67, 0, 347, 68,
+ 244, 286, 69, 0, 0, 0, 273, 0, 0, 262,
+ 263, 0, 251, 259, 287, 288, 331, 342, 0, 302,
+ 303, 304, 305, 0, 298, 299, 300, 301, 328, 329,
+ 0, 0, 0, 0, 0, 291, 292, 248, 246, 208,
+ 216, 212, 228, 204, 249, 0, 155, 220, 224, 197,
+ 186, 0, 0, 205, 0, 0, 0, 0, 198, 0,
+ 0, 0, 0, 0, 190, 188, 191, 189, 187, 200,
+ 199, 201, 0, 213, 0, 209, 0, 247, 155, 0,
+ 229, 244, 245, 0, 244, 0, 0, 294, 0, 0,
+ 0, 296, 0, 217, 0, 0, 221, 0, 0, 225,
+ 284, 0, 276, 285, 279, 0, 283, 0, 244, 277,
+ 0, 244, 0, 0, 295, 0, 0, 0, 297, 346,
+ 334, 0, 0, 336, 0, 330, 0, 320, 0, 0,
+ 0, 290, 0, 289, 0, 348, 0, 104, 266, 269,
+ 0, 105, 272, 108, 133, 110, 111, 76, 115, 116,
+ 67, 117, 120, 74, 77, 68, 244, 69, 79, 123,
+ 72, 125, 75, 127, 128, 273, 130, 131, 135, 0,
+ 97, 0, 0, 99, 103, 101, 88, 100, 102, 0,
+ 98, 87, 267, 265, 143, 144, 149, 0, 142, 0,
+ 319, 0, 306, 307, 0, 318, 0, 0, 0, 309,
+ 314, 312, 315, 0, 0, 313, 314, 0, 310, 0,
+ 311, 268, 317, 0, 268, 316, 0, 321, 322, 0,
+ 268, 323, 324, 0, 0, 325, 0, 0, 0, 326,
+ 327, 161, 160, 0, 0, 0, 293, 0, 0, 0,
+ 308, 281, 274, 0, 282, 278, 0, 280, 270, 0,
+ 271, 275, 91, 0, 0, 95, 82, 0, 84, 93,
+ 0, 85, 94, 96, 86, 92, 83, 0, 89, 165,
+ 163, 167, 164, 162, 166, 339, 6, 340, 4, 2,
+ 65, 90, 0, 0, 68, 70, 69, 31, 5, 0,
+ 66, 0, 45, 44, 43, 0, 0, 58, 0, 59,
+ 35, 36, 37, 38, 40, 41, 62, 39, 0, 45,
+ 0, 0, 0, 0, 0, 54, 0, 55, 0, 0,
+ 26, 0, 0, 63, 27, 0, 30, 28, 24, 0,
+ 29, 25, 0, 56, 0, 57, 143, 0, 60, 64,
+ 0, 0, 0, 0, 61, 0, 52, 46, 53, 47,
+ 0, 0, 0, 0, 49, 0, 50, 51, 48, 0,
+ 0, 143, 268, 0, 0, 42, 105, 272, 108, 133,
+ 110, 111, 76, 115, 116, 67, 117, 120, 74, 77,
+ 68, 244, 69, 79, 123, 72, 125, 75, 127, 128,
+ 273, 130, 131, 135, 0, 32, 33, 0, 34, 8,
+ 0, 10, 0, 9, 0, 1, 21, 12, 0, 13,
+ 0, 14, 0, 19, 20, 0, 15, 16, 0, 17,
+ 18, 11, 23, 7, 349};
+
+const short QQmlJSGrammar::goto_default [] = {
+ 7, 625, 207, 196, 205, 508, 496, 624, 643, 495,
+ 623, 621, 626, 22, 622, 18, 507, 549, 539, 546,
+ 541, 526, 191, 195, 197, 201, 233, 208, 230, 530,
+ 570, 569, 200, 232, 26, 474, 473, 356, 355, 9,
+ 354, 357, 107, 17, 145, 24, 13, 144, 19, 25,
+ 57, 23, 8, 28, 27, 269, 15, 263, 10, 259,
+ 12, 261, 11, 260, 20, 267, 21, 268, 14, 262,
+ 258, 299, 411, 264, 265, 202, 193, 192, 204, 203,
+ 229, 194, 360, 359, 231, 463, 462, 321, 322, 465,
+ 324, 464, 323, 419, 423, 426, 422, 421, 441, 442,
+ 185, 199, 181, 184, 198, 206, 0};
+
+const short QQmlJSGrammar::action_index [] = {
+ 404, 1275, 2411, 2411, 2509, 1000, 68, 92, 90, -102,
+ 88, 62, 60, 256, -102, 298, 86, -102, -102, 638,
+ 83, 134, 172, 219, -102, -102, -102, 454, 194, 1275,
+ -102, -102, -102, 381, -102, 2215, 1555, 1275, 1275, 1275,
+ -102, 790, 1275, -102, -102, -102, 1275, 1275, -102, -102,
+ -102, -102, -102, 1275, -102, 1275, 1275, -102, 1275, 1275,
+ 102, 217, -102, -102, 1275, 1275, 1275, -102, -102, -102,
+ 204, 1275, 304, 1275, 1275, 1275, 1275, 539, 1275, 1275,
+ 1275, 1275, 1275, 1275, 308, 1275, 1275, 1275, 103, 131,
+ 135, 308, 210, 225, 216, 308, 444, 390, 434, 1275,
+ 82, 1275, 100, 2117, 1275, 1275, -102, -102, -102, -102,
+ -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,
+ -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,
+ -102, -102, -102, -102, -102, -102, -102, -102, -102, -102,
+ 139, 1275, -102, -102, 91, 10, -102, 1275, -102, -102,
+ 1275, -102, -102, -102, -102, -102, -102, -102, -102, -102,
+ -102, -102, -102, -102, 1275, 26, 1275, 1275, 69, 66,
+ 1275, -102, 2117, 1275, 1275, -102, 97, -102, 44, -102,
+ -102, 67, -102, 297, 78, 24, -102, 291, -102, 36,
+ 2411, -102, -102, -102, -102, -102, 234, -102, -102, 12,
+ -102, -102, -102, -102, -102, -102, 2411, -102, -102, 464,
+ -102, 461, 115, 2509, 42, 381, 58, 46, 2705, 70,
+ 1275, -102, 74, 57, 1275, 65, -102, 59, 61, -102,
+ -102, 367, -102, -102, -102, -102, -102, -102, 106, -102,
+ -102, -102, -102, 87, -102, -102, -102, -102, -102, -102,
+ 56, 55, 1275, 99, 84, -102, -102, 1461, -102, 75,
+ 48, 52, -102, 306, 72, 53, 579, 77, 110, 370,
+ 230, 381, 1275, 286, 1275, 1275, 1275, 1275, 380, 1275,
+ 1275, 1275, 1275, 1275, 184, 169, 166, 190, 198, 460,
+ 363, 353, 1275, 50, 1275, 63, 1275, -102, 638, 1275,
+ -102, 1275, 64, 39, 1275, 30, 2509, -102, 1275, 173,
+ 2509, -102, 1275, 79, 1275, 1275, 81, 80, 1275, -102,
+ 71, 149, 32, -102, -102, 1275, -102, 381, 1275, -102,
+ 73, 1275, 76, 2509, -102, 1275, 142, 2509, -102, -16,
+ 381, -42, -12, 2411, -39, -102, 2509, -102, 1275, 154,
+ 2509, 14, 2509, -102, 20, 16, -32, -102, -102, 2509,
+ -51, 519, -4, 511, 136, 1275, 2509, -2, -35, 395,
+ -1, -27, 908, 4, 6, -102, 1370, -102, 0, -36,
+ 27, 1275, 47, 22, 1275, 45, 1275, 21, 17, 1275,
+ -102, 2313, 144, -102, -102, -102, -102, -102, -102, 1275,
+ -102, -102, -102, -102, 274, -102, 1275, -21, -102, 2509,
+ -102, 138, -102, -102, 2509, -102, 1275, 132, 5, -102,
+ 40, -102, 41, 101, 1275, -102, 38, 34, -102, -38,
+ -102, 2509, -102, 105, 2509, -102, 245, -102, -102, 96,
+ 2509, 11, -102, -7, -11, -102, 352, 8, 18, -102,
+ -102, -102, -102, 1275, 129, 2509, -102, 1275, 130, 2509,
+ -102, 49, -102, 226, -102, -102, 1275, -102, -102, 362,
+ -102, -102, -102, 107, 1837, -102, -102, 1649, -102, -102,
+ 1743, -102, -102, -102, -102, -102, -102, 114, -102, -102,
+ -102, -102, -102, -102, -102, -102, -102, 2411, -102, -102,
+ -102, 94, 9, 818, 189, -10, 31, -102, -102, 223,
+ -102, 191, -102, -102, -102, 300, 178, -102, 1928, -102,
+ -102, -102, -102, -102, -102, -102, -102, -102, 257, -25,
+ 381, 195, -22, 305, 240, -102, -6, -102, 818, 127,
+ -102, -18, 818, -102, -102, 1184, -102, -102, -102, 1092,
+ -102, -102, 237, -102, 1928, -102, 294, -8, -102, -102,
+ 176, 381, 19, 1928, -102, 165, -102, 174, -102, 2,
+ -52, 381, 183, 381, -102, 117, -102, -102, -102, 2019,
+ 880, 285, 2607, 1555, 3, -102, 522, 35, 453, 108,
+ 1275, 2509, 51, 23, 475, 54, -17, 700, 7, 43,
+ -102, 1370, -102, 28, -3, 33, 1275, 37, 15, 1275,
+ 25, 1275, 1, 13, 124, -102, -102, 29, -102, -102,
+ 728, -102, 250, -43, 627, -102, -102, 231, 372, -102,
+ 222, -102, 111, -102, -102, 381, -102, -102, 104, -102,
+ -102, -102, -102, -102, -102,
+
+ -107, 9, -103, 2, 5, 266, 1, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -39,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, 86,
+ -107, -107, -107, 8, -107, -107, -22, 19, 71, 174,
+ -107, 186, 171, -107, -107, -107, 184, 178, -107, -107,
+ -107, -107, -107, 144, -107, 124, 150, -107, 165, 161,
+ -107, -107, -107, -107, 156, 160, 157, -107, -107, -107,
+ -107, 147, -107, 142, 135, 179, 166, -107, 177, 170,
+ 117, 72, 134, 92, -107, 75, 94, 66, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, 181,
+ -107, 106, -107, 143, 78, 55, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -5, -107, -107, -107, -107, -107, 54, -107, -107,
+ 51, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, 114, -107, 113, 38, -107, -107,
+ 41, -107, 231, 63, 112, -107, -107, -107, -107, -107,
+ -107, -107, -107, 30, -107, -107, -107, 52, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, 36, -107, -107, 45,
+ -107, 42, -107, 40, -107, 80, -107, -107, 77, -107,
+ 88, -107, -107, -107, 83, 74, -107, -107, -107, -107,
+ -107, -10, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, 23, -107, -107, -107, -107, 100, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, 4, 223, -107, 230, 236, 222, 205, -107, 127,
+ 125, 115, 96, 102, -107, -107, -107, -107, -107, -107,
+ -107, -107, 234, -107, 215, -107, 199, -107, -107, 197,
+ -107, 190, -107, -107, 163, -107, 90, -107, 0, -107,
+ -1, -107, 203, -107, 189, 211, -107, -107, 195, -107,
+ -107, -107, -107, -107, -107, 191, -107, 98, 119, -107,
+ -107, 95, -107, 81, -107, 79, -107, 82, -107, -107,
+ 101, -107, -107, -16, -107, -107, 53, -107, 46, -107,
+ 57, -107, 59, -107, -107, -107, -107, -107, -107, 35,
+ -107, 33, -107, 39, -107, 89, 67, -107, -107, 58,
+ -107, -107, 84, -107, -107, -107, 73, -107, -107, -107,
+ -107, 65, -107, 43, 93, -107, 109, -107, -107, 49,
+ -107, 47, -107, -107, -107, -107, -107, -107, -107, 50,
+ -107, -107, -107, -107, -107, -107, 108, -107, -107, 61,
+ -107, -107, -107, -107, 62, -107, 68, -107, -107, -107,
+ -107, -107, -23, -107, 69, -107, -19, -107, -107, -107,
+ -107, 97, -107, -107, 99, -107, -107, -107, -107, -107,
+ 60, -61, -107, -107, 34, -107, 37, -107, 29, -107,
+ -107, -107, -107, 32, -107, 76, -107, 44, -107, 56,
+ -107, -107, -107, -107, -107, -107, 31, -107, -107, 116,
+ -107, -107, -107, -107, -6, -107, -107, 70, -107, -107,
+ 64, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107, -107, -107, 193, -107, -107,
+ -107, -107, -107, 7, -107, -107, -107, -107, -107, -107,
+ -107, -20, -107, -107, -107, -7, -107, -107, 290, -107,
+ -107, -107, -107, -107, -107, -107, -107, -107, -107, -107,
+ -2, -25, -107, -15, -107, -107, -107, -107, 172, -107,
+ -107, -107, 287, -107, -107, 288, -107, -107, -107, 291,
+ -107, -107, -107, -107, 336, -107, -107, 20, -107, -107,
+ 15, 3, -107, 304, -107, -107, -107, 24, -107, -107,
+ -107, 28, 21, 26, -107, -107, -107, -107, -107, 320,
+ 104, -107, 13, 381, -3, -107, 6, -107, 10, -107,
+ 167, 22, -107, -107, 12, -107, -107, 87, -107, -107,
+ -107, 25, -107, -107, -107, -107, 11, -107, 14, 85,
+ -107, 121, -107, -107, -107, -107, -107, 27, -107, -107,
+ 17, -107, -107, 18, 91, -107, -107, -107, 16, -107,
+ -107, -107, -107, -107, -107, -4, -107, -107, -107, -107,
+ -107, -107, -107, -107, -107};
+
+const short QQmlJSGrammar::action_info [] = {
+ 416, 257, 533, -132, 403, -113, 346, -102, 575, 348,
+ 572, -121, 531, -103, -121, 545, 345, 430, 342, 348,
+ 340, 343, 440, 401, 391, 545, 563, 389, 538, 446,
+ 352, 444, -129, 416, -124, -102, 545, 453, 420, 408,
+ -124, 431, -132, 424, -126, 424, 424, 620, 440, 457,
+ -103, 440, -129, 457, -126, 440, 560, 453, -113, 257,
+ 565, 346, 545, 335, 272, 346, 466, 236, 448, 190,
+ 149, 164, 141, 170, 99, 511, 272, 409, 257, 312,
+ 296, 414, 348, 312, 189, 164, 187, 318, 325, 71,
+ 306, 252, 644, 416, 141, 453, 292, 457, 440, 147,
+ 304, 71, 443, 183, 179, 141, 0, 141, 0, 172,
+ 99, 427, 434, 141, 301, 477, 444, 0, 0, 0,
+ 0, 0, 141, 0, 0, 0, 0, 292, 173, 294,
+ 58, 294, 542, 251, 331, 542, 333, 141, 141, 101,
+ 141, 59, 0, 58, 62, 256, 255, 141, 247, 246,
+ 141, 399, 0, 177, 59, 63, 428, 327, 620, 254,
+ 314, 101, 141, 478, 315, 640, 639, 242, 241, 249,
+ 248, 58, 634, 633, 488, 58, 249, 248, 577, 576,
+ 615, 141, 59, 543, 166, 518, 59, 172, 167, 455,
+ 459, 85, 418, 86, 85, 142, 86, 249, 248, 413,
+ 412, 567, 337, 512, 87, 512, 173, 87, 174, 85,
+ 328, 86, 512, 0, 350, 85, 64, 86, 529, 85,
+ 512, 86, 87, 85, 512, 86, 568, 566, 87, 64,
+ 579, 64, 87, 310, 469, 85, 87, 86, 0, 519,
+ 517, 85, 141, 86, 554, 0, 172, 536, 87, 514,
+ 85, 514, 86, 141, 87, 85, 545, 86, 514, 0,
+ 513, 65, 513, 87, 514, 173, 514, 66, 87, 513,
+ 514, 103, 172, 0, 65, 513, 65, 513, 0, 0,
+ 66, 513, 66, 637, 636, 0, 0, 470, 468, 172,
+ 104, 173, 105, 406, 0, 235, 234, 630, 555, 553,
+ 172, 537, 535, 0, 274, 275, 438, 437, 173, 172,
+ 406, 631, 629, 635, 0, 580, 73, 74, -90, 173,
+ 34, 174, 73, 74, 274, 275, 34, -90, 173, 34,
+ 174, 276, 277, 85, 34, 86, 0, 0, 0, 0,
+ 0, 628, 0, 75, 76, 0, 87, 0, 0, 75,
+ 76, 276, 277, 0, 0, 0, 0, 48, 50, 49,
+ 0, 0, 0, 48, 50, 49, 48, 50, 49, 0,
+ 0, 48, 50, 49, 0, 0, 279, 280, 0, 0,
+ 0, 34, 0, 45, 0, 281, 279, 280, 282, 45,
+ 283, 34, 45, 279, 280, 281, 34, 45, 282, 0,
+ 283, 34, 281, 279, 280, 282, 0, 283, 0, 0,
+ 34, 0, 281, 78, 79, 282, 0, 283, 48, 50,
+ 49, 80, 81, 0, 34, 82, 0, 83, 48, 50,
+ 49, -345, 0, 48, 50, 49, 0, 0, 48, 50,
+ 49, 0, 0, 0, 45, 0, 0, 48, 50, 49,
+ 0, 0, 0, 0, 45, 0, 0, 78, 79, 45,
+ 0, 48, 50, 49, 45, 80, 81, 78, 79, 82,
+ 0, 83, 0, 45, 0, 80, 81, 78, 79, 82,
+ 0, 83, 34, 279, 280, 80, 81, 45, 0, 82,
+ 34, 83, 281, 34, 0, 282, 0, 283, 6, 5,
+ 4, 1, 3, 2, 34, 0, 0, 0, 0, 0,
+ 0, -345, 0, 0, 245, 244, 0, 0, 0, 48,
+ 50, 49, 245, 244, 0, 240, 239, 48, 50, 49,
+ 48, 50, 49, 0, 0, 0, 0, 0, 0, 0,
+ 34, 48, 50, 49, 0, 45, 0, 0, 34, 0,
+ 0, 34, 0, 45, 0, 0, 45, 0, 0, 0,
+ 0, 0, 78, 79, 0, 0, 0, 45, 0, 0,
+ 80, 81, 245, 244, 82, 0, 83, 48, 50, 49,
+ 240, 239, 151, 240, 239, 48, 50, 49, 48, 50,
+ 49, 0, 152, 0, 0, 0, 153, 0, 0, 0,
+ 0, 0, 0, 45, 0, 154, 0, 155, 0, 0,
+ 308, 45, 0, 0, 45, 0, 0, 0, 156, 0,
+ 157, 62, 0, 0, 0, 0, 0, 0, 158, 0,
+ 0, 159, 63, 0, 0, 0, 0, 160, 0, 30,
+ 31, 151, 0, 161, 0, 0, 0, 0, 0, 33,
+ 0, 152, 0, 0, 0, 153, 34, 0, 0, 162,
+ 35, 36, 0, 37, 154, 0, 155, 0, 0, 0,
+ 503, 0, 0, 0, 44, 0, 0, 156, 0, 157,
+ 62, 0, 0, 0, 0, 0, 0, 158, 0, 0,
+ 159, 63, 51, 48, 50, 49, 160, 52, 0, 0,
+ 0, 0, 161, 0, 0, 0, 0, 0, 43, 54,
+ 32, 0, 30, 31, 40, 0, 0, 0, 162, 45,
+ 0, 0, 33, 0, 0, 0, 0, 0, 0, 34,
+ 0, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 30, 31, 0, 41, 0, 0, 0, 44, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 51, 48, 50, 49, 0,
+ 52, 503, 0, 0, 0, 44, 0, 0, 0, 0,
+ 0, 43, 54, 32, 0, 0, 0, 40, 0, 0,
+ 0, 0, 45, 51, 48, 50, 49, 0, 52, 0,
+ 0, 0, 30, 31, 0, 0, 0, 0, 0, 43,
+ 54, 32, 33, 0, 0, 40, 0, 0, 0, 34,
+ 45, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 30, 31, 0, 41, 0, 0, 0, 44, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 51, 48, 50, 49, 0,
+ 52, 503, 0, 0, 0, 44, 0, 0, 0, 0,
+ 0, 43, 54, 32, 0, 0, 0, 40, 0, 0,
+ 0, 0, 45, 51, 48, 50, 49, 0, 52, 0,
+ 0, 0, 30, 31, 0, 0, 0, 0, 0, 43,
+ 54, 32, 33, 0, 0, 40, 0, 0, 0, 34,
+ 45, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 30, 31, 0, 503, 0, 0, 0, 44, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 0, 0,
+ 0, 35, 36, 0, 37, 51, 48, 50, 49, 0,
+ 52, 41, 0, 0, 0, 44, 0, 0, 0, 0,
+ 0, 43, 54, 32, 0, 0, 0, 40, 0, 0,
+ 0, 0, 45, 51, 48, 50, 49, 0, 52, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 43,
+ 54, 32, 0, 0, 0, 40, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 502, 0, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 215, 0, 0, 0, 0, 0, 0, 34,
+ 0, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 0, 0, 0, 503, 0, 0, 0, 44, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 51, 504, 506, 505, 0,
+ 52, 0, 0, 0, 0, 226, 0, 0, 0, 0,
+ 0, 43, 54, 32, 210, 0, 0, 40, 0, 0,
+ 0, 0, 45, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 502, 0, 30, 31, 0, 0, 0, 0,
+ 0, 0, 0, 0, 215, 0, 0, 0, 0, 0,
+ 0, 34, 0, 0, 0, 35, 36, 0, 37, 0,
+ 0, 0, 0, 0, 0, 503, 0, 0, 0, 44,
+ 0, 0, 0, 0, 0, 0, 0, 550, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 51, 504, 506,
+ 505, 0, 52, 0, 0, 0, 0, 226, 0, 0,
+ 0, 0, 0, 43, 54, 32, 210, 0, 0, 40,
+ 0, 0, 0, 0, 45, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 502, 0, 30, 31, 0, 0,
+ 0, 0, 0, 0, 0, 0, 215, 0, 0, 0,
+ 0, 0, 0, 34, 0, 0, 0, 35, 36, 0,
+ 37, 0, 0, 0, 0, 0, 0, 503, 0, 0,
+ 0, 44, 0, 0, 0, 0, 0, 0, 0, 547,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 51,
+ 504, 506, 505, 0, 52, 0, 0, 0, 0, 226,
+ 0, 0, 0, 0, 0, 43, 54, 32, 210, 0,
+ 0, 40, 0, 0, 0, 0, 45, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 29, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 0, 35, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 41, 42,
+ 0, 0, 44, 0, 0, 0, 46, 0, 47, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 51, 48, 50, 49, 0, 52, 0, 53, 0, 55,
+ 0, 56, 0, 0, 0, 0, 43, 54, 32, 0,
+ 0, 0, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, -122, 0, 0,
+ 0, 29, 30, 31, 0, 0, 0, 0, 0, 0,
+ 0, 0, 33, 0, 0, 0, 0, 0, 0, 34,
+ 0, 0, 0, 35, 36, 0, 37, 0, 0, 0,
+ 38, 0, 39, 41, 42, 0, 0, 44, 0, 0,
+ 0, 46, 0, 47, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 51, 48, 50, 49, 0,
+ 52, 0, 53, 0, 55, 0, 56, 0, 0, 0,
+ 0, 43, 54, 32, 0, 0, 0, 40, 0, 0,
+ 0, 0, 45, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 29, 30, 31, 0, 0, 0, 0, 0,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0,
+ 34, 0, 0, 0, 35, 36, 0, 37, 0, 0,
+ 0, 38, 0, 39, 41, 42, 0, 0, 44, 0,
+ 0, 0, 46, 0, 47, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 51, 48, 50, 49,
+ 0, 52, 0, 53, 0, 55, 271, 56, 0, 0,
+ 0, 0, 43, 54, 32, 0, 0, 0, 40, 0,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 475, 0, 0, 29, 30, 31, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
+ 0, 0, 0, 0, 34, 0, 0, 0, 35, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 41, 42,
+ 0, 0, 44, 0, 0, 0, 46, 0, 47, 0,
+ 0, 476, 0, 0, 0, 0, 0, 0, 0, 0,
+ 51, 48, 50, 49, 0, 52, 0, 53, 0, 55,
+ 0, 56, 0, 0, 0, 0, 43, 54, 32, 0,
+ 0, 0, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 475, 0, 0,
+ 29, 30, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 33, 0, 0, 0, 0, 0, 0, 34, 0,
+ 0, 0, 35, 36, 0, 37, 0, 0, 0, 38,
+ 0, 39, 41, 42, 0, 0, 44, 0, 0, 0,
+ 46, 0, 47, 0, 0, 481, 0, 0, 0, 0,
+ 0, 0, 0, 0, 51, 48, 50, 49, 0, 52,
+ 0, 53, 0, 55, 0, 56, 0, 0, 0, 0,
+ 43, 54, 32, 0, 0, 0, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 483, 0, 0, 29, 30, 31, 0, 0, 0,
+ 0, 0, 0, 0, 0, 33, 0, 0, 0, 0,
+ 0, 0, 34, 0, 0, 0, 35, 36, 0, 37,
+ 0, 0, 0, 38, 0, 39, 41, 42, 0, 0,
+ 44, 0, 0, 0, 46, 0, 47, 0, 0, 484,
+ 0, 0, 0, 0, 0, 0, 0, 0, 51, 48,
+ 50, 49, 0, 52, 0, 53, 0, 55, 0, 56,
+ 0, 0, 0, 0, 43, 54, 32, 0, 0, 0,
+ 40, 0, 0, 0, 0, 45, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 483, 0, 0, 29, 30,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 33,
+ 0, 0, 0, 0, 0, 0, 34, 0, 0, 0,
+ 35, 36, 0, 37, 0, 0, 0, 38, 0, 39,
+ 41, 42, 0, 0, 44, 0, 0, 0, 46, 0,
+ 47, 0, 0, 486, 0, 0, 0, 0, 0, 0,
+ 0, 0, 51, 48, 50, 49, 0, 52, 0, 53,
+ 0, 55, 0, 56, 0, 0, 0, 0, 43, 54,
+ 32, 0, 0, 0, 40, 0, 0, 0, 0, 45,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 29,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 33, 0, 0, 0, 0, 0, 0, 34, 217, 0,
+ 0, 218, 36, 0, 37, 0, 0, 0, 38, 0,
+ 39, 41, 42, 0, 0, 44, 0, 0, 0, 46,
+ 0, 47, 0, 0, 0, 0, 0, 0, 0, 221,
+ 0, 0, 0, 51, 48, 50, 49, 223, 52, 0,
+ 53, 225, 55, 0, 56, 0, 228, 0, 0, 43,
+ 54, 32, 0, 0, 0, 40, 0, 0, 0, 0,
+ 45, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 29, 30, 31, 0, 0, 0, 0, 0, 0, 0,
+ 0, 33, 0, 0, 0, 0, 0, 0, 34, 217,
+ 0, 0, 582, 583, 0, 37, 0, 0, 0, 38,
+ 0, 39, 41, 42, 0, 0, 44, 0, 0, 0,
+ 46, 0, 47, 0, 0, 0, 0, 0, 0, 0,
+ 221, 0, 0, 0, 51, 48, 50, 49, 223, 52,
+ 0, 53, 225, 55, 0, 56, 0, 228, 0, 0,
+ 43, 54, 32, 0, 0, 0, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 109, 110, 111, 0, 0, 113, 115, 116, 0,
+ 0, 117, 0, 118, 0, 0, 0, 120, 121, 122,
+ 0, 0, 0, 0, 0, 0, 34, 123, 124, 125,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 126, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 129, 0, 0, 0,
+ 0, 0, 0, 48, 50, 49, 130, 131, 132, 0,
+ 134, 135, 136, 137, 138, 139, 0, 0, 127, 133,
+ 119, 112, 114, 128, 0, 0, 0, 0, 0, 45,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 109,
+ 110, 111, 0, 0, 113, 115, 116, 0, 0, 117,
+ 0, 118, 0, 0, 0, 120, 121, 122, 0, 0,
+ 0, 0, 0, 0, 393, 123, 124, 125, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 126, 0,
+ 0, 0, 394, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 129, 0, 0, 0, 0, 0,
+ 398, 395, 397, 0, 130, 131, 132, 0, 134, 135,
+ 136, 137, 138, 139, 0, 0, 127, 133, 119, 112,
+ 114, 128, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 109, 110, 111,
+ 0, 0, 113, 115, 116, 0, 0, 117, 0, 118,
+ 0, 0, 0, 120, 121, 122, 0, 0, 0, 0,
+ 0, 0, 393, 123, 124, 125, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 126, 0, 0, 0,
+ 394, 0, 0, 0, 0, 0, 0, 0, 396, 0,
+ 0, 0, 129, 0, 0, 0, 0, 0, 398, 395,
+ 397, 0, 130, 131, 132, 0, 134, 135, 136, 137,
+ 138, 139, 0, 0, 127, 133, 119, 112, 114, 128,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 209, 0, 0, 0, 0,
+ 211, 0, 29, 30, 31, 213, 0, 0, 0, 0,
+ 0, 0, 214, 215, 0, 0, 0, 0, 0, 0,
+ 216, 217, 0, 0, 218, 36, 0, 37, 0, 0,
+ 0, 38, 0, 39, 41, 42, 0, 0, 44, 0,
+ 0, 0, 46, 0, 47, 0, 0, 0, 0, 0,
+ 220, 0, 221, 0, 0, 0, 51, 219, 222, 49,
+ 223, 52, 224, 53, 225, 55, 226, 56, 227, 228,
+ 0, 0, 43, 54, 32, 210, 212, 0, 40, 0,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 209, 0, 0, 0, 0, 211, 0,
+ 29, 30, 31, 213, 0, 0, 0, 0, 0, 0,
+ 214, 33, 0, 0, 0, 0, 0, 0, 216, 217,
+ 0, 0, 218, 36, 0, 37, 0, 0, 0, 38,
+ 0, 39, 41, 42, 0, 0, 44, 0, 0, 0,
+ 46, 0, 47, 0, 0, 0, 0, 0, 220, 0,
+ 221, 0, 0, 0, 51, 219, 222, 49, 223, 52,
+ 224, 53, 225, 55, 226, 56, 227, 228, 0, 0,
+ 43, 54, 32, 210, 212, 0, 40, 0, 0, 0,
+ 0, 45, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 586, 110, 111, 0, 0, 588, 115, 590, 30,
+ 31, 591, 0, 118, 0, 0, 0, 120, 593, 594,
+ 0, 0, 0, 0, 0, 0, 595, 596, 124, 125,
+ 218, 36, 0, 37, 0, 0, 0, 38, 0, 39,
+ 597, 42, 0, 0, 599, 0, 0, 0, 46, 0,
+ 47, 0, 0, 0, 0, 0, 601, 0, 221, 0,
+ 0, 0, 603, 600, 602, 49, 604, 605, 606, 53,
+ 608, 609, 610, 611, 612, 613, 0, 0, 598, 607,
+ 592, 587, 589, 128, 40, 0, 0, 0, 0, 45,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 361,
+ 110, 111, 0, 0, 363, 115, 365, 30, 31, 366,
+ 0, 118, 0, 0, 0, 120, 368, 369, 0, 0,
+ 0, 0, 0, 0, 370, 371, 124, 125, 218, 36,
+ 0, 37, 0, 0, 0, 38, 0, 39, 372, 42,
+ 0, 0, 374, 0, 0, 0, 46, 0, 47, 0,
+ -268, 0, 0, 0, 376, 0, 221, 0, 0, 0,
+ 378, 375, 377, 49, 379, 380, 381, 53, 383, 384,
+ 385, 386, 387, 388, 0, 0, 373, 382, 367, 362,
+ 364, 128, 40, 0, 0, 0, 0, 45, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,
+
+ 534, 311, 497, 309, 532, 461, 498, 499, 516, 515,
+ 619, 638, 16, 552, 436, 358, 616, 472, 562, 320,
+ 528, 238, 487, 182, 250, 243, 253, 182, 302, 641,
+ 627, 632, 150, 485, 143, 454, 439, 402, 445, 559,
+ 237, 574, 250, 578, 561, 186, 618, 458, 238, 349,
+ 573, 449, 447, 571, 243, 347, 450, 243, 460, 351,
+ 238, 353, 358, 410, 415, 439, 176, 188, 436, 250,
+ 467, 417, 433, 182, 425, 429, 302, 169, 456, 358,
+ 171, 140, 336, 334, 338, 344, 436, 392, 390, 400,
+ 163, 302, 307, 148, 146, 339, 439, 404, 302, 358,
+ 404, 358, 0, 482, 501, 480, 0, 642, 0, 479,
+ 0, 0, 0, 320, 60, 0, 186, 501, 90, 60,
+ 60, 489, 302, 60, 617, 93, 0, 88, 0, 405,
+ 0, 461, 405, 60, 60, 451, 180, 60, 0, 180,
+ 60, 60, 60, 451, 60, 95, 89, 146, 266, 287,
+ 60, 146, 407, 270, 60, 288, 178, 60, 106, 452,
+ 0, 60, 60, 60, 102, 60, 302, 332, 286, 60,
+ 92, 452, 60, 60, 451, 60, 165, 168, 285, 432,
+ 284, 435, 60, 60, 108, 501, 329, 94, 540, 96,
+ 60, 330, 60, 302, 494, 60, 77, 237, 60, 404,
+ 452, 341, 471, 72, 60, 60, 67, 69, 60, 60,
+ 68, 0, 70, 60, 60, 60, 61, 180, 60, 60,
+ 98, 491, 60, 91, 490, 60, 60, 60, 493, 60,
+ 84, 405, 60, 97, 492, 305, 0, 60, 0, 298,
+ 0, 100, 270, 298, 270, 298, 106, 298, 270, 0,
+ 270, 60, 270, 60, 316, 0, 270, 0, 270, 298,
+ 291, 326, 303, 60, 270, 319, 313, 300, 270, 297,
+ 60, 60, 108, 175, 295, 270, 270, 290, 60, 501,
+ 273, 317, 60, 270, 60, 278, 509, 270, 0, 270,
+ 0, 289, 0, 548, 0, 293, 551, 0, 500, 510,
+ 501, 501, 0, 544, 501, 0, 0, 0, 509, 0,
+ 0, 509, 520, 521, 522, 523, 527, 524, 525, 0,
+ 500, 510, 0, 500, 510, 564, 520, 521, 522, 523,
+ 527, 524, 525, 581, 0, 0, 0, 0, 0, 0,
+ 584, 585, 520, 521, 522, 523, 527, 524, 525, 556,
+ 0, 0, 0, 0, 0, 0, 557, 558, 520, 521,
+ 522, 523, 527, 524, 525, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 556, 0, 0, 540, 0, 614,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 472, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0};
+
+const short QQmlJSGrammar::action_check [] = {
+ 36, 36, 24, 7, 55, 7, 7, 7, 60, 36,
+ 8, 7, 37, 7, 7, 33, 55, 55, 60, 36,
+ 36, 33, 33, 55, 8, 33, 7, 7, 34, 36,
+ 16, 20, 7, 36, 7, 7, 33, 36, 33, 60,
+ 7, 7, 7, 5, 7, 5, 5, 90, 33, 36,
+ 7, 33, 7, 36, 7, 33, 66, 36, 7, 36,
+ 29, 7, 33, 31, 1, 7, 17, 55, 60, 33,
+ 60, 2, 8, 7, 48, 66, 1, 7, 36, 2,
+ 8, 7, 36, 2, 60, 2, 8, 7, 17, 1,
+ 60, 36, 0, 36, 8, 36, 48, 36, 33, 8,
+ 61, 1, 6, 36, 60, 8, -1, 8, -1, 15,
+ 48, 10, 7, 8, 61, 8, 20, -1, -1, -1,
+ -1, -1, 8, -1, -1, -1, -1, 48, 34, 79,
+ 40, 79, 8, 77, 61, 8, 60, 8, 8, 79,
+ 8, 51, -1, 40, 42, 61, 62, 8, 61, 62,
+ 8, 7, -1, 56, 51, 53, 55, 8, 90, 60,
+ 50, 79, 8, 56, 54, 61, 62, 61, 62, 61,
+ 62, 40, 61, 62, 60, 40, 61, 62, 61, 62,
+ 56, 8, 51, 56, 50, 7, 51, 15, 54, 60,
+ 60, 25, 60, 27, 25, 56, 27, 61, 62, 61,
+ 62, 36, 60, 29, 38, 29, 34, 38, 36, 25,
+ 61, 27, 29, -1, 60, 25, 12, 27, 29, 25,
+ 29, 27, 38, 25, 29, 27, 61, 62, 38, 12,
+ 7, 12, 38, 60, 8, 25, 38, 27, -1, 61,
+ 62, 25, 8, 27, 7, -1, 15, 7, 38, 75,
+ 25, 75, 27, 8, 38, 25, 33, 27, 75, -1,
+ 86, 57, 86, 38, 75, 34, 75, 63, 38, 86,
+ 75, 15, 15, -1, 57, 86, 57, 86, -1, -1,
+ 63, 86, 63, 61, 62, -1, -1, 61, 62, 15,
+ 34, 34, 36, 36, -1, 61, 62, 47, 61, 62,
+ 15, 61, 62, -1, 18, 19, 61, 62, 34, 15,
+ 36, 61, 62, 91, -1, 92, 18, 19, 33, 34,
+ 29, 36, 18, 19, 18, 19, 29, 33, 34, 29,
+ 36, 45, 46, 25, 29, 27, -1, -1, -1, -1,
+ -1, 91, -1, 45, 46, -1, 38, -1, -1, 45,
+ 46, 45, 46, -1, -1, -1, -1, 66, 67, 68,
+ -1, -1, -1, 66, 67, 68, 66, 67, 68, -1,
+ -1, 66, 67, 68, -1, -1, 23, 24, -1, -1,
+ -1, 29, -1, 92, -1, 32, 23, 24, 35, 92,
+ 37, 29, 92, 23, 24, 32, 29, 92, 35, -1,
+ 37, 29, 32, 23, 24, 35, -1, 37, -1, -1,
+ 29, -1, 32, 23, 24, 35, -1, 37, 66, 67,
+ 68, 31, 32, -1, 29, 35, -1, 37, 66, 67,
+ 68, 36, -1, 66, 67, 68, -1, -1, 66, 67,
+ 68, -1, -1, -1, 92, -1, -1, 66, 67, 68,
+ -1, -1, -1, -1, 92, -1, -1, 23, 24, 92,
+ -1, 66, 67, 68, 92, 31, 32, 23, 24, 35,
+ -1, 37, -1, 92, -1, 31, 32, 23, 24, 35,
+ -1, 37, 29, 23, 24, 31, 32, 92, -1, 35,
+ 29, 37, 32, 29, -1, 35, -1, 37, 94, 95,
+ 96, 97, 98, 99, 29, -1, -1, -1, -1, -1,
+ -1, 36, -1, -1, 61, 62, -1, -1, -1, 66,
+ 67, 68, 61, 62, -1, 61, 62, 66, 67, 68,
+ 66, 67, 68, -1, -1, -1, -1, -1, -1, -1,
+ 29, 66, 67, 68, -1, 92, -1, -1, 29, -1,
+ -1, 29, -1, 92, -1, -1, 92, -1, -1, -1,
+ -1, -1, 23, 24, -1, -1, -1, 92, -1, -1,
+ 31, 32, 61, 62, 35, -1, 37, 66, 67, 68,
+ 61, 62, 3, 61, 62, 66, 67, 68, 66, 67,
+ 68, -1, 13, -1, -1, -1, 17, -1, -1, -1,
+ -1, -1, -1, 92, -1, 26, -1, 28, -1, -1,
+ 31, 92, -1, -1, 92, -1, -1, -1, 39, -1,
+ 41, 42, -1, -1, -1, -1, -1, -1, 49, -1,
+ -1, 52, 53, -1, -1, -1, -1, 58, -1, 12,
+ 13, 3, -1, 64, -1, -1, -1, -1, -1, 22,
+ -1, 13, -1, -1, -1, 17, 29, -1, -1, 80,
+ 33, 34, -1, 36, 26, -1, 28, -1, -1, -1,
+ 43, -1, -1, -1, 47, -1, -1, 39, -1, 41,
+ 42, -1, -1, -1, -1, -1, -1, 49, -1, -1,
+ 52, 53, 65, 66, 67, 68, 58, 70, -1, -1,
+ -1, -1, 64, -1, -1, -1, -1, -1, 81, 82,
+ 83, -1, 12, 13, 87, -1, -1, -1, 80, 92,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ -1, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ 12, 13, -1, 43, -1, -1, -1, 47, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, 65, 66, 67, 68, -1,
+ 70, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, 87, -1, -1,
+ -1, -1, 92, 65, 66, 67, 68, -1, 70, -1,
+ -1, -1, 12, 13, -1, -1, -1, -1, -1, 81,
+ 82, 83, 22, -1, -1, 87, -1, -1, -1, 29,
+ 92, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ 12, 13, -1, 43, -1, -1, -1, 47, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, 65, 66, 67, 68, -1,
+ 70, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, 87, -1, -1,
+ -1, -1, 92, 65, 66, 67, 68, -1, 70, -1,
+ -1, -1, 12, 13, -1, -1, -1, -1, -1, 81,
+ 82, 83, 22, -1, -1, 87, -1, -1, -1, 29,
+ 92, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ 12, 13, -1, 43, -1, -1, -1, 47, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, -1, -1,
+ -1, 33, 34, -1, 36, 65, 66, 67, 68, -1,
+ 70, 43, -1, -1, -1, 47, -1, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, 87, -1, -1,
+ -1, -1, 92, 65, 66, 67, 68, -1, 70, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 81,
+ 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 10, -1, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ -1, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ -1, -1, -1, 43, -1, -1, -1, 47, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 65, 66, 67, 68, -1,
+ 70, -1, -1, -1, -1, 75, -1, -1, -1, -1,
+ -1, 81, 82, 83, 84, -1, -1, 87, -1, -1,
+ -1, -1, 92, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 10, -1, 12, 13, -1, -1, -1, -1,
+ -1, -1, -1, -1, 22, -1, -1, -1, -1, -1,
+ -1, 29, -1, -1, -1, 33, 34, -1, 36, -1,
+ -1, -1, -1, -1, -1, 43, -1, -1, -1, 47,
+ -1, -1, -1, -1, -1, -1, -1, 55, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 65, 66, 67,
+ 68, -1, 70, -1, -1, -1, -1, 75, -1, -1,
+ -1, -1, -1, 81, 82, 83, 84, -1, -1, 87,
+ -1, -1, -1, -1, 92, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 10, -1, 12, 13, -1, -1,
+ -1, -1, -1, -1, -1, -1, 22, -1, -1, -1,
+ -1, -1, -1, 29, -1, -1, -1, 33, 34, -1,
+ 36, -1, -1, -1, -1, -1, -1, 43, -1, -1,
+ -1, 47, -1, -1, -1, -1, -1, -1, -1, 55,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 65,
+ 66, 67, 68, -1, 70, -1, -1, -1, -1, 75,
+ -1, -1, -1, -1, -1, 81, 82, 83, 84, -1,
+ -1, 87, -1, -1, -1, -1, 92, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
+ -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
+ -1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 7, -1, -1,
+ -1, 11, 12, 13, -1, -1, -1, -1, -1, -1,
+ -1, -1, 22, -1, -1, -1, -1, -1, -1, 29,
+ -1, -1, -1, 33, 34, -1, 36, -1, -1, -1,
+ 40, -1, 42, 43, 44, -1, -1, 47, -1, -1,
+ -1, 51, -1, 53, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 65, 66, 67, 68, -1,
+ 70, -1, 72, -1, 74, -1, 76, -1, -1, -1,
+ -1, 81, 82, 83, -1, -1, -1, 87, -1, -1,
+ -1, -1, 92, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 11, 12, 13, -1, -1, -1, -1, -1,
+ -1, -1, -1, 22, -1, -1, -1, -1, -1, -1,
+ 29, -1, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
+ -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 65, 66, 67, 68,
+ -1, 70, -1, 72, -1, 74, 75, 76, -1, -1,
+ -1, -1, 81, 82, 83, -1, -1, -1, 87, -1,
+ -1, -1, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 8, -1, -1, 11, 12, 13, -1,
+ -1, -1, -1, -1, -1, -1, -1, 22, -1, -1,
+ -1, -1, -1, -1, 29, -1, -1, -1, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ -1, 56, -1, -1, -1, -1, -1, -1, -1, -1,
+ 65, 66, 67, 68, -1, 70, -1, 72, -1, 74,
+ -1, 76, -1, -1, -1, -1, 81, 82, 83, -1,
+ -1, -1, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 8, -1, -1,
+ 11, 12, 13, -1, -1, -1, -1, -1, -1, -1,
+ -1, 22, -1, -1, -1, -1, -1, -1, 29, -1,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
+ -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
+ 51, -1, 53, -1, -1, 56, -1, -1, -1, -1,
+ -1, -1, -1, -1, 65, 66, 67, 68, -1, 70,
+ -1, 72, -1, 74, -1, 76, -1, -1, -1, -1,
+ 81, 82, 83, -1, -1, -1, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 8, -1, -1, 11, 12, 13, -1, -1, -1,
+ -1, -1, -1, -1, -1, 22, -1, -1, -1, -1,
+ -1, -1, 29, -1, -1, -1, 33, 34, -1, 36,
+ -1, -1, -1, 40, -1, 42, 43, 44, -1, -1,
+ 47, -1, -1, -1, 51, -1, 53, -1, -1, 56,
+ -1, -1, -1, -1, -1, -1, -1, -1, 65, 66,
+ 67, 68, -1, 70, -1, 72, -1, 74, -1, 76,
+ -1, -1, -1, -1, 81, 82, 83, -1, -1, -1,
+ 87, -1, -1, -1, -1, 92, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 8, -1, -1, 11, 12,
+ 13, -1, -1, -1, -1, -1, -1, -1, -1, 22,
+ -1, -1, -1, -1, -1, -1, 29, -1, -1, -1,
+ 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
+ 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
+ 53, -1, -1, 56, -1, -1, -1, -1, -1, -1,
+ -1, -1, 65, 66, 67, 68, -1, 70, -1, 72,
+ -1, 74, -1, 76, -1, -1, -1, -1, 81, 82,
+ 83, -1, -1, -1, 87, -1, -1, -1, -1, 92,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 11,
+ 12, 13, -1, -1, -1, -1, -1, -1, -1, -1,
+ 22, -1, -1, -1, -1, -1, -1, 29, 30, -1,
+ -1, 33, 34, -1, 36, -1, -1, -1, 40, -1,
+ 42, 43, 44, -1, -1, 47, -1, -1, -1, 51,
+ -1, 53, -1, -1, -1, -1, -1, -1, -1, 61,
+ -1, -1, -1, 65, 66, 67, 68, 69, 70, -1,
+ 72, 73, 74, -1, 76, -1, 78, -1, -1, 81,
+ 82, 83, -1, -1, -1, 87, -1, -1, -1, -1,
+ 92, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 11, 12, 13, -1, -1, -1, -1, -1, -1, -1,
+ -1, 22, -1, -1, -1, -1, -1, -1, 29, 30,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
+ -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
+ 51, -1, 53, -1, -1, -1, -1, -1, -1, -1,
+ 61, -1, -1, -1, 65, 66, 67, 68, 69, 70,
+ -1, 72, 73, 74, -1, 76, -1, 78, -1, -1,
+ 81, 82, 83, -1, -1, -1, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 4, 5, 6, -1, -1, 9, 10, 11, -1,
+ -1, 14, -1, 16, -1, -1, -1, 20, 21, 22,
+ -1, -1, -1, -1, -1, -1, 29, 30, 31, 32,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 59, -1, -1, -1,
+ -1, -1, -1, 66, 67, 68, 69, 70, 71, -1,
+ 73, 74, 75, 76, 77, 78, -1, -1, 81, 82,
+ 83, 84, 85, 86, -1, -1, -1, -1, -1, 92,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
+ 5, 6, -1, -1, 9, 10, 11, -1, -1, 14,
+ -1, 16, -1, -1, -1, 20, 21, 22, -1, -1,
+ -1, -1, -1, -1, 29, 30, 31, 32, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 43, -1,
+ -1, -1, 47, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 59, -1, -1, -1, -1, -1,
+ 65, 66, 67, -1, 69, 70, 71, -1, 73, 74,
+ 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
+ 85, 86, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 4, 5, 6,
+ -1, -1, 9, 10, 11, -1, -1, 14, -1, 16,
+ -1, -1, -1, 20, 21, 22, -1, -1, -1, -1,
+ -1, -1, 29, 30, 31, 32, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 43, -1, -1, -1,
+ 47, -1, -1, -1, -1, -1, -1, -1, 55, -1,
+ -1, -1, 59, -1, -1, -1, -1, -1, 65, 66,
+ 67, -1, 69, 70, 71, -1, 73, 74, 75, 76,
+ 77, 78, -1, -1, 81, 82, 83, 84, 85, 86,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 4, -1, -1, -1, -1,
+ 9, -1, 11, 12, 13, 14, -1, -1, -1, -1,
+ -1, -1, 21, 22, -1, -1, -1, -1, -1, -1,
+ 29, 30, -1, -1, 33, 34, -1, 36, -1, -1,
+ -1, 40, -1, 42, 43, 44, -1, -1, 47, -1,
+ -1, -1, 51, -1, 53, -1, -1, -1, -1, -1,
+ 59, -1, 61, -1, -1, -1, 65, 66, 67, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ -1, -1, 81, 82, 83, 84, 85, -1, 87, -1,
+ -1, -1, -1, 92, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 4, -1, -1, -1, -1, 9, -1,
+ 11, 12, 13, 14, -1, -1, -1, -1, -1, -1,
+ 21, 22, -1, -1, -1, -1, -1, -1, 29, 30,
+ -1, -1, 33, 34, -1, 36, -1, -1, -1, 40,
+ -1, 42, 43, 44, -1, -1, 47, -1, -1, -1,
+ 51, -1, 53, -1, -1, -1, -1, -1, 59, -1,
+ 61, -1, -1, -1, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, -1, -1,
+ 81, 82, 83, 84, 85, -1, 87, -1, -1, -1,
+ -1, 92, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 4, 5, 6, -1, -1, 9, 10, 11, 12,
+ 13, 14, -1, 16, -1, -1, -1, 20, 21, 22,
+ -1, -1, -1, -1, -1, -1, 29, 30, 31, 32,
+ 33, 34, -1, 36, -1, -1, -1, 40, -1, 42,
+ 43, 44, -1, -1, 47, -1, -1, -1, 51, -1,
+ 53, -1, -1, -1, -1, -1, 59, -1, 61, -1,
+ -1, -1, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, -1, -1, 81, 82,
+ 83, 84, 85, 86, 87, -1, -1, -1, -1, 92,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 4,
+ 5, 6, -1, -1, 9, 10, 11, 12, 13, 14,
+ -1, 16, -1, -1, -1, 20, 21, 22, -1, -1,
+ -1, -1, -1, -1, 29, 30, 31, 32, 33, 34,
+ -1, 36, -1, -1, -1, 40, -1, 42, 43, 44,
+ -1, -1, 47, -1, -1, -1, 51, -1, 53, -1,
+ 55, -1, -1, -1, 59, -1, 61, -1, -1, -1,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, -1, -1, 81, 82, 83, 84,
+ 85, 86, 87, -1, -1, -1, -1, 92, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1,
+
+ 15, 2, 105, 3, 29, 15, 4, 2, 15, 29,
+ 9, 15, 3, 15, 3, 2, 19, 39, 15, 15,
+ 13, 15, 3, 15, 2, 15, 3, 15, 3, 11,
+ 13, 15, 71, 39, 39, 3, 22, 2, 99, 19,
+ 4, 15, 2, 15, 29, 15, 19, 3, 15, 3,
+ 29, 22, 15, 29, 15, 2, 22, 15, 2, 2,
+ 15, 2, 2, 2, 2, 22, 3, 15, 3, 2,
+ 39, 3, 3, 15, 97, 94, 3, 39, 2, 2,
+ 39, 3, 3, 2, 2, 101, 3, 40, 39, 39,
+ 39, 3, 2, 39, 39, 15, 22, 13, 3, 2,
+ 13, 2, -1, 39, 13, 35, -1, 16, -1, 39,
+ -1, -1, -1, 15, 48, -1, 15, 13, 52, 48,
+ 48, 50, 3, 48, 20, 53, -1, 52, -1, 45,
+ -1, 15, 45, 48, 48, 50, 50, 48, -1, 50,
+ 48, 48, 48, 50, 48, 53, 52, 39, 48, 53,
+ 48, 39, 44, 53, 48, 53, 44, 48, 15, 50,
+ -1, 48, 48, 48, 58, 48, 3, 72, 53, 48,
+ 53, 50, 48, 48, 50, 48, 62, 64, 53, 82,
+ 53, 82, 48, 48, 41, 13, 88, 53, 16, 54,
+ 48, 72, 48, 3, 50, 48, 54, 4, 48, 13,
+ 50, 100, 86, 56, 48, 48, 50, 50, 48, 48,
+ 50, -1, 51, 48, 48, 48, 51, 50, 48, 48,
+ 54, 50, 48, 53, 50, 48, 48, 48, 50, 48,
+ 53, 45, 48, 54, 50, 72, -1, 48, -1, 48,
+ -1, 60, 53, 48, 53, 48, 15, 48, 53, -1,
+ 53, 48, 53, 48, 65, -1, 53, -1, 53, 48,
+ 55, 70, 72, 48, 53, 70, 63, 70, 53, 70,
+ 48, 48, 41, 42, 59, 53, 53, 55, 48, 13,
+ 57, 70, 48, 53, 48, 55, 20, 53, -1, 53,
+ -1, 55, -1, 5, -1, 61, 5, -1, 32, 33,
+ 13, 13, -1, 16, 13, -1, -1, -1, 20, -1,
+ -1, 20, 22, 23, 24, 25, 26, 27, 28, -1,
+ 32, 33, -1, 32, 33, 21, 22, 23, 24, 25,
+ 26, 27, 28, 13, -1, -1, -1, -1, -1, -1,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 13,
+ -1, -1, -1, -1, -1, -1, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 13, -1, -1, 16, -1, 18,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 39, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1};
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/qmlparser/qqmljsgrammar_p.h b/src/tools/qdoc/qmlparser/qqmljsgrammar_p.h
new file mode 100644
index 0000000000..455391a862
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsgrammar_p.h
@@ -0,0 +1,211 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+// This file was generated by qlalr - DO NOT EDIT!
+#ifndef QQMLJSGRAMMAR_P_H
+#define QQMLJSGRAMMAR_P_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlJSGrammar
+{
+public:
+ enum VariousConstants {
+ EOF_SYMBOL = 0,
+ REDUCE_HERE = 101,
+ SHIFT_THERE = 100,
+ T_AND = 1,
+ T_AND_AND = 2,
+ T_AND_EQ = 3,
+ T_AS = 91,
+ T_AUTOMATIC_SEMICOLON = 62,
+ T_BREAK = 4,
+ T_CASE = 5,
+ T_CATCH = 6,
+ T_COLON = 7,
+ T_COMMA = 8,
+ T_COMMENT = 88,
+ T_CONST = 84,
+ T_CONTINUE = 9,
+ T_DEBUGGER = 85,
+ T_DEFAULT = 10,
+ T_DELETE = 11,
+ T_DIVIDE_ = 12,
+ T_DIVIDE_EQ = 13,
+ T_DO = 14,
+ T_DOT = 15,
+ T_ELSE = 16,
+ T_EQ = 17,
+ T_EQ_EQ = 18,
+ T_EQ_EQ_EQ = 19,
+ T_ERROR = 93,
+ T_FALSE = 83,
+ T_FEED_JS_EXPRESSION = 97,
+ T_FEED_JS_PROGRAM = 99,
+ T_FEED_JS_SOURCE_ELEMENT = 98,
+ T_FEED_JS_STATEMENT = 96,
+ T_FEED_UI_OBJECT_MEMBER = 95,
+ T_FEED_UI_PROGRAM = 94,
+ T_FINALLY = 20,
+ T_FOR = 21,
+ T_FUNCTION = 22,
+ T_GE = 23,
+ T_GT = 24,
+ T_GT_GT = 25,
+ T_GT_GT_EQ = 26,
+ T_GT_GT_GT = 27,
+ T_GT_GT_GT_EQ = 28,
+ T_IDENTIFIER = 29,
+ T_IF = 30,
+ T_IMPORT = 90,
+ T_IN = 31,
+ T_INSTANCEOF = 32,
+ T_LBRACE = 33,
+ T_LBRACKET = 34,
+ T_LE = 35,
+ T_LPAREN = 36,
+ T_LT = 37,
+ T_LT_LT = 38,
+ T_LT_LT_EQ = 39,
+ T_MINUS = 40,
+ T_MINUS_EQ = 41,
+ T_MINUS_MINUS = 42,
+ T_MULTILINE_STRING_LITERAL = 87,
+ T_NEW = 43,
+ T_NOT = 44,
+ T_NOT_EQ = 45,
+ T_NOT_EQ_EQ = 46,
+ T_NULL = 81,
+ T_NUMERIC_LITERAL = 47,
+ T_ON = 92,
+ T_OR = 48,
+ T_OR_EQ = 49,
+ T_OR_OR = 50,
+ T_PLUS = 51,
+ T_PLUS_EQ = 52,
+ T_PLUS_PLUS = 53,
+ T_PROPERTY = 66,
+ T_PUBLIC = 89,
+ T_QUESTION = 54,
+ T_RBRACE = 55,
+ T_RBRACKET = 56,
+ T_READONLY = 68,
+ T_REMAINDER = 57,
+ T_REMAINDER_EQ = 58,
+ T_RESERVED_WORD = 86,
+ T_RETURN = 59,
+ T_RPAREN = 60,
+ T_SEMICOLON = 61,
+ T_SIGNAL = 67,
+ T_STAR = 63,
+ T_STAR_EQ = 64,
+ T_STRING_LITERAL = 65,
+ T_SWITCH = 69,
+ T_THIS = 70,
+ T_THROW = 71,
+ T_TILDE = 72,
+ T_TRUE = 82,
+ T_TRY = 73,
+ T_TYPEOF = 74,
+ T_VAR = 75,
+ T_VOID = 76,
+ T_WHILE = 77,
+ T_WITH = 78,
+ T_XOR = 79,
+ T_XOR_EQ = 80,
+
+ ACCEPT_STATE = 644,
+ RULE_COUNT = 349,
+ STATE_COUNT = 645,
+ TERMINAL_COUNT = 102,
+ NON_TERMINAL_COUNT = 107,
+
+ GOTO_INDEX_OFFSET = 645,
+ GOTO_INFO_OFFSET = 2807,
+ GOTO_CHECK_OFFSET = 2807
+ };
+
+ static const char *const spell [];
+ static const short lhs [];
+ static const short rhs [];
+ static const short goto_default [];
+ static const short action_default [];
+ static const short action_index [];
+ static const short action_info [];
+ static const short action_check [];
+
+ static inline int nt_action (int state, int nt)
+ {
+ const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;
+ if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)
+ return goto_default [nt];
+
+ return action_info [GOTO_INFO_OFFSET + yyn];
+ }
+
+ static inline int t_action (int state, int token)
+ {
+ const int yyn = action_index [state] + token;
+
+ if (yyn < 0 || action_check [yyn] != token)
+ return - action_default [state];
+
+ return action_info [yyn];
+ }
+};
+
+
+QT_END_NAMESPACE
+#endif // QQMLJSGRAMMAR_P_H
+
diff --git a/src/tools/qdoc/qmlparser/qqmljskeywords_p.h b/src/tools/qdoc/qmlparser/qqmljskeywords_p.h
new file mode 100644
index 0000000000..bbcc4855a3
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljskeywords_p.h
@@ -0,0 +1,860 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSKEYWORDS_P_H
+#define QQMLJSKEYWORDS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+static inline int classify2(const QChar *s, bool qmlMode) {
+ if (s[0].unicode() == 'a') {
+ if (s[1].unicode() == 's') {
+ return qmlMode ? Lexer::T_AS : Lexer::T_RESERVED_WORD;
+ }
+ }
+ else if (s[0].unicode() == 'd') {
+ if (s[1].unicode() == 'o') {
+ return Lexer::T_DO;
+ }
+ }
+ else if (s[0].unicode() == 'i') {
+ if (s[1].unicode() == 'f') {
+ return Lexer::T_IF;
+ }
+ else if (s[1].unicode() == 'n') {
+ return Lexer::T_IN;
+ }
+ }
+ else if (qmlMode && s[0].unicode() == 'o') {
+ if (s[1].unicode() == 'n') {
+ return Lexer::T_ON;
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify3(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'f') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'r') {
+ return Lexer::T_FOR;
+ }
+ }
+ }
+ else if (s[0].unicode() == 'i') {
+ if (s[1].unicode() == 'n') {
+ if (s[2].unicode() == 't') {
+ return Lexer::T_INT;
+ }
+ }
+ }
+ else if (s[0].unicode() == 'n') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 'w') {
+ return Lexer::T_NEW;
+ }
+ }
+ }
+ else if (s[0].unicode() == 't') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'y') {
+ return Lexer::T_TRY;
+ }
+ }
+ }
+ else if (s[0].unicode() == 'v') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 'r') {
+ return Lexer::T_VAR;
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify4(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'b') {
+ if (s[1].unicode() == 'y') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'e') {
+ return Lexer::T_BYTE;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'c') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 's') {
+ if (s[3].unicode() == 'e') {
+ return Lexer::T_CASE;
+ }
+ }
+ }
+ else if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'a') {
+ if (s[3].unicode() == 'r') {
+ return Lexer::T_CHAR;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'e') {
+ if (s[1].unicode() == 'l') {
+ if (s[2].unicode() == 's') {
+ if (s[3].unicode() == 'e') {
+ return Lexer::T_ELSE;
+ }
+ }
+ }
+ else if (s[1].unicode() == 'n') {
+ if (s[2].unicode() == 'u') {
+ if (s[3].unicode() == 'm') {
+ return Lexer::T_ENUM;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'g') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'o') {
+ return Lexer::T_GOTO;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'l') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 'g') {
+ return Lexer::T_LONG;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'n') {
+ if (s[1].unicode() == 'u') {
+ if (s[2].unicode() == 'l') {
+ if (s[3].unicode() == 'l') {
+ return Lexer::T_NULL;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 't') {
+ if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'i') {
+ if (s[3].unicode() == 's') {
+ return Lexer::T_THIS;
+ }
+ }
+ }
+ else if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'u') {
+ if (s[3].unicode() == 'e') {
+ return Lexer::T_TRUE;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'v') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'i') {
+ if (s[3].unicode() == 'd') {
+ return Lexer::T_VOID;
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'w') {
+ if (s[1].unicode() == 'i') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'h') {
+ return Lexer::T_WITH;
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify5(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'b') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'e') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 'k') {
+ return Lexer::T_BREAK;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'c') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'c') {
+ if (s[4].unicode() == 'h') {
+ return Lexer::T_CATCH;
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'l') {
+ if (s[2].unicode() == 'a') {
+ if (s[3].unicode() == 's') {
+ if (s[4].unicode() == 's') {
+ return Lexer::T_CLASS;
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 's') {
+ if (s[4].unicode() == 't') {
+ return Lexer::T_CONST;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'f') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 'l') {
+ if (s[3].unicode() == 's') {
+ if (s[4].unicode() == 'e') {
+ return Lexer::T_FALSE;
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'i') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 'l') {
+ return Lexer::T_FINAL;
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'l') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 't') {
+ return Lexer::T_FLOAT;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 's') {
+ if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 'r') {
+ if (s[4].unicode() == 't') {
+ return Lexer::T_SHORT;
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'u') {
+ if (s[2].unicode() == 'p') {
+ if (s[3].unicode() == 'e') {
+ if (s[4].unicode() == 'r') {
+ return Lexer::T_SUPER;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 't') {
+ if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'r') {
+ if (s[3].unicode() == 'o') {
+ if (s[4].unicode() == 'w') {
+ return Lexer::T_THROW;
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'w') {
+ if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'i') {
+ if (s[3].unicode() == 'l') {
+ if (s[4].unicode() == 'e') {
+ return Lexer::T_WHILE;
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify6(const QChar *s, bool qmlMode) {
+ if (s[0].unicode() == 'd') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 'l') {
+ if (s[3].unicode() == 'e') {
+ if (s[4].unicode() == 't') {
+ if (s[5].unicode() == 'e') {
+ return Lexer::T_DELETE;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'u') {
+ if (s[3].unicode() == 'b') {
+ if (s[4].unicode() == 'l') {
+ if (s[5].unicode() == 'e') {
+ return Lexer::T_DOUBLE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'e') {
+ if (s[1].unicode() == 'x') {
+ if (s[2].unicode() == 'p') {
+ if (s[3].unicode() == 'o') {
+ if (s[4].unicode() == 'r') {
+ if (s[5].unicode() == 't') {
+ return Lexer::T_EXPORT;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'i') {
+ if (s[1].unicode() == 'm') {
+ if (s[2].unicode() == 'p') {
+ if (s[3].unicode() == 'o') {
+ if (s[4].unicode() == 'r') {
+ if (s[5].unicode() == 't') {
+ return qmlMode ? Lexer::T_IMPORT : Lexer::T_RESERVED_WORD;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'n') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'i') {
+ if (s[4].unicode() == 'v') {
+ if (s[5].unicode() == 'e') {
+ return Lexer::T_NATIVE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'p') {
+ if (s[1].unicode() == 'u') {
+ if (s[2].unicode() == 'b') {
+ if (s[3].unicode() == 'l') {
+ if (s[4].unicode() == 'i') {
+ if (s[5].unicode() == 'c') {
+ return qmlMode ? Lexer::T_PUBLIC : Lexer::T_RESERVED_WORD;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'r') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'u') {
+ if (s[4].unicode() == 'r') {
+ if (s[5].unicode() == 'n') {
+ return Lexer::T_RETURN;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 's') {
+ if (qmlMode && s[1].unicode() == 'i') {
+ if (s[2].unicode() == 'g') {
+ if (s[3].unicode() == 'n') {
+ if (s[4].unicode() == 'a') {
+ if (s[5].unicode() == 'l') {
+ return Lexer::T_SIGNAL;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 't') {
+ if (s[2].unicode() == 'a') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'i') {
+ if (s[5].unicode() == 'c') {
+ return Lexer::T_STATIC;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'w') {
+ if (s[2].unicode() == 'i') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'c') {
+ if (s[5].unicode() == 'h') {
+ return Lexer::T_SWITCH;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 't') {
+ if (s[1].unicode() == 'h') {
+ if (s[2].unicode() == 'r') {
+ if (s[3].unicode() == 'o') {
+ if (s[4].unicode() == 'w') {
+ if (s[5].unicode() == 's') {
+ return Lexer::T_THROWS;
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'y') {
+ if (s[2].unicode() == 'p') {
+ if (s[3].unicode() == 'e') {
+ if (s[4].unicode() == 'o') {
+ if (s[5].unicode() == 'f') {
+ return Lexer::T_TYPEOF;
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify7(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'b') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 'l') {
+ if (s[4].unicode() == 'e') {
+ if (s[5].unicode() == 'a') {
+ if (s[6].unicode() == 'n') {
+ return Lexer::T_BOOLEAN;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'd') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 'f') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 'u') {
+ if (s[5].unicode() == 'l') {
+ if (s[6].unicode() == 't') {
+ return Lexer::T_DEFAULT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'e') {
+ if (s[1].unicode() == 'x') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'e') {
+ if (s[4].unicode() == 'n') {
+ if (s[5].unicode() == 'd') {
+ if (s[6].unicode() == 's') {
+ return Lexer::T_EXTENDS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'f') {
+ if (s[1].unicode() == 'i') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 'l') {
+ if (s[5].unicode() == 'l') {
+ if (s[6].unicode() == 'y') {
+ return Lexer::T_FINALLY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'p') {
+ if (s[1].unicode() == 'a') {
+ if (s[2].unicode() == 'c') {
+ if (s[3].unicode() == 'k') {
+ if (s[4].unicode() == 'a') {
+ if (s[5].unicode() == 'g') {
+ if (s[6].unicode() == 'e') {
+ return Lexer::T_PACKAGE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'i') {
+ if (s[3].unicode() == 'v') {
+ if (s[4].unicode() == 'a') {
+ if (s[5].unicode() == 't') {
+ if (s[6].unicode() == 'e') {
+ return Lexer::T_PRIVATE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify8(const QChar *s, bool qmlMode) {
+ if (s[0].unicode() == 'a') {
+ if (s[1].unicode() == 'b') {
+ if (s[2].unicode() == 's') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'r') {
+ if (s[5].unicode() == 'a') {
+ if (s[6].unicode() == 'c') {
+ if (s[7].unicode() == 't') {
+ return Lexer::T_ABSTRACT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'c') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'i') {
+ if (s[5].unicode() == 'n') {
+ if (s[6].unicode() == 'u') {
+ if (s[7].unicode() == 'e') {
+ return Lexer::T_CONTINUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'd') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 'b') {
+ if (s[3].unicode() == 'u') {
+ if (s[4].unicode() == 'g') {
+ if (s[5].unicode() == 'g') {
+ if (s[6].unicode() == 'e') {
+ if (s[7].unicode() == 'r') {
+ return Lexer::T_DEBUGGER;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'f') {
+ if (s[1].unicode() == 'u') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 'c') {
+ if (s[4].unicode() == 't') {
+ if (s[5].unicode() == 'i') {
+ if (s[6].unicode() == 'o') {
+ if (s[7].unicode() == 'n') {
+ return Lexer::T_FUNCTION;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (qmlMode && s[0].unicode() == 'p') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 'p') {
+ if (s[4].unicode() == 'e') {
+ if (s[5].unicode() == 'r') {
+ if (s[6].unicode() == 't') {
+ if (s[7].unicode() == 'y') {
+ return Lexer::T_PROPERTY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (qmlMode && s[0].unicode() == 'r') {
+ if (s[1].unicode() == 'e') {
+ if (s[2].unicode() == 'a') {
+ if (s[3].unicode() == 'd') {
+ if (s[4].unicode() == 'o') {
+ if (s[5].unicode() == 'n') {
+ if (s[6].unicode() == 'l') {
+ if (s[7].unicode() == 'y') {
+ return Lexer::T_READONLY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'v') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'l') {
+ if (s[3].unicode() == 'a') {
+ if (s[4].unicode() == 't') {
+ if (s[5].unicode() == 'i') {
+ if (s[6].unicode() == 'l') {
+ if (s[7].unicode() == 'e') {
+ return Lexer::T_VOLATILE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify9(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'i') {
+ if (s[1].unicode() == 'n') {
+ if (s[2].unicode() == 't') {
+ if (s[3].unicode() == 'e') {
+ if (s[4].unicode() == 'r') {
+ if (s[5].unicode() == 'f') {
+ if (s[6].unicode() == 'a') {
+ if (s[7].unicode() == 'c') {
+ if (s[8].unicode() == 'e') {
+ return Lexer::T_INTERFACE;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 'p') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'o') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'e') {
+ if (s[5].unicode() == 'c') {
+ if (s[6].unicode() == 't') {
+ if (s[7].unicode() == 'e') {
+ if (s[8].unicode() == 'd') {
+ return Lexer::T_PROTECTED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[0].unicode() == 't') {
+ if (s[1].unicode() == 'r') {
+ if (s[2].unicode() == 'a') {
+ if (s[3].unicode() == 'n') {
+ if (s[4].unicode() == 's') {
+ if (s[5].unicode() == 'i') {
+ if (s[6].unicode() == 'e') {
+ if (s[7].unicode() == 'n') {
+ if (s[8].unicode() == 't') {
+ return Lexer::T_TRANSIENT;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify10(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 'i') {
+ if (s[1].unicode() == 'm') {
+ if (s[2].unicode() == 'p') {
+ if (s[3].unicode() == 'l') {
+ if (s[4].unicode() == 'e') {
+ if (s[5].unicode() == 'm') {
+ if (s[6].unicode() == 'e') {
+ if (s[7].unicode() == 'n') {
+ if (s[8].unicode() == 't') {
+ if (s[9].unicode() == 's') {
+ return Lexer::T_IMPLEMENTS;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (s[1].unicode() == 'n') {
+ if (s[2].unicode() == 's') {
+ if (s[3].unicode() == 't') {
+ if (s[4].unicode() == 'a') {
+ if (s[5].unicode() == 'n') {
+ if (s[6].unicode() == 'c') {
+ if (s[7].unicode() == 'e') {
+ if (s[8].unicode() == 'o') {
+ if (s[9].unicode() == 'f') {
+ return Lexer::T_INSTANCEOF;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+static inline int classify12(const QChar *s, bool /*qmlMode*/) {
+ if (s[0].unicode() == 's') {
+ if (s[1].unicode() == 'y') {
+ if (s[2].unicode() == 'n') {
+ if (s[3].unicode() == 'c') {
+ if (s[4].unicode() == 'h') {
+ if (s[5].unicode() == 'r') {
+ if (s[6].unicode() == 'o') {
+ if (s[7].unicode() == 'n') {
+ if (s[8].unicode() == 'i') {
+ if (s[9].unicode() == 'z') {
+ if (s[10].unicode() == 'e') {
+ if (s[11].unicode() == 'd') {
+ return Lexer::T_SYNCHRONIZED;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return Lexer::T_IDENTIFIER;
+}
+
+int Lexer::classify(const QChar *s, int n, bool qmlMode) {
+ switch (n) {
+ case 2: return classify2(s, qmlMode);
+ case 3: return classify3(s, qmlMode);
+ case 4: return classify4(s, qmlMode);
+ case 5: return classify5(s, qmlMode);
+ case 6: return classify6(s, qmlMode);
+ case 7: return classify7(s, qmlMode);
+ case 8: return classify8(s, qmlMode);
+ case 9: return classify9(s, qmlMode);
+ case 10: return classify10(s, qmlMode);
+ case 12: return classify12(s, qmlMode);
+ default: return Lexer::T_IDENTIFIER;
+ } // switch
+}
+
+#endif // QQMLJSKEYWORDS_P_H
diff --git a/src/tools/qdoc/qmlparser/qqmljslexer.cpp b/src/tools/qdoc/qmlparser/qqmljslexer.cpp
new file mode 100644
index 0000000000..4c75c6e30e
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljslexer.cpp
@@ -0,0 +1,1171 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmljslexer_p.h"
+#include "qqmljsengine_p.h"
+#include "qqmljsmemorypool_p.h"
+
+#ifdef QT_BOOTSTRAPPED
+#define tr(x, y) QString(QLatin1String(y))
+#else
+#include <QtCore/QCoreApplication>
+#define tr(x, y) QCoreApplication::translate(x, y)
+#endif
+#include <QtCore/QVarLengthArray>
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
+QT_END_NAMESPACE
+
+using namespace QQmlJS;
+
+static int regExpFlagFromChar(const QChar &ch)
+{
+ switch (ch.unicode()) {
+ case 'g': return Lexer::RegExp_Global;
+ case 'i': return Lexer::RegExp_IgnoreCase;
+ case 'm': return Lexer::RegExp_Multiline;
+ }
+ return 0;
+}
+
+static unsigned char convertHex(ushort c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ else if (c >= 'a' && c <= 'f')
+ return (c - 'a' + 10);
+ else
+ return (c - 'A' + 10);
+}
+
+static QChar convertHex(QChar c1, QChar c2)
+{
+ return QChar((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
+}
+
+static QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4)
+{
+ return QChar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode()),
+ (convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
+}
+
+Lexer::Lexer(Engine *engine)
+ : _engine(engine)
+ , _codePtr(0)
+ , _lastLinePtr(0)
+ , _tokenLinePtr(0)
+ , _tokenStartPtr(0)
+ , _char(QLatin1Char('\n'))
+ , _errorCode(NoError)
+ , _currentLineNumber(0)
+ , _tokenValue(0)
+ , _parenthesesState(IgnoreParentheses)
+ , _parenthesesCount(0)
+ , _stackToken(-1)
+ , _patternFlags(0)
+ , _tokenKind(0)
+ , _tokenLength(0)
+ , _tokenLine(0)
+ , _validTokenText(false)
+ , _prohibitAutomaticSemicolon(false)
+ , _restrictedKeyword(false)
+ , _terminator(false)
+ , _followsClosingBrace(false)
+ , _delimited(true)
+ , _qmlMode(true)
+{
+ if (engine)
+ engine->setLexer(this);
+}
+
+bool Lexer::qmlMode() const
+{
+ return _qmlMode;
+}
+
+QString Lexer::code() const
+{
+ return _code;
+}
+
+void Lexer::setCode(const QString &code, int lineno, bool qmlMode)
+{
+ if (_engine)
+ _engine->setCode(code);
+
+ _qmlMode = qmlMode;
+ _code = code;
+ _tokenText.clear();
+ _tokenText.reserve(1024);
+ _errorMessage.clear();
+ _tokenSpell = QStringRef();
+
+ _codePtr = code.unicode();
+ _lastLinePtr = _codePtr;
+ _tokenLinePtr = _codePtr;
+ _tokenStartPtr = _codePtr;
+
+ _char = QLatin1Char('\n');
+ _errorCode = NoError;
+
+ _currentLineNumber = lineno;
+ _tokenValue = 0;
+
+ // parentheses state
+ _parenthesesState = IgnoreParentheses;
+ _parenthesesCount = 0;
+
+ _stackToken = -1;
+
+ _patternFlags = 0;
+ _tokenLength = 0;
+ _tokenLine = lineno;
+
+ _validTokenText = false;
+ _prohibitAutomaticSemicolon = false;
+ _restrictedKeyword = false;
+ _terminator = false;
+ _followsClosingBrace = false;
+ _delimited = true;
+}
+
+void Lexer::scanChar()
+{
+ _char = *_codePtr++;
+
+ if (_char == QLatin1Char('\n')) {
+ _lastLinePtr = _codePtr; // points to the first character after the newline
+ ++_currentLineNumber;
+ }
+}
+
+int Lexer::lex()
+{
+ const int previousTokenKind = _tokenKind;
+
+ _tokenSpell = QStringRef();
+ _tokenKind = scanToken();
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+
+ _delimited = false;
+ _restrictedKeyword = false;
+ _followsClosingBrace = (previousTokenKind == T_RBRACE);
+
+ // update the flags
+ switch (_tokenKind) {
+ case T_LBRACE:
+ case T_SEMICOLON:
+ case T_COLON:
+ _delimited = true;
+ break;
+
+ case T_IF:
+ case T_FOR:
+ case T_WHILE:
+ case T_WITH:
+ _parenthesesState = CountParentheses;
+ _parenthesesCount = 0;
+ break;
+
+ case T_DO:
+ _parenthesesState = BalancedParentheses;
+ break;
+
+ case T_CONTINUE:
+ case T_BREAK:
+ case T_RETURN:
+ case T_THROW:
+ _restrictedKeyword = true;
+ break;
+ } // switch
+
+ // update the parentheses state
+ switch (_parenthesesState) {
+ case IgnoreParentheses:
+ break;
+
+ case CountParentheses:
+ if (_tokenKind == T_RPAREN) {
+ --_parenthesesCount;
+ if (_parenthesesCount == 0)
+ _parenthesesState = BalancedParentheses;
+ } else if (_tokenKind == T_LPAREN) {
+ ++_parenthesesCount;
+ }
+ break;
+
+ case BalancedParentheses:
+ _parenthesesState = IgnoreParentheses;
+ break;
+ } // switch
+
+ return _tokenKind;
+}
+
+bool Lexer::isUnicodeEscapeSequence(const QChar *chars)
+{
+ if (isHexDigit(chars[0]) && isHexDigit(chars[1]) && isHexDigit(chars[2]) && isHexDigit(chars[3]))
+ return true;
+
+ return false;
+}
+
+QChar Lexer::decodeUnicodeEscapeCharacter(bool *ok)
+{
+ if (_char == QLatin1Char('u') && isUnicodeEscapeSequence(&_codePtr[0])) {
+ scanChar(); // skip u
+
+ const QChar c1 = _char;
+ scanChar();
+
+ const QChar c2 = _char;
+ scanChar();
+
+ const QChar c3 = _char;
+ scanChar();
+
+ const QChar c4 = _char;
+ scanChar();
+
+ if (ok)
+ *ok = true;
+
+ return convertUnicode(c1, c2, c3, c4);
+ }
+
+ *ok = false;
+ return QChar();
+}
+
+int Lexer::scanToken()
+{
+ if (_stackToken != -1) {
+ int tk = _stackToken;
+ _stackToken = -1;
+ return tk;
+ }
+
+ _terminator = false;
+
+again:
+ _validTokenText = false;
+ _tokenLinePtr = _lastLinePtr;
+
+ while (_char.isSpace()) {
+ if (_char == QLatin1Char('\n')) {
+ _tokenLinePtr = _codePtr;
+
+ if (_restrictedKeyword) {
+ // automatic semicolon insertion
+ _tokenLine = _currentLineNumber;
+ _tokenStartPtr = _codePtr - 1; // ### TODO: insert it before the optional \r sequence.
+ return T_SEMICOLON;
+ } else {
+ _terminator = true;
+ syncProhibitAutomaticSemicolon();
+ }
+ }
+
+ scanChar();
+ }
+
+ _tokenStartPtr = _codePtr - 1;
+ _tokenLine = _currentLineNumber;
+
+ if (_char.isNull())
+ return EOF_SYMBOL;
+
+ const QChar ch = _char;
+ scanChar();
+
+ switch (ch.unicode()) {
+ case '~': return T_TILDE;
+ case '}': return T_RBRACE;
+
+ case '|':
+ if (_char == QLatin1Char('|')) {
+ scanChar();
+ return T_OR_OR;
+ } else if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_OR_EQ;
+ }
+ return T_OR;
+
+ case '{': return T_LBRACE;
+
+ case '^':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_XOR_EQ;
+ }
+ return T_XOR;
+
+ case ']': return T_RBRACKET;
+ case '[': return T_LBRACKET;
+ case '?': return T_QUESTION;
+
+ case '>':
+ if (_char == QLatin1Char('>')) {
+ scanChar();
+ if (_char == QLatin1Char('>')) {
+ scanChar();
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_GT_GT_GT_EQ;
+ }
+ return T_GT_GT_GT;
+ } else if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_GT_GT_EQ;
+ }
+ return T_GT_GT;
+ } else if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_GE;
+ }
+ return T_GT;
+
+ case '=':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_EQ_EQ_EQ;
+ }
+ return T_EQ_EQ;
+ }
+ return T_EQ;
+
+ case '<':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_LE;
+ } else if (_char == QLatin1Char('<')) {
+ scanChar();
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_LT_LT_EQ;
+ }
+ return T_LT_LT;
+ }
+ return T_LT;
+
+ case ';': return T_SEMICOLON;
+ case ':': return T_COLON;
+
+ case '/':
+ if (_char == QLatin1Char('*')) {
+ scanChar();
+ while (!_char.isNull()) {
+ if (_char == QLatin1Char('*')) {
+ scanChar();
+ if (_char == QLatin1Char('/')) {
+ scanChar();
+
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 4,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+
+ goto again;
+ }
+ } else {
+ scanChar();
+ }
+ }
+ } else if (_char == QLatin1Char('/')) {
+ while (!_char.isNull() && _char != QLatin1Char('\n')) {
+ scanChar();
+ }
+ if (_engine) {
+ _engine->addComment(tokenOffset() + 2, _codePtr - _tokenStartPtr - 1 - 2,
+ tokenStartLine(), tokenStartColumn() + 2);
+ }
+ goto again;
+ } if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_DIVIDE_EQ;
+ }
+ return T_DIVIDE_;
+
+ case '.':
+ if (_char.isDigit()) {
+ QVarLengthArray<char,32> chars;
+
+ chars.append(ch.unicode()); // append the `.'
+
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+
+ if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
+ if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+ _codePtr[1].isDigit())) {
+
+ chars.append(_char.unicode());
+ scanChar(); // consume `e'
+
+ if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
+ chars.append(_char.unicode());
+ scanChar(); // consume the sign
+ }
+
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+ }
+ }
+
+ chars.append('\0');
+
+ const char *begin = chars.constData();
+ const char *end = 0;
+ bool ok = false;
+
+ _tokenValue = qstrtod(begin, &end, &ok);
+
+ if (end - begin != chars.size() - 1) {
+ _errorCode = IllegalExponentIndicator;
+ _errorMessage = tr("QQmlParser", "Illegal syntax for exponential number");
+ return T_ERROR;
+ }
+
+ return T_NUMERIC_LITERAL;
+ }
+ return T_DOT;
+
+ case '-':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_MINUS_EQ;
+ } else if (_char == QLatin1Char('-')) {
+ scanChar();
+
+ if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) {
+ _stackToken = T_MINUS_MINUS;
+ return T_SEMICOLON;
+ }
+
+ return T_MINUS_MINUS;
+ }
+ return T_MINUS;
+
+ case ',': return T_COMMA;
+
+ case '+':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_PLUS_EQ;
+ } else if (_char == QLatin1Char('+')) {
+ scanChar();
+
+ if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) {
+ _stackToken = T_PLUS_PLUS;
+ return T_SEMICOLON;
+ }
+
+ return T_PLUS_PLUS;
+ }
+ return T_PLUS;
+
+ case '*':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_STAR_EQ;
+ }
+ return T_STAR;
+
+ case ')': return T_RPAREN;
+ case '(': return T_LPAREN;
+
+ case '&':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_AND_EQ;
+ } else if (_char == QLatin1Char('&')) {
+ scanChar();
+ return T_AND_AND;
+ }
+ return T_AND;
+
+ case '%':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_REMAINDER_EQ;
+ }
+ return T_REMAINDER;
+
+ case '!':
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ if (_char == QLatin1Char('=')) {
+ scanChar();
+ return T_NOT_EQ_EQ;
+ }
+ return T_NOT_EQ;
+ }
+ return T_NOT;
+
+ case '\'':
+ case '"': {
+ const QChar quote = ch;
+ bool multilineStringLiteral = false;
+
+ const QChar *startCode = _codePtr;
+
+ if (_engine) {
+ while (!_char.isNull()) {
+ if (_char == QLatin1Char('\n') || _char == QLatin1Char('\\')) {
+ break;
+ } else if (_char == quote) {
+ _tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode);
+ scanChar();
+
+ return T_STRING_LITERAL;
+ }
+ scanChar();
+ }
+ }
+
+ _validTokenText = true;
+ _tokenText.resize(0);
+ startCode--;
+ while (startCode != _codePtr - 1)
+ _tokenText += *startCode++;
+
+ while (! _char.isNull()) {
+ if (_char == QLatin1Char('\n')) {
+ multilineStringLiteral = true;
+ _tokenText += _char;
+ scanChar();
+ } else if (_char == quote) {
+ scanChar();
+
+ if (_engine)
+ _tokenSpell = _engine->newStringRef(_tokenText);
+
+ return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL;
+ } else if (_char == QLatin1Char('\\')) {
+ scanChar();
+
+ QChar u;
+ bool ok = false;
+
+ switch (_char.unicode()) {
+ // unicode escape sequence
+ case 'u':
+ u = decodeUnicodeEscapeCharacter(&ok);
+ if (! ok)
+ u = _char;
+ break;
+
+ // hex escape sequence
+ case 'x':
+ case 'X':
+ if (isHexDigit(_codePtr[0]) && isHexDigit(_codePtr[1])) {
+ scanChar();
+
+ const QChar c1 = _char;
+ scanChar();
+
+ const QChar c2 = _char;
+ scanChar();
+
+ u = convertHex(c1, c2);
+ } else {
+ u = _char;
+ }
+ break;
+
+ // single character escape sequence
+ case '\\': u = QLatin1Char('\\'); scanChar(); break;
+ case '\'': u = QLatin1Char('\''); scanChar(); break;
+ case '\"': u = QLatin1Char('\"'); scanChar(); break;
+ case 'b': u = QLatin1Char('\b'); scanChar(); break;
+ case 'f': u = QLatin1Char('\f'); scanChar(); break;
+ case 'n': u = QLatin1Char('\n'); scanChar(); break;
+ case 'r': u = QLatin1Char('\r'); scanChar(); break;
+ case 't': u = QLatin1Char('\t'); scanChar(); break;
+ case 'v': u = QLatin1Char('\v'); scanChar(); break;
+
+ case '0':
+ if (! _codePtr[1].isDigit()) {
+ scanChar();
+ u = QLatin1Char('\0');
+ } else {
+ // ### parse deprecated octal escape sequence ?
+ u = _char;
+ }
+ break;
+
+ case '\r':
+ while (_char == QLatin1Char('\r'))
+ scanChar();
+
+ if (_char == QLatin1Char('\n')) {
+ u = _char;
+ scanChar();
+ } else {
+ u = QLatin1Char('\n');
+ }
+
+ break;
+
+ case '\n':
+ u = _char;
+ scanChar();
+ break;
+
+ default:
+ // non escape character
+ u = _char;
+ scanChar();
+ }
+
+ _tokenText += u;
+ } else {
+ _tokenText += _char;
+ scanChar();
+ }
+ }
+
+ _errorCode = UnclosedStringLiteral;
+ _errorMessage = tr("QQmlParser", "Unclosed string at end of line");
+ return T_ERROR;
+ }
+
+ default:
+ if (ch.isLetter() || ch == QLatin1Char('$') || ch == QLatin1Char('_') || (ch == QLatin1Char('\\') && _char == QLatin1Char('u'))) {
+ bool identifierWithEscapeChars = false;
+ if (ch == QLatin1Char('\\')) {
+ identifierWithEscapeChars = true;
+ _tokenText.resize(0);
+ bool ok = false;
+ _tokenText += decodeUnicodeEscapeCharacter(&ok);
+ _validTokenText = true;
+ if (! ok) {
+ _errorCode = IllegalUnicodeEscapeSequence;
+ _errorMessage = tr("QQmlParser", "Illegal unicode escape sequence");
+ return T_ERROR;
+ }
+ }
+ while (true) {
+ if (_char.isLetterOrNumber() || _char == QLatin1Char('$') || _char == QLatin1Char('_')) {
+ if (identifierWithEscapeChars)
+ _tokenText += _char;
+
+ scanChar();
+ } else if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) {
+ if (! identifierWithEscapeChars) {
+ identifierWithEscapeChars = true;
+ _tokenText.resize(0);
+ _tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1);
+ _validTokenText = true;
+ }
+
+ scanChar(); // skip '\\'
+ bool ok = false;
+ _tokenText += decodeUnicodeEscapeCharacter(&ok);
+ if (! ok) {
+ _errorCode = IllegalUnicodeEscapeSequence;
+ _errorMessage = tr("QQmlParser", "Illegal unicode escape sequence");
+ return T_ERROR;
+ }
+ } else {
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+
+ int kind = T_IDENTIFIER;
+
+ if (! identifierWithEscapeChars)
+ kind = classify(_tokenStartPtr, _tokenLength, _qmlMode);
+
+ if (_engine) {
+ if (kind == T_IDENTIFIER && identifierWithEscapeChars)
+ _tokenSpell = _engine->newStringRef(_tokenText);
+ else
+ _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
+ }
+
+ return kind;
+ }
+ }
+ } else if (ch.isDigit()) {
+ if (ch != QLatin1Char('0')) {
+ double integer = ch.unicode() - '0';
+
+ QChar n = _char;
+ const QChar *code = _codePtr;
+ while (n.isDigit()) {
+ integer = integer * 10 + (n.unicode() - '0');
+ n = *code++;
+ }
+
+ if (n != QLatin1Char('.') && n != QLatin1Char('e') && n != QLatin1Char('E')) {
+ if (code != _codePtr) {
+ _codePtr = code - 1;
+ scanChar();
+ }
+ _tokenValue = integer;
+ return T_NUMERIC_LITERAL;
+ }
+ }
+
+ QVarLengthArray<char,32> chars;
+ chars.append(ch.unicode());
+
+ if (ch == QLatin1Char('0') && (_char == QLatin1Char('x') || _char == QLatin1Char('X'))) {
+ // parse hex integer literal
+
+ chars.append(_char.unicode());
+ scanChar(); // consume `x'
+
+ while (isHexDigit(_char)) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+
+ _tokenValue = integerFromString(chars.constData(), chars.size(), 16);
+ return T_NUMERIC_LITERAL;
+ }
+
+ // decimal integer literal
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar(); // consume the digit
+ }
+
+ if (_char == QLatin1Char('.')) {
+ chars.append(_char.unicode());
+ scanChar(); // consume `.'
+
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+
+ if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
+ if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+ _codePtr[1].isDigit())) {
+
+ chars.append(_char.unicode());
+ scanChar(); // consume `e'
+
+ if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
+ chars.append(_char.unicode());
+ scanChar(); // consume the sign
+ }
+
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+ }
+ }
+ } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
+ if (_codePtr[0].isDigit() || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
+ _codePtr[1].isDigit())) {
+
+ chars.append(_char.unicode());
+ scanChar(); // consume `e'
+
+ if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
+ chars.append(_char.unicode());
+ scanChar(); // consume the sign
+ }
+
+ while (_char.isDigit()) {
+ chars.append(_char.unicode());
+ scanChar();
+ }
+ }
+ }
+
+ chars.append('\0');
+
+ const char *begin = chars.constData();
+ const char *end = 0;
+ bool ok = false;
+
+ _tokenValue = qstrtod(begin, &end, &ok);
+
+ if (end - begin != chars.size() - 1) {
+ _errorCode = IllegalExponentIndicator;
+ _errorMessage = tr("QQmlParser", "Illegal syntax for exponential number");
+ return T_ERROR;
+ }
+
+ return T_NUMERIC_LITERAL;
+ }
+
+ break;
+ }
+
+ return T_ERROR;
+}
+
+bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
+{
+ _tokenText.resize(0);
+ _validTokenText = true;
+ _patternFlags = 0;
+
+ if (prefix == EqualPrefix)
+ _tokenText += QLatin1Char('=');
+
+ while (true) {
+ switch (_char.unicode()) {
+ case 0: // eof
+ case '\n': case '\r': // line terminator
+ _errorMessage = tr("QQmlParser", "Unterminated regular expression literal");
+ return false;
+
+ case '/':
+ scanChar();
+
+ // scan the flags
+ _patternFlags = 0;
+ while (isIdentLetter(_char)) {
+ int flag = regExpFlagFromChar(_char);
+ if (flag == 0) {
+ _errorMessage = tr("QQmlParser", "Invalid regular expression flag '%0'")
+ .arg(QChar(_char));
+ return false;
+ }
+ _patternFlags |= flag;
+ scanChar();
+ }
+
+ _tokenLength = _codePtr - _tokenStartPtr - 1;
+ return true;
+
+ case '\\':
+ // regular expression backslash sequence
+ _tokenText += _char;
+ scanChar();
+
+ if (_char.isNull() || isLineTerminator()) {
+ _errorMessage = tr("QQmlParser", "Unterminated regular expression backslash sequence");
+ return false;
+ }
+
+ _tokenText += _char;
+ scanChar();
+ break;
+
+ case '[':
+ // regular expression class
+ _tokenText += _char;
+ scanChar();
+
+ while (! _char.isNull() && ! isLineTerminator()) {
+ if (_char == QLatin1Char(']'))
+ break;
+ else if (_char == QLatin1Char('\\')) {
+ // regular expression backslash sequence
+ _tokenText += _char;
+ scanChar();
+
+ if (_char.isNull() || isLineTerminator()) {
+ _errorMessage = tr("QQmlParser", "Unterminated regular expression backslash sequence");
+ return false;
+ }
+
+ _tokenText += _char;
+ scanChar();
+ } else {
+ _tokenText += _char;
+ scanChar();
+ }
+ }
+
+ if (_char != QLatin1Char(']')) {
+ _errorMessage = tr("QQmlParser", "Unterminated regular expression class");
+ return false;
+ }
+
+ _tokenText += _char;
+ scanChar(); // skip ]
+ break;
+
+ default:
+ _tokenText += _char;
+ scanChar();
+ } // switch
+ } // while
+
+ return false;
+}
+
+bool Lexer::isLineTerminator() const
+{
+ return (_char == QLatin1Char('\n') || _char == QLatin1Char('\r'));
+}
+
+bool Lexer::isIdentLetter(QChar ch)
+{
+ // ASCII-biased, since all reserved words are ASCII, aand hence the
+ // bulk of content to be parsed.
+ if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z'))
+ || (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z'))
+ || ch == QLatin1Char('$')
+ || ch == QLatin1Char('_'))
+ return true;
+ if (ch.unicode() < 128)
+ return false;
+ return ch.isLetterOrNumber();
+}
+
+bool Lexer::isDecimalDigit(ushort c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+bool Lexer::isHexDigit(QChar c)
+{
+ return ((c >= QLatin1Char('0') && c <= QLatin1Char('9'))
+ || (c >= QLatin1Char('a') && c <= QLatin1Char('f'))
+ || (c >= QLatin1Char('A') && c <= QLatin1Char('F')));
+}
+
+bool Lexer::isOctalDigit(ushort c)
+{
+ return (c >= '0' && c <= '7');
+}
+
+int Lexer::tokenKind() const
+{
+ return _tokenKind;
+}
+
+int Lexer::tokenOffset() const
+{
+ return _tokenStartPtr - _code.unicode();
+}
+
+int Lexer::tokenLength() const
+{
+ return _tokenLength;
+}
+
+int Lexer::tokenStartLine() const
+{
+ return _tokenLine;
+}
+
+int Lexer::tokenStartColumn() const
+{
+ return _tokenStartPtr - _tokenLinePtr + 1;
+}
+
+int Lexer::tokenEndLine() const
+{
+ return _currentLineNumber;
+}
+
+int Lexer::tokenEndColumn() const
+{
+ return _codePtr - _lastLinePtr;
+}
+
+QStringRef Lexer::tokenSpell() const
+{
+ return _tokenSpell;
+}
+
+double Lexer::tokenValue() const
+{
+ return _tokenValue;
+}
+
+QString Lexer::tokenText() const
+{
+ if (_validTokenText)
+ return _tokenText;
+
+ if (_tokenKind == T_STRING_LITERAL)
+ return QString(_tokenStartPtr + 1, _tokenLength - 2);
+
+ return QString(_tokenStartPtr, _tokenLength);
+}
+
+Lexer::Error Lexer::errorCode() const
+{
+ return _errorCode;
+}
+
+QString Lexer::errorMessage() const
+{
+ return _errorMessage;
+}
+
+void Lexer::syncProhibitAutomaticSemicolon()
+{
+ if (_parenthesesState == BalancedParentheses) {
+ // we have seen something like "if (foo)", which means we should
+ // never insert an automatic semicolon at this point, since it would
+ // then be expanded into an empty statement (ECMA-262 7.9.1)
+ _prohibitAutomaticSemicolon = true;
+ _parenthesesState = IgnoreParentheses;
+ } else {
+ _prohibitAutomaticSemicolon = false;
+ }
+}
+
+bool Lexer::prevTerminator() const
+{
+ return _terminator;
+}
+
+bool Lexer::followsClosingBrace() const
+{
+ return _followsClosingBrace;
+}
+
+bool Lexer::canInsertAutomaticSemicolon(int token) const
+{
+ return token == T_RBRACE
+ || token == EOF_SYMBOL
+ || _terminator
+ || _followsClosingBrace;
+}
+
+bool Lexer::scanDirectives(Directives *directives)
+{
+ if (_qmlMode) {
+ // the directives are a Javascript-only extension.
+ return false;
+ }
+
+ lex(); // fetch the first token
+
+ if (_tokenKind != T_DOT)
+ return true;
+
+ do {
+ lex(); // skip T_DOT
+
+ const int lineNumber = tokenStartLine();
+
+ if (! (_tokenKind == T_IDENTIFIER || _tokenKind == T_RESERVED_WORD))
+ return false; // expected a valid QML/JS directive
+
+ const QString directiveName = tokenText();
+
+ if (! (directiveName == QLatin1String("pragma") ||
+ directiveName == QLatin1String("import")))
+ return false; // not a valid directive name
+
+ // it must be a pragma or an import directive.
+ if (directiveName == QLatin1String("pragma")) {
+ // .pragma library
+ if (! (lex() == T_IDENTIFIER && tokenText() == QLatin1String("library")))
+ return false; // expected `library
+
+ // we found a .pragma library directive
+ directives->pragmaLibrary();
+
+ } else {
+ Q_ASSERT(directiveName == QLatin1String("import"));
+ lex(); // skip .import
+
+ QString pathOrUri;
+ QString version;
+ bool fileImport = false; // file or uri import
+
+ if (_tokenKind == T_STRING_LITERAL) {
+ // .import T_STRING_LITERAL as T_IDENTIFIER
+
+ fileImport = true;
+ pathOrUri = tokenText();
+
+ } else if (_tokenKind == T_IDENTIFIER) {
+ // .import T_IDENTIFIER (. T_IDENTIFIER)* T_NUMERIC_LITERAL as T_IDENTIFIER
+
+ pathOrUri = tokenText();
+
+ lex(); // skip the first T_IDENTIFIER
+ for (; _tokenKind == T_DOT; lex()) {
+ if (lex() != T_IDENTIFIER)
+ return false;
+
+ pathOrUri += QLatin1Char('.');
+ pathOrUri += tokenText();
+ }
+
+ if (_tokenKind != T_NUMERIC_LITERAL)
+ return false; // expected the module version number
+
+ version = tokenText();
+ }
+
+ //
+ // recognize the mandatory `as' followed by the module name
+ //
+ if (! (lex() == T_RESERVED_WORD && tokenText() == QLatin1String("as")))
+ return false; // expected `as'
+
+ if (lex() != T_IDENTIFIER)
+ return false; // expected module name
+
+ const QString module = tokenText();
+
+ if (fileImport)
+ directives->importFile(pathOrUri, module);
+ else
+ directives->importModule(pathOrUri, version, module);
+ }
+
+ if (tokenStartLine() != lineNumber)
+ return false; // the directives cannot span over multiple lines
+
+ // fetch the first token after the .pragma/.import directive
+ lex();
+ } while (_tokenKind == T_DOT);
+
+ return true;
+}
+
+#include "qqmljskeywords_p.h"
diff --git a/src/tools/qdoc/qmlparser/qqmljslexer_p.h b/src/tools/qdoc/qmlparser/qqmljslexer_p.h
new file mode 100644
index 0000000000..6b51852f5f
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljslexer_p.h
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSLEXER_P_H
+#define QQMLJSLEXER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqmljsglobal_p.h"
+#include "qqmljsgrammar_p.h"
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Engine;
+
+class QML_PARSER_EXPORT Directives {
+public:
+ virtual ~Directives() {}
+
+ virtual void pragmaLibrary()
+ {
+ }
+
+ virtual void importFile(const QString &jsfile, const QString &module)
+ {
+ Q_UNUSED(jsfile);
+ Q_UNUSED(module);
+ }
+
+ virtual void importModule(const QString &uri, const QString &version, const QString &module)
+ {
+ Q_UNUSED(uri);
+ Q_UNUSED(version);
+ Q_UNUSED(module);
+ }
+};
+
+class QML_PARSER_EXPORT Lexer: public QQmlJSGrammar
+{
+public:
+ enum {
+ T_ABSTRACT = T_RESERVED_WORD,
+ T_BOOLEAN = T_RESERVED_WORD,
+ T_BYTE = T_RESERVED_WORD,
+ T_CHAR = T_RESERVED_WORD,
+ T_CLASS = T_RESERVED_WORD,
+ T_DOUBLE = T_RESERVED_WORD,
+ T_ENUM = T_RESERVED_WORD,
+ T_EXPORT = T_RESERVED_WORD,
+ T_EXTENDS = T_RESERVED_WORD,
+ T_FINAL = T_RESERVED_WORD,
+ T_FLOAT = T_RESERVED_WORD,
+ T_GOTO = T_RESERVED_WORD,
+ T_IMPLEMENTS = T_RESERVED_WORD,
+ T_INT = T_RESERVED_WORD,
+ T_INTERFACE = T_RESERVED_WORD,
+ T_LET = T_RESERVED_WORD,
+ T_LONG = T_RESERVED_WORD,
+ T_NATIVE = T_RESERVED_WORD,
+ T_PACKAGE = T_RESERVED_WORD,
+ T_PRIVATE = T_RESERVED_WORD,
+ T_PROTECTED = T_RESERVED_WORD,
+ T_SHORT = T_RESERVED_WORD,
+ T_STATIC = T_RESERVED_WORD,
+ T_SUPER = T_RESERVED_WORD,
+ T_SYNCHRONIZED = T_RESERVED_WORD,
+ T_THROWS = T_RESERVED_WORD,
+ T_TRANSIENT = T_RESERVED_WORD,
+ T_VOLATILE = T_RESERVED_WORD,
+ T_YIELD = T_RESERVED_WORD
+ };
+
+ enum Error {
+ NoError,
+ IllegalCharacter,
+ UnclosedStringLiteral,
+ IllegalEscapeSequence,
+ IllegalUnicodeEscapeSequence,
+ UnclosedComment,
+ IllegalExponentIndicator,
+ IllegalIdentifier
+ };
+
+ enum RegExpBodyPrefix {
+ NoPrefix,
+ EqualPrefix
+ };
+
+ enum RegExpFlag {
+ RegExp_Global = 0x01,
+ RegExp_IgnoreCase = 0x02,
+ RegExp_Multiline = 0x04
+ };
+
+public:
+ Lexer(Engine *engine);
+
+ bool qmlMode() const;
+
+ QString code() const;
+ void setCode(const QString &code, int lineno, bool qmlMode = true);
+
+ int lex();
+
+ bool scanRegExp(RegExpBodyPrefix prefix = NoPrefix);
+ bool scanDirectives(Directives *directives);
+
+ int regExpFlags() const { return _patternFlags; }
+ QString regExpPattern() const { return _tokenText; }
+
+ int tokenKind() const;
+ int tokenOffset() const;
+ int tokenLength() const;
+
+ int tokenStartLine() const;
+ int tokenStartColumn() const;
+
+ int tokenEndLine() const;
+ int tokenEndColumn() const;
+
+ QStringRef tokenSpell() const;
+ double tokenValue() const;
+ QString tokenText() const;
+
+ Error errorCode() const;
+ QString errorMessage() const;
+
+ bool prevTerminator() const;
+ bool followsClosingBrace() const;
+ bool canInsertAutomaticSemicolon(int token) const;
+
+ enum ParenthesesState {
+ IgnoreParentheses,
+ CountParentheses,
+ BalancedParentheses
+ };
+
+protected:
+ int classify(const QChar *s, int n, bool qmlMode);
+
+private:
+ inline void scanChar();
+ int scanToken();
+
+ bool isLineTerminator() const;
+ static bool isIdentLetter(QChar c);
+ static bool isDecimalDigit(ushort c);
+ static bool isHexDigit(QChar c);
+ static bool isOctalDigit(ushort c);
+ static bool isUnicodeEscapeSequence(const QChar *chars);
+
+ void syncProhibitAutomaticSemicolon();
+ QChar decodeUnicodeEscapeCharacter(bool *ok);
+
+private:
+ Engine *_engine;
+
+ QString _code;
+ QString _tokenText;
+ QString _errorMessage;
+ QStringRef _tokenSpell;
+
+ const QChar *_codePtr;
+ const QChar *_lastLinePtr;
+ const QChar *_tokenLinePtr;
+ const QChar *_tokenStartPtr;
+
+ QChar _char;
+ Error _errorCode;
+
+ int _currentLineNumber;
+ double _tokenValue;
+
+ // parentheses state
+ ParenthesesState _parenthesesState;
+ int _parenthesesCount;
+
+ int _stackToken;
+
+ int _patternFlags;
+ int _tokenKind;
+ int _tokenLength;
+ int _tokenLine;
+
+ bool _validTokenText;
+ bool _prohibitAutomaticSemicolon;
+ bool _restrictedKeyword;
+ bool _terminator;
+ bool _followsClosingBrace;
+ bool _delimited;
+ bool _qmlMode;
+};
+
+} // end of namespace QQmlJS
+
+QT_QML_END_NAMESPACE
+
+#endif // LEXER_H
diff --git a/src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h b/src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h
new file mode 100644
index 0000000000..fd52fd25e4
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSMEMORYPOOL_P_H
+#define QQMLJSMEMORYPOOL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qqmljsglobal_p.h"
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qdebug.h>
+
+#include <cstring>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class QML_PARSER_EXPORT MemoryPool : public QSharedData
+{
+ MemoryPool(const MemoryPool &other);
+ void operator =(const MemoryPool &other);
+
+public:
+ MemoryPool()
+ : _blocks(0),
+ _allocatedBlocks(0),
+ _blockCount(-1),
+ _ptr(0),
+ _end(0)
+ { }
+
+ ~MemoryPool()
+ {
+ if (_blocks) {
+ for (int i = 0; i < _allocatedBlocks; ++i) {
+ if (char *b = _blocks[i])
+ qFree(b);
+ }
+
+ qFree(_blocks);
+ }
+ }
+
+ inline void *allocate(size_t size)
+ {
+ size = (size + 7) & ~7;
+ if (_ptr && (_ptr + size < _end)) {
+ void *addr = _ptr;
+ _ptr += size;
+ return addr;
+ }
+ return allocate_helper(size);
+ }
+
+ void reset()
+ {
+ _blockCount = -1;
+ _ptr = _end = 0;
+ }
+
+private:
+ void *allocate_helper(size_t size)
+ {
+ Q_ASSERT(size < BLOCK_SIZE);
+
+ if (++_blockCount == _allocatedBlocks) {
+ if (! _allocatedBlocks)
+ _allocatedBlocks = DEFAULT_BLOCK_COUNT;
+ else
+ _allocatedBlocks *= 2;
+
+ _blocks = (char **) qRealloc(_blocks, sizeof(char *) * _allocatedBlocks);
+
+ for (int index = _blockCount; index < _allocatedBlocks; ++index)
+ _blocks[index] = 0;
+ }
+
+ char *&block = _blocks[_blockCount];
+
+ if (! block)
+ block = (char *) qMalloc(BLOCK_SIZE);
+
+ _ptr = block;
+ _end = _ptr + BLOCK_SIZE;
+
+ void *addr = _ptr;
+ _ptr += size;
+ return addr;
+ }
+
+private:
+ char **_blocks;
+ int _allocatedBlocks;
+ int _blockCount;
+ char *_ptr;
+ char *_end;
+
+ enum
+ {
+ BLOCK_SIZE = 8 * 1024,
+ DEFAULT_BLOCK_COUNT = 8
+ };
+};
+
+class QML_PARSER_EXPORT Managed
+{
+ Managed(const Managed &other);
+ void operator = (const Managed &other);
+
+public:
+ Managed() {}
+ ~Managed() {}
+
+ void *operator new(size_t size, MemoryPool *pool) { return pool->allocate(size); }
+ void operator delete(void *) {}
+ void operator delete(void *, MemoryPool *) {}
+};
+
+} // namespace QQmlJS
+
+QT_QML_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/qmlparser/qqmljsparser.cpp b/src/tools/qdoc/qmlparser/qqmljsparser.cpp
new file mode 100644
index 0000000000..431351b8b2
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsparser.cpp
@@ -0,0 +1,1817 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QtDebug>
+#ifdef QT_BOOTSTRAPPED
+#define tr(x, y) QString(QLatin1String(y))
+#else
+#include <QtCore/QCoreApplication>
+#define tr(x, y) QCoreApplication::translate(x, y)
+#endif
+
+#include <string.h>
+
+#include "qqmljsengine_p.h"
+#include "qqmljslexer_p.h"
+#include "qqmljsast_p.h"
+#include "qqmljsmemorypool_p.h"
+
+
+
+#include "qqmljsparser_p.h"
+#include <QVarLengthArray>
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+using namespace QQmlJS;
+
+QT_QML_BEGIN_NAMESPACE
+
+void Parser::reallocateStack()
+{
+ if (! stack_size)
+ stack_size = 128;
+ else
+ stack_size <<= 1;
+
+ sym_stack = reinterpret_cast<Value*> (realloc(sym_stack, stack_size * sizeof(Value)));
+ state_stack = reinterpret_cast<int*> (realloc(state_stack, stack_size * sizeof(int)));
+ location_stack = reinterpret_cast<AST::SourceLocation*> (realloc(location_stack, stack_size * sizeof(AST::SourceLocation)));
+ string_stack = reinterpret_cast<QStringRef*> (realloc(string_stack, stack_size * sizeof(QStringRef)));
+}
+
+Parser::Parser(Engine *engine):
+ driver(engine),
+ pool(engine->pool()),
+ tos(0),
+ stack_size(0),
+ sym_stack(0),
+ state_stack(0),
+ location_stack(0),
+ string_stack(0),
+ first_token(0),
+ last_token(0)
+{
+}
+
+Parser::~Parser()
+{
+ if (stack_size) {
+ free(sym_stack);
+ free(state_stack);
+ free(location_stack);
+ free(string_stack);
+ }
+}
+
+static inline AST::SourceLocation location(Lexer *lexer)
+{
+ AST::SourceLocation loc;
+ loc.offset = lexer->tokenOffset();
+ loc.length = lexer->tokenLength();
+ loc.startLine = lexer->tokenStartLine();
+ loc.startColumn = lexer->tokenStartColumn();
+ return loc;
+}
+
+AST::UiQualifiedId *Parser::reparseAsQualifiedId(AST::ExpressionNode *expr)
+{
+ QVarLengthArray<QStringRef, 4> nameIds;
+ QVarLengthArray<AST::SourceLocation, 4> locations;
+
+ AST::ExpressionNode *it = expr;
+ while (AST::FieldMemberExpression *m = AST::cast<AST::FieldMemberExpression *>(it)) {
+ nameIds.append(m->name);
+ locations.append(m->identifierToken);
+ it = m->base;
+ }
+
+ if (AST::IdentifierExpression *idExpr = AST::cast<AST::IdentifierExpression *>(it)) {
+ AST::UiQualifiedId *q = new (pool) AST::UiQualifiedId(idExpr->name);
+ q->identifierToken = idExpr->identifierToken;
+
+ AST::UiQualifiedId *currentId = q;
+ for (int i = nameIds.size() - 1; i != -1; --i) {
+ currentId = new (pool) AST::UiQualifiedId(currentId, nameIds[i]);
+ currentId->identifierToken = locations[i];
+ }
+
+ return currentId->finish();
+ }
+
+ return 0;
+}
+
+bool Parser::parse(int startToken)
+{
+ Lexer *lexer = driver->lexer();
+ bool hadErrors = false;
+ int yytoken = -1;
+ int action = 0;
+
+ token_buffer[0].token = startToken;
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ tos = -1;
+ program = 0;
+
+ do {
+ if (++tos == stack_size)
+ reallocateStack();
+
+ state_stack[tos] = action;
+
+ _Lcheck_token:
+ if (yytoken == -1 && -TERMINAL_COUNT != action_index[action]) {
+ yyprevlloc = yylloc;
+
+ if (first_token == last_token) {
+ yytoken = lexer->lex();
+ yylval = lexer->tokenValue();
+ yytokenspell = lexer->tokenSpell();
+ yylloc = location(lexer);
+ } else {
+ yytoken = first_token->token;
+ yylval = first_token->dval;
+ yytokenspell = first_token->spell;
+ yylloc = first_token->loc;
+ ++first_token;
+ }
+ }
+
+ action = t_action(action, yytoken);
+ if (action > 0) {
+ if (action != ACCEPT_STATE) {
+ yytoken = -1;
+ sym(1).dval = yylval;
+ stringRef(1) = yytokenspell;
+ loc(1) = yylloc;
+ } else {
+ --tos;
+ return ! hadErrors;
+ }
+ } else if (action < 0) {
+ const int r = -action - 1;
+ tos -= rhs[r];
+
+ switch (r) {
+
+case 0: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 1: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 2: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 3: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 4: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 5: {
+ sym(1).Node = sym(2).Node;
+ program = sym(1).Node;
+} break;
+
+case 6: {
+ sym(1).UiProgram = new (pool) AST::UiProgram(sym(1).UiImportList,
+ sym(2).UiObjectMemberList->finish());
+} break;
+
+case 8: {
+ sym(1).Node = sym(1).UiImportList->finish();
+} break;
+
+case 9: {
+ sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImport);
+} break;
+
+case 10: {
+ sym(1).Node = new (pool) AST::UiImportList(sym(1).UiImportList, sym(2).UiImport);
+} break;
+
+case 13: {
+ sym(1).UiImport->semicolonToken = loc(2);
+} break;
+
+case 15: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->semicolonToken = loc(3);
+} break;
+
+case 17: {
+ sym(1).UiImport->versionToken = loc(2);
+ sym(1).UiImport->asToken = loc(3);
+ sym(1).UiImport->importIdToken = loc(4);
+ sym(1).UiImport->importId = stringRef(4);
+ sym(1).UiImport->semicolonToken = loc(5);
+} break;
+
+case 19: {
+ sym(1).UiImport->asToken = loc(2);
+ sym(1).UiImport->importIdToken = loc(3);
+ sym(1).UiImport->importId = stringRef(3);
+ sym(1).UiImport->semicolonToken = loc(4);
+} break;
+
+case 20: {
+ AST::UiImport *node = 0;
+
+ if (AST::StringLiteral *importIdLiteral = AST::cast<AST::StringLiteral *>(sym(2).Expression)) {
+ node = new (pool) AST::UiImport(importIdLiteral->value);
+ node->fileNameToken = loc(2);
+ } else if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(2).Expression)) {
+ node = new (pool) AST::UiImport(qualifiedId);
+ node->fileNameToken = loc(2);
+ }
+
+ sym(1).Node = node;
+
+ if (node) {
+ node->importToken = loc(1);
+ } else {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id or a string literal")));
+
+ return false; // ### remove me
+ }
+} break;
+
+case 21: {
+ sym(1).Node = 0;
+} break;
+
+case 22: {
+ sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
+} break;
+
+case 23: {
+ sym(1).Node = new (pool) AST::UiObjectMemberList(sym(1).UiObjectMember);
+} break;
+
+case 24: {
+ AST::UiObjectMemberList *node = new (pool) AST:: UiObjectMemberList(
+ sym(1).UiObjectMemberList, sym(2).UiObjectMember);
+ sym(1).Node = node;
+} break;
+
+case 25: {
+ sym(1).Node = new (pool) AST::UiArrayMemberList(sym(1).UiObjectMember);
+} break;
+
+case 26: {
+ AST::UiArrayMemberList *node = new (pool) AST::UiArrayMemberList(
+ sym(1).UiArrayMemberList, sym(3).UiObjectMember);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 27: {
+ AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer((AST::UiObjectMemberList*)0);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 28: {
+ AST::UiObjectInitializer *node = new (pool) AST::UiObjectInitializer(sym(2).UiObjectMemberList->finish());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 29: {
+ AST::UiObjectDefinition *node = new (pool) AST::UiObjectDefinition(sym(1).UiQualifiedId,
+ sym(2).UiObjectInitializer);
+ sym(1).Node = node;
+} break;
+
+case 31: {
+ AST::UiArrayBinding *node = new (pool) AST::UiArrayBinding(
+ sym(1).UiQualifiedId, sym(4).UiArrayMemberList->finish());
+ node->colonToken = loc(2);
+ node->lbracketToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 32: {
+ AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
+ sym(1).UiQualifiedId, sym(3).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 33: {
+ AST::UiObjectBinding *node = new (pool) AST::UiObjectBinding(
+ sym(3).UiQualifiedId, sym(1).UiQualifiedId, sym(4).UiObjectInitializer);
+ node->colonToken = loc(2);
+ node->hasOnToken = true;
+ sym(1).Node = node;
+} break;
+
+case 41:
+{
+ AST::UiScriptBinding *node = new (pool) AST::UiScriptBinding(
+ sym(1).UiQualifiedId, sym(3).Statement);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 45: {
+ sym(1).Node = 0;
+} break;
+
+case 46: {
+ sym(1).Node = sym(1).UiParameterList->finish ();
+} break;
+
+case 47: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(stringRef(1), stringRef(2));
+ node->propertyTypeToken = loc(1);
+ node->identifierToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 48: {
+ AST::UiParameterList *node = new (pool) AST::UiParameterList(sym(1).UiParameterList, stringRef(3), stringRef(4));
+ node->commaToken = loc(2);
+ node->identifierToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 50: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2));
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->parameters = sym(4).UiParameterList;
+ node->semicolonToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 52: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(QStringRef(), stringRef(2));
+ node->type = AST::UiPublicMember::Signal;
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 54: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6));
+ node->typeModifier = stringRef(2);
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 56: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3));
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 58: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4));
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->semicolonToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 59: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3),
+ sym(5).Statement);
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 60: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4),
+ sym(6).Statement);
+ node->isReadonlyMember = true;
+ node->readonlyToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 61: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(3), stringRef(4),
+ sym(6).Statement);
+ node->isDefaultMember = true;
+ node->defaultToken = loc(1);
+ node->propertyToken = loc(2);
+ node->typeToken = loc(3);
+ node->identifierToken = loc(4);
+ node->colonToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 62: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(4), stringRef(6));
+ node->typeModifier = stringRef(2);
+ node->propertyToken = loc(1);
+ node->typeModifierToken = loc(2);
+ node->typeToken = loc(4);
+ node->identifierToken = loc(6);
+ node->semicolonToken = loc(7); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(6));
+ propertyName->identifierToken = loc(6);
+ propertyName->next = 0;
+
+ AST::UiArrayBinding *binding = new (pool) AST::UiArrayBinding(
+ propertyName, sym(9).UiArrayMemberList->finish());
+ binding->colonToken = loc(7);
+ binding->lbracketToken = loc(8);
+ binding->rbracketToken = loc(10);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+
+case 63: {
+ AST::UiPublicMember *node = new (pool) AST::UiPublicMember(stringRef(2), stringRef(3));
+ node->propertyToken = loc(1);
+ node->typeToken = loc(2);
+ node->identifierToken = loc(3);
+ node->semicolonToken = loc(4); // insert a fake ';' before ':'
+
+ AST::UiQualifiedId *propertyName = new (pool) AST::UiQualifiedId(stringRef(3));
+ propertyName->identifierToken = loc(3);
+ propertyName->next = 0;
+
+ AST::UiObjectBinding *binding = new (pool) AST::UiObjectBinding(
+ propertyName, sym(5).UiQualifiedId, sym(6).UiObjectInitializer);
+ binding->colonToken = loc(4);
+
+ node->binding = binding;
+
+ sym(1).Node = node;
+} break;
+
+case 64: {
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+} break;
+
+case 65: {
+ sym(1).Node = new (pool) AST::UiSourceElement(sym(1).Node);
+} break;
+
+case 71: {
+ AST::ThisExpression *node = new (pool) AST::ThisExpression();
+ node->thisToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 72: {
+ AST::IdentifierExpression *node = new (pool) AST::IdentifierExpression(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 73: {
+ AST::NullExpression *node = new (pool) AST::NullExpression();
+ node->nullToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 74: {
+ AST::TrueLiteral *node = new (pool) AST::TrueLiteral();
+ node->trueToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 75: {
+ AST::FalseLiteral *node = new (pool) AST::FalseLiteral();
+ node->falseToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 76: {
+ AST::NumericLiteral *node = new (pool) AST::NumericLiteral(sym(1).dval);
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+case 77:
+case 78: {
+ AST::StringLiteral *node = new (pool) AST::StringLiteral(stringRef(1));
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 79: {
+ bool rx = lexer->scanRegExp(Lexer::NoPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false; // ### remove me
+ }
+
+ loc(1).length = lexer->tokenLength();
+ yylloc = loc(1); // adjust the location of the current token
+
+ AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
+ driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 80: {
+ bool rx = lexer->scanRegExp(Lexer::EqualPrefix);
+ if (!rx) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, location(lexer), lexer->errorMessage()));
+ return false;
+ }
+
+ loc(1).length = lexer->tokenLength();
+ yylloc = loc(1); // adjust the location of the current token
+
+ AST::RegExpLiteral *node = new (pool) AST::RegExpLiteral(
+ driver->newStringRef(lexer->regExpPattern()), lexer->regExpFlags());
+ node->literalToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 81: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral((AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 82: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 83: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish ());
+ node->lbracketToken = loc(1);
+ node->rbracketToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 84: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
+ (AST::Elision *) 0);
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 85: {
+ AST::ArrayLiteral *node = new (pool) AST::ArrayLiteral(sym(2).ElementList->finish (),
+ sym(4).Elision->finish());
+ node->lbracketToken = loc(1);
+ node->commaToken = loc(3);
+ node->rbracketToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 86: {
+ AST::ObjectLiteral *node = 0;
+ if (sym(2).Node)
+ node = new (pool) AST::ObjectLiteral(
+ sym(2).PropertyNameAndValueList->finish ());
+ else
+ node = new (pool) AST::ObjectLiteral();
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 87: {
+ AST::ObjectLiteral *node = new (pool) AST::ObjectLiteral(
+ sym(2).PropertyNameAndValueList->finish ());
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 88: {
+ AST::NestedExpression *node = new (pool) AST::NestedExpression(sym(2).Expression);
+ node->lparenToken = loc(1);
+ node->rparenToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 89: {
+ if (AST::ArrayMemberExpression *mem = AST::cast<AST::ArrayMemberExpression *>(sym(1).Expression)) {
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, mem->lbracketToken,
+ QLatin1String("Ignored annotation")));
+
+ sym(1).Expression = mem->base;
+ }
+
+ if (AST::UiQualifiedId *qualifiedId = reparseAsQualifiedId(sym(1).Expression)) {
+ sym(1).UiQualifiedId = qualifiedId;
+ } else {
+ sym(1).UiQualifiedId = 0;
+
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, loc(1),
+ QLatin1String("Expected a qualified name id")));
+
+ return false; // ### recover
+ }
+} break;
+
+case 90: {
+ sym(1).Node = new (pool) AST::ElementList((AST::Elision *) 0, sym(1).Expression);
+} break;
+
+case 91: {
+ sym(1).Node = new (pool) AST::ElementList(sym(1).Elision->finish(), sym(2).Expression);
+} break;
+
+case 92: {
+ AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList,
+ (AST::Elision *) 0, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 93: {
+ AST::ElementList *node = new (pool) AST::ElementList(sym(1).ElementList, sym(3).Elision->finish(),
+ sym(4).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 94: {
+ AST::Elision *node = new (pool) AST::Elision();
+ node->commaToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 95: {
+ AST::Elision *node = new (pool) AST::Elision(sym(1).Elision);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 96: {
+ AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList(
+ sym(1).PropertyName, sym(3).Expression);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 97: {
+ AST::PropertyNameAndValueList *node = new (pool) AST::PropertyNameAndValueList(
+ sym(1).PropertyNameAndValueList, sym(3).PropertyName, sym(5).Expression);
+ node->commaToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 98: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+case 99:
+case 100: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 101: {
+ AST::StringLiteralPropertyName *node = new (pool) AST::StringLiteralPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 102: {
+ AST::NumericLiteralPropertyName *node = new (pool) AST::NumericLiteralPropertyName(sym(1).dval);
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 103: {
+ AST::IdentifierPropertyName *node = new (pool) AST::IdentifierPropertyName(stringRef(1));
+ node->propertyNameToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 139: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 140: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 141: {
+ AST::NewMemberExpression *node = new (pool) AST::NewMemberExpression(sym(2).Expression, sym(4).ArgumentList);
+ node->newToken = loc(1);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 143: {
+ AST::NewExpression *node = new (pool) AST::NewExpression(sym(2).Expression);
+ node->newToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 144: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 145: {
+ AST::CallExpression *node = new (pool) AST::CallExpression(sym(1).Expression, sym(3).ArgumentList);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 146: {
+ AST::ArrayMemberExpression *node = new (pool) AST::ArrayMemberExpression(sym(1).Expression, sym(3).Expression);
+ node->lbracketToken = loc(2);
+ node->rbracketToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 147: {
+ AST::FieldMemberExpression *node = new (pool) AST::FieldMemberExpression(sym(1).Expression, stringRef(3));
+ node->dotToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 148: {
+ sym(1).Node = 0;
+} break;
+
+case 149: {
+ sym(1).Node = sym(1).ArgumentList->finish();
+} break;
+
+case 150: {
+ sym(1).Node = new (pool) AST::ArgumentList(sym(1).Expression);
+} break;
+
+case 151: {
+ AST::ArgumentList *node = new (pool) AST::ArgumentList(sym(1).ArgumentList, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 155: {
+ AST::PostIncrementExpression *node = new (pool) AST::PostIncrementExpression(sym(1).Expression);
+ node->incrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 156: {
+ AST::PostDecrementExpression *node = new (pool) AST::PostDecrementExpression(sym(1).Expression);
+ node->decrementToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 158: {
+ AST::DeleteExpression *node = new (pool) AST::DeleteExpression(sym(2).Expression);
+ node->deleteToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 159: {
+ AST::VoidExpression *node = new (pool) AST::VoidExpression(sym(2).Expression);
+ node->voidToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 160: {
+ AST::TypeOfExpression *node = new (pool) AST::TypeOfExpression(sym(2).Expression);
+ node->typeofToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 161: {
+ AST::PreIncrementExpression *node = new (pool) AST::PreIncrementExpression(sym(2).Expression);
+ node->incrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 162: {
+ AST::PreDecrementExpression *node = new (pool) AST::PreDecrementExpression(sym(2).Expression);
+ node->decrementToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 163: {
+ AST::UnaryPlusExpression *node = new (pool) AST::UnaryPlusExpression(sym(2).Expression);
+ node->plusToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 164: {
+ AST::UnaryMinusExpression *node = new (pool) AST::UnaryMinusExpression(sym(2).Expression);
+ node->minusToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 165: {
+ AST::TildeExpression *node = new (pool) AST::TildeExpression(sym(2).Expression);
+ node->tildeToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 166: {
+ AST::NotExpression *node = new (pool) AST::NotExpression(sym(2).Expression);
+ node->notToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 168: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Mul, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 169: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Div, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 170: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Mod, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 172: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Add, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 173: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Sub, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 175: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::LShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 176: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::RShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 177: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::URShift, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 179: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 180: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 181: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 182: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 183: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 184: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::In, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 186: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Lt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 187: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Gt, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 188: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Le, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 189: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Ge, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 190: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::InstanceOf, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 192: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 193: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 194: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 195: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 197: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Equal, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 198: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::NotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 199: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 200: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::StrictNotEqual, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 202: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 204: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitAnd, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 206: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 208: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitXor, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 210: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 212: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::BitOr, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 214: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 216: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::And, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 218: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 220: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ QSOperator::Or, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 222: {
+ AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 224: {
+ AST::ConditionalExpression *node = new (pool) AST::ConditionalExpression(sym(1).Expression,
+ sym(3).Expression, sym(5).Expression);
+ node->questionToken = loc(2);
+ node->colonToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 226: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 228: {
+ AST::BinaryExpression *node = new (pool) AST::BinaryExpression(sym(1).Expression,
+ sym(2).ival, sym(3).Expression);
+ node->operatorToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 229: {
+ sym(1).ival = QSOperator::Assign;
+} break;
+
+case 230: {
+ sym(1).ival = QSOperator::InplaceMul;
+} break;
+
+case 231: {
+ sym(1).ival = QSOperator::InplaceDiv;
+} break;
+
+case 232: {
+ sym(1).ival = QSOperator::InplaceMod;
+} break;
+
+case 233: {
+ sym(1).ival = QSOperator::InplaceAdd;
+} break;
+
+case 234: {
+ sym(1).ival = QSOperator::InplaceSub;
+} break;
+
+case 235: {
+ sym(1).ival = QSOperator::InplaceLeftShift;
+} break;
+
+case 236: {
+ sym(1).ival = QSOperator::InplaceRightShift;
+} break;
+
+case 237: {
+ sym(1).ival = QSOperator::InplaceURightShift;
+} break;
+
+case 238: {
+ sym(1).ival = QSOperator::InplaceAnd;
+} break;
+
+case 239: {
+ sym(1).ival = QSOperator::InplaceXor;
+} break;
+
+case 240: {
+ sym(1).ival = QSOperator::InplaceOr;
+} break;
+
+case 242: {
+ AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 243: {
+ sym(1).Node = 0;
+} break;
+
+case 246: {
+ AST::Expression *node = new (pool) AST::Expression(sym(1).Expression, sym(3).Expression);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 247: {
+ sym(1).Node = 0;
+} break;
+
+case 264: {
+ AST::Block *node = new (pool) AST::Block(sym(2).StatementList);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 265: {
+ sym(1).Node = new (pool) AST::StatementList(sym(1).Statement);
+} break;
+
+case 266: {
+ sym(1).Node = new (pool) AST::StatementList(sym(1).StatementList, sym(2).Statement);
+} break;
+
+case 267: {
+ sym(1).Node = 0;
+} break;
+
+case 268: {
+ sym(1).Node = sym(1).StatementList->finish ();
+} break;
+
+case 270: {
+ AST::VariableStatement *node = new (pool) AST::VariableStatement(
+ sym(2).VariableDeclarationList->finish (/*readOnly=*/sym(1).ival == T_CONST));
+ node->declarationKindToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 271: {
+ sym(1).ival = T_CONST;
+} break;
+
+case 272: {
+ sym(1).ival = T_VAR;
+} break;
+
+case 273: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
+} break;
+
+case 274: {
+ AST::VariableDeclarationList *node = new (pool) AST::VariableDeclarationList(
+ sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+ node->commaToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 275: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclaration);
+} break;
+
+case 276: {
+ sym(1).Node = new (pool) AST::VariableDeclarationList(sym(1).VariableDeclarationList, sym(3).VariableDeclaration);
+} break;
+
+case 277: {
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 278: {
+ AST::VariableDeclaration *node = new (pool) AST::VariableDeclaration(stringRef(1), sym(2).Expression);
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 279: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+
+case 280: {
+ sym(1).Node = 0;
+} break;
+
+case 282: {
+ // ### TODO: AST for initializer
+ sym(1) = sym(2);
+} break;
+
+case 283: {
+ sym(1).Node = 0;
+} break;
+
+case 285: {
+ AST::EmptyStatement *node = new (pool) AST::EmptyStatement();
+ node->semicolonToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 287: {
+ AST::ExpressionStatement *node = new (pool) AST::ExpressionStatement(sym(1).Expression);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 288: {
+ AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement, sym(7).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ node->elseToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 289: {
+ AST::IfStatement *node = new (pool) AST::IfStatement(sym(3).Expression, sym(5).Statement);
+ node->ifToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 291: {
+ AST::DoWhileStatement *node = new (pool) AST::DoWhileStatement(sym(2).Statement, sym(5).Expression);
+ node->doToken = loc(1);
+ node->whileToken = loc(3);
+ node->lparenToken = loc(4);
+ node->rparenToken = loc(6);
+ node->semicolonToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 292: {
+ AST::WhileStatement *node = new (pool) AST::WhileStatement(sym(3).Expression, sym(5).Statement);
+ node->whileToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 293: {
+ AST::ForStatement *node = new (pool) AST::ForStatement(sym(3).Expression,
+ sym(5).Expression, sym(7).Expression, sym(9).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->firstSemicolonToken = loc(4);
+ node->secondSemicolonToken = loc(6);
+ node->rparenToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 294: {
+ AST::LocalForStatement *node = new (pool) AST::LocalForStatement(
+ sym(4).VariableDeclarationList->finish (/*readOnly=*/false), sym(6).Expression,
+ sym(8).Expression, sym(10).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->firstSemicolonToken = loc(5);
+ node->secondSemicolonToken = loc(7);
+ node->rparenToken = loc(9);
+ sym(1).Node = node;
+} break;
+
+case 295: {
+ AST:: ForEachStatement *node = new (pool) AST::ForEachStatement(sym(3).Expression,
+ sym(5).Expression, sym(7).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->inToken = loc(4);
+ node->rparenToken = loc(6);
+ sym(1).Node = node;
+} break;
+
+case 296: {
+ AST::LocalForEachStatement *node = new (pool) AST::LocalForEachStatement(
+ sym(4).VariableDeclaration, sym(6).Expression, sym(8).Statement);
+ node->forToken = loc(1);
+ node->lparenToken = loc(2);
+ node->varToken = loc(3);
+ node->inToken = loc(5);
+ node->rparenToken = loc(7);
+ sym(1).Node = node;
+} break;
+
+case 298: {
+ AST::ContinueStatement *node = new (pool) AST::ContinueStatement();
+ node->continueToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 300: {
+ AST::ContinueStatement *node = new (pool) AST::ContinueStatement(stringRef(2));
+ node->continueToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 302: {
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(QStringRef());
+ node->breakToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 304: {
+ AST::BreakStatement *node = new (pool) AST::BreakStatement(stringRef(2));
+ node->breakToken = loc(1);
+ node->identifierToken = loc(2);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 306: {
+ AST::ReturnStatement *node = new (pool) AST::ReturnStatement(sym(2).Expression);
+ node->returnToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 307: {
+ AST::WithStatement *node = new (pool) AST::WithStatement(sym(3).Expression, sym(5).Statement);
+ node->withToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 308: {
+ AST::SwitchStatement *node = new (pool) AST::SwitchStatement(sym(3).Expression, sym(5).CaseBlock);
+ node->switchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 309: {
+ AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 310: {
+ AST::CaseBlock *node = new (pool) AST::CaseBlock(sym(2).CaseClauses, sym(3).DefaultClause, sym(4).CaseClauses);
+ node->lbraceToken = loc(1);
+ node->rbraceToken = loc(5);
+ sym(1).Node = node;
+} break;
+
+case 311: {
+ sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClause);
+} break;
+
+case 312: {
+ sym(1).Node = new (pool) AST::CaseClauses(sym(1).CaseClauses, sym(2).CaseClause);
+} break;
+
+case 313: {
+ sym(1).Node = 0;
+} break;
+
+case 314: {
+ sym(1).Node = sym(1).CaseClauses->finish ();
+} break;
+
+case 315: {
+ AST::CaseClause *node = new (pool) AST::CaseClause(sym(2).Expression, sym(4).StatementList);
+ node->caseToken = loc(1);
+ node->colonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 316: {
+ AST::DefaultClause *node = new (pool) AST::DefaultClause(sym(3).StatementList);
+ node->defaultToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+case 317:
+case 318: {
+ AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 319: {
+ AST::LabelledStatement *node = new (pool) AST::LabelledStatement(stringRef(1), sym(3).Statement);
+ node->identifierToken = loc(1);
+ node->colonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 321: {
+ AST::ThrowStatement *node = new (pool) AST::ThrowStatement(sym(2).Expression);
+ node->throwToken = loc(1);
+ node->semicolonToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 322: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 323: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 324: {
+ AST::TryStatement *node = new (pool) AST::TryStatement(sym(2).Statement, sym(3).Catch, sym(4).Finally);
+ node->tryToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 325: {
+ AST::Catch *node = new (pool) AST::Catch(stringRef(3), sym(5).Block);
+ node->catchToken = loc(1);
+ node->lparenToken = loc(2);
+ node->identifierToken = loc(3);
+ node->rparenToken = loc(4);
+ sym(1).Node = node;
+} break;
+
+case 326: {
+ AST::Finally *node = new (pool) AST::Finally(sym(2).Block);
+ node->finallyToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 328: {
+ AST::DebuggerStatement *node = new (pool) AST::DebuggerStatement();
+ node->debuggerToken = loc(1);
+ node->semicolonToken = loc(2);
+ sym(1).Node = node;
+} break;
+
+case 329: {
+ AST::FunctionDeclaration *node = new (pool) AST::FunctionDeclaration(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 330: {
+ AST::FunctionExpression *node = new (pool) AST::FunctionExpression(stringRef(2), sym(4).FormalParameterList, sym(7).FunctionBody);
+ node->functionToken = loc(1);
+ if (! stringRef(2).isNull())
+ node->identifierToken = loc(2);
+ node->lparenToken = loc(3);
+ node->rparenToken = loc(5);
+ node->lbraceToken = loc(6);
+ node->rbraceToken = loc(8);
+ sym(1).Node = node;
+} break;
+
+case 331: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(stringRef(1));
+ node->identifierToken = loc(1);
+ sym(1).Node = node;
+} break;
+
+case 332: {
+ AST::FormalParameterList *node = new (pool) AST::FormalParameterList(sym(1).FormalParameterList, stringRef(3));
+ node->commaToken = loc(2);
+ node->identifierToken = loc(3);
+ sym(1).Node = node;
+} break;
+
+case 333: {
+ sym(1).Node = 0;
+} break;
+
+case 334: {
+ sym(1).Node = sym(1).FormalParameterList->finish ();
+} break;
+
+case 335: {
+ sym(1).Node = 0;
+} break;
+
+case 337: {
+ sym(1).Node = new (pool) AST::FunctionBody(sym(1).SourceElements->finish ());
+} break;
+
+case 339: {
+ sym(1).Node = new (pool) AST::Program(sym(1).SourceElements->finish ());
+} break;
+
+case 340: {
+ sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElement);
+} break;
+
+case 341: {
+ sym(1).Node = new (pool) AST::SourceElements(sym(1).SourceElements, sym(2).SourceElement);
+} break;
+
+case 342: {
+ sym(1).Node = new (pool) AST::StatementSourceElement(sym(1).Statement);
+} break;
+
+case 343: {
+ sym(1).Node = new (pool) AST::FunctionSourceElement(sym(1).FunctionDeclaration);
+} break;
+
+case 344: {
+ stringRef(1) = QStringRef();
+} break;
+
+case 346: {
+ sym(1).Node = 0;
+} break;
+
+ } // switch
+ action = nt_action(state_stack[tos], lhs[r] - TERMINAL_COUNT);
+ } // if
+ } while (action != 0);
+
+ if (first_token == last_token) {
+ const int errorState = state_stack[tos];
+
+ // automatic insertion of `;'
+ if (yytoken != -1 && t_action(errorState, T_AUTOMATIC_SEMICOLON) && lexer->canInsertAutomaticSemicolon(yytoken)) {
+ SavedToken &tk = token_buffer[0];
+ tk.token = yytoken;
+ tk.dval = yylval;
+ tk.spell = yytokenspell;
+ tk.loc = yylloc;
+
+ yylloc = yyprevlloc;
+ yylloc.offset += yylloc.length;
+ yylloc.startColumn += yylloc.length;
+ yylloc.length = 0;
+
+ //const QString msg = tr("QQmlParser", "Missing `;'");
+ //diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Warning, yylloc, msg));
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[1];
+
+ yytoken = T_SEMICOLON;
+ yylval = 0;
+
+ action = errorState;
+
+ goto _Lcheck_token;
+ }
+
+ hadErrors = true;
+
+ token_buffer[0].token = yytoken;
+ token_buffer[0].dval = yylval;
+ token_buffer[0].spell = yytokenspell;
+ token_buffer[0].loc = yylloc;
+
+ token_buffer[1].token = yytoken = lexer->lex();
+ token_buffer[1].dval = yylval = lexer->tokenValue();
+ token_buffer[1].spell = yytokenspell = lexer->tokenSpell();
+ token_buffer[1].loc = yylloc = location(lexer);
+
+ if (t_action(errorState, yytoken)) {
+ QString msg;
+ int token = token_buffer[0].token;
+ if (token < 0 || token >= TERMINAL_COUNT)
+ msg = tr("QQmlParser", "Syntax error");
+ else
+ msg = tr("QQmlParser", "Unexpected token `%1'").arg(QLatin1String(spell[token]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+
+ static int tokens[] = {
+ T_PLUS,
+ T_EQ,
+
+ T_COMMA,
+ T_COLON,
+ T_SEMICOLON,
+
+ T_RPAREN, T_RBRACKET, T_RBRACE,
+
+ T_NUMERIC_LITERAL,
+ T_IDENTIFIER,
+
+ T_LPAREN, T_LBRACKET, T_LBRACE,
+
+ EOF_SYMBOL
+ };
+
+ for (int *tk = tokens; *tk != EOF_SYMBOL; ++tk) {
+ int a = t_action(errorState, *tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = tr("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[*tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = *tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ first_token = &token_buffer[0];
+ last_token = &token_buffer[2];
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ for (int tk = 1; tk < TERMINAL_COUNT; ++tk) {
+ if (tk == T_AUTOMATIC_SEMICOLON || tk == T_FEED_UI_PROGRAM ||
+ tk == T_FEED_JS_STATEMENT || tk == T_FEED_JS_EXPRESSION ||
+ tk == T_FEED_JS_SOURCE_ELEMENT)
+ continue;
+
+ int a = t_action(errorState, tk);
+ if (a > 0 && t_action(a, yytoken)) {
+ const QString msg = tr("QQmlParser", "Expected token `%1'").arg(QLatin1String(spell[tk]));
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+
+ yytoken = tk;
+ yylval = 0;
+ yylloc = token_buffer[0].loc;
+ yylloc.length = 0;
+
+ action = errorState;
+ goto _Lcheck_token;
+ }
+ }
+
+ const QString msg = tr("QQmlParser", "Syntax error");
+ diagnostic_messages.append(DiagnosticMessage(DiagnosticMessage::Error, token_buffer[0].loc, msg));
+ }
+
+ return false;
+}
+
+QT_QML_END_NAMESPACE
+
+
diff --git a/src/tools/qdoc/qmlparser/qqmljsparser_p.h b/src/tools/qdoc/qmlparser/qqmljsparser_p.h
new file mode 100644
index 0000000000..ad532c32c7
--- /dev/null
+++ b/src/tools/qdoc/qmlparser/qqmljsparser_p.h
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+//
+// This file is automatically generated from qmljs.g.
+// Changes will be lost.
+//
+
+#ifndef QQMLJSPARSER_P_H
+#define QQMLJSPARSER_P_H
+
+#include "qqmljsglobal_p.h"
+#include "qqmljsgrammar_p.h"
+#include "qqmljsast_p.h"
+#include "qqmljsengine_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+QT_QML_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class Engine;
+
+class QML_PARSER_EXPORT Parser: protected QQmlJSGrammar
+{
+public:
+ union Value {
+ int ival;
+ double dval;
+ AST::ArgumentList *ArgumentList;
+ AST::CaseBlock *CaseBlock;
+ AST::CaseClause *CaseClause;
+ AST::CaseClauses *CaseClauses;
+ AST::Catch *Catch;
+ AST::DefaultClause *DefaultClause;
+ AST::ElementList *ElementList;
+ AST::Elision *Elision;
+ AST::ExpressionNode *Expression;
+ AST::Finally *Finally;
+ AST::FormalParameterList *FormalParameterList;
+ AST::FunctionBody *FunctionBody;
+ AST::FunctionDeclaration *FunctionDeclaration;
+ AST::Node *Node;
+ AST::PropertyName *PropertyName;
+ AST::PropertyNameAndValueList *PropertyNameAndValueList;
+ AST::SourceElement *SourceElement;
+ AST::SourceElements *SourceElements;
+ AST::Statement *Statement;
+ AST::StatementList *StatementList;
+ AST::Block *Block;
+ AST::VariableDeclaration *VariableDeclaration;
+ AST::VariableDeclarationList *VariableDeclarationList;
+
+ AST::UiProgram *UiProgram;
+ AST::UiImportList *UiImportList;
+ AST::UiImport *UiImport;
+ AST::UiParameterList *UiParameterList;
+ AST::UiPublicMember *UiPublicMember;
+ AST::UiObjectDefinition *UiObjectDefinition;
+ AST::UiObjectInitializer *UiObjectInitializer;
+ AST::UiObjectBinding *UiObjectBinding;
+ AST::UiScriptBinding *UiScriptBinding;
+ AST::UiArrayBinding *UiArrayBinding;
+ AST::UiObjectMember *UiObjectMember;
+ AST::UiObjectMemberList *UiObjectMemberList;
+ AST::UiArrayMemberList *UiArrayMemberList;
+ AST::UiQualifiedId *UiQualifiedId;
+ };
+
+public:
+ Parser(Engine *engine);
+ ~Parser();
+
+ // parse a UI program
+ bool parse() { return parse(T_FEED_UI_PROGRAM); }
+ bool parseStatement() { return parse(T_FEED_JS_STATEMENT); }
+ bool parseExpression() { return parse(T_FEED_JS_EXPRESSION); }
+ bool parseSourceElement() { return parse(T_FEED_JS_SOURCE_ELEMENT); }
+ bool parseUiObjectMember() { return parse(T_FEED_UI_OBJECT_MEMBER); }
+ bool parseProgram() { return parse(T_FEED_JS_PROGRAM); }
+
+ AST::UiProgram *ast() const
+ { return AST::cast<AST::UiProgram *>(program); }
+
+ AST::Statement *statement() const
+ {
+ if (! program)
+ return 0;
+
+ return program->statementCast();
+ }
+
+ AST::ExpressionNode *expression() const
+ {
+ if (! program)
+ return 0;
+
+ return program->expressionCast();
+ }
+
+ AST::UiObjectMember *uiObjectMember() const
+ {
+ if (! program)
+ return 0;
+
+ return program->uiObjectMemberCast();
+ }
+
+ AST::Node *rootNode() const
+ { return program; }
+
+ QList<DiagnosticMessage> diagnosticMessages() const
+ { return diagnostic_messages; }
+
+ inline DiagnosticMessage diagnosticMessage() const
+ {
+ foreach (const DiagnosticMessage &d, diagnostic_messages) {
+ if (! d.kind == DiagnosticMessage::Warning)
+ return d;
+ }
+
+ return DiagnosticMessage();
+ }
+
+ inline QString errorMessage() const
+ { return diagnosticMessage().message; }
+
+ inline int errorLineNumber() const
+ { return diagnosticMessage().loc.startLine; }
+
+ inline int errorColumnNumber() const
+ { return diagnosticMessage().loc.startColumn; }
+
+protected:
+ bool parse(int startToken);
+
+ void reallocateStack();
+
+ inline Value &sym(int index)
+ { return sym_stack [tos + index - 1]; }
+
+ inline QStringRef &stringRef(int index)
+ { return string_stack [tos + index - 1]; }
+
+ inline AST::SourceLocation &loc(int index)
+ { return location_stack [tos + index - 1]; }
+
+ AST::UiQualifiedId *reparseAsQualifiedId(AST::ExpressionNode *expr);
+
+protected:
+ Engine *driver;
+ MemoryPool *pool;
+ int tos;
+ int stack_size;
+ Value *sym_stack;
+ int *state_stack;
+ AST::SourceLocation *location_stack;
+ QStringRef *string_stack;
+
+ AST::Node *program;
+
+ // error recovery
+ enum { TOKEN_BUFFER_SIZE = 3 };
+
+ struct SavedToken {
+ int token;
+ double dval;
+ AST::SourceLocation loc;
+ QStringRef spell;
+ };
+
+ double yylval;
+ QStringRef yytokenspell;
+ AST::SourceLocation yylloc;
+ AST::SourceLocation yyprevlloc;
+
+ SavedToken token_buffer[TOKEN_BUFFER_SIZE];
+ SavedToken *first_token;
+ SavedToken *last_token;
+
+ QList<DiagnosticMessage> diagnostic_messages;
+};
+
+} // end of namespace QQmlJS
+
+
+
+#define J_SCRIPT_REGEXPLITERAL_RULE1 79
+
+#define J_SCRIPT_REGEXPLITERAL_RULE2 80
+
+QT_QML_END_NAMESPACE
+
+
+
+#endif // QQMLJSPARSER_P_H
diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp
new file mode 100644
index 0000000000..f04b220f32
--- /dev/null
+++ b/src/tools/qdoc/qmlvisitor.cpp
@@ -0,0 +1,619 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QFileInfo>
+#include <QStringList>
+#include <QtGlobal>
+#include "qqmljsast_p.h"
+#include "qqmljsastfwd_p.h"
+#include "qqmljsengine_p.h"
+#include <qdebug.h>
+#include "node.h"
+#include "codeparser.h"
+#include "qmlvisitor.h"
+
+QT_BEGIN_NAMESPACE
+
+#define COMMAND_DEPRECATED Doc::alias(QLatin1String("deprecated")) // ### don't document
+#define COMMAND_INGROUP Doc::alias(QLatin1String("ingroup"))
+#define COMMAND_INTERNAL Doc::alias(QLatin1String("internal"))
+#define COMMAND_OBSOLETE Doc::alias(QLatin1String("obsolete"))
+#define COMMAND_PAGEKEYWORDS Doc::alias(QLatin1String("pagekeywords"))
+#define COMMAND_PRELIMINARY Doc::alias(QLatin1String("preliminary"))
+#define COMMAND_SINCE Doc::alias(QLatin1String("since"))
+
+#define COMMAND_QMLABSTRACT Doc::alias(QLatin1String("qmlabstract"))
+#define COMMAND_QMLCLASS Doc::alias(QLatin1String("qmlclass"))
+#define COMMAND_QMLMODULE Doc::alias(QLatin1String("qmlmodule"))
+#define COMMAND_QMLPROPERTY Doc::alias(QLatin1String("qmlproperty"))
+#define COMMAND_QMLATTACHEDPROPERTY Doc::alias(QLatin1String("qmlattachedproperty"))
+#define COMMAND_QMLINHERITS Doc::alias(QLatin1String("inherits"))
+#define COMMAND_INQMLMODULE Doc::alias(QLatin1String("inqmlmodule"))
+#define COMMAND_QMLSIGNAL Doc::alias(QLatin1String("qmlsignal"))
+#define COMMAND_QMLATTACHEDSIGNAL Doc::alias(QLatin1String("qmlattachedsignal"))
+#define COMMAND_QMLMETHOD Doc::alias(QLatin1String("qmlmethod"))
+#define COMMAND_QMLATTACHEDMETHOD Doc::alias(QLatin1String("qmlattachedmethod"))
+#define COMMAND_QMLDEFAULT Doc::alias(QLatin1String("default"))
+#define COMMAND_QMLREADONLY Doc::alias(QLatin1String("readonly"))
+#define COMMAND_QMLBASICTYPE Doc::alias(QLatin1String("qmlbasictype"))
+#define COMMAND_QMLMODULE Doc::alias(QLatin1String("qmlmodule"))
+
+/*!
+ The constructor stores all the parameters in local data members.
+ */
+QmlDocVisitor::QmlDocVisitor(const QString &filePath,
+ const QString &code,
+ QQmlJS::Engine *engine,
+ Tree *tree,
+ QSet<QString> &commands,
+ QSet<QString> &topics)
+ : nestingLevel(0)
+{
+ this->filePath = filePath;
+ this->name = QFileInfo(filePath).baseName();
+ document = code;
+ this->engine = engine;
+ this->tree = tree;
+ this->commands = commands;
+ this->topics = topics;
+ current = tree->root();
+}
+
+/*!
+ The destructor does nothing.
+ */
+QmlDocVisitor::~QmlDocVisitor()
+{
+ // nothing.
+}
+
+/*!
+ Returns the location of thre nearest comment above the \a offset.
+ */
+QQmlJS::AST::SourceLocation QmlDocVisitor::precedingComment(quint32 offset) const
+{
+ QListIterator<QQmlJS::AST::SourceLocation> it(engine->comments());
+ it.toBack();
+
+ while (it.hasPrevious()) {
+
+ QQmlJS::AST::SourceLocation loc = it.previous();
+
+ if (loc.begin() <= lastEndOffset)
+ // Return if we reach the end of the preceding structure.
+ break;
+
+ else if (usedComments.contains(loc.begin()))
+ // Return if we encounter a previously used comment.
+ break;
+
+ else if (loc.begin() > lastEndOffset && loc.end() < offset) {
+
+ // Only examine multiline comments in order to avoid snippet markers.
+ if (document.mid(loc.offset - 1, 1) == "*") {
+ QString comment = document.mid(loc.offset, loc.length);
+ if (comment.startsWith(QLatin1Char('!')) || comment.startsWith(QLatin1Char('*')))
+ return loc;
+ }
+ }
+ }
+
+ return QQmlJS::AST::SourceLocation();
+}
+
+/*!
+ Finds the nearest unused qdoc comment above the QML entity
+ represented by the \a node and processes the qdoc commands
+ in that comment. The proceesed documentation is stored in
+ the \a node.
+
+ If a qdoc comment is found about \a location, true is returned.
+ If a comment is not found there, false is returned.
+ */
+bool QmlDocVisitor::applyDocumentation(QQmlJS::AST::SourceLocation location, Node* node)
+{
+ QQmlJS::AST::SourceLocation loc = precedingComment(location.begin());
+
+ if (loc.isValid()) {
+ QString source = document.mid(loc.offset, loc.length);
+ Location start(filePath);
+ start.setLineNo(loc.startLine);
+ start.setColumnNo(loc.startColumn);
+ Location finish(filePath);
+ finish.setLineNo(loc.startLine);
+ finish.setColumnNo(loc.startColumn);
+
+ Doc doc(start, finish, source.mid(1), commands, topics);
+ node->setDoc(doc);
+ applyMetacommands(loc, node, doc);
+ usedComments.insert(loc.offset);
+ if (doc.isEmpty())
+ return false;
+ return true;
+ }
+ Location codeLoc(filePath);
+ codeLoc.setLineNo(location.startLine);
+ node->setLocation(codeLoc);
+ return false;
+}
+
+/*!
+ A QML property argument has the form...
+
+ <type> <component>::<name>
+ <type> <QML-module>::<component>::<name>
+
+ This function splits the argument into one of those
+ two forms. The three part form is the old form, which
+ was used before the creation of QtQuick 2 and Qt
+ Components. A <QML-module> is the QML equivalent of a
+ C++ namespace. So this function splits \a arg on "::"
+ and stores the parts in the \e {type}, \e {module},
+ \e {component}, and \a {name}, fields of \a qpa. If it
+ is successful, it returns true. If not enough parts
+ are found, a qdoc warning is emitted and false is
+ returned.
+ */
+bool QmlDocVisitor::splitQmlPropertyArg(const Doc& doc,
+ const QString& arg,
+ QmlPropArgs& qpa)
+{
+ qpa.clear();
+ QStringList blankSplit = arg.split(QLatin1Char(' '));
+ if (blankSplit.size() > 1) {
+ qpa.type_ = blankSplit[0];
+ QStringList colonSplit(blankSplit[1].split("::"));
+ if (colonSplit.size() == 3) {
+ qpa.module_ = colonSplit[0];
+ qpa.component_ = colonSplit[1];
+ qpa.name_ = colonSplit[2];
+ return true;
+ }
+ else if (colonSplit.size() == 2) {
+ qpa.component_ = colonSplit[0];
+ qpa.name_ = colonSplit[1];
+ return true;
+ }
+ else if (colonSplit.size() == 1) {
+ qpa.name_ = colonSplit[0];
+ return true;
+ }
+ QString msg = "Unrecognizable QML module/component qualifier for " + arg;
+ doc.location().warning(tr(msg.toLatin1().data()));
+ }
+ else {
+ QString msg = "Missing property type for " + arg;
+ doc.location().warning(tr(msg.toLatin1().data()));
+ }
+ return false;
+}
+
+/*!
+ Applies the metacommands found in the comment.
+ */
+void QmlDocVisitor::applyMetacommands(QQmlJS::AST::SourceLocation,
+ Node* node,
+ Doc& doc)
+{
+ const TopicList& topicsUsed = doc.topicsUsed();
+ if (topicsUsed.size() > 0) {
+ if (node->type() == Node::QmlProperty) {
+ QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
+ for (int i=0; i<topicsUsed.size(); ++i) {
+ if (topicsUsed.at(i).topic == "qmlproperty") {
+ QmlPropArgs qpa;
+ if (splitQmlPropertyArg(doc, topicsUsed.at(i).args, qpa)) {
+ QmlPropertyNode* n = new QmlPropertyNode(qpn, qpa.name_, qpa.type_, false);
+ qpn->appendQmlPropNode(n);
+ }
+ else
+ qDebug() << " FAILED TO PARSE QML PROPERTY:"
+ << topicsUsed.at(i).topic << topicsUsed.at(i).args;
+ }
+ }
+ }
+ }
+ QSet<QString> metacommands = doc.metaCommandsUsed();
+ if (metacommands.count() > 0) {
+ QString topic;
+ QStringList args;
+ QSet<QString>::iterator i = metacommands.begin();
+ while (i != metacommands.end()) {
+ if (topics.contains(*i)) {
+ topic = *i;
+ break;
+ }
+ ++i;
+ }
+ if (!topic.isEmpty()) {
+ args = doc.metaCommandArgs(topic);
+ if (topic == COMMAND_QMLCLASS) {
+ }
+ else if (topic == COMMAND_QMLPROPERTY) {
+ if (node->type() == Node::QmlProperty) {
+ QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
+ qpn->setReadOnly(0);
+ if (qpn->dataType() == "alias") {
+ QStringList part = args[0].split(QLatin1Char(' '));
+ qpn->setDataType(part[0]);
+ }
+ }
+ }
+ else if (topic == COMMAND_QMLMODULE) {
+ }
+ else if (topic == COMMAND_QMLATTACHEDPROPERTY) {
+ if (node->type() == Node::QmlProperty) {
+ QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
+ qpn->setReadOnly(0);
+ }
+ }
+ else if (topic == COMMAND_QMLSIGNAL) {
+ }
+ else if (topic == COMMAND_QMLATTACHEDSIGNAL) {
+ }
+ else if (topic == COMMAND_QMLMETHOD) {
+ }
+ else if (topic == COMMAND_QMLATTACHEDMETHOD) {
+ }
+ else if (topic == COMMAND_QMLBASICTYPE) {
+ }
+ }
+ metacommands.subtract(topics);
+ i = metacommands.begin();
+ while (i != metacommands.end()) {
+ QString command = *i;
+ args = doc.metaCommandArgs(command);
+ if (command == COMMAND_QMLABSTRACT) {
+ if ((node->type() == Node::Fake) && (node->subType() == Node::QmlClass)) {
+ node->setAbstract(true);
+ }
+ }
+ else if (command == COMMAND_DEPRECATED) {
+ node->setStatus(Node::Deprecated);
+ }
+ else if (command == COMMAND_INQMLMODULE) {
+ node->setQmlModuleName(args[0]);
+ tree->addToQmlModule(node,args[0]);
+ QString qmid = node->qmlModuleIdentifier();
+ QmlClassNode* qcn = static_cast<QmlClassNode*>(node);
+ QmlClassNode::moduleMap.insert(qmid + "::" + node->name(), qcn);
+ }
+ else if (command == COMMAND_QMLINHERITS) {
+ if (node->name() == args[0])
+ doc.location().warning(tr("%1 tries to inherit itself").arg(args[0]));
+ else {
+ qDebug() << "QML Component:" << node->name() << "inherits:" << args[0];
+ CodeParser::setLink(node, Node::InheritsLink, args[0]);
+ if (node->subType() == Node::QmlClass) {
+ QmlClassNode::addInheritedBy(args[0],node);
+ }
+ }
+ }
+ else if (command == COMMAND_QMLDEFAULT) {
+ if (node->type() == Node::QmlProperty) {
+ QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
+ qpn->setDefault();
+ }
+ }
+ else if (command == COMMAND_QMLREADONLY) {
+ if (node->type() == Node::QmlProperty) {
+ QmlPropertyNode* qpn = static_cast<QmlPropertyNode*>(node);
+ qpn->setReadOnly(1);
+ }
+ }
+ else if (command == COMMAND_INGROUP) {
+ tree->addToGroup(node, args[0]);
+ }
+ else if (command == COMMAND_INTERNAL) {
+ node->setAccess(Node::Private);
+ node->setStatus(Node::Internal);
+ }
+ else if (command == COMMAND_OBSOLETE) {
+ if (node->status() != Node::Compat)
+ node->setStatus(Node::Obsolete);
+ }
+ else if (command == COMMAND_PAGEKEYWORDS) {
+ // Not done yet. Do we need this?
+ }
+ else if (command == COMMAND_PRELIMINARY) {
+ node->setStatus(Node::Preliminary);
+ }
+ else if (command == COMMAND_SINCE) {
+ QString arg = args.join(" ");
+ node->setSince(arg);
+ }
+ else {
+ doc.location().warning(tr("The \\%1 command is ignored in QML files").arg(command));
+ }
+ ++i;
+ }
+ }
+}
+
+/*!
+ Begin the visit of the object \a definition, recording it in a tree
+ structure. Increment the object nesting level, which is used to
+ test whether we are at the public API level. The public level is
+ level 1.
+*/
+bool QmlDocVisitor::visit(QQmlJS::AST::UiObjectDefinition *definition)
+{
+ QString type = definition->qualifiedTypeNameId->name.toString();
+ nestingLevel++;
+
+ if (current->type() == Node::Namespace) {
+ QmlClassNode *component = new QmlClassNode(current, name, 0);
+ component->setTitle(name);
+ component->setImportList(importList);
+
+ if (applyDocumentation(definition->firstSourceLocation(), component)) {
+ QmlClassNode::addInheritedBy(type, component);
+ if (!component->links().contains(Node::InheritsLink))
+ component->setLink(Node::InheritsLink, type, type);
+ }
+ current = component;
+ }
+
+ return true;
+}
+
+/*!
+ End the visit of the object \a definition. In particular,
+ decrement the object nesting level, which is used to test
+ whether we are at the public API level. The public API
+ level is level 1. It won't decrement below 0.
+ */
+void QmlDocVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *definition)
+{
+ if (nestingLevel > 0)
+ --nestingLevel;
+ lastEndOffset = definition->lastSourceLocation().end();
+}
+
+/*!
+ Note that the imports list can be traversed by iteration to obtain
+ all the imports in the document at once, having found just one:
+
+ *it = imports; it; it = it->next
+
+ */
+bool QmlDocVisitor::visit(QQmlJS::AST::UiImportList *imports)
+{
+ QQmlJS::AST::UiImport* imp = imports->import;
+ quint32 length = imp->versionToken.offset - imp->fileNameToken.offset - 1;
+ QString module = document.mid(imp->fileNameToken.offset,length);
+ QString version = document.mid(imp->versionToken.offset, imp->versionToken.length);
+ if (version.size() > 1) {
+ int dot = version.lastIndexOf(QChar('.'));
+ if (dot > 0)
+ version = version.left(dot);
+ }
+ importList.append(QPair<QString, QString>(module, version));
+
+ return true;
+}
+
+/*!
+ End the visit of the imports list.
+ */
+void QmlDocVisitor::endVisit(QQmlJS::AST::UiImportList *definition)
+{
+ lastEndOffset = definition->lastSourceLocation().end();
+}
+
+typedef QQmlJS::AST::ExpressionNode EN;
+typedef QQmlJS::AST::IdentifierExpression IE;
+typedef QQmlJS::AST::FieldMemberExpression FME;
+
+static QString reconstituteFieldMemberExpression(EN* en)
+{
+ QString s;
+ if (en) {
+ qDebug() << " There is an expression" << en->kind;
+ if (en->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) {
+ FME* fme = (FME*) en;
+ s = reconstituteFieldMemberExpression(fme->base);
+ s += QLatin1Char('.') + fme->name.toString();
+ }
+ else if (en->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
+ IE* ie = (IE*) en;
+ s = ie->name.toString();
+ }
+ else {
+ qDebug() << " But it wasn't a recognized expression kind";
+ }
+ }
+ return s;
+}
+
+/*!
+ Visits the public \a member declaration, which can be a
+ signal or a property. It is a custom signal or property.
+ Only visit the \a member if the nestingLevel is 1.
+*/
+bool QmlDocVisitor::visit(QQmlJS::AST::UiPublicMember *member)
+{
+ if (nestingLevel > 1)
+ return true;
+ switch (member->type) {
+ case QQmlJS::AST::UiPublicMember::Signal:
+ {
+ if (current->type() == Node::Fake) {
+ QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current);
+ if (qmlClass) {
+
+ QString name = member->name.toString();
+ FunctionNode *qmlSignal = new FunctionNode(Node::QmlSignal, current, name, false);
+
+ QList<Parameter> parameters;
+ for (QQmlJS::AST::UiParameterList *it = member->parameters; it; it = it->next) {
+ if (!it->type.isEmpty() && !it->name.isEmpty())
+ parameters.append(Parameter(it->type.toString(), "", it->name.toString()));
+ }
+
+ qmlSignal->setParameters(parameters);
+ applyDocumentation(member->firstSourceLocation(), qmlSignal);
+ }
+ }
+ break;
+ }
+ case QQmlJS::AST::UiPublicMember::Property:
+ {
+ QString type = member->memberType.toString();
+ QString name = member->name.toString();
+ if (current->type() == Node::Fake) {
+ QmlClassNode *qmlClass = static_cast<QmlClassNode *>(current);
+ if (qmlClass) {
+ QString name = member->name.toString();
+ QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlClass, name, type, false);
+ qmlPropNode->setReadOnly(member->isReadonlyMember);
+ if (member->isDefaultMember)
+ qmlPropNode->setDefault();
+ applyDocumentation(member->firstSourceLocation(), qmlPropNode);
+ }
+#if 0
+ if (qmlClass) {
+ QString name = member->name->asString();
+ QmlPropGroupNode *qmlPropGroup = new QmlPropGroupNode(qmlClass, name, false);
+ if (member->isDefaultMember)
+ qmlPropGroup->setDefault();
+ QmlPropertyNode *qmlPropNode = new QmlPropertyNode(qmlPropGroup, name, type, false);
+ qmlPropNode->setWritable(!member->isReadonlyMember);
+ applyDocumentation(member->firstSourceLocation(), qmlPropGroup);
+ }
+#endif
+ }
+ break;
+ }
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/*!
+ End the visit of the \a member.
+ */
+void QmlDocVisitor::endVisit(QQmlJS::AST::UiPublicMember* member)
+{
+ lastEndOffset = member->lastSourceLocation().end();
+}
+
+bool QmlDocVisitor::visit(QQmlJS::AST::IdentifierPropertyName *)
+{
+ return true;
+}
+
+/*!
+ Begin the visit of the function declaration \a fd, but only
+ if the nesting level is 1.
+ */
+bool QmlDocVisitor::visit(QQmlJS::AST::FunctionDeclaration* fd)
+{
+ if (nestingLevel > 1)
+ return true;
+ if (current->type() == Node::Fake) {
+ QmlClassNode* qmlClass = static_cast<QmlClassNode*>(current);
+ if (qmlClass) {
+ QString name = fd->name.toString();
+ FunctionNode* qmlMethod = new FunctionNode(Node::QmlMethod, current, name, false);
+ QList<Parameter> parameters;
+ QQmlJS::AST::FormalParameterList* formals = fd->formals;
+ if (formals) {
+ QQmlJS::AST::FormalParameterList* fpl = formals;
+ do {
+ parameters.append(Parameter(QString(""), QString(""), fpl->name.toString()));
+ fpl = fpl->next;
+ } while (fpl && fpl != formals);
+ qmlMethod->setParameters(parameters);
+ }
+ applyDocumentation(fd->firstSourceLocation(), qmlMethod);
+ }
+ }
+ return true;
+}
+
+/*!
+ End the visit of the function declaration, \a fd.
+ */
+void QmlDocVisitor::endVisit(QQmlJS::AST::FunctionDeclaration* fd)
+{
+ lastEndOffset = fd->lastSourceLocation().end();
+}
+
+/*!
+ Begin the visit of the signal handler declaration \a sb, but only
+ if the nesting level is 1.
+ */
+bool QmlDocVisitor::visit(QQmlJS::AST::UiScriptBinding* sb)
+{
+ if (nestingLevel > 1)
+ return true;
+ if (current->type() == Node::Fake) {
+ QString handler = sb->qualifiedId->name.toString();
+ if (handler.length() > 2 && handler.startsWith("on") && handler.at(2).isUpper()) {
+ QmlClassNode* qmlClass = static_cast<QmlClassNode*>(current);
+ if (qmlClass) {
+ FunctionNode* qmlSH = new FunctionNode(Node::QmlSignalHandler,current,handler,false);
+ applyDocumentation(sb->firstSourceLocation(), qmlSH);
+ }
+ }
+ }
+ return true;
+}
+
+void QmlDocVisitor::endVisit(QQmlJS::AST::UiScriptBinding* sb)
+{
+ lastEndOffset = sb->lastSourceLocation().end();
+}
+
+bool QmlDocVisitor::visit(QQmlJS::AST::UiQualifiedId* )
+{
+ return true;
+}
+
+void QmlDocVisitor::endVisit(QQmlJS::AST::UiQualifiedId* )
+{
+ // nothing.
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/qmlvisitor.h b/src/tools/qdoc/qmlvisitor.h
new file mode 100644
index 0000000000..bb3d6ac799
--- /dev/null
+++ b/src/tools/qdoc/qmlvisitor.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLVISITOR_H
+#define QMLVISITOR_H
+
+#include <QString>
+#include "qqmljsastvisitor_p.h"
+#include "node.h"
+#include "tree.h"
+
+QT_BEGIN_NAMESPACE
+
+struct QmlPropArgs
+{
+ QString type_;
+ QString module_;
+ QString component_;
+ QString name_;
+
+ void clear() {
+ type_.clear();
+ module_.clear();
+ component_.clear();
+ name_.clear();
+ }
+};
+
+class QmlDocVisitor : public QQmlJS::AST::Visitor
+{
+public:
+ QmlDocVisitor(const QString &filePath,
+ const QString &code,
+ QQmlJS::Engine *engine,
+ Tree *tree,
+ QSet<QString> &commands,
+ QSet<QString> &topics);
+ virtual ~QmlDocVisitor();
+
+ bool visit(QQmlJS::AST::UiImportList *imports);
+ void endVisit(QQmlJS::AST::UiImportList *definition);
+
+ bool visit(QQmlJS::AST::UiObjectDefinition *definition);
+ void endVisit(QQmlJS::AST::UiObjectDefinition *definition);
+
+ bool visit(QQmlJS::AST::UiPublicMember *member);
+ void endVisit(QQmlJS::AST::UiPublicMember *definition);
+
+ bool visit(QQmlJS::AST::IdentifierPropertyName *idproperty);
+
+ bool visit(QQmlJS::AST::FunctionDeclaration *);
+ void endVisit(QQmlJS::AST::FunctionDeclaration *);
+
+ bool visit(QQmlJS::AST::UiScriptBinding *);
+ void endVisit(QQmlJS::AST::UiScriptBinding *);
+
+ bool visit(QQmlJS::AST::UiQualifiedId *);
+ void endVisit(QQmlJS::AST::UiQualifiedId *);
+
+private:
+ QQmlJS::AST::SourceLocation precedingComment(quint32 offset) const;
+ bool applyDocumentation(QQmlJS::AST::SourceLocation location, Node *node);
+ void applyMetacommands(QQmlJS::AST::SourceLocation location, Node* node, Doc& doc);
+ bool splitQmlPropertyArg(const Doc& doc,
+ const QString& arg,
+ QmlPropArgs& qpa);
+
+ QQmlJS::Engine *engine;
+ quint32 lastEndOffset;
+ quint32 nestingLevel;
+ QString filePath;
+ QString name;
+ QString document;
+ QList<QPair<QString, QString> > importList;
+ QSet<QString> commands;
+ QSet<QString> topics;
+ QSet<quint32> usedComments;
+ Tree *tree;
+ InnerNode *current;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/quoter.cpp b/src/tools/qdoc/quoter.cpp
new file mode 100644
index 0000000000..0c16acbe73
--- /dev/null
+++ b/src/tools/qdoc/quoter.cpp
@@ -0,0 +1,377 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qdebug.h>
+
+#include "quoter.h"
+
+QT_BEGIN_NAMESPACE
+
+static void replaceMultipleNewlines(QString &s)
+{
+ const int n = s.size();
+ bool slurping = false;
+ int j = -1;
+ const QChar newLine = QLatin1Char('\n');
+ QChar *d = s.data();
+ for (int i = 0; i != n; ++i) {
+ const QChar c = d[i];
+ bool hit = (c == newLine);
+ if (slurping && hit)
+ continue;
+ d[++j] = c;
+ slurping = hit;
+ }
+ s.resize(++j);
+}
+
+// This is equivalent to line.split( QRegExp("\n(?!\n|$)") ) but much faster
+QStringList Quoter::splitLines(const QString &line)
+{
+ QStringList result;
+ int i = line.size();
+ while (true) {
+ int j = i - 1;
+ while (j >= 0 && line.at(j) == QLatin1Char('\n'))
+ --j;
+ while (j >= 0 && line.at(j) != QLatin1Char('\n'))
+ --j;
+ result.prepend(line.mid(j + 1, i - j - 1));
+ if (j < 0)
+ break;
+ i = j;
+ }
+ return result;
+}
+
+/*
+ Transforms 'int x = 3 + 4' into 'int x=3+4'. A white space is kept
+ between 'int' and 'x' because it is meaningful in C++.
+*/
+static void trimWhiteSpace( QString& str )
+{
+ enum { Normal, MetAlnum, MetSpace } state = Normal;
+ const int n = str.length();
+
+ int j = -1;
+ QChar *d = str.data();
+ for ( int i = 0; i != n; ++i ) {
+ const QChar c = d[i];
+ if ( c.isLetterOrNumber() ) {
+ if ( state == Normal ) {
+ state = MetAlnum;
+ } else {
+ if ( state == MetSpace )
+ str[++j] = c;
+ state = Normal;
+ }
+ str[++j] = c;
+ } else if ( c.isSpace() ) {
+ if ( state == MetAlnum )
+ state = MetSpace;
+ } else {
+ state = Normal;
+ str[++j] = c;
+ }
+ }
+ str.resize(++j);
+}
+
+Quoter::Quoter()
+ : silent( false )
+{
+ /* We're going to hard code these delimiters:
+ * C++, Qt, Qt Script, Java:
+ //! [<id>]
+ * .pro, .py files:
+ #! [<id>]
+ * .html, .qrc, .ui, .xq, .xml files:
+ <!-- [<id>] -->
+ */
+ commentHash["pro"] = "#!";
+ commentHash["py"] = "#!";
+ commentHash["html"] = "<!--";
+ commentHash["qrc"] = "<!--";
+ commentHash["ui"] = "<!--";
+ commentHash["xml"] = "<!--";
+ commentHash["xq"] = "<!--";
+}
+
+void Quoter::reset()
+{
+ silent = false;
+ plainLines.clear();
+ markedLines.clear();
+ codeLocation = Location::null;
+}
+
+void Quoter::quoteFromFile( const QString& userFriendlyFilePath,
+ const QString& plainCode,
+ const QString& markedCode )
+{
+ silent = false;
+
+ /*
+ Split the source code into logical lines. Empty lines are
+ treated specially. Before:
+
+ p->alpha();
+ p->beta();
+
+ p->gamma();
+
+
+ p->delta();
+
+ After:
+
+ p->alpha();
+ p->beta();\n
+ p->gamma();\n\n
+ p->delta();
+
+ Newlines are preserved because they affect codeLocation.
+ */
+ codeLocation = Location( userFriendlyFilePath );
+
+ plainLines = splitLines(plainCode);
+ markedLines = splitLines(markedCode);
+ if (markedLines.count() != plainLines.count()) {
+ codeLocation.warning(tr("Something is wrong with qdoc's handling of marked code"));
+ markedLines = plainLines;
+ }
+
+ /*
+ Squeeze blanks (cat -s).
+ */
+ QStringList::Iterator m = markedLines.begin();
+ while ( m != markedLines.end() ) {
+ replaceMultipleNewlines( *m );
+ ++m;
+ }
+ codeLocation.start();
+}
+
+QString Quoter::quoteLine( const Location& docLocation, const QString& command,
+ const QString& pattern )
+{
+ if ( plainLines.isEmpty() ) {
+ failedAtEnd( docLocation, command );
+ return QString();
+ }
+
+ if ( pattern.isEmpty() ) {
+ docLocation.warning( tr("Missing pattern after '\\%1'").arg(command) );
+ return QString();
+ }
+
+ if ( match(docLocation, pattern, plainLines.first()) )
+ return getLine();
+
+ if ( !silent ) {
+ docLocation.warning( tr("Command '\\%1' failed").arg(command) );
+ codeLocation.warning( tr("Pattern '%1' didn't match here")
+ .arg(pattern) );
+ silent = true;
+ }
+ return QString();
+}
+
+QString Quoter::quoteSnippet(const Location &docLocation, const QString &identifier)
+{
+ QString comment = commentForCode();
+ QString delimiter = comment + QString(" [%1]").arg(identifier);
+ QString t;
+ int indent = 0;
+
+ while (!plainLines.isEmpty()) {
+ if (match(docLocation, delimiter, plainLines.first())) {
+ QString startLine = getLine();
+ while (indent < startLine.length() && startLine[indent] == QLatin1Char(' '))
+ indent++;
+ break;
+ }
+ getLine();
+ }
+ while (!plainLines.isEmpty()) {
+ QString line = plainLines.first();
+ if (match(docLocation, delimiter, line)) {
+ QString lastLine = getLine(indent);
+ int dIndex = lastLine.indexOf(delimiter);
+ if (dIndex > 0) {
+ // The delimiter might be preceded on the line by other
+ // delimeters, so look for the first comment on the line.
+ QString leading = lastLine.left(dIndex);
+ dIndex = leading.indexOf(comment);
+ if (dIndex != -1)
+ leading = leading.left(dIndex);
+ if (leading.endsWith(QLatin1String("<@comment>")))
+ leading.chop(10);
+ if (!leading.trimmed().isEmpty())
+ t += leading;
+ }
+ return t;
+ }
+
+ t += removeSpecialLines(line, comment, indent);
+ }
+ failedAtEnd(docLocation, QString("snippet (%1)").arg(delimiter));
+ return t;
+}
+
+QString Quoter::quoteTo( const Location& docLocation, const QString& command,
+ const QString& pattern )
+{
+ QString t;
+ QString comment = commentForCode();
+
+ if ( pattern.isEmpty() ) {
+ while ( !plainLines.isEmpty() ) {
+ QString line = plainLines.first();
+ t += removeSpecialLines(line, comment);
+ }
+ } else {
+ while ( !plainLines.isEmpty() ) {
+ if ( match(docLocation, pattern, plainLines.first()) ) {
+ return t;
+ }
+ t += getLine();
+ }
+ failedAtEnd( docLocation, command );
+ }
+ return t;
+}
+
+QString Quoter::quoteUntil( const Location& docLocation, const QString& command,
+ const QString& pattern )
+{
+ QString t = quoteTo( docLocation, command, pattern );
+ t += getLine();
+ return t;
+}
+
+QString Quoter::getLine(int unindent)
+{
+ if ( plainLines.isEmpty() )
+ return QString();
+
+ plainLines.removeFirst();
+
+ QString t = markedLines.takeFirst();
+ int i = 0;
+ while (i < unindent && i < t.length() && t[i] == QLatin1Char(' '))
+ i++;
+
+ t = t.mid(i);
+ t += QLatin1Char('\n');
+ codeLocation.advanceLines( t.count( QLatin1Char('\n') ) );
+ return t;
+}
+
+bool Quoter::match( const Location& docLocation, const QString& pattern0,
+ const QString& line )
+{
+ QString str = line;
+ while ( str.endsWith(QLatin1Char('\n')) )
+ str.truncate( str.length() - 1 );
+
+ QString pattern = pattern0;
+ if ( pattern.startsWith(QLatin1Char('/'))
+ && pattern.endsWith(QLatin1Char('/'))
+ && pattern.length() > 2 ) {
+ QRegExp rx( pattern.mid(1, pattern.length() - 2) );
+ if ( !silent && !rx.isValid() ) {
+ docLocation.warning( tr("Invalid regular expression '%1'")
+ .arg(rx.pattern()) );
+ silent = true;
+ }
+ return str.indexOf( rx ) != -1;
+ }
+ trimWhiteSpace(str);
+ trimWhiteSpace(pattern);
+ return str.indexOf(pattern) != -1;
+}
+
+void Quoter::failedAtEnd( const Location& docLocation, const QString& command )
+{
+ if (!silent && !command.isEmpty()) {
+ if ( codeLocation.filePath().isEmpty() ) {
+ docLocation.warning( tr("Unexpected '\\%1'").arg(command) );
+ } else {
+ docLocation.warning( tr("Command '\\%1' failed at end of file '%2'")
+ .arg(command).arg(codeLocation.filePath()) );
+ }
+ silent = true;
+ }
+}
+
+QString Quoter::commentForCode() const
+{
+ QString suffix = QFileInfo(codeLocation.fileName()).suffix();
+ return commentHash.value(suffix, "//!");
+}
+
+QString Quoter::removeSpecialLines(const QString &line, const QString &comment, int unindent)
+{
+ QString t;
+
+ // Remove special macros to support Qt namespacing.
+ QString trimmed = line.trimmed();
+ if (trimmed.startsWith("QT_BEGIN_NAMESPACE")) {
+ getLine();
+ } else if (trimmed.startsWith("QT_END_NAMESPACE")) {
+ getLine();
+ t += QLatin1Char('\n');
+ } else if (!trimmed.startsWith(comment)) {
+ // Ordinary code
+ t += getLine(unindent);
+ } else {
+ // Comments
+ if (line.contains(QLatin1Char('\n')))
+ t += QLatin1Char('\n');
+ getLine();
+ }
+ return t;
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/quoter.h b/src/tools/qdoc/quoter.h
new file mode 100644
index 0000000000..54817eabac
--- /dev/null
+++ b/src/tools/qdoc/quoter.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ quoter.h
+*/
+
+#ifndef QUOTER_H
+#define QUOTER_H
+
+#include <qhash.h>
+#include <qstringlist.h>
+
+#include "location.h"
+
+QT_BEGIN_NAMESPACE
+
+class Quoter
+{
+public:
+ Quoter();
+
+ void reset();
+ void quoteFromFile( const QString& userFriendlyFileName,
+ const QString& plainCode, const QString& markedCode );
+ QString quoteLine( const Location& docLocation, const QString& command,
+ const QString& pattern );
+ QString quoteTo( const Location& docLocation, const QString& command,
+ const QString& pattern );
+ QString quoteUntil( const Location& docLocation, const QString& command,
+ const QString& pattern );
+ QString quoteSnippet(const Location &docLocation, const QString &identifier);
+
+ static QStringList splitLines(const QString &line);
+
+private:
+ QString getLine(int unindent = 0);
+ void failedAtEnd( const Location& docLocation, const QString& command );
+ bool match( const Location& docLocation, const QString& pattern,
+ const QString& line );
+ QString commentForCode() const;
+ QString removeSpecialLines(const QString &line, const QString &comment,
+ int unindent = 0);
+
+ bool silent;
+ bool validRegExp;
+ QStringList plainLines;
+ QStringList markedLines;
+ Location codeLocation;
+ QHash<QString,QString> commentHash;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/separator.cpp b/src/tools/qdoc/separator.cpp
new file mode 100644
index 0000000000..4c2b2009ec
--- /dev/null
+++ b/src/tools/qdoc/separator.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ separator.cpp
+*/
+
+#include "separator.h"
+#include "tr.h"
+
+QT_BEGIN_NAMESPACE
+
+QString separator(int index, int count)
+{
+ if (index == count - 1)
+ return tr(".", "terminator");
+ if (count == 2)
+ return tr(" and ", "separator when N = 2");
+ if (index == 0)
+ return tr(", ", "first separator when N > 2");
+ if (index < count - 2)
+ return tr(", ", "general separator when N > 2");
+ return tr(", and ", "last separator when N > 2");
+}
+
+QString comma(int index, int count)
+{
+ if (index == count - 1)
+ return QString("");
+ if (count == 2)
+ return tr(" and ", "separator when N = 2");
+ if (index == 0)
+ return tr(", ", "first separator when N > 2");
+ if (index < count - 2)
+ return tr(", ", "general separator when N > 2");
+ return tr(", and ", "last separator when N > 2");
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/separator.h b/src/tools/qdoc/separator.h
new file mode 100644
index 0000000000..df7284ea1a
--- /dev/null
+++ b/src/tools/qdoc/separator.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ separator.h
+*/
+
+#ifndef SEPARATOR_H
+#define SEPARATOR_H
+
+#include <qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+QString separator( int index, int count );
+QString comma( int index, int count );
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/text.cpp b/src/tools/qdoc/text.cpp
new file mode 100644
index 0000000000..275716ad77
--- /dev/null
+++ b/src/tools/qdoc/text.cpp
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ text.cpp
+*/
+
+#include <qregexp.h>
+#include "text.h"
+#include <stdio.h>
+
+QT_BEGIN_NAMESPACE
+
+Text::Text()
+ : first(0), last(0)
+{
+}
+
+Text::Text(const QString &str)
+ : first(0), last(0)
+{
+ operator<<(str);
+}
+
+Text::Text(const Text& text)
+ : first(0), last(0)
+{
+ operator=(text);
+}
+
+Text::~Text()
+{
+ clear();
+}
+
+Text& Text::operator=(const Text& text)
+{
+ if (this != &text) {
+ clear();
+ operator<<(text);
+ }
+ return *this;
+}
+
+Text& Text::operator<<(Atom::Type atomType)
+{
+ return operator<<(Atom(atomType));
+}
+
+Text& Text::operator<<(const QString& string)
+{
+ return operator<<(Atom(Atom::String, string));
+}
+
+Text& Text::operator<<(const Atom& atom)
+{
+ if (atom.count() < 2) {
+ if (first == 0) {
+ first = new Atom(atom.type(), atom.string());
+ last = first;
+ }
+ else
+ last = new Atom(last, atom.type(), atom.string());
+ }
+ else {
+ if (first == 0) {
+ first = new Atom(atom.type(), atom.string(), atom.string(1));
+ last = first;
+ }
+ else
+ last = new Atom(last, atom.type(), atom.string(), atom.string(1));
+ }
+ return *this;
+}
+
+Text& Text::operator<<(const Text& text)
+{
+ const Atom* atom = text.firstAtom();
+ while (atom != 0) {
+ operator<<(*atom);
+ atom = atom->next();
+ }
+ return *this;
+}
+
+void Text::stripFirstAtom()
+{
+ if (first != 0) {
+ if (first == last)
+ last = 0;
+ Atom* oldFirst = first;
+ first = first->next();
+ delete oldFirst;
+ }
+}
+
+void Text::stripLastAtom()
+{
+ if (last != 0) {
+ Atom* oldLast = last;
+ if (first == last) {
+ first = 0;
+ last = 0;
+ } else {
+ last = first;
+ while (last->next() != oldLast)
+ last = last->next();
+ last->setNext(0);
+ }
+ delete oldLast;
+ }
+}
+
+QString Text::toString() const
+{
+ QString str;
+ const Atom* atom = firstAtom();
+ while (atom != 0) {
+ if (atom->type() == Atom::String ||
+ atom->type() == Atom::AutoLink ||
+ atom->type() == Atom::C ||
+ atom->type() == Atom::GuidLink)
+ str += atom->string();
+ atom = atom->next();
+ }
+ return str;
+}
+
+Text Text::subText(Atom::Type left, Atom::Type right, const Atom* from, bool inclusive) const
+{
+ const Atom* begin = from ? from : firstAtom();
+ const Atom* end;
+
+ while (begin != 0 && begin->type() != left)
+ begin = begin->next();
+ if (begin != 0) {
+ if (!inclusive)
+ begin = begin->next();
+ }
+
+ end = begin;
+ while (end != 0 && end->type() != right)
+ end = end->next();
+ if (end == 0)
+ begin = 0;
+ else if (inclusive)
+ end = end->next();
+ return subText(begin, end);
+}
+
+Text Text::sectionHeading(const Atom* sectionLeft)
+{
+ if (sectionLeft != 0) {
+ const Atom* begin = sectionLeft;
+ while (begin != 0 && begin->type() != Atom::SectionHeadingLeft)
+ begin = begin->next();
+ if (begin != 0)
+ begin = begin->next();
+
+ const Atom* end = begin;
+ while (end != 0 && end->type() != Atom::SectionHeadingRight)
+ end = end->next();
+
+ if (end != 0)
+ return subText(begin, end);
+ }
+ return Text();
+}
+
+const Atom* Text::sectionHeadingAtom(const Atom* sectionLeft)
+{
+ if (sectionLeft != 0) {
+ const Atom* begin = sectionLeft;
+ while (begin != 0 && begin->type() != Atom::SectionHeadingLeft)
+ begin = begin->next();
+ if (begin != 0)
+ begin = begin->next();
+
+ return begin;
+ }
+ return 0;
+}
+
+void Text::dump() const
+{
+ const Atom* atom = firstAtom();
+ while (atom != 0) {
+ QString str = atom->string();
+ str.replace("\\", "\\\\");
+ str.replace("\"", "\\\"");
+ str.replace("\n", "\\n");
+ str.replace(QRegExp("[^\x20-\x7e]"), "?");
+ if (!str.isEmpty())
+ str = " \"" + str + "\"";
+ fprintf(stderr, " %-15s%s\n", atom->typeString().toLatin1().data(), str.toLatin1().data());
+ atom = atom->next();
+ }
+}
+
+Text Text::subText(const Atom* begin, const Atom* end)
+{
+ Text text;
+ if (begin != 0) {
+ while (begin != end) {
+ text << *begin;
+ begin = begin->next();
+ }
+ }
+ return text;
+}
+
+void Text::clear()
+{
+ while (first != 0) {
+ Atom* atom = first;
+ first = first->next();
+ delete atom;
+ }
+ first = 0;
+ last = 0;
+}
+
+int Text::compare(const Text &text1, const Text &text2)
+{
+ if (text1.isEmpty())
+ return text2.isEmpty() ? 0 : -1;
+ if (text2.isEmpty())
+ return 1;
+
+ const Atom* atom1 = text1.firstAtom();
+ const Atom* atom2 = text2.firstAtom();
+
+ for (;;) {
+ if (atom1->type() != atom2->type())
+ return (int)atom1->type() - (int)atom2->type();
+ int cmp = QString::compare(atom1->string(), atom2->string());
+ if (cmp != 0)
+ return cmp;
+
+ if (atom1 == text1.lastAtom())
+ return atom2 == text2.lastAtom() ? 0 : -1;
+ if (atom2 == text2.lastAtom())
+ return 1;
+ atom1 = atom1->next();
+ atom2 = atom2->next();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/text.h b/src/tools/qdoc/text.h
new file mode 100644
index 0000000000..07ccb0edb8
--- /dev/null
+++ b/src/tools/qdoc/text.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ text.h
+*/
+
+#ifndef TEXT_H
+#define TEXT_H
+
+#include "atom.h"
+
+QT_BEGIN_NAMESPACE
+
+class Text
+{
+public:
+ Text();
+ explicit Text(const QString &str);
+ Text(const Text& text);
+ ~Text();
+
+ Text& operator=(const Text& text);
+
+ Atom *firstAtom() { return first; }
+ Atom *lastAtom() { return last; }
+ Text& operator<<(Atom::Type atomType);
+ Text& operator<<(const QString& string);
+ Text& operator<<(const Atom& atom);
+ Text& operator<<(const Text& text);
+ void stripFirstAtom();
+ void stripLastAtom();
+
+ bool isEmpty() const { return first == 0; }
+ QString toString() const;
+ const Atom *firstAtom() const { return first; }
+ const Atom *lastAtom() const { return last; }
+ Text subText(Atom::Type left, Atom::Type right, const Atom *from = 0, bool inclusive = false) const;
+ void dump() const;
+ void clear();
+
+ static Text subText(const Atom *begin, const Atom *end = 0);
+ static Text sectionHeading(const Atom *sectionBegin);
+ static const Atom *sectionHeadingAtom(const Atom *sectionLeft);
+ static int compare(const Text &text1, const Text &text2);
+
+private:
+
+ Atom *first;
+ Atom *last;
+};
+
+inline bool operator==(const Text &text1, const Text &text2)
+{ return Text::compare(text1, text2) == 0; }
+inline bool operator!=(const Text &text1, const Text &text2)
+{ return Text::compare(text1, text2) != 0; }
+inline bool operator<(const Text &text1, const Text &text2)
+{ return Text::compare(text1, text2) < 0; }
+inline bool operator<=(const Text &text1, const Text &text2)
+{ return Text::compare(text1, text2) <= 0; }
+inline bool operator>(const Text &text1, const Text &text2)
+{ return Text::compare(text1, text2) > 0; }
+inline bool operator>=(const Text &text1, const Text &text2)
+{ return Text::compare(text1, text2) >= 0; }
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/tokenizer.cpp b/src/tools/qdoc/tokenizer.cpp
new file mode 100644
index 0000000000..c87764b934
--- /dev/null
+++ b/src/tools/qdoc/tokenizer.cpp
@@ -0,0 +1,771 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "config.h"
+#include "tokenizer.h"
+
+#include <qfile.h>
+#include <qhash.h>
+#include <qregexp.h>
+#include <qstring.h>
+#include <qtextcodec.h>
+
+#include <ctype.h>
+#include <string.h>
+
+QT_BEGIN_NAMESPACE
+
+#define LANGUAGE_CPP "Cpp"
+
+/* qmake ignore Q_OBJECT */
+
+/*
+ Keep in sync with tokenizer.h.
+*/
+static const char *kwords[] = {
+ "char", "class", "const", "double", "enum", "explicit",
+ "friend", "inline", "int", "long", "namespace", "operator",
+ "private", "protected", "public", "short", "signals", "signed",
+ "slots", "static", "struct", "template", "typedef", "typename",
+ "union", "unsigned", "using", "virtual", "void", "volatile",
+ "__int64",
+ "Q_OBJECT",
+ "Q_OVERRIDE",
+ "Q_PROPERTY",
+ "Q_PRIVATE_PROPERTY",
+ "Q_DECLARE_SEQUENTIAL_ITERATOR",
+ "Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR",
+ "Q_DECLARE_ASSOCIATIVE_ITERATOR",
+ "Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR",
+ "Q_DECLARE_FLAGS",
+ "Q_SIGNALS",
+ "Q_SLOTS",
+ "QT_COMPAT",
+ "QT_COMPAT_CONSTRUCTOR",
+ "QT_DEPRECATED",
+ "QT_MOC_COMPAT",
+ "QT_MODULE",
+ "QT3_SUPPORT",
+ "QT3_SUPPORT_CONSTRUCTOR",
+ "QT3_MOC_SUPPORT",
+ "QDOC_PROPERTY"
+};
+
+static const int KwordHashTableSize = 4096;
+static int kwordHashTable[KwordHashTableSize];
+
+static QHash<QByteArray, bool> *ignoredTokensAndDirectives = 0;
+
+static QRegExp *comment = 0;
+static QRegExp *versionX = 0;
+static QRegExp *definedX = 0;
+
+static QRegExp *defines = 0;
+static QRegExp *falsehoods = 0;
+
+static QTextCodec *sourceCodec = 0;
+
+/*
+ This function is a perfect hash function for the 37 keywords of C99
+ (with a hash table size of 512). It should perform well on our
+ Qt-enhanced C++ subset.
+*/
+static int hashKword(const char *s, int len)
+{
+ return (((uchar) s[0]) + (((uchar) s[2]) << 5) +
+ (((uchar) s[len - 1]) << 3)) % KwordHashTableSize;
+}
+
+static void insertKwordIntoHash(const char *s, int number)
+{
+ int k = hashKword(s, strlen(s));
+ while (kwordHashTable[k]) {
+ if (++k == KwordHashTableSize)
+ k = 0;
+ }
+ kwordHashTable[k] = number;
+}
+
+Tokenizer::Tokenizer(const Location& loc, QFile &in)
+{
+ init();
+ yyIn = in.readAll();
+ yyPos = 0;
+ start(loc);
+}
+
+Tokenizer::Tokenizer(const Location& loc, const QByteArray &in)
+ : yyIn(in)
+{
+ init();
+ yyPos = 0;
+ start(loc);
+}
+
+Tokenizer::~Tokenizer()
+{
+ delete[] yyLexBuf1;
+ delete[] yyLexBuf2;
+}
+
+int Tokenizer::getToken()
+{
+ char *t = yyPrevLex;
+ yyPrevLex = yyLex;
+ yyLex = t;
+
+ while (yyCh != EOF) {
+ yyTokLoc = yyCurLoc;
+ yyLexLen = 0;
+
+ if (isspace(yyCh)) {
+ do {
+ yyCh = getChar();
+ } while (isspace(yyCh));
+ }
+ else if (isalpha(yyCh) || yyCh == '_') {
+ do {
+ yyCh = getChar();
+ } while (isalnum(yyCh) || yyCh == '_');
+
+ int k = hashKword(yyLex, yyLexLen);
+ for (;;) {
+ int i = kwordHashTable[k];
+ if (i == 0) {
+ return Tok_Ident;
+ }
+ else if (i == -1) {
+ if (!parsingMacro && ignoredTokensAndDirectives->contains(yyLex)) {
+ if (ignoredTokensAndDirectives->value(yyLex)) { // it's a directive
+ int parenDepth = 0;
+ while (yyCh != EOF && (yyCh != ')' || parenDepth > 1)) {
+ if (yyCh == '(')
+ ++parenDepth;
+ else if (yyCh == ')')
+ --parenDepth;
+ yyCh = getChar();
+ }
+ if (yyCh == ')')
+ yyCh = getChar();
+ }
+ break;
+ }
+ }
+ else if (strcmp(yyLex, kwords[i - 1]) == 0) {
+ int ret = (int) Tok_FirstKeyword + i - 1;
+ if (ret != Tok_explicit && ret != Tok_inline && ret != Tok_typename)
+ return ret;
+ break;
+ }
+
+ if (++k == KwordHashTableSize)
+ k = 0;
+ }
+ }
+ else if (isdigit(yyCh)) {
+ do {
+ yyCh = getChar();
+ } while (isalnum(yyCh) || yyCh == '.' || yyCh == '+' ||
+ yyCh == '-');
+ return Tok_Number;
+ }
+ else {
+ switch (yyCh) {
+ case '!':
+ case '%':
+ yyCh = getChar();
+ if (yyCh == '=')
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ case '"':
+ yyCh = getChar();
+
+ while (yyCh != EOF && yyCh != '"') {
+ if (yyCh == '\\')
+ yyCh = getChar();
+ yyCh = getChar();
+ }
+ yyCh = getChar();
+
+ if (yyCh == EOF)
+ yyTokLoc.warning(tr("Unterminated C++ string literal"),
+ tr("Maybe you forgot '/*!' at the beginning of the file?"));
+ else
+ return Tok_String;
+ break;
+ case '#':
+ return getTokenAfterPreprocessor();
+ case '&':
+ yyCh = getChar();
+ if (yyCh == '&' || yyCh == '=') {
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ }
+ else {
+ return Tok_Ampersand;
+ }
+ case '\'':
+ yyCh = getChar();
+ if (yyCh == '\\')
+ yyCh = getChar();
+ do {
+ yyCh = getChar();
+ } while (yyCh != EOF && yyCh != '\'');
+
+ if (yyCh == EOF) {
+ yyTokLoc.warning(tr("Unterminated C++ character"
+ " literal"));
+ }
+ else {
+ yyCh = getChar();
+ return Tok_Number;
+ }
+ break;
+ case '(':
+ yyCh = getChar();
+ if (yyNumPreprocessorSkipping == 0)
+ yyParenDepth++;
+ if (isspace(yyCh)) {
+ do {
+ yyCh = getChar();
+ } while (isspace(yyCh));
+ yyLexLen = 1;
+ yyLex[1] = '\0';
+ }
+ if (yyCh == '*') {
+ yyCh = getChar();
+ return Tok_LeftParenAster;
+ }
+ return Tok_LeftParen;
+ case ')':
+ yyCh = getChar();
+ if (yyNumPreprocessorSkipping == 0)
+ yyParenDepth--;
+ return Tok_RightParen;
+ case '*':
+ yyCh = getChar();
+ if (yyCh == '=') {
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ } else {
+ return Tok_Aster;
+ }
+ case '^':
+ yyCh = getChar();
+ if (yyCh == '=') {
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ } else {
+ return Tok_Caret;
+ }
+ case '+':
+ yyCh = getChar();
+ if (yyCh == '+' || yyCh == '=')
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ case ',':
+ yyCh = getChar();
+ return Tok_Comma;
+ case '-':
+ yyCh = getChar();
+ if (yyCh == '-' || yyCh == '=') {
+ yyCh = getChar();
+ } else if (yyCh == '>') {
+ yyCh = getChar();
+ if (yyCh == '*')
+ yyCh = getChar();
+ }
+ return Tok_SomeOperator;
+ case '.':
+ yyCh = getChar();
+ if (yyCh == '*') {
+ yyCh = getChar();
+ } else if (yyCh == '.') {
+ do {
+ yyCh = getChar();
+ } while (yyCh == '.');
+ return Tok_Ellipsis;
+ } else if (isdigit(yyCh)) {
+ do {
+ yyCh = getChar();
+ } while (isalnum(yyCh) || yyCh == '.' || yyCh == '+' ||
+ yyCh == '-');
+ return Tok_Number;
+ }
+ return Tok_SomeOperator;
+ case '/':
+ yyCh = getChar();
+ if (yyCh == '/') {
+ do {
+ yyCh = getChar();
+ } while (yyCh != EOF && yyCh != '\n');
+ } else if (yyCh == '*') {
+ bool metDoc = false; // empty doc is no doc
+ bool metSlashAsterBang = false;
+ bool metAster = false;
+ bool metAsterSlash = false;
+
+ yyCh = getChar();
+ if (yyCh == '!')
+ metSlashAsterBang = true;
+
+ while (!metAsterSlash) {
+ if (yyCh == EOF) {
+ yyTokLoc.warning(tr("Unterminated C++ comment"));
+ break;
+ } else {
+ if (yyCh == '*') {
+ metAster = true;
+ } else if (metAster && yyCh == '/') {
+ metAsterSlash = true;
+ } else {
+ metAster = false;
+ if (isgraph(yyCh))
+ metDoc = true;
+ }
+ }
+ yyCh = getChar();
+ }
+ if (metSlashAsterBang && metDoc)
+ return Tok_Doc;
+ else if (yyParenDepth > 0)
+ return Tok_Comment;
+ } else {
+ if (yyCh == '=')
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ }
+ break;
+ case ':':
+ yyCh = getChar();
+ if (yyCh == ':') {
+ yyCh = getChar();
+ return Tok_Gulbrandsen;
+ } else {
+ return Tok_Colon;
+ }
+ case ';':
+ yyCh = getChar();
+ return Tok_Semicolon;
+ case '<':
+ yyCh = getChar();
+ if (yyCh == '<') {
+ yyCh = getChar();
+ if (yyCh == '=')
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ } else if (yyCh == '=') {
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ } else {
+ return Tok_LeftAngle;
+ }
+ case '=':
+ yyCh = getChar();
+ if (yyCh == '=') {
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ } else {
+ return Tok_Equal;
+ }
+ case '>':
+ yyCh = getChar();
+ if (yyCh == '>') {
+ yyCh = getChar();
+ if (yyCh == '=')
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ } else if (yyCh == '=') {
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ } else {
+ return Tok_RightAngle;
+ }
+ case '?':
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ case '[':
+ yyCh = getChar();
+ if (yyNumPreprocessorSkipping == 0)
+ yyBracketDepth++;
+ return Tok_LeftBracket;
+ case '\\':
+ yyCh = getChar();
+ yyCh = getChar(); // skip one character
+ break;
+ case ']':
+ yyCh = getChar();
+ if (yyNumPreprocessorSkipping == 0)
+ yyBracketDepth--;
+ return Tok_RightBracket;
+ case '{':
+ yyCh = getChar();
+ if (yyNumPreprocessorSkipping == 0)
+ yyBraceDepth++;
+ return Tok_LeftBrace;
+ case '}':
+ yyCh = getChar();
+ if (yyNumPreprocessorSkipping == 0)
+ yyBraceDepth--;
+ return Tok_RightBrace;
+ case '|':
+ yyCh = getChar();
+ if (yyCh == '|' || yyCh == '=')
+ yyCh = getChar();
+ return Tok_SomeOperator;
+ case '~':
+ yyCh = getChar();
+ return Tok_Tilde;
+ case '@':
+ yyCh = getChar();
+ return Tok_At;
+ default:
+ // ### We should really prevent qdoc from looking at snippet files rather than
+ // ### suppress warnings when reading them.
+ if (yyNumPreprocessorSkipping == 0 && !yyTokLoc.fileName().endsWith(".qdoc")) {
+ yyTokLoc.warning(tr("Hostile character 0x%1 in C++ source")
+ .arg((uchar)yyCh, 1, 16));
+ }
+ yyCh = getChar();
+ }
+ }
+ }
+
+ if (yyPreprocessorSkipping.count() > 1) {
+ yyTokLoc.warning(tr("Expected #endif before end of file"));
+ // clear it out or we get an infinite loop!
+ while (!yyPreprocessorSkipping.isEmpty()) {
+ popSkipping();
+ }
+ }
+
+ strcpy(yyLex, "end-of-input");
+ yyLexLen = strlen(yyLex);
+ return Tok_Eoi;
+}
+
+void Tokenizer::initialize(const Config &config)
+{
+ QString versionSym = config.getString(CONFIG_VERSIONSYM);
+
+ QString sourceEncoding = config.getString(CONFIG_SOURCEENCODING);
+ if (sourceEncoding.isEmpty())
+ sourceEncoding = QLatin1String("ISO-8859-1");
+ sourceCodec = QTextCodec::codecForName(sourceEncoding.toLocal8Bit());
+
+ comment = new QRegExp("/(?:\\*.*\\*/|/.*\n|/[^\n]*$)");
+ comment->setMinimal(true);
+ versionX = new QRegExp("$cannot possibly match^");
+ if (!versionSym.isEmpty())
+ versionX->setPattern("[ \t]*(?:" + QRegExp::escape(versionSym)
+ + ")[ \t]+\"([^\"]*)\"[ \t]*");
+ definedX = new QRegExp("defined ?\\(?([A-Z_0-9a-z]+) ?\\)");
+
+ QStringList d = config.getStringList(CONFIG_DEFINES);
+ d += "qdoc";
+ defines = new QRegExp(d.join("|"));
+ falsehoods = new QRegExp(config.getStringList(CONFIG_FALSEHOODS).join("|"));
+
+ memset(kwordHashTable, 0, sizeof(kwordHashTable));
+ for (int i = 0; i < Tok_LastKeyword - Tok_FirstKeyword + 1; i++)
+ insertKwordIntoHash(kwords[i], i + 1);
+
+ ignoredTokensAndDirectives = new QHash<QByteArray, bool>;
+
+ QStringList tokens = config.getStringList(LANGUAGE_CPP + Config::dot + CONFIG_IGNORETOKENS);
+ foreach (const QString &t, tokens) {
+ const QByteArray tb = t.toAscii();
+ ignoredTokensAndDirectives->insert(tb, false);
+ insertKwordIntoHash(tb.data(), -1);
+ }
+
+ QStringList directives = config.getStringList(LANGUAGE_CPP + Config::dot
+ + CONFIG_IGNOREDIRECTIVES);
+ foreach (const QString &d, directives) {
+ const QByteArray db = d.toAscii();
+ ignoredTokensAndDirectives->insert(db, true);
+ insertKwordIntoHash(db.data(), -1);
+ }
+}
+
+void Tokenizer::terminate()
+{
+ delete comment;
+ comment = 0;
+ delete versionX;
+ versionX = 0;
+ delete definedX;
+ definedX = 0;
+ delete defines;
+ defines = 0;
+ delete falsehoods;
+ falsehoods = 0;
+ delete ignoredTokensAndDirectives;
+ ignoredTokensAndDirectives = 0;
+}
+
+void Tokenizer::init()
+{
+ yyLexBuf1 = new char[(int) yyLexBufSize];
+ yyLexBuf2 = new char[(int) yyLexBufSize];
+ yyPrevLex = yyLexBuf1;
+ yyPrevLex[0] = '\0';
+ yyLex = yyLexBuf2;
+ yyLex[0] = '\0';
+ yyLexLen = 0;
+ yyPreprocessorSkipping.push(false);
+ yyNumPreprocessorSkipping = 0;
+ yyBraceDepth = 0;
+ yyParenDepth = 0;
+ yyBracketDepth = 0;
+ yyCh = '\0';
+ parsingMacro = false;
+}
+
+void Tokenizer::start(const Location& loc)
+{
+ yyTokLoc = loc;
+ yyCurLoc = loc;
+ yyCurLoc.start();
+ strcpy(yyPrevLex, "beginning-of-input");
+ strcpy(yyLex, "beginning-of-input");
+ yyLexLen = strlen(yyLex);
+ yyBraceDepth = 0;
+ yyParenDepth = 0;
+ yyBracketDepth = 0;
+ yyCh = '\0';
+ yyCh = getChar();
+}
+
+/*
+ Returns the next token, if # was met. This function interprets the
+ preprocessor directive, skips over any #ifdef'd out tokens, and returns the
+ token after all of that.
+*/
+int Tokenizer::getTokenAfterPreprocessor()
+{
+ yyCh = getChar();
+ while (isspace(yyCh) && yyCh != '\n')
+ yyCh = getChar();
+
+ /*
+ #directive condition
+ */
+ QString directive;
+ QString condition;
+
+ while (isalpha(yyCh)) {
+ directive += QChar(yyCh);
+ yyCh = getChar();
+ }
+ if (!directive.isEmpty()) {
+ while (yyCh != EOF && yyCh != '\n') {
+ if (yyCh == '\\')
+ yyCh = getChar();
+ condition += yyCh;
+ yyCh = getChar();
+ }
+ condition.remove(*comment);
+ condition = condition.simplified();
+
+ /*
+ The #if, #ifdef, #ifndef, #elif, #else, and #endif
+ directives have an effect on the skipping stack. For
+ instance, if the code processed so far is
+
+ #if 1
+ #if 0
+ #if 1
+ // ...
+ #else
+
+ the skipping stack contains, from bottom to top, false true
+ true (assuming 0 is false and 1 is true). If at least one
+ entry of the stack is true, the tokens are skipped.
+
+ This mechanism is simple yet hard to understand.
+ */
+ if (directive[0] == QChar('i')) {
+ if (directive == QString("if"))
+ pushSkipping(!isTrue(condition));
+ else if (directive == QString("ifdef"))
+ pushSkipping(!defines->exactMatch(condition));
+ else if (directive == QString("ifndef"))
+ pushSkipping(defines->exactMatch(condition));
+ } else if (directive[0] == QChar('e')) {
+ if (directive == QString("elif")) {
+ bool old = popSkipping();
+ if (old)
+ pushSkipping(!isTrue(condition));
+ else
+ pushSkipping(true);
+ } else if (directive == QString("else")) {
+ pushSkipping(!popSkipping());
+ } else if (directive == QString("endif")) {
+ popSkipping();
+ }
+ } else if (directive == QString("define")) {
+ if (versionX->exactMatch(condition))
+ yyVersion = versionX->cap(1);
+ }
+ }
+
+ int tok;
+ do {
+ /*
+ We set yyLex now, and after getToken() this will be
+ yyPrevLex. This way, we skip over the preprocessor
+ directive.
+ */
+ qstrcpy(yyLex, yyPrevLex);
+
+ /*
+ If getToken() meets another #, it will call
+ getTokenAfterPreprocessor() once again, which could in turn
+ call getToken() again, etc. Unless there are 10,000 or so
+ preprocessor directives in a row, this shouldn't overflow
+ the stack.
+ */
+ tok = getToken();
+ } while (yyNumPreprocessorSkipping > 0 && tok != Tok_Eoi);
+ return tok;
+}
+
+/*
+ Pushes a new skipping value onto the stack. This corresponds to entering a
+ new #if block.
+*/
+void Tokenizer::pushSkipping(bool skip)
+{
+ yyPreprocessorSkipping.push(skip);
+ if (skip)
+ yyNumPreprocessorSkipping++;
+}
+
+/*
+ Pops a skipping value from the stack. This corresponds to reaching a #endif.
+*/
+bool Tokenizer::popSkipping()
+{
+ if (yyPreprocessorSkipping.isEmpty()) {
+ yyTokLoc.warning(tr("Unexpected #elif, #else or #endif"));
+ return true;
+ }
+
+ bool skip = yyPreprocessorSkipping.pop();
+ if (skip)
+ yyNumPreprocessorSkipping--;
+ return skip;
+}
+
+/*
+ Returns true if the condition evaluates as true, otherwise false. The
+ condition is represented by a string. Unsophisticated parsing techniques are
+ used. The preprocessing method could be named StriNg-Oriented PreProcessing,
+ as SNOBOL stands for StriNg-Oriented symBOlic Language.
+*/
+bool Tokenizer::isTrue(const QString &condition)
+{
+ int firstOr = -1;
+ int firstAnd = -1;
+ int parenDepth = 0;
+
+ /*
+ Find the first logical operator at top level, but be careful
+ about precedence. Examples:
+
+ X || Y // the or
+ X || Y || Z // the leftmost or
+ X || Y && Z // the or
+ X && Y || Z // the or
+ (X || Y) && Z // the and
+ */
+ for (int i = 0; i < (int) condition.length() - 1; i++) {
+ QChar ch = condition[i];
+ if (ch == QChar('(')) {
+ parenDepth++;
+ } else if (ch == QChar(')')) {
+ parenDepth--;
+ } else if (parenDepth == 0) {
+ if (condition[i + 1] == ch) {
+ if (ch == QChar('|')) {
+ firstOr = i;
+ break;
+ } else if (ch == QChar('&')) {
+ if (firstAnd == -1)
+ firstAnd = i;
+ }
+ }
+ }
+ }
+ if (firstOr != -1)
+ return isTrue(condition.left(firstOr)) ||
+ isTrue(condition.mid(firstOr + 2));
+ if (firstAnd != -1)
+ return isTrue(condition.left(firstAnd)) &&
+ isTrue(condition.mid(firstAnd + 2));
+
+ QString t = condition.simplified();
+ if (t.isEmpty())
+ return true;
+
+ if (t[0] == QChar('!'))
+ return !isTrue(t.mid(1));
+ if (t[0] == QChar('(') && t.endsWith(QChar(')')))
+ return isTrue(t.mid(1, t.length() - 2));
+
+ if (definedX->exactMatch(t))
+ return defines->exactMatch(definedX->cap(1));
+ else
+ return !falsehoods->exactMatch(t);
+}
+
+QString Tokenizer::lexeme() const
+{
+ return sourceCodec->toUnicode(yyLex);
+}
+
+QString Tokenizer::previousLexeme() const
+{
+ return sourceCodec->toUnicode(yyPrevLex);
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/tokenizer.h b/src/tools/qdoc/tokenizer.h
new file mode 100644
index 0000000000..b6d6e1d9ca
--- /dev/null
+++ b/src/tools/qdoc/tokenizer.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ tokenizer.h
+*/
+
+#ifndef TOKENIZER_H
+#define TOKENIZER_H
+
+#include <qfile.h>
+#include <qstack.h>
+#include <qstring.h>
+
+#include "location.h"
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Here come the C++ tokens we support. The first part contains
+ all-purpose tokens; then come keywords.
+
+ If you add a keyword, make sure to modify the keyword array in
+ tokenizer.cpp as well, and possibly adjust Tok_FirstKeyword and
+ Tok_LastKeyword.
+*/
+enum { Tok_Eoi, Tok_Ampersand, Tok_Aster, Tok_Caret, Tok_LeftParen,
+ Tok_RightParen, Tok_LeftParenAster, Tok_Equal, Tok_LeftBrace,
+ Tok_RightBrace, Tok_Semicolon, Tok_Colon, Tok_LeftAngle,
+ Tok_RightAngle, Tok_Comma, Tok_Ellipsis, Tok_Gulbrandsen,
+ Tok_LeftBracket, Tok_RightBracket, Tok_Tilde, Tok_SomeOperator,
+ Tok_Number, Tok_String, Tok_Doc, Tok_Comment, Tok_Ident, Tok_At,
+ Tok_char, Tok_class, Tok_const, Tok_double, Tok_enum,
+ Tok_explicit, Tok_friend, Tok_inline, Tok_int, Tok_long,
+ Tok_namespace, Tok_operator, Tok_private, Tok_protected,
+ Tok_public, Tok_short, Tok_signals, Tok_signed, Tok_slots,
+ Tok_static, Tok_struct, Tok_template, Tok_typedef,
+ Tok_typename, Tok_union, Tok_unsigned, Tok_using, Tok_virtual,
+ Tok_void, Tok_volatile, Tok_int64, Tok_Q_OBJECT, Tok_Q_OVERRIDE,
+ Tok_Q_PROPERTY, Tok_Q_PRIVATE_PROPERTY, Tok_Q_DECLARE_SEQUENTIAL_ITERATOR,
+ Tok_Q_DECLARE_MUTABLE_SEQUENTIAL_ITERATOR,
+ Tok_Q_DECLARE_ASSOCIATIVE_ITERATOR,
+ Tok_Q_DECLARE_MUTABLE_ASSOCIATIVE_ITERATOR,
+ Tok_Q_DECLARE_FLAGS, Tok_Q_SIGNALS, Tok_Q_SLOTS, Tok_QT_COMPAT,
+ Tok_QT_COMPAT_CONSTRUCTOR, Tok_QT_DEPRECATED, Tok_QT_MOC_COMPAT,
+ Tok_QT_MODULE, Tok_QT3_SUPPORT, Tok_QT3_SUPPORT_CONSTRUCTOR,
+ Tok_QT3_MOC_SUPPORT, Tok_QDOC_PROPERTY,
+ Tok_FirstKeyword = Tok_char, Tok_LastKeyword = Tok_QDOC_PROPERTY };
+
+/*
+ The Tokenizer class implements lexical analysis of C++ source
+ files.
+
+ Not every operator or keyword of C++ is recognized; only those
+ that are interesting to us. Some Qt keywords or macros are also
+ recognized.
+*/
+
+class Tokenizer
+{
+public:
+ Tokenizer(const Location& loc, const QByteArray &in);
+ Tokenizer(const Location& loc, QFile &file);
+
+ ~Tokenizer();
+
+ int getToken();
+ void setParsingFnOrMacro(bool macro) { parsingMacro = macro; }
+ bool parsingFnOrMacro() const { return parsingMacro; }
+
+ const Location &location() const { return yyTokLoc; }
+ QString previousLexeme() const;
+ QString lexeme() const;
+ QString version() const { return yyVersion; }
+ int braceDepth() const { return yyBraceDepth; }
+ int parenDepth() const { return yyParenDepth; }
+ int bracketDepth() const { return yyBracketDepth; }
+
+ static void initialize(const Config &config);
+ static void terminate();
+ static bool isTrue(const QString &condition);
+
+private:
+ void init();
+ void start(const Location& loc);
+ /*
+ This limit on the length of a lexeme seems fairly high, but a
+ doc comment can be arbitrarily long. The previous 65,536 limit
+ was reached by Mark Summerfield.
+ */
+ enum { yyLexBufSize = 524288 };
+
+ int getch()
+ {
+ return yyPos == yyIn.size() ? EOF : yyIn[yyPos++];
+ }
+
+ inline int getChar()
+ {
+ if (yyCh == EOF)
+ return EOF;
+ if (yyLexLen < yyLexBufSize - 1) {
+ yyLex[yyLexLen++] = (char) yyCh;
+ yyLex[yyLexLen] = '\0';
+ }
+ yyCurLoc.advance(yyCh);
+ int ch = getch();
+ if (ch == EOF)
+ return EOF;
+ // cast explicitly to make sure the value of ch
+ // is in range [0..255] to avoid assert messages
+ // when using debug CRT that checks its input.
+ return int(uint(uchar(ch)));
+ }
+
+ int getTokenAfterPreprocessor();
+ void pushSkipping(bool skip);
+ bool popSkipping();
+
+ Location yyTokLoc;
+ Location yyCurLoc;
+ char *yyLexBuf1;
+ char *yyLexBuf2;
+ char *yyPrevLex;
+ char *yyLex;
+ size_t yyLexLen;
+ QStack<bool> yyPreprocessorSkipping;
+ int yyNumPreprocessorSkipping;
+ int yyBraceDepth;
+ int yyParenDepth;
+ int yyBracketDepth;
+ int yyCh;
+
+ QString yyVersion;
+ bool parsingMacro;
+
+protected:
+ QByteArray yyIn;
+ int yyPos;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/tr.h b/src/tools/qdoc/tr.h
new file mode 100644
index 0000000000..f01e645ca6
--- /dev/null
+++ b/src/tools/qdoc/tr.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ tr.h
+*/
+
+#ifndef TR_H
+#define TR_H
+
+#ifndef QT_BOOTSTRAPPED
+# include "qcoreapplication.h"
+#endif
+
+#include <qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(QT_BOOTSTRAPPED) || defined(QT_NO_TRANSLATION)
+inline QString tr(const char *sourceText, const char *comment = 0)
+{
+ Q_UNUSED(comment);
+ return QString( QLatin1String(sourceText) );
+}
+#else
+inline QString tr(const char *sourceText, const char *comment = 0)
+{
+ return QCoreApplication::instance()->translate("", sourceText, comment);
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/tree.cpp b/src/tools/qdoc/tree.cpp
new file mode 100644
index 0000000000..c52e45739a
--- /dev/null
+++ b/src/tools/qdoc/tree.cpp
@@ -0,0 +1,2358 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ tree.cpp
+*/
+
+#include <QDomDocument>
+#include "atom.h"
+#include "doc.h"
+#include "htmlgenerator.h"
+#include "location.h"
+#include "node.h"
+#include "text.h"
+#include "tree.h"
+#include <limits.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+struct InheritanceBound
+{
+ Node::Access access;
+ QStringList basePath;
+ QString dataTypeWithTemplateArgs;
+ InnerNode* parent;
+
+ InheritanceBound()
+ : access(Node::Public) { }
+ InheritanceBound(Node::Access access0,
+ const QStringList& basePath0,
+ const QString& dataTypeWithTemplateArgs0,
+ InnerNode* parent)
+ : access(access0), basePath(basePath0),
+ dataTypeWithTemplateArgs(dataTypeWithTemplateArgs0),
+ parent(parent) { }
+};
+
+struct Target
+{
+ Node* node;
+ Atom* atom;
+ int priority;
+};
+
+typedef QMap<PropertyNode::FunctionRole, QString> RoleMap;
+typedef QMap<PropertyNode*, RoleMap> PropertyMap;
+typedef QMultiHash<QString, FakeNode*> FakeNodeHash;
+typedef QMultiHash<QString, Target> TargetHash;
+
+class TreePrivate
+{
+public:
+ QMap<ClassNode* , QList<InheritanceBound> > unresolvedInheritanceMap;
+ PropertyMap unresolvedPropertyMap;
+ NodeMultiMap groupMap;
+ NodeMultiMap qmlModuleMap;
+ QMultiMap<QString, QString> publicGroupMap;
+ FakeNodeHash fakeNodesByTitle;
+ TargetHash targetHash;
+ QList<QPair<ClassNode*,QString> > basesList;
+ QList<QPair<FunctionNode*,QString> > relatedList;
+};
+
+/*!
+ \class Tree
+
+ This class constructs and maintains a tree of instances of
+ Node and its many subclasses.
+ */
+
+/*!
+ The default constructor is the only constructor.
+ */
+Tree::Tree()
+ : roo(0, "")
+{
+ priv = new TreePrivate;
+}
+
+/*!
+ The destructor deletes the internal, private tree.
+ */
+Tree::~Tree()
+{
+ delete priv;
+}
+
+/*!
+ This function simply calls the const version of itself and
+ returns the result.
+ */
+Node* Tree::findNode(const QStringList& path, Node* relative, int findFlags, const Node* self)
+{
+ return const_cast<Node*>(const_cast<const Tree*>(this)->findNode(path,
+ relative,
+ findFlags,
+ self));
+}
+
+/*!
+ Searches the tree for a node that matches the \a path. The
+ search begins at \a start but can move up the parent chain
+ recursively if no match is found.
+ */
+const Node* Tree::findNode(const QStringList& path,
+ const Node* start,
+ int findFlags,
+ const Node* self) const
+{
+ const Node* current = start;
+ if (!current)
+ current = root();
+
+ /*
+ First, search for a node assuming we don't want a QML node.
+ If that search fails, search again assuming we do want a
+ QML node.
+ */
+ const Node* n = findNode(path,current,findFlags,self,false);
+ if (!n) {
+ n = findNode(path,current,findFlags,self,true);
+ }
+ return n;
+}
+
+/*!
+ This code in this function was extracted from the other
+ version of findNode() that has the same signature without
+ the last bool parameter \a qml. This function is called
+ only by that other findNode(). It can be called a second
+ time if the first call returns null. If \a qml is false,
+ the search will only match a node that is not a QML node.
+ If \a qml is true, the search will only match a node that
+ is a QML node.
+ */
+const Node* Tree::findNode(const QStringList& path,
+ const Node* start,
+ int findFlags,
+ const Node* self,
+ bool qml) const
+{
+ const Node* current = start;
+ do {
+ const Node* node = current;
+ int i;
+ int start_idx = 0;
+
+ /*
+ If the path contains one or two double colons ("::"),
+ check first to see if the first two path strings refer
+ to a QML element. If yes, that reference identifies a
+ QML class node.
+ */
+ if (qml && path.size() >= 2) {
+ QmlClassNode* qcn = QmlClassNode::moduleMap.value(path[0]+ "::" +path[1]);
+ if (qcn) {
+ node = qcn;
+ if (path.size() == 2)
+ return node;
+ start_idx = 2;
+ }
+ }
+
+ for (i = start_idx; i < path.size(); ++i) {
+ if (node == 0 || !node->isInnerNode())
+ break;
+
+ const Node* next = static_cast<const InnerNode*>(node)->findNode(path.at(i), qml);
+
+ if (!next && (findFlags & SearchEnumValues) && i == path.size()-1)
+ next = static_cast<const InnerNode*>(node)->findEnumNodeForValue(path.at(i));
+
+ if (!next && !qml && node->type() == Node::Class && (findFlags & SearchBaseClasses)) {
+ NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
+ foreach (const Node* baseClass, baseClasses) {
+ next = static_cast<const InnerNode*>(baseClass)->findNode(path.at(i));
+ if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1)
+ next = static_cast<const InnerNode*>(baseClass)
+ ->findEnumNodeForValue(path.at(i));
+ if (next)
+ break;
+ }
+ }
+ node = next;
+ }
+ if (node && i == path.size()
+ && (!(findFlags & NonFunction) || node->type() != Node::Function
+ || ((FunctionNode*)node)->metaness() == FunctionNode::MacroWithoutParams)) {
+ if ((node != self) && (node->subType() != Node::QmlPropertyGroup)) {
+ if (node->subType() == Node::Collision) {
+ node = node->applyModuleIdentifier(start);
+ }
+ return node;
+ }
+ }
+ current = current->parent();
+ } while (current);
+
+ return 0;
+}
+
+/*!
+ Find the node with the specified \a path name of the
+ specified \a type.
+ */
+Node* Tree::findNode(const QStringList& path,
+ Node::Type type,
+ Node* relative,
+ int findFlags)
+{
+ return const_cast<Node*>(const_cast<const Tree*>(this)->findNode(path,
+ type,
+ relative,
+ findFlags));
+}
+
+/*!
+ This function just calls the const version of itself and returns
+ a pointer to the QML class node, or null.
+ */
+QmlClassNode* Tree::findQmlClassNode(const QString& module, const QString& element)
+{
+ return const_cast<QmlClassNode*>(const_cast<const Tree*>(this)->findQmlClassNode(module, element));
+}
+
+/*!
+ Find the node with the specified \a path name of the
+ specified \a type.
+ */
+const Node* Tree::findNode(const QStringList& path,
+ Node::Type type,
+ const Node* relative,
+ int findFlags) const
+{
+ const Node* node = findNode(path, relative, findFlags);
+ if (node != 0 && node->type() == type)
+ return node;
+ return 0;
+}
+
+/*!
+ Find the QML class node for the specified \a module and \a name
+ identifiers. The \a module identifier may be empty. If the module
+ identifier is empty, then begin by finding the FakeNode that has
+ the specified \a name. If that FakeNode is a QML class, return it.
+ If it is a collision node, return its current child, if the current
+ child is a QML class. If the collision node does not have a child
+ that is a QML class node, return 0.
+ */
+const QmlClassNode* Tree::findQmlClassNode(const QString& module, const QString& name) const
+{
+ if (module.isEmpty()) {
+ const Node* n = findNode(QStringList(name), Node::Fake);
+ if (n) {
+ if (n->subType() == Node::QmlClass)
+ return static_cast<const QmlClassNode*>(n);
+ else if (n->subType() == Node::Collision) {
+ const NameCollisionNode* ncn;
+ ncn = static_cast<const NameCollisionNode*>(n);
+ return static_cast<const QmlClassNode*>(ncn->findAny(Node::Fake,Node::QmlClass));
+ }
+ }
+ return 0;
+ }
+ return QmlClassNode::moduleMap.value(module + "::" + name);
+}
+
+/*!
+ First, search for a node with the specified \a name. If a matching
+ node is found, if it is a collision node, another collision with
+ this name has been found, so return the collision node. If the
+ matching node is not a collision node, the first collision for this
+ name has been found, so create a NameCollisionNode with the matching
+ node as its first child, and return a pointer to the new
+ NameCollisionNode. Otherwise return 0.
+ */
+NameCollisionNode* Tree::checkForCollision(const QString& name) const
+{
+ Node* n = const_cast<Node*>(findNode(QStringList(name)));
+ if (n) {
+ if (n->subType() == Node::Collision) {
+ NameCollisionNode* ncn = static_cast<NameCollisionNode*>(n);
+ return ncn;
+ }
+ if (n->isInnerNode())
+ return new NameCollisionNode(static_cast<InnerNode*>(n));
+ }
+ return 0;
+}
+
+/*!
+ This function is like checkForCollision() in that it searches
+ for a collision node with the specified \a name. But it doesn't
+ create anything. If it finds a match, it returns the pointer.
+ Otherwise it returns 0.
+ */
+NameCollisionNode* Tree::findCollisionNode(const QString& name) const
+{
+ Node* n = const_cast<Node*>(findNode(QStringList(name)));
+ if (n) {
+ if (n->subType() == Node::Collision) {
+ NameCollisionNode* ncn = static_cast<NameCollisionNode*>(n);
+ return ncn;
+ }
+ }
+ return 0;
+}
+
+/*!
+ This function just calls the const version of the same function
+ and returns the function node.
+ */
+FunctionNode* Tree::findFunctionNode(const QStringList& path,
+ Node* relative,
+ int findFlags)
+{
+ return const_cast<FunctionNode*>
+ (const_cast<const Tree*>(this)->findFunctionNode(path,relative,findFlags));
+}
+
+/*!
+ This function begins searching the tree at \a relative for
+ the \l {FunctionNode} {function node} identified by \a path.
+ The \a findFlags are used to restrict the search. If a node
+ that matches the \a path is found, it is returned. Otherwise,
+ 0 is returned. If \a relative is 0, the root of the tree is
+ used as the starting point.
+ */
+const FunctionNode* Tree::findFunctionNode(const QStringList& path,
+ const Node* relative,
+ int findFlags) const
+{
+ if (!relative)
+ relative = root();
+
+ /*
+ If the path contains two double colons ("::"), check
+ first to see if it is a reference to a QML method. If
+ it is a reference to a QML method, first look up the
+ QML class node in the QML module map.
+ */
+ if (path.size() == 3) {
+ QmlClassNode* qcn = QmlClassNode::moduleMap.value(path[0]+ "::" +path[1]);
+ if (qcn) {
+ return static_cast<const FunctionNode*>(qcn->findFunctionNode(path[2]));
+ }
+ }
+
+ do {
+ const Node* node = relative;
+ int i;
+
+ for (i = 0; i < path.size(); ++i) {
+ if (node == 0 || !node->isInnerNode())
+ break;
+
+ const Node* next;
+ if (i == path.size() - 1)
+ next = ((InnerNode*) node)->findFunctionNode(path.at(i));
+ else
+ next = ((InnerNode*) node)->findNode(path.at(i));
+
+ if (!next && node->type() == Node::Class &&
+ (findFlags & SearchBaseClasses)) {
+ NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node));
+ foreach (const Node* baseClass, baseClasses) {
+ if (i == path.size() - 1)
+ next = static_cast<const InnerNode*>(baseClass)->findFunctionNode(path.at(i));
+ else
+ next = static_cast<const InnerNode*>(baseClass)->findNode(path.at(i));
+
+ if (next)
+ break;
+ }
+ }
+
+ node = next;
+ }
+ if (node && i == path.size() && node->isFunction()) {
+ // CppCodeParser::processOtherMetaCommand ensures that reimplemented
+ // functions are private.
+ const FunctionNode* func = static_cast<const FunctionNode*>(node);
+ while (func->access() == Node::Private) {
+ const FunctionNode* from = func->reimplementedFrom();
+ if (from != 0) {
+ if (from->access() != Node::Private)
+ return from;
+ else
+ func = from;
+ }
+ else
+ break;
+ }
+ return func;
+ }
+ relative = relative->parent();
+ } while (relative);
+
+ return 0;
+}
+
+/*!
+ This function just calls the const version of itself and
+ returns the result.
+ */
+FunctionNode* Tree::findFunctionNode(const QStringList& parentPath,
+ const FunctionNode* clone,
+ Node* relative,
+ int findFlags)
+{
+ return const_cast<FunctionNode*>(
+ const_cast<const Tree*>(this)->findFunctionNode(parentPath,
+ clone,
+ relative,
+ findFlags));
+}
+
+/*!
+ This function first ignores the \a clone node and searches
+ for the node having the \a parentPath by calling the main
+ findFunction(\a {parentPath}, \a {relative}, \a {findFlags}).
+ If that search is successful, then it searches for the \a clone
+ in the found parent node.
+ */
+const FunctionNode* Tree::findFunctionNode(const QStringList& parentPath,
+ const FunctionNode* clone,
+ const Node* relative,
+ int findFlags) const
+{
+ const Node* parent = findNode(parentPath, relative, findFlags);
+ if (parent == 0 || !parent->isInnerNode()) {
+ return 0;
+ }
+ else {
+ return ((InnerNode*)parent)->findFunctionNode(clone);
+ }
+}
+
+static const int NumSuffixes = 3;
+static const char* const suffixes[NumSuffixes] = { "", "s", "es" };
+
+/*!
+ This function searches for a node with the specified \a title.
+ If \a relative is provided, use it to disambiguate if it has a
+ QML module identifier.
+ */
+const FakeNode* Tree::findFakeNodeByTitle(const QString& title, const Node* relative ) const
+{
+ for (int pass = 0; pass < NumSuffixes; ++pass) {
+ FakeNodeHash::const_iterator i = priv->fakeNodesByTitle.find(Doc::canonicalTitle(title + suffixes[pass]));
+ if (i != priv->fakeNodesByTitle.constEnd()) {
+ if (relative && !relative->qmlModuleIdentifier().isEmpty()) {
+ const FakeNode* fn = i.value();
+ InnerNode* parent = fn->parent();
+ if (parent && parent->type() == Node::Fake && parent->subType() == Node::Collision) {
+ const NodeList& nl = parent->childNodes();
+ NodeList::ConstIterator it = nl.begin();
+ while (it != nl.end()) {
+ if ((*it)->qmlModuleIdentifier() == relative->qmlModuleIdentifier()) {
+ /*
+ By returning here, we avoid printing all the duplicate
+ header warnings, which are not really duplicates now,
+ because of the QML module identifier being used as a
+ namespace qualifier.
+ */
+ fn = static_cast<const FakeNode*>(*it);
+ return fn;
+ }
+ ++it;
+ }
+ }
+ }
+ /*
+ Reporting all these duplicate section titles is probably
+ overkill. We should report the duplicate file and let
+ that suffice.
+ */
+ FakeNodeHash::const_iterator j = i;
+ ++j;
+ if (j != priv->fakeNodesByTitle.constEnd() && j.key() == i.key()) {
+ QList<Location> internalLocations;
+ while (j != priv->fakeNodesByTitle.constEnd()) {
+ if (j.key() == i.key() && j.value()->url().isEmpty())
+ internalLocations.append(j.value()->doc().location());
+ ++j;
+ }
+ if (internalLocations.size() > 0) {
+ i.value()->doc().location().warning(
+ tr("Page '%1' defined in more than one location:").arg(title));
+ foreach (const Location &location, internalLocations)
+ location.warning(tr("(defined here)"));
+ }
+ }
+ return i.value();
+ }
+ }
+ return 0;
+}
+
+/*!
+ This function searches for a \a target anchor node. If it
+ finds one, it sets \a atom from the found node and returns
+ the found node.
+ */
+const Node*
+Tree::findUnambiguousTarget(const QString& target, Atom *&atom, const Node* relative) const
+{
+ Target bestTarget = {0, 0, INT_MAX};
+ int numBestTargets = 0;
+ QList<Target> bestTargetList;
+
+ for (int pass = 0; pass < NumSuffixes; ++pass) {
+ TargetHash::const_iterator i = priv->targetHash.find(Doc::canonicalTitle(target + suffixes[pass]));
+ if (i != priv->targetHash.constEnd()) {
+ TargetHash::const_iterator j = i;
+ do {
+ const Target& candidate = j.value();
+ if (candidate.priority < bestTarget.priority) {
+ bestTarget = candidate;
+ bestTargetList.clear();
+ bestTargetList.append(candidate);
+ numBestTargets = 1;
+ } else if (candidate.priority == bestTarget.priority) {
+ bestTargetList.append(candidate);
+ ++numBestTargets;
+ }
+ ++j;
+ } while (j != priv->targetHash.constEnd() && j.key() == i.key());
+
+ if (numBestTargets == 1) {
+ atom = bestTarget.atom;
+ return bestTarget.node;
+ }
+ else if (bestTargetList.size() > 1) {
+ if (relative && !relative->qmlModuleIdentifier().isEmpty()) {
+ for (int i=0; i<bestTargetList.size(); ++i) {
+ const Node* n = bestTargetList.at(i).node;
+ if (relative->qmlModuleIdentifier() == n->qmlModuleIdentifier()) {
+ atom = bestTargetList.at(i).atom;
+ return n;
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*!
+ This function searches for a node with a canonical title
+ constructed from \a target and each of the possible suffixes.
+ If the node it finds is \a node, it returns the Atom from that
+ node. Otherwise it returns null.
+ */
+Atom* Tree::findTarget(const QString& target, const Node* node) const
+{
+ for (int pass = 0; pass < NumSuffixes; ++pass) {
+ QString key = Doc::canonicalTitle(target + suffixes[pass]);
+ TargetHash::const_iterator i = priv->targetHash.find(key);
+
+ if (i != priv->targetHash.constEnd()) {
+ do {
+ if (i.value().node == node)
+ return i.value().atom;
+ ++i;
+ } while (i != priv->targetHash.constEnd() && i.key() == key);
+ }
+ }
+ return 0;
+}
+
+/*!
+ */
+void Tree::addBaseClass(ClassNode* subclass, Node::Access access,
+ const QStringList& basePath,
+ const QString& dataTypeWithTemplateArgs,
+ InnerNode* parent)
+{
+ priv->unresolvedInheritanceMap[subclass].append(
+ InheritanceBound(access,
+ basePath,
+ dataTypeWithTemplateArgs,
+ parent)
+ );
+}
+
+/*!
+ */
+void Tree::addPropertyFunction(PropertyNode* property,
+ const QString& funcName,
+ PropertyNode::FunctionRole funcRole)
+{
+ priv->unresolvedPropertyMap[property].insert(funcRole, funcName);
+}
+
+/*!
+ This function adds the \a node to the \a group. The group
+ can be listed anywhere using the \e{annotated list} command.
+ */
+void Tree::addToGroup(Node* node, const QString& group)
+{
+ priv->groupMap.insert(group, node);
+}
+
+/*!
+ This function adds the \a node to the QML \a module. The QML
+ module can be listed anywhere using the \e{annotated list}
+ command.
+ */
+void Tree::addToQmlModule(Node* node, const QString& module)
+{
+ priv->qmlModuleMap.insert(module, node);
+}
+
+/*!
+ Returns the group map.
+ */
+NodeMultiMap Tree::groups() const
+{
+ return priv->groupMap;
+}
+
+/*!
+ Returns the QML module map.
+ */
+NodeMultiMap Tree::qmlModules() const
+{
+ return priv->qmlModuleMap;
+}
+
+/*!
+ */
+void Tree::addToPublicGroup(Node* node, const QString& group)
+{
+ priv->publicGroupMap.insert(node->name(), group);
+ addToGroup(node, group);
+}
+
+/*!
+ */
+QMultiMap<QString, QString> Tree::publicGroups() const
+{
+ return priv->publicGroupMap;
+}
+
+/*!
+ */
+void Tree::resolveInheritance(NamespaceNode* rootNode)
+{
+ if (!rootNode)
+ rootNode = root();
+
+ for (int pass = 0; pass < 2; pass++) {
+ NodeList::ConstIterator c = rootNode->childNodes().begin();
+ while (c != rootNode->childNodes().end()) {
+ if ((*c)->type() == Node::Class) {
+ resolveInheritance(pass, (ClassNode*)* c);
+ }
+ else if ((*c)->type() == Node::Namespace) {
+ NamespaceNode* ns = static_cast<NamespaceNode*>(*c);
+ resolveInheritance(ns);
+ }
+ ++c;
+ }
+ if (rootNode == root())
+ priv->unresolvedInheritanceMap.clear();
+ }
+}
+
+/*!
+ */
+void Tree::resolveProperties()
+{
+ PropertyMap::ConstIterator propEntry;
+
+ propEntry = priv->unresolvedPropertyMap.begin();
+ while (propEntry != priv->unresolvedPropertyMap.end()) {
+ PropertyNode* property = propEntry.key();
+ InnerNode* parent = property->parent();
+ QString getterName = (*propEntry)[PropertyNode::Getter];
+ QString setterName = (*propEntry)[PropertyNode::Setter];
+ QString resetterName = (*propEntry)[PropertyNode::Resetter];
+ QString notifierName = (*propEntry)[PropertyNode::Notifier];
+
+ NodeList::ConstIterator c = parent->childNodes().begin();
+ while (c != parent->childNodes().end()) {
+ if ((*c)->type() == Node::Function) {
+ FunctionNode* function = static_cast<FunctionNode*>(*c);
+ if (function->access() == property->access() &&
+ (function->status() == property->status() ||
+ function->doc().isEmpty())) {
+ if (function->name() == getterName) {
+ property->addFunction(function, PropertyNode::Getter);
+ }
+ else if (function->name() == setterName) {
+ property->addFunction(function, PropertyNode::Setter);
+ }
+ else if (function->name() == resetterName) {
+ property->addFunction(function, PropertyNode::Resetter);
+ }
+ else if (function->name() == notifierName) {
+ property->addSignal(function, PropertyNode::Notifier);
+ }
+ }
+ }
+ ++c;
+ }
+ ++propEntry;
+ }
+
+ propEntry = priv->unresolvedPropertyMap.begin();
+ while (propEntry != priv->unresolvedPropertyMap.end()) {
+ PropertyNode* property = propEntry.key();
+ // redo it to set the property functions
+ if (property->overriddenFrom())
+ property->setOverriddenFrom(property->overriddenFrom());
+ ++propEntry;
+ }
+
+ priv->unresolvedPropertyMap.clear();
+}
+
+/*!
+ */
+void Tree::resolveInheritance(int pass, ClassNode* classe)
+{
+ if (pass == 0) {
+ QList<InheritanceBound> bounds = priv->unresolvedInheritanceMap[classe];
+ QList<InheritanceBound>::ConstIterator b = bounds.begin();
+ while (b != bounds.end()) {
+ ClassNode* baseClass = (ClassNode*)findNode((*b).basePath,
+ Node::Class);
+ if (!baseClass && (*b).parent) {
+ baseClass = (ClassNode*)findNode((*b).basePath,
+ Node::Class,
+ (*b).parent);
+ }
+ if (baseClass) {
+ classe->addBaseClass((*b).access,
+ baseClass,
+ (*b).dataTypeWithTemplateArgs);
+ }
+ ++b;
+ }
+ }
+ else {
+ NodeList::ConstIterator c = classe->childNodes().begin();
+ while (c != classe->childNodes().end()) {
+ if ((*c)->type() == Node::Function) {
+ FunctionNode* func = (FunctionNode*)* c;
+ FunctionNode* from = findVirtualFunctionInBaseClasses(classe, func);
+ if (from != 0) {
+ if (func->virtualness() == FunctionNode::NonVirtual)
+ func->setVirtualness(FunctionNode::ImpureVirtual);
+ func->setReimplementedFrom(from);
+ }
+ }
+ else if ((*c)->type() == Node::Property) {
+ fixPropertyUsingBaseClasses(classe, static_cast<PropertyNode*>(*c));
+ }
+ ++c;
+ }
+ }
+}
+
+/*!
+ For each node in the group map, add the node to the appropriate
+ group node.
+ */
+void Tree::resolveGroups()
+{
+ NodeMultiMap::const_iterator i;
+ for (i = priv->groupMap.constBegin(); i != priv->groupMap.constEnd(); ++i) {
+ if (i.value()->access() == Node::Private)
+ continue;
+
+ FakeNode* fake =
+ static_cast<FakeNode*>(findNode(QStringList(i.key()),Node::Fake));
+ if (fake && fake->subType() == Node::Group) {
+ fake->addGroupMember(i.value());
+ }
+ }
+}
+
+/*!
+ For each node in the QML module map, add the node to the
+ appropriate QML module node.
+ */
+void Tree::resolveQmlModules()
+{
+ NodeMultiMap::const_iterator i;
+ for (i = priv->qmlModuleMap.constBegin(); i != priv->qmlModuleMap.constEnd(); ++i) {
+ FakeNode* fake =
+ static_cast<FakeNode*>(findNode(QStringList(i.key()),Node::Fake));
+ if (fake && fake->subType() == Node::QmlModule) {
+ fake->addQmlModuleMember(i.value());
+ }
+ }
+}
+
+/*!
+ */
+void Tree::resolveTargets(InnerNode* root)
+{
+ // need recursion
+
+ foreach (Node* child, root->childNodes()) {
+ if (child->type() == Node::Fake) {
+ FakeNode* node = static_cast<FakeNode*>(child);
+ if (!node->title().isEmpty())
+ priv->fakeNodesByTitle.insert(Doc::canonicalTitle(node->title()), node);
+ if (node->subType() == Node::Collision) {
+ resolveTargets(node);
+ }
+ }
+
+ if (child->doc().hasTableOfContents()) {
+ const QList<Atom*>& toc = child->doc().tableOfContents();
+ Target target;
+ target.node = child;
+ target.priority = 3;
+
+ for (int i = 0; i < toc.size(); ++i) {
+ target.atom = toc.at(i);
+ QString title = Text::sectionHeading(target.atom).toString();
+ if (!title.isEmpty())
+ priv->targetHash.insert(Doc::canonicalTitle(title), target);
+ }
+ }
+ if (child->doc().hasKeywords()) {
+ const QList<Atom*>& keywords = child->doc().keywords();
+ Target target;
+ target.node = child;
+ target.priority = 1;
+
+ for (int i = 0; i < keywords.size(); ++i) {
+ target.atom = keywords.at(i);
+ priv->targetHash.insert(Doc::canonicalTitle(target.atom->string()), target);
+ }
+ }
+ if (child->doc().hasTargets()) {
+ const QList<Atom*>& toc = child->doc().targets();
+ Target target;
+ target.node = child;
+ target.priority = 2;
+
+ for (int i = 0; i < toc.size(); ++i) {
+ target.atom = toc.at(i);
+ priv->targetHash.insert(Doc::canonicalTitle(target.atom->string()), target);
+ }
+ }
+ }
+}
+
+/*!
+ For each QML class node that points to a C++ class node,
+ follow its C++ class node pointer and set the C++ class
+ node's QML class node pointer back to the QML class node.
+ */
+void Tree::resolveCppToQmlLinks()
+{
+
+ foreach (Node* child, roo.childNodes()) {
+ if (child->type() == Node::Fake && child->subType() == Node::QmlClass) {
+ QmlClassNode* qcn = static_cast<QmlClassNode*>(child);
+ ClassNode* cn = const_cast<ClassNode*>(qcn->classNode());
+ if (cn)
+ cn->setQmlElement(qcn);
+ }
+ }
+}
+
+/*!
+ For each QML class node in the tree, determine whether
+ it inherits a QML base class and, if so, which one, and
+ store that pointer in the QML class node's state.
+ */
+void Tree::resolveQmlInheritance()
+{
+
+ foreach (Node* child, roo.childNodes()) {
+ if (child->type() == Node::Fake) {
+ if (child->subType() == Node::QmlClass) {
+ QmlClassNode* qcn = static_cast<QmlClassNode*>(child);
+ qcn->resolveInheritance(this);
+ }
+ else if (child->subType() == Node::Collision) {
+ NameCollisionNode* ncn = static_cast<NameCollisionNode*>(child);
+ foreach (Node* child, ncn->childNodes()) {
+ if (child->type() == Node::Fake) {
+ if (child->subType() == Node::QmlClass) {
+ QmlClassNode* qcn = static_cast<QmlClassNode*>(child);
+ qcn->resolveInheritance(this);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/*!
+ */
+void Tree::fixInheritance(NamespaceNode* rootNode)
+{
+ if (!rootNode)
+ rootNode = root();
+
+ NodeList::ConstIterator c = rootNode->childNodes().begin();
+ while (c != rootNode->childNodes().end()) {
+ if ((*c)->type() == Node::Class)
+ static_cast<ClassNode*>(*c)->fixBaseClasses();
+ else if ((*c)->type() == Node::Namespace) {
+ NamespaceNode* ns = static_cast<NamespaceNode*>(*c);
+ fixInheritance(ns);
+ }
+ ++c;
+ }
+}
+
+/*!
+ */
+FunctionNode* Tree::findVirtualFunctionInBaseClasses(ClassNode* classe,
+ FunctionNode* clone)
+{
+ QList<RelatedClass>::ConstIterator r = classe->baseClasses().begin();
+ while (r != classe->baseClasses().end()) {
+ FunctionNode* func;
+ if (((func = findVirtualFunctionInBaseClasses((*r).node, clone)) != 0 ||
+ (func = (*r).node->findFunctionNode(clone)) != 0)) {
+ if (func->virtualness() != FunctionNode::NonVirtual)
+ return func;
+ }
+ ++r;
+ }
+ return 0;
+}
+
+/*!
+ */
+void Tree::fixPropertyUsingBaseClasses(ClassNode* classe,
+ PropertyNode* property)
+{
+ QList<RelatedClass>::const_iterator r = classe->baseClasses().begin();
+ while (r != classe->baseClasses().end()) {
+ PropertyNode* baseProperty =
+ static_cast<PropertyNode*>(r->node->findNode(property->name(),
+ Node::Property));
+ if (baseProperty) {
+ fixPropertyUsingBaseClasses(r->node, baseProperty);
+ property->setOverriddenFrom(baseProperty);
+ }
+ else {
+ fixPropertyUsingBaseClasses(r->node, property);
+ }
+ ++r;
+ }
+}
+
+/*!
+ */
+NodeList Tree::allBaseClasses(const ClassNode* classe) const
+{
+ NodeList result;
+ foreach (const RelatedClass& r, classe->baseClasses()) {
+ result += r.node;
+ result += allBaseClasses(r.node);
+ }
+ return result;
+}
+
+/*!
+ */
+void Tree::readIndexes(const QStringList& indexFiles)
+{
+ foreach (const QString& indexFile, indexFiles)
+ readIndexFile(indexFile);
+}
+
+/*!
+ Read the QDomDocument at \a path and get the index from it.
+ */
+void Tree::readIndexFile(const QString& path)
+{
+ QFile file(path);
+ if (file.open(QFile::ReadOnly)) {
+ QDomDocument document;
+ document.setContent(&file);
+ file.close();
+
+ QDomElement indexElement = document.documentElement();
+ QString indexUrl = indexElement.attribute("url", "");
+ priv->basesList.clear();
+ priv->relatedList.clear();
+
+ // Scan all elements in the XML file, constructing a map that contains
+ // base classes for each class found.
+
+ QDomElement child = indexElement.firstChildElement();
+ while (!child.isNull()) {
+ readIndexSection(child, root(), indexUrl);
+ child = child.nextSiblingElement();
+ }
+
+ // Now that all the base classes have been found for this index,
+ // arrange them into an inheritance hierarchy.
+
+ resolveIndex();
+ }
+}
+
+/*!
+ */
+void Tree::readIndexSection(const QDomElement& element,
+ InnerNode* parent,
+ const QString& indexUrl)
+{
+ QString name = element.attribute("name");
+ QString href = element.attribute("href");
+
+ Node* section;
+ Location location;
+
+ if (element.nodeName() == "namespace") {
+ section = new NamespaceNode(parent, name);
+
+ if (!indexUrl.isEmpty())
+ location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html");
+ else if (!indexUrl.isNull())
+ location = Location(name.toLower() + ".html");
+
+ }
+ else if (element.nodeName() == "class") {
+ section = new ClassNode(parent, name);
+ priv->basesList.append(QPair<ClassNode*,QString>(
+ static_cast<ClassNode*>(section), element.attribute("bases")));
+
+ if (!indexUrl.isEmpty())
+ location = Location(indexUrl + QLatin1Char('/') + name.toLower() + ".html");
+ else if (!indexUrl.isNull())
+ location = Location(name.toLower() + ".html");
+
+ }
+ else if ((element.nodeName() == "qmlclass") ||
+ ((element.nodeName() == "page") && (element.attribute("subtype") == "qmlclass"))) {
+ QmlClassNode* qcn = new QmlClassNode(parent, name, 0);
+ qcn->setTitle(element.attribute("title"));
+ if (element.hasAttribute("location"))
+ name = element.attribute("location", "");
+ if (!indexUrl.isEmpty())
+ location = Location(indexUrl + QLatin1Char('/') + name);
+ else if (!indexUrl.isNull())
+ location = Location(name);
+ section = qcn;
+ }
+ else if (element.nodeName() == "qmlbasictype") {
+ QmlBasicTypeNode* qbtn = new QmlBasicTypeNode(parent, name);
+ qbtn->setTitle(element.attribute("title"));
+ if (element.hasAttribute("location"))
+ name = element.attribute("location", "");
+ if (!indexUrl.isEmpty())
+ location = Location(indexUrl + QLatin1Char('/') + name);
+ else if (!indexUrl.isNull())
+ location = Location(name);
+ section = qbtn;
+ }
+ else if (element.nodeName() == "page") {
+ Node::SubType subtype;
+ Node::PageType ptype = Node::NoPageType;
+ if (element.attribute("subtype") == "example") {
+ subtype = Node::Example;
+ ptype = Node::ExamplePage;
+ }
+ else if (element.attribute("subtype") == "header") {
+ subtype = Node::HeaderFile;
+ ptype = Node::ApiPage;
+ }
+ else if (element.attribute("subtype") == "file") {
+ subtype = Node::File;
+ ptype = Node::NoPageType;
+ }
+ else if (element.attribute("subtype") == "group") {
+ subtype = Node::Group;
+ ptype = Node::OverviewPage;
+ }
+ else if (element.attribute("subtype") == "module") {
+ subtype = Node::Module;
+ ptype = Node::OverviewPage;
+ }
+ else if (element.attribute("subtype") == "page") {
+ subtype = Node::Page;
+ ptype = Node::ArticlePage;
+ }
+ else if (element.attribute("subtype") == "externalpage") {
+ subtype = Node::ExternalPage;
+ ptype = Node::ArticlePage;
+ }
+ else if (element.attribute("subtype") == "qmlclass") {
+ subtype = Node::QmlClass;
+ ptype = Node::ApiPage;
+ }
+ else if (element.attribute("subtype") == "qmlpropertygroup") {
+ subtype = Node::QmlPropertyGroup;
+ ptype = Node::ApiPage;
+ }
+ else if (element.attribute("subtype") == "qmlbasictype") {
+ subtype = Node::QmlBasicType;
+ ptype = Node::ApiPage;
+ }
+ else
+ return;
+
+ FakeNode* fakeNode = new FakeNode(parent, name, subtype, ptype);
+ fakeNode->setTitle(element.attribute("title"));
+
+ if (element.hasAttribute("location"))
+ name = element.attribute("location", "");
+
+ if (!indexUrl.isEmpty())
+ location = Location(indexUrl + QLatin1Char('/') + name);
+ else if (!indexUrl.isNull())
+ location = Location(name);
+
+ section = fakeNode;
+
+ }
+ else if (element.nodeName() == "enum") {
+ EnumNode* enumNode = new EnumNode(parent, name);
+
+ if (!indexUrl.isEmpty())
+ location =
+ Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
+ else if (!indexUrl.isNull())
+ location = Location(parent->name().toLower() + ".html");
+
+ QDomElement child = element.firstChildElement("value");
+ while (!child.isNull()) {
+ EnumItem item(child.attribute("name"), child.attribute("value"));
+ enumNode->addItem(item);
+ child = child.nextSiblingElement("value");
+ }
+
+ section = enumNode;
+
+ } else if (element.nodeName() == "typedef") {
+ section = new TypedefNode(parent, name);
+
+ if (!indexUrl.isEmpty())
+ location =
+ Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
+ else if (!indexUrl.isNull())
+ location = Location(parent->name().toLower() + ".html");
+
+ }
+ else if (element.nodeName() == "property") {
+ section = new PropertyNode(parent, name);
+
+ if (!indexUrl.isEmpty())
+ location =
+ Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
+ else if (!indexUrl.isNull())
+ location = Location(parent->name().toLower() + ".html");
+
+ } else if (element.nodeName() == "function") {
+ FunctionNode::Virtualness virt;
+ if (element.attribute("virtual") == "non")
+ virt = FunctionNode::NonVirtual;
+ else if (element.attribute("virtual") == "impure")
+ virt = FunctionNode::ImpureVirtual;
+ else if (element.attribute("virtual") == "pure")
+ virt = FunctionNode::PureVirtual;
+ else
+ return;
+
+ FunctionNode::Metaness meta;
+ if (element.attribute("meta") == "plain")
+ meta = FunctionNode::Plain;
+ else if (element.attribute("meta") == "signal")
+ meta = FunctionNode::Signal;
+ else if (element.attribute("meta") == "slot")
+ meta = FunctionNode::Slot;
+ else if (element.attribute("meta") == "constructor")
+ meta = FunctionNode::Ctor;
+ else if (element.attribute("meta") == "destructor")
+ meta = FunctionNode::Dtor;
+ else if (element.attribute("meta") == "macro")
+ meta = FunctionNode::MacroWithParams;
+ else if (element.attribute("meta") == "macrowithparams")
+ meta = FunctionNode::MacroWithParams;
+ else if (element.attribute("meta") == "macrowithoutparams")
+ meta = FunctionNode::MacroWithoutParams;
+ else
+ return;
+
+ FunctionNode* functionNode = new FunctionNode(parent, name);
+ functionNode->setReturnType(element.attribute("return"));
+ functionNode->setVirtualness(virt);
+ functionNode->setMetaness(meta);
+ functionNode->setConst(element.attribute("const") == "true");
+ functionNode->setStatic(element.attribute("static") == "true");
+ functionNode->setOverload(element.attribute("overload") == "true");
+
+ if (element.hasAttribute("relates")
+ && element.attribute("relates") != parent->name()) {
+ priv->relatedList.append(
+ QPair<FunctionNode*,QString>(functionNode,
+ element.attribute("relates")));
+ }
+
+ QDomElement child = element.firstChildElement("parameter");
+ while (!child.isNull()) {
+ // Do not use the default value for the parameter; it is not
+ // required, and has been known to cause problems.
+ Parameter parameter(child.attribute("left"),
+ child.attribute("right"),
+ child.attribute("name"),
+ ""); // child.attribute("default")
+ functionNode->addParameter(parameter);
+ child = child.nextSiblingElement("parameter");
+ }
+
+ section = functionNode;
+
+ if (!indexUrl.isEmpty())
+ location =
+ Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
+ else if (!indexUrl.isNull())
+ location = Location(parent->name().toLower() + ".html");
+
+ }
+ else if (element.nodeName() == "variable") {
+ section = new VariableNode(parent, name);
+
+ if (!indexUrl.isEmpty())
+ location = Location(indexUrl + QLatin1Char('/') + parent->name().toLower() + ".html");
+ else if (!indexUrl.isNull())
+ location = Location(parent->name().toLower() + ".html");
+
+ }
+ else if (element.nodeName() == "keyword") {
+ Target target;
+ target.node = parent;
+ target.priority = 1;
+ target.atom = new Atom(Atom::Target, name);
+ priv->targetHash.insert(name, target);
+ return;
+
+ }
+ else if (element.nodeName() == "target") {
+ Target target;
+ target.node = parent;
+ target.priority = 2;
+ target.atom = new Atom(Atom::Target, name);
+ priv->targetHash.insert(name, target);
+ return;
+
+ }
+ else if (element.nodeName() == "contents") {
+ Target target;
+ target.node = parent;
+ target.priority = 3;
+ target.atom = new Atom(Atom::Target, name);
+ priv->targetHash.insert(name, target);
+ return;
+
+ }
+ else
+ return;
+
+ QString access = element.attribute("access");
+ if (access == "public")
+ section->setAccess(Node::Public);
+ else if (access == "protected")
+ section->setAccess(Node::Protected);
+ else if (access == "private")
+ section->setAccess(Node::Private);
+ else
+ section->setAccess(Node::Public);
+
+ if ((element.nodeName() != "page") &&
+ (element.nodeName() != "qmlclass") &&
+ (element.nodeName() != "qmlbasictype")) {
+ QString threadSafety = element.attribute("threadsafety");
+ if (threadSafety == "non-reentrant")
+ section->setThreadSafeness(Node::NonReentrant);
+ else if (threadSafety == "reentrant")
+ section->setThreadSafeness(Node::Reentrant);
+ else if (threadSafety == "thread safe")
+ section->setThreadSafeness(Node::ThreadSafe);
+ else
+ section->setThreadSafeness(Node::UnspecifiedSafeness);
+ }
+ else
+ section->setThreadSafeness(Node::UnspecifiedSafeness);
+
+ QString status = element.attribute("status");
+ if (status == "compat")
+ section->setStatus(Node::Compat);
+ else if (status == "obsolete")
+ section->setStatus(Node::Obsolete);
+ else if (status == "deprecated")
+ section->setStatus(Node::Deprecated);
+ else if (status == "preliminary")
+ section->setStatus(Node::Preliminary);
+ else if (status == "commendable")
+ section->setStatus(Node::Commendable);
+ else if (status == "internal")
+ section->setStatus(Node::Internal);
+ else if (status == "main")
+ section->setStatus(Node::Main);
+ else
+ section->setStatus(Node::Commendable);
+
+ section->setModuleName(element.attribute("module"));
+ if (!indexUrl.isEmpty()) {
+ if (indexUrl.startsWith(QLatin1Char('.')))
+ section->setUrl(href);
+ else
+ section->setUrl(indexUrl + QLatin1Char('/') + href);
+ }
+
+ // Create some content for the node.
+ QSet<QString> emptySet;
+
+ Doc doc(location, location, " ", emptySet); // placeholder
+ section->setDoc(doc);
+
+ if (section->isInnerNode()) {
+ InnerNode* inner = static_cast<InnerNode*>(section);
+ if (inner) {
+ QDomElement child = element.firstChildElement();
+
+ while (!child.isNull()) {
+ if (element.nodeName() == "class")
+ readIndexSection(child, inner, indexUrl);
+ else if (element.nodeName() == "qmlclass")
+ readIndexSection(child, inner, indexUrl);
+ else if (element.nodeName() == "page")
+ readIndexSection(child, inner, indexUrl);
+ else if (element.nodeName() == "namespace" && !name.isEmpty())
+ // The root node in the index is a namespace with an empty name.
+ readIndexSection(child, inner, indexUrl);
+ else
+ readIndexSection(child, parent, indexUrl);
+
+ child = child.nextSiblingElement();
+ }
+ }
+ }
+}
+
+/*!
+ */
+QString Tree::readIndexText(const QDomElement& element)
+{
+ QString text;
+ QDomNode child = element.firstChild();
+ while (!child.isNull()) {
+ if (child.isText())
+ text += child.toText().nodeValue();
+ child = child.nextSibling();
+ }
+ return text;
+}
+
+/*!
+ */
+void Tree::resolveIndex()
+{
+ QPair<ClassNode*,QString> pair;
+
+ foreach (pair, priv->basesList) {
+ foreach (const QString& base, pair.second.split(QLatin1Char(','))) {
+ Node* baseClass = root()->findNode(base, Node::Class);
+ if (baseClass) {
+ pair.first->addBaseClass(Node::Public,
+ static_cast<ClassNode*>(baseClass));
+ }
+ }
+ }
+
+ QPair<FunctionNode*,QString> relatedPair;
+
+ foreach (relatedPair, priv->relatedList) {
+ Node* classNode = root()->findNode(relatedPair.second, Node::Class);
+ if (classNode)
+ relatedPair.first->setRelates(static_cast<ClassNode*>(classNode));
+ }
+}
+
+/*!
+ Generate the index section with the given \a writer for the \a node
+ specified, returning true if an element was written; otherwise returns
+ false.
+ */
+bool Tree::generateIndexSection(QXmlStreamWriter& writer,
+ const Node* node,
+ bool generateInternalNodes) const
+{
+ if (!node->url().isEmpty())
+ return false;
+
+ QString nodeName;
+ switch (node->type()) {
+ case Node::Namespace:
+ nodeName = "namespace";
+ break;
+ case Node::Class:
+ nodeName = "class";
+ break;
+ case Node::Fake:
+ nodeName = "page";
+ if (node->subType() == Node::QmlClass)
+ nodeName = "qmlclass";
+ else if (node->subType() == Node::QmlBasicType)
+ nodeName = "qmlbasictype";
+ break;
+ case Node::Enum:
+ nodeName = "enum";
+ break;
+ case Node::Typedef:
+ nodeName = "typedef";
+ break;
+ case Node::Property:
+ nodeName = "property";
+ break;
+ case Node::Function:
+ nodeName = "function";
+ break;
+ case Node::Variable:
+ nodeName = "variable";
+ break;
+ case Node::Target:
+ nodeName = "target";
+ break;
+ case Node::QmlProperty:
+ nodeName = "qmlproperty";
+ break;
+ case Node::QmlSignal:
+ nodeName = "qmlsignal";
+ break;
+ case Node::QmlSignalHandler:
+ nodeName = "qmlsignalhandler";
+ break;
+ case Node::QmlMethod:
+ nodeName = "qmlmethod";
+ break;
+ default:
+ return false;
+ }
+
+ QString access;
+ switch (node->access()) {
+ case Node::Public:
+ access = "public";
+ break;
+ case Node::Protected:
+ access = "protected";
+ break;
+ case Node::Private:
+ // Do not include private non-internal nodes in the index.
+ // (Internal public and protected nodes are marked as private
+ // by qdoc. We can check their internal status to determine
+ // whether they were really private to begin with.)
+ if (node->status() == Node::Internal && generateInternalNodes)
+ access = "internal";
+ else
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ QString objName = node->name();
+
+ // Special case: only the root node should have an empty name.
+ if (objName.isEmpty() && node != root())
+ return false;
+
+ writer.writeStartElement(nodeName);
+
+ QXmlStreamAttributes attributes;
+ writer.writeAttribute("access", access);
+
+ if (node->type() != Node::Fake) {
+ QString threadSafety;
+ switch (node->threadSafeness()) {
+ case Node::NonReentrant:
+ threadSafety = "non-reentrant";
+ break;
+ case Node::Reentrant:
+ threadSafety = "reentrant";
+ break;
+ case Node::ThreadSafe:
+ threadSafety = "thread safe";
+ break;
+ case Node::UnspecifiedSafeness:
+ default:
+ threadSafety = "unspecified";
+ break;
+ }
+ writer.writeAttribute("threadsafety", threadSafety);
+ }
+
+ QString status;
+ switch (node->status()) {
+ case Node::Compat:
+ status = "compat";
+ break;
+ case Node::Obsolete:
+ status = "obsolete";
+ break;
+ case Node::Deprecated:
+ status = "deprecated";
+ break;
+ case Node::Preliminary:
+ status = "preliminary";
+ break;
+ case Node::Commendable:
+ status = "commendable";
+ break;
+ case Node::Internal:
+ status = "internal";
+ break;
+ case Node::Main:
+ default:
+ status = "main";
+ break;
+ }
+ writer.writeAttribute("status", status);
+
+ writer.writeAttribute("name", objName);
+ QString fullName = node->fullDocumentName();
+ if (fullName != objName)
+ writer.writeAttribute("fullname", fullName);
+ QString href = node->outputSubdirectory();
+ if (!href.isEmpty())
+ href.append(QLatin1Char('/'));
+ href.append(HtmlGenerator::fullDocumentLocation(node));
+ writer.writeAttribute("href", href);
+ if ((node->type() != Node::Fake) && (!node->isQmlNode()))
+ writer.writeAttribute("location", node->location().fileName());
+
+ switch (node->type()) {
+
+ case Node::Class:
+ {
+ // Classes contain information about their base classes.
+
+ const ClassNode* classNode = static_cast<const ClassNode*>(node);
+ QList<RelatedClass> bases = classNode->baseClasses();
+ QSet<QString> baseStrings;
+ foreach (const RelatedClass& related, bases) {
+ ClassNode* baseClassNode = related.node;
+ baseStrings.insert(baseClassNode->name());
+ }
+ writer.writeAttribute("bases", QStringList(baseStrings.toList()).join(","));
+ writer.writeAttribute("module", node->moduleName());
+ }
+ break;
+
+ case Node::Namespace:
+ writer.writeAttribute("module", node->moduleName());
+ break;
+
+ case Node::Fake:
+ {
+ /*
+ Fake nodes (such as manual pages) contain subtypes,
+ titles and other attributes.
+ */
+
+ const FakeNode* fakeNode = static_cast<const FakeNode*>(node);
+ switch (fakeNode->subType()) {
+ case Node::Example:
+ writer.writeAttribute("subtype", "example");
+ break;
+ case Node::HeaderFile:
+ writer.writeAttribute("subtype", "header");
+ break;
+ case Node::File:
+ writer.writeAttribute("subtype", "file");
+ break;
+ case Node::Group:
+ writer.writeAttribute("subtype", "group");
+ break;
+ case Node::Module:
+ writer.writeAttribute("subtype", "module");
+ break;
+ case Node::Page:
+ writer.writeAttribute("subtype", "page");
+ break;
+ case Node::ExternalPage:
+ writer.writeAttribute("subtype", "externalpage");
+ break;
+ case Node::QmlClass:
+ //writer.writeAttribute("subtype", "qmlclass");
+ break;
+ case Node::QmlBasicType:
+ //writer.writeAttribute("subtype", "qmlbasictype");
+ break;
+ default:
+ break;
+ }
+ writer.writeAttribute("title", fakeNode->title());
+ writer.writeAttribute("fulltitle", fakeNode->fullTitle());
+ writer.writeAttribute("subtitle", fakeNode->subTitle());
+ writer.writeAttribute("location", fakeNode->doc().location().fileName());
+ }
+ break;
+
+ case Node::Function:
+ {
+ /*
+ Function nodes contain information about the type of
+ function being described.
+ */
+
+ const FunctionNode* functionNode =
+ static_cast<const FunctionNode*>(node);
+
+ switch (functionNode->virtualness()) {
+ case FunctionNode::NonVirtual:
+ writer.writeAttribute("virtual", "non");
+ break;
+ case FunctionNode::ImpureVirtual:
+ writer.writeAttribute("virtual", "impure");
+ break;
+ case FunctionNode::PureVirtual:
+ writer.writeAttribute("virtual", "pure");
+ break;
+ default:
+ break;
+ }
+ switch (functionNode->metaness()) {
+ case FunctionNode::Plain:
+ writer.writeAttribute("meta", "plain");
+ break;
+ case FunctionNode::Signal:
+ writer.writeAttribute("meta", "signal");
+ break;
+ case FunctionNode::Slot:
+ writer.writeAttribute("meta", "slot");
+ break;
+ case FunctionNode::Ctor:
+ writer.writeAttribute("meta", "constructor");
+ break;
+ case FunctionNode::Dtor:
+ writer.writeAttribute("meta", "destructor");
+ break;
+ case FunctionNode::MacroWithParams:
+ writer.writeAttribute("meta", "macrowithparams");
+ break;
+ case FunctionNode::MacroWithoutParams:
+ writer.writeAttribute("meta", "macrowithoutparams");
+ break;
+ default:
+ break;
+ }
+ writer.writeAttribute("const", functionNode->isConst()?"true":"false");
+ writer.writeAttribute("static", functionNode->isStatic()?"true":"false");
+ writer.writeAttribute("overload", functionNode->isOverload()?"true":"false");
+ if (functionNode->isOverload())
+ writer.writeAttribute("overload-number", QString::number(functionNode->overloadNumber()));
+ if (functionNode->relates())
+ writer.writeAttribute("relates", functionNode->relates()->name());
+ const PropertyNode* propertyNode = functionNode->associatedProperty();
+ if (propertyNode)
+ writer.writeAttribute("associated-property", propertyNode->name());
+ writer.writeAttribute("type", functionNode->returnType());
+ }
+ break;
+
+ case Node::QmlProperty:
+ {
+ const QmlPropertyNode* qpn = static_cast<const QmlPropertyNode*>(node);
+ writer.writeAttribute("type", qpn->dataType());
+ writer.writeAttribute("attached", qpn->isAttached() ? "true" : "false");
+ writer.writeAttribute("writable", qpn->isWritable(this) ? "true" : "false");
+ }
+ break;
+ case Node::Property:
+ {
+ const PropertyNode* propertyNode = static_cast<const PropertyNode*>(node);
+ writer.writeAttribute("type", propertyNode->dataType());
+ foreach (const Node* fnNode, propertyNode->getters()) {
+ if (fnNode) {
+ const FunctionNode* functionNode = static_cast<const FunctionNode*>(fnNode);
+ writer.writeStartElement("getter");
+ writer.writeAttribute("name", functionNode->name());
+ writer.writeEndElement(); // getter
+ }
+ }
+ foreach (const Node* fnNode, propertyNode->setters()) {
+ if (fnNode) {
+ const FunctionNode* functionNode = static_cast<const FunctionNode*>(fnNode);
+ writer.writeStartElement("setter");
+ writer.writeAttribute("name", functionNode->name());
+ writer.writeEndElement(); // getter
+ }
+ }
+ foreach (const Node* fnNode, propertyNode->resetters()) {
+ if (fnNode) {
+ const FunctionNode* functionNode = static_cast<const FunctionNode*>(fnNode);
+ writer.writeStartElement("resetter");
+ writer.writeAttribute("name", functionNode->name());
+ writer.writeEndElement(); // getter
+ }
+ }
+ }
+ break;
+
+ case Node::Variable:
+ {
+ const VariableNode* variableNode =
+ static_cast<const VariableNode*>(node);
+ writer.writeAttribute("type", variableNode->dataType());
+ writer.writeAttribute("static",
+ variableNode->isStatic() ? "true" : "false");
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Inner nodes and function nodes contain child nodes of some sort, either
+ // actual child nodes or function parameters. For these, we close the
+ // opening tag, create child elements, then add a closing tag for the
+ // element. Elements for all other nodes are closed in the opening tag.
+
+ if (node->isInnerNode()) {
+
+ const InnerNode* inner = static_cast<const InnerNode*>(node);
+
+ // For internal pages, we canonicalize the target, keyword and content
+ // item names so that they can be used by qdoc for other sets of
+ // documentation.
+ // The reason we do this here is that we don't want to ruin
+ // externally composed indexes, containing non-qdoc-style target names
+ // when reading in indexes.
+
+ if (inner->doc().hasTargets()) {
+ bool external = false;
+ if (inner->type() == Node::Fake) {
+ const FakeNode* fakeNode = static_cast<const FakeNode*>(inner);
+ if (fakeNode->subType() == Node::ExternalPage)
+ external = true;
+ }
+
+ foreach (const Atom* target, inner->doc().targets()) {
+ QString targetName = target->string();
+ if (!external)
+ targetName = Doc::canonicalTitle(targetName);
+
+ writer.writeStartElement("target");
+ writer.writeAttribute("name", targetName);
+ writer.writeEndElement(); // target
+ }
+ }
+ if (inner->doc().hasKeywords()) {
+ foreach (const Atom* keyword, inner->doc().keywords()) {
+ writer.writeStartElement("keyword");
+ writer.writeAttribute("name",
+ Doc::canonicalTitle(keyword->string()));
+ writer.writeEndElement(); // keyword
+ }
+ }
+ if (inner->doc().hasTableOfContents()) {
+ for (int i = 0; i < inner->doc().tableOfContents().size(); ++i) {
+ Atom* item = inner->doc().tableOfContents()[i];
+ int level = inner->doc().tableOfContentsLevels()[i];
+
+ QString title = Text::sectionHeading(item).toString();
+ writer.writeStartElement("contents");
+ writer.writeAttribute("name", Doc::canonicalTitle(title));
+ writer.writeAttribute("title", title);
+ writer.writeAttribute("level", QString::number(level));
+ writer.writeEndElement(); // contents
+ }
+ }
+
+ }
+ else if (node->type() == Node::Function) {
+
+ const FunctionNode* functionNode = static_cast<const FunctionNode*>(node);
+ // Write a signature attribute for convenience.
+ QStringList signatureList;
+ QStringList resolvedParameters;
+
+ foreach (const Parameter& parameter, functionNode->parameters()) {
+ QString leftType = parameter.leftType();
+ const Node* leftNode =
+ const_cast<Tree*>(this)->findNode(parameter.leftType().split("::"),
+ Node::Typedef, 0, SearchBaseClasses|NonFunction);
+ if (!leftNode) {
+ leftNode = const_cast<Tree*>(this)->findNode(
+ parameter.leftType().split("::"), Node::Typedef,
+ node->parent(), SearchBaseClasses|NonFunction);
+ }
+ if (leftNode) {
+ if (leftNode->type() == Node::Typedef) {
+ const TypedefNode* typedefNode =
+ static_cast<const TypedefNode*>(leftNode);
+ if (typedefNode->associatedEnum()) {
+ leftType = "QFlags<" +
+ typedefNode->associatedEnum()->fullDocumentName() +
+ QLatin1Char('>');
+ }
+ }
+ else
+ leftType = leftNode->fullDocumentName();
+ }
+ resolvedParameters.append(leftType);
+ signatureList.append(leftType + QLatin1Char(' ') + parameter.name());
+ }
+
+ QString signature = functionNode->name()+QLatin1Char('(')+signatureList.join(", ")+QLatin1Char(')');
+ if (functionNode->isConst())
+ signature += " const";
+ writer.writeAttribute("signature", signature);
+
+ for (int i = 0; i < functionNode->parameters().size(); ++i) {
+ Parameter parameter = functionNode->parameters()[i];
+ writer.writeStartElement("parameter");
+ writer.writeAttribute("left", resolvedParameters[i]);
+ writer.writeAttribute("right", parameter.rightType());
+ writer.writeAttribute("name", parameter.name());
+ writer.writeAttribute("default", parameter.defaultValue());
+ writer.writeEndElement(); // parameter
+ }
+
+ }
+ else if (node->type() == Node::Enum) {
+
+ const EnumNode* enumNode = static_cast<const EnumNode*>(node);
+ if (enumNode->flagsType()) {
+ writer.writeAttribute("typedef",enumNode->flagsType()->fullDocumentName());
+ }
+ foreach (const EnumItem& item, enumNode->items()) {
+ writer.writeStartElement("value");
+ writer.writeAttribute("name", item.name());
+ writer.writeAttribute("value", item.value());
+ writer.writeEndElement(); // value
+ }
+
+ }
+ else if (node->type() == Node::Typedef) {
+
+ const TypedefNode* typedefNode = static_cast<const TypedefNode*>(node);
+ if (typedefNode->associatedEnum()) {
+ writer.writeAttribute("enum",typedefNode->associatedEnum()->fullDocumentName());
+ }
+ }
+
+ return true;
+}
+
+
+/*!
+ Returns true if the node \a n1 is less than node \a n2.
+ The comparison is performed by comparing properties of the nodes in order
+ of increasing complexity.
+*/
+bool compareNodes(const Node* n1, const Node* n2)
+{
+ // Private nodes can occur in any order since they won't normally be
+ // written to the index.
+ if (n1->access() == Node::Private && n2->access() == Node::Private)
+ return true;
+
+ if (n1->location().filePath() < n2->location().filePath())
+ return true;
+ else if (n1->location().filePath() > n2->location().filePath())
+ return false;
+
+ if (n1->type() < n2->type())
+ return true;
+ else if (n1->type() > n2->type())
+ return false;
+
+ if (n1->name() < n2->name())
+ return true;
+ else if (n1->name() > n2->name())
+ return false;
+
+ if (n1->access() < n2->access())
+ return true;
+ else if (n1->access() > n2->access())
+ return false;
+
+ if (n1->type() == Node::Function && n2->type() == Node::Function) {
+ const FunctionNode* f1 = static_cast<const FunctionNode*>(n1);
+ const FunctionNode* f2 = static_cast<const FunctionNode*>(n2);
+
+ if (f1->isConst() < f2->isConst())
+ return true;
+ else if (f1->isConst() > f2->isConst())
+ return false;
+
+ if (f1->signature() < f2->signature())
+ return true;
+ else if (f1->signature() > f2->signature())
+ return false;
+ }
+
+ if (n1->type() == Node::Fake && n2->type() == Node::Fake) {
+ const FakeNode* f1 = static_cast<const FakeNode*>(n1);
+ const FakeNode* f2 = static_cast<const FakeNode*>(n2);
+ if (f1->fullTitle() < f2->fullTitle())
+ return true;
+ else if (f1->fullTitle() > f2->fullTitle())
+ return false;
+ }
+
+ return false;
+}
+
+/*!
+ Generate index sections for the child nodes of the given \a node
+ using the \a writer specified. If \a generateInternalNodes is true,
+ nodes marked as internal will be included in the index; otherwise,
+ they will be omitted.
+*/
+void Tree::generateIndexSections(QXmlStreamWriter& writer,
+ const Node* node,
+ bool generateInternalNodes) const
+{
+ if (generateIndexSection(writer, node, generateInternalNodes)) {
+
+ if (node->isInnerNode()) {
+ const InnerNode* inner = static_cast<const InnerNode*>(node);
+
+ NodeList cnodes = inner->childNodes();
+ qSort(cnodes.begin(), cnodes.end(), compareNodes);
+
+ foreach (const Node* child, cnodes) {
+ /*
+ Don't generate anything for a QML property group node.
+ It is just a place holder for a collection of QML property
+ nodes. Recurse to its children, which are the QML property
+ nodes.
+ */
+ if (child->subType() == Node::QmlPropertyGroup) {
+ const InnerNode* pgn = static_cast<const InnerNode*>(child);
+ foreach (const Node* c, pgn->childNodes()) {
+ generateIndexSections(writer, c, generateInternalNodes);
+ }
+ }
+ else
+ generateIndexSections(writer, child, generateInternalNodes);
+ }
+
+ /*
+ foreach (const Node* child, inner->relatedNodes()) {
+ QDomElement childElement = generateIndexSections(document, child);
+ element.appendChild(childElement);
+ }
+*/
+ }
+ writer.writeEndElement();
+ }
+}
+
+/*!
+ Outputs an index file.
+ */
+void Tree::generateIndex(const QString& fileName,
+ const QString& url,
+ const QString& title,
+ bool generateInternalNodes) const
+{
+ QFile file(fileName);
+ if (!file.open(QFile::WriteOnly | QFile::Text))
+ return ;
+
+ QXmlStreamWriter writer(&file);
+ writer.setAutoFormatting(true);
+ writer.writeStartDocument();
+ writer.writeDTD("<!DOCTYPE QDOCINDEX>");
+
+ writer.writeStartElement("INDEX");
+ writer.writeAttribute("url", url);
+ writer.writeAttribute("title", title);
+ writer.writeAttribute("version", version());
+
+ generateIndexSections(writer, root(), generateInternalNodes);
+
+ writer.writeEndElement(); // INDEX
+ writer.writeEndElement(); // QDOCINDEX
+ writer.writeEndDocument();
+ file.close();
+}
+
+/*!
+ Generate the tag file section with the given \a writer for the \a node
+ specified, returning true if an element was written; otherwise returns
+ false.
+ */
+void Tree::generateTagFileCompounds(QXmlStreamWriter& writer,
+ const InnerNode* inner) const
+{
+ foreach (const Node* node, inner->childNodes()) {
+
+ if (!node->url().isEmpty())
+ continue;
+
+ QString kind;
+ switch (node->type()) {
+ case Node::Namespace:
+ kind = "namespace";
+ break;
+ case Node::Class:
+ kind = "class";
+ break;
+ case Node::Enum:
+ case Node::Typedef:
+ case Node::Property:
+ case Node::Function:
+ case Node::Variable:
+ case Node::Target:
+ default:
+ continue;
+ }
+
+ QString access;
+ switch (node->access()) {
+ case Node::Public:
+ access = "public";
+ break;
+ case Node::Protected:
+ access = "protected";
+ break;
+ case Node::Private:
+ default:
+ continue;
+ }
+
+ QString objName = node->name();
+
+ // Special case: only the root node should have an empty name.
+ if (objName.isEmpty() && node != root())
+ continue;
+
+ // *** Write the starting tag for the element here. ***
+ writer.writeStartElement("compound");
+ writer.writeAttribute("kind", kind);
+
+ if (node->type() == Node::Class) {
+ writer.writeTextElement("name", node->fullDocumentName());
+ writer.writeTextElement("filename", HtmlGenerator::fullDocumentLocation(node,true));
+
+ // Classes contain information about their base classes.
+ const ClassNode* classNode = static_cast<const ClassNode*>(node);
+ QList<RelatedClass> bases = classNode->baseClasses();
+ foreach (const RelatedClass& related, bases) {
+ ClassNode* baseClassNode = related.node;
+ writer.writeTextElement("base", baseClassNode->name());
+ }
+
+ // Recurse to write all members.
+ generateTagFileMembers(writer, static_cast<const InnerNode*>(node));
+ writer.writeEndElement();
+
+ // Recurse to write all compounds.
+ generateTagFileCompounds(writer, static_cast<const InnerNode*>(node));
+ } else {
+ writer.writeTextElement("name", node->fullDocumentName());
+ writer.writeTextElement("filename", HtmlGenerator::fullDocumentLocation(node,true));
+
+ // Recurse to write all members.
+ generateTagFileMembers(writer, static_cast<const InnerNode*>(node));
+ writer.writeEndElement();
+
+ // Recurse to write all compounds.
+ generateTagFileCompounds(writer, static_cast<const InnerNode*>(node));
+ }
+ }
+}
+
+/*!
+ */
+void Tree::generateTagFileMembers(QXmlStreamWriter& writer,
+ const InnerNode* inner) const
+{
+ foreach (const Node* node, inner->childNodes()) {
+
+ if (!node->url().isEmpty())
+ continue;
+
+ QString nodeName;
+ QString kind;
+ switch (node->type()) {
+ case Node::Enum:
+ nodeName = "member";
+ kind = "enum";
+ break;
+ case Node::Typedef:
+ nodeName = "member";
+ kind = "typedef";
+ break;
+ case Node::Property:
+ nodeName = "member";
+ kind = "property";
+ break;
+ case Node::Function:
+ nodeName = "member";
+ kind = "function";
+ break;
+ case Node::Namespace:
+ nodeName = "namespace";
+ break;
+ case Node::Class:
+ nodeName = "class";
+ break;
+ case Node::Variable:
+ case Node::Target:
+ default:
+ continue;
+ }
+
+ QString access;
+ switch (node->access()) {
+ case Node::Public:
+ access = "public";
+ break;
+ case Node::Protected:
+ access = "protected";
+ break;
+ case Node::Private:
+ default:
+ continue;
+ }
+
+ QString objName = node->name();
+
+ // Special case: only the root node should have an empty name.
+ if (objName.isEmpty() && node != root())
+ continue;
+
+ // *** Write the starting tag for the element here. ***
+ writer.writeStartElement(nodeName);
+ if (!kind.isEmpty())
+ writer.writeAttribute("kind", kind);
+
+ switch (node->type()) {
+
+ case Node::Class:
+ writer.writeCharacters(node->fullDocumentName());
+ writer.writeEndElement();
+ break;
+ case Node::Namespace:
+ writer.writeCharacters(node->fullDocumentName());
+ writer.writeEndElement();
+ break;
+ case Node::Function:
+ {
+ /*
+ Function nodes contain information about
+ the type of function being described.
+ */
+
+ const FunctionNode* functionNode =
+ static_cast<const FunctionNode*>(node);
+ writer.writeAttribute("protection", access);
+
+ switch (functionNode->virtualness()) {
+ case FunctionNode::NonVirtual:
+ writer.writeAttribute("virtualness", "non");
+ break;
+ case FunctionNode::ImpureVirtual:
+ writer.writeAttribute("virtualness", "virtual");
+ break;
+ case FunctionNode::PureVirtual:
+ writer.writeAttribute("virtual", "pure");
+ break;
+ default:
+ break;
+ }
+ writer.writeAttribute("static",
+ functionNode->isStatic() ? "yes" : "no");
+
+ if (functionNode->virtualness() == FunctionNode::NonVirtual)
+ writer.writeTextElement("type", functionNode->returnType());
+ else
+ writer.writeTextElement("type",
+ "virtual " + functionNode->returnType());
+
+ writer.writeTextElement("name", objName);
+ QStringList pieces = HtmlGenerator::fullDocumentLocation(node,true).split(QLatin1Char('#'));
+ writer.writeTextElement("anchorfile", pieces[0]);
+ writer.writeTextElement("anchor", pieces[1]);
+
+ // Write a signature attribute for convenience.
+ QStringList signatureList;
+
+ foreach (const Parameter& parameter, functionNode->parameters()) {
+ QString leftType = parameter.leftType();
+ const Node* leftNode = const_cast<Tree*>(this)->findNode(parameter.leftType().split("::"),
+ Node::Typedef, 0, SearchBaseClasses|NonFunction);
+ if (!leftNode) {
+ leftNode = const_cast<Tree*>(this)->findNode(
+ parameter.leftType().split("::"), Node::Typedef,
+ node->parent(), SearchBaseClasses|NonFunction);
+ }
+ if (leftNode) {
+ const TypedefNode* typedefNode = static_cast<const TypedefNode*>(leftNode);
+ if (typedefNode->associatedEnum()) {
+ leftType = "QFlags<" +
+ typedefNode->associatedEnum()->fullDocumentName() +
+ QLatin1Char('>');
+ }
+ }
+ signatureList.append(leftType + QLatin1Char(' ') + parameter.name());
+ }
+
+ QString signature = QLatin1Char('(')+signatureList.join(", ")+QLatin1Char(')');
+ if (functionNode->isConst())
+ signature += " const";
+ if (functionNode->virtualness() == FunctionNode::PureVirtual)
+ signature += " = 0";
+ writer.writeTextElement("arglist", signature);
+ }
+ writer.writeEndElement(); // member
+ break;
+
+ case Node::Property:
+ {
+ const PropertyNode* propertyNode = static_cast<const PropertyNode*>(node);
+ writer.writeAttribute("type", propertyNode->dataType());
+ writer.writeTextElement("name", objName);
+ QStringList pieces = HtmlGenerator::fullDocumentLocation(node,true).split(QLatin1Char('#'));
+ writer.writeTextElement("anchorfile", pieces[0]);
+ writer.writeTextElement("anchor", pieces[1]);
+ writer.writeTextElement("arglist", "");
+ }
+ writer.writeEndElement(); // member
+ break;
+
+ case Node::Enum:
+ {
+ const EnumNode* enumNode = static_cast<const EnumNode*>(node);
+ writer.writeTextElement("name", objName);
+ QStringList pieces = HtmlGenerator::fullDocumentLocation(node).split(QLatin1Char('#'));
+ writer.writeTextElement("anchor", pieces[1]);
+ writer.writeTextElement("arglist", "");
+ writer.writeEndElement(); // member
+
+ for (int i = 0; i < enumNode->items().size(); ++i) {
+ EnumItem item = enumNode->items().value(i);
+ writer.writeStartElement("member");
+ writer.writeAttribute("name", item.name());
+ writer.writeTextElement("anchor", pieces[1]);
+ writer.writeTextElement("arglist", "");
+ writer.writeEndElement(); // member
+ }
+ }
+ break;
+
+ case Node::Typedef:
+ {
+ const TypedefNode* typedefNode = static_cast<const TypedefNode*>(node);
+ if (typedefNode->associatedEnum())
+ writer.writeAttribute("type", typedefNode->associatedEnum()->fullDocumentName());
+ else
+ writer.writeAttribute("type", "");
+ writer.writeTextElement("name", objName);
+ QStringList pieces = HtmlGenerator::fullDocumentLocation(node,true).split(QLatin1Char('#'));
+ writer.writeTextElement("anchorfile", pieces[0]);
+ writer.writeTextElement("anchor", pieces[1]);
+ writer.writeTextElement("arglist", "");
+ }
+ writer.writeEndElement(); // member
+ break;
+
+ case Node::Variable:
+ case Node::Target:
+ default:
+ break;
+ }
+ }
+}
+
+/*!
+ */
+void Tree::generateTagFile(const QString& fileName) const
+{
+ QFile file(fileName);
+ if (!file.open(QFile::WriteOnly | QFile::Text))
+ return ;
+
+ QXmlStreamWriter writer(&file);
+ writer.setAutoFormatting(true);
+ writer.writeStartDocument();
+
+ writer.writeStartElement("tagfile");
+
+ generateTagFileCompounds(writer, root());
+
+ writer.writeEndElement(); // tagfile
+ writer.writeEndDocument();
+ file.close();
+}
+
+/*!
+ */
+void Tree::addExternalLink(const QString& url, const Node* relative)
+{
+ FakeNode* fakeNode = new FakeNode(root(), url, Node::ExternalPage, Node::ArticlePage);
+ fakeNode->setAccess(Node::Public);
+
+ // Create some content for the node.
+ QSet<QString> emptySet;
+ Location location(relative->doc().location());
+ Doc doc(location, location, " ", emptySet); // placeholder
+ fakeNode->setDoc(doc);
+}
+
+QT_END_NAMESPACE
diff --git a/src/tools/qdoc/tree.h b/src/tools/qdoc/tree.h
new file mode 100644
index 0000000000..d39babfab0
--- /dev/null
+++ b/src/tools/qdoc/tree.h
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ tree.h
+*/
+
+#ifndef TREE_H
+#define TREE_H
+
+#include "node.h"
+#include <QDomElement>
+#include <QXmlStreamWriter>
+
+QT_BEGIN_NAMESPACE
+
+class QStringList;
+class TreePrivate;
+
+class Tree
+{
+public:
+ enum FindFlag { SearchBaseClasses = 0x1,
+ SearchEnumValues = 0x2,
+ NonFunction = 0x4 };
+
+ Tree();
+ ~Tree();
+
+ Node* findNode(const QStringList &path,
+ Node* relative=0,
+ int findFlags=0,
+ const Node* self=0);
+ Node* findNode(const QStringList &path,
+ Node::Type type,
+ Node* relative = 0,
+ int findFlags = 0);
+ const Node* findNode(const QStringList& path,
+ const Node* start,
+ int findFlags,
+ const Node* self,
+ bool qml) const;
+ QmlClassNode* findQmlClassNode(const QString& module, const QString& name);
+ NameCollisionNode* checkForCollision(const QString& name) const;
+ NameCollisionNode* findCollisionNode(const QString& name) const;
+ FunctionNode *findFunctionNode(const QStringList &path,
+ Node *relative = 0,
+ int findFlags = 0);
+ FunctionNode *findFunctionNode(const QStringList &parentPath,
+ const FunctionNode *clone,
+ Node *relative = 0,
+ int findFlags = 0);
+ void addBaseClass(ClassNode *subclass,
+ Node::Access access,
+ const QStringList &basePath,
+ const QString &dataTypeWithTemplateArgs,
+ InnerNode *parent = 0);
+ void addPropertyFunction(PropertyNode *property,
+ const QString &funcName,
+ PropertyNode::FunctionRole funcRole);
+ void addToGroup(Node *node, const QString &group);
+ void addToPublicGroup(Node *node, const QString &group);
+ void addToQmlModule(Node* node, const QString& module);
+ NodeMultiMap groups() const;
+ NodeMultiMap qmlModules() const;
+ QMultiMap<QString,QString> publicGroups() const;
+ void resolveInheritance(NamespaceNode *rootNode = 0);
+ void resolveProperties();
+ void resolveGroups();
+ void resolveQmlModules();
+ void resolveTargets(InnerNode* root);
+ void resolveCppToQmlLinks();
+ void fixInheritance(NamespaceNode *rootNode = 0);
+ void setVersion(const QString &version) { vers = version; }
+ NamespaceNode *root() { return &roo; }
+
+ QString version() const { return vers; }
+ const Node* findNode(const QStringList &path,
+ const Node* relative = 0,
+ int findFlags = 0,
+ const Node* self=0) const;
+ const Node* findNode(const QStringList &path,
+ Node::Type type, const
+ Node* relative = 0,
+ int findFlags = 0) const;
+ const QmlClassNode* findQmlClassNode(const QString& module, const QString& element) const;
+ const FunctionNode *findFunctionNode(const QStringList &path,
+ const Node *relative = 0,
+ int findFlags = 0) const;
+ const FunctionNode *findFunctionNode(const QStringList &parentPath,
+ const FunctionNode *clone,
+ const Node *relative = 0,
+ int findFlags = 0) const;
+ const FakeNode *findFakeNodeByTitle(const QString &title, const Node* relative = 0) const;
+ const Node *findUnambiguousTarget(const QString &target, Atom *&atom, const Node* relative) const;
+ Atom *findTarget(const QString &target, const Node *node) const;
+ const NamespaceNode *root() const { return &roo; }
+ void readIndexes(const QStringList &indexFiles);
+ bool generateIndexSection(QXmlStreamWriter &writer, const Node *node,
+ bool generateInternalNodes = false) const;
+ void generateIndexSections(QXmlStreamWriter &writer, const Node *node,
+ bool generateInternalNodes = false) const;
+ void generateIndex(const QString &fileName,
+ const QString &url,
+ const QString &title,
+ bool generateInternalNodes = false) const;
+ void generateTagFileCompounds(QXmlStreamWriter &writer,
+ const InnerNode *inner) const;
+ void generateTagFileMembers(QXmlStreamWriter &writer,
+ const InnerNode *inner) const;
+ void generateTagFile(const QString &fileName) const;
+ void addExternalLink(const QString &url, const Node *relative);
+ QString fullDocumentLocation(const Node *node) const;
+ void resolveQmlInheritance();
+
+private:
+ void resolveInheritance(int pass, ClassNode *classe);
+ FunctionNode *findVirtualFunctionInBaseClasses(ClassNode *classe,
+ FunctionNode *clone);
+ void fixPropertyUsingBaseClasses(ClassNode *classe, PropertyNode *property);
+ NodeList allBaseClasses(const ClassNode *classe) const;
+ void readIndexFile(const QString &path);
+ void readIndexSection(const QDomElement &element, InnerNode *parent,
+ const QString &indexUrl);
+ QString readIndexText(const QDomElement &element);
+ void resolveIndex();
+
+private:
+ NamespaceNode roo;
+ QString vers;
+ TreePrivate *priv;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/tools/qdoc/yyindent.cpp b/src/tools/qdoc/yyindent.cpp
new file mode 100644
index 0000000000..3f21ca4177
--- /dev/null
+++ b/src/tools/qdoc/yyindent.cpp
@@ -0,0 +1,1190 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ This file is a self-contained interactive indenter for C++ and Qt
+ Script.
+
+ The general problem of indenting a C++ program is ill posed. On
+ the one hand, an indenter has to analyze programs written in a
+ free-form formal language that is best described in terms of
+ tokens, not characters, not lines. On the other hand, indentation
+ applies to lines and white space characters matter, and otherwise
+ the programs to indent are formally invalid in general, as they
+ are begin edited.
+
+ The approach taken here works line by line. We receive a program
+ consisting of N lines or more, and we want to compute the
+ indentation appropriate for the Nth line. Lines beyond the Nth
+ lines are of no concern to us, so for simplicity we pretend the
+ program has exactly N lines and we call the Nth line the "bottom
+ line". Typically, we have to indent the bottom line when it's
+ still empty, so we concentrate our analysis on the N - 1 lines
+ that precede.
+
+ By inspecting the (N - 1)-th line, the (N - 2)-th line, ...
+ backwards, we determine the kind of the bottom line and indent it
+ accordingly.
+
+ * The bottom line is a comment line. See
+ bottomLineStartsInCComment() and
+ indentWhenBottomLineStartsInCComment().
+ * The bottom line is a continuation line. See isContinuationLine()
+ and indentForContinuationLine().
+ * The bottom line is a standalone line. See
+ indentForStandaloneLine().
+
+ Certain tokens that influence the indentation, notably braces,
+ are looked for in the lines. This is done by simple string
+ comparison, without a real tokenizer. Confusing constructs such
+ as comments and string literals are removed beforehand.
+*/
+
+#include <qregexp.h>
+#include <qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+/* qmake ignore Q_OBJECT */
+
+/*
+ The indenter avoids getting stuck in almost infinite loops by
+ imposing arbitrary limits on the number of lines it analyzes when
+ looking for a construct.
+
+ For example, the indenter never considers more than BigRoof lines
+ backwards when looking for the start of a C-style comment.
+*/
+static const int SmallRoof = 40;
+static const int BigRoof = 400;
+
+/*
+ The indenter supports a few parameters:
+
+ * ppHardwareTabSize is the size of a '\t' in your favorite editor.
+ * ppIndentSize is the size of an indentation, or software tab
+ size.
+ * ppContinuationIndentSize is the extra indent for a continuation
+ line, when there is nothing to align against on the previous
+ line.
+ * ppCommentOffset is the indentation within a C-style comment,
+ when it cannot be picked up.
+*/
+
+static int ppHardwareTabSize = 8;
+static int ppIndentSize = 4;
+static int ppContinuationIndentSize = 8;
+
+static const int ppCommentOffset = 2;
+
+void setTabSize( int size )
+{
+ ppHardwareTabSize = size;
+}
+
+void setIndentSize( int size )
+{
+ ppIndentSize = size;
+ ppContinuationIndentSize = 2 * size;
+}
+
+static QRegExp *literal = 0;
+static QRegExp *label = 0;
+static QRegExp *inlineCComment = 0;
+static QRegExp *braceX = 0;
+static QRegExp *iflikeKeyword = 0;
+
+/*
+ Returns the first non-space character in the string t, or
+ QChar::Null if the string is made only of white space.
+*/
+static QChar firstNonWhiteSpace( const QString& t )
+{
+ int i = 0;
+ while ( i < (int) t.length() ) {
+ if ( !t[i].isSpace() )
+ return t[i];
+ i++;
+ }
+ return QChar::Null;
+}
+
+/*
+ Returns true if string t is made only of white space; otherwise
+ returns false.
+*/
+static bool isOnlyWhiteSpace( const QString& t )
+{
+ return firstNonWhiteSpace( t ).isNull();
+}
+
+/*
+ Assuming string t is a line, returns the column number of a given
+ index. Column numbers and index are identical for strings that don't
+ contain '\t's.
+*/
+int columnForIndex( const QString& t, int index )
+{
+ int col = 0;
+ if ( index > (int) t.length() )
+ index = t.length();
+
+ for ( int i = 0; i < index; i++ ) {
+ if ( t[i] == QChar('\t') ) {
+ col = ( (col / ppHardwareTabSize) + 1 ) * ppHardwareTabSize;
+ } else {
+ col++;
+ }
+ }
+ return col;
+}
+
+/*
+ Returns the indentation size of string t.
+*/
+int indentOfLine( const QString& t )
+{
+ return columnForIndex( t, t.indexOf(firstNonWhiteSpace(t)) );
+}
+
+/*
+ Replaces t[k] by ch, unless t[k] is '\t'. Tab characters are better
+ left alone since they break the "index equals column" rule. No
+ provisions are taken against '\n' or '\r', which shouldn't occur in
+ t anyway.
+*/
+static inline void eraseChar( QString& t, int k, QChar ch )
+{
+ if ( t[k] != '\t' )
+ t[k] = ch;
+}
+
+/*
+ Removes some nefast constructs from a code line and returns the
+ resulting line.
+*/
+static QString trimmedCodeLine( const QString& t )
+{
+ QString trimmed = t;
+ int k;
+
+ /*
+ Replace character and string literals by X's, since they may
+ contain confusing characters (such as '{' and ';'). "Hello!" is
+ replaced by XXXXXXXX. The literals are rigourously of the same
+ length before and after; otherwise, we would break alignment of
+ continuation lines.
+ */
+ k = 0;
+ while ( (k = trimmed.indexOf(*literal, k)) != -1 ) {
+ for ( int i = 0; i < literal->matchedLength(); i++ )
+ eraseChar( trimmed, k + i, 'X' );
+ k += literal->matchedLength();
+ }
+
+ /*
+ Replace inline C-style comments by spaces. Other comments are
+ handled elsewhere.
+ */
+ k = 0;
+ while ( (k = trimmed.indexOf(*inlineCComment, k)) != -1 ) {
+ for ( int i = 0; i < inlineCComment->matchedLength(); i++ )
+ eraseChar( trimmed, k + i, ' ' );
+ k += inlineCComment->matchedLength();
+ }
+
+ /*
+ Replace goto and switch labels by whitespace, but be careful
+ with this case:
+
+ foo1: bar1;
+ bar2;
+ */
+ while ( trimmed.lastIndexOf(':') != -1 && trimmed.indexOf(*label) != -1 ) {
+ QString cap1 = label->cap( 1 );
+ int pos1 = label->pos( 1 );
+ int stop = cap1.length();
+
+ if ( pos1 + stop < (int) trimmed.length() && ppIndentSize < stop )
+ stop = ppIndentSize;
+
+ int i = 0;
+ while ( i < stop ) {
+ eraseChar( trimmed, pos1 + i, ' ' );
+ i++;
+ }
+ while ( i < (int) cap1.length() ) {
+ eraseChar( trimmed, pos1 + i, ';' );
+ i++;
+ }
+ }
+
+ /*
+ Remove C++-style comments.
+ */
+ k = trimmed.indexOf( "//" );
+ if ( k != -1 )
+ trimmed.truncate( k );
+
+ return trimmed;
+}
+
+/*
+ Returns '(' if the last parenthesis is opening, ')' if it is
+ closing, and QChar::Null if there are no parentheses in t.
+*/
+static inline QChar lastParen( const QString& t )
+{
+ int i = t.length();
+ while ( i > 0 ) {
+ i--;
+ if ( t[i] == QChar('(') || t[i] == QChar(')') )
+ return t[i];
+ }
+ return QChar::Null;
+}
+
+/*
+ Returns true if typedIn the same as okayCh or is null; otherwise
+ returns false.
+*/
+static inline bool okay( QChar typedIn, QChar okayCh )
+{
+ return typedIn == QChar::Null || typedIn == okayCh;
+}
+
+/*
+ The "linizer" is a group of functions and variables to iterate
+ through the source code of the program to indent. The program is
+ given as a list of strings, with the bottom line being the line
+ to indent. The actual program might contain extra lines, but
+ those are uninteresting and not passed over to us.
+*/
+
+struct LinizerState
+{
+ QString line;
+ int braceDepth;
+ bool leftBraceFollows;
+
+ QStringList::ConstIterator iter;
+ bool inCComment;
+ bool pendingRightBrace;
+};
+
+static QStringList *yyProgram = 0;
+static LinizerState *yyLinizerState = 0;
+
+// shorthands
+static const QString *yyLine = 0;
+static const int *yyBraceDepth = 0;
+static const bool *yyLeftBraceFollows = 0;
+
+/*
+ Saves and restores the state of the global linizer. This enables
+ backtracking.
+*/
+#define YY_SAVE() \
+ LinizerState savedState = *yyLinizerState
+#define YY_RESTORE() \
+ *yyLinizerState = savedState
+
+/*
+ Advances to the previous line in yyProgram and update yyLine
+ accordingly. yyLine is cleaned from comments and other damageable
+ constructs. Empty lines are skipped.
+*/
+static bool readLine()
+{
+ int k;
+
+ yyLinizerState->leftBraceFollows =
+ ( firstNonWhiteSpace(yyLinizerState->line) == QChar('{') );
+
+ do {
+ if ( yyLinizerState->iter == yyProgram->begin() ) {
+ yyLinizerState->line.clear();
+ return false;
+ }
+
+ --yyLinizerState->iter;
+ yyLinizerState->line = *yyLinizerState->iter;
+
+ yyLinizerState->line = trimmedCodeLine( yyLinizerState->line );
+
+ /*
+ Remove C-style comments that span multiple lines. If the
+ bottom line starts in a C-style comment, we are not aware
+ of that and eventually yyLine will contain a slash-aster.
+
+ Notice that both if's can be executed, since
+ yyLinizerState->inCComment is potentially set to false in
+ the first if. The order of the if's is also important.
+ */
+
+ if ( yyLinizerState->inCComment ) {
+ QString slashAster( "/*" );
+
+ k = yyLinizerState->line.indexOf( slashAster );
+ if ( k == -1 ) {
+ yyLinizerState->line.clear();
+ } else {
+ yyLinizerState->line.truncate( k );
+ yyLinizerState->inCComment = false;
+ }
+ }
+
+ if ( !yyLinizerState->inCComment ) {
+ QString asterSlash( "*/" );
+
+ k = yyLinizerState->line.indexOf( asterSlash );
+ if ( k != -1 ) {
+ for ( int i = 0; i < k + 2; i++ )
+ eraseChar( yyLinizerState->line, i, ' ' );
+ yyLinizerState->inCComment = true;
+ }
+ }
+
+ /*
+ Remove preprocessor directives.
+ */
+ k = 0;
+ while ( k < (int) yyLinizerState->line.length() ) {
+ QChar ch = yyLinizerState->line[k];
+ if ( ch == QChar('#') ) {
+ yyLinizerState->line.clear();
+ } else if ( !ch.isSpace() ) {
+ break;
+ }
+ k++;
+ }
+
+ /*
+ Remove trailing spaces.
+ */
+ k = yyLinizerState->line.length();
+ while ( k > 0 && yyLinizerState->line[k - 1].isSpace() )
+ k--;
+ yyLinizerState->line.truncate( k );
+
+ /*
+ '}' increment the brace depth and '{' decrements it and not
+ the other way around, as we are parsing backwards.
+ */
+ yyLinizerState->braceDepth +=
+ yyLinizerState->line.count( '}' ) -
+ yyLinizerState->line.count( '{' );
+
+ /*
+ We use a dirty trick for
+
+ } else ...
+
+ We don't count the '}' yet, so that it's more or less
+ equivalent to the friendly construct
+
+ }
+ else ...
+ */
+ if ( yyLinizerState->pendingRightBrace )
+ yyLinizerState->braceDepth++;
+ yyLinizerState->pendingRightBrace =
+ ( yyLinizerState->line.indexOf(*braceX) == 0 );
+ if ( yyLinizerState->pendingRightBrace )
+ yyLinizerState->braceDepth--;
+ } while ( yyLinizerState->line.isEmpty() );
+
+ return true;
+}
+
+/*
+ Resets the linizer to its initial state, with yyLine containing the
+ line above the bottom line of the program.
+*/
+static void startLinizer()
+{
+ yyLinizerState->braceDepth = 0;
+ yyLinizerState->inCComment = false;
+ yyLinizerState->pendingRightBrace = false;
+
+ yyLine = &yyLinizerState->line;
+ yyBraceDepth = &yyLinizerState->braceDepth;
+ yyLeftBraceFollows = &yyLinizerState->leftBraceFollows;
+
+ yyLinizerState->iter = yyProgram->end();
+ --yyLinizerState->iter;
+ yyLinizerState->line = *yyLinizerState->iter;
+ readLine();
+}
+
+/*
+ Returns true if the start of the bottom line of yyProgram (and
+ potentially the whole line) is part of a C-style comment;
+ otherwise returns false.
+*/
+static bool bottomLineStartsInCComment()
+{
+ QString slashAster( "/*" );
+ QString asterSlash( "*/" );
+
+ /*
+ We could use the linizer here, but that would slow us down
+ terribly. We are better to trim only the code lines we need.
+ */
+ QStringList::ConstIterator p = yyProgram->end();
+ --p; // skip bottom line
+
+ for ( int i = 0; i < BigRoof; i++ ) {
+ if ( p == yyProgram->begin() )
+ return false;
+ --p;
+
+ if ( (*p).indexOf(slashAster) != -1 || (*p).indexOf(asterSlash) != -1 ) {
+ QString trimmed = trimmedCodeLine( *p );
+
+ if ( trimmed.indexOf(slashAster) != -1 ) {
+ return true;
+ } else if ( trimmed.indexOf(asterSlash) != -1 ) {
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram
+ assuming that it starts in a C-style comment, a condition that is
+ tested elsewhere.
+
+ Essentially, we're trying to align against some text on the
+ previous line.
+*/
+static int indentWhenBottomLineStartsInCComment()
+{
+ int k = yyLine->lastIndexOf( "/*" );
+ if ( k == -1 ) {
+ /*
+ We found a normal text line in a comment. Align the
+ bottom line with the text on this line.
+ */
+ return indentOfLine( *yyLine );
+ } else {
+ /*
+ The C-style comment starts on this line. If there is
+ text on the same line, align with it. Otherwise, align
+ with the slash-aster plus a given offset.
+ */
+ int indent = columnForIndex( *yyLine, k );
+ k += 2;
+ while ( k < (int) yyLine->length() ) {
+ if ( !(*yyLine)[k].isSpace() )
+ return columnForIndex( *yyLine, k );
+ k++;
+ }
+ return indent + ppCommentOffset;
+ }
+}
+
+/*
+ A function called match...() modifies the linizer state. If it
+ returns true, yyLine is the top line of the matched construct;
+ otherwise, the linizer is left in an unknown state.
+
+ A function called is...() keeps the linizer state intact.
+*/
+
+/*
+ Returns true if the current line (and upwards) forms a braceless
+ control statement; otherwise returns false.
+
+ The first line of the following example is a "braceless control
+ statement":
+
+ if ( x )
+ y;
+*/
+static bool matchBracelessControlStatement()
+{
+ int delimDepth = 0;
+
+ if ( yyLine->endsWith("else") )
+ return true;
+
+ if ( !yyLine->endsWith(QLatin1Char(')')) )
+ return false;
+
+ for ( int i = 0; i < SmallRoof; i++ ) {
+ int j = yyLine->length();
+ while ( j > 0 ) {
+ j--;
+ QChar ch = (*yyLine)[j];
+
+ switch ( ch.unicode() ) {
+ case ')':
+ delimDepth++;
+ break;
+ case '(':
+ delimDepth--;
+ if ( delimDepth == 0 ) {
+ if ( yyLine->indexOf(*iflikeKeyword) != -1 ) {
+ /*
+ We have
+
+ if ( x )
+ y
+
+ "if ( x )" is not part of the statement
+ "y".
+ */
+ return true;
+ }
+ }
+ if ( delimDepth == -1 ) {
+ /*
+ We have
+
+ if ( (1 +
+ 2)
+
+ and not
+
+ if ( 1 +
+ 2 )
+ */
+ return false;
+ }
+ break;
+ case '{':
+ case '}':
+ case ';':
+ /*
+ We met a statement separator, but not where we
+ expected it. What follows is probably a weird
+ continuation line. Be careful with ';' in for,
+ though.
+ */
+ if ( ch != QChar(';') || delimDepth == 0 )
+ return false;
+ }
+ }
+
+ if ( !readLine() )
+ break;
+ }
+ return false;
+}
+
+/*
+ Returns true if yyLine is an unfinished line; otherwise returns
+ false.
+
+ In many places we'll use the terms "standalone line", "unfinished
+ line" and "continuation line". The meaning of these should be
+ evident from this code example:
+
+ a = b; // standalone line
+ c = d + // unfinished line
+ e + // unfinished continuation line
+ f + // unfinished continuation line
+ g; // continuation line
+*/
+static bool isUnfinishedLine()
+{
+ bool unf = false;
+
+ YY_SAVE();
+
+ if ( yyLine->isEmpty() )
+ return false;
+
+ QChar lastCh = (*yyLine)[(int) yyLine->length() - 1];
+ if ( QString("{};").indexOf(lastCh) == -1 && !yyLine->endsWith("...") ) {
+ /*
+ It doesn't end with ';' or similar. If it's neither
+ "Q_OBJECT" nor "if ( x )", it must be an unfinished line.
+ */
+ unf = ( yyLine->indexOf("Q_OBJECT") == -1 &&
+ !matchBracelessControlStatement() );
+ } else if ( lastCh == QChar(';') ) {
+ if ( lastParen(*yyLine) == QChar('(') ) {
+ /*
+ Exception:
+
+ for ( int i = 1; i < 10;
+ */
+ unf = true;
+ } else if ( readLine() && yyLine->endsWith(QLatin1Char(';')) &&
+ lastParen(*yyLine) == QChar('(') ) {
+ /*
+ Exception:
+
+ for ( int i = 1;
+ i < 10;
+ */
+ unf = true;
+ }
+ }
+
+ YY_RESTORE();
+ return unf;
+}
+
+/*
+ Returns true if yyLine is a continuation line; otherwise returns
+ false.
+*/
+static bool isContinuationLine()
+{
+ bool cont = false;
+
+ YY_SAVE();
+ if ( readLine() )
+ cont = isUnfinishedLine();
+ YY_RESTORE();
+ return cont;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram,
+ assuming it's a continuation line.
+
+ We're trying to align the continuation line against some parenthesis
+ or other bracked left opened on a previous line, or some interesting
+ operator such as '='.
+*/
+static int indentForContinuationLine()
+{
+ int braceDepth = 0;
+ int delimDepth = 0;
+
+ bool leftBraceFollowed = *yyLeftBraceFollows;
+
+ for ( int i = 0; i < SmallRoof; i++ ) {
+ int hook = -1;
+
+ int j = yyLine->length();
+ while ( j > 0 && hook < 0 ) {
+ j--;
+ QChar ch = (*yyLine)[j];
+
+ switch ( ch.unicode() ) {
+ case ')':
+ case ']':
+ delimDepth++;
+ break;
+ case '}':
+ braceDepth++;
+ break;
+ case '(':
+ case '[':
+ delimDepth--;
+ /*
+ An unclosed delimiter is a good place to align at,
+ at least for some styles (including Qt's).
+ */
+ if ( delimDepth == -1 )
+ hook = j;
+ break;
+ case '{':
+ braceDepth--;
+ /*
+ A left brace followed by other stuff on the same
+ line is typically for an enum or an initializer.
+ Such a brace must be treated just like the other
+ delimiters.
+ */
+ if ( braceDepth == -1 ) {
+ if ( j < (int) yyLine->length() - 1 ) {
+ hook = j;
+ } else {
+ return 0; // shouldn't happen
+ }
+ }
+ break;
+ case '=':
+ /*
+ An equal sign is a very natural alignment hook
+ because it's usually the operator with the lowest
+ precedence in statements it appears in. Case in
+ point:
+
+ int x = 1 +
+ 2;
+
+ However, we have to beware of constructs such as
+ default arguments and explicit enum constant
+ values:
+
+ void foo( int x = 0,
+ int y = 0 );
+
+ And not
+
+ void foo( int x = 0,
+ int y = 0 );
+
+ These constructs are caracterized by a ',' at the
+ end of the unfinished lines or by unbalanced
+ parentheses.
+ */
+ if ( QString("!=<>").indexOf((*yyLine)[j - 1]) == -1 &&
+ (*yyLine)[j + 1] != '=' ) {
+ if ( braceDepth == 0 && delimDepth == 0 &&
+ j < (int) yyLine->length() - 1 &&
+ !yyLine->endsWith(QLatin1Char(',')) &&
+ (yyLine->contains('(') == yyLine->contains(')')) )
+ hook = j;
+ }
+ }
+ }
+
+ if ( hook >= 0 ) {
+ /*
+ Yes, we have a delimiter or an operator to align
+ against! We don't really align against it, but rather
+ against the following token, if any. In this example,
+ the following token is "11":
+
+ int x = ( 11 +
+ 2 );
+
+ If there is no such token, we use a continuation indent:
+
+ static QRegExp foo( QString(
+ "foo foo foo foo foo foo foo foo foo") );
+ */
+ hook++;
+ while ( hook < (int) yyLine->length() ) {
+ if ( !(*yyLine)[hook].isSpace() )
+ return columnForIndex( *yyLine, hook );
+ hook++;
+ }
+ return indentOfLine( *yyLine ) + ppContinuationIndentSize;
+ }
+
+ if ( braceDepth != 0 )
+ break;
+
+ /*
+ The line's delimiters are balanced. It looks like a
+ continuation line or something.
+ */
+ if ( delimDepth == 0 ) {
+ if ( leftBraceFollowed ) {
+ /*
+ We have
+
+ int main()
+ {
+
+ or
+
+ Bar::Bar()
+ : Foo( x )
+ {
+
+ The "{" should be flush left.
+ */
+ if ( !isContinuationLine() )
+ return indentOfLine( *yyLine );
+ } else if ( isContinuationLine() || yyLine->endsWith(QLatin1Char(',')) ) {
+ /*
+ We have
+
+ x = a +
+ b +
+ c;
+
+ or
+
+ int t[] = {
+ 1, 2, 3,
+ 4, 5, 6
+
+ The "c;" should fall right under the "b +", and the
+ "4, 5, 6" right under the "1, 2, 3,".
+ */
+ return indentOfLine( *yyLine );
+ } else {
+ /*
+ We have
+
+ stream << 1 +
+ 2;
+
+ We could, but we don't, try to analyze which
+ operator has precedence over which and so on, to
+ obtain the excellent result
+
+ stream << 1 +
+ 2;
+
+ We do have a special trick above for the assignment
+ operator above, though.
+ */
+ return indentOfLine( *yyLine ) + ppContinuationIndentSize;
+ }
+ }
+
+ if ( !readLine() )
+ break;
+ }
+ return 0;
+}
+
+/*
+ Returns the recommended indent for the bottom line of yyProgram if
+ that line is standalone (or should be indented likewise).
+
+ Indenting a standalone line is tricky, mostly because of braceless
+ control statements. Grossly, we are looking backwards for a special
+ line, a "hook line", that we can use as a starting point to indent,
+ and then modify the indentation level according to the braces met
+ along the way to that hook.
+
+ Let's consider a few examples. In all cases, we want to indent the
+ bottom line.
+
+ Example 1:
+
+ x = 1;
+ y = 2;
+
+ The hook line is "x = 1;". We met 0 opening braces and 0 closing
+ braces. Therefore, "y = 2;" inherits the indent of "x = 1;".
+
+ Example 2:
+
+ if ( x ) {
+ y;
+
+ The hook line is "if ( x ) {". No matter what precedes it, "y;" has
+ to be indented one level deeper than the hook line, since we met one
+ opening brace along the way.
+
+ Example 3:
+
+ if ( a )
+ while ( b ) {
+ c;
+ }
+ d;
+
+ To indent "d;" correctly, we have to go as far as the "if ( a )".
+ Compare with
+
+ if ( a ) {
+ while ( b ) {
+ c;
+ }
+ d;
+
+ Still, we're striving to go back as little as possible to
+ accommodate people with irregular indentation schemes. A hook line
+ near at hand is much more reliable than a remote one.
+*/
+static int indentForStandaloneLine()
+{
+ for ( int i = 0; i < SmallRoof; i++ ) {
+ if ( !*yyLeftBraceFollows ) {
+ YY_SAVE();
+
+ if ( matchBracelessControlStatement() ) {
+ /*
+ The situation is this, and we want to indent "z;":
+
+ if ( x &&
+ y )
+ z;
+
+ yyLine is "if ( x &&".
+ */
+ return indentOfLine( *yyLine ) + ppIndentSize;
+ }
+ YY_RESTORE();
+ }
+
+ if ( yyLine->endsWith(QLatin1Char(';')) || yyLine->contains('{') ) {
+ /*
+ The situation is possibly this, and we want to indent
+ "z;":
+
+ while ( x )
+ y;
+ z;
+
+ We return the indent of "while ( x )". In place of "y;",
+ any arbitrarily complex compound statement can appear.
+ */
+
+ if ( *yyBraceDepth > 0 ) {
+ do {
+ if ( !readLine() )
+ break;
+ } while ( *yyBraceDepth > 0 );
+ }
+
+ LinizerState hookState;
+
+ while ( isContinuationLine() )
+ readLine();
+ hookState = *yyLinizerState;
+
+ readLine();
+ if ( *yyBraceDepth <= 0 ) {
+ do {
+ if ( !matchBracelessControlStatement() )
+ break;
+ hookState = *yyLinizerState;
+ } while ( readLine() );
+ }
+
+ *yyLinizerState = hookState;
+
+ while ( isContinuationLine() )
+ readLine();
+
+ /*
+ Never trust lines containing only '{' or '}', as some
+ people (Richard M. Stallman) format them weirdly.
+ */
+ if ( yyLine->trimmed().length() > 1 )
+ return indentOfLine( *yyLine ) - *yyBraceDepth * ppIndentSize;
+ }
+
+ if ( !readLine() )
+ return -*yyBraceDepth * ppIndentSize;
+ }
+ return 0;
+}
+
+/*
+ Constructs global variables used by the indenter.
+*/
+static void initializeIndenter()
+{
+ literal = new QRegExp( "([\"'])(?:\\\\.|[^\\\\])*\\1" );
+ literal->setMinimal( true );
+ label = new QRegExp(
+ "^\\s*((?:case\\b([^:]|::)+|[a-zA-Z_0-9]+)(?:\\s+slots)?:)(?!:)" );
+ inlineCComment = new QRegExp( "/\\*.*\\*/" );
+ inlineCComment->setMinimal( true );
+ braceX = new QRegExp( "^\\s*\\}\\s*(?:else|catch)\\b" );
+ iflikeKeyword = new QRegExp( "\\b(?:catch|do|for|if|while)\\b" );
+
+ yyLinizerState = new LinizerState;
+}
+
+/*
+ Destroys global variables used by the indenter.
+*/
+static void terminateIndenter()
+{
+ delete literal;
+ delete label;
+ delete inlineCComment;
+ delete braceX;
+ delete iflikeKeyword;
+ delete yyLinizerState;
+}
+
+/*
+ Returns the recommended indent for the bottom line of program.
+ Unless null, typedIn stores the character of yyProgram that
+ triggered reindentation.
+
+ This function works better if typedIn is set properly; it is
+ slightly more conservative if typedIn is completely wild, and
+ slighly more liberal if typedIn is always null. The user might be
+ annoyed by the liberal behavior.
+*/
+int indentForBottomLine( const QStringList& program, QChar typedIn )
+{
+ if ( program.isEmpty() )
+ return 0;
+
+ initializeIndenter();
+
+ yyProgram = new QStringList( program );
+ startLinizer();
+
+ const QString& bottomLine = program.last();
+ QChar firstCh = firstNonWhiteSpace( bottomLine );
+ int indent;
+
+ if ( bottomLineStartsInCComment() ) {
+ /*
+ The bottom line starts in a C-style comment. Indent it
+ smartly, unless the user has already played around with it,
+ in which case it's better to leave her stuff alone.
+ */
+ if ( isOnlyWhiteSpace(bottomLine) ) {
+ indent = indentWhenBottomLineStartsInCComment();
+ } else {
+ indent = indentOfLine( bottomLine );
+ }
+ } else if ( okay(typedIn, '#') && firstCh == QChar('#') ) {
+ /*
+ Preprocessor directives go flush left.
+ */
+ indent = 0;
+ } else {
+ if ( isUnfinishedLine() ) {
+ indent = indentForContinuationLine();
+ } else {
+ indent = indentForStandaloneLine();
+ }
+
+ if ( okay(typedIn, '}') && firstCh == QChar('}') ) {
+ /*
+ A closing brace is one level more to the left than the
+ code it follows.
+ */
+ indent -= ppIndentSize;
+ } else if ( okay(typedIn, ':') ) {
+ QRegExp caseLabel(
+ "\\s*(?:case\\b(?:[^:]|::)+"
+ "|(?:public|protected|private|signals|default)(?:\\s+slots)?\\s*"
+ ")?:.*" );
+
+ if ( caseLabel.exactMatch(bottomLine) ) {
+ /*
+ Move a case label (or the ':' in front of a
+ constructor initialization list) one level to the
+ left, but only if the user did not play around with
+ it yet. Some users have exotic tastes in the
+ matter, and most users probably are not patient
+ enough to wait for the final ':' to format their
+ code properly.
+
+ We don't attempt the same for goto labels, as the
+ user is probably the middle of "foo::bar". (Who
+ uses goto, anyway?)
+ */
+ if ( indentOfLine(bottomLine) <= indent )
+ indent -= ppIndentSize;
+ else
+ indent = indentOfLine( bottomLine );
+ }
+ }
+ }
+ delete yyProgram;
+ terminateIndenter();
+ return qMax( 0, indent );
+}
+
+QT_END_NAMESPACE
+
+#ifdef Q_TEST_YYINDENT
+/*
+ Test driver.
+*/
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <errno.h>
+
+QT_BEGIN_NAMESPACE
+
+static QString fileContents( const QString& fileName )
+{
+ QFile f( fileName );
+ if ( !f.open(QFile::ReadOnly) ) {
+ qWarning( "yyindent error: Cannot open file '%s' for reading: %s",
+ fileName.toLatin1().data(), strerror(errno) );
+ return QString();
+ }
+
+ QTextStream t( &f );
+ QString contents = t.read();
+ f.close();
+ if ( contents.isEmpty() )
+ qWarning( "yyindent error: File '%s' is empty", fileName.toLatin1().data() );
+ return contents;
+}
+
+QT_END_NAMESPACE
+
+int main( int argc, char **argv )
+{
+ QT_USE_NAMESPACE
+
+ if ( argc != 2 ) {
+ qWarning( "usage: yyindent file.cpp" );
+ return 1;
+ }
+
+ QString code = fileContents( argv[1] );
+ QStringList program = QStringList::split( '\n', code, true );
+ QStringList p;
+ QString out;
+
+ while ( !program.isEmpty() && program.last().trimmed().isEmpty() )
+ program.remove( program.fromLast() );
+
+ QStringList::ConstIterator line = program.begin();
+ while ( line != program.end() ) {
+ p.push_back( *line );
+ QChar typedIn = firstNonWhiteSpace( *line );
+ if ( p.last().endsWith(QLatin1Char(':')) )
+ typedIn = ':';
+
+ int indent = indentForBottomLine( p, typedIn );
+
+ if ( !(*line).trimmed().isEmpty() ) {
+ for ( int j = 0; j < indent; j++ )
+ out += QLatin1Char(' ');
+ out += (*line).trimmed();
+ }
+ out += QLatin1Char('\n');
+ ++line;
+ }
+
+ while ( out.endsWith(QLatin1Char('\n')) )
+ out.truncate( out.length() - 1 );
+
+ printf( "%s\n", out.toLatin1().data() );
+ return 0;
+}
+
+#endif // Q_TEST_YYINDENT
diff --git a/src/tools/tools.pro b/src/tools/tools.pro
index 082339cac9..1d12423744 100644
--- a/src/tools/tools.pro
+++ b/src/tools/tools.pro
@@ -1,6 +1,6 @@
TEMPLATE = subdirs
-TOOLS_SUBDIRS = src_tools_bootstrap src_tools_moc src_tools_rcc
+TOOLS_SUBDIRS = src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_qdoc
!contains(QT_CONFIG, no-gui): TOOLS_SUBDIRS += src_tools_uic
# Set subdir and respective target name
src_tools_bootstrap.subdir = $$QT_SOURCE_TREE/src/tools/bootstrap
@@ -11,12 +11,15 @@ src_tools_rcc.subdir = $$QT_SOURCE_TREE/src/tools/rcc
src_tools_rcc.target = sub-rcc
src_tools_uic.subdir = $$QT_SOURCE_TREE/src/tools/uic
src_tools_uic.target = sub-uic
+src_tools_qdoc.subdir = $$QT_SOURCE_TREE/src/tools/qdoc
+src_tools_qdoc.target = sub-qdoc
!wince*:!ordered {
# Set dependencies for each subdir
src_tools_moc.depends = src_tools_bootstrap
src_tools_rcc.depends = src_tools_bootstrap
src_tools_uic.depends = src_tools_bootstrap
+ src_tools_qdoc.depends = src_tools_bootstrap
}
# Special handling, depending on type of project, if it used debug/release or only has one configuration