From 448a3cfe17735499cb43186200e8d52669b6a7ca Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 5 Mar 2012 15:34:40 +0100 Subject: Move qdoc into qtbase and bootstrap it We need qdoc in qtbase to be able to properly modularize our documentation and build it when building the different Qt modules. qdoc does contain a copy of the qml parser from qmldevtools, but this is the lesser evil compared to how we are currently forced to genereate our docs (and the fact that no developer can run qdoc and check the docs for their module). Change-Id: I9f748459382a11cf5d5153d1ee611d7a5d3f4ac1 Reviewed-by: Casper van Donderen Reviewed-by: Martin Smith --- configure | 2 +- src/tools/qdoc/TODO.txt | 87 + src/tools/qdoc/atom.cpp | 387 + src/tools/qdoc/atom.h | 237 + src/tools/qdoc/codechunk.cpp | 150 + src/tools/qdoc/codechunk.h | 123 + src/tools/qdoc/codemarker.cpp | 682 ++ src/tools/qdoc/codemarker.h | 192 + src/tools/qdoc/codeparser.cpp | 409 + src/tools/qdoc/codeparser.h | 107 + src/tools/qdoc/config.cpp | 978 +++ src/tools/qdoc/config.h | 199 + src/tools/qdoc/cppcodemarker.cpp | 1354 +++ src/tools/qdoc/cppcodemarker.h | 96 + src/tools/qdoc/cppcodeparser.cpp | 2502 ++++++ src/tools/qdoc/cppcodeparser.h | 196 + src/tools/qdoc/ditaxmlgenerator.cpp | 6434 ++++++++++++++ src/tools/qdoc/ditaxmlgenerator.h | 543 ++ src/tools/qdoc/doc.cpp | 3393 ++++++++ src/tools/qdoc/doc.h | 198 + src/tools/qdoc/doc/config/compat.qdocconf | 31 + src/tools/qdoc/doc/config/config.pro | 13 + src/tools/qdoc/doc/config/images/arrow_down.png | Bin 0 -> 177 bytes src/tools/qdoc/doc/config/images/bg_l.png | Bin 0 -> 100 bytes src/tools/qdoc/doc/config/images/bg_l_blank.png | Bin 0 -> 84 bytes src/tools/qdoc/doc/config/images/bg_ll_blank.png | Bin 0 -> 320 bytes src/tools/qdoc/doc/config/images/bg_r.png | Bin 0 -> 96 bytes src/tools/qdoc/doc/config/images/bg_ul_blank.png | Bin 0 -> 304 bytes src/tools/qdoc/doc/config/images/box_bg.png | Bin 0 -> 89 bytes src/tools/qdoc/doc/config/images/breadcrumb.png | Bin 0 -> 134 bytes src/tools/qdoc/doc/config/images/bullet_dn.png | Bin 0 -> 230 bytes src/tools/qdoc/doc/config/images/bullet_gt.png | Bin 0 -> 124 bytes src/tools/qdoc/doc/config/images/bullet_sq.png | Bin 0 -> 74 bytes src/tools/qdoc/doc/config/images/bullet_up.png | Bin 0 -> 210 bytes .../qdoc/doc/config/images/feedbackground.png | Bin 0 -> 263 bytes src/tools/qdoc/doc/config/images/header_bg.png | Bin 0 -> 114 bytes src/tools/qdoc/doc/config/images/horBar.png | Bin 0 -> 2807 bytes src/tools/qdoc/doc/config/images/page.png | Bin 0 -> 3102 bytes src/tools/qdoc/doc/config/images/page_bg.png | Bin 0 -> 84 bytes src/tools/qdoc/doc/config/images/spinner.gif | Bin 0 -> 2037 bytes .../qdoc/doc/config/images/sprites-combined.png | Bin 0 -> 62534 bytes src/tools/qdoc/doc/config/macros.qdocconf | 40 + src/tools/qdoc/doc/config/qdoc-online.qdocconf | 2 + src/tools/qdoc/doc/config/qdoc-project.qdocconf | 48 + src/tools/qdoc/doc/config/qdoc.qdocconf | 2 + src/tools/qdoc/doc/config/qt-cpp-ignore.qdocconf | 98 + src/tools/qdoc/doc/config/qt-defines.qdocconf | 17 + .../doc/config/qt-html-default-styles.qdocconf | 32 + .../qdoc/doc/config/qt-html-online-styles.qdocconf | 72 + .../doc/config/qt-html-templates-online.qdocconf | 115 + .../qdoc/doc/config/qt-html-templates.qdocconf | 54 + src/tools/qdoc/doc/config/style/offline.css | 673 ++ src/tools/qdoc/doc/corefeatures.qdoc | 35 + .../qdoc/doc/examples/componentset/ProgressBar.qml | 135 + .../qdoc/doc/examples/componentset/Switch.qml | 142 + .../qdoc/doc/examples/componentset/TabWidget.qml | 183 + .../doc/examples/componentset/componentset.pro | 5 + .../doc/examples/componentset/uicomponents.qdoc | 37 + src/tools/qdoc/doc/examples/examples.qdoc | 84 + .../qdoc/doc/examples/layoutmanagement.qdocinc | 13 + src/tools/qdoc/doc/examples/main.cpp | 54 + src/tools/qdoc/doc/examples/minimum.qdocconf | 42 + src/tools/qdoc/doc/examples/objectmodel.qdocinc | 11 + src/tools/qdoc/doc/examples/samples.qdocinc | 109 + src/tools/qdoc/doc/examples/signalandslots.qdocinc | 9 + src/tools/qdoc/doc/files/compat.qdocconf | 12 + src/tools/qdoc/doc/files/qt.qdocconf | 115 + src/tools/qdoc/doc/images/happy.gif | Bin 0 -> 11526 bytes src/tools/qdoc/doc/images/happyguy.jpg | Bin 0 -> 53442 bytes src/tools/qdoc/doc/images/qt-logo.png | Bin 0 -> 5149 bytes src/tools/qdoc/doc/images/training.jpg | Bin 0 -> 8368 bytes src/tools/qdoc/doc/qdoc-guide.qdoc | 671 ++ src/tools/qdoc/doc/qdoc-manual.qdoc | 8780 ++++++++++++++++++++ src/tools/qdoc/editdistance.cpp | 114 + src/tools/qdoc/editdistance.h | 59 + src/tools/qdoc/generator.cpp | 1495 ++++ src/tools/qdoc/generator.h | 221 + src/tools/qdoc/helpprojectwriter.cpp | 772 ++ src/tools/qdoc/helpprojectwriter.h | 111 + src/tools/qdoc/htmlgenerator.cpp | 5115 ++++++++++++ src/tools/qdoc/htmlgenerator.h | 319 + src/tools/qdoc/jscodemarker.cpp | 148 + src/tools/qdoc/jscodemarker.h | 75 + src/tools/qdoc/location.cpp | 398 + src/tools/qdoc/location.h | 131 + src/tools/qdoc/main.cpp | 481 ++ src/tools/qdoc/node.cpp | 2780 +++++++ src/tools/qdoc/node.h | 958 +++ src/tools/qdoc/openedlist.cpp | 228 + src/tools/qdoc/openedlist.h | 91 + src/tools/qdoc/pagegenerator.cpp | 388 + src/tools/qdoc/pagegenerator.h | 99 + src/tools/qdoc/plaincodemarker.cpp | 137 + src/tools/qdoc/plaincodemarker.h | 79 + src/tools/qdoc/puredocparser.cpp | 63 + src/tools/qdoc/puredocparser.h | 72 + src/tools/qdoc/qdoc.pro | 114 + src/tools/qdoc/qmlcodemarker.cpp | 302 + src/tools/qdoc/qmlcodemarker.h | 86 + src/tools/qdoc/qmlcodeparser.cpp | 291 + src/tools/qdoc/qmlcodeparser.h | 92 + src/tools/qdoc/qmlmarkupvisitor.cpp | 851 ++ src/tools/qdoc/qmlmarkupvisitor.h | 178 + src/tools/qdoc/qmlparser/qmlparser.pri | 19 + src/tools/qdoc/qmlparser/qqmljs.g | 3016 +++++++ src/tools/qdoc/qmlparser/qqmljsast.cpp | 931 +++ src/tools/qdoc/qmlparser/qqmljsast_p.h | 2640 ++++++ src/tools/qdoc/qmlparser/qqmljsastfwd_p.h | 186 + src/tools/qdoc/qmlparser/qqmljsastvisitor.cpp | 58 + src/tools/qdoc/qmlparser/qqmljsastvisitor_p.h | 329 + src/tools/qdoc/qmlparser/qqmljsengine_p.cpp | 161 + src/tools/qdoc/qmlparser/qqmljsengine_p.h | 126 + src/tools/qdoc/qmlparser/qqmljsglobal_p.h | 69 + src/tools/qdoc/qmlparser/qqmljsgrammar.cpp | 1013 +++ src/tools/qdoc/qmlparser/qqmljsgrammar_p.h | 211 + src/tools/qdoc/qmlparser/qqmljskeywords_p.h | 860 ++ src/tools/qdoc/qmlparser/qqmljslexer.cpp | 1171 +++ src/tools/qdoc/qmlparser/qqmljslexer_p.h | 248 + src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h | 173 + src/tools/qdoc/qmlparser/qqmljsparser.cpp | 1817 ++++ src/tools/qdoc/qmlparser/qqmljsparser_p.h | 248 + src/tools/qdoc/qmlvisitor.cpp | 619 ++ src/tools/qdoc/qmlvisitor.h | 122 + src/tools/qdoc/quoter.cpp | 377 + src/tools/qdoc/quoter.h | 93 + src/tools/qdoc/separator.cpp | 77 + src/tools/qdoc/separator.h | 58 + src/tools/qdoc/text.cpp | 287 + src/tools/qdoc/text.h | 106 + src/tools/qdoc/tokenizer.cpp | 771 ++ src/tools/qdoc/tokenizer.h | 182 + src/tools/qdoc/tr.h | 72 + src/tools/qdoc/tree.cpp | 2358 ++++++ src/tools/qdoc/tree.h | 174 + src/tools/qdoc/yyindent.cpp | 1190 +++ src/tools/tools.pro | 5 +- 136 files changed, 65916 insertions(+), 2 deletions(-) create mode 100644 src/tools/qdoc/TODO.txt create mode 100644 src/tools/qdoc/atom.cpp create mode 100644 src/tools/qdoc/atom.h create mode 100644 src/tools/qdoc/codechunk.cpp create mode 100644 src/tools/qdoc/codechunk.h create mode 100644 src/tools/qdoc/codemarker.cpp create mode 100644 src/tools/qdoc/codemarker.h create mode 100644 src/tools/qdoc/codeparser.cpp create mode 100644 src/tools/qdoc/codeparser.h create mode 100644 src/tools/qdoc/config.cpp create mode 100644 src/tools/qdoc/config.h create mode 100644 src/tools/qdoc/cppcodemarker.cpp create mode 100644 src/tools/qdoc/cppcodemarker.h create mode 100644 src/tools/qdoc/cppcodeparser.cpp create mode 100644 src/tools/qdoc/cppcodeparser.h create mode 100644 src/tools/qdoc/ditaxmlgenerator.cpp create mode 100644 src/tools/qdoc/ditaxmlgenerator.h create mode 100644 src/tools/qdoc/doc.cpp create mode 100644 src/tools/qdoc/doc.h create mode 100644 src/tools/qdoc/doc/config/compat.qdocconf create mode 100644 src/tools/qdoc/doc/config/config.pro create mode 100644 src/tools/qdoc/doc/config/images/arrow_down.png create mode 100755 src/tools/qdoc/doc/config/images/bg_l.png create mode 100755 src/tools/qdoc/doc/config/images/bg_l_blank.png create mode 100644 src/tools/qdoc/doc/config/images/bg_ll_blank.png create mode 100755 src/tools/qdoc/doc/config/images/bg_r.png create mode 100644 src/tools/qdoc/doc/config/images/bg_ul_blank.png create mode 100755 src/tools/qdoc/doc/config/images/box_bg.png create mode 100755 src/tools/qdoc/doc/config/images/breadcrumb.png create mode 100644 src/tools/qdoc/doc/config/images/bullet_dn.png create mode 100755 src/tools/qdoc/doc/config/images/bullet_gt.png create mode 100755 src/tools/qdoc/doc/config/images/bullet_sq.png create mode 100644 src/tools/qdoc/doc/config/images/bullet_up.png create mode 100755 src/tools/qdoc/doc/config/images/feedbackground.png create mode 100644 src/tools/qdoc/doc/config/images/header_bg.png create mode 100755 src/tools/qdoc/doc/config/images/horBar.png create mode 100644 src/tools/qdoc/doc/config/images/page.png create mode 100755 src/tools/qdoc/doc/config/images/page_bg.png create mode 100644 src/tools/qdoc/doc/config/images/spinner.gif create mode 100755 src/tools/qdoc/doc/config/images/sprites-combined.png create mode 100644 src/tools/qdoc/doc/config/macros.qdocconf create mode 100644 src/tools/qdoc/doc/config/qdoc-online.qdocconf create mode 100644 src/tools/qdoc/doc/config/qdoc-project.qdocconf create mode 100644 src/tools/qdoc/doc/config/qdoc.qdocconf create mode 100644 src/tools/qdoc/doc/config/qt-cpp-ignore.qdocconf create mode 100644 src/tools/qdoc/doc/config/qt-defines.qdocconf create mode 100644 src/tools/qdoc/doc/config/qt-html-default-styles.qdocconf create mode 100644 src/tools/qdoc/doc/config/qt-html-online-styles.qdocconf create mode 100644 src/tools/qdoc/doc/config/qt-html-templates-online.qdocconf create mode 100644 src/tools/qdoc/doc/config/qt-html-templates.qdocconf create mode 100644 src/tools/qdoc/doc/config/style/offline.css create mode 100644 src/tools/qdoc/doc/corefeatures.qdoc create mode 100644 src/tools/qdoc/doc/examples/componentset/ProgressBar.qml create mode 100644 src/tools/qdoc/doc/examples/componentset/Switch.qml create mode 100644 src/tools/qdoc/doc/examples/componentset/TabWidget.qml create mode 100644 src/tools/qdoc/doc/examples/componentset/componentset.pro create mode 100644 src/tools/qdoc/doc/examples/componentset/uicomponents.qdoc create mode 100644 src/tools/qdoc/doc/examples/examples.qdoc create mode 100644 src/tools/qdoc/doc/examples/layoutmanagement.qdocinc create mode 100644 src/tools/qdoc/doc/examples/main.cpp create mode 100644 src/tools/qdoc/doc/examples/minimum.qdocconf create mode 100644 src/tools/qdoc/doc/examples/objectmodel.qdocinc create mode 100644 src/tools/qdoc/doc/examples/samples.qdocinc create mode 100644 src/tools/qdoc/doc/examples/signalandslots.qdocinc create mode 100644 src/tools/qdoc/doc/files/compat.qdocconf create mode 100644 src/tools/qdoc/doc/files/qt.qdocconf create mode 100644 src/tools/qdoc/doc/images/happy.gif create mode 100644 src/tools/qdoc/doc/images/happyguy.jpg create mode 100644 src/tools/qdoc/doc/images/qt-logo.png create mode 100644 src/tools/qdoc/doc/images/training.jpg create mode 100644 src/tools/qdoc/doc/qdoc-guide.qdoc create mode 100644 src/tools/qdoc/doc/qdoc-manual.qdoc create mode 100644 src/tools/qdoc/editdistance.cpp create mode 100644 src/tools/qdoc/editdistance.h create mode 100644 src/tools/qdoc/generator.cpp create mode 100644 src/tools/qdoc/generator.h create mode 100644 src/tools/qdoc/helpprojectwriter.cpp create mode 100644 src/tools/qdoc/helpprojectwriter.h create mode 100644 src/tools/qdoc/htmlgenerator.cpp create mode 100644 src/tools/qdoc/htmlgenerator.h create mode 100644 src/tools/qdoc/jscodemarker.cpp create mode 100644 src/tools/qdoc/jscodemarker.h create mode 100644 src/tools/qdoc/location.cpp create mode 100644 src/tools/qdoc/location.h create mode 100644 src/tools/qdoc/main.cpp create mode 100644 src/tools/qdoc/node.cpp create mode 100644 src/tools/qdoc/node.h create mode 100644 src/tools/qdoc/openedlist.cpp create mode 100644 src/tools/qdoc/openedlist.h create mode 100644 src/tools/qdoc/pagegenerator.cpp create mode 100644 src/tools/qdoc/pagegenerator.h create mode 100644 src/tools/qdoc/plaincodemarker.cpp create mode 100644 src/tools/qdoc/plaincodemarker.h create mode 100644 src/tools/qdoc/puredocparser.cpp create mode 100644 src/tools/qdoc/puredocparser.h create mode 100644 src/tools/qdoc/qdoc.pro create mode 100644 src/tools/qdoc/qmlcodemarker.cpp create mode 100644 src/tools/qdoc/qmlcodemarker.h create mode 100644 src/tools/qdoc/qmlcodeparser.cpp create mode 100644 src/tools/qdoc/qmlcodeparser.h create mode 100644 src/tools/qdoc/qmlmarkupvisitor.cpp create mode 100644 src/tools/qdoc/qmlmarkupvisitor.h create mode 100644 src/tools/qdoc/qmlparser/qmlparser.pri create mode 100644 src/tools/qdoc/qmlparser/qqmljs.g create mode 100644 src/tools/qdoc/qmlparser/qqmljsast.cpp create mode 100644 src/tools/qdoc/qmlparser/qqmljsast_p.h create mode 100644 src/tools/qdoc/qmlparser/qqmljsastfwd_p.h create mode 100644 src/tools/qdoc/qmlparser/qqmljsastvisitor.cpp create mode 100644 src/tools/qdoc/qmlparser/qqmljsastvisitor_p.h create mode 100644 src/tools/qdoc/qmlparser/qqmljsengine_p.cpp create mode 100644 src/tools/qdoc/qmlparser/qqmljsengine_p.h create mode 100644 src/tools/qdoc/qmlparser/qqmljsglobal_p.h create mode 100644 src/tools/qdoc/qmlparser/qqmljsgrammar.cpp create mode 100644 src/tools/qdoc/qmlparser/qqmljsgrammar_p.h create mode 100644 src/tools/qdoc/qmlparser/qqmljskeywords_p.h create mode 100644 src/tools/qdoc/qmlparser/qqmljslexer.cpp create mode 100644 src/tools/qdoc/qmlparser/qqmljslexer_p.h create mode 100644 src/tools/qdoc/qmlparser/qqmljsmemorypool_p.h create mode 100644 src/tools/qdoc/qmlparser/qqmljsparser.cpp create mode 100644 src/tools/qdoc/qmlparser/qqmljsparser_p.h create mode 100644 src/tools/qdoc/qmlvisitor.cpp create mode 100644 src/tools/qdoc/qmlvisitor.h create mode 100644 src/tools/qdoc/quoter.cpp create mode 100644 src/tools/qdoc/quoter.h create mode 100644 src/tools/qdoc/separator.cpp create mode 100644 src/tools/qdoc/separator.h create mode 100644 src/tools/qdoc/text.cpp create mode 100644 src/tools/qdoc/text.h create mode 100644 src/tools/qdoc/tokenizer.cpp create mode 100644 src/tools/qdoc/tokenizer.h create mode 100644 src/tools/qdoc/tr.h create mode 100644 src/tools/qdoc/tree.cpp create mode 100644 src/tools/qdoc/tree.h create mode 100644 src/tools/qdoc/yyindent.cpp 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

+ * 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 + * 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

...

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 +#include "atom.h" +#include "location.h" +#include + +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 + +#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 +#include + +#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 + +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 + + 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 +#include "codemarker.h" +#include "config.h" +#include "node.h" +#include +#include + +QT_BEGIN_NAMESPACE + +QString CodeMarker::defaultLang; +QList 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::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::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::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::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::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(string.toUInt()); + } + else { + return reinterpret_cast(string.toULongLong()); + } +} + +QString CodeMarker::stringForNode(const Node *node) +{ + if (sizeof(const Node *) == sizeof(ulong)) { + return QString::number(reinterpret_cast(node)); + } + else { + return QString::number(reinterpret_cast(node)); + } +} + +static const QString samp = QLatin1String("&"); +static const QString slt = QLatin1String("<"); +static const QString sgt = QLatin1String(">"); +static const QString squot = QLatin1String("""); + +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(""); + } + pendingWord.clear(); + + switch (ch.unicode()) { + case '\0': + break; + case '&': + result += QLatin1String("&"); + break; + case '<': + result += QLatin1String("<"); + break; + case '>': + result += QLatin1String(">"); + 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("'); +} + +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("'); +} + +QString CodeMarker::linkTag(const Node *node, const QString& body) +{ + return QLatin1String("<@link node=\"") + stringForNode(node) + + QLatin1String("\">") + body + QLatin1String(""); +} + +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(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(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 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 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(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
& 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(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(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 ¶ms = 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(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
CodeMarker::qmlSections(const QmlClassNode* , + SynopsisStyle ) +{ + return QList
(); +} + +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 + +#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 > 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 memberMap; + QMap reimpMemberMap; + QList > 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
sections(const InnerNode *inner, + SynopsisStyle style, + Status status) = 0; + virtual QList
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
& sectionList, const FastSection& fastSection, bool includeKeys = false); + +private: + QString macName(const Node *parent, const QString &name = QString()); + + static QString defaultLang; + static QList 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 + +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::parsers; +bool CodeParser::showInternal = false; +QMap 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::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::ConstIterator p = parsers.begin(); + while (p != parsers.end()) { + (*p)->terminateParser(); + ++p; + } +} + +CodeParser *CodeParser::parserForLanguage(const QString& language) +{ + QList::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::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::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 CodeParser::commonMetaCommands() +{ + return QSet() << 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(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(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(node); + fake->setTitle(arg); + if (fake->subType() == Node::Example) { + ExampleNode::exampleNodeMap.insert(fake->title(),static_cast(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 + +#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 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 parsers; + static bool showInternal; + static QMap 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 +#include +#include +#include +#include +#include +#include "config.h" +#include + +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 +{ +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 Config::overrideOutputFormats; +QMap 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 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 Config::getStringSet(const QString& var) const +{ + return QSet::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::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 subRegExps = getRegExpList(var); + QList::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 Config::getRegExpList(const QString& var) const +{ + QStringList strs = getStringList(var); + QStringList::ConstIterator s = strs.begin(); + QList 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 Config::subVars(const QString& var) const +{ + QSet 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 &excludedDirs, + const QSet &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 &excludedDirs, + const QSet &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 +#include +#include + +#include "location.h" + +QT_BEGIN_NAMESPACE + +typedef QMultiMap 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 getOutputFormats() const; + QString getString(const QString& var) const; + QSet getStringSet(const QString& var) const; + QStringList getStringList(const QString& var) const; + QStringList getCleanPathList(const QString& var) const; + QRegExp getRegExp(const QString& var) const; + QList getRegExpList(const QString& var) const; + QSet subVars(const QString& var) const; + void subVarsAndValues(const QString& var, QStringMultiMap& t) const; + QStringList getAllFiles(const QString& filesVar, + const QString& dirsVar, + const QSet &excludedDirs = QSet(), + const QSet &excludedFiles = QSet()); + + static QStringList getFilesHere(const QString& dir, + const QString& nameFilter, + const QSet &excludedDirs = QSet(), + const QSet &excludedFiles = QSet()); + 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 overrideOutputFormats; + +private: + static bool isMetaKeyChar(QChar ch); + void load(Location location, const QString& fileName); + + QString prog; + Location loc; + Location lastLoc; + QMap locMap; + QMap stringListValueMap; + QMap stringValueMap; + + static QMap uncompressedFiles; + static QMap 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 +#include + +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 + ""; + + 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::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()) + ""; + 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(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(node); + if (typedeff->associatedEnum()) { + synopsis = "flags " + name; + } + else { + synopsis = "typedef " + name; + } + break; + case Node::Property: + property = static_cast(node); + synopsis = name + " : " + typified(property->qualifiedDataType()); + break; + case Node::Variable: + variable = static_cast(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(""); + } + 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(node); + if (pn->isAttached()) + name.prepend(pn->element() + QLatin1Char('.')); + } + name = "<@name>" + name + ""; + QString synopsis = name; + if (node->type() == Node::QmlProperty) { + const QmlPropertyNode* pn = static_cast(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(""); + } + 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>::"); + 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>::"); + node = node->parent(); + } + if (!fullName.isEmpty()) + fullName.append("<@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 <<@headerfile>" + *inc + ">\n"; + ++inc; + } + return code; +} + +QString CppCodeMarker::functionBeginRegExp(const QString& funcName) +{ + return QLatin1Char('^') + QRegExp::escape(funcName) + QLatin1Char('$'); + +} + +QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */) +{ + return "^\\}$"; +} + +QList
CppCodeMarker::sections(const InnerNode *inner, + SynopsisStyle style, + Status status) +{ + QList
sections; + + if (inner->type() == Node::Class) { + const ClassNode *classe = static_cast(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(*r); + if (func->isMacro()) + insert(macros, *r, style, status); + else + insert(relatedNonMembers, *r, style, status); + } + else { + insert(relatedNonMembers, *r, style, status); + } + ++r; + } + + QStack 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(*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::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(*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(*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 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::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(*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); + return new TargetNode(static_cast(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 types; + QMap 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("'); + } + + 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
CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, + SynopsisStyle style) +{ + QList
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(*c); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + while (p != qpgn->childNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + const QmlPropertyNode* pn = static_cast(*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(*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(*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(*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(*c); + if (mn->isAttached()) + insert(qmlattachedmethods,*c,style,Okay); + else + insert(qmlmethods,*c,style,Okay); + } + ++c; + } + if (qcn->qmlBase() != 0) { + qcn = static_cast(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(*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(*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(*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(*c); + if (mn->isAttached()) + insert(qmlattachedmethods,*c,style,Okay); + else + insert(qmlmethods,*c,style,Okay); + } + ++c; + } + if (qcn->qmlBase() != 0) { + qcn = static_cast(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(*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(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
sections(const InnerNode *innerNode, + SynopsisStyle style, + Status status); + virtual QList
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 +#include +#include +#include "codechunk.h" +#include "config.h" +#include "cppcodeparser.h" +#include "tokenizer.h" +#include "tree.h" +#include + +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", "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( + 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 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(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(candidates.first()); + + overloads = candidates; + candidates.clear(); + for (int i = 0; i < overloads.count(); ++i) { + FunctionNode *overload = static_cast(overloads.at(i)); + QList params1 = overload->parameters(); + QList 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(candidates.first()); + + candidates.clear(); + for (int i = 0; i < overloads.count(); ++i) { + FunctionNode *overload = static_cast(overloads.at(i)); + QList params1 = overload->parameters(); + QList 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(candidates.first()); + + return 0; + } + } + delete clone; + } + return func; +} + +/*! + Returns the set of strings reopresenting the topic commands. + */ +QSet CppCodeParser::topicCommands() +{ + return QSet() << 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 params = func->parameters(); + for (int i = 0; i < params.size(); ++i) { + Parameter ¶m = 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(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(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(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... + + :: + :::: + + 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 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... + + ::(, , ...) + ::::(, , ...) + + 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(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 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(tre->findNode(QStringList(arg), + Node::Fake)); + } + else { + QStringList newPath = arg.split("::"); + pseudoParent = + static_cast(tre->findNode(QStringList(newPath), + Node::Class)); + if (!pseudoParent) + pseudoParent = + static_cast(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(node); + qpn->setDefault(); + } + else if (node->type() == Node::Fake && node->subType() == Node::QmlPropertyGroup) { + QmlPropGroupNode* qpgn = static_cast(node); + qpgn->setDefault(); + } + } + else if (command == COMMAND_QMLREADONLY) { + if (node->type() == Node::QmlProperty) { + QmlPropertyNode* qpn = static_cast(node); + qpn->setReadOnly(1); + } + else if (node->type() == Node::Fake && node->subType() == Node::QmlPropertyGroup) { + QmlPropGroupNode* qpgn = static_cast(node); + qpgn->setReadOnly(1); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + while (p != qpgn->childNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + QmlPropertyNode* qpn = static_cast(*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 metaCommands = doc.metaCommandsUsed(); + QSet::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(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(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 topicCommandsAllowed = topicCommands(); + QSet otherMetacommandsAllowed = otherMetaCommands(); + QSet 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 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 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::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(*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 ¯oDef, + 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 + +#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 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 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 ¯oDef, + Tree *tree); + void createExampleFileNodes(FakeNode *fake); + + QMap 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 usedNamespaces; + QMap sequentialIteratorClasses; + QMap mutableSequentialIteratorClasses; + QMap associativeIteratorClasses; + QMap 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 +#include +#include +#include +#include +#include + +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("<","<"); + t = t.replace(">",">"); + t = t.replace("&","&"); + t = t.replace(""","\""); + xmlWriter().writeCharacters(t); +} + +/*! + Appends an 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(); // + } + 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{}. 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{
} + 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(); //

+ } + return ++sectionNestingLevel; +} + +/*! + If the section nesting level is greater than 0, decrement + it. If it becomes 0, output a \c {
}. Return the + decremented section nesting level. + */ +int DitaXmlGenerator::leaveSection() +{ + if (sectionNestingLevel > 0) { + --sectionNestingLevel; + if (sectionNestingLevel == 0) + writeEndTag(); //
or + } + 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 editionNames = config.subVars(CONFIG_EDITION); + QSet::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::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(); // or

+ 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(); // + } + break; + case Atom::Qml: + writeStartTag(DT_codeblock); + xmlWriter().writeAttribute("outputclass","qml"); + writeText(trimmedTrailing(atom->string()), marker, relative); + writeEndTag(); // + break; + case Atom::CodeNew: + writeStartTag(DT_p); + xmlWriter().writeCharacters("you can rewrite it as"); + writeEndTag(); //

+ writeStartTag(DT_codeblock); + writeText(trimmedTrailing(atom->string()), marker, relative); + writeEndTag(); // + break; + case Atom::CodeOld: + writeStartTag(DT_p); + xmlWriter().writeCharacters("For example, if you have code like"); + writeEndTag(); //

+ // fallthrough + case Atom::CodeBad: + writeStartTag(DT_codeblock); + writeCharacters(trimmedTrailing(plainCode(atom->string()))); + writeEndTag(); // + 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(); // , , or

+ if (divNestingLevel > 0) + --divNestingLevel; + } + break; + case Atom::FootnoteLeft: + // ### For now + if (in_para) { + writeEndTag(); //

+ in_para = false; + } + 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(); // + 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 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 groups = tree_->groups(); + foreach (const QString &groupName, editionGroupMap[editionName]) { + QList 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(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
sections; + QList
::ConstIterator s; + for (int i=0; itype()) { + 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(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(); // + + 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(); //

+ 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(); // + xmlWriter().writeCharacters(":"); + writeEndTag(); //

+ + 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(relative); + if (cen->imageFileName().isEmpty()) { + ExampleNode* en = const_cast(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(); // + } + writeEndTag(); // + if (currentTag() != DT_xref) + writeEndTag(); // + } + break; + case Atom::ImageText: + // nothing + break; + case Atom::ImportantLeft: + writeStartTag(DT_note); + xmlWriter().writeAttribute("type","important"); + break; + case Atom::ImportantRight: + writeEndTag(); // + break; + case Atom::NoteLeft: + writeStartTag(DT_note); + xmlWriter().writeAttribute("type","note"); + break; + case Atom::NoteRight: + writeEndTag(); // + 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(); //

+ 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(); // + writeStartTag(DT_stentry); + xmlWriter().writeCharacters("Value"); + writeEndTag(); // + writeStartTag(DT_stentry); + xmlWriter().writeCharacters("Description"); + writeEndTag(); // + writeEndTag(); // + } + else { + writeStartTag(DT_simpletable); + xmlWriter().writeAttribute("outputclass","valuelist"); + writeStartTag(DT_sthead); + writeStartTag(DT_stentry); + xmlWriter().writeCharacters("Constant"); + writeEndTag(); // + writeStartTag(DT_stentry); + xmlWriter().writeCharacters("Value"); + writeEndTag(); // + writeEndTag(); // + } + } + 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(); // + writeEndTag(); // + writeStartTag(DT_stentry); + + QString itemValue; + if (relative->type() == Node::Enum) { + const EnumNode *enume = static_cast(relative); + itemValue = enume->itemValue(atom->next()->string()); + } + + if (itemValue.isEmpty()) + xmlWriter().writeCharacters("?"); + else { + writeStartTag(DT_tt); + writeCharacters(protectEnc(itemValue)); + writeEndTag(); // + } + skipAhead = 1; + } + break; + case Atom::ListTagRight: + if (atom->string() == ATOM_LIST_TAG) + writeEndTag(); // + break; + case Atom::ListItemLeft: + if (atom->string() == ATOM_LIST_TAG) { + writeStartTag(DT_dd); + } + else if (atom->string() == ATOM_LIST_VALUE) { + if (threeColumnEnumValueTable) { + writeEndTag(); // + 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(); // + } + else if (atom->string() == ATOM_LIST_VALUE) { + writeEndTag(); // + writeEndTag(); // + } + else { + writeEndTag(); // + } + break; + case Atom::ListRight: + if (atom->string() == ATOM_LIST_BULLET) { + writeEndTag(); // + } + else if (atom->string() == ATOM_LIST_TAG) { + writeEndTag(); // + } + else if (atom->string() == ATOM_LIST_VALUE) { + writeEndTag(); // + } + else { + writeEndTag(); // + } + 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(); //

+ in_para = false; + } + break; + case Atom::QuotationLeft: + writeStartTag(DT_lq); + break; + case Atom::QuotationRight: + writeEndTag(); // + break; + case Atom::RawString: + if (atom->string() == " ") + break; + if (atom->string().startsWith(QLatin1Char('&'))) + writeCharacters(atom->string()); + else if (atom->string() == "*") { + writeStartTag(DT_sup); + writeCharacters("*"); + writeEndTag(); // + } + else if (atom->string() == "®") { + writeStartTag(DT_tm); + xmlWriter().writeAttribute("tmtype","reg"); + writeEndTag(); // + } + else { + writeStartTag(DT_pre); + xmlWriter().writeAttribute("outputclass","raw-html"); + writeCharacters(atom->string()); + writeEndTag(); // + } + break; + case Atom::SectionLeft: +#if 0 + if (inApiDesc) { + writeEndTag(); // + 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(); // (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(); //

+ 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(); // + writeEndTag(); // + writeEndTag(); // + inTableHeader = false; + inTableBody = false; + tableColumnCount = 0; + break; + case Atom::TableHeaderLeft: + if (inTableBody) { + writeEndTag(); // + writeEndTag(); // + writeEndTag(); // + 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(); // + if (matchAhead(atom, Atom::TableHeaderLeft)) { + skipAhead = 1; + writeStartTag(DT_row); + xmlWriter().writeAttribute("valign","top"); + } + else { + writeEndTag(); // + 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(); // + break; + case Atom::TableItemLeft: + { + QString values; + writeStartTag(DT_entry); + for (int i=0; icount(); ++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(); // + else { + writeEndTag(); // + } + 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(); //

+ in_para = false; + } + writeStartTag(DT_p); + writeGuidAttribute(Doc::canonicalTitle(atom->string())); + xmlWriter().writeAttribute("outputclass","target"); + //xmlWriter().writeCharacters(protectEnc(atom->string())); + writeEndTag(); //

+ break; + case Atom::UnhandledFormat: + writeStartTag(DT_b); + xmlWriter().writeAttribute("outputclass","error"); + xmlWriter().writeCharacters(""); + writeEndTag(); // + break; + case Atom::UnknownCommand: + writeStartTag(DT_b); + xmlWriter().writeAttribute("outputclass","error unknown-command"); + writeCharacters(protectEnc(atom->string())); + writeEndTag(); // + 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 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
::ConstIterator s; + + QString title; + QString rawTitle; + QString fullTitle; + if (inner->type() == Node::Namespace) { + const NamespaceNode* nsn = const_cast(static_cast(inner)); + rawTitle = marker->plainName(inner); + fullTitle = marker->plainFullName(inner); + title = rawTitle + " Namespace"; + + /* + Note: Because the C++ specialization we are using + has no element, we are using the + element with an outputclass attribute + set to "namespace" . + */ + generateHeader(inner, fullTitle); + generateBrief(inner, marker); // + writeProlog(inner); + + writeStartTag(DT_cxxClassDetail); + writeStartTag(DT_cxxClassDefinition); + writeLocation(nsn); + writeEndTag(); // + + enterApiDesc(QString(),title); + Text brief = nsn->doc().briefText(); // zzz + if (!brief.isEmpty()) { + writeStartTag(DT_p); + generateText(brief, nsn, marker); + writeEndTag(); //

+ } + generateIncludes(nsn, marker); + generateStatus(nsn, marker); + generateThreadSafeness(nsn, marker); + generateSince(nsn, marker); + + enterSection("h2","Detailed Description"); + generateBody(nsn, marker); + generateAlsoList(nsn, marker); + leaveSection(); + leaveSection(); // + + bool needOtherSection = false; + QList
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(); // + 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(); // + 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(); // + s = summarySections.begin(); + while (s != summarySections.end()) { + if (s->members.isEmpty()) + generateSectionInheritedList(*s, inner, marker); + ++s; + } + } + leaveSection(); + } + + writeEndTag(); // + + // not included: + // not included: + + QList
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(); // + } + else if (inner->type() == Node::Class) { + const ClassNode* cn = const_cast(static_cast(inner)); + rawTitle = marker->plainName(inner); + fullTitle = marker->plainFullName(inner); + title = rawTitle + " Class"; + + generateHeader(inner, fullTitle); + generateBrief(inner, marker); // + writeProlog(inner); + + writeStartTag(DT_cxxClassDetail); + writeStartTag(DT_cxxClassDefinition); + writeStartTag(DT_cxxClassAccessSpecifier); + xmlWriter().writeAttribute("value",inner->accessString()); + writeEndTag(); // + if (cn->isAbstract()) { + writeStartTag(DT_cxxClassAbstract); + xmlWriter().writeAttribute("name","abstract"); + xmlWriter().writeAttribute("value","abstract"); + writeEndTag(); // + } + writeDerivations(cn, marker); // + + // not included: + + writeLocation(cn); + writeEndTag(); // + + enterApiDesc(QString(),title); + Text brief = cn->doc().briefText(); // zzz + if (!brief.isEmpty()) { + writeStartTag(DT_p); + generateText(brief, cn, marker); + writeEndTag(); //

+ } + 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(); // + + bool needOtherSection = false; + QList
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(); //

+ 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(); //

+ 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(); //

+ s = summarySections.begin(); + while (s != summarySections.end()) { + if (s->members.isEmpty()) + generateSectionInheritedList(*s, inner, marker); + ++s; + } + } + leaveSection(); + } + + // not included: or + + writeEndTag(); // + + // not included: + // not included: + + QList
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(); // + } + else if ((inner->type() == Node::Fake) && (inner->subType() == Node::HeaderFile)) { + const FakeNode* fn = const_cast(static_cast(inner)); + rawTitle = marker->plainName(inner); + fullTitle = marker->plainFullName(inner); + title = rawTitle; + + /* + Note: Because the C++ specialization we are using + has no element, we are using the + element with an outputclass attribute + set to "headerfile" . + */ + generateHeader(inner, fullTitle); + generateBrief(inner, marker); // + 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(); //

+ } + 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(); // + + bool needOtherSection = false; + QList
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(); //

+ 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(); //

+ 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(); //

+ s = summarySections.begin(); + while (s != summarySections.end()) { + if (s->members.isEmpty()) + generateSectionInheritedList(*s, inner, marker); + ++s; + } + } + leaveSection(); + } + + writeEndTag(); // + + // not included: + // not included: + + QList
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(); // + } + else if ((inner->type() == Node::Fake) && (inner->subType() == Node::QmlClass)) { + const QmlClassNode* qcn = const_cast(static_cast(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); // + 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(); //

+ } + 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(); // + + QList
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(); //

+ generateQmlSummary(*s,qcn,marker); + //generateSection(s->members, inner, marker, CodeMarker::Summary); + //generateSectionInheritedList(*s, inner, marker); + } + ++s; + } + leaveSection(); + } + + QList
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(); //

+ NodeList::ConstIterator m = (*s).members.begin(); + while (m != (*s).members.end()) { + generateDetailedQmlMember(*m, qcn, marker); + ++m; + } + } + ++s; + } + leaveSection(); + } + writeEndTag(); // + writeEndTag(); // + } +} + + +/*! + 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(); // + writeEndTag(); // +} + +/*! + 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(fake); + writeDitaMap(dmn); + return; + } + + QList
sections; + QList
::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); // + 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(); //

+ 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(); //
+ writeEndTag(); // + writeRelatedLinks(fake, marker); + writeEndTag(); // +} + +/*! + This function writes a \e{} element inside a + \e{} 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(); // + writeEndTag(); // + } +} + +/*! + This function writes a \e{} 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 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(); // + } +} + +/*! + 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{} + 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 = ""; + } + else if (node->type() == Node::Namespace) { + mainTag = DT_cxxClass; + nameTag = DT_apiName; + dtd = "dtd/cxxClass.dtd"; + version = "0.7.0"; + doctype = ""; + 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 = ""; + outputclass = "headerfile"; + } + else if (node->subType() == Node::QmlClass) { + mainTag = DT_cxxClass; + nameTag = DT_apiName; + dtd = "dtd/cxxClass.dtd"; + version = "0.7.0"; + doctype = ""; + outputclass = "QML-class"; + } + else { + mainTag = DT_topic; + nameTag = DT_title; + dtd = "dtd/topic.dtd"; + doctype = ""; + 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); // or <apiName> + writeCharacters(name); + writeEndTag(); // or +} + +/*! + Outputs the \e brief command as a 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(); // + } +} + +/*! + 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 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 = ""; /* width=\"" + QString::number((100 + numColumns - 1) / numColumns) + "%\">";*/ + out() << "\n" + << 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() << "
    "; + sectionNumber.append("1"); + } while (sectionNumber.size() < nextLevel); + } + else { + while (sectionNumber.size() > nextLevel) { + out() << "
\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() << "" << tdTag << "
    \n"; + columnSize = 0; + } + out() << "
  • "; + out() << ""; + generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); + out() << "
  • \n"; + + ++columnSize; + } + while (!sectionNumber.isEmpty()) { + out() << "
\n"; + sectionNumber.removeLast(); + } + + if (numColumns > 1) + out() << "
\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
* sections) +{ + QList 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() << "
\n"; + out() << "

Contents

\n"; + sectionNumber.append("1"); + out() << "
    \n"; + + if (node->subType() == Node::Module) { + if (moduleNamespaceMap.contains(node->name())) { + out() << "
  • Namespaces
  • \n"; + } + if (moduleClassMap.contains(node->name())) { + out() << "
  • Classes
  • \n"; + } + out() << "
  • Detailed Description
  • \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
    ::ConstIterator s = sections->begin(); + while (s != sections->end()) { + if (!s->members.isEmpty() || !s->reimpMembers.isEmpty()) { + out() << "
  • " << (*s).name + << "
  • \n"; + } + ++s; + } + out() << "
  • Detailed Description
  • \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() << "
  • "; + out() << ""; + generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); + out() << "
  • \n"; + } + while (!sectionNumber.isEmpty()) { + sectionNumber.removeLast(); + } + out() << "
\n"; + out() << "
\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
sections = marker->sections(inner, CodeMarker::Detailed, status); + QMutableListIterator
j(sections); + while (j.hasNext()) { + if (j.next().members.size() == 0) + j.remove(); + } + if (sections.isEmpty()) + return; + + QList
::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& classMap) +{ + if (classMap.isEmpty()) + return; + + NodeMap topLevel; + NodeMap::ConstIterator c = classMap.begin(); + while (c != classMap.end()) { + const ClassNode* classe = static_cast(*c); + if (classe->baseClasses().isEmpty()) + topLevel.insert(classe->name(), classe); + ++c; + } + + QStack stack; + stack.push(topLevel); + + writeStartTag(DT_ul); + while (!stack.isEmpty()) { + if (stack.top().isEmpty()) { + stack.pop(); + writeEndTag(); // + if (!stack.isEmpty()) + writeEndTag(); // + } + else { + const ClassNode *child = + static_cast(*stack.top().begin()); + writeStartTag(DT_li); + generateFullName(child, relative, marker); + writeEndTag(); // + 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(); //

+ writeEndTag(); // + + 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(); //

+ writeEndTag(); // + } + } + else { + writeStartTag(DT_entry); + writeStartTag(DT_p); + writeCharacters(protectEnc(node->doc().briefText().toString())); // zzz + writeEndTag(); //

+ writeEndTag(); // + } + writeEndTag(); // + } + writeEndTag(); // + writeEndTag(); // + writeEndTag(); // +} + +/*! + 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 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 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 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(); // + } + } + writeEndTag(); //

+ } + + /* + Output a

element to contain all the

elements. + */ + writeStartTag(DT_p); + xmlWriter().writeAttribute("outputclass","compactlist"); + + for (int i=0; i. + */ + if (curParOffset == 0) { + if (i > 0) { + writeEndTag(); // + writeEndTag(); //
+ } + 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(); // + } + + /* + Output a
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; isubType() == Node::QmlClass) + pieces << it.value()->name(); + else + pieces = fullName(it.value(), relative, marker).split("::"); + xmlWriter().writeCharacters(protectEnc(pieces.last())); + writeEndTag(); // + if (pieces.size() > 1) { + xmlWriter().writeCharacters(" ("); + generateFullName(it.value()->parent(),relative,marker); + xmlWriter().writeCharacters(")"); + } + } + writeEndTag(); //
+ curParOffset++; + } + writeEndTag(); // + writeEndTag(); // + writeEndTag(); //

+} + +/*! + 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(); // + + } + writeEndTag(); //

+ + char nextLetter = 'a'; + char currentLetter; + + writeStartTag(DT_ul); + QMap::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(); //

+ 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(); // + ++f; + } + writeEndTag(); // +} + +/*! + Write the legalese texts as XML to the current XML stream. + */ +void DitaXmlGenerator::generateLegaleseList(const Node* relative, + CodeMarker* marker) +{ + QMap::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(); // + ++it; + } while (it != legaleseTexts.end() && it.key() == text); + writeEndTag(); // + } +} + +/*! + 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])"), + "\\1\\2"); + marked.replace("<@param>", ""); + marked.replace("", ""); + + marked.replace("<@extra>", ""); + marked.replace("", ""); + + if (summary) { + marked.remove("<@type>"); + marked.remove(""); + } + 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 > fakeNodeMap; + QMap groupTitlesMap; + QMap 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(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(member); + if (page) { + QString sortKey = page->fullTitle().toLower(); + if (sortKey.startsWith("the ")) + sortKey.remove(0, 4); + sortKey.replace(singleDigit, "0\\1"); + fakeNodeMap[const_cast(fakeNode)].insert(sortKey, page); + groupTitlesMap[fakeNode->fullTitle()] = const_cast(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(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(); // + writeEndTag(); //

+ 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(); // + writeEndTag(); // + } + writeEndTag(); // + } + } + + if (!uncategorizedNodeMap.isEmpty()) { + writeStartTag(DT_p); + xmlWriter().writeAttribute("outputclass","h3"); + xmlWriter().writeCharacters("Miscellaneous"); + writeEndTag(); //

+ 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(); // + writeEndTag(); // + } + writeEndTag(); // + } +} + +/*! + 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(); // + } + ++m; + } + writeEndTag(); // + } +} + +/*! + 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 >::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(); // + writeEndTag(); // + ++p; + } + writeEndTag(); // +} + +/*! + 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])"), + " \\1\\2"); +#if 0 + marked.replace("<@param>",""); + marked.replace("",""); +#endif + if (style == CodeMarker::Summary) { + marked.remove("<@name>"); // was "" + marked.remove(""); // was "" + } + + if (style == CodeMarker::Subpage) { + QRegExp extraRegExp("<@extra>.*"); + extraRegExp.setMinimal(true); + marked.remove(extraRegExp); + } +#if 0 + else { + marked.replace("<@extra>",""); + marked.replace("",""); + } +#endif + + if (style != CodeMarker::Detailed) { + marked.remove("<@type>"); + marked.remove(""); + } + 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 "", "<@type>", + "<@headerfile>", "<@headerfile>", + "<@func>", "<@func>", + "<@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=\"([^\"]+)\">).*()" + // replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)()" 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(); // + } + else if (k == 5) { // <@extra> + if (!html.isEmpty()) { + writeCharacters(html); + html.clear(); + } + writeStartTag(DT_tt); + writeCharacters(arg.toString()); + writeEndTag(); // + } + 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(); // + } + else + writeEndTag(); // + inLink = false; + writeCharacters(protectEnc(atom->string().mid(k))); + } + else if (marker->recognizeLanguage("Java")) { + // hack for Java: remove () and use 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(); // + } + 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("&"); + } + else if (ch == QLatin1Char('<')) { + APPEND("<"); + } + else if (ch == QLatin1Char('>')) { + APPEND(">"); + } + else if (ch == QLatin1Char('"')) { + APPEND("""); + } +#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(node); + if (tdn->associatedEnum()) + return guidForNode(tdn->associatedEnum()); + } + return node->guid(); + case Node::Function: + { + const FunctionNode* fn = static_cast(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(node)->subType() == Node::ExternalPage) + return node->name(); + if (static_cast(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(); // +} + +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(*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(*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(*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(*c)); + } + else if ((*c)->type() == Node::Function) { + const FunctionNode* func = static_cast(*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(*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(*c)); + if ((*c)->type() == Node::Namespace) { + const NamespaceNode *nspace = static_cast(*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), relative); + } + } + + if (!node) + relative->doc().location().warning(tr("Cannot link to '%1'").arg(target)); + + return node; +} + +const QPair DitaXmlGenerator::anchorForNode(const Node* node) +{ + QPair anchorPair; + anchorPair.first = PageGenerator::fileName(node); + if (node->type() == Node::Fake) { + const FakeNode *fakeNode = static_cast(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(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(); // + } + else { + if (inObsoleteLink) { + writeStartTag(DT_sup); + xmlWriter().writeCharacters("(obsolete)"); + writeEndTag(); // + } + writeEndTag(); // + } + } + 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(); // + ++m; + } + writeEndTag(); // + } +} + +/*! + 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(node); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + writeStartTag(DT_ul); + while (p != qpgn->childNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + qpn = static_cast(*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(); // + } + ++p; + } + writeEndTag(); // + } + else if (node->type() == Node::QmlProperty) { + qpn = static_cast(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(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(); // + writeEndTag(); // + } + 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(*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(); // + } + ++p; + } + writeEndTag(); // + } + } + else if (node->type() == Node::QmlSignal) { + Node* n = const_cast(node); + writeStartTag(DT_ul); + writeStartTag(DT_li); + writeGuidAttribute(n); + marked = getMarkedUpSynopsis(n, relative, marker, CodeMarker::Detailed); + writeText(marked, marker, relative); + writeEndTag(); // + writeEndTag(); // + } + else if (node->type() == Node::QmlSignalHandler) { + Node* n = const_cast(node); + writeStartTag(DT_ul); + writeStartTag(DT_li); + writeGuidAttribute(n); + marked = getMarkedUpSynopsis(n, relative, marker, CodeMarker::Detailed); + writeText(marked, marker, relative); + writeEndTag(); // + writeEndTag(); // + } + else if (node->type() == Node::QmlMethod) { + Node* n = const_cast(node); + writeStartTag(DT_ul); + writeStartTag(DT_li); + writeGuidAttribute(n); + marked = getMarkedUpSynopsis(n, relative, marker, CodeMarker::Detailed); + writeText(marked, marker, relative); + writeEndTag(); // + writeEndTag(); // + } + 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(); //

+ } +} + +/*! + 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(); //

+ } +} + +/*! + 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(); //

+ } +} + +/*! + 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 element. + \code + + + ... + + ... + + \endcode + + The element is: + + \code + + + Base + + \endcode + */ +void DitaXmlGenerator::writeDerivations(const ClassNode* cn, CodeMarker* marker) +{ + QList::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(); // + + // not included: + + writeStartTag(DT_cxxClassBaseClass); + QString attr = fileName((*r).node) + QLatin1Char('#') + (*r).node->guid(); + xmlWriter().writeAttribute("href",attr); + writeCharacters(marker->plainFullName((*r).node)); + writeEndTag(); // + + // not included: or + + writeEndTag(); // + + // not included: + + ++r; + } + writeEndTag(); // + } +} + +/*! + Writes a 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(static_cast(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(); // + writeStartTag(s3a); + xmlWriter().writeAttribute("name","lineNumber"); + QString lineNr; + xmlWriter().writeAttribute("value",lineNr.setNum(n->location().lineNo())); + writeEndTag(); // + if (s3b != DT_NONE) { + writeStartTag(s3b); + xmlWriter().writeAttribute("name","lineNumber"); + QString lineNr; + xmlWriter().writeAttribute("value",lineNr.setNum(n->location().lineNo())); + writeEndTag(); // + } + writeEndTag(); // ApiItemLocation> +} + +/*! + Write the 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(static_cast(*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(); // + generateBrief(fn,marker); + + // not included: + + writeStartTag(DT_cxxFunctionDetail); + writeStartTag(DT_cxxFunctionDefinition); + writeStartTag(DT_cxxFunctionAccessSpecifier); + xmlWriter().writeAttribute("value",fn->accessString()); + writeEndTag(); // + + // not included: + + if (fn->isStatic()) { + writeStartTag(DT_cxxFunctionStorageClassSpecifierStatic); + xmlWriter().writeAttribute("name","static"); + xmlWriter().writeAttribute("value","static"); + writeEndTag(); // + } + + // not included: , + + if (fn->isConst()) { + writeStartTag(DT_cxxFunctionConst); + xmlWriter().writeAttribute("name","const"); + xmlWriter().writeAttribute("value","const"); + writeEndTag(); // + } + + // not included: + // virtualness() != FunctionNode::NonVirtual) { + writeStartTag(DT_cxxFunctionVirtual); + xmlWriter().writeAttribute("name","virtual"); + xmlWriter().writeAttribute("value","virtual"); + writeEndTag(); // + if (fn->virtualness() == FunctionNode::PureVirtual) { + writeStartTag(DT_cxxFunctionPureVirtual); + xmlWriter().writeAttribute("name","pure virtual"); + xmlWriter().writeAttribute("value","pure virtual"); + writeEndTag(); // + } + } + + if (fn->name() == parent->name()) { + writeStartTag(DT_cxxFunctionConstructor); + xmlWriter().writeAttribute("name","constructor"); + xmlWriter().writeAttribute("value","constructor"); + writeEndTag(); // + } + else if (fn->name()[0] == QChar('~')) { + writeStartTag(DT_cxxFunctionDestructor); + xmlWriter().writeAttribute("name","destructor"); + xmlWriter().writeAttribute("value","destructor"); + writeEndTag(); // + } + else { + writeStartTag(DT_cxxFunctionDeclaredType); + QString src = marker->typified(fn->returnType()); + replaceTypesWithLinks(fn,parent,marker,src); + writeEndTag(); // + } + + // not included: + + QString fq = fullQualification(fn); + if (!fq.isEmpty()) { + writeStartTag(DT_cxxFunctionScopedName); + writeCharacters(fq); + writeEndTag(); // + } + writeStartTag(DT_cxxFunctionPrototype); + writeCharacters(fn->signature(true)); + writeEndTag(); // + + 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(); // + + 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(); // + } + } + writeParameters(fn,parent,marker); + writeLocation(fn); + writeEndTag(); // + + writeApiDesc(fn, marker, QString()); + // generateAlsoList(inner, marker); + + // not included: or + + writeEndTag(); // + writeEndTag(); // + + 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 + 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; iresolveTarget(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 element. + */ +void DitaXmlGenerator::writeParameters(const FunctionNode* fn, + const InnerNode* parent, + CodeMarker* marker) +{ + const QList& parameters = fn->parameters(); + if (!parameters.isEmpty()) { + writeStartTag(DT_cxxFunctionParameters); + QList::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(); // + writeStartTag(DT_cxxFunctionParameterDeclarationName); + writeCharacters((*p).name()); + writeEndTag(); // + + // not included: + + if (!(*p).defaultValue().isEmpty()) { + writeStartTag(DT_cxxFunctionParameterDefaultValue); + writeCharacters((*p).defaultValue()); + writeEndTag(); // + } + + // not included: + + writeEndTag(); // + ++p; + } + writeEndTag(); // + } +} + +/*! + 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(*m); + writeStartTag(DT_cxxEnumeration); + xmlWriter().writeAttribute("id",en->guid()); + if (!attribute.isEmpty()) + xmlWriter().writeAttribute("outputclass",attribute); + writeStartTag(DT_apiName); + writeCharacters(en->name()); + writeEndTag(); // + generateBrief(en,marker); + + // not included + + writeStartTag(DT_cxxEnumerationDetail); + writeStartTag(DT_cxxEnumerationDefinition); + writeStartTag(DT_cxxEnumerationAccessSpecifier); + xmlWriter().writeAttribute("value",en->accessString()); + writeEndTag(); // + + QString fq = fullQualification(en); + if (!fq.isEmpty()) { + writeStartTag(DT_cxxEnumerationScopedName); + writeCharacters(fq); + writeEndTag(); // + } + const QList& items = en->items(); + if (!items.isEmpty()) { + writeStartTag(DT_cxxEnumerationPrototype); + writeCharacters(en->name()); + xmlWriter().writeCharacters(" = { "); + QList::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(); // + } + + writeStartTag(DT_cxxEnumerationNameLookup); + writeCharacters(en->parent()->name() + "::" + en->name()); + writeEndTag(); // + + // not included: + + if (!items.isEmpty()) { + writeStartTag(DT_cxxEnumerators); + QList::ConstIterator i = items.begin(); + while (i != items.end()) { + writeStartTag(DT_cxxEnumerator); + writeStartTag(DT_apiName); + writeCharacters((*i).name()); + writeEndTag(); // + + QString fq = fullQualification(en->parent()); + if (!fq.isEmpty()) { + writeStartTag(DT_cxxEnumeratorScopedName); + writeCharacters(fq + "::" + (*i).name()); + writeEndTag(); // + } + writeStartTag(DT_cxxEnumeratorPrototype); + writeCharacters((*i).name()); + writeEndTag(); // + writeStartTag(DT_cxxEnumeratorNameLookup); + writeCharacters(en->parent()->name() + "::" + (*i).name()); + writeEndTag(); // + + 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(); // + } + + // not included: + + if (!(*i).text().isEmpty()) { + writeStartTag(DT_apiDesc); + generateText((*i).text(), en, marker); + writeEndTag(); // + } + writeEndTag(); // + ++i; + } + writeEndTag(); // + } + + writeLocation(en); + writeEndTag(); // + + writeApiDesc(en, marker, QString()); + + // not included: or + + writeEndTag(); // + + // not included: + + writeEndTag(); // + } + ++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(*m); + writeStartTag(DT_cxxTypedef); + xmlWriter().writeAttribute("id",tn->guid()); + if (!attribute.isEmpty()) + xmlWriter().writeAttribute("outputclass",attribute); + writeStartTag(DT_apiName); + writeCharacters(tn->name()); + writeEndTag(); // + generateBrief(tn,marker); + + // not included: + + writeStartTag(DT_cxxTypedefDetail); + writeStartTag(DT_cxxTypedefDefinition); + writeStartTag(DT_cxxTypedefAccessSpecifier); + xmlWriter().writeAttribute("value",tn->accessString()); + writeEndTag(); // + + // not included: + + QString fq = fullQualification(tn); + if (!fq.isEmpty()) { + writeStartTag(DT_cxxTypedefScopedName); + writeCharacters(fq); + writeEndTag(); // + } + + // not included: + + writeStartTag(DT_cxxTypedefNameLookup); + writeCharacters(tn->parent()->name() + "::" + tn->name()); + writeEndTag(); // + + // not included: + + writeLocation(tn); + writeEndTag(); // + + writeApiDesc(tn, marker, QString()); + + // not included: or + + writeEndTag(); // + + // not included: + + writeEndTag(); // + } + ++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(*m); + writeStartTag(DT_cxxVariable); + xmlWriter().writeAttribute("id",pn->guid()); + if (!attribute.isEmpty()) + xmlWriter().writeAttribute("outputclass",attribute); + writeStartTag(DT_apiName); + writeCharacters(pn->name()); + writeEndTag(); // + generateBrief(pn,marker); + + // not included: + + writeStartTag(DT_cxxVariableDetail); + writeStartTag(DT_cxxVariableDefinition); + writeStartTag(DT_cxxVariableAccessSpecifier); + xmlWriter().writeAttribute("value",pn->accessString()); + writeEndTag(); // + + // not included: , + // , + // , + // , + + if (!pn->qualifiedDataType().isEmpty()) { + writeStartTag(DT_cxxVariableDeclaredType); + writeCharacters(pn->qualifiedDataType()); + writeEndTag(); // + } + QString fq = fullQualification(pn); + if (!fq.isEmpty()) { + writeStartTag(DT_cxxVariableScopedName); + writeCharacters(fq); + writeEndTag(); // + } + + 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(); // + + writeStartTag(DT_cxxVariableNameLookup); + writeCharacters(pn->parent()->name() + "::" + pn->name()); + writeEndTag(); // + + if (pn->overriddenFrom() != 0) { + PropertyNode* opn = (PropertyNode*)pn->overriddenFrom(); + writeStartTag(DT_cxxVariableReimplemented); + xmlWriter().writeAttribute("href",opn->ditaXmlHref()); + writeCharacters(marker->plainFullName(opn)); + writeEndTag(); // + } + + writeLocation(pn); + writeEndTag(); // + + writeApiDesc(pn, marker, QString()); + + // not included: or + + writeEndTag(); // + + // not included: + + writeEndTag(); // + } + ++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(*m); + writeStartTag(DT_cxxVariable); + xmlWriter().writeAttribute("id",vn->guid()); + if (!attribute.isEmpty()) + xmlWriter().writeAttribute("outputclass",attribute); + writeStartTag(DT_apiName); + writeCharacters(vn->name()); + writeEndTag(); // + generateBrief(vn,marker); + + // not included: + + writeStartTag(DT_cxxVariableDetail); + writeStartTag(DT_cxxVariableDefinition); + writeStartTag(DT_cxxVariableAccessSpecifier); + xmlWriter().writeAttribute("value",vn->accessString()); + writeEndTag(); // + + // not included: + + if (vn->isStatic()) { + writeStartTag(DT_cxxVariableStorageClassSpecifierStatic); + xmlWriter().writeAttribute("name","static"); + xmlWriter().writeAttribute("value","static"); + writeEndTag(); // + } + + // not included: , + // , + + writeStartTag(DT_cxxVariableDeclaredType); + writeCharacters(vn->leftType()); + if (!vn->rightType().isEmpty()) + writeCharacters(vn->rightType()); + writeEndTag(); // + + QString fq = fullQualification(vn); + if (!fq.isEmpty()) { + writeStartTag(DT_cxxVariableScopedName); + writeCharacters(fq); + writeEndTag(); // + } + + writeStartTag(DT_cxxVariablePrototype); + writeCharacters(vn->leftType() + QLatin1Char(' ')); + //writeCharacters(vn->parent()->name() + "::" + vn->name()); + writeCharacters(vn->name()); + if (!vn->rightType().isEmpty()) + writeCharacters(vn->rightType()); + writeEndTag(); // + + writeStartTag(DT_cxxVariableNameLookup); + writeCharacters(vn->parent()->name() + "::" + vn->name()); + writeEndTag(); // + + // not included: + + writeLocation(vn); + writeEndTag(); // + + writeApiDesc(vn, marker, QString()); + + // not included: or + + writeEndTag(); // + + // not included: + + writeEndTag(); // + } + ++m; + } +} + +/*! + This function writes a \macro as a . + */ +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(*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(); // + generateBrief(fn,marker); + + // not included: + + writeStartTag(DT_cxxDefineDetail); + writeStartTag(DT_cxxDefineDefinition); + writeStartTag(DT_cxxDefineAccessSpecifier); + xmlWriter().writeAttribute("value",fn->accessString()); + writeEndTag(); // + + 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(); // + + writeStartTag(DT_cxxDefineNameLookup); + writeCharacters(fn->name()); + writeEndTag(); // + + if (fn->reimplementedFrom() != 0) { + FunctionNode* rfn = (FunctionNode*)fn->reimplementedFrom(); + writeStartTag(DT_cxxDefineReimplemented); + xmlWriter().writeAttribute("href",rfn->ditaXmlHref()); + writeCharacters(marker->plainFullName(rfn)); + writeEndTag(); // + } + + 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(); // + + // not included: + + writeEndTag(); // + } + writeEndTag(); // + } + } + + writeLocation(fn); + writeEndTag(); // + + writeApiDesc(fn, marker, QString()); + + // not included: or + + writeEndTag(); // + + // not included: + + writeEndTag(); // + } + } + ++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
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 {} 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(); // + } + ++m; + } + writeEndTag(); // + writeEndTag(); // +} + +/*! + 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(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(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 matches = nmm->values(key); + if (!matches.isEmpty()) { + for (int i=0; ichildNodes(); + if (children.size() == 0) + return; + + bool related; + QString message; + for (int i=0; iisInternal() || 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(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 = ""; + + 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(); // + writeEndTag(); // + GuidMaps::iterator i = guidMaps.begin(); + while (i != guidMaps.end()) { + writeStartTag(DT_topicref); + if (i.key() != "qt.ditamap") + xmlWriter().writeAttribute("href",i.key()); + writeEndTag(); // + ++i; + } + endSubPage(); + + for (unsigned i=0; iroot()); +#if 0 + for (unsigned i=0; isize() > 0) + qDebug() << "NODE TYPE:" << Node::nodeTypeString(i) << nodeTypeMaps[i]->size(); + } + for (unsigned i=1; isize() > 0) + qDebug() << "NODE SUBTYPE:" << Node::nodeSubtypeString(i) << nodeSubtypeMaps[i]->size(); + } + for (unsigned i=1; isize() > 0) + qDebug() << "PAGE TYPE:" << Node::pageTypeString(i) << pageTypeMaps[i]->size(); + } +#endif + beginSubPage(tree->root(),"test.ditamap"); + + doctype = ""; + xmlWriter().writeDTD(doctype); + writeStartTag(DT_map); + writeStartTag(DT_topicmeta); + writeStartTag(DT_shortdesc); + xmlWriter().writeCharacters("The top level map for the Qt documentation"); + writeEndTag(); // + writeEndTag(); // + + 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; iname()); + + QString doctype; + doctype = ""; + // doctype = ""; + + xmlWriter().writeDTD(doctype); + writeStartTag(DT_map); + writeStartTag(DT_topicmeta); + writeStartTag(DT_shortdesc); + xmlWriter().writeCharacters(node->title()); + writeEndTag(); // + writeEndTag(); // + 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(); // or + } +} + +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(i.value()); + switch (fn->subType()) { + case Node::Group: { + const NodeList& members = fn->groupMembers(); + for (int j=0; jname()); + xmlWriter().writeAttribute("href",fileName(members[j])); + writeEndTag(); // + } + break; + } + case Node::QmlModule: { + const NodeList& members = fn->qmlModuleMembers(); + for (int j=0; jname()); + xmlWriter().writeAttribute("href",fileName(members[j])); + writeEndTag(); // + } + break; + } + case Node::Example: { + const ExampleNode* en = static_cast(fn); + if (!en->imageFileName().isEmpty()) { + writeStartTag(DT_topicref); + xmlWriter().writeAttribute("navtitle","image"); + xmlWriter().writeAttribute("href",en->imageFileName()); + writeEndTag(); // + } + const NodeList& files = en->childNodes(); + for (int j=0; jname()); + writeEndTag(); // + } + 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(); // + } + } + 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(); // + } + } + break; + } + default: + break; + } + break; + } + case Node::Namespace: { + const NamespaceNode* nn = static_cast(i.value()); + const NodeList& c = nn->childNodes(); + for (int j=0; jisInternal() || 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(); // + } + } + break; + } + case Node::Class: { + const NamespaceNode* nn = static_cast(i.value()); + const NodeList& c = nn->childNodes(); + for (int j=0; jisInternal() || 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(); // + } + } + break; + } + default: + break; + } + writeEndTag(); // + ++i; + } + writeEndTag(); // +} + + +/*! + 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 element for the \a inner node + using the \a marker. The element contains + the element, plus some others. This + function writes one or more of these elements: + + \list + \o * + \o * + \o not used + \o * + \o * + \o * + \o * + \o not used + \o * + \o not used + \o not used + \o not used + \o * + \o * + \o * + \o not used + \o * + \o * + \o * + \o * + \o not used + \o not used + \o not used + \o not used + \o not used + \o * + \o * + \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(); // + writeStartTag(DT_copyrholder); + if (!s.isEmpty()) + xmlWriter().writeCharacters(t); + writeEndTag(); // + writeEndTag(); // + s = getMetadataElement(inner,DT_permissions); + writeStartTag(DT_permissions); + xmlWriter().writeAttribute("view",s); + writeEndTag(); // + writeStartTag(DT_metadata); + QStringList sl = getMetadataElements(inner,DT_audience); + if (!sl.isEmpty()) { + for (int i=0; i + } + } + 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(); // + } + if (vrm.size() > 0) { + writeStartTag(DT_prodinfo); + if (!writeMetadataElement(inner,DT_prodname,false)) { + writeStartTag(DT_prodname); + xmlWriter().writeCharacters(projectDescription); + writeEndTag(); // + } + 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(); // + writeEndTag(); // + if (!writeMetadataElement(inner,DT_component,false)) { + QString component = inner->moduleName(); + if (!component.isEmpty()) { + writeStartTag(DT_component); + xmlWriter().writeCharacters(component); + writeEndTag(); // + } + } + writeEndTag(); // + } + const QStringMultiMap& metaTagMap = inner->doc().metaTagMap(); + QMapIterator i(metaTagMap); + while (i.hasNext()) { + i.next(); + writeStartTag(DT_othermeta); + xmlWriter().writeAttribute("name",i.key()); + xmlWriter().writeAttribute("content",i.value()); + writeEndTag(); // + } + writeEndTag(); // + writeEndTag(); // +} + +/*! + 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 +#include +#include +#include "codemarker.h" +#include "config.h" +#include "pagegenerator.h" + +QT_BEGIN_NAMESPACE + +typedef QMap GuidMap; +typedef QMap 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 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
* 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 refMap; + QMap name2guidMap; + GuidMaps guidMaps; + QMap moduleClassMap; + QMap moduleNamespaceMap; + NodeMap nonCompatClasses; + NodeMap mainClasses; + NodeMap compatClasses; + NodeMap obsoleteClasses; + NodeMap namespaceIndex; + NodeMap serviceClasses; +#ifdef QDOC_QML + NodeMap qmlClasses; +#endif + QMap funcIndex; + QMap legaleseTexts; + static int id; + static QString ditaTags[]; + QStack xmlWriterStack; + QStack tagStack; + QStringMultiMap metadataDefaults; + QVector nodeTypeMaps; + QVector nodeSubtypeMaps; + QVector 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 +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +Q_GLOBAL_STATIC(QSet, null_Set_QString) +Q_GLOBAL_STATIC(TopicList, nullTopicList) +Q_GLOBAL_STATIC(QStringList, null_QStringList) +Q_GLOBAL_STATIC(QList, 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 QHash_QString_int; +typedef QHash 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 tableOfContents; + QList tableOfContentsLevels; + QList keywords; + QList 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 params; + QList alsoList; + QStringList enumItemList; + QStringList omitEnumItemList; + QSet 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 &metaCommandSet, + const QSet& 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& 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 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 targetMap; + QMap pendingFormats; + QStack openedCommands; + QStack openedLists; + Quoter quoter; + QStack 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& metaCommandSet, + const QSet& 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 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 ¯o = 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::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 &metaCommandSet, + const QString &str) +{ + QSet 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::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 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& metaCommandSet) +{ + priv = new DocPrivate(start_loc,end_loc,source); + DocParser parser; + parser.parse(source,priv,metaCommandSet,QSet()); +} + +/*! + 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& metaCommandSet, + const QSet& 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 &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 &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 &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 &Doc::tableOfContents() const +{ + priv->constructExtra(); + return priv->extra->tableOfContents; +} + +const QList &Doc::tableOfContentsLevels() const +{ + priv->constructExtra(); + return priv->extra->tableOfContentsLevels; +} + +const QList &Doc::keywords() const +{ + priv->constructExtra(); + return priv->extra->keywords; +} + +const QList &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 commands = config.subVars(CONFIG_ALIAS); + QSet::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 macroNames = config.subVars(CONFIG_MACRO); + QSet::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 formats = config.subVars(macroDotName); + QSet::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 "er, + 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 +#include +#include + +#include "location.h" + +QT_BEGIN_NAMESPACE + +class Atom; +class CodeMarker; +class Config; +class DocPrivate; +class Quoter; +class Text; +class FakeNode; +class DitaRef; + +typedef QMap QCommandMap; +typedef QMap QStringMap; +typedef QMultiMap QStringMultiMap; + +struct Topic +{ + QString topic; + QString args; + Topic(QString& t, QString a) : topic(t), args(a) { } +}; +typedef QList TopicList; + +typedef QList 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 &metaCommandSet); + Doc(const Location& start_loc, + const Location& end_loc, + const QString& source, + const QSet& metaCommandSet, + const QSet& 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 ¶meterNames() const; + const QStringList &enumItemNames() const; + const QStringList &omitEnumItemNames() const; + const QSet &metaCommandsUsed() const; + const TopicList& topicsUsed() const; + QStringList metaCommandArgs( const QString& metaCommand ) const; + const QList &alsoList() const; + bool hasTableOfContents() const; + bool hasKeywords() const; + bool hasTargets() const; + const QList &tableOfContents() const; + const QList &tableOfContentsLevels() const; + const QList &keywords() const; + const QList &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 "er, + 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/arrow_down.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/bg_l.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/bg_l_blank.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/bg_ll_blank.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/bg_r.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/bg_ul_blank.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/box_bg.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/breadcrumb.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/bullet_dn.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/bullet_gt.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/bullet_sq.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/bullet_up.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/feedbackground.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/header_bg.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/horBar.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/page.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/page_bg.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/spinner.gif 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 Binary files /dev/null and b/src/tools/qdoc/doc/config/images/sprites-combined.png 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 = "á" +macro.Aring.HTML = "Å" +macro.aring.HTML = "å" +macro.Auml.HTML = "Ä" +macro.author = "\\bold{Author:}" +macro.br.HTML = "
" +macro.BR.HTML = "
" +macro.copyright.HTML = "©" +macro.eacute.HTML = "é" +macro.gui = "\\bold" +macro.hr.HTML = "
" +macro.iacute.HTML = "í" +macro.key = "\\bold" +macro.menu = "\\bold" +macro.note = "\\bold{Note:}" +macro.oslash.HTML = "ø" +macro.ouml.HTML = "ö" +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 = "*" +macro.rarrow.HTML = "→" +macro.reg.HTML = "®" +macro.return = "Returns" +macro.starslash = "\\c{*/}" +macro.begincomment = "\\c{/*}" +macro.endcomment = "\\c{*/}" +macro.uuml.HTML = "ü" +macro.mdash.HTML = "—" +macro.pi.HTML = "Π" +macro.beginqdoc.HTML = "/*!" +macro.endqdoc.HTML = "*/" + +macro.beginfloatleft.HTML = "
" +macro.beginfloatright.HTML = "
" +macro.endfloat.HTML = "
" +macro.clearfloat.HTML = "
" +macro.emptyspan.HTML = "" 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 = \ + " \n" + +HTML.headerscripts = + +HTML.endheader = \ + "\n" \ + "\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 = \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + "\n" \ + "\n" \ + "\n\n" + +HTML.headerscripts = \ + "\n" \ + "\n\n" + +HTML.endheader = \ + "\n" \ + "\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 = \ + "
\n" \ + "
\n" \ + "
\n" \ + " Home
\n" \ + " QDoc Reference Documentation\n" \ + "
\n" \ + "
\n" \ + " \n" \ + "
\n" \ + "
\n" \ + " \n" \ + "
\n" \ + "
\n" \ + "
\n" \ + "
\n" \ + "
\n" \ + " \n" \ + "
\n" \ + "
\n" \ + "
\n" \ + "
\n" \ + "
\n" \ + "
    \n" \ + "
  • Home
  • \n" \ + " \n" + +HTML.postpostheader = \ + "
\n" \ + "
\n" \ + "
\n" \ + " \n" \ + "
\n" \ + "
\n" \ + "
\n" + +HTML.footer = \ + "
\n" \ + "
\n" \ + "
\n" \ + "
\n" \ + " \n" \ + "
\n" \ + "
\n" \ + "
\n" \ + "

\n" \ + " © 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.

\n" \ + "

\n" \ + " All other trademarks are property of their respective owners. Privacy Policy

\n" \ + "
\n" \ + "

\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.

\n" \ + "

\n" \ + " Alternatively, this document may be used under the terms of the GNU\n" \ + " Free Documentation License version 1.3\n" \ + " as published by the Free Software Foundation.

\n" \ + "
\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 = \ + "
\n" \ + "
\n" \ + " QDoc Reference Documentation\n" \ + "
\n" \ + "
\n" \ + "
    \n" \ + "
  • Home
  • \n" \ + " \n" + +HTML.postpostheader = \ + "
\n" \ + "
\n" \ + "
\n" \ + "
\n" + +HTML.footer = \ + "
\n" \ + " \n" \ + "
\n" \ + "
\n" \ + "
\n" \ + "

\n" \ + " © 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.

\n" \ + "

\n" \ + " All other trademarks are property of their respective owners. Privacy Policy

\n" \ + "
\n" \ + "

\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.

\n" \ + "

\n" \ + " Alternatively, this document may be used under the terms of the GNU\n" \ + " Free Documentation License version 1.3\n" \ + " as published by the Free Software Foundation.

\n" \ + "
\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 " 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 " 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 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 " 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 +#include + +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 Binary files /dev/null and b/src/tools/qdoc/doc/images/happy.gif 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 Binary files /dev/null and b/src/tools/qdoc/doc/images/happyguy.jpg 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 Binary files /dev/null and b/src/tools/qdoc/doc/images/qt-logo.png 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 Binary files /dev/null and b/src/tools/qdoc/doc/images/training.jpg 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()} 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 = + exampledirs = + imagedirs = + + 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 = + \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 = + \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 = "Π" + \endcode + The snippet code will replace any instances of \c{\\pi} with \c Π 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 +

+ \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 + +

+ + + +

+
+ \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 + + +

Qt Developer Guide

+
+ + + +

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. +

+
+ +
    +
  • + Getting started +
  • +
  • + Installation +
  • +
  • + How to learn Qt +
  • +
  • + Tutorials +
  • +
  • + Examples +
  • +
  • + What's new in Qt 4.7 +
  • +
+
+
+
+ \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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QDoc SyntaxGenerated Documentation
1A variation of a command button is a \e menu + button.A variation of a command button is a menu + button.
2The QPushButton widget provides a + \e {command button}.The QPushButton widget provides a + command button.
3Another class of buttons are option buttons + \e (see QRadioButton).Another class of buttons are option buttons + (see QRadioButton).
4A push button emits the signal \e clicked().A push button emits the signal clicked().
5The \e QPushButton's checked property is + false by default.The QPushButton's checked property is + false by default.
+ \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 + +

Basic Qt

+
+

This is the first part.

+ + +

Getting Started

+
+ This is the first part's first chapter.

+ + +

Hello Qt

+
+

This is the first chapter's first section.

+ + +

Making Connections

+
+

This is the first chapter's second section.

+ + +

Using the Reference Documentation

+
+

This is the first chapter's third section.

+ + +

Creating Dialogs

+
+

This is the first part's second chapter.

+ + +

Subclassing QDialog

+
+

This is the second chapter's first section.

+ + ... + + +

Intermediate Qt

+
+

This is the second part.

+ + +

Layout Management

+
+

This is the second part's first chapter.

+ + +

Basic Layouts

+
+

This is the first chapter's first section.

+ + ... + + \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 + #include + + int main(int argc, char *argv[]) + { + ... + } + \ endcode + * / + \endcode + + QDoc renders this as: + + \code + #include + #include + + 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 } - 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 actions) + { + ... + } + \endcode + + QDoc renders this as: + + \quotation + \bold {void QWidget::addActions ( QList + \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 + + + + + + + + + + + + + +
QtQt Creator
Oh so happy! + Oh so happy! +
Oh so happy! + Oh so happy! +
+ \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 + + + + + + + + + + + + + + + + + + + + + +
Qt Core FeatureBrief Description
+ + Signals and Slots + Signals and slots are used for communication + between objects.
+ + Layout ManagementThe Qt layout system provides a simple + and powerful way of specifying the layout + of child widgets.
+ + Drag and DropDrag and drop provides a simple visual + mechanism which users can use to transfer + information between and within applications.
+ \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 + + + + + + + + + + + + + + + + +
+ This header cell spans three columns but only one row +
+ This table cell spans two columns but only one row + + This table cell spans only one column, but two rows. +
A regular table cellA regular table cell
+ \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 + + + + + + + + + + +
Qt Core FeatureBrief Description
+ + Signals and Slots + Signals and slots are used for communication + between objects.
+ \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 + + + + + + + + + + + + + + + + + + + + + +
Qt Core FeatureBrief Description
+ + Signals and Slots + Signals and slots are used for communication + between objects.
+ + Layout ManagementThe Qt layout system provides a simple + and powerful way of specifying the layout + of child widgets.
+ + Drag and DropDrag and drop provides a simple visual + mechanism which users can use to transfer + information between and within applications.
+ \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 + + + + + + + + + + + + + + + + +
+ This header cell spans three columns but only one row +
+ This table item spans two columns but only one row + + This table item spans only one column, but two rows. +
A regular table itemA regular table item
+ \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{
} and \bold{
} 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 +
+

As our solutions were being adopted into new environments, + we saw an escalating need for easier integration with a wider + range of enterprise applications.

+
+ \endcode + + The built-in style sheet for most browsers will render the + contents of the
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{
} 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 +

geometry : + QRect +

+ \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 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 +

PreviewWindow Class Reference

+ \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 +

Properties

+ \endraw + + \list + \o 52 properties inherited from QWidget + \o 1 property inherited from QObject + \endlist + + \raw HTML +

Public Functions

+ \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 +

Public Slots

+ \endraw + + \list + \o 17 public slots inherited from QWidget + \o 1 public slot inherited from QObject + \endlist + + \raw HTML +

Additional Inherited Members

+ \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 +
+

Detailed Description

+ \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 +
+

Member Function Documentation

+ \endraw + + \target constructor + \raw HTML +

PreviewWindow(QWidget *parent = 0)

+ \endraw + + Constructs a preview window widget with \e parent. + + \target function + \raw HTML +

setWindowFlags(Qt::WindowFlags flags)

+ \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 + \title Global Qt Declarations + + \brief The header file provides basic + declarations and is included by all other Qt headers. + + \sa + * / + \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 + {
} and \bold {
} 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 +
+

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.

+
+ \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 + + + + + QWidget + the QWidget class is the base class of all user interface objects. + + Qt Development Frameworks + Nokia + + + Nokia + + + + + + + Class reference + + Qt Reference Documentation + + + + QtGui + + + + + + + + \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 + + + + + + + + + + + +
Basic WidgetsBasic GUI widgets such as buttons, comboboxes + and scrollbars.
Database ClassesDatabase related classes, e.g. for SQL databases.
+ \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 + + +

+ Blue(#0000ff), + dark blue(#000080) and + cyan(#00ffff). +

+ \endraw + * / + \endcode + + QDoc renders this as: + + \quotation + Qt has some predefined QColor objects. + + \raw HTML + + +

+ Blue(#0000ff), + dark blue(#000080) and + cyan(#00ffff). +

+ \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 +

PreviewWindow Class Reference

+ \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 +

Properties

+ \endraw + + \list + \o 52 properties inherited from QWidget + \o 1 property inherited from QObject + \endlist + + \raw HTML +

Public Functions

+ \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 +

Public Slots

+ \endraw + + \list + \o 17 public slots inherited from QWidget + \o 1 public slot inherited from QObject + \endlist + + \raw HTML +

Additional Inherited Members

+ \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 +
+

Detailed Description

+ \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 +
+

Member Function Documentation

+ \endraw + + \target constructor + \raw HTML +

PreviewWindow(QWidget *parent = 0)

+ \endraw + + Constructs a preview window widget with \e parent. + + \target function + \raw HTML +

setWindowFlags(Qt::WindowFlags flags)

+ \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 +

enum Qt::Corner

+ +

This enum type specifies a corner in a rectangle:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ConstantValueDescription
Qt::TopLeftCorner0x00000The top-left corner of the rectangle.
Qt::TopRightCorner0x00001The top-right corner of the rectangle.
Qt::BottomLeftCorner0x00002The bottom-left corner of the rectangle.
Qt::BottomRightCorner0x00003The bottom-right corner of the rectangle.
+ \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 +

Image Viewer Example

+ \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 +

bool QToolBar::isAreaAllowed(Qt::ToolBarArea area) const +

+ \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 + \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 + +

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.

+ +

+ + + + + + + + + + + + +
+ QAbstractSocket + + The base functionality common to all socket types +
+ QBuffer + + QIODevice interface for a QByteArray +
+ QClipboard + + Access to the window system clipboard +
+ \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 + + \title Generic Algorithms + + \brief The header file provides + generic template-based algorithms. + + Qt provides a number of global template functions in \c + 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 +

<QtAlgorithms> - + Generic Algorithms

+

The header file provides generic + template-based algorithms. + More... +

+ +

Functions

+
    +
  • RandomAccessIterator + qBinaryFind + (RandomAccessIterator begin, RandomAccessIterator end, + const T & value)
  • +
  • ...
+
+ \endraw + + \target header + + \raw HTML +

Detailed Description

+

The header file provides generic + template-based algorithms.

+ \endraw + + Qt provides a number of global template functions in \c + 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 + + 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 +

void Q_ASSERT ( bool test )

+ \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 +

Q_PROPERTY ( ... )

+ \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 +

Q_OBJECT

+ \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 +

QtNetwork Module

+ \endraw + + The QtNetwork module offers classes that allow you to + write TCP/IP clients and servers.\l {module + details} {More...} + + \raw HTML +

+ + + + + + + + + + + + + +
+ QAbstractSocket + + The base functionality common to all socket types +
+ QFtp + + Implementation of the FTP protocol +
......
+ +


+ \endraw + + \target module details + + \raw HTML +

Detailed Description

+ +

+ 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. +

+ \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 +

Qt Namespace Reference

+

The Qt namespace contains miscellaneous + identifiers used throughout the Qt library. + More... +

+ +
#include <Qt>
+ + + +

Types

+ +
+ \endraw + + \target name + + \raw HTML +

Detailed Description

+

The Qt namespace contains miscellaneous identifiers + used throughout the Qt library.

+ \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 +

flat : bool

+ \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 +

width : const int

+ \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. + * / + \endcode + + QDoc includes this in \c {qobject.html} as: + + \quotation + \raw HTML +

typedef QObjectList

+ \endraw + + Synonym for QList. + \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 +

typedef QtMsgHandler

+ \endraw + + This is a typedef for a pointer to a function with the + following signature: + + \raw HTML + +
    void myMsgHandler(QtMsgType, const char *);
+
+ \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 +

typedef QLinkedList::Iterator

+ \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 +

+ + QPalette + + QStyleOption::palette +

+ \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 +

+ const int QTreeWidgetItem::Type +

+ \endraw + + The default type for tree widget items. + + See also \l {QTreeWidgetItem::UserType} {UserType} and \l + {QTreeWidgetItem::type()} {type()}. + + \raw HTML +

+ const int QTreeWidgetItem::UserType +

+ \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 + + + +

+ [Previous: + Basic Qt] + [Contents] + [Next: + Creating Dialogs] +

+ +

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. +

+ +

+ [Previous: + Basic Qt] + [Contents] + [Next: + Creating Dialogs] +

+ +
+ \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 + + ... + + + ... + + \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 +

Qt 3 Support Members for MyClass

+ \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 +
+

Member Function Documentation

+

void MyQt3SupportMemberFunction ()

+

Use MyNewFunction() instead.

+ \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 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 +

Obsolete Members for MyClass

+ \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 +
+

Member Function Documentation

+

void MyObsoleteFunction ()

+

Use MyNewFunction() instead.

+ \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 +

+ Joining + QChar::joining () const

+ \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 +

QIcon QStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const

+ \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 +

QLocale Class Reference

+ \endraw + + The QLocale class converts between numbers and their string + representations in various languages. More... + + \code + #include + \endcode + + \bold {Note:} All the functions in this class are \l + {threads.html#reentrant} {reentrant}, except \l + {QLocale::setDefault()} {setDefault()}. + + ... + + \raw HTML +
+

Member Type Documentation

+ \endraw + + ... + + \raw HTML +

void QLocale::setDefault ( const QLocale & locale )

+ \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 +

QAction + * QMenu::addAction ( const QIcon & icon, + const QString & text ) +

+ \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 +

Signal and Slots

+ \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 +

Qtopia Core

+

Qt for Embedded Linux

+ \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 = "Home" + \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 = "á" + macro.Aring.DITAXML = "Å" + macro.aring.DITAXML = "å" + macro.Auml.DITAXML = "Ä" + macro.br.DITAXML = " " + macro.BR.DITAXML = " " + macro.copyright.DITAXML = "©" + macro.eacute.DITAXML = "é" + macro.hr.DITAXML = " " + macro.iacute.DITAXML = "í" + macro.oslash.DITAXML = "ø" + macro.ouml.DITAXML = "ö" + macro.raisedaster.DITAXML = "*" + macro.rarrow.DITAXML = "→" + macro.reg.DITAXML = "®" + macro.uuml.DITAXML = "ü" + macro.mdash.DITAXML = "—" + macro.emptyspan.DITAXML = " " + \endcode + + You can also set default values for some of the tags in the DITA + \c {} and \c {} 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 = "*" + \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 = "


\n" \ + ... + "
" + \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 = "" \ + "" \ + "
" + \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& candidates ) +{ + if (actual.isEmpty()) + return ""; + + int deltaBest = 10000; + int numBest = 0; + QString best; + + QSet::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 +#include + +QT_BEGIN_NAMESPACE + +int editDistance( const QString& s, const QString& t ); +QString nearestName( const QString& actual, const QSet& 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 +#ifdef DEBUG_MULTIPLE_QDOCCONF_FILES +#include +#endif +#include +#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::generators; +QMap > Generator::fmtLeftMaps; +QMap > Generator::fmtRightMaps; +QMap Generator::imgFileExts; +QSet 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 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("&"), + lt("<"), + gt(">"), + 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 formats = config.subVars(imagesDotFileExtensions); + QSet::ConstIterator f = formats.begin(); + while (f != formats.end()) { + imgFileExts[*f] = config.getStringList(imagesDotFileExtensions + + Config::dot + *f); + ++f; + } + + QList::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 formattingNames = config.subVars(CONFIG_FORMATTING); + QSet::ConstIterator n = formattingNames.begin(); + while (n != formattingNames.end()) { + QString formattingDotName = CONFIG_FORMATTING + Config::dot + *n; + + QSet formats = config.subVars(formattingDotName); + QSet::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::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::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(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(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 definedItems; + QList::ConstIterator it = enume->items().begin(); + while (it != enume->items().end()) { + definedItems.insert((*it).name()); + ++it; + } + + QSet documentedItems = enume->doc().enumItemNames().toSet(); + QSet allItems = definedItems + documentedItems; + if (allItems.count() > definedItems.count() || + allItems.count() > documentedItems.count()) { + QSet::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(node); + QSet definedParams; + QList::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 documentedParams = func->doc().parameterNames(); + QSet allParams = definedParams + documentedParams; + if (allParams.count() > definedParams.count() + || allParams.count() > documentedParams.count()) { + QSet::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 ¶m, + 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(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 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::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 &alsoList) +{ + if (node->type() == Node::Function) { + const FunctionNode *func = static_cast(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& Generator::formattingLeftMap() +{ + return fmtLeftMaps[format()]; +} + +QMap& 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(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 . + if (project.isEmpty()) + text << "version"; + else + text << project; + text << " " << since[0]; + } else { + // Reconstruct the 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 &classes, + CodeMarker *marker) +{ + QList::ConstIterator r; + QMap 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 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(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(node))->serviceName().isEmpty()) + return (static_cast(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(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(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(*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(*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 +#include +#include +#include +#include + +#include "node.h" +#include "text.h" + +QT_BEGIN_NAMESPACE + +typedef QMap NodeMap; +typedef QMultiMap NodeMultiMap; +typedef QMap NewSinceMaps; +typedef QMap ParentMaps; +typedef QMap 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 &formattingLeftMap(); + QMap &formattingRightMap(); + QMap editionModuleMap; + QMap editionGroupMap; + + static QString trimmedTrailing(const QString &string); + static bool matchAhead(const Atom *atom, Atom::Type expectedAtomType); + static void supplementAlsoList(const Node *node, QList &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 &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 generators; + static QMap > fmtLeftMaps; + static QMap > fmtRightMaps; + static QMap imgFileExts; + static QSet 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 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 +#include + +#include "atom.h" +#include "helpprojectwriter.h" +#include "htmlgenerator.h" +#include "config.h" +#include "node.h" +#include "tree.h" +#include + +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 customFilterNames = config.subVars(prefix + "customFilters"); + foreach (const QString &filterName, customFilterNames) { + QString name = config.getString(prefix + "customFilters" + Config::dot + filterName + Config::dot + "name"); + QSet 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 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 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 allSubTypes = QSet::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 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 &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(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(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(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(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(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(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(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(node); + + // Ensure that we don't visit nodes more than once. + QMap 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(node); + foreach (const Node* n, inner->childNodes()) { + if (n->access() == Node::Private) + continue; + childMap[n->fullDocumentName()] = n; + } + } + else + childMap[static_cast(node)->fullTitle()] = node; + } + else { + if (node->type() == Node::Function) { + const FunctionNode *funcNode = static_cast(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(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 >::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 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 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(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(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 +#include +#include + +#include "config.h" +#include "node.h" + +QT_BEGIN_NAMESPACE + +class Tree; +typedef QPair QStringNodePair; + +struct SubProject +{ + QString title; + QString indexTitle; + QHash > selectors; + bool sortPages; + QString type; + QHash nodes; +}; + +struct HelpProject +{ + QString name; + QString helpNamespace; + QString virtualFolder; + QString fileName; + QString indexRoot; + QString indexTitle; + QList keywords; + QSet files; + QSet extraFiles; + QSet filterAttributes; + QHash > customFilters; + QSet excluded; + QMap subprojects; + QHash > memberStatus; +}; + +class HelpProjectWriter +{ +public: + HelpProjectWriter(const Config &config, const QString &defaultFileName); + void addExtraFile(const QString &file); + void addExtraFiles(const QSet &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 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 +#include +#include +#include +#include +#include + +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=\"([^\"]+)\">).*()"); +static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)()"); +static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)()"); +static QRegExp spanTag(""); +static QRegExp unknownTag("]*>"); + +static void addLink(const QString &linkTarget, + const QStringRef &nestedStuff, + QString *res) +{ + if (!linkTarget.isEmpty()) { + *res += ""; + *res += nestedStuff; + *res += ""; + } + 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, "", "" }, + { ATOM_FORMATTING_INDEX, "" }, + { ATOM_FORMATTING_ITALIC, "", "" }, + { ATOM_FORMATTING_PARAMETER, "", "" }, + { ATOM_FORMATTING_SUBSCRIPT, "", "" }, + { ATOM_FORMATTING_SUPERSCRIPT, "", "" }, + { ATOM_FORMATTING_TELETYPE, "", "" }, + { ATOM_FORMATTING_UNDERLINE, "", "" }, + { 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 editionNames = config.subVars(CONFIG_EDITION); + QSet::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() << "

"; + 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() << "

\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() << "

"; + in_para = true; + break; + case Atom::CaptionRight: + endLink(); + if (in_para) { + out() << "

\n"; + in_para = false; + } + break; + case Atom::Code: + out() << "
"
+              << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
+                                                 marker,relative))
+              << "
\n"; + break; +#ifdef QDOC_QML + case Atom::Qml: + out() << "
"
+              << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
+                                                 marker,relative))
+              << "
\n"; + break; + case Atom::JavaScript: + out() << "
"
+              << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
+                                                 marker,relative))
+              << "
\n"; + break; +#endif + case Atom::CodeNew: + out() << "

you can rewrite it as

\n" + << "
"
+              << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),
+                                                 marker,relative))
+              << "
\n"; + break; + case Atom::CodeOld: + out() << "

For example, if you have code like

\n"; + // fallthrough + case Atom::CodeBad: + out() << "
"
+              << trimmedTrailing(protectEnc(plainCode(indent(codeIndent,atom->string()))))
+              << "
\n"; + break; + case Atom::DivLeft: + out() << "string().isEmpty()) + out() << ' ' << atom->string(); + out() << '>'; + break; + case Atom::DivRight: + out() << "
"; + break; + case Atom::FootnoteLeft: + // ### For now + if (in_para) { + out() << "

\n"; + in_para = false; + } + 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) << "" + << subscriptRegExp.cap(2) << ""; + skipAhead = 1; + } + } + } + break; + case Atom::FormattingRight: + if (atom->string() == ATOM_FORMATTING_LINK) { + endLink(); + } + else if (atom->string().startsWith("span ")) { + out() << ""; + } + else { + out() << formattingRightMap()[atom->string()]; + } + break; + case Atom::AnnotatedList: + { + QList 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 groups = myTree->groups(); + foreach (const QString &groupName, editionGroupMap[editionName]) { + QList 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(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(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 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
sections; + QList
::ConstIterator s; + + for (int i=0; itype()) { + 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(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() << "
    \n"; + s = sections.constBegin(); + while (s != sections.constEnd()) { + if (!(*s).members.isEmpty()) { + + out() << "
  • " + << "" + << (*s).name + << "
  • \n"; + } + ++s; + } + out() << "
\n"; + + int idx = 0; + s = sections.constBegin(); + while (s != sections.constEnd()) { + if (!(*s).members.isEmpty()) { + out() << "\n"; + out() << "

" << protectEnc((*s).name) << "

\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() << "

Class "; + + out() << ""; + QStringList pieces = fullName(pmap.key(), 0, marker).split("::"); + out() << protectEnc(pieces.last()); + out() << "" << ":

\n"; + + generateSection(nlist, 0, marker, CodeMarker::Summary); + out() << "
"; + ++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() << "

"; + if (fileName.isEmpty()) { + out() << "[Missing image " + << protectEnc(atom->string()) << "]"; + } + else { + QString prefix = ""; + if (!baseDir().isEmpty()) + prefix = "../"; + out() << "\"""; + helpProjectWriter->addExtraFile(fileName); + if ((relative->type() == Node::Fake) && + (relative->subType() == Node::Example)) { + const ExampleNode* cen = static_cast(relative); + if (cen->imageFileName().isEmpty()) { + ExampleNode* en = const_cast(cen); + en->setImageFileName(fileName); + } + } + } + if (atom->type() == Atom::Image) + out() << "

"; + } + break; + case Atom::ImageText: + break; + case Atom::ImportantLeft: + out() << "

"; + out() << formattingLeftMap()[ATOM_FORMATTING_BOLD]; + out() << "Important: "; + out() << formattingRightMap()[ATOM_FORMATTING_BOLD]; + break; + case Atom::ImportantRight: + out() << "

"; + break; + case Atom::NoteLeft: + out() << "

"; + out() << formattingLeftMap()[ATOM_FORMATTING_BOLD]; + out() << "Note: "; + out() << formattingRightMap()[ATOM_FORMATTING_BOLD]; + break; + case Atom::NoteRight: + out() << "

"; + break; + case Atom::LegaleseLeft: + out() << "
"; + break; + case Atom::LegaleseRight: + out() << "
"; + break; + case Atom::LineBreak: + out() << "
"; + 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() << "

\n"; + in_para = false; + } + if (atom->string() == ATOM_LIST_BULLET) { + out() << "
    \n"; + } + else if (atom->string() == ATOM_LIST_TAG) { + out() << "
    \n"; + } + else if (atom->string() == ATOM_LIST_VALUE) { + threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom); + if (threeColumnEnumValueTable) { + out() << ""; + if (++numTableRows % 2 == 1) + out() << ""; + else + out() << ""; + + out() << "" + << "" + << "\n"; + } + else { + out() << "
    ConstantValueDescription
    " + << "\n"; + } + } + else { + out() << "
      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() << "
      "; + } + else { // (atom->string() == ATOM_LIST_VALUE) + // ### Trenton + + out() << "
    \n"; + } + else { + out() << "\n"; + } + break; + case Atom::ListRight: + if (atom->string() == ATOM_LIST_BULLET) { + out() << "\n"; + } + else if (atom->string() == ATOM_LIST_TAG) { + out() << "\n"; + } + else if (atom->string() == ATOM_LIST_VALUE) { + out() << "
    ConstantValue
    " + << protectEnc(plainCode(marker->markedUpEnumValue(atom->next()->string(), + relative))) + << ""; + + QString itemValue; + if (relative->type() == Node::Enum) { + const EnumNode *enume = static_cast(relative); + itemValue = enume->itemValue(atom->next()->string()); + } + + if (itemValue.isEmpty()) + out() << '?'; + else + out() << "" << protectEnc(itemValue) << ""; + + skipAhead = 1; + } + break; + case Atom::ListTagRight: + if (atom->string() == ATOM_LIST_TAG) + out() << "\n"; + break; + case Atom::ListItemLeft: + if (atom->string() == ATOM_LIST_TAG) { + out() << "
    "; + } + else if (atom->string() == ATOM_LIST_VALUE) { + if (threeColumnEnumValueTable) { + out() << "
    "; + if (matchAhead(atom, Atom::ListItemRight)) + out() << " "; + } + } + else { + out() << "
  • "; + } + if (matchAhead(atom, Atom::ParaLeft)) + skipAhead = 1; + break; + case Atom::ListItemRight: + if (atom->string() == ATOM_LIST_TAG) { + out() << "\n"; + } + else if (atom->string() == ATOM_LIST_VALUE) { + out() << "
  • \n"; + } + else { + out() << "\n"; + } + break; + case Atom::Nop: + break; + case Atom::ParaLeft: + out() << "

    "; + in_para = true; + break; + case Atom::ParaRight: + endLink(); + if (in_para) { + out() << "

    \n"; + in_para = false; + } + //if (!matchAhead(atom, Atom::ListItemRight) && !matchAhead(atom, Atom::TableItemRight)) + // out() << "

    \n"; + break; + case Atom::QuotationLeft: + out() << "
    "; + break; + case Atom::QuotationRight: + out() << "
    \n"; + break; + case Atom::RawString: + out() << atom->string(); + break; + case Atom::SectionLeft: + out() << "" << divNavTop << '\n'; + break; + case Atom::SectionRight: + break; + case Atom::SectionHeadingLeft: + out() << "string().toInt() + hOffset(relative)) + QLatin1Char('>'); + inSectionHeading = true; + break; + case Atom::SectionHeadingRight: + out() << "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() << "

    \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() << ""; + out() << "\n "; + numTableRows = 0; + } + break; + case Atom::TableRight: + out() << "
    \n"; + break; + case Atom::TableHeaderLeft: + out() << ""; + inTableHeader = true; + break; + case Atom::TableHeaderRight: + out() << ""; + if (matchAhead(atom, Atom::TableHeaderLeft)) { + skipAhead = 1; + out() << "\n"; + } + else { + out() << "\n"; + inTableHeader = false; + } + break; + case Atom::TableRowLeft: + if (!atom->string().isEmpty()) + out() << "string() << '>'; + else if (++numTableRows % 2 == 1) + out() << ""; + else + out() << ""; + break; + case Atom::TableRowRight: + out() << "\n"; + break; + case Atom::TableItemLeft: + { + if (inTableHeader) + out() << "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() << ">

    "; + } + if (matchAhead(atom, Atom::ParaLeft)) + skipAhead = 1; + } + break; + case Atom::TableItemRight: + if (inTableHeader) + out() << ""; + else { + out() << ""; + //out() << "

    "; + } + if (matchAhead(atom, Atom::ParaLeft)) + skipAhead = 1; + break; + case Atom::TableOfContents: + break; + case Atom::Target: + out() << "string()) << "\">"; + break; + case Atom::UnhandledFormat: + out() << "<Missing HTML>"; + break; + case Atom::UnknownCommand: + out() << "\\" << protectEnc(atom->string()) + << ""; + 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
    sections; + QList
    ::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(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,§ions); + 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() << "\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() << "
    \n"; + out() << "" << divNavTop << "\n"; + out() << "

    " << protectEnc((*s).name) << "

    \n"; + generateSection(s->members, inner, marker, CodeMarker::Summary); + } + if (!s->reimpMembers.isEmpty()) { + QString name = QString("Reimplemented ") + (*s).name; + // out() << "
    \n"; + out() << "" << divNavTop << "\n"; + out() << "

    " << protectEnc(name) << "

    \n"; + generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary); + } + + if (!s->inherited.isEmpty()) { + out() << "
      \n"; + generateSectionInheritedList(*s, inner, marker); + out() << "
    \n"; + } + } + ++s; + } + + if (needOtherSection) { + out() << "

    Additional Inherited Members

    \n" + "
      \n"; + + s = sections.begin(); + while (s != sections.end()) { + if (s->members.isEmpty() && !s->inherited.isEmpty()) + generateSectionInheritedList(*s, inner, marker); + ++s; + } + out() << "
    \n"; + } + + out() << "" << divNavTop << '\n'; + + if (!inner->doc().isEmpty()) { + generateExtractionMark(inner, DetailedDescriptionMark); + //out() << "
    \n" + out() << "
    \n" // QTBUG-9504 + << "

    " << "Detailed Description" << "

    \n"; + generateBody(inner, marker); + out() << "
    \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() << "
    \n"; + if (!(*s).divClass.isEmpty()) + out() << "
    \n"; // QTBUG-9504 + out() << "

    " << protectEnc((*s).name) << "

    \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() << "

    class "; + generateFullName(*m, inner, marker); + out() << "

    "; + generateBrief(*m, marker, inner); + } + + QStringList names; + names << (*m)->name(); + if ((*m)->type() == Node::Function) { + const FunctionNode *func = reinterpret_cast(*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(*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(*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() << "
    \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; iclearCurrentChild(); + 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() << "

    " << protectEnc(fullTitle) << "

    \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& targets = ncn->linkTargets(); + if (!targets.isEmpty()) { + QMap::ConstIterator t = targets.begin(); + while (t != targets.end()) { + out() << ""; + out() << "

    " << protectEnc(t.key()) << "

    \n"; + out() << "
      \n"; + it = nl.begin(); + while (it != nl.end()) { + InnerNode* n = static_cast(*it); + Node* p = n->findNode(t.key()); + if (p) { + QString link = linkForNode(p,0); + QString label = n->qmlModuleIdentifier() + "::" + n->name() + "::" + p->name(); + out() << "
    • "; + out() << ""; + out() << protectEnc(label) << ""; + out() << "
    • \n"; + } + ++it; + } + out() << "
    \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(fake); + writeDitaMap(dmn); + return; + } + + SubTitleSize subTitleSize = LargeSubTitle; + QList
    sections; + QList
    ::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(fake); + sections = marker->qmlSections(qml_cn,CodeMarker::Summary); + generateTableOfContents(fake,marker,§ions); + + // 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() << "" << divNavTop << '\n'; + out() << "

    Namespaces

    \n"; + generateAnnotatedList(fake, marker, moduleNamespaceMap[fake->name()]); + } + if (moduleClassMap.contains(fake->name())) { + out() << "" << divNavTop << '\n'; + out() << "

    Classes

    \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() << "\n"; + } + else if (fake->subType() == Node::QmlClass) { + const_cast(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() << "\n"; + } + + s = sections.begin(); + while (s != sections.end()) { + out() << "" << divNavTop << "\n"; + out() << "

    " << protectEnc((*s).name) << "

    \n"; + generateQmlSummary(*s,fake,marker); + ++s; + } + + generateExtractionMark(fake, DetailedDescriptionMark); + out() << "" << divNavTop << '\n'; + out() << "

    " << "Detailed Description" << "

    \n"; + generateBody(fake, marker); + if (cn) + generateQmlText(cn->doc().body(), cn, marker, fake->name()); + generateAlsoList(fake, marker); + generateExtractionMark(fake, EndMark); + //out() << "
    \n"; + + sections = marker->qmlSections(qml_cn,CodeMarker::Detailed); + s = sections.begin(); + while (s != sections.end()) { + out() << "

    " << protectEnc((*s).name) << "

    \n"; + NodeList::ConstIterator m = (*s).members.begin(); + while (m != (*s).members.end()) { + generateDetailedQmlMember(*m, fake, marker); + out() << "
    \n"; + ++m; + } + ++s; + } + generateFooter(fake); + const_cast(fake)->clearCurrentChild(); + return; + } + + sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay); + s = sections.begin(); + while (s != sections.end()) { + out() << "" << divNavTop << '\n'; + out() << "

    " << protectEnc((*s).name) << "

    \n"; + generateSectionList(*s, fake, marker, CodeMarker::Summary); + ++s; + } + + Text brief = fake->doc().briefText(); + if (fake->subType() == Node::Module && !brief.isEmpty()) { + generateExtractionMark(fake, DetailedDescriptionMark); + out() << "" << divNavTop << '\n'; + out() << "
    \n"; // QTBUG-9504 + out() << "

    " << "Detailed Description" << "

    \n"; + } + else { + generateExtractionMark(fake, DetailedDescriptionMark); + out() << "
    \n"; // QTBUG-9504 + } + + generateBody(fake, marker); + out() << "
    \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() << "
    \n"; + out() << "

    " << protectEnc((*s).name) << "

    \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(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(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("\n").arg(outputEncoding); + out() << "\n"; + out() << QString("\n").arg(naturalLanguage); + out() << "\n"; + out() << " \n"; + if (node && !node->doc().location().isEmpty()) + out() << "\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() << " " << shortVersion << protectEnc(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 linkPair; + QPair 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() << " \n"; + + navigationLinks += "[Previous: "; + if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) + navigationLinks += protect(anchorPair.second); + else + navigationLinks += protect(linkPair.second); + navigationLinks += "]\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() << " \n"; + + navigationLinks += "[Next: "; + if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) + navigationLinks += protect(anchorPair.second); + else + navigationLinks += protect(linkPair.second); + navigationLinks += "]\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() << " \n"; + } + } + + if (node && !node->links().empty()) + out() << "

    \n" << navigationLinks << "

    \n"; +} + +void HtmlGenerator::generateTitle(const QString& title, + const Text &subTitle, + SubTitleSize subTitleSize, + const Node *relative, + CodeMarker *marker) +{ + if (!title.isEmpty()) + out() << "

    " << protectEnc(title) << "

    \n"; + if (!subTitle.isEmpty()) { + out() << ""; + else + out() << " class=\"subtitle\">"; + generateText(subTitle, relative, marker); + out() << "\n"; + } +} + +void HtmlGenerator::generateFooter(const Node *node) +{ + if (node && !node->links().empty()) + out() << "

    \n" << navigationLinks << "

    \n"; + + out() << QString(footer).replace("\\" + COMMAND_VERSION, myTree->version()) + << QString(address).replace("\\" + COMMAND_VERSION, myTree->version()); + + out() << "\n"; + out() << "\n"; +} + +void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, + const Node *relative) +{ + Text brief = node->doc().briefText(); + if (!brief.isEmpty()) { + generateExtractionMark(node, BriefMark); + out() << "

    "; + generateText(brief, node, marker); + + if (!relative || node == relative) + out() << " More...

    \n"; + + + generateExtractionMark(node, EndMark); + } +} + +void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker) +{ + if (!inner->includes().isEmpty()) { + out() << "
    "
    +              << trimmedTrailing(highlightedCode(indent(codeIndent,
    +                                                        marker->markedUpIncludes(inner->includes())),
    +                                                 marker,inner))
    +              << "
    "; + } +} + +/*! + Revised for the new doc format. + Generates a table of contents beginning at \a node. + */ +void HtmlGenerator::generateTableOfContents(const Node *node, + CodeMarker *marker, + QList
    * sections) +{ + QList 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() << "
    \n"; + out() << "

    Contents

    \n"; + sectionNumber.append("1"); + out() << "
      \n"; + + if (node->subType() == Node::Module) { + if (moduleNamespaceMap.contains(node->name())) { + out() << "
    • Namespaces
    • \n"; + } + if (moduleClassMap.contains(node->name())) { + out() << "
    • Classes
    • \n"; + } + out() << "
    • Detailed Description
    • \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
      ::ConstIterator s = sections->begin(); + while (s != sections->end()) { + if (!s->members.isEmpty() || !s->reimpMembers.isEmpty()) { + out() << "
    • " << (*s).name + << "
    • \n"; + } + ++s; + } + out() << "
    • Detailed Description
    • \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() << "
    • "; + out() << ""; + generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); + out() << "
    • \n"; + } + while (!sectionNumber.isEmpty()) { + sectionNumber.removeLast(); + } + out() << "
    \n"; + out() << "
    \n"; + inContents = false; + inLink = false; +} + +QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, + CodeMarker *marker) +{ + QList
    sections; + QList
    ::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() << "

    This is the complete list of members for "; + generateFullName(inner, 0, marker); + out() << ", including inherited members.

    \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
    sections; + QList
    ::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() << "

    This is the complete list of members for "; + generateFullName(qml_cn, 0, marker); + out() << ", including inherited members.

    \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
    sections = marker->sections(inner, + CodeMarker::Summary, + status); + QMutableListIterator
    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() << "

    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.

    \n"; + } + else { + out() << "

    The following class members are obsolete. " + << "They are provided to keep old source code working. " + << "We strongly advise against using them in new code.

    \n"; + } + + out() << "

    \n"; + + for (i = 0; i < sections.size(); ++i) { + out() << "

    " << protectEnc(sections.at(i).name) << "

    \n"; + generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); + } + + sections = marker->sections(inner, CodeMarker::Detailed, status); + for (i = 0; i < sections.size(); ++i) { + //out() << "
    \n"; + out() << "

    " << protectEnc(sections.at(i).name) << "

    \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 &classMap) +{ + if (classMap.isEmpty()) + return; + + NodeMap topLevel; + NodeMap::ConstIterator c = classMap.begin(); + while (c != classMap.end()) { + const ClassNode *classe = static_cast(*c); + if (classe->baseClasses().isEmpty()) + topLevel.insert(classe->name(), classe); + ++c; + } + + QStack stack; + stack.push(topLevel); + + out() << "
      \n"; + while (!stack.isEmpty()) { + if (stack.top().isEmpty()) { + stack.pop(); + out() << "
    \n"; + } + else { + const ClassNode *child = + static_cast(*stack.top().begin()); + out() << "
  • "; + generateFullName(child, relative, marker); + out() << "
  • \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() << "
      \n"; + } + } + } +} + +void HtmlGenerator::generateAnnotatedList(const Node *relative, + CodeMarker *marker, + const NodeMap &nodeMap, + bool allOdd) +{ + out() << "\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() << ""; + else + out() << ""; + out() << ""; + + if (!(node->type() == Node::Fake)) { + Text brief = node->doc().trimmedBriefText(name); + if (!brief.isEmpty()) { + out() << ""; + } + } + else { + out() << ""; + } + out() << "\n"; + } + out() << "

      "; + generateFullName(node, relative, marker); + out() << "

      "; + generateText(brief, node, marker); + out() << "

      "; + out() << protectEnc(node->doc().briefText().toString()); + out() << "

      \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 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 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"; + for (int i = 0; i < 26; i++) { + QChar ch('a' + i); + if (usedParagraphNames.contains(char('a' + i))) + out() << QString("%2 ").arg(ch).arg(ch.toUpper()); + } + out() << "

      \n"; + } + + /* + Output a
      element to contain all the
      elements. + */ + out() << "
      \n"; + numTableRows = 0; + + int curParNr = 0; + int curParOffset = 0; + + for (int i=0; i. + */ + if (curParOffset == 0) { + if (i > 0) + out() << "
      \n"; + if (++numTableRows % 2 == 1) + out() << "
      "; + else + out() << "
      "; + out() << "
      "; + if (includeAlphabet) { + QChar c = paragraphName[curParNr][0].toLower(); + out() << QString("").arg(c); + } + out() << "" + << paragraphName[curParNr] + << ""; + out() << "
      \n"; + } + + /* + Output a
      for the current offset in the current paragraph. + */ + out() << "
      "; + if ((curParNr < NumParagraphs) && + !paragraphName[curParNr].isEmpty()) { + NodeMap::Iterator it; + it = paragraph[curParNr].begin(); + for (int i=0; i"; + + 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() << ""; + if (pieces.size() > 1) { + out() << " ("; + generateFullName(it.value()->parent(), relative, marker); + out() << ')'; + } + } + out() << "
      \n"; + curParOffset++; + } + if (classMap.count() > 0) + out() << "
      \n"; + + out() << "
      \n"; +} + +void HtmlGenerator::generateFunctionIndex(const Node *relative, + CodeMarker *marker) +{ + out() << "

      "; + for (int i = 0; i < 26; i++) { + QChar ch('a' + i); + out() << QString("%2 ").arg(ch).arg(ch.toUpper()); + } + out() << "

      \n"; + + char nextLetter = 'a'; + char currentLetter; + +#if 1 + out() << "
        \n"; +#endif + QMap::ConstIterator f = funcIndex.begin(); + while (f != funcIndex.end()) { +#if 1 + out() << "
      • "; +#else + out() << "

        "; +#endif + out() << protectEnc(f.key()) << ':'; + + currentLetter = f.key()[0].unicode(); + while (islower(currentLetter) && currentLetter >= nextLetter) { + out() << QString("").arg(nextLetter); + nextLetter++; + } + + NodeMap::ConstIterator s = (*f).begin(); + while (s != (*f).end()) { + out() << ' '; + generateFullName((*s)->parent(), relative, marker, *s); + ++s; + } +#if 1 + out() << "

      • "; +#else + out() << "

        "; +#endif + out() << '\n'; + ++f; + } +#if 1 + out() << "
      \n"; +#endif +} + +void HtmlGenerator::generateLegaleseList(const Node *relative, + CodeMarker *marker) +{ + QMap::ConstIterator it = legaleseTexts.begin(); + while (it != legaleseTexts.end()) { + Text text = it.key(); + //out() << "
      \n"; + generateText(text, relative, marker); + out() << "
        \n"; + do { + out() << "
      • "; + generateFullName(it.value(), relative, marker); + out() << "
      • \n"; + ++it; + } while (it != legaleseTexts.end() && it.key() == text); + out() << "
      \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])"), + "\\1\\2"); + marked.replace("<@param>", ""); + marked.replace("", ""); + + if (summary) + marked.replace("@name>", "b>"); + + marked.replace("<@extra>", ""); + marked.replace("", ""); + + if (summary) { + marked.remove("<@type>"); + marked.remove(""); + } + out() << highlightedCode(marked, marker, relative, false, node); +} + +void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */) +{ + QMap > fakeNodeMap; + QMap groupTitlesMap; + QMap 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(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(member); + if (page) { + QString sortKey = page->fullTitle().toLower(); + if (sortKey.startsWith("the ")) + sortKey.remove(0, 4); + sortKey.replace(singleDigit, "0\\1"); + fakeNodeMap[const_cast(fakeNode)].insert(sortKey, page); + groupTitlesMap[fakeNode->fullTitle()] = const_cast(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(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("

      %2

      \n").arg( + linkForNode(groupNode, relative)).arg( + protectEnc(groupNode->fullTitle())); + + if (fakeNodeMap[groupNode].count() == 0) + continue; + + out() << "
        \n"; + + foreach (const FakeNode *fakeNode, fakeNodeMap[groupNode]) { + QString title = fakeNode->fullTitle(); + if (title.startsWith("The ")) + title.remove(0, 4); + out() << "
      • " + << protectEnc(title) << "
      • \n"; + } + out() << "
      \n"; + } + } + + if (!uncategorizedNodeMap.isEmpty()) { + out() << QString("

      Miscellaneous

      \n"); + out() << "
        \n"; + foreach (const FakeNode *fakeNode, uncategorizedNodeMap) { + QString title = fakeNode->fullTitle(); + if (title.startsWith("The ")) + title.remove(0, 4); + out() << "
      • " + << protectEnc(title) << "
      • \n"; + } + out() << "
      \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() << "\n"; + } + else { + if (twoColumn) + out() << "
      \n" + << "\n"; + else + out() << "\n"; + i++; + ++m; + } + if (alignNames) + out() << "
      "; + out() << "
        \n"; + } + + int i = 0; + NodeList::ConstIterator m = nl.begin(); + while (m != nl.end()) { + if ((*m)->access() == Node::Private) { + ++m; + continue; + } + + if (alignNames) { + out() << "
      "; + } + else { + if (twoColumn && i == (int) (nl.count() + 1) / 2) + out() << "
        \n"; + out() << "
      • "; + } + + generateSynopsis(*m, relative, marker, style, alignNames); + if (alignNames) + out() << "
      \n"; + else { + out() << "
    \n"; + if (twoColumn) + out() << "\n\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() << "\n"; + } + else { + if (twoColumn) + out() << "
    \n" + << "\n"; + else + out() << "\n"; + i++; + ++m; + } + if (alignNames) + out() << "
    "; + out() << "
      \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() << "
    "; + } + else { + if (twoColumn && i == (int) (section.members.count() + 1) / 2) + out() << "
      \n"; + out() << "
    • "; + } + + 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() << "
    \n"; + else { + out() << "
\n"; + if (twoColumn) + out() << "\n\n"; + } + } + + if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { + out() << "
    \n"; + generateSectionInheritedList(section, relative, marker); + out() << "
\n"; + } +} + +void HtmlGenerator::generateSectionInheritedList(const Section& section, + const Node *relative, + CodeMarker *marker) +{ + QList >::ConstIterator p = section.inherited.begin(); + while (p != section.inherited.end()) { + out() << "
  • "; + out() << (*p).second << ' '; + if ((*p).second == 1) { + out() << section.singularMember; + } + else { + out() << section.pluralMember; + } + out() << " inherited from " + << protectEnc(marker->plainFullName((*p).first, relative)) + << "
  • \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])"), + "\\1\\2"); + marked.replace("<@param>", " "); + marked.replace("", ""); + + if (style == CodeMarker::Summary) { + marked.remove("<@name>"); // was "" + marked.remove(""); // was "" + } + + if (style == CodeMarker::Subpage) { + QRegExp extraRegExp("<@extra>.*"); + extraRegExp.setMinimal(true); + marked.remove(extraRegExp); + } else { + marked.replace("<@extra>", ""); + marked.replace("", ""); + } + + if (style != CodeMarker::Detailed) { + marked.remove("<@type>"); + marked.remove(""); + } + + 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=\"([^\"]+)\">).*()" + 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 += ""; + done = true; + } + i += 2; + if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) { + html += ""; + const Node* n = CodeMarker::nodeForString(par1.toString()); + QString link = linkForNode(n, relative); + addLink(link, arg, &html); + html += ""; + } + else { + html += charLangle; + html += charAt; + } + } + else { + html += src.at(i++); + } + } + + // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)()" + 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)(?: +[^>]*)?>)(.*)()" tags + src = html; + html = QString(); + + for (int i=0, srcSize=src.size(); iresolveTarget(arg.toString(), myTree, relative, self); + html += QLatin1String(""); + 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(""); + 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>" -> ""; + // "<@preprocessor>" -> ""; + // "<@string>" -> ""; + // "<@char>" -> ""; + // "<@number>" -> ""; + // "<@op>" -> ""; + // "<@type>" -> ""; + // "<@name>" -> ""; + // "<@keyword>" -> ""; + // "" -> "" + src = html; + html = QString(); + static const QString spanTags[] = { + "<@comment>", "", + "<@preprocessor>", "", + "<@string>", "", + "<@char>", "", + "<@number>", "", + "<@op>", "", + "<@type>", "", + "<@name>", "", + "<@keyword>", "", + "", "", + "", "", + "", "", + "", "", + "", "", + "", "", + "", "", + "", "", + "", "", + }; + // 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() << ""; + } else { + out() << ""; + } + 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("&"); + } else if (ch == QLatin1Char('<')) { + APPEND("<"); + } else if (ch == QLatin1Char('>')) { + APPEND(">"); + } else if (ch == QLatin1Char('"')) { + APPEND("""); + } 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(node)->subType() == Node::ExternalPage) + return node->name(); + if (static_cast(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(node); + if (typedeffe->associatedEnum()) { + return refForNode(typedeffe->associatedEnum()); + } + else { + ref = node->name() + "-typedef"; + } + break; + case Node::Function: + func = static_cast(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() << "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() << ""; +} + +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(node))->flagsType()) { +#ifdef GENERATE_MAC_REFS + generateMacRef(enume->flagsType(), marker); +#endif + out() << "

    "; + out() << ""; + generateSynopsis(enume, relative, marker, CodeMarker::Detailed); + out() << "
    "; + generateSynopsis(enume->flagsType(), + relative, + marker, + CodeMarker::Detailed); + out() << "

    \n"; + } + else { + out() << "

    "; + out() << ""; + generateSynopsis(node, relative, marker, CodeMarker::Detailed); + out() << "

    " << divNavTop << '\n'; + } + + generateStatus(node, marker); + generateBody(node, marker); + generateThreadSafeness(node, marker); + generateSince(node, marker); + + if (node->type() == Node::Property) { + const PropertyNode *property = static_cast(node); + Section section; + + section.members += property->getters(); + section.members += property->setters(); + section.members += property->resetters(); + + if (!section.members.isEmpty()) { + out() << "

    Access functions:

    \n"; + generateSectionList(section, node, marker, CodeMarker::Accessors); + } + + Section notifiers; + notifiers.members += property->notifiers(); + + if (!notifiers.members.isEmpty()) { + out() << "

    Notifier signal:

    \n"; + //out() << "

    This signal is emitted when the property value is changed.

    \n"; + generateSectionList(notifiers, node, marker, CodeMarker::Accessors); + } + } + else if (node->type() == Node::Enum) { + const EnumNode *enume = static_cast(node); + if (enume->flagsType()) { + out() << "

    The " << protectEnc(enume->flagsType()->name()) + << " type is a typedef for " + << "QFlags<" + << protectEnc(enume->name()) + << ">. It stores an OR combination of " + << protectEnc(enume->name()) + << " values.

    \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(*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(*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(*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(*c)); + } + else if ((*c)->type() == Node::Function) { + const FunctionNode *func = static_cast(*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(*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(*c)); + if ((*c)->type() == Node::Namespace) { + const NamespaceNode *nspace = static_cast(*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), relative); + } + } + + if (!node) + relative->doc().location().warning(tr("Cannot link to '%1'").arg(target)); + return node; +} + +const QPair HtmlGenerator::anchorForNode(const Node *node) +{ + QPair anchorPair; + + anchorPair.first = PageGenerator::fileName(node); + if (node->type() == Node::Fake) { + const FakeNode *fakeNode = static_cast(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(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 :: , where is a QML + element or component without a module qualifier. If so, it + constructs a link to the clause on the disambiguation + page for and returns that link string. It also + adds the as a target in the NameCollisionNode for + . 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() << "\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() << ""; + } + else if (node == 0 || + (relative != 0 && node->status() == relative->status())) { + out() << ""; + } + else { + switch (node->status()) { + case Node::Obsolete: + out() << ""; + break; + case Node::Compat: + out() << ""; + break; + default: + out() << ""; + } + } + inLink = true; +} + +void HtmlGenerator::endLink() +{ + if (inLink) { + if (link.isEmpty()) { + if (showBrokenLinks) + out() << ""; + } + else { + if (inObsoleteLink) { + out() << "(obsolete)"; + } + out() << ""; + } + } + 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() << "
      \n"; + NodeList::ConstIterator m; + m = section.members.begin(); + while (m != section.members.end()) { + out() << "
    • "; + generateQmlItem(*m,relative,marker,true); + out() << "
    • \n"; + ++m; + } + out() << "
    \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() << "
    "; + if (node->subType() == Node::QmlPropertyGroup) { + const QmlPropGroupNode* qpgn = static_cast(node); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + out() << "
    "; + out() << ""; + while (p != qpgn->childNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + qpn = static_cast(*p); + out() << ""; + out() << ""; + } + ++p; + } + out() << "

    "; + out() << ""; + + int ro = qpn->getReadOnly(); + if (ro < 0) { + if (!qpn->isWritable(myTree)) { + out() << "read-only"; + } + } + else if (ro > 0) { + out() << "read-only"; + } + if (qpgn->isDefault()) + out() << "default"; + generateQmlItem(qpn, relative, marker, false); + out() << "

    "; + out() << "
    "; + } + else if (node->type() == Node::QmlProperty) { + qpn = static_cast(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(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() << "
    "; + out() << ""; + out() << ""; + out() << ""; + out() << "

    "; + out() << ""; + int ro = qpn->getReadOnly(); + if (ro < 0) { + const ClassNode* cn = qpn->declarativeCppNode(); + if (cn && !qpn->isWritable(myTree)) { + out() << "read-only"; + } + } + else if (ro > 0) { + out() << "read-only"; + } + if (qpn->isDefault()) + out() << "default"; + generateQmlItem(qpn, relative, marker, false); + out() << "

    "; + out() << "
    "; + } + 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() << "
    "; + out() << ""; + while (p != qpn->qmlPropNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + QmlPropertyNode* q = static_cast(*p); + out() << ""; + out() << ""; + } + ++p; + } + out() << "

    "; + out() << ""; + + int ro = qpn->getReadOnly(); + if (ro < 0) { + if (!qpn->isWritable(myTree)) { + out() << "read-only"; + } + } + else if (ro > 0) { + out() << "read-only"; + } + if (qpn->isDefault()) + out() << "default"; + generateQmlItem(q, relative, marker, false); + out() << "

    "; + out() << "
    "; + } + } + else if (node->type() == Node::QmlSignal) { + const FunctionNode* qsn = static_cast(node); + out() << "
    "; + out() << ""; + out() << ""; + out() << ""; + out() << "

    "; + out() << ""; + generateSynopsis(qsn,relative,marker,CodeMarker::Detailed,false); + out() << "

    "; + out() << "
    "; + } + else if (node->type() == Node::QmlSignalHandler) { + const FunctionNode* qshn = static_cast(node); + out() << "
    "; + out() << ""; + out() << ""; + out() << ""; + out() << "

    "; + out() << ""; + generateSynopsis(qshn,relative,marker,CodeMarker::Detailed,false); + out() << "

    "; + out() << "
    "; + } + else if (node->type() == Node::QmlMethod) { + const FunctionNode* qmn = static_cast(node); + out() << "
    "; + out() << ""; + out() << ""; + out() << ""; + out() << "

    "; + out() << ""; + generateSynopsis(qmn,relative,marker,CodeMarker::Detailed,false); + out() << "

    "; + out() << "
    "; + } + out() << "
    "; + generateStatus(node, marker); + generateBody(node, marker); + generateThreadSafeness(node, marker); + generateSince(node, marker); + generateAlsoList(node, marker); + out() << "
    "; + out() << "
    "; + 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 element for the given \a node using the \a writer. + Return true if a 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(node); + if (!inner->pageKeywords().isEmpty()) + pageWords << inner->pageKeywords(); + + switch (node->type()) { + case Node::Fake: + { + const FakeNode* fake = static_cast(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 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 + 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(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() << "\n"; + } else { + out() << "\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(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; n0 && wrote_one) + writer.writeCharacters(","); + writer.writeCharacters(tag); + wrote_one = true; + } + writer.writeEndElement(); // tags + } + + QString ename = en->name().mid(en->name().lastIndexOf('/')+1); + QSet 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; iisInternal() || 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(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 = ""; + + xmlWriter().writeDTD(doctype); + xmlWriter().writeStartElement("map"); + xmlWriter().writeStartElement("topicmeta"); + xmlWriter().writeStartElement("shortdesc"); + xmlWriter().writeCharacters(node->title()); + xmlWriter().writeEndElement(); // + xmlWriter().writeEndElement(); // + 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(); // or + } +} + +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 +#include +#include +#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 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
    * 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 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 moduleClassMap; + QMap moduleNamespaceMap; + NodeMap nonCompatClasses; + NodeMap mainClasses; + NodeMap compatClasses; + NodeMap obsoleteClasses; + NodeMap namespaceIndex; + NodeMap serviceClasses; + NodeMap qmlClasses; + QMap funcIndex; + QMap legaleseTexts; + QStack 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 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 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 +#include "config.h" +#include "location.h" + +#include +#include +#include + +#include + +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 *oldStk = stk; + + stkBottom = other.stkBottom; + if (other.stk == 0) { + stk = 0; + stkTop = &stkBottom; + } + else { + stk = new QStack(*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; + 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 + +#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 *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 +#include +#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 + +#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 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 " + "Define 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 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 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 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 excludedDirs; + QSet excludedFiles; + QSet headers; + QSet 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::fromList(headerList); + + sourceList = config.getAllFiles(CONFIG_SOURCES,CONFIG_SOURCEDIRS,excludedDirs,excludedFiles); + sources = QSet::fromList(sourceList); + + /* + Parse each header file in the set using the appropriate parser and add it + to the big tree. + */ + QSet usedParsers; + + QSet::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::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::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 +#include + +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 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(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; isubType() == QmlPropertyGroup) { + node = static_cast(n)->findNode(name); + if (node) + return node; + } + } + } + return primaryFunctionMap.value(name); +} +void InnerNode::findNodes(const QString& name, QList& n) +{ + n.clear(); + Node* node = 0; + QList nodes = childMap.values(name); + /* + 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; isubType() == QmlPropertyGroup) { + node = static_cast(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; isubType() != QmlPropertyGroup) + n.append(node); + else { + node = static_cast(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 nodes = childMap.values(name); + if (!nodes.isEmpty()) { + for (int i=0; iisQmlNode()) + return node; + } + else if (node->isQmlNode() && (node->subType() != QmlPropertyGroup)) + return node; + } + } + if (qml && (type() == Fake) && (subType() == QmlClass)) { + for (int i=0; isubType() == QmlPropertyGroup) { + node = static_cast(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(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::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::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::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::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::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(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(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::ConstIterator p1 = f1->parameters().begin(); + QList::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::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::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 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 &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 &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(n); + + const PropertyNode *pn = 0; + + const QList &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& 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& 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::Iterator t = params.begin(); + QList::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::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 ¶meter, 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::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; istatus() == 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 QmlClassNode::inheritedBy; +QMap 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 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(n); + if (base_ && base_->subType() == Node::QmlClass) { + return; + } + } + if (base_ && base_->subType() == Node::Collision) { + const NameCollisionNode* ncn = static_cast(base_); + const NodeList& children = ncn->childNodes(); + for (int i=0; iqmlModuleIdentifier()) { + base_ = static_cast(children.at(j)); + return; + } + } + } + QString qmid = qmlModuleIdentifier(); + for (int k=0; kqmlModuleIdentifier()) { + base_ = static_cast(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(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, .. + + QStringList path(extractClassName(pn->qualifiedDataType())); + const Node* nn = tree->findNode(path,Class); + if (nn) { + const ClassNode* cn = static_cast(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(*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(this); + if (tdn->associatedEnum()) { + return tdn->associatedEnum()->idForNode(); + } + else { + str = "typedef-" + name(); + } + break; + case Node::Function: + func = static_cast(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 (i0 && i= '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 +#include +#include +#include + +#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 NodeMap; +typedef QMultiMap NodeMultiMap; +typedef QMultiMap ExampleNodeMap; +typedef QList > 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 > 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 > 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 NodeList; +typedef QMap NodeMap; +typedef QMultiMap 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& 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 childMap; + QMap primaryFunctionMap; + QMap 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 &baseClasses() const { return bases; } + const QList &derivedClasses() const { return derived; } + const QList &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 bases; + QList derived; + QList 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& linkTargets() const { return targets; } + void addLinkTarget(const QString& t, const QString& v) { targets.insert(t,v); } + +private: + InnerNode* current; + QMap 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 inheritedBy; + static QMap 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(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& items() const { return itms; } + Access itemAccess(const QString& name) const; + const TypedefNode* flagsType() const { return ft; } + QString itemValue(const QString &name) const; + +private: + QList itms; + QSet 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& 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& parameters() const { return params; } + QStringList parameterNames() const; + QString rawParameters(bool names = false, bool values = false) const; + const FunctionNode* reimplementedFrom() const { return rf; } + const QList &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 params; + const FunctionNode* rf; + const PropertyNode* ap; + QList 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 ¶meters) +{ + 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 + +#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 + +#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 +#include +#include +#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:" <).*()"); + 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 " + 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(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(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(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(node); + collisionNodes.append(const_cast(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(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 +#include +#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 outStreamStack; + QList 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
    PlainCodeMarker::sections(const InnerNode * /* innerNode */, + SynopsisStyle /* style */, + Status /* status */) +{ + return QList
    (); +} + +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
    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 + +#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>::"); + 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 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 " declarations within \a script. + Currently supported pragmas are: library +*/ +QList QmlCodeMarker::extractPragmas(QString &script) +{ + const QString pragma(QLatin1String("pragma")); + const QString library(QLatin1String("library")); + QList 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 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 + +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 topicCommandsAllowed = topicCommands(); + QSet otherMetacommandsAllowed = otherMetaCommands(); + QSet 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 QmlCodeParser::topicCommands() +{ + return QSet() << 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 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 " 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 +#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 topicCommands(); + virtual QSet 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 +#include +#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 &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("&"); +static const QString slt = QLatin1String("<"); +static const QString sgt = QLatin1String(">"); +static const QString squot = QLatin1String("""); + +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(""); + } 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 &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")).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 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 +#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 &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 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 extraTypes; + QList 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 +#include + +#include + +#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 +#include + +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(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 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 diagnostic_messages; +}; + +} // end of namespace QQmlJS + + +:/ + + +/. + +#include "qqmljsparser_p.h" +#include + +// +// 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 (realloc(sym_stack, stack_size * sizeof(Value))); + state_stack = reinterpret_cast (realloc(state_stack, stack_size * sizeof(int))); + location_stack = reinterpret_cast (realloc(location_stack, stack_size * sizeof(AST::SourceLocation))); + string_stack = reinterpret_cast (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 nameIds; + QVarLengthArray locations; + + AST::ExpressionNode *it = expr; + while (AST::FieldMemberExpression *m = AST::cast(it)) { + nameIds.append(m->name); + locations.append(m->identifierToken); + it = m->base; + } + + if (AST::IdentifierExpression *idExpr = AST::cast(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(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(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 + +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 +_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(sourceElement)) + return funDecl->firstSourceLocation(); + else if (VariableStatement *varStmt = cast(sourceElement)) + return varStmt->firstSourceLocation(); + + return SourceLocation(); + } + + virtual SourceLocation lastSourceLocation() const + { + if (FunctionDeclaration *funDecl = cast(sourceElement)) + return funDecl->lastSourceLocation(); + else if (VariableStatement *varStmt = cast(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 + +// +// 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 +#include +#include + +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 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 +#include + +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 _comments; + QString _extraCode; + QString _code; + +public: + Engine(); + ~Engine(); + + void setCode(const QString &code); + + void addComment(int pos, int len, int line, int col); + QList 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 + +#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 + +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 +#define tr(x, y) QCoreApplication::translate(x, y) +#endif +#include +#include + +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 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 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 + +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 +#include +#include + +#include + +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 +#ifdef QT_BOOTSTRAPPED +#define tr(x, y) QString(QLatin1String(y)) +#else +#include +#define tr(x, y) QCoreApplication::translate(x, y) +#endif + +#include + +#include "qqmljsengine_p.h" +#include "qqmljslexer_p.h" +#include "qqmljsast_p.h" +#include "qqmljsmemorypool_p.h" + + + +#include "qqmljsparser_p.h" +#include + +// +// 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 (realloc(sym_stack, stack_size * sizeof(Value))); + state_stack = reinterpret_cast (realloc(state_stack, stack_size * sizeof(int))); + location_stack = reinterpret_cast (realloc(location_stack, stack_size * sizeof(AST::SourceLocation))); + string_stack = reinterpret_cast (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 nameIds; + QVarLengthArray locations; + + AST::ExpressionNode *it = expr; + while (AST::FieldMemberExpression *m = AST::cast(it)) { + nameIds.append(m->name); + locations.append(m->identifierToken); + it = m->base; + } + + if (AST::IdentifierExpression *idExpr = AST::cast(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(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(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 +#include + +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(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 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 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 +#include +#include +#include "qqmljsast_p.h" +#include "qqmljsastfwd_p.h" +#include "qqmljsengine_p.h" +#include +#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 &commands, + QSet &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 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... + + :: + :::: + + 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 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(node); + for (int i=0; iappendQmlPropNode(n); + } + else + qDebug() << " FAILED TO PARSE QML PROPERTY:" + << topicsUsed.at(i).topic << topicsUsed.at(i).args; + } + } + } + } + QSet metacommands = doc.metaCommandsUsed(); + if (metacommands.count() > 0) { + QString topic; + QStringList args; + QSet::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(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(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(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(node); + qpn->setDefault(); + } + } + else if (command == COMMAND_QMLREADONLY) { + if (node->type() == Node::QmlProperty) { + QmlPropertyNode* qpn = static_cast(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(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(current); + if (qmlClass) { + + QString name = member->name.toString(); + FunctionNode *qmlSignal = new FunctionNode(Node::QmlSignal, current, name, false); + + QList 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(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(current); + if (qmlClass) { + QString name = fd->name.toString(); + FunctionNode* qmlMethod = new FunctionNode(Node::QmlMethod, current, name, false); + QList 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(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 +#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 &commands, + QSet &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 > importList; + QSet commands; + QSet topics; + QSet 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 +#include +#include + +#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: + //! [] + * .pro, .py files: + #! [] + * .html, .qrc, .ui, .xq, .xml files: + + */ + commentHash["pro"] = "#!"; + commentHash["py"] = "#!"; + commentHash["html"] = " - + - + - + - + - + @@ -40,7 +40,7 @@ - + @@ -70,25 +70,25 @@ - + - + - + - + - + - + diff --git a/tests/auto/testlib/selftests/tst_selftests.cpp b/tests/auto/testlib/selftests/tst_selftests.cpp index 5d216992d7..a9ec4e31f2 100644 --- a/tests/auto/testlib/selftests/tst_selftests.cpp +++ b/tests/auto/testlib/selftests/tst_selftests.cpp @@ -104,7 +104,7 @@ inline bool qCompare } if (qAbs(qreal(r1.total) - qreal(r2.total)) <= qreal(r1.total)*variance) { - return compare_helper(true, "COMPARE()", file, line); + return compare_helper(true, 0, 0, 0, actual, expected, file, line); } // Whoops, didn't match. Compare the whole string for the most useful failure message. -- cgit v1.2.3 From 8854b74cf4511c758b998abfc269cc1f3a11d4a1 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Wed, 7 Mar 2012 16:17:46 +1000 Subject: selftests: Improve reporting of problems with loading expected output If the expected output file was missing (e.g. not included in selftests.qrc), tst_selftests would trigger an assert inside QList by calling QList::at() on an empty list. Make tst_selftests detect this error instead and give a meaningful error message. When loading expected output for the crashes selftest, where there are several alternative versions of the expected output, the code reused the "exp" variable when loading the alternative test output files. This caused the last file loaded to be used unintentionally if none of the alternative files had the correct number of lines. Use a different variable so that exp remains empty if none of the alternatives are valid and a failure can be reported. Change-Id: I35b2a3d905d069d3ee8dcb1447836eb68d5c8612 Reviewed-by: Rohan McGovern --- tests/auto/testlib/selftests/tst_selftests.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/auto/testlib/selftests/tst_selftests.cpp b/tests/auto/testlib/selftests/tst_selftests.cpp index a9ec4e31f2..97458abfbf 100644 --- a/tests/auto/testlib/selftests/tst_selftests.cpp +++ b/tests/auto/testlib/selftests/tst_selftests.cpp @@ -571,12 +571,13 @@ void tst_Selftests::doRunSubTest(QString const& subdir, QStringList const& logge // the actual output. if (exp.count() == 0) { QList > expArr; + QList tmp; int i = 1; do { - exp = expectedResult(subdir + QString("_%1").arg(i++), logger); - if (exp.count()) - expArr += exp; - } while (exp.count()); + tmp = expectedResult(subdir + QString("_%1").arg(i++), logger); + if (tmp.count()) + expArr += tmp; + } while (tmp.count()); for (int j = 0; j < expArr.count(); ++j) { if (res.count() == expArr.at(j).count()) { @@ -584,12 +585,24 @@ void tst_Selftests::doRunSubTest(QString const& subdir, QStringList const& logge break; } } + + if (expArr.count()) { + QVERIFY2(exp.count(), + qPrintable(QString::fromLatin1("None of the expected output files for " + "%1 format has matching line count.") + .arg(loggers.at(n)))); + } } else { QVERIFY2(res.count() == exp.count(), qPrintable(QString::fromLatin1("Mismatch in line count: %1 != %2 (%3).") .arg(res.count()).arg(exp.count()).arg(loggers.at(n)))); } + // By this point, we should have loaded a non-empty expected data file. + QVERIFY2(exp.count(), + qPrintable(QString::fromLatin1("Expected test data for %1 format is empty or not found.") + .arg(loggers.at(n)))); + // For xml output formats, verify that the log is valid XML. if (logFormat(logger) == "xunitxml" || logFormat(logger) == "xml" || logFormat(logger) == "lightxml") { QByteArray xml(actualOutputs[n]); -- cgit v1.2.3 From 4560ea230f4055d1be480f862a275639d661b339 Mon Sep 17 00:00:00 2001 From: Nick Ratelle Date: Thu, 5 Jan 2012 17:13:46 -0500 Subject: Fixes potential memory leak in qtextcodec.cpp Change-Id: I56c0a1a6cc261bd15653bc4cbb94daed1f8aa811 Reviewed-by: Olivier Goffart --- src/corelib/codecs/qtextcodec.cpp | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index 13f0ec8ce5..c031a43985 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -48,6 +48,7 @@ #include "qlist.h" #include "qfile.h" #include "qstringlist.h" +#include "qvarlengtharray.h" #ifdef Q_OS_UNIX # include "qiconvcodec_p.h" @@ -220,10 +221,7 @@ QString QWindowsLocalCodec::convertToUnicode(const char *chars, int length, Conv if (!mb || !mblen) return QString(); - const int wclen_auto = 4096; - wchar_t wc_auto[wclen_auto]; - int wclen = wclen_auto; - wchar_t *wc = wc_auto; + QVarLengthArray wc(4096); int len; QString sp; bool prepend = false; @@ -243,7 +241,7 @@ QString QWindowsLocalCodec::convertToUnicode(const char *chars, int length, Conv prev[1] = mb[0]; remainingChars = 0; len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, - prev, 2, wc, wclen); + prev, 2, wc.data(), wc.length()); if (len) { prepend = true; sp.append(QChar(wc[0])); @@ -254,18 +252,12 @@ QString QWindowsLocalCodec::convertToUnicode(const char *chars, int length, Conv } while (!(len=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, - mb, mblen, wc, wclen))) { + mb, mblen, wc.data(), wc.length()))) { int r = GetLastError(); if (r == ERROR_INSUFFICIENT_BUFFER) { - if (wc != wc_auto) { - qWarning("MultiByteToWideChar: Size changed"); - break; - } else { - wclen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, + const int wclen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mb, mblen, 0, 0); - wc = new wchar_t[wclen]; - // and try again... - } + wc.resize(wclen); } else if (r == ERROR_NO_UNICODE_TRANSLATION) { //find the last non NULL character while (mblen > 1 && !(mb[mblen-1])) @@ -283,8 +275,10 @@ QString QWindowsLocalCodec::convertToUnicode(const char *chars, int length, Conv break; } } + if (len <= 0) return QString(); + if (wc[len-1] == 0) // len - 1: we don't want terminator --len; @@ -293,9 +287,7 @@ QString QWindowsLocalCodec::convertToUnicode(const char *chars, int length, Conv state->state_data[0] = (char)state_data; state->remainingChars = remainingChars; } - QString s((QChar*)wc, len); - if (wc != wc_auto) - delete [] wc; + QString s((QChar*)wc.data(), len); if (prepend) { return sp+s; } -- cgit v1.2.3 From 316b050324042f03da8e31fde76e1fd8e16a4697 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Tue, 14 Feb 2012 11:17:36 +0100 Subject: Changelog: QEvent::Accessibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I705d21f62e6101599ab59d9b8768c47d3a536bfd Reviewed-by: Jan-Arve Sæther --- dist/changes-5.0.0 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dist/changes-5.0.0 b/dist/changes-5.0.0 index 500e97085b..97aa7bdfc6 100644 --- a/dist/changes-5.0.0 +++ b/dist/changes-5.0.0 @@ -322,6 +322,9 @@ QtCore QRegularExpressionMatchIterator. They aim to replace QRegExp with a more powerful and flexible regular expression engine. +* QEvent::AccessibilityPrepare, AccessibilityHelp and AccessibilityDescription removed: + * The enum values simply didn't make sense in the first place and should simply be dropped. + QtGui ----- * Accessibility has been refactored. The hierachy of accessible objects is implemented via -- cgit v1.2.3 From b55ed97e7967fca675fa43a8c0cd7445bbbbb493 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 7 Mar 2012 13:39:57 +0100 Subject: Call updateAccessibility with the right index. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Qt 4 index 0 was the widget itself. With the cleanup of child index this now changed. The default constructor uses -1 as parameter to signify that the widget is the cause, not a child. Change-Id: I329a1cc91bf2d1d1d8534739acbddfe107f40364 Reviewed-by: Jan-Arve Sæther --- src/widgets/dialogs/qdialog.cpp | 4 ++-- src/widgets/dialogs/qmessagebox.cpp | 2 +- src/widgets/graphicsview/qgraphicsscene.cpp | 2 +- src/widgets/kernel/qwhatsthis.cpp | 4 ++-- src/widgets/kernel/qwidget.cpp | 14 +++++------ src/widgets/widgets/qabstractbutton.cpp | 2 +- src/widgets/widgets/qabstractslider.cpp | 2 +- src/widgets/widgets/qabstractspinbox.cpp | 4 ++-- src/widgets/widgets/qlineedit_p.cpp | 2 +- src/widgets/widgets/qmenu.cpp | 2 +- src/widgets/widgets/qprogressbar.cpp | 2 +- src/widgets/widgets/qwidgetlinecontrol.cpp | 4 ++-- .../other/qaccessibility/tst_qaccessibility.cpp | 28 +++++++++++----------- 13 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/widgets/dialogs/qdialog.cpp b/src/widgets/dialogs/qdialog.cpp index 4170df4799..f1a6a294d2 100644 --- a/src/widgets/dialogs/qdialog.cpp +++ b/src/widgets/dialogs/qdialog.cpp @@ -754,7 +754,7 @@ void QDialog::setVisible(bool visible) } #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::DialogStart, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::DialogStart, this)); #endif } else { @@ -763,7 +763,7 @@ void QDialog::setVisible(bool visible) #ifndef QT_NO_ACCESSIBILITY if (isVisible()) - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::DialogEnd, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::DialogEnd, this)); #endif // Reimplemented to exit a modal event loop when the dialog is hidden. diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp index 3909125fe7..e1b134ee48 100644 --- a/src/widgets/dialogs/qmessagebox.cpp +++ b/src/widgets/dialogs/qmessagebox.cpp @@ -1463,7 +1463,7 @@ void QMessageBox::showEvent(QShowEvent *e) d->updateSize(); #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::Alert, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::Alert, this)); #endif #ifdef Q_OS_WIN if (const HMENU systemMenu = qt_getWindowsSystemMenu(this)) { diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp index 015cd254d4..830853094a 100644 --- a/src/widgets/graphicsview/qgraphicsscene.cpp +++ b/src/widgets/graphicsview/qgraphicsscene.cpp @@ -843,7 +843,7 @@ void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item, #ifndef QT_NO_ACCESSIBILITY if (focusItem) { if (QGraphicsObject *focusObj = focusItem->toGraphicsObject()) { - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::Focus, focusObj, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::Focus, focusObj)); } } #endif diff --git a/src/widgets/kernel/qwhatsthis.cpp b/src/widgets/kernel/qwhatsthis.cpp index 4a6f3518d0..1c20b98139 100644 --- a/src/widgets/kernel/qwhatsthis.cpp +++ b/src/widgets/kernel/qwhatsthis.cpp @@ -412,7 +412,7 @@ QWhatsThisPrivate::QWhatsThisPrivate() #endif } #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ContextHelpStart, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ContextHelpStart, this)); #endif } @@ -424,7 +424,7 @@ QWhatsThisPrivate::~QWhatsThisPrivate() QApplication::restoreOverrideCursor(); #endif #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ContextHelpEnd, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ContextHelpEnd, this)); #endif instance = 0; } diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index bf864503a4..03ada1ac7a 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -5965,7 +5965,7 @@ void QWidget::setFocus(Qt::FocusReason reason) // menus update the focus manually and this would create bogus events if (!(f->inherits("QMenuBar") || f->inherits("QMenu") || f->inherits("QMenuItem"))) # endif - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::Focus, f, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::Focus, f)); #endif #ifndef QT_NO_GRAPHICSVIEW if (QWExtra *topData = window()->d_func()->extra) { @@ -6045,7 +6045,7 @@ void QWidget::clearFocus() #endif { #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::Focus, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::Focus, this)); #endif } } @@ -7052,7 +7052,7 @@ void QWidgetPrivate::show_helper() #ifndef QT_NO_ACCESSIBILITY if (q->windowType() != Qt::ToolTip) // Tooltips are read aloud twice in MS narrator. - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ObjectShow, q, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ObjectShow, q)); #endif if (QApplicationPrivate::hidden_focus_widget == q) { @@ -7143,7 +7143,7 @@ void QWidgetPrivate::hide_helper() #ifndef QT_NO_ACCESSIBILITY if (wasVisible) - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ObjectHide, q, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ObjectHide, q)); #endif } @@ -7375,7 +7375,7 @@ void QWidgetPrivate::hideChildren(bool spontaneous) qApp->d_func()->sendSyntheticEnterLeave(widget); #ifndef QT_NO_ACCESSIBILITY if (!spontaneous) - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ObjectHide, widget, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ObjectHide, widget)); #endif } } @@ -10386,7 +10386,7 @@ void QWidget::setAccessibleName(const QString &name) { Q_D(QWidget); d->accessibleName = name; - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::NameChanged, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::NameChanged, this)); } QString QWidget::accessibleName() const @@ -10408,7 +10408,7 @@ void QWidget::setAccessibleDescription(const QString &description) { Q_D(QWidget); d->accessibleDescription = description; - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::DescriptionChanged, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::DescriptionChanged, this)); } QString QWidget::accessibleDescription() const diff --git a/src/widgets/widgets/qabstractbutton.cpp b/src/widgets/widgets/qabstractbutton.cpp index 80e125947e..f7c8ad7773 100644 --- a/src/widgets/widgets/qabstractbutton.cpp +++ b/src/widgets/widgets/qabstractbutton.cpp @@ -647,7 +647,7 @@ void QAbstractButton::setText(const QString &text) update(); updateGeometry(); #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::NameChanged, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::NameChanged, this)); #endif } diff --git a/src/widgets/widgets/qabstractslider.cpp b/src/widgets/widgets/qabstractslider.cpp index 6aff2e9077..b0216e5277 100644 --- a/src/widgets/widgets/qabstractslider.cpp +++ b/src/widgets/widgets/qabstractslider.cpp @@ -538,7 +538,7 @@ void QAbstractSlider::setValue(int value) emit sliderMoved((d->position = value)); } #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ValueChanged, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ValueChanged, this)); #endif sliderChange(SliderValueChange); emit valueChanged(value); diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp index e9652a9869..c083369136 100644 --- a/src/widgets/widgets/qabstractspinbox.cpp +++ b/src/widgets/widgets/qabstractspinbox.cpp @@ -976,7 +976,7 @@ void QAbstractSpinBox::keyPressEvent(QKeyEvent *event) } } #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ValueChanged, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ValueChanged, this)); #endif return; } @@ -1595,7 +1595,7 @@ void QAbstractSpinBoxPrivate::updateState(bool up, bool fromKeyboard /* = false buttonState = (up ? Up : Down) | (fromKeyboard ? Keyboard : Mouse); q->stepBy(up ? 1 : -1); #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ValueChanged, q, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ValueChanged, q)); #endif } } diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp index e3404a62de..d06e98e31a 100644 --- a/src/widgets/widgets/qlineedit_p.cpp +++ b/src/widgets/widgets/qlineedit_p.cpp @@ -144,7 +144,7 @@ void QLineEditPrivate::_q_selectionChanged() emit q->selectionChanged(); #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextSelectionChanged, q, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextSelectionChanged, q)); #endif } diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index fd030a5383..af4a87e282 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -2091,7 +2091,7 @@ void QMenu::hideEvent(QHideEvent *) d->eventLoop->exit(); d->setCurrentAction(0); #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::PopupMenuEnd, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::PopupMenuEnd, this)); #endif #ifndef QT_NO_MENUBAR if (QMenuBar *mb = qobject_cast(d->causedPopup.widget)) diff --git a/src/widgets/widgets/qprogressbar.cpp b/src/widgets/widgets/qprogressbar.cpp index 816b847cf5..c1a34bfb7a 100644 --- a/src/widgets/widgets/qprogressbar.cpp +++ b/src/widgets/widgets/qprogressbar.cpp @@ -314,7 +314,7 @@ void QProgressBar::setValue(int value) d->value = value; emit valueChanged(value); #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ValueChanged, this, 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::ValueChanged, this)); #endif if (d->repaintRequired()) repaint(); diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index 73c3d14f9b..a04339f864 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -768,7 +768,7 @@ void QWidgetLineControl::internalSetText(const QString &txt, int pos, bool edite #ifndef QT_NO_ACCESSIBILITY if (changed) - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextUpdated, parent(), 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextUpdated, parent())); #endif } @@ -1367,7 +1367,7 @@ void QWidgetLineControl::emitCursorPositionChanged() m_lastCursorPos = m_cursor; cursorPositionChanged(oldLast, m_cursor); #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextCaretMoved, parent(), 0)); + QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::TextCaretMoved, parent())); #endif } } diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index 4c370bebc7..3e3fce2e1c 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -415,7 +415,7 @@ void tst_QAccessibility::eventTest() button->setObjectName(QString("Olaf")); button->show(); - QVERIFY_EVENT(button, 0, QAccessible::ObjectShow); + QVERIFY_EVENT(button, -1, QAccessible::ObjectShow); button->setFocus(Qt::MouseFocusReason); QTestAccessibility::clearEvents(); QTest::mouseClick(button, Qt::LeftButton, 0); @@ -423,12 +423,12 @@ void tst_QAccessibility::eventTest() QVERIFY_EVENT(button, 0, QAccessible::StateChanged); button->setAccessibleName("Olaf the second"); - QVERIFY_EVENT(button, 0, QAccessible::NameChanged); + QVERIFY_EVENT(button, -1, QAccessible::NameChanged); button->setAccessibleDescription("This is a button labeled Olaf"); - QVERIFY_EVENT(button, 0, QAccessible::DescriptionChanged); + QVERIFY_EVENT(button, -1, QAccessible::DescriptionChanged); button->hide(); - QVERIFY_EVENT(button, 0, QAccessible::ObjectHide); + QVERIFY_EVENT(button, -1, QAccessible::ObjectHide); delete button; } @@ -732,16 +732,16 @@ void tst_QAccessibility::hideShowTest() window->show(); QVERIFY(!state(window).invisible); QVERIFY(!state(child).invisible); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(window, 0, QAccessible::ObjectShow))); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(child, 0, QAccessible::ObjectShow))); + QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(window, -1, QAccessible::ObjectShow))); + QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(child, -1, QAccessible::ObjectShow))); QTestAccessibility::clearEvents(); // hide() and veryfy that both window and child are invisible and get ObjectHide events. window->hide(); QVERIFY(state(window).invisible); QVERIFY(state(child).invisible); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(window, 0, QAccessible::ObjectHide))); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(child, 0, QAccessible::ObjectHide))); + QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(window, -1, QAccessible::ObjectHide))); + QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(child, -1, QAccessible::ObjectHide))); QTestAccessibility::clearEvents(); delete window; @@ -822,7 +822,7 @@ void tst_QAccessibility::mainWindowTest() QLatin1String name = QLatin1String("I am the main window"); mw->setWindowTitle(name); QTest::qWaitForWindowShown(mw); - QVERIFY_EVENT(mw, 0, QAccessible::ObjectShow); + QVERIFY_EVENT(mw, -1, QAccessible::ObjectShow); QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(mw); QCOMPARE(interface->text(QAccessible::Name), name); @@ -1052,12 +1052,12 @@ void tst_QAccessibility::scrollBarTest() scrollBar->resize(200, 50); scrollBar->show(); QVERIFY(!scrollBarInterface->state().invisible); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(scrollBar, 0, QAccessible::ObjectShow))); + QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(scrollBar, -1, QAccessible::ObjectShow))); QTestAccessibility::clearEvents(); scrollBar->hide(); QVERIFY(scrollBarInterface->state().invisible); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(scrollBar, 0, QAccessible::ObjectHide))); + QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(scrollBar, -1, QAccessible::ObjectHide))); QTestAccessibility::clearEvents(); // Test that the left/right subcontrols are set to unavailable when the scrollBar is at the minimum/maximum. @@ -1498,7 +1498,7 @@ void tst_QAccessibility::spinBoxTest() QTest::keyPress(spinBox, Qt::Key_Up); QTest::qWait(200); EventList events = QTestAccessibility::events(); - QTestAccessibilityEvent expectedEvent(spinBox, 0, (int)QAccessible::ValueChanged); + QTestAccessibilityEvent expectedEvent(spinBox, -1, (int)QAccessible::ValueChanged); QVERIFY(events.contains(expectedEvent)); delete spinBox; QTestAccessibility::clearEvents(); @@ -1769,7 +1769,7 @@ void tst_QAccessibility::lineEditTest() le->setFocus(Qt::TabFocusReason); QTestAccessibility::clearEvents(); le2->setFocus(Qt::TabFocusReason); - QTRY_VERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(le2, 0, QAccessible::Focus))); + QTRY_VERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(le2, -1, QAccessible::Focus))); le->setText(QLatin1String("500")); le->setValidator(new QIntValidator()); @@ -1789,7 +1789,7 @@ void tst_QAccessibility::lineEditTest() le3->deselect(); le3->setCursorPosition(3); QCOMPARE(textIface->cursorPosition(), 3); - QTRY_VERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(le3, 0, QAccessible::TextCaretMoved))); + QTRY_VERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(le3, -1, QAccessible::TextCaretMoved))); QCOMPARE(textIface->selectionCount(), 0); QTestAccessibility::clearEvents(); -- cgit v1.2.3 From 48209e21ec088a481c310f8b4a755209c5de0b15 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Sun, 5 Feb 2012 23:41:34 +0100 Subject: Add accessible role Desktop. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Another role that is mostly needed to make Qt based desktops accessible. Would be nice to have for KDE's Plasma in the future. Change-Id: I1d2ce9d55d677f73cc59f0a3646ee5e588c1d948 Reviewed-by: Jan-Arve Sæther (cherry picked from commit edc6fae534835a2c72edffb52255fe522a37928f) --- src/gui/accessible/qaccessible.cpp | 2 ++ src/gui/accessible/qaccessible.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index e5b290ae1f..a7843ba227 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -308,6 +308,7 @@ QT_BEGIN_NAMESPACE \value ColumnHeader A header for a column of data. \value ComboBox A list of choices that the user can select from. \value Cursor An object that represents the mouse cursor. + \value Desktop The object represents the desktop or workspace. \value Dial An object that represents a dial or knob. \value Dialog A dialog box. \value Document A document window, usually in an MDI environment. @@ -345,6 +346,7 @@ QT_BEGIN_NAMESPACE \value StaticText Static text, such as labels for other widgets. \value StatusBar A status bar. \value Table A table representing data in a grid of rows and columns. + \value Terminal A terminal or command line interface. \value TitleBar The title bar caption of a window. \value ToolBar A tool bar, which groups widgets that the user accesses frequently. \value ToolTip A tool tip which provides information about other objects. diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index 6ad1bb9da9..9aea9dbce9 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -292,6 +292,7 @@ public: // Additional Qt roles where enum value does not map directly to MSAA: LayeredPane = 0x0000003F, Terminal = 0x00000040, + Desktop = 0x00000041, UserRole = 0x0000ffff }; -- cgit v1.2.3 From d78fab531a34ee911e373eaef0fbf3626b74c07c Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Thu, 8 Mar 2012 11:20:41 +1000 Subject: testlib: Make QTestResult::verify() more robust. The statementStr parameter should always be non-null, so assert if it is null. The description parameter can be null in some cases (particularly when the verify is successful, and thus no error description is going to be displayed), so tolerate this. Change-Id: I87b416d5f3b793bc608cd4aca14a4f7fe7527488 Reviewed-by: Rohan McGovern --- src/testlib/qtestresult.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testlib/qtestresult.cpp b/src/testlib/qtestresult.cpp index 231fc8f3b1..cbededfee2 100644 --- a/src/testlib/qtestresult.cpp +++ b/src/testlib/qtestresult.cpp @@ -230,6 +230,8 @@ static bool checkStatement(bool statement, const char *msg, const char *file, in bool QTestResult::verify(bool statement, const char *statementStr, const char *description, const char *file, int line) { + QTEST_ASSERT(statementStr); + char msg[1024]; if (QTestLog::verboseLevel() >= 2) { @@ -240,7 +242,7 @@ bool QTestResult::verify(bool statement, const char *statementStr, const char * format = QTest::expectFailMode ? "'%s' returned TRUE unexpectedly. (%s)" : "'%s' returned FALSE. (%s)"; - qsnprintf(msg, 1024, format, statementStr, description); + qsnprintf(msg, 1024, format, statementStr, description ? description : ""); return checkStatement(statement, msg, file, line); } -- cgit v1.2.3 From a44da8fc12bdd1fc62311307b7cae391858a206e Mon Sep 17 00:00:00 2001 From: Pierre Rossi Date: Tue, 6 Mar 2012 16:42:03 +0100 Subject: Remove dead code. This logic was introduced as part of change I92dfb39289a359f49caa02c2caf8baf66098fb59 but isn't used anymore. Change-Id: I5bcfea99a7a2993434e1e978195a70dae52d6cfa Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qfont.cpp | 14 -------------- src/gui/text/qfont_p.h | 1 - src/gui/text/qfontengine.cpp | 16 ---------------- src/gui/text/qfontengine_p.h | 1 - 4 files changed, 32 deletions(-) diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index c68452d55a..56ff298d9b 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2733,20 +2733,6 @@ void QFontCache::updateHitCountAndTimeStamp(Engine &value) value.data->name()); } -void QFontCache::removeEngine(QFontEngine *engine) -{ - EngineCache::iterator it = engineCache.begin(); - while (it != engineCache.end()) { - if (it.value().data == engine) { - it = engineCache.erase(it); - if (--engine->cache_count == 0) - decreaseCost(engine->cache_cost); - } else { - ++it; - } - } -} - void QFontCache::insertEngine(const Key &key, QFontEngine *engine, bool insertMulti) { FC_DEBUG("QFontCache: inserting new engine %p", engine); diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h index 06cf787880..13e5fcbedd 100644 --- a/src/gui/text/qfont_p.h +++ b/src/gui/text/qfont_p.h @@ -245,7 +245,6 @@ public: void updateHitCountAndTimeStamp(Engine &value); void insertEngine(const Key &key, QFontEngine *engine, bool insertMulti = false); - void removeEngine(QFontEngine *engine); private: void increaseCost(uint cost); diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 142d627100..53c5f9fc31 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -1421,22 +1421,6 @@ bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const return true; } -void QFontEngineMulti::unloadEngine(int at) -{ - QFontEngine *fontEngine = engines.at(at); - if (fontEngine == 0) - return; - - // If there are other references to the engine, keep it around and keep the reference - if (fontEngine->ref.load() == 1) { - QFontCache::instance()->removeEngine(fontEngine); - if (fontEngine->cache_count == 0) { - delete fontEngine; - engines[at] = 0; - } - } -} - glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs) { if (glyphs.numGlyphs <= 0) diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 660e3be459..b4436426b2 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -401,7 +401,6 @@ protected: friend class QPSPrintEngineFontMulti; friend class QRawFont; virtual void loadEngine(int at) = 0; - virtual void unloadEngine(int at); QVector engines; }; -- cgit v1.2.3 From 7de046db735ffc1e17d11dca1bb815876e796cdc Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Tue, 28 Feb 2012 12:50:27 +0100 Subject: Enablers for shared graphics cache in raster paint engine Required changes for using shared graphics cache for distance field raster glyph rendering. Most of the logic is in platform plugins. Platform plugins should implement QPlatformIntegration::createImagePaintEngine() to create a subclass of QRasterEngine. Change-Id: Icf0a396e722e43b4caa2c1849aae38753cde38f1 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/image/qimage.cpp | 6 +- src/gui/kernel/qplatformintegration_qpa.cpp | 9 +++ src/gui/kernel/qplatformintegration_qpa.h | 1 + src/gui/opengl/qopenglpaintengine.cpp | 6 +- src/gui/opengl/qopenglpaintengine_p.h | 2 +- src/gui/painting/qpaintengine_raster.cpp | 19 ++++-- src/gui/painting/qpaintengine_raster_p.h | 18 ++++-- src/gui/painting/qpaintengineex.cpp | 7 ++- src/gui/painting/qpaintengineex_p.h | 4 +- src/gui/painting/qpainter.cpp | 13 ++--- src/gui/text/qdistancefield.cpp | 67 +++++++++++++++++----- src/gui/text/qdistancefield_p.h | 2 + src/gui/text/qfontengine.cpp | 4 +- src/gui/text/qfontengine_p.h | 6 +- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 6 +- .../gl2paintengineex/qpaintengineex_opengl2_p.h | 2 +- 16 files changed, 116 insertions(+), 56 deletions(-) diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 3e53b04728..61a3895a6b 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -50,6 +50,7 @@ #include "qstringlist.h" #include "qvariant.h" #include "qimagepixmapcleanuphooks_p.h" +#include "qplatformintegration_qpa.h" #include #include #include @@ -62,6 +63,7 @@ #include +#include #include #include @@ -4900,7 +4902,9 @@ QPaintEngine *QImage::paintEngine() const return 0; if (!d->paintEngine) { - d->paintEngine = new QRasterPaintEngine(const_cast(this)); + QPaintDevice *paintDevice = const_cast(this); + QPaintEngine *paintEngine = QGuiApplicationPrivate::platformIntegration()->createImagePaintEngine(paintDevice); + d->paintEngine = paintEngine ? paintEngine : new QRasterPaintEngine(paintDevice); } return d->paintEngine; diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp index 7a3fe05f7a..fd3714d303 100644 --- a/src/gui/kernel/qplatformintegration_qpa.cpp +++ b/src/gui/kernel/qplatformintegration_qpa.cpp @@ -240,6 +240,15 @@ QPlatformSharedGraphicsCache *QPlatformIntegration::createPlatformSharedGraphics return 0; } +/*! + Factory function for QPaintEngine. This function will return 0 if the platform + integration does not support creating any paint engine the given \a paintDevice. +*/ +QPaintEngine *QPlatformIntegration::createImagePaintEngine(QPaintDevice *paintDevice) const +{ + return 0; +} + /*! Returns the platforms input context. diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h index 483964b8f3..a05c0f61b7 100644 --- a/src/gui/kernel/qplatformintegration_qpa.h +++ b/src/gui/kernel/qplatformintegration_qpa.h @@ -91,6 +91,7 @@ public: virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; #endif virtual QPlatformSharedGraphicsCache *createPlatformSharedGraphicsCache(const char *cacheId) const; + virtual QPaintEngine *createImagePaintEngine(QPaintDevice *paintDevice) const; // Event dispatcher: virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const = 0; diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index eb32ac162f..73be87bc1d 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -1405,8 +1405,7 @@ void QOpenGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) // don't try to cache huge fonts or vastly transformed fonts QFontEngine *fontEngine = textItem->fontEngine(); - const qreal pixelSize = fontEngine->fontDef.pixelSize; - if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) { + if (shouldDrawCachedGlyphs(fontEngine, s->matrix) || det < 0.25f || det > 4.f) { QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat) : d->glyphCacheType; @@ -1460,8 +1459,7 @@ void QOpenGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &text bool drawCached = txtype < QTransform::TxProject; // don't try to cache huge fonts or vastly transformed fonts - const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; - if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) + if (shouldDrawCachedGlyphs(ti.fontEngine, s->matrix) || det < 0.25f || det > 4.f) drawCached = false; QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 diff --git a/src/gui/opengl/qopenglpaintengine_p.h b/src/gui/opengl/qopenglpaintengine_p.h index 0a6ef2a4d2..1b3dfbae28 100644 --- a/src/gui/opengl/qopenglpaintengine_p.h +++ b/src/gui/opengl/qopenglpaintengine_p.h @@ -157,7 +157,7 @@ public: void setRenderTextActive(bool); bool isNativePaintingActive() const; - bool supportsTransformations(qreal, const QTransform &) const { return true; } + bool supportsTransformations(QFontEngine *, const QTransform &) const { return true; } private: Q_DISABLE_COPY(QOpenGL2PaintEngineEx) diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index f2aac442dc..b5e8bca7e0 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -2465,6 +2465,15 @@ static inline bool monoVal(const uchar* s, int x) return (s[x>>3] << (x&7)) & 0x80; } +/*! + \internal + */ +QRasterBuffer *QRasterPaintEngine::rasterBuffer() +{ + Q_D(QRasterPaintEngine); + return d->rasterBuffer.data(); +} + /*! \internal */ @@ -2923,7 +2932,7 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) ensureRasterState(); QFontEngine *fontEngine = textItem->fontEngine(); - if (shouldDrawCachedGlyphs(fontEngine->fontDef.pixelSize, state()->matrix)) { + if (shouldDrawCachedGlyphs(fontEngine, state()->matrix)) { drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, fontEngine); } else if (state()->matrix.type() < QTransform::TxProject) { @@ -3207,18 +3216,18 @@ void QRasterPaintEngine::releaseDC(HDC) const #endif -bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const +bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine) const { const QTransform &m = state()->matrix; - return supportsTransformations(fontEngine->fontDef.pixelSize, m); + return supportsTransformations(fontEngine, m); } -bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const +bool QRasterPaintEngine::supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const { if (m.type() >= QTransform::TxProject) return true; - return !shouldDrawCachedGlyphs(pixelSize, m); + return !shouldDrawCachedGlyphs(fontEngine, m); } /*! diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h index 7b353188a3..79ed03e393 100644 --- a/src/gui/painting/qpaintengine_raster_p.h +++ b/src/gui/painting/qpaintengine_raster_p.h @@ -194,8 +194,11 @@ public: void clip(const QVectorPath &path, Qt::ClipOperation op); void clip(const QRect &rect, Qt::ClipOperation op); void clip(const QRegion ®ion, Qt::ClipOperation op); + inline const QClipData *clip() const; void drawStaticTextItem(QStaticTextItem *textItem); + virtual bool drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, + QFontEngine *fontEngine); enum ClipType { RectClip, @@ -227,14 +230,15 @@ public: static bool clearTypeFontsEnabled(); #endif + QRasterBuffer *rasterBuffer(); void alphaPenBlt(const void* src, int bpl, int depth, int rx,int ry,int w,int h); Type type() const { return Raster; } QPoint coordinateOffset() const; - bool supportsTransformations(const QFontEngine *fontEngine) const; - bool supportsTransformations(qreal pixelSize, const QTransform &m) const; + bool supportsTransformations(QFontEngine *fontEngine) const; + bool supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const; protected: QRasterPaintEngine(QRasterPaintEnginePrivate &d, QPaintDevice *); @@ -247,10 +251,6 @@ private: void fillRect(const QRectF &rect, QSpanData *data); void drawBitmap(const QPointF &pos, const QImage &image, QSpanData *fill); - bool drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, - QFontEngine *fontEngine); - - bool setClipRectInDeviceCoords(const QRect &r, Qt::ClipOperation op); inline void ensureBrush(const QBrush &brush) { @@ -492,6 +492,12 @@ inline const QClipData *QRasterPaintEnginePrivate::clip() const { return baseClip.data(); } +inline const QClipData *QRasterPaintEngine::clip() const { + Q_D(const QRasterPaintEngine); + if (state() && state()->clip && state()->clip->enabled) + return state()->clip; + return d->baseClip.data(); +} QT_END_NAMESPACE #endif // QPAINTENGINE_RASTER_P_H diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 93f36ba0ab..36414f4774 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -1081,9 +1081,9 @@ void QPaintEngineEx::drawStaticTextItem(QStaticTextItem *staticTextItem) } } -bool QPaintEngineEx::supportsTransformations(qreal pixelSize, const QTransform &m) const +bool QPaintEngineEx::supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const { - Q_UNUSED(pixelSize); + Q_UNUSED(fontEngine); if (!m.isAffine()) return true; @@ -1091,8 +1091,9 @@ bool QPaintEngineEx::supportsTransformations(qreal pixelSize, const QTransform & return false; } -bool QPaintEngineEx::shouldDrawCachedGlyphs(qreal pixelSize, const QTransform &m) const +bool QPaintEngineEx::shouldDrawCachedGlyphs(QFontEngine *fontEngine, const QTransform &m) const { + qreal pixelSize = fontEngine->fontDef.pixelSize; return (pixelSize * pixelSize * qAbs(m.determinant())) < QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE; } diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 62c5d972de..bc944b2297 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -226,8 +226,8 @@ public: IsEmulationEngine = 0x02 // If set, this object is a QEmulationEngine. }; virtual uint flags() const {return 0;} - virtual bool supportsTransformations(qreal pixelSize, const QTransform &m) const; - virtual bool shouldDrawCachedGlyphs(qreal pixelSize, const QTransform &m) const; + virtual bool supportsTransformations(QFontEngine *fontEngine, const QTransform &m) const; + virtual bool shouldDrawCachedGlyphs(QFontEngine *fontEngine, const QTransform &m) const; protected: QPaintEngineEx(QPaintEngineExPrivate &data); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 0f5468df4e..973dabc4cb 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -5551,14 +5551,9 @@ void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun) QVarLengthArray fixedPointPositions(count); QRawFontPrivate *fontD = QRawFontPrivate::get(font); - bool supportsTransformations; - if (d->extended != 0) { - supportsTransformations = d->extended->supportsTransformations(fontD->fontEngine->fontDef.pixelSize, - d->state->matrix); - } else { - supportsTransformations = d->engine->type() == QPaintEngine::CoreGraphics - || d->state->matrix.isAffine(); - } + bool supportsTransformations = d->extended + ? d->extended->supportsTransformations(fontD->fontEngine, d->state->matrix) + : d->engine->type() == QPaintEngine::CoreGraphics || d->state->matrix.isAffine(); for (int i=0; iextended->supportsTransformations(staticText_d->font.pixelSize(), + bool supportsTransformations = d->extended->supportsTransformations(staticText_d->font.d->engineForScript(QUnicodeTables::Common), d->state->matrix); if (supportsTransformations && !staticText_d->untransformedCoordinates) { staticText_d->untransformedCoordinates = true; diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp index fb06a26c8f..a1deb47175 100644 --- a/src/gui/text/qdistancefield.cpp +++ b/src/gui/text/qdistancefield.cpp @@ -692,17 +692,8 @@ static QImage makeDistanceField(int imgSize, const QPainterPath &path, int dfSca return image; } -bool qt_fontHasNarrowOutlines(const QRawFont &f) +static bool imageHasNarrowOutlines(const QImage &im) { - QRawFont font = f; - font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE); - Q_ASSERT(font.isValid()); - - QVector glyphIndices = font.glyphIndexesForString(QLatin1String("O")); - if (glyphIndices.size() < 1) - return false; - - QImage im = font.alphaMapForGlyph(glyphIndices.at(0), QRawFont::PixelAntialiasing); if (im.isNull()) return false; @@ -742,6 +733,56 @@ bool qt_fontHasNarrowOutlines(const QRawFont &f) return minHThick == 1 || minVThick == 1; } +bool qt_fontHasNarrowOutlines(QFontEngine *fontEngine) +{ + QFontEngine *fe = fontEngine->cloneWithSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE); + + QGlyphLayout glyphs; + glyph_t glyph; + glyphs.glyphs = &glyph; + int numGlyphs; + QChar *chars = QString(QLatin1String("O")).data(); + fe->stringToCMap(chars, 1, &glyphs, &numGlyphs, QTextEngine::GlyphIndicesOnly); + QImage im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform()); + delete fe; + + return imageHasNarrowOutlines(im); +} + +bool qt_fontHasNarrowOutlines(const QRawFont &f) +{ + QRawFont font = f; + font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE); + Q_ASSERT(font.isValid()); + + QVector glyphIndices = font.glyphIndexesForString(QLatin1String("O")); + if (glyphIndices.size() < 1) + return false; + + return imageHasNarrowOutlines(font.alphaMapForGlyph(glyphIndices.at(0), + QRawFont::PixelAntialiasing)); +} + +static QImage renderDistanceFieldPath(const QPainterPath &path, bool doubleResolution) +{ + QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE(doubleResolution), + path, + QT_DISTANCEFIELD_SCALE(doubleResolution), + QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution)); + return im; +} + +QImage qt_renderDistanceFieldGlyph(QFontEngine *fe, glyph_t glyph, bool doubleResolution) +{ + QFixedPoint position; + QPainterPath path; + fe->addGlyphsToPath(&glyph, &position, 1, &path, 0); + path.translate(-path.boundingRect().topLeft()); + path.setFillRule(Qt::WindingFill); + + return renderDistanceFieldPath(path, doubleResolution); +} + QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution) { QRawFont renderFont = font; @@ -751,11 +792,7 @@ QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool dou path.translate(-path.boundingRect().topLeft()); path.setFillRule(Qt::WindingFill); - QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE(doubleResolution), - path, - QT_DISTANCEFIELD_SCALE(doubleResolution), - QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution)); - return im; + return renderDistanceFieldPath(path, doubleResolution); } QT_END_NAMESPACE diff --git a/src/gui/text/qdistancefield_p.h b/src/gui/text/qdistancefield_p.h index 486d291b78..bf87e7d3cb 100644 --- a/src/gui/text/qdistancefield_p.h +++ b/src/gui/text/qdistancefield_p.h @@ -79,6 +79,8 @@ QT_BEGIN_NAMESPACE bool Q_GUI_EXPORT qt_fontHasNarrowOutlines(const QRawFont &f); QImage Q_GUI_EXPORT qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution); +bool Q_GUI_EXPORT qt_fontHasNarrowOutlines(QFontEngine *fontEngine); +QImage Q_GUI_EXPORT qt_renderDistanceFieldGlyph(QFontEngine *fontEngine, glyph_t glyph, bool doubleResolution); QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 53c5f9fc31..364a356b96 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -775,7 +775,7 @@ QByteArray QFontEngine::getSfntTable(uint tag) const return table; } -void QFontEngine::setGlyphCache(void *key, QFontEngineGlyphCache *data) +void QFontEngine::setGlyphCache(const void *key, QFontEngineGlyphCache *data) { Q_ASSERT(data); @@ -794,7 +794,7 @@ void QFontEngine::setGlyphCache(void *key, QFontEngineGlyphCache *data) } -QFontEngineGlyphCache *QFontEngine::glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const +QFontEngineGlyphCache *QFontEngine::glyphCache(const void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const { for (QLinkedList::const_iterator it = m_glyphCaches.constBegin(), end = m_glyphCaches.constEnd(); it != end; ++it) { QFontEngineGlyphCache *c = it->cache.data(); diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index b4436426b2..1114cdf12c 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -239,8 +239,8 @@ public: virtual HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints); - void setGlyphCache(void *key, QFontEngineGlyphCache *data); - QFontEngineGlyphCache *glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const; + void setGlyphCache(const void *key, QFontEngineGlyphCache *data); + QFontEngineGlyphCache *glyphCache(const void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const; static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize); static quint32 getTrueTypeGlyphIndex(const uchar *cmap, uint unicode); @@ -284,7 +284,7 @@ protected: private: struct GlyphCacheEntry { - void *context; + const void *context; QExplicitlySharedDataPointer cache; bool operator==(const GlyphCacheEntry &other) const { return context == other.context && cache == other.cache; } }; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 29dab0e1e0..ca32adcd6f 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1432,8 +1432,7 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) // don't try to cache huge fonts or vastly transformed fonts QFontEngine *fontEngine = textItem->fontEngine(); - const qreal pixelSize = fontEngine->fontDef.pixelSize; - if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) { + if (shouldDrawCachedGlyphs(fontEngine, s->matrix) || det < 0.25f || det > 4.f) { QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat) : d->glyphCacheType; @@ -1491,8 +1490,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem bool drawCached = txtype < QTransform::TxProject; // don't try to cache huge fonts or vastly transformed fonts - const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; - if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) + if (shouldDrawCachedGlyphs(ti.fontEngine, s->matrix) || det < 0.25f || det > 4.f) drawCached = false; QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index c5d3417555..8eeee334f5 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -155,7 +155,7 @@ public: void setRenderTextActive(bool); bool isNativePaintingActive() const; - bool supportsTransformations(qreal, const QTransform &) const { return true; } + bool supportsTransformations(QFontEngine *, const QTransform &) const { return true; } private: Q_DISABLE_COPY(QGL2PaintEngineEx) }; -- cgit v1.2.3 From a27d5be4dc48e3bd7dbb2a624b17821daa60aaf0 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 23 Feb 2012 07:39:45 +0100 Subject: examples: compile w/QT_NO_CAST_FROM_BYTEARRAY, at least on Unix This is all pretty straight-forward, adding .constData() or using QString::fromLatin1() instead of QLatin1String(). Change-Id: I984706452db7d0841620a0f64e179906123f3849 Reviewed-by: Stephen Kelly --- examples/desktop/screenshot/screenshot.cpp | 2 +- examples/tools/codecs/mainwindow.cpp | 2 +- examples/touch/fingerpaint/mainwindow.cpp | 6 +++--- examples/widgets/scribble/mainwindow.cpp | 6 +++--- examples/widgets/stylesheet/stylesheeteditor.cpp | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/desktop/screenshot/screenshot.cpp b/examples/desktop/screenshot/screenshot.cpp index 7773728daa..66467d439f 100644 --- a/examples/desktop/screenshot/screenshot.cpp +++ b/examples/desktop/screenshot/screenshot.cpp @@ -102,7 +102,7 @@ void Screenshot::saveScreenshot() .arg(format.toUpper()) .arg(format)); if (!fileName.isEmpty()) - originalPixmap.save(fileName, format.toAscii()); + originalPixmap.save(fileName, format.toAscii().constData()); } //! [3] diff --git a/examples/tools/codecs/mainwindow.cpp b/examples/tools/codecs/mainwindow.cpp index 8f3c94e3d5..4adff6da6e 100644 --- a/examples/tools/codecs/mainwindow.cpp +++ b/examples/tools/codecs/mainwindow.cpp @@ -99,7 +99,7 @@ void MainWindow::save() QByteArray codecName = action->data().toByteArray(); QTextStream out(&file); - out.setCodec(codecName); + out.setCodec(codecName.constData()); out << textEdit->toPlainText(); } } diff --git a/examples/touch/fingerpaint/mainwindow.cpp b/examples/touch/fingerpaint/mainwindow.cpp index 288068fa09..be005cf612 100644 --- a/examples/touch/fingerpaint/mainwindow.cpp +++ b/examples/touch/fingerpaint/mainwindow.cpp @@ -206,12 +206,12 @@ bool MainWindow::saveFile(const QByteArray &fileFormat) QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), initialPath, tr("%1 Files (*.%2);;All Files (*)") - .arg(QString(fileFormat.toUpper())) - .arg(QString(fileFormat))); + .arg(QString::fromLatin1(fileFormat.toUpper())) + .arg(QString::fromLatin1(fileFormat))); if (fileName.isEmpty()) { return false; } else { - return scribbleArea->saveImage(fileName, fileFormat); + return scribbleArea->saveImage(fileName, fileFormat.constData()); } } //! [20] diff --git a/examples/widgets/scribble/mainwindow.cpp b/examples/widgets/scribble/mainwindow.cpp index 4a59e93a61..00bf9884c9 100644 --- a/examples/widgets/scribble/mainwindow.cpp +++ b/examples/widgets/scribble/mainwindow.cpp @@ -239,12 +239,12 @@ bool MainWindow::saveFile(const QByteArray &fileFormat) QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), initialPath, tr("%1 Files (*.%2);;All Files (*)") - .arg(QString(fileFormat.toUpper())) - .arg(QString(fileFormat))); + .arg(QString::fromLatin1(fileFormat.toUpper())) + .arg(QString::fromLatin1(fileFormat))); if (fileName.isEmpty()) { return false; } else { - return scribbleArea->saveImage(fileName, fileFormat); + return scribbleArea->saveImage(fileName, fileFormat.constData()); } } //! [20] diff --git a/examples/widgets/stylesheet/stylesheeteditor.cpp b/examples/widgets/stylesheet/stylesheeteditor.cpp index 88f5100d12..5514291a7f 100644 --- a/examples/widgets/stylesheet/stylesheeteditor.cpp +++ b/examples/widgets/stylesheet/stylesheeteditor.cpp @@ -85,7 +85,7 @@ void StyleSheetEditor::loadStyleSheet(const QString &sheetName) { QFile file(":/qss/" + sheetName.toLower() + ".qss"); file.open(QFile::ReadOnly); - QString styleSheet = QLatin1String(file.readAll()); + QString styleSheet = QString::fromLatin1(file.readAll()); ui.styleTextEdit->setPlainText(styleSheet); qApp->setStyleSheet(styleSheet); -- cgit v1.2.3 From 84984af0e11029716a5a601869964470dff2d0be Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Sun, 26 Feb 2012 21:04:57 +0000 Subject: Remove usage of QtXml from rcc, add test Ported from QDom to QXmlStreamReader. This enables removal of QtXml classes from bootstrap. A new rcc test was added, copying the data from the QResourceFileEngine test. The new test runs rcc to create binary resources, dynamically loads them under various locales and checks that they do contain the expected files. Change-Id: I15d23dfda45de851a421156951ce2a60af4c1f7f Reviewed-by: Lars Knoll Reviewed-by: hjk --- src/tools/rcc/rcc.cpp | 304 +++++++++++-------- tests/auto/tools/rcc/.gitignore | 1 + .../tools/rcc/data/binary/aliasdir/aliasdir.txt | 1 + .../tools/rcc/data/binary/aliasdir/compressme.txt | 322 +++++++++++++++++++++ tests/auto/tools/rcc/data/binary/aliases.expected | 4 + tests/auto/tools/rcc/data/binary/aliases.qrc | 10 + .../tools/rcc/data/binary/allfeatures.de.expected | 13 + .../rcc/data/binary/allfeatures.de_CH.expected | 13 + .../tools/rcc/data/binary/allfeatures.expected | 13 + .../tools/rcc/data/binary/allfeatures.ko.expected | 13 + .../auto/tools/rcc/data/binary/allfeatures.locale | 3 + tests/auto/tools/rcc/data/binary/allfeatures.qrc | 30 ++ tests/auto/tools/rcc/data/binary/blahblah.txt | 1 + tests/auto/tools/rcc/data/binary/currentdir.txt | 1 + tests/auto/tools/rcc/data/binary/currentdir2.txt | 1 + .../auto/tools/rcc/data/binary/locale.de.expected | 5 + .../tools/rcc/data/binary/locale.de_CH.expected | 6 + tests/auto/tools/rcc/data/binary/locale.expected | 4 + .../auto/tools/rcc/data/binary/locale.it.expected | 6 + tests/auto/tools/rcc/data/binary/locale.locale | 3 + tests/auto/tools/rcc/data/binary/locale.qrc | 30 ++ tests/auto/tools/rcc/data/binary/multiple.expected | 5 + tests/auto/tools/rcc/data/binary/multiple.qrc | 10 + .../tools/rcc/data/binary/otherdir/otherdir.txt | 1 + tests/auto/tools/rcc/data/binary/prefixes.expected | 6 + tests/auto/tools/rcc/data/binary/prefixes.qrc | 21 ++ tests/auto/tools/rcc/data/binary/search_file.txt | 1 + .../rcc/data/binary/searchpath1/search_file.txt | 1 + .../rcc/data/binary/searchpath2/search_file.txt | 1 + tests/auto/tools/rcc/data/binary/simple.expected | 3 + tests/auto/tools/rcc/data/binary/simple.qrc | 7 + tests/auto/tools/rcc/data/binary/subdir/subdir.txt | 1 + tests/auto/tools/rcc/data/binary/test/german.txt | 1 + .../auto/tools/rcc/data/binary/test/test/test1.txt | 1 + .../auto/tools/rcc/data/binary/test/test/test2.txt | 1 + tests/auto/tools/rcc/data/binary/test/testdir.txt | 1 + tests/auto/tools/rcc/data/binary/test/testdir2.txt | 1 + tests/auto/tools/rcc/data/images.bin.expected | Bin 663 -> 0 bytes tests/auto/tools/rcc/data/images.expected | 126 -------- tests/auto/tools/rcc/data/images.qrc | 7 - tests/auto/tools/rcc/data/images/circle.png | Bin 165 -> 0 bytes .../auto/tools/rcc/data/images/images.bin.expected | Bin 0 -> 663 bytes tests/auto/tools/rcc/data/images/images.expected | 126 ++++++++ tests/auto/tools/rcc/data/images/images.qrc | 7 + tests/auto/tools/rcc/data/images/images/circle.png | Bin 0 -> 165 bytes tests/auto/tools/rcc/data/images/images/square.png | Bin 0 -> 94 bytes .../rcc/data/images/images/subdir/triangle.png | Bin 0 -> 170 bytes tests/auto/tools/rcc/data/images/square.png | Bin 94 -> 0 bytes .../auto/tools/rcc/data/images/subdir/triangle.png | Bin 170 -> 0 bytes tests/auto/tools/rcc/data/parentdir.txt | 1 + tests/auto/tools/rcc/rcc.pro | 7 - tests/auto/tools/rcc/tst_rcc.cpp | 212 +++++++++++++- 52 files changed, 1061 insertions(+), 271 deletions(-) create mode 100644 tests/auto/tools/rcc/data/binary/aliasdir/aliasdir.txt create mode 100644 tests/auto/tools/rcc/data/binary/aliasdir/compressme.txt create mode 100644 tests/auto/tools/rcc/data/binary/aliases.expected create mode 100644 tests/auto/tools/rcc/data/binary/aliases.qrc create mode 100644 tests/auto/tools/rcc/data/binary/allfeatures.de.expected create mode 100644 tests/auto/tools/rcc/data/binary/allfeatures.de_CH.expected create mode 100644 tests/auto/tools/rcc/data/binary/allfeatures.expected create mode 100644 tests/auto/tools/rcc/data/binary/allfeatures.ko.expected create mode 100644 tests/auto/tools/rcc/data/binary/allfeatures.locale create mode 100644 tests/auto/tools/rcc/data/binary/allfeatures.qrc create mode 100644 tests/auto/tools/rcc/data/binary/blahblah.txt create mode 100644 tests/auto/tools/rcc/data/binary/currentdir.txt create mode 100644 tests/auto/tools/rcc/data/binary/currentdir2.txt create mode 100644 tests/auto/tools/rcc/data/binary/locale.de.expected create mode 100644 tests/auto/tools/rcc/data/binary/locale.de_CH.expected create mode 100644 tests/auto/tools/rcc/data/binary/locale.expected create mode 100644 tests/auto/tools/rcc/data/binary/locale.it.expected create mode 100644 tests/auto/tools/rcc/data/binary/locale.locale create mode 100644 tests/auto/tools/rcc/data/binary/locale.qrc create mode 100644 tests/auto/tools/rcc/data/binary/multiple.expected create mode 100644 tests/auto/tools/rcc/data/binary/multiple.qrc create mode 100644 tests/auto/tools/rcc/data/binary/otherdir/otherdir.txt create mode 100644 tests/auto/tools/rcc/data/binary/prefixes.expected create mode 100644 tests/auto/tools/rcc/data/binary/prefixes.qrc create mode 100644 tests/auto/tools/rcc/data/binary/search_file.txt create mode 100644 tests/auto/tools/rcc/data/binary/searchpath1/search_file.txt create mode 100644 tests/auto/tools/rcc/data/binary/searchpath2/search_file.txt create mode 100644 tests/auto/tools/rcc/data/binary/simple.expected create mode 100644 tests/auto/tools/rcc/data/binary/simple.qrc create mode 100644 tests/auto/tools/rcc/data/binary/subdir/subdir.txt create mode 100644 tests/auto/tools/rcc/data/binary/test/german.txt create mode 100644 tests/auto/tools/rcc/data/binary/test/test/test1.txt create mode 100644 tests/auto/tools/rcc/data/binary/test/test/test2.txt create mode 100644 tests/auto/tools/rcc/data/binary/test/testdir.txt create mode 100644 tests/auto/tools/rcc/data/binary/test/testdir2.txt delete mode 100644 tests/auto/tools/rcc/data/images.bin.expected delete mode 100644 tests/auto/tools/rcc/data/images.expected delete mode 100644 tests/auto/tools/rcc/data/images.qrc delete mode 100644 tests/auto/tools/rcc/data/images/circle.png create mode 100644 tests/auto/tools/rcc/data/images/images.bin.expected create mode 100644 tests/auto/tools/rcc/data/images/images.expected create mode 100644 tests/auto/tools/rcc/data/images/images.qrc create mode 100644 tests/auto/tools/rcc/data/images/images/circle.png create mode 100644 tests/auto/tools/rcc/data/images/images/square.png create mode 100644 tests/auto/tools/rcc/data/images/images/subdir/triangle.png delete mode 100644 tests/auto/tools/rcc/data/images/square.png delete mode 100644 tests/auto/tools/rcc/data/images/subdir/triangle.png create mode 100644 tests/auto/tools/rcc/data/parentdir.txt diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index dfe23983b7..8a9afec690 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -50,8 +50,7 @@ #include #include #include - -#include +#include QT_BEGIN_NAMESPACE @@ -356,6 +355,12 @@ RCCResourceLibrary::~RCCResourceLibrary() delete m_root; } +enum RCCXmlTag { + RccTag, + ResourceTag, + FileTag +}; + bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, const QString &fname, QString currentPath, bool ignoreErrors) { @@ -364,98 +369,168 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, if (!currentPath.isEmpty() && !currentPath.endsWith(slash)) currentPath += slash; - QDomDocument document; - { - QString errorMsg; - int errorLine = 0; - int errorColumn = 0; - if (!document.setContent(inputDevice, &errorMsg, &errorLine, &errorColumn)) { - if (ignoreErrors) - return true; - const QString msg = QString::fromUtf8("RCC Parse Error: '%1' Line: %2 Column: %3 [%4]\n").arg(fname).arg(errorLine).arg(errorColumn).arg(errorMsg); - m_errorDevice->write(msg.toUtf8()); - return false; - } - } - - QDomElement domRoot = document.firstChildElement(m_strings.TAG_RCC).toElement(); - if (!domRoot.isNull() && domRoot.tagName() == m_strings.TAG_RCC) { - for (QDomNode node = domRoot.firstChild(); !node.isNull(); node = node.nextSibling()) { - if (!node.isElement()) - continue; - - QDomElement child = node.toElement(); - if (!child.isNull() && child.tagName() == m_strings.TAG_RESOURCE) { - QLocale::Language language = QLocale::c().language(); - QLocale::Country country = QLocale::c().country(); - - if (child.hasAttribute(m_strings.ATTRIBUTE_LANG)) { - QString attribute = child.attribute(m_strings.ATTRIBUTE_LANG); - QLocale lang = QLocale(attribute); - language = lang.language(); - if (2 == attribute.length()) { - // Language only - country = QLocale::AnyCountry; - } else { - country = lang.country(); + QXmlStreamReader reader(inputDevice); + QStack tokens; + + QString prefix; + QLocale::Language language = QLocale::c().language(); + QLocale::Country country = QLocale::c().country(); + QString alias; + int compressLevel = m_compressLevel; + int compressThreshold = m_compressThreshold; + + while (!reader.atEnd()) { + QXmlStreamReader::TokenType t = reader.readNext(); + switch (t) { + case QXmlStreamReader::StartElement: + if (reader.name() == m_strings.TAG_RCC) { + if (!tokens.isEmpty()) + reader.raiseError(QLatin1String("expected tag")); + else + tokens.push(RccTag); + } else if (reader.name() == m_strings.TAG_RESOURCE) { + if (tokens.isEmpty() || tokens.top() != RccTag) { + reader.raiseError(QLatin1String("unexpected tag")); + } else { + tokens.push(ResourceTag); + + QXmlStreamAttributes attributes = reader.attributes(); + language = QLocale::c().language(); + country = QLocale::c().country(); + + if (attributes.hasAttribute(m_strings.ATTRIBUTE_LANG)) { + QString attribute = attributes.value(m_strings.ATTRIBUTE_LANG).toString(); + QLocale lang = QLocale(attribute); + language = lang.language(); + if (2 == attribute.length()) { + // Language only + country = QLocale::AnyCountry; + } else { + country = lang.country(); + } } + + prefix.clear(); + if (attributes.hasAttribute(m_strings.ATTRIBUTE_PREFIX)) + prefix = attributes.value(m_strings.ATTRIBUTE_PREFIX).toString(); + if (!prefix.startsWith(slash)) + prefix.prepend(slash); + if (!prefix.endsWith(slash)) + prefix += slash; + } + } else if (reader.name() == m_strings.TAG_FILE) { + if (tokens.isEmpty() || tokens.top() != ResourceTag) { + reader.raiseError(QLatin1String("unexpected tag")); + } else { + tokens.push(FileTag); + + QXmlStreamAttributes attributes = reader.attributes(); + alias.clear(); + if (attributes.hasAttribute(m_strings.ATTRIBUTE_ALIAS)) + alias = attributes.value(m_strings.ATTRIBUTE_ALIAS).toString(); + + compressLevel = m_compressLevel; + if (attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESS)) + compressLevel = attributes.value(m_strings.ATTRIBUTE_COMPRESS).toString().toInt(); + + compressThreshold = m_compressThreshold; + if (attributes.hasAttribute(m_strings.ATTRIBUTE_THRESHOLD)) + compressThreshold = attributes.value(m_strings.ATTRIBUTE_THRESHOLD).toString().toInt(); + + // Special case for -no-compress. Overrides all other settings. + if (m_compressLevel == -2) + compressLevel = 0; + } + } else { + reader.raiseError(QString(QLatin1String("unexpected tag: %1")).arg(reader.name().toString())); + } + break; + + case QXmlStreamReader::EndElement: + if (reader.name() == m_strings.TAG_RCC) { + if (!tokens.isEmpty() && tokens.top() == RccTag) + tokens.pop(); + else + reader.raiseError(QLatin1String("unexpected closing tag")); + } else if (reader.name() == m_strings.TAG_RESOURCE) { + if (!tokens.isEmpty() && tokens.top() == ResourceTag) + tokens.pop(); + else + reader.raiseError(QLatin1String("unexpected closing tag")); + } else if (reader.name() == m_strings.TAG_FILE) { + if (!tokens.isEmpty() && tokens.top() == FileTag) + tokens.pop(); + else + reader.raiseError(QLatin1String("unexpected closing tag")); + } + break; + + case QXmlStreamReader::Characters: + if (reader.isWhitespace()) + break; + if (tokens.isEmpty() || tokens.top() != FileTag) { + reader.raiseError(QLatin1String("unexpected text")); + } else { + QString fileName = reader.text().toString(); + if (fileName.isEmpty()) { + const QString msg = QString::fromLatin1("RCC: Warning: Null node in XML of '%1'\n").arg(fname); + m_errorDevice->write(msg.toUtf8()); } - QString prefix; - if (child.hasAttribute(m_strings.ATTRIBUTE_PREFIX)) - prefix = child.attribute(m_strings.ATTRIBUTE_PREFIX); - if (!prefix.startsWith(slash)) - prefix.prepend(slash); - if (!prefix.endsWith(slash)) - prefix += slash; - - for (QDomNode res = child.firstChild(); !res.isNull(); res = res.nextSibling()) { - if (res.isElement() && res.toElement().tagName() == m_strings.TAG_FILE) { - - QString fileName(res.firstChild().toText().data()); - if (fileName.isEmpty()) { - const QString msg = QString::fromUtf8("RCC: Warning: Null node in XML of '%1'\n").arg(fname); - m_errorDevice->write(msg.toUtf8()); - } - QString alias; - if (res.toElement().hasAttribute(m_strings.ATTRIBUTE_ALIAS)) - alias = res.toElement().attribute(m_strings.ATTRIBUTE_ALIAS); - else - alias = fileName; - - int compressLevel = m_compressLevel; - if (res.toElement().hasAttribute(m_strings.ATTRIBUTE_COMPRESS)) - compressLevel = res.toElement().attribute(m_strings.ATTRIBUTE_COMPRESS).toInt(); - int compressThreshold = m_compressThreshold; - if (res.toElement().hasAttribute(m_strings.ATTRIBUTE_THRESHOLD)) - compressThreshold = res.toElement().attribute(m_strings.ATTRIBUTE_THRESHOLD).toInt(); - - // Special case for -no-compress. Overrides all other settings. - if (m_compressLevel == -2) - compressLevel = 0; - - alias = QDir::cleanPath(alias); - while (alias.startsWith(QLatin1String("../"))) - alias.remove(0, 3); - alias = QDir::cleanPath(m_resourceRoot) + prefix + alias; - - QString absFileName = fileName; - if (QDir::isRelativePath(absFileName)) - absFileName.prepend(currentPath); - QFileInfo file(absFileName); - if (!file.exists()) { - m_failedResources.push_back(absFileName); - const QString msg = QString::fromUtf8("RCC: Error in '%1': Cannot find file '%2'\n").arg(fname).arg(fileName); - m_errorDevice->write(msg.toUtf8()); - if (ignoreErrors) - continue; - else - return false; - } else if (file.isFile()) { + if (alias.isNull()) + alias = fileName; + + alias = QDir::cleanPath(alias); + while (alias.startsWith(QLatin1String("../"))) + alias.remove(0, 3); + alias = QDir::cleanPath(m_resourceRoot) + prefix + alias; + + QString absFileName = fileName; + if (QDir::isRelativePath(absFileName)) + absFileName.prepend(currentPath); + QFileInfo file(absFileName); + if (!file.exists()) { + m_failedResources.push_back(absFileName); + const QString msg = QString::fromLatin1("RCC: Error in '%1': Cannot find file '%2'\n").arg(fname).arg(fileName); + m_errorDevice->write(msg.toUtf8()); + if (ignoreErrors) + continue; + else + return false; + } else if (file.isFile()) { + const bool arc = + addFile(alias, + RCCFileInfo(alias.section(slash, -1), + file, + language, + country, + RCCFileInfo::NoFlags, + compressLevel, + compressThreshold) + ); + if (!arc) + m_failedResources.push_back(absFileName); + } else { + QDir dir; + if (file.isDir()) { + dir.setPath(file.filePath()); + } else { + dir.setPath(file.path()); + dir.setNameFilters(QStringList(file.fileName())); + if (alias.endsWith(file.fileName())) + alias = alias.left(alias.length()-file.fileName().length()); + } + if (!alias.endsWith(slash)) + alias += slash; + QDirIterator it(dir, QDirIterator::FollowSymlinks|QDirIterator::Subdirectories); + while (it.hasNext()) { + it.next(); + QFileInfo child(it.fileInfo()); + if (child.fileName() != QLatin1String(".") && child.fileName() != QLatin1String("..")) { const bool arc = - addFile(alias, - RCCFileInfo(alias.section(slash, -1), - file, + addFile(alias + child.fileName(), + RCCFileInfo(child.fileName(), + child, language, country, RCCFileInfo::NoFlags, @@ -463,44 +538,29 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, compressThreshold) ); if (!arc) - m_failedResources.push_back(absFileName); - } else { - QDir dir; - if (file.isDir()) { - dir.setPath(file.filePath()); - } else { - dir.setPath(file.path()); - dir.setNameFilters(QStringList(file.fileName())); - if (alias.endsWith(file.fileName())) - alias = alias.left(alias.length()-file.fileName().length()); - } - if (!alias.endsWith(slash)) - alias += slash; - QDirIterator it(dir, QDirIterator::FollowSymlinks|QDirIterator::Subdirectories); - while (it.hasNext()) { - it.next(); - QFileInfo child(it.fileInfo()); - if (child.fileName() != QLatin1String(".") && child.fileName() != QLatin1String("..")) { - const bool arc = - addFile(alias + child.fileName(), - RCCFileInfo(child.fileName(), - child, - language, - country, - RCCFileInfo::NoFlags, - compressLevel, - compressThreshold) - ); - if (!arc) - m_failedResources.push_back(child.fileName()); - } - } + m_failedResources.push_back(child.fileName()); } } } } + break; + + default: + break; } } + + if (reader.hasError()) { + if (ignoreErrors) + return true; + int errorLine = reader.lineNumber(); + int errorColumn = reader.columnNumber(); + QString errorMessage = reader.errorString(); + QString msg = QString::fromLatin1("RCC Parse Error: '%1' Line: %2 Column: %3 [%4]\n").arg(fname).arg(errorLine).arg(errorColumn).arg(errorMessage); + m_errorDevice->write(msg.toUtf8()); + return false; + } + if (m_root == 0) { const QString msg = QString::fromUtf8("RCC: Warning: No resources in '%1'.\n").arg(fname); m_errorDevice->write(msg.toUtf8()); diff --git a/tests/auto/tools/rcc/.gitignore b/tests/auto/tools/rcc/.gitignore index 1da39dbd88..6d81961fdb 100644 --- a/tests/auto/tools/rcc/.gitignore +++ b/tests/auto/tools/rcc/.gitignore @@ -1 +1,2 @@ tst_rcc +data/binary/*.rcc diff --git a/tests/auto/tools/rcc/data/binary/aliasdir/aliasdir.txt b/tests/auto/tools/rcc/data/binary/aliasdir/aliasdir.txt new file mode 100644 index 0000000000..dcf7937f0a --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/aliasdir/aliasdir.txt @@ -0,0 +1 @@ +"This is a korean text file" diff --git a/tests/auto/tools/rcc/data/binary/aliasdir/compressme.txt b/tests/auto/tools/rcc/data/binary/aliasdir/compressme.txt new file mode 100644 index 0000000000..bd596cdacd --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/aliasdir/compressme.txt @@ -0,0 +1,322 @@ +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 +111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 diff --git a/tests/auto/tools/rcc/data/binary/aliases.expected b/tests/auto/tools/rcc/data/binary/aliases.expected new file mode 100644 index 0000000000..693b633717 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/aliases.expected @@ -0,0 +1,4 @@ +currentdir.txt currentdir.txt +alias.txt currentdir2.txt +otheralias.txt blahblah.txt +alias3 ../parentdir.txt diff --git a/tests/auto/tools/rcc/data/binary/aliases.qrc b/tests/auto/tools/rcc/data/binary/aliases.qrc new file mode 100644 index 0000000000..ac049c3e65 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/aliases.qrc @@ -0,0 +1,10 @@ + + + currentdir.txt + currentdir2.txt + blahblah.txt + + + ../parentdir.txt + + diff --git a/tests/auto/tools/rcc/data/binary/allfeatures.de.expected b/tests/auto/tools/rcc/data/binary/allfeatures.de.expected new file mode 100644 index 0000000000..fa918d0039 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/allfeatures.de.expected @@ -0,0 +1,13 @@ +/test/abc/123/+++/currentdir.txt currentdir.txt +/test/abc/123/+++/currentdir2.txt ./currentdir2.txt +/test/abc/123/+++/parentdir.txt ../parentdir.txt +/test/abc/123/+++/subdir/subdir.txt subdir/subdir.txt +/search_file.txt search_file.txt +/searchpath1/search_file.txt searchpath1/search_file.txt +/searchpath2/search_file.txt searchpath2/search_file.txt +test/testdir.txt test/testdir.txt +otherdir/otherdir.txt otherdir/otherdir.txt +aliasdir/aliasdir.txt test/german.txt +test/test/test1.txt test/test/test1.txt +test/test/test2.txt test/test/test2.txt +withoutslashes/blahblah.txt blahblah.txt diff --git a/tests/auto/tools/rcc/data/binary/allfeatures.de_CH.expected b/tests/auto/tools/rcc/data/binary/allfeatures.de_CH.expected new file mode 100644 index 0000000000..59960d4187 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/allfeatures.de_CH.expected @@ -0,0 +1,13 @@ +/test/abc/123/+++/currentdir.txt currentdir.txt +/test/abc/123/+++/currentdir2.txt ./currentdir2.txt +/test/abc/123/+++/parentdir.txt ../parentdir.txt +/test/abc/123/+++/subdir/subdir.txt subdir/subdir.txt +/search_file.txt search_file.txt +/searchpath1/search_file.txt searchpath1/search_file.txt +/searchpath2/search_file.txt searchpath2/search_file.txt +test/testdir.txt test/testdir.txt +otherdir/otherdir.txt otherdir/otherdir.txt +aliasdir/aliasdir.txt aliasdir/compressme.txt +test/test/test1.txt test/test/test1.txt +test/test/test2.txt test/test/test2.txt +withoutslashes/blahblah.txt blahblah.txt diff --git a/tests/auto/tools/rcc/data/binary/allfeatures.expected b/tests/auto/tools/rcc/data/binary/allfeatures.expected new file mode 100644 index 0000000000..831120c053 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/allfeatures.expected @@ -0,0 +1,13 @@ +/test/abc/123/+++/currentdir.txt currentdir.txt +/test/abc/123/+++/currentdir2.txt ./currentdir2.txt +/test/abc/123/+++/parentdir.txt ../parentdir.txt +/test/abc/123/+++/subdir/subdir.txt subdir/subdir.txt +/search_file.txt search_file.txt +/searchpath1/search_file.txt searchpath1/search_file.txt +/searchpath2/search_file.txt searchpath2/search_file.txt +test/testdir.txt test/testdir.txt +otherdir/otherdir.txt otherdir/otherdir.txt +aliasdir/aliasdir.txt test/testdir2.txt +test/test/test1.txt test/test/test1.txt +test/test/test2.txt test/test/test2.txt +withoutslashes/blahblah.txt blahblah.txt diff --git a/tests/auto/tools/rcc/data/binary/allfeatures.ko.expected b/tests/auto/tools/rcc/data/binary/allfeatures.ko.expected new file mode 100644 index 0000000000..80b42c378e --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/allfeatures.ko.expected @@ -0,0 +1,13 @@ +/test/abc/123/+++/currentdir.txt currentdir.txt +/test/abc/123/+++/currentdir2.txt ./currentdir2.txt +/test/abc/123/+++/parentdir.txt ../parentdir.txt +/test/abc/123/+++/subdir/subdir.txt subdir/subdir.txt +/search_file.txt search_file.txt +/searchpath1/search_file.txt searchpath1/search_file.txt +/searchpath2/search_file.txt searchpath2/search_file.txt +test/testdir.txt test/testdir.txt +otherdir/otherdir.txt otherdir/otherdir.txt +aliasdir/aliasdir.txt aliasdir/aliasdir.txt +test/test/test1.txt test/test/test1.txt +test/test/test2.txt test/test/test2.txt +withoutslashes/blahblah.txt blahblah.txt diff --git a/tests/auto/tools/rcc/data/binary/allfeatures.locale b/tests/auto/tools/rcc/data/binary/allfeatures.locale new file mode 100644 index 0000000000..a6fcbab771 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/allfeatures.locale @@ -0,0 +1,3 @@ +ko +de_CH +de diff --git a/tests/auto/tools/rcc/data/binary/allfeatures.qrc b/tests/auto/tools/rcc/data/binary/allfeatures.qrc new file mode 100644 index 0000000000..1b88b1f2cd --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/allfeatures.qrc @@ -0,0 +1,30 @@ + + + currentdir.txt + ./currentdir2.txt + ../parentdir.txt + subdir/subdir.txt + + + searchpath1/search_file.txt + searchpath2/search_file.txt + search_file.txt + + test/testdir.txt + otherdir/otherdir.txt + test/testdir2.txt + test/test + + + aliasdir/aliasdir.txt + + + aliasdir/compressme.txt + + + test/german.txt + + + blahblah.txt + + diff --git a/tests/auto/tools/rcc/data/binary/blahblah.txt b/tests/auto/tools/rcc/data/binary/blahblah.txt new file mode 100644 index 0000000000..19f0805d8d --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/blahblah.txt @@ -0,0 +1 @@ +qwerty diff --git a/tests/auto/tools/rcc/data/binary/currentdir.txt b/tests/auto/tools/rcc/data/binary/currentdir.txt new file mode 100644 index 0000000000..65f1f43def --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/currentdir.txt @@ -0,0 +1 @@ +"This is the current dir" diff --git a/tests/auto/tools/rcc/data/binary/currentdir2.txt b/tests/auto/tools/rcc/data/binary/currentdir2.txt new file mode 100644 index 0000000000..7d89108011 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/currentdir2.txt @@ -0,0 +1 @@ +"This is also the current dir" diff --git a/tests/auto/tools/rcc/data/binary/locale.de.expected b/tests/auto/tools/rcc/data/binary/locale.de.expected new file mode 100644 index 0000000000..649e56be68 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/locale.de.expected @@ -0,0 +1,5 @@ +currentdir.txt currentdir.txt +currentdir2.txt currentdir2.txt +search_file.txt search_file.txt +/root/test/testdir.txt test/testdir.txt +test/testdir2.txt test/testdir2.txt diff --git a/tests/auto/tools/rcc/data/binary/locale.de_CH.expected b/tests/auto/tools/rcc/data/binary/locale.de_CH.expected new file mode 100644 index 0000000000..55b57f44d1 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/locale.de_CH.expected @@ -0,0 +1,6 @@ +currentdir.txt blahblah.txt +currentdir2.txt currentdir2.txt +search_file.txt search_file.txt +/root/test/testdir.txt test/testdir.txt +test/testdir2.txt test/testdir2.txt +parentdir.txt ../parentdir.txt diff --git a/tests/auto/tools/rcc/data/binary/locale.expected b/tests/auto/tools/rcc/data/binary/locale.expected new file mode 100644 index 0000000000..ef693bc41d --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/locale.expected @@ -0,0 +1,4 @@ +currentdir.txt currentdir.txt +search_file.txt search_file.txt +/root/test/testdir.txt test/testdir.txt +test/testdir2.txt test/testdir2.txt diff --git a/tests/auto/tools/rcc/data/binary/locale.it.expected b/tests/auto/tools/rcc/data/binary/locale.it.expected new file mode 100644 index 0000000000..0a1066e3c4 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/locale.it.expected @@ -0,0 +1,6 @@ +currentdir.txt currentdir.txt +search_file.txt search_file.txt +/root/test/testdir.txt test/testdir.txt +test/testdir2.txt test/testdir2.txt +/root/otherdir/otherdir.txt otherdir/otherdir.txt +/root/currentdir.txt subdir/subdir.txt diff --git a/tests/auto/tools/rcc/data/binary/locale.locale b/tests/auto/tools/rcc/data/binary/locale.locale new file mode 100644 index 0000000000..828b9e437c --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/locale.locale @@ -0,0 +1,3 @@ +de +de_CH +it diff --git a/tests/auto/tools/rcc/data/binary/locale.qrc b/tests/auto/tools/rcc/data/binary/locale.qrc new file mode 100644 index 0000000000..6cef47b3a2 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/locale.qrc @@ -0,0 +1,30 @@ + + + currentdir.txt + + + currentdir2.txt + ../parentdir.txt + blahblah.txt + + + search_file.txt + + + + test/testdir.txt + + + + + test/testdir2.txt + + + + otherdir/otherdir.txt + subdir/subdir.txt + + + + + diff --git a/tests/auto/tools/rcc/data/binary/multiple.expected b/tests/auto/tools/rcc/data/binary/multiple.expected new file mode 100644 index 0000000000..6515e292f6 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/multiple.expected @@ -0,0 +1,5 @@ +blahblah.txt blahblah.txt +currentdir.txt currentdir.txt +currentdir2.txt currentdir2.txt +subdir/subdir.txt subdir/subdir.txt +otherdir/otherdir.txt otherdir/otherdir.txt diff --git a/tests/auto/tools/rcc/data/binary/multiple.qrc b/tests/auto/tools/rcc/data/binary/multiple.qrc new file mode 100644 index 0000000000..80745ac6ad --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/multiple.qrc @@ -0,0 +1,10 @@ + + + blahblah.txt + currentdir.txt + currentdir2.txt + + subdir/subdir.txt + otherdir/ + + diff --git a/tests/auto/tools/rcc/data/binary/otherdir/otherdir.txt b/tests/auto/tools/rcc/data/binary/otherdir/otherdir.txt new file mode 100644 index 0000000000..e1b430f33b --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/otherdir/otherdir.txt @@ -0,0 +1 @@ +"This is the other dir" diff --git a/tests/auto/tools/rcc/data/binary/prefixes.expected b/tests/auto/tools/rcc/data/binary/prefixes.expected new file mode 100644 index 0000000000..db07fecbbe --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/prefixes.expected @@ -0,0 +1,6 @@ +blahblah.txt blahblah.txt +/myroot/currentdir.txt currentdir.txt +/myroot/currentdir2.txt currentdir2.txt +/anotherroot/aliased.txt search_file.txt +/anotherroot/parentdir.txt ../parentdir.txt +/myroot/subdir/subdir.txt subdir/subdir.txt diff --git a/tests/auto/tools/rcc/data/binary/prefixes.qrc b/tests/auto/tools/rcc/data/binary/prefixes.qrc new file mode 100644 index 0000000000..db6b15ca0c --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/prefixes.qrc @@ -0,0 +1,21 @@ + + + blahblah.txt + + + + + currentdir.txt + + currentdir2.txt + + + + + + search_file.txt + ../parentdir.txt + + subdir/subdir.txt + + diff --git a/tests/auto/tools/rcc/data/binary/search_file.txt b/tests/auto/tools/rcc/data/binary/search_file.txt new file mode 100644 index 0000000000..d8649da39d --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/search_file.txt @@ -0,0 +1 @@ +root diff --git a/tests/auto/tools/rcc/data/binary/searchpath1/search_file.txt b/tests/auto/tools/rcc/data/binary/searchpath1/search_file.txt new file mode 100644 index 0000000000..3f31b59496 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/searchpath1/search_file.txt @@ -0,0 +1 @@ +path1 diff --git a/tests/auto/tools/rcc/data/binary/searchpath2/search_file.txt b/tests/auto/tools/rcc/data/binary/searchpath2/search_file.txt new file mode 100644 index 0000000000..8e3be1fa2e --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/searchpath2/search_file.txt @@ -0,0 +1 @@ +path2 diff --git a/tests/auto/tools/rcc/data/binary/simple.expected b/tests/auto/tools/rcc/data/binary/simple.expected new file mode 100644 index 0000000000..913a33ca46 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/simple.expected @@ -0,0 +1,3 @@ +blahblah.txt blahblah.txt +currentdir.txt currentdir.txt +currentdir2.txt currentdir2.txt diff --git a/tests/auto/tools/rcc/data/binary/simple.qrc b/tests/auto/tools/rcc/data/binary/simple.qrc new file mode 100644 index 0000000000..0d4da1909f --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/simple.qrc @@ -0,0 +1,7 @@ + + + blahblah.txt + currentdir.txt + currentdir2.txt + + diff --git a/tests/auto/tools/rcc/data/binary/subdir/subdir.txt b/tests/auto/tools/rcc/data/binary/subdir/subdir.txt new file mode 100644 index 0000000000..4506acf413 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/subdir/subdir.txt @@ -0,0 +1 @@ +"This is in the sub directory" diff --git a/tests/auto/tools/rcc/data/binary/test/german.txt b/tests/auto/tools/rcc/data/binary/test/german.txt new file mode 100644 index 0000000000..12b1cb7320 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/test/german.txt @@ -0,0 +1 @@ +Deutsch diff --git a/tests/auto/tools/rcc/data/binary/test/test/test1.txt b/tests/auto/tools/rcc/data/binary/test/test/test1.txt new file mode 100644 index 0000000000..8baef1b4ab --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/test/test/test1.txt @@ -0,0 +1 @@ +abc diff --git a/tests/auto/tools/rcc/data/binary/test/test/test2.txt b/tests/auto/tools/rcc/data/binary/test/test/test2.txt new file mode 100644 index 0000000000..24c5735c3e --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/test/test/test2.txt @@ -0,0 +1 @@ +def diff --git a/tests/auto/tools/rcc/data/binary/test/testdir.txt b/tests/auto/tools/rcc/data/binary/test/testdir.txt new file mode 100644 index 0000000000..b8cb3a8c01 --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/test/testdir.txt @@ -0,0 +1 @@ +"This is in the test directory" diff --git a/tests/auto/tools/rcc/data/binary/test/testdir2.txt b/tests/auto/tools/rcc/data/binary/test/testdir2.txt new file mode 100644 index 0000000000..dccfdc9bcf --- /dev/null +++ b/tests/auto/tools/rcc/data/binary/test/testdir2.txt @@ -0,0 +1 @@ +"This is another file in this directory" diff --git a/tests/auto/tools/rcc/data/images.bin.expected b/tests/auto/tools/rcc/data/images.bin.expected deleted file mode 100644 index cb67a25477..0000000000 Binary files a/tests/auto/tools/rcc/data/images.bin.expected and /dev/null differ diff --git a/tests/auto/tools/rcc/data/images.expected b/tests/auto/tools/rcc/data/images.expected deleted file mode 100644 index 71be819310..0000000000 --- a/tests/auto/tools/rcc/data/images.expected +++ /dev/null @@ -1,126 +0,0 @@ -/**************************************************************************** -** Resource object code -** -IGNORE: ** Created: Tue Jul 15 11:17:15 2008 -IGNORE: ** by: The Resource Compiler for Qt version 4.4.2 -** -** WARNING! All changes made in this file will be lost! -*****************************************************************************/ - -#include - -static const unsigned char qt_resource_data[] = { -IGNORE: // /data5/dev/qt/tests/auto/rcc/data/images/square.png - 0x0,0x0,0x0,0x5e, - 0x89, - 0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0, - 0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x1,0x3,0x0,0x0,0x0,0x49,0xb4,0xe8,0xb7, - 0x0,0x0,0x0,0x6,0x50,0x4c,0x54,0x45,0x0,0x0,0x0,0x58,0xa8,0xff,0x8c,0x14, - 0x1f,0xab,0x0,0x0,0x0,0x13,0x49,0x44,0x41,0x54,0x8,0xd7,0x63,0x60,0x0,0x81, - 0xfa,0xff,0xff,0xff,0xd,0x3e,0x2,0x4,0x0,0x8d,0x4d,0x68,0x6b,0xcf,0xb8,0x8e, - 0x86,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82, -IGNORE: // /data5/dev/qt/tests/auto/rcc/data/images/circle.png - 0x0,0x0,0x0,0xa5, - 0x89, - 0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0, - 0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0x73,0x7a,0x7a,0xf4, - 0x0,0x0,0x0,0x6c,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0xd7,0x5b,0xe,0x0,0x10, - 0xc,0x44,0x51,0xcb,0xb4,0x44,0xbb,0x64,0x3,0x1e,0xd5,0x18,0x1d,0x31,0x12,0xdf, - 0xf7,0x7c,0xd1,0xa6,0xf4,0xe8,0xa9,0x93,0x8b,0x8f,0xe6,0x52,0x87,0x17,0x81,0x59, - 0x46,0xd,0x18,0x7f,0xdc,0x13,0x1e,0x40,0x62,0xe2,0x5e,0xc4,0xd1,0xf8,0x2e,0x2, - 0x12,0xb7,0x22,0xa0,0x71,0xb,0x22,0x14,0x70,0x25,0x3e,0x43,0xfc,0xd,0xb8,0x1a, - 0xef,0x21,0x4,0x10,0x40,0x0,0x3d,0x44,0x14,0x0,0x7d,0xc7,0x14,0x13,0x11,0xc5, - 0x4c,0x48,0x31,0x15,0x53,0xec,0x5,0x14,0x9b,0x11,0xc5,0x6e,0x8,0xdd,0x8e,0x1b, - 0x14,0x54,0x19,0xf3,0xa1,0x23,0xdb,0xd5,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44, - 0xae,0x42,0x60,0x82, -IGNORE: // /data5/dev/qt/tests/auto/rcc/data/images/subdir/triangle.png - 0x0,0x0,0x0,0xaa, - 0x89, - 0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0, - 0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0x73,0x7a,0x7a,0xf4, - 0x0,0x0,0x0,0x71,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0xce,0x4b,0xa,0x80,0x30, - 0x10,0x4,0xd1,0x1c,0xd3,0x23,0x7a,0xcb,0x11,0x82,0xb8,0x50,0x62,0x92,0xf9,0xd5, - 0x66,0x1a,0x7a,0x5d,0xaf,0xb5,0x5a,0xcd,0x36,0xb9,0xcf,0xc4,0x8f,0x53,0xfa,0x9, - 0xc4,0x13,0xa7,0x10,0x28,0xe0,0x13,0xcf,0x44,0xc,0xe3,0x59,0x8,0x14,0x30,0x8d, - 0x47,0x23,0x50,0xc0,0x72,0x3c,0x2,0xb1,0x1d,0xf7,0x46,0xa0,0x0,0x75,0xdc,0x3, - 0x61,0x8e,0x5b,0x11,0x28,0xc0,0x2d,0xae,0x45,0xa0,0x0,0xf7,0xf8,0xe,0x22,0x2c, - 0xbe,0x8a,0x40,0x1,0xe1,0xf1,0x3f,0x44,0x5a,0x7c,0x84,0x40,0x1,0xe9,0xf1,0x37, - 0x42,0xe0,0xd7,0xd8,0x5d,0xf,0x6f,0x97,0x11,0x88,0x38,0xa9,0x1e,0x0,0x0,0x0, - 0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82, - -}; - -static const unsigned char qt_resource_name[] = { - // images - 0x0,0x6, - 0x7,0x3,0x7d,0xc3, - 0x0,0x69, - 0x0,0x6d,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x73, - // square.png - 0x0,0xa, - 0x8,0x8b,0x6,0x27, - 0x0,0x73, - 0x0,0x71,0x0,0x75,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x2e,0x0,0x70,0x0,0x6e,0x0,0x67, - // circle.png - 0x0,0xa, - 0xa,0x2d,0x16,0x47, - 0x0,0x63, - 0x0,0x69,0x0,0x72,0x0,0x63,0x0,0x6c,0x0,0x65,0x0,0x2e,0x0,0x70,0x0,0x6e,0x0,0x67, - // subdir - 0x0,0x6, - 0x7,0xab,0x8b,0x2, - 0x0,0x73, - 0x0,0x75,0x0,0x62,0x0,0x64,0x0,0x69,0x0,0x72, - // triangle.png - 0x0,0xc, - 0x5,0x59,0xa7,0xc7, - 0x0,0x74, - 0x0,0x72,0x0,0x69,0x0,0x61,0x0,0x6e,0x0,0x67,0x0,0x6c,0x0,0x65,0x0,0x2e,0x0,0x70,0x0,0x6e,0x0,0x67, - -}; - -static const unsigned char qt_resource_struct[] = { - // : - 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1, - // :/images - 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x2, - // :/images/subdir - 0x0,0x0,0x0,0x46,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x5, - // :/images/square.png - 0x0,0x0,0x0,0x12,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0, - // :/images/circle.png - 0x0,0x0,0x0,0x2c,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x62, - // :/images/subdir/triangle.png - 0x0,0x0,0x0,0x58,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0xb, - -}; - -QT_BEGIN_NAMESPACE - -extern Q_CORE_EXPORT bool qRegisterResourceData - (int, const unsigned char *, const unsigned char *, const unsigned char *); - -extern Q_CORE_EXPORT bool qUnregisterResourceData - (int, const unsigned char *, const unsigned char *, const unsigned char *); - -QT_END_NAMESPACE - - -int QT_MANGLE_NAMESPACE(qInitResources)() -{ - QT_PREPEND_NAMESPACE(qRegisterResourceData) - (0x01, qt_resource_struct, qt_resource_name, qt_resource_data); - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qInitResources)) - -int QT_MANGLE_NAMESPACE(qCleanupResources)() -{ - QT_PREPEND_NAMESPACE(qUnregisterResourceData) - (0x01, qt_resource_struct, qt_resource_name, qt_resource_data); - return 1; -} - -Q_DESTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qCleanupResources)) - diff --git a/tests/auto/tools/rcc/data/images.qrc b/tests/auto/tools/rcc/data/images.qrc deleted file mode 100644 index 773baef3e5..0000000000 --- a/tests/auto/tools/rcc/data/images.qrc +++ /dev/null @@ -1,7 +0,0 @@ - - - images/circle.png - images/square.png - images/subdir/triangle.png - - diff --git a/tests/auto/tools/rcc/data/images/circle.png b/tests/auto/tools/rcc/data/images/circle.png deleted file mode 100644 index dc392cb3f7..0000000000 Binary files a/tests/auto/tools/rcc/data/images/circle.png and /dev/null differ diff --git a/tests/auto/tools/rcc/data/images/images.bin.expected b/tests/auto/tools/rcc/data/images/images.bin.expected new file mode 100644 index 0000000000..cb67a25477 Binary files /dev/null and b/tests/auto/tools/rcc/data/images/images.bin.expected differ diff --git a/tests/auto/tools/rcc/data/images/images.expected b/tests/auto/tools/rcc/data/images/images.expected new file mode 100644 index 0000000000..71be819310 --- /dev/null +++ b/tests/auto/tools/rcc/data/images/images.expected @@ -0,0 +1,126 @@ +/**************************************************************************** +** Resource object code +** +IGNORE: ** Created: Tue Jul 15 11:17:15 2008 +IGNORE: ** by: The Resource Compiler for Qt version 4.4.2 +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include + +static const unsigned char qt_resource_data[] = { +IGNORE: // /data5/dev/qt/tests/auto/rcc/data/images/square.png + 0x0,0x0,0x0,0x5e, + 0x89, + 0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0, + 0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x1,0x3,0x0,0x0,0x0,0x49,0xb4,0xe8,0xb7, + 0x0,0x0,0x0,0x6,0x50,0x4c,0x54,0x45,0x0,0x0,0x0,0x58,0xa8,0xff,0x8c,0x14, + 0x1f,0xab,0x0,0x0,0x0,0x13,0x49,0x44,0x41,0x54,0x8,0xd7,0x63,0x60,0x0,0x81, + 0xfa,0xff,0xff,0xff,0xd,0x3e,0x2,0x4,0x0,0x8d,0x4d,0x68,0x6b,0xcf,0xb8,0x8e, + 0x86,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82, +IGNORE: // /data5/dev/qt/tests/auto/rcc/data/images/circle.png + 0x0,0x0,0x0,0xa5, + 0x89, + 0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0, + 0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0x73,0x7a,0x7a,0xf4, + 0x0,0x0,0x0,0x6c,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0xd7,0x5b,0xe,0x0,0x10, + 0xc,0x44,0x51,0xcb,0xb4,0x44,0xbb,0x64,0x3,0x1e,0xd5,0x18,0x1d,0x31,0x12,0xdf, + 0xf7,0x7c,0xd1,0xa6,0xf4,0xe8,0xa9,0x93,0x8b,0x8f,0xe6,0x52,0x87,0x17,0x81,0x59, + 0x46,0xd,0x18,0x7f,0xdc,0x13,0x1e,0x40,0x62,0xe2,0x5e,0xc4,0xd1,0xf8,0x2e,0x2, + 0x12,0xb7,0x22,0xa0,0x71,0xb,0x22,0x14,0x70,0x25,0x3e,0x43,0xfc,0xd,0xb8,0x1a, + 0xef,0x21,0x4,0x10,0x40,0x0,0x3d,0x44,0x14,0x0,0x7d,0xc7,0x14,0x13,0x11,0xc5, + 0x4c,0x48,0x31,0x15,0x53,0xec,0x5,0x14,0x9b,0x11,0xc5,0x6e,0x8,0xdd,0x8e,0x1b, + 0x14,0x54,0x19,0xf3,0xa1,0x23,0xdb,0xd5,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44, + 0xae,0x42,0x60,0x82, +IGNORE: // /data5/dev/qt/tests/auto/rcc/data/images/subdir/triangle.png + 0x0,0x0,0x0,0xaa, + 0x89, + 0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0, + 0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0x73,0x7a,0x7a,0xf4, + 0x0,0x0,0x0,0x71,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0xce,0x4b,0xa,0x80,0x30, + 0x10,0x4,0xd1,0x1c,0xd3,0x23,0x7a,0xcb,0x11,0x82,0xb8,0x50,0x62,0x92,0xf9,0xd5, + 0x66,0x1a,0x7a,0x5d,0xaf,0xb5,0x5a,0xcd,0x36,0xb9,0xcf,0xc4,0x8f,0x53,0xfa,0x9, + 0xc4,0x13,0xa7,0x10,0x28,0xe0,0x13,0xcf,0x44,0xc,0xe3,0x59,0x8,0x14,0x30,0x8d, + 0x47,0x23,0x50,0xc0,0x72,0x3c,0x2,0xb1,0x1d,0xf7,0x46,0xa0,0x0,0x75,0xdc,0x3, + 0x61,0x8e,0x5b,0x11,0x28,0xc0,0x2d,0xae,0x45,0xa0,0x0,0xf7,0xf8,0xe,0x22,0x2c, + 0xbe,0x8a,0x40,0x1,0xe1,0xf1,0x3f,0x44,0x5a,0x7c,0x84,0x40,0x1,0xe9,0xf1,0x37, + 0x42,0xe0,0xd7,0xd8,0x5d,0xf,0x6f,0x97,0x11,0x88,0x38,0xa9,0x1e,0x0,0x0,0x0, + 0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82, + +}; + +static const unsigned char qt_resource_name[] = { + // images + 0x0,0x6, + 0x7,0x3,0x7d,0xc3, + 0x0,0x69, + 0x0,0x6d,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x73, + // square.png + 0x0,0xa, + 0x8,0x8b,0x6,0x27, + 0x0,0x73, + 0x0,0x71,0x0,0x75,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x2e,0x0,0x70,0x0,0x6e,0x0,0x67, + // circle.png + 0x0,0xa, + 0xa,0x2d,0x16,0x47, + 0x0,0x63, + 0x0,0x69,0x0,0x72,0x0,0x63,0x0,0x6c,0x0,0x65,0x0,0x2e,0x0,0x70,0x0,0x6e,0x0,0x67, + // subdir + 0x0,0x6, + 0x7,0xab,0x8b,0x2, + 0x0,0x73, + 0x0,0x75,0x0,0x62,0x0,0x64,0x0,0x69,0x0,0x72, + // triangle.png + 0x0,0xc, + 0x5,0x59,0xa7,0xc7, + 0x0,0x74, + 0x0,0x72,0x0,0x69,0x0,0x61,0x0,0x6e,0x0,0x67,0x0,0x6c,0x0,0x65,0x0,0x2e,0x0,0x70,0x0,0x6e,0x0,0x67, + +}; + +static const unsigned char qt_resource_struct[] = { + // : + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1, + // :/images + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x2, + // :/images/subdir + 0x0,0x0,0x0,0x46,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x5, + // :/images/square.png + 0x0,0x0,0x0,0x12,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0, + // :/images/circle.png + 0x0,0x0,0x0,0x2c,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x62, + // :/images/subdir/triangle.png + 0x0,0x0,0x0,0x58,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0xb, + +}; + +QT_BEGIN_NAMESPACE + +extern Q_CORE_EXPORT bool qRegisterResourceData + (int, const unsigned char *, const unsigned char *, const unsigned char *); + +extern Q_CORE_EXPORT bool qUnregisterResourceData + (int, const unsigned char *, const unsigned char *, const unsigned char *); + +QT_END_NAMESPACE + + +int QT_MANGLE_NAMESPACE(qInitResources)() +{ + QT_PREPEND_NAMESPACE(qRegisterResourceData) + (0x01, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} + +Q_CONSTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qInitResources)) + +int QT_MANGLE_NAMESPACE(qCleanupResources)() +{ + QT_PREPEND_NAMESPACE(qUnregisterResourceData) + (0x01, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} + +Q_DESTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qCleanupResources)) + diff --git a/tests/auto/tools/rcc/data/images/images.qrc b/tests/auto/tools/rcc/data/images/images.qrc new file mode 100644 index 0000000000..773baef3e5 --- /dev/null +++ b/tests/auto/tools/rcc/data/images/images.qrc @@ -0,0 +1,7 @@ + + + images/circle.png + images/square.png + images/subdir/triangle.png + + diff --git a/tests/auto/tools/rcc/data/images/images/circle.png b/tests/auto/tools/rcc/data/images/images/circle.png new file mode 100644 index 0000000000..dc392cb3f7 Binary files /dev/null and b/tests/auto/tools/rcc/data/images/images/circle.png differ diff --git a/tests/auto/tools/rcc/data/images/images/square.png b/tests/auto/tools/rcc/data/images/images/square.png new file mode 100644 index 0000000000..c0fd2d540a Binary files /dev/null and b/tests/auto/tools/rcc/data/images/images/square.png differ diff --git a/tests/auto/tools/rcc/data/images/images/subdir/triangle.png b/tests/auto/tools/rcc/data/images/images/subdir/triangle.png new file mode 100644 index 0000000000..2ee15f8f1f Binary files /dev/null and b/tests/auto/tools/rcc/data/images/images/subdir/triangle.png differ diff --git a/tests/auto/tools/rcc/data/images/square.png b/tests/auto/tools/rcc/data/images/square.png deleted file mode 100644 index c0fd2d540a..0000000000 Binary files a/tests/auto/tools/rcc/data/images/square.png and /dev/null differ diff --git a/tests/auto/tools/rcc/data/images/subdir/triangle.png b/tests/auto/tools/rcc/data/images/subdir/triangle.png deleted file mode 100644 index 2ee15f8f1f..0000000000 Binary files a/tests/auto/tools/rcc/data/images/subdir/triangle.png and /dev/null differ diff --git a/tests/auto/tools/rcc/data/parentdir.txt b/tests/auto/tools/rcc/data/parentdir.txt new file mode 100644 index 0000000000..da8195e17b --- /dev/null +++ b/tests/auto/tools/rcc/data/parentdir.txt @@ -0,0 +1 @@ +abcdefgihklmnopqrstuvwxyz diff --git a/tests/auto/tools/rcc/rcc.pro b/tests/auto/tools/rcc/rcc.pro index ebe36cfaff..264b8ecc66 100644 --- a/tests/auto/tools/rcc/rcc.pro +++ b/tests/auto/tools/rcc/rcc.pro @@ -3,10 +3,3 @@ QT = core testlib TARGET = tst_rcc SOURCES += tst_rcc.cpp - -wince* { - DEFINES += SRCDIR=\\\"\\\" -} else { - DEFINES += SRCDIR=\\\"$$PWD/\\\" -} - diff --git a/tests/auto/tools/rcc/tst_rcc.cpp b/tests/auto/tools/rcc/tst_rcc.cpp index 0124b580a8..dbf5cebd9d 100644 --- a/tests/auto/tools/rcc/tst_rcc.cpp +++ b/tests/auto/tools/rcc/tst_rcc.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2012 Giuseppe D'Angelo ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/ ** @@ -39,28 +40,34 @@ ** ****************************************************************************/ +#include +#include #include #include -#include #include #include #include -#include - -#include +#include +#include +#include +#include +#include +typedef QMap QStringMap; +Q_DECLARE_METATYPE(QStringMap) class tst_rcc : public QObject { Q_OBJECT -public: - tst_rcc() {} private slots: void rcc_data(); void rcc(); -}; + void binary_data(); + void binary(); + void cleanupTestCase(); +}; QString findExpectedFile(const QString &base) { @@ -95,14 +102,16 @@ static QString doCompare(const QStringList &actual, const QStringList &expected) return ba; } - void tst_rcc::rcc_data() { QTest::addColumn("directory"); QTest::addColumn("qrcfile"); QTest::addColumn("expected"); - QTest::newRow("images") << SRCDIR "data" << "images.qrc" << "images.expected"; + QString dataPath = QFINDTESTDATA("data/images/"); + if (dataPath.isEmpty()) + QFAIL("data path not found"); + QTest::newRow("images") << dataPath << "images.qrc" << "images.expected"; } void tst_rcc::rcc() @@ -157,6 +166,191 @@ void tst_rcc::rcc() +static void createRccBinaryData(const QString &baseDir, const QString &qrcFileName, const QString &rccFileName) +{ + QString currentDir = QDir::currentPath(); + QDir::setCurrent(baseDir); + + QProcess rccProcess; + rccProcess.start("rcc", QStringList() << "-binary" << "-o" << rccFileName << qrcFileName); + bool ok = rccProcess.waitForFinished(); + if (!ok) { + QString errorString = QString::fromLatin1("Could not start rcc (is it in PATH?): %1").arg(rccProcess.errorString()); + QFAIL(qPrintable(errorString)); + } + + QByteArray output = rccProcess.readAllStandardOutput(); + if (!output.isEmpty()) { + QString errorMessage = QString::fromLatin1("rcc stdout: %1").arg(QString::fromLocal8Bit(output)); + QWARN(qPrintable(errorMessage)); + } + + output = rccProcess.readAllStandardError(); + if (!output.isEmpty()) { + QString errorMessage = QString::fromLatin1("rcc stderr: %1").arg(QString::fromLocal8Bit(output)); + QWARN(qPrintable(errorMessage)); + } + + QDir::setCurrent(currentDir); +} + +static QStringList readLinesFromFile(const QString &fileName) +{ + QFile file(fileName); + + bool ok = file.open(QIODevice::ReadOnly | QIODevice::Text); + if (!ok) + QWARN(qPrintable(QString::fromLatin1("Could not open testdata file %1: %2").arg(fileName, file.errorString()))); + + QStringList lines = QString::fromUtf8(file.readAll()).split(QLatin1Char('\n'), QString::SkipEmptyParts); + return lines; +} + +static QStringMap readExpectedFiles(const QString &fileName) +{ + QStringMap expectedFiles; + + QStringList lines = readLinesFromFile(fileName); + foreach (const QString &line, lines) { + QString resourceFileName = line.section(QLatin1Char(' '), 0, 0, QString::SectionSkipEmpty); + QString actualFileName = line.section(QLatin1Char(' '), 1, 1, QString::SectionSkipEmpty); + expectedFiles[resourceFileName] = actualFileName; + } + + return expectedFiles; +} + +/* + The following test looks for all *.qrc files under data/binary/. For each + .qrc file found, these files are processed (assuming the file found is + called "base.qrc"): + + - base.qrc : processed by rcc; creates base.rcc + - base.locale : (optional) list of locales to test, one per line + - base.expected : list of pairs (file path in resource, path to real file), + one per line; the pair separated by a whitespace; the paths to real files + relative to data/binary/ (for testing the C locale) + - base.localeName.expected : for each localeName in the base.locale file, + as the above .expected file +*/ + +void tst_rcc::binary_data() +{ + QTest::addColumn("resourceFile"); + QTest::addColumn("locale"); + QTest::addColumn("baseDirectory"); + QTest::addColumn("expectedFiles"); + + QString dataPath = QFINDTESTDATA("data/binary/"); + if (dataPath.isEmpty()) + QFAIL("data path not found"); + + QDirIterator iter(dataPath, QStringList() << QLatin1String("*.qrc")); + while (iter.hasNext()) + { + iter.next(); + QFileInfo qrcFileInfo = iter.fileInfo(); + QString absoluteBaseName = QFileInfo(qrcFileInfo.absolutePath(), qrcFileInfo.baseName()).absoluteFilePath(); + QString rccFileName = absoluteBaseName + QLatin1String(".rcc"); + createRccBinaryData(dataPath, qrcFileInfo.absoluteFilePath(), rccFileName); + + QString localeFileName = absoluteBaseName + QLatin1String(".locale"); + QFile localeFile(localeFileName); + if (localeFile.exists()) { + QStringList locales = readLinesFromFile(localeFileName); + foreach (const QString &locale, locales) { + QString expectedFileName = QString::fromLatin1("%1.%2.%3").arg(absoluteBaseName, locale, QLatin1String("expected")); + QStringMap expectedFiles = readExpectedFiles(expectedFileName); + QTest::newRow(qPrintable(qrcFileInfo.baseName() + QLatin1Char('_') + locale)) << rccFileName + << QLocale(locale) + << dataPath + << expectedFiles; + } + } + + // always test for the C locale as well + QString expectedFileName = absoluteBaseName + QLatin1String(".expected"); + QStringMap expectedFiles = readExpectedFiles(expectedFileName); + QTest::newRow(qPrintable(qrcFileInfo.baseName() + QLatin1String("_C"))) << rccFileName + << QLocale::c() + << dataPath + << expectedFiles; + } +} + +void tst_rcc::binary() +{ + QFETCH(QString, baseDirectory); + QFETCH(QString, resourceFile); + QFETCH(QLocale, locale); + QFETCH(QStringMap, expectedFiles); + + const QString rootPrefix = QLatin1String("/test_root/"); + const QString resourceRootPrefix = QLatin1Char(':') + rootPrefix; + + QLocale oldDefaultLocale; + QLocale::setDefault(locale); + QVERIFY(QFile::exists(resourceFile)); + QVERIFY(QResource::registerResource(resourceFile, rootPrefix)); + + { // need to destroy the iterators on the resource, in order to be able to unregister it + + // read all the files inside the resources + QDirIterator iter(resourceRootPrefix, QDir::Files, QDirIterator::Subdirectories); + QList filesFound; + while (iter.hasNext()) + filesFound << iter.next(); + + // add the test root prefix to the expected file names + QList expectedFileNames = expectedFiles.keys(); + for (QList::iterator i = expectedFileNames.begin(); i < expectedFileNames.end(); ++i) { + // poor man's canonicalPath, which doesn't work with resources + if ((*i).startsWith(QLatin1Char('/'))) + (*i).remove(0, 1); + *i = resourceRootPrefix + *i; + } + + // check that we have all (and only) the expected files + qSort(filesFound); + qSort(expectedFileNames); + QCOMPARE(filesFound, expectedFileNames); + + // now actually check the file contents + QDir directory(baseDirectory); + for (QStringMap::const_iterator i = expectedFiles.constBegin(); i != expectedFiles.constEnd(); ++i) { + QString resourceFileName = i.key(); + QString actualFileName = i.value(); + + QFile resourceFile(resourceRootPrefix + resourceFileName); + QVERIFY(resourceFile.open(QIODevice::ReadOnly)); + QByteArray resourceData = resourceFile.readAll(); + resourceFile.close(); + + QFile actualFile(QFileInfo(directory, actualFileName).absoluteFilePath()); + QVERIFY(actualFile.open(QIODevice::ReadOnly)); + QByteArray actualData = actualFile.readAll(); + actualFile.close(); + QCOMPARE(resourceData, actualData); + } + + } + + QVERIFY(QResource::unregisterResource(resourceFile, rootPrefix)); + QLocale::setDefault(oldDefaultLocale); +} + + +void tst_rcc::cleanupTestCase() +{ + QString dataPath = QFINDTESTDATA("data/binary/"); + if (dataPath.isEmpty()) + return; + QDir dataDir(dataPath); + QFileInfoList entries = dataDir.entryInfoList(QStringList() << QLatin1String("*.rcc")); + foreach (const QFileInfo &entry, entries) + QFile::remove(entry.absoluteFilePath()); +} + QTEST_APPLESS_MAIN(tst_rcc) #include "tst_rcc.moc" -- cgit v1.2.3 From 779b3188a96ef1043ff8091ebe90e44750e1fa3b Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Wed, 7 Mar 2012 09:58:34 -0800 Subject: Windows: Make QMenuBar autotest significant again The bug has been fix by 7bc576771de0b3c96905a6d11a75a01917334dc9 . Task-number: QTBUG-24326 Change-Id: Ifd37e9fe76cb24e49132f22909c95a55a230b1ed Reviewed-by: Sergio Ahumada Reviewed-by: Friedemann Kleint --- tests/auto/widgets/widgets/qmenubar/qmenubar.pro | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/auto/widgets/widgets/qmenubar/qmenubar.pro b/tests/auto/widgets/widgets/qmenubar/qmenubar.pro index 6f35d4516f..6bacaa0d37 100644 --- a/tests/auto/widgets/widgets/qmenubar/qmenubar.pro +++ b/tests/auto/widgets/widgets/qmenubar/qmenubar.pro @@ -5,5 +5,3 @@ SOURCES += tst_qmenubar.cpp # QTBUG-4965, QTBUG-11823 - unstable tests linux-*:system(". /etc/lsb-release && [ $DISTRIB_CODENAME = oneiric ]"):CONFIG += insignificant_test - -win32:CONFIG += insignificant_test # QTBUG-24326 -- cgit v1.2.3 From f71487da3a93ec5f52af496301d91e5b8777494d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Tue, 6 Mar 2012 13:34:30 +0100 Subject: Fix crash in QVariant::canConvert. The function was crashing when an unsupported type id was given as an input argument. Change-Id: I2b0e3e6d43f6f248dc71532f8e6485efe68e8120 Reviewed-by: Stephen Kelly --- src/corelib/kernel/qvariant.cpp | 2 ++ tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 029a261faf..c8456192ed 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -2445,6 +2445,8 @@ bool QVariant::canConvert(int targetTypeId) const if (currentType == uint(targetTypeId)) return true; + if (targetTypeId < 0 || targetTypeId >= QMetaType::User) + return false; // FIXME It should be LastCoreType intead of Uuid if (currentType > int(QMetaType::QUuid) || targetTypeId > int(QMetaType::QUuid)) { diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index ccdab17668..d78759e923 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -612,6 +612,12 @@ void tst_QVariant::canConvert() QCOMPARE(val.canConvert(QVariant::Time), TimeCast); QCOMPARE(val.canConvert(QVariant::UInt), UIntCast); QCOMPARE(val.canConvert(QVariant::ULongLong), ULongLongCast); + + // Invalid type ids + QCOMPARE(val.canConvert(-1), false); + QCOMPARE(val.canConvert(-23), false); + QCOMPARE(val.canConvert(-23876), false); + QCOMPARE(val.canConvert(23876), false); } void tst_QVariant::toInt_data() -- cgit v1.2.3 From cf6dd5baca26c202de26c8366010a8958ea08d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Thu, 8 Mar 2012 15:36:38 +0100 Subject: Crash fix in QMetaType::typeName. The function is public, so it should validate input instead of crashing Change-Id: Ifd9f1110f8631f942929d85db6a57eee7afffb6a Reviewed-by: Stephen Kelly --- src/corelib/kernel/qmetatype.cpp | 5 +++-- tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 410a5cc712..0be813f4f2 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -377,8 +377,9 @@ void QMetaType::registerStreamOperators(int idx, SaveOperator saveOp, \sa type(), isRegistered(), Type */ -const char *QMetaType::typeName(int type) +const char *QMetaType::typeName(int typeId) { + const uint type = typeId; // In theory it can be filled during compilation time, but for some reason template code // that is able to do it causes GCC 4.6 to generate additional 3K of executable code. Probably // it is not worth of it. @@ -400,7 +401,7 @@ const char *QMetaType::typeName(int type) } else { const QVector * const ct = customTypes(); QReadLocker locker(customTypesLock()); - return ct && ct->count() > type - QMetaType::User && !ct->at(type - QMetaType::User).typeName.isEmpty() + return ct && uint(ct->count()) > type - QMetaType::User && !ct->at(type - QMetaType::User).typeName.isEmpty() ? ct->at(type - QMetaType::User).typeName.constData() : 0; } diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index f8403f11a1..35439885c9 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -305,16 +305,20 @@ void tst_QMetaType::normalizedTypes() #define TYPENAME_DATA(MetaTypeName, MetaTypeId, RealType)\ QTest::newRow(#RealType) << QMetaType::MetaTypeName << #RealType; -#define TYPENAME_DATA_ALIAS(MetaTypeName, MetaTypeId, AliasType, RealTypeString)\ - QTest::newRow(RealTypeString) << QMetaType::MetaTypeName << #AliasType; - void tst_QMetaType::typeName_data() { QTest::addColumn("aType"); QTest::addColumn("aTypeName"); QT_FOR_EACH_STATIC_TYPE(TYPENAME_DATA) - QT_FOR_EACH_STATIC_ALIAS_TYPE(TYPENAME_DATA_ALIAS) + + QTest::newRow("Whity") << static_cast(::qMetaTypeId >()) << QString::fromLatin1("Whity"); + QTest::newRow("Whity") << static_cast(::qMetaTypeId >()) << QString::fromLatin1("Whity"); + QTest::newRow("Testspace::Foo") << static_cast(::qMetaTypeId()) << QString::fromLatin1("TestSpace::Foo"); + + QTest::newRow("-1") << QMetaType::Type(-1) << QString(); + QTest::newRow("-124125534") << QMetaType::Type(-124125534) << QString(); + QTest::newRow("124125534") << QMetaType::Type(124125534) << QString(); } void tst_QMetaType::typeName() -- cgit v1.2.3 From 763790bb5c4423952daf97ed0194db8db1ea1a3b Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 8 Mar 2012 10:41:55 +0100 Subject: Fix a bug in the assignment operators for QJsonObject and Array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When objects or arrays where being used read only, several objects can share the same d pointer, but will have different pointers into the binary data. Correctly change the pointer into the binary data even if the d-pointer is the same. Change-Id: Ife0ea5ac5daf46586f855dccdf35b51ec696a623 Reviewed-by: João Abecasis --- src/corelib/json/qjsonarray.cpp | 2 +- src/corelib/json/qjsonobject.cpp | 2 +- tests/auto/corelib/json/tst_qtjson.cpp | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/corelib/json/qjsonarray.cpp b/src/corelib/json/qjsonarray.cpp index 433a68105d..6bae2001a1 100644 --- a/src/corelib/json/qjsonarray.cpp +++ b/src/corelib/json/qjsonarray.cpp @@ -122,10 +122,10 @@ QJsonArray &QJsonArray::operator =(const QJsonArray &other) if (d && !d->ref.deref()) delete d; d = other.d; - a = other.a; if (d) d->ref.ref(); } + a = other.a; return *this; } diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/json/qjsonobject.cpp index cfe71e8959..e14000fac3 100644 --- a/src/corelib/json/qjsonobject.cpp +++ b/src/corelib/json/qjsonobject.cpp @@ -125,10 +125,10 @@ QJsonObject &QJsonObject::operator =(const QJsonObject &other) if (d && !d->ref.deref()) delete d; d = other.d; - o = other.o; if (d) d->ref.ref(); } + o = other.o; return *this; } diff --git a/tests/auto/corelib/json/tst_qtjson.cpp b/tests/auto/corelib/json/tst_qtjson.cpp index f35831c900..079ff6e76b 100644 --- a/tests/auto/corelib/json/tst_qtjson.cpp +++ b/tests/auto/corelib/json/tst_qtjson.cpp @@ -117,6 +117,9 @@ private Q_SLOTS: void testCompactionError(); void parseUnicodeEscapes(); + + void assignObjects(); + void assignArrays(); private: QString testDataDir; }; @@ -1774,5 +1777,35 @@ void TestQtJson::parseUnicodeEscapes() QCOMPARE(array.first().toString(), result); } +void TestQtJson::assignObjects() +{ + const char *json = + "[ { \"Key\": 1 }, { \"Key\": 2 } ]"; + + QJsonDocument doc = QJsonDocument::fromJson(json); + QJsonArray array = doc.array(); + + QJsonObject object = array.at(0).toObject(); + QCOMPARE(object.value("Key").toDouble(), 1.); + + object = array.at(1).toObject(); + QCOMPARE(object.value("Key").toDouble(), 2.); +} + +void TestQtJson::assignArrays() +{ + const char *json = + "[ [ 1 ], [ 2 ] ]"; + + QJsonDocument doc = QJsonDocument::fromJson(json); + QJsonArray array = doc.array(); + + QJsonArray inner = array.at(0).toArray() ; + QCOMPARE(inner.at(0).toDouble(), 1.); + + inner= array.at(1).toArray(); + QCOMPARE(inner.at(0).toDouble(), 2.); +} + QTEST_MAIN(TestQtJson) #include "tst_qtjson.moc" -- cgit v1.2.3 From f5b2a094677abaccb1c0a76f449144ccb89e4137 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 8 Mar 2012 11:38:09 +0200 Subject: Windows: Removing insignification from QTextEdit test The commit 660af10dee503729025952ed2374b8a081f941a2 seems to have fixed the test, so removing the insignification from it. Task-number: QTBUG-24348 Change-Id: I564e90db53d10b54e22342a1cdbef6826929c63a Reviewed-by: Friedemann Kleint --- tests/auto/widgets/widgets/qtextedit/qtextedit.pro | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/auto/widgets/widgets/qtextedit/qtextedit.pro b/tests/auto/widgets/widgets/qtextedit/qtextedit.pro index 294f1d84e7..85658c222e 100644 --- a/tests/auto/widgets/widgets/qtextedit/qtextedit.pro +++ b/tests/auto/widgets/widgets/qtextedit/qtextedit.pro @@ -17,5 +17,3 @@ wince* { } contains(QT_CONFIG,xcb):CONFIG+=insignificant_test # QTBUG-20756 crashes on xcb - -win32:CONFIG += insignificant_test # QTBUG-24348 -- cgit v1.2.3 From 3ca1a2c28ec710183a3853432fe97224fffcdfbf Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Thu, 8 Mar 2012 12:49:49 +0100 Subject: Defer window activation if the window hasn't beenn mapped yet. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I60d616fc60d3be9b55ab2599abadede5f7c11f93 Reviewed-by: Samuel Rødal --- src/plugins/platforms/xcb/qxcbwindow.cpp | 8 +++++++- src/plugins/platforms/xcb/qxcbwindow.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 542d7ab69f..055defde08 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -143,6 +143,7 @@ QXcbWindow::QXcbWindow(QWindow *window) , m_syncCounter(0) , m_mapped(false) , m_transparent(false) + , m_deferredActivation(false) , m_netWmUserTimeWindow(XCB_NONE) #if defined(XCB_USE_EGL) , m_eglSurface(0) @@ -1178,8 +1179,11 @@ void QXcbWindow::propagateSizeHints() void QXcbWindow::requestActivateWindow() { - if (!m_mapped) + if (!m_mapped) { + m_deferredActivation = true; return; + } + m_deferredActivation = false; updateNetWmUserTime(connection()->time()); @@ -1334,6 +1338,8 @@ void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) { if (event->window == m_window) { m_mapped = true; + if (m_deferredActivation) + requestActivateWindow(); QWindowSystemInterface::handleMapEvent(window()); } } diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 6ae55e77e6..c212095e98 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -154,6 +154,7 @@ private: bool m_mapped; bool m_transparent; + bool m_deferredActivation; xcb_window_t m_netWmUserTimeWindow; QSurfaceFormat m_format; -- cgit v1.2.3 From 2a72e10ed983f1ace97a3fc43783d82233e8f691 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 7 Mar 2012 16:21:11 +0100 Subject: QAccessibleEvent needs a virtual destructor. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ia0cd82c5457d39fe501e7ee6b5468ccb0f62f35a Reviewed-by: Jan-Arve Sæther --- src/gui/accessible/qaccessible.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index 9aea9dbce9..8c962ffb53 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -437,6 +437,9 @@ public: Q_ASSERT(obj); } + virtual ~QAccessibleEvent() + {} + QAccessible::Event type() const { return m_type; } QObject *object() const { return m_object; } int child() const { return m_child; } -- cgit v1.2.3 From 4035375c57bf26b49d819d931b08fa69d818acab Mon Sep 17 00:00:00 2001 From: Donald Carr Date: Wed, 7 Mar 2012 16:30:08 +0000 Subject: Remove legacy pre-QPA gui/egl implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I22a100cec7064df87eb2036adbca8a41aab5a10d Reviewed-by: Jørgen Lind Reviewed-by: Samuel Rødal --- src/gui/egl/egl.pri | 26 -- src/gui/egl/qegl.cpp | 751 ----------------------------------------- src/gui/egl/qegl_p.h | 191 ----------- src/gui/egl/qegl_qpa.cpp | 110 ------ src/gui/egl/qeglcontext_p.h | 117 ------- src/gui/egl/qeglproperties.cpp | 563 ------------------------------ src/gui/egl/qeglproperties_p.h | 95 ------ src/gui/gui.pro | 2 - 8 files changed, 1855 deletions(-) delete mode 100644 src/gui/egl/egl.pri delete mode 100644 src/gui/egl/qegl.cpp delete mode 100644 src/gui/egl/qegl_p.h delete mode 100644 src/gui/egl/qegl_qpa.cpp delete mode 100644 src/gui/egl/qeglcontext_p.h delete mode 100644 src/gui/egl/qeglproperties.cpp delete mode 100644 src/gui/egl/qeglproperties_p.h diff --git a/src/gui/egl/egl.pri b/src/gui/egl/egl.pri deleted file mode 100644 index e4a2bbef75..0000000000 --- a/src/gui/egl/egl.pri +++ /dev/null @@ -1,26 +0,0 @@ -contains(QT_CONFIG, egl): { - CONFIG += egl - - HEADERS += \ - egl/qegl_p.h \ - egl/qeglcontext_p.h \ - egl/qeglproperties_p.h - - SOURCES += \ - egl/qegl.cpp \ - egl/qeglproperties.cpp - unix { - !isEmpty(QMAKE_INCDIR_EGL){ - INCLUDEPATH += $$QMAKE_INCDIR_EGL - } - !isEmpty(QMAKE_LIBDIR_EGL){ - for(p, QMAKE_LIBDIR_EGL) { - exists($$p):LIBS += -L$$p - } - } - - !isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL - } - - SOURCES += egl/qegl_qpa.cpp -} diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp deleted file mode 100644 index 067886cf5a..0000000000 --- a/src/gui/egl/qegl.cpp +++ /dev/null @@ -1,751 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtGui 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 -#include -#include -#include -#include - -#include "qegl_p.h" -#include "qeglcontext_p.h" - - -QT_BEGIN_NAMESPACE - - -/* - QEglContextTracker is used to track the EGL contexts that we - create internally in Qt, so that we can call eglTerminate() to - free additional EGL resources when the last context is destroyed. -*/ - -class QEglContextTracker -{ -public: - static void ref() { contexts.ref(); } - static void deref() { - if (!contexts.deref()) { - eglTerminate(QEgl::display()); - displayOpen = 0; - } - } - static void setDisplayOpened() { displayOpen = 1; } - static bool displayOpened() { return displayOpen; } - -private: - static QBasicAtomicInt contexts; - static QBasicAtomicInt displayOpen; -}; - -QBasicAtomicInt QEglContextTracker::contexts = Q_BASIC_ATOMIC_INITIALIZER(0); -QBasicAtomicInt QEglContextTracker::displayOpen = Q_BASIC_ATOMIC_INITIALIZER(0); - -// Current GL and VG contexts. These are used to determine if -// we can avoid an eglMakeCurrent() after a call to lazyDoneCurrent(). -// If a background thread modifies the value, the worst that will -// happen is a redundant eglMakeCurrent() in the foreground thread. -static QEglContext * volatile currentGLContext = 0; -static QEglContext * volatile currentVGContext = 0; - -QEglContext::QEglContext() - : apiType(QEgl::OpenGL) - , ctx(EGL_NO_CONTEXT) - , cfg(QEGL_NO_CONFIG) - , currentSurface(EGL_NO_SURFACE) - , current(false) - , ownsContext(true) - , sharing(false) -{ - QEglContextTracker::ref(); -} - -QEglContext::~QEglContext() -{ - destroyContext(); - - if (currentGLContext == this) - currentGLContext = 0; - if (currentVGContext == this) - currentVGContext = 0; - QEglContextTracker::deref(); -} - -bool QEglContext::isValid() const -{ - return (ctx != EGL_NO_CONTEXT); -} - -bool QEglContext::isCurrent() const -{ - return current; -} - -EGLConfig QEgl::defaultConfig(int devType, API api, ConfigOptions options) -{ - if ( (devType != QInternal::Pixmap) && ((options & Renderable) == 0)) - qWarning("QEgl::defaultConfig() - Only configs for pixmaps make sense to be read-only!"); - - EGLConfig* targetConfig = 0; - - static EGLConfig defaultVGConfigs[] = { - QEGL_NO_CONFIG, // 0 Window Renderable Translucent - QEGL_NO_CONFIG, // 1 Window Renderable Opaque - QEGL_NO_CONFIG, // 2 Pixmap Renderable Translucent - QEGL_NO_CONFIG, // 3 Pixmap Renderable Opaque - QEGL_NO_CONFIG, // 4 Pixmap ReadOnly Translucent - QEGL_NO_CONFIG // 5 Pixmap ReadOnly Opaque - }; - if (api == OpenVG) { - if (devType == QInternal::Widget) { - if (options & Translucent) - targetConfig = &(defaultVGConfigs[0]); - else - targetConfig = &(defaultVGConfigs[1]); - } else if (devType == QInternal::Pixmap) { - if (options & Renderable) { - if (options & Translucent) - targetConfig = &(defaultVGConfigs[2]); - else // Opaque - targetConfig = &(defaultVGConfigs[3]); - } else { // Read-only - if (options & Translucent) - targetConfig = &(defaultVGConfigs[4]); - else // Opaque - targetConfig = &(defaultVGConfigs[5]); - } - } - } - - - static EGLConfig defaultGLConfigs[] = { - QEGL_NO_CONFIG, // 0 Window Renderable Translucent - QEGL_NO_CONFIG, // 1 Window Renderable Opaque - QEGL_NO_CONFIG, // 2 PBuffer Renderable Translucent - QEGL_NO_CONFIG, // 3 PBuffer Renderable Opaque - QEGL_NO_CONFIG, // 4 Pixmap Renderable Translucent - QEGL_NO_CONFIG, // 5 Pixmap Renderable Opaque - QEGL_NO_CONFIG, // 6 Pixmap ReadOnly Translucent - QEGL_NO_CONFIG // 7 Pixmap ReadOnly Opaque - }; - if (api == OpenGL) { - if (devType == QInternal::Widget) { - if (options & Translucent) - targetConfig = &(defaultGLConfigs[0]); - else // Opaque - targetConfig = &(defaultGLConfigs[1]); - } else if (devType == QInternal::Pbuffer) { - if (options & Translucent) - targetConfig = &(defaultGLConfigs[2]); - else // Opaque - targetConfig = &(defaultGLConfigs[3]); - } else if (devType == QInternal::Pixmap) { - if (options & Renderable) { - if (options & Translucent) - targetConfig = &(defaultGLConfigs[4]); - else // Opaque - targetConfig = &(defaultGLConfigs[5]); - } else { // ReadOnly - if (options & Translucent) - targetConfig = &(defaultGLConfigs[6]); - else // Opaque - targetConfig = &(defaultGLConfigs[7]); - } - } - } - - if (!targetConfig) { - qWarning("QEgl::defaultConfig() - No default config for device/api/options combo"); - return QEGL_NO_CONFIG; - } - if (*targetConfig != QEGL_NO_CONFIG) - return *targetConfig; - - - // We haven't found an EGL config for the target config yet, so do it now: - - - // Allow overriding from an environment variable: - QByteArray configId; - if (api == OpenVG) - configId = qgetenv("QT_VG_EGL_CONFIG"); - else - configId = qgetenv("QT_GL_EGL_CONFIG"); - if (!configId.isEmpty()) { - // Overridden, so get the EGLConfig for the specified config ID: - EGLint properties[] = { - EGL_CONFIG_ID, (EGLint)configId.toInt(), - EGL_NONE - }; - EGLint configCount = 0; - eglChooseConfig(display(), properties, targetConfig, 1, &configCount); - if (configCount > 0) - return *targetConfig; - qWarning() << "QEgl::defaultConfig() -" << configId << "appears to be invalid"; - } - - QEglProperties configAttribs; - configAttribs.setRenderableType(api); - - EGLint surfaceType; - switch (devType) { - case QInternal::Widget: - surfaceType = EGL_WINDOW_BIT; - break; - case QInternal::Pixmap: - surfaceType = EGL_PIXMAP_BIT; - break; - case QInternal::Pbuffer: - surfaceType = EGL_PBUFFER_BIT; - break; - default: - qWarning("QEgl::defaultConfig() - Can't create EGL surface for %d device type", devType); - return QEGL_NO_CONFIG; - }; -#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - // For OpenVG, we try to create a surface using a pre-multiplied format if - // the surface needs to have an alpha channel: - if (api == OpenVG && (options & Translucent)) - surfaceType |= EGL_VG_ALPHA_FORMAT_PRE_BIT; -#endif - configAttribs.setValue(EGL_SURFACE_TYPE, surfaceType); - -#ifdef EGL_BIND_TO_TEXTURE_RGBA - if (devType == QInternal::Pixmap || devType == QInternal::Pbuffer) { - if (options & Translucent) - configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); - else - configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); - } -#endif - - // Add paint engine requirements - if (api == OpenVG) { -#if !defined(QVG_SCISSOR_CLIP) && defined(EGL_ALPHA_MASK_SIZE) - configAttribs.setValue(EGL_ALPHA_MASK_SIZE, 1); -#endif - } else { - // Both OpenGL paint engines need to have stencil and sample buffers - configAttribs.setValue(EGL_STENCIL_SIZE, 1); - configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1); -#ifndef QT_OPENGL_ES_2 - // Additionally, the GL1 engine likes to have a depth buffer for clipping - configAttribs.setValue(EGL_DEPTH_SIZE, 1); -#endif - } - - if (options & Translucent) - configAttribs.setValue(EGL_ALPHA_SIZE, 1); - - *targetConfig = chooseConfig(&configAttribs, QEgl::BestPixelFormat); - return *targetConfig; -} - - -// Choose a configuration that matches "properties". -EGLConfig QEgl::chooseConfig(const QEglProperties* properties, QEgl::PixelFormatMatch match) -{ - QEglProperties props(*properties); - EGLConfig cfg = QEGL_NO_CONFIG; - do { - // Get the number of matching configurations for this set of properties. - EGLint matching = 0; - EGLDisplay dpy = QEgl::display(); - if (!eglChooseConfig(dpy, props.properties(), 0, 0, &matching) || !matching) - continue; - - // If we want the best pixel format, then return the first - // matching configuration. - if (match == QEgl::BestPixelFormat) { - eglChooseConfig(display(), props.properties(), &cfg, 1, &matching); - if (matching < 1) - continue; - return cfg; - } - - // Fetch all of the matching configurations and find the - // first that matches the pixel format we wanted. - EGLint size = matching; - EGLConfig *configs = new EGLConfig [size]; - eglChooseConfig(display(), props.properties(), configs, size, &matching); - for (EGLint index = 0; index < size; ++index) { - EGLint red, green, blue, alpha; - eglGetConfigAttrib(display(), configs[index], EGL_RED_SIZE, &red); - eglGetConfigAttrib(display(), configs[index], EGL_GREEN_SIZE, &green); - eglGetConfigAttrib(display(), configs[index], EGL_BLUE_SIZE, &blue); - eglGetConfigAttrib(display(), configs[index], EGL_ALPHA_SIZE, &alpha); - if (red == props.value(EGL_RED_SIZE) && - green == props.value(EGL_GREEN_SIZE) && - blue == props.value(EGL_BLUE_SIZE) && - (props.value(EGL_ALPHA_SIZE) == 0 || - alpha == props.value(EGL_ALPHA_SIZE))) { - cfg = configs[index]; - delete [] configs; - return cfg; - } - } - delete [] configs; - } while (props.reduceConfiguration()); - -#ifdef EGL_BIND_TO_TEXTURE_RGBA - // Don't report an error just yet if we failed to get a pbuffer - // configuration with texture rendering. Only report failure if - // we cannot get any pbuffer configurations at all. - if (props.value(EGL_BIND_TO_TEXTURE_RGBA) == EGL_DONT_CARE && - props.value(EGL_BIND_TO_TEXTURE_RGB) == EGL_DONT_CARE) -#endif - { - qWarning() << "QEglContext::chooseConfig(): Could not find a suitable EGL configuration"; - qWarning() << "Requested:" << props.toString(); - qWarning() << "Available:"; - QEgl::dumpAllConfigs(); - } - return QEGL_NO_CONFIG; -} - -bool QEglContext::chooseConfig(const QEglProperties& properties, QEgl::PixelFormatMatch match) -{ - cfg = QEgl::chooseConfig(&properties, match); - return cfg != QEGL_NO_CONFIG; -} - -EGLSurface QEglContext::createSurface(QPaintDevice* device, const QEglProperties *properties) -{ - return QEgl::createSurface(device, cfg, properties); -} - - -// Create the EGLContext. -bool QEglContext::createContext(QEglContext *shareContext, const QEglProperties *properties) -{ - // We need to select the correct API before calling eglCreateContext(). -#ifdef QT_OPENGL_ES -#ifdef EGL_OPENGL_ES_API - if (apiType == QEgl::OpenGL) - eglBindAPI(EGL_OPENGL_ES_API); -#endif -#else -#ifdef EGL_OPENGL_API - if (apiType == QEgl::OpenGL) - eglBindAPI(EGL_OPENGL_API); -#endif -#endif //defined(QT_OPENGL_ES) -#ifdef EGL_OPENVG_API - if (apiType == QEgl::OpenVG) - eglBindAPI(EGL_OPENVG_API); -#endif - - // Create a new context for the configuration. - QEglProperties contextProps; - if (properties) - contextProps = *properties; -#ifdef QT_OPENGL_ES_2 - if (apiType == QEgl::OpenGL) - contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); -#endif - sharing = false; - if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) - shareContext = 0; - if (shareContext) { - ctx = eglCreateContext(QEgl::display(), cfg, shareContext->ctx, contextProps.properties()); - if (ctx == EGL_NO_CONTEXT) { - qWarning() << "QEglContext::createContext(): Could not share context:" << QEgl::errorString(); - shareContext = 0; - } else { - sharing = true; - } - } - if (ctx == EGL_NO_CONTEXT) { - ctx = eglCreateContext(display(), cfg, EGL_NO_CONTEXT, contextProps.properties()); - if (ctx == EGL_NO_CONTEXT) { - qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << QEgl::errorString(); - return false; - } - } - return true; -} - -// Destroy an EGL surface object. If it was current on this context -// then call doneCurrent() for it first. -void QEglContext::destroySurface(EGLSurface surface) -{ - if (surface != EGL_NO_SURFACE) { - if (surface == currentSurface) - doneCurrent(); - eglDestroySurface(display(), surface); - } -} - -// Destroy the context. Note: this does not destroy the surface. -void QEglContext::destroyContext() -{ - if (ctx != EGL_NO_CONTEXT && ownsContext) - eglDestroyContext(display(), ctx); - ctx = EGL_NO_CONTEXT; - cfg = 0; -} - -bool QEglContext::makeCurrent(EGLSurface surface) -{ - if (ctx == EGL_NO_CONTEXT) { - qWarning() << "QEglContext::makeCurrent(): Cannot make invalid context current"; - return false; - } - - if (surface == EGL_NO_SURFACE) { - qWarning() << "QEglContext::makeCurrent(): Cannot make invalid surface current"; - return false; - } - - // If lazyDoneCurrent() was called on the surface, then we may be able - // to assume that it is still current within the thread. - if (surface == currentSurface && currentContext(apiType) == this) { - current = true; - return true; - } - - current = true; - currentSurface = surface; - setCurrentContext(apiType, this); - - // Force the right API to be bound before making the context current. - // The EGL implementation should be able to figure this out from ctx, - // but some systems require the API to be explicitly set anyway. -#ifdef EGL_OPENGL_ES_API - if (apiType == QEgl::OpenGL) - eglBindAPI(EGL_OPENGL_ES_API); -#endif -#ifdef EGL_OPENVG_API - if (apiType == QEgl::OpenVG) - eglBindAPI(EGL_OPENVG_API); -#endif - - bool ok = eglMakeCurrent(QEgl::display(), surface, surface, ctx); - if (!ok) - qWarning() << "QEglContext::makeCurrent(" << surface << "):" << QEgl::errorString(); - return ok; -} - -bool QEglContext::doneCurrent() -{ - // If the context is invalid, we assume that an error was reported - // when makeCurrent() was called. - if (ctx == EGL_NO_CONTEXT) - return false; - - current = false; - currentSurface = EGL_NO_SURFACE; - setCurrentContext(apiType, 0); - - // We need to select the correct API before calling eglMakeCurrent() - // with EGL_NO_CONTEXT because threads can have both OpenGL and OpenVG - // contexts active at the same time. -#ifdef EGL_OPENGL_ES_API - if (apiType == QEgl::OpenGL) - eglBindAPI(EGL_OPENGL_ES_API); -#endif -#ifdef EGL_OPENVG_API - if (apiType == QEgl::OpenVG) - eglBindAPI(EGL_OPENVG_API); -#endif - - bool ok = eglMakeCurrent(QEgl::display(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (!ok) - qWarning() << "QEglContext::doneCurrent():" << QEgl::errorString(); - return ok; -} - -// Act as though doneCurrent() was called, but keep the context -// and the surface active for the moment. This allows makeCurrent() -// to skip a call to eglMakeCurrent() if we are using the same -// surface as the last set of painting operations. We leave the -// currentContext() pointer as-is for now. -bool QEglContext::lazyDoneCurrent() -{ - current = false; - return true; -} - -bool QEglContext::swapBuffers(EGLSurface surface) -{ - if(ctx == EGL_NO_CONTEXT) - return false; - - bool ok = eglSwapBuffers(QEgl::display(), surface); - if (!ok) - qWarning() << "QEglContext::swapBuffers():" << QEgl::errorString(); - return ok; -} - -bool QEglContext::swapBuffersRegion2NOK(EGLSurface surface, const QRegion *region) { - QVector qrects = region->rects(); - EGLint *gl_rects; - uint count; - uint i; - - count = qrects.size(); - QVarLengthArray arr(4 * count); - gl_rects = arr.data(); - for (i = 0; i < count; i++) { - QRect qrect = qrects[i]; - - gl_rects[4 * i + 0] = qrect.x(); - gl_rects[4 * i + 1] = qrect.y(); - gl_rects[4 * i + 2] = qrect.width(); - gl_rects[4 * i + 3] = qrect.height(); - } - - bool ok = QEgl::eglSwapBuffersRegion2NOK(QEgl::display(), surface, count, gl_rects); - - if (!ok) - qWarning() << "QEglContext::swapBuffersRegion2NOK():" << QEgl::errorString(); - return ok; -} - -int QEglContext::configAttrib(int name) const -{ - EGLint value; - EGLBoolean success = eglGetConfigAttrib(QEgl::display(), cfg, name, &value); - if (success) - return value; - else - return EGL_DONT_CARE; -} - -typedef EGLImageKHR (EGLAPIENTRY *_eglCreateImageKHR)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint*); -typedef EGLBoolean (EGLAPIENTRY *_eglDestroyImageKHR)(EGLDisplay, EGLImageKHR); - -// Defined in qegl.cpp: -static _eglCreateImageKHR qt_eglCreateImageKHR = 0; -static _eglDestroyImageKHR qt_eglDestroyImageKHR = 0; - -typedef EGLBoolean (EGLAPIENTRY *_eglSwapBuffersRegion2NOK)(EGLDisplay, EGLSurface, EGLint, const EGLint*); - -static _eglSwapBuffersRegion2NOK qt_eglSwapBuffersRegion2NOK = 0; - -EGLDisplay QEgl::display() -{ - static EGLDisplay dpy = EGL_NO_DISPLAY; - if (!QEglContextTracker::displayOpened()) { - dpy = eglGetDisplay(nativeDisplay()); - QEglContextTracker::setDisplayOpened(); - if (dpy == EGL_NO_DISPLAY) { - qWarning("QEgl::display(): Falling back to EGL_DEFAULT_DISPLAY"); - dpy = eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); - } - if (dpy == EGL_NO_DISPLAY) { - qWarning("QEgl::display(): Can't even open the default display"); - return EGL_NO_DISPLAY; - } - - if (!eglInitialize(dpy, NULL, NULL)) { - qWarning() << "QEgl::display(): Cannot initialize EGL display:" << QEgl::errorString(); - return EGL_NO_DISPLAY; - } - - // Resolve the egl extension function pointers: -#if (defined(EGL_KHR_image) || defined(EGL_KHR_image_base)) && !defined(EGL_EGLEXT_PROTOTYPES) - if (QEgl::hasExtension("EGL_KHR_image") || QEgl::hasExtension("EGL_KHR_image_base")) { - qt_eglCreateImageKHR = (_eglCreateImageKHR) eglGetProcAddress("eglCreateImageKHR"); - qt_eglDestroyImageKHR = (_eglDestroyImageKHR) eglGetProcAddress("eglDestroyImageKHR"); - } -#endif - - if (QEgl::hasExtension("EGL_NOK_swap_region2")) { - qt_eglSwapBuffersRegion2NOK = (_eglSwapBuffersRegion2NOK) eglGetProcAddress("eglSwapBuffersRegion2NOK"); - } - } - - return dpy; -} - -EGLImageKHR QEgl::eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) -{ - if (qt_eglCreateImageKHR) - return qt_eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list); - - QEgl::display(); // Initialises function pointers - if (qt_eglCreateImageKHR) - return qt_eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list); - - qWarning("QEgl::eglCreateImageKHR() called but EGL_KHR_image(_base) extension not present"); - return 0; -} - -EGLBoolean QEgl::eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) -{ - if (qt_eglDestroyImageKHR) - return qt_eglDestroyImageKHR(dpy, img); - - QEgl::display(); // Initialises function pointers - if (qt_eglDestroyImageKHR) - return qt_eglDestroyImageKHR(dpy, img); - - qWarning("QEgl::eglDestroyImageKHR() called but EGL_KHR_image(_base) extension not present"); - return 0; -} - -EGLBoolean QEgl::eglSwapBuffersRegion2NOK(EGLDisplay dpy, EGLSurface surface, EGLint count, const EGLint *rects) -{ - if (qt_eglSwapBuffersRegion2NOK) - return qt_eglSwapBuffersRegion2NOK(dpy, surface, count, rects); - - QEgl::display(); // Initialises function pointers - if (qt_eglSwapBuffersRegion2NOK) - return qt_eglSwapBuffersRegion2NOK(dpy, surface, count, rects); - - qWarning("QEgl::eglSwapBuffersRegion2NOK() called but EGL_NOK_swap_region2 extension not present"); - return 0; -} - -EGLSurface QEgl::createSurface(QPaintDevice *device, EGLConfig cfg, const QEglProperties *properties) -{ - // Create the native drawable for the paint device. - int devType = device->devType(); - EGLNativePixmapType pixmapDrawable = 0; - EGLNativeWindowType windowDrawable = 0; - bool ok; - if (devType == QInternal::Pixmap) { - pixmapDrawable = nativePixmap(static_cast(device)); - ok = (pixmapDrawable != 0); - } else if (devType == QInternal::Widget) { - windowDrawable = nativeWindow(static_cast(device)); - ok = (windowDrawable != 0); - } else { - ok = false; - } - if (!ok) { - qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); - return EGL_NO_SURFACE; - } - - // Create the EGL surface to draw into, based on the native drawable. - const int *props; - if (properties) - props = properties->properties(); - else - props = 0; - EGLSurface surf; - if (devType == QInternal::Widget) - surf = eglCreateWindowSurface(QEgl::display(), cfg, windowDrawable, props); - else - surf = eglCreatePixmapSurface(QEgl::display(), cfg, pixmapDrawable, props); - if (surf == EGL_NO_SURFACE) { - qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); - } - return surf; -} - - -// Return the error string associated with a specific code. -QString QEgl::errorString(EGLint code) -{ - static const char * const errors[] = { - "Success (0x3000)", // No tr - "Not initialized (0x3001)", // No tr - "Bad access (0x3002)", // No tr - "Bad alloc (0x3003)", // No tr - "Bad attribute (0x3004)", // No tr - "Bad config (0x3005)", // No tr - "Bad context (0x3006)", // No tr - "Bad current surface (0x3007)", // No tr - "Bad display (0x3008)", // No tr - "Bad match (0x3009)", // No tr - "Bad native pixmap (0x300A)", // No tr - "Bad native window (0x300B)", // No tr - "Bad parameter (0x300C)", // No tr - "Bad surface (0x300D)", // No tr - "Context lost (0x300E)" // No tr - }; - if (code >= 0x3000 && code <= 0x300E) { - return QString::fromLatin1(errors[code - 0x3000]); - } else { - return QLatin1String("0x") + QString::number(int(code), 16); - } -} - -// Dump all of the EGL configurations supported by the system. -void QEgl::dumpAllConfigs() -{ - QEglProperties props; - EGLint count = 0; - if (!eglGetConfigs(display(), 0, 0, &count) || count < 1) - return; - EGLConfig *configs = new EGLConfig [count]; - eglGetConfigs(display(), configs, count, &count); - for (EGLint index = 0; index < count; ++index) { - props = QEglProperties(configs[index]); - qWarning() << props.toString(); - } - delete [] configs; -} - -QString QEgl::extensions() -{ - const char* exts = eglQueryString(QEgl::display(), EGL_EXTENSIONS); - return QString(QLatin1String(exts)); -} - -bool QEgl::hasExtension(const char* extensionName) -{ - QList extensions = - QByteArray(reinterpret_cast - (eglQueryString(QEgl::display(), EGL_EXTENSIONS))).split(' '); - return extensions.contains(extensionName); -} - -QEglContext *QEglContext::currentContext(QEgl::API api) -{ - if (api == QEgl::OpenGL) - return currentGLContext; - else - return currentVGContext; -} - -void QEglContext::setCurrentContext(QEgl::API api, QEglContext *context) -{ - if (api == QEgl::OpenGL) - currentGLContext = context; - else - currentVGContext = context; -} - -QT_END_NAMESPACE diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h deleted file mode 100644 index 3e78b97fcb..0000000000 --- a/src/gui/egl/qegl_p.h +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtGui 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 QEGL_P_H -#define QEGL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience of -// the QtGui and QtOpenVG modules. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -QT_BEGIN_INCLUDE_NAMESPACE - -#ifndef QT_NO_EGL -#if defined(QT_OPENGL_ES_2) -# include -#endif - -#if defined(QT_GLES_EGL) -# include -#else -# include -#endif -#if !defined(EGL_VERSION_1_2) -typedef unsigned int EGLenum; -typedef void *EGLClientBuffer; -#endif -#else - -//types from egltypes.h for compiling stub without EGL headers -typedef int EGLBoolean; -typedef int EGLint; -typedef int EGLenum; -typedef int NativeDisplayType; -typedef void* NativeWindowType; -typedef void* NativePixmapType; -typedef int EGLDisplay; -typedef int EGLConfig; -typedef int EGLSurface; -typedef int EGLContext; -typedef int EGLClientBuffer; -#define EGL_NONE 0x3038 /* Attrib list terminator */ - -#endif - - -// Internally we use the EGL-prefixed native types which are used in EGL >= 1.3. -// For older versions of EGL, we have to define these types ourselves here: -#if !defined(EGL_VERSION_1_3) && !defined(QEGL_NATIVE_TYPES_DEFINED) -#undef EGLNativeWindowType -#undef EGLNativePixmapType -#undef EGLNativeDisplayType -typedef NativeWindowType EGLNativeWindowType; -typedef NativePixmapType EGLNativePixmapType; -typedef NativeDisplayType EGLNativeDisplayType; -#define QEGL_NATIVE_TYPES_DEFINED 1 -#endif - -QT_END_INCLUDE_NAMESPACE - -#include -#include - -QT_BEGIN_NAMESPACE - -#define QEGL_NO_CONFIG ((EGLConfig)-1) - -#ifndef EGLAPIENTRY -#define EGLAPIENTRY -#endif - -// Declare/define the bits of EGL_KHR_image_base we need: -#if !defined(EGL_KHR_image) && !defined(EGL_KHR_image_base) -typedef void *EGLImageKHR; - -#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0) -#define EGL_IMAGE_PRESERVED_KHR 0x30D2 -#define EGL_KHR_image_base -#endif - -#if !defined(EGL_KHR_image) && !defined(EGL_KHR_image_pixmap) -#define EGL_NATIVE_PIXMAP_KHR 0x30B0 -#define EGL_KHR_image_pixmap -#endif - - -class QEglProperties; - -namespace QEgl { - enum API - { - OpenGL, - OpenVG - }; - - enum PixelFormatMatch - { - ExactPixelFormat, - BestPixelFormat - }; - - enum ConfigOption - { - NoOptions = 0, - Translucent = 0x01, - Renderable = 0x02 // Config will be compatable with the paint engines (VG or GL) - }; - Q_DECLARE_FLAGS(ConfigOptions, ConfigOption) - - // Most of the time we use the same config for things like widgets & pixmaps, so rather than - // go through the eglChooseConfig loop every time, we use defaultConfig, which will return - // the config for a particular device/api/option combo. This function assumes that once a - // config is chosen for a particular combo, it's safe to always use that combo. - Q_GUI_EXPORT EGLConfig defaultConfig(int devType, API api, ConfigOptions options); - - Q_GUI_EXPORT EGLConfig chooseConfig(const QEglProperties* configAttribs, QEgl::PixelFormatMatch match = QEgl::ExactPixelFormat); - Q_GUI_EXPORT EGLSurface createSurface(QPaintDevice *device, EGLConfig cfg, const QEglProperties *surfaceAttribs = 0); - - Q_GUI_EXPORT void dumpAllConfigs(); - -#ifdef QT_NO_EGL - Q_GUI_EXPORT QString errorString(EGLint code = 0); -#else - Q_GUI_EXPORT QString errorString(EGLint code = eglGetError()); -#endif - - Q_GUI_EXPORT QString extensions(); - Q_GUI_EXPORT bool hasExtension(const char* extensionName); - - Q_GUI_EXPORT EGLDisplay display(); - - Q_GUI_EXPORT EGLNativeDisplayType nativeDisplay(); - Q_GUI_EXPORT EGLNativeWindowType nativeWindow(QWidget*); - Q_GUI_EXPORT EGLNativePixmapType nativePixmap(QPixmap*); - - // Extension functions - Q_GUI_EXPORT EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); - Q_GUI_EXPORT EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img); - Q_GUI_EXPORT EGLBoolean eglSwapBuffersRegion2NOK(EGLDisplay dpy, EGLSurface surface, EGLint count, const EGLint *rects); - -} - -Q_DECLARE_OPERATORS_FOR_FLAGS(QEgl::ConfigOptions) - -QT_END_NAMESPACE - -#endif //QEGL_P_H diff --git a/src/gui/egl/qegl_qpa.cpp b/src/gui/egl/qegl_qpa.cpp deleted file mode 100644 index a0a16a5395..0000000000 --- a/src/gui/egl/qegl_qpa.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtGui 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 -#include -#include -#include "qeglcontext_p.h" - -#if !defined(QT_NO_EGL) - -#include -#include - -QT_BEGIN_NAMESPACE - -EGLNativeDisplayType QEgl::nativeDisplay() -{ - return EGLNativeDisplayType(EGL_DEFAULT_DISPLAY); -} - -EGLNativeWindowType QEgl::nativeWindow(QWidget* widget) -{ - return (EGLNativeWindowType)(widget->winId()); -} - -EGLNativePixmapType QEgl::nativePixmap(QPixmap* pixmap) -{ - Q_UNUSED(pixmap); - return 0; -} - -//EGLDisplay QEglContext::display() -//{ -// return eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); -//} - -static QPlatformScreen *screenForDevice(QPaintDevice *device) -{ - QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); - - QList screens = pi->screens(); - - int screenNumber; - if (device && device->devType() == QInternal::Widget) - screenNumber = qApp->desktop()->screenNumber(static_cast(device)); - else - screenNumber = 0; - if (screenNumber < 0 || screenNumber >= screens.size()) - return 0; - return screens[screenNumber]; -} - -// Set pixel format and other properties based on a paint device. -void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) -{ - if (!dev) - return; - - // Find the QOpenGLScreen for this paint device. - QPlatformScreen *screen = screenForDevice(dev); - if (!screen) - return; - int devType = dev->devType(); - if (devType == QInternal::Image) - setPixelFormat(static_cast(dev)->format()); - else - setPixelFormat(screen->format()); -} - -QT_END_NAMESPACE - -#endif // !QT_NO_EGL diff --git a/src/gui/egl/qeglcontext_p.h b/src/gui/egl/qeglcontext_p.h deleted file mode 100644 index 94654eb2a8..0000000000 --- a/src/gui/egl/qeglcontext_p.h +++ /dev/null @@ -1,117 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtGui 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 QEGLCONTEXT_P_H -#define QEGLCONTEXT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience of -// the QtGui and QtOpenVG modules. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -class Q_GUI_EXPORT QEglContext -{ -public: - QEglContext(); - ~QEglContext(); - - bool isValid() const; - bool isCurrent() const; - bool isSharing() const { return sharing; } - - QEgl::API api() const { return apiType; } - void setApi(QEgl::API api) { apiType = api; } - - bool chooseConfig(const QEglProperties& properties, QEgl::PixelFormatMatch match = QEgl::ExactPixelFormat); - bool createContext(QEglContext *shareContext = 0, const QEglProperties *properties = 0); - void destroyContext(); - EGLSurface createSurface(QPaintDevice *device, const QEglProperties *properties = 0); - void destroySurface(EGLSurface surface); - - bool makeCurrent(EGLSurface surface); - bool doneCurrent(); - bool lazyDoneCurrent(); - bool swapBuffers(EGLSurface surface); - bool swapBuffersRegion2NOK(EGLSurface surface, const QRegion *region); - - int configAttrib(int name) const; - - EGLContext context() const { return ctx; } - void setContext(EGLContext context) { ctx = context; ownsContext = false;} - - EGLDisplay display() {return QEgl::display();} - - EGLConfig config() const { return cfg; } - void setConfig(EGLConfig config) { cfg = config; } - -private: - QEgl::API apiType; - EGLContext ctx; - EGLConfig cfg; - EGLSurface currentSurface; - bool current; - bool ownsContext; - bool sharing; - - static QEglContext *currentContext(QEgl::API api); - static void setCurrentContext(QEgl::API api, QEglContext *context); - - friend class QMeeGoGraphicsSystem; - friend class QMeeGoPlatformPixmap; -}; - -QT_END_NAMESPACE - -#endif // QEGLCONTEXT_P_H diff --git a/src/gui/egl/qeglproperties.cpp b/src/gui/egl/qeglproperties.cpp deleted file mode 100644 index 414ad8d06a..0000000000 --- a/src/gui/egl/qeglproperties.cpp +++ /dev/null @@ -1,563 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtGui 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 -#include - -#include "qeglproperties_p.h" -#include "qeglcontext_p.h" - -QT_BEGIN_NAMESPACE - -// Initialize a property block. -QEglProperties::QEglProperties() -{ - props.append(EGL_NONE); -} - -QEglProperties::QEglProperties(EGLConfig cfg) -{ - props.append(EGL_NONE); - for (int name = 0x3020; name <= 0x304F; ++name) { - EGLint value; - if (name != EGL_NONE && eglGetConfigAttrib(QEgl::display(), cfg, name, &value)) - setValue(name, value); - } - eglGetError(); // Clear the error state. -} - -// Fetch the current value associated with a property. -int QEglProperties::value(int name) const -{ - for (int index = 0; index < (props.size() - 1); index += 2) { - if (props[index] == name) - return props[index + 1]; - } - - // If the attribute has not been explicitly set, return the EGL default - // The following defaults were taken from the EGL 1.4 spec: - switch(name) { - case EGL_BUFFER_SIZE: return 0; - case EGL_RED_SIZE: return 0; - case EGL_GREEN_SIZE: return 0; - case EGL_BLUE_SIZE: return 0; - case EGL_ALPHA_SIZE: return 0; -#ifdef EGL_LUMINANCE_SIZE - case EGL_LUMINANCE_SIZE: return 0; -#endif -#ifdef EGL_ALPHA_MASK_SIZE - case EGL_ALPHA_MASK_SIZE: return 0; -#endif -#ifdef EGL_BIND_TO_TEXTURE_RGB - case EGL_BIND_TO_TEXTURE_RGB: return EGL_DONT_CARE; -#endif -#ifdef EGL_BIND_TO_TEXTURE_RGBA - case EGL_BIND_TO_TEXTURE_RGBA: return EGL_DONT_CARE; -#endif -#ifdef EGL_COLOR_BUFFER_TYPE - case EGL_COLOR_BUFFER_TYPE: return EGL_RGB_BUFFER; -#endif - case EGL_CONFIG_CAVEAT: return EGL_DONT_CARE; - case EGL_CONFIG_ID: return EGL_DONT_CARE; - case EGL_DEPTH_SIZE: return 0; - case EGL_LEVEL: return 0; - case EGL_NATIVE_RENDERABLE: return EGL_DONT_CARE; - case EGL_NATIVE_VISUAL_TYPE: return EGL_DONT_CARE; - case EGL_MAX_SWAP_INTERVAL: return EGL_DONT_CARE; - case EGL_MIN_SWAP_INTERVAL: return EGL_DONT_CARE; -#ifdef EGL_RENDERABLE_TYPE - case EGL_RENDERABLE_TYPE: return EGL_OPENGL_ES_BIT; -#endif - case EGL_SAMPLE_BUFFERS: return 0; - case EGL_SAMPLES: return 0; - case EGL_STENCIL_SIZE: return 0; - case EGL_SURFACE_TYPE: return EGL_WINDOW_BIT; - case EGL_TRANSPARENT_TYPE: return EGL_NONE; - case EGL_TRANSPARENT_RED_VALUE: return EGL_DONT_CARE; - case EGL_TRANSPARENT_GREEN_VALUE: return EGL_DONT_CARE; - case EGL_TRANSPARENT_BLUE_VALUE: return EGL_DONT_CARE; - -#ifdef EGL_VERSION_1_3 - case EGL_CONFORMANT: return 0; - case EGL_MATCH_NATIVE_PIXMAP: return EGL_NONE; -#endif - - case EGL_MAX_PBUFFER_HEIGHT: - case EGL_MAX_PBUFFER_WIDTH: - case EGL_MAX_PBUFFER_PIXELS: - case EGL_NATIVE_VISUAL_ID: - case EGL_NONE: - // Attribute does not affect config selection. - return EGL_DONT_CARE; - default: - // Attribute is unknown in EGL <= 1.4. - return EGL_DONT_CARE; - } -} - -// Set the value associated with a property, replacing an existing -// value if there is one. -void QEglProperties::setValue(int name, int value) -{ - for (int index = 0; index < (props.size() - 1); index += 2) { - if (props[index] == name) { - props[index + 1] = value; - return; - } - } - props[props.size() - 1] = name; - props.append(value); - props.append(EGL_NONE); -} - -// Remove a property value. Returns false if the property is not present. -bool QEglProperties::removeValue(int name) -{ - for (int index = 0; index < (props.size() - 1); index += 2) { - if (props[index] == name) { - while ((index + 2) < props.size()) { - props[index] = props[index + 2]; - ++index; - } - props.resize(props.size() - 2); - return true; - } - } - return false; -} - -void QEglProperties::setDeviceType(int devType) -{ - if (devType == QInternal::Pixmap || devType == QInternal::Image) - setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT); - else if (devType == QInternal::Pbuffer) - setValue(EGL_SURFACE_TYPE, EGL_PBUFFER_BIT); - else - setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); -} - - -// Sets the red, green, blue, and alpha sizes based on a pixel format. -// Normally used to match a configuration request to the screen format. -void QEglProperties::setPixelFormat(QImage::Format pixelFormat) -{ - int red, green, blue, alpha; - switch (pixelFormat) { - case QImage::Format_RGB32: - case QImage::Format_RGB888: - red = green = blue = 8; alpha = 0; break; - case QImage::Format_ARGB32: - case QImage::Format_ARGB32_Premultiplied: - red = green = blue = alpha = 8; break; - case QImage::Format_RGB16: - red = 5; green = 6; blue = 5; alpha = 0; break; - case QImage::Format_ARGB8565_Premultiplied: - red = 5; green = 6; blue = 5; alpha = 8; break; - case QImage::Format_RGB666: - red = green = blue = 6; alpha = 0; break; - case QImage::Format_ARGB6666_Premultiplied: - red = green = blue = alpha = 6; break; - case QImage::Format_RGB555: - red = green = blue = 5; alpha = 0; break; - case QImage::Format_ARGB8555_Premultiplied: - red = green = blue = 5; alpha = 8; break; - case QImage::Format_RGB444: - red = green = blue = 4; alpha = 0; break; - case QImage::Format_ARGB4444_Premultiplied: - red = green = blue = alpha = 4; break; - default: - qWarning() << "QEglProperties::setPixelFormat(): Unsupported pixel format"; - red = green = blue = alpha = 1; break; - } - setValue(EGL_RED_SIZE, red); - setValue(EGL_GREEN_SIZE, green); - setValue(EGL_BLUE_SIZE, blue); - setValue(EGL_ALPHA_SIZE, alpha); -} - -void QEglProperties::setRenderableType(QEgl::API api) -{ -#ifdef EGL_RENDERABLE_TYPE -#if defined(QT_OPENGL_ES_2) - if (api == QEgl::OpenGL) - setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT); -#elif defined(QT_OPENGL_ES) - if (api == QEgl::OpenGL) - setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT); -#elif defined(EGL_OPENGL_BIT) - if (api == QEgl::OpenGL) - setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT); -#endif -#ifdef EGL_OPENVG_BIT - if (api == QEgl::OpenVG) - setValue(EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT); -#endif -#else - Q_UNUSED(api); -#endif -} - -// Reduce the complexity of a configuration request to ask for less -// because the previous request did not result in success. Returns -// true if the complexity was reduced, or false if no further -// reductions in complexity are possible. -bool QEglProperties::reduceConfiguration() -{ -#ifdef EGL_SWAP_BEHAVIOR - if (value(EGL_SWAP_BEHAVIOR) != EGL_DONT_CARE) - removeValue(EGL_SWAP_BEHAVIOR); -#endif - -#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - // For OpenVG, we sometimes try to create a surface using a pre-multiplied format. If we can't - // find a config which supports pre-multiplied formats, remove the flag on the surface type: - EGLint surfaceType = value(EGL_SURFACE_TYPE); - if (surfaceType & EGL_VG_ALPHA_FORMAT_PRE_BIT) { - surfaceType ^= EGL_VG_ALPHA_FORMAT_PRE_BIT; - setValue(EGL_SURFACE_TYPE, surfaceType); - return true; - } -#endif - // EGL chooses configs with the highest color depth over - // those with smaller (but faster) lower color depths. One - // way around this is to set EGL_BUFFER_SIZE to 16, which - // trumps the others. Of course, there may not be a 16-bit - // config available, so it's the first restraint we remove. - if (value(EGL_BUFFER_SIZE) == 16) { - removeValue(EGL_BUFFER_SIZE); - return true; - } - if (removeValue(EGL_SAMPLE_BUFFERS)) { - removeValue(EGL_SAMPLES); - return true; - } - if (removeValue(EGL_ALPHA_SIZE)) { -#if defined(EGL_BIND_TO_TEXTURE_RGBA) && defined(EGL_BIND_TO_TEXTURE_RGB) - if (removeValue(EGL_BIND_TO_TEXTURE_RGBA)) - setValue(EGL_BIND_TO_TEXTURE_RGB, TRUE); -#endif - return true; - } - if (removeValue(EGL_STENCIL_SIZE)) - return true; - if (removeValue(EGL_DEPTH_SIZE)) - return true; -#ifdef EGL_BIND_TO_TEXTURE_RGB - if (removeValue(EGL_BIND_TO_TEXTURE_RGB)) - return true; -#endif - return false; -} - -static void addTag(QString& str, const QString& tag) -{ - int lastnl = str.lastIndexOf(QLatin1String("\n")); - if (lastnl == -1) - lastnl = 0; - if ((str.length() - lastnl) >= 50) - str += QLatin1String("\n "); - str += tag; -} - -// Convert a property list to a string suitable for debug output. -QString QEglProperties::toString() const -{ - QString str; - int val; - - val = value(EGL_CONFIG_ID); - if (val != EGL_DONT_CARE) { - str += QLatin1String("id="); - str += QString::number(val); - str += QLatin1Char(' '); - } - -#ifdef EGL_RENDERABLE_TYPE - val = value(EGL_RENDERABLE_TYPE); - if (val != EGL_DONT_CARE) { - str += QLatin1String("type="); - QStringList types; - if ((val & EGL_OPENGL_ES_BIT) != 0) - types += QLatin1String("es1"); -#ifdef EGL_OPENGL_ES2_BIT - if ((val & EGL_OPENGL_ES2_BIT) != 0) - types += QLatin1String("es2"); -#endif -#ifdef EGL_OPENGL_BIT - if ((val & EGL_OPENGL_BIT) != 0) - types += QLatin1String("gl"); -#endif - if ((val & EGL_OPENVG_BIT) != 0) - types += QLatin1String("vg"); - if ((val & ~7) != 0) - types += QString::number(val); - str += types.join(QLatin1String(",")); - } else { - str += QLatin1String("type=any"); - } -#else - str += QLatin1String("type=es1"); -#endif - - int red = value(EGL_RED_SIZE); - int green = value(EGL_GREEN_SIZE); - int blue = value(EGL_BLUE_SIZE); - int alpha = value(EGL_ALPHA_SIZE); - int bufferSize = value(EGL_BUFFER_SIZE); - if (bufferSize == (red + green + blue + alpha)) - bufferSize = 0; - str += QLatin1String(" rgba="); - str += QString::number(red); - str += QLatin1Char(','); - str += QString::number(green); - str += QLatin1Char(','); - str += QString::number(blue); - str += QLatin1Char(','); - str += QString::number(alpha); - if (bufferSize != 0) { - // Only report buffer size if different than r+g+b+a. - str += QLatin1String(" buffer-size="); - str += QString::number(bufferSize); - } - -#ifdef EGL_COLOR_BUFFER_TYPE - val = value(EGL_COLOR_BUFFER_TYPE); - if (val == EGL_LUMINANCE_BUFFER) { - addTag(str, QLatin1String(" color-buffer-type=luminance")); - } else if (val != EGL_DONT_CARE && val != EGL_RGB_BUFFER) { - addTag(str, QLatin1String(" color-buffer-type=")); - str += QString::number(val, 16); - } -#endif - - val = value(EGL_DEPTH_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" depth=")); - str += QString::number(val); - } - - val = value(EGL_STENCIL_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" stencil=")); - str += QString::number(val); - } - - val = value(EGL_SURFACE_TYPE); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" surface-type=")); - QStringList types; - if ((val & EGL_WINDOW_BIT) != 0) - types += QLatin1String("window"); - if ((val & EGL_PIXMAP_BIT) != 0) - types += QLatin1String("pixmap"); - if ((val & EGL_PBUFFER_BIT) != 0) - types += QLatin1String("pbuffer"); -#ifdef EGL_VG_COLORSPACE_LINEAR_BIT - if ((val & EGL_VG_COLORSPACE_LINEAR_BIT) != 0) - types += QLatin1String("vg-colorspace-linear"); -#endif -#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - if ((val & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0) - types += QLatin1String("vg-alpha-format-pre"); -#endif - if ((val & ~(EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT -#ifdef EGL_VG_COLORSPACE_LINEAR_BIT - | EGL_VG_COLORSPACE_LINEAR_BIT -#endif -#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - | EGL_VG_ALPHA_FORMAT_PRE_BIT -#endif - )) != 0) { - types += QString::number(val); - } - str += types.join(QLatin1String(",")); - } - - val = value(EGL_CONFIG_CAVEAT); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" caveat=")); - if (val == EGL_NONE) - str += QLatin1String("none"); - else if (val == EGL_SLOW_CONFIG) - str += QLatin1String("slow"); - else if (val == EGL_NON_CONFORMANT_CONFIG) - str += QLatin1String("non-conformant"); - else - str += QString::number(val, 16); - } - - val = value(EGL_LEVEL); - if (val != 0) { - addTag(str, QLatin1String(" level=")); - str += QString::number(val); - } - - int width, height, pixels; - width = value(EGL_MAX_PBUFFER_WIDTH); - height = value(EGL_MAX_PBUFFER_HEIGHT); - pixels = value(EGL_MAX_PBUFFER_PIXELS); - if (height != EGL_DONT_CARE || width != EGL_DONT_CARE) { - addTag(str, QLatin1String(" max-pbuffer-size=")); - str += QString::number(width); - str += QLatin1Char('x'); - str += QString::number(height); - if (pixels != (width * height)) { - addTag(str, QLatin1String(" max-pbuffer-pixels=")); - str += QString::number(pixels); - } - } - - val = value(EGL_NATIVE_RENDERABLE); - if (val != EGL_DONT_CARE) { - if (val) - addTag(str, QLatin1String(" native-renderable=true")); - else - addTag(str, QLatin1String(" native-renderable=false")); - } - - val = value(EGL_NATIVE_VISUAL_ID); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" visual-id=")); - str += QString::number(val); - } - - val = value(EGL_NATIVE_VISUAL_TYPE); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" visual-type=")); - str += QString::number(val); - } - -#ifdef EGL_PRESERVED_RESOURCES - val = value(EGL_PRESERVED_RESOURCES); - if (val != EGL_DONT_CARE) { - if (val) - addTag(str, QLatin1String(" preserved-resources=true")); - else - addTag(str, QLatin1String(" preserved-resources=false")); - } -#endif - - val = value(EGL_SAMPLES); - if (val != 0) { - addTag(str, QLatin1String(" samples=")); - str += QString::number(val); - } - - val = value(EGL_SAMPLE_BUFFERS); - if (val != 0) { - addTag(str, QLatin1String(" sample-buffers=")); - str += QString::number(val); - } - - val = value(EGL_TRANSPARENT_TYPE); - if (val == EGL_TRANSPARENT_RGB) { - addTag(str, QLatin1String(" transparent-rgb=")); - str += QString::number(value(EGL_TRANSPARENT_RED_VALUE)); - str += QLatin1Char(','); - str += QString::number(value(EGL_TRANSPARENT_GREEN_VALUE)); - str += QLatin1Char(','); - str += QString::number(value(EGL_TRANSPARENT_BLUE_VALUE)); - } - -#if defined(EGL_BIND_TO_TEXTURE_RGB) && defined(EGL_BIND_TO_TEXTURE_RGBA) - val = value(EGL_BIND_TO_TEXTURE_RGB); - int val2 = value(EGL_BIND_TO_TEXTURE_RGBA); - if (val != EGL_DONT_CARE || val2 != EGL_DONT_CARE) { - addTag(str, QLatin1String(" bind-texture=")); - if (val == EGL_TRUE) - str += QLatin1String("rgb"); - else - str += QLatin1String("no-rgb"); - if (val2 == EGL_TRUE) - str += QLatin1String(",rgba"); - else - str += QLatin1String(",no-rgba"); - } -#endif - -#ifdef EGL_MIN_SWAP_INTERVAL - val = value(EGL_MIN_SWAP_INTERVAL); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" min-swap-interval=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_MIN_SWAP_INTERVAL - val = value(EGL_MAX_SWAP_INTERVAL); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" max-swap-interval=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_LUMINANCE_SIZE - val = value(EGL_LUMINANCE_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" luminance=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_ALPHA_MASK_SIZE - val = value(EGL_ALPHA_MASK_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" alpha-mask=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_CONFORMANT - val = value(EGL_CONFORMANT); - if (val != 0) { - if (val) - addTag(str, QLatin1String(" conformant=true")); - else - addTag(str, QLatin1String(" conformant=false")); - } -#endif - - return str; -} - -QT_END_NAMESPACE - - diff --git a/src/gui/egl/qeglproperties_p.h b/src/gui/egl/qeglproperties_p.h deleted file mode 100644 index a5fc8f9b1f..0000000000 --- a/src/gui/egl/qeglproperties_p.h +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtGui 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 QEGLPROPERTIES_P_H -#define QEGLPROPERTIES_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the QtGui and QtOpenVG modules. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QPaintDevice; - -class Q_GUI_EXPORT QEglProperties -{ -public: - QEglProperties(); - QEglProperties(EGLConfig); - QEglProperties(const QEglProperties& other) : props(other.props) {} - ~QEglProperties() {} - - int value(int name) const; - void setValue(int name, int value); - bool removeValue(int name); - bool isEmpty() const { return props[0] == EGL_NONE; } - - const int *properties() const { return props.constData(); } - - void setPixelFormat(QImage::Format pixelFormat); - void setDeviceType(int devType); - void setPaintDeviceFormat(QPaintDevice *dev); - void setRenderableType(QEgl::API api); - - bool reduceConfiguration(); - - QString toString() const; - -private: - QVarLengthArray props; -}; - -QT_END_NAMESPACE - -#endif // QEGLPROPERTIES_P_H diff --git a/src/gui/gui.pro b/src/gui/gui.pro index db045930a3..a8a7df6e30 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -32,8 +32,6 @@ include(util/util.pri) include(math3d/math3d.pri) include(opengl/opengl.pri) -include(egl/egl.pri) - QMAKE_LIBS += $$QMAKE_LIBS_GUI DEFINES += Q_INTERNAL_QAPP_SRC -- cgit v1.2.3 From 5f9d126ca8ae4678ead6a70bccb459413e4c86cc Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 5 Mar 2012 12:15:50 +0100 Subject: remove strange .qmake.cache hacks they are obsolete (qmake knows the qt build configuration anyway), and messing with QTDIR is a recipe for disaster. Change-Id: Ib3594f38ec3192a5f70771f8bc5d8fd435bbbd15 Reviewed-by: Joerg Bornemann --- tests/auto/tools/qmake/testdata/one_space/one_space.pro | 5 ----- tests/auto/tools/qmake/testdata/simple_app/simple_app.pro | 5 ----- tests/auto/tools/qmake/testdata/simple_dll/simple_dll.pro | 5 ----- tests/auto/tools/qmake/testdata/subdirs/simple_app/simple_app.pro | 5 ----- tests/auto/tools/qmake/testdata/subdirs/simple_dll/simple_dll.pro | 6 ------ 5 files changed, 26 deletions(-) diff --git a/tests/auto/tools/qmake/testdata/one_space/one_space.pro b/tests/auto/tools/qmake/testdata/one_space/one_space.pro index 247bd27096..c5ffa40742 100644 --- a/tests/auto/tools/qmake/testdata/one_space/one_space.pro +++ b/tests/auto/tools/qmake/testdata/one_space/one_space.pro @@ -3,8 +3,3 @@ CONFIG += qt warn_on SOURCES = main.cpp TARGET = "one space" DESTDIR = ./ - -infile($(QTDIR)/.qmake.cache, CONFIG, debug):CONFIG += debug -infile($(QTDIR)/.qmake.cache, CONFIG, release):CONFIG += release - - diff --git a/tests/auto/tools/qmake/testdata/simple_app/simple_app.pro b/tests/auto/tools/qmake/testdata/simple_app/simple_app.pro index a8c4ad613d..94af3cd3ba 100644 --- a/tests/auto/tools/qmake/testdata/simple_app/simple_app.pro +++ b/tests/auto/tools/qmake/testdata/simple_app/simple_app.pro @@ -6,8 +6,3 @@ SOURCES = test_file.cpp \ RESOURCES = test.qrc TARGET = simple_app DESTDIR = ./ - -infile($(QTDIR)/.qmake.cache, CONFIG, debug):CONFIG += debug -infile($(QTDIR)/.qmake.cache, CONFIG, release):CONFIG += release - - diff --git a/tests/auto/tools/qmake/testdata/simple_dll/simple_dll.pro b/tests/auto/tools/qmake/testdata/simple_dll/simple_dll.pro index 9af38ecce6..09c18d1631 100644 --- a/tests/auto/tools/qmake/testdata/simple_dll/simple_dll.pro +++ b/tests/auto/tools/qmake/testdata/simple_dll/simple_dll.pro @@ -12,8 +12,3 @@ MOC_DIR = tmp OBJECTS_DIR = tmp TARGET = simple_dll DESTDIR = ./ - -infile($(QTDIR)/.qmake.cache, CONFIG, debug):CONFIG += debug -infile($(QTDIR)/.qmake.cache, CONFIG, release):CONFIG += release - - diff --git a/tests/auto/tools/qmake/testdata/subdirs/simple_app/simple_app.pro b/tests/auto/tools/qmake/testdata/subdirs/simple_app/simple_app.pro index f496d5bb8e..4191f142d8 100644 --- a/tests/auto/tools/qmake/testdata/subdirs/simple_app/simple_app.pro +++ b/tests/auto/tools/qmake/testdata/subdirs/simple_app/simple_app.pro @@ -5,8 +5,3 @@ SOURCES = test_file.cpp \ main.cpp TARGET = simple_app DESTDIR = ./ - -infile($(QTDIR)/.qmake.cache, CONFIG, debug):CONFIG += debug -infile($(QTDIR)/.qmake.cache, CONFIG, release):CONFIG += release - - diff --git a/tests/auto/tools/qmake/testdata/subdirs/simple_dll/simple_dll.pro b/tests/auto/tools/qmake/testdata/subdirs/simple_dll/simple_dll.pro index a54a07a0e7..09c18d1631 100644 --- a/tests/auto/tools/qmake/testdata/subdirs/simple_dll/simple_dll.pro +++ b/tests/auto/tools/qmake/testdata/subdirs/simple_dll/simple_dll.pro @@ -1,4 +1,3 @@ -include($(QTDIR)/.qmake.cache) TEMPLATE = lib CONFIG += qt warn_on dll @@ -13,8 +12,3 @@ MOC_DIR = tmp OBJECTS_DIR = tmp TARGET = simple_dll DESTDIR = ./ - -infile($(QTDIR)/.qmake.cache, CONFIG, debug):CONFIG += debug -infile($(QTDIR)/.qmake.cache, CONFIG, release):CONFIG += release - - -- cgit v1.2.3 From 63511b60a1549b7f1ff1a919b46a9a64fc3c38c9 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 5 Mar 2012 14:19:21 +0100 Subject: delete dumpcpp.prf it seems to be a no-op. presumably it was meant to be an auto-rebuild hack like in moc.prf, but it wasn't really "wired". Change-Id: I914456f5f5a63a06c2004b16edcf2e2ade448270 Reviewed-by: Joerg Bornemann --- mkspecs/features/win32/dumpcpp.prf | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 mkspecs/features/win32/dumpcpp.prf diff --git a/mkspecs/features/win32/dumpcpp.prf b/mkspecs/features/win32/dumpcpp.prf deleted file mode 100644 index 19637998c7..0000000000 --- a/mkspecs/features/win32/dumpcpp.prf +++ /dev/null @@ -1,11 +0,0 @@ -isEmpty(QMAKE_DUMPCPP_NAME) { - QMAKE_DUMPCPP_NAME = make_dumpcpp -} - -# auto depend on dumpcpp -!contains(TARGET, dumpcpp) { - isEmpty(QMAKE_DUMPCPP_SRC): QMAKE_DUMPCPP_SRC = "$(QTDIR)/tools/activeqt/dumpcpp" - make_dumpcpp.commands = (cd $$QMAKE_DUMPCPP_SRC && $(QMAKE) && $(MAKE)) - QMAKE_EXTRA_TARGETS += $$QMAKE_DUMPCPP_NAME -} - -- cgit v1.2.3 From 59ae59977b05b0edf2ae841fc5149bdb401d8164 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 5 Mar 2012 14:20:17 +0100 Subject: use $$QT_BUILD_TREE instead of $$(QTDIR) it's a "tad" more reliable Change-Id: I7207daa6869d1682719cc357794cf6efff496225 Reviewed-by: Joerg Bornemann --- tests/benchmarks/gui/image/qimagereader/qimagereader.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/benchmarks/gui/image/qimagereader/qimagereader.pro b/tests/benchmarks/gui/image/qimagereader/qimagereader.pro index cc2c8e0701..87c9de5461 100644 --- a/tests/benchmarks/gui/image/qimagereader/qimagereader.pro +++ b/tests/benchmarks/gui/image/qimagereader/qimagereader.pro @@ -14,11 +14,11 @@ wince*: { addFiles.path = . CONFIG(debug, debug|release):{ - imageFormatsPlugins.files = $$(QTDIR)/plugins/imageformats/*d4.dll + imageFormatsPlugins.files = $$QT_BUILD_TREE/plugins/imageformats/*d4.dll } CONFIG(release, debug|release):{ - imageFormatsPlugins.files = $$(QTDIR)/plugins/imageformats/*[^d]4.dll + imageFormatsPlugins.files = $$QT_BUILD_TREE/plugins/imageformats/*[^d]4.dll } imageFormatsPlugins.path = imageformats DEPLOYMENT += addFiles imageFormatsPlugins -- cgit v1.2.3 From d6206075be868adda80d3d3468b126b77b489bca Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 2 Mar 2012 17:52:12 +0100 Subject: remove automatic building of moc from moc.prf the problem this (probably) tried to solve has been solved via ordered builds a *long* time ago. Change-Id: I84c58076c864735eea4210ec60aa060fe3e5d97e Reviewed-by: Joerg Bornemann --- configure | 1 - mkspecs/features/moc.prf | 6 ------ 2 files changed, 7 deletions(-) diff --git a/configure b/configure index 151ddb046f..8df49a9928 100755 --- a/configure +++ b/configure @@ -6731,7 +6731,6 @@ QMAKE_LIBDIR_QT = \$\$QT_BUILD_TREE/lib include(\$\$PWD/mkspecs/qmodule.pri) CONFIG += $QMAKE_CONFIG dylib depend_includepath fix_output_dirs no_private_qt_headers_warning QTDIR_build QMAKE_ABSOLUTE_SOURCE_ROOT = \$\$QT_SOURCE_TREE -QMAKE_MOC_SRC = \$\$QT_BUILD_TREE/src/moc EOF diff --git a/mkspecs/features/moc.prf b/mkspecs/features/moc.prf index 3f155a2d6b..94f8100f88 100644 --- a/mkspecs/features/moc.prf +++ b/mkspecs/features/moc.prf @@ -97,12 +97,6 @@ equals(MOC_DIR, .) { unix:!no_mocdepend { moc_source.depends += $$first(QMAKE_MOC) moc_header.depends += $$first(QMAKE_MOC) - !contains(TARGET, moc) { #auto build moc - isEmpty(QMAKE_MOC_SRC):QMAKE_MOC_SRC = "$(QTDIR)/src/tools/moc" - make_moc.target = $$first(QMAKE_MOC) - make_moc.commands = (cd $$QMAKE_MOC_SRC && $(MAKE)) - QMAKE_EXTRA_TARGETS += make_moc - } } #generate a mocclean -- cgit v1.2.3 From deea66c9f43c0a71d1f6387d7d4d59edeae79648 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 2 Mar 2012 21:32:02 +0100 Subject: remove obviously counterproductive uses of QT_SOURCE_TREE & QT_BUILD_TREE Change-Id: I77cf734b58f350d82277c084a680ab56fdf82f08 Reviewed-by: Joerg Bornemann --- qtbase.pro | 20 ++++++++++---------- src/src.pro | 28 ++++++++++++++-------------- src/tools/tools.pro | 8 ++++---- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/qtbase.pro b/qtbase.pro index 9290d5adcd..7648a63826 100644 --- a/qtbase.pro +++ b/qtbase.pro @@ -96,36 +96,36 @@ CONFIG -= qt #qmake qmake.path = $$[QT_HOST_BINS] win32 { - qmake.files=$$QT_BUILD_TREE/bin/qmake.exe + qmake.files = $$OUT_PWD/bin/qmake.exe } else { - qmake.files=$$QT_BUILD_TREE/bin/qmake + qmake.files = $$OUT_PWD/bin/qmake } INSTALLS += qmake #syncqt syncqt.path = $$[QT_HOST_BINS] -syncqt.files=$$QT_BUILD_TREE/bin/syncqt -win32:syncqt.files=$$QT_BUILD_TREE/bin/syncqt.bat +syncqt.files = $$OUT_PWD/bin/syncqt +win32:syncqt.files = $$OUT_PWD/bin/syncqt.bat INSTALLS += syncqt #qtmodule-configtests configtests.path = $$[QT_HOST_BINS] -configtests.files=$$QT_BUILD_TREE/bin/qtmodule-configtests +configtests.files = $$PWD/bin/qtmodule-configtests INSTALLS += configtests #mkspecs mkspecs.path = $$[QT_HOST_DATA]/mkspecs -mkspecs.files=$$QT_BUILD_TREE/mkspecs/qconfig.pri $$QT_BUILD_TREE/mkspecs/qmodule.pri $$files($$QT_SOURCE_TREE/mkspecs/*) -mkspecs.files -= $$QT_SOURCE_TREE/mkspecs/modules +mkspecs.files = $$OUT_PWD/mkspecs/qconfig.pri $$OUT_PWD/mkspecs/qmodule.pri $$files($$PWD/mkspecs/*) +mkspecs.files -= $$PWD/mkspecs/modules unix { DEFAULT_QMAKESPEC = $$QMAKESPEC DEFAULT_QMAKESPEC ~= s,^.*mkspecs/,,g mkspecs.commands += $(DEL_FILE) $(INSTALL_ROOT)$$mkspecs.path/default; $(SYMLINK) $$DEFAULT_QMAKESPEC $(INSTALL_ROOT)$$mkspecs.path/default - mkspecs.files -= $$QT_SOURCE_TREE/mkspecs/default + mkspecs.files -= $$PWD/mkspecs/default } -win32:!equals(QT_BUILD_TREE, $$QT_SOURCE_TREE) { +win32:!equals(OUT_PWD, $$PWD) { # When shadow building on Windows, the default mkspec only exists in the build tree. - mkspecs.files += $$QT_BUILD_TREE/mkspecs/default + mkspecs.files += $$OUT_PWD/mkspecs/default } INSTALLS += mkspecs diff --git a/src/src.pro b/src/src.pro index 941064eb59..21916b31f4 100644 --- a/src/src.pro +++ b/src/src.pro @@ -16,35 +16,35 @@ contains(QT_CONFIG, no-gui): SRC_SUBDIRS -= src_gui contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2): SRC_SUBDIRS += src_opengl SRC_SUBDIRS += src_plugins -src_winmain.subdir = $$QT_SOURCE_TREE/src/winmain +src_winmain.subdir = $$PWD/winmain src_winmain.target = sub-winmain -src_corelib.subdir = $$QT_SOURCE_TREE/src/corelib +src_corelib.subdir = $$PWD/corelib src_corelib.target = sub-corelib -src_xml.subdir = $$QT_SOURCE_TREE/src/xml +src_xml.subdir = $$PWD/xml src_xml.target = sub-xml -src_dbus.subdir = $$QT_SOURCE_TREE/src/dbus +src_dbus.subdir = $$PWD/dbus src_dbus.target = sub-dbus -src_gui.subdir = $$QT_SOURCE_TREE/src/gui +src_gui.subdir = $$PWD/gui src_gui.target = sub-gui -src_sql.subdir = $$QT_SOURCE_TREE/src/sql +src_sql.subdir = $$PWD/sql src_sql.target = sub-sql -src_network.subdir = $$QT_SOURCE_TREE/src/network +src_network.subdir = $$PWD/network src_network.target = sub-network -src_opengl.subdir = $$QT_SOURCE_TREE/src/opengl +src_opengl.subdir = $$PWD/opengl src_opengl.target = sub-opengl -src_plugins.subdir = $$QT_SOURCE_TREE/src/plugins +src_plugins.subdir = $$PWD/plugins src_plugins.target = sub-plugins -src_widgets.subdir = $$QT_SOURCE_TREE/src/widgets +src_widgets.subdir = $$PWD/widgets src_widgets.target = sub-widgets !wince*: { - src_printsupport.subdir = $$QT_SOURCE_TREE/src/printsupport + src_printsupport.subdir = $$PWD/printsupport src_printsupport.target = sub-printsupport } -src_testlib.subdir = $$QT_SOURCE_TREE/src/testlib +src_testlib.subdir = $$PWD/testlib src_testlib.target = sub-testlib -src_platformsupport.subdir = $$QT_SOURCE_TREE/src/platformsupport +src_platformsupport.subdir = $$PWD/platformsupport src_platformsupport.target = sub-platformsupport -src_concurrent.subdir = $$QT_SOURCE_TREE/src/concurrent +src_concurrent.subdir = $$PWD/concurrent src_concurrent.target = sub-concurrent diff --git a/src/tools/tools.pro b/src/tools/tools.pro index 1d12423744..8c2739a381 100644 --- a/src/tools/tools.pro +++ b/src/tools/tools.pro @@ -3,13 +3,13 @@ TEMPLATE = subdirs 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 +src_tools_bootstrap.subdir = $$PWD/bootstrap src_tools_bootstrap.target = sub-tools-bootstrap -src_tools_moc.subdir = $$QT_SOURCE_TREE/src/tools/moc +src_tools_moc.subdir = $$PWD/moc src_tools_moc.target = sub-moc -src_tools_rcc.subdir = $$QT_SOURCE_TREE/src/tools/rcc +src_tools_rcc.subdir = $$PWD/rcc src_tools_rcc.target = sub-rcc -src_tools_uic.subdir = $$QT_SOURCE_TREE/src/tools/uic +src_tools_uic.subdir = $$PWD/uic src_tools_uic.target = sub-uic src_tools_qdoc.subdir = $$QT_SOURCE_TREE/src/tools/qdoc src_tools_qdoc.target = sub-qdoc -- cgit v1.2.3 From adfcd9892266812596d0b19c72d38248e3ebf3b1 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 5 Mar 2012 11:49:51 +0100 Subject: replace uses of QMAKE_INCDIR_QT and QMAKE_LIBDIR_QT with module-specific variables Change-Id: Id410887fa97f345a229e0cbf395633ccf303fa2f Reviewed-by: Joerg Bornemann --- mkspecs/features/qt.prf | 2 +- mkspecs/features/qt_functions.prf | 2 +- src/platformsupport/platformsupport.pro | 2 +- src/winmain/winmain.pro | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf index 21443aa5b5..f5ee74cf86 100644 --- a/mkspecs/features/qt.prf +++ b/mkspecs/features/qt.prf @@ -189,7 +189,7 @@ for(QTLIB, QT) { qt_compat { !qt_compat_no_warning:QTDIR_build:warning(***USE of COMPAT inside of QTDIR!**) #just for us - INCLUDEPATH *= $$QMAKE_INCDIR_QT/Qt + INCLUDEPATH *= $$QT.core.includes DEFINES *= QT_COMPAT } diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 31b28156e8..370187b722 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -146,7 +146,7 @@ defineTest(qtAddModule) { # to give access to sources or include files, and not for linking. !isEmpty(MODULE_LIBS) { !isEmpty(QMAKE_LSB) { - QMAKE_LFLAGS *= --lsb-libpath=$$$$QMAKE_LIBDIR_QT + QMAKE_LFLAGS *= --lsb-libpath=$$MODULE_LIBS QMAKE_LFLAGS *= -L/opt/lsb/lib QMAKE_LFLAGS *= --lsb-shared-libs=$${MODULE_NAME}$${QT_LIBINFIX} } diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 8322d4c70f..47618f02e3 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -3,7 +3,7 @@ TARGET = QtPlatformSupport QPRO_PWD = $$PWD QT += core-private gui-private TEMPLATE = lib -DESTDIR = $$QMAKE_LIBDIR_QT +DESTDIR = $$QT.gui.libs CONFIG += module CONFIG += staticlib diff --git a/src/winmain/winmain.pro b/src/winmain/winmain.pro index 6630d86326..04a3756bb5 100644 --- a/src/winmain/winmain.pro +++ b/src/winmain/winmain.pro @@ -11,11 +11,11 @@ win32 { win32-borland:DEFINES += QT_NEEDS_QMAIN SOURCES = qtmain_win.cpp CONFIG += png - INCLUDEPATH += tmp $$QMAKE_INCDIR_QT/QtCore + INCLUDEPATH += tmp $$QT.core.includes } !win32:error("$$_FILE_ is intended only for Windows!") load(qt_module_config) -DESTDIR = $$QMAKE_LIBDIR_QT +DESTDIR = $$QT.core.libs wince*:QMAKE_POST_LINK = -- cgit v1.2.3 From 4c0df9feb2b44d0c4fcaa5076f00aa08fbc1dda5 Mon Sep 17 00:00:00 2001 From: Martin Petersson Date: Wed, 7 Mar 2012 12:05:59 +0100 Subject: QtNetwork: blacklist two more certificates The comodogate 72:03:21:05:c5:0c:08:57:3d:8e:a5:30:4e:fe:e8:b0 certificate is a test certificate and the MD5 Collisions was created as a proof of concept deliberately made to be expired at the time of it's creation. Task-number: QTBUG-24654 Change-Id: Ic8eb417363569fe50bf19cd229658f5e371862f7 Reviewed-by: Richard J. Moore --- src/network/ssl/qsslcertificate.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index a9573bf1d8..65634a3cb7 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -1161,6 +1161,8 @@ static const char *certificate_blacklist[] = { "07:27:14:a9", "Digisign Server ID (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Verizon CyberTrust "4c:0e:63:6a", "Digisign Server ID - (Enrich)", // (Malaysian) Digicert Sdn. Bhd. cross-signed by Entrust + "72:03:21:05:c5:0c:08:57:3d:8e:a5:30:4e:fe:e8:b0", "UTN-USERFirst-Hardware", // comodogate test certificate + "41", "MD5 Collisions Inc. (http://www.phreedom.org/md5)", // http://www.phreedom.org/research/rogue-ca/ 0 }; -- cgit v1.2.3 From c35d65e27d9232452d2e57973cdb132181440bbf Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 8 Mar 2012 16:13:28 +0100 Subject: Windows: Fix flag handling. Fix a typo that caused a variable to be hidden such that the Qt::WindowFlags were not used. Change-Id: Iea4456b0cd4c968e0fbfdd53e5006ffee0298b24 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowswindow.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 1edb243f4e..fa3661db22 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -441,17 +441,17 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange) const { if (desktop || !hwnd) return; - UINT flags = SWP_NOMOVE | SWP_NOSIZE; + UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE; if (frameChange) - flags |= SWP_FRAMECHANGED; + swpFlags |= SWP_FRAMECHANGED; if (topLevel) { - flags |= SWP_NOACTIVATE; + swpFlags |= SWP_NOACTIVATE; if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) { - SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, flags); + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, swpFlags); if (flags & Qt::WindowStaysOnBottomHint) qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time"; } else if (flags & Qt::WindowStaysOnBottomHint) { - SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, flags); + SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, swpFlags); } if (flags & (Qt::CustomizeWindowHint|Qt::WindowTitleHint)) { HMENU systemMenu = GetSystemMenu(hwnd, FALSE); @@ -461,7 +461,7 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange) const EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED); } } else { // child. - SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags); + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, swpFlags); } } -- cgit v1.2.3 From b5431419923e8f00e2d8a4a75a20f75f66241842 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 23 Feb 2012 02:53:08 +0000 Subject: QRegularExpression: improve JIT memory handling PCRE's JIT uses by default 32K on the pcre_exec caller's stack. This is fine for most situations, but in some cases (esp. patterns with lot of recursion) more memory is required. Therefore, if a match execution fails due to exhausting JIT memory, we let PCRE allocate up to 512KB to be used for the JIT's stack. The pointer to the allocated memory is put in thread local storage (so it can be reused from the same thread, if needed, and automatically goes away when the thread dies). Change-Id: Ica5fb7d517068befff88ebb198a603a26ec5d8a7 Reviewed-by: Bradley T. Hughes Reviewed-by: Thiago Macieira --- src/corelib/tools/qregularexpression.cpp | 96 +++++++++++++++++++--- .../qregularexpression/tst_qregularexpression.cpp | 27 ++++++ .../qregularexpression/tst_qregularexpression.h | 2 + 3 files changed, 113 insertions(+), 12 deletions(-) diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp index 0fa7d6459e..5deb485d3e 100644 --- a/src/corelib/tools/qregularexpression.cpp +++ b/src/corelib/tools/qregularexpression.cpp @@ -47,6 +47,8 @@ #include #include #include +#include +#include #include @@ -989,6 +991,47 @@ void QRegularExpressionPrivate::getPatternInfo() (patternNewlineSetting == PCRE_NEWLINE_ANYCRLF); } + +/*! + \class QPcreJitStackPointer + \internal + + Simple "smartpointer" wrapper around a pcre_jit_stack, to be used with + QThreadStorage. +*/ +class QPcreJitStackPointer +{ + Q_DISABLE_COPY(QPcreJitStackPointer); + +public: + QPcreJitStackPointer() + { + // The default JIT stack size in PCRE is 32K, + // we allocate from 32K up to 512K. + stack = pcre16_jit_stack_alloc(32*1024, 512*1024); + } + ~QPcreJitStackPointer() + { + if (stack) + pcre16_jit_stack_free(stack); + } + + pcre16_jit_stack *stack; +}; + +Q_GLOBAL_STATIC(QThreadStorage, jitStacks) + +/*! + \internal +*/ +static pcre16_jit_stack *qtPcreCallback(void *) +{ + if (jitStacks()->hasLocalData()) + return jitStacks()->localData()->stack; + + return 0; +} + /*! \internal */ @@ -1044,6 +1087,9 @@ pcre16_extra *QRegularExpressionPrivate::optimizePattern() const char *err; studyData = pcre16_study(compiledPattern, studyOptions, &err); + if (studyData && studyData->flags & PCRE_EXTRA_EXECUTABLE_JIT) + pcre16_assign_jit_stack(studyData, qtPcreCallback, 0); + if (!studyData && err) qWarning("QRegularExpressionPrivate::optimizePattern(): pcre_study failed: %s", err); @@ -1067,6 +1113,32 @@ int QRegularExpressionPrivate::captureIndexForName(const QString &name) const return -1; } +/*! + \internal + + This is a simple wrapper for pcre16_exec for handling the case in which the + JIT runs out of memory. In that case, we allocate a thread-local JIT stack + and re-run pcre16_exec. +*/ +static int pcre16SafeExec(const pcre16 *code, const pcre16_extra *extra, + const unsigned short *subject, int length, + int startOffset, int options, + int *ovector, int ovecsize) +{ + int result = pcre16_exec(code, extra, subject, length, + startOffset, options, ovector, ovecsize); + + if (result == PCRE_ERROR_JIT_STACKLIMIT && !jitStacks()->hasLocalData()) { + QPcreJitStackPointer *p = new QPcreJitStackPointer; + jitStacks()->setLocalData(p); + + result = pcre16_exec(code, extra, subject, length, + startOffset, options, ovector, ovecsize); + } + + return result; +} + /*! \internal @@ -1134,15 +1206,15 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString int result; if (!previousMatchWasEmpty) { - result = pcre16_exec(compiledPattern, currentStudyData, - subjectUtf16, subjectLength, - offset, pcreOptions, - captureOffsets, captureOffsetsCount); + result = pcre16SafeExec(compiledPattern, currentStudyData, + subjectUtf16, subjectLength, + offset, pcreOptions, + captureOffsets, captureOffsetsCount); } else { - result = pcre16_exec(compiledPattern, currentStudyData, - subjectUtf16, subjectLength, - offset, pcreOptions | PCRE_NOTEMPTY_ATSTART | PCRE_ANCHORED, - captureOffsets, captureOffsetsCount); + result = pcre16SafeExec(compiledPattern, currentStudyData, + subjectUtf16, subjectLength, + offset, pcreOptions | PCRE_NOTEMPTY_ATSTART | PCRE_ANCHORED, + captureOffsets, captureOffsetsCount); if (result == PCRE_ERROR_NOMATCH) { ++offset; @@ -1157,10 +1229,10 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString ++offset; } - result = pcre16_exec(compiledPattern, currentStudyData, - subjectUtf16, subjectLength, - offset, pcreOptions, - captureOffsets, captureOffsetsCount); + result = pcre16SafeExec(compiledPattern, currentStudyData, + subjectUtf16, subjectLength, + offset, pcreOptions, + captureOffsets, captureOffsetsCount); } } diff --git a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp index 72157c0536..38b82ecf77 100644 --- a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp +++ b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp @@ -1196,3 +1196,30 @@ void tst_QRegularExpression::captureCount() if (!re.isValid()) QCOMPARE(re.captureCount(), -1); } + +void tst_QRegularExpression::pcreJitStackUsage_data() +{ + QTest::addColumn("pattern"); + QTest::addColumn("subject"); + // these patterns cause enough backtrack (or even infinite recursion) + // in the regexp engine, so that JIT requests more memory. + QTest::newRow("jitstack01") << "(?(R)a*(?1)|((?R))b)" << "aaaabcde"; + QTest::newRow("jitstack02") << "(?(R)a*(?1)|((?R))b)" << "aaaaaaabcde"; +} + +void tst_QRegularExpression::pcreJitStackUsage() +{ + QFETCH(QString, pattern); + QFETCH(QString, subject); + + QRegularExpression re(pattern); + QVERIFY(re.isValid()); + QRegularExpressionMatch match = re.match(subject); + consistencyCheck(match); + QRegularExpressionMatchIterator iterator = re.globalMatch(subject); + consistencyCheck(iterator); + while (iterator.hasNext()) { + match = iterator.next(); + consistencyCheck(match); + } +} diff --git a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h index 1a703a8f92..fd8bdfa3af 100644 --- a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h +++ b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h @@ -71,6 +71,8 @@ private slots: void operatoreq(); void captureCount_data(); void captureCount(); + void pcreJitStackUsage_data(); + void pcreJitStackUsage(); private: void provideRegularExpressions(); -- cgit v1.2.3 From 824cc9492144dff2494645319854cb68ba5570c6 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Sun, 26 Feb 2012 22:37:45 +0000 Subject: QRegularExpression: minor fix to captureIndexForName Although passing a null pointer to pcre16_get_stringnumber for the compiled pattern should simply make it error out, it's actually an undocumented behaviour, so let's stay safe and add an explicit check. Tests for this codepath are added. Change-Id: Ifd9c87874f6812ba487104ec1a5bbc83c3b16761 Reviewed-by: Thiago Macieira --- src/corelib/tools/qregularexpression.cpp | 3 ++ .../qregularexpression/tst_qregularexpression.cpp | 58 +++++++++++++++++++++- .../qregularexpression/tst_qregularexpression.h | 2 + 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp index 5deb485d3e..c7e8e6ccb8 100644 --- a/src/corelib/tools/qregularexpression.cpp +++ b/src/corelib/tools/qregularexpression.cpp @@ -1106,6 +1106,9 @@ int QRegularExpressionPrivate::captureIndexForName(const QString &name) const { Q_ASSERT(!name.isEmpty()); + if (!compiledPattern) + return -1; + int index = pcre16_get_stringnumber(compiledPattern, name.utf16()); if (index >= 0) return index; diff --git a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp index 38b82ecf77..a4c04d6207 100644 --- a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp +++ b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.cpp @@ -95,8 +95,13 @@ bool operator==(const QRegularExpressionMatch &rem, const Match &m) } Q_FOREACH (const QString &name, m.namedCaptured.keys()) { - if (rem.captured(name) != m.namedCaptured.value(name)) + QString remCaptured = rem.captured(name); + QString mCaptured = m.namedCaptured.value(name); + if (remCaptured != mCaptured + || remCaptured.isNull() != mCaptured.isNull() + || remCaptured.isEmpty() != mCaptured.isEmpty()) { return false; + } } } @@ -571,6 +576,32 @@ void tst_QRegularExpression::normalMatch_data() << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) << m; + // non existing names for capturing groups + m.clear(); + m.isValid = true; m.hasMatch = true; + m.captured << "a string" << "a" << "string"; + m.namedCaptured["article"] = "a"; + m.namedCaptured["noun"] = "string"; + m.namedCaptured["nonexisting1"] = QString(); + m.namedCaptured["nonexisting2"] = QString(); + m.namedCaptured["nonexisting3"] = QString(); + QTest::newRow("match10") << QRegularExpression("(?
    \\w+) (?\\w+)") + << "a string" + << 0 + << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) + << m; + + m.clear(); + m.isValid = true; m.hasMatch = true; + m.captured << "" << ""; + m.namedCaptured["digits"] = ""; // empty VS null + m.namedCaptured["nonexisting"] = QString(); + QTest::newRow("match11") << QRegularExpression("(?\\d*)") + << "abcde" + << 0 + << QRegularExpression::MatchOptions(QRegularExpression::NoMatchOption) + << m; + // *** m.clear(); @@ -1223,3 +1254,28 @@ void tst_QRegularExpression::pcreJitStackUsage() consistencyCheck(match); } } + +void tst_QRegularExpression::regularExpressionMatch_data() +{ + QTest::addColumn("pattern"); + QTest::addColumn("subject"); + + QTest::newRow("validity01") << "(?\\d+)" << "1234 abcd"; + QTest::newRow("validity02") << "(?\\d+) (?\\w+)" << "1234 abcd"; +} + +void tst_QRegularExpression::regularExpressionMatch() +{ + QFETCH(QString, pattern); + QFETCH(QString, subject); + + QRegularExpression re(pattern); + QVERIFY(re.isValid()); + QRegularExpressionMatch match = re.match(subject); + consistencyCheck(match); + QCOMPARE(match.captured("non-existing").isNull(), true); + QTest::ignoreMessage(QtWarningMsg, "QRegularExpressionMatch::captured: empty capturing group name passed"); + QCOMPARE(match.captured("").isNull(), true); + QTest::ignoreMessage(QtWarningMsg, "QRegularExpressionMatch::captured: empty capturing group name passed"); + QCOMPARE(match.captured(QString()).isNull(), true); +} diff --git a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h index fd8bdfa3af..72a19199fd 100644 --- a/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h +++ b/tests/auto/corelib/tools/qregularexpression/tst_qregularexpression.h @@ -73,6 +73,8 @@ private slots: void captureCount(); void pcreJitStackUsage_data(); void pcreJitStackUsage(); + void regularExpressionMatch_data(); + void regularExpressionMatch(); private: void provideRegularExpressions(); -- cgit v1.2.3 From 1e13160a005f9f33cfeb2f2b602756e6627bef58 Mon Sep 17 00:00:00 2001 From: Girish Ramakrishnan Date: Thu, 8 Mar 2012 05:11:11 -0800 Subject: Fix qtmodule-configtests to honor error codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test is marked as fail if qmake or make fails. Change-Id: I565c68af4a9271d7aa36fb592ac399aa728ba4d8 Reviewed-by: Tor Arne Vestbø --- bin/qtmodule-configtests | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/bin/qtmodule-configtests b/bin/qtmodule-configtests index 412f57ff8a..965a3e556b 100755 --- a/bin/qtmodule-configtests +++ b/bin/qtmodule-configtests @@ -268,17 +268,19 @@ sub executeTest { unlink $testOutFile1, $testOutFile2; # Run qmake && make - executeLoggedCommand($QMAKE, @QMAKEARGS); - my ($makeExitCode, $makeOutput) = executeLoggedCommand($MAKE); - - # If make prints "blah blah blah\nSkipped." we consider this a skipped test - if ($makeOutput !~ qr(^Skipped\.$)ms) { - # Check the test exists (can't reliably execute, especially for cross compilation) - if (-e $testOutFile1 or -e $testOutFile2) { - $ret = 1; + my ($qmakeExitCode, $qmakeOutput) = executeLoggedCommand($QMAKE, @QMAKEARGS); + if ($qmakeExitCode == 0) { + my ($makeExitCode, $makeOutput) = executeLoggedCommand($MAKE); + + # If make prints "blah blah blah\nSkipped." we consider this a skipped test + if ($makeOutput !~ qr(^Skipped\.$)ms) { + # Check the test exists (can't reliably execute, especially for cross compilation) + if ($makeExitCode == 0 and (-e $testOutFile1 or -e $testOutFile2)) { + $ret = 1; + } + } else { + $ret = 2; } - } else { - $ret = 2; } my $fh; -- cgit v1.2.3 From a0933f4d7485d22f38b80c67f79b8d3f721b19a2 Mon Sep 17 00:00:00 2001 From: Rick Stockton Date: Wed, 7 Mar 2012 16:38:37 -0800 Subject: BlackBerry Plugin: support 8 mouse buttons, instead of just 3. The mask of possible mouse buttons in QNX provides tracking for the up/down State of up to 8 mouse buttons. This update adds support for the 5 buttons which we previously ignored in Qt on this Platform. Task-number: QTBUG-24682 Change-Id: I8c1d2b2a5d0deb3b857fb387c242c3792e21ff95 Reviewed-by: Kevin Krammer Reviewed-by: Robin Burchell --- src/plugins/platforms/blackberry/qbbeventthread.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/blackberry/qbbeventthread.cpp b/src/plugins/platforms/blackberry/qbbeventthread.cpp index 547428d1c4..6951921fe9 100644 --- a/src/plugins/platforms/blackberry/qbbeventthread.cpp +++ b/src/plugins/platforms/blackberry/qbbeventthread.cpp @@ -380,13 +380,26 @@ void QBBEventThread::handlePointerEvent(screen_event_t event) QPoint localPoint(windowPos[0], windowPos[1]); // Convert buttons. + // Some QNX header files invert 'Right Button versus "Left Button' ('Right' == 0x01). But they also offer a 'Button Swap' bit, + // so we may receive events as shown. (If this is wrong, the fix is easy.) + // QNX Button mask is 8 buttons wide, with a maximum value of x080. Qt::MouseButtons buttons = Qt::NoButton; - if (buttonState & 1) + if (buttonState & 0x01) buttons |= Qt::LeftButton; - if (buttonState & 2) + if (buttonState & 0x02) buttons |= Qt::MidButton; - if (buttonState & 4) + if (buttonState & 0x04) buttons |= Qt::RightButton; + if (buttonState & 0x08) + buttons |= Qt::ExtraButton1; // AKA 'Qt::BackButton' + if (buttonState & 0x10) + buttons |= Qt::ExtraButton2; // AKA 'Qt::ForwardButton' + if (buttonState & 0x20) + buttons |= Qt::ExtraButton3; + if (buttonState & 0x40) + buttons |= Qt::ExtraButton4; + if (buttonState & 0x80) + buttons |= Qt::ExtraButton5; if (w) { // Inject mouse event into Qt only if something has changed. -- cgit v1.2.3 From d59e85d9095f5d8fa787149fe8d34e8dfac0a0b5 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 1 Mar 2012 17:45:55 +0100 Subject: remove the fixed qt tool assignments from the configures the tool locations are now determined with qtPrepareTool(), which takes non-installed qt builds into account already. Change-Id: I17b2c5f4b181417f2a612be2f540768e7dc0ae4e Reviewed-by: Joerg Bornemann --- configure | 3 --- tools/configure/configureapp.cpp | 4 ---- 2 files changed, 7 deletions(-) diff --git a/configure b/configure index 8df49a9928..756088d517 100755 --- a/configure +++ b/configure @@ -6722,9 +6722,6 @@ QT_BUILD_TREE = \$\$quote($outpath) QT_BUILD_PARTS = $CFG_BUILD_PARTS #local paths that cannot be queried from the QT_INSTALL_* properties while building QTDIR -QMAKE_MOC = \$\$QT_BUILD_TREE/bin/moc -QMAKE_UIC = \$\$QT_BUILD_TREE/bin/uic -QMAKE_RCC = \$\$QT_BUILD_TREE/bin/rcc QMAKE_INCDIR_QT = \$\$QT_BUILD_TREE/include QMAKE_LIBDIR_QT = \$\$QT_BUILD_TREE/lib diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index a586821bdc..eafe547063 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -2512,10 +2512,6 @@ void Configure::generateCachefile() //so that we can build without an install first (which would be impossible) moduleStream << "#local paths that cannot be queried from the QT_INSTALL_* properties while building QTDIR" << endl; - moduleStream << "QMAKE_MOC = $$QT_BUILD_TREE" << fixSeparators("/bin/moc.exe", true) << endl; - moduleStream << "QMAKE_UIC = $$QT_BUILD_TREE" << fixSeparators("/bin/uic.exe", true) << endl; - moduleStream << "QMAKE_RCC = $$QT_BUILD_TREE" << fixSeparators("/bin/rcc.exe", true) << endl; - moduleStream << "QMAKE_DUMPCPP = $$QT_BUILD_TREE" << fixSeparators("/bin/dumpcpp.exe", true) << endl; moduleStream << "QMAKE_INCDIR_QT = $$QT_BUILD_TREE" << fixSeparators("/include", true) << endl; moduleStream << "QMAKE_LIBDIR_QT = $$QT_BUILD_TREE" << fixSeparators("/lib", true) << endl; -- cgit v1.2.3 From 2640b71be405790440c1cd939ab6d67a4ab3757f Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 1 Mar 2012 21:44:54 +0100 Subject: remove support for QMAKE_PLATFORM_DIR this was a somewhat magic support for sysroots, automatically rewriting a number of path-holding variables. this was (as usual) completely undocumented, extremely fragile, and we are coming up with something better now anyway. Change-Id: I045910f532cb3efc839ea81c7a48f8db695e4092 Reviewed-by: Joerg Bornemann --- qmake/generators/makefile.cpp | 32 -------------------------------- qmake/generators/makefile.h | 3 --- qmake/generators/win32/msvc_vcproj.cpp | 1 - 3 files changed, 36 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 63367f116a..1904b8f6c6 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -306,7 +306,6 @@ MakefileGenerator::setProjectFile(QMakeProject *p) return; project = p; init(); - usePlatformDir(); findLibraries(); if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE && project->isActiveConfig("link_prl")) //load up prl's' @@ -1028,7 +1027,6 @@ MakefileGenerator::writePrlFile(QTextStream &t) bool MakefileGenerator::writeProjectMakefile() { - usePlatformDir(); QTextStream t(&Option::output); //header @@ -1146,36 +1144,6 @@ MakefileGenerator::writePrlFile() } } -// Manipulate directories, so it's possible to build -// several cross-platform targets concurrently -void -MakefileGenerator::usePlatformDir() -{ - QString pltDir(project->first("QMAKE_PLATFORM_DIR")); - if(pltDir.isEmpty()) - return; - QChar sep = QDir::separator(); - QString slashPltDir = sep + pltDir; - - QString dirs[] = { QString("OBJECTS_DIR"), QString("DESTDIR"), QString("QMAKE_PKGCONFIG_DESTDIR"), - QString("SUBLIBS_DIR"), QString("DLLDESTDIR"), QString("QMAKE_LIBTOOL_DESTDIR"), - QString("PRECOMPILED_DIR"), QString("QMAKE_LIBDIR_QT"), QString() }; - for(int i = 0; !dirs[i].isEmpty(); ++i) { - QString filePath = project->first(dirs[i]); - project->values(dirs[i]) = QStringList(filePath + (filePath.isEmpty() ? pltDir : slashPltDir)); - } - - QString libs[] = { QString("QMAKE_LIBS_QT"), QString("QMAKE_LIBS_QT_THREAD"), QString("QMAKE_LIBS_QT_ENTRY"), QString() }; - for(int i = 0; !libs[i].isEmpty(); ++i) { - QString filePath = project->first(libs[i]); - int fpi = filePath.lastIndexOf(sep); - if(fpi == -1) - project->values(libs[i]).prepend(pltDir + sep); - else - project->values(libs[i]) = QStringList(filePath.left(fpi) + slashPltDir + filePath.mid(fpi)); - } -} - void MakefileGenerator::writeObj(QTextStream &t, const QString &src) { diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h index 68d247a8f3..5b64ea68fb 100644 --- a/qmake/generators/makefile.h +++ b/qmake/generators/makefile.h @@ -198,9 +198,6 @@ protected: filterIncludedFiles("GENERATED_SOURCES"); } - //for cross-platform dependent directories - virtual void usePlatformDir(); - //for installs virtual QString defaultInstall(const QString &); diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 434d4b4559..2f19ea4495 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -247,7 +247,6 @@ bool VcprojGenerator::writeMakefile(QTextStream &t) bool VcprojGenerator::writeProjectMakefile() { - usePlatformDir(); QTextStream t(&Option::output); // Check if all requirements are fulfilled -- cgit v1.2.3 From 6a5e2fdde368870a9830b26ae1c60c17c329df51 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 2 Mar 2012 20:12:03 +0100 Subject: don't put QMAKE_ABSOLUTE_SOURCE_ROOT into .qmake.cache this is oxymoronic: if a .qmake.cache is present, telling qmake the project root is utterly pointless. the windows variant never had this. Change-Id: Iefc6e242ad7458dc699b955a3657f31f1ecf4c7b Reviewed-by: Joerg Bornemann --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index 756088d517..72b1fd64b7 100755 --- a/configure +++ b/configure @@ -6727,7 +6727,6 @@ QMAKE_LIBDIR_QT = \$\$QT_BUILD_TREE/lib include(\$\$PWD/mkspecs/qmodule.pri) CONFIG += $QMAKE_CONFIG dylib depend_includepath fix_output_dirs no_private_qt_headers_warning QTDIR_build -QMAKE_ABSOLUTE_SOURCE_ROOT = \$\$QT_SOURCE_TREE EOF -- cgit v1.2.3 From 3c47b52bd37488d41a3ad068de7976c838b7d63c Mon Sep 17 00:00:00 2001 From: Donald Carr Date: Wed, 29 Feb 2012 23:55:13 +0000 Subject: Add cross_compile to qconfig.pri for global advertising .qmake.cache is not necessarily accessible to other modules which depend on information about whether we are cross compiling or not. We might as well advertise this fact globally via the CONFIG variable in qconfig.pri. Change-Id: I6dee3e6604e5ca1c775c5f9f834fe29b4e27adb8 Reviewed-by: Donald Carr Reviewed-by: Girish Ramakrishnan Reviewed-by: Oswald Buddenhagen Reviewed-by: Johannes Zellner --- configure | 1 + tools/configure/configureapp.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 72b1fd64b7..2b8b4031ef 100755 --- a/configure +++ b/configure @@ -2528,6 +2528,7 @@ fi if [ "$PLATFORM" != "$XPLATFORM" ]; then QT_CROSS_COMPILE=yes QMAKE_CONFIG="$QMAKE_CONFIG cross_compile" + QTCONFIG_CONFIG="$QTCONFIG_CONFIG cross_compile" fi if [ "$BUILD_ON_MAC" = "yes" ]; then diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index eafe547063..dea7415d43 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -2367,8 +2367,10 @@ void Configure::generateOutputVars() } } - if (dictionary.contains("XQMAKESPEC") && (dictionary["QMAKESPEC"] != dictionary["XQMAKESPEC"])) + if (dictionary.contains("XQMAKESPEC") && (dictionary["QMAKESPEC"] != dictionary["XQMAKESPEC"])) { qmakeConfig += "cross_compile"; + dictionary["CROSS_COMPILE"] = "yes"; + } // Directories and settings for .qmake.cache -------------------- @@ -2605,6 +2607,8 @@ void Configure::generateCachefile() configStream << " no_plugin_manifest"; if (dictionary["QPA"] == "yes") configStream << " qpa"; + if (dictionary["CROSS_COMPILE"] == "yes") + configStream << " cross_compile"; if (dictionary["DIRECTWRITE"] == "yes") configStream << "directwrite"; -- cgit v1.2.3 From 3650ce5a85f560114de01d61d8bcde03316e9fdc Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 28 Feb 2012 11:57:12 +0000 Subject: Add debug stream operator for QNetworkProxy Change-Id: Ib8e7ba041ede33dc9c751432e39be2d6a9f4662d Reviewed-by: Thiago Macieira --- src/network/kernel/qnetworkproxy.cpp | 47 ++++++++++++++++++++++++++++++++++++ src/network/kernel/qnetworkproxy.h | 4 +++ 2 files changed, 51 insertions(+) diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp index 0281eaf48b..feef74e737 100644 --- a/src/network/kernel/qnetworkproxy.cpp +++ b/src/network/kernel/qnetworkproxy.cpp @@ -224,8 +224,10 @@ #include "private/qsocks5socketengine_p.h" #include "private/qhttpsocketengine_p.h" #include "qauthenticator.h" +#include "qdebug.h" #include "qhash.h" #include "qmutex.h" +#include "qstringlist.h" #include "qurl.h" #ifndef QT_NO_BEARERMANAGEMENT @@ -1508,6 +1510,51 @@ QList QNetworkProxyFactory::proxyForQuery(const QNetworkProxyQuer return globalNetworkProxy()->proxyForQuery(query); } +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QNetworkProxy &proxy) +{ + QNetworkProxy::ProxyType type = proxy.type(); + switch (type) { + case QNetworkProxy::NoProxy: + debug << "NoProxy "; + break; + case QNetworkProxy::DefaultProxy: + debug << "DefaultProxy "; + break; + case QNetworkProxy::Socks5Proxy: + debug << "Socks5Proxy "; + break; + case QNetworkProxy::HttpProxy: + debug << "HttpProxy "; + break; + case QNetworkProxy::HttpCachingProxy: + debug << "HttpCachingProxy "; + break; + case QNetworkProxy::FtpCachingProxy: + debug << "FtpCachingProxy "; + break; + default: + debug << "Unknown proxy " << int(type); + break; + } + debug << "\"" << proxy.hostName() << ":" << proxy.port() << "\" "; + QNetworkProxy::Capabilities caps = proxy.capabilities(); + QStringList scaps; + if (caps & QNetworkProxy::TunnelingCapability) + scaps << QStringLiteral("Tunnel"); + if (caps & QNetworkProxy::ListeningCapability) + scaps << QStringLiteral("Listen"); + if (caps & QNetworkProxy::UdpTunnelingCapability) + scaps << QStringLiteral("UDP"); + if (caps & QNetworkProxy::CachingCapability) + scaps << QStringLiteral("Caching"); + if (caps & QNetworkProxy::HostNameLookupCapability) + scaps << QStringLiteral("NameLookup"); + debug << "[" << scaps.join(QStringLiteral(" ")) << "]"; + return debug; +} +#endif + QT_END_NAMESPACE #endif // QT_NO_NETWORKPROXY diff --git a/src/network/kernel/qnetworkproxy.h b/src/network/kernel/qnetworkproxy.h index 8f961c43ac..805f5cdb5c 100644 --- a/src/network/kernel/qnetworkproxy.h +++ b/src/network/kernel/qnetworkproxy.h @@ -203,6 +203,10 @@ public: static QList systemProxyForQuery(const QNetworkProxyQuery &query = QNetworkProxyQuery()); }; +#ifndef QT_NO_DEBUG_STREAM +Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkProxy &proxy); +#endif + QT_END_NAMESPACE QT_END_HEADER -- cgit v1.2.3 From 9731607fb33812de27e29fb87863ccb5794333eb Mon Sep 17 00:00:00 2001 From: Yuchen Deng Date: Thu, 1 Mar 2012 20:24:56 +0800 Subject: Build fix when use '-no-stl' option error C2039: 'move' : is not a member of 'std' error C3861: 'move': identifier not found Change-Id: I40beb59f893a8969275154664c947889eb570c95 Reviewed-by: Thiago Macieira --- src/corelib/mimetypes/qmimetype.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp index 4099487f9b..a868129788 100644 --- a/src/corelib/mimetypes/qmimetype.cpp +++ b/src/corelib/mimetypes/qmimetype.cpp @@ -51,6 +51,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE bool qt_isQMimeTypeDebuggingActivated (false); -- cgit v1.2.3 From 4ba895a863a3468db2fe67beaa7e8b0b386b01dd Mon Sep 17 00:00:00 2001 From: Rafael Roquetto Date: Thu, 8 Mar 2012 11:58:32 +0100 Subject: Fix platforms.pro to match new qnx mkspec name Change-Id: Ib159b519d11c9b88979f0f47b87801552586abc0 Reviewed-by: Friedemann Kleint Reviewed-by: Sean Harmer Reviewed-by: Robin Burchell --- src/plugins/platforms/platforms.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 8f728a5fb0..52d3d83bbc 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -12,6 +12,6 @@ mac { win32: SUBDIRS += windows -blackberry-armv7le-qcc { +qnx-*-qcc { SUBDIRS += blackberry } -- cgit v1.2.3 From 7e53debcf285426042f0f7283b28f716d3b728b1 Mon Sep 17 00:00:00 2001 From: Pierre Rossi Date: Wed, 7 Mar 2012 14:53:57 +0100 Subject: Fix a performance regression with shouldLoadFontEngineForCharacter. Calling FcFontMatch should be avoided as much as possible. We can simply cache the patterns it returns, which should still save memory compared to loading all font engines as we did before. Change-Id: I67208a4f919338a948535f717cfd0139dbea2e5f Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../fontconfig/qfontenginemultifontconfig.cpp | 45 +++++++++++++++------- .../fontconfig/qfontenginemultifontconfig_p.h | 7 ++++ 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp index 7b28b20bcb..2016500767 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig.cpp @@ -42,7 +42,6 @@ #include "qfontenginemultifontconfig_p.h" #include -#include #include QT_BEGIN_NAMESPACE @@ -53,6 +52,14 @@ QFontEngineMultiFontConfig::QFontEngineMultiFontConfig(QFontEngine *fe, int scri { } +QFontEngineMultiFontConfig::~QFontEngineMultiFontConfig() +{ + Q_FOREACH (FcPattern *pattern, cachedMatchPatterns) { + if (pattern) + FcPatternDestroy(pattern); + } +} + bool QFontEngineMultiFontConfig::shouldLoadFontEngineForCharacter(int at, uint ucs4) const { QFontEngineFT *fontEngine = static_cast(engines.at(at)); @@ -61,27 +68,37 @@ bool QFontEngineMultiFontConfig::shouldLoadFontEngineForCharacter(int at, uint u FcCharSet *charSet = fontEngine->freetype->charset; charSetHasChar = FcCharSetHasChar(charSet, ucs4); } else { - FcPattern *requestPattern = FcPatternCreate(); - - FcValue value; - value.type = FcTypeString; - QByteArray cs = fallbackFamilyAt(at-1).toUtf8(); - value.u.s = reinterpret_cast(cs.data()); - FcPatternAdd(requestPattern, FC_FAMILY, value, true); - - FcResult result; - FcPattern *matchPattern = FcFontMatch(0, requestPattern, &result); + FcPattern *matchPattern = getMatchPatternForFallback(at - 1); if (matchPattern != 0) { FcCharSet *charSet; FcPatternGetCharSet(matchPattern, FC_CHARSET, 0, &charSet); charSetHasChar = FcCharSetHasChar(charSet, ucs4); - FcPatternDestroy(matchPattern); } - - FcPatternDestroy(requestPattern); } return charSetHasChar; } + +FcPattern * QFontEngineMultiFontConfig::getMatchPatternForFallback(int fallBackIndex) const +{ + Q_ASSERT(fallBackIndex < fallbackFamilyCount()); + if (engines.size() - 1 > cachedMatchPatterns.size()) + cachedMatchPatterns.resize(engines.size() - 1); + FcPattern *ret = cachedMatchPatterns.at(fallBackIndex); + if (ret) + return ret; + FcPattern *requestPattern = FcPatternCreate(); + FcValue value; + value.type = FcTypeString; + QByteArray cs = fallbackFamilyAt(fallBackIndex).toUtf8(); + value.u.s = reinterpret_cast(cs.data()); + FcPatternAdd(requestPattern, FC_FAMILY, value, true); + FcResult result; + ret = FcFontMatch(0, requestPattern, &result); + cachedMatchPatterns.insert(fallBackIndex, ret); + FcPatternDestroy(requestPattern); + return ret; +} + QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h index 4323cb7d2e..260a9b5c70 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h +++ b/src/platformsupport/fontdatabases/fontconfig/qfontenginemultifontconfig_p.h @@ -43,6 +43,7 @@ #define QFONTENGINEMULTIFONTCONFIG_H #include +#include QT_BEGIN_NAMESPACE @@ -52,7 +53,13 @@ class QFontEngineMultiFontConfig : public QFontEngineMultiQPA public: explicit QFontEngineMultiFontConfig(QFontEngine *fe, int script, const QStringList &fallbacks); + ~QFontEngineMultiFontConfig(); + bool shouldLoadFontEngineForCharacter(int at, uint ucs4) const; +private: + FcPattern* getMatchPatternForFallback(int at) const; + + mutable QVector cachedMatchPatterns; }; QT_END_NAMESPACE -- cgit v1.2.3 From 47a62485c01e177327ad23611de9cba174df671e Mon Sep 17 00:00:00 2001 From: Martin Petersson Date: Wed, 7 Mar 2012 16:17:11 +0100 Subject: Use SSL_MODE_RELEASE_BUFFERS in QSslSocket If SSL_MODE_RELEASE_BUFFERS is available we should tell OpenSSL to release memory early. http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html Task-number: QTBUG-14985 Change-Id: Ib6656ebb3c4d67ca868b317ee83ddbf0983953f9 Reviewed-by: Richard J. Moore Reviewed-by: Shane Kearns Reviewed-by: Markus Goetz --- src/network/ssl/qsslsocket_openssl.cpp | 7 +++++++ src/network/ssl/qsslsocket_openssl_symbols_p.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 20ad82407c..df60a0fcce 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -338,6 +338,13 @@ init_context: long options = setupOpenSslOptions(configuration.protocol, configuration.sslOptions); q_SSL_CTX_set_options(ctx, options); +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + // Tell OpenSSL to release memory early + // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html + if (q_SSLeay() >= 0x10000000L) + q_SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); +#endif + // Initialize ciphers QByteArray cipherString; int first = true; diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index 758763523f..b0d748692f 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -411,6 +411,7 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length); bp,(char *)x,enc,kstr,klen,cb,u) #endif #define q_SSL_CTX_set_options(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL) +#define q_SSL_CTX_set_mode(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL) #define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_sk_num)(st) #define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_sk_value)(st, i) #define q_sk_GENERAL_NAME_num(st) q_SKM_sk_num(GENERAL_NAME, (st)) -- cgit v1.2.3 From 5434295389caf821d39adceb2b34c1a18e8d1403 Mon Sep 17 00:00:00 2001 From: ABBAPOH Date: Sun, 26 Feb 2012 15:17:14 +0400 Subject: Remove calls for default constructors Change-Id: Ib33013bed9e6b7bb9ef54c858da5cd61f35f2c41 Reviewed-by: David Faure Reviewed-by: Oswald Buddenhagen --- src/corelib/mimetypes/qmimetype.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp index a868129788..6cbd938be3 100644 --- a/src/corelib/mimetypes/qmimetype.cpp +++ b/src/corelib/mimetypes/qmimetype.cpp @@ -64,12 +64,6 @@ bool qt_isQMimeTypeDebuggingActivated (false); #endif QMimeTypePrivate::QMimeTypePrivate() - : name() - //, comment() - , localeComments() - , genericIconName() - , iconName() - , globPatterns() {} QMimeTypePrivate::QMimeTypePrivate(const QMimeType &other) -- cgit v1.2.3 From d26ef66a660fb7d3e1cb94c863c4076a2ecd8199 Mon Sep 17 00:00:00 2001 From: Donald Carr Date: Tue, 6 Mar 2012 22:35:30 +0000 Subject: Remove widgets dependency from eglfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit eglfs uses the (old) OpenGL paint engine for paint operations. This drags in a QWidget dependency and hence everything bar the kitchen sink. This change gets eglfs buildable without widget support although anything which relies on a QPaintDevice will end up rendering nothing to the screen. (Similar to the QWS simplegl driver) Change-Id: If7fcdb79038ef7568e771402fd1667bc0318ff5f Reviewed-by: Jørgen Lind Reviewed-by: Girish Ramakrishnan --- src/plugins/platforms/eglfs/eglfs.pro | 6 +++++- src/plugins/platforms/eglfs/qeglfsbackingstore.cpp | 21 +++++++++++++++------ src/plugins/platforms/eglfs/qeglfsbackingstore.h | 2 +- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro index 8675dc164e..291e09d6ed 100644 --- a/src/plugins/platforms/eglfs/eglfs.pro +++ b/src/plugins/platforms/eglfs/eglfs.pro @@ -2,7 +2,11 @@ TARGET = qeglfs TEMPLATE = lib CONFIG += plugin -QT += opengl core-private gui-private opengl-private platformsupport-private widgets-private +QT += core-private gui-private platformsupport-private + +!contains(QT_CONFIG, no-widgets) { + QT += opengl opengl-private widgets-private +} DESTDIR = $$QT.gui.plugins/platforms diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp index 331b768a93..d2e4a47e56 100644 --- a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp +++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp @@ -39,17 +39,19 @@ ** ****************************************************************************/ -#include - #include "qeglfsbackingstore.h" +#ifndef QT_NO_WIDGETS +#include +#include +#endif //QT_NO_WIDGETS + #include #include -#include - QT_BEGIN_NAMESPACE +#ifndef QT_NO_WIDGETS class QEglFSPaintDevice : public QGLPaintDevice { public: @@ -73,15 +75,20 @@ private: QEglFSScreen *m_screen; QGLContext *m_context; }; - +#endif //QT_NO_WIDGETS QEglFSBackingStore::QEglFSBackingStore(QWindow *window) - : QPlatformBackingStore(window) + : QPlatformBackingStore(window), + m_paintDevice(0) { #ifdef QEGL_EXTRA_DEBUG qWarning("QEglBackingStore %p, %p", window, window->screen()); #endif +#ifdef QT_NO_WIDGETS + m_paintDevice = new QImage(0,0); +#else m_paintDevice = new QEglFSPaintDevice(static_cast(window->screen()->handle())); +#endif //QT_NO_WIDGETS } void QEglFSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) @@ -92,7 +99,9 @@ void QEglFSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo #ifdef QEGL_EXTRA_DEBUG qWarning("QEglBackingStore::flush %p", window); #endif +#ifndef QT_NO_WIDGETS static_cast(m_paintDevice)->context()->swapBuffers(); +#endif //QT_NO_WIDGETS } void QEglFSBackingStore::resize(const QSize &size, const QRegion &staticContents) diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.h b/src/plugins/platforms/eglfs/qeglfsbackingstore.h index 5623a96004..1ae3ecdc61 100644 --- a/src/plugins/platforms/eglfs/qeglfsbackingstore.h +++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.h @@ -53,7 +53,7 @@ class QEglFSBackingStore : public QPlatformBackingStore { public: QEglFSBackingStore(QWindow *window); - ~QEglFSBackingStore() {} + ~QEglFSBackingStore() { delete m_paintDevice; } QPaintDevice *paintDevice() { return m_paintDevice; } void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); -- cgit v1.2.3 From e02c396acb15e7363542f08c3bed33b0245146c5 Mon Sep 17 00:00:00 2001 From: David Faure Date: Thu, 8 Mar 2012 16:04:16 +0100 Subject: Fix copy/paste error in QAbstractItemModel::insertRow docu. This method is not virtual. Change-Id: I1c82a63af07d7e78e7a572c0dfcfb2b82122d421 Reviewed-by: Stephen Kelly --- src/corelib/itemmodels/qabstractitemmodel.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp index 7a1357959e..c6f174bcf8 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.cpp +++ b/src/corelib/itemmodels/qabstractitemmodel.cpp @@ -1223,12 +1223,11 @@ void QAbstractItemModelPrivate::columnsRemoved(const QModelIndex &parent, /*! \fn bool QAbstractItemModel::insertRow(int row, const QModelIndex &parent) - \note The base class implementation of this function does nothing and - returns false. - Inserts a single row before the given \a row in the child items of the \a parent specified. + \note This function calls the virtual method insertRows. + Returns true if the row is inserted; otherwise returns false. \sa insertRows() insertColumn() removeRow() -- cgit v1.2.3 From bbc97c38d5917d8a403719531454ee24cde9c4fe Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 7 Mar 2012 09:57:39 +0100 Subject: misc: Fix some random typos and grammar while reading code. Typos: recieve -> receive descrived -> describe Grammar: this types -> these types Change-Id: Iedacc51a6322996f423ac9472af0a597424a4fed Reviewed-by: Casper van Donderen --- dist/changes-4.5.0-garden | 2 +- src/corelib/global/qprocessordetection.h | 2 +- src/corelib/kernel/qvariant.cpp | 8 ++++---- src/plugins/platforms/kms/qkmsdevice.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dist/changes-4.5.0-garden b/dist/changes-4.5.0-garden index ce258e7630..c0946a10e5 100644 --- a/dist/changes-4.5.0-garden +++ b/dist/changes-4.5.0-garden @@ -118,7 +118,7 @@ Optimizations SystemGc from the CCoeControl we are currently painting on instead. - qeventdispatcher_s60.cpp - * Stopped using Active Objects to recieve events, we get them from + * Stopped using Active Objects to receive events, we get them from C*AppUi and CCoeControl instead. - QWidget diff --git a/src/corelib/global/qprocessordetection.h b/src/corelib/global/qprocessordetection.h index 1f16f090a9..fcd7c69ee7 100644 --- a/src/corelib/global/qprocessordetection.h +++ b/src/corelib/global/qprocessordetection.h @@ -225,7 +225,7 @@ /* SuperH family, optional revision: SH-4A - SuperH is bi-endian, use endianness auto-detection descrived above. + SuperH is bi-endian, use endianness auto-detection described above. */ // #elif defined(__sh__) // # define Q_PROCESSOR_SH diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index c8456192ed..e630b5bba8 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -1676,12 +1676,12 @@ void QVariant::load(QDataStream &s) // by moving all ids down by 97. typeId -= 97; } else if (typeId == 69 /* QIcon */) { - // In Qt5 after modularization project this types where moved to a separate module (and ids were downgraded) + // In Qt5 after modularization project these types where moved to a separate module (and ids were downgraded) typeId = QMetaType::QIcon; } else if (typeId == 75 /* QSizePolicy */) { typeId = QMetaType::QSizePolicy; } else if (typeId >= 70) { - // and as a result this types recieved lower ids too + // and as a result these types received lower ids too if (typeId <= 74) { // QImage QPolygon QRegion QBitmap QCursor typeId -=1; } else if (typeId <= 86) { // QKeySequence QPen QTextLength QTextFormat QMatrix QTransform QMatrix4x4 QVector2D QVector3D QVector4D QQuaternion @@ -1749,12 +1749,12 @@ void QVariant::save(QDataStream &s) const // by moving all ids down by 97. typeId += 97; } else if (typeId == QMetaType::QIcon) { - // In Qt5 after modularization project this types where moved to a separate module (and ids were downgraded) + // In Qt5 after modularization project these types where moved to a separate module (and ids were downgraded) typeId = 69; } else if (typeId == QMetaType::QSizePolicy) { typeId = 75; } else if (typeId >= QMetaType::QImage) { - // and as a result this types recieved lower ids too + // and as a result these types received lower ids too if (typeId <= QMetaType::QCursor) { typeId +=1; } else if (typeId <= QMetaType::QQuaternion) { diff --git a/src/plugins/platforms/kms/qkmsdevice.cpp b/src/plugins/platforms/kms/qkmsdevice.cpp index 01bf1d12be..8d42871401 100644 --- a/src/plugins/platforms/kms/qkmsdevice.cpp +++ b/src/plugins/platforms/kms/qkmsdevice.cpp @@ -127,7 +127,7 @@ void QKmsDevice::createScreens() void QKmsDevice::handlePageFlipCompleted() { - //qDebug() << "Display signal recieved"; + //qDebug() << "Display signal received"; drmEventContext eventContext; memset(&eventContext, 0, sizeof eventContext); -- cgit v1.2.3 From c3b72e9c2f6b35b33e8564aaa96291901a02ecee Mon Sep 17 00:00:00 2001 From: Jon Trulson Date: Wed, 29 Feb 2012 16:06:56 -0700 Subject: Start eventTime timer so that the .elapsed method will work. QWindowSystemInterfacePrivate::eventTime.start() is never called, resulting in all calls to QWindowSystemInterfacePrivate::eventTime.elapsed() within qwindowsysteminterface_qpa.cpp to return 0. This could cause events to be lost, such as mouse button press events from the evdevmouse input plugin. Change-Id: Iba9d23b51af80e8532d24ccf382e9077c06bb4be Reviewed-by: Laszlo Agocs --- src/gui/kernel/qwindowsysteminterface_qpa.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/kernel/qwindowsysteminterface_qpa.cpp b/src/gui/kernel/qwindowsysteminterface_qpa.cpp index 5b77d97950..6f0abbdd0c 100644 --- a/src/gui/kernel/qwindowsysteminterface_qpa.cpp +++ b/src/gui/kernel/qwindowsysteminterface_qpa.cpp @@ -266,6 +266,10 @@ void QWindowSystemInterfacePrivate::queueWindowSystemEvent(QWindowSystemInterfac windowSystemEventQueue.append(ev); queueMutex.unlock(); + // Make sure the event timer is started. + if (!QWindowSystemInterfacePrivate::eventTime.isValid()) + QWindowSystemInterfacePrivate::eventTime.start(); + QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::qt_qpa_core_dispatcher(); if (dispatcher) dispatcher->wakeUp(); -- cgit v1.2.3 From 9f86923b5c936eefb6f435b46c1dbfc260aa431d Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Thu, 8 Mar 2012 15:48:51 -0800 Subject: tst_qimagereader: does not depend on QtWidgets Both tst_qimagereader.cpp and tst_qimagewriter.cpp do not depend on QtWidgets. Change-Id: I7e8b31c23db203c44ccb4cd4e8e747d18c5d7ed7 Reviewed-by: Friedemann Kleint --- tests/auto/gui/image/qimagereader/qimagereader.pro | 2 +- tests/auto/gui/image/qimagereader/tst_qimagereader.cpp | 1 - tests/auto/gui/image/qimagewriter/qimagewriter.pro | 2 +- tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/auto/gui/image/qimagereader/qimagereader.pro b/tests/auto/gui/image/qimagereader/qimagereader.pro index 14d23f05ba..7686643b3a 100644 --- a/tests/auto/gui/image/qimagereader/qimagereader.pro +++ b/tests/auto/gui/image/qimagereader/qimagereader.pro @@ -2,7 +2,7 @@ CONFIG += testcase TARGET = tst_qimagereader SOURCES += tst_qimagereader.cpp MOC_DIR=tmp -QT += widgets widgets-private core-private gui-private network testlib +QT += core-private gui-private network testlib RESOURCES += qimagereader.qrc win32-msvc:QMAKE_CXXFLAGS -= -Zm200 diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp index 6f6662a80f..876d69ea1c 100644 --- a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include diff --git a/tests/auto/gui/image/qimagewriter/qimagewriter.pro b/tests/auto/gui/image/qimagewriter/qimagewriter.pro index b6c80b8d62..f77ff0659b 100644 --- a/tests/auto/gui/image/qimagewriter/qimagewriter.pro +++ b/tests/auto/gui/image/qimagewriter/qimagewriter.pro @@ -1,6 +1,6 @@ CONFIG += testcase TARGET = tst_qimagewriter -QT += widgets testlib +QT += testlib SOURCES += tst_qimagewriter.cpp MOC_DIR=tmp win32-msvc:QMAKE_CXXFLAGS -= -Zm200 diff --git a/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp b/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp index ad9da27c7e..932d652b69 100644 --- a/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp +++ b/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp @@ -48,7 +48,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From 37c46fee300d265ea17fafdb7f9f9e75caded16a Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Thu, 8 Mar 2012 18:37:30 -0800 Subject: Clean up for some auto tests of the gui/kernel. They are not dependent on QtWidgets. Change-Id: Icbc0b0b6f0b72537fd3058cc038a1f5c4bf2aba7 Reviewed-by: Friedemann Kleint --- tests/auto/gui/kernel/qdrag/qdrag.pro | 2 +- .../qfileopeneventexternal/qfileopeneventexternal.cpp | 7 +++---- .../qfileopeneventexternal/qfileopeneventexternal.pro | 2 +- tests/auto/gui/kernel/qkeysequence/qkeysequence.pro | 2 +- tests/auto/gui/kernel/qpalette/qpalette.pro | 2 +- tests/auto/gui/kernel/qpalette/tst_qpalette.cpp | 1 - 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/auto/gui/kernel/qdrag/qdrag.pro b/tests/auto/gui/kernel/qdrag/qdrag.pro index 0173b57215..ac3fde8028 100644 --- a/tests/auto/gui/kernel/qdrag/qdrag.pro +++ b/tests/auto/gui/kernel/qdrag/qdrag.pro @@ -4,7 +4,7 @@ CONFIG += testcase TARGET = tst_qdrag -QT += widgets testlib +QT += testlib SOURCES += tst_qdrag.cpp diff --git a/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.cpp b/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.cpp index 9d138f6a2e..a9f9c8db08 100644 --- a/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.cpp +++ b/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.cpp @@ -40,13 +40,12 @@ ****************************************************************************/ #include -#include #include -struct MyApplication : public QApplication +struct MyApplication : public QGuiApplication { MyApplication(int& argc, char** argv) - : QApplication(argc, argv) + : QGuiApplication(argc, argv) {} bool event(QEvent * event) @@ -59,7 +58,7 @@ struct MyApplication : public QApplication file.write(QByteArray("+external")); return true; } else { - return QApplication::event(event); + return QGuiApplication::event(event); } } }; diff --git a/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.pro b/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.pro index 7de7b2ec57..b84ff760ca 100644 --- a/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.pro +++ b/tests/auto/gui/kernel/qfileopenevent/qfileopeneventexternal/qfileopeneventexternal.pro @@ -1,4 +1,4 @@ TEMPLATE = app TARGET = qfileopeneventexternal -QT += core gui widgets +QT += core gui SOURCES += qfileopeneventexternal.cpp diff --git a/tests/auto/gui/kernel/qkeysequence/qkeysequence.pro b/tests/auto/gui/kernel/qkeysequence/qkeysequence.pro index cf4337b156..9f79fe9ab7 100644 --- a/tests/auto/gui/kernel/qkeysequence/qkeysequence.pro +++ b/tests/auto/gui/kernel/qkeysequence/qkeysequence.pro @@ -1,7 +1,7 @@ CONFIG += testcase TARGET = tst_qkeysequence -QT += widgets testlib +QT += testlib QT += core-private gui-private SOURCES += tst_qkeysequence.cpp diff --git a/tests/auto/gui/kernel/qpalette/qpalette.pro b/tests/auto/gui/kernel/qpalette/qpalette.pro index 8975704f0f..9dd3f3e715 100644 --- a/tests/auto/gui/kernel/qpalette/qpalette.pro +++ b/tests/auto/gui/kernel/qpalette/qpalette.pro @@ -1,6 +1,6 @@ CONFIG += testcase TARGET = tst_qpalette -QT += widgets testlib +QT += testlib SOURCES += tst_qpalette.cpp diff --git a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp index cc46831965..dc393fc2c3 100644 --- a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp +++ b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp @@ -43,7 +43,6 @@ #include #include "qpalette.h" -#include class tst_QPalette : public QObject { -- cgit v1.2.3 From 38224d8d009a0f35e4316a035636c2c2b929c524 Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Thu, 8 Mar 2012 18:45:13 -0800 Subject: Make tst_qmouseevent.cpp independent of QtWidgets Change-Id: I6759c7be44c2d890c1a745effdd70faa3467fe5b Reviewed-by: Friedemann Kleint --- tests/auto/gui/kernel/qmouseevent/qmouseevent.pro | 2 +- .../auto/gui/kernel/qmouseevent/tst_qmouseevent.cpp | 20 ++++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/tests/auto/gui/kernel/qmouseevent/qmouseevent.pro b/tests/auto/gui/kernel/qmouseevent/qmouseevent.pro index b99c3016b0..5fa886334a 100644 --- a/tests/auto/gui/kernel/qmouseevent/qmouseevent.pro +++ b/tests/auto/gui/kernel/qmouseevent/qmouseevent.pro @@ -1,4 +1,4 @@ CONFIG += testcase TARGET = tst_qmouseevent -QT += widgets testlib +QT += testlib SOURCES += tst_qmouseevent.cpp diff --git a/tests/auto/gui/kernel/qmouseevent/tst_qmouseevent.cpp b/tests/auto/gui/kernel/qmouseevent/tst_qmouseevent.cpp index d8f1f0640e..012502469b 100644 --- a/tests/auto/gui/kernel/qmouseevent/tst_qmouseevent.cpp +++ b/tests/auto/gui/kernel/qmouseevent/tst_qmouseevent.cpp @@ -41,21 +41,14 @@ #include -#include -#include -#include -#include - - #include -#include +#include -class MouseEventWidget : public QWidget +class MouseEventWidget : public QWindow { public: - MouseEventWidget(QWidget *parent = 0) : QWidget(parent) + MouseEventWidget(QWindow *parent = 0) : QWindow(parent) { - setFocusPolicy(Qt::StrongFocus); } bool mousePressEventRecieved; bool mouseReleaseEventRecieved; @@ -68,7 +61,7 @@ public: protected: void mousePressEvent(QMouseEvent *e) { - QWidget::mousePressEvent(e); + QWindow::mousePressEvent(e); mousePressButton = e->button(); mousePressButtons = e->buttons(); mousePressModifiers = e->modifiers(); @@ -77,7 +70,7 @@ protected: } void mouseReleaseEvent(QMouseEvent *e) { - QWidget::mouseReleaseEvent(e); + QWindow::mouseReleaseEvent(e); mouseReleaseButton = e->button(); mouseReleaseButtons = e->buttons(); mouseReleaseModifiers = e->modifiers(); @@ -179,12 +172,14 @@ void tst_QMouseEvent::checkMousePressEvent() int modifiers = keyPressed; QTest::mousePress(testMouseWidget, Qt::MouseButton(buttonPressed), Qt::KeyboardModifiers(keyPressed)); + qApp->processEvents(); QVERIFY(testMouseWidget->mousePressEventRecieved); QCOMPARE(testMouseWidget->mousePressButton, button); QCOMPARE(testMouseWidget->mousePressButtons, buttons); QCOMPARE(testMouseWidget->mousePressModifiers, modifiers); QTest::mouseRelease(testMouseWidget, Qt::MouseButton(buttonPressed), Qt::KeyboardModifiers(keyPressed)); + qApp->processEvents(); } void tst_QMouseEvent::checkMouseReleaseEvent_data() @@ -218,6 +213,7 @@ void tst_QMouseEvent::checkMouseReleaseEvent() int modifiers = keyPressed; QTest::mouseClick(testMouseWidget, Qt::MouseButton(buttonReleased), Qt::KeyboardModifiers(keyPressed)); + qApp->processEvents(); QVERIFY(testMouseWidget->mouseReleaseEventRecieved); QCOMPARE(testMouseWidget->mouseReleaseButton, button); QCOMPARE(testMouseWidget->mouseReleaseButtons, buttons); -- cgit v1.2.3 From 46e51ce1dd17aedc34acbf5e80f824025877afaf Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 9 Mar 2012 10:50:23 +0100 Subject: do not copy/symlink qmake to build dir make is perfectly capable of doing shadow builds Change-Id: I7e1c27cddc385b7a17ae5645b9cd26fa56d2f029 Reviewed-by: Marius Storm-Olsen --- configure | 24 +------ qmake/Makefile.unix | 145 +++++++++++++++++++-------------------- qmake/Makefile.win32 | 4 +- qmake/Makefile.win32-g++ | 6 +- tools/configure/configureapp.cpp | 51 +++----------- 5 files changed, 88 insertions(+), 142 deletions(-) diff --git a/configure b/configure index 2b8b4031ef..5e574e668a 100755 --- a/configure +++ b/configure @@ -2221,29 +2221,6 @@ if [ "$OPT_SHADOW" = "yes" ]; then [ -d "$outpath/bin" ] || mkdir -p "$outpath/bin" - # symlink the qmake directory - find "$relpath/qmake" | while read a; do - my_a=`echo "$a" | sed "s,^${relpath}/,${outpath}/,"` - if [ '!' -f "$my_a" ]; then - if [ -d "$a" ]; then - # directories are created... - mkdir -p "$my_a" - else - a_dir=`dirname "$my_a"` - [ -d "$a_dir" ] || mkdir -p "$a_dir" - # ... and files are symlinked - case `basename "$a"` in - *.o|*.d|GNUmakefile*|qmake) - ;; - *) - rm -f "$my_a" - ln -s "$a" "$my_a" - ;; - esac - fi - fi - done - # make a syncqt script that can be used in the shadow rm -f "$outpath/bin/syncqt" if [ -x "$relpath/bin/syncqt" ]; then @@ -4098,6 +4075,7 @@ if true; then ###[ '!' -f "$outpath/bin/qmake" ]; #mkspecs/default is used as a (gasp!) default mkspec so QMAKESPEC needn't be set once configured rm -rf mkspecs/default ln -s `echo $XQMAKESPEC | sed "s,^${relpath}/mkspecs/,,"` mkspecs/default + mkdir -p "$outpath/qmake" || exit # fix makefiles for mkfile in GNUmakefile Makefile; do EXTRA_LFLAGS= diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix index d9835932d6..03a8597eff 100644 --- a/qmake/Makefile.unix +++ b/qmake/Makefile.unix @@ -6,6 +6,8 @@ QTSRCS = @QMAKE_QTSRCS@ QMAKESPEC = @QMAKESPEC@ LFLAGS = @QMAKE_LFLAGS@ +QMKSRC = $(SOURCE_PATH)/qmake + #qmake code OBJS=project.o property.o main.o makefile.o unixmake2.o unixmake.o \ mingw_make.o option.o winmakefile.o projectgenerator.o \ @@ -69,8 +71,8 @@ DEPEND_SRC=project.cpp property.cpp meta.cpp main.cpp generators/makefile.cpp ge $(SOURCE_PATH)/src/corelib/global/qlogging.cpp \ $(QTSRCS) -CPPFLAGS = -g -I. -Igenerators -Igenerators/unix -Igenerators/win32 \ - -Igenerators/mac -Igenerators/integrity \ +CPPFLAGS = -g -I$(QMKSRC) -I$(QMKSRC)/generators -I$(QMKSRC)/generators/unix -I$(QMKSRC)/generators/win32 \ + -I$(QMKSRC)/generators/mac -I$(QMKSRC)/generators/integrity \ -I$(BUILD_PATH)/include -I$(BUILD_PATH)/include/QtCore \ -I$(BUILD_PATH)/include/QtCore/$(QT_VERSION) -I$(BUILD_PATH)/include/QtCore/$(QT_VERSION)/QtCore \ -I$(BUILD_PATH)/src/corelib/global \ @@ -97,7 +99,74 @@ distclean:: clean depend: makedepend -D__MAKEDEPEND__ $(CPPFLAGS) $(DEPEND_SRC) -# don't use optimization for these + +project.o: $(QMKSRC)/project.cpp $(QMKSRC)/project.h $(QMKSRC)/option.h + $(CXX) -c -o $@ $(CXXFLAGS) $< + +property.o: $(QMKSRC)/property.cpp $(QMKSRC)/project.h $(QMKSRC)/option.h + $(CXX) -c -o $@ $(CXXFLAGS) $< + +meta.o: $(QMKSRC)/meta.cpp $(QMKSRC)/project.h $(QMKSRC)/option.h + $(CXX) -c -o $@ $(CXXFLAGS) $< + +main.o: $(QMKSRC)/main.cpp $(QMKSRC)/project.h + $(CXX) -c -o $@ $(CXXFLAGS) $< + +option.o: $(QMKSRC)/option.cpp $(QMKSRC)/option.h + $(CXX) -c -o $@ $(CXXFLAGS) $< + +metamakefile.o: $(QMKSRC)/generators/metamakefile.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +xmloutput.o: $(QMKSRC)/generators/xmloutput.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +makefiledeps.o: $(QMKSRC)/generators/makefiledeps.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +makefile.o: $(QMKSRC)/generators/makefile.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +unixmake.o: $(QMKSRC)/generators/unix/unixmake.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +unixmake2.o: $(QMKSRC)/generators/unix/unixmake2.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +winmakefile.o: $(QMKSRC)/generators/win32/winmakefile.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +borland_bmake.o: $(QMKSRC)/generators/win32/borland_bmake.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +mingw_make.o: $(QMKSRC)/generators/win32/mingw_make.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +msvc_objectmodel.o: $(QMKSRC)/generators/win32/msvc_objectmodel.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +msvc_vcproj.o: $(QMKSRC)/generators/win32/msvc_vcproj.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +msbuild_objectmodel.o: $(QMKSRC)/generators/win32/msbuild_objectmodel.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +msvc_vcxproj.o: $(QMKSRC)/generators/win32/msvc_vcxproj.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +msvc_nmake.o: $(QMKSRC)/generators/win32/msvc_nmake.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +pbuilder_pbx.o: $(QMKSRC)/generators/mac/pbuilder_pbx.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +gbuild.o: $(QMKSRC)/generators/integrity/gbuild.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + +projectgenerator.o: $(QMKSRC)/generators/projectgenerator.cpp + $(CXX) -c -o $@ $(CXXFLAGS) $< + + qtextstream.o: $(SOURCE_PATH)/src/corelib/io/qtextstream.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/io/qtextstream.cpp @@ -242,75 +311,9 @@ qhash.o: $(SOURCE_PATH)/src/corelib/tools/qhash.cpp qlinkedlist.o: $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qlinkedlist.cpp -winmakefile.o: generators/win32/winmakefile.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/winmakefile.cpp - -project.o: project.cpp project.h option.h - $(CXX) -c -o $@ $(CXXFLAGS) project.cpp - -property.o: property.cpp project.h option.h - $(CXX) -c -o $@ $(CXXFLAGS) property.cpp - -meta.o: meta.cpp project.h option.h - $(CXX) -c -o $@ $(CXXFLAGS) meta.cpp - -main.o: main.cpp project.h - $(CXX) -c -o $@ $(CXXFLAGS) main.cpp - -option.o: option.cpp option.h $(BUILD_PATH)/src/corelib/global/qconfig.cpp - $(CXX) -c -o $@ $(CXXFLAGS) option.cpp - qcryptographichash.o: $(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/tools/qcryptographichash.cpp -metamakefile.o: generators/metamakefile.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/metamakefile.cpp - -xmloutput.o: generators/xmloutput.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/xmloutput.cpp - -makefiledeps.o: generators/makefiledeps.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/makefiledeps.cpp - -makefile.o: generators/makefile.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/makefile.cpp - -unixmake.o: generators/unix/unixmake.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/unix/unixmake.cpp - -unixmake2.o: generators/unix/unixmake2.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/unix/unixmake2.cpp - -borland_bmake.o: generators/win32/borland_bmake.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/borland_bmake.cpp - -mingw_make.o: generators/win32/mingw_make.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/mingw_make.cpp - -msvc_objectmodel.o: generators/win32/msvc_objectmodel.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/msvc_objectmodel.cpp - -msvc_vcproj.o: generators/win32/msvc_vcproj.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/msvc_vcproj.cpp - -msbuild_objectmodel.o: generators/win32/msbuild_objectmodel.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/msbuild_objectmodel.cpp - -msvc_vcxproj.o: generators/win32/msvc_vcxproj.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/msvc_vcxproj.cpp - -msvc_nmake.o: generators/win32/msvc_nmake.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/win32/msvc_nmake.cpp - -pbuilder_pbx.o: generators/mac/pbuilder_pbx.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/mac/pbuilder_pbx.cpp - -gbuild.o: generators/integrity/gbuild.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/integrity/gbuild.cpp - -projectgenerator.o: generators/projectgenerator.cpp - $(CXX) -c -o $@ $(CXXFLAGS) generators/projectgenerator.cpp - qxmlstream.o: $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/xml/qxmlstream.cpp @@ -320,8 +323,4 @@ qxmlutils.o: $(SOURCE_PATH)/src/corelib/xml/qxmlutils.cpp qlogging.o: $(SOURCE_PATH)/src/corelib/global/qlogging.cpp $(CXX) -c -o $@ $(CXXFLAGS) $(SOURCE_PATH)/src/corelib/global/qlogging.cpp -#default rules -.cpp.o: - $(CXX) -c -o $@ $(CXXFLAGS) $< - # DO NOT DELETE THIS LINE -- make depend depends on it diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32 index f640216036..89444c9c3c 100644 --- a/qmake/Makefile.win32 +++ b/qmake/Makefile.win32 @@ -7,6 +7,8 @@ SOURCE_PATH = .. BUILD_PATH = .. !endif +QMKSRC = $(SOURCE_PATH)\qmake + # # specific stuff for NMake and ICC # @@ -31,7 +33,7 @@ CFLAGS_EXTRA = /MP CFLAGS_BARE = -c -Fo./ \ -W3 -nologo -O1 \ $(CFLAGS_EXTRA) \ - -I. -Igenerators -Igenerators\unix -Igenerators\win32 -Igenerators\mac -Igenerators\integrity \ + -I$(QMKSRC) -I$(QMKSRC)\generators -I$(QMKSRC)\generators\unix -I$(QMKSRC)\generators\win32 -I$(QMKSRC)\generators\mac -I$(QMKSRC)\generators\integrity \ -I$(BUILD_PATH)\include -I$(BUILD_PATH)\include\QtCore -I$(BUILD_PATH)\include\QtCore\$(QT_VERSION) -I$(BUILD_PATH)\include\QtCore\$(QT_VERSION)\QtCore \ -I$(BUILD_PATH)\src\corelib\global \ -I$(SOURCE_PATH)\mkspecs\$(QMAKESPEC) \ diff --git a/qmake/Makefile.win32-g++ b/qmake/Makefile.win32-g++ index 57e6c1aa4e..95108b351b 100644 --- a/qmake/Makefile.win32-g++ +++ b/qmake/Makefile.win32-g++ @@ -43,9 +43,7 @@ endif # CXX = g++ CFLAGS = -c -o$@ -O \ - -I. -Igenerators -Igenerators/unix \ - -Igenerators/win32 -Igenerators/mac \ - -Igenerators/integrity \ + -I$(QMKSRC) -I$(QMKSRC)/generators -I$(QMKSRC)/generators/unix -I$(QMKSRC)/generators/win32 -I$(QMKSRC)/generators/mac -I$(QMKSRC)/generators/integrity \ -I$(BUILD_PATH)/include -I$(BUILD_PATH)/include/QtCore -I$(BUILD_PATH)/include/QtCore/$(QT_VERSION) -I$(BUILD_PATH)/include/QtCore/$(QT_VERSION)/QtCore \ -I$(BUILD_PATH)/src/corelib/global \ -I$(SOURCE_PATH)/mkspecs/win32-g++ \ @@ -131,7 +129,7 @@ qmake.exe: $(OBJS) $(QTOBJS) $(LINKQMAKE) -$(COPY) qmake.exe $(BUILD_PATH)\bin\qmake.exe -Makefile: Makefile.win32-g++ +Makefile: $(SOURCE_PATH)/qmake/Makefile.win32-g++ @echo "Out of date, please rerun configure" clean:: diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index dea7415d43..62ec3e8d8c 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -142,46 +142,6 @@ Configure::Configure(int& argc, char** argv) cout << "Preparing build tree..." << endl; QDir(buildPath).mkpath("bin"); - { //duplicate qmake - QStack qmake_dirs; - qmake_dirs.push("qmake"); - while (!qmake_dirs.isEmpty()) { - QString dir = qmake_dirs.pop(); - QString od(buildPath + "/" + dir); - QString id(sourcePath + "/" + dir); - QFileInfoList entries = QDir(id).entryInfoList(QDir::NoDotAndDotDot|QDir::AllEntries); - for (int i = 0; i < entries.size(); ++i) { - QFileInfo fi(entries.at(i)); - if (fi.isDir()) { - qmake_dirs.push(dir + "/" + fi.fileName()); - QDir().mkpath(od + "/" + fi.fileName()); - } else { - QDir().mkpath(od); - bool justCopy = true; - const QString fname = fi.fileName(); - const QString outFile(od + "/" + fname), inFile(id + "/" + fname); - if (fi.fileName() == "Makefile") { //ignore - } else if (fi.suffix() == "h" || fi.suffix() == "cpp") { - QTemporaryFile tmpFile; - if (tmpFile.open()) { - QTextStream stream(&tmpFile); - stream << "#include \"" << inFile << "\"" << endl; - justCopy = false; - stream.flush(); - tmpFile.flush(); - if (filesDiffer(tmpFile.fileName(), outFile)) { - QFile::remove(outFile); - tmpFile.copy(outFile); - } - } - } - if (justCopy && filesDiffer(inFile, outFile)) - QFile::copy(inFile, outFile); - } - } - } - } - { //make a syncqt script(s) that can be used in the shadow QFile syncqt(buildPath + "/bin/syncqt"); if (syncqt.open(QFile::WriteOnly)) { @@ -3145,7 +3105,16 @@ void Configure::buildQmake() // Build qmake QString pwd = QDir::currentPath(); - QDir::setCurrent(buildPath + "/qmake"); + if (!QDir(buildPath).mkpath("qmake")) { + cout << "Cannot create qmake build dir." << endl; + dictionary[ "DONE" ] = "error"; + return; + } + if (!QDir::setCurrent(buildPath + "/qmake")) { + cout << "Cannot enter qmake build dir." << endl; + dictionary[ "DONE" ] = "error"; + return; + } QString makefile = "Makefile"; { -- cgit v1.2.3 From 7c89d44d95c1c91f77aca3359cd8964a354fc41c Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 9 Mar 2012 11:06:18 +0200 Subject: Windows: Fix QStyleSheetStyle autotest antialiasing issues Antialiasing of fonts was causing two tests that relied on finding at least a certain number of pixels of certain color to find one or two too few pixels of that color and thus fail. Fixed by increasing the amount of text displayed to make sure enough pixels of correct color would be present. Also removing the test insignification, as the test will now pass completely when run under Windows Classic theme, which CI uses. Task-number: QTBUG-24323 Change-Id: Ic0b614d33e4e4f5df18d53cb72a05db5d8b6b5e7 Reviewed-by: Friedemann Kleint --- .../styles/qstylesheetstyle/qstylesheetstyle.pro | 2 -- .../qstylesheetstyle/tst_qstylesheetstyle.cpp | 30 +++++++++++++--------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/tests/auto/widgets/styles/qstylesheetstyle/qstylesheetstyle.pro b/tests/auto/widgets/styles/qstylesheetstyle/qstylesheetstyle.pro index dd17183b30..c96004bd5d 100644 --- a/tests/auto/widgets/styles/qstylesheetstyle/qstylesheetstyle.pro +++ b/tests/auto/widgets/styles/qstylesheetstyle/qstylesheetstyle.pro @@ -6,5 +6,3 @@ SOURCES += tst_qstylesheetstyle.cpp RESOURCES += resources.qrc requires(contains(QT_CONFIG,private_tests)) - -win32:CONFIG += insignificant_test # QTBUG-24323 diff --git a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp index 544923a1c3..3bff332252 100644 --- a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -728,22 +728,27 @@ void tst_QStyleSheetStyle::focusColors() // is reached if at least ten pixels of the right color can be found in // the image. // For this reason, we use unusual and extremely ugly colors! :-) + // Note that in case of anti-aliased text, ensuring that we have at least + // ten pixels of the right color requires quite a many characters, as the + // majority of the pixels will have slightly different colors due to the + // anti-aliasing effect. #if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC) && !(defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(Q_CC_INTEL)) QSKIP("This is a fragile test which fails on many esoteric platforms because of focus problems. " "That doesn't mean that the feature doesn't work in practice."); #endif QList widgets; - widgets << new QPushButton("TESTING"); - widgets << new QLineEdit("TESTING"); - widgets << new QLabel("TESTING"); + widgets << new QPushButton("TESTING TESTING"); + widgets << new QLineEdit("TESTING TESTING"); + widgets << new QLabel("TESTING TESTING"); QSpinBox *spinbox = new QSpinBox; - spinbox->setValue(8888); + spinbox->setMaximum(1000000000); + spinbox->setValue(123456789); widgets << spinbox; QComboBox *combobox = new QComboBox; combobox->setEditable(true); - combobox->addItems(QStringList() << "TESTING"); + combobox->addItems(QStringList() << "TESTING TESTING"); widgets << combobox; - widgets << new QLabel("TESTING"); + widgets << new QLabel("TESTING TESTING"); #ifdef Q_WS_QWS // QWS has its own special focus logic which is slightly different @@ -794,17 +799,18 @@ void tst_QStyleSheetStyle::hoverColors() if (!PlatformQuirks::haveMouseCursor()) QSKIP("No mouse Cursor on this platform"); QList widgets; - widgets << new QPushButton("TESTING"); - widgets << new QLineEdit("TESTING"); - widgets << new QLabel("TESTING"); + widgets << new QPushButton("TESTING TESTING"); + widgets << new QLineEdit("TESTING TESTING"); + widgets << new QLabel("TESTING TESTING"); QSpinBox *spinbox = new QSpinBox; - spinbox->setValue(8888); + spinbox->setMaximum(1000000000); + spinbox->setValue(123456789); widgets << spinbox; QComboBox *combobox = new QComboBox; combobox->setEditable(true); - combobox->addItems(QStringList() << "TESTING"); + combobox->addItems(QStringList() << "TESTING TESTING"); widgets << combobox; - widgets << new QLabel("TESTING"); + widgets << new QLabel("TESTING TESTING"); foreach (QWidget *widget, widgets) { //without Qt::X11BypassWindowManagerHint the window manager may move the window after we moved the cursor -- cgit v1.2.3 From 5368ad604c958fc95683a72631ac47f59316fc26 Mon Sep 17 00:00:00 2001 From: Kevin Krammer Date: Fri, 9 Mar 2012 12:59:48 +0100 Subject: Use qt_safe_read to read from low-level file descriptor Change-Id: I7c7bc379a423be4de471c5972cb98101c90bab8c Reviewed-by: Robin Burchell --- src/plugins/platforms/blackberry/qbbnavigatorthread.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp b/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp index 65cbb77d31..03cf458b80 100644 --- a/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp +++ b/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -257,7 +258,7 @@ void QBBNavigatorThread::readData() // attempt to read pps data errno = 0; - int bytes = read(m_fd, buffer, ppsBufferSize - 1); + int bytes = qt_safe_read(m_fd, buffer, ppsBufferSize - 1); if (bytes == -1) { qFatal("QBB: failed to read navigator pps, errno=%d", errno); } -- cgit v1.2.3 From 53d24330f7c6c28f08cdc8b85c09c35b8f0fe296 Mon Sep 17 00:00:00 2001 From: Kevin Krammer Date: Fri, 9 Mar 2012 12:56:41 +0100 Subject: Make tst_qapplication build when QT_NO_SHAREDMEMORY is defined Change-Id: I8cfd0ff2e17e6d5c04b81a042c665bcbbca36256 Reviewed-by: David Faure --- tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp index 9bbb6aa7f6..91ecbf23a2 100644 --- a/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp +++ b/tests/auto/widgets/kernel/qapplication/tst_qapplication.cpp @@ -2160,7 +2160,9 @@ void tst_QApplication::abortQuitOnShow() Q_GLOBAL_STATIC(QLocale, tst_qapp_locale); Q_GLOBAL_STATIC(QProcess, tst_qapp_process); Q_GLOBAL_STATIC(QFileSystemWatcher, tst_qapp_fileSystemWatcher); +#ifndef QT_NO_SHAREDMEMORY Q_GLOBAL_STATIC(QSharedMemory, tst_qapp_sharedMemory); +#endif Q_GLOBAL_STATIC(QElapsedTimer, tst_qapp_elapsedTimer); Q_GLOBAL_STATIC(QMutex, tst_qapp_mutex); Q_GLOBAL_STATIC(QWidget, tst_qapp_widget); @@ -2177,7 +2179,9 @@ void tst_QApplication::globalStaticObjectDestruction() QVERIFY(tst_qapp_locale()); QVERIFY(tst_qapp_process()); QVERIFY(tst_qapp_fileSystemWatcher()); +#ifndef QT_NO_SHAREDMEMORY QVERIFY(tst_qapp_sharedMemory()); +#endif QVERIFY(tst_qapp_elapsedTimer()); QVERIFY(tst_qapp_mutex()); QVERIFY(tst_qapp_widget()); -- cgit v1.2.3 From 657f634c0e8a1bf4f544b4c42b35640b4dfcc486 Mon Sep 17 00:00:00 2001 From: Rafael Roquetto Date: Fri, 9 Mar 2012 12:19:15 +0100 Subject: Fixes mismatching delete operator Change-Id: Ib6640daa0fdd12f98f9d7e257c226e0abdcf31dc Reviewed-by: Kevin Krammer Reviewed-by: Robin Burchell --- src/corelib/codecs/qtextcodec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index c031a43985..784a75bcad 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -351,7 +351,7 @@ QString QWindowsLocalCodec::convertToUnicodeCharByChar(const char *chars, int le s.append(QChar(ws[i])); delete [] ws; #endif - delete mbcs; + delete [] mbcs; return s; } -- cgit v1.2.3 From 816893d91d550c08297ebcdfc3306bb3d9c0c2f6 Mon Sep 17 00:00:00 2001 From: David Faure Date: Wed, 7 Mar 2012 22:52:42 +0100 Subject: Fix some duplication between QGuiApplication and QApplication, MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for the mouseButtons and keyboardModifiers vars and methods. Implement queryKeyboardModifiers with a new virtual in QPlatformIntegration. Task-number: QTBUG-11243 Change-Id: I9e95841542ac61c73ff72d7682ad962ea8aada42 Reviewed-by: Friedemann Kleint Reviewed-by: Samuel Rødal --- src/gui/kernel/qguiapplication.cpp | 46 +++++++++++++++++++- src/gui/kernel/qguiapplication.h | 1 + src/gui/kernel/qplatformintegration_qpa.cpp | 5 +++ src/gui/kernel/qplatformintegration_qpa.h | 2 + src/widgets/kernel/qapplication.cpp | 65 ----------------------------- src/widgets/kernel/qapplication.h | 4 -- src/widgets/kernel/qapplication_p.h | 3 -- 7 files changed, 52 insertions(+), 74 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 42ce3745de..bfc52a816c 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -753,7 +753,17 @@ static QClipboard *clipboard(); #endif /*! - Returns the currently held keyboard modifiers. + Returns the current state of the modifier keys on the keyboard. The current + state is updated sychronously as the event queue is emptied of events that + will spontaneously change the keyboard state (QEvent::KeyPress and + QEvent::KeyRelease events). + + It should be noted this may not reflect the actual keys held on the input + device at the time of calling but rather the modifiers as last reported in + one of the above events. If no keys are being held Qt::NoModifier is + returned. + + \sa mouseButtons(), queryKeyboardModifiers() */ Qt::KeyboardModifiers QGuiApplication::keyboardModifiers() { @@ -761,7 +771,39 @@ Qt::KeyboardModifiers QGuiApplication::keyboardModifiers() } /*! - Returns the currently held mouse buttons. + \fn Qt::KeyboardModifiers QApplication::queryKeyboardModifiers() + + Queries and returns the state of the modifier keys on the keyboard. + Unlike keyboardModifiers, this method returns the actual keys held + on the input device at the time of calling the method. + + It does not rely on the keypress events having been received by this + process, which makes it possible to check the modifiers while moving + a window, for instance. Note that in most cases, you should use + keyboardModifiers(), which is faster and more accurate since it contains + the state of the modifiers as they were when the currently processed + event was received. + + \sa keyboardModifiers() +*/ +Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers() +{ + QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); + return pi->queryKeyboardModifiers(); +} + +/*! + Returns the current state of the buttons on the mouse. The current state is + updated syncronously as the event queue is emptied of events that will + spontaneously change the mouse state (QEvent::MouseButtonPress and + QEvent::MouseButtonRelease events). + + It should be noted this may not reflect the actual buttons held on the + input device at the time of calling but rather the mouse buttons as last + reported in one of the above events. If no mouse buttons are being held + Qt::NoButton is returned. + + \sa keyboardModifiers() */ Qt::MouseButtons QGuiApplication::mouseButtons() { diff --git a/src/gui/kernel/qguiapplication.h b/src/gui/kernel/qguiapplication.h index c374a05986..6fdbb000fe 100644 --- a/src/gui/kernel/qguiapplication.h +++ b/src/gui/kernel/qguiapplication.h @@ -113,6 +113,7 @@ public: static void setPalette(const QPalette &pal); static Qt::KeyboardModifiers keyboardModifiers(); + static Qt::KeyboardModifiers queryKeyboardModifiers(); static Qt::MouseButtons mouseButtons(); static void setLayoutDirection(Qt::LayoutDirection direction); diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp index fd3714d303..e8721edce7 100644 --- a/src/gui/kernel/qplatformintegration_qpa.cpp +++ b/src/gui/kernel/qplatformintegration_qpa.cpp @@ -291,6 +291,11 @@ QVariant QPlatformIntegration::styleHint(StyleHint hint) const return 0; } +Qt::KeyboardModifiers QPlatformIntegration::queryKeyboardModifiers() const +{ + return QGuiApplication::keyboardModifiers(); +} + /*! Should be called by the implementation whenever a new screen is added. diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h index a05c0f61b7..3f9de9df5e 100644 --- a/src/gui/kernel/qplatformintegration_qpa.h +++ b/src/gui/kernel/qplatformintegration_qpa.h @@ -124,6 +124,8 @@ public: virtual QVariant styleHint(StyleHint hint) const; + virtual Qt::KeyboardModifiers queryKeyboardModifiers() const; + virtual QPlatformTheme *platformTheme() const; protected: diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index 90b64db579..348eb2f343 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -371,9 +371,6 @@ void qt_init(QApplicationPrivate *priv, int type ); void qt_cleanup(); -Qt::MouseButtons QApplicationPrivate::mouse_buttons = Qt::NoButton; -Qt::KeyboardModifiers QApplicationPrivate::modifier_buttons = Qt::NoModifier; - QStyle *QApplicationPrivate::app_style = 0; // default application style QString QApplicationPrivate::styleOverride; // style override @@ -2665,68 +2662,6 @@ QDesktopWidget *QApplication::desktop() return qt_desktopWidget; } -/*! - Returns the current state of the modifier keys on the keyboard. The current - state is updated sychronously as the event queue is emptied of events that - will spontaneously change the keyboard state (QEvent::KeyPress and - QEvent::KeyRelease events). - - It should be noted this may not reflect the actual keys held on the input - device at the time of calling but rather the modifiers as last reported in - one of the above events. If no keys are being held Qt::NoModifier is - returned. - - \sa mouseButtons(), queryKeyboardModifiers() -*/ - -Qt::KeyboardModifiers QApplication::keyboardModifiers() -{ - return QApplicationPrivate::modifier_buttons; -} - -/*! - \fn Qt::KeyboardModifiers QApplication::queryKeyboardModifiers() - - Queries and returns the state of the modifier keys on the keyboard. - Unlike keyboardModifiers, this method returns the actual keys held - on the input device at the time of calling the method. - - It does not rely on the keypress events having been received by this - process, which makes it possible to check the modifiers while moving - a window, for instance. Note that in most cases, you should use - keyboardModifiers(), which is faster and more accurate since it contains - the state of the modifiers as they were when the currently processed - event was received. - - \sa keyboardModifiers() - - \since 4.8 -*/ - -Qt::KeyboardModifiers QApplication::queryKeyboardModifiers() -{ - qWarning("queryKeyboardModifiers() doesn't have a QPA implementation"); - return QApplicationPrivate::modifier_buttons; -} - -/*! - Returns the current state of the buttons on the mouse. The current state is - updated syncronously as the event queue is emptied of events that will - spontaneously change the mouse state (QEvent::MouseButtonPress and - QEvent::MouseButtonRelease events). - - It should be noted this may not reflect the actual buttons held on the - input device at the time of calling but rather the mouse buttons as last - reported in one of the above events. If no mouse buttons are being held - Qt::NoButton is returned. - - \sa keyboardModifiers() -*/ - -Qt::MouseButtons QApplication::mouseButtons() -{ - return QApplicationPrivate::mouse_buttons; -} /*! \fn bool QApplication::isSessionRestored() const diff --git a/src/widgets/kernel/qapplication.h b/src/widgets/kernel/qapplication.h index 060765969f..55ed6998fa 100644 --- a/src/widgets/kernel/qapplication.h +++ b/src/widgets/kernel/qapplication.h @@ -150,10 +150,6 @@ public: static void beep(); static void alert(QWidget *widget, int duration = 0); - static Qt::KeyboardModifiers keyboardModifiers(); - static Qt::KeyboardModifiers queryKeyboardModifiers(); - static Qt::MouseButtons mouseButtons(); - static void setCursorFlashTime(int); static int cursorFlashTime(); diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index 2d639172e2..74af3bca6d 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -247,9 +247,6 @@ public: QPoint toolTipPos, toolTipGlobalPos, hoverGlobalPos; QPointer toolTipWidget; - static Qt::MouseButtons mouse_buttons; - static Qt::KeyboardModifiers modifier_buttons; - static QSize app_strut; static QWidgetList *popupWidgets; static QStyle *app_style; -- cgit v1.2.3 From f16b08dfc641437ed53765b5de45911ba38d7410 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 9 Mar 2012 10:17:16 +0100 Subject: qws: Remove decorations/kbd/mouse plugin support from configure Change-Id: Iaca207ed892b2f5f5d1650ed27007532a172544c Reviewed-by: Oswald Buddenhagen --- configure | 142 ++------------------------------------------------------------ 1 file changed, 4 insertions(+), 138 deletions(-) diff --git a/configure b/configure index 5e574e668a..95838ce751 100755 --- a/configure +++ b/configure @@ -639,17 +639,6 @@ rm -f "$outpath/config.tests/.qmake.cache" cp "$QMAKE_VARS_FILE" "$outpath/config.tests/.qmake.cache" QMakeVar add styles "cde mac motif plastique cleanlooks windows" -QMakeVar add decorations "default windows styled" -QMakeVar add mouse-drivers "pc" -if [ "$UNAME_SYSTEM" = "Linux" ] ; then - QMakeVar add gfx-drivers "linuxfb" - QMakeVar add mouse-drivers "linuxtp" -fi -QMakeVar add kbd-drivers "tty" - -if [ "$CFG_DEV" = "yes" ]; then - QMakeVar add kbd-drivers "um" -fi # QTDIR may be set and point to an old or system-wide Qt installation unset QTDIR @@ -705,30 +694,10 @@ CFG_V8SNAPSHOT=auto CFG_DECLARATIVE_DEBUG=yes CFG_JAVASCRIPTCORE_JIT=auto -CFG_GFX_AVAILABLE="linuxfb transformed qvfb vnc multiscreen directfb" -CFG_GFX_ON="linuxfb multiscreen" -CFG_GFX_PLUGIN_AVAILABLE= -CFG_GFX_PLUGIN= -CFG_GFX_OFF= -CFG_KBD_AVAILABLE="tty linuxinput qvfb" -CFG_KBD_ON="tty" #default, see QMakeVar above -CFG_MOUSE_AVAILABLE="pc linuxtp linuxinput tslib qvfb" -CFG_MOUSE_ON="pc linuxtp" #default, see QMakeVar above - CFG_ARCH= CFG_HOST_ARCH= -CFG_KBD_PLUGIN_AVAILABLE= -CFG_KBD_PLUGIN= -CFG_KBD_OFF= -CFG_MOUSE_PLUGIN_AVAILABLE= -CFG_MOUSE_PLUGIN= -CFG_MOUSE_OFF= CFG_USE_GNUMAKE=no CFG_IM=yes -CFG_DECORATION_AVAILABLE="styled windows default" -CFG_DECORATION_ON="${CFG_DECORATION_AVAILABLE}" # all on by default -CFG_DECORATION_PLUGIN_AVAILABLE= -CFG_DECORATION_PLUGIN= CFG_XINPUT2=auto CFG_XINPUT=runtime CFG_XKB=auto @@ -849,7 +818,7 @@ QT_CFLAGS_GSTREAMER= QT_LIBS_GSTREAMER= #------------------------------------------------------------------------------- -# check SQL drivers, mouse drivers and decorations available in this package +# check SQL drivers available in this package #------------------------------------------------------------------------------- # opensource version removes some drivers, so force them to be off @@ -868,47 +837,6 @@ if [ -d "$relpath/src/plugins/sqldrivers" ]; then done fi -CFG_DECORATION_PLUGIN_AVAILABLE= -if [ -d "$relpath/src/plugins/decorations" ]; then - for a in "$relpath/src/plugins/decorations/"*; do - if [ -d "$a" ]; then - base_a=`basename "$a"` - CFG_DECORATION_PLUGIN_AVAILABLE="${CFG_DECORATION_PLUGIN_AVAILABLE} ${base_a}" - fi - done -fi - -CFG_KBD_PLUGIN_AVAILABLE= -if [ -d "$relpath/src/plugins/kbddrivers" ]; then - for a in "$relpath/src/plugins/kbddrivers/"*; do - if [ -d "$a" ]; then - base_a=`basename "$a"` - CFG_KBD_PLUGIN_AVAILABLE="${CFG_KBD_PLUGIN_AVAILABLE} ${base_a}" - fi - done -fi - -CFG_MOUSE_PLUGIN_AVAILABLE= -if [ -d "$relpath/src/plugins/mousedrivers" ]; then - for a in "$relpath/src/plugins/mousedrivers/"*; do - if [ -d "$a" ]; then - base_a=`basename "$a"` - CFG_MOUSE_PLUGIN_AVAILABLE="${CFG_MOUSE_PLUGIN_AVAILABLE} ${base_a}" - fi - done -fi - -CFG_GFX_PLUGIN_AVAILABLE= -if [ -d "$relpath/src/plugins/gfxdrivers" ]; then - for a in "$relpath/src/plugins/gfxdrivers/"*; do - if [ -d "$a" ]; then - base_a=`basename "$a"` - CFG_GFX_PLUGIN_AVAILABLE="${CFG_GFX_PLUGIN_AVAILABLE} ${base_a}" - fi - done - CFG_GFX_OFF="$CFG_GFX_AVAILABLE" # assume all off -fi - CFG_IMAGEFORMAT_PLUGIN_AVAILABLE= if [ -d "$relpath/src/plugins/imageformats" ]; then for a in "$relpath/src/plugins/imageformats/"*; do @@ -960,7 +888,7 @@ while [ "$#" -gt 0 ]; do VAL=no ;; #Qt style yes options - -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-xinput2|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-xcb|-wayland|-nis|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-debug-and-release|-exceptions|-harfbuzz|-prefix-install|-silent|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-phonon-backend|-audio-backend|-declarative-debug|-javascript-jit|-rpath|-force-pkg-config|-icu|-force-asserts|-testcocoon) + -incremental|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-xinput2|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-xcb|-wayland|-nis|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-debug-and-release|-exceptions|-harfbuzz|-prefix-install|-silent|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-phonon-backend|-audio-backend|-declarative-debug|-javascript-jit|-rpath|-force-pkg-config|-icu|-force-asserts|-testcocoon) VAR=`echo $1 | sed "s,^-\(.*\),\1,"` VAL=yes ;; @@ -1249,20 +1177,6 @@ while [ "$#" -gt 0 ]; do UNKNOWN_OPT=yes fi ;; - qvfb) # left for commandline compatibility, not documented - if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then - if [ "$VAL" = "yes" ]; then - QMakeVar add gfx-drivers qvfb - QMakeVar add kbd-drivers qvfb - QMakeVar add mouse-drivers qvfb - CFG_GFX_ON="$CFG_GFX_ON qvfb" - CFG_KBD_ON="$CFG_KBD_ON qvfb" - CFG_MOUSE_ON="$CFG_MOUSE_ON qvfb" - fi - else - UNKNOWN_OPT=yes - fi - ;; nomake) CFG_NOBUILD_PARTS="$CFG_NOBUILD_PARTS $VAL" ;; @@ -1891,7 +1805,7 @@ while [ "$#" -gt 0 ]; do UNKNOWN_OPT=yes fi ;; - sql-*|gfx-*|decoration-*|kbd-*|mouse-*|imageformat-*) + sql-*|imageformat-*) # if Qt style options were used, $VAL can be "no", "qt", or "plugin" # if autoconf style options were used, $VAL can be "yes" or "no" [ "$VAL" = "yes" ] && VAL=qt @@ -1909,30 +1823,6 @@ while [ "$#" -gt 0 ]; do sql) avail="$CFG_SQL_AVAILABLE" ;; - gfx) - avail="$CFG_GFX_AVAILABLE" - if [ "$OPT" = "plugin" ]; then - avail="$CFG_GFX_PLUGIN_AVAILABLE" - fi - ;; - decoration) - avail="$CFG_DECORATION_AVAILABLE" - if [ "$OPT" = "plugin" ]; then - avail="$CFG_DECORATION_PLUGIN_AVAILABLE" - fi - ;; - kbd) - avail="$CFG_KBD_AVAILABLE" - if [ "$OPT" = "plugin" ]; then - avail="$CFG_KBD_PLUGIN_AVAILABLE" - fi - ;; - mouse) - avail="$CFG_MOUSE_AVAILABLE" - if [ "$OPT" = "plugin" ]; then - avail="$CFG_MOUSE_PLUGIN_AVAILABLE" - fi - ;; imageformat) avail="$CFG_IMAGEFORMAT_PLUGIN_AVAILABLE" if [ "$OPT" != "plugin" ]; then @@ -1969,36 +1859,12 @@ while [ "$#" -gt 0 ]; do if [ "$OPT" = "plugin" ] || [ "$OPT" = "qt" ]; then if [ "$OPT" = "plugin" ]; then - [ "$VAR" = "decoration" ] && QMakeVar del "${VAR}s" "$VAL" - [ "$VAR" = "decoration" ] && CFG_DECORATION_ON=`echo "${CFG_DECORATION_ON} " | sed "s,${VAL} ,,g"` && CFG_DECORATION_PLUGIN="$CFG_DECORATION_PLUGIN ${VAL}" - [ "$VAR" = "kbd" ] && QMakeVar del "${VAR}s" "$VAL" - [ "$VAR" = "kbd" ] && CFG_KBD_ON=`echo "${CFG_KBD_ON} " | sed "s,${VAL} ,,g"` && CFG_KBD_PLUGIN="$CFG_KBD_PLUGIN ${VAL}" - [ "$VAR" = "mouse" ] && QMakeVar del "${VAR}s" "$VAL" - [ "$VAR" = "mouse" ] && CFG_MOUSE_ON=`echo "${CFG_MOUSE_ON} " | sed "s,${VAL} ,,g"` && CFG_MOUSE_PLUGIN="$CFG_MOUSE_PLUGIN ${VAL}" - [ "$VAR" = "gfx" ] && QMakeVar del "${VAR}s" "$VAL" - [ "$VAR" = "gfx" ] && CFG_GFX_ON=`echo "${CFG_GFX_ON} " | sed "s,${VAL} ,,g"` && CFG_GFX_PLUGIN="${CFG_GFX_PLUGIN} ${VAL}" VAR="${VAR}-${OPT}" - else - if [ "$VAR" = "gfx" ] || [ "$VAR" = "kbd" ] || [ "$VAR" = "decoration" ] || [ "$VAR" = "mouse" ]; then - [ "$VAR" = "gfx" ] && CFG_GFX_ON="$CFG_GFX_ON $VAL" - [ "$VAR" = "kbd" ] && CFG_KBD_ON="$CFG_KBD_ON $VAL" - [ "$VAR" = "decoration" ] && CFG_DECORATION_ON="$CFG_DECORATION_ON $VAL" - [ "$VAR" = "mouse" ] && CFG_MOUSE_ON="$CFG_MOUSE_ON $VAL" - VAR="${VAR}-driver" - fi fi QMakeVar add "${VAR}s" "${VAL}" elif [ "$OPT" = "no" ]; then PLUG_VAR="${VAR}-plugin" - if [ "$VAR" = "gfx" ] || [ "$VAR" = "kbd" ] || [ "$VAR" = "mouse" ]; then - IN_VAR="${VAR}-driver" - else - IN_VAR="${VAR}" - fi - [ "$VAR" = "decoration" ] && CFG_DECORATION_ON=`echo "${CFG_DECORATION_ON} " | sed "s,${VAL} ,,g"` - [ "$VAR" = "gfx" ] && CFG_GFX_ON=`echo "${CFG_GFX_ON} " | sed "s,${VAL} ,,g"` - [ "$VAR" = "kbd" ] && CFG_KBD_ON=`echo "${CFG_KBD_ON} " | sed "s,${VAL} ,,g"` - [ "$VAR" = "mouse" ] && CFG_MOUSE_ON=`echo "${CFG_MOUSE_ON} " | sed "s,${VAL} ,,g"` + IN_VAR="${VAR}" QMakeVar del "${IN_VAR}s" "$VAL" QMakeVar del "${PLUG_VAR}s" "$VAL" fi -- cgit v1.2.3 From 65ebf592ba0f0e0654162620a92c9a22af0534ab Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Fri, 9 Mar 2012 17:15:26 +0100 Subject: remove assignment of QMAKE_MOC & QMAKE_UIC from mkspecs (part 2) Follow-up to d13bedb9d8fb66f58ba901864555bcc9b6e463e0 where the regexp was a bit too tight and missed many specs. Also cleaned up QMAKE_IDC, QMAKE_RCC and QMAKE_IDL. Change-Id: Ia15007141739019ef5ccfdda0c856c478f732b85 Reviewed-by: Oswald Buddenhagen --- mkspecs/common/wince/qmake.conf | 4 ---- mkspecs/unsupported/qws/qnx-641/qmake.conf | 3 --- mkspecs/unsupported/qws/qnx-generic-g++/qmake.conf | 3 --- mkspecs/unsupported/qws/qnx-i386-g++/qmake.conf | 3 --- mkspecs/unsupported/qws/qnx-ppc-g++/qmake.conf | 3 --- mkspecs/unsupported/win32-borland/qmake.conf | 4 ---- mkspecs/unsupported/win32-g++-cross/qmake.conf | 7 ------- mkspecs/unsupported/win32-msvc2003/qmake.conf | 4 ---- mkspecs/win32-g++/qmake.conf | 5 ----- mkspecs/win32-icc/qmake.conf | 4 ---- mkspecs/win32-msvc2005/qmake.conf | 4 ---- mkspecs/win32-msvc2008/qmake.conf | 4 ---- mkspecs/win32-msvc2010/qmake.conf | 4 ---- 13 files changed, 52 deletions(-) diff --git a/mkspecs/common/wince/qmake.conf b/mkspecs/common/wince/qmake.conf index 57b89b9650..6b7a2d71fe 100644 --- a/mkspecs/common/wince/qmake.conf +++ b/mkspecs/common/wince/qmake.conf @@ -70,10 +70,6 @@ QMAKE_LIBS_OPENGL_ES2 = libGLESv2.lib QMAKE_LIBS_QT_ENTRY = -lqtmain -QMAKE_MOC = $$[QT_INSTALL_BINS]\\moc.exe -QMAKE_UIC = $$[QT_INSTALL_BINS]\\uic.exe -QMAKE_IDC = $$[QT_INSTALL_BINS]\\idc.exe - QMAKE_IDL = midl QMAKE_LIB = lib QMAKE_RC = rc diff --git a/mkspecs/unsupported/qws/qnx-641/qmake.conf b/mkspecs/unsupported/qws/qnx-641/qmake.conf index 441f408802..0636ca7347 100644 --- a/mkspecs/unsupported/qws/qnx-641/qmake.conf +++ b/mkspecs/unsupported/qws/qnx-641/qmake.conf @@ -75,9 +75,6 @@ QMAKE_LIBS_DYNLOAD = QMAKE_LIBS_THREAD = QMAKE_LIBS_NETWORK += -lsocket QMAKE_LIBS_GUI += -lsocket -QMAKE_MOC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc.exe -QMAKE_UIC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic.exe -QMAKE_IDC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc.exe QMAKE_AR = ntox86-ar cqs QMAKE_RANLIB = diff --git a/mkspecs/unsupported/qws/qnx-generic-g++/qmake.conf b/mkspecs/unsupported/qws/qnx-generic-g++/qmake.conf index bb760b24a7..608da6948e 100644 --- a/mkspecs/unsupported/qws/qnx-generic-g++/qmake.conf +++ b/mkspecs/unsupported/qws/qnx-generic-g++/qmake.conf @@ -78,9 +78,6 @@ QMAKE_LIBS_THREAD = QMAKE_LIBS_NETWORK += -lsocket QMAKE_LIBS_GUI += -lsocket -QMAKE_MOC = $$[QT_INSTALL_BINS]/moc -QMAKE_UIC = $$[QT_INSTALL_BINS]/uic - QMAKE_AR = ar cqs QMAKE_RANLIB = diff --git a/mkspecs/unsupported/qws/qnx-i386-g++/qmake.conf b/mkspecs/unsupported/qws/qnx-i386-g++/qmake.conf index b43c39143f..395f4fe3bf 100644 --- a/mkspecs/unsupported/qws/qnx-i386-g++/qmake.conf +++ b/mkspecs/unsupported/qws/qnx-i386-g++/qmake.conf @@ -74,9 +74,6 @@ QMAKE_LIBS_THREAD = QMAKE_LIBS_NETWORK += -lsocket QMAKE_LIBS_GUI += -lsocket -QMAKE_MOC = $$[QT_INSTALL_BINS]/moc -QMAKE_UIC = $$[QT_INSTALL_BINS]/uic - QMAKE_AR = ar cqs QMAKE_RANLIB = diff --git a/mkspecs/unsupported/qws/qnx-ppc-g++/qmake.conf b/mkspecs/unsupported/qws/qnx-ppc-g++/qmake.conf index 29a2952989..433b09161f 100644 --- a/mkspecs/unsupported/qws/qnx-ppc-g++/qmake.conf +++ b/mkspecs/unsupported/qws/qnx-ppc-g++/qmake.conf @@ -74,9 +74,6 @@ QMAKE_LIBS_THREAD = QMAKE_LIBS_NETWORK += -lsocket QMAKE_LIBS_GUI += -lsocket -QMAKE_MOC = $$[QT_INSTALL_BINS]/moc -QMAKE_UIC = $$[QT_INSTALL_BINS]/uic - QMAKE_AR = ar cqs QMAKE_RANLIB = diff --git a/mkspecs/unsupported/win32-borland/qmake.conf b/mkspecs/unsupported/win32-borland/qmake.conf index 2ba742c104..c1aa7e46ad 100644 --- a/mkspecs/unsupported/win32-borland/qmake.conf +++ b/mkspecs/unsupported/win32-borland/qmake.conf @@ -69,10 +69,6 @@ QMAKE_LIBS_QT_ENTRY = -lqtmain #QMAKE_LIBS_OPENGL = #QMAKE_LFLAGS_OPENGL = /dopengl32.dll -QMAKE_MOC = $$[QT_INSTALL_BINS]\\moc.exe -QMAKE_UIC = $$[QT_INSTALL_BINS]\\uic.exe -QMAKE_IDC = $$[QT_INSTALL_BINS]\\idc.exe - QMAKE_IDL = midl QMAKE_LIB = tlib /C /P256 QMAKE_RC = brcc32 -dQ_CC_BOR diff --git a/mkspecs/unsupported/win32-g++-cross/qmake.conf b/mkspecs/unsupported/win32-g++-cross/qmake.conf index 9dcff807fa..9c85c9033c 100644 --- a/mkspecs/unsupported/win32-g++-cross/qmake.conf +++ b/mkspecs/unsupported/win32-g++-cross/qmake.conf @@ -65,7 +65,6 @@ QMAKE_LINK_OBJECT_SCRIPT= object_script QMAKE_PREFIX_STATICLIB = lib QMAKE_EXTENSION_STATICLIB = a - QMAKE_LIBS = QMAKE_LIBS_CORE = -lole32 -luuid -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 QMAKE_LIBS_GUI = -lgdi32 -lcomdlg32 -loleaut32 -limm32 -lwinmm -lwinspool -lws2_32 -lole32 -luuid -luser32 -ladvapi32 @@ -88,12 +87,6 @@ QMAKE_DEL_DIR = rmdir QMAKE_SYMBOLIC_LINK = ln -s QMAKE_CHK_DIR_EXISTS = test -d -#QMAKE_IDC = i686-pc-mingw32-idc -QMAKE_MOC = i686-pc-mingw32-moc -QMAKE_RCC = i686-pc-mingw32-rcc -QMAKE_UIC = i686-pc-mingw32-uic - -#QMAKE_IDL = midl QMAKE_LIB = i686-pc-mingw32-ar -ru QMAKE_RC = i686-pc-mingw32-windres QMAKE_ZIP = zip -r -9 diff --git a/mkspecs/unsupported/win32-msvc2003/qmake.conf b/mkspecs/unsupported/win32-msvc2003/qmake.conf index a573a4dd8c..29681c1034 100644 --- a/mkspecs/unsupported/win32-msvc2003/qmake.conf +++ b/mkspecs/unsupported/win32-msvc2003/qmake.conf @@ -67,10 +67,6 @@ QMAKE_LIBS_COMPAT = advapi32.lib shell32.lib comdlg32.lib user32.lib gdi32 QMAKE_LIBS_QT_ENTRY = -lqtmain -QMAKE_MOC = $$[QT_INSTALL_BINS]\\moc.exe -QMAKE_UIC = $$[QT_INSTALL_BINS]\\uic.exe -QMAKE_IDC = $$[QT_INSTALL_BINS]\\idc.exe - QMAKE_IDL = midl QMAKE_LIB = lib /NOLOGO QMAKE_RC = rc diff --git a/mkspecs/win32-g++/qmake.conf b/mkspecs/win32-g++/qmake.conf index 641e4109ff..7a04a51932 100644 --- a/mkspecs/win32-g++/qmake.conf +++ b/mkspecs/win32-g++/qmake.conf @@ -65,7 +65,6 @@ QMAKE_LINK_OBJECT_SCRIPT= object_script QMAKE_PREFIX_STATICLIB = lib QMAKE_EXTENSION_STATICLIB = a - QMAKE_LIBS = QMAKE_LIBS_CORE = -lole32 -luuid -lws2_32 -ladvapi32 -lshell32 -luser32 -lkernel32 QMAKE_LIBS_GUI = -lgdi32 -lcomdlg32 -loleaut32 -limm32 -lwinmm -lwinspool -lws2_32 -lole32 -luuid -luser32 -ladvapi32 @@ -96,10 +95,6 @@ QMAKE_LIBS_QT_ENTRY = -lmingw32 -lqtmain QMAKE_CHK_DIR_EXISTS = if not exist } -QMAKE_MOC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc.exe -QMAKE_UIC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic.exe -QMAKE_IDC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc.exe - QMAKE_IDL = midl QMAKE_LIB = ar -ru QMAKE_RC = windres diff --git a/mkspecs/win32-icc/qmake.conf b/mkspecs/win32-icc/qmake.conf index 2dd796d7ea..8a7260aca0 100644 --- a/mkspecs/win32-icc/qmake.conf +++ b/mkspecs/win32-icc/qmake.conf @@ -67,10 +67,6 @@ QMAKE_LIBS_OPENGL = glu32.lib opengl32.lib gdi32.lib user32.lib delayimp.l QMAKE_LIBS_COMPAT = advapi32.lib shell32.lib comdlg32.lib user32.lib gdi32.lib ws2_32.lib QMAKE_LIBS_QT_ENTRY = -lqtmain -QMAKE_MOC = $$[QT_INSTALL_BINS]\\moc.exe -QMAKE_UIC = $$[QT_INSTALL_BINS]\\uic.exe -QMAKE_IDC = $$[QT_INSTALL_BINS]\\idc.exe - QMAKE_IDL = midl QMAKE_LIB = xilib /NOLOGO QMAKE_RC = rc diff --git a/mkspecs/win32-msvc2005/qmake.conf b/mkspecs/win32-msvc2005/qmake.conf index d4b9521b6d..66f10236c0 100644 --- a/mkspecs/win32-msvc2005/qmake.conf +++ b/mkspecs/win32-msvc2005/qmake.conf @@ -71,10 +71,6 @@ QMAKE_LIBS_COMPAT = advapi32.lib shell32.lib comdlg32.lib user32.lib gdi32 QMAKE_LIBS_QT_ENTRY = -lqtmain -QMAKE_MOC = $$[QT_INSTALL_BINS]\\moc.exe -QMAKE_UIC = $$[QT_INSTALL_BINS]\\uic.exe -QMAKE_IDC = $$[QT_INSTALL_BINS]\\idc.exe - QMAKE_IDL = midl QMAKE_LIB = lib /NOLOGO QMAKE_RC = rc diff --git a/mkspecs/win32-msvc2008/qmake.conf b/mkspecs/win32-msvc2008/qmake.conf index 00fafc7872..e360165ce3 100644 --- a/mkspecs/win32-msvc2008/qmake.conf +++ b/mkspecs/win32-msvc2008/qmake.conf @@ -73,10 +73,6 @@ QMAKE_LIBS_COMPAT = advapi32.lib shell32.lib comdlg32.lib user32.lib gdi32 QMAKE_LIBS_QT_ENTRY = -lqtmain -QMAKE_MOC = $$[QT_INSTALL_BINS]\\moc.exe -QMAKE_UIC = $$[QT_INSTALL_BINS]\\uic.exe -QMAKE_IDC = $$[QT_INSTALL_BINS]\\idc.exe - QMAKE_IDL = midl QMAKE_LIB = lib /NOLOGO QMAKE_RC = rc diff --git a/mkspecs/win32-msvc2010/qmake.conf b/mkspecs/win32-msvc2010/qmake.conf index b53ff1a478..99645a0a96 100644 --- a/mkspecs/win32-msvc2010/qmake.conf +++ b/mkspecs/win32-msvc2010/qmake.conf @@ -73,10 +73,6 @@ QMAKE_LIBS_COMPAT = advapi32.lib shell32.lib comdlg32.lib user32.lib gdi32 QMAKE_LIBS_QT_ENTRY = -lqtmain -QMAKE_MOC = $$[QT_INSTALL_BINS]\\moc.exe -QMAKE_UIC = $$[QT_INSTALL_BINS]\\uic.exe -QMAKE_IDC = $$[QT_INSTALL_BINS]\\idc.exe - QMAKE_IDL = midl QMAKE_LIB = lib /NOLOGO QMAKE_RC = rc -- cgit v1.2.3 From 8a15c41d36b1905a20fdbf506dee9ddb8930a434 Mon Sep 17 00:00:00 2001 From: Rafael Roquetto Date: Fri, 9 Mar 2012 11:59:29 +0100 Subject: Fixes wrong iconv_open call under QNX The wrong macro logic was causing iconv_open to never be called under QNX. Change-Id: I3367872fc8440f87fb59667770acd06262aef723 Reviewed-by: Andreas Holzammer Reviewed-by: Mark Brand Reviewed-by: Oswald Buddenhagen --- src/corelib/codecs/qiconvcodec.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/codecs/qiconvcodec.cpp b/src/corelib/codecs/qiconvcodec.cpp index aa0ddca753..be22ff9bca 100644 --- a/src/corelib/codecs/qiconvcodec.cpp +++ b/src/corelib/codecs/qiconvcodec.cpp @@ -465,7 +465,7 @@ iconv_t QIconvCodec::createIconv_t(const char *to, const char *from) Q_ASSERT((to == 0 && from != 0) || (to != 0 && from == 0)); iconv_t cd = (iconv_t) -1; -#if defined(__GLIBC__) || defined(GNU_LIBICONV) +#if defined(__GLIBC__) || defined(GNU_LIBICONV) || defined(Q_OS_QNX) #if defined(Q_OS_QNX) // on QNX the default locale is UTF-8, and an empty string will cause iconv_open to fail static const char empty_codeset[] = "UTF-8"; -- cgit v1.2.3 From 8b7ea1273d562f91b23804b73f2a7ec10ef9610d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 8 Mar 2012 10:25:13 +0100 Subject: byteorder: Improve the implementation comments for auto-detect Parts of the auto-detection is using __BYTE_ORDER__. This pre-processor macro was added in GCC 4.6. Document that in the auto-detection code. Remove the misleading error message in qsysinfo.h. Change-Id: I66430ba1c9a1cdf476889ae6d5f3ca476243e000 Reviewed-by: Bradley T. Hughes --- src/corelib/global/qprocessordetection.h | 20 ++++++++++++++------ src/corelib/global/qsysinfo.h | 2 -- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/corelib/global/qprocessordetection.h b/src/corelib/global/qprocessordetection.h index fcd7c69ee7..6231dae5dc 100644 --- a/src/corelib/global/qprocessordetection.h +++ b/src/corelib/global/qprocessordetection.h @@ -75,7 +75,7 @@ /* Alpha family, no revisions or variants - Alpha is bi-endian, use endianness auto-detection described above. + Alpha is bi-endian, use endianness auto-detection implemented below. */ // #elif defined(__alpha__) || defined(_M_ALPHA) // # define Q_PROCESSOR_ALPHA @@ -85,7 +85,7 @@ ARM family, known revisions: V5, V6, and V7 ARM is bi-endian, detect using __ARMEL__ or __ARMEB__, falling back to - auto-detection described above. + auto-detection implemented below. */ #if defined(__arm__) || defined(__TARGET_ARCH_ARM) # define Q_PROCESSOR_ARM @@ -154,7 +154,7 @@ /* Itanium (IA-64) family, no revisions or variants - Itanium is bi-endian, use endianness auto-detection described above. + Itanium is bi-endian, use endianness auto-detection implemented below. */ #elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64) # define Q_PROCESSOR_IA64 @@ -163,7 +163,7 @@ /* MIPS family, known revisions: I, II, III, IV, 32, 64 - MIPS is bi-endian, use endianness auto-detection described above. + MIPS is bi-endian, use endianness auto-detection implemented below. */ #elif defined(__mips) || defined(__mips__) || defined(_M_MRX000) # define Q_PROCESSOR_MIPS @@ -197,7 +197,7 @@ See http://en.wikipedia.org/wiki/Power_Architecture and http://en.wikipedia.org/wiki/File:PowerISA-evolution.svg - Power is bi-endian, use endianness auto-detection described above. + Power is bi-endian, use endianness auto-detection implemented below. */ #elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \ || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \ @@ -225,7 +225,7 @@ /* SuperH family, optional revision: SH-4A - SuperH is bi-endian, use endianness auto-detection described above. + SuperH is bi-endian, use endianness auto-detection implemented below. */ // #elif defined(__sh__) // # define Q_PROCESSOR_SH @@ -249,6 +249,14 @@ #endif +/* + NOTE: + GCC 4.6 added __BYTE_ORDER__, __ORDER_BIG_ENDIAN__, __ORDER_LITTLE_ENDIAN__ + and __ORDER_PDP_ENDIAN__ in SVN r165881. If you are using GCC 4.6 or newer, + this code will properly detect your target byte order; if you are not, and + the __LITTLE_ENDIAN__ or __BIG_ENDIAN__ macros are not defined, then this + code will fail to detect the target byte order. +*/ // Some processors support either endian format, try to detect which we are using. #if !defined(Q_BYTE_ORDER) # if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == Q_BIG_ENDIAN || __BYTE_ORDER__ == Q_LITTLE_ENDIAN) diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h index e6e207ec3d..74c8d1de7f 100644 --- a/src/corelib/global/qsysinfo.h +++ b/src/corelib/global/qsysinfo.h @@ -80,8 +80,6 @@ public: # error "Undefined byte order" # endif }; -#else -# error "Qt not configured correctly, please run configure" #endif #if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN) enum WinVersion { -- cgit v1.2.3 From c50e5f321fa2d1d3d28be744a9455739bad6d714 Mon Sep 17 00:00:00 2001 From: Rafael Roquetto Date: Fri, 9 Mar 2012 11:49:28 +0100 Subject: Updated codecs.pri to reflect new QNX mkspec name Change-Id: Icd4a9dd774991c2be180b885b3892ff85a3f8dc1 Reviewed-by: Oswald Buddenhagen --- src/corelib/codecs/codecs.pri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/codecs/codecs.pri b/src/corelib/codecs/codecs.pri index c3a15ab4f9..a6f8914516 100644 --- a/src/corelib/codecs/codecs.pri +++ b/src/corelib/codecs/codecs.pri @@ -38,7 +38,7 @@ unix { contains(QT_CONFIG,iconv) { HEADERS += codecs/qiconvcodec_p.h SOURCES += codecs/qiconvcodec.cpp - blackberry-*-qcc:LIBS_PRIVATE *= -liconv + qnx-*-qcc:LIBS_PRIVATE *= -liconv } else:contains(QT_CONFIG,gnu-libiconv) { HEADERS += codecs/qiconvcodec_p.h SOURCES += codecs/qiconvcodec.cpp -- cgit v1.2.3 From 65a9c12733e0d7151dca1862c176fc6f47fce7f5 Mon Sep 17 00:00:00 2001 From: Donald Carr Date: Fri, 9 Mar 2012 10:26:36 +0000 Subject: Remove erroneous never referenced QT_NO_GUI define Logic was clearly always off kilter, and this was only defined for GUI builds Change-Id: Ie85c156510e7c450a5192408b4c365ff07ce2029 Reviewed-by: Donald Carr Reviewed-by: Oswald Buddenhagen --- configure | 2 -- 1 file changed, 2 deletions(-) diff --git a/configure b/configure index 95838ce751..cac9a038a4 100755 --- a/configure +++ b/configure @@ -5793,8 +5793,6 @@ if [ "$CFG_GUI" = "auto" ]; then fi if [ "$CFG_GUI" = "no" ]; then QT_CONFIG="$QT_CONFIG no-gui" -else - QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_GUI" fi -- cgit v1.2.3 From d4db23eb4d9113338ead0ed5f1c5b788681d8f43 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 9 Mar 2012 19:11:54 +0100 Subject: another attempt at solving the popping up of .qmake.cache problem syncqt may generate that file also as a result of configure tests. so just check for the file's existence instead of trying to reproduce under which circumstances it should appear. Change-Id: Ia24f96b05fc70e104f7be19d08cea614ffb505be Reviewed-by: Marius Storm-Olsen --- mkspecs/features/default_pre.prf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkspecs/features/default_pre.prf b/mkspecs/features/default_pre.prf index 5d8684bf00..c3776c4da5 100644 --- a/mkspecs/features/default_pre.prf +++ b/mkspecs/features/default_pre.prf @@ -48,7 +48,7 @@ CONFIG = lex yacc warn_on debug uic resources $$CONFIG } # Let qmake know about the unexpectedly appearing cache file. - contains(QTFWD, -cache-module-fwd):_QMAKE_CACHE_ = $$QMAKE_SYNCQT_OUTDIR/.qmake.cache + exists($$QMAKE_SYNCQT_OUTDIR/.qmake.cache):_QMAKE_CACHE_ = $$QMAKE_SYNCQT_OUTDIR/.qmake.cache unset(QTFWD) unset(PRO_BASENAME) -- cgit v1.2.3 From 849b760c9047a9306d5a63d7fa60d0ab2431e1dd Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Fri, 9 Mar 2012 21:27:45 +0100 Subject: Revert "QNam: only init channels when needed." This reverts commit ff25691d00d634068c6389f8f1607d7cc95ac5be. The change broke qtdeclarative. Several autotests crash because QHttpNetworkConnection::transparentProxy() calls proxy() on a null socket. Task-number: QTBUG-24717 Change-Id: I57e3ccf5d20683f59cf7450083d1fcb3fa1c40fe Reviewed-by: Kent Hansen --- src/network/access/qhttpnetworkconnection.cpp | 106 +++++++++------------ .../access/qhttpnetworkconnectionchannel.cpp | 67 +------------ .../access/qhttpnetworkconnectionchannel_p.h | 11 --- 3 files changed, 46 insertions(+), 138 deletions(-) diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 890072eb7e..6aa3a5a5f4 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -123,8 +123,8 @@ void QHttpNetworkConnectionPrivate::init() //push session down to channels channels[i].networkSession = networkSession; #endif + channels[i].init(); } - delayedConnectionTimer.setSingleShot(true); QObject::connect(&delayedConnectionTimer, SIGNAL(timeout()), q, SLOT(_q_connectDelayedChannel())); } @@ -135,14 +135,12 @@ void QHttpNetworkConnectionPrivate::pauseConnection() // Disable all socket notifiers for (int i = 0; i < channelCount; i++) { - if (channels[i].socket) { #ifndef QT_NO_SSL - if (encrypt) - QSslSocketPrivate::pauseSocketNotifiers(static_cast(channels[i].socket)); - else + if (encrypt) + QSslSocketPrivate::pauseSocketNotifiers(static_cast(channels[i].socket)); + else #endif - QAbstractSocketPrivate::pauseSocketNotifiers(channels[i].socket); - } + QAbstractSocketPrivate::pauseSocketNotifiers(channels[i].socket); } } @@ -151,18 +149,16 @@ void QHttpNetworkConnectionPrivate::resumeConnection() state = RunningState; // Enable all socket notifiers for (int i = 0; i < channelCount; i++) { - if (channels[i].socket) { #ifndef QT_NO_SSL - if (encrypt) - QSslSocketPrivate::resumeSocketNotifiers(static_cast(channels[i].socket)); - else + if (encrypt) + QSslSocketPrivate::resumeSocketNotifiers(static_cast(channels[i].socket)); + else #endif - QAbstractSocketPrivate::resumeSocketNotifiers(channels[i].socket); + QAbstractSocketPrivate::resumeSocketNotifiers(channels[i].socket); - // Resume pending upload if needed - if (channels[i].state == QHttpNetworkConnectionChannel::WritingState) - QMetaObject::invokeMethod(&channels[i], "_q_uploadDataReadyRead", Qt::QueuedConnection); - } + // Resume pending upload if needed + if (channels[i].state == QHttpNetworkConnectionChannel::WritingState) + QMetaObject::invokeMethod(&channels[i], "_q_uploadDataReadyRead", Qt::QueuedConnection); } // queue _q_startNextRequest @@ -350,15 +346,11 @@ void QHttpNetworkConnectionPrivate::emitReplyError(QAbstractSocket *socket, QNetworkReply::NetworkError errorCode) { Q_Q(QHttpNetworkConnection); - - int i = 0; - if (socket) - i = indexOf(socket); - - if (reply) { + if (socket && reply) { // this error matters only to this reply reply->d_func()->errorString = errorDetail(errorCode, socket); emit reply->finishedWithError(errorCode, reply->d_func()->errorString); + int i = indexOf(socket); // remove the corrupt data if any reply->d_func()->eraseData(); @@ -366,8 +358,7 @@ void QHttpNetworkConnectionPrivate::emitReplyError(QAbstractSocket *socket, channels[i].close(); channels[i].reply = 0; channels[i].request = QHttpNetworkRequest(); - if (socket) - channels[i].requeueCurrentlyPipelinedRequests(); + channels[i].requeueCurrentlyPipelinedRequests(); // send the next request QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection); @@ -591,9 +582,9 @@ void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair) bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket) { - int i = 0; - if (socket) - i = indexOf(socket); + Q_ASSERT(socket); + + int i = indexOf(socket); if (!highPriorityQueue.isEmpty()) { // remove from queue before sendRequest! else we might pipeline the same request again @@ -749,15 +740,15 @@ bool QHttpNetworkConnectionPrivate::fillPipeline(QList &queue, } -QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket, const QString &extraDetail) +QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket* socket, + const QString &extraDetail) { + Q_ASSERT(socket); + QString errorString; switch (errorCode) { case QNetworkReply::HostNotFoundError: - if (socket) - errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(socket->peerName()); - else - errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(hostName); + errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(socket->peerName()); break; case QNetworkReply::ConnectionRefusedError: errorString = QCoreApplication::translate("QHttp", "Connection refused"); @@ -900,11 +891,9 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() return; // try to get a free AND connected socket for (int i = 0; i < channelCount; ++i) { - if (channels[i].socket) { - if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) { - if (dequeueRequest(channels[i].socket)) - channels[i].sendRequest(); - } + if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) { + if (dequeueRequest(channels[i].socket)) + channels[i].sendRequest(); } } @@ -919,7 +908,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty()) return; for (int i = 0; i < channelCount; i++) - if (channels[i].socket && channels[i].socket->state() == QAbstractSocket::ConnectedState) + if (channels[i].socket->state() == QAbstractSocket::ConnectedState) fillPipeline(channels[i].socket); // If there is not already any connected channels we need to connect a new one. @@ -927,19 +916,11 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() // connected or not. This is to reuse connected channels before we connect new once. int queuedRequest = highPriorityQueue.count() + lowPriorityQueue.count(); for (int i = 0; i < channelCount; ++i) { - bool connectChannel = false; - if (channels[i].socket) { - if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) || (channels[i].socket->state() == QAbstractSocket::HostLookupState)) - queuedRequest--; - if ( queuedRequest <=0 ) - break; - if (!channels[i].reply && !channels[i].isSocketBusy() && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) - connectChannel = true; - } else { // not previously used channel - connectChannel = true; - } - - if (connectChannel) { + if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) || (channels[i].socket->state() == QAbstractSocket::HostLookupState)) + queuedRequest--; + if ( queuedRequest <=0 ) + break; + if (!channels[i].reply && !channels[i].isSocketBusy() && (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) { if (networkLayerState == IPv4) channels[i].networkLayerPreference = QAbstractSocket::IPv4Protocol; else if (networkLayerState == IPv6) @@ -947,9 +928,6 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() channels[i].ensureConnection(); queuedRequest--; } - - if ( queuedRequest <=0 ) - break; } } @@ -980,8 +958,8 @@ void QHttpNetworkConnectionPrivate::startHostInfoLookup() #ifndef QT_NO_NETWORKPROXY if (networkProxy.capabilities() & QNetworkProxy::HostNameLookupCapability) { lookupHost = networkProxy.hostName(); - } else if (channels[0].proxy.capabilities() & QNetworkProxy::HostNameLookupCapability) { - lookupHost = channels[0].proxy.hostName(); + } else if (channels[0].socket->proxy().capabilities() & QNetworkProxy::HostNameLookupCapability) { + lookupHost = channels[0].socket->proxy().hostName(); } #endif QHostAddress temp; @@ -1191,7 +1169,7 @@ void QHttpNetworkConnection::setTransparentProxy(const QNetworkProxy &networkPro { Q_D(QHttpNetworkConnection); for (int i = 0; i < d->channelCount; ++i) - d->channels[i].setProxy(networkProxy); + d->channels[i].socket->setProxy(networkProxy); } QNetworkProxy QHttpNetworkConnection::transparentProxy() const @@ -1212,7 +1190,7 @@ void QHttpNetworkConnection::setSslConfiguration(const QSslConfiguration &config // set the config on all channels for (int i = 0; i < d->channelCount; ++i) - d->channels[i].setSslConfiguration(config); + static_cast(d->channels[i].socket)->setSslConfiguration(config); } void QHttpNetworkConnection::ignoreSslErrors(int channel) @@ -1223,11 +1201,13 @@ void QHttpNetworkConnection::ignoreSslErrors(int channel) if (channel == -1) { // ignore for all channels for (int i = 0; i < d->channelCount; ++i) { - d->channels[i].ignoreSslErrors(); + static_cast(d->channels[i].socket)->ignoreSslErrors(); + d->channels[i].ignoreAllSslErrors = true; } } else { - d->channels[channel].ignoreSslErrors(); + static_cast(d->channels[channel].socket)->ignoreSslErrors(); + d->channels[channel].ignoreAllSslErrors = true; } } @@ -1239,11 +1219,13 @@ void QHttpNetworkConnection::ignoreSslErrors(const QList &errors, int if (channel == -1) { // ignore for all channels for (int i = 0; i < d->channelCount; ++i) { - d->channels[i].ignoreSslErrors(errors); + static_cast(d->channels[i].socket)->ignoreSslErrors(errors); + d->channels[i].ignoreSslErrorsList = errors; } } else { - d->channels[channel].ignoreSslErrors(errors); + static_cast(d->channels[channel].socket)->ignoreSslErrors(errors); + d->channels[channel].ignoreSslErrorsList = errors; } } diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index a009222bd5..3991bffa47 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -65,7 +65,6 @@ QT_BEGIN_NAMESPACE QHttpNetworkConnectionChannel::QHttpNetworkConnectionChannel() : socket(0) , ssl(false) - , isInitialized(false) , state(IdleState) , reply(0) , written(0) @@ -153,38 +152,19 @@ void QHttpNetworkConnectionChannel::init() QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)), this, SLOT(_q_encryptedBytesWritten(qint64)), Qt::DirectConnection); - - if (ignoreAllSslErrors) - sslSocket->ignoreSslErrors(); - - if (!ignoreSslErrorsList.isEmpty()) - sslSocket->ignoreSslErrors(ignoreSslErrorsList); - - if (!sslConfiguration.isNull()) - sslSocket->setSslConfiguration(sslConfiguration); } - #endif - -#ifndef QT_NO_NETWORKPROXY - if (proxy.type() != QNetworkProxy::NoProxy) - socket->setProxy(proxy); -#endif - isInitialized = true; } void QHttpNetworkConnectionChannel::close() { - if (!socket) - state = QHttpNetworkConnectionChannel::IdleState; - else if (socket->state() == QAbstractSocket::UnconnectedState) + if (socket->state() == QAbstractSocket::UnconnectedState) state = QHttpNetworkConnectionChannel::IdleState; else state = QHttpNetworkConnectionChannel::ClosingState; - if (socket) - socket->close(); + socket->close(); } @@ -547,9 +527,6 @@ void QHttpNetworkConnectionChannel::handleUnexpectedEOF() bool QHttpNetworkConnectionChannel::ensureConnection() { - if (!isInitialized) - init(); - QAbstractSocket::SocketState socketState = socket->state(); // resend this request after we receive the disconnected signal @@ -858,46 +835,6 @@ bool QHttpNetworkConnectionChannel::resetUploadData() } } -#ifndef QT_NO_NETWORKPROXY - -void QHttpNetworkConnectionChannel::setProxy(const QNetworkProxy &networkProxy) -{ - if (socket) - socket->setProxy(networkProxy); - - proxy = networkProxy; -} - -#endif - -#ifndef QT_NO_SSL - -void QHttpNetworkConnectionChannel::ignoreSslErrors() -{ - if (socket) - static_cast(socket)->ignoreSslErrors(); - - ignoreAllSslErrors = true; -} - - -void QHttpNetworkConnectionChannel::ignoreSslErrors(const QList &errors) -{ - if (socket) - static_cast(socket)->ignoreSslErrors(errors); - - ignoreSslErrorsList = errors; -} - -void QHttpNetworkConnectionChannel::setSslConfiguration(const QSslConfiguration &config) -{ - if (socket) - static_cast(socket)->setSslConfiguration(config); - - sslConfiguration = config; -} - -#endif void QHttpNetworkConnectionChannel::pipelineInto(HttpMessagePair &pair) { diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 2648cba2a5..7da9b514d6 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -72,7 +72,6 @@ #ifndef QT_NO_SSL # include # include -# include #else # include #endif @@ -101,7 +100,6 @@ public: }; QAbstractSocket *socket; bool ssl; - bool isInitialized; ChannelState state; QHttpNetworkRequest request; // current request QHttpNetworkReply *reply; // current reply for this request @@ -120,10 +118,6 @@ public: #ifndef QT_NO_SSL bool ignoreAllSslErrors; QList ignoreSslErrorsList; - QSslConfiguration sslConfiguration; - void ignoreSslErrors(); - void ignoreSslErrors(const QList &errors); - void setSslConfiguration(const QSslConfiguration &config); #endif #ifndef QT_NO_BEARERMANAGEMENT QSharedPointer networkSession; @@ -150,11 +144,6 @@ public: void setConnection(QHttpNetworkConnection *c); QPointer connection; -#ifndef QT_NO_NETWORKPROXY - QNetworkProxy proxy; - void setProxy(const QNetworkProxy &networkProxy); -#endif - void init(); void close(); -- cgit v1.2.3 From f744b82344ffd4f5719dcab57c4074179448e170 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 24 Feb 2012 20:00:08 +0100 Subject: fix the check for libraries having themselves as dependencies Change-Id: I6dc56228a068fe9158e989afd1c545a3d69848e6 Reviewed-by: Joerg Bornemann Reviewed-by: Marius Storm-Olsen --- mkspecs/features/qt.prf | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf index f5ee74cf86..f71afbb04e 100644 --- a/mkspecs/features/qt.prf +++ b/mkspecs/features/qt.prf @@ -168,12 +168,13 @@ for(QTLIB, QT) { QT = $$resolve_depends(NEWQT, "QT.") # Finally actually add the modules for(QTLIB, QT) { - isEmpty(QT.$${QTLIB}.name) { + QTLIBNAME = $$eval(QT.$${QTLIB}.name) + isEmpty(QTLIBNAME) { message("Warning: unknown QT module: $$QTLIB") next() } - target_qt:isEqual(TARGET, QTLIB) { + target_qt:isEqual(TARGET, $$QTLIBNAME) { warning($$TARGET cannot have a QT of $$QTLIB) next() } -- cgit v1.2.3 From bcf8c6984a3bce9ed5b09cb51739617c910a46a2 Mon Sep 17 00:00:00 2001 From: ABBAPOH Date: Sun, 26 Feb 2012 15:17:59 +0400 Subject: Fix commas according to qt coding style Change-Id: Ibf49f1c3d426917d1cfcb382c8ed2771d43d6e99 Reviewed-by: David Faure --- src/corelib/mimetypes/qmimetype.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp index 6cbd938be3..e537ee0efb 100644 --- a/src/corelib/mimetypes/qmimetype.cpp +++ b/src/corelib/mimetypes/qmimetype.cpp @@ -67,12 +67,12 @@ QMimeTypePrivate::QMimeTypePrivate() {} QMimeTypePrivate::QMimeTypePrivate(const QMimeType &other) - : name(other.d->name) - //, comment(other.d->comment) - , localeComments(other.d->localeComments) - , genericIconName(other.d->genericIconName) - , iconName(other.d->iconName) - , globPatterns(other.d->globPatterns) + : name(other.d->name), + // comment(other.d->comment), + localeComments(other.d->localeComments), + genericIconName(other.d->genericIconName), + iconName(other.d->iconName), + globPatterns(other.d->globPatterns) {} void QMimeTypePrivate::clear() -- cgit v1.2.3 From 7a1a0fc76b7a60483e8ef728102d10d39f0c7a23 Mon Sep 17 00:00:00 2001 From: ABBAPOH Date: Sun, 26 Feb 2012 15:19:00 +0400 Subject: Remove commented 'comment' Change-Id: I996a34fb2dc91da8b68039b4bc797a255c99d2e0 Reviewed-by: David Faure --- src/corelib/mimetypes/qmimetype.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp index e537ee0efb..ebf687bb4b 100644 --- a/src/corelib/mimetypes/qmimetype.cpp +++ b/src/corelib/mimetypes/qmimetype.cpp @@ -68,7 +68,6 @@ QMimeTypePrivate::QMimeTypePrivate() QMimeTypePrivate::QMimeTypePrivate(const QMimeType &other) : name(other.d->name), - // comment(other.d->comment), localeComments(other.d->localeComments), genericIconName(other.d->genericIconName), iconName(other.d->iconName), @@ -78,7 +77,6 @@ QMimeTypePrivate::QMimeTypePrivate(const QMimeType &other) void QMimeTypePrivate::clear() { name.clear(); - //comment.clear(); localeComments.clear(); genericIconName.clear(); iconName.clear(); @@ -93,7 +91,6 @@ bool QMimeTypePrivate::operator==(const QMimeTypePrivate &other) const { DBG(); if (name == other.name && - //comment == other.comment && localeComments == other.localeComments && genericIconName == other.genericIconName && iconName == other.iconName && -- cgit v1.2.3 From bc3a6c75f84f36e8323e0576f1323a183c20d009 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 8 Mar 2012 10:28:56 +0100 Subject: byteorder: Fix compilation for MIPS and GCC < 4.6. Use the pre-processor macros to detect the byte order. This is how it is done for ARM and other platforms. Use the variant of the macro with the most underscores to match our ARM detection. Change-Id: I7d2b34bf45a7f3979b44a1fe2e95f678152a5dcd Reviewed-by: Bradley T. Hughes --- src/corelib/global/qprocessordetection.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/corelib/global/qprocessordetection.h b/src/corelib/global/qprocessordetection.h index 6231dae5dc..d62794e706 100644 --- a/src/corelib/global/qprocessordetection.h +++ b/src/corelib/global/qprocessordetection.h @@ -188,7 +188,13 @@ # if defined(_MIPS_ARCH_MIPS64) || defined(__mips64) # define Q_PROCESSOR_MIPS_64 # endif +# if defined(__MIPSEL__) +# define Q_BYTE_ORDER Q_LITTLE_ENDIAN +# elif defined(__MIPSEB__) +# define Q_BYTE_ORDER Q_BIG_ENDIAN +# else // Q_BYTE_ORDER not defined, use endianness auto-detection +# endif /* Power family, known variants: 32- and 64-bit -- cgit v1.2.3 From 11eed81ae9913b4aa2d7e4060c3421158d79881b Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 8 Mar 2012 11:57:34 +0100 Subject: qdoc3: qdoc user manual update Changed \bold to \b, \i to \e, and \o to \li. Task-number: QTBUG-24578 Change-Id: If02517164f30f05436596224c1b1895a86d9e9f8 Reviewed-by: Casper van Donderen --- src/tools/qdoc/doc/config/compat.qdocconf | 19 - .../qdoc/doc/examples/componentset/ProgressBar.qml | 4 +- src/tools/qdoc/doc/examples/examples.qdoc | 6 +- .../qdoc/doc/examples/layoutmanagement.qdocinc | 8 +- src/tools/qdoc/doc/examples/mainwindow.cpp | 251 ++++ src/tools/qdoc/doc/examples/minimum.qdocconf | 4 - src/tools/qdoc/doc/examples/samples.qdocinc | 8 +- src/tools/qdoc/doc/qdoc-guide.qdoc | 173 +-- src/tools/qdoc/doc/qdoc-manual.qdoc | 1392 ++++++++++---------- 9 files changed, 1048 insertions(+), 817 deletions(-) create mode 100644 src/tools/qdoc/doc/examples/mainwindow.cpp diff --git a/src/tools/qdoc/doc/config/compat.qdocconf b/src/tools/qdoc/doc/config/compat.qdocconf index 0b59629ec3..3e7ea6c891 100644 --- a/src/tools/qdoc/doc/config/compat.qdocconf +++ b/src/tools/qdoc/doc/config/compat.qdocconf @@ -1,28 +1,9 @@ -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" diff --git a/src/tools/qdoc/doc/examples/componentset/ProgressBar.qml b/src/tools/qdoc/doc/examples/componentset/ProgressBar.qml index fc6d6a644f..5255e864ac 100644 --- a/src/tools/qdoc/doc/examples/componentset/ProgressBar.qml +++ b/src/tools/qdoc/doc/examples/componentset/ProgressBar.qml @@ -83,12 +83,12 @@ Item { QDoc will not publish the documentation within omit and endomit. \endomit - \sa secondcolor + \sa secondColor */ property alias color: gradient1.color /*! - \qmlproperty color ProgressBar::secondcolor + \qmlproperty color ProgressBar::secondColor The second color of the ProgressBar's gradient. Must bind to a color type. diff --git a/src/tools/qdoc/doc/examples/examples.qdoc b/src/tools/qdoc/doc/examples/examples.qdoc index 69ea11afe6..800589b9ac 100644 --- a/src/tools/qdoc/doc/examples/examples.qdoc +++ b/src/tools/qdoc/doc/examples/examples.qdoc @@ -34,12 +34,12 @@ 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. + \l{UI Components} module. The \l{componentset/uicomponents.qdoc}{uicomponents.qdoc} file generates - the overview page for the \l {UI Components} module page. + the overview page for the \l{UI Components} module page. - The generated documentation is available in the \l {UI Components} module. + The generated documentation is available in the \l{UI Components} module. \section1 QML Class diff --git a/src/tools/qdoc/doc/examples/layoutmanagement.qdocinc b/src/tools/qdoc/doc/examples/layoutmanagement.qdocinc index 01f8acf363..780b03c8ff 100644 --- a/src/tools/qdoc/doc/examples/layoutmanagement.qdocinc +++ b/src/tools/qdoc/doc/examples/layoutmanagement.qdocinc @@ -6,8 +6,8 @@ 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 ... + \li Positioning of child widgets. + \li Sensible default sizes for windows. + \li Sensible minimum sizes for windows. + \li ... \endlist diff --git a/src/tools/qdoc/doc/examples/mainwindow.cpp b/src/tools/qdoc/doc/examples/mainwindow.cpp new file mode 100644 index 0000000000..4892d65e90 --- /dev/null +++ b/src/tools/qdoc/doc/examples/mainwindow.cpp @@ -0,0 +1,251 @@ +/**************************************************************************** +** +** 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 + +#include "mainwindow.h" +#include "scribblearea.h" + +//! [0] +MainWindow::MainWindow() +{ + scribbleArea = new ScribbleArea; + setCentralWidget(scribbleArea); + + createActions(); + createMenus(); + + setWindowTitle(tr("Scribble")); + resize(500, 500); +} +//! [0] + +//! [1] +void MainWindow::closeEvent(QCloseEvent *event) +//! [1] //! [2] +{ + if (maybeSave()) { + event->accept(); + } else { + event->ignore(); + } +} +//! [2] + +//! [3] +void MainWindow::open() +//! [3] //! [4] +{ + if (maybeSave()) { + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open File"), QDir::currentPath()); + if (!fileName.isEmpty()) + scribbleArea->openImage(fileName); + } +} +//! [4] + +//! [5] +void MainWindow::save() +//! [5] //! [6] +{ + QAction *action = qobject_cast(sender()); + QByteArray fileFormat = action->data().toByteArray(); + saveFile(fileFormat); +} +//! [6] + +//! [7] +void MainWindow::penColor() +//! [7] //! [8] +{ + QColor newColor = QColorDialog::getColor(scribbleArea->penColor()); + if (newColor.isValid()) + scribbleArea->setPenColor(newColor); +} +//! [8] + +//! [9] +void MainWindow::penWidth() +//! [9] //! [10] +{ + bool ok; + int newWidth = QInputDialog::getInteger(this, tr("Scribble"), + tr("Select pen width:"), + scribbleArea->penWidth(), + 1, 50, 1, &ok); + if (ok) + scribbleArea->setPenWidth(newWidth); +} +//! [10] + +//! [11] +void MainWindow::about() +//! [11] //! [12] +{ + QMessageBox::about(this, tr("About Scribble"), + tr("

    The Scribble example shows how to use QMainWindow as the " + "base widget for an application, and how to reimplement some of " + "QWidget's event handlers to receive the events generated for " + "the application's widgets:

    We reimplement the mouse event " + "handlers to facilitate drawing, the paint event handler to " + "update the application and the resize event handler to optimize " + "the application's appearance. In addition we reimplement the " + "close event handler to intercept the close events before " + "terminating the application.

    The example also demonstrates " + "how to use QPainter to draw an image in real time, as well as " + "to repaint widgets.

    ")); +} +//! [12] + +//! [13] +void MainWindow::createActions() +//! [13] //! [14] +{ + openAct = new QAction(tr("&Open..."), this); + openAct->setShortcuts(QKeySequence::Open); + connect(openAct, SIGNAL(triggered()), this, SLOT(open())); + + foreach (QByteArray format, QImageWriter::supportedImageFormats()) { + QString text = tr("%1...").arg(QString(format).toUpper()); + + QAction *action = new QAction(text, this); + action->setData(format); + connect(action, SIGNAL(triggered()), this, SLOT(save())); + saveAsActs.append(action); + } + + printAct = new QAction(tr("&Print..."), this); + connect(printAct, SIGNAL(triggered()), scribbleArea, SLOT(print())); + + exitAct = new QAction(tr("E&xit"), this); + exitAct->setShortcuts(QKeySequence::Quit); + connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); + + penColorAct = new QAction(tr("&Pen Color..."), this); + connect(penColorAct, SIGNAL(triggered()), this, SLOT(penColor())); + + penWidthAct = new QAction(tr("Pen &Width..."), this); + connect(penWidthAct, SIGNAL(triggered()), this, SLOT(penWidth())); + + clearScreenAct = new QAction(tr("&Clear Screen"), this); + clearScreenAct->setShortcut(tr("Ctrl+L")); + connect(clearScreenAct, SIGNAL(triggered()), + scribbleArea, SLOT(clearImage())); + + aboutAct = new QAction(tr("&About"), this); + connect(aboutAct, SIGNAL(triggered()), this, SLOT(about())); + + aboutQtAct = new QAction(tr("About &Qt"), this); + connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); +} +//! [14] + +//! [15] +void MainWindow::createMenus() +//! [15] //! [16] +{ + saveAsMenu = new QMenu(tr("&Save As"), this); + foreach (QAction *action, saveAsActs) + saveAsMenu->addAction(action); + + fileMenu = new QMenu(tr("&File"), this); + fileMenu->addAction(openAct); + fileMenu->addMenu(saveAsMenu); + fileMenu->addAction(printAct); + fileMenu->addSeparator(); + fileMenu->addAction(exitAct); + + optionMenu = new QMenu(tr("&Options"), this); + optionMenu->addAction(penColorAct); + optionMenu->addAction(penWidthAct); + optionMenu->addSeparator(); + optionMenu->addAction(clearScreenAct); + + helpMenu = new QMenu(tr("&Help"), this); + helpMenu->addAction(aboutAct); + helpMenu->addAction(aboutQtAct); + + menuBar()->addMenu(fileMenu); + menuBar()->addMenu(optionMenu); + menuBar()->addMenu(helpMenu); +} +//! [16] + +//! [17] +bool MainWindow::maybeSave() +//! [17] //! [18] +{ + if (scribbleArea->isModified()) { + QMessageBox::StandardButton ret; + ret = QMessageBox::warning(this, tr("Scribble"), + tr("The image has been modified.\n" + "Do you want to save your changes?"), + QMessageBox::Save | QMessageBox::Discard + | QMessageBox::Cancel); + if (ret == QMessageBox::Save) { + return saveFile("png"); + } else if (ret == QMessageBox::Cancel) { + return false; + } + } + return true; +} +//! [18] + +//! [19] +bool MainWindow::saveFile(const QByteArray &fileFormat) +//! [19] //! [20] +{ + QString initialPath = QDir::currentPath() + "/untitled." + fileFormat; + + QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), + initialPath, + tr("%1 Files (*.%2);;All Files (*)") + .arg(QString(fileFormat.toUpper())) + .arg(QString(fileFormat))); + if (fileName.isEmpty()) { + return false; + } else { + return scribbleArea->saveImage(fileName, fileFormat); + } +} +//! [20] diff --git a/src/tools/qdoc/doc/examples/minimum.qdocconf b/src/tools/qdoc/doc/examples/minimum.qdocconf index 1dcff501c0..e360685f1d 100644 --- a/src/tools/qdoc/doc/examples/minimum.qdocconf +++ b/src/tools/qdoc/doc/examples/minimum.qdocconf @@ -36,7 +36,3 @@ exampledirs = . # directories containing the images used in the documentation. imagedirs = ./images - - - - diff --git a/src/tools/qdoc/doc/examples/samples.qdocinc b/src/tools/qdoc/doc/examples/samples.qdocinc index 58213210f2..b08302dd08 100644 --- a/src/tools/qdoc/doc/examples/samples.qdocinc +++ b/src/tools/qdoc/doc/examples/samples.qdocinc @@ -39,7 +39,7 @@ 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. + \b{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. @@ -65,9 +65,9 @@ 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 + \li \c qdoc binary + \li \c qdocconf configuration files + \li \c Documentation in \c C++, \c QML, and \c .qdoc files \endlist */ //! [sample-page] diff --git a/src/tools/qdoc/doc/qdoc-guide.qdoc b/src/tools/qdoc/doc/qdoc-guide.qdoc index 704e03b7c7..c3b37822fb 100644 --- a/src/tools/qdoc/doc/qdoc-guide.qdoc +++ b/src/tools/qdoc/doc/qdoc-guide.qdoc @@ -39,9 +39,9 @@ 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 + \li \c QDoc binary + \li \c qdocconf configuration files + \li \c Documentation in \c C++, \c QML, and \c .qdoc files \endlist This section intends to cover the basic necessities for creating a @@ -55,11 +55,11 @@ \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} + \li \l{Creating QDoc Configuration Files} + \li \l{Writing Documentation} + \li \l{Categories of Documentation} + \li \l{Configuration File Example} + \li \l{QML Documentation Example} \endlist */ @@ -236,9 +236,6 @@ 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 @@ -296,21 +293,21 @@ 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. + \li \l{enum-command}{\\enum} - for enumeration documentation + \li \l{class-command}{\\class} - for C++ class documentation + \li \l{qmlclass-command}{\\qmlclass} - for QML component documentation + \li \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 + \li \c howto + \li \c overview + \li \c tutorial + \li \c faq + \li \c article - \e default when there is no type \endlist \snippet examples/samples.qdocinc sample-faq @@ -338,12 +335,12 @@ \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. + QDoc can do \e markup of text similar to other markup or + documentation tools. QDoc can mark a section of text in \b{bold}, + when the text is marked up with the \l{b-command}{\\b} command. \code - \bold{This} text will be in \bold{bold}. + \b{This} text will be in \b{bold}. \endcode The \l{Markup Commands} page has a full listing of the available markup @@ -355,15 +352,15 @@ ingredients present. \list - \o Assign a topic to a QDoc comment - A comment could be a page, a + \li 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 + \li 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 + \li Mark sections of the document with \l{Markup Commands}{markup commands} - QDoc can create layouts and format the documentation for the documentation. \endlist @@ -408,14 +405,14 @@ 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 + \li How-To's + \li Tutorial + \li Overview + \li Article + \li FAQ (Frequently Asked Questions) + \li C++ API Documentation + \li QML Component Documentation + \li Code Example \endlist QDoc has the ability to format a page depending on the type. Further, @@ -453,42 +450,64 @@ 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} + \li \l{qmlattachedproperty-command}{\\qmlattachedproperty} + \li \l{qmlattachedsignal-command}{\\qmlattachedsignal} + \li \l{qmlbasictype-command}{\\qmlbasictype} + \li \l{qmlclass-command}{\\qmlclass} - creates a QML component documentation + \li \l{qmlmethod-command}{\\qmlmethod} + \li \l{qmlproperty-command}{\\qmlproperty} + \li \l{qmlsignal-command}{\\qmlsignal} + \li \l{inherits-command}{\\inherits} + \li \l{qmlmodule-command}{\\qmlmodule} + \li \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. + To document a QML type, start by creating a QDoc comment that uses the + \l{qmlclass-command} {\\qmlclass} command as its topic command. \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. + If your QML type is defined in a \e qml file, document it there. + If your QML type is represented by a C++ class, document it in the + \e cpp file for that C++ class. Don't document a QML type in a + \e{cpp} file if the QML type is defined in a \e{qml} file. + + When documenting a QML type in a \e{qml} file, place each QDoc + comment directly above the entity to which the comment applies. + For example, place the QDoc comment containing the \e{\\qmlclass} + command (the topic comment) directly above the outer QML type in + the \e{qml} file. Place the comment for documenting a QML property + directly above the property declaration, and so on for QML signal + handlers and QML methods. Note that when documenting QML + properties in a \e{qml} file, you don't normally include the + \e{\\qmlproperty} command as a topic command (which you must do + when documenting QML types in \e{cpp} files), because the QML + parser automatically associates each QDoc comment with the next + QML declaration it parses. The same is true for QML signal handler + and QML method comments. But it is sometimes useful to include one + or more \e{\\qmlproperty} commands in the comment, e.g. when the + property type is another QML type and you want the user to only + use certain properties within that other QML type, but not all of + them. But when documenting a property that has an alias, place the + QDoc comment for it directly above the alias declaration. In these + cases, the QDoc comment \e must contain a \e{\\qmlproperty} + command, because that is the only way QDoc can know the type of + the aliased property. + + When documenting a QML type in the \e cpp file of its + corresponding C++ class (if it has one), you normally place each + QDoc comment directly above the entity it documents. However, QDoc + does not use the QML parser to parse these files (the C++ parser + is used), so these QML QDoc comments can appear anywhere in the + \e{cpp} file. Note that QML QDoc comments in \e cpp files \e must + use the QML topic commands. i.e., the \l{qmlclass-command} + {\\qmlclass} command \e must appear in the QDoc comment for the + QML type, and a \l{qmlproperty-command} {\\qmlproperty} command \e + must appear in each QML property QDoc comment. \section3 QML Modules @@ -500,14 +519,14 @@ 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 + \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}. + 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. @@ -607,10 +626,10 @@ \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} + \li \l{config/compat.qdocconf} + \li \l{config/macros.qdocconf} + \li \l{config/qt-cpp-ignore.qdocconf} + \li \l{config/qt-defines.qdocconf} \endlist QDoc allows macros to help with aliasing and for inputting special HTML @@ -624,9 +643,9 @@ \section1 Project Information \list - \o \l{config/qdoc-online.qdocconf} - \o \l{config/qdoc.qdocconf} - \o \l{config/qdoc-project.qdocconf} + \li \l{config/qdoc-online.qdocconf} + \li \l{config/qdoc.qdocconf} + \li \l{config/qdoc-project.qdocconf} \endlist These configuration files dictate how QDoc will generate the project. @@ -643,10 +662,10 @@ \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} + \li \l{config/qt-html-default-styles.qdocconf} + \li \l{config/qt-html-online-styles.qdocconf} + \li \l{config/qt-html-templates-online.qdocconf} + \li \l{config/qt-html-templates.qdocconf} \endlist These files indicate which styles QDoc should use for the HTML formats. @@ -657,7 +676,7 @@ \section1 Project File \list - \o \l{config/config.pro} + \li \l{config/config.pro} \endlist Every example page (such as this one) needs a Qt project file. QDoc will diff --git a/src/tools/qdoc/doc/qdoc-manual.qdoc b/src/tools/qdoc/doc/qdoc-manual.qdoc index f3e01658fd..3e67579f2a 100644 --- a/src/tools/qdoc/doc/qdoc-manual.qdoc +++ b/src/tools/qdoc/doc/qdoc-manual.qdoc @@ -32,42 +32,42 @@ \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} + \li \l {Introduction to QDoc} + \li \l {Getting Started with QDoc} + \li \l {Command Index} + \li \l {Topic Commands} + \li \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} + \li \l {Document Navigation} + \li \l {Reporting Status} + \li \l {Thread Support} + \li \l {Relating Things} + \li \l {Grouping Things} + \li \l {Naming Things} \endlist - \o \l{Markup Commands} + \li \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} + \li \l {Text Markup} + \li \l {Document Structure} + \li \l {Including Code Inline} + \li \l {Including External Code} + \li \l {Creating Links} + \li \l {Including Images} + \li \l {Tables and Lists} + \li \l {Special Content} + \li \l {Miscellaneous} \endlist - \o \l {The QDoc Configuration File} + \li \l{Creating DITA Maps} + \li \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} + \li \l {Generic Configuration Variables} + \li \l {Creating Help Project Files} + \li \l {C++ Specific Configuration Variables} + \li \l {HTML Specific Configuration Variables} + \li \l {Supporting Derived Projects} + \li \l {qt.qdocconf} + \li \l {minimum.qdocconf} + \li \l {Generating DITA XML Output} \endlist \endlist @@ -87,7 +87,7 @@ 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.: + exclamation mark \b{!} e.g.: \code / *! @@ -185,7 +185,7 @@ {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 {/*!} . + an exclamation mark, i.e. \b {/*!} . For each qdoc comment it finds, it searches the master tree for the item where the documentation belongs. The it interprets the @@ -205,9 +205,9 @@ QDoc interprets three types of commands: \list - \o \l {Topic Commands} - \o \l {Context Commands} - \o \l {Markup Commands} + \li \l {Topic Commands} + \li \l {Context Commands} + \li \l {Markup Commands} \endlist Topic commands identify the elememt you are documenting, e.g. a C++ @@ -239,69 +239,72 @@ 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} {\\\\} + \li \l {04-qdoc-commands-textmarkup.html#a-command} {\\a} + \li \l {11-qdoc-commands-specialcontent.html#abstract-command} {\\abstract} + \li \l {12-0-qdoc-commands-miscellaneous.html#annotatedlist-command} {\\annotatedlist} + \li \l {04-qdoc-commands-textmarkup.html#b-command} {\\b} \span {class="newStuff"} {(new 5/3/2012)} + \li \l {06-qdoc-commands-includecodeinline.html#badcode-command} {\\badcode} + \li \l {04-qdoc-commands-textmarkup.html#b-command} {\\bold} {(deprecated, use \\b)} + \li \l {11-qdoc-commands-specialcontent.html#brief-command} {\\brief} + \li \l {04-qdoc-commands-textmarkup.html#c-command} {\\c} + \li \l {09-qdoc-commands-includingimages.html#caption-command} {\\caption} + \li \l {05-qdoc-commands-documentstructure.html#chapter-command} {\\chapter} + \li \l {06-qdoc-commands-includecodeinline.html#code-command} {\\code} + \li \l {07-0-qdoc-commands-includingexternalcode.html#codeline-command} {\\codeline} + \li \l {04-qdoc-commands-textmarkup.html#div-command} {\\div} + \li \l {07-0-qdoc-commands-includingexternalcode.html#dots-command} {\\dots} + \li \l {04-qdoc-commands-textmarkup.html#e-command} {\\e} \span {class="newStuff"} {(new 5/3/2012)} + \li \l {12-0-qdoc-commands-miscellaneous.html#else-command} {\\else} + \li \l {12-0-qdoc-commands-miscellaneous.html#endif-command} {\\endif} + \li \l {12-0-qdoc-commands-miscellaneous.html#expire-command} {\\expire} + \li \l {11-qdoc-commands-specialcontent.html#footnote-command} {\\footnote} + \li \l {12-0-qdoc-commands-miscellaneous.html#generatelist-command} {\\generatelist} + \li \l {10-qdoc-commands-tablesandlists.html#header-command} {\\header} + \li \l {04-qdoc-commands-textmarkup.html#e-command} {\\i} \span {class="newStuff"} {(deprecated, use \\e)} + \li \l {12-0-qdoc-commands-miscellaneous.html#if-command} {\\if} + \li \l {09-qdoc-commands-includingimages.html#image-command} {\\image} + \li \l {12-0-qdoc-commands-miscellaneous.html#include-command} {\\include} + \li \l {12-0-qdoc-commands-miscellaneous.html#include-command} {\\input} + \li \l {09-qdoc-commands-includingimages.html#inlineimage-command} {\\inlineimage} + \li \l {08-qdoc-commands-creatinglinks.html#keyword-command} {\\keyword} + \li \l {08-qdoc-commands-creatinglinks.html#l-command} {\\l} + \li \l {11-qdoc-commands-specialcontent.html#legalese-command} {\\legalese} + \li \l {10-qdoc-commands-tablesandlists.html#li-command} {\\li} \span {class="newStuff"} {(new 5/3/2012)} + \li \l {10-qdoc-commands-tablesandlists.html#list-command} {\\list} + \li \l {12-0-qdoc-commands-miscellaneous.html#meta-command} {\\meta} + \li \l {06-qdoc-commands-includecodeinline.html#newcode-command} {\\newcode} + \li \l {10-qdoc-commands-tablesandlists.html#li-command} {\\o} \span {class="newStuff"} {(deprecated, use \\li)} + \li \l {06-qdoc-commands-includecodeinline.html#oldcode-command} {\\oldcode} + \li \l {12-0-qdoc-commands-miscellaneous.html#omit-command} {\\omit} + \li \l {05-qdoc-commands-documentstructure.html#part-command} {\\part} + \li \l {07-0-qdoc-commands-includingexternalcode.html#printline-command} {\\printline} + \li \l {07-0-qdoc-commands-includingexternalcode.html#printto-command} {\\printto} + \li \l {07-0-qdoc-commands-includingexternalcode.html#printuntil-command} {\\printuntil} + \li \l {11-qdoc-commands-specialcontent.html#quotation-command} {\\quotation} + \li \l {07-0-qdoc-commands-includingexternalcode.html#quotefile-command} {\\quotefile} + \li \l {07-0-qdoc-commands-includingexternalcode.html#quotefromfile-command} {\\quotefromfile} + \li \l {12-0-qdoc-commands-miscellaneous.html#raw-command} {\\raw} + \li \l {10-qdoc-commands-tablesandlists.html#row-command} {\\row} + \li \l {08-qdoc-commands-creatinglinks.html#sa-command} {\\sa} + \li \l {05-qdoc-commands-documentstructure.html#sectionOne-command} {\\section1} + \li \l {05-qdoc-commands-documentstructure.html#sectionTwo-command} {\\section2} + \li \l {05-qdoc-commands-documentstructure.html#sectionThree-command} {\\section3} + \li \l {05-qdoc-commands-documentstructure.html#sectionFour-command} {\\section4} + \li \l {07-0-qdoc-commands-includingexternalcode.html#skipline-command} {\\skipline} + \li \l {07-0-qdoc-commands-includingexternalcode.html#skipto-command} {\\skipto} + \li \l {07-0-qdoc-commands-includingexternalcode.html#skipuntil-command} {\\skipuntil} + \li \l {07-0-qdoc-commands-includingexternalcode.html#snippet-command} {\\snippet} + \li \l {04-qdoc-commands-textmarkup.html#span-command} {\\span} + \li \l {04-qdoc-commands-textmarkup.html#sub-command} {\\sub} + \li \l {04-qdoc-commands-textmarkup.html#sup-command} {\\sup} + \li \l {10-qdoc-commands-tablesandlists.html#table-command} {\\table} + \li \l {11-qdoc-commands-specialcontent.html#tableofcontents-command} {\\tableofcontents} + \li \l {08-qdoc-commands-creatinglinks.html#target-command} {\\target} + \li \l {04-qdoc-commands-textmarkup.html#tt-command} {\\tt} + \li \l {04-qdoc-commands-textmarkup.html#underline-command} {\\underline} + \li \l {12-0-qdoc-commands-miscellaneous.html#raw-command} {\\unicode} + \li \l {11-qdoc-commands-specialcontent.html#warning-command} {\\warning} + \li \l {04-qdoc-commands-textmarkup.html#backslash-command} {\\\\} \endlist */ @@ -343,7 +346,7 @@ QDoc renders this as: \quotation - \bold {QLineEdit::QLineEdit ( const QString & + \b {QLineEdit::QLineEdit ( const QString & contents, QWidget *parent )} Constructs a line edit containing the text \a contents. @@ -453,7 +456,7 @@ Your DITA XML publishing program must then recognize the \e {outputclass} attribute value. - \note The \bold {\\div} command can be nested. + \note The \b {\\div} command can be nested. Below is an example taken from the index.qdoc file used to generate index.html for Qt 4.7: @@ -475,12 +478,12 @@ \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} + \li \l{Getting Started Guides} {Getting started} + \li \l{Installation} {Installation} + \li \l{how-to-learn-qt.html} {How to learn Qt} + \li \l{tutorials.html} {Tutorials} + \li \l{Qt Examples} {Examples} + \li \l{qt4-7-intro.html} {What's new in Qt 4.7} \endlist \enddiv \enddiv @@ -507,12 +510,12 @@ \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} + \li \l{Getting Started Guides} {Getting started} + \li \l{Installation} {Installation} + \li \l{how-to-learn-qt.html} {How to learn Qt} + \li \l{tutorials.html} {Tutorials} + \li \l{Qt Examples} {Examples} + \li \l{qt4-7-intro.html} {What's new in Qt 4.7} \endlist \enddiv \enddiv @@ -586,10 +589,10 @@ / *! 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 + \li \span {class="variableName"} {mutableComplex1} in globals.cpp at line 14 + \li \span {class="variableName"} {mutableComplex2} in globals.cpp at line 15 + \li \span {class="variableName"} {constComplex1} in globals.cpp at line 16 + \li \span {class="variableName"} {constComplex2} in globals.cpp at line 17 \endlist * / \endcode @@ -608,13 +611,13 @@ 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 + \li \span {class="variableName"} {mutableComplex1} in globals.cpp at line 14 + \li \span {class="variableName"} {mutableComplex2} in globals.cpp at line 15 + \li \span {class="variableName"} {constComplex1} in globals.cpp at line 16 + \li \span {class="variableName"} {constComplex2} in globals.cpp at line 17 \endlist - \note The \bold span command does not cause a new paragraph to be + \note The \b span command does not cause a new paragraph to be started. See also \l {div-command} {\\div}. @@ -625,7 +628,7 @@ 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 + (e.g. \l {e-command} {\\e}, \l {b-command} {\\b} and \l {underline-command} {\\underline}). \code @@ -661,43 +664,38 @@ See also \l {c-command} {\\c}. - \target bold-command - \section1 \\bold + \target b-command + \section1 \\b - The \\bold command renders its argument in bold font. + The \\b command renders its argument in bold font. This command used + to be called \\bold. \code / *! - This is regular text; \bold {this text is - rendered using the \\bold command}. + This is regular text; \b {this text is + rendered using the \\b command}. * / \endcode QDoc renders this as: \quotation - This is regular text; \bold {this text is rendered using - the \\bold command}. + This is regular text; \b {this text is rendered using + the \\b command}. \endquotation - \target i-command - \section1 \\i (italics) + \target e-command + \section1 \\e (emphasis, italics) \span {class="newStuff"} {(new 5/3/2012)} - 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}. + The \\e command renders its argument in a special font, normally italics. This + command used to be called \\i, which is now deprecated. Use \e for italics. If the argument contains spaces or other punctuation, enclose the argument in curly brackets. \code / *! - Here, we render \i {a few words} in italic. + Here, we render \e {a few words} in italic. * / \endcode @@ -708,14 +706,14 @@ \endquotation If you want to use other QDoc commands within an argument that - contains spaces, you always need to enclose the argument with + contains spaces, you always need to enclose the argument in 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")) + for example: \e QPushButton(tr("A Brand New Button")) * / \endcode @@ -1148,7 +1146,7 @@ formatting. The source code begins on a new line, rendered in the code. - \bold{Note:} Although all these commands are for rendering C++ + \b{Note:} Although all these commands are for rendering C++ code, the \l{07-0-qdoc-commands-includingexternalcode.html#snippet-command} {\\snippet} and @@ -1396,7 +1394,7 @@ 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++ + \b{Note:} Although all these commands are for rendering C++ code, the \l{07-0-qdoc-commands-includingexternalcode.html#snippet-command} {\\snippet} and @@ -1510,15 +1508,10 @@ (\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 + QDoc remembers which file it is quoting from, and the current + position in 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}. @@ -1608,7 +1601,7 @@ \code / *! - \quotefromfile widgets/scribble/mainwindow.cpp + \quotefromfile examples/mainwindow.cpp \skipto closeEvent \printuntil /^\}/ @@ -1624,7 +1617,7 @@ QDoc renders this as: \quotation - \quotefromfile widgets/scribble/mainwindow.cpp + \quotefromfile examples/mainwindow.cpp \skipto closeEvent \printuntil /^\}/ @@ -2112,35 +2105,35 @@ \list - \o \c {\l QWidget} - The name of a class documented with the \l + \li \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, + \li \c {\l QWidget::sizeHint()} - The name of a member function, documented with or without an \l {fn-command} {\\fn} command. - \o \c {\l } - The subject of a \l {headerfile-command} + \li \c {\l } - The subject of a \l {headerfile-command} {\\headerfile} command. - \o \c {\l widgets/wiggly} - The relative path used in an \l + \li \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 + \li \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 + \li \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} + \li \c {\l fontmatching} - The argument of a \l {target-command} {\\target} command. - \o \c {\l {Shared Classes}} - A keyword named in a \l + \li \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 + \li \c {\l network.html} - The file name used in a \l {page-command} {\\page} command. - \o \c {\l http://qt.nokia.com/} - A URL. + \li \c {\l http://qt.nokia.com/} - A URL. \endlist @@ -2153,7 +2146,7 @@ appear in the link, you can use the following syntax: \list - \o \c {\l {QWidget::} {sizeHint()}} + \li \c {\l {QWidget::} {sizeHint()}} \endlist QDoc renders this as: @@ -2192,10 +2185,10 @@ different syntax versions: \list - \o \c property() - \o \c setProperty() - \o \c isProperty() - \o \c hasProperty() + \li \c property() + \li \c setProperty() + \li \c isProperty() + \li \c hasProperty() \endlist The \\sa command supports the same kind of links as the \l @@ -2217,7 +2210,7 @@ QDoc renders this as: \quotation - \bold {void QWidget::addActions ( QList + \b {void QWidget::addActions ( QList \e actions )} Appends the actions \e actions to this widget's list of @@ -2259,8 +2252,8 @@ 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) + \li \c {\l {capturing parentheses}} (from within the same qdoc comment) + \li \c {\l qregexp.html#capturing-parentheses} (from elsewhere in the same document) \endlist \note The brackets in the link example are required because the @@ -2269,7 +2262,7 @@ 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} + \li \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 @@ -2352,11 +2345,6 @@ 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 @@ -2413,9 +2401,9 @@ \code / *! \list 1 - \o \inlineimage happy.gif Oh so happy! - \o \inlineimage happy.gif Oh so happy! - \o \inlineimage happy.gif Oh so happy! + \li \inlineimage happy.gif Oh so happy! + \li \inlineimage happy.gif Oh so happy! + \li \inlineimage happy.gif Oh so happy! \endlist * / \endcode @@ -2423,9 +2411,9 @@ 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! + \li \inlineimage happy.gif Oh so happy! + \li \inlineimage happy.gif Oh so happy! + \li \inlineimage happy.gif Oh so happy! \endlist Here is an example of including inline images in a table: @@ -2434,14 +2422,14 @@ / *! \table \header - \o Qt - \o Qt Creator + \li Qt + \li Qt Creator \row - \o \inlineimage happy.gif Oh so happy! - \o \inlineimage happy.gif Oh so happy! + \li \inlineimage happy.gif Oh so happy! + \li \inlineimage happy.gif Oh so happy! \row - \o \inlineimage happy.gif Oh so happy! - \o \inlineimage happy.gif Oh so happy! + \li \inlineimage happy.gif Oh so happy! + \li \inlineimage happy.gif Oh so happy! \endtable * / \endcode @@ -2511,9 +2499,9 @@ / *! \table 100% \row - \o \image windowsvista-pushbutton.png + \li \image windowsvista-pushbutton.png \caption The QPushButton widget provides a command button. - \o \image windowsvista-toolbutton.png + \li \image windowsvista-toolbutton.png \caption The QToolButton class provides a quick-access button to commands or options, usually used inside a QToolBar. \endtable @@ -2524,9 +2512,9 @@ \table 100% \row - \o \image windowsvista-pushbutton.png + \li \image windowsvista-pushbutton.png \caption The QPushButton widget provides a command button. - \o \image windowsvista-toolbutton.png + \li \image windowsvista-toolbutton.png \caption The QToolButton class provides a quick-access button to commands or options, usually used inside a QToolBar. \endtable @@ -2572,29 +2560,29 @@ 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 + \l {row-command} {\\row} command and consists of cells, each of which + starts with an \l {li-command} {\\li} command. There is also a \l {header-command} {\\header} command which is a special kind of row - with a special formatting. + that has a special format. \code / *! \table \header - \o Qt Core Feature - \o Brief Description + \li Qt Core Feature + \li Brief Description \row - \o \l {Signal and Slots} - \o Signals and slots are used for communication + \li \l {Signal and Slots} + \li Signals and slots are used for communication between objects. \row - \o \l {Layout Management} - \o The Qt layout system provides a simple + \li \l {Layout Management} + \li 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 + \li \l {Drag and Drop} + \li Drag and drop provides a simple visual mechanism which users can use to transfer information between and within applications. \endtable @@ -2648,16 +2636,16 @@ / *! \table \header - \o {3,1} This header cell spans three columns + \li {3,1} This header cell spans three columns but only one row. \row - \o {2, 1} This table cell spans two columns + \li {2, 1} This table cell spans two columns but only one row - \o {1, 2} This table cell spans only one column, + \li {1, 2} This table cell spans only one column, but two rows. \row - \o A regular table cell - \o A regular table cell + \li A regular table cell + \li A regular table cell \endtable * / \endcode @@ -2691,7 +2679,7 @@ \endraw - See also \l {header-command} {\\header}, \l {row-command} {\\row} and \l {o-command} {\\o}. + See also \l {header-command} {\\header}, \l {row-command} {\\row} and \l {li-command} {\\li}. \target header-command \section1 \\header @@ -2701,7 +2689,7 @@ 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. + cells. A cell is created with the \l {li-command} {\\li} command. A header cell's text is centered within the table cell and rendered using a bold font. @@ -2710,11 +2698,11 @@ / *! \table \header - \o Qt Core Feature - \o Brief Description + \li Qt Core Feature + \li Brief Description \row - \o \l {Signal and Slots} - \o Signals and slots are used for communication + \li \l {Signal and Slots} + \li Signals and slots are used for communication between objects. \endtable * / @@ -2741,18 +2729,18 @@ \endraw - See also \l {table-command} {\\table}, \l {row-command} {\\row} and \l {o-command} {\\o}. + See also \l {table-command} {\\table}, \l {row-command} {\\row} and \l {li-command} {\\li}. \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 + The \\row command begins a new row in a table. The \l {li-command} + {\\li 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. + cells. A cell is created with the \l {li-command} {\\li} command. The background cell color of each row alternates between two shades of grey, making it easier to distinguish the rows from each @@ -2762,20 +2750,20 @@ / *! \table \header - \o Qt Core Feature - \o Brief Description + \li Qt Core Feature + \li Brief Description \row - \o \l {Signal and Slots} - \o Signals and slots are used for communication + \li \l {Signal and Slots} + \li Signals and slots are used for communication between objects. \row - \o \l {Layout Management} - \o The Qt layout system provides a simple + \li \l {Layout Management} + \li 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 + \li \l {Drag and Drop} + \li Drag and drop provides a simple visual mechanism which users can use to transfer information between and within applications. \endtable @@ -2823,7 +2811,7 @@ \endraw See also \l {table-command} {\\table}, \l {header-command} - {\\header} and \l {o-command} {\\o}. + {\\header} and \l {li-command} {\\li}. \target value-command \section1 \\value @@ -2858,24 +2846,24 @@ The \\list and \\endlist commands delimit a list of items. - Create each list item with the \l {o-command} {\\o} command. A + Create each list item with the \l {li-command} {\\li} command. A list always contains one or more items. Lists can be nested. For example: \code / *! \list - \o Qt Reference Documentation: Getting Started + \li Qt Reference Documentation: Getting Started \list - \o How to Learn Qt - \o Installation + \li How to Learn Qt + \li Installation \list - \o Qt/X11 - \o Qt/Windows - \o Qt/Mac - \o Qt/Embedded + \li Qt/X11 + \li Qt/Windows + \li Qt/Mac + \li Qt/Embedded \endlist - \o Tutorial and Examples + \li Tutorial and Examples \endlist \endlist * / @@ -2884,17 +2872,17 @@ QDoc renders this as: \list - \o Qt Reference Documentation: Getting Started + \li Qt Reference Documentation: Getting Started \list - \o How to Learn Qt - \o Installation + \li How to Learn Qt + \li Installation \list - \o Qt/X11 - \o Qt/Windows - \o Qt/Mac - \o Qt/Embedded + \li Qt/X11 + \li Qt/Windows + \li Qt/Mac + \li Qt/Embedded \endlist - \o Tutorial and Examples + \li Tutorial and Examples \endlist \endlist @@ -2904,9 +2892,9 @@ \code / *! \list - \o How to Learn Qt - \o Installation - \o Tutorial and Examples + \li How to Learn Qt + \li Installation + \li Tutorial and Examples \endlist * / \endcode @@ -2914,9 +2902,9 @@ QDoc renders the list items with bullets (the default): \list - \o How to Learn Qt - \o Installation - \o Tutorial and Examples + \li How to Learn Qt + \li Installation + \li Tutorial and Examples \endlist \warning There appears to be a bug in qdoc3 here. If you include @@ -2927,18 +2915,18 @@ bullets are replaced with characters in alphabetical order: \list A - \o How to Learn Qt - \o Installation - \o Tutorial and Examples + \li How to Learn Qt + \li Installation + \li 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 + \li How to Learn Qt + \li Installation + \li Tutorial and Examples \endlist @@ -2946,9 +2934,9 @@ roman numerals: \list i - \o How to Learn Qt - \o Installation - \o Tutorial and Examples + \li How to Learn Qt + \li Installation + \li Tutorial and Examples \endlist Finally, you can make the list items appear with roman numbers @@ -2956,9 +2944,9 @@ argument: \list I - \o How to Learn Qt - \o Installation - \o Tutorial and Examples + \li How to Learn Qt + \li Installation + \li Tutorial and Examples \endlist You can also make the listing start at any character or number by @@ -2968,9 +2956,9 @@ \code / *! \list G - \o How to Learn Qt - \o Installation - \o Tutorial and Examples + \li How to Learn Qt + \li Installation + \li Tutorial and Examples \endlist * / \endcode @@ -2978,50 +2966,42 @@ QDoc renders this as: \list G - \o How to Learn Qt - \o Installation - \o Tutorial and Examples + \li How to Learn Qt + \li Installation + \li Tutorial and Examples \endlist - See also \l {o-command} {\\o}. - - \target o-command - \section1 \\o (cell, item) + See also \l {li-command} {\\li}. - The \\o command announce a table or list item. + \target li-command + \section1 \\li (table cell, 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. + The \\li command marks a table cell or a list item. This command + is only used in \l{table-command} {tables} and \l{list-command} + {lists}. - 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}. + It considers everything until the next \\li command, or until the + next \l {table-command} {\\endtable} or \l {list-command} {\\endlist} + command, as its argument. See \l {table-command} {\\table} and \l + {list-command} {\\list} for examples. - If the command is used within a table, you can in addition specify + If the command is used within a table, you can also specify how many rows or columns the item should span. \code / *! \table \header - \o {3,1} This header cell spans three columns + \li {3,1} This header cell spans three columns but only one row. \row - \o {2, 1} This table item spans two columns + \li {2, 1} This table item spans two columns but only one row - \o {1, 2} This table item spans only one column, + \li {1, 2} This table item spans only one column, but two rows. \row - \o A regular table item - \o A regular table item + \li A regular table item + \li A regular table item \endtable * / \endcode @@ -3058,7 +3038,7 @@ 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}. + {\\header}, and \l {list-command} {\\list}. */ @@ -3083,7 +3063,7 @@ The abstract section is rendered as an indented italicized paragraph. - \warning The \bold{\\abstract} and \bold{\\endabstract} commands + \warning The \b{\\abstract} and \b{\\endabstract} commands have not been implemented. The abstract section is rendered as a regular HTML paragraph. @@ -3093,7 +3073,7 @@ The \\quotation and \\endquotation commands delimit a long quotation. The text in the delimited block is surrounded by - \bold{
    } and \bold{
    } in the html output, + \b{
    } and \b{
    } in the html output, e.g.: \code @@ -3112,7 +3092,7 @@ * / \endcode - The text in the \bold{\\quotation} block will appear in the generated HTML as: + The text in the \b{\\quotation} block will appear in the generated HTML as: \code
    @@ -3133,12 +3113,7 @@ applications. \endquotation - But you can redefine the \bold{
    } 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. + But you can redefine the \b{
    } tag in your style.css file. \target footnote-command \section1 \\footnote @@ -3147,7 +3122,7 @@ The footnote is rendered at the bottom of the page. - \warning The \bold{\\footnote} and \bold{\\endfootnote} commands + \warning The \b{\\footnote} and \b{\\endfootnote} commands have not been implemented. The footnote is rendered as a regular HTML paragraph. @@ -3233,9 +3208,9 @@ 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 & )} + \li \b {const QRect & geometry () const} + \li \b {void setGeometry ( int x, int y, int w, int h )} + \li \b {void setGeometry ( const QRect & )} \endlist See also \l @@ -3289,8 +3264,8 @@ \endraw \list - \o 52 properties inherited from QWidget - \o 1 property inherited from QObject + \li 52 properties inherited from QWidget + \li 1 property inherited from QObject \endlist \raw HTML @@ -3298,13 +3273,13 @@ \endraw \list - \o \l {constructor} {PreviewWindow}(QWidget *parent = 0) - \o void \l {function} {setWindowFlags}(Qt::WindowFlags flags) + \li \l {constructor} {PreviewWindow}(QWidget *parent = 0) + \li void \l {function} {setWindowFlags}(Qt::WindowFlags flags) \endlist \list - \o 183 public functions inherited from QWidget - \o 28 public functions inherited from QObject + \li 183 public functions inherited from QWidget + \li 28 public functions inherited from QObject \endlist \raw HTML @@ -3312,8 +3287,8 @@ \endraw \list - \o 17 public slots inherited from QWidget - \o 1 public slot inherited from QObject + \li 17 public slots inherited from QWidget + \li 1 public slot inherited from QObject \endlist \raw HTML @@ -3321,12 +3296,12 @@ \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 + \li 1 signal inherited from QWidget + \li 1 signal inherited from QObject + \li 4 static public members inherited from QWidget + \li 4 static public members inherited from QObject + \li 39 protected functions inherited from QWidget + \li 7 protected functions inherited from QObject \endlist \target preview window @@ -3409,8 +3384,8 @@ The \\legalese and \\endlegalese commands delimit a licence agreement. - In the generated HTML, the delimited text is surrounded by a \bold - {
    } and \bold {
    } tags. + In the generated HTML, the delimited text is surrounded by a \b + {
    } and \b {
    } tags. For example, here is a license agreement enclosed in \\legalese and \\endlegalese: @@ -3506,7 +3481,7 @@ \page 12-0-qdoc-commands-miscellaneous.html \previouspage Special Content \contentspage Table of Contents - \nextpage The QDoc Configuration File + \nextpage Creating DITA Maps \title Miscellaneous @@ -3608,14 +3583,14 @@ \table \row - \o QDial - \o Rounded range control (like a speedometer or potentiometer) + \li QDial + \li Rounded range control (like a speedometer or potentiometer) \row - \o QDialog - \o The base class of dialog windows + \li QDialog + \li The base class of dialog windows \row - \o QDir - \o Access to directory structures and their contents + \li QDir + \li Access to directory structures and their contents \endtable A C++ class is documented with the \l {class-command} {\\class} @@ -3848,7 +3823,7 @@ / *! \if defined(opensourceedition) - \bold{Note:} This edition is for the development of + \b{Note:} This edition is for the development of \l{Qt Open Source Edition} {Free and Open Source} software only; see \l{Qt Commercial Editions}. @@ -4147,20 +4122,20 @@ / *! \table \row - \o Basic Widgets - \o Basic GUI widgets such as buttons, comboboxes + \li Basic Widgets + \li Basic GUI widgets such as buttons, comboboxes and scrollbars. \omit \row - \o Component Model - \o Interfaces and helper classes for the Qt + \li Component Model + \li Interfaces and helper classes for the Qt Component Model. \endomit \row - \o Database Classes - \o Database related classes, e.g. for SQL databases. + \li Database Classes + \li Database related classes, e.g. for SQL databases. \endtable * / \endcode @@ -4464,8 +4439,8 @@ \endraw \list - \o 52 properties inherited from QWidget - \o 1 property inherited from QObject + \li 52 properties inherited from QWidget + \li 1 property inherited from QObject \endlist \raw HTML @@ -4473,13 +4448,13 @@ \endraw \list - \o \l {constructor} {PreviewWindow}(QWidget *parent = 0) - \o void \l {function} {setWindowFlags}(Qt::WindowFlags flags) + \li \l {constructor} {PreviewWindow}(QWidget *parent = 0) + \li void \l {function} {setWindowFlags}(Qt::WindowFlags flags) \endlist \list - \o 183 public functions inherited from QWidget - \o 28 public functions inherited from QObject + \li 183 public functions inherited from QWidget + \li 28 public functions inherited from QObject \endlist \raw HTML @@ -4487,8 +4462,8 @@ \endraw \list - \o 17 public slots inherited from QWidget - \o 1 public slot inherited from QObject + \li 17 public slots inherited from QWidget + \li 1 public slot inherited from QObject \endlist \raw HTML @@ -4496,12 +4471,12 @@ \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 + \li 1 signal inherited from QWidget + \li 1 signal inherited from QObject + \li 4 static public members inherited from QWidget + \li 4 static public members inherited from QObject + \li 39 protected functions inherited from QWidget + \li 7 protected functions inherited from QObject \endlist \target preview window @@ -4687,11 +4662,11 @@ Files: \list - \o \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-imageviewer-cpp.html} + \li \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} + \li \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} + \li \l{http://qt.nokia.com/doc/4.0/widgets-imageviewer-main-cpp.html} {widgets/imageviewer/main.cpp} \endlist @@ -5214,19 +5189,19 @@ \list - \o faq - A frequently asked question. + \li faq - A frequently asked question. - \o howto - A user guide for how to use some component of the + \li howto - A user guide for how to use some component of the software. - \o example - A page that describes a working example. + \li example - A page that describes a working example. - \o overview - For text pages that provide an overview of some + \li overview - For text pages that provide an overview of some important subject. - \o tutorial - For text pages that are part of a tutorial. + \li tutorial - For text pages that are part of a tutorial. - \o api - This is the type of page used for C++ class references + \li 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. @@ -5309,8 +5284,8 @@ Access functions: \list - \o \bold { bool isFlat () const} - \o \bold { void setFlat ( bool )} + \li \b { bool isFlat () const} + \li \b { void setFlat ( bool )} \endlist \endquotation @@ -5343,7 +5318,7 @@ Access functions: \list - \o \bold { int width () const} + \li \b { int width () const} \endlist See also \l{QWidget::geometry} {geometry}, @@ -5490,9 +5465,9 @@ are available: \list - \o \l Rotation - \o \l Scale - \o \l Translate + \li \l Rotation + \li \l Scale + \li \l Translate \endlist The Transform elements let you create and control advanced @@ -5843,28 +5818,28 @@ 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} + \li \l {16-qdoc-commands-status.html#compat-command}{\\compat}, + \li \l {15-qdoc-commands-navigation.html#contentspage-command}{\\contentspage}, + \li \l {15-qdoc-commands-navigation.html#indexpage-command}{\\indexpage}, + \li \l {19-qdoc-commands-grouping.html#ingroup-command}{\\ingroup}, + \li \l {18-qdoc-commands-relating.html#inherits-command}{\\inherits}, + \li \l {19-qdoc-commands-grouping.html#inmodule-command}{\\inmodule}, + \li \l {16-qdoc-commands-status.html#internal-command}{\\internal}, + \li \l {19-qdoc-commands-grouping.html#mainclass-command}{\\mainclass}, + \li \l {15-qdoc-commands-navigation.html#nextpage-command}{\\nextpage}, + \li \l {17-qdoc-commands-thread.html#nonreentrant-command}{\\nonreentrant}, + \li \l {16-qdoc-commands-status.html#obsolete-command}{\\obsolete}, + \li \l {18-qdoc-commands-relating.html#overload-command}{\\overload}, + \li \l {16-qdoc-commands-status.html#preliminary-command}{\\preliminary}, + \li \l {15-qdoc-commands-navigation.html#previouspage-command}{\\previouspage}, + \li \l {17-qdoc-commands-thread.html#reentrant-command}{\\reentrant}, + \li \l {18-qdoc-commands-relating.html#reimp-command}{\\reimp}, + \li \l {18-qdoc-commands-relating.html#relates-command}{\\relates}, + \li \l {16-qdoc-commands-status.html#since-command}{\\since}, + \li \l {15-qdoc-commands-navigation.html#startpage-command}{\\startpage}, + \li \l {20-qdoc-commands-namingthings.html#subtitle-command}{\\subtitle} + \li \l {17-qdoc-commands-thread.html#threadsafe-command}{\\threadsafe}, + \li \l {20-qdoc-commands-namingthings.html#title-command}{\\title} \endlist */ @@ -5901,9 +5876,9 @@ Table of contents: \list - \o \l {Getting Started} - \o \l {Creating Dialogs} - \o \l {Creating Main Windows} + \li \l {Getting Started} + \li \l {Creating Dialogs} + \li \l {Creating Main Windows} \endlist * / @@ -5945,9 +5920,9 @@ \title Index \list - \o \l {Basic Qt} - \o \l {Creating Dialogs} - \o \l {Getting Started} + \li \l {Basic Qt} + \li \l {Creating Dialogs} + \li \l {Getting Started} \endlist * / \endcode @@ -6108,7 +6083,7 @@ reference page. \quotation - \bold {This class is part of the Qt 3 support + \b {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 @@ -6137,15 +6112,15 @@

    Qt 3 Support Members for MyClass

    \endraw - \bold {The following class members are part of the Qt 3 + \b {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 ... + \li void MyQt3SupportMemberFunction() + \li ... \endlist \raw HTML @@ -6211,15 +6186,15 @@

    Obsolete Members for MyClass

    \endraw - \bold {The following class members are obsolete.} They are + \b {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 ... + \li void MyObsoleteFunction() \c (obsolete) + \li ... \endlist \raw HTML @@ -6297,7 +6272,7 @@ QChar::joining () const \endraw - \bold {This function is under development and + \b {This function is under development and subject to change.} Returns information about the joining properties of the @@ -6310,12 +6285,12 @@ \quotation \list - \o ... - \o Joining + \li ... + \li Joining \l {http://qt.nokia.com/doc/4.0/qchar.html#Joining-enum} {joining}() const \c (preliminary) - \o ... + \li ... \endlist \endquotation @@ -6451,7 +6426,7 @@ #include \endcode - \bold {Note:} All the functions in this class are \l + \b {Note:} All the functions in this class are \l {threads.html#reentrant} {reentrant}, except \l {QLocale::setDefault()} {setDefault()}. @@ -6489,7 +6464,7 @@ 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 + included. In addition a warning, "\b Warning: This function is not reentrant.", is generated in the nonreentrant functions' documentation. @@ -6578,7 +6553,7 @@ \code / *! - \qmlclass PauseAnimation QQuickPauseAnimation + \qmlclass PauseAnimation QDeclarativePauseAnimation \ingroup qml-animation-transition \since 4.7 \inherits Animation @@ -6617,12 +6592,12 @@ 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 + marked with the \b {\\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 + parameter to the \b{\\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. @@ -6667,7 +6642,7 @@ {QWidget::addAction}(). \endquotation - If you don't include the function name with the \bold{\\overlaod} + If you don't include the function name with the \b{\\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: @@ -6937,9 +6912,146 @@ */ /*! - \page 21-0-qdoc-configuration.html + \page 21-0-qdoc-creating-dita-maps.html \previouspage Miscellaneous \contentspage Table of Contents + \nextpage The QDoc Configuration File + + \title Creating DITA Maps + + You can create DITA map files using three new qdoc commands, the \l{ditamap-command} + {ditamap} command, the \l{topicref-command} {topicref} command, and the \l{mapref-command} + {mapref} command. How these DITA maps will be used automatically or manually by the + documentation build process is still under consideration. This section will be updated + as the decisions are made. + + \section1 What is a DITA map? + + A complete description of DITA can be found at the + \l{http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=dita} + {OASIS Darwin Information Typing Architecture} site. + + An explanation of the DITA map is found at that site + \l{http://docs.oasis-open.org/dita/v1.2/os/spec/langref/map.html}{here}. + + \target ditamap-command + \section1 \\ditamap + + The \\ditamap command is for creating a DITA map using qdoc commands. + The \\ditamap command is a kind of \\page command that produces a + \e{.ditamap} instead of a \e{.html} or \e{.xml} file. The file that + is created actually contains XML text, but the \e{.ditamap} suffix is + used to identify the file as containing a DITA MAP. + + The argument is the name of the the file to be created. In the following + example, the file \e{creator.ditamap} is output: + \code + \ditamap creator.ditamap + \endcode + + \target topicref-command + \section1 \\topicref \\endtopicref + + The \\topicref \\endtopicref commands are for creating a topicref + in the ditamap. The \\endtopicref command is required because + \\topicref commands can be nested. + + \\topicref has two arguments. The first argument becomes the value + of the \e navtitle attribute. Normally, you use the title of the + topic being referenced. This title is often what will appear in a + table of contents constructed from the ditamap. + + The second argument is the name of the page being referenced. The + second argument is actually optional, for example if you are using + a topicref as a container for other topicrefs and maprefs. It is + also optional if you want qdoc to find the page name for you by + looking up the title in its internal data structure. It is recommended + that you provide the second parameter if you know the page name. + + \code + \topicref {QML Module QtQuick 2} {qtquick-2.xml} + \mapref {Creator Manual} {creator-manual.ditamap} \endmapref + \topicref {QML Mouse Events} {qtquick2-mouseevents.xml} \endtopicref + \topicref {Property Binding} {qtquick2-propertybinding.xml} \endtopicref + \endtopicref + \endcode + + \target mapref-command + \section1 \\mapref + + The \\mapref command is for creating a mapref in the ditamap. A + mapref refers to another ditamap, which you want to include in + your ditamap. Like the \\topicref command, the \\mapref command + has two arguments, but for the \\mapref command, both arguments + are required. The arguments are essentially the same as described + for \\topicref, but for \\mapref, the second command must be the + name of another ditamap, i.e. it must have the \e{.ditamap} + suffix. You must provide the file name. qdoc can't look up the + file name for you. + + \code + \mapref {Creator Manual} {creator-manual.ditamap} \endmapref + \endcode + + \section1 An example ditamap page + + The following example uses the three qdoc ditamap commands described above. + + \code + \ditamap creator.ditamap + \title The DITA Map For Creator + + \topicref {QML Module QtQuick 1} + \topicref {QML Mouse Events} \endtopicref + \topicref {Property Binding} \endtopicref + \endtopicref + + \topicref {QML Module QtQuick 2} {qtquick-2.xml} + \mapref {Creator Manual} {creator-manual.ditamap} \endmapref + \topicref {QML Mouse Events} {qtquick2-mouseevents.xml} \endtopicref + \topicref {Property Binding} {qtquick2-propertybinding.xml} \endtopicref + \endtopicref + + \topicref {QML Module QtQuick.Particles 2} {qtquick-particles-2.xml} + \topicref {Age} {qml-qtquick-particles2-age.xml} \endtopicref + \endtopicref + \endcode + + \section1 The resulting ditamap file + + This is the \e{.ditamap} file you get when you input the qdoc + ditamap page shown above. Note that you can write ditamap files + directly in XML just as easily as you can write them using the + qdoc commands. The choice is yours. + + \code + + + + + The DITA Map For Creator + + + + + + + + + + + + + + + \endcode + +*/ + +/*! + \page 21-0-qdoc-configuration.html + \previouspage Creating DITA Maps + \contentspage Table of Contents \nextpage Generic Configuration Variables \title The QDoc Configuration File @@ -6998,54 +7110,54 @@ \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} + \li \l {22-qdoc-configuration-generalvariables.html#alias-variable} {alias} + \li \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoredirectives-variable} {Cpp.ignoredirectives} + \li \l {23-qdoc-configuration-cppvariables.html#Cpp.ignoretokens-variable} {Cpp.ignoretokens} + \li \l {22-qdoc-configuration-generalvariables.html#basedir-variable} {basedir} \span {class="newStuff"} {(experimental)} + \li \l {22-qdoc-configuration-generalvariables.html#defines-variable} {defines} + \li \l {22-qdoc-configuration-generalvariables.html#edition-variable} {edition} + \li \l {22-qdoc-configuration-generalvariables.html#exampledirs-variable} {exampledirs} + \li \l {22-qdoc-configuration-generalvariables.html#examples-variable} {examples} + \li \l {22-qdoc-configuration-generalvariables.html#examples.fileextensions-variable} {examples.fileextensions} + \li \l {22-qdoc-configuration-generalvariables.html#excludedirs-variable} {excludedirs} + \li \l {22-qdoc-configuration-generalvariables.html#excludefiles-variable} {excludefiles} + \li \l {22-qdoc-configuration-generalvariables.html#extraimages-variable} {extraimages} + \li \l {22-qdoc-configuration-generalvariables.html#falsehoods-variable} {falsehoods} + \li \l {22-qdoc-configuration-generalvariables.html#headerdirs-variable} {headerdirs} + \li \l {22-qdoc-configuration-generalvariables.html#headers-variable} {headers} + \li \l {22-qdoc-configuration-generalvariables.html#headers.fileextensions-variable} {headers.fileextensions} + \li \l {24-qdoc-configuration-htmlvariables.html#HTML.footer-variable} {HTML.footer} + \li \l {24-qdoc-configuration-htmlvariables.html#HTML.postheader-variable} {HTML.postheader} + \li \l {24-qdoc-configuration-htmlvariables.html#HTML.style-variable} {HTML.style} + \li \l {22-qdoc-configuration-generalvariables.html#imagedirs-variable} {imagedirs} + \li \l {22-qdoc-configuration-generalvariables.html#images-variable} {images} + \li \l {22-qdoc-configuration-generalvariables.html#images.fileextensions-variable} {images.fileextensions} + \li \l {22-qdoc-configuration-generalvariables.html#language-variable} {language} + \li \l {22-qdoc-configuration-generalvariables.html#macro-variable} {macro} + \li \l {22-qdoc-configuration-generalvariables.html#outputdir-variable} {outputdir} + \li \l {22-qdoc-configuration-generalvariables.html#outputformats-variable} {outputformats} + \li \l {22-qdoc-configuration-generalvariables.html#sourcedirs-variable} {sourcedirs} + \li \l {22-qdoc-configuration-generalvariables.html#sources-variable} {sources} + \li \l {22-qdoc-configuration-generalvariables.html#sources.fileextensions-variable} {sources.fileextensions} + \li \l {22-qdoc-configuration-generalvariables.html#spurious-variable} {spurious} + \li \l {22-qdoc-configuration-generalvariables.html#tabsize-variable} {tabsize} + \li \l {22-qdoc-configuration-generalvariables.html#version-variable} {version} + \li \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} + \li \l {Generic Configuration Variables} + \li \l {C++ Specific Configuration Variables} + \li \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 + \li A minimum configuration file: \l minimum.qdocconf + \li The Qt configuration file: \l qt.qdocconf \endlist */ @@ -7062,7 +7174,7 @@ /*! \page 21-2-qt-qdocconf.html - \previouspage Compatibility Issues + \previouspage Supporting Derived Projects \contentspage Table of Contents \nextpage minimum.qdocconf @@ -7153,13 +7265,11 @@ temporary-command-name}. \code - alias.i = e + alias.e = i \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}. + This renames the built-in command \\e (italics) to be \\i. The \c + alias variable is often used for compatibility reasons. See also \l {macro-variable} {macro}. @@ -7176,7 +7286,7 @@ 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)} + \target basedir-variable \section1 basedir The \c basedir variable tells QDoc two things. First, the fact that @@ -7746,7 +7856,7 @@ when generating DITA XML. \code - macro.gui = "\\bold" + macro.gui = "\\b" macro.raisedaster.HTML = "*" \endcode @@ -8379,7 +8489,6 @@ \page 25-qdoc-configuration-derivedprojects.html \previouspage HTML Specific Configuration Variables \contentspage Table of Contents - \nextpage Compatibility Issues \title Supporting Derived Projects @@ -8486,8 +8595,6 @@ 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 @@ -8505,11 +8612,9 @@ \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. + contains this file. - \bold {To resolve the actual links to Qt classes, the + \b {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.} @@ -8521,134 +8626,6 @@ 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 @@ -8661,116 +8638,123 @@ \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} + \li \l {04-qdoc-commands-textmarkup.html#a-command} {\\a} + \li \l {11-qdoc-commands-specialcontent.html#abstract-command} {\\abstract} + \li \l {12-0-qdoc-commands-miscellaneous.html#annotatedlist-command} {\\annotatedlist} + \li \l {04-qdoc-commands-textmarkup.html#b-command} {\\b} \span {class="newStuff"} {(new 5/3/2012)} + \li \l { 22-qdoc-configuration-generalvariables.html#basedir-variable} {basedir} \span {class="newStuff"} {(experimental)} + \li \l {06-qdoc-commands-includecodeinline.html#badcode-command} {\\badcode} + \li \l {04-qdoc-commands-textmarkup.html#b-command} {\\bold} \span {class="newStuff"} {(deprecated, use \\b)} + \li \l {11-qdoc-commands-specialcontent.html#brief-command} {\\brief} + \li \l {04-qdoc-commands-textmarkup.html#c-command} {\\c} + \li \l {09-qdoc-commands-includingimages.html#caption-command} {\\caption} + \li \l {05-qdoc-commands-documentstructure.html#chapter-command} {\\chapter} + \li \l {13-qdoc-commands-topics.html#class-command} {\\class} + \li \l {06-qdoc-commands-includecodeinline.html#code-command} {\\code} + \li \l {07-0-qdoc-commands-includingexternalcode.html#codeline-command} {\\codeline}, + \li \l {16-qdoc-commands-status.html#compat-command} {\\compat} + \li \l {15-qdoc-commands-navigation.html#contentspage-command} {\\contentspage} + \li \l {16-qdoc-commands-status.html#default-command} {\\default} + \li \l {21-0-qdoc-creating-dita-maps.html#ditamap-command} {\\ditamap} \span {class="newStuff"} {(new 05/03/12)} + \li \l {04-qdoc-commands-textmarkup.html#div-command} {\\div} + \li \l {07-0-qdoc-commands-includingexternalcode.html#dots-command} {\\dots} + \li \l {04-qdoc-commands-textmarkup.html#e-command} {\\e} \span {class="newStuff"} {(new 5/3/2012)} + \li \l {12-0-qdoc-commands-miscellaneous.html#else-command} {\\else} + \li \l {12-0-qdoc-commands-miscellaneous.html#endif-command} {\\endif} + \li \l {13-qdoc-commands-topics.html#enum-command} {\\enum} + \li \l {13-qdoc-commands-topics.html#example-command} {\\example} + \li \l {12-0-qdoc-commands-miscellaneous.html#expire-command} {\\expire} + \li \l {13-qdoc-commands-topics.html#externalpage-command} {\\externalpage} + \li \l {13-qdoc-commands-topics.html#fn-command} {\\fn} + \li \l {11-qdoc-commands-specialcontent.html#footnote-command} {\\footnote} + \li \l {12-0-qdoc-commands-miscellaneous.html#generatelist-command} {\\generatelist} + \li \l {13-qdoc-commands-topics.html#group-command} {\\group} + \li \l {10-qdoc-commands-tablesandlists.html#header-command} {\\header} + \li \l {13-qdoc-commands-topics.html#headerfile-command} {\\headerfile} + \li \l {04-qdoc-commands-textmarkup.html#e-command} {\\i} \span {class="newStuff"} {(deprecated, use \\e)} + \li \l {12-0-qdoc-commands-miscellaneous.html#if-command} {\\if} + \li \l {09-qdoc-commands-includingimages.html#image-command} {\\image} + \li \l {12-0-qdoc-commands-miscellaneous.html#include-command} {\\include} + \li \l {15-qdoc-commands-navigation.html#indexpage-command} {\\indexpage} + \li \l {19-qdoc-commands-grouping.html#ingroup-command} {\\ingroup} + \li \l {18-qdoc-commands-relating.html#inherits-command}{\\inherits} + \li \l {19-qdoc-commands-grouping.html#inmodule-command} {\\inmodule} + \li \l {09-qdoc-commands-includingimages.html#inlineimage-command} {\\inlineimage} + \li \l {16-qdoc-commands-status.html#internal-command} {\\internal} + \li \l {08-qdoc-commands-creatinglinks.html#keyword-command} {\\keyword} + \li \l {08-qdoc-commands-creatinglinks.html#l-command} {\\l} + \li \l {11-qdoc-commands-specialcontent.html#legalese-command} {\\legalese} + \li \l {10-qdoc-commands-tablesandlists.html#li-command} {\\li} \span {class="newStuff"} {(new 5/3/2012)} + \li \l {10-qdoc-commands-tablesandlists.html#list-command} {\\list} + \li \l {13-qdoc-commands-topics.html#macro-command} {\\macro} + \li \l {19-qdoc-commands-grouping.html#mainclass-command} {\\mainclass} + \li \l {21-0-qdoc-creating-dita-maps.html#mapref-command} {\\mapref} \span {class="newStuff"} {(new 05/03/12)} + \li \l {12-0-qdoc-commands-miscellaneous.html#meta-command} {\\meta} + \li \l {13-qdoc-commands-topics.html#module-command} {\\module} + \li \l {13-qdoc-commands-topics.html#namespace-command} {\\namespace} + \li \l {15-qdoc-commands-navigation.html#nextpage-command} {\\nextpage} + \li \l {06-qdoc-commands-includecodeinline.html#newcode-command} {\\newcode} + \li \l {17-qdoc-commands-thread.html#nonreentrant-command} {\\nonreentrant} + \li \l {10-qdoc-commands-tablesandlists.html#li-command} {\\o} \span {class="newStuff"} {(deprecated, use \\li)} + + \li \l {16-qdoc-commands-status.html#obsolete-command} {\\obsolete} + \li \l {06-qdoc-commands-includecodeinline.html#oldcode-command} {\\oldcode} + \li \l {12-0-qdoc-commands-miscellaneous.html#omit-command} {\\omit} + \li \l {10-qdoc-commands-tablesandlists.html#omitvalue-command} {\\omitvalue} + \li \l {18-qdoc-commands-relating.html#overload-command} {\\overload} + \li \l {13-qdoc-commands-topics.html#page-command} {\\page} + \li \l {05-qdoc-commands-documentstructure.html#part-command} {\\part} + \li \l {16-qdoc-commands-status.html#preliminary-command} {\\preliminary} + \li \l {15-qdoc-commands-navigation.html#previouspage-command} {\\previouspage} + \li \l {07-0-qdoc-commands-includingexternalcode.html#printline-command} {\\printline} + \li \l {07-0-qdoc-commands-includingexternalcode.html#printto-command} {\\printto} + \li \l {07-0-qdoc-commands-includingexternalcode.html#printuntil-command} {\\printuntil} + \li \l {13-qdoc-commands-topics.html#property-command} {\\property} + \li \l {13-qdoc-commands-topics.html#qmlattachedproperty-command} {\\qmlattachedproperty} + \li \l {13-qdoc-commands-topics.html#qmlattachedsignal-command} {\\qmlattachedsignal} + \li \l {13-qdoc-commands-topics.html#qmlbasictype-command} {\\qmlbasictype} + \li \l {13-qdoc-commands-topics.html#qmlclass-command} {\\qmlclass} + \li \l {13-qdoc-commands-topics.html#qmlmethod-command} {\\qmlmethod} + \li \l {13-qdoc-commands-topics.html#qmlproperty-command} {\\qmlproperty} + \li \l {13-qdoc-commands-topics.html#qmlsignal-command} {\\qmlsignal} + \li \l {13-qdoc-commands-topics.html#qmlmodule-command} {\\qmlmodule} + \li \l {13-qdoc-commands-topics.html#inqmlmodule-command} {\\inqmlmodule} + \li \l {11-qdoc-commands-specialcontent.html#quotation-command} {\\quotation} + \li \l {07-0-qdoc-commands-includingexternalcode.html#quotefile-command} {\\quotefile} + \li \l {07-0-qdoc-commands-includingexternalcode.html#quotefromfile-command} {\\quotefromfile} + \li \l {12-0-qdoc-commands-miscellaneous.html#raw-command} {\\raw} \span {class="newStuff"} {(avoid)} + \li \l {17-qdoc-commands-thread.html#reentrant-command} {\\reentrant} + \li \l {18-qdoc-commands-relating.html#reimp-command} {\\reimp} + \li \l {18-qdoc-commands-relating.html#relates-command} {\\relates} + \li \l {10-qdoc-commands-tablesandlists.html#row-command} {\\row} + \li \l {08-qdoc-commands-creatinglinks.html#sa-command} {\\sa} + \li \l {05-qdoc-commands-documentstructure.html#sectionOne-command} {\\section1} + \li \l {05-qdoc-commands-documentstructure.html#sectionTwo-command} {\\section2} + \li \l {05-qdoc-commands-documentstructure.html#sectionThree-command} {\\section3} + \li \l {05-qdoc-commands-documentstructure.html#sectionFour-command} {\\section4} + \li \l {13-qdoc-commands-topics.html#service-command} {\\service} + \li \l {16-qdoc-commands-status.html#since-command} {\\since} + \li \l {07-0-qdoc-commands-includingexternalcode.html#skipline-command} {\\skipline} + \li \l {07-0-qdoc-commands-includingexternalcode.html#skipto-command} {\\skipto} + \li \l {07-0-qdoc-commands-includingexternalcode.html#skipuntil-command} {\\skipuntil} + \li \l {07-0-qdoc-commands-includingexternalcode.html#snippet-command} {\\snippet}, + \li \l {04-qdoc-commands-textmarkup.html#span-command} {\\span} + \li \l {15-qdoc-commands-navigation.html#startpage-command} {\\startpage} + \li \l {04-qdoc-commands-textmarkup.html#sub-command} {\\sub} + \li \l {20-qdoc-commands-namingthings.html#subtitle-command} {\\subtitle} + \li \l {04-qdoc-commands-textmarkup.html#sup-command} {\\sup} + \li \l {10-qdoc-commands-tablesandlists.html#table-command} {\\table} + \li \l {11-qdoc-commands-specialcontent.html#tableofcontents-command} {\\tableofcontents} + \li \l {08-qdoc-commands-creatinglinks.html#target-command} {\\target} + \li \l {17-qdoc-commands-thread.html#threadsafe-command} {\\threadsafe} + \li \l {20-qdoc-commands-namingthings.html#title-command} {\\title} + \li \l {21-0-qdoc-creating-dita-maps.html#topicref-command} {\\topicref} \span {class="newStuff"} {(new 05/03/12)} + \li \l {04-qdoc-commands-textmarkup.html#tt-command} {\\tt} + \li \l {13-qdoc-commands-topics.html#typedef-command} {\\typedef} + \li \l {04-qdoc-commands-textmarkup.html#underline-command} {\\underline} + \li \l {13-qdoc-commands-topics.html#variable-command} {\\variable} + \li \l {10-qdoc-commands-tablesandlists.html#value-command} {\\value} + \li \l {11-qdoc-commands-specialcontent.html#warning-command} {\\warning} \endlist */ -- cgit v1.2.3 From d8e6350c16a1cf696cf65d9cc898c7bd34419ec7 Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Sat, 10 Mar 2012 18:28:40 +0000 Subject: Remove unneeded check. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It would have already crashed on QOpenGLSharedResource(ctx->shareGroup()). Change-Id: Ib68759457a0fa7e4417dcd30cc40fbabf3df232c Reviewed-by: Samuel Rødal --- src/gui/opengl/qopengltextureglyphcache_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/opengl/qopengltextureglyphcache_p.h b/src/gui/opengl/qopengltextureglyphcache_p.h index 1b4f4f7429..4b6101e7c9 100644 --- a/src/gui/opengl/qopengltextureglyphcache_p.h +++ b/src/gui/opengl/qopengltextureglyphcache_p.h @@ -72,7 +72,7 @@ public: , m_width(0) , m_height(0) { - if (ctx && !ctx->d_func()->workaround_brokenFBOReadBack) + if (!ctx->d_func()->workaround_brokenFBOReadBack) QOpenGLFunctions(ctx).glGenFramebuffers(1, &m_fbo); #ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG -- cgit v1.2.3 From 472cc7ac27ea552a254b9a56663a8e94082b137a Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 9 Mar 2012 14:35:11 +0100 Subject: XCB: Implement native events for for windows. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Iacea1231b49ebe57da96f4012d3f314e1b037105 Reviewed-by: Samuel Rødal --- src/plugins/platforms/xcb/qxcbconnection.cpp | 16 ++++++++++++---- src/plugins/platforms/xcb/qxcbnativeinterface.cpp | 6 ++++-- src/plugins/platforms/xcb/qxcbnativeinterface.h | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 367b24da9d..76979bf05f 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -235,16 +235,24 @@ QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id) #define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \ { \ event_t *e = (event_t *)event; \ - if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember)) \ - platformWindow->handler(e); \ + if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember)) { \ + long result = 0; \ + handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \ + if (!handled) \ + platformWindow->handler(e); \ + } \ } \ break; #define HANDLE_KEYBOARD_EVENT(event_t, handler) \ { \ event_t *e = (event_t *)event; \ - if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) \ - m_keyboard->handler(platformWindow, e); \ + if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) { \ + long result = 0; \ + handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \ + if (!handled) \ + m_keyboard->handler(platformWindow, e); \ + } \ } \ break; diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index f56072f9d7..fc320ee69c 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -76,7 +76,9 @@ public: Q_GLOBAL_STATIC(QXcbResourceMap, qXcbResourceMap) -QXcbNativeInterface::QXcbNativeInterface() +QXcbNativeInterface::QXcbNativeInterface() : + m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t")) + { qFill(m_eventFilters, m_eventFilters + EventFilterCount, EventFilter(0)); } @@ -134,7 +136,7 @@ void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceStr QPlatformNativeInterface::EventFilter QXcbNativeInterface::setEventFilter(const QByteArray &eventType, QPlatformNativeInterface::EventFilter filter) { int type = -1; - if (eventType == QByteArrayLiteral("xcb_generic_event_t")) + if (eventType == m_genericEventFilterType) type = GenericEventFilter; if (type == -1) { qWarning("QXcbNativeInterface: %s: Attempt to set invalid event filter type '%s'.", diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index 6f6130d3e9..c6835ff9e0 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -71,6 +71,7 @@ public: void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); + inline const QByteArray &genericEventFilterType() const { return m_genericEventFilterType; } EventFilter setEventFilter(const QByteArray &eventType, EventFilter filter); EventFilter eventFilter(EventFilterType type) const { return m_eventFilters[type]; } @@ -83,6 +84,7 @@ public: void *eglContextForContext(QOpenGLContext *context); private: + const QByteArray m_genericEventFilterType; EventFilter m_eventFilters[EventFilterCount]; static QXcbScreen *qPlatformScreenForWindow(QWindow *window); -- cgit v1.2.3 From e9ed5853f4c5600691d2f369e26a1a7881f9750f Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Fri, 9 Mar 2012 19:04:43 -0800 Subject: Make tst_qsql.cpp independent of QtWidgets Change-Id: I032902bea6fe2c7d9eb0491886fded7602ae2bcc Reviewed-by: Mark Brand Reviewed-by: Robin Burchell --- tests/auto/sql/kernel/qsql/qsql.pro | 2 +- tests/auto/sql/kernel/qsql/tst_qsql.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/auto/sql/kernel/qsql/qsql.pro b/tests/auto/sql/kernel/qsql/qsql.pro index ac21bb392c..df6e553d8a 100644 --- a/tests/auto/sql/kernel/qsql/qsql.pro +++ b/tests/auto/sql/kernel/qsql/qsql.pro @@ -2,7 +2,7 @@ CONFIG += testcase TARGET = tst_qsql SOURCES += tst_qsql.cpp -QT += sql sql-private gui widgets testlib +QT += sql sql-private gui testlib wince*: { DEPLOYMENT_PLUGIN += qsqlite diff --git a/tests/auto/sql/kernel/qsql/tst_qsql.cpp b/tests/auto/sql/kernel/qsql/tst_qsql.cpp index b02093adae..2656f4802f 100644 --- a/tests/auto/sql/kernel/qsql/tst_qsql.cpp +++ b/tests/auto/sql/kernel/qsql/tst_qsql.cpp @@ -152,7 +152,7 @@ void tst_QSql::basicDriverTest() } // make sure that the static stuff will be deleted -// when using multiple QApplication objects +// when using multiple QGuiApplication objects void tst_QSql::open() { int i; @@ -160,7 +160,7 @@ void tst_QSql::open() const char *argv[] = {"test"}; int count = -1; for ( i = 0; i < 10; ++i ) { - QApplication app(argc, const_cast(argv), false); + QGuiApplication app(argc, const_cast(argv), false); tst_Databases dbs; dbs.open(); -- cgit v1.2.3 From e3429f764b37c3d58faf06c6e1856e66fb8d64b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Thu, 8 Mar 2012 15:56:33 +0100 Subject: Crash fix in QMetaType::typeFlags. The function is public, so it should validate input instead of crashing Change-Id: Id67463b0b61ab74a76c1ede7f052bdbed37822b6 Reviewed-by: Stephen Kelly --- src/corelib/kernel/qmetatype.cpp | 2 +- tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 0be813f4f2..5032cf9590 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -1616,7 +1616,7 @@ private: static quint32 customTypeFlags(const int type) { const QVector * const ct = customTypes(); - if (Q_UNLIKELY(!ct)) + if (Q_UNLIKELY(!ct || type < QMetaType::User)) return 0; QReadLocker locker(customTypesLock()); if (Q_UNLIKELY(ct->count() <= type - QMetaType::User)) diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 35439885c9..3c21a5053f 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -743,6 +743,12 @@ QT_FOR_EACH_STATIC_CORE_POINTER(ADD_METATYPE_TEST_ROW) QTest::newRow("QPair") << ::qMetaTypeId >() << false << true << false; QTest::newRow("QPair") << ::qMetaTypeId >() << true << true << false; QTest::newRow("QPair") << ::qMetaTypeId >() << true << false << false; + + // invalid ids. + QTest::newRow("-1") << -1 << false << false << false; + QTest::newRow("-124125534") << -124125534 << false << false << false; + QTest::newRow("124125534") << 124125534 << false << false << false; + } void tst_QMetaType::flags() -- cgit v1.2.3 From 15c13b91e66b0bd0d179f0303bb17c7793f80a07 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Tue, 7 Feb 2012 12:25:07 +1000 Subject: Add Q_IS_ENUM(), and provide as flag in QMetaType::typeFlags() Add Q_IS_ENUM() macro to determine if a given type is an enumeration. Use information from that in QMetaType::registerType() to store whether custom registered metatypes are enums or not. This information can then be accessed by calling QMetaType::typeFlags(int type). This is used by the declarative code to determine whether a custom type in a variant can be safely cast to an integer, which is required to allow passing non-local enums as signal/slot params. Change-Id: I9733837f56af201fa3017b4a22b761437a3c0de4 Reviewed-by: Lars Knoll --- src/corelib/global/global.pri | 4 +- src/corelib/global/qisenum.h | 64 ++++ src/corelib/global/qtypetraits.h | 420 +++++++++++++++++++++ src/corelib/kernel/qmetatype.h | 6 +- tests/auto/corelib/global/qglobal/tst_qglobal.cpp | 122 ++++++ .../corelib/kernel/qmetatype/tst_qmetatype.cpp | 34 ++ 6 files changed, 648 insertions(+), 2 deletions(-) create mode 100644 src/corelib/global/qisenum.h create mode 100644 src/corelib/global/qtypetraits.h diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri index 49128374e0..58cff6b81c 100644 --- a/src/corelib/global/global.pri +++ b/src/corelib/global/global.pri @@ -11,7 +11,9 @@ HEADERS += \ global/qnumeric.h \ global/qlogging.h \ global/qtypeinfo.h \ - global/qsysinfo.h + global/qsysinfo.h \ + global/qisenum.h \ + global/qtypetraits.h SOURCES += \ global/qglobal.cpp \ diff --git a/src/corelib/global/qisenum.h b/src/corelib/global/qisenum.h new file mode 100644 index 0000000000..c9b6ec6695 --- /dev/null +++ b/src/corelib/global/qisenum.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include + +#ifndef QISENUM_H +#define QISENUM_H + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +#ifndef Q_IS_ENUM +# if defined(Q_CC_GNU) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) +# define Q_IS_ENUM(x) __is_enum(x) +# elif defined(Q_CC_MSVC) && defined(_MSC_FULL_VER) && (_MSC_FULL_VER >=140050215) +# define Q_IS_ENUM(x) __is_enum(x) +# else +# include +# define Q_IS_ENUM(x) QtPrivate::is_enum::value +# endif +#endif + +QT_END_HEADER +QT_END_NAMESPACE + +#endif // QISENUM_H diff --git a/src/corelib/global/qtypetraits.h b/src/corelib/global/qtypetraits.h new file mode 100644 index 0000000000..92bd949570 --- /dev/null +++ b/src/corelib/global/qtypetraits.h @@ -0,0 +1,420 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// 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 Google Inc. 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. + +// ---- +// +// This code is compiled directly on many platforms, including client +// platforms like Windows, Mac, and embedded systems. Before making +// any changes here, make sure that you're not breaking any platforms. +// +// Define a small subset of tr1 type traits. The traits we define are: +// is_integral +// is_floating_point +// is_pointer +// is_enum +// is_reference +// is_pod +// has_trivial_constructor +// has_trivial_copy +// has_trivial_assign +// has_trivial_destructor +// remove_const +// remove_volatile +// remove_cv +// remove_reference +// add_reference +// remove_pointer +// is_same +// is_convertible +// We can add more type traits as required. + +// Changes from the original implementation: +// - Move base types from template_util.h directly into this header. +// - Use Qt macros for long long type differences on Windows. +// - Enclose in QtPrivate namespace. + +#ifndef QTYPETRAITS_H +#define QTYPETRAITS_H + +#include // For pair +#include "QtCore/qglobal.h" + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +namespace QtPrivate { + +// Types small_ and big_ are guaranteed such that sizeof(small_) < +// sizeof(big_) +typedef char small_; + +struct big_ { + char dummy[2]; +}; + +// Identity metafunction. +template +struct identity_ { + typedef T type; +}; + +// integral_constant, defined in tr1, is a wrapper for an integer +// value. We don't really need this generality; we could get away +// with hardcoding the integer type to bool. We use the fully +// general integer_constant for compatibility with tr1. + +template +struct integral_constant { + static const T value = v; + typedef T value_type; + typedef integral_constant type; +}; + +template const T integral_constant::value; + + +// Abbreviations: true_type and false_type are structs that represent boolean +// true and false values. Also define the boost::mpl versions of those names, +// true_ and false_. +typedef integral_constant true_type; +typedef integral_constant false_type; +typedef true_type true_; +typedef false_type false_; + +// if_ is a templatized conditional statement. +// if_ is a compile time evaluation of cond. +// if_<>::type contains A if cond is true, B otherwise. +template +struct if_{ + typedef A type; +}; + +template +struct if_ { + typedef B type; +}; + + +// type_equals_ is a template type comparator, similar to Loki IsSameType. +// type_equals_::value is true iff "A" is the same type as "B". +// +// New code should prefer base::is_same, defined in base/type_traits.h. +// It is functionally identical, but is_same is the standard spelling. +template +struct type_equals_ : public false_ { +}; + +template +struct type_equals_ : public true_ { +}; + +// and_ is a template && operator. +// and_::value evaluates "A::value && B::value". +template +struct and_ : public integral_constant { +}; + +// or_ is a template || operator. +// or_::value evaluates "A::value || B::value". +template +struct or_ : public integral_constant { +}; + +template struct is_integral; +template struct is_floating_point; +template struct is_pointer; +// MSVC can't compile this correctly, and neither can gcc 3.3.5 (at least) +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) +// is_enum uses is_convertible, which is not available on MSVC. +template struct is_enum; +#endif +template struct is_reference; +template struct is_pod; +template struct has_trivial_constructor; +template struct has_trivial_copy; +template struct has_trivial_assign; +template struct has_trivial_destructor; +template struct remove_const; +template struct remove_volatile; +template struct remove_cv; +template struct remove_reference; +template struct add_reference; +template struct remove_pointer; +template struct is_same; +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) +template struct is_convertible; +#endif + +// is_integral is false except for the built-in integer types. A +// cv-qualified type is integral if and only if the underlying type is. +template struct is_integral : false_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +#if defined(_MSC_VER) +// wchar_t is not by default a distinct type from unsigned short in +// Microsoft C. +// See http://msdn2.microsoft.com/en-us/library/dh8che7s(VS.80).aspx +template<> struct is_integral<__wchar_t> : true_type { }; +#else +template<> struct is_integral : true_type { }; +#endif +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +#if defined(Q_OS_WIN) && !defined(Q_CC_GNU) +template<> struct is_integral<__int64> : true_type { }; +template<> struct is_integral : true_type { }; +#else +template<> struct is_integral : true_type { }; +template<> struct is_integral : true_type { }; +#endif +template struct is_integral : is_integral { }; +template struct is_integral : is_integral { }; +template struct is_integral : is_integral { }; + +// is_floating_point is false except for the built-in floating-point types. +// A cv-qualified type is integral if and only if the underlying type is. +template struct is_floating_point : false_type { }; +template<> struct is_floating_point : true_type { }; +template<> struct is_floating_point : true_type { }; +template<> struct is_floating_point : true_type { }; +template struct is_floating_point + : is_floating_point { }; +template struct is_floating_point + : is_floating_point { }; +template struct is_floating_point + : is_floating_point { }; + +// is_pointer is false except for pointer types. A cv-qualified type (e.g. +// "int* const", as opposed to "int const*") is cv-qualified if and only if +// the underlying type is. +template struct is_pointer : false_type { }; +template struct is_pointer : true_type { }; +template struct is_pointer : is_pointer { }; +template struct is_pointer : is_pointer { }; +template struct is_pointer : is_pointer { }; + +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) + +namespace internal { + +template struct is_class_or_union { + template static small_ tester(void (U::*)()); + template static big_ tester(...); + static const bool value = sizeof(tester(0)) == sizeof(small_); +}; + +// is_convertible chokes if the first argument is an array. That's why +// we use add_reference here. +template struct is_enum_impl + : is_convertible::type, int> { }; + +template struct is_enum_impl : false_type { }; + +} // namespace internal + +// Specified by TR1 [4.5.1] primary type categories. + +// Implementation note: +// +// Each type is either void, integral, floating point, array, pointer, +// reference, member object pointer, member function pointer, enum, +// union or class. Out of these, only integral, floating point, reference, +// class and enum types are potentially convertible to int. Therefore, +// if a type is not a reference, integral, floating point or class and +// is convertible to int, it's a enum. Adding cv-qualification to a type +// does not change whether it's an enum. +// +// Is-convertible-to-int check is done only if all other checks pass, +// because it can't be used with some types (e.g. void or classes with +// inaccessible conversion operators). +template struct is_enum + : internal::is_enum_impl< + is_same::value || + is_integral::value || + is_floating_point::value || + is_reference::value || + internal::is_class_or_union::value, + T> { }; + +template struct is_enum : is_enum { }; +template struct is_enum : is_enum { }; +template struct is_enum : is_enum { }; + +#endif + +// is_reference is false except for reference types. +template struct is_reference : false_type {}; +template struct is_reference : true_type {}; + + +// We can't get is_pod right without compiler help, so fail conservatively. +// We will assume it's false except for arithmetic types, enumerations, +// pointers and cv-qualified versions thereof. Note that std::pair +// is not a POD even if T and U are PODs. +template struct is_pod + : integral_constant::value || + is_floating_point::value || +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) + // is_enum is not available on MSVC. + is_enum::value || +#endif + is_pointer::value)> { }; +template struct is_pod : is_pod { }; +template struct is_pod : is_pod { }; +template struct is_pod : is_pod { }; + + +// We can't get has_trivial_constructor right without compiler help, so +// fail conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial +// constructors. (3) array of a type with a trivial constructor. +// (4) const versions thereof. +template struct has_trivial_constructor : is_pod { }; +template struct has_trivial_constructor > + : integral_constant::value && + has_trivial_constructor::value)> { }; +template struct has_trivial_constructor + : has_trivial_constructor { }; +template struct has_trivial_constructor + : has_trivial_constructor { }; + +// We can't get has_trivial_copy right without compiler help, so fail +// conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial copy +// constructors. (3) array of a type with a trivial copy constructor. +// (4) const versions thereof. +template struct has_trivial_copy : is_pod { }; +template struct has_trivial_copy > + : integral_constant::value && + has_trivial_copy::value)> { }; +template struct has_trivial_copy + : has_trivial_copy { }; +template struct has_trivial_copy : has_trivial_copy { }; + +// We can't get has_trivial_assign right without compiler help, so fail +// conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial copy +// constructors. (3) array of a type with a trivial assign constructor. +template struct has_trivial_assign : is_pod { }; +template struct has_trivial_assign > + : integral_constant::value && + has_trivial_assign::value)> { }; +template struct has_trivial_assign + : has_trivial_assign { }; + +// We can't get has_trivial_destructor right without compiler help, so +// fail conservatively. We will assume it's false except for: (1) types +// for which is_pod is true. (2) std::pair of types with trivial +// destructors. (3) array of a type with a trivial destructor. +// (4) const versions thereof. +template struct has_trivial_destructor : is_pod { }; +template struct has_trivial_destructor > + : integral_constant::value && + has_trivial_destructor::value)> { }; +template struct has_trivial_destructor + : has_trivial_destructor { }; +template struct has_trivial_destructor + : has_trivial_destructor { }; + +// Specified by TR1 [4.7.1] +template struct remove_const { typedef T type; }; +template struct remove_const { typedef T type; }; +template struct remove_volatile { typedef T type; }; +template struct remove_volatile { typedef T type; }; +template struct remove_cv { + typedef typename remove_const::type>::type type; +}; + + +// Specified by TR1 [4.7.2] Reference modifications. +template struct remove_reference { typedef T type; }; +template struct remove_reference { typedef T type; }; + +template struct add_reference { typedef T& type; }; +template struct add_reference { typedef T& type; }; + +// Specified by TR1 [4.7.4] Pointer modifications. +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { typedef T type; }; +template struct remove_pointer { + typedef T type; }; + +// Specified by TR1 [4.6] Relationships between types +template struct is_same : public false_type { }; +template struct is_same : public true_type { }; + +// Specified by TR1 [4.6] Relationships between types +#if !defined(_MSC_VER) && !(defined(__GNUC__) && __GNUC__ <= 3) +namespace internal { + +// This class is an implementation detail for is_convertible, and you +// don't need to know how it works to use is_convertible. For those +// who care: we declare two different functions, one whose argument is +// of type To and one with a variadic argument list. We give them +// return types of different size, so we can use sizeof to trick the +// compiler into telling us which function it would have chosen if we +// had called it with an argument of type From. See Alexandrescu's +// _Modern C++ Design_ for more details on this sort of trick. + +template +struct ConvertHelper { + static small_ Test(To); + static big_ Test(...); + static From Create(); +}; +} // namespace internal + +// Inherits from true_type if From is convertible to To, false_type otherwise. +template +struct is_convertible + : integral_constant::Test( + internal::ConvertHelper::Create())) + == sizeof(small_)> { +}; +#endif + +} + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QTYPETRAITS_H diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index eacb8403dc..0010c27beb 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -45,6 +45,7 @@ #include #include #include +#include #include @@ -209,7 +210,8 @@ public: NeedsConstruction = 0x1, NeedsDestruction = 0x2, MovableType = 0x4, - PointerToQObject = 0x8 + PointerToQObject = 0x8, + IsEnumeration = 0x10 }; Q_DECLARE_FLAGS(TypeFlags, TypeFlag) @@ -455,6 +457,8 @@ int qRegisterMetaType(const char *typeName } if (QtPrivate::IsPointerToTypeDerivedFromQObject::Value) flags |= QMetaType::PointerToQObject; + if (Q_IS_ENUM(T)) + flags |= QMetaType::IsEnumeration; return QMetaType::registerType(typeName, qMetaTypeDeleteHelper, qMetaTypeCreateHelper, diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp index 8fedaf427a..b3d76bef8a 100644 --- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp +++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp @@ -41,10 +41,12 @@ #include +#include class tst_QGlobal: public QObject { Q_OBJECT + private slots: void qIsNull(); void for_each(); @@ -53,6 +55,7 @@ private slots: void checkptr(); void qstaticassert(); void qConstructorFunction(); + void isEnum(); }; void tst_QGlobal::qIsNull() @@ -293,5 +296,124 @@ void tst_QGlobal::qConstructorFunction() QCOMPARE(qConstructorFunctionValue, 123); } +struct isEnum_A { + int n_; +}; + +enum isEnum_B_Byte { isEnum_B_Byte_x = 63 }; +enum isEnum_B_Short { isEnum_B_Short_x = 1024 }; +enum isEnum_B_Int { isEnum_B_Int_x = 1 << 20 }; + +union isEnum_C {}; + +class isEnum_D { +public: + operator int() const; +}; + +class isEnum_E { +private: + operator int() const; +}; + +class isEnum_F { +public: + enum AnEnum {}; +}; + +#if defined (Q_COMPILER_CLASS_ENUM) +enum class isEnum_G : qint64 {}; +#endif + +void tst_QGlobal::isEnum() +{ +#if defined (Q_CC_MSVC) +#define IS_ENUM_TRUE(x) (Q_IS_ENUM(x) == true) +#define IS_ENUM_FALSE(x) (Q_IS_ENUM(x) == false) +#else +#define IS_ENUM_TRUE(x) (Q_IS_ENUM(x) == true && QtPrivate::is_enum::value == true) +#define IS_ENUM_FALSE(x) (Q_IS_ENUM(x) == false && QtPrivate::is_enum::value == false) +#endif + + QVERIFY(IS_ENUM_TRUE(isEnum_B_Byte)); + QVERIFY(IS_ENUM_TRUE(const isEnum_B_Byte)); + QVERIFY(IS_ENUM_TRUE(volatile isEnum_B_Byte)); + QVERIFY(IS_ENUM_TRUE(const volatile isEnum_B_Byte)); + + QVERIFY(IS_ENUM_TRUE(isEnum_B_Short)); + QVERIFY(IS_ENUM_TRUE(const isEnum_B_Short)); + QVERIFY(IS_ENUM_TRUE(volatile isEnum_B_Short)); + QVERIFY(IS_ENUM_TRUE(const volatile isEnum_B_Short)); + + QVERIFY(IS_ENUM_TRUE(isEnum_B_Int)); + QVERIFY(IS_ENUM_TRUE(const isEnum_B_Int)); + QVERIFY(IS_ENUM_TRUE(volatile isEnum_B_Int)); + QVERIFY(IS_ENUM_TRUE(const volatile isEnum_B_Int)); + + QVERIFY(IS_ENUM_TRUE(isEnum_F::AnEnum)); + QVERIFY(IS_ENUM_TRUE(const isEnum_F::AnEnum)); + QVERIFY(IS_ENUM_TRUE(volatile isEnum_F::AnEnum)); + QVERIFY(IS_ENUM_TRUE(const volatile isEnum_F::AnEnum)); + + QVERIFY(IS_ENUM_FALSE(void)); + QVERIFY(IS_ENUM_FALSE(isEnum_B_Byte &)); + QVERIFY(IS_ENUM_FALSE(isEnum_B_Byte[1])); + QVERIFY(IS_ENUM_FALSE(const isEnum_B_Byte[1])); + QVERIFY(IS_ENUM_FALSE(isEnum_B_Byte[])); + QVERIFY(IS_ENUM_FALSE(int)); + QVERIFY(IS_ENUM_FALSE(float)); + QVERIFY(IS_ENUM_FALSE(isEnum_A)); + QVERIFY(IS_ENUM_FALSE(isEnum_A *)); + QVERIFY(IS_ENUM_FALSE(const isEnum_A)); + QVERIFY(IS_ENUM_FALSE(isEnum_C)); + QVERIFY(IS_ENUM_FALSE(isEnum_D)); + QVERIFY(IS_ENUM_FALSE(isEnum_E)); + QVERIFY(IS_ENUM_FALSE(void())); + QVERIFY(IS_ENUM_FALSE(void(*)())); + QVERIFY(IS_ENUM_FALSE(int isEnum_A::*)); + QVERIFY(IS_ENUM_FALSE(void (isEnum_A::*)())); + + QVERIFY(IS_ENUM_FALSE(size_t)); + QVERIFY(IS_ENUM_FALSE(bool)); + QVERIFY(IS_ENUM_FALSE(wchar_t)); + + QVERIFY(IS_ENUM_FALSE(char)); + QVERIFY(IS_ENUM_FALSE(unsigned char)); + QVERIFY(IS_ENUM_FALSE(short)); + QVERIFY(IS_ENUM_FALSE(unsigned short)); + QVERIFY(IS_ENUM_FALSE(int)); + QVERIFY(IS_ENUM_FALSE(unsigned int)); + QVERIFY(IS_ENUM_FALSE(long)); + QVERIFY(IS_ENUM_FALSE(unsigned long)); + + QVERIFY(IS_ENUM_FALSE(qint8)); + QVERIFY(IS_ENUM_FALSE(quint8)); + QVERIFY(IS_ENUM_FALSE(qint16)); + QVERIFY(IS_ENUM_FALSE(quint16)); + QVERIFY(IS_ENUM_FALSE(qint32)); + QVERIFY(IS_ENUM_FALSE(quint32)); + QVERIFY(IS_ENUM_FALSE(qint64)); + QVERIFY(IS_ENUM_FALSE(quint64)); + + QVERIFY(IS_ENUM_FALSE(void *)); + QVERIFY(IS_ENUM_FALSE(int *)); + +#if defined (Q_COMPILER_UNICODE_STRINGS) + QVERIFY(IS_ENUM_FALSE(char16_t)); + QVERIFY(IS_ENUM_FALSE(char32_t)); +#endif + +#if defined (Q_COMPILER_CLASS_ENUM) + // Strongly type class enums are not handled by the + // fallback type traits implementation. Any compiler + // supported by Qt that supports C++0x class enums + // should also support the __is_enum intrinsic. + QVERIFY(Q_IS_ENUM(isEnum_G) == true); +#endif + +#undef IS_ENUM_TRUE +#undef IS_ENUM_FALSE +} + QTEST_MAIN(tst_QGlobal) #include "tst_qglobal.moc" diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index 3c21a5053f..bc5fa2716b 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -94,6 +94,7 @@ private slots: void isRegistered(); void isRegisteredStaticLess_data(); void isRegisteredStaticLess(); + void isEnum(); void registerStreamBuiltin(); void automaticTemplateRegistration(); }; @@ -1042,6 +1043,39 @@ void tst_QMetaType::isRegistered() QCOMPARE(QMetaType::isRegistered(typeId), registered); } +enum isEnumTest_Enum0 {}; +struct isEnumTest_Struct0 { enum A{}; }; + +enum isEnumTest_Enum1 {}; +struct isEnumTest_Struct1 {}; + +Q_DECLARE_METATYPE(isEnumTest_Struct1) +Q_DECLARE_METATYPE(isEnumTest_Enum1) + +void tst_QMetaType::isEnum() +{ + int type0 = qRegisterMetaType("int"); + QVERIFY((QMetaType::typeFlags(type0) & QMetaType::IsEnumeration) == 0); + + int type1 = qRegisterMetaType("isEnumTest_Enum0"); + QVERIFY((QMetaType::typeFlags(type1) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration); + + int type2 = qRegisterMetaType("isEnumTest_Struct0"); + QVERIFY((QMetaType::typeFlags(type2) & QMetaType::IsEnumeration) == 0); + + int type3 = qRegisterMetaType("isEnumTest_Enum0 *"); + QVERIFY((QMetaType::typeFlags(type3) & QMetaType::IsEnumeration) == 0); + + int type4 = qRegisterMetaType("isEnumTest_Struct0::A"); + QVERIFY((QMetaType::typeFlags(type4) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration); + + int type5 = ::qMetaTypeId(); + QVERIFY((QMetaType::typeFlags(type5) & QMetaType::IsEnumeration) == 0); + + int type6 = ::qMetaTypeId(); + QVERIFY((QMetaType::typeFlags(type6) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration); +} + void tst_QMetaType::isRegisteredStaticLess_data() { isRegistered_data(); -- cgit v1.2.3 From a4c0109e016709dbeea1497cd122722e5ec5e26b Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Thu, 8 Mar 2012 11:30:10 +1000 Subject: testlib: Improve formatting of QCOMPARE failure messages. Make the various versions of the failure message align consistently so that it's a little easier to compare the actual and expected values. Of course, the value won't align nicely unless the "actual" and "expected" strings are the same length, but at least this commit makes that consistent across all versions of the message. Change-Id: If9ce231df3b5d279a06f6458fdb5da0aa4586068 Reviewed-by: Rohan McGovern --- src/testlib/qtest.h | 6 ++-- src/testlib/qtest_gui.h | 10 +++--- src/testlib/qtestresult.cpp | 2 +- .../testlib/selftests/expected_cmptest.lightxml | 36 +++++++++++----------- tests/auto/testlib/selftests/expected_cmptest.txt | 36 +++++++++++----------- tests/auto/testlib/selftests/expected_cmptest.xml | 36 +++++++++++----------- .../testlib/selftests/expected_cmptest.xunitxml | 36 +++++++++++----------- .../testlib/selftests/expected_datetime.lightxml | 6 ++-- tests/auto/testlib/selftests/expected_datetime.txt | 6 ++-- tests/auto/testlib/selftests/expected_datetime.xml | 6 ++-- .../testlib/selftests/expected_datetime.xunitxml | 6 ++-- tests/auto/testlib/selftests/expected_float.txt | 12 ++++---- .../testlib/selftests/expected_strcmp.lightxml | 10 +++--- tests/auto/testlib/selftests/expected_strcmp.txt | 10 +++--- tests/auto/testlib/selftests/expected_strcmp.xml | 10 +++--- .../testlib/selftests/expected_strcmp.xunitxml | 10 +++--- .../testlib/selftests/expected_subtest.lightxml | 4 +-- tests/auto/testlib/selftests/expected_subtest.txt | 4 +-- tests/auto/testlib/selftests/expected_subtest.xml | 4 +-- .../testlib/selftests/expected_subtest.xunitxml | 4 +-- .../auto/testlib/selftests/expected_xunit.lightxml | 2 +- tests/auto/testlib/selftests/expected_xunit.txt | 2 +- tests/auto/testlib/selftests/expected_xunit.xml | 2 +- .../auto/testlib/selftests/expected_xunit.xunitxml | 2 +- 24 files changed, 131 insertions(+), 131 deletions(-) diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h index 477d344d71..d167324aef 100644 --- a/src/testlib/qtest.h +++ b/src/testlib/qtest.h @@ -197,15 +197,15 @@ inline bool qCompare(QStringList const &t1, QStringList const &t2, const int expectedSize = t2.count(); if (actualSize != expectedSize) { qsnprintf(msg, sizeof(msg), "Compared QStringLists have different sizes.\n" - " Actual (%s) size : '%d'\n" + " Actual (%s) size: '%d'\n" " Expected (%s) size: '%d'", actual, actualSize, expected, expectedSize); isOk = false; } for (int i = 0; isOk && i < actualSize; ++i) { if (t1.at(i) != t2.at(i)) { qsnprintf(msg, sizeof(msg), "Compared QStringLists differ at index %d.\n" - " Actual (%s) : '%s'\n" - " Expected (%s) : '%s'", i, actual, t1.at(i).toLatin1().constData(), + " Actual (%s): '%s'\n" + " Expected (%s): '%s'", i, actual, t1.at(i).toLatin1().constData(), expected, t2.at(i).toLatin1().constData()); isOk = false; } diff --git a/src/testlib/qtest_gui.h b/src/testlib/qtest_gui.h index 3067c35e02..f10ddd8473 100644 --- a/src/testlib/qtest_gui.h +++ b/src/testlib/qtest_gui.h @@ -100,7 +100,7 @@ inline bool qCompare(QImage const &t1, QImage const &t2, const bool t2Null = t2.isNull(); if (t1Null != t2Null) { qsnprintf(msg, 1024, "Compared QImages differ.\n" - " Actual (%s).isNull() : %d\n" + " Actual (%s).isNull(): %d\n" " Expected (%s).isNull(): %d", actual, t1Null, expected, t2Null); return compare_helper(false, msg, 0, 0, actual, expected, file, line); } @@ -108,7 +108,7 @@ inline bool qCompare(QImage const &t1, QImage const &t2, return compare_helper(true, 0, 0, 0, actual, expected, file, line); if (t1.width() != t2.width() || t2.height() != t2.height()) { qsnprintf(msg, 1024, "Compared QImages differ in size.\n" - " Actual (%s) : %dx%d\n" + " Actual (%s): %dx%d\n" " Expected (%s): %dx%d", actual, t1.width(), t1.height(), expected, t2.width(), t2.height()); @@ -116,7 +116,7 @@ inline bool qCompare(QImage const &t1, QImage const &t2, } if (t1.format() != t2.format()) { qsnprintf(msg, 1024, "Compared QImages differ in format.\n" - " Actual (%s) : %d\n" + " Actual (%s): %d\n" " Expected (%s): %d", actual, t1.format(), expected, t2.format()); return compare_helper(false, msg, 0, 0, actual, expected, file, line); @@ -137,7 +137,7 @@ inline bool qCompare(QPixmap const &t1, QPixmap const &t2, const char *actual, c const bool t2Null = t2.isNull(); if (t1Null != t2Null) { qsnprintf(msg, 1024, "Compared QPixmaps differ.\n" - " Actual (%s).isNull() : %d\n" + " Actual (%s).isNull(): %d\n" " Expected (%s).isNull(): %d", actual, t1Null, expected, t2Null); return compare_helper(false, msg, 0, 0, actual, expected, file, line); } @@ -145,7 +145,7 @@ inline bool qCompare(QPixmap const &t1, QPixmap const &t2, const char *actual, c return compare_helper(true, 0, 0, 0, actual, expected, file, line); if (t1.width() != t2.width() || t2.height() != t2.height()) { qsnprintf(msg, 1024, "Compared QPixmaps differ in size.\n" - " Actual (%s) : %dx%d\n" + " Actual (%s): %dx%d\n" " Expected (%s): %dx%d", actual, t1.width(), t1.height(), expected, t2.width(), t2.height()); diff --git a/src/testlib/qtestresult.cpp b/src/testlib/qtestresult.cpp index cbededfee2..9d62a9eb57 100644 --- a/src/testlib/qtestresult.cpp +++ b/src/testlib/qtestresult.cpp @@ -277,7 +277,7 @@ bool QTestResult::compare(bool success, const char *failureMsg, if (success && QTest::expectFailMode) { qsnprintf(msg, 1024, "QCOMPARE(%s, %s) returned TRUE unexpectedly.", actual, expected); } else if (val1 || val2) { - qsnprintf(msg, 1024, "%s\n Actual (%s): %s\n Expected (%s): %s", + qsnprintf(msg, 1024, "%s\n Actual (%s): %s\n Expected (%s): %s", failureMsg, actual, val1 ? val1 : "", expected, val2 ? val2 : ""); diff --git a/tests/auto/testlib/selftests/expected_cmptest.lightxml b/tests/auto/testlib/selftests/expected_cmptest.lightxml index d1cccd4bd2..83b2e6e137 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.lightxml +++ b/tests/auto/testlib/selftests/expected_cmptest.lightxml @@ -15,7 +15,7 @@ @@ -24,19 +24,19 @@ ) + Actual (actual): QVariant(PhonyClass,) Expected (expected): QVariant(PhonyClass,)]]> @@ -50,31 +50,31 @@ + Actual (opA): 'string3' + Expected (opB): 'DIFFERS']]> + Actual (opA): 'string3' + Expected (opB): 'DIFFERS']]> @@ -85,13 +85,13 @@ @@ -100,7 +100,7 @@ @@ -115,13 +115,13 @@ @@ -130,13 +130,13 @@ diff --git a/tests/auto/testlib/selftests/expected_cmptest.txt b/tests/auto/testlib/selftests/expected_cmptest.txt index fce635ae5a..de666ed8b1 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.txt +++ b/tests/auto/testlib/selftests/expected_cmptest.txt @@ -4,76 +4,76 @@ PASS : tst_Cmptest::initTestCase() PASS : tst_Cmptest::compare_boolfuncs() PASS : tst_Cmptest::compare_pointerfuncs() FAIL! : tst_Cmptest::compare_tostring(int, string) Compared values are not the same - Actual (actual): QVariant(int,123) + Actual (actual): QVariant(int,123) Expected (expected): QVariant(QString,hi) Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(214)] PASS : tst_Cmptest::compare_tostring(both invalid) FAIL! : tst_Cmptest::compare_tostring(null hash, invalid) Compared values are not the same - Actual (actual): QVariant(QVariantHash) + Actual (actual): QVariant(QVariantHash) Expected (expected): QVariant() Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(214)] FAIL! : tst_Cmptest::compare_tostring(string, null user type) Compared values are not the same - Actual (actual): QVariant(QString,A simple string) + Actual (actual): QVariant(QString,A simple string) Expected (expected): QVariant(PhonyClass) Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(214)] FAIL! : tst_Cmptest::compare_tostring(both non-null user type) Compared values are not the same - Actual (actual): QVariant(PhonyClass,) + Actual (actual): QVariant(PhonyClass,) Expected (expected): QVariant(PhonyClass,) Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(214)] PASS : tst_Cmptest::compareQStringLists(empty lists) PASS : tst_Cmptest::compareQStringLists(equal lists) FAIL! : tst_Cmptest::compareQStringLists(last item different) Compared QStringLists differ at index 2. - Actual (opA) : 'string3' - Expected (opB) : 'DIFFERS' + Actual (opA): 'string3' + Expected (opB): 'DIFFERS' Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(308)] FAIL! : tst_Cmptest::compareQStringLists(second-last item different) Compared QStringLists differ at index 2. - Actual (opA) : 'string3' - Expected (opB) : 'DIFFERS' + Actual (opA): 'string3' + Expected (opB): 'DIFFERS' Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(308)] FAIL! : tst_Cmptest::compareQStringLists(prefix) Compared QStringLists have different sizes. - Actual (opA) size : '2' + Actual (opA) size: '2' Expected (opB) size: '1' Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(308)] FAIL! : tst_Cmptest::compareQStringLists(short list second) Compared QStringLists have different sizes. - Actual (opA) size : '12' + Actual (opA) size: '12' Expected (opB) size: '1' Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(308)] FAIL! : tst_Cmptest::compareQStringLists(short list first) Compared QStringLists have different sizes. - Actual (opA) size : '1' + Actual (opA) size: '1' Expected (opB) size: '12' Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(308)] PASS : tst_Cmptest::compareQPixmaps(both null) FAIL! : tst_Cmptest::compareQPixmaps(one null) Compared QPixmaps differ. - Actual (opA).isNull() : 1 + Actual (opA).isNull(): 1 Expected (opB).isNull(): 0 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(333)] FAIL! : tst_Cmptest::compareQPixmaps(other null) Compared QPixmaps differ. - Actual (opA).isNull() : 0 + Actual (opA).isNull(): 0 Expected (opB).isNull(): 1 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(333)] PASS : tst_Cmptest::compareQPixmaps(equal) FAIL! : tst_Cmptest::compareQPixmaps(different size) Compared QPixmaps differ in size. - Actual (opA) : 11x20 + Actual (opA): 11x20 Expected (opB): 20x20 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(333)] FAIL! : tst_Cmptest::compareQPixmaps(different pixels) Compared values are not the same Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(333)] PASS : tst_Cmptest::compareQImages(both null) FAIL! : tst_Cmptest::compareQImages(one null) Compared QImages differ. - Actual (opA).isNull() : 1 + Actual (opA).isNull(): 1 Expected (opB).isNull(): 0 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(360)] FAIL! : tst_Cmptest::compareQImages(other null) Compared QImages differ. - Actual (opA).isNull() : 0 + Actual (opA).isNull(): 0 Expected (opB).isNull(): 1 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(360)] PASS : tst_Cmptest::compareQImages(equal) FAIL! : tst_Cmptest::compareQImages(different size) Compared QImages differ in size. - Actual (opA) : 11x20 + Actual (opA): 11x20 Expected (opB): 20x20 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(360)] FAIL! : tst_Cmptest::compareQImages(different format) Compared QImages differ in format. - Actual (opA) : 6 + Actual (opA): 6 Expected (opB): 3 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/cmptest/tst_cmptest.cpp(360)] FAIL! : tst_Cmptest::compareQImages(different pixels) Compared values are not the same diff --git a/tests/auto/testlib/selftests/expected_cmptest.xml b/tests/auto/testlib/selftests/expected_cmptest.xml index 90bb313518..339ef01e2d 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.xml +++ b/tests/auto/testlib/selftests/expected_cmptest.xml @@ -17,7 +17,7 @@ @@ -26,19 +26,19 @@ ) + Actual (actual): QVariant(PhonyClass,) Expected (expected): QVariant(PhonyClass,)]]> @@ -52,31 +52,31 @@ + Actual (opA): 'string3' + Expected (opB): 'DIFFERS']]> + Actual (opA): 'string3' + Expected (opB): 'DIFFERS']]> @@ -87,13 +87,13 @@ @@ -102,7 +102,7 @@ @@ -117,13 +117,13 @@ @@ -132,13 +132,13 @@ diff --git a/tests/auto/testlib/selftests/expected_cmptest.xunitxml b/tests/auto/testlib/selftests/expected_cmptest.xunitxml index 00f5f7f480..33e78a5290 100644 --- a/tests/auto/testlib/selftests/expected_cmptest.xunitxml +++ b/tests/auto/testlib/selftests/expected_cmptest.xunitxml @@ -9,59 +9,59 @@ + Actual (opA): 'string3' + Expected (opB): 'DIFFERS'" result="fail"/> + Actual (opA): 'string3' + Expected (opB): 'DIFFERS'" result="fail"/> diff --git a/tests/auto/testlib/selftests/expected_datetime.lightxml b/tests/auto/testlib/selftests/expected_datetime.lightxml index 17fd48a196..39af3a2fcf 100644 --- a/tests/auto/testlib/selftests/expected_datetime.lightxml +++ b/tests/auto/testlib/selftests/expected_datetime.lightxml @@ -8,7 +8,7 @@ @@ -19,13 +19,13 @@ diff --git a/tests/auto/testlib/selftests/expected_datetime.txt b/tests/auto/testlib/selftests/expected_datetime.txt index 239886ca8e..6bd4103284 100644 --- a/tests/auto/testlib/selftests/expected_datetime.txt +++ b/tests/auto/testlib/selftests/expected_datetime.txt @@ -2,16 +2,16 @@ Config: Using QTest library @INSERT_QT_VERSION_HERE@, Qt @INSERT_QT_VERSION_HERE@ PASS : tst_DateTime::initTestCase() FAIL! : tst_DateTime::dateTime() Compared values are not the same - Actual (local): 2000/05/03 04:03:04.000[local time] + Actual (local): 2000/05/03 04:03:04.000[local time] Expected (utc): 2000/05/03 04:03:04.000[UTC] Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/datetime/tst_datetime.cpp(33)] PASS : tst_DateTime::qurl(empty urls) FAIL! : tst_DateTime::qurl(empty rhs) Compared values are not the same - Actual (operandA): http://example.com + Actual (operandA): http://example.com Expected (operandB): Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/datetime/tst_datetime.cpp(41)] FAIL! : tst_DateTime::qurl(empty lhs) Compared values are not the same - Actual (operandA): + Actual (operandA): Expected (operandB): http://example.com Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/datetime/tst_datetime.cpp(41)] PASS : tst_DateTime::qurl(same urls) diff --git a/tests/auto/testlib/selftests/expected_datetime.xml b/tests/auto/testlib/selftests/expected_datetime.xml index 747ff13730..a3b7bbdee0 100644 --- a/tests/auto/testlib/selftests/expected_datetime.xml +++ b/tests/auto/testlib/selftests/expected_datetime.xml @@ -10,7 +10,7 @@ @@ -21,13 +21,13 @@ diff --git a/tests/auto/testlib/selftests/expected_datetime.xunitxml b/tests/auto/testlib/selftests/expected_datetime.xunitxml index f25e20674b..b6bb600251 100644 --- a/tests/auto/testlib/selftests/expected_datetime.xunitxml +++ b/tests/auto/testlib/selftests/expected_datetime.xunitxml @@ -7,15 +7,15 @@ diff --git a/tests/auto/testlib/selftests/expected_float.txt b/tests/auto/testlib/selftests/expected_float.txt index 6ebbeffde5..6a7804adc0 100644 --- a/tests/auto/testlib/selftests/expected_float.txt +++ b/tests/auto/testlib/selftests/expected_float.txt @@ -3,28 +3,28 @@ Config: Using QTest library @INSERT_QT_VERSION_HERE@, Qt @INSERT_QT_VERSION_HERE PASS : tst_float::initTestCase() PASS : tst_float::floatComparisons(should SUCCEED 1) FAIL! : tst_float::floatComparisons(should FAIL 1) Compared floats are not the same (fuzzy compare) - Actual (operandLeft): 1 + Actual (operandLeft): 1 Expected (operandRight): 3 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(61)] FAIL! : tst_float::floatComparisons(should FAIL 2) Compared floats are not the same (fuzzy compare) - Actual (operandLeft): 1e-07 + Actual (operandLeft): 1e-07 Expected (operandRight): 3e-07 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(61)] FAIL! : tst_float::floatComparisons(should FAIL 3) Compared floats are not the same (fuzzy compare) - Actual (operandLeft): 99998 + Actual (operandLeft): 99998 Expected (operandRight): 99999 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(61)] PASS : tst_float::floatComparisons(should SUCCEED 2) FAIL! : tst_float::compareFloatTests(1e0) Compared floats are not the same (fuzzy compare) - Actual (t1): 1 + Actual (t1): 1 Expected (t3): 3 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(104)] FAIL! : tst_float::compareFloatTests(1e-7) Compared floats are not the same (fuzzy compare) - Actual (t1): 1e-07 + Actual (t1): 1e-07 Expected (t3): 3e-07 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(104)] FAIL! : tst_float::compareFloatTests(1e+7) Compared floats are not the same (fuzzy compare) - Actual (t1): 1e+07 + Actual (t1): 1e+07 Expected (t3): 3e+07 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/float/tst_float.cpp(104)] PASS : tst_float::cleanupTestCase() diff --git a/tests/auto/testlib/selftests/expected_strcmp.lightxml b/tests/auto/testlib/selftests/expected_strcmp.lightxml index 3e71add066..d5135fd7df 100644 --- a/tests/auto/testlib/selftests/expected_strcmp.lightxml +++ b/tests/auto/testlib/selftests/expected_strcmp.lightxml @@ -20,35 +20,35 @@ diff --git a/tests/auto/testlib/selftests/expected_strcmp.txt b/tests/auto/testlib/selftests/expected_strcmp.txt index a9e51dae5c..804d6b9265 100644 --- a/tests/auto/testlib/selftests/expected_strcmp.txt +++ b/tests/auto/testlib/selftests/expected_strcmp.txt @@ -9,23 +9,23 @@ XFAIL : tst_StrCmp::compareByteArray() Next test should fail XFAIL : tst_StrCmp::compareByteArray() Next test should fail Loc: [./tst_strcmp.cpp(69)] FAIL! : tst_StrCmp::compareByteArray() Compared values are not the same - Actual (a): 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 ... + Actual (a): 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 42 ... Expected (b): 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 ... Loc: [./tst_strcmp.cpp(76)] FAIL! : tst_StrCmp::failByteArray() Compared values are not the same - Actual (QByteArray("abc")): 61 62 63 + Actual (QByteArray("abc")): 61 62 63 Expected (QByteArray("cba")): 63 62 61 Loc: [./tst_strcmp.cpp(82)] FAIL! : tst_StrCmp::failByteArrayNull() Compared values are not the same - Actual (QByteArray("foo")): 66 6F 6F + Actual (QByteArray("foo")): 66 6F 6F Expected (QByteArray()): Loc: [./tst_strcmp.cpp(88)] FAIL! : tst_StrCmp::failByteArrayEmpty() Compared values are not the same - Actual (QByteArray("")): + Actual (QByteArray("")): Expected (QByteArray("foo")): 66 6F 6F Loc: [./tst_strcmp.cpp(93)] FAIL! : tst_StrCmp::failByteArraySingleChars() Compared values are not the same - Actual (QByteArray("6")): 36 + Actual (QByteArray("6")): 36 Expected (QByteArray("7")): 37 Loc: [./tst_strcmp.cpp(100)] PASS : tst_StrCmp::cleanupTestCase() diff --git a/tests/auto/testlib/selftests/expected_strcmp.xml b/tests/auto/testlib/selftests/expected_strcmp.xml index 280eec3c9a..c35509ad7f 100644 --- a/tests/auto/testlib/selftests/expected_strcmp.xml +++ b/tests/auto/testlib/selftests/expected_strcmp.xml @@ -22,35 +22,35 @@ diff --git a/tests/auto/testlib/selftests/expected_strcmp.xunitxml b/tests/auto/testlib/selftests/expected_strcmp.xunitxml index c2b694b8bb..a900e2f17a 100644 --- a/tests/auto/testlib/selftests/expected_strcmp.xunitxml +++ b/tests/auto/testlib/selftests/expected_strcmp.xunitxml @@ -11,27 +11,27 @@ diff --git a/tests/auto/testlib/selftests/expected_subtest.lightxml b/tests/auto/testlib/selftests/expected_subtest.lightxml index e7d8d53efc..b156dc3991 100644 --- a/tests/auto/testlib/selftests/expected_subtest.lightxml +++ b/tests/auto/testlib/selftests/expected_subtest.lightxml @@ -122,7 +122,7 @@ @@ -140,7 +140,7 @@ diff --git a/tests/auto/testlib/selftests/expected_subtest.txt b/tests/auto/testlib/selftests/expected_subtest.txt index 7b29bfc8c3..940eb167fa 100644 --- a/tests/auto/testlib/selftests/expected_subtest.txt +++ b/tests/auto/testlib/selftests/expected_subtest.txt @@ -33,14 +33,14 @@ PASS : tst_Subtest::test3(data0) QDEBUG : tst_Subtest::test3(data1) init test3 data1 QDEBUG : tst_Subtest::test3(data1) test2 test3 data1 FAIL! : tst_Subtest::test3(data1) Compared values are not the same - Actual (str): hello1 + Actual (str): hello1 Expected (QString("hello0")): hello0 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/subtest/tst_subtest.cpp(154)] QDEBUG : tst_Subtest::test3(data1) cleanup test3 data1 QDEBUG : tst_Subtest::test3(data2) init test3 data2 QDEBUG : tst_Subtest::test3(data2) test2 test3 data2 FAIL! : tst_Subtest::test3(data2) Compared values are not the same - Actual (str): hello2 + Actual (str): hello2 Expected (QString("hello0")): hello0 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/subtest/tst_subtest.cpp(154)] QDEBUG : tst_Subtest::test3(data2) cleanup test3 data2 diff --git a/tests/auto/testlib/selftests/expected_subtest.xml b/tests/auto/testlib/selftests/expected_subtest.xml index 8a3846599c..89dd7e3006 100644 --- a/tests/auto/testlib/selftests/expected_subtest.xml +++ b/tests/auto/testlib/selftests/expected_subtest.xml @@ -124,7 +124,7 @@ @@ -142,7 +142,7 @@ diff --git a/tests/auto/testlib/selftests/expected_subtest.xunitxml b/tests/auto/testlib/selftests/expected_subtest.xunitxml index c228dc8f54..6097000e7f 100644 --- a/tests/auto/testlib/selftests/expected_subtest.xunitxml +++ b/tests/auto/testlib/selftests/expected_subtest.xunitxml @@ -38,13 +38,13 @@ diff --git a/tests/auto/testlib/selftests/expected_xunit.lightxml b/tests/auto/testlib/selftests/expected_xunit.lightxml index 71a57373d6..0615f6fd61 100644 --- a/tests/auto/testlib/selftests/expected_xunit.lightxml +++ b/tests/auto/testlib/selftests/expected_xunit.lightxml @@ -17,7 +17,7 @@ diff --git a/tests/auto/testlib/selftests/expected_xunit.txt b/tests/auto/testlib/selftests/expected_xunit.txt index 51c8f89599..88e2949580 100644 --- a/tests/auto/testlib/selftests/expected_xunit.txt +++ b/tests/auto/testlib/selftests/expected_xunit.txt @@ -6,7 +6,7 @@ WARNING: tst_Xunit::testFunc1() just a QWARN() ! PASS : tst_Xunit::testFunc1() QDEBUG : tst_Xunit::testFunc2() a qDebug() call with comment-ending stuff --> FAIL! : tst_Xunit::testFunc2() Compared values are not the same - Actual (2): 2 + Actual (2): 2 Expected (3): 3 Loc: [/home/user/dev/qt5/qtbase/tests/auto/testlib/selftests/xunit/tst_xunit.cpp(74)] SKIP : tst_Xunit::testFunc3() skipping this function! diff --git a/tests/auto/testlib/selftests/expected_xunit.xml b/tests/auto/testlib/selftests/expected_xunit.xml index a1e6b20963..bfd1e9f8fa 100644 --- a/tests/auto/testlib/selftests/expected_xunit.xml +++ b/tests/auto/testlib/selftests/expected_xunit.xml @@ -19,7 +19,7 @@ diff --git a/tests/auto/testlib/selftests/expected_xunit.xunitxml b/tests/auto/testlib/selftests/expected_xunit.xunitxml index e7403443ea..7d133da7a5 100644 --- a/tests/auto/testlib/selftests/expected_xunit.xunitxml +++ b/tests/auto/testlib/selftests/expected_xunit.xunitxml @@ -11,7 +11,7 @@ -- cgit v1.2.3 From a71e12b1709557e9a7263dbf191ec28689ccd992 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Thu, 8 Mar 2012 15:48:23 +1000 Subject: Remove redundant and incorrect comment from QList autotest. Change-Id: I3187d0d8ace120181a4c49bbc68f421ddf5acbe0 Reviewed-by: Rohan McGovern --- tests/auto/corelib/tools/qlist/tst_qlist.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp index fbb821c730..934130d3ee 100644 --- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp +++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp @@ -43,12 +43,6 @@ #include #include -/*! - \class tst_QVector - \internal - \since 4.5 - \brief Test Qt's class QList. - */ class tst_QList : public QObject { Q_OBJECT -- cgit v1.2.3 From 70cb55bc6df486b51addf0c622bf3e77d324abf5 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Mon, 5 Mar 2012 15:05:16 +0100 Subject: Force properties to be applied in the order in which they are specified. Previously, property setting was randomized in order, which means that things like: qproperty-foo: 4; qproperty-bar: 5; where foo may affect bar worked by chance - or not at all - depending on the hash function. Change-Id: Ifb9813ee72842cefb278cbedb644f24b91113f3f Reviewed-by: Olivier Goffart --- src/widgets/styles/qstylesheetstyle.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp index 5c0ee254d4..7a0cc09452 100644 --- a/src/widgets/styles/qstylesheetstyle.cpp +++ b/src/widgets/styles/qstylesheetstyle.cpp @@ -2498,7 +2498,13 @@ void QStyleSheetStyle::setGeometry(QWidget *w) void QStyleSheetStyle::setProperties(QWidget *w) { + // we have two data structures here: a hash of property -> value for lookup, + // and a vector giving properties in the order they are specified. + // + // this means we only set a property once (thanks to the hash) but we set + // properties in the order they are specified. QHash propertyHash; + QVector properties; QVector decls = declarations(styleRules(w), QString()); // run through the declarations in order @@ -2535,10 +2541,17 @@ void QStyleSheetStyle::setProperties(QWidget *w) #endif default: v = decl.d->values.at(0).variant; break; } + + if (propertyHash.contains(property)) { + // we're ignoring the original appearance of this property + properties.remove(properties.indexOf(property)); + } + propertyHash[property] = v; + properties.append(property); } - // apply the values - const QList properties = propertyHash.keys(); + + // apply the values from left to right order for (int i = 0; i < properties.count(); i++) { const QString &property = properties.at(i); w->setProperty(property.toLatin1(), propertyHash[property]); -- cgit v1.2.3 From 16a1d5c81bfaf2103b8584d59f6bbd844fc67985 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Thu, 8 Mar 2012 16:20:31 +1000 Subject: Fix compile warnings in QCoreApplication autotest. - Use const_cast to avoid "deprecated conversion from string constant to 'char*'" warning when building argv arrays from string literals. - Use Q_UNUSED to avoid warnings on unused local variables. Change-Id: Idd2c8279adc102b6ebc6af7486ba26fe9ed4e7c1 Reviewed-by: Rohan McGovern --- .../qcoreapplication/tst_qcoreapplication.cpp | 39 ++++++++++++---------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp index 572c2fdfd1..84d723ca61 100644 --- a/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp +++ b/tests/auto/corelib/kernel/qcoreapplication/tst_qcoreapplication.cpp @@ -85,7 +85,7 @@ public: void tst_QCoreApplication::sendEventsOnProcessEvents() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); EventSpy spy; @@ -107,7 +107,7 @@ void tst_QCoreApplication::getSetCheck() // Test the property { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); QCOMPARE(app.property("applicationVersion").toString(), v); } @@ -119,7 +119,7 @@ void tst_QCoreApplication::getSetCheck() void tst_QCoreApplication::qAppName() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); QVERIFY(!::qAppName().isEmpty()); } @@ -131,7 +131,7 @@ void tst_QCoreApplication::argc() #endif { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); QCOMPARE(argc, 1); QCOMPARE(app.arguments().count(), 1); @@ -139,7 +139,10 @@ void tst_QCoreApplication::argc() { int argc = 4; - char *argv[] = { "tst_qcoreapplication", "arg1", "arg2", "arg3" }; + char *argv[] = { const_cast("tst_qcoreapplication"), + const_cast("arg1"), + const_cast("arg2"), + const_cast("arg3") }; QCoreApplication app(argc, argv); QCOMPARE(argc, 4); QCOMPARE(app.arguments().count(), 4); @@ -155,7 +158,8 @@ void tst_QCoreApplication::argc() { int argc = 2; - char *argv[] = { "tst_qcoreapplication", "-qmljsdebugger=port:3768,block" }; + char *argv[] = { const_cast("tst_qcoreapplication"), + const_cast("-qmljsdebugger=port:3768,block") }; QCoreApplication app(argc, argv); QCOMPARE(argc, 1); QCOMPARE(app.arguments().count(), 1); @@ -187,7 +191,7 @@ public: void tst_QCoreApplication::postEvent() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); EventSpy spy; @@ -272,7 +276,7 @@ void tst_QCoreApplication::postEvent() void tst_QCoreApplication::removePostedEvents() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); EventSpy spy; @@ -451,7 +455,7 @@ public: void tst_QCoreApplication::deliverInDefinedOrder() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); DeliverInDefinedOrderObject obj(&app); @@ -491,7 +495,7 @@ public: void tst_QCoreApplication::globalPostedEventsCount() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); QCoreApplication::sendPostedEvents(); @@ -537,7 +541,7 @@ public: void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); ProcessEventsAlwaysSendsPostedEventsObject object; @@ -555,7 +559,7 @@ void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents() void tst_QCoreApplication::reexec() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); // exec once @@ -570,7 +574,7 @@ void tst_QCoreApplication::reexec() void tst_QCoreApplication::execAfterExit() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); app.exit(1); @@ -581,7 +585,7 @@ void tst_QCoreApplication::execAfterExit() void tst_QCoreApplication::eventLoopExecAfterExit() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); // exec once and exit @@ -633,8 +637,7 @@ void tst_QCoreApplication::customEventDispatcher() QVERIFY(!weak_ed.isNull()); { int argc = 1; - char *arg0 = "tst_qcoreapplication"; - char *argv[] = { arg0 }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); // instantiating app should not overwrite the ED QCOMPARE(QCoreApplication::eventDispatcher(), ed); @@ -728,10 +731,12 @@ private slots: QCOMPARE(privateClass->quitLockRef.load(), 2); JobObject *job3 = new JobObject(job2); + Q_UNUSED(job3); QCOMPARE(privateClass->quitLockRef.load(), 3); JobObject *job4 = new JobObject(job2); + Q_UNUSED(job4); QCOMPARE(privateClass->quitLockRef.load(), 4); @@ -747,7 +752,7 @@ private slots: void tst_QCoreApplication::testQuitLock() { int argc = 1; - char *argv[] = { "tst_qcoreapplication" }; + char *argv[] = { const_cast("tst_qcoreapplication") }; QCoreApplication app(argc, argv); QuitTester tester; -- cgit v1.2.3 From 0e905e91382ac5903c8784a28ed6b5a15adf404e Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Thu, 8 Mar 2012 15:52:03 +1000 Subject: Remove outdated assumption from QVariant autotest. The test was assuming that "data()" is a special function in autotests, but that hasn't been the case since early prototypes of testlib. Change-Id: Ic24cf5dc539b55d12eba0a6ab17173e2ed698f21 Reviewed-by: Rohan McGovern --- tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index d78759e923..655c714322 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -228,7 +228,7 @@ private slots: void podUserType(); - void data_(); // data is virtual function in QtTestCase + void data(); void constData(); void saveLoadCustomTypes(); @@ -2221,7 +2221,7 @@ void tst_QVariant::basicUserType() QCOMPARE(v.toByteArray(), QByteArray("bar")); } -void tst_QVariant::data_() +void tst_QVariant::data() { QVariant v; -- cgit v1.2.3 From 37546c563e32960fbf50d4a692993721ae2da273 Mon Sep 17 00:00:00 2001 From: Vincent A Date: Wed, 7 Mar 2012 19:24:29 +0100 Subject: Support Growl >=1.3 in QSystemTrayIcon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The app name has changed in Growl 1.3, but the id stays the same. Also don't send notifications if Growl is not running to follow recommendations. Change-Id: I31ff7df272b4af1b4f1e4db80c47e7ba75038dec Reviewed-by: Morten Johan Sørvig --- src/widgets/util/qsystemtrayicon_mac.mm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/widgets/util/qsystemtrayicon_mac.mm b/src/widgets/util/qsystemtrayicon_mac.mm index 59342cb8a4..7f7d7cdc6a 100644 --- a/src/widgets/util/qsystemtrayicon_mac.mm +++ b/src/widgets/util/qsystemtrayicon_mac.mm @@ -260,7 +260,11 @@ void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString notificationIcon = QLatin1String("image from location \"file://") + notificationIconFile.fileName() + QLatin1String("\""); } const QString script(QLatin1String( - "tell application \"GrowlHelperApp\"\n" + "tell application \"System Events\"\n" + "set isRunning to (count of (every process whose bundle identifier is \"com.Growl.GrowlHelperApp\")) > 0\n" + "end tell\n" + "if isRunning\n" + "tell application id \"com.Growl.GrowlHelperApp\"\n" "-- Make a list of all the notification types (all)\n" "set the allNotificationsList to {\"") + notificationType + QLatin1String("\"}\n" @@ -276,7 +280,7 @@ void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString QLatin1String("\" description \"") + message + QLatin1String("\" application name \"") + notificationApp + QLatin1String("\" ") + notificationIcon + - QLatin1String("\nend tell")); + QLatin1String("\nend tell\nend if")); qt_mac_execute_apple_script(script, 0); #elif 0 Q_Q(QSystemTrayIcon); -- cgit v1.2.3 From 2e886cfbcb0ae80a3545943d917352eb54804e98 Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Thu, 8 Mar 2012 16:05:03 -0800 Subject: Move tst_qicon.cpp and tst_qpixmapfilter.cpp to QtWidgets QIcon and QPixmapFilter belong to QtWidgets instead of QtGui. Change-Id: I6d82811e04046edb0cc67c55970c161612e86d3f Reviewed-by: Sergio Ahumada Reviewed-by: Gunnar Sletta Reviewed-by: Friedemann Kleint --- tests/auto/gui/image/image.pro | 2 - tests/auto/gui/image/qicon/.gitignore | 1 - .../testtheme/16x16/actions/appointment-new.png | Bin 897 -> 0 bytes .../testtheme/22x22/actions/appointment-new.png | Bin 1411 -> 0 bytes .../testtheme/32x32/actions/appointment-new.png | Bin 2399 -> 0 bytes .../gui/image/qicon/icons/testtheme/index.theme | 492 ---------------- .../icons/testtheme/scalable/actions/svg-only.svg | 425 -------------- .../themeparent/16x16/actions/address-book-new.png | Bin 796 -> 0 bytes .../themeparent/16x16/actions/appointment-new.png | Bin 897 -> 0 bytes .../themeparent/22x22/actions/address-book-new.png | Bin 924 -> 0 bytes .../themeparent/22x22/actions/appointment-new.png | Bin 1411 -> 0 bytes .../themeparent/32x32/actions/address-book-new.png | Bin 1897 -> 0 bytes .../themeparent/32x32/actions/appointment-new.png | Bin 2399 -> 0 bytes .../gui/image/qicon/icons/themeparent/index.theme | 492 ---------------- .../scalable/actions/address-book-new.svg | 389 ------------- .../scalable/actions/appointment-new.svg | 425 -------------- tests/auto/gui/image/qicon/image.png | Bin 14743 -> 0 bytes tests/auto/gui/image/qicon/qicon.pro | 12 - tests/auto/gui/image/qicon/rect.png | Bin 175 -> 0 bytes tests/auto/gui/image/qicon/tst_qicon.cpp | 637 --------------------- tests/auto/gui/image/qicon/tst_qicon.qrc | 20 - tests/auto/gui/image/qpixmapfilter/noise.png | Bin 7517 -> 0 bytes .../auto/gui/image/qpixmapfilter/qpixmapfilter.pro | 14 - .../gui/image/qpixmapfilter/tst_qpixmapfilter.cpp | 447 --------------- tests/auto/widgets/effects/effects.pro | 1 + tests/auto/widgets/effects/qpixmapfilter/noise.png | Bin 0 -> 7517 bytes .../effects/qpixmapfilter/qpixmapfilter.pro | 14 + .../effects/qpixmapfilter/tst_qpixmapfilter.cpp | 447 +++++++++++++++ tests/auto/widgets/kernel/kernel.pro | 1 + tests/auto/widgets/kernel/qicon/.gitignore | 1 + .../testtheme/16x16/actions/appointment-new.png | Bin 0 -> 897 bytes .../testtheme/22x22/actions/appointment-new.png | Bin 0 -> 1411 bytes .../testtheme/32x32/actions/appointment-new.png | Bin 0 -> 2399 bytes .../kernel/qicon/icons/testtheme/index.theme | 492 ++++++++++++++++ .../icons/testtheme/scalable/actions/svg-only.svg | 425 ++++++++++++++ .../themeparent/16x16/actions/address-book-new.png | Bin 0 -> 796 bytes .../themeparent/16x16/actions/appointment-new.png | Bin 0 -> 897 bytes .../themeparent/22x22/actions/address-book-new.png | Bin 0 -> 924 bytes .../themeparent/22x22/actions/appointment-new.png | Bin 0 -> 1411 bytes .../themeparent/32x32/actions/address-book-new.png | Bin 0 -> 1897 bytes .../themeparent/32x32/actions/appointment-new.png | Bin 0 -> 2399 bytes .../kernel/qicon/icons/themeparent/index.theme | 492 ++++++++++++++++ .../scalable/actions/address-book-new.svg | 389 +++++++++++++ .../scalable/actions/appointment-new.svg | 425 ++++++++++++++ tests/auto/widgets/kernel/qicon/image.png | Bin 0 -> 14743 bytes tests/auto/widgets/kernel/qicon/qicon.pro | 12 + tests/auto/widgets/kernel/qicon/rect.png | Bin 0 -> 175 bytes tests/auto/widgets/kernel/qicon/tst_qicon.cpp | 637 +++++++++++++++++++++ tests/auto/widgets/kernel/qicon/tst_qicon.qrc | 20 + 49 files changed, 3356 insertions(+), 3356 deletions(-) delete mode 100644 tests/auto/gui/image/qicon/.gitignore delete mode 100644 tests/auto/gui/image/qicon/icons/testtheme/16x16/actions/appointment-new.png delete mode 100644 tests/auto/gui/image/qicon/icons/testtheme/22x22/actions/appointment-new.png delete mode 100644 tests/auto/gui/image/qicon/icons/testtheme/32x32/actions/appointment-new.png delete mode 100644 tests/auto/gui/image/qicon/icons/testtheme/index.theme delete mode 100644 tests/auto/gui/image/qicon/icons/testtheme/scalable/actions/svg-only.svg delete mode 100644 tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/address-book-new.png delete mode 100644 tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/appointment-new.png delete mode 100644 tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/address-book-new.png delete mode 100644 tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/appointment-new.png delete mode 100644 tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/address-book-new.png delete mode 100644 tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/appointment-new.png delete mode 100644 tests/auto/gui/image/qicon/icons/themeparent/index.theme delete mode 100644 tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/address-book-new.svg delete mode 100644 tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/appointment-new.svg delete mode 100644 tests/auto/gui/image/qicon/image.png delete mode 100644 tests/auto/gui/image/qicon/qicon.pro delete mode 100644 tests/auto/gui/image/qicon/rect.png delete mode 100644 tests/auto/gui/image/qicon/tst_qicon.cpp delete mode 100644 tests/auto/gui/image/qicon/tst_qicon.qrc delete mode 100644 tests/auto/gui/image/qpixmapfilter/noise.png delete mode 100644 tests/auto/gui/image/qpixmapfilter/qpixmapfilter.pro delete mode 100644 tests/auto/gui/image/qpixmapfilter/tst_qpixmapfilter.cpp create mode 100644 tests/auto/widgets/effects/qpixmapfilter/noise.png create mode 100644 tests/auto/widgets/effects/qpixmapfilter/qpixmapfilter.pro create mode 100644 tests/auto/widgets/effects/qpixmapfilter/tst_qpixmapfilter.cpp create mode 100644 tests/auto/widgets/kernel/qicon/.gitignore create mode 100644 tests/auto/widgets/kernel/qicon/icons/testtheme/16x16/actions/appointment-new.png create mode 100644 tests/auto/widgets/kernel/qicon/icons/testtheme/22x22/actions/appointment-new.png create mode 100644 tests/auto/widgets/kernel/qicon/icons/testtheme/32x32/actions/appointment-new.png create mode 100644 tests/auto/widgets/kernel/qicon/icons/testtheme/index.theme create mode 100644 tests/auto/widgets/kernel/qicon/icons/testtheme/scalable/actions/svg-only.svg create mode 100644 tests/auto/widgets/kernel/qicon/icons/themeparent/16x16/actions/address-book-new.png create mode 100644 tests/auto/widgets/kernel/qicon/icons/themeparent/16x16/actions/appointment-new.png create mode 100644 tests/auto/widgets/kernel/qicon/icons/themeparent/22x22/actions/address-book-new.png create mode 100644 tests/auto/widgets/kernel/qicon/icons/themeparent/22x22/actions/appointment-new.png create mode 100644 tests/auto/widgets/kernel/qicon/icons/themeparent/32x32/actions/address-book-new.png create mode 100644 tests/auto/widgets/kernel/qicon/icons/themeparent/32x32/actions/appointment-new.png create mode 100644 tests/auto/widgets/kernel/qicon/icons/themeparent/index.theme create mode 100644 tests/auto/widgets/kernel/qicon/icons/themeparent/scalable/actions/address-book-new.svg create mode 100644 tests/auto/widgets/kernel/qicon/icons/themeparent/scalable/actions/appointment-new.svg create mode 100644 tests/auto/widgets/kernel/qicon/image.png create mode 100644 tests/auto/widgets/kernel/qicon/qicon.pro create mode 100644 tests/auto/widgets/kernel/qicon/rect.png create mode 100644 tests/auto/widgets/kernel/qicon/tst_qicon.cpp create mode 100644 tests/auto/widgets/kernel/qicon/tst_qicon.qrc diff --git a/tests/auto/gui/image/image.pro b/tests/auto/gui/image/image.pro index fa8f8df29d..5a03063f47 100644 --- a/tests/auto/gui/image/image.pro +++ b/tests/auto/gui/image/image.pro @@ -5,11 +5,9 @@ SUBDIRS=\ qpixmap \ qpixmapcache \ qimage \ - qpixmapfilter \ qimageiohandler \ qimagewriter \ qmovie \ - qicon \ qpicture \ !contains(QT_CONFIG, private_tests): SUBDIRS -= \ diff --git a/tests/auto/gui/image/qicon/.gitignore b/tests/auto/gui/image/qicon/.gitignore deleted file mode 100644 index c101ef9d28..0000000000 --- a/tests/auto/gui/image/qicon/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qicon diff --git a/tests/auto/gui/image/qicon/icons/testtheme/16x16/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/testtheme/16x16/actions/appointment-new.png deleted file mode 100644 index 18b7c6781e..0000000000 Binary files a/tests/auto/gui/image/qicon/icons/testtheme/16x16/actions/appointment-new.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/icons/testtheme/22x22/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/testtheme/22x22/actions/appointment-new.png deleted file mode 100644 index d676ffd463..0000000000 Binary files a/tests/auto/gui/image/qicon/icons/testtheme/22x22/actions/appointment-new.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/icons/testtheme/32x32/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/testtheme/32x32/actions/appointment-new.png deleted file mode 100644 index 85daef3b0b..0000000000 Binary files a/tests/auto/gui/image/qicon/icons/testtheme/32x32/actions/appointment-new.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/icons/testtheme/index.theme b/tests/auto/gui/image/qicon/icons/testtheme/index.theme deleted file mode 100644 index e18736ab43..0000000000 --- a/tests/auto/gui/image/qicon/icons/testtheme/index.theme +++ /dev/null @@ -1,492 +0,0 @@ -[Icon Theme] -_Name=Test -_Comment=Test Theme -Inherits=crystalsvg, themeparent -Example=x-directory-normal - -# KDE Specific Stuff -DisplayDepth=32 -LinkOverlay=link_overlay -LockOverlay=lock_overlay -ZipOverlay=zip_overlay -DesktopDefault=48 -DesktopSizes=16,22,32,48,64,72,96,128 -ToolbarDefault=22 -ToolbarSizes=16,22,32,48 -MainToolbarDefault=22 -MainToolbarSizes=16,22,32,48 -SmallDefault=16 -SmallSizes=16 -PanelDefault=32 -PanelSizes=16,22,32,48,64,72,96,128 - -# Directory list -Directories=16x16/actions,16x16/apps,16x16/categories,16x16/devices,16x16/emblems,16x16/emotes,16x16/mimetypes,16x16/places,16x16/status,22x22/actions,22x22/apps,22x22/categories,22x22/devices,22x22/emblems,22x22/emotes,22x22/mimetypes,22x22/places,22x22/status,24x24/actions,24x24/apps,24x24/categories,24x24/devices,24x24/emblems,24x24/emotes,24x24/mimetypes,24x24/places,24x24/status,32x32/actions,32x32/apps,32x32/categories,32x32/devices,32x32/emblems,32x32/emotes,32x32/mimetypes,32x32/places,32x32/status,48x48/actions,48x48/apps,48x48/categories,48x48/devices,48x48/emblems,48x48/emotes,48x48/mimetypes,48x48/places,48x48/status,64x64/actions,64x64/apps,64x64/categories,64x64/devices,64x64/emblems,64x64/emotes,64x64/mimetypes,64x64/places,64x64/status,72x72/actions,72x72/apps,72x72/categories,72x72/devices,72x72/emblems,72x72/emotes,72x72/mimetypes,72x72/places,72x72/status,96x96/actions,96x96/apps,96x96/categories,96x96/devices,96x96/emblems,96x96/emotes,96x96/mimetypes,96x96/places,96x96/status,128x128/actions,128x128/apps,128x128/categories,128x128/devices,128x128/emblems,128x128/emotes,128x128/mimetypes,128x128/places,128x128/status,scalable/actions,scalable/apps,scalable/categories,scalable/devices,scalable/emblems,scalable/emotes,scalable/mimetypes,scalable/places,scalable/status - -[16x16/actions] -Size=16 -Context=Actions -Type=Fixed - -[16x16/apps] -Size=16 -Context=Applications -Type=Fixed - -[16x16/categories] -Size=16 -Context=Categories -Type=Fixed - -[16x16/devices] -Size=16 -Context=Devices -Type=Fixed - -[16x16/emblems] -Size=16 -Context=Emblems -Type=Fixed - -[16x16/emotes] -Size=16 -Context=Emotes -Type=Fixed - -[16x16/mimetypes] -Size=16 -Context=MimeTypes -Type=Fixed - -[16x16/places] -Size=16 -Context=Places -Type=Fixed - -[16x16/status] -Size=16 -Context=Status -Type=Fixed - -[22x22/actions] -Size=22 -Context=Actions -Type=Fixed - -[22x22/apps] -Size=22 -Context=Applications -Type=Fixed - -[22x22/categories] -Size=22 -Context=Categories -Type=Fixed - -[22x22/devices] -Size=22 -Context=Devices -Type=Fixed - -[22x22/emblems] -Size=22 -Context=Emblems -Type=Fixed - -[22x22/emotes] -Size=22 -Context=Emotes -Type=Fixed - -[22x22/mimetypes] -Size=22 -Context=MimeTypes -Type=Fixed - -[22x22/places] -Size=22 -Context=Places -Type=Fixed - -[22x22/status] -Size=22 -Context=Status -Type=Fixed - -[24x24/actions] -Size=24 -Context=Actions -Type=Fixed - -[24x24/apps] -Size=24 -Context=Applications -Type=Fixed - -[24x24/categories] -Size=24 -Context=Categories -Type=Fixed - -[24x24/devices] -Size=24 -Context=Devices -Type=Fixed - -[24x24/emblems] -Size=24 -Context=Emblems -Type=Fixed - -[24x24/emotes] -Size=24 -Context=Emotes -Type=Fixed - -[24x24/mimetypes] -Size=24 -Context=MimeTypes -Type=Fixed - -[24x24/places] -Size=24 -Context=Places -Type=Fixed - -[24x24/status] -Size=24 -Context=Status -Type=Fixed - -[32x32/actions] -Size=32 -Context=Actions -Type=Fixed - -[32x32/apps] -Size=32 -Context=Applications -Type=Fixed - -[32x32/categories] -Size=32 -Context=Categories -Type=Fixed - -[32x32/devices] -Size=32 -Context=Devices -Type=Fixed - -[32x32/emblems] -Size=32 -Context=Emblems -Type=Fixed - -[32x32/emotes] -Size=32 -Context=Emotes -Type=Fixed - -[32x32/mimetypes] -Size=32 -Context=MimeTypes -Type=Fixed - -[32x32/places] -Size=32 -Context=Places -Type=Fixed - -[32x32/status] -Size=32 -Context=Status -Type=Fixed - -[48x48/actions] -Size=48 -Context=Actions -Type=Fixed - -[48x48/apps] -Size=48 -Context=Applications -Type=Fixed - -[48x48/categories] -Size=48 -Context=Categories -Type=Fixed - -[48x48/devices] -Size=48 -Context=Devices -Type=Fixed - -[48x48/emblems] -Size=48 -Context=Emblems -Type=Fixed - -[48x48/emotes] -Size=48 -Context=Emotes -Type=Fixed - -[48x48/mimetypes] -Size=48 -Context=MimeTypes -Type=Fixed - -[48x48/places] -Size=48 -Context=Places -Type=Fixed - -[48x48/status] -Size=48 -Context=Status -Type=Fixed - -[64x64/actions] -Size=64 -Context=Actions -Type=Fixed - -[64x64/apps] -Size=64 -Context=Applications -Type=Fixed - -[64x64/categories] -Size=64 -Context=Categories -Type=Fixed - -[64x64/devices] -Size=64 -Context=Devices -Type=Fixed - -[64x64/emblems] -Size=64 -Context=Emblems -Type=Fixed - -[64x64/emotes] -Size=64 -Context=Emotes -Type=Fixed - -[64x64/mimetypes] -Size=64 -Context=MimeTypes -Type=Fixed - -[64x64/places] -Size=64 -Context=Places -Type=Fixed - -[64x64/status] -Size=64 -Context=Status -Type=Fixed - -[72x72/actions] -Size=72 -Context=Actions -Type=Fixed - -[72x72/apps] -Size=72 -Context=Applications -Type=Fixed - -[72x72/categories] -Size=72 -Context=Categories -Type=Fixed - -[72x72/devices] -Size=72 -Context=Devices -Type=Fixed - -[72x72/emblems] -Size=72 -Context=Emblems -Type=Fixed - -[72x72/emotes] -Size=72 -Context=Emotes -Type=Fixed - -[72x72/mimetypes] -Size=72 -Context=MimeTypes -Type=Fixed - -[72x72/places] -Size=72 -Context=Places -Type=Fixed - -[72x72/status] -Size=72 -Context=Status -Type=Fixed - -[96x96/actions] -Size=96 -Context=Actions -Type=Fixed - -[96x96/apps] -Size=96 -Context=Applications -Type=Fixed - -[96x96/categories] -Size=96 -Context=Categories -Type=Fixed - -[96x96/devices] -Size=96 -Context=Devices -Type=Fixed - -[96x96/emblems] -Size=96 -Context=Emblems -Type=Fixed - -[96x96/emotes] -Size=96 -Context=Emotes -Type=Fixed - -[96x96/mimetypes] -Size=96 -Context=MimeTypes -Type=Fixed - -[96x96/places] -Size=96 -Context=Places -Type=Fixed - -[96x96/status] -Size=96 -Context=Status -Type=Fixed - -[128x128/actions] -Size=128 -Context=Actions -Type=Fixed - -[128x128/apps] -Size=128 -Context=Applications -Type=Fixed - -[128x128/categories] -Size=128 -Context=Categories -Type=Fixed - -[128x128/devices] -Size=128 -Context=Devices -Type=Fixed - -[128x128/emblems] -Size=128 -Context=Emblems -Type=Fixed - -[128x128/emotes] -Size=128 -Context=Emotes -Type=Fixed - -[128x128/mimetypes] -Size=128 -Context=MimeTypes -Type=Fixed - -[128x128/places] -Size=128 -Context=Places -Type=Fixed - -[128x128/status] -Size=128 -Context=Status -Type=Fixed - -[scalable/actions] -Size=48 -Context=Actions -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/apps] -Size=48 -Context=Applications -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/categories] -Size=48 -Context=Categories -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/devices] -Size=48 -Context=Devices -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/emblems] -Size=48 -Context=Emblems -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/emotes] -Size=48 -Context=Emotes -Type=Scalable -Minsize=32 -MaxSize=256 - -[scalable/mimetypes] -Size=48 -Context=MimeTypes -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/places] -Size=48 -Context=Places -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/status] -Size=48 -Context=Status -Type=Scalable -MinSize=32 -MaxSize=256 diff --git a/tests/auto/gui/image/qicon/icons/testtheme/scalable/actions/svg-only.svg b/tests/auto/gui/image/qicon/icons/testtheme/scalable/actions/svg-only.svg deleted file mode 100644 index 4cb14f82f0..0000000000 --- a/tests/auto/gui/image/qicon/icons/testtheme/scalable/actions/svg-only.svg +++ /dev/null @@ -1,425 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - New Appointment - - - appointment - new - meeting - rvsp - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/address-book-new.png b/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/address-book-new.png deleted file mode 100644 index 2098cfdf36..0000000000 Binary files a/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/address-book-new.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/appointment-new.png deleted file mode 100644 index 18b7c6781e..0000000000 Binary files a/tests/auto/gui/image/qicon/icons/themeparent/16x16/actions/appointment-new.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/address-book-new.png b/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/address-book-new.png deleted file mode 100644 index fad446cd92..0000000000 Binary files a/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/address-book-new.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/appointment-new.png deleted file mode 100644 index d676ffd463..0000000000 Binary files a/tests/auto/gui/image/qicon/icons/themeparent/22x22/actions/appointment-new.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/address-book-new.png b/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/address-book-new.png deleted file mode 100644 index 420139d307..0000000000 Binary files a/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/address-book-new.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/appointment-new.png b/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/appointment-new.png deleted file mode 100644 index 85daef3b0b..0000000000 Binary files a/tests/auto/gui/image/qicon/icons/themeparent/32x32/actions/appointment-new.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/icons/themeparent/index.theme b/tests/auto/gui/image/qicon/icons/themeparent/index.theme deleted file mode 100644 index e536a0bf2f..0000000000 --- a/tests/auto/gui/image/qicon/icons/themeparent/index.theme +++ /dev/null @@ -1,492 +0,0 @@ -[Icon Theme] -_Name=Test -_Comment=Test Theme -Inherits=gnome,crystalsvg -Example=x-directory-normal - -# KDE Specific Stuff -DisplayDepth=32 -LinkOverlay=link_overlay -LockOverlay=lock_overlay -ZipOverlay=zip_overlay -DesktopDefault=48 -DesktopSizes=16,22,32,48,64,72,96,128 -ToolbarDefault=22 -ToolbarSizes=16,22,32,48 -MainToolbarDefault=22 -MainToolbarSizes=16,22,32,48 -SmallDefault=16 -SmallSizes=16 -PanelDefault=32 -PanelSizes=16,22,32,48,64,72,96,128 - -# Directory list -Directories=16x16/actions,16x16/apps,16x16/categories,16x16/devices,16x16/emblems,16x16/emotes,16x16/mimetypes,16x16/places,16x16/status,22x22/actions,22x22/apps,22x22/categories,22x22/devices,22x22/emblems,22x22/emotes,22x22/mimetypes,22x22/places,22x22/status,24x24/actions,24x24/apps,24x24/categories,24x24/devices,24x24/emblems,24x24/emotes,24x24/mimetypes,24x24/places,24x24/status,32x32/actions,32x32/apps,32x32/categories,32x32/devices,32x32/emblems,32x32/emotes,32x32/mimetypes,32x32/places,32x32/status,48x48/actions,48x48/apps,48x48/categories,48x48/devices,48x48/emblems,48x48/emotes,48x48/mimetypes,48x48/places,48x48/status,64x64/actions,64x64/apps,64x64/categories,64x64/devices,64x64/emblems,64x64/emotes,64x64/mimetypes,64x64/places,64x64/status,72x72/actions,72x72/apps,72x72/categories,72x72/devices,72x72/emblems,72x72/emotes,72x72/mimetypes,72x72/places,72x72/status,96x96/actions,96x96/apps,96x96/categories,96x96/devices,96x96/emblems,96x96/emotes,96x96/mimetypes,96x96/places,96x96/status,128x128/actions,128x128/apps,128x128/categories,128x128/devices,128x128/emblems,128x128/emotes,128x128/mimetypes,128x128/places,128x128/status,scalable/actions,scalable/apps,scalable/categories,scalable/devices,scalable/emblems,scalable/emotes,scalable/mimetypes,scalable/places,scalable/status - -[16x16/actions] -Size=16 -Context=Actions -Type=Fixed - -[16x16/apps] -Size=16 -Context=Applications -Type=Fixed - -[16x16/categories] -Size=16 -Context=Categories -Type=Fixed - -[16x16/devices] -Size=16 -Context=Devices -Type=Fixed - -[16x16/emblems] -Size=16 -Context=Emblems -Type=Fixed - -[16x16/emotes] -Size=16 -Context=Emotes -Type=Fixed - -[16x16/mimetypes] -Size=16 -Context=MimeTypes -Type=Fixed - -[16x16/places] -Size=16 -Context=Places -Type=Fixed - -[16x16/status] -Size=16 -Context=Status -Type=Fixed - -[22x22/actions] -Size=22 -Context=Actions -Type=Fixed - -[22x22/apps] -Size=22 -Context=Applications -Type=Fixed - -[22x22/categories] -Size=22 -Context=Categories -Type=Fixed - -[22x22/devices] -Size=22 -Context=Devices -Type=Fixed - -[22x22/emblems] -Size=22 -Context=Emblems -Type=Fixed - -[22x22/emotes] -Size=22 -Context=Emotes -Type=Fixed - -[22x22/mimetypes] -Size=22 -Context=MimeTypes -Type=Fixed - -[22x22/places] -Size=22 -Context=Places -Type=Fixed - -[22x22/status] -Size=22 -Context=Status -Type=Fixed - -[24x24/actions] -Size=24 -Context=Actions -Type=Fixed - -[24x24/apps] -Size=24 -Context=Applications -Type=Fixed - -[24x24/categories] -Size=24 -Context=Categories -Type=Fixed - -[24x24/devices] -Size=24 -Context=Devices -Type=Fixed - -[24x24/emblems] -Size=24 -Context=Emblems -Type=Fixed - -[24x24/emotes] -Size=24 -Context=Emotes -Type=Fixed - -[24x24/mimetypes] -Size=24 -Context=MimeTypes -Type=Fixed - -[24x24/places] -Size=24 -Context=Places -Type=Fixed - -[24x24/status] -Size=24 -Context=Status -Type=Fixed - -[32x32/actions] -Size=32 -Context=Actions -Type=Fixed - -[32x32/apps] -Size=32 -Context=Applications -Type=Fixed - -[32x32/categories] -Size=32 -Context=Categories -Type=Fixed - -[32x32/devices] -Size=32 -Context=Devices -Type=Fixed - -[32x32/emblems] -Size=32 -Context=Emblems -Type=Fixed - -[32x32/emotes] -Size=32 -Context=Emotes -Type=Fixed - -[32x32/mimetypes] -Size=32 -Context=MimeTypes -Type=Fixed - -[32x32/places] -Size=32 -Context=Places -Type=Fixed - -[32x32/status] -Size=32 -Context=Status -Type=Fixed - -[48x48/actions] -Size=48 -Context=Actions -Type=Fixed - -[48x48/apps] -Size=48 -Context=Applications -Type=Fixed - -[48x48/categories] -Size=48 -Context=Categories -Type=Fixed - -[48x48/devices] -Size=48 -Context=Devices -Type=Fixed - -[48x48/emblems] -Size=48 -Context=Emblems -Type=Fixed - -[48x48/emotes] -Size=48 -Context=Emotes -Type=Fixed - -[48x48/mimetypes] -Size=48 -Context=MimeTypes -Type=Fixed - -[48x48/places] -Size=48 -Context=Places -Type=Fixed - -[48x48/status] -Size=48 -Context=Status -Type=Fixed - -[64x64/actions] -Size=64 -Context=Actions -Type=Fixed - -[64x64/apps] -Size=64 -Context=Applications -Type=Fixed - -[64x64/categories] -Size=64 -Context=Categories -Type=Fixed - -[64x64/devices] -Size=64 -Context=Devices -Type=Fixed - -[64x64/emblems] -Size=64 -Context=Emblems -Type=Fixed - -[64x64/emotes] -Size=64 -Context=Emotes -Type=Fixed - -[64x64/mimetypes] -Size=64 -Context=MimeTypes -Type=Fixed - -[64x64/places] -Size=64 -Context=Places -Type=Fixed - -[64x64/status] -Size=64 -Context=Status -Type=Fixed - -[72x72/actions] -Size=72 -Context=Actions -Type=Fixed - -[72x72/apps] -Size=72 -Context=Applications -Type=Fixed - -[72x72/categories] -Size=72 -Context=Categories -Type=Fixed - -[72x72/devices] -Size=72 -Context=Devices -Type=Fixed - -[72x72/emblems] -Size=72 -Context=Emblems -Type=Fixed - -[72x72/emotes] -Size=72 -Context=Emotes -Type=Fixed - -[72x72/mimetypes] -Size=72 -Context=MimeTypes -Type=Fixed - -[72x72/places] -Size=72 -Context=Places -Type=Fixed - -[72x72/status] -Size=72 -Context=Status -Type=Fixed - -[96x96/actions] -Size=96 -Context=Actions -Type=Fixed - -[96x96/apps] -Size=96 -Context=Applications -Type=Fixed - -[96x96/categories] -Size=96 -Context=Categories -Type=Fixed - -[96x96/devices] -Size=96 -Context=Devices -Type=Fixed - -[96x96/emblems] -Size=96 -Context=Emblems -Type=Fixed - -[96x96/emotes] -Size=96 -Context=Emotes -Type=Fixed - -[96x96/mimetypes] -Size=96 -Context=MimeTypes -Type=Fixed - -[96x96/places] -Size=96 -Context=Places -Type=Fixed - -[96x96/status] -Size=96 -Context=Status -Type=Fixed - -[128x128/actions] -Size=128 -Context=Actions -Type=Fixed - -[128x128/apps] -Size=128 -Context=Applications -Type=Fixed - -[128x128/categories] -Size=128 -Context=Categories -Type=Fixed - -[128x128/devices] -Size=128 -Context=Devices -Type=Fixed - -[128x128/emblems] -Size=128 -Context=Emblems -Type=Fixed - -[128x128/emotes] -Size=128 -Context=Emotes -Type=Fixed - -[128x128/mimetypes] -Size=128 -Context=MimeTypes -Type=Fixed - -[128x128/places] -Size=128 -Context=Places -Type=Fixed - -[128x128/status] -Size=128 -Context=Status -Type=Fixed - -[scalable/actions] -Size=48 -Context=Actions -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/apps] -Size=48 -Context=Applications -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/categories] -Size=48 -Context=Categories -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/devices] -Size=48 -Context=Devices -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/emblems] -Size=48 -Context=Emblems -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/emotes] -Size=48 -Context=Emotes -Type=Scalable -Minsize=32 -MaxSize=256 - -[scalable/mimetypes] -Size=48 -Context=MimeTypes -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/places] -Size=48 -Context=Places -Type=Scalable -MinSize=32 -MaxSize=256 - -[scalable/status] -Size=48 -Context=Status -Type=Scalable -MinSize=32 -MaxSize=256 diff --git a/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/address-book-new.svg b/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/address-book-new.svg deleted file mode 100644 index 600a82c1b0..0000000000 --- a/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/address-book-new.svg +++ /dev/null @@ -1,389 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Addess Book - New - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - - address - contact - book - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/appointment-new.svg b/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/appointment-new.svg deleted file mode 100644 index 4cb14f82f0..0000000000 --- a/tests/auto/gui/image/qicon/icons/themeparent/scalable/actions/appointment-new.svg +++ /dev/null @@ -1,425 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - New Appointment - - - appointment - new - meeting - rvsp - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/auto/gui/image/qicon/image.png b/tests/auto/gui/image/qicon/image.png deleted file mode 100644 index 8d703640c1..0000000000 Binary files a/tests/auto/gui/image/qicon/image.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/qicon.pro b/tests/auto/gui/image/qicon/qicon.pro deleted file mode 100644 index c44c080ced..0000000000 --- a/tests/auto/gui/image/qicon/qicon.pro +++ /dev/null @@ -1,12 +0,0 @@ -CONFIG += testcase -TARGET = tst_qicon - -QT += widgets testlib -SOURCES += tst_qicon.cpp -RESOURCES = tst_qicon.qrc - -wince* { - QT += xml svg - DEPLOYMENT_PLUGIN += qsvg -} -TESTDATA += icons/* *.png *.svg *.svgz diff --git a/tests/auto/gui/image/qicon/rect.png b/tests/auto/gui/image/qicon/rect.png deleted file mode 100644 index b5d3ecbddf..0000000000 Binary files a/tests/auto/gui/image/qicon/rect.png and /dev/null differ diff --git a/tests/auto/gui/image/qicon/tst_qicon.cpp b/tests/auto/gui/image/qicon/tst_qicon.cpp deleted file mode 100644 index 4a9ab93921..0000000000 --- a/tests/auto/gui/image/qicon/tst_qicon.cpp +++ /dev/null @@ -1,637 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the test suite 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 -#include -#include -#include - -Q_DECLARE_METATYPE(QSize) - -class tst_QIcon : public QObject -{ - Q_OBJECT -public: - tst_QIcon(); - -private slots: - void actualSize_data(); // test with 1 pixmap - void actualSize(); - void actualSize2_data(); // test with 2 pixmaps with different aspect ratio - void actualSize2(); - void isNull(); - void swap(); - void bestMatch(); - void cacheKey(); - void detach(); - void addFile(); - void availableSizes(); - void name(); - void streamAvailableSizes_data(); - void streamAvailableSizes(); - void fromTheme(); - - void task184901_badCache(); - void task223279_inconsistentAddFile(); - -private: - bool haveImageFormat(QByteArray const&); - - const static QIcon staticIcon; -}; - -// Creating an icon statically should not cause a crash. -// But we do not officially support this. See QTBUG-8666 -const QIcon tst_QIcon::staticIcon = QIcon::fromTheme("edit-find"); - -bool tst_QIcon::haveImageFormat(QByteArray const& desiredFormat) -{ - return QImageReader::supportedImageFormats().contains(desiredFormat); -} - -tst_QIcon::tst_QIcon() -{ -} - -void tst_QIcon::actualSize_data() -{ - QTest::addColumn("source"); - QTest::addColumn("argument"); - QTest::addColumn("result"); - - // square image - QTest::newRow("resource0") << ":/image.png" << QSize(128, 128) << QSize(128, 128); - QTest::newRow("resource1") << ":/image.png" << QSize( 64, 64) << QSize( 64, 64); - QTest::newRow("resource2") << ":/image.png" << QSize( 32, 64) << QSize( 32, 32); - QTest::newRow("resource3") << ":/image.png" << QSize( 16, 64) << QSize( 16, 16); - QTest::newRow("resource4") << ":/image.png" << QSize( 16, 128) << QSize( 16, 16); - QTest::newRow("resource5") << ":/image.png" << QSize( 128, 16) << QSize( 16, 16); - QTest::newRow("resource6") << ":/image.png" << QSize( 150, 150) << QSize( 128, 128); - // rect image - QTest::newRow("resource7") << ":/rect.png" << QSize( 20, 40) << QSize( 20, 40); - QTest::newRow("resource8") << ":/rect.png" << QSize( 10, 20) << QSize( 10, 20); - QTest::newRow("resource9") << ":/rect.png" << QSize( 15, 50) << QSize( 15, 30); - QTest::newRow("resource10") << ":/rect.png" << QSize( 25, 50) << QSize( 20, 40); - - const QString prefix = QFileInfo(QFINDTESTDATA("icons")).absolutePath() + "/"; - QTest::newRow("external0") << prefix + "image.png" << QSize(128, 128) << QSize(128, 128); - QTest::newRow("external1") << prefix + "image.png" << QSize( 64, 64) << QSize( 64, 64); - QTest::newRow("external2") << prefix + "image.png" << QSize( 32, 64) << QSize( 32, 32); - QTest::newRow("external3") << prefix + "image.png" << QSize( 16, 64) << QSize( 16, 16); - QTest::newRow("external4") << prefix + "image.png" << QSize( 16, 128) << QSize( 16, 16); - QTest::newRow("external5") << prefix + "image.png" << QSize( 128, 16) << QSize( 16, 16); - QTest::newRow("external6") << prefix + "image.png" << QSize( 150, 150) << QSize( 128, 128); - // rect image - QTest::newRow("external7") << ":/rect.png" << QSize( 20, 40) << QSize( 20, 40); - QTest::newRow("external8") << ":/rect.png" << QSize( 10, 20) << QSize( 10, 20); - QTest::newRow("external9") << ":/rect.png" << QSize( 15, 50) << QSize( 15, 30); - QTest::newRow("external10") << ":/rect.png" << QSize( 25, 50) << QSize( 20, 40); -} - -void tst_QIcon::actualSize() -{ - QFETCH(QString, source); - QFETCH(QSize, argument); - QFETCH(QSize, result); - - { - QPixmap pixmap(source); - QIcon icon(pixmap); - QCOMPARE(icon.actualSize(argument), result); - QCOMPARE(icon.pixmap(argument).size(), result); - } - - { - QIcon icon(source); - QCOMPARE(icon.actualSize(argument), result); - QCOMPARE(icon.pixmap(argument).size(), result); - } -} - -void tst_QIcon::actualSize2_data() -{ - QTest::addColumn("argument"); - QTest::addColumn("result"); - - // two images - 128x128 and 20x40. Let the games begin - QTest::newRow("trivial1") << QSize( 128, 128) << QSize( 128, 128); - QTest::newRow("trivial2") << QSize( 20, 40) << QSize( 20, 40); - - // QIcon chooses the one with the smallest area to choose the pixmap - QTest::newRow("best1") << QSize( 100, 100) << QSize( 100, 100); - QTest::newRow("best2") << QSize( 20, 20) << QSize( 10, 20); - QTest::newRow("best3") << QSize( 15, 30) << QSize( 15, 30); - QTest::newRow("best4") << QSize( 5, 5) << QSize( 2, 5); - QTest::newRow("best5") << QSize( 10, 15) << QSize( 7, 15); -} - -void tst_QIcon::actualSize2() -{ - QIcon icon; - const QString prefix = QFileInfo(QFINDTESTDATA("icons")).absolutePath() + "/"; - - icon.addPixmap(QPixmap(prefix + "image.png")); - icon.addPixmap(QPixmap(prefix + "rect.png")); - - QFETCH(QSize, argument); - QFETCH(QSize, result); - - QCOMPARE(icon.actualSize(argument), result); - QCOMPARE(icon.pixmap(argument).size(), result); -} - -void tst_QIcon::isNull() { - // test default constructor - QIcon defaultConstructor; - QVERIFY(defaultConstructor.isNull()); - - // test copy constructor - QVERIFY(QIcon(defaultConstructor).isNull()); - - // test pixmap constructor - QPixmap nullPixmap; - QVERIFY(QIcon(nullPixmap).isNull()); - - // test string constructor with empty string - QIcon iconEmptyString = QIcon(QString()); - QVERIFY(iconEmptyString.isNull()); - QVERIFY(!iconEmptyString.actualSize(QSize(32, 32)).isValid());; - - // test string constructor with non-existing file - QIcon iconNoFile = QIcon("imagedoesnotexist"); - QVERIFY(!iconNoFile.isNull()); - QVERIFY(!iconNoFile.actualSize(QSize(32, 32)).isValid()); - - // test string constructor with non-existing file with suffix - QIcon iconNoFileSuffix = QIcon("imagedoesnotexist.png"); - QVERIFY(!iconNoFileSuffix.isNull()); - QVERIFY(!iconNoFileSuffix.actualSize(QSize(32, 32)).isValid()); - - const QString prefix = QFileInfo(QFINDTESTDATA("icons")).absolutePath() + "/"; - // test string constructor with existing file but unsupported format - QIcon iconUnsupportedFormat = QIcon(prefix + "tst_qicon.cpp"); - QVERIFY(!iconUnsupportedFormat.isNull()); - QVERIFY(!iconUnsupportedFormat.actualSize(QSize(32, 32)).isValid()); - - // test string constructor with existing file and supported format - QIcon iconSupportedFormat = QIcon(prefix + "image.png"); - QVERIFY(!iconSupportedFormat.isNull()); - QVERIFY(iconSupportedFormat.actualSize(QSize(32, 32)).isValid()); -} - -void tst_QIcon::swap() -{ - QPixmap p1(1, 1), p2(2, 2); - p1.fill(Qt::black); - p2.fill(Qt::black); - - QIcon i1(p1), i2(p2); - const qint64 i1k = i1.cacheKey(); - const qint64 i2k = i2.cacheKey(); - QVERIFY(i1k != i2k); - i1.swap(i2); - QCOMPARE(i1.cacheKey(), i2k); - QCOMPARE(i2.cacheKey(), i1k); -} - -void tst_QIcon::bestMatch() -{ - QPixmap p1(1, 1); - QPixmap p2(2, 2); - QPixmap p3(3, 3); - QPixmap p4(4, 4); - QPixmap p5(5, 5); - QPixmap p6(6, 6); - QPixmap p7(7, 7); - QPixmap p8(8, 8); - - p1.fill(Qt::black); - p2.fill(Qt::black); - p3.fill(Qt::black); - p4.fill(Qt::black); - p5.fill(Qt::black); - p6.fill(Qt::black); - p7.fill(Qt::black); - p8.fill(Qt::black); - - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < 2; ++j) { - QIcon::State state = (j == 0) ? QIcon::On : QIcon::Off; - QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off - : QIcon::On; - QIcon::Mode mode; - QIcon::Mode oppositeMode; - - QIcon icon; - - switch (i) { - case 0: - default: - mode = QIcon::Normal; - oppositeMode = QIcon::Active; - break; - case 1: - mode = QIcon::Active; - oppositeMode = QIcon::Normal; - break; - case 2: - mode = QIcon::Disabled; - oppositeMode = QIcon::Selected; - break; - case 3: - mode = QIcon::Selected; - oppositeMode = QIcon::Disabled; - } - - /* - The test mirrors the code in - QPixmapIconEngine::bestMatch(), to make sure that - nobody breaks QPixmapIconEngine by mistake. Before - you change this test or the code that it tests, - please talk to the maintainer if possible. - */ - if (mode == QIcon::Disabled || mode == QIcon::Selected) { - icon.addPixmap(p1, oppositeMode, oppositeState); - QVERIFY(icon.pixmap(100, mode, state).size() == p1.size()); - - icon.addPixmap(p2, oppositeMode, state); - QVERIFY(icon.pixmap(100, mode, state).size() == p2.size()); - - icon.addPixmap(p3, QIcon::Active, oppositeState); - QVERIFY(icon.pixmap(100, mode, state).size() == p3.size()); - - icon.addPixmap(p4, QIcon::Normal, oppositeState); - QVERIFY(icon.pixmap(100, mode, state).size() == p4.size()); - - icon.addPixmap(p5, mode, oppositeState); - QVERIFY(icon.pixmap(100, mode, state).size() == p5.size()); - - icon.addPixmap(p6, QIcon::Active, state); - QVERIFY(icon.pixmap(100, mode, state).size() == p6.size()); - - icon.addPixmap(p7, QIcon::Normal, state); - QVERIFY(icon.pixmap(100, mode, state).size() == p7.size()); - - icon.addPixmap(p8, mode, state); - QVERIFY(icon.pixmap(100, mode, state).size() == p8.size()); - } else { - icon.addPixmap(p1, QIcon::Selected, oppositeState); - QVERIFY(icon.pixmap(100, mode, state).size() == p1.size()); - - icon.addPixmap(p2, QIcon::Disabled, oppositeState); - QVERIFY(icon.pixmap(100, mode, state).size() == p2.size()); - - icon.addPixmap(p3, QIcon::Selected, state); - QVERIFY(icon.pixmap(100, mode, state).size() == p3.size()); - - icon.addPixmap(p4, QIcon::Disabled, state); - QVERIFY(icon.pixmap(100, mode, state).size() == p4.size()); - - icon.addPixmap(p5, oppositeMode, oppositeState); - QVERIFY(icon.pixmap(100, mode, state).size() == p5.size()); - - icon.addPixmap(p6, mode, oppositeState); - QVERIFY(icon.pixmap(100, mode, state).size() == p6.size()); - - icon.addPixmap(p7, oppositeMode, state); - QVERIFY(icon.pixmap(100, mode, state).size() == p7.size()); - - icon.addPixmap(p8, mode, state); - QVERIFY(icon.pixmap(100, mode, state).size() == p8.size()); - } - } - } -} - -void tst_QIcon::cacheKey() -{ - QIcon icon1("image.png"); - qint64 icon1_key = icon1.cacheKey(); - QIcon icon2 = icon1; - - QVERIFY(icon2.cacheKey() == icon1.cacheKey()); - icon2.detach(); - QVERIFY(icon2.cacheKey() != icon1.cacheKey()); - QVERIFY(icon1.cacheKey() == icon1_key); -} - -void tst_QIcon::detach() -{ - QImage img(32, 32, QImage::Format_ARGB32_Premultiplied); - img.fill(0xffff0000); - QIcon icon1(QPixmap::fromImage(img)); - QIcon icon2 = icon1; - icon2.addFile(QFINDTESTDATA("image.png"), QSize(64, 64)); - - QImage img1 = icon1.pixmap(64, 64).toImage(); - QImage img2 = icon2.pixmap(64, 64).toImage(); - QVERIFY(img1 != img2); - - img1 = icon1.pixmap(32, 32).toImage(); - img2 = icon2.pixmap(32, 32).toImage(); - QVERIFY(img1 == img2); -} - -void tst_QIcon::addFile() -{ - QIcon icon; - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-32.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png")); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png"), QSize(), QIcon::Selected); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-32.png"), QSize(), QIcon::Selected); - icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-128.png"), QSize(), QIcon::Selected); - -#ifndef Q_OS_WINCE - QVERIFY(icon.pixmap(16, QIcon::Normal).toImage() == - QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")).toImage()); - QVERIFY(icon.pixmap(32, QIcon::Normal).toImage() == - QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-32.png")).toImage()); - QVERIFY(icon.pixmap(128, QIcon::Normal).toImage() == - QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png")).toImage()); - QVERIFY(icon.pixmap(16, QIcon::Selected).toImage() == - QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png")).toImage()); - QVERIFY(icon.pixmap(32, QIcon::Selected).toImage() == - QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-32.png")).toImage()); - QVERIFY(icon.pixmap(128, QIcon::Selected).toImage() == - QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-128.png")).toImage()); -#else - // WinCE only includes the 16x16 images for size reasons - QVERIFY(icon.pixmap(16, QIcon::Normal).toImage() == - QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")).toImage()); - QVERIFY(icon.pixmap(16, QIcon::Selected).toImage() == - QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png")).toImage()); -#endif -} - -static bool sizeLess(const QSize &a, const QSize &b) -{ - return a.width() < b.width(); -} - -void tst_QIcon::availableSizes() -{ - { - QIcon icon; - icon.addFile("image.png", QSize(32,32)); - icon.addFile("image.png", QSize(64,64)); - icon.addFile("image.png", QSize(128,128)); - icon.addFile("image.png", QSize(256,256), QIcon::Disabled); - icon.addFile("image.png", QSize(16,16), QIcon::Normal, QIcon::On); - - QList availableSizes = icon.availableSizes(); - QCOMPARE(availableSizes.size(), 3); - qSort(availableSizes.begin(), availableSizes.end(), sizeLess); - QCOMPARE(availableSizes.at(0), QSize(32,32)); - QCOMPARE(availableSizes.at(1), QSize(64,64)); - QCOMPARE(availableSizes.at(2), QSize(128,128)); - - availableSizes = icon.availableSizes(QIcon::Disabled); - QCOMPARE(availableSizes.size(), 1); - QCOMPARE(availableSizes.at(0), QSize(256,256)); - - availableSizes = icon.availableSizes(QIcon::Normal, QIcon::On); - QCOMPARE(availableSizes.size(), 1); - QCOMPARE(availableSizes.at(0), QSize(16,16)); - } - - { - // we try to load an icon from resources - QIcon icon(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); - QList availableSizes = icon.availableSizes(); - QCOMPARE(availableSizes.size(), 1); - QCOMPARE(availableSizes.at(0), QSize(16, 16)); - } - - { - // load an icon from binary data. - QPixmap pix; - QFile file(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); - QVERIFY(file.open(QIODevice::ReadOnly)); - uchar *data = file.map(0, file.size()); - QVERIFY(data != 0); - pix.loadFromData(data, file.size()); - QIcon icon(pix); - - QList availableSizes = icon.availableSizes(); - QCOMPARE(availableSizes.size(), 1); - QCOMPARE(availableSizes.at(0), QSize(16,16)); - } - - { - // there shouldn't be available sizes for invalid images! - QVERIFY(QIcon(QLatin1String("")).availableSizes().isEmpty()); - QVERIFY(QIcon(QLatin1String("non-existing.png")).availableSizes().isEmpty()); - } -} - -void tst_QIcon::name() -{ - { - // No name if icon does not come from a theme - QIcon icon(":/image.png"); - QString name = icon.name(); - QVERIFY(name.isEmpty()); - } - - { - // Getting the name of an icon coming from a theme should work - QString searchPath = QLatin1String(":/icons"); - QIcon::setThemeSearchPaths(QStringList() << searchPath); - QString themeName("testtheme"); - QIcon::setThemeName(themeName); - - QIcon icon = QIcon::fromTheme("appointment-new"); - QString name = icon.name(); - QCOMPARE(name, QLatin1String("appointment-new")); - } -} - -void tst_QIcon::streamAvailableSizes_data() -{ - QTest::addColumn("icon"); - - QIcon icon; - icon.addFile(":/image.png", QSize(32,32)); - QTest::newRow( "32x32" ) << icon; - icon.addFile(":/image.png", QSize(64,64)); - QTest::newRow( "64x64" ) << icon; - icon.addFile(":/image.png", QSize(128,128)); - QTest::newRow( "128x128" ) << icon; - icon.addFile(":/image.png", QSize(256,256)); - QTest::newRow( "256x256" ) << icon; -} - -void tst_QIcon::streamAvailableSizes() -{ - QFETCH(QIcon, icon); - - QByteArray ba; - // write to QByteArray - { - QBuffer buffer(&ba); - buffer.open(QIODevice::WriteOnly); - QDataStream stream(&buffer); - stream << icon; - } - - // read from QByteArray - { - QBuffer buffer(&ba); - buffer.open(QIODevice::ReadOnly); - QDataStream stream(&buffer); - QIcon i; - stream >> i; - QCOMPARE(i.isNull(), icon.isNull()); - QCOMPARE(i.availableSizes(), icon.availableSizes()); - } -} - - -static inline bool operator<(const QSize &lhs, const QSize &rhs) -{ - if (lhs.width() < rhs.width()) - return true; - else if (lhs.width() == lhs.width()) - return lhs.height() < lhs.height(); - return false; -} - -void tst_QIcon::task184901_badCache() -{ - QPixmap pm(QFINDTESTDATA("image.png")); - QIcon icon(pm); - - //the disabled icon must have an effect (grayed) - QVERIFY(icon.pixmap(32, QIcon::Normal).toImage() != icon.pixmap(32, QIcon::Disabled).toImage()); - - icon.addPixmap(pm, QIcon::Disabled); - //the disabled icon must now be the same as the normal one. - QVERIFY( icon.pixmap(32, QIcon::Normal).toImage() == icon.pixmap(32, QIcon::Disabled).toImage() ); -} - -void tst_QIcon::fromTheme() -{ - QString searchPath = QLatin1String(":/icons"); - QIcon::setThemeSearchPaths(QStringList() << searchPath); - QVERIFY(QIcon::themeSearchPaths().size() == 1); - QCOMPARE(searchPath, QIcon::themeSearchPaths()[0]); - - QString themeName("testtheme"); - QIcon::setThemeName(themeName); - QCOMPARE(QIcon::themeName(), themeName); - - // Test normal icon - QIcon appointmentIcon = QIcon::fromTheme("appointment-new"); - QVERIFY(!appointmentIcon.isNull()); - QVERIFY(!appointmentIcon.availableSizes(QIcon::Normal, QIcon::Off).isEmpty()); - QVERIFY(appointmentIcon.availableSizes().contains(QSize(16, 16))); - QVERIFY(appointmentIcon.availableSizes().contains(QSize(32, 32))); - QVERIFY(appointmentIcon.availableSizes().contains(QSize(22, 22))); - - // Test icon from parent theme - QIcon abIcon = QIcon::fromTheme("address-book-new"); - QVERIFY(!abIcon.isNull()); - QVERIFY(QIcon::hasThemeIcon("address-book-new")); - QVERIFY(!abIcon.availableSizes().isEmpty()); - - // Test non existing icon - QIcon noIcon = QIcon::fromTheme("broken-icon"); - QVERIFY(noIcon.isNull()); - QVERIFY(!QIcon::hasThemeIcon("broken-icon")); - - // Test non existing icon with fallback - noIcon = QIcon::fromTheme("broken-icon", abIcon); - QVERIFY(noIcon.cacheKey() == abIcon.cacheKey()); - - // Test svg-only icon - noIcon = QIcon::fromTheme("svg-icon", abIcon); - QVERIFY(!noIcon.availableSizes().isEmpty()); - - QByteArray ba; - // write to QByteArray - { - QBuffer buffer(&ba); - buffer.open(QIODevice::WriteOnly); - QDataStream stream(&buffer); - stream << abIcon; - } - - // read from QByteArray - { - QBuffer buffer(&ba); - buffer.open(QIODevice::ReadOnly); - QDataStream stream(&buffer); - QIcon i; - stream >> i; - QCOMPARE(i.isNull(), abIcon.isNull()); - QCOMPARE(i.availableSizes(), abIcon.availableSizes()); - } - - // Make sure setting the theme name clears the state - QIcon::setThemeName(""); - abIcon = QIcon::fromTheme("address-book-new"); - QVERIFY(abIcon.isNull()); -} - - -void tst_QIcon::task223279_inconsistentAddFile() -{ - QIcon icon1; - icon1.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); - icon1.addFile(QLatin1String("IconThatDoesntExist"), QSize(32, 32)); - QPixmap pm1 = icon1.pixmap(32, 32); - - QIcon icon2; - icon2.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); - icon2.addFile(QLatin1String("IconThatDoesntExist")); - QPixmap pm2 = icon1.pixmap(32, 32); - - QCOMPARE(pm1.isNull(), false); - QCOMPARE(pm1.size(), QSize(16,16)); - QCOMPARE(pm1.isNull(), pm2.isNull()); - QCOMPARE(pm1.size(), pm2.size()); -} - - -QTEST_MAIN(tst_QIcon) -#include "tst_qicon.moc" diff --git a/tests/auto/gui/image/qicon/tst_qicon.qrc b/tests/auto/gui/image/qicon/tst_qicon.qrc deleted file mode 100644 index 7925a33c84..0000000000 --- a/tests/auto/gui/image/qicon/tst_qicon.qrc +++ /dev/null @@ -1,20 +0,0 @@ - - -image.png -rect.png -./icons/testtheme/16x16/actions/appointment-new.png -./icons/testtheme/22x22/actions/appointment-new.png -./icons/testtheme/32x32/actions/appointment-new.png -./icons/testtheme/index.theme -./icons/testtheme/scalable/actions/svg-only.svg -./icons/themeparent/16x16/actions/address-book-new.png -./icons/themeparent/16x16/actions/appointment-new.png -./icons/themeparent/22x22/actions/address-book-new.png -./icons/themeparent/22x22/actions/appointment-new.png -./icons/themeparent/32x32/actions/address-book-new.png -./icons/themeparent/32x32/actions/appointment-new.png -./icons/themeparent/index.theme -./icons/themeparent/scalable/actions/address-book-new.svg -./icons/themeparent/scalable/actions/appointment-new.svg - - diff --git a/tests/auto/gui/image/qpixmapfilter/noise.png b/tests/auto/gui/image/qpixmapfilter/noise.png deleted file mode 100644 index 1bebaf528e..0000000000 Binary files a/tests/auto/gui/image/qpixmapfilter/noise.png and /dev/null differ diff --git a/tests/auto/gui/image/qpixmapfilter/qpixmapfilter.pro b/tests/auto/gui/image/qpixmapfilter/qpixmapfilter.pro deleted file mode 100644 index 872686b82f..0000000000 --- a/tests/auto/gui/image/qpixmapfilter/qpixmapfilter.pro +++ /dev/null @@ -1,14 +0,0 @@ -CONFIG += testcase -TARGET = tst_qpixmapfilter - -QT += widgets widgets-private testlib -QT += gui-private - -SOURCES += tst_qpixmapfilter.cpp - -wince*: { - addFiles.files = noise.png - addFiles.path = . - DEPLOYMENT += addFiles -} - diff --git a/tests/auto/gui/image/qpixmapfilter/tst_qpixmapfilter.cpp b/tests/auto/gui/image/qpixmapfilter/tst_qpixmapfilter.cpp deleted file mode 100644 index c9b2e054da..0000000000 --- a/tests/auto/gui/image/qpixmapfilter/tst_qpixmapfilter.cpp +++ /dev/null @@ -1,447 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the test suite 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 -#include -#include -#include - -class tst_QPixmapFilter : public QObject -{ - Q_OBJECT - -public: - tst_QPixmapFilter(); - virtual ~tst_QPixmapFilter(); - - -public slots: - void init(); - void cleanup(); - -private slots: - void colorizeSetColor(); - void colorizeSetStrength(); - void colorizeProcess(); - void colorizeDraw(); - void colorizeDrawStrength(); - void colorizeDrawSubRect(); - void colorizeProcessSubRect(); - void convolutionBoundingRectFor(); - void convolutionDrawSubRect(); - void dropShadowBoundingRectFor(); - void blurIndexed8(); - - void testDefaultImplementations(); -}; - -class CustomFilter : public QPixmapFilter -{ -public: - enum { Type = QPixmapFilter::UserFilter + 1 }; - - CustomFilter() : QPixmapFilter((QPixmapFilter::FilterType) Type, 0) { }; - - void draw(QPainter *p, const QPointF &pt, const QPixmap &src, const QRectF &srcRect = QRectF()) const { - p->drawPixmap(QRectF(pt, srcRect.size()), src, srcRect); - } -}; - -tst_QPixmapFilter::tst_QPixmapFilter() -{ -} - -tst_QPixmapFilter::~tst_QPixmapFilter() -{ -} - -void tst_QPixmapFilter::init() -{ -} - -void tst_QPixmapFilter::cleanup() -{ -} - -void tst_QPixmapFilter::testDefaultImplementations() -{ - CustomFilter filter; - QCOMPARE(filter.type(), (QPixmapFilter::FilterType) CustomFilter::Type); - - QCOMPARE(filter.boundingRectFor(QRectF(1, 2, 4, 8)), QRectF(1, 2, 4, 8)); - - QPixmap src(10, 10); - src.fill(Qt::blue); - - QPixmap test(src.size()); - QPainter p(&test); - filter.draw(&p, QPointF(0, 0), src, src.rect()); - p.end(); - - QCOMPARE(test.toImage().pixel(0, 0), 0xff0000ff); -} - -void tst_QPixmapFilter::colorizeSetColor() -{ - QPixmapColorizeFilter filter; - filter.setColor(QColor(50, 100, 200)); - QCOMPARE(filter.color(), QColor(50, 100, 200)); -} - -void tst_QPixmapFilter::colorizeSetStrength() -{ - QPixmapColorizeFilter filter; - QCOMPARE(filter.strength(), qreal(1)); - filter.setStrength(0.5); - QCOMPARE(filter.strength(), qreal(0.5)); - filter.setStrength(0.0); - QCOMPARE(filter.strength(), qreal(0.0)); -} - -void tst_QPixmapFilter::colorizeProcess() -{ - QPixmapColorizeFilter filter; - filter.setColor(QColor(100, 100, 100)); - - QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(0, 0, 50, 50)); - QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(30, 20, 10, 40)); - QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(2.2, 6.3, 11.4, 47.5)); - - QPixmap source("noise.png"); - QImage result(source.size(), QImage::Format_ARGB32_Premultiplied); - result.fill(0); - QPainter p(&result); - filter.draw(&p, QPointF(0, 0), source); - p.end(); - QImage resultImg = result; - for(int y = 0; y < resultImg.height(); y++) - { - for(int x = 0; x < resultImg.width(); x++) - { - QRgb pixel = resultImg.pixel(x,y); - QCOMPARE(qRed(pixel), qGreen(pixel)); - QCOMPARE(qGreen(pixel), qBlue(pixel)); - } - } -} - -void tst_QPixmapFilter::colorizeDraw() -{ - QPixmapColorizeFilter filter; - filter.setColor(QColor(100, 100, 100)); - - QPixmap pixmap("noise.png"); - QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); - QPainter painter(&result); - painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.fillRect(result.rect(), QColor(128, 0, 0, 0)); - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - filter.draw(&painter, QPointF(0, 0), pixmap); - painter.end(); - - QImage resultImg = result; - for(int y = 0; y < resultImg.height(); y++) - { - for(int x = 0; x < resultImg.width(); x++) - { - QRgb pixel = resultImg.pixel(x,y); - QCOMPARE(qRed(pixel), qGreen(pixel)); - QCOMPARE(qGreen(pixel), qBlue(pixel)); - } - } -} - -void tst_QPixmapFilter::colorizeDrawStrength() -{ - QPixmapColorizeFilter filter; - filter.setColor(Qt::blue); - filter.setStrength(0.3); - - QImage source(256, 128, QImage::Format_ARGB32); - source.fill(qRgb(255, 0, 0)); - QPixmap pixmap = QPixmap::fromImage(source); - - QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); - QPainter painter(&result); - painter.setCompositionMode(QPainter::CompositionMode_Source); - filter.draw(&painter, QPointF(0, 0), pixmap); - painter.end(); - - QImage resultImg = result; - for(int y = 0; y < resultImg.height(); y++) - { - for(int x = 0; x < resultImg.width(); x++) - { - QRgb pixel = resultImg.pixel(x,y); - QCOMPARE(qRed(pixel), 206); - QCOMPARE(qGreen(pixel), 26); - QCOMPARE(qBlue(pixel), 75); - } - } -} - -void tst_QPixmapFilter::colorizeDrawSubRect() -{ - QPixmapColorizeFilter filter; - filter.setColor(QColor(255, 255, 255)); - - QPixmap pixmap("noise.png"); - QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); - QPainter painter(&result); - painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.fillRect(result.rect(), QColor(128, 0, 0, 255)); - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - filter.draw(&painter, QPointF(16, 16), pixmap, QRectF(16, 16, 16, 16)); - painter.end(); - - QImage resultImg = result; - QImage sourceImg = pixmap.toImage(); - for(int y = 0; y < resultImg.height(); y++) - { - for(int x = 0; x < resultImg.width(); x++) - { - QRgb pixel = resultImg.pixel(x,y); - if(x>=16 && x<32 && y>=16 && y<32) { - QCOMPARE(qRed(pixel), qGreen(pixel)); - QCOMPARE(qGreen(pixel), qBlue(pixel)); - } else { - QCOMPARE(qRed(pixel), 128); - QCOMPARE(qGreen(pixel), 0); - QCOMPARE(qBlue(pixel), 0); - QCOMPARE(qAlpha(pixel), 255); - } - } - } -} - -void tst_QPixmapFilter::colorizeProcessSubRect() -{ - QPixmapColorizeFilter filter; - filter.setColor(QColor(200, 200, 200)); - - QPixmap source("noise.png"); - QImage result(QSize(16, 16), QImage::Format_ARGB32_Premultiplied); - result.fill(0); - QPainter p(&result); - filter.draw(&p, QPointF(0, 0), source, QRectF(16, 16, 16, 16)); - p.end(); - - QImage resultImg = result; - for(int y = 0; y < resultImg.height(); y++) - { - for(int x = 0; x < resultImg.width(); x++) - { - QRgb pixel = resultImg.pixel(x,y); - QCOMPARE(qRed(pixel), qGreen(pixel)); - QCOMPARE(qGreen(pixel), qBlue(pixel)); - } - } -} - -void tst_QPixmapFilter::convolutionBoundingRectFor() -{ - QPixmapConvolutionFilter filter; - QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(0, 0, 50, 50)); - QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(30, 20, 10, 40)); - QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(2.2, 6.3, 11.4, 47.5)); - qreal kernel[] = { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0 - }; - filter.setConvolutionKernel(kernel, 2, 2); - QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(-1, -1, 51, 51)); - QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(29, 19, 11, 41)); - QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(1.2, 5.3, 12.4, 48.5)); - - filter.setConvolutionKernel(kernel, 3, 3); - QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(-1, -1, 52, 52)); - QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(29, 19, 12, 42)); - QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(1.2, 5.3, 13.4, 49.5)); - - filter.setConvolutionKernel(kernel, 4, 4); - QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(-2, -2, 53, 53)); - QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(28, 18, 13, 43)); - QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(0.2, 4.3, 14.4, 50.5)); -} - -void tst_QPixmapFilter::convolutionDrawSubRect() -{ - QPixmapConvolutionFilter filter; - qreal kernel[] = { - 0, 0, 0, - 0, 0, 0, - 0, 0, 1 - }; - filter.setConvolutionKernel(kernel, 3, 3); - - QPixmap pixmap("noise.png"); - QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); - QPainter painter(&result); - painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.fillRect(result.rect(), QColor(128, 0, 0, 255)); - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - filter.draw(&painter, QPointF(16, 16), pixmap, QRectF(16, 16, 16, 16)); - painter.end(); - - QImage resultImg = result; - QImage sourceImg = pixmap.toImage(); - for(int y = 0; y < resultImg.height()-1; y++) - { - for(int x = 0; x < resultImg.width()-1; x++) - { - QRgb pixel = resultImg.pixel(x,y); - QRgb srcPixel = sourceImg.pixel(x+1,y+1); - if(x>=15 && x<33 && y>=15 && y<33) { - QCOMPARE(pixel, srcPixel); - } else { - QCOMPARE(qRed(pixel), 128); - QCOMPARE(qGreen(pixel), 0); - QCOMPARE(qBlue(pixel), 0); - QCOMPARE(qAlpha(pixel), 255); - } - } - } - - - kernel[2] = 1; - kernel[8] = 0; - filter.setConvolutionKernel(kernel, 3, 3); - - QPainter painter2(&result); - painter2.setCompositionMode(QPainter::CompositionMode_Source); - painter2.fillRect(result.rect(), QColor(128, 0, 0, 255)); - painter2.setCompositionMode(QPainter::CompositionMode_SourceOver); - filter.draw(&painter2, QPointF(16, 16), pixmap, QRectF(16, 16, 16, 16)); - painter2.end(); - - resultImg = result; - sourceImg = pixmap.toImage(); - for(int y = 1; y < resultImg.height(); y++) - { - for(int x = 0; x < resultImg.width()-1; x++) - { - QRgb pixel = resultImg.pixel(x,y); - QRgb srcPixel = sourceImg.pixel(x+1,y-1); - if(x>=15 && x<33 && y>=15 && y<33) { - QCOMPARE(pixel, srcPixel); - } else { - QCOMPARE(qRed(pixel), 128); - QCOMPARE(qGreen(pixel), 0); - QCOMPARE(qBlue(pixel), 0); - QCOMPARE(qAlpha(pixel), 255); - } - } - } - -} - -void tst_QPixmapFilter::dropShadowBoundingRectFor() -{ - QPixmapDropShadowFilter filter; - filter.setBlurRadius(0); - - QCOMPARE(filter.blurRadius(), 0.); - - const QRectF rect1(0, 0, 50, 50); - const QRectF rect2(30, 20, 10, 40); - const QRectF rect3(2.2, 6.3, 11.4, 47.5); - - filter.setOffset(QPointF(0,0)); - QCOMPARE(filter.boundingRectFor(rect1), rect1); - QCOMPARE(filter.boundingRectFor(rect2), rect2); - QCOMPARE(filter.boundingRectFor(rect3), rect3); - - filter.setOffset(QPointF(1,1)); - QCOMPARE(filter.offset(), QPointF(1, 1)); - QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(0, 0, 1, 1)); - QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(0, 0, 1, 1)); - QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(0, 0, 1, 1)); - - filter.setOffset(QPointF(-1,-1)); - QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-1, -1, 0, 0)); - QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-1, -1, 0, 0)); - QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-1, -1, 0, 0)); - - filter.setBlurRadius(2); - filter.setOffset(QPointF(0,0)); - qreal delta = 2; - QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-delta, -delta, delta, delta)); - QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-delta, -delta, delta, delta)); - QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-delta, -delta, delta, delta)); - - filter.setOffset(QPointF(1,1)); - QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-delta + 1, -delta + 1, delta + 1, delta + 1)); - QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-delta + 1, -delta + 1, delta + 1, delta + 1)); - QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-delta + 1, -delta + 1, delta + 1, delta + 1)); - - filter.setOffset(QPointF(-10,-10)); - QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-delta - 10, -delta - 10, 0, 0)); - QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-delta - 10, -delta - 10, 0, 0)); - QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-delta - 10, -delta - 10, 0, 0)); -} - -QT_BEGIN_NAMESPACE -void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); -QT_END_NAMESPACE - -void tst_QPixmapFilter::blurIndexed8() -{ - QImage img(16, 32, QImage::Format_Indexed8); - img.setColorCount(256); - for (int i = 0; i < 256; ++i) - img.setColor(i, qRgb(i, i, i)); - - img.fill(255); - - QImage original = img; - qt_blurImage(img, 10, true, false); - QCOMPARE(original.size(), img.size()); - - original = img; - qt_blurImage(img, 10, true, true); - QCOMPARE(original.size(), QSize(img.height(), img.width())); -} - -QTEST_MAIN(tst_QPixmapFilter) -#include "tst_qpixmapfilter.moc" diff --git a/tests/auto/widgets/effects/effects.pro b/tests/auto/widgets/effects/effects.pro index fab24d6296..e598707f3e 100644 --- a/tests/auto/widgets/effects/effects.pro +++ b/tests/auto/widgets/effects/effects.pro @@ -1,4 +1,5 @@ TEMPLATE=subdirs SUBDIRS=\ qgraphicseffect \ + qpixmapfilter \ diff --git a/tests/auto/widgets/effects/qpixmapfilter/noise.png b/tests/auto/widgets/effects/qpixmapfilter/noise.png new file mode 100644 index 0000000000..1bebaf528e Binary files /dev/null and b/tests/auto/widgets/effects/qpixmapfilter/noise.png differ diff --git a/tests/auto/widgets/effects/qpixmapfilter/qpixmapfilter.pro b/tests/auto/widgets/effects/qpixmapfilter/qpixmapfilter.pro new file mode 100644 index 0000000000..872686b82f --- /dev/null +++ b/tests/auto/widgets/effects/qpixmapfilter/qpixmapfilter.pro @@ -0,0 +1,14 @@ +CONFIG += testcase +TARGET = tst_qpixmapfilter + +QT += widgets widgets-private testlib +QT += gui-private + +SOURCES += tst_qpixmapfilter.cpp + +wince*: { + addFiles.files = noise.png + addFiles.path = . + DEPLOYMENT += addFiles +} + diff --git a/tests/auto/widgets/effects/qpixmapfilter/tst_qpixmapfilter.cpp b/tests/auto/widgets/effects/qpixmapfilter/tst_qpixmapfilter.cpp new file mode 100644 index 0000000000..c9b2e054da --- /dev/null +++ b/tests/auto/widgets/effects/qpixmapfilter/tst_qpixmapfilter.cpp @@ -0,0 +1,447 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite 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 +#include +#include +#include + +class tst_QPixmapFilter : public QObject +{ + Q_OBJECT + +public: + tst_QPixmapFilter(); + virtual ~tst_QPixmapFilter(); + + +public slots: + void init(); + void cleanup(); + +private slots: + void colorizeSetColor(); + void colorizeSetStrength(); + void colorizeProcess(); + void colorizeDraw(); + void colorizeDrawStrength(); + void colorizeDrawSubRect(); + void colorizeProcessSubRect(); + void convolutionBoundingRectFor(); + void convolutionDrawSubRect(); + void dropShadowBoundingRectFor(); + void blurIndexed8(); + + void testDefaultImplementations(); +}; + +class CustomFilter : public QPixmapFilter +{ +public: + enum { Type = QPixmapFilter::UserFilter + 1 }; + + CustomFilter() : QPixmapFilter((QPixmapFilter::FilterType) Type, 0) { }; + + void draw(QPainter *p, const QPointF &pt, const QPixmap &src, const QRectF &srcRect = QRectF()) const { + p->drawPixmap(QRectF(pt, srcRect.size()), src, srcRect); + } +}; + +tst_QPixmapFilter::tst_QPixmapFilter() +{ +} + +tst_QPixmapFilter::~tst_QPixmapFilter() +{ +} + +void tst_QPixmapFilter::init() +{ +} + +void tst_QPixmapFilter::cleanup() +{ +} + +void tst_QPixmapFilter::testDefaultImplementations() +{ + CustomFilter filter; + QCOMPARE(filter.type(), (QPixmapFilter::FilterType) CustomFilter::Type); + + QCOMPARE(filter.boundingRectFor(QRectF(1, 2, 4, 8)), QRectF(1, 2, 4, 8)); + + QPixmap src(10, 10); + src.fill(Qt::blue); + + QPixmap test(src.size()); + QPainter p(&test); + filter.draw(&p, QPointF(0, 0), src, src.rect()); + p.end(); + + QCOMPARE(test.toImage().pixel(0, 0), 0xff0000ff); +} + +void tst_QPixmapFilter::colorizeSetColor() +{ + QPixmapColorizeFilter filter; + filter.setColor(QColor(50, 100, 200)); + QCOMPARE(filter.color(), QColor(50, 100, 200)); +} + +void tst_QPixmapFilter::colorizeSetStrength() +{ + QPixmapColorizeFilter filter; + QCOMPARE(filter.strength(), qreal(1)); + filter.setStrength(0.5); + QCOMPARE(filter.strength(), qreal(0.5)); + filter.setStrength(0.0); + QCOMPARE(filter.strength(), qreal(0.0)); +} + +void tst_QPixmapFilter::colorizeProcess() +{ + QPixmapColorizeFilter filter; + filter.setColor(QColor(100, 100, 100)); + + QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(0, 0, 50, 50)); + QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(30, 20, 10, 40)); + QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(2.2, 6.3, 11.4, 47.5)); + + QPixmap source("noise.png"); + QImage result(source.size(), QImage::Format_ARGB32_Premultiplied); + result.fill(0); + QPainter p(&result); + filter.draw(&p, QPointF(0, 0), source); + p.end(); + QImage resultImg = result; + for(int y = 0; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width(); x++) + { + QRgb pixel = resultImg.pixel(x,y); + QCOMPARE(qRed(pixel), qGreen(pixel)); + QCOMPARE(qGreen(pixel), qBlue(pixel)); + } + } +} + +void tst_QPixmapFilter::colorizeDraw() +{ + QPixmapColorizeFilter filter; + filter.setColor(QColor(100, 100, 100)); + + QPixmap pixmap("noise.png"); + QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&result); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(result.rect(), QColor(128, 0, 0, 0)); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + filter.draw(&painter, QPointF(0, 0), pixmap); + painter.end(); + + QImage resultImg = result; + for(int y = 0; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width(); x++) + { + QRgb pixel = resultImg.pixel(x,y); + QCOMPARE(qRed(pixel), qGreen(pixel)); + QCOMPARE(qGreen(pixel), qBlue(pixel)); + } + } +} + +void tst_QPixmapFilter::colorizeDrawStrength() +{ + QPixmapColorizeFilter filter; + filter.setColor(Qt::blue); + filter.setStrength(0.3); + + QImage source(256, 128, QImage::Format_ARGB32); + source.fill(qRgb(255, 0, 0)); + QPixmap pixmap = QPixmap::fromImage(source); + + QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&result); + painter.setCompositionMode(QPainter::CompositionMode_Source); + filter.draw(&painter, QPointF(0, 0), pixmap); + painter.end(); + + QImage resultImg = result; + for(int y = 0; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width(); x++) + { + QRgb pixel = resultImg.pixel(x,y); + QCOMPARE(qRed(pixel), 206); + QCOMPARE(qGreen(pixel), 26); + QCOMPARE(qBlue(pixel), 75); + } + } +} + +void tst_QPixmapFilter::colorizeDrawSubRect() +{ + QPixmapColorizeFilter filter; + filter.setColor(QColor(255, 255, 255)); + + QPixmap pixmap("noise.png"); + QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&result); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(result.rect(), QColor(128, 0, 0, 255)); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + filter.draw(&painter, QPointF(16, 16), pixmap, QRectF(16, 16, 16, 16)); + painter.end(); + + QImage resultImg = result; + QImage sourceImg = pixmap.toImage(); + for(int y = 0; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width(); x++) + { + QRgb pixel = resultImg.pixel(x,y); + if(x>=16 && x<32 && y>=16 && y<32) { + QCOMPARE(qRed(pixel), qGreen(pixel)); + QCOMPARE(qGreen(pixel), qBlue(pixel)); + } else { + QCOMPARE(qRed(pixel), 128); + QCOMPARE(qGreen(pixel), 0); + QCOMPARE(qBlue(pixel), 0); + QCOMPARE(qAlpha(pixel), 255); + } + } + } +} + +void tst_QPixmapFilter::colorizeProcessSubRect() +{ + QPixmapColorizeFilter filter; + filter.setColor(QColor(200, 200, 200)); + + QPixmap source("noise.png"); + QImage result(QSize(16, 16), QImage::Format_ARGB32_Premultiplied); + result.fill(0); + QPainter p(&result); + filter.draw(&p, QPointF(0, 0), source, QRectF(16, 16, 16, 16)); + p.end(); + + QImage resultImg = result; + for(int y = 0; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width(); x++) + { + QRgb pixel = resultImg.pixel(x,y); + QCOMPARE(qRed(pixel), qGreen(pixel)); + QCOMPARE(qGreen(pixel), qBlue(pixel)); + } + } +} + +void tst_QPixmapFilter::convolutionBoundingRectFor() +{ + QPixmapConvolutionFilter filter; + QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(0, 0, 50, 50)); + QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(30, 20, 10, 40)); + QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(2.2, 6.3, 11.4, 47.5)); + qreal kernel[] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + }; + filter.setConvolutionKernel(kernel, 2, 2); + QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(-1, -1, 51, 51)); + QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(29, 19, 11, 41)); + QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(1.2, 5.3, 12.4, 48.5)); + + filter.setConvolutionKernel(kernel, 3, 3); + QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(-1, -1, 52, 52)); + QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(29, 19, 12, 42)); + QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(1.2, 5.3, 13.4, 49.5)); + + filter.setConvolutionKernel(kernel, 4, 4); + QCOMPARE(filter.boundingRectFor(QRectF(0, 0, 50, 50)), QRectF(-2, -2, 53, 53)); + QCOMPARE(filter.boundingRectFor(QRectF(30, 20, 10, 40)), QRectF(28, 18, 13, 43)); + QCOMPARE(filter.boundingRectFor(QRectF(2.2, 6.3, 11.4, 47.5)), QRectF(0.2, 4.3, 14.4, 50.5)); +} + +void tst_QPixmapFilter::convolutionDrawSubRect() +{ + QPixmapConvolutionFilter filter; + qreal kernel[] = { + 0, 0, 0, + 0, 0, 0, + 0, 0, 1 + }; + filter.setConvolutionKernel(kernel, 3, 3); + + QPixmap pixmap("noise.png"); + QImage result(pixmap.size(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&result); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(result.rect(), QColor(128, 0, 0, 255)); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + filter.draw(&painter, QPointF(16, 16), pixmap, QRectF(16, 16, 16, 16)); + painter.end(); + + QImage resultImg = result; + QImage sourceImg = pixmap.toImage(); + for(int y = 0; y < resultImg.height()-1; y++) + { + for(int x = 0; x < resultImg.width()-1; x++) + { + QRgb pixel = resultImg.pixel(x,y); + QRgb srcPixel = sourceImg.pixel(x+1,y+1); + if(x>=15 && x<33 && y>=15 && y<33) { + QCOMPARE(pixel, srcPixel); + } else { + QCOMPARE(qRed(pixel), 128); + QCOMPARE(qGreen(pixel), 0); + QCOMPARE(qBlue(pixel), 0); + QCOMPARE(qAlpha(pixel), 255); + } + } + } + + + kernel[2] = 1; + kernel[8] = 0; + filter.setConvolutionKernel(kernel, 3, 3); + + QPainter painter2(&result); + painter2.setCompositionMode(QPainter::CompositionMode_Source); + painter2.fillRect(result.rect(), QColor(128, 0, 0, 255)); + painter2.setCompositionMode(QPainter::CompositionMode_SourceOver); + filter.draw(&painter2, QPointF(16, 16), pixmap, QRectF(16, 16, 16, 16)); + painter2.end(); + + resultImg = result; + sourceImg = pixmap.toImage(); + for(int y = 1; y < resultImg.height(); y++) + { + for(int x = 0; x < resultImg.width()-1; x++) + { + QRgb pixel = resultImg.pixel(x,y); + QRgb srcPixel = sourceImg.pixel(x+1,y-1); + if(x>=15 && x<33 && y>=15 && y<33) { + QCOMPARE(pixel, srcPixel); + } else { + QCOMPARE(qRed(pixel), 128); + QCOMPARE(qGreen(pixel), 0); + QCOMPARE(qBlue(pixel), 0); + QCOMPARE(qAlpha(pixel), 255); + } + } + } + +} + +void tst_QPixmapFilter::dropShadowBoundingRectFor() +{ + QPixmapDropShadowFilter filter; + filter.setBlurRadius(0); + + QCOMPARE(filter.blurRadius(), 0.); + + const QRectF rect1(0, 0, 50, 50); + const QRectF rect2(30, 20, 10, 40); + const QRectF rect3(2.2, 6.3, 11.4, 47.5); + + filter.setOffset(QPointF(0,0)); + QCOMPARE(filter.boundingRectFor(rect1), rect1); + QCOMPARE(filter.boundingRectFor(rect2), rect2); + QCOMPARE(filter.boundingRectFor(rect3), rect3); + + filter.setOffset(QPointF(1,1)); + QCOMPARE(filter.offset(), QPointF(1, 1)); + QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(0, 0, 1, 1)); + QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(0, 0, 1, 1)); + QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(0, 0, 1, 1)); + + filter.setOffset(QPointF(-1,-1)); + QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-1, -1, 0, 0)); + QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-1, -1, 0, 0)); + QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-1, -1, 0, 0)); + + filter.setBlurRadius(2); + filter.setOffset(QPointF(0,0)); + qreal delta = 2; + QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-delta, -delta, delta, delta)); + QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-delta, -delta, delta, delta)); + QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-delta, -delta, delta, delta)); + + filter.setOffset(QPointF(1,1)); + QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-delta + 1, -delta + 1, delta + 1, delta + 1)); + QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-delta + 1, -delta + 1, delta + 1, delta + 1)); + QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-delta + 1, -delta + 1, delta + 1, delta + 1)); + + filter.setOffset(QPointF(-10,-10)); + QCOMPARE(filter.boundingRectFor(rect1), rect1.adjusted(-delta - 10, -delta - 10, 0, 0)); + QCOMPARE(filter.boundingRectFor(rect2), rect2.adjusted(-delta - 10, -delta - 10, 0, 0)); + QCOMPARE(filter.boundingRectFor(rect3), rect3.adjusted(-delta - 10, -delta - 10, 0, 0)); +} + +QT_BEGIN_NAMESPACE +void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); +QT_END_NAMESPACE + +void tst_QPixmapFilter::blurIndexed8() +{ + QImage img(16, 32, QImage::Format_Indexed8); + img.setColorCount(256); + for (int i = 0; i < 256; ++i) + img.setColor(i, qRgb(i, i, i)); + + img.fill(255); + + QImage original = img; + qt_blurImage(img, 10, true, false); + QCOMPARE(original.size(), img.size()); + + original = img; + qt_blurImage(img, 10, true, true); + QCOMPARE(original.size(), QSize(img.height(), img.width())); +} + +QTEST_MAIN(tst_QPixmapFilter) +#include "tst_qpixmapfilter.moc" diff --git a/tests/auto/widgets/kernel/kernel.pro b/tests/auto/widgets/kernel/kernel.pro index 850863c112..3a00300ac3 100644 --- a/tests/auto/widgets/kernel/kernel.pro +++ b/tests/auto/widgets/kernel/kernel.pro @@ -13,6 +13,7 @@ SUBDIRS=\ qwidget \ qwidget_window \ qwidgetaction \ + qicon \ SUBDIRS -= qsound diff --git a/tests/auto/widgets/kernel/qicon/.gitignore b/tests/auto/widgets/kernel/qicon/.gitignore new file mode 100644 index 0000000000..c101ef9d28 --- /dev/null +++ b/tests/auto/widgets/kernel/qicon/.gitignore @@ -0,0 +1 @@ +tst_qicon diff --git a/tests/auto/widgets/kernel/qicon/icons/testtheme/16x16/actions/appointment-new.png b/tests/auto/widgets/kernel/qicon/icons/testtheme/16x16/actions/appointment-new.png new file mode 100644 index 0000000000..18b7c6781e Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/icons/testtheme/16x16/actions/appointment-new.png differ diff --git a/tests/auto/widgets/kernel/qicon/icons/testtheme/22x22/actions/appointment-new.png b/tests/auto/widgets/kernel/qicon/icons/testtheme/22x22/actions/appointment-new.png new file mode 100644 index 0000000000..d676ffd463 Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/icons/testtheme/22x22/actions/appointment-new.png differ diff --git a/tests/auto/widgets/kernel/qicon/icons/testtheme/32x32/actions/appointment-new.png b/tests/auto/widgets/kernel/qicon/icons/testtheme/32x32/actions/appointment-new.png new file mode 100644 index 0000000000..85daef3b0b Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/icons/testtheme/32x32/actions/appointment-new.png differ diff --git a/tests/auto/widgets/kernel/qicon/icons/testtheme/index.theme b/tests/auto/widgets/kernel/qicon/icons/testtheme/index.theme new file mode 100644 index 0000000000..e18736ab43 --- /dev/null +++ b/tests/auto/widgets/kernel/qicon/icons/testtheme/index.theme @@ -0,0 +1,492 @@ +[Icon Theme] +_Name=Test +_Comment=Test Theme +Inherits=crystalsvg, themeparent +Example=x-directory-normal + +# KDE Specific Stuff +DisplayDepth=32 +LinkOverlay=link_overlay +LockOverlay=lock_overlay +ZipOverlay=zip_overlay +DesktopDefault=48 +DesktopSizes=16,22,32,48,64,72,96,128 +ToolbarDefault=22 +ToolbarSizes=16,22,32,48 +MainToolbarDefault=22 +MainToolbarSizes=16,22,32,48 +SmallDefault=16 +SmallSizes=16 +PanelDefault=32 +PanelSizes=16,22,32,48,64,72,96,128 + +# Directory list +Directories=16x16/actions,16x16/apps,16x16/categories,16x16/devices,16x16/emblems,16x16/emotes,16x16/mimetypes,16x16/places,16x16/status,22x22/actions,22x22/apps,22x22/categories,22x22/devices,22x22/emblems,22x22/emotes,22x22/mimetypes,22x22/places,22x22/status,24x24/actions,24x24/apps,24x24/categories,24x24/devices,24x24/emblems,24x24/emotes,24x24/mimetypes,24x24/places,24x24/status,32x32/actions,32x32/apps,32x32/categories,32x32/devices,32x32/emblems,32x32/emotes,32x32/mimetypes,32x32/places,32x32/status,48x48/actions,48x48/apps,48x48/categories,48x48/devices,48x48/emblems,48x48/emotes,48x48/mimetypes,48x48/places,48x48/status,64x64/actions,64x64/apps,64x64/categories,64x64/devices,64x64/emblems,64x64/emotes,64x64/mimetypes,64x64/places,64x64/status,72x72/actions,72x72/apps,72x72/categories,72x72/devices,72x72/emblems,72x72/emotes,72x72/mimetypes,72x72/places,72x72/status,96x96/actions,96x96/apps,96x96/categories,96x96/devices,96x96/emblems,96x96/emotes,96x96/mimetypes,96x96/places,96x96/status,128x128/actions,128x128/apps,128x128/categories,128x128/devices,128x128/emblems,128x128/emotes,128x128/mimetypes,128x128/places,128x128/status,scalable/actions,scalable/apps,scalable/categories,scalable/devices,scalable/emblems,scalable/emotes,scalable/mimetypes,scalable/places,scalable/status + +[16x16/actions] +Size=16 +Context=Actions +Type=Fixed + +[16x16/apps] +Size=16 +Context=Applications +Type=Fixed + +[16x16/categories] +Size=16 +Context=Categories +Type=Fixed + +[16x16/devices] +Size=16 +Context=Devices +Type=Fixed + +[16x16/emblems] +Size=16 +Context=Emblems +Type=Fixed + +[16x16/emotes] +Size=16 +Context=Emotes +Type=Fixed + +[16x16/mimetypes] +Size=16 +Context=MimeTypes +Type=Fixed + +[16x16/places] +Size=16 +Context=Places +Type=Fixed + +[16x16/status] +Size=16 +Context=Status +Type=Fixed + +[22x22/actions] +Size=22 +Context=Actions +Type=Fixed + +[22x22/apps] +Size=22 +Context=Applications +Type=Fixed + +[22x22/categories] +Size=22 +Context=Categories +Type=Fixed + +[22x22/devices] +Size=22 +Context=Devices +Type=Fixed + +[22x22/emblems] +Size=22 +Context=Emblems +Type=Fixed + +[22x22/emotes] +Size=22 +Context=Emotes +Type=Fixed + +[22x22/mimetypes] +Size=22 +Context=MimeTypes +Type=Fixed + +[22x22/places] +Size=22 +Context=Places +Type=Fixed + +[22x22/status] +Size=22 +Context=Status +Type=Fixed + +[24x24/actions] +Size=24 +Context=Actions +Type=Fixed + +[24x24/apps] +Size=24 +Context=Applications +Type=Fixed + +[24x24/categories] +Size=24 +Context=Categories +Type=Fixed + +[24x24/devices] +Size=24 +Context=Devices +Type=Fixed + +[24x24/emblems] +Size=24 +Context=Emblems +Type=Fixed + +[24x24/emotes] +Size=24 +Context=Emotes +Type=Fixed + +[24x24/mimetypes] +Size=24 +Context=MimeTypes +Type=Fixed + +[24x24/places] +Size=24 +Context=Places +Type=Fixed + +[24x24/status] +Size=24 +Context=Status +Type=Fixed + +[32x32/actions] +Size=32 +Context=Actions +Type=Fixed + +[32x32/apps] +Size=32 +Context=Applications +Type=Fixed + +[32x32/categories] +Size=32 +Context=Categories +Type=Fixed + +[32x32/devices] +Size=32 +Context=Devices +Type=Fixed + +[32x32/emblems] +Size=32 +Context=Emblems +Type=Fixed + +[32x32/emotes] +Size=32 +Context=Emotes +Type=Fixed + +[32x32/mimetypes] +Size=32 +Context=MimeTypes +Type=Fixed + +[32x32/places] +Size=32 +Context=Places +Type=Fixed + +[32x32/status] +Size=32 +Context=Status +Type=Fixed + +[48x48/actions] +Size=48 +Context=Actions +Type=Fixed + +[48x48/apps] +Size=48 +Context=Applications +Type=Fixed + +[48x48/categories] +Size=48 +Context=Categories +Type=Fixed + +[48x48/devices] +Size=48 +Context=Devices +Type=Fixed + +[48x48/emblems] +Size=48 +Context=Emblems +Type=Fixed + +[48x48/emotes] +Size=48 +Context=Emotes +Type=Fixed + +[48x48/mimetypes] +Size=48 +Context=MimeTypes +Type=Fixed + +[48x48/places] +Size=48 +Context=Places +Type=Fixed + +[48x48/status] +Size=48 +Context=Status +Type=Fixed + +[64x64/actions] +Size=64 +Context=Actions +Type=Fixed + +[64x64/apps] +Size=64 +Context=Applications +Type=Fixed + +[64x64/categories] +Size=64 +Context=Categories +Type=Fixed + +[64x64/devices] +Size=64 +Context=Devices +Type=Fixed + +[64x64/emblems] +Size=64 +Context=Emblems +Type=Fixed + +[64x64/emotes] +Size=64 +Context=Emotes +Type=Fixed + +[64x64/mimetypes] +Size=64 +Context=MimeTypes +Type=Fixed + +[64x64/places] +Size=64 +Context=Places +Type=Fixed + +[64x64/status] +Size=64 +Context=Status +Type=Fixed + +[72x72/actions] +Size=72 +Context=Actions +Type=Fixed + +[72x72/apps] +Size=72 +Context=Applications +Type=Fixed + +[72x72/categories] +Size=72 +Context=Categories +Type=Fixed + +[72x72/devices] +Size=72 +Context=Devices +Type=Fixed + +[72x72/emblems] +Size=72 +Context=Emblems +Type=Fixed + +[72x72/emotes] +Size=72 +Context=Emotes +Type=Fixed + +[72x72/mimetypes] +Size=72 +Context=MimeTypes +Type=Fixed + +[72x72/places] +Size=72 +Context=Places +Type=Fixed + +[72x72/status] +Size=72 +Context=Status +Type=Fixed + +[96x96/actions] +Size=96 +Context=Actions +Type=Fixed + +[96x96/apps] +Size=96 +Context=Applications +Type=Fixed + +[96x96/categories] +Size=96 +Context=Categories +Type=Fixed + +[96x96/devices] +Size=96 +Context=Devices +Type=Fixed + +[96x96/emblems] +Size=96 +Context=Emblems +Type=Fixed + +[96x96/emotes] +Size=96 +Context=Emotes +Type=Fixed + +[96x96/mimetypes] +Size=96 +Context=MimeTypes +Type=Fixed + +[96x96/places] +Size=96 +Context=Places +Type=Fixed + +[96x96/status] +Size=96 +Context=Status +Type=Fixed + +[128x128/actions] +Size=128 +Context=Actions +Type=Fixed + +[128x128/apps] +Size=128 +Context=Applications +Type=Fixed + +[128x128/categories] +Size=128 +Context=Categories +Type=Fixed + +[128x128/devices] +Size=128 +Context=Devices +Type=Fixed + +[128x128/emblems] +Size=128 +Context=Emblems +Type=Fixed + +[128x128/emotes] +Size=128 +Context=Emotes +Type=Fixed + +[128x128/mimetypes] +Size=128 +Context=MimeTypes +Type=Fixed + +[128x128/places] +Size=128 +Context=Places +Type=Fixed + +[128x128/status] +Size=128 +Context=Status +Type=Fixed + +[scalable/actions] +Size=48 +Context=Actions +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/apps] +Size=48 +Context=Applications +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/categories] +Size=48 +Context=Categories +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/devices] +Size=48 +Context=Devices +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emblems] +Size=48 +Context=Emblems +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emotes] +Size=48 +Context=Emotes +Type=Scalable +Minsize=32 +MaxSize=256 + +[scalable/mimetypes] +Size=48 +Context=MimeTypes +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/places] +Size=48 +Context=Places +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/status] +Size=48 +Context=Status +Type=Scalable +MinSize=32 +MaxSize=256 diff --git a/tests/auto/widgets/kernel/qicon/icons/testtheme/scalable/actions/svg-only.svg b/tests/auto/widgets/kernel/qicon/icons/testtheme/scalable/actions/svg-only.svg new file mode 100644 index 0000000000..4cb14f82f0 --- /dev/null +++ b/tests/auto/widgets/kernel/qicon/icons/testtheme/scalable/actions/svg-only.svg @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + New Appointment + + + appointment + new + meeting + rvsp + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/auto/widgets/kernel/qicon/icons/themeparent/16x16/actions/address-book-new.png b/tests/auto/widgets/kernel/qicon/icons/themeparent/16x16/actions/address-book-new.png new file mode 100644 index 0000000000..2098cfdf36 Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/icons/themeparent/16x16/actions/address-book-new.png differ diff --git a/tests/auto/widgets/kernel/qicon/icons/themeparent/16x16/actions/appointment-new.png b/tests/auto/widgets/kernel/qicon/icons/themeparent/16x16/actions/appointment-new.png new file mode 100644 index 0000000000..18b7c6781e Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/icons/themeparent/16x16/actions/appointment-new.png differ diff --git a/tests/auto/widgets/kernel/qicon/icons/themeparent/22x22/actions/address-book-new.png b/tests/auto/widgets/kernel/qicon/icons/themeparent/22x22/actions/address-book-new.png new file mode 100644 index 0000000000..fad446cd92 Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/icons/themeparent/22x22/actions/address-book-new.png differ diff --git a/tests/auto/widgets/kernel/qicon/icons/themeparent/22x22/actions/appointment-new.png b/tests/auto/widgets/kernel/qicon/icons/themeparent/22x22/actions/appointment-new.png new file mode 100644 index 0000000000..d676ffd463 Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/icons/themeparent/22x22/actions/appointment-new.png differ diff --git a/tests/auto/widgets/kernel/qicon/icons/themeparent/32x32/actions/address-book-new.png b/tests/auto/widgets/kernel/qicon/icons/themeparent/32x32/actions/address-book-new.png new file mode 100644 index 0000000000..420139d307 Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/icons/themeparent/32x32/actions/address-book-new.png differ diff --git a/tests/auto/widgets/kernel/qicon/icons/themeparent/32x32/actions/appointment-new.png b/tests/auto/widgets/kernel/qicon/icons/themeparent/32x32/actions/appointment-new.png new file mode 100644 index 0000000000..85daef3b0b Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/icons/themeparent/32x32/actions/appointment-new.png differ diff --git a/tests/auto/widgets/kernel/qicon/icons/themeparent/index.theme b/tests/auto/widgets/kernel/qicon/icons/themeparent/index.theme new file mode 100644 index 0000000000..e536a0bf2f --- /dev/null +++ b/tests/auto/widgets/kernel/qicon/icons/themeparent/index.theme @@ -0,0 +1,492 @@ +[Icon Theme] +_Name=Test +_Comment=Test Theme +Inherits=gnome,crystalsvg +Example=x-directory-normal + +# KDE Specific Stuff +DisplayDepth=32 +LinkOverlay=link_overlay +LockOverlay=lock_overlay +ZipOverlay=zip_overlay +DesktopDefault=48 +DesktopSizes=16,22,32,48,64,72,96,128 +ToolbarDefault=22 +ToolbarSizes=16,22,32,48 +MainToolbarDefault=22 +MainToolbarSizes=16,22,32,48 +SmallDefault=16 +SmallSizes=16 +PanelDefault=32 +PanelSizes=16,22,32,48,64,72,96,128 + +# Directory list +Directories=16x16/actions,16x16/apps,16x16/categories,16x16/devices,16x16/emblems,16x16/emotes,16x16/mimetypes,16x16/places,16x16/status,22x22/actions,22x22/apps,22x22/categories,22x22/devices,22x22/emblems,22x22/emotes,22x22/mimetypes,22x22/places,22x22/status,24x24/actions,24x24/apps,24x24/categories,24x24/devices,24x24/emblems,24x24/emotes,24x24/mimetypes,24x24/places,24x24/status,32x32/actions,32x32/apps,32x32/categories,32x32/devices,32x32/emblems,32x32/emotes,32x32/mimetypes,32x32/places,32x32/status,48x48/actions,48x48/apps,48x48/categories,48x48/devices,48x48/emblems,48x48/emotes,48x48/mimetypes,48x48/places,48x48/status,64x64/actions,64x64/apps,64x64/categories,64x64/devices,64x64/emblems,64x64/emotes,64x64/mimetypes,64x64/places,64x64/status,72x72/actions,72x72/apps,72x72/categories,72x72/devices,72x72/emblems,72x72/emotes,72x72/mimetypes,72x72/places,72x72/status,96x96/actions,96x96/apps,96x96/categories,96x96/devices,96x96/emblems,96x96/emotes,96x96/mimetypes,96x96/places,96x96/status,128x128/actions,128x128/apps,128x128/categories,128x128/devices,128x128/emblems,128x128/emotes,128x128/mimetypes,128x128/places,128x128/status,scalable/actions,scalable/apps,scalable/categories,scalable/devices,scalable/emblems,scalable/emotes,scalable/mimetypes,scalable/places,scalable/status + +[16x16/actions] +Size=16 +Context=Actions +Type=Fixed + +[16x16/apps] +Size=16 +Context=Applications +Type=Fixed + +[16x16/categories] +Size=16 +Context=Categories +Type=Fixed + +[16x16/devices] +Size=16 +Context=Devices +Type=Fixed + +[16x16/emblems] +Size=16 +Context=Emblems +Type=Fixed + +[16x16/emotes] +Size=16 +Context=Emotes +Type=Fixed + +[16x16/mimetypes] +Size=16 +Context=MimeTypes +Type=Fixed + +[16x16/places] +Size=16 +Context=Places +Type=Fixed + +[16x16/status] +Size=16 +Context=Status +Type=Fixed + +[22x22/actions] +Size=22 +Context=Actions +Type=Fixed + +[22x22/apps] +Size=22 +Context=Applications +Type=Fixed + +[22x22/categories] +Size=22 +Context=Categories +Type=Fixed + +[22x22/devices] +Size=22 +Context=Devices +Type=Fixed + +[22x22/emblems] +Size=22 +Context=Emblems +Type=Fixed + +[22x22/emotes] +Size=22 +Context=Emotes +Type=Fixed + +[22x22/mimetypes] +Size=22 +Context=MimeTypes +Type=Fixed + +[22x22/places] +Size=22 +Context=Places +Type=Fixed + +[22x22/status] +Size=22 +Context=Status +Type=Fixed + +[24x24/actions] +Size=24 +Context=Actions +Type=Fixed + +[24x24/apps] +Size=24 +Context=Applications +Type=Fixed + +[24x24/categories] +Size=24 +Context=Categories +Type=Fixed + +[24x24/devices] +Size=24 +Context=Devices +Type=Fixed + +[24x24/emblems] +Size=24 +Context=Emblems +Type=Fixed + +[24x24/emotes] +Size=24 +Context=Emotes +Type=Fixed + +[24x24/mimetypes] +Size=24 +Context=MimeTypes +Type=Fixed + +[24x24/places] +Size=24 +Context=Places +Type=Fixed + +[24x24/status] +Size=24 +Context=Status +Type=Fixed + +[32x32/actions] +Size=32 +Context=Actions +Type=Fixed + +[32x32/apps] +Size=32 +Context=Applications +Type=Fixed + +[32x32/categories] +Size=32 +Context=Categories +Type=Fixed + +[32x32/devices] +Size=32 +Context=Devices +Type=Fixed + +[32x32/emblems] +Size=32 +Context=Emblems +Type=Fixed + +[32x32/emotes] +Size=32 +Context=Emotes +Type=Fixed + +[32x32/mimetypes] +Size=32 +Context=MimeTypes +Type=Fixed + +[32x32/places] +Size=32 +Context=Places +Type=Fixed + +[32x32/status] +Size=32 +Context=Status +Type=Fixed + +[48x48/actions] +Size=48 +Context=Actions +Type=Fixed + +[48x48/apps] +Size=48 +Context=Applications +Type=Fixed + +[48x48/categories] +Size=48 +Context=Categories +Type=Fixed + +[48x48/devices] +Size=48 +Context=Devices +Type=Fixed + +[48x48/emblems] +Size=48 +Context=Emblems +Type=Fixed + +[48x48/emotes] +Size=48 +Context=Emotes +Type=Fixed + +[48x48/mimetypes] +Size=48 +Context=MimeTypes +Type=Fixed + +[48x48/places] +Size=48 +Context=Places +Type=Fixed + +[48x48/status] +Size=48 +Context=Status +Type=Fixed + +[64x64/actions] +Size=64 +Context=Actions +Type=Fixed + +[64x64/apps] +Size=64 +Context=Applications +Type=Fixed + +[64x64/categories] +Size=64 +Context=Categories +Type=Fixed + +[64x64/devices] +Size=64 +Context=Devices +Type=Fixed + +[64x64/emblems] +Size=64 +Context=Emblems +Type=Fixed + +[64x64/emotes] +Size=64 +Context=Emotes +Type=Fixed + +[64x64/mimetypes] +Size=64 +Context=MimeTypes +Type=Fixed + +[64x64/places] +Size=64 +Context=Places +Type=Fixed + +[64x64/status] +Size=64 +Context=Status +Type=Fixed + +[72x72/actions] +Size=72 +Context=Actions +Type=Fixed + +[72x72/apps] +Size=72 +Context=Applications +Type=Fixed + +[72x72/categories] +Size=72 +Context=Categories +Type=Fixed + +[72x72/devices] +Size=72 +Context=Devices +Type=Fixed + +[72x72/emblems] +Size=72 +Context=Emblems +Type=Fixed + +[72x72/emotes] +Size=72 +Context=Emotes +Type=Fixed + +[72x72/mimetypes] +Size=72 +Context=MimeTypes +Type=Fixed + +[72x72/places] +Size=72 +Context=Places +Type=Fixed + +[72x72/status] +Size=72 +Context=Status +Type=Fixed + +[96x96/actions] +Size=96 +Context=Actions +Type=Fixed + +[96x96/apps] +Size=96 +Context=Applications +Type=Fixed + +[96x96/categories] +Size=96 +Context=Categories +Type=Fixed + +[96x96/devices] +Size=96 +Context=Devices +Type=Fixed + +[96x96/emblems] +Size=96 +Context=Emblems +Type=Fixed + +[96x96/emotes] +Size=96 +Context=Emotes +Type=Fixed + +[96x96/mimetypes] +Size=96 +Context=MimeTypes +Type=Fixed + +[96x96/places] +Size=96 +Context=Places +Type=Fixed + +[96x96/status] +Size=96 +Context=Status +Type=Fixed + +[128x128/actions] +Size=128 +Context=Actions +Type=Fixed + +[128x128/apps] +Size=128 +Context=Applications +Type=Fixed + +[128x128/categories] +Size=128 +Context=Categories +Type=Fixed + +[128x128/devices] +Size=128 +Context=Devices +Type=Fixed + +[128x128/emblems] +Size=128 +Context=Emblems +Type=Fixed + +[128x128/emotes] +Size=128 +Context=Emotes +Type=Fixed + +[128x128/mimetypes] +Size=128 +Context=MimeTypes +Type=Fixed + +[128x128/places] +Size=128 +Context=Places +Type=Fixed + +[128x128/status] +Size=128 +Context=Status +Type=Fixed + +[scalable/actions] +Size=48 +Context=Actions +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/apps] +Size=48 +Context=Applications +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/categories] +Size=48 +Context=Categories +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/devices] +Size=48 +Context=Devices +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emblems] +Size=48 +Context=Emblems +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/emotes] +Size=48 +Context=Emotes +Type=Scalable +Minsize=32 +MaxSize=256 + +[scalable/mimetypes] +Size=48 +Context=MimeTypes +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/places] +Size=48 +Context=Places +Type=Scalable +MinSize=32 +MaxSize=256 + +[scalable/status] +Size=48 +Context=Status +Type=Scalable +MinSize=32 +MaxSize=256 diff --git a/tests/auto/widgets/kernel/qicon/icons/themeparent/scalable/actions/address-book-new.svg b/tests/auto/widgets/kernel/qicon/icons/themeparent/scalable/actions/address-book-new.svg new file mode 100644 index 0000000000..600a82c1b0 --- /dev/null +++ b/tests/auto/widgets/kernel/qicon/icons/themeparent/scalable/actions/address-book-new.svg @@ -0,0 +1,389 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Addess Book - New + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + + address + contact + book + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/auto/widgets/kernel/qicon/icons/themeparent/scalable/actions/appointment-new.svg b/tests/auto/widgets/kernel/qicon/icons/themeparent/scalable/actions/appointment-new.svg new file mode 100644 index 0000000000..4cb14f82f0 --- /dev/null +++ b/tests/auto/widgets/kernel/qicon/icons/themeparent/scalable/actions/appointment-new.svg @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + New Appointment + + + appointment + new + meeting + rvsp + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/auto/widgets/kernel/qicon/image.png b/tests/auto/widgets/kernel/qicon/image.png new file mode 100644 index 0000000000..8d703640c1 Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/image.png differ diff --git a/tests/auto/widgets/kernel/qicon/qicon.pro b/tests/auto/widgets/kernel/qicon/qicon.pro new file mode 100644 index 0000000000..c44c080ced --- /dev/null +++ b/tests/auto/widgets/kernel/qicon/qicon.pro @@ -0,0 +1,12 @@ +CONFIG += testcase +TARGET = tst_qicon + +QT += widgets testlib +SOURCES += tst_qicon.cpp +RESOURCES = tst_qicon.qrc + +wince* { + QT += xml svg + DEPLOYMENT_PLUGIN += qsvg +} +TESTDATA += icons/* *.png *.svg *.svgz diff --git a/tests/auto/widgets/kernel/qicon/rect.png b/tests/auto/widgets/kernel/qicon/rect.png new file mode 100644 index 0000000000..b5d3ecbddf Binary files /dev/null and b/tests/auto/widgets/kernel/qicon/rect.png differ diff --git a/tests/auto/widgets/kernel/qicon/tst_qicon.cpp b/tests/auto/widgets/kernel/qicon/tst_qicon.cpp new file mode 100644 index 0000000000..4a9ab93921 --- /dev/null +++ b/tests/auto/widgets/kernel/qicon/tst_qicon.cpp @@ -0,0 +1,637 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite 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 +#include +#include +#include + +Q_DECLARE_METATYPE(QSize) + +class tst_QIcon : public QObject +{ + Q_OBJECT +public: + tst_QIcon(); + +private slots: + void actualSize_data(); // test with 1 pixmap + void actualSize(); + void actualSize2_data(); // test with 2 pixmaps with different aspect ratio + void actualSize2(); + void isNull(); + void swap(); + void bestMatch(); + void cacheKey(); + void detach(); + void addFile(); + void availableSizes(); + void name(); + void streamAvailableSizes_data(); + void streamAvailableSizes(); + void fromTheme(); + + void task184901_badCache(); + void task223279_inconsistentAddFile(); + +private: + bool haveImageFormat(QByteArray const&); + + const static QIcon staticIcon; +}; + +// Creating an icon statically should not cause a crash. +// But we do not officially support this. See QTBUG-8666 +const QIcon tst_QIcon::staticIcon = QIcon::fromTheme("edit-find"); + +bool tst_QIcon::haveImageFormat(QByteArray const& desiredFormat) +{ + return QImageReader::supportedImageFormats().contains(desiredFormat); +} + +tst_QIcon::tst_QIcon() +{ +} + +void tst_QIcon::actualSize_data() +{ + QTest::addColumn("source"); + QTest::addColumn("argument"); + QTest::addColumn("result"); + + // square image + QTest::newRow("resource0") << ":/image.png" << QSize(128, 128) << QSize(128, 128); + QTest::newRow("resource1") << ":/image.png" << QSize( 64, 64) << QSize( 64, 64); + QTest::newRow("resource2") << ":/image.png" << QSize( 32, 64) << QSize( 32, 32); + QTest::newRow("resource3") << ":/image.png" << QSize( 16, 64) << QSize( 16, 16); + QTest::newRow("resource4") << ":/image.png" << QSize( 16, 128) << QSize( 16, 16); + QTest::newRow("resource5") << ":/image.png" << QSize( 128, 16) << QSize( 16, 16); + QTest::newRow("resource6") << ":/image.png" << QSize( 150, 150) << QSize( 128, 128); + // rect image + QTest::newRow("resource7") << ":/rect.png" << QSize( 20, 40) << QSize( 20, 40); + QTest::newRow("resource8") << ":/rect.png" << QSize( 10, 20) << QSize( 10, 20); + QTest::newRow("resource9") << ":/rect.png" << QSize( 15, 50) << QSize( 15, 30); + QTest::newRow("resource10") << ":/rect.png" << QSize( 25, 50) << QSize( 20, 40); + + const QString prefix = QFileInfo(QFINDTESTDATA("icons")).absolutePath() + "/"; + QTest::newRow("external0") << prefix + "image.png" << QSize(128, 128) << QSize(128, 128); + QTest::newRow("external1") << prefix + "image.png" << QSize( 64, 64) << QSize( 64, 64); + QTest::newRow("external2") << prefix + "image.png" << QSize( 32, 64) << QSize( 32, 32); + QTest::newRow("external3") << prefix + "image.png" << QSize( 16, 64) << QSize( 16, 16); + QTest::newRow("external4") << prefix + "image.png" << QSize( 16, 128) << QSize( 16, 16); + QTest::newRow("external5") << prefix + "image.png" << QSize( 128, 16) << QSize( 16, 16); + QTest::newRow("external6") << prefix + "image.png" << QSize( 150, 150) << QSize( 128, 128); + // rect image + QTest::newRow("external7") << ":/rect.png" << QSize( 20, 40) << QSize( 20, 40); + QTest::newRow("external8") << ":/rect.png" << QSize( 10, 20) << QSize( 10, 20); + QTest::newRow("external9") << ":/rect.png" << QSize( 15, 50) << QSize( 15, 30); + QTest::newRow("external10") << ":/rect.png" << QSize( 25, 50) << QSize( 20, 40); +} + +void tst_QIcon::actualSize() +{ + QFETCH(QString, source); + QFETCH(QSize, argument); + QFETCH(QSize, result); + + { + QPixmap pixmap(source); + QIcon icon(pixmap); + QCOMPARE(icon.actualSize(argument), result); + QCOMPARE(icon.pixmap(argument).size(), result); + } + + { + QIcon icon(source); + QCOMPARE(icon.actualSize(argument), result); + QCOMPARE(icon.pixmap(argument).size(), result); + } +} + +void tst_QIcon::actualSize2_data() +{ + QTest::addColumn("argument"); + QTest::addColumn("result"); + + // two images - 128x128 and 20x40. Let the games begin + QTest::newRow("trivial1") << QSize( 128, 128) << QSize( 128, 128); + QTest::newRow("trivial2") << QSize( 20, 40) << QSize( 20, 40); + + // QIcon chooses the one with the smallest area to choose the pixmap + QTest::newRow("best1") << QSize( 100, 100) << QSize( 100, 100); + QTest::newRow("best2") << QSize( 20, 20) << QSize( 10, 20); + QTest::newRow("best3") << QSize( 15, 30) << QSize( 15, 30); + QTest::newRow("best4") << QSize( 5, 5) << QSize( 2, 5); + QTest::newRow("best5") << QSize( 10, 15) << QSize( 7, 15); +} + +void tst_QIcon::actualSize2() +{ + QIcon icon; + const QString prefix = QFileInfo(QFINDTESTDATA("icons")).absolutePath() + "/"; + + icon.addPixmap(QPixmap(prefix + "image.png")); + icon.addPixmap(QPixmap(prefix + "rect.png")); + + QFETCH(QSize, argument); + QFETCH(QSize, result); + + QCOMPARE(icon.actualSize(argument), result); + QCOMPARE(icon.pixmap(argument).size(), result); +} + +void tst_QIcon::isNull() { + // test default constructor + QIcon defaultConstructor; + QVERIFY(defaultConstructor.isNull()); + + // test copy constructor + QVERIFY(QIcon(defaultConstructor).isNull()); + + // test pixmap constructor + QPixmap nullPixmap; + QVERIFY(QIcon(nullPixmap).isNull()); + + // test string constructor with empty string + QIcon iconEmptyString = QIcon(QString()); + QVERIFY(iconEmptyString.isNull()); + QVERIFY(!iconEmptyString.actualSize(QSize(32, 32)).isValid());; + + // test string constructor with non-existing file + QIcon iconNoFile = QIcon("imagedoesnotexist"); + QVERIFY(!iconNoFile.isNull()); + QVERIFY(!iconNoFile.actualSize(QSize(32, 32)).isValid()); + + // test string constructor with non-existing file with suffix + QIcon iconNoFileSuffix = QIcon("imagedoesnotexist.png"); + QVERIFY(!iconNoFileSuffix.isNull()); + QVERIFY(!iconNoFileSuffix.actualSize(QSize(32, 32)).isValid()); + + const QString prefix = QFileInfo(QFINDTESTDATA("icons")).absolutePath() + "/"; + // test string constructor with existing file but unsupported format + QIcon iconUnsupportedFormat = QIcon(prefix + "tst_qicon.cpp"); + QVERIFY(!iconUnsupportedFormat.isNull()); + QVERIFY(!iconUnsupportedFormat.actualSize(QSize(32, 32)).isValid()); + + // test string constructor with existing file and supported format + QIcon iconSupportedFormat = QIcon(prefix + "image.png"); + QVERIFY(!iconSupportedFormat.isNull()); + QVERIFY(iconSupportedFormat.actualSize(QSize(32, 32)).isValid()); +} + +void tst_QIcon::swap() +{ + QPixmap p1(1, 1), p2(2, 2); + p1.fill(Qt::black); + p2.fill(Qt::black); + + QIcon i1(p1), i2(p2); + const qint64 i1k = i1.cacheKey(); + const qint64 i2k = i2.cacheKey(); + QVERIFY(i1k != i2k); + i1.swap(i2); + QCOMPARE(i1.cacheKey(), i2k); + QCOMPARE(i2.cacheKey(), i1k); +} + +void tst_QIcon::bestMatch() +{ + QPixmap p1(1, 1); + QPixmap p2(2, 2); + QPixmap p3(3, 3); + QPixmap p4(4, 4); + QPixmap p5(5, 5); + QPixmap p6(6, 6); + QPixmap p7(7, 7); + QPixmap p8(8, 8); + + p1.fill(Qt::black); + p2.fill(Qt::black); + p3.fill(Qt::black); + p4.fill(Qt::black); + p5.fill(Qt::black); + p6.fill(Qt::black); + p7.fill(Qt::black); + p8.fill(Qt::black); + + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 2; ++j) { + QIcon::State state = (j == 0) ? QIcon::On : QIcon::Off; + QIcon::State oppositeState = (state == QIcon::On) ? QIcon::Off + : QIcon::On; + QIcon::Mode mode; + QIcon::Mode oppositeMode; + + QIcon icon; + + switch (i) { + case 0: + default: + mode = QIcon::Normal; + oppositeMode = QIcon::Active; + break; + case 1: + mode = QIcon::Active; + oppositeMode = QIcon::Normal; + break; + case 2: + mode = QIcon::Disabled; + oppositeMode = QIcon::Selected; + break; + case 3: + mode = QIcon::Selected; + oppositeMode = QIcon::Disabled; + } + + /* + The test mirrors the code in + QPixmapIconEngine::bestMatch(), to make sure that + nobody breaks QPixmapIconEngine by mistake. Before + you change this test or the code that it tests, + please talk to the maintainer if possible. + */ + if (mode == QIcon::Disabled || mode == QIcon::Selected) { + icon.addPixmap(p1, oppositeMode, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p1.size()); + + icon.addPixmap(p2, oppositeMode, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p2.size()); + + icon.addPixmap(p3, QIcon::Active, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p3.size()); + + icon.addPixmap(p4, QIcon::Normal, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p4.size()); + + icon.addPixmap(p5, mode, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p5.size()); + + icon.addPixmap(p6, QIcon::Active, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p6.size()); + + icon.addPixmap(p7, QIcon::Normal, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p7.size()); + + icon.addPixmap(p8, mode, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p8.size()); + } else { + icon.addPixmap(p1, QIcon::Selected, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p1.size()); + + icon.addPixmap(p2, QIcon::Disabled, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p2.size()); + + icon.addPixmap(p3, QIcon::Selected, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p3.size()); + + icon.addPixmap(p4, QIcon::Disabled, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p4.size()); + + icon.addPixmap(p5, oppositeMode, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p5.size()); + + icon.addPixmap(p6, mode, oppositeState); + QVERIFY(icon.pixmap(100, mode, state).size() == p6.size()); + + icon.addPixmap(p7, oppositeMode, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p7.size()); + + icon.addPixmap(p8, mode, state); + QVERIFY(icon.pixmap(100, mode, state).size() == p8.size()); + } + } + } +} + +void tst_QIcon::cacheKey() +{ + QIcon icon1("image.png"); + qint64 icon1_key = icon1.cacheKey(); + QIcon icon2 = icon1; + + QVERIFY(icon2.cacheKey() == icon1.cacheKey()); + icon2.detach(); + QVERIFY(icon2.cacheKey() != icon1.cacheKey()); + QVERIFY(icon1.cacheKey() == icon1_key); +} + +void tst_QIcon::detach() +{ + QImage img(32, 32, QImage::Format_ARGB32_Premultiplied); + img.fill(0xffff0000); + QIcon icon1(QPixmap::fromImage(img)); + QIcon icon2 = icon1; + icon2.addFile(QFINDTESTDATA("image.png"), QSize(64, 64)); + + QImage img1 = icon1.pixmap(64, 64).toImage(); + QImage img2 = icon2.pixmap(64, 64).toImage(); + QVERIFY(img1 != img2); + + img1 = icon1.pixmap(32, 32).toImage(); + img2 = icon2.pixmap(32, 32).toImage(); + QVERIFY(img1 == img2); +} + +void tst_QIcon::addFile() +{ + QIcon icon; + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-32.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png")); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png"), QSize(), QIcon::Selected); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-32.png"), QSize(), QIcon::Selected); + icon.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-128.png"), QSize(), QIcon::Selected); + +#ifndef Q_OS_WINCE + QVERIFY(icon.pixmap(16, QIcon::Normal).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")).toImage()); + QVERIFY(icon.pixmap(32, QIcon::Normal).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-32.png")).toImage()); + QVERIFY(icon.pixmap(128, QIcon::Normal).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-128.png")).toImage()); + QVERIFY(icon.pixmap(16, QIcon::Selected).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png")).toImage()); + QVERIFY(icon.pixmap(32, QIcon::Selected).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-32.png")).toImage()); + QVERIFY(icon.pixmap(128, QIcon::Selected).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-128.png")).toImage()); +#else + // WinCE only includes the 16x16 images for size reasons + QVERIFY(icon.pixmap(16, QIcon::Normal).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")).toImage()); + QVERIFY(icon.pixmap(16, QIcon::Selected).toImage() == + QPixmap(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-save-16.png")).toImage()); +#endif +} + +static bool sizeLess(const QSize &a, const QSize &b) +{ + return a.width() < b.width(); +} + +void tst_QIcon::availableSizes() +{ + { + QIcon icon; + icon.addFile("image.png", QSize(32,32)); + icon.addFile("image.png", QSize(64,64)); + icon.addFile("image.png", QSize(128,128)); + icon.addFile("image.png", QSize(256,256), QIcon::Disabled); + icon.addFile("image.png", QSize(16,16), QIcon::Normal, QIcon::On); + + QList availableSizes = icon.availableSizes(); + QCOMPARE(availableSizes.size(), 3); + qSort(availableSizes.begin(), availableSizes.end(), sizeLess); + QCOMPARE(availableSizes.at(0), QSize(32,32)); + QCOMPARE(availableSizes.at(1), QSize(64,64)); + QCOMPARE(availableSizes.at(2), QSize(128,128)); + + availableSizes = icon.availableSizes(QIcon::Disabled); + QCOMPARE(availableSizes.size(), 1); + QCOMPARE(availableSizes.at(0), QSize(256,256)); + + availableSizes = icon.availableSizes(QIcon::Normal, QIcon::On); + QCOMPARE(availableSizes.size(), 1); + QCOMPARE(availableSizes.at(0), QSize(16,16)); + } + + { + // we try to load an icon from resources + QIcon icon(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); + QList availableSizes = icon.availableSizes(); + QCOMPARE(availableSizes.size(), 1); + QCOMPARE(availableSizes.at(0), QSize(16, 16)); + } + + { + // load an icon from binary data. + QPixmap pix; + QFile file(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); + QVERIFY(file.open(QIODevice::ReadOnly)); + uchar *data = file.map(0, file.size()); + QVERIFY(data != 0); + pix.loadFromData(data, file.size()); + QIcon icon(pix); + + QList availableSizes = icon.availableSizes(); + QCOMPARE(availableSizes.size(), 1); + QCOMPARE(availableSizes.at(0), QSize(16,16)); + } + + { + // there shouldn't be available sizes for invalid images! + QVERIFY(QIcon(QLatin1String("")).availableSizes().isEmpty()); + QVERIFY(QIcon(QLatin1String("non-existing.png")).availableSizes().isEmpty()); + } +} + +void tst_QIcon::name() +{ + { + // No name if icon does not come from a theme + QIcon icon(":/image.png"); + QString name = icon.name(); + QVERIFY(name.isEmpty()); + } + + { + // Getting the name of an icon coming from a theme should work + QString searchPath = QLatin1String(":/icons"); + QIcon::setThemeSearchPaths(QStringList() << searchPath); + QString themeName("testtheme"); + QIcon::setThemeName(themeName); + + QIcon icon = QIcon::fromTheme("appointment-new"); + QString name = icon.name(); + QCOMPARE(name, QLatin1String("appointment-new")); + } +} + +void tst_QIcon::streamAvailableSizes_data() +{ + QTest::addColumn("icon"); + + QIcon icon; + icon.addFile(":/image.png", QSize(32,32)); + QTest::newRow( "32x32" ) << icon; + icon.addFile(":/image.png", QSize(64,64)); + QTest::newRow( "64x64" ) << icon; + icon.addFile(":/image.png", QSize(128,128)); + QTest::newRow( "128x128" ) << icon; + icon.addFile(":/image.png", QSize(256,256)); + QTest::newRow( "256x256" ) << icon; +} + +void tst_QIcon::streamAvailableSizes() +{ + QFETCH(QIcon, icon); + + QByteArray ba; + // write to QByteArray + { + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + QDataStream stream(&buffer); + stream << icon; + } + + // read from QByteArray + { + QBuffer buffer(&ba); + buffer.open(QIODevice::ReadOnly); + QDataStream stream(&buffer); + QIcon i; + stream >> i; + QCOMPARE(i.isNull(), icon.isNull()); + QCOMPARE(i.availableSizes(), icon.availableSizes()); + } +} + + +static inline bool operator<(const QSize &lhs, const QSize &rhs) +{ + if (lhs.width() < rhs.width()) + return true; + else if (lhs.width() == lhs.width()) + return lhs.height() < lhs.height(); + return false; +} + +void tst_QIcon::task184901_badCache() +{ + QPixmap pm(QFINDTESTDATA("image.png")); + QIcon icon(pm); + + //the disabled icon must have an effect (grayed) + QVERIFY(icon.pixmap(32, QIcon::Normal).toImage() != icon.pixmap(32, QIcon::Disabled).toImage()); + + icon.addPixmap(pm, QIcon::Disabled); + //the disabled icon must now be the same as the normal one. + QVERIFY( icon.pixmap(32, QIcon::Normal).toImage() == icon.pixmap(32, QIcon::Disabled).toImage() ); +} + +void tst_QIcon::fromTheme() +{ + QString searchPath = QLatin1String(":/icons"); + QIcon::setThemeSearchPaths(QStringList() << searchPath); + QVERIFY(QIcon::themeSearchPaths().size() == 1); + QCOMPARE(searchPath, QIcon::themeSearchPaths()[0]); + + QString themeName("testtheme"); + QIcon::setThemeName(themeName); + QCOMPARE(QIcon::themeName(), themeName); + + // Test normal icon + QIcon appointmentIcon = QIcon::fromTheme("appointment-new"); + QVERIFY(!appointmentIcon.isNull()); + QVERIFY(!appointmentIcon.availableSizes(QIcon::Normal, QIcon::Off).isEmpty()); + QVERIFY(appointmentIcon.availableSizes().contains(QSize(16, 16))); + QVERIFY(appointmentIcon.availableSizes().contains(QSize(32, 32))); + QVERIFY(appointmentIcon.availableSizes().contains(QSize(22, 22))); + + // Test icon from parent theme + QIcon abIcon = QIcon::fromTheme("address-book-new"); + QVERIFY(!abIcon.isNull()); + QVERIFY(QIcon::hasThemeIcon("address-book-new")); + QVERIFY(!abIcon.availableSizes().isEmpty()); + + // Test non existing icon + QIcon noIcon = QIcon::fromTheme("broken-icon"); + QVERIFY(noIcon.isNull()); + QVERIFY(!QIcon::hasThemeIcon("broken-icon")); + + // Test non existing icon with fallback + noIcon = QIcon::fromTheme("broken-icon", abIcon); + QVERIFY(noIcon.cacheKey() == abIcon.cacheKey()); + + // Test svg-only icon + noIcon = QIcon::fromTheme("svg-icon", abIcon); + QVERIFY(!noIcon.availableSizes().isEmpty()); + + QByteArray ba; + // write to QByteArray + { + QBuffer buffer(&ba); + buffer.open(QIODevice::WriteOnly); + QDataStream stream(&buffer); + stream << abIcon; + } + + // read from QByteArray + { + QBuffer buffer(&ba); + buffer.open(QIODevice::ReadOnly); + QDataStream stream(&buffer); + QIcon i; + stream >> i; + QCOMPARE(i.isNull(), abIcon.isNull()); + QCOMPARE(i.availableSizes(), abIcon.availableSizes()); + } + + // Make sure setting the theme name clears the state + QIcon::setThemeName(""); + abIcon = QIcon::fromTheme("address-book-new"); + QVERIFY(abIcon.isNull()); +} + + +void tst_QIcon::task223279_inconsistentAddFile() +{ + QIcon icon1; + icon1.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); + icon1.addFile(QLatin1String("IconThatDoesntExist"), QSize(32, 32)); + QPixmap pm1 = icon1.pixmap(32, 32); + + QIcon icon2; + icon2.addFile(QLatin1String(":/trolltech/styles/commonstyle/images/standardbutton-open-16.png")); + icon2.addFile(QLatin1String("IconThatDoesntExist")); + QPixmap pm2 = icon1.pixmap(32, 32); + + QCOMPARE(pm1.isNull(), false); + QCOMPARE(pm1.size(), QSize(16,16)); + QCOMPARE(pm1.isNull(), pm2.isNull()); + QCOMPARE(pm1.size(), pm2.size()); +} + + +QTEST_MAIN(tst_QIcon) +#include "tst_qicon.moc" diff --git a/tests/auto/widgets/kernel/qicon/tst_qicon.qrc b/tests/auto/widgets/kernel/qicon/tst_qicon.qrc new file mode 100644 index 0000000000..7925a33c84 --- /dev/null +++ b/tests/auto/widgets/kernel/qicon/tst_qicon.qrc @@ -0,0 +1,20 @@ + + +image.png +rect.png +./icons/testtheme/16x16/actions/appointment-new.png +./icons/testtheme/22x22/actions/appointment-new.png +./icons/testtheme/32x32/actions/appointment-new.png +./icons/testtheme/index.theme +./icons/testtheme/scalable/actions/svg-only.svg +./icons/themeparent/16x16/actions/address-book-new.png +./icons/themeparent/16x16/actions/appointment-new.png +./icons/themeparent/22x22/actions/address-book-new.png +./icons/themeparent/22x22/actions/appointment-new.png +./icons/themeparent/32x32/actions/address-book-new.png +./icons/themeparent/32x32/actions/appointment-new.png +./icons/themeparent/index.theme +./icons/themeparent/scalable/actions/address-book-new.svg +./icons/themeparent/scalable/actions/appointment-new.svg + + -- cgit v1.2.3 From 9abefae4fb123ff506d3a903e62da1e88c2c79e4 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sat, 10 Mar 2012 23:51:31 +0100 Subject: Restore some source compatibility Add an implicit #include back in to avoid needless SC and compilation breaks. Add some deprecated method for codecForTr, until all other modules are ported to mot use it anymore. Change-Id: I5334b47a0c32819b9eb6b7203cc98ce4e6073a64 Reviewed-by: Kent Hansen --- src/corelib/codecs/qtextcodec.h | 4 ++++ src/corelib/kernel/qcoreapplication.h | 6 +++++- src/corelib/tools/qlocale.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/corelib/codecs/qtextcodec.h b/src/corelib/codecs/qtextcodec.h index b4b170f7d7..690214323d 100644 --- a/src/corelib/codecs/qtextcodec.h +++ b/src/corelib/codecs/qtextcodec.h @@ -72,6 +72,10 @@ public: static QTextCodec* codecForLocale(); static void setCodecForLocale(QTextCodec *c); +#if QT_DEPRECATED_SINCE(5, 0) + QT_DEPRECATED static QTextCodec *codecForTr() { return codecForMib(4); /* Latin1 */ } +#endif + static QTextCodec *codecForHtml(const QByteArray &ba); static QTextCodec *codecForHtml(const QByteArray &ba, QTextCodec *defaultCodec); diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index 0a5181a508..cf76511f25 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -137,7 +137,11 @@ public: static void installTranslator(QTranslator * messageFile); static void removeTranslator(QTranslator * messageFile); #endif - enum Encoding { UnicodeUTF8, Latin1, DefaultCodec = Latin1 }; + enum Encoding { UnicodeUTF8, Latin1, DefaultCodec = Latin1 +#if QT_DEPRECATED_SINCE(5, 0) + , CodecForTr = Latin1 +#endif + }; static QString translate(const char * context, const char * key, const char * disambiguation = 0, diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h index 2ecd934100..c029f627b2 100644 --- a/src/corelib/tools/qlocale.h +++ b/src/corelib/tools/qlocale.h @@ -42,6 +42,7 @@ #ifndef QLOCALE_H #define QLOCALE_H +#include #include #include -- cgit v1.2.3 From 17659df556a866f2be3959a7558cebdac9925f66 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Sun, 11 Mar 2012 12:14:43 +0000 Subject: Update qnx mkspecs to not use fixed tool paths This changeset allows Qt to be built for QNX platforms in light of commit d59e85d9095f5d8fa787149fe8d34e8dfac0a0b5. Change-Id: Idf8e89cf1b0a5625ef7ee6397c223137fa151cdc Reviewed-by: Rafael Roquetto Reviewed-by: Oswald Buddenhagen --- mkspecs/common/qcc-base-qnx.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/mkspecs/common/qcc-base-qnx.conf b/mkspecs/common/qcc-base-qnx.conf index 2bc33117bb..11e8ca43a2 100644 --- a/mkspecs/common/qcc-base-qnx.conf +++ b/mkspecs/common/qcc-base-qnx.conf @@ -41,9 +41,6 @@ QMAKE_LFLAGS = -Wl,-rpath-link,$${QNX_DIR}/$${QNX_CPUDIR}/lib -Wl,-rp QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS] QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS] -QMAKE_MOC = $$[QT_INSTALL_BINS]/moc -QMAKE_UIC = $$[QT_INSTALL_BINS]/uic -QMAKE_RCC = $$[QT_INSTALL_BINS]/rcc QMAKE_CXX = $$QMAKE_CC -lang-c++ -- cgit v1.2.3 From 197ba93cf06bd57fecf9d1b2e54a778113962248 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 2 Mar 2012 19:30:00 +0100 Subject: rip out -incremental from configure the feature is rather obscure and unlikely to be used by anyone. Change-Id: I2dfb4ca4d5d1f210d385c013f46bc6389fd6ea2d Reviewed-by: Joerg Bornemann --- configure | 26 +------------------------- qmake/qmake.pri | 1 - tools/configure/configureapp.cpp | 2 +- 3 files changed, 2 insertions(+), 27 deletions(-) diff --git a/configure b/configure index cac9a038a4..aa1722d4a5 100755 --- a/configure +++ b/configure @@ -651,7 +651,6 @@ CFG_CONFIGURE_EXIT_ON_ERROR=yes CFG_PROFILE=no CFG_EXCEPTIONS=unspecified CFG_GUI=auto # (yes|no|auto) -CFG_INCREMENTAL=auto CFG_QCONFIG=full CFG_DEBUG=auto CFG_MYSQL_CONFIG= @@ -888,7 +887,7 @@ while [ "$#" -gt 0 ]; do VAL=no ;; #Qt style yes options - -incremental|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-xinput2|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-xcb|-wayland|-nis|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-debug-and-release|-exceptions|-harfbuzz|-prefix-install|-silent|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-phonon-backend|-audio-backend|-declarative-debug|-javascript-jit|-rpath|-force-pkg-config|-icu|-force-asserts|-testcocoon) + -profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-xinput2|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-xcb|-wayland|-nis|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-debug-and-release|-exceptions|-harfbuzz|-prefix-install|-silent|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-phonon-backend|-audio-backend|-declarative-debug|-javascript-jit|-rpath|-force-pkg-config|-icu|-force-asserts|-testcocoon) VAR=`echo $1 | sed "s,^-\(.*\),\1,"` VAL=yes ;; @@ -1360,13 +1359,6 @@ while [ "$#" -gt 0 ]; do UNKNOWN_OPT=yes fi ;; - incremental) - if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then - CFG_INCREMENTAL="$VAL" - else - UNKNOWN_OPT=yes - fi - ;; fatal_error) if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then CFG_CONFIGURE_EXIT_ON_ERROR="$VAL" @@ -6580,21 +6572,6 @@ else echo "QMAKESPEC = $XPLATFORM" >> "$CACHEFILE.tmp" fi -# incrementals -INCREMENTAL="" -[ "$CFG_INCREMENTAL" = "auto" ] && "$WHICH" p4 >/dev/null 2>&1 && [ "$CFG_DEV" = "yes" ] && CFG_INCREMENTAL="yes" -if [ "$CFG_INCREMENTAL" = "yes" ]; then - find "$relpath" -perm u+w -mtime -3 | grep 'cpp$' | while read f; do - # don't need to worry about generated files - [ -r `echo $f | sed "s,cpp$,ui,"` ] && continue - basename "$f" | grep '^moc_' >/dev/null 2>&1 && continue - # done - INCREMENTAL="$INCREMENTAL `basename \"$f\" | sed 's,.cpp,.o,'`" - done - [ '!' -z "$INCREMENTAL" ] && echo "QMAKE_INCREMENTAL += $INCREMENTAL" >> "$CACHEFILE.tmp" - [ -r "$outpath/.qmake.incremental" ] && echo "include($outpath/.qmake.incremental)" >> "$CACHEFILE.tmp" -fi - # replace .qmake.cache if it differs from the newly created temp file if cmp -s "$CACHEFILE.tmp" "$CACHEFILE"; then rm -f "$CACHEFILE.tmp" @@ -6677,7 +6654,6 @@ if [ "$OPT_VERBOSE" = "yes" ]; then echo "qmake switches ......... $QMAKE_SWITCHES" fi -[ "$CFG_INCREMENTAL" = "yes" ] && [ '!' -z "$INCREMENTAL" ] && echo "Incremental ............ $INCREMENTAL" echo "Build .................. $CFG_BUILD_PARTS" echo "Configuration .......... $QMAKE_CONFIG $QT_CONFIG" if [ "$CFG_DEBUG_RELEASE" = "yes" ]; then diff --git a/qmake/qmake.pri b/qmake/qmake.pri index abb073c48e..fb530a6380 100644 --- a/qmake/qmake.pri +++ b/qmake/qmake.pri @@ -1,6 +1,5 @@ CONFIG += depend_includepath -QMAKE_INCREMENTAL = SKIP_DEPENDS += qconfig.h qmodules.h DEFINES += QT_NO_TEXTCODEC QT_NO_LIBRARY QT_NO_STL QT_NO_COMPRESS QT_NO_UNICODETABLES \ QT_NO_GEOM_VARIANT QT_NO_DATASTREAM diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 62ec3e8d8c..8423953d7d 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -2451,7 +2451,7 @@ void Configure::generateCachefile() for (QStringList::Iterator var = qmakeVars.begin(); var != qmakeVars.end(); ++var) { cacheStream << (*var) << endl; } - cacheStream << "CONFIG += " << qmakeConfig.join(" ") << " incremental depend_includepath no_private_qt_headers_warning QTDIR_build" << endl; + cacheStream << "CONFIG += " << qmakeConfig.join(" ") << "depend_includepath no_private_qt_headers_warning QTDIR_build" << endl; cacheStream.flush(); cacheFile.close(); -- cgit v1.2.3 From aed6eaa5b211a4676c15627657f3a7bda6e3866d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 9 Mar 2012 19:11:27 +0100 Subject: QT_RAW_INSTALL_FOO => QT_INSTALL_FOO/raw this makes the "sysrootable" properties more magic, with the raw versions being omitted from the qmake -query output and automatically falling back to the "cooked" variant if there is no sysroot set. this makes the "normal" qmake -query less noisy. this will become even more obvious when i add more "overloads" of the properties. Change-Id: I08000986427264ec6238c8fe0a77f5cecdbf1201 Reviewed-by: Joerg Bornemann --- dist/changes-5.0.0 | 2 +- mkspecs/features/qt_module_config.prf | 16 ++++++++-------- qmake/project.cpp | 2 +- qmake/property.cpp | 34 ++++++++++++++++------------------ 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/dist/changes-5.0.0 b/dist/changes-5.0.0 index 97aa7bdfc6..ba1adde6c0 100644 --- a/dist/changes-5.0.0 +++ b/dist/changes-5.0.0 @@ -207,7 +207,7 @@ information about a particular change. an entirely pristine context. * Configure's -sysroot and -hostprefix are now handled slightly differently. The QT_INSTALL_... properties are now automatically prefixed with the sysroot; - the raw values are available as QT_RAW_INSTALL_... and the sysroot as QT_SYSROOT. + the raw values are available as QT_INSTALL_.../raw and the sysroot as QT_SYSROOT. The new QT_HOST_... properties can be used to refer to the Qt host tools. * Several functions and built-in variables were modified to return normalized paths. diff --git a/mkspecs/features/qt_module_config.prf b/mkspecs/features/qt_module_config.prf index 98cdab121f..cae5f47387 100644 --- a/mkspecs/features/qt_module_config.prf +++ b/mkspecs/features/qt_module_config.prf @@ -118,24 +118,24 @@ load(qt_installs) unix|win32-g++* { CONFIG += create_pc - QMAKE_PKGCONFIG_LIBDIR = $$[QT_RAW_INSTALL_LIBS] - QMAKE_PKGCONFIG_INCDIR = $$[QT_RAW_INSTALL_HEADERS]/$$TARGET - QMAKE_PKGCONFIG_CFLAGS = -I$$[QT_RAW_INSTALL_HEADERS] + QMAKE_PKGCONFIG_LIBDIR = $$[QT_INSTALL_LIBS/raw] + QMAKE_PKGCONFIG_INCDIR = $$[QT_INSTALL_HEADERS/raw]/$$TARGET + QMAKE_PKGCONFIG_CFLAGS = -I$$[QT_INSTALL_HEADERS/raw] QMAKE_PKGCONFIG_DESTDIR = pkgconfig include_replace.match = $$QMAKE_INCDIR_QT - include_replace.replace = $$[QT_RAW_INSTALL_HEADERS] + include_replace.replace = $$[QT_INSTALL_HEADERS/raw] lib_replace.match = $$QMAKE_LIBDIR_QT - lib_replace.replace = $$[QT_RAW_INSTALL_LIBS] + lib_replace.replace = $$[QT_INSTALL_LIBS/raw] prefix_replace.match = $$QT_BUILD_TREE - prefix_replace.replace = $$[QT_RAW_INSTALL_PREFIX] + prefix_replace.replace = $$[QT_INSTALL_PREFIX/raw] QMAKE_PKGCONFIG_INSTALL_REPLACE += include_replace lib_replace prefix_replace } unix { CONFIG += create_libtool explicitlib - QMAKE_PRL_LIBDIR = $$[QT_RAW_INSTALL_LIBS] ### XXX + QMAKE_PRL_LIBDIR = $$[QT_INSTALL_LIBS/raw] ### XXX QMAKE_PRL_INSTALL_REPLACE += include_replace lib_replace - QMAKE_LIBTOOL_LIBDIR = $$[QT_RAW_INSTALL_LIBS] + QMAKE_LIBTOOL_LIBDIR = $$[QT_INSTALL_LIBS/raw] QMAKE_LIBTOOL_INSTALL_REPLACE += include_replace lib_replace } diff --git a/qmake/project.cpp b/qmake/project.cpp index 7655f05f2e..8b5ed1e2ac 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -2782,7 +2782,7 @@ QMakeProject::doVariableReplaceExpand(const QString &str, QHash 'z') && (unicode < 'A' || unicode > 'Z') && - (unicode < '0' || unicode > '9')) + (unicode < '0' || unicode > '9') && (!term || unicode != '/')) break; var.append(QChar(unicode)); if(++i == str_len) diff --git a/qmake/property.cpp b/qmake/property.cpp index 8ed9462c60..1952b5069b 100644 --- a/qmake/property.cpp +++ b/qmake/property.cpp @@ -68,18 +68,6 @@ static const struct { { "QT_INSTALL_CONFIGURATION", QLibraryInfo::SettingsPath, false }, { "QT_INSTALL_EXAMPLES", QLibraryInfo::ExamplesPath, false }, { "QT_INSTALL_DEMOS", QLibraryInfo::ExamplesPath, false }, // Just backwards compat - { "QT_RAW_INSTALL_PREFIX", QLibraryInfo::PrefixPath, true }, - { "QT_RAW_INSTALL_DATA", QLibraryInfo::DataPath, true }, - { "QT_RAW_INSTALL_DOCS", QLibraryInfo::DocumentationPath, true }, - { "QT_RAW_INSTALL_HEADERS", QLibraryInfo::HeadersPath, true }, - { "QT_RAW_INSTALL_LIBS", QLibraryInfo::LibrariesPath, true }, - { "QT_RAW_INSTALL_BINS", QLibraryInfo::BinariesPath, true }, - { "QT_RAW_INSTALL_TESTS", QLibraryInfo::TestsPath, true }, - { "QT_RAW_INSTALL_PLUGINS", QLibraryInfo::PluginsPath, true }, - { "QT_RAW_INSTALL_IMPORTS", QLibraryInfo::ImportsPath, true }, - { "QT_RAW_INSTALL_TRANSLATIONS", QLibraryInfo::TranslationsPath, true }, - { "QT_RAW_INSTALL_CONFIGURATION", QLibraryInfo::SettingsPath, true }, - { "QT_RAW_INSTALL_EXAMPLES", QLibraryInfo::ExamplesPath, true }, { "QT_HOST_PREFIX", QLibraryInfo::HostPrefixPath, true }, { "QT_HOST_DATA", QLibraryInfo::HostDataPath, true }, { "QT_HOST_BINS", QLibraryInfo::HostBinariesPath, true }, @@ -87,10 +75,15 @@ static const struct { QMakeProperty::QMakeProperty() : settings(0) { - for (int i = 0; i < sizeof(propList)/sizeof(propList[0]); i++) - m_values[QString::fromLatin1(propList[i].name)] = propList[i].raw - ? QLibraryInfo::rawLocation(propList[i].loc) - : QLibraryInfo::location(propList[i].loc); + for (int i = 0; i < sizeof(propList)/sizeof(propList[0]); i++) { + QString name = QString::fromLatin1(propList[i].name); + QString val = QLibraryInfo::rawLocation(propList[i].loc); + if (!propList[i].raw) { + m_values[name] = QLibraryInfo::location(propList[i].loc); + name += "/raw"; + } + m_values[name] = val; + } } QMakeProperty::~QMakeProperty() @@ -216,8 +209,13 @@ QMakeProperty::exec() #ifdef QT_VERSION_STR specialProps.append("QT_VERSION"); #endif - foreach (QString prop, specialProps) - fprintf(stdout, "%s:%s\n", prop.toLatin1().constData(), value(prop).toLatin1().constData()); + foreach (QString prop, specialProps) { + QString val = value(prop); + QString pval = value(prop + "/raw"); + fprintf(stdout, "%s:%s\n", prop.toLatin1().constData(), val.toLatin1().constData()); + if (!pval.isEmpty() && pval != val) + fprintf(stdout, "%s/raw:%s\n", prop.toLatin1().constData(), pval.toLatin1().constData()); + } return true; } for(QStringList::ConstIterator it = Option::prop::properties.begin(); -- cgit v1.2.3 From 2dd6f1467fca051e977eeda0369b9b89e25065b1 Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Tue, 6 Mar 2012 18:05:27 +0000 Subject: Allow qmake to find features when using mkspecs in nested dirs Commit 8e5eb1bddcfc introduced the assumtion that mkspecs are immediately below the mkspecs directory itself. This is not true for e.g. unsupported/blackberry-armv7le-qcc. This commit restores qmake's ability to find the "root" of the mkspecs collection no matter how deeply the actual mkspecs are nested. Task-number: QTBUG-24665 Change-Id: I98faaf8e6ae7b8524277aea6c17e685e507e37b3 Reviewed-by: Sean Harmer Reviewed-by: Joerg Bornemann Reviewed-by: Oswald Buddenhagen --- qmake/project.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/qmake/project.cpp b/qmake/project.cpp index 8b5ed1e2ac..b82b793319 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -579,14 +579,19 @@ QStringList qmake_feature_paths(QMakeProperty *prop=0) // The spec is already platform-dependent, so no subdirs here. feature_roots << Option::mkfile::qmakespec + base_concat; + // Also check directly under the root directory of the mkspecs collection QFileInfo specfi(Option::mkfile::qmakespec); - if (!specfi.isRoot()) { - QDir specdir(specfi.absolutePath()); - if (specdir.exists(QLatin1String("features"))) { - for(QStringList::Iterator concat_it = concat.begin(); - concat_it != concat.end(); ++concat_it) - feature_roots << (specdir.path() + (*concat_it)); + QDir specrootdir(specfi.absolutePath()); + while (!specrootdir.isRoot()) { + const QString specrootpath = specrootdir.path(); + if (specrootpath.endsWith(mkspecs_concat)) { + if (QFile::exists(specrootpath + base_concat)) + for (QStringList::Iterator concat_it = concat.begin(); + concat_it != concat.end(); ++concat_it) + feature_roots << (specrootpath + (*concat_it)); + break; } + specrootdir.cdUp(); } } for(QStringList::Iterator concat_it = concat.begin(); -- cgit v1.2.3 From 12c89098832de7475ad6ad11fe92f50b13f713f4 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Sat, 10 Mar 2012 10:04:04 +0100 Subject: sanitize install target names qmake uses the variable name verbatim, which makes the generated makefile look "interesting" without this cleanup. Change-Id: If6c4f12563a0ee6429513fbfac534f40bb7c0b97 Reviewed-by: Rohan McGovern --- mkspecs/features/testcase.prf | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mkspecs/features/testcase.prf b/mkspecs/features/testcase.prf index 9bb9875f6d..b00d15579f 100644 --- a/mkspecs/features/testcase.prf +++ b/mkspecs/features/testcase.prf @@ -97,7 +97,11 @@ contains(INSTALLS, target) { # ... # for(file, TESTDATA) { - tdi = testdata_install_$${file} + tnam = $$file + tnam ~= s,\\.\\.,dotdot, + tnam ~= s,[?*],wildcard, + tnam ~= s,[^A-Za-z0-9],_, + tdi = testdata_$$tnam tdif = $${tdi}.files tdip = $${tdi}.path -- cgit v1.2.3 From 6a0f84e0a86b9c27a861e19b4eb7bb4701a1e3c7 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 9 Mar 2012 14:26:43 +0200 Subject: Migrate QWindowSystemInterface to use QElapsedTimer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I7dfb0590dce79678d49f5d6ef8f60758719bcf72 Reviewed-by: Samuel Rødal --- src/gui/kernel/qguiapplication.cpp | 2 ++ src/gui/kernel/qwindowsysteminterface_qpa.cpp | 6 +----- src/gui/kernel/qwindowsysteminterface_qpa_p.h | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index bfc52a816c..26690c78cf 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -696,6 +696,8 @@ void QGuiApplicationPrivate::init() // trigger registering of QVariant's GUI types qRegisterGuiVariant(); + QWindowSystemInterfacePrivate::eventTime.start(); + is_app_running = true; init_plugins(pluginList); QWindowSystemInterface::sendWindowSystemEvents(QCoreApplicationPrivate::eventDispatcher, QEventLoop::AllEvents); diff --git a/src/gui/kernel/qwindowsysteminterface_qpa.cpp b/src/gui/kernel/qwindowsysteminterface_qpa.cpp index 6f0abbdd0c..be9ac8e545 100644 --- a/src/gui/kernel/qwindowsysteminterface_qpa.cpp +++ b/src/gui/kernel/qwindowsysteminterface_qpa.cpp @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE -QTime QWindowSystemInterfacePrivate::eventTime; +QElapsedTimer QWindowSystemInterfacePrivate::eventTime; //------------------------------------------------------------ // @@ -266,10 +266,6 @@ void QWindowSystemInterfacePrivate::queueWindowSystemEvent(QWindowSystemInterfac windowSystemEventQueue.append(ev); queueMutex.unlock(); - // Make sure the event timer is started. - if (!QWindowSystemInterfacePrivate::eventTime.isValid()) - QWindowSystemInterfacePrivate::eventTime.start(); - QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::qt_qpa_core_dispatcher(); if (dispatcher) dispatcher->wakeUp(); diff --git a/src/gui/kernel/qwindowsysteminterface_qpa_p.h b/src/gui/kernel/qwindowsysteminterface_qpa_p.h index f5c141b4c9..fe97b486ad 100644 --- a/src/gui/kernel/qwindowsysteminterface_qpa_p.h +++ b/src/gui/kernel/qwindowsysteminterface_qpa_p.h @@ -42,6 +42,7 @@ #define QWINDOWSYSTEMINTERFACE_QPA_P_H #include "qwindowsysteminterface_qpa.h" +#include QT_BEGIN_HEADER @@ -272,7 +273,7 @@ public: static WindowSystemEvent * getWindowSystemEvent(); static void queueWindowSystemEvent(WindowSystemEvent *ev); - static QTime eventTime; + static QElapsedTimer eventTime; static QList convertTouchPoints(const QList &points, QEvent::Type *type); }; -- cgit v1.2.3 From 0ecec0e903f80c8657f323a51973b81cdeebcac1 Mon Sep 17 00:00:00 2001 From: Casper van Donderen Date: Mon, 12 Mar 2012 10:48:44 +0100 Subject: Remove unnecessary function. The reconstituteFieldMemberExpression static function was not usedf anywhere. Change-Id: Ide23045d7f7c3194a9725ae658df85562ba29ad5 Reviewed-by: Martin Smith --- src/tools/qdoc/qmlvisitor.cpp | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/tools/qdoc/qmlvisitor.cpp b/src/tools/qdoc/qmlvisitor.cpp index f04b220f32..9c934ebcd1 100644 --- a/src/tools/qdoc/qmlvisitor.cpp +++ b/src/tools/qdoc/qmlvisitor.cpp @@ -439,31 +439,6 @@ 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. -- cgit v1.2.3 From eb57da5b3ff9915d2254fdbf57992fa0320d9041 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 7 Mar 2012 13:51:31 +0100 Subject: Update accessibility StateChange by custom event. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Subclass QAccessibleEvent to give details what changed in the state change. Change-Id: I9005d311e85a3c8bfa6e062833fa6a8a7dc6a4a4 Reviewed-by: Jan-Arve Sæther --- src/gui/accessible/qaccessible.cpp | 3 ++- src/gui/accessible/qaccessible.h | 15 +++++++++++++++ src/widgets/kernel/qwidget.cpp | 14 +++++--------- src/widgets/widgets/qabstractbutton.cpp | 10 +++++++--- src/widgets/widgets/qpushbutton.cpp | 4 +++- tests/auto/other/qaccessibility/tst_qaccessibility.cpp | 2 -- 6 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index a7843ba227..91b0b5fbe6 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -257,7 +257,8 @@ QT_BEGIN_NAMESPACE \value SelectionWithin Several changes to a selection has occurred in an item view. \value SoundPlayed A sound has been played by an object - \value StateChanged The QAccessible::State of an object has changed. + \omitvalue StateChanged The QAccessible::State of an object has changed. + This value is used internally for the QAccessibleStateChangeEvent. \value TableCaptionChanged A table caption has been changed. \value TableColumnDescriptionChanged The description of a table column, typically found in the column's header, has been changed. diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index 8c962ffb53..e8a5cf8bad 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -452,6 +452,21 @@ private: int m_child; }; +class Q_GUI_EXPORT QAccessibleStateChangeEvent :public QAccessibleEvent +{ +public: + inline QAccessibleStateChangeEvent(QAccessible::State state, QObject *obj, int chld = -1) + : QAccessibleEvent(QAccessible::StateChanged, obj, chld), m_changedStates(state) + {} + + QAccessible::State changedStates() const { + return m_changedStates; + } + +private: + QAccessible::State m_changedStates; +}; + #define QAccessibleInterface_iid "org.qt-project.Qt.QAccessibleInterface" Q_DECLARE_INTERFACE(QAccessibleInterface, QAccessibleInterface_iid) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 03ada1ac7a..1493f61972 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -8245,12 +8245,15 @@ bool QWidget::event(QEvent *event) void QWidget::changeEvent(QEvent * event) { switch(event->type()) { - case QEvent::EnabledChange: + case QEvent::EnabledChange: { update(); #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::StateChanged, this, 0)); + QAccessible::State s; + s.disabled = true; + QAccessible::updateAccessibility(QAccessibleStateChangeEvent(s, this)); #endif break; + } case QEvent::FontChange: case QEvent::StyleChange: { @@ -10515,13 +10518,6 @@ void QWidget::updateMicroFocus() { // updating everything since this is currently called for any kind of state change qApp->inputMethod()->update(Qt::ImQueryAll); - -#ifndef QT_NO_ACCESSIBILITY - if (isVisible()) { - // ##### is this correct - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::StateChanged, this, 0)); - } -#endif } /*! diff --git a/src/widgets/widgets/qabstractbutton.cpp b/src/widgets/widgets/qabstractbutton.cpp index f7c8ad7773..aebef8ddc9 100644 --- a/src/widgets/widgets/qabstractbutton.cpp +++ b/src/widgets/widgets/qabstractbutton.cpp @@ -504,9 +504,6 @@ void QAbstractButtonPrivate::refresh() if (blockRefresh) return; q->update(); -#ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::StateChanged, q, 0)); -#endif } void QAbstractButtonPrivate::click() @@ -767,6 +764,13 @@ void QAbstractButton::setChecked(bool checked) d->notifyChecked(); if (guard) emit toggled(checked); + + +#ifndef QT_NO_ACCESSIBILITY + QAccessible::State s; + s.checked = true; + QAccessible::updateAccessibility(QAccessibleStateChangeEvent(s, this)); +#endif } bool QAbstractButton::isChecked() const diff --git a/src/widgets/widgets/qpushbutton.cpp b/src/widgets/widgets/qpushbutton.cpp index 7ca5dcb486..059b0f801c 100644 --- a/src/widgets/widgets/qpushbutton.cpp +++ b/src/widgets/widgets/qpushbutton.cpp @@ -376,7 +376,9 @@ void QPushButton::setDefault(bool enable) } update(); #ifndef QT_NO_ACCESSIBILITY - QAccessible::updateAccessibility(QAccessibleEvent(QAccessible::StateChanged, this, 0)); + QAccessible::State s; + s.defaultButton = true; + QAccessible::updateAccessibility(QAccessibleStateChangeEvent(s, this)); #endif } diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index 3e3fce2e1c..b8649a6443 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -419,8 +419,6 @@ void tst_QAccessibility::eventTest() button->setFocus(Qt::MouseFocusReason); QTestAccessibility::clearEvents(); QTest::mouseClick(button, Qt::LeftButton, 0); - QVERIFY_EVENT(button, 0, QAccessible::StateChanged); - QVERIFY_EVENT(button, 0, QAccessible::StateChanged); button->setAccessibleName("Olaf the second"); QVERIFY_EVENT(button, -1, QAccessible::NameChanged); -- cgit v1.2.3 From 57cf7c8a1bb1905294038ba5c98f1e8235fc08af Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Fri, 9 Mar 2012 18:09:17 -0800 Subject: Clean up some auto tests of gui These unit tests do not depent on QtWidget. Change-Id: I95526125c563885c0531da7ebfee06bca9a87b1c Reviewed-by: Gunnar Sletta Reviewed-by: Friedemann Kleint --- tests/auto/gui/painting/qbrush/qbrush.pro | 2 +- tests/auto/gui/painting/qpolygon/qpolygon.pro | 2 +- tests/auto/gui/painting/qpolygon/tst_qpolygon.cpp | 1 - .../qabstracttextdocumentlayout.pro | 2 +- tests/auto/gui/text/qstatictext/qstatictext.pro | 2 +- tests/auto/gui/text/qstatictext/tst_qstatictext.cpp | 11 +++++------ tests/auto/gui/text/qtextblock/qtextblock.pro | 2 +- tests/auto/gui/text/qtextpiecetable/qtextpiecetable.pro | 2 +- tests/auto/gui/util/qdesktopservices/qdesktopservices.pro | 2 +- tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp | 1 - 10 files changed, 12 insertions(+), 15 deletions(-) diff --git a/tests/auto/gui/painting/qbrush/qbrush.pro b/tests/auto/gui/painting/qbrush/qbrush.pro index 2a470c4db1..3ef9b36ef5 100644 --- a/tests/auto/gui/painting/qbrush/qbrush.pro +++ b/tests/auto/gui/painting/qbrush/qbrush.pro @@ -1,4 +1,4 @@ CONFIG += testcase TARGET = tst_qbrush -QT += widgets testlib +QT += testlib SOURCES += tst_qbrush.cpp diff --git a/tests/auto/gui/painting/qpolygon/qpolygon.pro b/tests/auto/gui/painting/qpolygon/qpolygon.pro index 869fbd30c5..804fc0dfd2 100644 --- a/tests/auto/gui/painting/qpolygon/qpolygon.pro +++ b/tests/auto/gui/painting/qpolygon/qpolygon.pro @@ -1,6 +1,6 @@ CONFIG += testcase TARGET = tst_qpolygon -QT += widgets testlib +QT += testlib SOURCES += tst_qpolygon.cpp unix:!mac:LIBS+=-lm diff --git a/tests/auto/gui/painting/qpolygon/tst_qpolygon.cpp b/tests/auto/gui/painting/qpolygon/tst_qpolygon.cpp index 5e5f661a09..f9dbbbf219 100644 --- a/tests/auto/gui/painting/qpolygon/tst_qpolygon.cpp +++ b/tests/auto/gui/painting/qpolygon/tst_qpolygon.cpp @@ -47,7 +47,6 @@ #include #include -#include class tst_QPolygon : public QObject { diff --git a/tests/auto/gui/text/qabstracttextdocumentlayout/qabstracttextdocumentlayout.pro b/tests/auto/gui/text/qabstracttextdocumentlayout/qabstracttextdocumentlayout.pro index 025b3f8a26..3848a287dc 100644 --- a/tests/auto/gui/text/qabstracttextdocumentlayout/qabstracttextdocumentlayout.pro +++ b/tests/auto/gui/text/qabstracttextdocumentlayout/qabstracttextdocumentlayout.pro @@ -4,7 +4,7 @@ CONFIG += testcase TARGET = tst_qabstracttextdocumentlayout -QT += widgets testlib +QT += testlib SOURCES += tst_qabstracttextdocumentlayout.cpp diff --git a/tests/auto/gui/text/qstatictext/qstatictext.pro b/tests/auto/gui/text/qstatictext/qstatictext.pro index a0955af710..67f2e047a4 100644 --- a/tests/auto/gui/text/qstatictext/qstatictext.pro +++ b/tests/auto/gui/text/qstatictext/qstatictext.pro @@ -1,6 +1,6 @@ CONFIG += testcase TARGET = tst_qstatictext -QT += widgets widgets-private testlib +QT += testlib QT += core core-private gui gui-private SOURCES += tst_qstatictext.cpp diff --git a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp index 66145f2dcf..fbb9549425 100644 --- a/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp +++ b/tests/auto/gui/text/qstatictext/tst_qstatictext.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include -#include +#include #include #include @@ -48,7 +48,6 @@ #include #include -#include // #define DEBUG_SAVE_IMAGE @@ -296,7 +295,7 @@ void tst_QStaticText::prepareToWrongData() void tst_QStaticText::setFont() { - QFont font = QApplication::font(); + QFont font = QGuiApplication::font(); font.setBold(true); font.setPointSize(28); @@ -618,7 +617,7 @@ void tst_QStaticText::plainTextVsRichText() void tst_QStaticText::setPenPlainText() { - QFont font = QApplication::font(); + QFont font = QGuiApplication::font(); font.setStyleStrategy(QFont::NoAntialias); QFontMetricsF fm(font); @@ -646,7 +645,7 @@ void tst_QStaticText::setPenPlainText() void tst_QStaticText::setPenRichText() { - QFont font = QApplication::font(); + QFont font = QGuiApplication::font(); font.setStyleStrategy(QFont::NoAntialias); QFontMetricsF fm(font); @@ -675,7 +674,7 @@ void tst_QStaticText::setPenRichText() void tst_QStaticText::richTextOverridesPen() { - QFont font = QApplication::font(); + QFont font = QGuiApplication::font(); font.setStyleStrategy(QFont::NoAntialias); QFontMetricsF fm(font); diff --git a/tests/auto/gui/text/qtextblock/qtextblock.pro b/tests/auto/gui/text/qtextblock/qtextblock.pro index cad009a35a..cf3456bbf6 100644 --- a/tests/auto/gui/text/qtextblock/qtextblock.pro +++ b/tests/auto/gui/text/qtextblock/qtextblock.pro @@ -1,7 +1,7 @@ CONFIG += testcase TARGET = tst_qtextblock -QT += widgets widgets-private testlib +QT += testlib QT += core-private gui-private SOURCES += tst_qtextblock.cpp diff --git a/tests/auto/gui/text/qtextpiecetable/qtextpiecetable.pro b/tests/auto/gui/text/qtextpiecetable/qtextpiecetable.pro index 930d18f5fe..1419e32012 100644 --- a/tests/auto/gui/text/qtextpiecetable/qtextpiecetable.pro +++ b/tests/auto/gui/text/qtextpiecetable/qtextpiecetable.pro @@ -1,6 +1,6 @@ CONFIG += testcase TARGET = tst_qtextpiecetable -QT += widgets widgets-private testlib +QT += testlib QT += core-private gui-private SOURCES += tst_qtextpiecetable.cpp HEADERS += ../qtextdocument/common.h diff --git a/tests/auto/gui/util/qdesktopservices/qdesktopservices.pro b/tests/auto/gui/util/qdesktopservices/qdesktopservices.pro index 98bc5c3d0d..cf14e6b47a 100644 --- a/tests/auto/gui/util/qdesktopservices/qdesktopservices.pro +++ b/tests/auto/gui/util/qdesktopservices/qdesktopservices.pro @@ -1,5 +1,5 @@ CONFIG += testcase -QT += widgets testlib +QT += testlib SOURCES += tst_qdesktopservices.cpp TARGET = tst_qdesktopservices diff --git a/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp b/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp index ad45d00520..0ad37c21e8 100644 --- a/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp +++ b/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp @@ -41,7 +41,6 @@ #include -#include #include #include -- cgit v1.2.3 From 4eeb07d886940087de85ba1c4a12e634f35d8d9d Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Fri, 9 Mar 2012 18:43:21 -0800 Subject: Move tst_qprinter.cpp to QtPrintSupport QPrinter and QPrinterInfo belong to QtPrintSupport. Change-Id: I0c146e0c717be365e752c1eaf7dbe6765fb72da2 Reviewed-by: Gunnar Sletta Reviewed-by: Friedemann Kleint --- tests/auto/auto.pro | 1 + tests/auto/gui/painting/painting.pro | 2 - tests/auto/gui/painting/qprinter/.gitignore | 4 - tests/auto/gui/painting/qprinter/qprinter.pro | 7 - tests/auto/gui/painting/qprinter/tst_qprinter.cpp | 1023 -------------------- tests/auto/gui/painting/qprinterinfo/.gitignore | 1 - .../gui/painting/qprinterinfo/qprinterinfo.pro | 10 - .../gui/painting/qprinterinfo/tst_qprinterinfo.cpp | 393 -------- tests/auto/printsupport/kernel/kernel.pro | 4 + tests/auto/printsupport/kernel/qprinter/.gitignore | 4 + .../auto/printsupport/kernel/qprinter/qprinter.pro | 7 + .../printsupport/kernel/qprinter/tst_qprinter.cpp | 1023 ++++++++++++++++++++ .../printsupport/kernel/qprinterinfo/.gitignore | 1 + .../kernel/qprinterinfo/qprinterinfo.pro | 10 + .../kernel/qprinterinfo/tst_qprinterinfo.cpp | 393 ++++++++ tests/auto/printsupport/printsupport.pro | 3 + 16 files changed, 1446 insertions(+), 1440 deletions(-) delete mode 100644 tests/auto/gui/painting/qprinter/.gitignore delete mode 100644 tests/auto/gui/painting/qprinter/qprinter.pro delete mode 100644 tests/auto/gui/painting/qprinter/tst_qprinter.cpp delete mode 100644 tests/auto/gui/painting/qprinterinfo/.gitignore delete mode 100644 tests/auto/gui/painting/qprinterinfo/qprinterinfo.pro delete mode 100644 tests/auto/gui/painting/qprinterinfo/tst_qprinterinfo.cpp create mode 100644 tests/auto/printsupport/kernel/kernel.pro create mode 100644 tests/auto/printsupport/kernel/qprinter/.gitignore create mode 100644 tests/auto/printsupport/kernel/qprinter/qprinter.pro create mode 100644 tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp create mode 100644 tests/auto/printsupport/kernel/qprinterinfo/.gitignore create mode 100644 tests/auto/printsupport/kernel/qprinterinfo/qprinterinfo.pro create mode 100644 tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp create mode 100644 tests/auto/printsupport/printsupport.pro diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 63c4ca6a48..124af19799 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -13,6 +13,7 @@ SUBDIRS += \ concurrent \ other \ widgets \ + printsupport \ cross_compile: SUBDIRS -= tools !contains(QT_CONFIG, opengl): SUBDIRS -= opengl diff --git a/tests/auto/gui/painting/painting.pro b/tests/auto/gui/painting/painting.pro index 62230eeac7..8f018fd921 100644 --- a/tests/auto/gui/painting/painting.pro +++ b/tests/auto/gui/painting/painting.pro @@ -7,12 +7,10 @@ SUBDIRS=\ qregion \ qpainter \ qpathclipper \ - qprinterinfo \ qpen \ qpaintengine \ qtransform \ qwmatrix \ - qprinter \ qpolygon \ !contains(QT_CONFIG, private_tests): SUBDIRS -= \ diff --git a/tests/auto/gui/painting/qprinter/.gitignore b/tests/auto/gui/painting/qprinter/.gitignore deleted file mode 100644 index 85de0e9675..0000000000 --- a/tests/auto/gui/painting/qprinter/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -tqpluginloader/st_qprinter -silly -test.pdf - diff --git a/tests/auto/gui/painting/qprinter/qprinter.pro b/tests/auto/gui/painting/qprinter/qprinter.pro deleted file mode 100644 index 7543e91f8c..0000000000 --- a/tests/auto/gui/painting/qprinter/qprinter.pro +++ /dev/null @@ -1,7 +0,0 @@ -CONFIG += testcase -TARGET = tst_qprinter -QT += printsupport widgets testlib -SOURCES += tst_qprinter.cpp - -mac*:CONFIG+=insignificant_test -win32:CONFIG += insignificant_test # QTBUG-24191 diff --git a/tests/auto/gui/painting/qprinter/tst_qprinter.cpp b/tests/auto/gui/painting/qprinter/tst_qprinter.cpp deleted file mode 100644 index 3460ad702b..0000000000 --- a/tests/auto/gui/painting/qprinter/tst_qprinter.cpp +++ /dev/null @@ -1,1023 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the test suite 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 - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef Q_OS_WIN -#include -#endif - -Q_DECLARE_METATYPE(QRect) - -QT_FORWARD_DECLARE_CLASS(QPrinter) - -// Helper class to make sure temp files are cleaned up after test complete -class TempFileCleanup -{ -public: - TempFileCleanup(const QString &file) - : m_file(file) - { - } - - ~TempFileCleanup() - { - QFile::remove(m_file); - } -private: - QString m_file; -}; - -class tst_QPrinter : public QObject -{ - Q_OBJECT - -#ifdef QT_NO_PRINTER -public slots: - void initTestCase(); -#else -private slots: - void getSetCheck(); -// Add your testfunctions and testdata create functions here - void testPageSize(); - void testPageRectAndPaperRect(); - void testPageRectAndPaperRect_data(); - void testSetOptions(); - void testMargins_data(); - void testMargins(); - void testNonExistentPrinter(); - void testPageSetupDialog(); - void testMulitpleSets_data(); - void testMulitpleSets(); - void testPageMargins_data(); - void testPageMargins(); - void changingOutputFormat(); - void outputFormatFromSuffix(); - void setGetPaperSize(); - void valuePreservation(); - void errorReporting(); - void testCustomPageSizes(); -#if !defined(QT_NO_COMPLETER) && !defined(QT_NO_FILEDIALOG) - void printDialogCompleter(); -#endif - - void testCopyCount(); - void testCurrentPage(); - - void taskQTBUG4497_reusePrinterOnDifferentFiles(); - void testPdfTitle(); -#endif -}; - -#ifdef QT_NO_PRINTER -void tst_QPrinter::initTestCase() -{ - QSKIP("This test requires printing support"); -} - -#else - -// Testing get/set functions -void tst_QPrinter::getSetCheck() -{ - QPrinter obj1; - // OutputFormat QPrinter::outputFormat() - // void QPrinter::setOutputFormat(OutputFormat) - obj1.setOutputFormat(QPrinter::OutputFormat(QPrinter::PdfFormat)); - QCOMPARE(QPrinter::OutputFormat(QPrinter::PdfFormat), obj1.outputFormat()); - - // bool QPrinter::collateCopies() - // void QPrinter::setCollateCopies(bool) - obj1.setCollateCopies(false); - QCOMPARE(false, obj1.collateCopies()); - obj1.setCollateCopies(true); - QCOMPARE(true, obj1.collateCopies()); - - obj1.setColorMode(QPrinter::GrayScale); - QCOMPARE(obj1.colorMode(), QPrinter::GrayScale); - obj1.setColorMode(QPrinter::Color); - QCOMPARE(obj1.colorMode(), QPrinter::Color); - - obj1.setCreator(QString::fromLatin1("RandomQtUser")); - QCOMPARE(obj1.creator(), QString::fromLatin1("RandomQtUser")); - - obj1.setDocName(QString::fromLatin1("RandomQtDocument")); - QCOMPARE(obj1.docName(), QString::fromLatin1("RandomQtDocument")); - - obj1.setDoubleSidedPrinting(true); - QCOMPARE(obj1.doubleSidedPrinting(), true); - obj1.setDoubleSidedPrinting(false); - QCOMPARE(obj1.doubleSidedPrinting(), false); - - obj1.setFromTo(1, 4); - QCOMPARE(obj1.fromPage(), 1); - QCOMPARE(obj1.toPage(), 4); - - obj1.setFullPage(true); - QCOMPARE(obj1.fullPage(), true); - obj1.setFullPage(false); - QCOMPARE(obj1.fullPage(), false); - - obj1.setOrientation(QPrinter::Landscape); - QCOMPARE(obj1.orientation(), QPrinter::Landscape); - obj1.setOrientation(QPrinter::Portrait); - QCOMPARE(obj1.orientation(), QPrinter::Portrait); - - obj1.setOutputFileName(QString::fromLatin1("RandomQtName")); - QCOMPARE(obj1.outputFileName(), QString::fromLatin1("RandomQtName")); - - obj1.setPageOrder(QPrinter::FirstPageFirst); - QCOMPARE(obj1.pageOrder(), QPrinter::FirstPageFirst); - obj1.setPageOrder(QPrinter::LastPageFirst); - QCOMPARE(obj1.pageOrder(), QPrinter::LastPageFirst); - - obj1.setPaperSource(QPrinter::Cassette); - QCOMPARE(obj1.paperSource(), QPrinter::Cassette); - obj1.setPaperSource(QPrinter::Middle); - QCOMPARE(obj1.paperSource(), QPrinter::Middle); - -#ifdef Q_OS_UNIX - obj1.setPrintProgram(QString::fromLatin1("/bin/true")); - QCOMPARE(obj1.printProgram(), QString::fromLatin1("/bin/true")); - - obj1.setPrinterSelectionOption(QString::fromLatin1("--option")); - QCOMPARE(obj1.printerSelectionOption(), QString::fromLatin1("--option")); -#endif - - obj1.setPrinterName(QString::fromLatin1("myPrinter")); - QCOMPARE(obj1.printerName(), QString::fromLatin1("myPrinter")); - - // bool QPrinter::fontEmbeddingEnabled() - // void QPrinter::setFontEmbeddingEnabled(bool) - obj1.setFontEmbeddingEnabled(false); - QCOMPARE(false, obj1.fontEmbeddingEnabled()); - obj1.setFontEmbeddingEnabled(true); - QCOMPARE(true, obj1.fontEmbeddingEnabled()); - - // PageSize QPrinter::pageSize() - // void QPrinter::setPageSize(PageSize) - obj1.setPageSize(QPrinter::PageSize(QPrinter::A4)); - QCOMPARE(QPrinter::PageSize(QPrinter::A4), obj1.pageSize()); - obj1.setPageSize(QPrinter::PageSize(QPrinter::Letter)); - QCOMPARE(QPrinter::PageSize(QPrinter::Letter), obj1.pageSize()); - obj1.setPageSize(QPrinter::PageSize(QPrinter::Legal)); - QCOMPARE(QPrinter::PageSize(QPrinter::Legal), obj1.pageSize()); - - // PrintRange QPrinter::printRange() - // void QPrinter::setPrintRange(PrintRange) - obj1.setPrintRange(QPrinter::PrintRange(QPrinter::AllPages)); - QCOMPARE(QPrinter::PrintRange(QPrinter::AllPages), obj1.printRange()); - obj1.setPrintRange(QPrinter::PrintRange(QPrinter::Selection)); - QCOMPARE(QPrinter::PrintRange(QPrinter::Selection), obj1.printRange()); - obj1.setPrintRange(QPrinter::PrintRange(QPrinter::PageRange)); - QCOMPARE(QPrinter::PrintRange(QPrinter::PageRange), obj1.printRange()); -} - -#define MYCOMPARE(a, b) QCOMPARE(QVariant((int)a), QVariant((int)b)) - -void tst_QPrinter::testPageSetupDialog() -{ - // Make sure this doesn't crash at least - { - QPrinter printer; - QPageSetupDialog dialog(&printer); - } -} - -void tst_QPrinter::testPageSize() -{ -#if 1 - QSKIP("QPrinter::winPageSize(): Windows only and currently not implemented / QTBUG-22927"); -#else - QPrinter prn; - - prn.setPageSize(QPrinter::Letter); - MYCOMPARE(prn.pageSize(), QPrinter::Letter); - MYCOMPARE(prn.winPageSize(), DMPAPER_LETTER); - - prn.setPageSize(QPrinter::A4); - MYCOMPARE(prn.pageSize(), QPrinter::A4); - MYCOMPARE(prn.winPageSize(), DMPAPER_A4); - - prn.setWinPageSize(DMPAPER_LETTER); - MYCOMPARE(prn.winPageSize(), DMPAPER_LETTER); - MYCOMPARE(prn.pageSize(), QPrinter::Letter); - - prn.setWinPageSize(DMPAPER_A4); - MYCOMPARE(prn.winPageSize(), DMPAPER_A4); - MYCOMPARE(prn.pageSize(), QPrinter::A4); -#endif -} - -void tst_QPrinter::testPageRectAndPaperRect_data() -{ - QTest::addColumn("orientation"); - QTest::addColumn("withPainter"); - QTest::addColumn("resolution"); - QTest::addColumn("doPaperRect"); - - // paperrect - QTest::newRow("paperRect0") << int(QPrinter::Portrait) << true << 300 << true; - QTest::newRow("paperRect1") << int(QPrinter::Portrait) << false << 300 << true; - QTest::newRow("paperRect2") << int(QPrinter::Landscape) << true << 300 << true; - QTest::newRow("paperRect3") << int(QPrinter::Landscape) << false << 300 << true; - QTest::newRow("paperRect4") << int(QPrinter::Portrait) << true << 600 << true; - QTest::newRow("paperRect5") << int(QPrinter::Portrait) << false << 600 << true; - QTest::newRow("paperRect6") << int(QPrinter::Landscape) << true << 600 << true; - QTest::newRow("paperRect7") << int(QPrinter::Landscape) << false << 600 << true; - QTest::newRow("paperRect8") << int(QPrinter::Portrait) << true << 1200 << true; - QTest::newRow("paperRect9") << int(QPrinter::Portrait) << false << 1200 << true; - QTest::newRow("paperRect10") << int(QPrinter::Landscape) << true << 1200 << true; - QTest::newRow("paperRect11") << int(QPrinter::Landscape) << false << 1200 << true; - - // page rect - QTest::newRow("pageRect0") << int(QPrinter::Portrait) << true << 300 << false; - QTest::newRow("pageRect1") << int(QPrinter::Portrait) << false << 300 << false; - QTest::newRow("pageRect2") << int(QPrinter::Landscape) << true << 300 << false; - QTest::newRow("pageRect3") << int(QPrinter::Landscape) << false << 300 << false; - QTest::newRow("pageRect4") << int(QPrinter::Portrait) << true << 600 << false; - QTest::newRow("pageRect5") << int(QPrinter::Portrait) << false << 600 << false; - QTest::newRow("pageRect6") << int(QPrinter::Landscape) << true << 600 << false; - QTest::newRow("pageRect7") << int(QPrinter::Landscape) << false << 600 << false; - QTest::newRow("pageRect8") << int(QPrinter::Portrait) << true << 1200 << false; - QTest::newRow("pageRect9") << int(QPrinter::Portrait) << false << 1200 << false; - QTest::newRow("pageRect10") << int(QPrinter::Landscape) << true << 1200 << false; - QTest::newRow("pageRect11") << int(QPrinter::Landscape) << false << 1200 << false; -} - -void tst_QPrinter::testPageRectAndPaperRect() -{ - QFETCH(bool, withPainter); - QFETCH(int, orientation); - QFETCH(int, resolution); - QFETCH(bool, doPaperRect); - - QPainter *painter = 0; - QPrinter printer(QPrinter::HighResolution); - printer.setOrientation(QPrinter::Orientation(orientation)); - printer.setOutputFileName("silly"); - TempFileCleanup tmpFile("silly"); - - QRect pageRect = doPaperRect ? printer.paperRect() : printer.pageRect(); - float inchesX = float(pageRect.width()) / float(printer.resolution()); - float inchesY = float(pageRect.height()) / float(printer.resolution()); - printer.setResolution(resolution); - if (withPainter) - painter = new QPainter(&printer); - - QRect otherRect = doPaperRect ? printer.paperRect() : printer.pageRect(); - float otherInchesX = float(otherRect.width()) / float(printer.resolution()); - float otherInchesY = float(otherRect.height()) / float(printer.resolution()); - if (painter != 0) - delete painter; - - QVERIFY(qAbs(otherInchesX - inchesX) < 0.01); - QVERIFY(qAbs(otherInchesY - inchesY) < 0.01); - - QVERIFY(printer.orientation() == QPrinter::Portrait || pageRect.width() > pageRect.height()); - QVERIFY(printer.orientation() != QPrinter::Portrait || pageRect.width() < pageRect.height()); -} - -void tst_QPrinter::testSetOptions() -{ - QPrinter prn; - QPrintDialog dlg(&prn); - - // Verify default values - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), true); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), false); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), true); - - dlg.setEnabledOptions(QAbstractPrintDialog::PrintPageRange); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), false); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), false); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), true); - - dlg.setEnabledOptions((QAbstractPrintDialog::PrintDialogOptions(QAbstractPrintDialog::PrintSelection - | QAbstractPrintDialog::PrintPageRange))); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), false); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), true); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), true); - - dlg.setEnabledOptions(QAbstractPrintDialog::PrintSelection); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), false); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), true); - MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), false); -} - -void tst_QPrinter::testMargins_data() -{ - QTest::addColumn("orientation"); - QTest::addColumn("fullpage"); - QTest::addColumn("pagesize"); - QTest::addColumn("width"); - QTest::addColumn("height"); - QTest::addColumn("withPainter"); - - QTest::newRow("data0") << int(QPrinter::Portrait) << true << int(QPrinter::A4) << 210 << 297 << false; - QTest::newRow("data1") << int(QPrinter::Landscape) << true << int(QPrinter::A4) << 297 << 210 << false; - QTest::newRow("data2") << int(QPrinter::Landscape) << false << int(QPrinter::A4) << 297 << 210 << false; - QTest::newRow("data3") << int(QPrinter::Portrait) << false << int(QPrinter::A4) << 210 << 297 << false; - QTest::newRow("data4") << int(QPrinter::Portrait) << true << int(QPrinter::A4) << 210 << 297 << true; - QTest::newRow("data5") << int(QPrinter::Landscape) << true << int(QPrinter::A4) << 297 << 210 << true; - QTest::newRow("data6") << int(QPrinter::Landscape) << false << int(QPrinter::A4) << 297 << 210 << true; - QTest::newRow("data7") << int(QPrinter::Portrait) << false << int(QPrinter::A4) << 210 << 297 << true; -} - -void tst_QPrinter::testMargins() -{ - QFETCH(bool, withPainter); - QFETCH(int, orientation); - QFETCH(int, pagesize); - QFETCH(int, width); - QFETCH(int, height); - QFETCH(bool, fullpage); - Q_UNUSED(width); - Q_UNUSED(height); - QPrinter printer; - QPainter *painter = 0; - printer.setOutputFileName("silly"); - printer.setOrientation((QPrinter::Orientation)orientation); - printer.setFullPage(fullpage); - printer.setPageSize((QPrinter::PageSize)pagesize); - if (withPainter) - painter = new QPainter(&printer); - - if (painter) - delete painter; - QFile::remove("silly"); -} - -void tst_QPrinter::testNonExistentPrinter() -{ -#ifndef Q_OS_WIN - QSKIP("QPrinter::testNonExistentPrinter() is not relevant for this platform"); -#else - QPrinter printer; - QPainter painter; - - // Make sure it doesn't crash on setting or getting properties - printer.setPrinterName("some non existing printer"); - printer.setPageSize(QPrinter::A4); - printer.setOrientation(QPrinter::Portrait); - printer.setFullPage(true); - printer.pageSize(); - printer.orientation(); - printer.fullPage(); - printer.setCopyCount(1); - printer.printerName(); - - // nor metrics - QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmWidth), 0); - QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmHeight), 0); - QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmWidthMM), 0); - QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmHeightMM), 0); - QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmNumColors), 0); - QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmDepth), 0); - QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmDpiX), 0); - QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmDpiY), 0); - QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmPhysicalDpiX), 0); - QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmPhysicalDpiY), 0); - - QVERIFY(!painter.begin(&printer)); -#endif -} - -void tst_QPrinter::testMulitpleSets_data() -{ - QTest::addColumn("resolution"); - QTest::addColumn("pageSize"); - QTest::addColumn("widthMMAfter"); - QTest::addColumn("heightMMAfter"); - - - QTest::newRow("lowRes") << int(QPrinter::ScreenResolution) << int(QPrinter::A4) << 210 << 297; - QTest::newRow("lowResLetter") << int(QPrinter::ScreenResolution) << int(QPrinter::Letter) << 216 << 279; - QTest::newRow("lowResA5") << int(QPrinter::ScreenResolution) << int(QPrinter::A5) << 148 << 210; - QTest::newRow("midRes") << int(QPrinter::PrinterResolution) << int(QPrinter::A4) << 210 << 297; - QTest::newRow("midResLetter") << int(QPrinter::PrinterResolution) << int(QPrinter::Letter) << 216 << 279; - QTest::newRow("midResA5") << int(QPrinter::PrinterResolution) << int(QPrinter::A5) << 148 << 210; - QTest::newRow("highRes") << int(QPrinter::HighResolution) << int(QPrinter::A4) << 210 << 297; - QTest::newRow("highResLetter") << int(QPrinter::HighResolution) << int(QPrinter::Letter) << 216 << 279; - QTest::newRow("highResA5") << int(QPrinter::HighResolution) << int(QPrinter::A5) << 148 << 210; -} - -static void computePageValue(const QPrinter &printer, int &retWidth, int &retHeight) -{ - const double Inch2MM = 25.4; - - double width = double(printer.paperRect().width()) / printer.logicalDpiX() * Inch2MM; - double height = double(printer.paperRect().height()) / printer.logicalDpiY() * Inch2MM; - retWidth = qRound(width); - retHeight = qRound(height); -} - -void tst_QPrinter::testMulitpleSets() -{ - // A very simple test, but Mac needs to have its format "validated" if the format is changed - // This takes care of that. - QFETCH(int, resolution); - QFETCH(int, pageSize); - QFETCH(int, widthMMAfter); - QFETCH(int, heightMMAfter); - - - QPrinter::PrinterMode mode = QPrinter::PrinterMode(resolution); - QPrinter::PageSize printerPageSize = QPrinter::PageSize(pageSize); - QPrinter printer(mode); - printer.setFullPage(true); - - int paperWidth, paperHeight; - //const int Tolerance = 2; - - computePageValue(printer, paperWidth, paperHeight); - printer.setPageSize(printerPageSize); - - if (printer.pageSize() != printerPageSize) { - QSKIP("Current page size is not supported on this printer"); - return; - } - - QCOMPARE(printer.widthMM(), widthMMAfter); - QCOMPARE(printer.heightMM(), heightMMAfter); - - computePageValue(printer, paperWidth, paperHeight); - - QVERIFY(qAbs(paperWidth - widthMMAfter) <= 2); - QVERIFY(qAbs(paperHeight - heightMMAfter) <= 2); - - // Set it again and see if it still works. - printer.setPageSize(printerPageSize); - QCOMPARE(printer.widthMM(), widthMMAfter); - QCOMPARE(printer.heightMM(), heightMMAfter); - - printer.setOrientation(QPrinter::Landscape); - computePageValue(printer, paperWidth, paperHeight); - QVERIFY(qAbs(paperWidth - heightMMAfter) <= 2); - QVERIFY(qAbs(paperHeight - widthMMAfter) <= 2); -} - -void tst_QPrinter::changingOutputFormat() -{ -#if QT_VERSION < 0x050000 - QPrinter p; - p.setOutputFormat(QPrinter::PostScriptFormat); - p.setPageSize(QPrinter::A8); - p.setOutputFormat(QPrinter::PdfFormat); - QCOMPARE(p.pageSize(), QPrinter::A8); -#endif -} - -void tst_QPrinter::outputFormatFromSuffix() -{ - if (QPrinterInfo::availablePrinters().size() == 0) - QSKIP("No printers available."); - QPrinter p; - QVERIFY(p.outputFormat() == QPrinter::NativeFormat); - p.setOutputFileName("test.pdf"); - TempFileCleanup tmpFile("test.pdf"); - QVERIFY(p.outputFormat() == QPrinter::PdfFormat); - p.setOutputFileName(QString()); - QVERIFY(p.outputFormat() == QPrinter::NativeFormat); -} - -void tst_QPrinter::setGetPaperSize() -{ - QPrinter p; - p.setOutputFormat(QPrinter::PdfFormat); - QSizeF size(500, 10); - p.setPaperSize(size, QPrinter::Millimeter); - QCOMPARE(p.paperSize(QPrinter::Millimeter), size); - QSizeF ptSize = p.paperSize(QPrinter::Point); - //qDebug() << ptSize; - QVERIFY(qAbs(ptSize.width() - size.width() * (72/25.4)) < 1E-4); - QVERIFY(qAbs(ptSize.height() - size.height() * (72/25.4)) < 1E-4); -} - -void tst_QPrinter::testPageMargins_data() -{ - QTest::addColumn("left"); - QTest::addColumn("top"); - QTest::addColumn("right"); - QTest::addColumn("bottom"); - QTest::addColumn("unit"); - - QTest::newRow("data0") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Millimeter); - QTest::newRow("data1") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Point); - QTest::newRow("data2") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Inch); - QTest::newRow("data3") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Pica); - QTest::newRow("data4") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Didot); - QTest::newRow("data5") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Cicero); -} - -void tst_QPrinter::testPageMargins() -{ - QPrinter obj1; - - qreal toMillimeters[6]; - toMillimeters[QPrinter::Millimeter] = 1; - toMillimeters[QPrinter::Point] = 0.352777778; - toMillimeters[QPrinter::Inch] = 25.4; - toMillimeters[QPrinter::Pica] = 4.23333333; - toMillimeters[QPrinter::Didot] = 0.376; - toMillimeters[QPrinter::Cicero] = 4.51166667; - - QFETCH(qreal, left); - QFETCH(qreal, top); - QFETCH(qreal, right); - QFETCH(qreal, bottom); - QFETCH(int, unit); - - qreal nLeft, nTop, nRight, nBottom; - - obj1.setPageMargins(left, top, right, bottom, static_cast(unit)); - - qreal tolerance = 0.05; - - obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Millimeter); - QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Millimeter]) < tolerance); - QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Millimeter]) < tolerance); - QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Millimeter]) < tolerance); - QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Millimeter]) < tolerance); - - obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Point); - QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Point]) < tolerance); - QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Point]) < tolerance); - QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Point]) < tolerance); - QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Point]) < tolerance); - - obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Inch); - QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Inch]) < tolerance); - QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Inch]) < tolerance); - QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Inch]) < tolerance); - QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Inch]) < tolerance); - - obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Pica); - QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Pica]) < tolerance); - QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Pica]) < tolerance); - QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Pica]) < tolerance); - QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Pica]) < tolerance); - - obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Didot); - QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Didot]) < tolerance); - QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Didot]) < tolerance); - QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Didot]) < tolerance); - QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Didot]) < tolerance); - - obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Cicero); - QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Cicero]) < tolerance); - QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Cicero]) < tolerance); - QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Cicero]) < tolerance); - QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Cicero]) < tolerance); -} - -void tst_QPrinter::valuePreservation() -{ - QPrinter::OutputFormat oldFormat = QPrinter::PdfFormat; - QPrinter::OutputFormat newFormat = QPrinter::NativeFormat; // TODO: Correct? - - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - bool status = printer.collateCopies(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.collateCopies(), status); - - printer.setCollateCopies(!status); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.collateCopies(), !status); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.collateCopies(), !status); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QPrinter::ColorMode status = printer.colorMode(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.colorMode(), status); - - printer.setColorMode(QPrinter::ColorMode(!status)); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.colorMode(), QPrinter::ColorMode(!status)); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.colorMode(), QPrinter::ColorMode(!status)); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QString status = printer.creator(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.creator(), status); - - status = QString::fromLatin1("Mr. Test"); - printer.setCreator(status); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.creator(), status); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.creator(), status); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QString status = printer.docName(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.docName(), status); - - status = QString::fromLatin1("Test document"); - printer.setDocName(status); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.docName(), status); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.docName(), status); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - bool status = printer.doubleSidedPrinting(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.doubleSidedPrinting(), status); - - printer.setDoubleSidedPrinting(!status); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.doubleSidedPrinting(), !status); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.doubleSidedPrinting(), !status); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - bool status = printer.fontEmbeddingEnabled(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.fontEmbeddingEnabled(), status); - - printer.setFontEmbeddingEnabled(!status); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.fontEmbeddingEnabled(), !status); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.fontEmbeddingEnabled(), !status); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - bool status = printer.fullPage(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.fullPage(), status); - - printer.setFullPage(!status); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.fullPage(), !status); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.fullPage(), !status); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QPrinter::Orientation status = printer.orientation(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.orientation(), status); - - printer.setOrientation(QPrinter::Orientation(!status)); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.orientation(), QPrinter::Orientation(!status)); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.orientation(), QPrinter::Orientation(!status)); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QString status = printer.outputFileName(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.outputFileName(), status); - - status = QString::fromLatin1("Test file"); - printer.setOutputFileName(status); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.outputFileName(), status); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.outputFileName(), status); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QPrinter::PageOrder status = printer.pageOrder(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.pageOrder(), status); - - printer.setPageOrder(QPrinter::PageOrder(!status)); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.pageOrder(), QPrinter::PageOrder(!status)); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.pageOrder(), QPrinter::PageOrder(!status)); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QPrinter::PageSize status = printer.pageSize(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.pageSize(), status); - - printer.setPageSize(QPrinter::B5); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.pageSize(), QPrinter::B5); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.pageSize(), QPrinter::B5); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QPrinter::PaperSource status = printer.paperSource(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.paperSource(), status); - - printer.setPaperSource(QPrinter::Manual); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.paperSource(), QPrinter::Manual); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.paperSource(), QPrinter::Manual); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QString status = printer.printProgram(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.printProgram(), status); - - status = QString::fromLatin1("/usr/local/bin/lpr"); - printer.setPrintProgram(status); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.printProgram(), status); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.printProgram(), status); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QPrinter::PrintRange status = printer.printRange(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.printRange(), status); - - printer.setPrintRange(QPrinter::PrintRange(!status)); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.printRange(), QPrinter::PrintRange(!status)); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.printRange(), QPrinter::PrintRange(!status)); - } - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QString status = printer.printerName(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.printerName(), status); - - status = QString::fromLatin1("SuperDuperPrinter"); - printer.setPrinterName(status); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.printerName(), status); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.printerName(), status); - } -#ifndef Q_OS_WIN - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - QString status = printer.printerSelectionOption(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.printerSelectionOption(), status); - - status = QString::fromLatin1("Optional option"); - printer.setPrinterSelectionOption(status); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.printerSelectionOption(), status); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.printerSelectionOption(), status); - } -#endif - { - QPrinter printer; - printer.setOutputFormat(oldFormat); - int status = printer.resolution(); - printer.setOutputFormat(newFormat); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.resolution(), status); - - printer.setResolution(status-150); - printer.setOutputFormat(newFormat); - QCOMPARE(printer.resolution(), status-150); - printer.setOutputFormat(oldFormat); - QCOMPARE(printer.resolution(), status-150); - } -} - -void tst_QPrinter::errorReporting() -{ - QPrinter p; - p.setOutputFormat(QPrinter::PdfFormat); - QCOMPARE(p.isValid(), true); - QPainter painter; -#ifndef Q_WS_WIN - // not sure how to choose a never-writable file on windows. But its QFile behavior anyway, so lets rely on it failing elsewhere - p.setOutputFileName("/foobar/nonwritable.pdf"); - QCOMPARE(painter.begin(&p), false); // it should check the output file is writable -#endif - p.setOutputFileName("test.pdf"); - TempFileCleanup tmpFile("test.pdf"); - QCOMPARE(painter.begin(&p), true); // it should check the output - QCOMPARE(p.isValid(), true); - painter.end(); -} - -void tst_QPrinter::testCustomPageSizes() -{ - QPrinter p; - - QSizeF customSize(8.5, 11.0); - p.setPaperSize(customSize, QPrinter::Inch); - - QSizeF paperSize = p.paperSize(QPrinter::Inch); - QCOMPARE(paperSize, customSize); - - QPrinter p2(QPrinter::HighResolution); - p2.setPaperSize(customSize, QPrinter::Inch); - paperSize = p.paperSize(QPrinter::Inch); - QCOMPARE(paperSize, customSize); -} - -#if !defined(QT_NO_COMPLETER) && !defined(QT_NO_FILEDIALOG) -void tst_QPrinter::printDialogCompleter() -{ - QPrintDialog dialog; - dialog.printer()->setOutputFileName("file.pdf"); - TempFileCleanup tmpFile("file.pdf"); - dialog.setEnabledOptions(QAbstractPrintDialog::PrintToFile); - dialog.show(); - - QTest::qWait(100); - - QTest::keyClick(&dialog, Qt::Key_Tab); - QTest::keyClick(&dialog, 'P'); - // The test passes if it doesn't crash. -} -#endif - -void tst_QPrinter::testCopyCount() -{ - QPrinter p; - p.setCopyCount(15); - QCOMPARE(p.copyCount(), 15); -} - -static void printPage(QPainter *painter) -{ - painter->setPen(QPen(Qt::black, 4)); - painter->drawRect(50, 60, 70, 80); -} - -void tst_QPrinter::taskQTBUG4497_reusePrinterOnDifferentFiles() -{ - TempFileCleanup tmpFile1("out1.ps"); - TempFileCleanup tmpFile2("out2.ps"); - - QPrinter printer; - { - - printer.setOutputFileName("out1.ps"); - QPainter painter(&printer); - printPage(&painter); - - } - { - - printer.setOutputFileName("out2.ps"); - QPainter painter(&printer); - printPage(&painter); - - } - QFile file1("out1.ps"); - QVERIFY(file1.open(QIODevice::ReadOnly)); - - QFile file2("out2.ps"); - QVERIFY(file2.open(QIODevice::ReadOnly)); - - QEXPECT_FAIL("", "QTBUG-22562, QTBUG-22296", Abort); - QCOMPARE(file1.readAll(), file2.readAll()); -} - -void tst_QPrinter::testCurrentPage() -{ - QPrinter printer; - printer.setFromTo(1, 10); - - // Test set print range - printer.setPrintRange(QPrinter::CurrentPage); - QCOMPARE(printer.printRange(), QPrinter::CurrentPage); - QCOMPARE(printer.fromPage(), 1); - QCOMPARE(printer.toPage(), 10); - - QPrintDialog dialog(&printer); - - // Test default Current Page option to off - QCOMPARE(dialog.isOptionEnabled(QPrintDialog::PrintCurrentPage), false); - - // Test enable Current Page option - dialog.setOption(QPrintDialog::PrintCurrentPage); - QCOMPARE(dialog.isOptionEnabled(QPrintDialog::PrintCurrentPage), true); - -} - -void tst_QPrinter::testPdfTitle() -{ - // Check the document name is represented correctly in produced pdf - { - QPainter painter; - QPrinter printer; - // This string is just the UTF-8 encoding of the string: \()f ø hiragana o - const unsigned char titleBuf[]={0x5c, 0x28, 0x29, 0x66, 0xc3, 0xb8, 0xe3, 0x81, 0x8a, 0x00}; - const char *title = reinterpret_cast(titleBuf); - printer.setOutputFileName("file.pdf"); - printer.setDocName(QString::fromUtf8(title)); - painter.begin(&printer); - painter.end(); - } - TempFileCleanup tmpFile("file.pdf"); - QFile file("file.pdf"); - QVERIFY(file.open(QIODevice::ReadOnly)); - // The we expect the title to appear in the PDF as: - // ASCII('\title (') UTF16(\\\(\)f ø hiragana o) ASCII(')'). - // which has the following binary representation - const unsigned char expectedBuf[] = { - 0x2f, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x28, 0xfe, - 0xff, 0x00, 0x5c, 0x5c, 0x00, 0x5c, 0x28, 0x00, 0x5c, - 0x29, 0x00, 0x66, 0x00, 0xf8, 0x30, 0x4a, 0x29}; - const char *expected = reinterpret_cast(expectedBuf); - QVERIFY(file.readAll().contains(QByteArray(expected, 26))); -} - -#endif - -QTEST_MAIN(tst_QPrinter) -#include "tst_qprinter.moc" diff --git a/tests/auto/gui/painting/qprinterinfo/.gitignore b/tests/auto/gui/painting/qprinterinfo/.gitignore deleted file mode 100644 index fcef7c1997..0000000000 --- a/tests/auto/gui/painting/qprinterinfo/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qprinterinfo diff --git a/tests/auto/gui/painting/qprinterinfo/qprinterinfo.pro b/tests/auto/gui/painting/qprinterinfo/qprinterinfo.pro deleted file mode 100644 index 88cb07f338..0000000000 --- a/tests/auto/gui/painting/qprinterinfo/qprinterinfo.pro +++ /dev/null @@ -1,10 +0,0 @@ -CONFIG += testcase -TARGET = tst_qprinterinfo -SOURCES += tst_qprinterinfo.cpp - -QT += printsupport network testlib - -DEFINES += QT_USE_USING_NAMESPACE - -mac: CONFIG += insignificant_test # QTBUG-23060 -win32:CONFIG += insignificant_test # QTBUG-24190 diff --git a/tests/auto/gui/painting/qprinterinfo/tst_qprinterinfo.cpp b/tests/auto/gui/painting/qprinterinfo/tst_qprinterinfo.cpp deleted file mode 100644 index 2323dc8df3..0000000000 --- a/tests/auto/gui/painting/qprinterinfo/tst_qprinterinfo.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the test suite 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 -#include -#include -#include -#include - -#ifdef Q_OS_UNIX -# include -# include -# include -#endif - -Q_DECLARE_METATYPE(QRect) - -class tst_QPrinterInfo : public QObject -{ - Q_OBJECT - -#ifdef QT_NO_PRINTER -public slots: - void initTestCase(); -#else -private slots: - void testForDefaultPrinter(); - void testForPrinters(); - void testForPaperSizes(); - void testConstructors(); - void testAssignment(); - -private: - void macFixNameFormat(QString *printerName); - QString getDefaultPrinterFromSystem(); - QStringList getPrintersFromSystem(); - - QString getOutputFromCommand(const QStringList& command); -#endif -}; - -#ifdef QT_NO_PRINTER -void tst_QPrinterInfo::initTestCase() -{ - QSKIP("This test requires printing support"); -} - -#else - -void tst_QPrinterInfo::macFixNameFormat(QString *printerName) -{ -// Modify the format of the printer name to match Qt, lpstat returns -// foo___domain_no, Qt returns foo @ domain.no -#ifdef Q_OS_MAC - printerName->replace(QLatin1String("___"), QLatin1String(" @ ")); - printerName->replace(QLatin1String("_"), QLatin1String(".")); -#else - Q_UNUSED(printerName); -#endif -} - -QString tst_QPrinterInfo::getDefaultPrinterFromSystem() -{ - QStringList command; - command << "lpstat" << "-d"; - QString output = getOutputFromCommand(command); - - QRegExp noDefaultReg("[^:]*no .*default"); - int pos = noDefaultReg.indexIn(output); - if (pos >= 0) { - return QString(); - } - - QRegExp defaultReg("default.*: *([a-zA-Z0-9_-]+)"); - defaultReg.indexIn(output); - QString printer = defaultReg.cap(1); - macFixNameFormat(&printer); - return printer; -} - -QStringList tst_QPrinterInfo::getPrintersFromSystem() -{ - QStringList ans; - - QStringList command; - command << "lpstat" << "-p"; - QString output = getOutputFromCommand(command); - QStringList list = output.split(QChar::fromLatin1('\n')); - - QRegExp reg("^[Pp]rinter ([.a-zA-Z0-9-_@]+)"); - for (int c = 0; c < list.size(); ++c) { - if (reg.indexIn(list[c]) >= 0) { - QString printer = reg.cap(1); - macFixNameFormat(&printer); - ans << printer; - } - } - - return ans; -} - -// This function does roughly the same as the `command substitution` in -// the shell. -QString tst_QPrinterInfo::getOutputFromCommand(const QStringList& command) -{ -// The command execution does nothing on non-unix systems. -#ifdef Q_OS_UNIX - int pid; - int status = 0; - int pipePtr[2]; - - // Create a pipe that is shared between parent and child process. - if (pipe(pipePtr) < 0) { - return QString(); - } - pid = fork(); - if (pid < 0) { - close(pipePtr[0]); - close(pipePtr[1]); - return QString(); - } else if (pid == 0) { - // In child. - // Close the reading end. - close(pipePtr[0]); - // Redirect stdout to the pipe. - if (dup2(pipePtr[1], 1) < 0) { - exit(1); - } - - char** argv = new char*[command.size()+1]; - for (int c = 0; c < command.size(); ++c) { - argv[c] = new char[command[c].size()+1]; - strcpy(argv[c], command[c].toLatin1().data()); - } - argv[command.size()] = NULL; - execvp(argv[0], argv); - // Shouldn't get here, but it's possible if command is not found. - close(pipePtr[1]); - close(1); - for (int c = 0; c < command.size(); ++c) { - delete [] argv[c]; - } - delete [] argv; - exit(1); - } else { - // In parent. - // Close the writing end. - close(pipePtr[1]); - - QFile pipeRead; - if (!pipeRead.open(pipePtr[0], QIODevice::ReadOnly)) { - close(pipePtr[0]); - return QString(); - } - QByteArray array; - array = pipeRead.readAll(); - pipeRead.close(); - close(pipePtr[0]); - wait(&status); - return QString(array); - } -#else - return QString(); -#endif -} - -void tst_QPrinterInfo::testForDefaultPrinter() -{ -#if defined(Q_OS_UNIX) || defined(Q_OS_WIN32) -# ifdef Q_OS_WIN32 - if (QHostInfo::localHostName() == "fantomet" || QHostInfo::localHostName() == "bobo") { - QWARN("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows and may fail"); - } else { - QSKIP("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows"); - } - QString defSysPrinter; - if (QHostInfo::localHostName() == "fantomet") { - defSysPrinter = "Yacc (Lexmark Optra T610 PS3)"; - } else if (QHostInfo::localHostName() == "bobo") { - defSysPrinter = "press"; - } -# else - QString defSysPrinter = getDefaultPrinterFromSystem(); -# endif - if (defSysPrinter == "") - QSKIP("No default printer available"); - - QList list = QPrinterInfo::availablePrinters(); - bool found = false; - for (int c = 0; c < list.size(); ++c) { - if (list[c].isDefault()) { - QVERIFY(list.at(c).printerName() == defSysPrinter); - QVERIFY(!list.at(c).isNull()); - found = true; - } else { - QVERIFY(list.at(c).printerName() != defSysPrinter); - QVERIFY(!list.at(c).isNull()); - } - } - - if (!found && defSysPrinter != "") QFAIL("No default printer reported by Qt, although there is one"); -#else - QSKIP("Test doesn't work on non-Unix"); -#endif -} - -void tst_QPrinterInfo::testForPrinters() -{ -#if defined(Q_OS_UNIX) || defined(Q_OS_WIN32) -# ifdef Q_OS_WIN32 - if (QHostInfo::localHostName() == "fantomet" || QHostInfo::localHostName() == "bobo") { - QWARN("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows and may fail"); - } else { - QSKIP("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows"); - } - QStringList sysPrinters; - if (QHostInfo::localHostName() == "fantomet") { - sysPrinters - << "Press" - << "Canon PS-IPU Color Laser Copier v52.3" - << "EPSON EPL-N4000 PS3" - << "Kroksleiven" - << "Lexmark Optra Color 1200 PS" - << "Yacc (Lexmark Optra T610 PCL)" - << "Yacc (Lexmark Optra T610 PS3)" - ; - } else if (QHostInfo::localHostName() == "bobo") { - sysPrinters - << "press" - << "finnmarka" - << "nordmarka" - ; - } -# else - QStringList sysPrinters = getPrintersFromSystem(); -# endif - QList printers = QPrinterInfo::availablePrinters(); - - QCOMPARE(printers.size(), sysPrinters.size()); - - QHash qtPrinters; - - for (int j = 0; j < printers.size(); ++j) { - qtPrinters.insert(printers.at(j).printerName(), !printers.at(j).isNull()); - } - - for (int i = 0; i < sysPrinters.size(); ++i) { - if (!qtPrinters.value(sysPrinters.at(i))) { - qDebug() << "Available printers: " << qtPrinters; - QFAIL(qPrintable(QString("Printer '%1' reported by system, but not reported by Qt").arg(sysPrinters.at(i)))); - } - } -#else - QSKIP("Test doesn't work on non-Unix"); -#endif -} - -void tst_QPrinterInfo::testForPaperSizes() -{ -QSKIP("PaperSize feature doesn't work on Windows, fails on Mac, and is unstable on Linux"); - // This test is based on common printers found at the Oslo - // office. It is likely to be skipped or fail for other locations. - QStringList hardPrinters; - hardPrinters << "Finnmarka" << "Huldra"; - - QList > hardSizes; - hardSizes - << QList() - << QList() - ; - hardSizes[0] // Finnmarka - << QPrinter::Letter - << QPrinter::A4 - << QPrinter::A3 - << QPrinter::A5 - << QPrinter::B4 - << QPrinter::B5 - << QPrinter::Custom // COM10 - << QPrinter::Custom // C5 - << QPrinter::Custom // DL - << QPrinter::Custom // Monarch - << QPrinter::Executive - << QPrinter::Custom // Foolscap - << QPrinter::Custom // ISO B5 - << QPrinter::Ledger - << QPrinter::Legal - << QPrinter::Custom // Japanese Post Card - << QPrinter::Custom // Invoice - ; - hardSizes[1] // Huldra - << QPrinter::Custom // Not listed at http://localhost:631/, name "Custom" - << QPrinter::Letter - << QPrinter::A4 - << QPrinter::A5 - << QPrinter::A6 - << QPrinter::B5 - << QPrinter::Custom // #5 1/2 Envelope - << QPrinter::Custom // 6x9 Envelope - << QPrinter::Custom // #10 Envelope - << QPrinter::Custom // A7 Envelope - << QPrinter::Custom // C5 Envelope - << QPrinter::Custom // DL Envelope - << QPrinter::Custom // Monarch Envelope - << QPrinter::Custom // #6 3/4 Envelope - << QPrinter::Executive - << QPrinter::Custom // US Folio - << QPrinter::Custom // Index Card - << QPrinter::Custom // ISO B5 - << QPrinter::Legal - << QPrinter::Custom // Statement - ; - - QList printers = QPrinterInfo::availablePrinters(); - for (int i = 0; i < printers.size(); ++i) { - for (int j = 0; j < hardPrinters.size(); ++j) { - if (printers[i].printerName() == hardPrinters[j]) { - QList sizes = printers[i].supportedPaperSizes(); - qSort(sizes); - qSort(hardSizes[j]); - QCOMPARE(sizes, hardSizes[j]); - } - } - } -} - -void tst_QPrinterInfo::testConstructors() -{ - QList prns(QPrinterInfo::availablePrinters()); - - for (int c = 0; c < prns.size(); ++c) { - QList list1, list2; - list1 = prns[c].supportedPaperSizes(); - QPrinter pr(prns[c]); - list2 = QPrinterInfo(pr).supportedPaperSizes(); - QCOMPARE(list2, list1); - } -} - -void tst_QPrinterInfo::testAssignment() -{ - QList prns(QPrinterInfo::availablePrinters()); - - for (int c = 0; c < prns.size(); ++c) { - QPrinterInfo pi = QPrinterInfo::defaultPrinter(); - pi = prns[c]; - QCOMPARE(pi.printerName(), prns[c].printerName()); - QCOMPARE(pi.supportedPaperSizes(), prns[c].supportedPaperSizes()); - } -} - -#endif - -QTEST_MAIN(tst_QPrinterInfo) -#include "tst_qprinterinfo.moc" diff --git a/tests/auto/printsupport/kernel/kernel.pro b/tests/auto/printsupport/kernel/kernel.pro new file mode 100644 index 0000000000..6f5802bf3e --- /dev/null +++ b/tests/auto/printsupport/kernel/kernel.pro @@ -0,0 +1,4 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qprinter \ + qprinterinfo \ diff --git a/tests/auto/printsupport/kernel/qprinter/.gitignore b/tests/auto/printsupport/kernel/qprinter/.gitignore new file mode 100644 index 0000000000..85de0e9675 --- /dev/null +++ b/tests/auto/printsupport/kernel/qprinter/.gitignore @@ -0,0 +1,4 @@ +tqpluginloader/st_qprinter +silly +test.pdf + diff --git a/tests/auto/printsupport/kernel/qprinter/qprinter.pro b/tests/auto/printsupport/kernel/qprinter/qprinter.pro new file mode 100644 index 0000000000..7543e91f8c --- /dev/null +++ b/tests/auto/printsupport/kernel/qprinter/qprinter.pro @@ -0,0 +1,7 @@ +CONFIG += testcase +TARGET = tst_qprinter +QT += printsupport widgets testlib +SOURCES += tst_qprinter.cpp + +mac*:CONFIG+=insignificant_test +win32:CONFIG += insignificant_test # QTBUG-24191 diff --git a/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp b/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp new file mode 100644 index 0000000000..3460ad702b --- /dev/null +++ b/tests/auto/printsupport/kernel/qprinter/tst_qprinter.cpp @@ -0,0 +1,1023 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef Q_OS_WIN +#include +#endif + +Q_DECLARE_METATYPE(QRect) + +QT_FORWARD_DECLARE_CLASS(QPrinter) + +// Helper class to make sure temp files are cleaned up after test complete +class TempFileCleanup +{ +public: + TempFileCleanup(const QString &file) + : m_file(file) + { + } + + ~TempFileCleanup() + { + QFile::remove(m_file); + } +private: + QString m_file; +}; + +class tst_QPrinter : public QObject +{ + Q_OBJECT + +#ifdef QT_NO_PRINTER +public slots: + void initTestCase(); +#else +private slots: + void getSetCheck(); +// Add your testfunctions and testdata create functions here + void testPageSize(); + void testPageRectAndPaperRect(); + void testPageRectAndPaperRect_data(); + void testSetOptions(); + void testMargins_data(); + void testMargins(); + void testNonExistentPrinter(); + void testPageSetupDialog(); + void testMulitpleSets_data(); + void testMulitpleSets(); + void testPageMargins_data(); + void testPageMargins(); + void changingOutputFormat(); + void outputFormatFromSuffix(); + void setGetPaperSize(); + void valuePreservation(); + void errorReporting(); + void testCustomPageSizes(); +#if !defined(QT_NO_COMPLETER) && !defined(QT_NO_FILEDIALOG) + void printDialogCompleter(); +#endif + + void testCopyCount(); + void testCurrentPage(); + + void taskQTBUG4497_reusePrinterOnDifferentFiles(); + void testPdfTitle(); +#endif +}; + +#ifdef QT_NO_PRINTER +void tst_QPrinter::initTestCase() +{ + QSKIP("This test requires printing support"); +} + +#else + +// Testing get/set functions +void tst_QPrinter::getSetCheck() +{ + QPrinter obj1; + // OutputFormat QPrinter::outputFormat() + // void QPrinter::setOutputFormat(OutputFormat) + obj1.setOutputFormat(QPrinter::OutputFormat(QPrinter::PdfFormat)); + QCOMPARE(QPrinter::OutputFormat(QPrinter::PdfFormat), obj1.outputFormat()); + + // bool QPrinter::collateCopies() + // void QPrinter::setCollateCopies(bool) + obj1.setCollateCopies(false); + QCOMPARE(false, obj1.collateCopies()); + obj1.setCollateCopies(true); + QCOMPARE(true, obj1.collateCopies()); + + obj1.setColorMode(QPrinter::GrayScale); + QCOMPARE(obj1.colorMode(), QPrinter::GrayScale); + obj1.setColorMode(QPrinter::Color); + QCOMPARE(obj1.colorMode(), QPrinter::Color); + + obj1.setCreator(QString::fromLatin1("RandomQtUser")); + QCOMPARE(obj1.creator(), QString::fromLatin1("RandomQtUser")); + + obj1.setDocName(QString::fromLatin1("RandomQtDocument")); + QCOMPARE(obj1.docName(), QString::fromLatin1("RandomQtDocument")); + + obj1.setDoubleSidedPrinting(true); + QCOMPARE(obj1.doubleSidedPrinting(), true); + obj1.setDoubleSidedPrinting(false); + QCOMPARE(obj1.doubleSidedPrinting(), false); + + obj1.setFromTo(1, 4); + QCOMPARE(obj1.fromPage(), 1); + QCOMPARE(obj1.toPage(), 4); + + obj1.setFullPage(true); + QCOMPARE(obj1.fullPage(), true); + obj1.setFullPage(false); + QCOMPARE(obj1.fullPage(), false); + + obj1.setOrientation(QPrinter::Landscape); + QCOMPARE(obj1.orientation(), QPrinter::Landscape); + obj1.setOrientation(QPrinter::Portrait); + QCOMPARE(obj1.orientation(), QPrinter::Portrait); + + obj1.setOutputFileName(QString::fromLatin1("RandomQtName")); + QCOMPARE(obj1.outputFileName(), QString::fromLatin1("RandomQtName")); + + obj1.setPageOrder(QPrinter::FirstPageFirst); + QCOMPARE(obj1.pageOrder(), QPrinter::FirstPageFirst); + obj1.setPageOrder(QPrinter::LastPageFirst); + QCOMPARE(obj1.pageOrder(), QPrinter::LastPageFirst); + + obj1.setPaperSource(QPrinter::Cassette); + QCOMPARE(obj1.paperSource(), QPrinter::Cassette); + obj1.setPaperSource(QPrinter::Middle); + QCOMPARE(obj1.paperSource(), QPrinter::Middle); + +#ifdef Q_OS_UNIX + obj1.setPrintProgram(QString::fromLatin1("/bin/true")); + QCOMPARE(obj1.printProgram(), QString::fromLatin1("/bin/true")); + + obj1.setPrinterSelectionOption(QString::fromLatin1("--option")); + QCOMPARE(obj1.printerSelectionOption(), QString::fromLatin1("--option")); +#endif + + obj1.setPrinterName(QString::fromLatin1("myPrinter")); + QCOMPARE(obj1.printerName(), QString::fromLatin1("myPrinter")); + + // bool QPrinter::fontEmbeddingEnabled() + // void QPrinter::setFontEmbeddingEnabled(bool) + obj1.setFontEmbeddingEnabled(false); + QCOMPARE(false, obj1.fontEmbeddingEnabled()); + obj1.setFontEmbeddingEnabled(true); + QCOMPARE(true, obj1.fontEmbeddingEnabled()); + + // PageSize QPrinter::pageSize() + // void QPrinter::setPageSize(PageSize) + obj1.setPageSize(QPrinter::PageSize(QPrinter::A4)); + QCOMPARE(QPrinter::PageSize(QPrinter::A4), obj1.pageSize()); + obj1.setPageSize(QPrinter::PageSize(QPrinter::Letter)); + QCOMPARE(QPrinter::PageSize(QPrinter::Letter), obj1.pageSize()); + obj1.setPageSize(QPrinter::PageSize(QPrinter::Legal)); + QCOMPARE(QPrinter::PageSize(QPrinter::Legal), obj1.pageSize()); + + // PrintRange QPrinter::printRange() + // void QPrinter::setPrintRange(PrintRange) + obj1.setPrintRange(QPrinter::PrintRange(QPrinter::AllPages)); + QCOMPARE(QPrinter::PrintRange(QPrinter::AllPages), obj1.printRange()); + obj1.setPrintRange(QPrinter::PrintRange(QPrinter::Selection)); + QCOMPARE(QPrinter::PrintRange(QPrinter::Selection), obj1.printRange()); + obj1.setPrintRange(QPrinter::PrintRange(QPrinter::PageRange)); + QCOMPARE(QPrinter::PrintRange(QPrinter::PageRange), obj1.printRange()); +} + +#define MYCOMPARE(a, b) QCOMPARE(QVariant((int)a), QVariant((int)b)) + +void tst_QPrinter::testPageSetupDialog() +{ + // Make sure this doesn't crash at least + { + QPrinter printer; + QPageSetupDialog dialog(&printer); + } +} + +void tst_QPrinter::testPageSize() +{ +#if 1 + QSKIP("QPrinter::winPageSize(): Windows only and currently not implemented / QTBUG-22927"); +#else + QPrinter prn; + + prn.setPageSize(QPrinter::Letter); + MYCOMPARE(prn.pageSize(), QPrinter::Letter); + MYCOMPARE(prn.winPageSize(), DMPAPER_LETTER); + + prn.setPageSize(QPrinter::A4); + MYCOMPARE(prn.pageSize(), QPrinter::A4); + MYCOMPARE(prn.winPageSize(), DMPAPER_A4); + + prn.setWinPageSize(DMPAPER_LETTER); + MYCOMPARE(prn.winPageSize(), DMPAPER_LETTER); + MYCOMPARE(prn.pageSize(), QPrinter::Letter); + + prn.setWinPageSize(DMPAPER_A4); + MYCOMPARE(prn.winPageSize(), DMPAPER_A4); + MYCOMPARE(prn.pageSize(), QPrinter::A4); +#endif +} + +void tst_QPrinter::testPageRectAndPaperRect_data() +{ + QTest::addColumn("orientation"); + QTest::addColumn("withPainter"); + QTest::addColumn("resolution"); + QTest::addColumn("doPaperRect"); + + // paperrect + QTest::newRow("paperRect0") << int(QPrinter::Portrait) << true << 300 << true; + QTest::newRow("paperRect1") << int(QPrinter::Portrait) << false << 300 << true; + QTest::newRow("paperRect2") << int(QPrinter::Landscape) << true << 300 << true; + QTest::newRow("paperRect3") << int(QPrinter::Landscape) << false << 300 << true; + QTest::newRow("paperRect4") << int(QPrinter::Portrait) << true << 600 << true; + QTest::newRow("paperRect5") << int(QPrinter::Portrait) << false << 600 << true; + QTest::newRow("paperRect6") << int(QPrinter::Landscape) << true << 600 << true; + QTest::newRow("paperRect7") << int(QPrinter::Landscape) << false << 600 << true; + QTest::newRow("paperRect8") << int(QPrinter::Portrait) << true << 1200 << true; + QTest::newRow("paperRect9") << int(QPrinter::Portrait) << false << 1200 << true; + QTest::newRow("paperRect10") << int(QPrinter::Landscape) << true << 1200 << true; + QTest::newRow("paperRect11") << int(QPrinter::Landscape) << false << 1200 << true; + + // page rect + QTest::newRow("pageRect0") << int(QPrinter::Portrait) << true << 300 << false; + QTest::newRow("pageRect1") << int(QPrinter::Portrait) << false << 300 << false; + QTest::newRow("pageRect2") << int(QPrinter::Landscape) << true << 300 << false; + QTest::newRow("pageRect3") << int(QPrinter::Landscape) << false << 300 << false; + QTest::newRow("pageRect4") << int(QPrinter::Portrait) << true << 600 << false; + QTest::newRow("pageRect5") << int(QPrinter::Portrait) << false << 600 << false; + QTest::newRow("pageRect6") << int(QPrinter::Landscape) << true << 600 << false; + QTest::newRow("pageRect7") << int(QPrinter::Landscape) << false << 600 << false; + QTest::newRow("pageRect8") << int(QPrinter::Portrait) << true << 1200 << false; + QTest::newRow("pageRect9") << int(QPrinter::Portrait) << false << 1200 << false; + QTest::newRow("pageRect10") << int(QPrinter::Landscape) << true << 1200 << false; + QTest::newRow("pageRect11") << int(QPrinter::Landscape) << false << 1200 << false; +} + +void tst_QPrinter::testPageRectAndPaperRect() +{ + QFETCH(bool, withPainter); + QFETCH(int, orientation); + QFETCH(int, resolution); + QFETCH(bool, doPaperRect); + + QPainter *painter = 0; + QPrinter printer(QPrinter::HighResolution); + printer.setOrientation(QPrinter::Orientation(orientation)); + printer.setOutputFileName("silly"); + TempFileCleanup tmpFile("silly"); + + QRect pageRect = doPaperRect ? printer.paperRect() : printer.pageRect(); + float inchesX = float(pageRect.width()) / float(printer.resolution()); + float inchesY = float(pageRect.height()) / float(printer.resolution()); + printer.setResolution(resolution); + if (withPainter) + painter = new QPainter(&printer); + + QRect otherRect = doPaperRect ? printer.paperRect() : printer.pageRect(); + float otherInchesX = float(otherRect.width()) / float(printer.resolution()); + float otherInchesY = float(otherRect.height()) / float(printer.resolution()); + if (painter != 0) + delete painter; + + QVERIFY(qAbs(otherInchesX - inchesX) < 0.01); + QVERIFY(qAbs(otherInchesY - inchesY) < 0.01); + + QVERIFY(printer.orientation() == QPrinter::Portrait || pageRect.width() > pageRect.height()); + QVERIFY(printer.orientation() != QPrinter::Portrait || pageRect.width() < pageRect.height()); +} + +void tst_QPrinter::testSetOptions() +{ + QPrinter prn; + QPrintDialog dlg(&prn); + + // Verify default values + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), true); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), false); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), true); + + dlg.setEnabledOptions(QAbstractPrintDialog::PrintPageRange); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), false); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), false); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), true); + + dlg.setEnabledOptions((QAbstractPrintDialog::PrintDialogOptions(QAbstractPrintDialog::PrintSelection + | QAbstractPrintDialog::PrintPageRange))); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), false); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), true); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), true); + + dlg.setEnabledOptions(QAbstractPrintDialog::PrintSelection); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintToFile), false); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintSelection), true); + MYCOMPARE(dlg.isOptionEnabled(QAbstractPrintDialog::PrintPageRange), false); +} + +void tst_QPrinter::testMargins_data() +{ + QTest::addColumn("orientation"); + QTest::addColumn("fullpage"); + QTest::addColumn("pagesize"); + QTest::addColumn("width"); + QTest::addColumn("height"); + QTest::addColumn("withPainter"); + + QTest::newRow("data0") << int(QPrinter::Portrait) << true << int(QPrinter::A4) << 210 << 297 << false; + QTest::newRow("data1") << int(QPrinter::Landscape) << true << int(QPrinter::A4) << 297 << 210 << false; + QTest::newRow("data2") << int(QPrinter::Landscape) << false << int(QPrinter::A4) << 297 << 210 << false; + QTest::newRow("data3") << int(QPrinter::Portrait) << false << int(QPrinter::A4) << 210 << 297 << false; + QTest::newRow("data4") << int(QPrinter::Portrait) << true << int(QPrinter::A4) << 210 << 297 << true; + QTest::newRow("data5") << int(QPrinter::Landscape) << true << int(QPrinter::A4) << 297 << 210 << true; + QTest::newRow("data6") << int(QPrinter::Landscape) << false << int(QPrinter::A4) << 297 << 210 << true; + QTest::newRow("data7") << int(QPrinter::Portrait) << false << int(QPrinter::A4) << 210 << 297 << true; +} + +void tst_QPrinter::testMargins() +{ + QFETCH(bool, withPainter); + QFETCH(int, orientation); + QFETCH(int, pagesize); + QFETCH(int, width); + QFETCH(int, height); + QFETCH(bool, fullpage); + Q_UNUSED(width); + Q_UNUSED(height); + QPrinter printer; + QPainter *painter = 0; + printer.setOutputFileName("silly"); + printer.setOrientation((QPrinter::Orientation)orientation); + printer.setFullPage(fullpage); + printer.setPageSize((QPrinter::PageSize)pagesize); + if (withPainter) + painter = new QPainter(&printer); + + if (painter) + delete painter; + QFile::remove("silly"); +} + +void tst_QPrinter::testNonExistentPrinter() +{ +#ifndef Q_OS_WIN + QSKIP("QPrinter::testNonExistentPrinter() is not relevant for this platform"); +#else + QPrinter printer; + QPainter painter; + + // Make sure it doesn't crash on setting or getting properties + printer.setPrinterName("some non existing printer"); + printer.setPageSize(QPrinter::A4); + printer.setOrientation(QPrinter::Portrait); + printer.setFullPage(true); + printer.pageSize(); + printer.orientation(); + printer.fullPage(); + printer.setCopyCount(1); + printer.printerName(); + + // nor metrics + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmWidth), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmHeight), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmWidthMM), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmHeightMM), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmNumColors), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmDepth), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmDpiX), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmDpiY), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmPhysicalDpiX), 0); + QCOMPARE(printer.printEngine()->metric(QPaintDevice::PdmPhysicalDpiY), 0); + + QVERIFY(!painter.begin(&printer)); +#endif +} + +void tst_QPrinter::testMulitpleSets_data() +{ + QTest::addColumn("resolution"); + QTest::addColumn("pageSize"); + QTest::addColumn("widthMMAfter"); + QTest::addColumn("heightMMAfter"); + + + QTest::newRow("lowRes") << int(QPrinter::ScreenResolution) << int(QPrinter::A4) << 210 << 297; + QTest::newRow("lowResLetter") << int(QPrinter::ScreenResolution) << int(QPrinter::Letter) << 216 << 279; + QTest::newRow("lowResA5") << int(QPrinter::ScreenResolution) << int(QPrinter::A5) << 148 << 210; + QTest::newRow("midRes") << int(QPrinter::PrinterResolution) << int(QPrinter::A4) << 210 << 297; + QTest::newRow("midResLetter") << int(QPrinter::PrinterResolution) << int(QPrinter::Letter) << 216 << 279; + QTest::newRow("midResA5") << int(QPrinter::PrinterResolution) << int(QPrinter::A5) << 148 << 210; + QTest::newRow("highRes") << int(QPrinter::HighResolution) << int(QPrinter::A4) << 210 << 297; + QTest::newRow("highResLetter") << int(QPrinter::HighResolution) << int(QPrinter::Letter) << 216 << 279; + QTest::newRow("highResA5") << int(QPrinter::HighResolution) << int(QPrinter::A5) << 148 << 210; +} + +static void computePageValue(const QPrinter &printer, int &retWidth, int &retHeight) +{ + const double Inch2MM = 25.4; + + double width = double(printer.paperRect().width()) / printer.logicalDpiX() * Inch2MM; + double height = double(printer.paperRect().height()) / printer.logicalDpiY() * Inch2MM; + retWidth = qRound(width); + retHeight = qRound(height); +} + +void tst_QPrinter::testMulitpleSets() +{ + // A very simple test, but Mac needs to have its format "validated" if the format is changed + // This takes care of that. + QFETCH(int, resolution); + QFETCH(int, pageSize); + QFETCH(int, widthMMAfter); + QFETCH(int, heightMMAfter); + + + QPrinter::PrinterMode mode = QPrinter::PrinterMode(resolution); + QPrinter::PageSize printerPageSize = QPrinter::PageSize(pageSize); + QPrinter printer(mode); + printer.setFullPage(true); + + int paperWidth, paperHeight; + //const int Tolerance = 2; + + computePageValue(printer, paperWidth, paperHeight); + printer.setPageSize(printerPageSize); + + if (printer.pageSize() != printerPageSize) { + QSKIP("Current page size is not supported on this printer"); + return; + } + + QCOMPARE(printer.widthMM(), widthMMAfter); + QCOMPARE(printer.heightMM(), heightMMAfter); + + computePageValue(printer, paperWidth, paperHeight); + + QVERIFY(qAbs(paperWidth - widthMMAfter) <= 2); + QVERIFY(qAbs(paperHeight - heightMMAfter) <= 2); + + // Set it again and see if it still works. + printer.setPageSize(printerPageSize); + QCOMPARE(printer.widthMM(), widthMMAfter); + QCOMPARE(printer.heightMM(), heightMMAfter); + + printer.setOrientation(QPrinter::Landscape); + computePageValue(printer, paperWidth, paperHeight); + QVERIFY(qAbs(paperWidth - heightMMAfter) <= 2); + QVERIFY(qAbs(paperHeight - widthMMAfter) <= 2); +} + +void tst_QPrinter::changingOutputFormat() +{ +#if QT_VERSION < 0x050000 + QPrinter p; + p.setOutputFormat(QPrinter::PostScriptFormat); + p.setPageSize(QPrinter::A8); + p.setOutputFormat(QPrinter::PdfFormat); + QCOMPARE(p.pageSize(), QPrinter::A8); +#endif +} + +void tst_QPrinter::outputFormatFromSuffix() +{ + if (QPrinterInfo::availablePrinters().size() == 0) + QSKIP("No printers available."); + QPrinter p; + QVERIFY(p.outputFormat() == QPrinter::NativeFormat); + p.setOutputFileName("test.pdf"); + TempFileCleanup tmpFile("test.pdf"); + QVERIFY(p.outputFormat() == QPrinter::PdfFormat); + p.setOutputFileName(QString()); + QVERIFY(p.outputFormat() == QPrinter::NativeFormat); +} + +void tst_QPrinter::setGetPaperSize() +{ + QPrinter p; + p.setOutputFormat(QPrinter::PdfFormat); + QSizeF size(500, 10); + p.setPaperSize(size, QPrinter::Millimeter); + QCOMPARE(p.paperSize(QPrinter::Millimeter), size); + QSizeF ptSize = p.paperSize(QPrinter::Point); + //qDebug() << ptSize; + QVERIFY(qAbs(ptSize.width() - size.width() * (72/25.4)) < 1E-4); + QVERIFY(qAbs(ptSize.height() - size.height() * (72/25.4)) < 1E-4); +} + +void tst_QPrinter::testPageMargins_data() +{ + QTest::addColumn("left"); + QTest::addColumn("top"); + QTest::addColumn("right"); + QTest::addColumn("bottom"); + QTest::addColumn("unit"); + + QTest::newRow("data0") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Millimeter); + QTest::newRow("data1") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Point); + QTest::newRow("data2") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Inch); + QTest::newRow("data3") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Pica); + QTest::newRow("data4") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Didot); + QTest::newRow("data5") << qreal(5.5) << qreal(6.5) << qreal(7.5) << qreal(8.5) << static_cast(QPrinter::Cicero); +} + +void tst_QPrinter::testPageMargins() +{ + QPrinter obj1; + + qreal toMillimeters[6]; + toMillimeters[QPrinter::Millimeter] = 1; + toMillimeters[QPrinter::Point] = 0.352777778; + toMillimeters[QPrinter::Inch] = 25.4; + toMillimeters[QPrinter::Pica] = 4.23333333; + toMillimeters[QPrinter::Didot] = 0.376; + toMillimeters[QPrinter::Cicero] = 4.51166667; + + QFETCH(qreal, left); + QFETCH(qreal, top); + QFETCH(qreal, right); + QFETCH(qreal, bottom); + QFETCH(int, unit); + + qreal nLeft, nTop, nRight, nBottom; + + obj1.setPageMargins(left, top, right, bottom, static_cast(unit)); + + qreal tolerance = 0.05; + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Millimeter); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Millimeter]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Millimeter]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Millimeter]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Millimeter]) < tolerance); + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Point); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Point]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Point]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Point]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Point]) < tolerance); + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Inch); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Inch]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Inch]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Inch]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Inch]) < tolerance); + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Pica); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Pica]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Pica]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Pica]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Pica]) < tolerance); + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Didot); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Didot]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Didot]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Didot]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Didot]) < tolerance); + + obj1.getPageMargins(&nLeft, &nTop, &nRight, &nBottom, QPrinter::Cicero); + QVERIFY(fabs(left*toMillimeters[unit] - nLeft*toMillimeters[QPrinter::Cicero]) < tolerance); + QVERIFY(fabs(top*toMillimeters[unit] - nTop*toMillimeters[QPrinter::Cicero]) < tolerance); + QVERIFY(fabs(right*toMillimeters[unit] - nRight*toMillimeters[QPrinter::Cicero]) < tolerance); + QVERIFY(fabs(bottom*toMillimeters[unit] - nBottom*toMillimeters[QPrinter::Cicero]) < tolerance); +} + +void tst_QPrinter::valuePreservation() +{ + QPrinter::OutputFormat oldFormat = QPrinter::PdfFormat; + QPrinter::OutputFormat newFormat = QPrinter::NativeFormat; // TODO: Correct? + + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + bool status = printer.collateCopies(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.collateCopies(), status); + + printer.setCollateCopies(!status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.collateCopies(), !status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.collateCopies(), !status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::ColorMode status = printer.colorMode(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.colorMode(), status); + + printer.setColorMode(QPrinter::ColorMode(!status)); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.colorMode(), QPrinter::ColorMode(!status)); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.colorMode(), QPrinter::ColorMode(!status)); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.creator(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.creator(), status); + + status = QString::fromLatin1("Mr. Test"); + printer.setCreator(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.creator(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.creator(), status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.docName(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.docName(), status); + + status = QString::fromLatin1("Test document"); + printer.setDocName(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.docName(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.docName(), status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + bool status = printer.doubleSidedPrinting(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.doubleSidedPrinting(), status); + + printer.setDoubleSidedPrinting(!status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.doubleSidedPrinting(), !status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.doubleSidedPrinting(), !status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + bool status = printer.fontEmbeddingEnabled(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.fontEmbeddingEnabled(), status); + + printer.setFontEmbeddingEnabled(!status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.fontEmbeddingEnabled(), !status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.fontEmbeddingEnabled(), !status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + bool status = printer.fullPage(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.fullPage(), status); + + printer.setFullPage(!status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.fullPage(), !status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.fullPage(), !status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::Orientation status = printer.orientation(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.orientation(), status); + + printer.setOrientation(QPrinter::Orientation(!status)); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.orientation(), QPrinter::Orientation(!status)); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.orientation(), QPrinter::Orientation(!status)); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.outputFileName(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.outputFileName(), status); + + status = QString::fromLatin1("Test file"); + printer.setOutputFileName(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.outputFileName(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.outputFileName(), status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::PageOrder status = printer.pageOrder(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.pageOrder(), status); + + printer.setPageOrder(QPrinter::PageOrder(!status)); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.pageOrder(), QPrinter::PageOrder(!status)); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.pageOrder(), QPrinter::PageOrder(!status)); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::PageSize status = printer.pageSize(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.pageSize(), status); + + printer.setPageSize(QPrinter::B5); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.pageSize(), QPrinter::B5); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.pageSize(), QPrinter::B5); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::PaperSource status = printer.paperSource(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.paperSource(), status); + + printer.setPaperSource(QPrinter::Manual); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.paperSource(), QPrinter::Manual); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.paperSource(), QPrinter::Manual); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.printProgram(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printProgram(), status); + + status = QString::fromLatin1("/usr/local/bin/lpr"); + printer.setPrintProgram(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.printProgram(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printProgram(), status); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QPrinter::PrintRange status = printer.printRange(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printRange(), status); + + printer.setPrintRange(QPrinter::PrintRange(!status)); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.printRange(), QPrinter::PrintRange(!status)); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printRange(), QPrinter::PrintRange(!status)); + } + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.printerName(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printerName(), status); + + status = QString::fromLatin1("SuperDuperPrinter"); + printer.setPrinterName(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.printerName(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printerName(), status); + } +#ifndef Q_OS_WIN + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + QString status = printer.printerSelectionOption(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printerSelectionOption(), status); + + status = QString::fromLatin1("Optional option"); + printer.setPrinterSelectionOption(status); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.printerSelectionOption(), status); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.printerSelectionOption(), status); + } +#endif + { + QPrinter printer; + printer.setOutputFormat(oldFormat); + int status = printer.resolution(); + printer.setOutputFormat(newFormat); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.resolution(), status); + + printer.setResolution(status-150); + printer.setOutputFormat(newFormat); + QCOMPARE(printer.resolution(), status-150); + printer.setOutputFormat(oldFormat); + QCOMPARE(printer.resolution(), status-150); + } +} + +void tst_QPrinter::errorReporting() +{ + QPrinter p; + p.setOutputFormat(QPrinter::PdfFormat); + QCOMPARE(p.isValid(), true); + QPainter painter; +#ifndef Q_WS_WIN + // not sure how to choose a never-writable file on windows. But its QFile behavior anyway, so lets rely on it failing elsewhere + p.setOutputFileName("/foobar/nonwritable.pdf"); + QCOMPARE(painter.begin(&p), false); // it should check the output file is writable +#endif + p.setOutputFileName("test.pdf"); + TempFileCleanup tmpFile("test.pdf"); + QCOMPARE(painter.begin(&p), true); // it should check the output + QCOMPARE(p.isValid(), true); + painter.end(); +} + +void tst_QPrinter::testCustomPageSizes() +{ + QPrinter p; + + QSizeF customSize(8.5, 11.0); + p.setPaperSize(customSize, QPrinter::Inch); + + QSizeF paperSize = p.paperSize(QPrinter::Inch); + QCOMPARE(paperSize, customSize); + + QPrinter p2(QPrinter::HighResolution); + p2.setPaperSize(customSize, QPrinter::Inch); + paperSize = p.paperSize(QPrinter::Inch); + QCOMPARE(paperSize, customSize); +} + +#if !defined(QT_NO_COMPLETER) && !defined(QT_NO_FILEDIALOG) +void tst_QPrinter::printDialogCompleter() +{ + QPrintDialog dialog; + dialog.printer()->setOutputFileName("file.pdf"); + TempFileCleanup tmpFile("file.pdf"); + dialog.setEnabledOptions(QAbstractPrintDialog::PrintToFile); + dialog.show(); + + QTest::qWait(100); + + QTest::keyClick(&dialog, Qt::Key_Tab); + QTest::keyClick(&dialog, 'P'); + // The test passes if it doesn't crash. +} +#endif + +void tst_QPrinter::testCopyCount() +{ + QPrinter p; + p.setCopyCount(15); + QCOMPARE(p.copyCount(), 15); +} + +static void printPage(QPainter *painter) +{ + painter->setPen(QPen(Qt::black, 4)); + painter->drawRect(50, 60, 70, 80); +} + +void tst_QPrinter::taskQTBUG4497_reusePrinterOnDifferentFiles() +{ + TempFileCleanup tmpFile1("out1.ps"); + TempFileCleanup tmpFile2("out2.ps"); + + QPrinter printer; + { + + printer.setOutputFileName("out1.ps"); + QPainter painter(&printer); + printPage(&painter); + + } + { + + printer.setOutputFileName("out2.ps"); + QPainter painter(&printer); + printPage(&painter); + + } + QFile file1("out1.ps"); + QVERIFY(file1.open(QIODevice::ReadOnly)); + + QFile file2("out2.ps"); + QVERIFY(file2.open(QIODevice::ReadOnly)); + + QEXPECT_FAIL("", "QTBUG-22562, QTBUG-22296", Abort); + QCOMPARE(file1.readAll(), file2.readAll()); +} + +void tst_QPrinter::testCurrentPage() +{ + QPrinter printer; + printer.setFromTo(1, 10); + + // Test set print range + printer.setPrintRange(QPrinter::CurrentPage); + QCOMPARE(printer.printRange(), QPrinter::CurrentPage); + QCOMPARE(printer.fromPage(), 1); + QCOMPARE(printer.toPage(), 10); + + QPrintDialog dialog(&printer); + + // Test default Current Page option to off + QCOMPARE(dialog.isOptionEnabled(QPrintDialog::PrintCurrentPage), false); + + // Test enable Current Page option + dialog.setOption(QPrintDialog::PrintCurrentPage); + QCOMPARE(dialog.isOptionEnabled(QPrintDialog::PrintCurrentPage), true); + +} + +void tst_QPrinter::testPdfTitle() +{ + // Check the document name is represented correctly in produced pdf + { + QPainter painter; + QPrinter printer; + // This string is just the UTF-8 encoding of the string: \()f ø hiragana o + const unsigned char titleBuf[]={0x5c, 0x28, 0x29, 0x66, 0xc3, 0xb8, 0xe3, 0x81, 0x8a, 0x00}; + const char *title = reinterpret_cast(titleBuf); + printer.setOutputFileName("file.pdf"); + printer.setDocName(QString::fromUtf8(title)); + painter.begin(&printer); + painter.end(); + } + TempFileCleanup tmpFile("file.pdf"); + QFile file("file.pdf"); + QVERIFY(file.open(QIODevice::ReadOnly)); + // The we expect the title to appear in the PDF as: + // ASCII('\title (') UTF16(\\\(\)f ø hiragana o) ASCII(')'). + // which has the following binary representation + const unsigned char expectedBuf[] = { + 0x2f, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x20, 0x28, 0xfe, + 0xff, 0x00, 0x5c, 0x5c, 0x00, 0x5c, 0x28, 0x00, 0x5c, + 0x29, 0x00, 0x66, 0x00, 0xf8, 0x30, 0x4a, 0x29}; + const char *expected = reinterpret_cast(expectedBuf); + QVERIFY(file.readAll().contains(QByteArray(expected, 26))); +} + +#endif + +QTEST_MAIN(tst_QPrinter) +#include "tst_qprinter.moc" diff --git a/tests/auto/printsupport/kernel/qprinterinfo/.gitignore b/tests/auto/printsupport/kernel/qprinterinfo/.gitignore new file mode 100644 index 0000000000..fcef7c1997 --- /dev/null +++ b/tests/auto/printsupport/kernel/qprinterinfo/.gitignore @@ -0,0 +1 @@ +tst_qprinterinfo diff --git a/tests/auto/printsupport/kernel/qprinterinfo/qprinterinfo.pro b/tests/auto/printsupport/kernel/qprinterinfo/qprinterinfo.pro new file mode 100644 index 0000000000..88cb07f338 --- /dev/null +++ b/tests/auto/printsupport/kernel/qprinterinfo/qprinterinfo.pro @@ -0,0 +1,10 @@ +CONFIG += testcase +TARGET = tst_qprinterinfo +SOURCES += tst_qprinterinfo.cpp + +QT += printsupport network testlib + +DEFINES += QT_USE_USING_NAMESPACE + +mac: CONFIG += insignificant_test # QTBUG-23060 +win32:CONFIG += insignificant_test # QTBUG-24190 diff --git a/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp b/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp new file mode 100644 index 0000000000..2323dc8df3 --- /dev/null +++ b/tests/auto/printsupport/kernel/qprinterinfo/tst_qprinterinfo.cpp @@ -0,0 +1,393 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite 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 +#include +#include +#include +#include + +#ifdef Q_OS_UNIX +# include +# include +# include +#endif + +Q_DECLARE_METATYPE(QRect) + +class tst_QPrinterInfo : public QObject +{ + Q_OBJECT + +#ifdef QT_NO_PRINTER +public slots: + void initTestCase(); +#else +private slots: + void testForDefaultPrinter(); + void testForPrinters(); + void testForPaperSizes(); + void testConstructors(); + void testAssignment(); + +private: + void macFixNameFormat(QString *printerName); + QString getDefaultPrinterFromSystem(); + QStringList getPrintersFromSystem(); + + QString getOutputFromCommand(const QStringList& command); +#endif +}; + +#ifdef QT_NO_PRINTER +void tst_QPrinterInfo::initTestCase() +{ + QSKIP("This test requires printing support"); +} + +#else + +void tst_QPrinterInfo::macFixNameFormat(QString *printerName) +{ +// Modify the format of the printer name to match Qt, lpstat returns +// foo___domain_no, Qt returns foo @ domain.no +#ifdef Q_OS_MAC + printerName->replace(QLatin1String("___"), QLatin1String(" @ ")); + printerName->replace(QLatin1String("_"), QLatin1String(".")); +#else + Q_UNUSED(printerName); +#endif +} + +QString tst_QPrinterInfo::getDefaultPrinterFromSystem() +{ + QStringList command; + command << "lpstat" << "-d"; + QString output = getOutputFromCommand(command); + + QRegExp noDefaultReg("[^:]*no .*default"); + int pos = noDefaultReg.indexIn(output); + if (pos >= 0) { + return QString(); + } + + QRegExp defaultReg("default.*: *([a-zA-Z0-9_-]+)"); + defaultReg.indexIn(output); + QString printer = defaultReg.cap(1); + macFixNameFormat(&printer); + return printer; +} + +QStringList tst_QPrinterInfo::getPrintersFromSystem() +{ + QStringList ans; + + QStringList command; + command << "lpstat" << "-p"; + QString output = getOutputFromCommand(command); + QStringList list = output.split(QChar::fromLatin1('\n')); + + QRegExp reg("^[Pp]rinter ([.a-zA-Z0-9-_@]+)"); + for (int c = 0; c < list.size(); ++c) { + if (reg.indexIn(list[c]) >= 0) { + QString printer = reg.cap(1); + macFixNameFormat(&printer); + ans << printer; + } + } + + return ans; +} + +// This function does roughly the same as the `command substitution` in +// the shell. +QString tst_QPrinterInfo::getOutputFromCommand(const QStringList& command) +{ +// The command execution does nothing on non-unix systems. +#ifdef Q_OS_UNIX + int pid; + int status = 0; + int pipePtr[2]; + + // Create a pipe that is shared between parent and child process. + if (pipe(pipePtr) < 0) { + return QString(); + } + pid = fork(); + if (pid < 0) { + close(pipePtr[0]); + close(pipePtr[1]); + return QString(); + } else if (pid == 0) { + // In child. + // Close the reading end. + close(pipePtr[0]); + // Redirect stdout to the pipe. + if (dup2(pipePtr[1], 1) < 0) { + exit(1); + } + + char** argv = new char*[command.size()+1]; + for (int c = 0; c < command.size(); ++c) { + argv[c] = new char[command[c].size()+1]; + strcpy(argv[c], command[c].toLatin1().data()); + } + argv[command.size()] = NULL; + execvp(argv[0], argv); + // Shouldn't get here, but it's possible if command is not found. + close(pipePtr[1]); + close(1); + for (int c = 0; c < command.size(); ++c) { + delete [] argv[c]; + } + delete [] argv; + exit(1); + } else { + // In parent. + // Close the writing end. + close(pipePtr[1]); + + QFile pipeRead; + if (!pipeRead.open(pipePtr[0], QIODevice::ReadOnly)) { + close(pipePtr[0]); + return QString(); + } + QByteArray array; + array = pipeRead.readAll(); + pipeRead.close(); + close(pipePtr[0]); + wait(&status); + return QString(array); + } +#else + return QString(); +#endif +} + +void tst_QPrinterInfo::testForDefaultPrinter() +{ +#if defined(Q_OS_UNIX) || defined(Q_OS_WIN32) +# ifdef Q_OS_WIN32 + if (QHostInfo::localHostName() == "fantomet" || QHostInfo::localHostName() == "bobo") { + QWARN("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows and may fail"); + } else { + QSKIP("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows"); + } + QString defSysPrinter; + if (QHostInfo::localHostName() == "fantomet") { + defSysPrinter = "Yacc (Lexmark Optra T610 PS3)"; + } else if (QHostInfo::localHostName() == "bobo") { + defSysPrinter = "press"; + } +# else + QString defSysPrinter = getDefaultPrinterFromSystem(); +# endif + if (defSysPrinter == "") + QSKIP("No default printer available"); + + QList list = QPrinterInfo::availablePrinters(); + bool found = false; + for (int c = 0; c < list.size(); ++c) { + if (list[c].isDefault()) { + QVERIFY(list.at(c).printerName() == defSysPrinter); + QVERIFY(!list.at(c).isNull()); + found = true; + } else { + QVERIFY(list.at(c).printerName() != defSysPrinter); + QVERIFY(!list.at(c).isNull()); + } + } + + if (!found && defSysPrinter != "") QFAIL("No default printer reported by Qt, although there is one"); +#else + QSKIP("Test doesn't work on non-Unix"); +#endif +} + +void tst_QPrinterInfo::testForPrinters() +{ +#if defined(Q_OS_UNIX) || defined(Q_OS_WIN32) +# ifdef Q_OS_WIN32 + if (QHostInfo::localHostName() == "fantomet" || QHostInfo::localHostName() == "bobo") { + QWARN("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows and may fail"); + } else { + QSKIP("Test is hardcoded to \"fantomet\" and \"bobo\" on Windows"); + } + QStringList sysPrinters; + if (QHostInfo::localHostName() == "fantomet") { + sysPrinters + << "Press" + << "Canon PS-IPU Color Laser Copier v52.3" + << "EPSON EPL-N4000 PS3" + << "Kroksleiven" + << "Lexmark Optra Color 1200 PS" + << "Yacc (Lexmark Optra T610 PCL)" + << "Yacc (Lexmark Optra T610 PS3)" + ; + } else if (QHostInfo::localHostName() == "bobo") { + sysPrinters + << "press" + << "finnmarka" + << "nordmarka" + ; + } +# else + QStringList sysPrinters = getPrintersFromSystem(); +# endif + QList printers = QPrinterInfo::availablePrinters(); + + QCOMPARE(printers.size(), sysPrinters.size()); + + QHash qtPrinters; + + for (int j = 0; j < printers.size(); ++j) { + qtPrinters.insert(printers.at(j).printerName(), !printers.at(j).isNull()); + } + + for (int i = 0; i < sysPrinters.size(); ++i) { + if (!qtPrinters.value(sysPrinters.at(i))) { + qDebug() << "Available printers: " << qtPrinters; + QFAIL(qPrintable(QString("Printer '%1' reported by system, but not reported by Qt").arg(sysPrinters.at(i)))); + } + } +#else + QSKIP("Test doesn't work on non-Unix"); +#endif +} + +void tst_QPrinterInfo::testForPaperSizes() +{ +QSKIP("PaperSize feature doesn't work on Windows, fails on Mac, and is unstable on Linux"); + // This test is based on common printers found at the Oslo + // office. It is likely to be skipped or fail for other locations. + QStringList hardPrinters; + hardPrinters << "Finnmarka" << "Huldra"; + + QList > hardSizes; + hardSizes + << QList() + << QList() + ; + hardSizes[0] // Finnmarka + << QPrinter::Letter + << QPrinter::A4 + << QPrinter::A3 + << QPrinter::A5 + << QPrinter::B4 + << QPrinter::B5 + << QPrinter::Custom // COM10 + << QPrinter::Custom // C5 + << QPrinter::Custom // DL + << QPrinter::Custom // Monarch + << QPrinter::Executive + << QPrinter::Custom // Foolscap + << QPrinter::Custom // ISO B5 + << QPrinter::Ledger + << QPrinter::Legal + << QPrinter::Custom // Japanese Post Card + << QPrinter::Custom // Invoice + ; + hardSizes[1] // Huldra + << QPrinter::Custom // Not listed at http://localhost:631/, name "Custom" + << QPrinter::Letter + << QPrinter::A4 + << QPrinter::A5 + << QPrinter::A6 + << QPrinter::B5 + << QPrinter::Custom // #5 1/2 Envelope + << QPrinter::Custom // 6x9 Envelope + << QPrinter::Custom // #10 Envelope + << QPrinter::Custom // A7 Envelope + << QPrinter::Custom // C5 Envelope + << QPrinter::Custom // DL Envelope + << QPrinter::Custom // Monarch Envelope + << QPrinter::Custom // #6 3/4 Envelope + << QPrinter::Executive + << QPrinter::Custom // US Folio + << QPrinter::Custom // Index Card + << QPrinter::Custom // ISO B5 + << QPrinter::Legal + << QPrinter::Custom // Statement + ; + + QList printers = QPrinterInfo::availablePrinters(); + for (int i = 0; i < printers.size(); ++i) { + for (int j = 0; j < hardPrinters.size(); ++j) { + if (printers[i].printerName() == hardPrinters[j]) { + QList sizes = printers[i].supportedPaperSizes(); + qSort(sizes); + qSort(hardSizes[j]); + QCOMPARE(sizes, hardSizes[j]); + } + } + } +} + +void tst_QPrinterInfo::testConstructors() +{ + QList prns(QPrinterInfo::availablePrinters()); + + for (int c = 0; c < prns.size(); ++c) { + QList list1, list2; + list1 = prns[c].supportedPaperSizes(); + QPrinter pr(prns[c]); + list2 = QPrinterInfo(pr).supportedPaperSizes(); + QCOMPARE(list2, list1); + } +} + +void tst_QPrinterInfo::testAssignment() +{ + QList prns(QPrinterInfo::availablePrinters()); + + for (int c = 0; c < prns.size(); ++c) { + QPrinterInfo pi = QPrinterInfo::defaultPrinter(); + pi = prns[c]; + QCOMPARE(pi.printerName(), prns[c].printerName()); + QCOMPARE(pi.supportedPaperSizes(), prns[c].supportedPaperSizes()); + } +} + +#endif + +QTEST_MAIN(tst_QPrinterInfo) +#include "tst_qprinterinfo.moc" diff --git a/tests/auto/printsupport/printsupport.pro b/tests/auto/printsupport/printsupport.pro new file mode 100644 index 0000000000..69ba296738 --- /dev/null +++ b/tests/auto/printsupport/printsupport.pro @@ -0,0 +1,3 @@ +TEMPLATE=subdirs +SUBDIRS=\ + kernel \ -- cgit v1.2.3 From 61692bfefec3f15a2be219bdb29893872a7feadf Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 7 Mar 2012 20:48:06 +0100 Subject: Remove QAccessible2::TableModelChange. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was never a good idea since it has issues: It doesn't really work with more than one update without the client fetching the data. The same is unlikely to work reliable since it involves two ipc roundtrips. Instead we should have an extended QAccessibleEvent that contains the data so that the bridges can decide how to pass on the data if needed. Change-Id: Iaf6b74f49586f7155909a6fe1a17137b71b31175 Reviewed-by: Jan-Arve Sæther --- src/gui/accessible/qaccessible2.h | 29 ------------- src/plugins/accessible/widgets/itemviews.cpp | 64 ---------------------------- src/plugins/accessible/widgets/itemviews.h | 11 ----- 3 files changed, 104 deletions(-) diff --git a/src/gui/accessible/qaccessible2.h b/src/gui/accessible/qaccessible2.h index b84c484f74..61e46ebf04 100644 --- a/src/gui/accessible/qaccessible2.h +++ b/src/gui/accessible/qaccessible2.h @@ -70,24 +70,6 @@ namespace QAccessible2 LineBoundary, NoBoundary }; - - enum TableModelChangeType { - TableModelChangeInsert, - TableModelChangeDelete, - TableModelChangeUpdate - }; - - struct TableModelChange { - int firstColumn; - int firstRow; - int lastColumn; - int lastRow; - TableModelChangeType type; - - TableModelChange() - : firstColumn(0), firstRow(0), lastColumn(0), lastRow(0), type(TableModelChangeUpdate) - {} - }; } class Q_GUI_EXPORT QAccessibleTextInterface @@ -230,19 +212,8 @@ public: virtual bool unselectRow(int row) = 0; // Unselects one column, leaving other selected columns selected (if any). virtual bool unselectColumn(int column) = 0; - // Returns the type and extents describing how a table changed. - virtual QAccessible2::TableModelChange modelChange() const = 0; protected: - // These functions are called when the model changes. - virtual void modelReset() = 0; - virtual void rowsInserted(const QModelIndex &parent, int first, int last) = 0; - virtual void rowsRemoved(const QModelIndex &parent, int first, int last) = 0; - virtual void columnsInserted(const QModelIndex &parent, int first, int last) = 0; - virtual void columnsRemoved(const QModelIndex &parent, int first, int last) = 0; - virtual void rowsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row) = 0; - virtual void columnsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column) = 0; - friend class QAbstractItemView; friend class QAbstractItemViewPrivate; }; diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp index a9f3a858d2..a2fe2cb7fd 100644 --- a/src/plugins/accessible/widgets/itemviews.cpp +++ b/src/plugins/accessible/widgets/itemviews.cpp @@ -156,63 +156,6 @@ QHeaderView *QAccessibleTable::verticalHeader() const return header; } -void QAccessibleTable::modelReset() -{} - -void QAccessibleTable::rowsInserted(const QModelIndex &, int first, int last) -{ - lastChange.firstRow = first; - lastChange.lastRow = last; - lastChange.firstColumn = 0; - lastChange.lastColumn = 0; - lastChange.type = QAccessible2::TableModelChangeInsert; -} - -void QAccessibleTable::rowsRemoved(const QModelIndex &, int first, int last) -{ - lastChange.firstRow = first; - lastChange.lastRow = last; - lastChange.firstColumn = 0; - lastChange.lastColumn = 0; - lastChange.type = QAccessible2::TableModelChangeDelete; -} - -void QAccessibleTable::columnsInserted(const QModelIndex &, int first, int last) -{ - lastChange.firstRow = 0; - lastChange.lastRow = 0; - lastChange.firstColumn = first; - lastChange.lastColumn = last; - lastChange.type = QAccessible2::TableModelChangeInsert; -} - -void QAccessibleTable::columnsRemoved(const QModelIndex &, int first, int last) -{ - lastChange.firstRow = 0; - lastChange.lastRow = 0; - lastChange.firstColumn = first; - lastChange.lastColumn = last; - lastChange.type = QAccessible2::TableModelChangeDelete; -} - -void QAccessibleTable::rowsMoved( const QModelIndex &, int, int, const QModelIndex &, int) -{ - lastChange.firstRow = 0; - lastChange.lastRow = 0; - lastChange.firstColumn = 0; - lastChange.lastColumn = 0; - lastChange.type = QAccessible2::TableModelChangeUpdate; -} - -void QAccessibleTable::columnsMoved( const QModelIndex &, int, int, const QModelIndex &, int) -{ - lastChange.firstRow = 0; - lastChange.lastRow = 0; - lastChange.firstColumn = 0; - lastChange.lastColumn = 0; - lastChange.type = QAccessible2::TableModelChangeUpdate; -} - QAccessibleTableCell *QAccessibleTable::cell(const QModelIndex &index) const { if (index.isValid()) @@ -349,13 +292,6 @@ bool QAccessibleTable::unselectColumn(int column) return true; } -QAccessible2::TableModelChange QAccessibleTable::modelChange() const -{ - QAccessible2::TableModelChange change; - // FIXME - return change; -} - QAccessible::Role QAccessibleTable::role() const { return m_role; diff --git a/src/plugins/accessible/widgets/itemviews.h b/src/plugins/accessible/widgets/itemviews.h index 3d852a2377..2672cd4a16 100644 --- a/src/plugins/accessible/widgets/itemviews.h +++ b/src/plugins/accessible/widgets/itemviews.h @@ -88,7 +88,6 @@ public: virtual QString rowDescription(int row) const; virtual int columnCount() const; virtual int rowCount() const; - virtual QAccessible2::TableModelChange modelChange() const; // selection virtual int selectedCellCount() const; @@ -104,18 +103,8 @@ public: virtual bool unselectRow(int row); virtual bool unselectColumn(int column); -protected: - virtual void modelReset(); - virtual void rowsInserted(const QModelIndex &parent, int first, int last); - virtual void rowsRemoved(const QModelIndex &parent, int first, int last); - virtual void columnsInserted(const QModelIndex &parent, int first, int last); - virtual void columnsRemoved(const QModelIndex &parent, int first, int last); - virtual void rowsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row); - virtual void columnsMoved( const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column); - protected: QAbstractItemView* view; - QAccessible2::TableModelChange lastChange; inline QAccessibleTableCell *cell(const QModelIndex &index) const; inline QAccessible::Role cellRole() const { switch (m_role) { -- cgit v1.2.3 From 9a81e371079d6aab20f6c4a43031857f4172688c Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Fri, 9 Mar 2012 17:21:22 +0000 Subject: Rename blackberry QPA plugin to QNX Changing the naming scheme from Blackberry to QNX in line with pattern of using platform names. Change-Id: I048a6a18010bc932311d63c8dde19ccab97894c8 Reviewed-by: Robin Burchell Reviewed-by: Nicolas Arnaud-Cormos --- src/plugins/platforms/blackberry/blackberry.pro | 71 - src/plugins/platforms/blackberry/main.cpp | 72 - src/plugins/platforms/blackberry/qbbbuffer.cpp | 165 -- src/plugins/platforms/blackberry/qbbbuffer.h | 74 - src/plugins/platforms/blackberry/qbbclipboard.cpp | 244 --- src/plugins/platforms/blackberry/qbbclipboard.h | 66 - .../platforms/blackberry/qbbeventthread.cpp | 572 ------- src/plugins/platforms/blackberry/qbbeventthread.h | 90 -- .../platforms/blackberry/qbbglbackingstore.cpp | 189 --- .../platforms/blackberry/qbbglbackingstore.h | 95 -- src/plugins/platforms/blackberry/qbbglcontext.cpp | 356 ---- src/plugins/platforms/blackberry/qbbglcontext.h | 93 -- .../platforms/blackberry/qbbinputcontext_imf.cpp | 1696 -------------------- .../platforms/blackberry/qbbinputcontext_imf.h | 132 -- .../platforms/blackberry/qbbinputcontext_noimf.cpp | 187 --- .../platforms/blackberry/qbbinputcontext_noimf.h | 84 - .../platforms/blackberry/qbbintegration.cpp | 293 ---- src/plugins/platforms/blackberry/qbbintegration.h | 119 -- .../platforms/blackberry/qbbkeytranslator.h | 269 ---- .../platforms/blackberry/qbbnavigatorthread.cpp | 280 ---- .../platforms/blackberry/qbbnavigatorthread.h | 78 - .../platforms/blackberry/qbbrasterbackingstore.cpp | 166 -- .../platforms/blackberry/qbbrasterbackingstore.h | 81 - src/plugins/platforms/blackberry/qbbrootwindow.cpp | 257 --- src/plugins/platforms/blackberry/qbbrootwindow.h | 81 - src/plugins/platforms/blackberry/qbbscreen.cpp | 315 ---- src/plugins/platforms/blackberry/qbbscreen.h | 121 -- .../platforms/blackberry/qbbvirtualkeyboard.cpp | 500 ------ .../platforms/blackberry/qbbvirtualkeyboard.h | 130 -- src/plugins/platforms/blackberry/qbbwindow.cpp | 665 -------- src/plugins/platforms/blackberry/qbbwindow.h | 133 -- src/plugins/platforms/platforms.pro | 2 +- src/plugins/platforms/qnx/main.cpp | 72 + src/plugins/platforms/qnx/qnx.pro | 71 + src/plugins/platforms/qnx/qqnxbuffer.cpp | 165 ++ src/plugins/platforms/qnx/qqnxbuffer.h | 74 + src/plugins/platforms/qnx/qqnxclipboard.cpp | 244 +++ src/plugins/platforms/qnx/qqnxclipboard.h | 66 + src/plugins/platforms/qnx/qqnxeventthread.cpp | 572 +++++++ src/plugins/platforms/qnx/qqnxeventthread.h | 90 ++ src/plugins/platforms/qnx/qqnxglbackingstore.cpp | 189 +++ src/plugins/platforms/qnx/qqnxglbackingstore.h | 95 ++ src/plugins/platforms/qnx/qqnxglcontext.cpp | 356 ++++ src/plugins/platforms/qnx/qqnxglcontext.h | 93 ++ src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp | 1696 ++++++++++++++++++++ src/plugins/platforms/qnx/qqnxinputcontext_imf.h | 132 ++ .../platforms/qnx/qqnxinputcontext_noimf.cpp | 187 +++ src/plugins/platforms/qnx/qqnxinputcontext_noimf.h | 84 + src/plugins/platforms/qnx/qqnxintegration.cpp | 293 ++++ src/plugins/platforms/qnx/qqnxintegration.h | 119 ++ src/plugins/platforms/qnx/qqnxkeytranslator.h | 269 ++++ src/plugins/platforms/qnx/qqnxnavigatorthread.cpp | 280 ++++ src/plugins/platforms/qnx/qqnxnavigatorthread.h | 78 + .../platforms/qnx/qqnxrasterbackingstore.cpp | 166 ++ src/plugins/platforms/qnx/qqnxrasterbackingstore.h | 81 + src/plugins/platforms/qnx/qqnxrootwindow.cpp | 257 +++ src/plugins/platforms/qnx/qqnxrootwindow.h | 81 + src/plugins/platforms/qnx/qqnxscreen.cpp | 315 ++++ src/plugins/platforms/qnx/qqnxscreen.h | 121 ++ src/plugins/platforms/qnx/qqnxvirtualkeyboard.cpp | 500 ++++++ src/plugins/platforms/qnx/qqnxvirtualkeyboard.h | 130 ++ src/plugins/platforms/qnx/qqnxwindow.cpp | 665 ++++++++ src/plugins/platforms/qnx/qqnxwindow.h | 133 ++ 63 files changed, 7675 insertions(+), 7675 deletions(-) delete mode 100644 src/plugins/platforms/blackberry/blackberry.pro delete mode 100644 src/plugins/platforms/blackberry/main.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbbuffer.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbbuffer.h delete mode 100644 src/plugins/platforms/blackberry/qbbclipboard.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbclipboard.h delete mode 100644 src/plugins/platforms/blackberry/qbbeventthread.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbeventthread.h delete mode 100644 src/plugins/platforms/blackberry/qbbglbackingstore.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbglbackingstore.h delete mode 100644 src/plugins/platforms/blackberry/qbbglcontext.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbglcontext.h delete mode 100644 src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbinputcontext_imf.h delete mode 100644 src/plugins/platforms/blackberry/qbbinputcontext_noimf.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbinputcontext_noimf.h delete mode 100644 src/plugins/platforms/blackberry/qbbintegration.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbintegration.h delete mode 100644 src/plugins/platforms/blackberry/qbbkeytranslator.h delete mode 100644 src/plugins/platforms/blackberry/qbbnavigatorthread.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbnavigatorthread.h delete mode 100644 src/plugins/platforms/blackberry/qbbrasterbackingstore.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbrasterbackingstore.h delete mode 100644 src/plugins/platforms/blackberry/qbbrootwindow.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbrootwindow.h delete mode 100644 src/plugins/platforms/blackberry/qbbscreen.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbscreen.h delete mode 100644 src/plugins/platforms/blackberry/qbbvirtualkeyboard.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbvirtualkeyboard.h delete mode 100644 src/plugins/platforms/blackberry/qbbwindow.cpp delete mode 100644 src/plugins/platforms/blackberry/qbbwindow.h create mode 100644 src/plugins/platforms/qnx/main.cpp create mode 100644 src/plugins/platforms/qnx/qnx.pro create mode 100644 src/plugins/platforms/qnx/qqnxbuffer.cpp create mode 100644 src/plugins/platforms/qnx/qqnxbuffer.h create mode 100644 src/plugins/platforms/qnx/qqnxclipboard.cpp create mode 100644 src/plugins/platforms/qnx/qqnxclipboard.h create mode 100644 src/plugins/platforms/qnx/qqnxeventthread.cpp create mode 100644 src/plugins/platforms/qnx/qqnxeventthread.h create mode 100644 src/plugins/platforms/qnx/qqnxglbackingstore.cpp create mode 100644 src/plugins/platforms/qnx/qqnxglbackingstore.h create mode 100644 src/plugins/platforms/qnx/qqnxglcontext.cpp create mode 100644 src/plugins/platforms/qnx/qqnxglcontext.h create mode 100644 src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp create mode 100644 src/plugins/platforms/qnx/qqnxinputcontext_imf.h create mode 100644 src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp create mode 100644 src/plugins/platforms/qnx/qqnxinputcontext_noimf.h create mode 100644 src/plugins/platforms/qnx/qqnxintegration.cpp create mode 100644 src/plugins/platforms/qnx/qqnxintegration.h create mode 100644 src/plugins/platforms/qnx/qqnxkeytranslator.h create mode 100644 src/plugins/platforms/qnx/qqnxnavigatorthread.cpp create mode 100644 src/plugins/platforms/qnx/qqnxnavigatorthread.h create mode 100644 src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp create mode 100644 src/plugins/platforms/qnx/qqnxrasterbackingstore.h create mode 100644 src/plugins/platforms/qnx/qqnxrootwindow.cpp create mode 100644 src/plugins/platforms/qnx/qqnxrootwindow.h create mode 100644 src/plugins/platforms/qnx/qqnxscreen.cpp create mode 100644 src/plugins/platforms/qnx/qqnxscreen.h create mode 100644 src/plugins/platforms/qnx/qqnxvirtualkeyboard.cpp create mode 100644 src/plugins/platforms/qnx/qqnxvirtualkeyboard.h create mode 100644 src/plugins/platforms/qnx/qqnxwindow.cpp create mode 100644 src/plugins/platforms/qnx/qqnxwindow.h diff --git a/src/plugins/platforms/blackberry/blackberry.pro b/src/plugins/platforms/blackberry/blackberry.pro deleted file mode 100644 index 94b9c5dbc8..0000000000 --- a/src/plugins/platforms/blackberry/blackberry.pro +++ /dev/null @@ -1,71 +0,0 @@ -TARGET = blackberry -include(../../qpluginbase.pri) - -QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms -QT += opengl opengl-private platformsupport platformsupport-private widgets-private - -# Uncomment this to build with support for IMF once it becomes available in the BBNDK -#CONFIG += qbb_imf - -# Uncomment these to enable debugging output for various aspects of the plugin -#DEFINES += QBBBUFFER_DEBUG -#DEFINES += QBBCLIPBOARD_DEBUG -#DEFINES += QBBEVENTTHREAD_DEBUG -#DEFINES += QBBGLBACKINGSTORE_DEBUG -#DEFINES += QBBGLCONTEXT_DEBUG -#DEFINES += QBBINPUTCONTEXT_DEBUG -#DEFINES += QBBINPUTCONTEXT_IMF_EVENT_DEBUG -#DEFINES += QBBINTEGRATION_DEBUG -#DEFINES += QBBNAVIGATORTHREAD_DEBUG -#DEFINES += QBBRASTERBACKINGSTORE_DEBUG -#DEFINES += QBBROOTWINDOW_DEBUG -#DEFINES += QBBSCREEN_DEBUG -#DEFINES += QBBVIRTUALKEYBOARD_DEBUG -#DEFINES += QBBWINDOW_DEBUG - -SOURCES = main.cpp \ - qbbbuffer.cpp \ - qbbeventthread.cpp \ - qbbglcontext.cpp \ - qbbglbackingstore.cpp \ - qbbintegration.cpp \ - qbbnavigatorthread.cpp \ - qbbscreen.cpp \ - qbbwindow.cpp \ - qbbrasterbackingstore.cpp \ - qbbvirtualkeyboard.cpp \ - qbbclipboard.cpp \ - qbbrootwindow.cpp - -HEADERS = qbbbuffer.h \ - qbbeventthread.h \ - qbbkeytranslator.h \ - qbbintegration.h \ - qbbnavigatorthread.h \ - qbbglcontext.h \ - qbbglbackingstore.h \ - qbbscreen.h \ - qbbwindow.h \ - qbbrasterbackingstore.h \ - qbbvirtualkeyboard.h \ - qbbclipboard.h \ - qbbrootwindow.h - -CONFIG(qbb_imf) { - DEFINES += QBB_IMF - HEADERS += qbbinputcontext_imf.h - SOURCES += qbbinputcontext_imf.cpp -} else { - HEADERS += qbbinputcontext_noimf.h - SOURCES += qbbinputcontext_noimf.cpp -} - -QMAKE_CXXFLAGS += -I./private - -LIBS += -lpps -lscreen -lEGL -lclipboard - -include (../../../platformsupport/eglconvenience/eglconvenience.pri) -include (../../../platformsupport/fontdatabases/fontdatabases.pri) - -target.path += $$[QT_INSTALL_PLUGINS]/platforms -INSTALLS += target diff --git a/src/plugins/platforms/blackberry/main.cpp b/src/plugins/platforms/blackberry/main.cpp deleted file mode 100644 index b9e09c0384..0000000000 --- a/src/plugins/platforms/blackberry/main.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 -#include "qbbintegration.h" - -QT_BEGIN_NAMESPACE - -class QBBIntegrationPlugin : public QPlatformIntegrationPlugin -{ -public: - QStringList keys() const; - QPlatformIntegration *create(const QString&, const QStringList&); -}; - -QStringList QBBIntegrationPlugin::keys() const -{ - QStringList list; - list << QLatin1String("blackberry"); - return list; -} - -QPlatformIntegration *QBBIntegrationPlugin::create(const QString& system, const QStringList& paramList) -{ - Q_UNUSED(paramList); - if (system.toLower() == QLatin1String("blackberry")) - return new QBBIntegration; - - return 0; -} - -Q_EXPORT_PLUGIN2(blackberry, QBBIntegrationPlugin) - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/blackberry/qbbbuffer.cpp b/src/plugins/platforms/blackberry/qbbbuffer.cpp deleted file mode 100644 index c4ac04898d..0000000000 --- a/src/plugins/platforms/blackberry/qbbbuffer.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbbuffer.h" - -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -QBBBuffer::QBBBuffer() - : m_buffer(0) -{ -#if defined(QBBBUFFER_DEBUG) - qDebug() << "QBBBuffer::QBBBuffer - empty"; -#endif -} - -QBBBuffer::QBBBuffer(screen_buffer_t buffer) - : m_buffer(buffer) -{ -#if defined(QBBBUFFER_DEBUG) - qDebug() << "QBBBuffer::QBBBuffer - normal"; -#endif - - // Get size of buffer - errno = 0; - int size[2]; - int result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_BUFFER_SIZE, size); - if (result != 0) { - qFatal("QBB: failed to query buffer size, errno=%d", errno); - } - - // Get stride of buffer - errno = 0; - int stride; - result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride); - if (result != 0) { - qFatal("QBB: failed to query buffer stride, errno=%d", errno); - } - - // Get access to buffer's data - errno = 0; - uchar *dataPtr = 0; - result = screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, (void **)&dataPtr); - if (result != 0) { - qFatal("QBB: failed to query buffer pointer, errno=%d", errno); - } - if (dataPtr == NULL) { - qFatal("QBB: buffer pointer is NULL, errno=%d", errno); - } - - // Get format of buffer - errno = 0; - int screenFormat; - result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_FORMAT, &screenFormat); - if (result != 0) { - qFatal("QBB: failed to query buffer format, errno=%d", errno); - } - - // Convert screen format to QImage format - QImage::Format imageFormat = QImage::Format_Invalid; - switch (screenFormat) { - case SCREEN_FORMAT_RGBX4444: - imageFormat = QImage::Format_RGB444; - break; - case SCREEN_FORMAT_RGBA4444: - imageFormat = QImage::Format_ARGB4444_Premultiplied; - break; - case SCREEN_FORMAT_RGBX5551: - imageFormat = QImage::Format_RGB555; - break; - case SCREEN_FORMAT_RGB565: - imageFormat = QImage::Format_RGB16; - break; - case SCREEN_FORMAT_RGBX8888: - imageFormat = QImage::Format_RGB32; - break; - case SCREEN_FORMAT_RGBA8888: - imageFormat = QImage::Format_ARGB32_Premultiplied; - break; - default: - qFatal("QBB: unsupported buffer format, format=%d", screenFormat); - } - - // wrap buffer in an image - m_image = QImage(dataPtr, size[0], size[1], stride, imageFormat); -} - -QBBBuffer::QBBBuffer(const QBBBuffer &other) - : m_buffer(other.m_buffer), - m_image(other.m_image) -{ -#if defined(QBBBUFFER_DEBUG) - qDebug() << "QBBBuffer::QBBBuffer - copy"; -#endif -} - -QBBBuffer::~QBBBuffer() -{ -#if defined(QBBBUFFER_DEBUG) - qDebug() << "QBBBuffer::~QBBBuffer"; -#endif -} - -void QBBBuffer::invalidateInCache() -{ -#if defined(QBBBUFFER_DEBUG) - qDebug() << "QBBBuffer::invalidateInCache"; -#endif - - // Verify native buffer exists - if (m_buffer == 0) { - qFatal("QBB: can't invalidate cache for null buffer"); - } - - // Evict buffer's data from cache - errno = 0; - int result = msync(m_image.bits(), m_image.height() * m_image.bytesPerLine(), MS_INVALIDATE | MS_CACHE_ONLY); - if (result != 0) { - qFatal("QBB: failed to invalidate cache, errno=%d", errno); - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/blackberry/qbbbuffer.h b/src/plugins/platforms/blackberry/qbbbuffer.h deleted file mode 100644 index 45cedb21a8..0000000000 --- a/src/plugins/platforms/blackberry/qbbbuffer.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBBUFFER_H -#define QBBBUFFER_H - -#include - -#include - -QT_BEGIN_NAMESPACE - -class QBBBuffer -{ -public: - QBBBuffer(); - QBBBuffer(screen_buffer_t buffer); - QBBBuffer(const QBBBuffer &other); - virtual ~QBBBuffer(); - - screen_buffer_t nativeBuffer() const { return m_buffer; } - const QImage *image() const { return (m_buffer != NULL) ? &m_image : NULL; } - QImage *image() { return (m_buffer != NULL) ? &m_image : NULL; } - - QRect rect() const { return m_image.rect(); } - - void invalidateInCache(); - -private: - screen_buffer_t m_buffer; - QImage m_image; -}; - -QT_END_NAMESPACE - -#endif // QBBBUFFER_H diff --git a/src/plugins/platforms/blackberry/qbbclipboard.cpp b/src/plugins/platforms/blackberry/qbbclipboard.cpp deleted file mode 100644 index 293a0c771b..0000000000 --- a/src/plugins/platforms/blackberry/qbbclipboard.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QT_NO_CLIPBOARD - -#include "qbbclipboard.h" - -#include - -#include -#include -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -// null terminated array -static const char *typeList[] = {"text/html", "text/plain", "image/png", "image/jpeg", "application/x-color", 0}; - -static QByteArray readClipboardBuff(const char *type) -{ - char *pbuffer; - if (is_clipboard_format_present(type) == 0) { - int size = get_clipboard_data(type, &pbuffer); - if (size != -1 && pbuffer) { - const QByteArray result = QByteArray(pbuffer, size); - free(pbuffer); - return result; - } - } - - return QByteArray(); -} - -class QBBClipboard::MimeData : public QMimeData -{ - Q_OBJECT -public: - MimeData(QBBClipboard *clipboard) - : QMimeData(), - m_clipboard(clipboard), - m_userMimeData(0) - { - Q_ASSERT(clipboard); - - for (int i = 0; typeList[i] != 0; ++i) { - m_formatsToCheck << QString::fromUtf8(typeList[i]); - } - } - - ~MimeData() - { - delete m_userMimeData; - } - - void addFormatToCheck(const QString &format) { - m_formatsToCheck << format; - -#if defined(QBBCLIPBOARD_DEBUG) - qDebug() << Q_FUNC_INFO << "formats=" << m_formatsToCheck; -#endif - } - - bool hasFormat(const QString &mimetype) const - { - const bool result = is_clipboard_format_present(mimetype.toUtf8().constData()) == 0; -#if defined(QBBCLIPBOARD_DEBUG) - qDebug() << Q_FUNC_INFO << "mimetype=" << mimetype << "result=" << result; -#endif - return result; - } - - QStringList formats() const - { - QStringList result; - - Q_FOREACH (const QString &format, m_formatsToCheck) { - if (is_clipboard_format_present(format.toUtf8().constData()) == 0) - result << format; - } - -#if defined(QBBCLIPBOARD_DEBUG) - qDebug() << Q_FUNC_INFO << "result=" << result; -#endif - return result; - } - - void setUserMimeData(QMimeData *userMimeData) - { - delete m_userMimeData; - m_userMimeData = userMimeData; - - // system clipboard API doesn't allow detection of changes by other applications - // simulate an owner change through delayed invocation - // basically transfer ownership of data to the system clipboard once event processing resumes - if (m_userMimeData) - QMetaObject::invokeMethod(this, "releaseOwnership", Qt::QueuedConnection); - } - - QMimeData *userMimeData() - { - return m_userMimeData; - } - -protected: - QVariant retrieveData(const QString &mimetype, QVariant::Type preferredType) const - { -#if defined(QBBCLIPBOARD_DEBUG) - qDebug() << Q_FUNC_INFO << "mimetype=" << mimetype << "preferredType=" << preferredType; -#endif - if (is_clipboard_format_present(mimetype.toUtf8().constData()) != 0) - return QMimeData::retrieveData(mimetype, preferredType); - - const QByteArray data = readClipboardBuff(mimetype.toUtf8().constData()); - return qVariantFromValue(data); - } - -private Q_SLOTS: - void releaseOwnership() - { - if (m_userMimeData) { -#if defined(QBBCLIPBOARD_DEBUG) - qDebug() << Q_FUNC_INFO << "user data formats=" << m_userMimeData->formats() << "system formats=" << formats(); -#endif - delete m_userMimeData; - m_userMimeData = 0; - m_clipboard->emitChanged(QClipboard::Clipboard); - } - } - -private: - QBBClipboard * const m_clipboard; - - QSet m_formatsToCheck; - QMimeData *m_userMimeData; -}; - -QBBClipboard::QBBClipboard() - : m_mimeData(new MimeData(this)) -{ -} - -QBBClipboard::~QBBClipboard() -{ - delete m_mimeData; -} - -void QBBClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) -{ - if (mode != QClipboard::Clipboard) - return; - - if (data == m_mimeData || data == m_mimeData->userMimeData()) - return; - - empty_clipboard(); - - m_mimeData->clear(); - m_mimeData->setUserMimeData(data); - - if (data == 0) - return; - - const QStringList formats = data->formats(); -#if defined(QBBCLIPBOARD_DEBUG) - qDebug() << Q_FUNC_INFO << "formats=" << formats; -#endif - - Q_FOREACH (const QString &format, formats) { - const QByteArray buf = data->data(format); - - if (buf.isEmpty()) - continue; - - int ret = set_clipboard_data(format.toUtf8().data(), buf.size(), buf.data()); -#if defined(QBBCLIPBOARD_DEBUG) - qDebug() << "QBB: set " << format << "to clipboard, size=" << buf.size() << ";ret=" << ret; -#endif - if (ret) - m_mimeData->addFormatToCheck(format); - } - - emitChanged(QClipboard::Clipboard); -} - -QMimeData *QBBClipboard::mimeData(QClipboard::Mode mode) -{ - if (mode != QClipboard::Clipboard) - return 0; - - if (m_mimeData->userMimeData()) - return m_mimeData->userMimeData(); - - m_mimeData->clear(); - - return m_mimeData; -} - -QT_END_NAMESPACE - -#include "qbbclipboard.moc" - -#endif //QT_NO_CLIPBOARD diff --git a/src/plugins/platforms/blackberry/qbbclipboard.h b/src/plugins/platforms/blackberry/qbbclipboard.h deleted file mode 100644 index 11a36ba8e5..0000000000 --- a/src/plugins/platforms/blackberry/qbbclipboard.h +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBCLIPBOARD_H -#define QBBCLIPBOARD_H - -#ifndef QT_NO_CLIPBOARD -#include - -QT_BEGIN_NAMESPACE - -class QBBClipboard : public QPlatformClipboard -{ -public: - QBBClipboard(); - virtual ~QBBClipboard(); - virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard); - virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); - -private: - class MimeData; - MimeData *m_mimeData; -}; - -QT_END_NAMESPACE - -#endif //QT_NO_CLIPBOARD -#endif //QBBCLIPBOARD_H diff --git a/src/plugins/platforms/blackberry/qbbeventthread.cpp b/src/plugins/platforms/blackberry/qbbeventthread.cpp deleted file mode 100644 index 6951921fe9..0000000000 --- a/src/plugins/platforms/blackberry/qbbeventthread.cpp +++ /dev/null @@ -1,572 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbeventthread.h" -#include "qbbintegration.h" -#include "qbbkeytranslator.h" - -#if defined(QBB_IMF) -#include "qbbinputcontext_imf.h" -#else -#include "qbbinputcontext_noimf.h" -#endif - -#include -#include -#include - -#include - -#include -#include -#include - -#include - -QBBEventThread::QBBEventThread(screen_context_t context, QPlatformScreen& screen) - : QThread(), - m_screenContext(context), - m_platformScreen(screen), - m_quit(false), - m_lastButtonState(Qt::NoButton), - m_lastMouseWindow(0) -{ - // Create a touch device - m_touchDevice = new QTouchDevice; - m_touchDevice->setType(QTouchDevice::TouchScreen); - m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); - QWindowSystemInterface::registerTouchDevice(m_touchDevice); - - // initialize array of touch points - for (int i = 0; i < MaximumTouchPoints; i++) { - - // map array index to id - m_touchPoints[i].id = i; - - // pressure is not supported - use default - m_touchPoints[i].pressure = 1.0; - - // nothing touching - m_touchPoints[i].state = Qt::TouchPointReleased; - } -} - -QBBEventThread::~QBBEventThread() -{ - // block until thread terminates - shutdown(); -} - -void QBBEventThread::run() -{ - screen_event_t event; - - // create screen event - errno = 0; - int result = screen_create_event(&event); - if (result) { - qFatal("QBB: failed to create event, errno=%d", errno); - } - -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: event loop started"; -#endif - - // loop indefinitely - while (!m_quit) { - - // block until screen event is available - errno = 0; - result = screen_get_event(m_screenContext, event, -1); - if (result) { - qFatal("QBB: failed to get event, errno=%d", errno); - } - - // process received event - dispatchEvent(event); - } - -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: event loop stopped"; -#endif - - // cleanup - screen_destroy_event(event); -} - -void QBBEventThread::shutdown() -{ - screen_event_t event; - - // create screen event - errno = 0; - int result = screen_create_event(&event); - if (result) { - qFatal("QBB: failed to create event, errno=%d", errno); - } - - // set the event type as user - errno = 0; - int type = SCREEN_EVENT_USER; - result = screen_set_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type); - if (result) { - qFatal("QBB: failed to set event type, errno=%d", errno); - } - - // NOTE: ignore SCREEN_PROPERTY_USER_DATA; treat all user events as shutdown events - - // post event to event loop so it will wake up and die - errno = 0; - result = screen_send_event(m_screenContext, event, getpid()); - if (result) { - qFatal("QBB: failed to set event type, errno=%d", errno); - } - - // cleanup - screen_destroy_event(event); - -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: event loop shutdown begin"; -#endif - - // block until thread terminates - wait(); - -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: event loop shutdown end"; -#endif -} - -void QBBEventThread::dispatchEvent(screen_event_t event) -{ - // get the event type - errno = 0; - int qnxType; - int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType); - if (result) { - qFatal("QBB: failed to query event type, errno=%d", errno); - } - - switch (qnxType) { - case SCREEN_EVENT_MTOUCH_TOUCH: - case SCREEN_EVENT_MTOUCH_MOVE: - case SCREEN_EVENT_MTOUCH_RELEASE: - handleTouchEvent(event, qnxType); - break; - - case SCREEN_EVENT_KEYBOARD: - handleKeyboardEvent(event); - break; - - case SCREEN_EVENT_POINTER: - handlePointerEvent(event); - break; - - case SCREEN_EVENT_CLOSE: - handleCloseEvent(event); - break; - - case SCREEN_EVENT_USER: - // treat all user events as shutdown requests -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: QNX user event"; -#endif - m_quit = true; - break; - - default: - // event ignored -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: QNX unknown event"; -#endif - break; - } -} - -void QBBEventThread::handleKeyboardEvent(screen_event_t event) -{ - // get flags of key event - errno = 0; - int flags; - int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_FLAGS, &flags); - if (result) { - qFatal("QBB: failed to query event flags, errno=%d", errno); - } - - // get key code - errno = 0; - int sym; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SYM, &sym); - if (result) { - qFatal("QBB: failed to query event sym, errno=%d", errno); - } - - int modifiers; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_MODIFIERS, &modifiers); - if (result) { - qFatal("QBB: failed to query event modifiers, errno=%d", errno); - } - - int scan; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SCAN, &scan); - if (result) { - qFatal("QBB: failed to query event modifiers, errno=%d", errno); - } - - int cap; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap); - if (result) { - qFatal("QBB: failed to query event cap, errno=%d", errno); - } - - injectKeyboardEvent(flags, sym, modifiers, scan, cap); -} - -void QBBEventThread::injectKeyboardEvent(int flags, int sym, int modifiers, int scan, int cap) -{ - Q_UNUSED(scan); - - Qt::KeyboardModifiers qtMod = Qt::NoModifier; - if (modifiers & KEYMOD_SHIFT) - qtMod |= Qt::ShiftModifier; - if (modifiers & KEYMOD_CTRL) - qtMod |= Qt::ControlModifier; - if (modifiers & KEYMOD_ALT) - qtMod |= Qt::AltModifier; - - // determine event type - QEvent::Type type = (flags & KEY_DOWN) ? QEvent::KeyPress : QEvent::KeyRelease; - - // Check if the key cap is valid - if (flags & KEY_CAP_VALID) { - Qt::Key key; - QString keyStr; - - if (cap >= 0x20 && cap <= 0x0ff) { - key = Qt::Key(std::toupper(cap)); // Qt expects the CAP to be upper case. - - if ( qtMod & Qt::ControlModifier ) { - keyStr = QChar((int)(key & 0x3f)); - } else { - if (flags & KEY_SYM_VALID) { - keyStr = QChar(sym); - } - } - } else if ((cap > 0x0ff && cap < UNICODE_PRIVATE_USE_AREA_FIRST) || cap > UNICODE_PRIVATE_USE_AREA_LAST) { - key = (Qt::Key)cap; - keyStr = QChar(sym); - } else { - if (isKeypadKey(cap)) - qtMod |= Qt::KeypadModifier; // Is this right? - key = keyTranslator(cap); - } - - QWindowSystemInterface::handleKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod, keyStr); -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: Qt key t=" << type << ", k=" << key << ", s=" << keyStr; -#endif - } -} - -void QBBEventThread::handlePointerEvent(screen_event_t event) -{ - errno = 0; - - // Query the window that was clicked - screen_window_t qnxWindow; - void *handle; - int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle); - if (result) { - qFatal("QBB: failed to query event window, errno=%d", errno); - } - qnxWindow = static_cast(handle); - - // Query the button states - int buttonState = 0; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState); - if (result) { - qFatal("QBB: failed to query event button state, errno=%d", errno); - } - - // Query the window position - int windowPos[2]; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos); - if (result) { - qFatal("QBB: failed to query event window position, errno=%d", errno); - } - - // Query the screen position - int pos[2]; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos); - if (result) { - qFatal("QBB: failed to query event position, errno=%d", errno); - } - - // Query the wheel delta - int wheelDelta = 0; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta); - if (result) { - qFatal("QBB: failed to query event wheel delta, errno=%d", errno); - } - - // Map window handle to top-level QWindow - QWindow *w = QBBIntegration::window(qnxWindow); - - // Generate enter and leave events as needed. - if (qnxWindow != m_lastMouseWindow) { - QWindow *wOld = QBBIntegration::window(m_lastMouseWindow); - - if (wOld) { - QWindowSystemInterface::handleLeaveEvent(wOld); -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: Qt leave, w=" << wOld; -#endif - } - - if (w) { - QWindowSystemInterface::handleEnterEvent(w); -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: Qt enter, w=" << w; -#endif - } - } - m_lastMouseWindow = qnxWindow; - - // Apply scaling to wheel delta and invert value for Qt. We'll probably want to scale - // this via a system preference at some point. But for now this is a sane value and makes - // the wheel usable. - wheelDelta *= -10; - - // convert point to local coordinates - QPoint globalPoint(pos[0], pos[1]); - QPoint localPoint(windowPos[0], windowPos[1]); - - // Convert buttons. - // Some QNX header files invert 'Right Button versus "Left Button' ('Right' == 0x01). But they also offer a 'Button Swap' bit, - // so we may receive events as shown. (If this is wrong, the fix is easy.) - // QNX Button mask is 8 buttons wide, with a maximum value of x080. - Qt::MouseButtons buttons = Qt::NoButton; - if (buttonState & 0x01) - buttons |= Qt::LeftButton; - if (buttonState & 0x02) - buttons |= Qt::MidButton; - if (buttonState & 0x04) - buttons |= Qt::RightButton; - if (buttonState & 0x08) - buttons |= Qt::ExtraButton1; // AKA 'Qt::BackButton' - if (buttonState & 0x10) - buttons |= Qt::ExtraButton2; // AKA 'Qt::ForwardButton' - if (buttonState & 0x20) - buttons |= Qt::ExtraButton3; - if (buttonState & 0x40) - buttons |= Qt::ExtraButton4; - if (buttonState & 0x80) - buttons |= Qt::ExtraButton5; - - if (w) { - // Inject mouse event into Qt only if something has changed. - if (m_lastGlobalMousePoint != globalPoint || - m_lastLocalMousePoint != localPoint || - m_lastButtonState != buttons) { - QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons); -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << static_cast(buttons); -#endif - } - - if (wheelDelta) { - // Screen only supports a single wheel, so we will assume Vertical orientation for - // now since that is pretty much standard. - QWindowSystemInterface::handleWheelEvent(w, localPoint, globalPoint, wheelDelta, Qt::Vertical); -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: Qt wheel, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), d=" << static_cast(wheelDelta); -#endif - } - } - - m_lastGlobalMousePoint = globalPoint; - m_lastLocalMousePoint = localPoint; - m_lastButtonState = buttons; -} - -void QBBEventThread::handleTouchEvent(screen_event_t event, int qnxType) -{ - // get display coordinates of touch - errno = 0; - int pos[2]; - int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos); - if (result) { - qFatal("QBB: failed to query event position, errno=%d", errno); - } - - // get window coordinates of touch - errno = 0; - int windowPos[2]; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos); - if (result) { - qFatal("QBB: failed to query event window position, errno=%d", errno); - } - - // determine which finger touched - errno = 0; - int touchId; - result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId); - if (result) { - qFatal("QBB: failed to query event touch id, errno=%d", errno); - } - - // determine which window was touched - errno = 0; - void *handle; - result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle); - if (result) { - qFatal("QBB: failed to query event window, errno=%d", errno); - } - screen_window_t qnxWindow = static_cast(handle); - - // check if finger is valid - if (touchId < MaximumTouchPoints) { - - // Map window handle to top-level QWindow - QWindow *w = QBBIntegration::window(qnxWindow); - - // Generate enter and leave events as needed. - if (qnxWindow != m_lastMouseWindow) { - QWindow *wOld = QBBIntegration::window(m_lastMouseWindow); - - if (wOld) { - QWindowSystemInterface::handleLeaveEvent(wOld); - #if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: Qt leave, w=" << wOld; - #endif - } - - if (w) { - QWindowSystemInterface::handleEnterEvent(w); - #if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: Qt enter, w=" << w; - #endif - } - } - m_lastMouseWindow = qnxWindow; - - if (w) { - // convert primary touch to mouse event - if (touchId == 0) { - - // convert point to local coordinates - QPoint globalPoint(pos[0], pos[1]); - QPoint localPoint(windowPos[0], windowPos[1]); - - // map touch state to button state - Qt::MouseButtons buttons = (qnxType == SCREEN_EVENT_MTOUCH_RELEASE) ? Qt::NoButton : Qt::LeftButton; - - // inject event into Qt - QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons); -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << buttons; -#endif - } - - // get size of screen which contains window - QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(w); - QSizeF screenSize = platformScreen->physicalSize(); - - // update cached position of current touch point - m_touchPoints[touchId].normalPosition = QPointF( static_cast(pos[0]) / screenSize.width(), static_cast(pos[1]) / screenSize.height() ); - m_touchPoints[touchId].area = QRectF( pos[0], pos[1], 0.0, 0.0 ); - - // determine event type and update state of current touch point - QEvent::Type type = QEvent::None; - switch (qnxType) { - case SCREEN_EVENT_MTOUCH_TOUCH: - m_touchPoints[touchId].state = Qt::TouchPointPressed; - type = QEvent::TouchBegin; - break; - case SCREEN_EVENT_MTOUCH_MOVE: - m_touchPoints[touchId].state = Qt::TouchPointMoved; - type = QEvent::TouchUpdate; - break; - case SCREEN_EVENT_MTOUCH_RELEASE: - m_touchPoints[touchId].state = Qt::TouchPointReleased; - type = QEvent::TouchEnd; - break; - } - - // build list of active touch points - QList pointList; - for (int i = 0; i < MaximumTouchPoints; i++) { - if (i == touchId) { - // current touch point is always active - pointList.append(m_touchPoints[i]); - } else if (m_touchPoints[i].state != Qt::TouchPointReleased) { - // finger is down but did not move - m_touchPoints[i].state = Qt::TouchPointStationary; - pointList.append(m_touchPoints[i]); - } - } - - // inject event into Qt - QWindowSystemInterface::handleTouchEvent(w, m_touchDevice, pointList); -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: Qt touch, w=" << w << ", p=(" << pos[0] << "," << pos[1] << "), t=" << type; -#endif - } - } -} - -void QBBEventThread::handleCloseEvent(screen_event_t event) -{ - // Query the window that was closed - void *handle; - int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle); - if (result != 0) { - qFatal("QBB: failed to query event window, errno=%d", errno); - } - screen_window_t qnxWindow = static_cast(handle); - - // Map window handle to top-level QWindow - QWindow *w = QBBIntegration::window(qnxWindow); - if (w != 0) { - QWindowSystemInterface::handleCloseEvent(w); - } -} - diff --git a/src/plugins/platforms/blackberry/qbbeventthread.h b/src/plugins/platforms/blackberry/qbbeventthread.h deleted file mode 100644 index afa738830c..0000000000 --- a/src/plugins/platforms/blackberry/qbbeventthread.h +++ /dev/null @@ -1,90 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBEVENTTHREAD_H -#define QBBEVENTTHREAD_H - -#include - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QBBEventThread : public QThread -{ -public: - QBBEventThread(screen_context_t context, QPlatformScreen& screen); - virtual ~QBBEventThread(); - - static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap); - -protected: - virtual void run(); - -private: - enum { - MaximumTouchPoints = 10 - }; - - void shutdown(); - void dispatchEvent(screen_event_t event); - void handleKeyboardEvent(screen_event_t event); - void handlePointerEvent(screen_event_t event); - void handleTouchEvent(screen_event_t event, int type); - void handleCloseEvent(screen_event_t event); - - screen_context_t m_screenContext; - QPlatformScreen& m_platformScreen; - bool m_quit; - QPoint m_lastGlobalMousePoint; - QPoint m_lastLocalMousePoint; - Qt::MouseButtons m_lastButtonState; - screen_window_t m_lastMouseWindow; - QTouchDevice *m_touchDevice; - QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints]; -}; - -QT_END_NAMESPACE - -#endif // QBBEVENTTHREAD_H diff --git a/src/plugins/platforms/blackberry/qbbglbackingstore.cpp b/src/plugins/platforms/blackberry/qbbglbackingstore.cpp deleted file mode 100644 index 91b07770e1..0000000000 --- a/src/plugins/platforms/blackberry/qbbglbackingstore.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbglbackingstore.h" -#include "qbbglcontext.h" -#include "qbbwindow.h" -#include "qbbscreen.h" - -#include - -#include -#include - -#include - -#include - -QT_BEGIN_NAMESPACE - -QBBGLPaintDevice::QBBGLPaintDevice(QWindow *window) - : QGLPaintDevice(), - m_window(0), - m_glContext(0) -{ - m_window = static_cast(window->handle()); - - // Extract the QPlatformOpenGLContext from the window - QPlatformOpenGLContext *platformOpenGLContext = m_window->platformOpenGLContext(); - - // Convert this to a QGLContext - m_glContext = QGLContext::fromOpenGLContext(platformOpenGLContext->context()); -} - -QBBGLPaintDevice::~QBBGLPaintDevice() -{ - // Cleanup GL context - delete m_glContext; -} - -QPaintEngine *QBBGLPaintDevice::paintEngine() const -{ - // Select a paint engine based on configued OpenGL version - return qt_qgl_paint_engine(); -} - -QSize QBBGLPaintDevice::size() const -{ - // Get size of EGL surface - return m_window->geometry().size(); -} - - -QBBGLBackingStore::QBBGLBackingStore(QWindow *window) - : QPlatformBackingStore(window), - m_openGLContext(0), - m_paintDevice(0), - m_requestedSize(), - m_size() -{ -#if defined(QBBGLBACKINGSTORE_DEBUG) - qDebug() << "QBBGLBackingStore::QBBGLBackingStore - w=" << window; -#endif - - // Create an OpenGL paint device which in turn creates a QGLContext for us - m_paintDevice = new QBBGLPaintDevice(window); - m_openGLContext = m_paintDevice->context()->contextHandle(); -} - -QBBGLBackingStore::~QBBGLBackingStore() -{ -#if defined(QBBGLBACKINGSTORE_DEBUG) - qDebug() << "QBBGLBackingStore::~QBBGLBackingStore - w=" << window(); -#endif - - // cleanup OpenGL paint device - delete m_paintDevice; -} - -void QBBGLBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) -{ - Q_UNUSED(region); - Q_UNUSED(offset); - -#if defined(QBBGLBACKINGSTORE_DEBUG) - qDebug() << "QBBGLBackingStore::flush - w=" << window; -#endif - - // update the display with newly rendered content - m_openGLContext->swapBuffers(window); -} - -void QBBGLBackingStore::resize(const QSize &size, const QRegion &staticContents) -{ - Q_UNUSED(staticContents); -#if defined(QBBGLBACKINGSTORE_DEBUG) - qDebug() << "QBBGLBackingStore::resize - w=" << window() << ", s=" << size; -#endif - // NOTE: defer resizing window buffers until next paint as - // resize() can be called multiple times before a paint occurs - m_requestedSize = size; -} - -void QBBGLBackingStore::beginPaint(const QRegion ®ion) -{ - Q_UNUSED(region); - -#if defined(QBBGLBACKINGSTORE_DEBUG) - qDebug() << "QBBGLBackingStore::beginPaint - w=" << window(); -#endif - - // resize EGL surface if window surface resized - if (m_size != m_requestedSize) { - resizeSurface(m_requestedSize); - } -} - -void QBBGLBackingStore::endPaint(const QRegion ®ion) -{ - Q_UNUSED(region); -#if defined(QBBGLBACKINGSTORE_DEBUG) - qDebug() << "QBBGLBackingStore::endPaint - w=" << window(); -#endif -} - -void QBBGLBackingStore::resizeSurface(const QSize &size) -{ - // need to destroy surface so make sure its not current - bool restoreCurrent = false; - QBBGLContext *platformContext = static_cast(m_openGLContext->handle()); - if (platformContext->isCurrent()) { - m_openGLContext->doneCurrent(); - restoreCurrent = true; - } - - // destroy old EGL surface - platformContext->destroySurface(); - - // resize window's buffers - static_cast(window()->handle())->setBufferSize(size); - - // re-create EGL surface with new size - m_size = size; - platformContext->createSurface(window()->handle()); - - // make context current again - if (restoreCurrent) { - m_openGLContext->makeCurrent(window()); - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/blackberry/qbbglbackingstore.h b/src/plugins/platforms/blackberry/qbbglbackingstore.h deleted file mode 100644 index 5455c5767c..0000000000 --- a/src/plugins/platforms/blackberry/qbbglbackingstore.h +++ /dev/null @@ -1,95 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBGLBACKINGSTORE_H -#define QBBGLBACKINGSTORE_H - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QGLContext; -class QBBGLContext; -class QBBScreen; -class QBBWindow; - -class QBBGLPaintDevice : public QGLPaintDevice -{ -public: - QBBGLPaintDevice(QWindow *window); - virtual ~QBBGLPaintDevice(); - - virtual QPaintEngine *paintEngine() const; - virtual QSize size() const; - virtual QGLContext *context() const { return m_glContext; } - -private: - QBBWindow *m_window; - QGLContext *m_glContext; -}; - -class QBBGLBackingStore : public QPlatformBackingStore -{ -public: - QBBGLBackingStore(QWindow *window); - virtual ~QBBGLBackingStore(); - - virtual QPaintDevice *paintDevice() { return m_paintDevice; } - virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); - virtual void resize(const QSize &size, const QRegion &staticContents); - virtual void beginPaint(const QRegion ®ion); - virtual void endPaint(const QRegion ®ion); - - void resizeSurface(const QSize &size); - -private: - QOpenGLContext *m_openGLContext; - QBBGLPaintDevice *m_paintDevice; - QSize m_requestedSize; - QSize m_size; -}; - -QT_END_NAMESPACE - -#endif // QBBGLBACKINGSTORE_H diff --git a/src/plugins/platforms/blackberry/qbbglcontext.cpp b/src/plugins/platforms/blackberry/qbbglcontext.cpp deleted file mode 100644 index fb74fdb5d2..0000000000 --- a/src/plugins/platforms/blackberry/qbbglcontext.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbglcontext.h" -#include "qbbrootwindow.h" -#include "qbbscreen.h" -#include "qbbwindow.h" - -#include "private/qeglconvenience_p.h" - -#include -#include - -QT_BEGIN_NAMESPACE - -EGLDisplay QBBGLContext::ms_eglDisplay = EGL_NO_DISPLAY; - -static EGLenum checkEGLError(const char *msg) -{ - static const char *errmsg[] = - { - "EGL function succeeded", - "EGL is not initialized, or could not be initialized, for the specified display", - "EGL cannot access a requested resource", - "EGL failed to allocate resources for the requested operation", - "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list", - "EGLConfig argument does not name a valid EGLConfig", - "EGLContext argument does not name a valid EGLContext", - "EGL current surface of the calling thread is no longer valid", - "EGLDisplay argument does not name a valid EGLDisplay", - "EGL arguments are inconsistent", - "EGLNativePixmapType argument does not refer to a valid native pixmap", - "EGLNativeWindowType argument does not refer to a valid native window", - "EGL one or more argument values are invalid", - "EGLSurface argument does not name a valid surface configured for rendering", - "EGL power management event has occurred", - }; - EGLenum error = eglGetError(); - fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]); - return error; -} - -QBBGLContext::QBBGLContext(QOpenGLContext *glContext) - : QPlatformOpenGLContext(), - m_glContext(glContext), - m_eglSurface(EGL_NO_SURFACE) -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - QSurfaceFormat format = m_glContext->format(); - - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (eglResult != EGL_TRUE) { - qFatal("QBB: failed to set EGL API, err=%d", eglGetError()); - } - - // Get colour channel sizes from window format - int alphaSize = format.alphaBufferSize(); - int redSize = format.redBufferSize(); - int greenSize = format.greenBufferSize(); - int blueSize = format.blueBufferSize(); - - // Check if all channels are don't care - if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) { - // Set colour channels based on depth of window's screen - QBBScreen *screen = static_cast(QBBScreen::screens().first()); - int depth = screen->depth(); - if (depth == 32) { - // SCREEN_FORMAT_RGBA8888 - alphaSize = 8; - redSize = 8; - greenSize = 8; - blueSize = 8; - } else { - // SCREEN_FORMAT_RGB565 - alphaSize = 0; - redSize = 5; - greenSize = 6; - blueSize = 5; - } - } else { - // Choose best match based on supported pixel formats - if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) { - // SCREEN_FORMAT_RGB565 - alphaSize = 0; - redSize = 5; - greenSize = 6; - blueSize = 5; - } else { - // SCREEN_FORMAT_RGBA8888 - alphaSize = 8; - redSize = 8; - greenSize = 8; - blueSize = 8; - } - } - - // Update colour channel sizes in window format - format.setAlphaBufferSize(alphaSize); - format.setRedBufferSize(redSize); - format.setGreenBufferSize(greenSize); - format.setBlueBufferSize(blueSize); - format.setSamples(2); - - // Select EGL config based on requested window format - m_eglConfig = q_configFromGLFormat(ms_eglDisplay, format); - if (m_eglConfig == 0) { - qFatal("QBB: failed to find EGL config"); - } - - m_eglContext = eglCreateContext(ms_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttrs()); - if (m_eglContext == EGL_NO_CONTEXT) { - checkEGLError("eglCreateContext"); - qFatal("QBB: failed to create EGL context, err=%d", eglGetError()); - } - - // Query/cache window format of selected EGL config - m_windowFormat = q_glFormatFromConfig(ms_eglDisplay, m_eglConfig); -} - -QBBGLContext::~QBBGLContext() -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - // Cleanup EGL context if it exists - if (m_eglContext != EGL_NO_CONTEXT) { - eglDestroyContext(ms_eglDisplay, m_eglContext); - } - - // Cleanup EGL surface if it exists - destroySurface(); -} - -void QBBGLContext::initialize() -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // Initialize connection to EGL - ms_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (ms_eglDisplay == EGL_NO_DISPLAY) { - checkEGLError("eglGetDisplay"); - qFatal("QBB: failed to obtain EGL display"); - } - - EGLBoolean eglResult = eglInitialize(ms_eglDisplay, 0, 0); - if (eglResult != EGL_TRUE) { - checkEGLError("eglInitialize"); - qFatal("QBB: failed to initialize EGL display, err=%d", eglGetError()); - } -} - -void QBBGLContext::shutdown() -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // Close connection to EGL - eglTerminate(ms_eglDisplay); -} - -bool QBBGLContext::makeCurrent(QPlatformSurface *surface) -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (eglResult != EGL_TRUE) { - qFatal("QBB: failed to set EGL API, err=%d", eglGetError()); - } - - if (m_eglSurface == EGL_NO_SURFACE) - createSurface(surface); - - eglResult = eglMakeCurrent(ms_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); - if (eglResult != EGL_TRUE) { - checkEGLError("eglMakeCurrent"); - qFatal("QBB: failed to set current EGL context, err=%d", eglGetError()); - } - return (eglResult == EGL_TRUE); -} - -void QBBGLContext::doneCurrent() -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (eglResult != EGL_TRUE) { - qFatal("QBB: failed to set EGL API, err=%d", eglGetError()); - } - - // clear curent EGL context and unbind EGL surface - eglResult = eglMakeCurrent(ms_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (eglResult != EGL_TRUE) { - qFatal("QBB: failed to clear current EGL context, err=%d", eglGetError()); - } -} - -void QBBGLContext::swapBuffers(QPlatformSurface *surface) -{ - Q_UNUSED(surface); -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (eglResult != EGL_TRUE) { - qFatal("QBB: failed to set EGL API, err=%d", eglGetError()); - } - - // Post EGL surface to window - eglResult = eglSwapBuffers(ms_eglDisplay, m_eglSurface); - if (eglResult != EGL_TRUE) { - qFatal("QBB: failed to swap EGL buffers, err=%d", eglGetError()); - } -} - -QFunctionPointer QBBGLContext::getProcAddress(const QByteArray &procName) -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (eglResult != EGL_TRUE) { - qFatal("QBB: failed to set EGL API, err=%d", eglGetError()); - } - - // Lookup EGL extension function pointer - return static_cast(eglGetProcAddress(procName.constData())); -} - -EGLint *QBBGLContext::contextAttrs() -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - // Choose EGL settings based on OpenGL version -#if defined(QT_OPENGL_ES_2) - static EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - return attrs; -#else - return 0; -#endif -} - -bool QBBGLContext::isCurrent() const -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - return (eglGetCurrentContext() == m_eglContext); -} - -void QBBGLContext::createSurface(QPlatformSurface *surface) -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // Get a pointer to the corresponding platform window - QBBWindow *platformWindow = dynamic_cast(surface); - if (!platformWindow) { - qFatal("QBB: unable to create EGLSurface without a QBBWindow"); - } - - // If the platform window does not yet have any buffers, we create - // a temporary set of buffers with a size of 1x1 pixels. This will - // suffice until such time as the platform window has obtained - // buffers of the proper size - if (!platformWindow->hasBuffers()) { - platformWindow->setPlatformOpenGLContext(this); - m_surfaceSize = platformWindow->geometry().size(); - platformWindow->setBufferSize(m_surfaceSize); - } - - // Obtain the native handle for our window - screen_window_t handle = platformWindow->nativeHandle(); - - const EGLint eglSurfaceAttrs[] = - { - EGL_RENDER_BUFFER, EGL_BACK_BUFFER, - EGL_NONE - }; - - // Create EGL surface - m_eglSurface = eglCreateWindowSurface(ms_eglDisplay, m_eglConfig, (EGLNativeWindowType) handle, eglSurfaceAttrs); - if (m_eglSurface == EGL_NO_SURFACE) { - checkEGLError("eglCreateWindowSurface"); - qFatal("QBB: failed to create EGL surface, err=%d", eglGetError()); - } -} - -void QBBGLContext::destroySurface() -{ -#if defined(QBBGLCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - // Destroy EGL surface if it exists - if (m_eglSurface != EGL_NO_SURFACE) { - EGLBoolean eglResult = eglDestroySurface(ms_eglDisplay, m_eglSurface); - if (eglResult != EGL_TRUE) { - qFatal("QBB: failed to destroy EGL surface, err=%d", eglGetError()); - } - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/blackberry/qbbglcontext.h b/src/plugins/platforms/blackberry/qbbglcontext.h deleted file mode 100644 index 8ea1df5f40..0000000000 --- a/src/plugins/platforms/blackberry/qbbglcontext.h +++ /dev/null @@ -1,93 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBGLCONTEXT_H -#define QBBGLCONTEXT_H - -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QBBWindow; - -class QBBGLContext : public QPlatformOpenGLContext -{ -public: - QBBGLContext(QOpenGLContext *glContext); - virtual ~QBBGLContext(); - - static void initialize(); - static void shutdown(); - - virtual bool makeCurrent(QPlatformSurface *surface); - virtual void doneCurrent(); - virtual void swapBuffers(QPlatformSurface *surface); - virtual QFunctionPointer getProcAddress(const QByteArray &procName); - - virtual QSurfaceFormat format() const { return m_windowFormat; } - - bool isCurrent() const; - - void createSurface(QPlatformSurface *surface); - void destroySurface(); - -private: - /** \todo Should this be non-static so we can use additional displays? */ - static EGLDisplay ms_eglDisplay; - - QSurfaceFormat m_windowFormat; - QOpenGLContext *m_glContext; - - EGLConfig m_eglConfig; - EGLContext m_eglContext; - EGLSurface m_eglSurface; - QSize m_surfaceSize; - - static EGLint *contextAttrs(); -}; - -QT_END_NAMESPACE - -#endif // QBBGLCONTEXT_H diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp b/src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp deleted file mode 100644 index fab3d3f151..0000000000 --- a/src/plugins/platforms/blackberry/qbbinputcontext_imf.cpp +++ /dev/null @@ -1,1696 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbinputcontext_imf.h" -#include "qbbeventthread.h" -#include "qbbvirtualkeyboard.h" - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include "imf/imf_client.h" -#include "imf/input_control.h" -#include -#include - -/** TODO: - Support inputMethodHints to restrict input (needs additional features in IMF). -*/ - -#define STRX(x) #x -#define STR(x) STRX(x) - -// Someone tell me why input_control methods are in this namespace, but the rest is not. -using namespace InputMethodSystem; - -#define qs(x) QString::fromLatin1(x) -#define iarg(name) event->mArgs[qs(#name)] = QVariant::fromValue(name) -#define parg(name) event->mArgs[qs(#name)] = QVariant::fromValue((void*)name) -namespace -{ - -spannable_string_t *toSpannableString(const QString &text); -static const input_session_t *sInputSession = 0; -bool isSessionOkay(input_session_t *ic) -{ - return ic !=0 && sInputSession != 0 && ic->component_id == sInputSession->component_id; -} - -enum ImfEventType -{ - ImfBeginBatchEdit, - ImfClearMetaKeyStates, - ImfCommitText, - ImfDeleteSurroundingText, - ImfEndBatchEdit, - ImfFinishComposingText, - ImfGetCursorCapsMode, - ImfGetCursorPosition, - ImfGetExtractedText, - ImfGetSelectedText, - ImfGetTextAfterCursor, - ImfGetTextBeforeCursor, - ImfPerformEditorAction, - ImfReportFullscreenMode, - ImfSendEvent, - ImfSendAsyncEvent, - ImfSetComposingRegion, - ImfSetComposingText, - ImfSetSelection -}; - -// We use this class as a round about way to support a posting synchronous event into -// Qt's main thread from the IMF thread. -class ImfEventResult -{ -public: - ImfEventResult() - { - m_mutex.lock(); - } - - ~ImfEventResult() - { - m_mutex.unlock(); - } - - void wait() - { - m_wait.wait(&m_mutex); - } - - void signal() - { - m_wait.wakeAll(); - } - - void setResult(const QVariant& result) - { - m_mutex.lock(); - m_retVal = result; - signal(); - m_mutex.unlock(); - } - - QVariant result() - { - return m_retVal; - } - -private: - QVariant m_retVal; - QMutex m_mutex; - QWaitCondition m_wait; -}; - -class ImfEvent : public QEvent -{ - public: - ImfEvent(input_session_t *session, ImfEventType type, ImfEventResult *result) : - QEvent((QEvent::Type)sUserEventType), - m_session(session), - m_imfType(type), - m_result(result) - { - } - ~ImfEvent() { } - - input_session_t *m_session; - ImfEventType m_imfType; - QVariantHash m_args; - ImfEventResult *m_result; - - static int sUserEventType; -}; -int ImfEvent::sUserEventType = QEvent::registerEventType(); - -static int32_t imfBeginBatchEdit(input_session_t *ic) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfBeginBatchEdit, &result); - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - - return ret; -} - -static int32_t imfClearMetaKeyStates(input_session_t *ic, int32_t states) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfClearMetaKeyStates, &result); - iarg(states); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - - return ret; -} - -static int32_t imfCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfCommitText, &result); - parg(text); - iarg(new_cursor_position); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - - return ret; -} - -static int32_t imfDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfDeleteSurroundingText, &result); - iarg(left_length); - iarg(right_length); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - - return ret; -} - -static int32_t imfEndBatchEdit(input_session_t *ic) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfEndBatchEdit, &result); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - - return ret; -} - -static int32_t imfFinishComposingText(input_session_t *ic) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfFinishComposingText, &result); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - - return ret; -} - -static int32_t imfGetCursorCapsMode(input_session_t *ic, int32_t req_modes) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetCursorCapsMode, &result); - iarg(req_modes); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - int32_t ret = result.result().value(); - return ret; -} - -static int32_t imfGetCursorPosition(input_session_t *ic) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetCursorPosition, &result); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - - return ret; -} - -static extracted_text_t *imfGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) { - extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1); - et->text = (spannable_string_t *)calloc(sizeof(spannable_string_t),1); - return et; - } - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetExtractedText, &result); - parg(request); - iarg(flags); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - return result.result().value(); -} - -static spannable_string_t *imfGetSelectedText(input_session_t *ic, int32_t flags) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return toSpannableString(""); - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetSelectedText, &result); - iarg(flags); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - return result.result().value(); -} - -static spannable_string_t *imfGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return toSpannableString(""); - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetTextAfterCursor, &result); - iarg(n); - iarg(flags); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - return result.result().value(); -} - -static spannable_string_t *imfGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return toSpannableString(""); - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfGetTextBeforeCursor, &result); - iarg(n); - iarg(flags); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - return result.result().value(); -} - -static int32_t imfPerformEditorAction(input_session_t *ic, int32_t editor_action) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfPerformEditorAction, &result); - iarg(editor_action); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - return ret; -} - -static int32_t imfReportFullscreenMode(input_session_t *ic, int32_t enabled) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfReportFullscreenMode, &result); - iarg(enabled); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - return ret; -} - -static int32_t imfSendEvent(input_session_t *ic, event_t *event) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEvent *imfEvent = new ImfEvent(ic, ImfSendEvent, 0); - imfEvent->m_args[qs("event")] = QVariant::fromValue(static_cast(event)); - - QCoreApplication::postEvent(QCoreApplication::instance(), imfEvent); - - return 0; -} - -static int32_t imfSendAsyncEvent(input_session_t *ic, event_t *event) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEvent *imfEvent = new ImfEvent(ic, ImfSendAsyncEvent, 0); - imfEvent->m_args[qs("event")] = QVariant::fromValue(static_cast(event)); - - QCoreApplication::postEvent(QCoreApplication::instance(), imfEvent); - - return 0; -} - -static int32_t imfSetComposingRegion(input_session_t *ic, int32_t start, int32_t end) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfSetComposingRegion, &result); - iarg(start); - iarg(end); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - return ret; -} - -static int32_t imfSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfSetComposingText, &result); - parg(text); - iarg(new_cursor_position); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - return ret; -} - -static int32_t imfSetSelection(input_session_t *ic, int32_t start, int32_t end) -{ -#if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - ImfEventResult result; - ImfEvent *event = new ImfEvent(ic, ImfSetSelection, &result); - iarg(start); - iarg(end); - - QCoreApplication::postEvent(QCoreApplication::instance(), event); - - result.wait(); - int32_t ret = result.result().value(); - return ret; -} - -static connection_interface_t ic_funcs = { - imfBeginBatchEdit, - imfClearMetaKeyStates, - imfCommitText, - imfDeleteSurroundingText, - imfEndBatchEdit, - imfFinishComposingText, - imfGetCursorCapsMode, - imfGetCursorPosition, - imfGetExtractedText, - imfGetSelectedText, - imfGetTextAfterCursor, - imfGetTextBeforeCursor, - imfPerformEditorAction, - imfReportFullscreenMode, - NULL, //ic_send_key_event - imfSendEvent, - imfSendAsyncEvent, - imfSetComposingRegion, - imfSetComposingText, - imfSetSelection, - NULL, //ic_set_candidates, -}; - -static void -initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType, int eventId) -{ - static int s_transactionId; - - // Make sure structure is squeaky clean since it's not clear just what is significant. - memset(pEvent, 0, sizeof(event_t)); - pEvent->event_type = eventType; - pEvent->event_id = eventId; - pEvent->pid = getpid(); - pEvent->component_id = pSession->component_id; - pEvent->transaction_id = ++s_transactionId; -} - -spannable_string_t *toSpannableString(const QString &text) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << text; -#endif - - spannable_string_t *pString = reinterpret_cast(malloc(sizeof(spannable_string_t))); - pString->str = (wchar_t *)malloc(sizeof(wchar_t) * text.length() + 1); - pString->length = text.length(); - pString->spans = NULL; - pString->spans_count = 0; - - const QChar *pData = text.constData(); - wchar_t *pDst = pString->str; - - while (!pData->isNull()) - { - *pDst = pData->unicode(); - pDst++; - pData++; - } - *pDst = 0; - - return pString; -} - -} // namespace - -static const input_session_t *(*p_ictrl_open_session)(connection_interface_t *) = 0; -static void (*p_ictrl_close_session)(input_session_t *) = 0; -static int32_t (*p_ictrl_dispatch_event)(event_t*) = 0; -static int32_t (*p_imf_client_init)() = 0; -static void (*p_imf_client_disconnect)() = 0; -static int32_t (*p_vkb_init_selection_service)() = 0; -static int32_t (*p_ictrl_get_num_active_sessions)() = 0; -static bool s_imfInitFailed = false; - -static bool imfAvailable() -{ - static bool s_imfDisabled = getenv("DISABLE_IMF") != NULL; - static bool s_imfReady = false; - - if ( s_imfInitFailed || s_imfDisabled) { - return false; - } - else if ( s_imfReady ) { - return true; - } - - if ( p_imf_client_init == NULL ) { - void *handle = dlopen("libinput_client.so.1", 0); - if ( handle ) { - p_imf_client_init = (int32_t (*)()) dlsym(handle, "imf_client_init"); - p_imf_client_disconnect = (void (*)()) dlsym(handle, "imf_client_disconnect"); - p_ictrl_open_session = (const input_session_t *(*)(connection_interface_t *))dlsym(handle, "ictrl_open_session"); - p_ictrl_close_session = (void (*)(input_session_t *))dlsym(handle, "ictrl_close_session"); - p_ictrl_dispatch_event = (int32_t (*)(event_t *))dlsym(handle, "ictrl_dispatch_event"); - p_vkb_init_selection_service = (int32_t (*)())dlsym(handle, "vkb_init_selection_service"); - p_ictrl_get_num_active_sessions = (int32_t (*)())dlsym(handle, "ictrl_get_num_active_sessions"); - } - else - { - qCritical() << Q_FUNC_INFO << "libinput_client.so.1 is not present - IMF services are disabled."; - s_imfDisabled = true; - return false; - } - if ( p_imf_client_init && p_ictrl_open_session && p_ictrl_dispatch_event ) { - s_imfReady = true; - } - else { - p_ictrl_open_session = NULL; - p_ictrl_dispatch_event = NULL; - s_imfDisabled = true; - qCritical() << Q_FUNC_INFO << "libinput_client.so.1 did not contain the correct symbols, library mismatch? IMF services are disabled."; - return false; - } - } - - return s_imfReady; -} - -QBBInputContext::QBBInputContext(): - QPlatformInputContext(), - m_lastCaretPos(0), - m_isComposing(false), - m_inputPanelVisible(false), - m_inputPanelLocale(QLocale::c()) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!imfAvailable()) - return; - - if ( p_imf_client_init() != 0 ) { - s_imfInitFailed = true; - qCritical("imf_client_init failed - IMF services will be unavailable"); - } - - QCoreApplication::instance()->installEventFilter(this); - - // p_vkb_init_selection_service(); - - QBBVirtualKeyboard &keyboard = QBBVirtualKeyboard::instance(); - connect(&keyboard, SIGNAL(visibilityChanged(bool)), this, SLOT(keyboardVisibilityChanged(bool))); - connect(&keyboard, SIGNAL(localeChanged(QLocale)), this, SLOT(keyboardLocaleChanged(QLocale))); - keyboardVisibilityChanged(keyboard.isVisible()); - keyboardLocaleChanged(keyboard.locale()); - - QInputMethod *inputMethod = qApp->inputMethod(); - connect(inputMethod, SIGNAL(inputItemChanged()), this, SLOT(inputItemChanged())); - -} - -QBBInputContext::~QBBInputContext() -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!imfAvailable()) - return; - - QCoreApplication::instance()->removeEventFilter(this); - p_imf_client_disconnect(); -} - -#define getarg(type, name) type name = imfEvent->mArgs[qs(#name)].value() -#define getparg(type, name) type name = (type)(imfEvent->mArgs[qs(#name)].value()) - -bool QBBInputContext::isValid() const -{ - return imfAvailable(); -} - -bool QBBInputContext::eventFilter(QObject *obj, QEvent *event) -{ - if (event->type() == ImfEvent::sUserEventType) { - // Forward the event to our real handler. - ImfEvent *imfEvent = static_cast(event); - switch (imfEvent->m_imfType) { - case ImfBeginBatchEdit: { - int32_t ret = onBeginBatchEdit(imfEvent->m_session); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfClearMetaKeyStates: { - getarg(int32_t, states); - int32_t ret = onClearMetaKeyStates(imfEvent->m_session, states); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfCommitText: { - getparg(spannable_string_t*, text); - getarg(int32_t, new_cursor_position); - int32_t ret = onCommitText(imfEvent->m_session, text, new_cursor_position); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfDeleteSurroundingText: { - getarg(int32_t, left_length); - getarg(int32_t, right_length); - int32_t ret = onDeleteSurroundingText(imfEvent->m_session, left_length, right_length); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfEndBatchEdit: { - int32_t ret = onEndBatchEdit(imfEvent->m_session); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfFinishComposingText: { - int32_t ret = onFinishComposingText(imfEvent->m_session); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfGetCursorCapsMode: { - getarg(int32_t, req_modes); - int32_t ret = onGetCursorCapsMode(imfEvent->m_session, req_modes); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfGetCursorPosition: { - int32_t ret = onGetCursorPosition(imfEvent->m_session); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfGetExtractedText: { - getparg(extracted_text_request_t*, request); - getarg(int32_t, flags); - extracted_text_t *ret = onGetExtractedText(imfEvent->m_session, request, flags); - imfEvent->m_result->setResult(QVariant::fromValue(static_cast(ret))); - break; - } - - case ImfGetSelectedText: { - getarg(int32_t, flags); - spannable_string_t *ret = onGetSelectedText(imfEvent->m_session, flags); - imfEvent->m_result->setResult(QVariant::fromValue(static_cast(ret))); - break; - } - - case ImfGetTextAfterCursor: { - getarg(int32_t, n); - getarg(int32_t, flags); - spannable_string_t *ret = onGetTextAfterCursor(imfEvent->m_session, n, flags); - imfEvent->m_result->setResult(QVariant::fromValue(static_cast(ret))); - break; - } - - case ImfGetTextBeforeCursor: { - getarg(int32_t, n); - getarg(int32_t, flags); - spannable_string_t *ret = onGetTextBeforeCursor(imfEvent->m_session, n, flags); - imfEvent->m_result->setResult(QVariant::fromValue((void*)ret)); - break; - } - - case ImfPerformEditorAction: { - getarg(int32_t, editor_action); - int32_t ret = onPerformEditorAction(imfEvent->m_session, editor_action); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfReportFullscreenMode: { - getarg(int32_t, enabled); - int32_t ret = onReportFullscreenMode(imfEvent->m_session, enabled); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfSendEvent: { - getparg(event_t*, event); - onSendEvent(imfEvent->m_session, event); - break; - } - - case ImfSendAsyncEvent: { - getparg(event_t*, event); - onSendAsyncEvent(imfEvent->m_session, event); - break; - } - - case ImfSetComposingRegion: { - getarg(int32_t, start); - getarg(int32_t, end); - int32_t ret = onSetComposingRegion(imfEvent->m_session, start, end); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfSetComposingText: { - getparg(spannable_string_t*, text); - getarg(int32_t, new_cursor_position); - int32_t ret = onSetComposingText(imfEvent->m_session, text, new_cursor_position); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - - case ImfSetSelection: { - getarg(int32_t, start); - getarg(int32_t, end); - int32_t ret = onSetSelection(imfEvent->m_session, start, end); - imfEvent->m_result->setResult(QVariant::fromValue(ret)); - break; - } - }; //switch - - return true; - } else { - // standard event processing - return QObject::eventFilter(obj, event); - } -} - -bool QBBInputContext::filterEvent( const QEvent *event ) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << event; -#endif - switch (event->type()) { - case QEvent::CloseSoftwareInputPanel: { - return dispatchCloseSoftwareInputPanel(); - } - case QEvent::RequestSoftwareInputPanel: { - return dispatchRequestSoftwareInputPanel(); - } - default: - return false; - } -} - -void QBBInputContext::reset() -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - endComposition(); -} - -void QBBInputContext::update(Qt::InputMethodQueries queries) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - reset(); - - QPlatformInputContext::update(queries); -} - -void QBBInputContext::closeSession() -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO -#endif - if (!imfAvailable()) - return; - - if (sInputSession) { - p_ictrl_close_session((input_session_t *)sInputSession); - sInputSession = 0; - } -} - -void QBBInputContext::openSession() -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO -#endif - if (!imfAvailable()) - return; - - closeSession(); - sInputSession = p_ictrl_open_session(&ic_funcs); -} - -bool QBBInputContext::hasSession() -{ - return sInputSession != 0; -} - -bool QBBInputContext::hasSelectedText() -{ - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!input) - return false; - - QInputMethodQueryEvent query(Qt::ImCurrentSelection); - QCoreApplication::sendEvent(input, &query); - - return !query.value(Qt::ImCurrentSelection).toString().isEmpty(); -} - -bool QBBInputContext::dispatchRequestSoftwareInputPanel() -{ - QBBVirtualKeyboard::instance().showKeyboard(); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << "QBB: requesting virtual keyboard"; -#endif - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return true; - - if (!hasSession()) - openSession(); - - // This also means that the caret position has moved - QInputMethodQueryEvent query(Qt::ImCursorPosition); - QCoreApplication::sendEvent(input, &query); - int caretPos = query.value(Qt::ImCursorPosition).toInt(); - caret_event_t caretEvent; - memset(&caretEvent, 0, sizeof(caret_event_t)); - initEvent(&caretEvent.event, sInputSession, EVENT_CARET, CARET_POS_CHANGED); - caretEvent.old_pos = m_lastCaretPos; - m_lastCaretPos = caretEvent.new_pos = caretPos; - p_ictrl_dispatch_event((event_t *)&caretEvent); - return true; -} - -bool QBBInputContext::dispatchCloseSoftwareInputPanel() -{ - QBBVirtualKeyboard::instance().hideKeyboard(); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << "QBB: hiding virtual keyboard"; -#endif - - // This also means we are stopping composition, but we should already have done that. - return true; -} - -/** - * IMF Event Dispatchers. - */ -bool QBBInputContext::dispatchFocusEvent(FocusEventId id, int hints) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!sInputSession) { - qWarning() << Q_FUNC_INFO << "Attempt to dispatch a focus event with no input session."; - return false; - } - - if (!imfAvailable()) - return false; - - // Set the last caret position to 0 since we don't really have one and we don't - // want to have the old one. - m_lastCaretPos = 0; - - focus_event_t focusEvent; - memset(&focusEvent, 0, sizeof(focusEvent)); - initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, id); - focusEvent.style = DEFAULT_STYLE; - - if (hints && Qt::ImhNoPredictiveText) - focusEvent.style |= NO_PREDICTION | NO_AUTO_CORRECTION; - if (hints && Qt::ImhNoAutoUppercase) - focusEvent.style |= NO_AUTO_TEXT; - - p_ictrl_dispatch_event((event_t *)&focusEvent); - - return true; -} - -bool QBBInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap) -{ - if (!imfAvailable()) - return false; - - int key = (flags & KEY_SYM_VALID) ? sym : cap; - bool navKey = false; - switch ( key ) { - case KEYCODE_RETURN: - /* In a single line edit we should end composition because enter might be used by something. - endComposition(); - return false;*/ - break; - - case KEYCODE_BACKSPACE: - case KEYCODE_DELETE: - // If there is a selection range, then we want a delete key to operate on that (by - // deleting the contents of the select range) rather than operating on the composition - // range. - if (hasSelectedText()) - return false; - break; - case KEYCODE_LEFT: - key = NAVIGATE_LEFT; - navKey = true; - break; - case KEYCODE_RIGHT: - key = NAVIGATE_RIGHT; - navKey = true; - break; - case KEYCODE_UP: - key = NAVIGATE_UP; - navKey = true; - break; - case KEYCODE_DOWN: - key = NAVIGATE_DOWN; - navKey = true; - break; - case KEYCODE_CAPS_LOCK: - case KEYCODE_LEFT_SHIFT: - case KEYCODE_RIGHT_SHIFT: - case KEYCODE_LEFT_CTRL: - case KEYCODE_RIGHT_CTRL: - case KEYCODE_LEFT_ALT: - case KEYCODE_RIGHT_ALT: - case KEYCODE_MENU: - case KEYCODE_LEFT_HYPER: - case KEYCODE_RIGHT_HYPER: - case KEYCODE_INSERT: - case KEYCODE_HOME: - case KEYCODE_PG_UP: - case KEYCODE_END: - case KEYCODE_PG_DOWN: - // Don't send these - key = 0; - break; - } - - if ( mod & KEYMOD_CTRL ) { - // If CTRL is pressed, just let AIR handle it. But terminate any composition first - //endComposition(); - return false; - } - - // Pass the keys we don't know about on through - if ( key == 0 ) - return false; - - // IMF doesn't need key releases so just swallow them. - if (!(flags & KEY_DOWN)) - return true; - - if ( navKey ) { - // Even if we're forwarding up events, we can't do this for - // navigation keys. - if ( flags & KEY_DOWN ) { - navigation_event_t navEvent; - initEvent(&navEvent.event, sInputSession, EVENT_NAVIGATION, key); - navEvent.magnitude = 1; -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "dispatch navigation event " << key; -#endif - p_ictrl_dispatch_event(&navEvent.event); - } - } - else { - key_event_t keyEvent; - initEvent(&keyEvent.event, sInputSession, EVENT_KEY, flags & KEY_DOWN ? IMF_KEY_DOWN : IMF_KEY_UP); - keyEvent.key_code = key; - keyEvent.character = 0; - keyEvent.meta_key_state = 0; - - p_ictrl_dispatch_event(&keyEvent.event); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "dispatch key event " << key; -#endif - } - - scan = 0; - return true; -} - -void QBBInputContext::endComposition() -{ - if (!m_isComposing) - return; - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return; - - QList attributes; - QInputMethodEvent event(QLatin1String(""), attributes); - event.setCommitString(m_composingText); - m_composingText = QString(); - m_isComposing = false; - QCoreApplication::sendEvent(input, &event); - - action_event_t actionEvent; - memset(&actionEvent, 0, sizeof(actionEvent)); - initEvent(&actionEvent.event, sInputSession, EVENT_ACTION, ACTION_END_COMPOSITION); - p_ictrl_dispatch_event(&actionEvent.event); -} - -void QBBInputContext::setComposingText(QString const& composingText) -{ - m_composingText = composingText; - m_isComposing = true; - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return; - - QList attributes; - QTextCharFormat format; - format.setFontUnderline(true); - attributes.push_back(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, composingText.length(), format)); - - QInputMethodEvent event(composingText, attributes); - - QCoreApplication::sendEvent(input, &event); -} - -int32_t QBBInputContext::processEvent(event_t *event) -{ - int32_t result = -1; - switch (event->event_type) { - case EVENT_SPELL_CHECK: { - #if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "EVENT_SPELL_CHECK"; - #endif - result = 0; - break; - } - - case EVENT_NAVIGATION: { - #if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "EVENT_NAVIGATION"; - #endif - - int key = event->event_id == NAVIGATE_UP ? KEYCODE_UP : - event->event_id == NAVIGATE_DOWN ? KEYCODE_DOWN : - event->event_id == NAVIGATE_LEFT ? KEYCODE_LEFT : - event->event_id == NAVIGATE_RIGHT ? KEYCODE_RIGHT : 0; - - QBBEventThread::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, key, 0, 0, 0); - QBBEventThread::injectKeyboardEvent(KEY_CAP_VALID, key, 0, 0, 0); - result = 0; - break; - } - - case EVENT_KEY: { - #if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "EVENT_KEY"; - #endif - key_event_t *kevent = static_cast(event); - - QBBEventThread::injectKeyboardEvent(KEY_DOWN | KEY_SYM_VALID | KEY_CAP_VALID, kevent->key_code, 0, 0, kevent->key_code); - QBBEventThread::injectKeyboardEvent(KEY_SYM_VALID | KEY_CAP_VALID, kevent->key_code, 0, 0, kevent->key_code); - - result = 0; - break; - } - - case EVENT_ACTION: - // Don't care, indicates that IMF is done. - break; - - case EVENT_CARET: - case EVENT_NOTHING: - case EVENT_FOCUS: - case EVENT_USER_ACTION: - case EVENT_STROKE: - case EVENT_INVOKE_LATER: - qCritical() << Q_FUNC_INFO << "Unsupported event type: " << event->event_type; - break; - default: - qCritical() << Q_FUNC_INFO << "Unknown event type: " << event->event_type; - } - return result; -} - -/** - * IMF Event Handlers - */ - -int32_t QBBInputContext::onBeginBatchEdit(input_session_t *ic) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - // We don't care. - return 0; -} - -int32_t QBBInputContext::onClearMetaKeyStates(input_session_t *ic, int32_t states) -{ - Q_UNUSED(states); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - // Should never get called. - qCritical() << Q_FUNC_INFO << "onClearMetaKeyStates is unsupported."; - return 0; -} - -int32_t QBBInputContext::onCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) -{ - Q_UNUSED(new_cursor_position); // TODO: How can we set the cursor position it's not part of the API. - if (!isSessionOkay(ic)) - return 0; - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return 0; - - QString commitString = QString::fromWCharArray(text->str, text->length); - -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "Committing [" << commitString << "]"; -#endif - - QList attributes; - QInputMethodEvent event(QLatin1String(""), attributes); - event.setCommitString(commitString, 0, 0); - - QCoreApplication::sendEvent(input, &event); - m_composingText = QString(); - - return 0; -} - -int32_t QBBInputContext::onDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "L:" << left_length << " R:" << right_length; -#endif - - if (!isSessionOkay(ic)) - return 0; - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return 0; - - if (hasSelectedText()) { - QBBEventThread::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, KEYCODE_DELETE, 0, 0, 0); - QBBEventThread::injectKeyboardEvent(KEY_CAP_VALID, KEYCODE_DELETE, 0, 0, 0); - reset(); - return 0; - } - - int replacementLength = left_length + right_length; - int replacementStart = -left_length; - - QList attributes; - QInputMethodEvent event(QLatin1String(""), attributes); - event.setCommitString(QLatin1String(""), replacementStart, replacementLength); - QCoreApplication::sendEvent(input, &event); - - return 0; -} - -int32_t QBBInputContext::onEndBatchEdit(input_session_t *ic) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - return 0; -} - -int32_t QBBInputContext::onFinishComposingText(input_session_t *ic) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return 0; - - // Only update the control, no need to send a message back to imf (don't call - // end composition) - QList attributes; - QInputMethodEvent event(QLatin1String(""), attributes); - event.setCommitString(m_composingText); - m_composingText = QString(); - m_isComposing = false; - QCoreApplication::sendEvent(input, &event); - - return 0; -} - -int32_t QBBInputContext::onGetCursorCapsMode(input_session_t *ic, int32_t req_modes) -{ - Q_UNUSED(req_modes); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - // Should never get called. - qCritical() << Q_FUNC_INFO << "onGetCursorCapsMode is unsupported."; - - return 0; -} - -int32_t QBBInputContext::onGetCursorPosition(input_session_t *ic) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return 0; - - QInputMethodQueryEvent query(Qt::ImCursorPosition); - QCoreApplication::sendEvent(input, &query); - m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); - - return m_lastCaretPos; -} - -extracted_text_t *QBBInputContext::onGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags) -{ - Q_UNUSED(flags); - Q_UNUSED(request); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) { - extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1); - et->text = reinterpret_cast(calloc(sizeof(spannable_string_t),1)); - return et; - } - - // Used to update dictionaries, but not supported right now. - extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1); - et->text = reinterpret_cast(calloc(sizeof(spannable_string_t),1)); - - return et; -} - -spannable_string_t *QBBInputContext::onGetSelectedText(input_session_t *ic, int32_t flags) -{ - Q_UNUSED(flags); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return toSpannableString(""); - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return 0; - - QInputMethodQueryEvent query(Qt::ImCurrentSelection); - QCoreApplication::sendEvent(input, &query); - QString text = query.value(Qt::ImCurrentSelection).toString(); - - return toSpannableString(text); -} - -spannable_string_t *QBBInputContext::onGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags) -{ - Q_UNUSED(flags); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return toSpannableString(""); - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return toSpannableString(""); - - QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText); - QCoreApplication::sendEvent(input, &query); - QString text = query.value(Qt::ImSurroundingText).toString(); - m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); - - return toSpannableString(text.mid(m_lastCaretPos+1, n)); -} - -spannable_string_t *QBBInputContext::onGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags) -{ - Q_UNUSED(flags); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return toSpannableString(""); - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return toSpannableString(""); - - QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText); - QCoreApplication::sendEvent(input, &query); - QString text = query.value(Qt::ImSurroundingText).toString(); - m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); - - if (n < m_lastCaretPos) { - return toSpannableString(text.mid(m_lastCaretPos - n, n)); - } else { - return toSpannableString(text.mid(0, m_lastCaretPos)); - } -} - -int32_t QBBInputContext::onPerformEditorAction(input_session_t *ic, int32_t editor_action) -{ - Q_UNUSED(editor_action); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - // Should never get called. - qCritical() << Q_FUNC_INFO << "onPerformEditorAction is unsupported."; - - return 0; -} - -int32_t QBBInputContext::onReportFullscreenMode(input_session_t *ic, int32_t enabled) -{ - Q_UNUSED(enabled); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - // Should never get called. - qCritical() << Q_FUNC_INFO << "onReportFullscreenMode is unsupported."; - - return 0; -} - -int32_t QBBInputContext::onSendEvent(input_session_t *ic, event_t *event) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - return processEvent(event); -} - -int32_t QBBInputContext::onSendAsyncEvent(input_session_t *ic, event_t *event) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - return processEvent(event); -} - -int32_t QBBInputContext::onSetComposingRegion(input_session_t *ic, int32_t start, int32_t end) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return 0; - - QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText); - QCoreApplication::sendEvent(input, &query); - QString text = query.value(Qt::ImSurroundingText).toString(); - m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); - - QString empty = QString::fromLatin1(""); - text = text.mid(start, end - start); - - // Delete the current text. - QList attributes; - QInputMethodEvent event(empty, attributes); - event.setCommitString(empty, start - m_lastCaretPos, end - start); - QCoreApplication::sendEvent(input, &event); - - // Move the specified text into a preedit string. - setComposingText(text); - - return 0; -} - -int32_t QBBInputContext::onSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) -{ - Q_UNUSED(new_cursor_position); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - QInputPanel *panel = qApp->inputPanel(); - QObject *input = panel->inputItem(); - if (!imfAvailable() || !input) - return 0; - - m_isComposing = true; - - QString preeditString = QString::fromWCharArray(text->str, text->length); - setComposingText(preeditString); - - return 0; -} - -int32_t QBBInputContext::onSetSelection(input_session_t *ic, int32_t start, int32_t end) -{ - Q_UNUSED(start); - Q_UNUSED(end); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - - if (!isSessionOkay(ic)) - return 0; - - // Should never get called. - qCritical() << Q_FUNC_INFO << "onSetSelection is unsupported."; - - return 0; -} - -void QBBInputContext::showInputPanel() -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - dispatchRequestSoftwareInputPanel(); -} - -void QBBInputContext::hideInputPanel() -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - dispatchCloseSoftwareInputPanel(); -} - -bool QBBInputContext::isInputPanelVisible() const -{ - return m_inputPanelVisible; -} - -QLocale QBBInputContext::locale() const -{ - return m_inputPanelLocale; -} - -void QBBInputContext::keyboardVisibilityChanged(bool visible) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "visible=" << visible; -#endif - if (m_inputPanelVisible != visible) { - m_inputPanelVisible = visible; - emitInputPanelVisibleChanged(); - } -} - -void QBBInputContext::keyboardLocaleChanged(const QLocale &locale) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "locale=" << locale; -#endif - if (m_inputPanelLocale != locale) { - m_inputPanelLocale = locale; - emitLocaleChanged(); - } -} - -void QBBInputContext::inputItemChanged() -{ - QInputMethod *inputMethod = qApp->inputMethod(); - QObject *inputItem = inputMethod->inputItem(); - -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "input item=" << inputItem; -#endif - - if (!inputItem) { - if (m_inputPanelVisible) - hideInputPanel(); - } else { - if (qobject_cast(inputItem)) { - QBBVirtualKeyboard::instance().setKeyboardMode(QBBVirtualKeyboard::NumPunc); - } else { - QBBVirtualKeyboard::instance().setKeyboardMode(QBBVirtualKeyboard::Default); - } - if (!m_inputPanelVisible) - showInputPanel(); - } -} diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_imf.h b/src/plugins/platforms/blackberry/qbbinputcontext_imf.h deleted file mode 100644 index 135ec02971..0000000000 --- a/src/plugins/platforms/blackberry/qbbinputcontext_imf.h +++ /dev/null @@ -1,132 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBINPUTCONTEXT_H -#define QBBINPUTCONTEXT_H - -#include - -#include -#include -#include - -#include "imf/imf_client.h" -#include "imf/input_control.h" - -QT_BEGIN_NAMESPACE - -class QBBInputContext : public QPlatformInputContext -{ - Q_OBJECT -public: - QBBInputContext(); - ~QBBInputContext(); - - virtual bool isValid() const; - - virtual bool filterEvent(const QEvent *event); - virtual void reset(); - virtual void update(Qt::InputMethodQueries); - bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap); - - virtual void showInputPanel(); - virtual void hideInputPanel(); - virtual bool isInputPanelVisible() const; - - virtual QLocale locale() const; - -protected: - // Filters only for IMF events. - bool eventFilter(QObject *obj, QEvent *event); - -private Q_SLOTS: - void keyboardVisibilityChanged(bool visible); - void keyboardLocaleChanged(const QLocale &locale); - void inputItemChanged(); - -private: - // IMF Event dispatchers - bool dispatchFocusEvent(FocusEventId id, int hints = Qt::ImhNone); - bool dispatchRequestSoftwareInputPanel(); - bool dispatchCloseSoftwareInputPanel(); - int32_t processEvent(event_t *event); - - void closeSession(); - void openSession(); - bool hasSession(); - void endComposition(); - void setComposingText(QString const &composingText); - bool hasSelectedText(); - - // IMF Event handlers - these events will come in from QCoreApplication. - int32_t onBeginBatchEdit(input_session_t *ic); - int32_t onClearMetaKeyStates(input_session_t *ic, int32_t states); - int32_t onCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position); - int32_t onDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length); - int32_t onEndBatchEdit(input_session_t *ic); - int32_t onFinishComposingText(input_session_t *ic); - int32_t onGetCursorCapsMode(input_session_t *ic, int32_t req_modes); - int32_t onGetCursorPosition(input_session_t *ic); - extracted_text_t *onGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags); - spannable_string_t *onGetSelectedText(input_session_t *ic, int32_t flags); - spannable_string_t *onGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags); - spannable_string_t *onGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags); - int32_t onPerformEditorAction(input_session_t *ic, int32_t editor_action); - int32_t onReportFullscreenMode(input_session_t *ic, int32_t enabled); - int32_t onSendEvent(input_session_t *ic, event_t *event); - int32_t onSendAsyncEvent(input_session_t *ic, event_t *event); - int32_t onSetComposingRegion(input_session_t *ic, int32_t start, int32_t end); - int32_t onSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position); - int32_t onSetSelection(input_session_t *ic, int32_t start, int32_t end); - int32_t onForceUpdate(); - - int m_lastCaretPos; - bool m_isComposing; - QString m_composingText; - bool m_inputPanelVisible; - QLocale m_inputPanelLocale; -}; - -Q_DECLARE_METATYPE(extracted_text_t*) - -QT_END_NAMESPACE - -#endif // QBBINPUTCONTEXT_H diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_noimf.cpp b/src/plugins/platforms/blackberry/qbbinputcontext_noimf.cpp deleted file mode 100644 index abe84e2e53..0000000000 --- a/src/plugins/platforms/blackberry/qbbinputcontext_noimf.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbinputcontext_noimf.h" -#include "qbbvirtualkeyboard.h" - -#include -#include -#include - -QBBInputContext::QBBInputContext() : - QPlatformInputContext(), - m_inputPanelVisible(false), - m_inputPanelLocale(QLocale::c()) -{ - QBBVirtualKeyboard &keyboard = QBBVirtualKeyboard::instance(); - connect(&keyboard, SIGNAL(visibilityChanged(bool)), this, SLOT(keyboardVisibilityChanged(bool))); - connect(&keyboard, SIGNAL(localeChanged(QLocale)), this, SLOT(keyboardLocaleChanged(QLocale))); - keyboardVisibilityChanged(keyboard.isVisible()); - keyboardLocaleChanged(keyboard.locale()); - - QInputMethod *inputMethod = qApp->inputMethod(); - connect(inputMethod, SIGNAL(inputItemChanged()), this, SLOT(inputItemChanged())); -} - -QBBInputContext::~QBBInputContext() -{ -} - -bool QBBInputContext::isValid() const -{ - return true; -} - -bool QBBInputContext::hasPhysicalKeyboard() -{ - // TODO: This should query the system to check if a USB keyboard is connected. - return false; -} - -void QBBInputContext::reset() -{ -} - -bool QBBInputContext::filterEvent( const QEvent *event ) -{ - if (hasPhysicalKeyboard()) - return false; - - if (event->type() == QEvent::CloseSoftwareInputPanel) { - QBBVirtualKeyboard::instance().hideKeyboard(); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << "QBB: hiding virtual keyboard"; -#endif - return false; - } - - if (event->type() == QEvent::RequestSoftwareInputPanel) { - QBBVirtualKeyboard::instance().showKeyboard(); -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << "QBB: requesting virtual keyboard"; -#endif - return false; - } - - return false; - -} - -bool QBBInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap) -{ - Q_UNUSED(flags); - Q_UNUSED(sym); - Q_UNUSED(mod); - Q_UNUSED(scan); - Q_UNUSED(cap); - return false; -} - -void QBBInputContext::showInputPanel() -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - QBBVirtualKeyboard::instance().showKeyboard(); -} - -void QBBInputContext::hideInputPanel() -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - QBBVirtualKeyboard::instance().hideKeyboard(); -} - -bool QBBInputContext::isInputPanelVisible() const -{ - return m_inputPanelVisible; -} - -QLocale QBBInputContext::locale() const -{ - return m_inputPanelLocale; -} - -void QBBInputContext::keyboardVisibilityChanged(bool visible) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "visible=" << visible; -#endif - if (m_inputPanelVisible != visible) { - m_inputPanelVisible = visible; - emitInputPanelVisibleChanged(); - } -} - -void QBBInputContext::keyboardLocaleChanged(const QLocale &locale) -{ -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "locale=" << locale; -#endif - if (m_inputPanelLocale != locale) { - m_inputPanelLocale = locale; - emitLocaleChanged(); - } -} - -void QBBInputContext::inputItemChanged() -{ - QInputMethod *inputMethod = qApp->inputMethod(); - QObject *inputItem = inputMethod->inputItem(); - -#if defined(QBBINPUTCONTEXT_DEBUG) - qDebug() << Q_FUNC_INFO << "input item=" << inputItem; -#endif - - if (!inputItem) { - if (m_inputPanelVisible) - hideInputPanel(); - } else { - if (qobject_cast(inputItem)) { - QBBVirtualKeyboard::instance().setKeyboardMode(QBBVirtualKeyboard::NumPunc); - } else { - QBBVirtualKeyboard::instance().setKeyboardMode(QBBVirtualKeyboard::Default); - } - if (!m_inputPanelVisible) - showInputPanel(); - } -} diff --git a/src/plugins/platforms/blackberry/qbbinputcontext_noimf.h b/src/plugins/platforms/blackberry/qbbinputcontext_noimf.h deleted file mode 100644 index 3d4d6da830..0000000000 --- a/src/plugins/platforms/blackberry/qbbinputcontext_noimf.h +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBINPUTCONTEXT_H -#define QBBINPUTCONTEXT_H - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QBBInputContext : public QPlatformInputContext -{ - Q_OBJECT -public: - explicit QBBInputContext(); - ~QBBInputContext(); - - virtual bool isValid() const; - - void reset(); - virtual bool filterEvent( const QEvent *event ); - bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap); - - virtual void showInputPanel(); - virtual void hideInputPanel(); - virtual bool isInputPanelVisible() const; - - virtual QLocale locale() const; - -private Q_SLOTS: - void keyboardVisibilityChanged(bool visible); - void keyboardLocaleChanged(const QLocale &locale); - void inputItemChanged(); - -private: - bool hasPhysicalKeyboard(); - - bool m_inputPanelVisible; - QLocale m_inputPanelLocale; -}; - -QT_END_NAMESPACE - -#endif // QBBINPUTCONTEXT_H diff --git a/src/plugins/platforms/blackberry/qbbintegration.cpp b/src/plugins/platforms/blackberry/qbbintegration.cpp deleted file mode 100644 index 9f922a419e..0000000000 --- a/src/plugins/platforms/blackberry/qbbintegration.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbintegration.h" -#include "qbbeventthread.h" -#include "qbbglbackingstore.h" -#include "qbbglcontext.h" -#include "qbbnavigatorthread.h" -#include "qbbrasterbackingstore.h" -#include "qbbscreen.h" -#include "qbbwindow.h" -#include "qbbvirtualkeyboard.h" -#include "qbbclipboard.h" -#include "qbbglcontext.h" - -#if defined(QBB_IMF) -#include "qbbinputcontext_imf.h" -#else -#include "qbbinputcontext_noimf.h" -#endif - -#include "private/qgenericunixfontdatabase_p.h" -#include "private/qgenericunixeventdispatcher_p.h" - -#include -#include -#include - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -QBBWindowMapper QBBIntegration::ms_windowMapper; -QMutex QBBIntegration::ms_windowMapperMutex; - -QBBIntegration::QBBIntegration() - : QPlatformIntegration() - , m_eventThread(0) - , m_navigatorThread(0) - , m_inputContext(0) - , m_fontDatabase(new QGenericUnixFontDatabase()) - , m_paintUsingOpenGL(false) - , m_eventDispatcher(createUnixEventDispatcher()) -#ifndef QT_NO_CLIPBOARD - , m_clipboard(0) -#endif -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // Open connection to QNX composition manager - errno = 0; - int result = screen_create_context(&m_screenContext, SCREEN_APPLICATION_CONTEXT); - if (result != 0) { - qFatal("QBB: failed to connect to composition manager, errno=%d", errno); - } - - // Create displays for all possible screens (which may not be attached) - QBBScreen::createDisplays(m_screenContext); - Q_FOREACH (QPlatformScreen *screen, QBBScreen::screens()) { - screenAdded(screen); - } - - // Initialize global OpenGL resources - QBBGLContext::initialize(); - - // Create/start event thread - m_eventThread = new QBBEventThread(m_screenContext, *QBBScreen::primaryDisplay()); - m_eventThread->start(); - - // Create/start navigator thread - m_navigatorThread = new QBBNavigatorThread(*QBBScreen::primaryDisplay()); - m_navigatorThread->start(); - - // Create/start the keyboard class. - QBBVirtualKeyboard::instance(); - - // Set up the input context - m_inputContext = new QBBInputContext; -} - -QBBIntegration::~QBBIntegration() -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << "QBB: platform plugin shutdown begin"; -#endif - // Destroy the keyboard class. - QBBVirtualKeyboard::destroy(); - -#ifndef QT_NO_CLIPBOARD - // Delete the clipboard - delete m_clipboard; -#endif - - // Stop/destroy event thread - delete m_eventThread; - - // Stop/destroy navigator thread - delete m_navigatorThread; - - // Destroy all displays - QBBScreen::destroyDisplays(); - - // Close connection to QNX composition manager - screen_destroy_context(m_screenContext); - - // Cleanup global OpenGL resources - QBBGLContext::shutdown(); - -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << "QBB: platform plugin shutdown end"; -#endif -} - -bool QBBIntegration::hasCapability(QPlatformIntegration::Capability cap) const -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - switch (cap) { - case ThreadedPixmaps: return true; -#if defined(QT_OPENGL_ES) - case OpenGL: - return true; -#endif - default: return QPlatformIntegration::hasCapability(cap); - } -} - -QPlatformWindow *QBBIntegration::createPlatformWindow(QWindow *window) const -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // New windows are created on the primary display. - return new QBBWindow(window, m_screenContext); -} - -QPlatformBackingStore *QBBIntegration::createPlatformBackingStore(QWindow *window) const -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - if (paintUsingOpenGL()) - return new QBBGLBackingStore(window); - else - return new QBBRasterBackingStore(window); -} - -QPlatformOpenGLContext *QBBIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - return new QBBGLContext(context); -} - -QPlatformInputContext *QBBIntegration::inputContext() const -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - return m_inputContext; -} - -void QBBIntegration::moveToScreen(QWindow *window, int screen) -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << "QBBIntegration::moveToScreen - w=" << window << ", s=" << screen; -#endif - - // get platform window used by widget - QBBWindow *platformWindow = static_cast(window->handle()); - - // lookup platform screen by index - QBBScreen *platformScreen = static_cast(QBBScreen::screens().at(screen)); - - // move the platform window to the platform screen - platformWindow->setScreen(platformScreen); -} - -QList QBBIntegration::screens() const -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - return QBBScreen::screens(); -} - -QAbstractEventDispatcher *QBBIntegration::guiThreadEventDispatcher() const -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - return m_eventDispatcher; -} - -#ifndef QT_NO_CLIPBOARD -QPlatformClipboard *QBBIntegration::clipboard() const -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - if (!m_clipboard) { - m_clipboard = new QBBClipboard; - } - return m_clipboard; -} -#endif - -QVariant QBBIntegration::styleHint(QPlatformIntegration::StyleHint hint) const -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - if (hint == ShowIsFullScreen) - return true; - - return QPlatformIntegration::styleHint(hint); -} - -QWindow *QBBIntegration::window(screen_window_t qnxWindow) -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - QMutexLocker locker(&ms_windowMapperMutex); - Q_UNUSED(locker); - return ms_windowMapper.value(qnxWindow, 0); -} - -void QBBIntegration::addWindow(screen_window_t qnxWindow, QWindow *window) -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - QMutexLocker locker(&ms_windowMapperMutex); - Q_UNUSED(locker); - ms_windowMapper.insert(qnxWindow, window); -} - -void QBBIntegration::removeWindow(screen_window_t qnxWindow) -{ -#if defined(QBBINTEGRATION_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - QMutexLocker locker(&ms_windowMapperMutex); - Q_UNUSED(locker); - ms_windowMapper.remove(qnxWindow); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/blackberry/qbbintegration.h b/src/plugins/platforms/blackberry/qbbintegration.h deleted file mode 100644 index 6b54329dac..0000000000 --- a/src/plugins/platforms/blackberry/qbbintegration.h +++ /dev/null @@ -1,119 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBINTEGRATION_H -#define QBBINTEGRATION_H - -#include - -#include - -#include - -QT_BEGIN_NAMESPACE - -class QBBEventThread; -class QBBInputContext; -class QBBNavigatorThread; -class QBBWindow; - -#ifndef QT_NO_CLIPBOARD -class QBBClipboard; -#endif - -template class QHash; -typedef QHash QBBWindowMapper; - -class QBBIntegration : public QPlatformIntegration -{ -public: - QBBIntegration(); - virtual ~QBBIntegration(); - - virtual bool hasCapability(QPlatformIntegration::Capability cap) const; - - virtual QPlatformWindow *createPlatformWindow(QWindow *window) const; - virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; - virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; - - virtual QPlatformInputContext *inputContext() const; - - virtual QList screens() const; - virtual void moveToScreen(QWindow *window, int screen); - - virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const; - - virtual QPlatformFontDatabase *fontDatabase() const { return m_fontDatabase; } - -#ifndef QT_NO_CLIPBOARD - virtual QPlatformClipboard *clipboard() const; -#endif - - virtual QVariant styleHint(StyleHint hint) const; - - bool paintUsingOpenGL() const { return m_paintUsingOpenGL; } - - static QWindow *window(screen_window_t qnxWindow); - -private: - static void addWindow(screen_window_t qnxWindow, QWindow *window); - static void removeWindow(screen_window_t qnxWindow); - - screen_context_t m_screenContext; - QBBEventThread *m_eventThread; - QBBNavigatorThread *m_navigatorThread; - QBBInputContext *m_inputContext; - QPlatformFontDatabase *m_fontDatabase; - bool m_paintUsingOpenGL; - QAbstractEventDispatcher *m_eventDispatcher; -#ifndef QT_NO_CLIPBOARD - mutable QBBClipboard* m_clipboard; -#endif - - static QBBWindowMapper ms_windowMapper; - static QMutex ms_windowMapperMutex; - - friend class QBBWindow; -}; - -QT_END_NAMESPACE - -#endif // QBBINTEGRATION_H diff --git a/src/plugins/platforms/blackberry/qbbkeytranslator.h b/src/plugins/platforms/blackberry/qbbkeytranslator.h deleted file mode 100644 index fdc1220aba..0000000000 --- a/src/plugins/platforms/blackberry/qbbkeytranslator.h +++ /dev/null @@ -1,269 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBKEYTRANSLATOR_H -#define QBBKEYTRANSLATOR_H - -#include - -#if defined(QBBEVENTTHREAD_DEBUG) -#include -#endif - -QT_BEGIN_NAMESPACE - -Qt::Key keyTranslator( int key ) -{ - switch (key) { - case KEYCODE_PAUSE: - return Qt::Key_Pause; - - case KEYCODE_SCROLL_LOCK: - return Qt::Key_ScrollLock; - - case KEYCODE_PRINT: - return Qt::Key_Print; - - case KEYCODE_SYSREQ: - return Qt::Key_SysReq; - -// case KEYCODE_BREAK: - - case KEYCODE_ESCAPE: - return Qt::Key_Escape; - - case KEYCODE_BACKSPACE: - return Qt::Key_Backspace; - - case KEYCODE_TAB: - return Qt::Key_Tab; - - case KEYCODE_BACK_TAB: - return Qt::Key_Backtab; - - case KEYCODE_RETURN: - return Qt::Key_Return; - - case KEYCODE_CAPS_LOCK: - return Qt::Key_CapsLock; - - case KEYCODE_LEFT_SHIFT: - case KEYCODE_RIGHT_SHIFT: - return Qt::Key_Shift; - - case KEYCODE_LEFT_CTRL: - case KEYCODE_RIGHT_CTRL: - return Qt::Key_Control; - - case KEYCODE_LEFT_ALT: - case KEYCODE_RIGHT_ALT: - return Qt::Key_Alt; - - case KEYCODE_MENU: - return Qt::Key_Menu; - - case KEYCODE_LEFT_HYPER: - return Qt::Key_Hyper_L; - - case KEYCODE_RIGHT_HYPER: - return Qt::Key_Hyper_R; - - case KEYCODE_INSERT: - return Qt::Key_Insert; - - case KEYCODE_HOME: - return Qt::Key_Home; - - case KEYCODE_PG_UP: - return Qt::Key_PageUp; - - case KEYCODE_DELETE: - return Qt::Key_Delete; - - case KEYCODE_END: - return Qt::Key_End; - - case KEYCODE_PG_DOWN: - return Qt::Key_PageDown; - - case KEYCODE_LEFT: - return Qt::Key_Left; - - case KEYCODE_RIGHT: - return Qt::Key_Right; - - case KEYCODE_UP: - return Qt::Key_Up; - - case KEYCODE_DOWN: - return Qt::Key_Down; - - case KEYCODE_NUM_LOCK: - return Qt::Key_NumLock; - - case KEYCODE_KP_PLUS: - return Qt::Key_Plus; - - case KEYCODE_KP_MINUS: - return Qt::Key_Minus; - - case KEYCODE_KP_MULTIPLY: - return Qt::Key_Asterisk; - - case KEYCODE_KP_DIVIDE: - return Qt::Key_Slash; - - case KEYCODE_KP_ENTER: - return Qt::Key_Enter; - - case KEYCODE_KP_HOME: - return Qt::Key_Home; - - case KEYCODE_KP_UP: - return Qt::Key_Up; - - case KEYCODE_KP_PG_UP: - return Qt::Key_PageUp; - - case KEYCODE_KP_LEFT: - return Qt::Key_Left; - - // Is this right? - case KEYCODE_KP_FIVE: - return Qt::Key_5; - - case KEYCODE_KP_RIGHT: - return Qt::Key_Right; - - case KEYCODE_KP_END: - return Qt::Key_End; - - case KEYCODE_KP_DOWN: - return Qt::Key_Down; - - case KEYCODE_KP_PG_DOWN: - return Qt::Key_PageDown; - - case KEYCODE_KP_INSERT: - return Qt::Key_Insert; - - case KEYCODE_KP_DELETE: - return Qt::Key_Delete; - - case KEYCODE_F1: - return Qt::Key_F1; - - case KEYCODE_F2: - return Qt::Key_F2; - - case KEYCODE_F3: - return Qt::Key_F3; - - case KEYCODE_F4: - return Qt::Key_F4; - - case KEYCODE_F5: - return Qt::Key_F5; - - case KEYCODE_F6: - return Qt::Key_F6; - - case KEYCODE_F7: - return Qt::Key_F7; - - case KEYCODE_F8: - return Qt::Key_F8; - - case KEYCODE_F9: - return Qt::Key_F9; - - case KEYCODE_F10: - return Qt::Key_F10; - - case KEYCODE_F11: - return Qt::Key_F11; - - case KEYCODE_F12: - return Qt::Key_F12; - - // See keycodes.h for more, but these are all the basics. And printables are already included. - - default: -#if defined(QBBEVENTTHREAD_DEBUG) - qDebug() << "QBB: unknown key for translation:" << key; -#endif - break; - } - - return Qt::Key_Escape; -} - -bool isKeypadKey( int key ) -{ - switch (key) - { - case KEYCODE_KP_PLUS: - case KEYCODE_KP_MINUS: - case KEYCODE_KP_MULTIPLY: - case KEYCODE_KP_DIVIDE: - case KEYCODE_KP_ENTER: - case KEYCODE_KP_HOME: - case KEYCODE_KP_UP: - case KEYCODE_KP_PG_UP: - case KEYCODE_KP_LEFT: - case KEYCODE_KP_FIVE: - case KEYCODE_KP_RIGHT: - case KEYCODE_KP_END: - case KEYCODE_KP_DOWN: - case KEYCODE_KP_PG_DOWN: - case KEYCODE_KP_INSERT: - case KEYCODE_KP_DELETE: - return true; - default: - break; - } - - return false; -} - -QT_END_NAMESPACE - -#endif // QBBKEYTRANSLATOR_H diff --git a/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp b/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp deleted file mode 100644 index 03cf458b80..0000000000 --- a/src/plugins/platforms/blackberry/qbbnavigatorthread.cpp +++ /dev/null @@ -1,280 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbnavigatorthread.h" -#include "qbbscreen.h" - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static const char *navigatorControlPath = "/pps/services/navigator/control"; -static const int ppsBufferSize = 4096; - -QBBNavigatorThread::QBBNavigatorThread(QBBScreen& primaryScreen) - : m_primaryScreen(primaryScreen), - m_fd(-1), - m_readNotifier(0) -{ -} - -QBBNavigatorThread::~QBBNavigatorThread() -{ - // block until thread terminates - shutdown(); - - delete m_readNotifier; -} - -void QBBNavigatorThread::run() -{ -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "QBB: navigator thread started"; -#endif - - // open connection to navigator - errno = 0; - m_fd = open(navigatorControlPath, O_RDWR); - if (m_fd == -1) { - qWarning("QBB: failed to open navigator pps, errno=%d", errno); - return; - } - - m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read); - // using direct connection to get the slot called in this thread's context - connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(readData()), Qt::DirectConnection); - - exec(); - - // close connection to navigator - close(m_fd); - -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "QBB: navigator thread stopped"; -#endif -} - -void QBBNavigatorThread::shutdown() -{ -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "QBB: navigator thread shutdown begin"; -#endif - - // signal thread to terminate - quit(); - - // block until thread terminates - wait(); - -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "QBB: navigator thread shutdown end"; -#endif -} - -void QBBNavigatorThread::parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id) -{ -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "PPS: data=" << ppsData; -#endif - - // tokenize pps data into lines - QList lines = ppsData.split('\n'); - - // validate pps object - if (lines.size() == 0 || lines.at(0) != "@control") { - qFatal("QBB: unrecognized pps object, data=%s", ppsData.constData()); - } - - // parse pps object attributes and extract values - for (int i = 1; i < lines.size(); i++) { - - // tokenize current attribute - const QByteArray &attr = lines.at(i); - -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "PPS: attr=" << attr; -#endif - - int firstColon = attr.indexOf(':'); - if (firstColon == -1) { - // abort - malformed attribute - continue; - } - - int secondColon = attr.indexOf(':', firstColon + 1); - if (secondColon == -1) { - // abort - malformed attribute - continue; - } - - QByteArray key = attr.left(firstColon); - QByteArray value = attr.mid(secondColon + 1); - -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "PPS: key=" << key; - qDebug() << "PPS: val=" << value; -#endif - - // save attribute value - if (key == "msg") { - msg = value; - } else if (key == "dat") { - dat = value; - } else if (key == "id") { - id = value; - } else { - qFatal("QBB: unrecognized pps attribute, attr=%s", key.constData()); - } - } -} - -void QBBNavigatorThread::replyPPS(const QByteArray &res, const QByteArray &id, const QByteArray &dat) -{ - // construct pps message - QByteArray ppsData = "res::"; - ppsData += res; - ppsData += "\nid::"; - ppsData += id; - if (!dat.isEmpty()) { - ppsData += "\ndat::"; - ppsData += dat; - } - ppsData += "\n"; - -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "PPS reply=" << ppsData; -#endif - - // send pps message to navigator - errno = 0; - int bytes = write(m_fd, ppsData.constData(), ppsData.size()); - if (bytes == -1) { - qFatal("QBB: failed to write navigator pps, errno=%d", errno); - } -} - -void QBBNavigatorThread::handleMessage(const QByteArray &msg, const QByteArray &dat, const QByteArray &id) -{ -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "PPS: msg=" << msg << ", dat=" << dat << ", id=" << id; -#endif - - // check message type - if (msg == "orientationCheck") { - - // reply to navigator that (any) orientation is acceptable -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "PPS: orientation check, o=" << dat; -#endif - replyPPS(msg, id, "true"); - - } else if (msg == "orientation") { - - // update screen geometry and reply to navigator that we're ready -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "PPS: orientation, o=" << dat; -#endif - m_primaryScreen.setRotation( dat.toInt() ); - QWindowSystemInterface::handleScreenGeometryChange(0, m_primaryScreen.geometry()); - replyPPS(msg, id, ""); - - } else if (msg == "SWIPE_DOWN") { - - // simulate menu key press -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "PPS: menu"; -#endif - QWindow *w = QGuiApplication::focusWindow(); - QWindowSystemInterface::handleKeyEvent(w, QEvent::KeyPress, Qt::Key_Menu, Qt::NoModifier); - QWindowSystemInterface::handleKeyEvent(w, QEvent::KeyRelease, Qt::Key_Menu, Qt::NoModifier); - - } else if (msg == "exit") { - - // shutdown everything -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "PPS: exit"; -#endif - QCoreApplication::quit(); - } -} - -void QBBNavigatorThread::readData() -{ -#if defined(QBBNAVIGATORTHREAD_DEBUG) - qDebug() << "QBB: reading navigator data"; -#endif - // allocate buffer for pps data - char buffer[ppsBufferSize]; - - // attempt to read pps data - errno = 0; - int bytes = qt_safe_read(m_fd, buffer, ppsBufferSize - 1); - if (bytes == -1) { - qFatal("QBB: failed to read navigator pps, errno=%d", errno); - } - - // check if pps data was received - if (bytes > 0) { - - // ensure data is null terminated - buffer[bytes] = '\0'; - - // process received message - QByteArray ppsData(buffer); - QByteArray msg; - QByteArray dat; - QByteArray id; - parsePPS(ppsData, msg, dat, id); - handleMessage(msg, dat, id); - } -} diff --git a/src/plugins/platforms/blackberry/qbbnavigatorthread.h b/src/plugins/platforms/blackberry/qbbnavigatorthread.h deleted file mode 100644 index fda24b0c67..0000000000 --- a/src/plugins/platforms/blackberry/qbbnavigatorthread.h +++ /dev/null @@ -1,78 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBNAVIGATORTHREAD_H -#define QBBNAVIGATORTHREAD_H - -#include - -QT_BEGIN_NAMESPACE - -class QBBScreen; -class QSocketNotifier; - -class QBBNavigatorThread : public QThread -{ - Q_OBJECT -public: - QBBNavigatorThread(QBBScreen &primaryScreen); - virtual ~QBBNavigatorThread(); - -protected: - virtual void run(); - -private Q_SLOTS: - void readData(); - -private: - void shutdown(); - void parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id); - void replyPPS(const QByteArray &res, const QByteArray &id, const QByteArray &dat); - void handleMessage(const QByteArray &msg, const QByteArray &dat, const QByteArray &id); - - QBBScreen &m_primaryScreen; - int m_fd; - QSocketNotifier *m_readNotifier; -}; - -QT_END_NAMESPACE - -#endif // QBBNAVIGATORTHREAD_H diff --git a/src/plugins/platforms/blackberry/qbbrasterbackingstore.cpp b/src/plugins/platforms/blackberry/qbbrasterbackingstore.cpp deleted file mode 100644 index 405e09260f..0000000000 --- a/src/plugins/platforms/blackberry/qbbrasterbackingstore.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbrasterbackingstore.h" -#include "qbbwindow.h" - -#include - -#include - -QT_BEGIN_NAMESPACE - -QBBRasterBackingStore::QBBRasterBackingStore(QWindow *window) - : QPlatformBackingStore(window) -{ -#if defined(QBBRASTERBACKINGSTORE_DEBUG) - qDebug() << "QBBRasterBackingStore::QBBRasterBackingStore - w=" << window; -#endif - - // save platform window associated with widget - m_platformWindow = static_cast(window->handle()); -} - -QBBRasterBackingStore::~QBBRasterBackingStore() -{ -#if defined(QBBRasterBackingStore_DEBUG) - qDebug() << "QBBRasterBackingStore::~QBBRasterBackingStore - w=" << window(); -#endif -} - -QPaintDevice *QBBRasterBackingStore::paintDevice() -{ - return m_platformWindow->renderBuffer().image(); -} - -void QBBRasterBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) -{ - Q_UNUSED(window); - Q_UNUSED(offset); - -#if defined(QBBRASTERBACKINGSTORE_DEBUG) - qDebug() << "QBBRasterBackingStore::flush - w=" << this->window(); -#endif - - // visit all pending scroll operations - for (int i = m_scrollOpList.size() - 1; i >= 0; i--) { - - // do the scroll operation - ScrollOp &op = m_scrollOpList[i]; - QRegion srcArea = op.totalArea.intersected( op.totalArea.translated(-op.dx, -op.dy) ); - m_platformWindow->scroll(srcArea, op.dx, op.dy); - } - - // clear all pending scroll operations - m_scrollOpList.clear(); - - // update the display with newly rendered content - m_platformWindow->post(region); -} - -void QBBRasterBackingStore::resize(const QSize &size, const QRegion &staticContents) -{ - Q_UNUSED(size); - Q_UNUSED(staticContents); -#if defined(QBBRASTERBACKINGSTORE_DEBUG) - qDebug() << "QBBRasterBackingStore::resize - w=" << window() << ", s=" << size; -#endif - - // NOTE: defer resizing window buffers until next paint as - // resize() can be called multiple times before a paint occurs -} - -bool QBBRasterBackingStore::scroll(const QRegion &area, int dx, int dy) -{ -#if defined(QBBRASTERBACKINGSTORE_DEBUG) - qDebug() << "QBBRasterBackingStore::scroll - w=" << window(); -#endif - - // calculate entire region affected by scroll operation (src + dst) - QRegion totalArea = area.translated(dx, dy); - totalArea += area; - - // visit all pending scroll operations - for (int i = m_scrollOpList.size() - 1; i >= 0; i--) { - - ScrollOp &op = m_scrollOpList[i]; - if (op.totalArea == totalArea) { - // same area is being scrolled again - update delta - op.dx += dx; - op.dy += dy; - return true; - } else if (op.totalArea.intersects(totalArea)) { - // current scroll overlaps previous scroll but is - // not equal in area - just paint everything - qWarning("QBB: pending scroll operations overlap but not equal"); - return false; - } - } - - // create new scroll operation - m_scrollOpList.append( ScrollOp(totalArea, dx, dy) ); - return true; -} - -void QBBRasterBackingStore::beginPaint(const QRegion ®ion) -{ - Q_UNUSED(region); - -#if defined(QBBRASTERBACKINGSTORE_DEBUG) - qDebug() << "QBBRasterBackingStore::beginPaint - w=" << window(); -#endif - - // resize window buffers if surface resized - QSize s = window()->size(); - if (s != m_platformWindow->bufferSize()) { - m_platformWindow->setBufferSize(s); - } -} - -void QBBRasterBackingStore::endPaint(const QRegion ®ion) -{ - Q_UNUSED(region); -#if defined(QBBRasterBackingStore_DEBUG) - qDebug() << "QBBRasterBackingStore::endPaint - w=" << window(); -#endif -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/blackberry/qbbrasterbackingstore.h b/src/plugins/platforms/blackberry/qbbrasterbackingstore.h deleted file mode 100644 index ca1e27bcc8..0000000000 --- a/src/plugins/platforms/blackberry/qbbrasterbackingstore.h +++ /dev/null @@ -1,81 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBRASTERWINDOWSURFACE_H -#define QBBRASTERWINDOWSURFACE_H - -#include - -#include - -QT_BEGIN_NAMESPACE - -class QBBWindow; - -class QBBRasterBackingStore : public QPlatformBackingStore -{ -public: - QBBRasterBackingStore(QWindow *window); - virtual ~QBBRasterBackingStore(); - - virtual QPaintDevice *paintDevice(); - virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); - virtual void resize(const QSize &size, const QRegion &staticContents); - virtual bool scroll(const QRegion &area, int dx, int dy); - virtual void beginPaint(const QRegion ®ion); - virtual void endPaint(const QRegion ®ion); - -private: - class ScrollOp { - public: - ScrollOp(const QRegion &a, int x, int y) : totalArea(a), dx(x), dy(y) {} - QRegion totalArea; - int dx; - int dy; - }; - - QBBWindow *m_platformWindow; - QList m_scrollOpList; -}; - -QT_END_NAMESPACE - -#endif // QBBRASTERWINDOWSURFACE_H diff --git a/src/plugins/platforms/blackberry/qbbrootwindow.cpp b/src/plugins/platforms/blackberry/qbbrootwindow.cpp deleted file mode 100644 index 831b0774f9..0000000000 --- a/src/plugins/platforms/blackberry/qbbrootwindow.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbrootwindow.h" - -#include "qbbscreen.h" - -#include - -#if defined(QBBROOTWINDOW_DEBUG) -#include -#endif - -#include -#include - -static const int MAGIC_ZORDER_FOR_NO_NAV = 10; - -QBBRootWindow::QBBRootWindow(QBBScreen *screen) - : m_screen(screen), - m_window(0), - m_windowGroupName() -{ -#if defined(QBBROOTWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // Create one top-level QNX window to act as a container for child windows - // since navigator only supports one application window - errno = 0; - int result = screen_create_window(&m_window, m_screen->nativeContext()); - int val[2]; - if (result != 0) { - qFatal("QBBRootWindow: failed to create window, errno=%d", errno); - } - - // Move window to proper display - errno = 0; - screen_display_t display = m_screen->nativeDisplay(); - result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window display, errno=%d", errno); - } - - // Make sure window is above navigator but below keyboard if running as root - // since navigator won't automatically set our z-order in this case - if (getuid() == 0) { - errno = 0; - val[0] = MAGIC_ZORDER_FOR_NO_NAV; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window z-order, errno=%d", errno); - } - } - - // Window won't be visible unless it has some buffers so make one dummy buffer that is 1x1 - errno = 0; - val[0] = SCREEN_USAGE_NATIVE; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window buffer usage, errno=%d", errno); - } - - errno = 0; - val[0] = m_screen->nativeFormat(); - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window pixel format, errno=%d", errno); - } - - errno = 0; - val[0] = 1; - val[1] = 1; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window buffer size, errno=%d", errno); - } - - errno = 0; - result = screen_create_window_buffers(m_window, 1); - if (result != 0) { - qFatal("QBB: failed to create window buffer, errno=%d", errno); - } - - // Window is always the size of the display - errno = 0; - QRect geometry = m_screen->geometry(); - val[0] = geometry.width(); - val[1] = geometry.height(); - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window size, errno=%d", errno); - } - - // Fill the window with solid black - errno = 0; - val[0] = 0; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_COLOR, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window colour, errno=%d", errno); - } - - // Make the window opaque - errno = 0; - val[0] = SCREEN_TRANSPARENCY_NONE; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window transparency, errno=%d", errno); - } - - // Set the swap interval to 1 - errno = 0; - val[0] = 1; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window swap interval, errno=%d", errno); - } - - // Set viewport size equal to window size but move outside buffer so the fill colour is used exclusively - errno = 0; - val[0] = geometry.width(); - val[1] = geometry.height(); - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window source size, errno=%d", errno); - } - - errno = 0; - val[0] = 1; - val[1] = 0; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_POSITION, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window source position, errno=%d", errno); - } - - createWindowGroup(); - post(); -} - -QBBRootWindow::~QBBRootWindow() -{ - // Cleanup top-level QNX window - screen_destroy_window(m_window); -} - -void QBBRootWindow::post() const -{ -#if defined(QBBROOTWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - errno = 0; - screen_buffer_t buffer; - int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&buffer); - if (result != 0) { - qFatal("QBBRootWindow: failed to query window buffer, errno=%d", errno); - } - - errno = 0; - int dirtyRect[] = {0, 0, 1, 1}; - result = screen_post_window(m_window, buffer, 1, dirtyRect, 0); - if (result != 0) { - qFatal("QBB: failed to post window buffer, errno=%d", errno); - } -} - -void QBBRootWindow::flush() const -{ -#if defined(QBBROOTWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // Force immediate display update - errno = 0; - int result = screen_flush_context(m_screen->nativeContext(), 0); - if (result != 0) { - qFatal("QBBRootWindow: failed to flush context, errno=%d", errno); - } -} - -void QBBRootWindow::setRotation(int rotation) -{ -#if defined(QBBROOTWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "angle =" << rotation; -#endif - errno = 0; - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window rotation, errno=%d", errno); - } -} - -void QBBRootWindow::resize(const QSize &size) -{ - errno = 0; - int val[] = {size.width(), size.height()}; - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window size, errno=%d", errno); - } - - errno = 0; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val); - if (result != 0) { - qFatal("QBBRootWindow: failed to set window source size, errno=%d", errno); - } - - // NOTE: display will update when child windows relayout and repaint -} - -void QBBRootWindow::createWindowGroup() -{ - // Generate a random window group name - m_windowGroupName = QUuid::createUuid().toString().toAscii(); - - // Create window group so child windows can be parented by container window - errno = 0; - int result = screen_create_window_group(m_window, m_windowGroupName.constData()); - if (result != 0) { - qFatal("QBBRootWindow: failed to create app window group, errno=%d", errno); - } -} diff --git a/src/plugins/platforms/blackberry/qbbrootwindow.h b/src/plugins/platforms/blackberry/qbbrootwindow.h deleted file mode 100644 index 0b89f52a5e..0000000000 --- a/src/plugins/platforms/blackberry/qbbrootwindow.h +++ /dev/null @@ -1,81 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBROOTWINDOW_H -#define QBBROOTWINDOW_H - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QBBScreen; - -class QBBRootWindow -{ -public: - QBBRootWindow(QBBScreen *screen); - ~QBBRootWindow(); - - screen_window_t nativeHandle() const { return m_window; } - - void post() const; - void flush() const; - - void setRotation(int rotation); - - void resize(const QSize &size); - - QByteArray groupName() const { return m_windowGroupName; } - -private: - void createWindowGroup(); - - QBBScreen *m_screen; - screen_window_t m_window; - QByteArray m_windowGroupName; -}; - -QT_END_NAMESPACE - -#endif // QBBROOTWINDOW_H diff --git a/src/plugins/platforms/blackberry/qbbscreen.cpp b/src/plugins/platforms/blackberry/qbbscreen.cpp deleted file mode 100644 index 11e40f6150..0000000000 --- a/src/plugins/platforms/blackberry/qbbscreen.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbscreen.h" -#include "qbbvirtualkeyboard.h" -#include "qbbwindow.h" - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -QList QBBScreen::ms_screens; -QList QBBScreen::ms_childWindows; - -QBBScreen::QBBScreen(screen_context_t screenContext, screen_display_t display, bool primaryScreen) - : m_screenContext(screenContext), - m_display(display), - m_rootWindow(), - m_primaryScreen(primaryScreen), - m_posted(false), - m_platformContext(0) -{ -#if defined(QBBSCREEN_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // Cache initial orientation of this display - // TODO: use ORIENTATION environment variable? - errno = 0; - int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION, &m_initialRotation); - if (result != 0) { - qFatal("QBBScreen: failed to query display rotation, errno=%d", errno); - } - m_currentRotation = m_initialRotation; - - // Cache size of this display in pixels - // TODO: use WIDTH and HEIGHT environment variables? - errno = 0; - int val[2]; - result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_SIZE, val); - if (result != 0) { - qFatal("QBBScreen: failed to query display size, errno=%d", errno); - } - - m_currentGeometry = m_initialGeometry = QRect(0, 0, val[0], val[1]); - - // Cache size of this display in millimeters - errno = 0; - result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_PHYSICAL_SIZE, val); - if (result != 0) { - qFatal("QBBScreen: failed to query display physical size, errno=%d", errno); - } - - // Peg the DPI to 96 (for now) so fonts are a reasonable size. We'll want to match - // everything with a QStyle later, and at that point the physical size can be used - // instead. - { - static const int dpi = 96; - int width = m_currentGeometry.width() / dpi * qreal(25.4) ; - int height = m_currentGeometry.height() / dpi * qreal(25.4) ; - - m_currentPhysicalSize = m_initialPhysicalSize = QSize(width,height); - } - - // We only create the root window if we are the primary display. - if (primaryScreen) - m_rootWindow = QSharedPointer(new QBBRootWindow(this)); -} - -QBBScreen::~QBBScreen() -{ -#if defined(QBBSCREEN_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif -} - -/* static */ -void QBBScreen::createDisplays(screen_context_t context) -{ -#if defined(QBBSCREEN_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // Query number of displays - errno = 0; - int displayCount; - int result = screen_get_context_property_iv(context, SCREEN_PROPERTY_DISPLAY_COUNT, &displayCount); - if (result != 0) { - qFatal("QBBScreen: failed to query display count, errno=%d", errno); - } - - // Get all displays - errno = 0; - screen_display_t *displays = (screen_display_t *)alloca(sizeof(screen_display_t) * displayCount); - result = screen_get_context_property_pv(context, SCREEN_PROPERTY_DISPLAYS, (void **)displays); - if (result != 0) { - qFatal("QBBScreen: failed to query displays, errno=%d", errno); - } - - for (int i=0; iupdateZorder(topZorder); - - // After a hierarchy update, we need to force a flush on all screens. - // Right now, all screens share a context. - screen_flush_context( primaryDisplay()->m_screenContext, 0 ); -} - -void QBBScreen::onWindowPost(QBBWindow *window) -{ -#if defined(QBBSCREEN_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - Q_UNUSED(window) - - // post app window (so navigator will show it) after first child window - // has posted; this only needs to happen once as the app window's content - // never changes - if (!m_posted && m_rootWindow) { - m_rootWindow->post(); - m_posted = true; - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/blackberry/qbbscreen.h b/src/plugins/platforms/blackberry/qbbscreen.h deleted file mode 100644 index 16606944d8..0000000000 --- a/src/plugins/platforms/blackberry/qbbscreen.h +++ /dev/null @@ -1,121 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBSCREEN_H -#define QBBSCREEN_H - -#include - -#include "qbbrootwindow.h" - -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QBBWindow; - -class QBBScreen : public QPlatformScreen -{ -public: - static QList screens() { return ms_screens; } - static void createDisplays(screen_context_t context); - static void destroyDisplays(); - static QBBScreen *primaryDisplay() { return static_cast(ms_screens.at(0)); } - static int defaultDepth(); - - virtual QRect geometry() const { return m_currentGeometry; } - virtual QRect availableGeometry() const; - virtual int depth() const { return defaultDepth(); } - virtual QImage::Format format() const { return (depth() == 32) ? QImage::Format_RGB32 : QImage::Format_RGB16; } - virtual QSizeF physicalSize() const { return m_currentPhysicalSize; } - - bool isPrimaryScreen() const { return m_primaryScreen; } - - int rotation() const { return m_currentRotation; } - void setRotation(int rotation); - - int nativeFormat() const { return (depth() == 32) ? SCREEN_FORMAT_RGBA8888 : SCREEN_FORMAT_RGB565; } - screen_display_t nativeDisplay() const { return m_display; } - screen_context_t nativeContext() const { return m_screenContext; } - const char *windowGroupName() const { return m_rootWindow->groupName().constData(); } - - /* Window hierarchy management */ - static void addWindow(QBBWindow *child); - static void removeWindow(QBBWindow *child); - static void raiseWindow(QBBWindow *window); - static void lowerWindow(QBBWindow *window); - static void updateHierarchy(); - - void onWindowPost(QBBWindow *window); - - QSharedPointer rootWindow() const { return m_rootWindow; } - -private: - QBBScreen(screen_context_t context, screen_display_t display, bool primaryScreen); - virtual ~QBBScreen(); - - static bool orthogonal(int rotation1, int rotation2); - - screen_context_t m_screenContext; - screen_display_t m_display; - QSharedPointer m_rootWindow; - bool m_primaryScreen; - bool m_posted; - bool m_usingOpenGL; - - int m_initialRotation; - int m_currentRotation; - QSize m_initialPhysicalSize; - QSize m_currentPhysicalSize; - QRect m_initialGeometry; - QRect m_currentGeometry; - QPlatformOpenGLContext *m_platformContext; - - static QList ms_screens; - static QList ms_childWindows; -}; - -QT_END_NAMESPACE - -#endif // QBBSCREEN_H diff --git a/src/plugins/platforms/blackberry/qbbvirtualkeyboard.cpp b/src/plugins/platforms/blackberry/qbbvirtualkeyboard.cpp deleted file mode 100644 index 082ef9b19d..0000000000 --- a/src/plugins/platforms/blackberry/qbbvirtualkeyboard.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbvirtualkeyboard.h" -#include "qbbscreen.h" - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -const char *QBBVirtualKeyboard::ms_PPSPath = "/pps/services/input/control?wait"; -const size_t QBBVirtualKeyboard::ms_bufferSize = 2048; - -static QBBVirtualKeyboard *s_instance = 0; - -// Huge hack for keyboard shadow (see QNX PR 88400). Should be removed ASAP. -#define KEYBOARD_SHADOW_HEIGHT 8 - -QBBVirtualKeyboard::QBBVirtualKeyboard() : - m_encoder(NULL), - m_decoder(NULL), - m_buffer(NULL), - m_height(0), - m_fd(-1), - m_keyboardMode(Default), - m_visible(false), - m_locale(QLatin1String("en_US")) -{ - connect(); -} - -QBBVirtualKeyboard::~QBBVirtualKeyboard() -{ - close(); -} - -/* static */ -QBBVirtualKeyboard& QBBVirtualKeyboard::instance() -{ - if (!s_instance) { - s_instance = new QBBVirtualKeyboard(); - s_instance->start(); - } - - return *s_instance; -} - -/* static */ -void QBBVirtualKeyboard::destroy() -{ - if (s_instance) { - delete s_instance; - s_instance = 0; - } -} - -void QBBVirtualKeyboard::close() -{ - if (m_fd) { - // any reads will fail after we close the fd, which is basically what we want. - ::close(m_fd); - } - - // Wait for the thread to die (should be immediate), then continue the cleanup. - wait(); - - if (m_fd) { - m_fd = -1; - } - - - if (m_decoder) - { - pps_decoder_cleanup(m_decoder); - delete m_decoder; - m_decoder = NULL; - } - - if (m_encoder) - { - pps_encoder_cleanup(m_encoder); - delete m_encoder; - m_encoder = NULL; - } - - delete [] m_buffer; - m_buffer = NULL; -} - -bool QBBVirtualKeyboard::connect() -{ - close(); - - m_encoder = new pps_encoder_t; - m_decoder = new pps_decoder_t; - - pps_encoder_initialize(m_encoder, false); - pps_decoder_initialize(m_decoder, NULL); - - errno = 0; - m_fd = ::open(ms_PPSPath, O_RDWR); - if (m_fd == -1) - { - qCritical("QBBVirtualKeyboard: Unable to open \"%s\" for keyboard: %s (%d).", - ms_PPSPath, strerror(errno), errno); - close(); - return false; - } - - m_buffer = new char[ms_bufferSize]; - if (!m_buffer) { - qCritical("QBBVirtualKeyboard: Unable to allocate buffer of %d bytes. Size is unavailable.", ms_bufferSize); - return false; - } - - if (!queryPPSInfo()) - return false; - - start(); - - return true; -} - -bool QBBVirtualKeyboard::queryPPSInfo() -{ - // Request info, requires id to regenerate res message. - pps_encoder_add_string(m_encoder, "msg", "info"); - pps_encoder_add_string(m_encoder, "id", "libWebView"); - - if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { - close(); - return false; - } - - pps_encoder_reset(m_encoder); - - return true; -} - -void QBBVirtualKeyboard::notifyClientActiveStateChange(bool active) -{ - if (!active) - hideKeyboard(); -} - -void QBBVirtualKeyboard::run() -{ - ppsDataReady(); -} - -void QBBVirtualKeyboard::ppsDataReady() -{ - while (1) { - ssize_t nread = read(m_fd, m_buffer, ms_bufferSize - 1); - -#ifdef QBBVIRTUALKEYBOARD_DEBUG - qDebug() << "QBB: keyboardMessage size: " << nread; -#endif - if (nread < 0) - break; - - // nread is the real space necessary, not the amount read. - if (static_cast(nread) > ms_bufferSize - 1) { - qCritical("QBBVirtualKeyboard: Keyboard buffer size too short; need %u.", nread + 1); - break; - } - - m_buffer[nread] = 0; - pps_decoder_parse_pps_str(m_decoder, m_buffer); - pps_decoder_push(m_decoder, NULL); -#ifdef QBBVIRTUALKEYBOARD_DEBUG - pps_decoder_dump_tree(m_decoder, stderr); -#endif - - const char *value; - if (pps_decoder_get_string(m_decoder, "error", &value) == PPS_DECODER_OK) { - qCritical("QBBVirtualKeyboard: Keyboard PPS decoder error: %s", value ? value : "[null]"); - continue; - } - - if (pps_decoder_get_string(m_decoder, "msg", &value) == PPS_DECODER_OK) { - if (strcmp(value, "show") == 0) { - const bool oldVisible = m_visible; - m_visible = true; - handleKeyboardStateChangeMessage(true); - if (oldVisible != m_visible) - emit visibilityChanged(m_visible); - } else if (strcmp(value, "hide") == 0) { - const bool oldVisible = m_visible; - m_visible = false; - handleKeyboardStateChangeMessage(false); - if (oldVisible != m_visible) - emit visibilityChanged(m_visible); - } else if (strcmp(value, "info") == 0) - handleKeyboardInfoMessage(); - else if (strcmp(value, "connect") == 0) { } - else - qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS msg value: %s", value ? value : "[null]"); - } else if (pps_decoder_get_string(m_decoder, "res", &value) == PPS_DECODER_OK) { - if (strcmp(value, "info") == 0) - handleKeyboardInfoMessage(); - else - qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS res value: %s", value ? value : "[null]"); - } else - qCritical("QBBVirtualKeyboard: Unexpected keyboard PPS message type"); - } - -#ifdef QBBVIRTUALKEYBOARD_DEBUG - qDebug() << "QBB: exiting keyboard thread"; -#endif - - if (m_decoder) - pps_decoder_cleanup(m_decoder); -} - -void QBBVirtualKeyboard::handleKeyboardInfoMessage() -{ - int newHeight = 0; - const char *value; - - if (pps_decoder_push(m_decoder, "dat") != PPS_DECODER_OK) { - qCritical("QBBVirtualKeyboard: Keyboard PPS dat object not found"); - return; - } - if (pps_decoder_get_int(m_decoder, "size", &newHeight) != PPS_DECODER_OK) { - qCritical("QBBVirtualKeyboard: Keyboard PPS size field not found"); - return; - } - if (pps_decoder_push(m_decoder, "locale") != PPS_DECODER_OK) { - qCritical("QBBVirtualKeyboard: Keyboard PPS locale object not found"); - return; - } - if (pps_decoder_get_string(m_decoder, "languageId", &value) != PPS_DECODER_OK) { - qCritical("QBBVirtualKeyboard: Keyboard PPS languageId field not found"); - return; - } - const QString languageId = QString::fromLatin1(value); - if (pps_decoder_get_string(m_decoder, "countryId", &value) != PPS_DECODER_OK) { - qCritical("QBBVirtualKeyboard: Keyboard PPS size countryId not found"); - return; - } - const QString countryId = QString::fromLatin1(value); - - // HUGE hack, should be removed ASAP. - newHeight -= KEYBOARD_SHADOW_HEIGHT; // We want to ignore the 8 pixel shadow above the keyboard. (PR 88400) - - if (newHeight != m_height) { - m_height = newHeight; - updateAvailableScreenGeometry(); - } - - const QLocale locale = QLocale(languageId + QLatin1Char('_') + countryId); - if (locale != m_locale) { - m_locale = locale; - emit localeChanged(locale); - } - -#ifdef QBBVIRTUALKEYBOARD_DEBUG - qDebug() << "QBB: handleKeyboardInfoMessage size=" << m_height << "locale=" << m_locale; -#endif -} - -void QBBVirtualKeyboard::handleKeyboardStateChangeMessage(bool visible) -{ - -#ifdef QBBVIRTUALKEYBOARD_DEBUG - qDebug() << "QBB: handleKeyboardStateChangeMessage " << visible; -#endif - updateAvailableScreenGeometry(); - - if (visible) - showKeyboard(); - else - hideKeyboard(); -} - -void QBBVirtualKeyboard::updateAvailableScreenGeometry() -{ -#ifdef QBBVIRTUALKEYBOARD_DEBUG - qDebug() << "QBB: updateAvailableScreenGeometry: keyboard visible=" << m_visible << ", keyboard height=" << m_height; -#endif - - // TODO: What screen index should be used? I assume primaryScreen here because it works, and - // we do it for handleScreenGeometryChange elsewhere but since we have support - // for more than one screen, that's not going to always work. - QBBScreen *platformScreen = QBBScreen::primaryDisplay(); - QWindowSystemInterface::handleScreenAvailableGeometryChange(platformScreen->screen(), platformScreen->availableGeometry()); -} - -bool QBBVirtualKeyboard::showKeyboard() -{ -#ifdef QBBVIRTUALKEYBOARD_DEBUG - qDebug() << "QBB: showKeyboard()"; -#endif - - // Try to connect. - if (m_fd == -1 && !connect()) - return false; - - // NOTE: This must be done everytime the keyboard is shown even if there is no change because - // hiding the keyboard wipes the setting. - applyKeyboardModeOptions(); - - pps_encoder_reset(m_encoder); - - // Send the show message. - pps_encoder_add_string(m_encoder, "msg", "show"); - - if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { - close(); - return false; - } - - pps_encoder_reset(m_encoder); - - // Return true if no error occurs. Sizing response will be triggered when confirmation of - // the change arrives. - return true; -} - -bool QBBVirtualKeyboard::hideKeyboard() -{ -#ifdef QBBVIRTUALKEYBOARD_DEBUG - qDebug() << "QBB: hideKeyboard()"; -#endif - - if (m_fd == -1 && !connect()) - return false; - - pps_encoder_add_string(m_encoder, "msg", "hide"); - - if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { - close(); - - //Try again. - if (connect()) { - if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { - close(); - return false; - } - } - else - return false; - } - - pps_encoder_reset(m_encoder); - - // Return true if no error occurs. Sizing response will be triggered when confirmation of - // the change arrives. - return true; -} - -void QBBVirtualKeyboard::setKeyboardMode(KeyboardMode mode) -{ - m_keyboardMode = mode; -} - -void QBBVirtualKeyboard::applyKeyboardModeOptions() -{ - // Try to connect. - if (m_fd == -1 && !connect()) - return; - - // Send the options message. - pps_encoder_add_string(m_encoder, "msg", "options"); - - pps_encoder_start_object(m_encoder, "dat"); - switch (m_keyboardMode) { - case Url: - addUrlModeOptions(); - break; - case Email: - addEmailModeOptions(); - break; - case Web: - addWebModeOptions(); - break; - case NumPunc: - addNumPuncModeOptions(); - break; - case Symbol: - addSymbolModeOptions(); - break; - case Phone: - addPhoneModeOptions(); - break; - case Pin: - addPinModeOptions(); - break; - case Default: - default: - addDefaultModeOptions(); - break; - } - - pps_encoder_end_object(m_encoder); - - if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { - close(); - } - - pps_encoder_reset(m_encoder); -} - -void QBBVirtualKeyboard::addDefaultModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "default"); -} - -void QBBVirtualKeyboard::addUrlModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "url"); -} - -void QBBVirtualKeyboard::addEmailModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "email"); -} - -void QBBVirtualKeyboard::addWebModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "web"); -} - -void QBBVirtualKeyboard::addNumPuncModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "numPunc"); -} - -void QBBVirtualKeyboard::addPhoneModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "phone"); -} - -void QBBVirtualKeyboard::addPinModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "pin"); -} - -void QBBVirtualKeyboard::addSymbolModeOptions() -{ - pps_encoder_add_string(m_encoder, "enter", "enter.default"); - pps_encoder_add_string(m_encoder, "type", "symbol"); -} diff --git a/src/plugins/platforms/blackberry/qbbvirtualkeyboard.h b/src/plugins/platforms/blackberry/qbbvirtualkeyboard.h deleted file mode 100644 index 14003ee897..0000000000 --- a/src/plugins/platforms/blackberry/qbbvirtualkeyboard.h +++ /dev/null @@ -1,130 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 VIRTUALKEYBOARD_H_ -#define VIRTUALKEYBOARD_H_ - -#include -#include -#include -#include - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -/* Shamelessly copied from the browser - this should be rewritten once we have a proper PPS wrapper class */ -class QBBVirtualKeyboard : public QThread -{ - Q_OBJECT -public: - // NOTE: Not all the following keyboard modes are currently used. - // Default - Regular Keyboard - // Url/Email - Enhanced keys for each types. - // Web - Regular keyboard with two blank keys, currently unused. - // NumPunc - Numbers & Punctionation, alternate to Symbol - // Symbol - All symbols, alternate to NumPunc, currently unused. - // Phone - Phone enhanced keyboard - currently unused as no alternate keyboard available to access a-zA-Z - // Pin - Keyboard for entering Pins (Hex values) currently unused. - // - // SPECIAL NOTE: Usage of NumPunc may have to be removed, ABC button is non-functional. - // - enum KeyboardMode { Default, Url, Email, Web, NumPunc, Symbol, Phone, Pin }; - - static QBBVirtualKeyboard& instance(); - static void destroy(); - - bool showKeyboard(); - bool hideKeyboard(); - int height() { return m_visible ? m_height : 0; } - void setKeyboardMode(KeyboardMode); - void notifyClientActiveStateChange(bool); - bool isVisible() const { return m_visible; } - QLocale locale() const { return m_locale; } - -Q_SIGNALS: - void localeChanged(const QLocale &locale); - void visibilityChanged(bool visible); - -private: - QBBVirtualKeyboard(); - virtual ~QBBVirtualKeyboard(); - - // Will be called internally if needed. - bool connect(); - void close(); - void ppsDataReady(); - bool queryPPSInfo(); - void handleKeyboardInfoMessage(); - void handleKeyboardStateChangeMessage(bool visible); - void updateAvailableScreenGeometry(); - - void applyKeyboardModeOptions(); - void addDefaultModeOptions(); - void addUrlModeOptions(); - void addEmailModeOptions(); - void addWebModeOptions(); - void addNumPuncModeOptions(); - void addSymbolModeOptions(); - void addPhoneModeOptions(); - void addPinModeOptions(); - - // QThread overrides - virtual void run(); - - pps_encoder_t *m_encoder; - pps_decoder_t *m_decoder; - char *m_buffer; - int m_height; - int m_fd; - KeyboardMode m_keyboardMode; - bool m_visible; - QLocale m_locale; - - // Path to keyboardManager in PPS. - static const char *ms_PPSPath; - static const size_t ms_bufferSize; -}; - -#endif /* VIRTUALKEYBOARD_H_ */ diff --git a/src/plugins/platforms/blackberry/qbbwindow.cpp b/src/plugins/platforms/blackberry/qbbwindow.cpp deleted file mode 100644 index bc9f112b01..0000000000 --- a/src/plugins/platforms/blackberry/qbbwindow.cpp +++ /dev/null @@ -1,665 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 "qbbwindow.h" -#include "qbbglcontext.h" -#include "qbbintegration.h" -#include "qbbscreen.h" - -#include -#include - -#include - -#include - -QT_BEGIN_NAMESPACE - -QBBWindow::QBBWindow(QWindow *window, screen_context_t context) - : QPlatformWindow(window), - m_screenContext(context), - m_window(0), - m_currentBufferIndex(-1), - m_previousBufferIndex(-1), - m_platformOpenGLContext(0), - m_screen(0), - m_parentWindow(0), - m_visible(true) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size(); -#endif - int result; - - // Create child QNX window - errno = 0; - result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW); - if (result != 0) { - qFatal("QBBWindow: failed to create window, errno=%d", errno); - } - - // Set window buffer usage based on rendering API - int val; - QSurface::SurfaceType surfaceType = window->surfaceType(); - switch (surfaceType) { - case QSurface::RasterSurface: - val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE; - break; - case QSurface::OpenGLSurface: - val = SCREEN_USAGE_OPENGL_ES2; - break; - default: - qFatal("QBBWindow: unsupported window API"); - break; - } - - errno = 0; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, &val); - if (result != 0) { - qFatal("QBBWindow: failed to set window buffer usage, errno=%d", errno); - } - - // Alpha channel is always pre-multiplied if present - errno = 0; - val = SCREEN_PRE_MULTIPLIED_ALPHA; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val); - if (result != 0) { - qFatal("QBBWindow: failed to set window alpha mode, errno=%d", errno); - } - - // Make the window opaque - errno = 0; - val = SCREEN_TRANSPARENCY_NONE; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, &val); - if (result != 0) { - qFatal("QBBWindow: failed to set window transparency, errno=%d", errno); - } - - // Set the window swap interval - errno = 0; - val = 1; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val); - if (result != 0) { - qFatal("QBBWindow: failed to set window swap interval, errno=%d", errno); - } - - // Assign the window to the primary display (this is the default specified by screen). - setScreen(QBBScreen::primaryDisplay()); - - // Add the window to the root of the hierarchy - QBBScreen::addWindow(this); - - // Add window to plugin's window mapper - QBBIntegration::addWindow(m_window, window); -} - -QBBWindow::~QBBWindow() -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window(); -#endif - // Remove from plugin's window mapper - QBBIntegration::removeWindow(m_window); - - // Remove from parent's Hierarchy. - removeFromParent(); - QBBScreen::updateHierarchy(); - - // We shouldn't allow this case unless QT allows it. Does it? Or should we send the - // handleCloseEvent on all children when this window is deleted? - if (m_childWindows.size() > 0) - qFatal("QBBWindow: window destroyed before children!"); - - // Cleanup QNX window and its buffers - screen_destroy_window(m_window); -} - -void QBBWindow::setGeometry(const QRect &rect) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window() << ", (" << rect.x() << "," << rect.y() << "," << rect.width() << "," << rect.height() << ")"; -#endif - - QRect oldGeometry = geometry(); - - // Call base class method - QPlatformWindow::setGeometry(rect); - - // Set window geometry equal to widget geometry - errno = 0; - int val[2]; - val[0] = rect.x(); - val[1] = rect.y(); - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val); - if (result != 0) { - qFatal("QBBWindow: failed to set window position, errno=%d", errno); - } - - errno = 0; - val[0] = rect.width(); - val[1] = rect.height(); - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val); - if (result != 0) { - qFatal("QBBWindow: failed to set window size, errno=%d", errno); - } - - // Set viewport size equal to window size - errno = 0; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val); - if (result != 0) { - qFatal("QBBWindow: failed to set window source size, errno=%d", errno); - } - - // Now move all children. - QPoint offset; - if (!oldGeometry.isEmpty()) { - offset = rect.topLeft(); - offset -= oldGeometry.topLeft(); - - QList::iterator it; - for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) { - (*it)->offset(offset); - } - } -} - -void QBBWindow::offset(const QPoint &offset) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window(); -#endif - // Move self and then children. - QRect newGeometry = geometry(); - newGeometry.translate(offset); - - // Call the base class - QPlatformWindow::setGeometry(newGeometry); - - int val[2]; - - errno = 0; - val[0] = newGeometry.x(); - val[1] = newGeometry.y(); - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val); - if (result != 0) { - qFatal("QBBWindow: failed to set window position, errno=%d", errno); - } - - QList::iterator it; - for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) { - (*it)->offset(offset); - } -} - -void QBBWindow::setVisible(bool visible) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window() << "visible =" << visible; -#endif - - m_visible = visible; - - QBBWindow *root = this; - while (root->m_parentWindow) - root = root->m_parentWindow; - - root->updateVisibility(root->m_visible); - - window()->requestActivateWindow(); -} - -void QBBWindow::updateVisibility(bool parentVisible) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "parentVisible =" << parentVisible << "window =" << window(); -#endif - // Set window visibility - errno = 0; - int val = (m_visible && parentVisible) ? 1 : 0; - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val); - if (result != 0) { - qFatal("QBBWindow: failed to set window visibility, errno=%d", errno); - } - - QList::iterator it; - for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) { - (*it)->updateVisibility(m_visible && parentVisible); - } -} - -void QBBWindow::setOpacity(qreal level) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window() << "opacity =" << level; -#endif - // Set window global alpha - errno = 0; - int val = (int)(level * 255); - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val); - if (result != 0) { - qFatal("QBBWindow: failed to set window global alpha, errno=%d", errno); - } - - // TODO: How to handle children of this window? If we change all the visibilities, then - // the transparency will look wrong... -} - -void QBBWindow::setBufferSize(const QSize &size) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window() << "size =" << size; -#endif - // Set window buffer size - errno = 0; - int val[2] = { size.width(), size.height() }; - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val); - if (result != 0) { - qFatal("QBBWindow: failed to set window buffer size, errno=%d", errno); - } - - // Create window buffers if they do not exist - if (!hasBuffers()) { - // Get pixel format from EGL config if using OpenGL; - // otherwise inherit pixel format of window's screen - if (m_platformOpenGLContext != 0) { - val[0] = platformWindowFormatToNativeFormat(m_platformOpenGLContext->format()); - } else { - val[0] = m_screen->nativeFormat(); - } - - errno = 0; - result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val); - if (result != 0) { - qFatal("QBBWindow: failed to set window pixel format, errno=%d", errno); - } - - errno = 0; - result = screen_create_window_buffers(m_window, MAX_BUFFER_COUNT); - if (result != 0) { - qFatal("QBBWindow: failed to create window buffers, errno=%d", errno); - } - } - - // Cache new buffer size - m_bufferSize = size; - - // Buffers were destroyed; reacquire them - m_currentBufferIndex = -1; - m_previousDirty = QRegion(); - m_scrolled = QRegion(); -} - -QBBBuffer &QBBWindow::renderBuffer() -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window(); -#endif - // Check if render buffer is invalid - if (m_currentBufferIndex == -1) { - // Get all buffers available for rendering - errno = 0; - screen_buffer_t buffers[MAX_BUFFER_COUNT]; - int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)buffers); - if (result != 0) { - qFatal("QBBWindow: failed to query window buffers, errno=%d", errno); - } - - // Wrap each buffer - for (int i = 0; i < MAX_BUFFER_COUNT; ++i) { - m_buffers[i] = QBBBuffer(buffers[i]); - } - - // Use the first available render buffer - m_currentBufferIndex = 0; - m_previousBufferIndex = -1; - } - - return m_buffers[m_currentBufferIndex]; -} - -void QBBWindow::scroll(const QRegion ®ion, int dx, int dy, bool flush) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window(); -#endif - copyBack(region, dx, dy, flush); - m_scrolled += region; -} - -void QBBWindow::post(const QRegion &dirty) -{ - // Check if render buffer exists and something was rendered - if (m_currentBufferIndex != -1 && !dirty.isEmpty()) { -#if defined(QBBWINDOW_DEBUG) - qDebug() << "QBBWindow::post - window =" << window(); -#endif - QBBBuffer ¤tBuffer = m_buffers[m_currentBufferIndex]; - - // Copy unmodified region from old render buffer to new render buffer; - // required to allow partial updates - QRegion preserve = m_previousDirty - dirty - m_scrolled; - copyBack(preserve, 0, 0); - - // Calculate region that changed - QRegion modified = preserve + dirty + m_scrolled; - QRect rect = modified.boundingRect(); - int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() }; - - // Update the display with contents of render buffer - errno = 0; - int result = screen_post_window(m_window, currentBuffer.nativeBuffer(), 1, dirtyRect, 0); - if (result != 0) { - qFatal("QBBWindow: failed to post window buffer, errno=%d", errno); - } - - // Advance to next nender buffer - m_previousBufferIndex = m_currentBufferIndex++; - if (m_currentBufferIndex >= MAX_BUFFER_COUNT) { - m_currentBufferIndex = 0; - } - - // Save modified region and clear scrolled region - m_previousDirty = dirty; - m_scrolled = QRegion(); - - // Notify screen that window posted - if (m_screen != 0) { - m_screen->onWindowPost(this); - } - } -} - -void QBBWindow::setScreen(QBBScreen *platformScreen) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window() << "platformScreen =" << platformScreen; -#endif - - if (m_screen == platformScreen) - return; - - m_screen = platformScreen; - - // Move window to proper screen/display - errno = 0; - screen_display_t display = platformScreen->nativeDisplay(); - int result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display); - if (result != 0) { - qFatal("QBBWindow: failed to set window display, errno=%d", errno); - } - - // Add window to display's window group - errno = 0; - result = screen_join_window_group(m_window, platformScreen->windowGroupName()); - if (result != 0) { - qFatal("QBBWindow: failed to join window group, errno=%d", errno); - } - - QList::iterator it; - for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) { - // Only subwindows and tooltips need necessarily be moved to another display with the window. - if ((window()->windowType() & Qt::WindowType_Mask) == Qt::SubWindow || - (window()->windowType() & Qt::WindowType_Mask) == Qt::ToolTip) - (*it)->setScreen(platformScreen); - } - - QBBScreen::updateHierarchy(); -} - -void QBBWindow::removeFromParent() -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window(); -#endif - // Remove from old Hierarchy position - if (m_parentWindow) { - if (m_parentWindow->m_childWindows.removeAll(this)) - m_parentWindow = 0; - else - qFatal("QBBWindow: Window Hierarchy broken; window has parent, but parent hasn't got child."); - } else { - QBBScreen::removeWindow(this); - } -} - -void QBBWindow::setParent(const QPlatformWindow *window) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << this->window() << "platformWindow =" << window; -#endif - // Cast away the const, we need to modify the hierarchy. - QBBWindow *newParent = 0; - - if (window) - newParent = static_cast((QPlatformWindow *)window); - - if (newParent == m_parentWindow) - return; - - removeFromParent(); - m_parentWindow = newParent; - - // Add to new hierarchy position. - if (m_parentWindow) { - if (m_parentWindow->m_screen != m_screen) - setScreen(m_parentWindow->m_screen); - - m_parentWindow->m_childWindows.push_back(this); - } else { - QBBScreen::addWindow(this); - } - - QBBScreen::updateHierarchy(); -} - -void QBBWindow::raise() -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window(); -#endif - - QBBWindow *oldParent = m_parentWindow; - if (oldParent) { - removeFromParent(); - oldParent->m_childWindows.push_back(this); - } else { - QBBScreen::raiseWindow(this); - } - - QBBScreen::updateHierarchy(); -} - -void QBBWindow::lower() -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window(); -#endif - - QBBWindow *oldParent = m_parentWindow; - if (oldParent) { - removeFromParent(); - oldParent->m_childWindows.push_front(this); - } else { - QBBScreen::lowerWindow(this); - } - - QBBScreen::updateHierarchy(); -} - -void QBBWindow::requestActivateWindow() -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window(); -#endif - - // TODO: Tell screen to set keyboard focus to this window. - - // Notify that we gained focus. - gainedFocus(); -} - -void QBBWindow::gainedFocus() -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window(); -#endif - - // Got focus - QWindowSystemInterface::handleWindowActivated(window()); -} - -void QBBWindow::setPlatformOpenGLContext(QBBGLContext *platformOpenGLContext) -{ - // This function does not take ownership of the platform gl context. - // It is owned by the frontend QOpenGLContext - m_platformOpenGLContext = platformOpenGLContext; -} - -void QBBWindow::updateZorder(int &topZorder) -{ - errno = 0; - int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, &topZorder); - topZorder++; - - if (result != 0) - qFatal("QBBWindow: failed to set window z-order=%d, errno=%d, mWindow=%p", topZorder, errno, m_window); - - QList::const_iterator it; - - for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) - (*it)->updateZorder(topZorder); -} - -void QBBWindow::copyBack(const QRegion ®ion, int dx, int dy, bool flush) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO << "window =" << window(); -#endif - int result; - - // Abort if previous buffer is invalid - if (m_previousBufferIndex == -1) { - return; - } - - // Abort if nothing to copy - if (region.isEmpty()) { - return; - } - - QBBBuffer ¤tBuffer = m_buffers[m_currentBufferIndex]; - QBBBuffer &previousBuffer = m_buffers[m_previousBufferIndex]; - - // Break down region into non-overlapping rectangles - QVector rects = region.rects(); - for (int i = rects.size() - 1; i >= 0; i--) { - // Clip rectangle to bounds of target - QRect rect = rects[i].intersected( currentBuffer.rect() ); - - if (rect.isEmpty()) - continue; - - // Setup blit operation - int attribs[] = { SCREEN_BLIT_SOURCE_X, rect.x(), - SCREEN_BLIT_SOURCE_Y, rect.y(), - SCREEN_BLIT_SOURCE_WIDTH, rect.width(), - SCREEN_BLIT_SOURCE_HEIGHT, rect.height(), - SCREEN_BLIT_DESTINATION_X, rect.x() + dx, - SCREEN_BLIT_DESTINATION_Y, rect.y() + dy, - SCREEN_BLIT_DESTINATION_WIDTH, rect.width(), - SCREEN_BLIT_DESTINATION_HEIGHT, rect.height(), - SCREEN_BLIT_END }; - - // Queue blit operation - errno = 0; - result = screen_blit(m_screenContext, currentBuffer.nativeBuffer(), previousBuffer.nativeBuffer(), attribs); - if (result != 0) { - qFatal("QBBWindow: failed to blit buffers, errno=%d", errno); - } - } - - // Check if flush requested - if (flush) { - // Wait for all blits to complete - errno = 0; - result = screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE); - if (result != 0) { - qFatal("QBBWindow: failed to flush blits, errno=%d", errno); - } - - // Buffer was modified outside the CPU - currentBuffer.invalidateInCache(); - } -} - -int QBBWindow::platformWindowFormatToNativeFormat(const QSurfaceFormat &format) -{ -#if defined(QBBWINDOW_DEBUG) - qDebug() << Q_FUNC_INFO; -#endif - // Extract size of colour channels from window format - int redSize = format.redBufferSize(); - if (redSize == -1) { - qFatal("QBBWindow: red size not defined"); - } - - int greenSize = format.greenBufferSize(); - if (greenSize == -1) { - qFatal("QBBWindow: green size not defined"); - } - - int blueSize = format.blueBufferSize(); - if (blueSize == -1) { - qFatal("QBBWindow: blue size not defined"); - } - - // select matching native format - if (redSize == 5 && greenSize == 6 && blueSize == 5) { - return SCREEN_FORMAT_RGB565; - } else if (redSize == 8 && greenSize == 8 && blueSize == 8) { - return SCREEN_FORMAT_RGBA8888; - } else { - qFatal("QBBWindow: unsupported pixel format"); - return 0; - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/blackberry/qbbwindow.h b/src/plugins/platforms/blackberry/qbbwindow.h deleted file mode 100644 index ffdeba423a..0000000000 --- a/src/plugins/platforms/blackberry/qbbwindow.h +++ /dev/null @@ -1,133 +0,0 @@ -/*************************************************************************** -** -** Copyright (C) 2011 - 2012 Research In Motion -** Contact: http://www.qt-project.org/ -** -** This file is part of the plugins 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 QBBWINDOW_H -#define QBBWINDOW_H - -#include - -#include "qbbbuffer.h" - -#include - -#include - -#include - -QT_BEGIN_NAMESPACE - -// all surfaces double buffered -#define MAX_BUFFER_COUNT 2 - -class QBBGLContext; -class QBBScreen; - -class QPlatformGLContext; -class QSurfaceFormat; - -class QBBWindow : public QPlatformWindow -{ -friend class QBBScreen; -public: - QBBWindow(QWindow *window, screen_context_t context); - virtual ~QBBWindow(); - - virtual void setGeometry(const QRect &rect); - virtual void setVisible(bool visible); - virtual void setOpacity(qreal level); - - virtual WId winId() const { return (WId)m_window; } - screen_window_t nativeHandle() const { return m_window; } - - void setBufferSize(const QSize &size); - QSize bufferSize() const { return m_bufferSize; } - bool hasBuffers() const { return !m_bufferSize.isEmpty(); } - - QBBBuffer &renderBuffer(); - void scroll(const QRegion ®ion, int dx, int dy, bool flush=false); - void post(const QRegion &dirty); - - void setScreen(QBBScreen *platformScreen); - - virtual void setParent(const QPlatformWindow *window); - virtual void raise(); - virtual void lower(); - virtual void requestActivateWindow(); - - void gainedFocus(); - - QBBScreen *screen() const { return m_screen; } - const QList& children() const { return m_childWindows; } - - void setPlatformOpenGLContext(QBBGLContext *platformOpenGLContext); - QBBGLContext *platformOpenGLContext() const { return m_platformOpenGLContext; } - -private: - void removeFromParent(); - void offset(const QPoint &offset); - void updateVisibility(bool parentVisible); - void updateZorder(int &topZorder); - - void fetchBuffers(); - - void copyBack(const QRegion ®ion, int dx, int dy, bool flush=false); - - static int platformWindowFormatToNativeFormat(const QSurfaceFormat &format); - - screen_context_t m_screenContext; - screen_window_t m_window; - QSize m_bufferSize; - QBBBuffer m_buffers[MAX_BUFFER_COUNT]; - int m_currentBufferIndex; - int m_previousBufferIndex; - QRegion m_previousDirty; - QRegion m_scrolled; - - QBBGLContext *m_platformOpenGLContext; - QBBScreen *m_screen; - QList m_childWindows; - QBBWindow *m_parentWindow; - bool m_visible; -}; - -QT_END_NAMESPACE - -#endif // QBBWINDOW_H diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 52d3d83bbc..c97c1def0c 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -13,5 +13,5 @@ mac { win32: SUBDIRS += windows qnx-*-qcc { - SUBDIRS += blackberry + SUBDIRS += qnx } diff --git a/src/plugins/platforms/qnx/main.cpp b/src/plugins/platforms/qnx/main.cpp new file mode 100644 index 0000000000..b1e1687150 --- /dev/null +++ b/src/plugins/platforms/qnx/main.cpp @@ -0,0 +1,72 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 +#include "qqnxintegration.h" + +QT_BEGIN_NAMESPACE + +class QQnxIntegrationPlugin : public QPlatformIntegrationPlugin +{ +public: + QStringList keys() const; + QPlatformIntegration *create(const QString&, const QStringList&); +}; + +QStringList QQnxIntegrationPlugin::keys() const +{ + QStringList list; + list << QLatin1String("qnx"); + return list; +} + +QPlatformIntegration *QQnxIntegrationPlugin::create(const QString& system, const QStringList& paramList) +{ + Q_UNUSED(paramList); + if (system.toLower() == QLatin1String("qnx")) + return new QQnxIntegration; + + return 0; +} + +Q_EXPORT_PLUGIN2(qnx, QQnxIntegrationPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro new file mode 100644 index 0000000000..1bd3548b7d --- /dev/null +++ b/src/plugins/platforms/qnx/qnx.pro @@ -0,0 +1,71 @@ +TARGET = qnx +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms +QT += opengl opengl-private platformsupport platformsupport-private widgets-private + +# Uncomment this to build with support for IMF once it becomes available in the BBNDK +#CONFIG += qqnx_imf + +# Uncomment these to enable debugging output for various aspects of the plugin +#DEFINES += QQNXBUFFER_DEBUG +#DEFINES += QQNXCLIPBOARD_DEBUG +#DEFINES += QQNXEVENTTHREAD_DEBUG +#DEFINES += QQNXGLBACKINGSTORE_DEBUG +#DEFINES += QQNXGLCONTEXT_DEBUG +#DEFINES += QQNXINPUTCONTEXT_DEBUG +#DEFINES += QQNXINPUTCONTEXT_IMF_EVENT_DEBUG +#DEFINES += QQNXINTEGRATION_DEBUG +#DEFINES += QQNXNAVIGATORTHREAD_DEBUG +#DEFINES += QQNXRASTERBACKINGSTORE_DEBUG +#DEFINES += QQNXROOTWINDOW_DEBUG +#DEFINES += QQNXSCREEN_DEBUG +#DEFINES += QQNXVIRTUALKEYBOARD_DEBUG +#DEFINES += QQNXWINDOW_DEBUG + +SOURCES = main.cpp \ + qqnxbuffer.cpp \ + qqnxeventthread.cpp \ + qqnxglcontext.cpp \ + qqnxglbackingstore.cpp \ + qqnxintegration.cpp \ + qqnxnavigatorthread.cpp \ + qqnxscreen.cpp \ + qqnxwindow.cpp \ + qqnxrasterbackingstore.cpp \ + qqnxvirtualkeyboard.cpp \ + qqnxclipboard.cpp \ + qqnxrootwindow.cpp + +HEADERS = qqnxbuffer.h \ + qqnxeventthread.h \ + qqnxkeytranslator.h \ + qqnxintegration.h \ + qqnxnavigatorthread.h \ + qqnxglcontext.h \ + qqnxglbackingstore.h \ + qqnxscreen.h \ + qqnxwindow.h \ + qqnxrasterbackingstore.h \ + qqnxvirtualkeyboard.h \ + qqnxclipboard.h \ + qqnxrootwindow.h + +CONFIG(qqnx_imf) { + DEFINES += QQNX_IMF + HEADERS += qqnxinputcontext_imf.h + SOURCES += qqnxinputcontext_imf.cpp +} else { + HEADERS += qqnxinputcontext_noimf.h + SOURCES += qqnxinputcontext_noimf.cpp +} + +QMAKE_CXXFLAGS += -I./private + +LIBS += -lpps -lscreen -lEGL -lclipboard + +include (../../../platformsupport/eglconvenience/eglconvenience.pri) +include (../../../platformsupport/fontdatabases/fontdatabases.pri) + +target.path += $$[QT_INSTALL_PLUGINS]/platforms +INSTALLS += target diff --git a/src/plugins/platforms/qnx/qqnxbuffer.cpp b/src/plugins/platforms/qnx/qqnxbuffer.cpp new file mode 100644 index 0000000000..048aec8ff6 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxbuffer.cpp @@ -0,0 +1,165 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxbuffer.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +QQnxBuffer::QQnxBuffer() + : m_buffer(0) +{ +#if defined(QQNXBUFFER_DEBUG) + qDebug() << "QQnxBuffer::QQnxBuffer - empty"; +#endif +} + +QQnxBuffer::QQnxBuffer(screen_buffer_t buffer) + : m_buffer(buffer) +{ +#if defined(QQNXBUFFER_DEBUG) + qDebug() << "QQnxBuffer::QQnxBuffer - normal"; +#endif + + // Get size of buffer + errno = 0; + int size[2]; + int result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_BUFFER_SIZE, size); + if (result != 0) { + qFatal("QQNX: failed to query buffer size, errno=%d", errno); + } + + // Get stride of buffer + errno = 0; + int stride; + result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride); + if (result != 0) { + qFatal("QQNX: failed to query buffer stride, errno=%d", errno); + } + + // Get access to buffer's data + errno = 0; + uchar *dataPtr = 0; + result = screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, (void **)&dataPtr); + if (result != 0) { + qFatal("QQNX: failed to query buffer pointer, errno=%d", errno); + } + if (dataPtr == NULL) { + qFatal("QQNX: buffer pointer is NULL, errno=%d", errno); + } + + // Get format of buffer + errno = 0; + int screenFormat; + result = screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_FORMAT, &screenFormat); + if (result != 0) { + qFatal("QQNX: failed to query buffer format, errno=%d", errno); + } + + // Convert screen format to QImage format + QImage::Format imageFormat = QImage::Format_Invalid; + switch (screenFormat) { + case SCREEN_FORMAT_RGBX4444: + imageFormat = QImage::Format_RGB444; + break; + case SCREEN_FORMAT_RGBA4444: + imageFormat = QImage::Format_ARGB4444_Premultiplied; + break; + case SCREEN_FORMAT_RGBX5551: + imageFormat = QImage::Format_RGB555; + break; + case SCREEN_FORMAT_RGB565: + imageFormat = QImage::Format_RGB16; + break; + case SCREEN_FORMAT_RGBX8888: + imageFormat = QImage::Format_RGB32; + break; + case SCREEN_FORMAT_RGBA8888: + imageFormat = QImage::Format_ARGB32_Premultiplied; + break; + default: + qFatal("QQNX: unsupported buffer format, format=%d", screenFormat); + } + + // wrap buffer in an image + m_image = QImage(dataPtr, size[0], size[1], stride, imageFormat); +} + +QQnxBuffer::QQnxBuffer(const QQnxBuffer &other) + : m_buffer(other.m_buffer), + m_image(other.m_image) +{ +#if defined(QQNXBUFFER_DEBUG) + qDebug() << "QQnxBuffer::QQnxBuffer - copy"; +#endif +} + +QQnxBuffer::~QQnxBuffer() +{ +#if defined(QQNXBUFFER_DEBUG) + qDebug() << "QQnxBuffer::~QQnxBuffer"; +#endif +} + +void QQnxBuffer::invalidateInCache() +{ +#if defined(QQNXBUFFER_DEBUG) + qDebug() << "QQnxBuffer::invalidateInCache"; +#endif + + // Verify native buffer exists + if (m_buffer == 0) { + qFatal("QQNX: can't invalidate cache for null buffer"); + } + + // Evict buffer's data from cache + errno = 0; + int result = msync(m_image.bits(), m_image.height() * m_image.bytesPerLine(), MS_INVALIDATE | MS_CACHE_ONLY); + if (result != 0) { + qFatal("QQNX: failed to invalidate cache, errno=%d", errno); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxbuffer.h b/src/plugins/platforms/qnx/qqnxbuffer.h new file mode 100644 index 0000000000..be8dfcafad --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxbuffer.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXBUFFER_H +#define QQNXBUFFER_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QQnxBuffer +{ +public: + QQnxBuffer(); + QQnxBuffer(screen_buffer_t buffer); + QQnxBuffer(const QQnxBuffer &other); + virtual ~QQnxBuffer(); + + screen_buffer_t nativeBuffer() const { return m_buffer; } + const QImage *image() const { return (m_buffer != NULL) ? &m_image : NULL; } + QImage *image() { return (m_buffer != NULL) ? &m_image : NULL; } + + QRect rect() const { return m_image.rect(); } + + void invalidateInCache(); + +private: + screen_buffer_t m_buffer; + QImage m_image; +}; + +QT_END_NAMESPACE + +#endif // QQNXBUFFER_H diff --git a/src/plugins/platforms/qnx/qqnxclipboard.cpp b/src/plugins/platforms/qnx/qqnxclipboard.cpp new file mode 100644 index 0000000000..8931a15139 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxclipboard.cpp @@ -0,0 +1,244 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QT_NO_CLIPBOARD + +#include "qqnxclipboard.h" + +#include + +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +// null terminated array +static const char *typeList[] = {"text/html", "text/plain", "image/png", "image/jpeg", "application/x-color", 0}; + +static QByteArray readClipboardBuff(const char *type) +{ + char *pbuffer; + if (is_clipboard_format_present(type) == 0) { + int size = get_clipboard_data(type, &pbuffer); + if (size != -1 && pbuffer) { + const QByteArray result = QByteArray(pbuffer, size); + free(pbuffer); + return result; + } + } + + return QByteArray(); +} + +class QQnxClipboard::MimeData : public QMimeData +{ + Q_OBJECT +public: + MimeData(QQnxClipboard *clipboard) + : QMimeData(), + m_clipboard(clipboard), + m_userMimeData(0) + { + Q_ASSERT(clipboard); + + for (int i = 0; typeList[i] != 0; ++i) { + m_formatsToCheck << QString::fromUtf8(typeList[i]); + } + } + + ~MimeData() + { + delete m_userMimeData; + } + + void addFormatToCheck(const QString &format) { + m_formatsToCheck << format; + +#if defined(QQNXCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "formats=" << m_formatsToCheck; +#endif + } + + bool hasFormat(const QString &mimetype) const + { + const bool result = is_clipboard_format_present(mimetype.toUtf8().constData()) == 0; +#if defined(QQNXCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "mimetype=" << mimetype << "result=" << result; +#endif + return result; + } + + QStringList formats() const + { + QStringList result; + + Q_FOREACH (const QString &format, m_formatsToCheck) { + if (is_clipboard_format_present(format.toUtf8().constData()) == 0) + result << format; + } + +#if defined(QQNXCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "result=" << result; +#endif + return result; + } + + void setUserMimeData(QMimeData *userMimeData) + { + delete m_userMimeData; + m_userMimeData = userMimeData; + + // system clipboard API doesn't allow detection of changes by other applications + // simulate an owner change through delayed invocation + // basically transfer ownership of data to the system clipboard once event processing resumes + if (m_userMimeData) + QMetaObject::invokeMethod(this, "releaseOwnership", Qt::QueuedConnection); + } + + QMimeData *userMimeData() + { + return m_userMimeData; + } + +protected: + QVariant retrieveData(const QString &mimetype, QVariant::Type preferredType) const + { +#if defined(QQNXCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "mimetype=" << mimetype << "preferredType=" << preferredType; +#endif + if (is_clipboard_format_present(mimetype.toUtf8().constData()) != 0) + return QMimeData::retrieveData(mimetype, preferredType); + + const QByteArray data = readClipboardBuff(mimetype.toUtf8().constData()); + return qVariantFromValue(data); + } + +private Q_SLOTS: + void releaseOwnership() + { + if (m_userMimeData) { +#if defined(QQNXCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "user data formats=" << m_userMimeData->formats() << "system formats=" << formats(); +#endif + delete m_userMimeData; + m_userMimeData = 0; + m_clipboard->emitChanged(QClipboard::Clipboard); + } + } + +private: + QQnxClipboard * const m_clipboard; + + QSet m_formatsToCheck; + QMimeData *m_userMimeData; +}; + +QQnxClipboard::QQnxClipboard() + : m_mimeData(new MimeData(this)) +{ +} + +QQnxClipboard::~QQnxClipboard() +{ + delete m_mimeData; +} + +void QQnxClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) +{ + if (mode != QClipboard::Clipboard) + return; + + if (data == m_mimeData || data == m_mimeData->userMimeData()) + return; + + empty_clipboard(); + + m_mimeData->clear(); + m_mimeData->setUserMimeData(data); + + if (data == 0) + return; + + const QStringList formats = data->formats(); +#if defined(QQNXCLIPBOARD_DEBUG) + qDebug() << Q_FUNC_INFO << "formats=" << formats; +#endif + + Q_FOREACH (const QString &format, formats) { + const QByteArray buf = data->data(format); + + if (buf.isEmpty()) + continue; + + int ret = set_clipboard_data(format.toUtf8().data(), buf.size(), buf.data()); +#if defined(QQNXCLIPBOARD_DEBUG) + qDebug() << "QQNX: set " << format << "to clipboard, size=" << buf.size() << ";ret=" << ret; +#endif + if (ret) + m_mimeData->addFormatToCheck(format); + } + + emitChanged(QClipboard::Clipboard); +} + +QMimeData *QQnxClipboard::mimeData(QClipboard::Mode mode) +{ + if (mode != QClipboard::Clipboard) + return 0; + + if (m_mimeData->userMimeData()) + return m_mimeData->userMimeData(); + + m_mimeData->clear(); + + return m_mimeData; +} + +QT_END_NAMESPACE + +#include "qqnxclipboard.moc" + +#endif //QT_NO_CLIPBOARD diff --git a/src/plugins/platforms/qnx/qqnxclipboard.h b/src/plugins/platforms/qnx/qqnxclipboard.h new file mode 100644 index 0000000000..1104885d8c --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxclipboard.h @@ -0,0 +1,66 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXCLIPBOARD_H +#define QQNXCLIPBOARD_H + +#ifndef QT_NO_CLIPBOARD +#include + +QT_BEGIN_NAMESPACE + +class QQnxClipboard : public QPlatformClipboard +{ +public: + QQnxClipboard(); + virtual ~QQnxClipboard(); + virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard); + virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); + +private: + class MimeData; + MimeData *m_mimeData; +}; + +QT_END_NAMESPACE + +#endif //QT_NO_CLIPBOARD +#endif //QQNXCLIPBOARD_H diff --git a/src/plugins/platforms/qnx/qqnxeventthread.cpp b/src/plugins/platforms/qnx/qqnxeventthread.cpp new file mode 100644 index 0000000000..cd30da1971 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxeventthread.cpp @@ -0,0 +1,572 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxeventthread.h" +#include "qqnxintegration.h" +#include "qqnxkeytranslator.h" + +#if defined(QQNX_IMF) +#include "qqnxinputcontext_imf.h" +#else +#include "qqnxinputcontext_noimf.h" +#endif + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +QQnxEventThread::QQnxEventThread(screen_context_t context, QPlatformScreen& screen) + : QThread(), + m_screenContext(context), + m_platformScreen(screen), + m_quit(false), + m_lastButtonState(Qt::NoButton), + m_lastMouseWindow(0) +{ + // Create a touch device + m_touchDevice = new QTouchDevice; + m_touchDevice->setType(QTouchDevice::TouchScreen); + m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | QTouchDevice::NormalizedPosition); + QWindowSystemInterface::registerTouchDevice(m_touchDevice); + + // initialize array of touch points + for (int i = 0; i < MaximumTouchPoints; i++) { + + // map array index to id + m_touchPoints[i].id = i; + + // pressure is not supported - use default + m_touchPoints[i].pressure = 1.0; + + // nothing touching + m_touchPoints[i].state = Qt::TouchPointReleased; + } +} + +QQnxEventThread::~QQnxEventThread() +{ + // block until thread terminates + shutdown(); +} + +void QQnxEventThread::run() +{ + screen_event_t event; + + // create screen event + errno = 0; + int result = screen_create_event(&event); + if (result) { + qFatal("QQNX: failed to create event, errno=%d", errno); + } + +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: event loop started"; +#endif + + // loop indefinitely + while (!m_quit) { + + // block until screen event is available + errno = 0; + result = screen_get_event(m_screenContext, event, -1); + if (result) { + qFatal("QQNX: failed to get event, errno=%d", errno); + } + + // process received event + dispatchEvent(event); + } + +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: event loop stopped"; +#endif + + // cleanup + screen_destroy_event(event); +} + +void QQnxEventThread::shutdown() +{ + screen_event_t event; + + // create screen event + errno = 0; + int result = screen_create_event(&event); + if (result) { + qFatal("QQNX: failed to create event, errno=%d", errno); + } + + // set the event type as user + errno = 0; + int type = SCREEN_EVENT_USER; + result = screen_set_event_property_iv(event, SCREEN_PROPERTY_TYPE, &type); + if (result) { + qFatal("QQNX: failed to set event type, errno=%d", errno); + } + + // NOTE: ignore SCREEN_PROPERTY_USER_DATA; treat all user events as shutdown events + + // post event to event loop so it will wake up and die + errno = 0; + result = screen_send_event(m_screenContext, event, getpid()); + if (result) { + qFatal("QQNX: failed to set event type, errno=%d", errno); + } + + // cleanup + screen_destroy_event(event); + +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: event loop shutdown begin"; +#endif + + // block until thread terminates + wait(); + +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: event loop shutdown end"; +#endif +} + +void QQnxEventThread::dispatchEvent(screen_event_t event) +{ + // get the event type + errno = 0; + int qnxType; + int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &qnxType); + if (result) { + qFatal("QQNX: failed to query event type, errno=%d", errno); + } + + switch (qnxType) { + case SCREEN_EVENT_MTOUCH_TOUCH: + case SCREEN_EVENT_MTOUCH_MOVE: + case SCREEN_EVENT_MTOUCH_RELEASE: + handleTouchEvent(event, qnxType); + break; + + case SCREEN_EVENT_KEYBOARD: + handleKeyboardEvent(event); + break; + + case SCREEN_EVENT_POINTER: + handlePointerEvent(event); + break; + + case SCREEN_EVENT_CLOSE: + handleCloseEvent(event); + break; + + case SCREEN_EVENT_USER: + // treat all user events as shutdown requests +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: QNX user event"; +#endif + m_quit = true; + break; + + default: + // event ignored +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: QNX unknown event"; +#endif + break; + } +} + +void QQnxEventThread::handleKeyboardEvent(screen_event_t event) +{ + // get flags of key event + errno = 0; + int flags; + int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_FLAGS, &flags); + if (result) { + qFatal("QQNX: failed to query event flags, errno=%d", errno); + } + + // get key code + errno = 0; + int sym; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SYM, &sym); + if (result) { + qFatal("QQNX: failed to query event sym, errno=%d", errno); + } + + int modifiers; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_MODIFIERS, &modifiers); + if (result) { + qFatal("QQNX: failed to query event modifiers, errno=%d", errno); + } + + int scan; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_SCAN, &scan); + if (result) { + qFatal("QQNX: failed to query event modifiers, errno=%d", errno); + } + + int cap; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &cap); + if (result) { + qFatal("QQNX: failed to query event cap, errno=%d", errno); + } + + injectKeyboardEvent(flags, sym, modifiers, scan, cap); +} + +void QQnxEventThread::injectKeyboardEvent(int flags, int sym, int modifiers, int scan, int cap) +{ + Q_UNUSED(scan); + + Qt::KeyboardModifiers qtMod = Qt::NoModifier; + if (modifiers & KEYMOD_SHIFT) + qtMod |= Qt::ShiftModifier; + if (modifiers & KEYMOD_CTRL) + qtMod |= Qt::ControlModifier; + if (modifiers & KEYMOD_ALT) + qtMod |= Qt::AltModifier; + + // determine event type + QEvent::Type type = (flags & KEY_DOWN) ? QEvent::KeyPress : QEvent::KeyRelease; + + // Check if the key cap is valid + if (flags & KEY_CAP_VALID) { + Qt::Key key; + QString keyStr; + + if (cap >= 0x20 && cap <= 0x0ff) { + key = Qt::Key(std::toupper(cap)); // Qt expects the CAP to be upper case. + + if ( qtMod & Qt::ControlModifier ) { + keyStr = QChar((int)(key & 0x3f)); + } else { + if (flags & KEY_SYM_VALID) { + keyStr = QChar(sym); + } + } + } else if ((cap > 0x0ff && cap < UNICODE_PRIVATE_USE_AREA_FIRST) || cap > UNICODE_PRIVATE_USE_AREA_LAST) { + key = (Qt::Key)cap; + keyStr = QChar(sym); + } else { + if (isKeypadKey(cap)) + qtMod |= Qt::KeypadModifier; // Is this right? + key = keyTranslator(cap); + } + + QWindowSystemInterface::handleKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod, keyStr); +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: Qt key t=" << type << ", k=" << key << ", s=" << keyStr; +#endif + } +} + +void QQnxEventThread::handlePointerEvent(screen_event_t event) +{ + errno = 0; + + // Query the window that was clicked + screen_window_t qnxWindow; + void *handle; + int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle); + if (result) { + qFatal("QQNX: failed to query event window, errno=%d", errno); + } + qnxWindow = static_cast(handle); + + // Query the button states + int buttonState = 0; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttonState); + if (result) { + qFatal("QQNX: failed to query event button state, errno=%d", errno); + } + + // Query the window position + int windowPos[2]; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos); + if (result) { + qFatal("QQNX: failed to query event window position, errno=%d", errno); + } + + // Query the screen position + int pos[2]; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos); + if (result) { + qFatal("QQNX: failed to query event position, errno=%d", errno); + } + + // Query the wheel delta + int wheelDelta = 0; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheelDelta); + if (result) { + qFatal("QQNX: failed to query event wheel delta, errno=%d", errno); + } + + // Map window handle to top-level QWindow + QWindow *w = QQnxIntegration::window(qnxWindow); + + // Generate enter and leave events as needed. + if (qnxWindow != m_lastMouseWindow) { + QWindow *wOld = QQnxIntegration::window(m_lastMouseWindow); + + if (wOld) { + QWindowSystemInterface::handleLeaveEvent(wOld); +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: Qt leave, w=" << wOld; +#endif + } + + if (w) { + QWindowSystemInterface::handleEnterEvent(w); +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: Qt enter, w=" << w; +#endif + } + } + m_lastMouseWindow = qnxWindow; + + // Apply scaling to wheel delta and invert value for Qt. We'll probably want to scale + // this via a system preference at some point. But for now this is a sane value and makes + // the wheel usable. + wheelDelta *= -10; + + // convert point to local coordinates + QPoint globalPoint(pos[0], pos[1]); + QPoint localPoint(windowPos[0], windowPos[1]); + + // Convert buttons. + // Some QNX header files invert 'Right Button versus "Left Button' ('Right' == 0x01). But they also offer a 'Button Swap' bit, + // so we may receive events as shown. (If this is wrong, the fix is easy.) + // QNX Button mask is 8 buttons wide, with a maximum value of x080. + Qt::MouseButtons buttons = Qt::NoButton; + if (buttonState & 0x01) + buttons |= Qt::LeftButton; + if (buttonState & 0x02) + buttons |= Qt::MidButton; + if (buttonState & 0x04) + buttons |= Qt::RightButton; + if (buttonState & 0x08) + buttons |= Qt::ExtraButton1; // AKA 'Qt::BackButton' + if (buttonState & 0x10) + buttons |= Qt::ExtraButton2; // AKA 'Qt::ForwardButton' + if (buttonState & 0x20) + buttons |= Qt::ExtraButton3; + if (buttonState & 0x40) + buttons |= Qt::ExtraButton4; + if (buttonState & 0x80) + buttons |= Qt::ExtraButton5; + + if (w) { + // Inject mouse event into Qt only if something has changed. + if (m_lastGlobalMousePoint != globalPoint || + m_lastLocalMousePoint != localPoint || + m_lastButtonState != buttons) { + QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons); +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << static_cast(buttons); +#endif + } + + if (wheelDelta) { + // Screen only supports a single wheel, so we will assume Vertical orientation for + // now since that is pretty much standard. + QWindowSystemInterface::handleWheelEvent(w, localPoint, globalPoint, wheelDelta, Qt::Vertical); +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: Qt wheel, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), d=" << static_cast(wheelDelta); +#endif + } + } + + m_lastGlobalMousePoint = globalPoint; + m_lastLocalMousePoint = localPoint; + m_lastButtonState = buttons; +} + +void QQnxEventThread::handleTouchEvent(screen_event_t event, int qnxType) +{ + // get display coordinates of touch + errno = 0; + int pos[2]; + int result = screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, pos); + if (result) { + qFatal("QQNX: failed to query event position, errno=%d", errno); + } + + // get window coordinates of touch + errno = 0; + int windowPos[2]; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, windowPos); + if (result) { + qFatal("QQNX: failed to query event window position, errno=%d", errno); + } + + // determine which finger touched + errno = 0; + int touchId; + result = screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touchId); + if (result) { + qFatal("QQNX: failed to query event touch id, errno=%d", errno); + } + + // determine which window was touched + errno = 0; + void *handle; + result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle); + if (result) { + qFatal("QQNX: failed to query event window, errno=%d", errno); + } + screen_window_t qnxWindow = static_cast(handle); + + // check if finger is valid + if (touchId < MaximumTouchPoints) { + + // Map window handle to top-level QWindow + QWindow *w = QQnxIntegration::window(qnxWindow); + + // Generate enter and leave events as needed. + if (qnxWindow != m_lastMouseWindow) { + QWindow *wOld = QQnxIntegration::window(m_lastMouseWindow); + + if (wOld) { + QWindowSystemInterface::handleLeaveEvent(wOld); + #if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: Qt leave, w=" << wOld; + #endif + } + + if (w) { + QWindowSystemInterface::handleEnterEvent(w); + #if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: Qt enter, w=" << w; + #endif + } + } + m_lastMouseWindow = qnxWindow; + + if (w) { + // convert primary touch to mouse event + if (touchId == 0) { + + // convert point to local coordinates + QPoint globalPoint(pos[0], pos[1]); + QPoint localPoint(windowPos[0], windowPos[1]); + + // map touch state to button state + Qt::MouseButtons buttons = (qnxType == SCREEN_EVENT_MTOUCH_RELEASE) ? Qt::NoButton : Qt::LeftButton; + + // inject event into Qt + QWindowSystemInterface::handleMouseEvent(w, localPoint, globalPoint, buttons); +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: Qt mouse, w=" << w << ", (" << localPoint.x() << "," << localPoint.y() << "), b=" << buttons; +#endif + } + + // get size of screen which contains window + QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(w); + QSizeF screenSize = platformScreen->physicalSize(); + + // update cached position of current touch point + m_touchPoints[touchId].normalPosition = QPointF( static_cast(pos[0]) / screenSize.width(), static_cast(pos[1]) / screenSize.height() ); + m_touchPoints[touchId].area = QRectF( pos[0], pos[1], 0.0, 0.0 ); + + // determine event type and update state of current touch point + QEvent::Type type = QEvent::None; + switch (qnxType) { + case SCREEN_EVENT_MTOUCH_TOUCH: + m_touchPoints[touchId].state = Qt::TouchPointPressed; + type = QEvent::TouchBegin; + break; + case SCREEN_EVENT_MTOUCH_MOVE: + m_touchPoints[touchId].state = Qt::TouchPointMoved; + type = QEvent::TouchUpdate; + break; + case SCREEN_EVENT_MTOUCH_RELEASE: + m_touchPoints[touchId].state = Qt::TouchPointReleased; + type = QEvent::TouchEnd; + break; + } + + // build list of active touch points + QList pointList; + for (int i = 0; i < MaximumTouchPoints; i++) { + if (i == touchId) { + // current touch point is always active + pointList.append(m_touchPoints[i]); + } else if (m_touchPoints[i].state != Qt::TouchPointReleased) { + // finger is down but did not move + m_touchPoints[i].state = Qt::TouchPointStationary; + pointList.append(m_touchPoints[i]); + } + } + + // inject event into Qt + QWindowSystemInterface::handleTouchEvent(w, m_touchDevice, pointList); +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: Qt touch, w=" << w << ", p=(" << pos[0] << "," << pos[1] << "), t=" << type; +#endif + } + } +} + +void QQnxEventThread::handleCloseEvent(screen_event_t event) +{ + // Query the window that was closed + void *handle; + int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle); + if (result != 0) { + qFatal("QQNX: failed to query event window, errno=%d", errno); + } + screen_window_t qnxWindow = static_cast(handle); + + // Map window handle to top-level QWindow + QWindow *w = QQnxIntegration::window(qnxWindow); + if (w != 0) { + QWindowSystemInterface::handleCloseEvent(w); + } +} + diff --git a/src/plugins/platforms/qnx/qqnxeventthread.h b/src/plugins/platforms/qnx/qqnxeventthread.h new file mode 100644 index 0000000000..61831233e9 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxeventthread.h @@ -0,0 +1,90 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXEVENTTHREAD_H +#define QQNXEVENTTHREAD_H + +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QQnxEventThread : public QThread +{ +public: + QQnxEventThread(screen_context_t context, QPlatformScreen& screen); + virtual ~QQnxEventThread(); + + static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap); + +protected: + virtual void run(); + +private: + enum { + MaximumTouchPoints = 10 + }; + + void shutdown(); + void dispatchEvent(screen_event_t event); + void handleKeyboardEvent(screen_event_t event); + void handlePointerEvent(screen_event_t event); + void handleTouchEvent(screen_event_t event, int type); + void handleCloseEvent(screen_event_t event); + + screen_context_t m_screenContext; + QPlatformScreen& m_platformScreen; + bool m_quit; + QPoint m_lastGlobalMousePoint; + QPoint m_lastLocalMousePoint; + Qt::MouseButtons m_lastButtonState; + screen_window_t m_lastMouseWindow; + QTouchDevice *m_touchDevice; + QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints]; +}; + +QT_END_NAMESPACE + +#endif // QQNXEVENTTHREAD_H diff --git a/src/plugins/platforms/qnx/qqnxglbackingstore.cpp b/src/plugins/platforms/qnx/qqnxglbackingstore.cpp new file mode 100644 index 0000000000..97a03e0042 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxglbackingstore.cpp @@ -0,0 +1,189 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxglbackingstore.h" +#include "qqnxglcontext.h" +#include "qqnxwindow.h" +#include "qqnxscreen.h" + +#include + +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +QQnxGLPaintDevice::QQnxGLPaintDevice(QWindow *window) + : QGLPaintDevice(), + m_window(0), + m_glContext(0) +{ + m_window = static_cast(window->handle()); + + // Extract the QPlatformOpenGLContext from the window + QPlatformOpenGLContext *platformOpenGLContext = m_window->platformOpenGLContext(); + + // Convert this to a QGLContext + m_glContext = QGLContext::fromOpenGLContext(platformOpenGLContext->context()); +} + +QQnxGLPaintDevice::~QQnxGLPaintDevice() +{ + // Cleanup GL context + delete m_glContext; +} + +QPaintEngine *QQnxGLPaintDevice::paintEngine() const +{ + // Select a paint engine based on configued OpenGL version + return qt_qgl_paint_engine(); +} + +QSize QQnxGLPaintDevice::size() const +{ + // Get size of EGL surface + return m_window->geometry().size(); +} + + +QQnxGLBackingStore::QQnxGLBackingStore(QWindow *window) + : QPlatformBackingStore(window), + m_openGLContext(0), + m_paintDevice(0), + m_requestedSize(), + m_size() +{ +#if defined(QQNXGLBACKINGSTORE_DEBUG) + qDebug() << "QQnxGLBackingStore::QQnxGLBackingStore - w=" << window; +#endif + + // Create an OpenGL paint device which in turn creates a QGLContext for us + m_paintDevice = new QQnxGLPaintDevice(window); + m_openGLContext = m_paintDevice->context()->contextHandle(); +} + +QQnxGLBackingStore::~QQnxGLBackingStore() +{ +#if defined(QQNXGLBACKINGSTORE_DEBUG) + qDebug() << "QQnxGLBackingStore::~QQnxGLBackingStore - w=" << window(); +#endif + + // cleanup OpenGL paint device + delete m_paintDevice; +} + +void QQnxGLBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(region); + Q_UNUSED(offset); + +#if defined(QQNXGLBACKINGSTORE_DEBUG) + qDebug() << "QQnxGLBackingStore::flush - w=" << window; +#endif + + // update the display with newly rendered content + m_openGLContext->swapBuffers(window); +} + +void QQnxGLBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + Q_UNUSED(staticContents); +#if defined(QQNXGLBACKINGSTORE_DEBUG) + qDebug() << "QQnxGLBackingStore::resize - w=" << window() << ", s=" << size; +#endif + // NOTE: defer resizing window buffers until next paint as + // resize() can be called multiple times before a paint occurs + m_requestedSize = size; +} + +void QQnxGLBackingStore::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); + +#if defined(QQNXGLBACKINGSTORE_DEBUG) + qDebug() << "QQnxGLBackingStore::beginPaint - w=" << window(); +#endif + + // resize EGL surface if window surface resized + if (m_size != m_requestedSize) { + resizeSurface(m_requestedSize); + } +} + +void QQnxGLBackingStore::endPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +#if defined(QQNXGLBACKINGSTORE_DEBUG) + qDebug() << "QQnxGLBackingStore::endPaint - w=" << window(); +#endif +} + +void QQnxGLBackingStore::resizeSurface(const QSize &size) +{ + // need to destroy surface so make sure its not current + bool restoreCurrent = false; + QQnxGLContext *platformContext = static_cast(m_openGLContext->handle()); + if (platformContext->isCurrent()) { + m_openGLContext->doneCurrent(); + restoreCurrent = true; + } + + // destroy old EGL surface + platformContext->destroySurface(); + + // resize window's buffers + static_cast(window()->handle())->setBufferSize(size); + + // re-create EGL surface with new size + m_size = size; + platformContext->createSurface(window()->handle()); + + // make context current again + if (restoreCurrent) { + m_openGLContext->makeCurrent(window()); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglbackingstore.h b/src/plugins/platforms/qnx/qqnxglbackingstore.h new file mode 100644 index 0000000000..d04fe22f5d --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxglbackingstore.h @@ -0,0 +1,95 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXGLBACKINGSTORE_H +#define QQNXGLBACKINGSTORE_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QGLContext; +class QQnxGLContext; +class QQnxScreen; +class QQnxWindow; + +class QQnxGLPaintDevice : public QGLPaintDevice +{ +public: + QQnxGLPaintDevice(QWindow *window); + virtual ~QQnxGLPaintDevice(); + + virtual QPaintEngine *paintEngine() const; + virtual QSize size() const; + virtual QGLContext *context() const { return m_glContext; } + +private: + QQnxWindow *m_window; + QGLContext *m_glContext; +}; + +class QQnxGLBackingStore : public QPlatformBackingStore +{ +public: + QQnxGLBackingStore(QWindow *window); + virtual ~QQnxGLBackingStore(); + + virtual QPaintDevice *paintDevice() { return m_paintDevice; } + virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + virtual void resize(const QSize &size, const QRegion &staticContents); + virtual void beginPaint(const QRegion ®ion); + virtual void endPaint(const QRegion ®ion); + + void resizeSurface(const QSize &size); + +private: + QOpenGLContext *m_openGLContext; + QQnxGLPaintDevice *m_paintDevice; + QSize m_requestedSize; + QSize m_size; +}; + +QT_END_NAMESPACE + +#endif // QQNXGLBACKINGSTORE_H diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp new file mode 100644 index 0000000000..d620feb710 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -0,0 +1,356 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxglcontext.h" +#include "qqnxrootwindow.h" +#include "qqnxscreen.h" +#include "qqnxwindow.h" + +#include "private/qeglconvenience_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +EGLDisplay QQnxGLContext::ms_eglDisplay = EGL_NO_DISPLAY; + +static EGLenum checkEGLError(const char *msg) +{ + static const char *errmsg[] = + { + "EGL function succeeded", + "EGL is not initialized, or could not be initialized, for the specified display", + "EGL cannot access a requested resource", + "EGL failed to allocate resources for the requested operation", + "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list", + "EGLConfig argument does not name a valid EGLConfig", + "EGLContext argument does not name a valid EGLContext", + "EGL current surface of the calling thread is no longer valid", + "EGLDisplay argument does not name a valid EGLDisplay", + "EGL arguments are inconsistent", + "EGLNativePixmapType argument does not refer to a valid native pixmap", + "EGLNativeWindowType argument does not refer to a valid native window", + "EGL one or more argument values are invalid", + "EGLSurface argument does not name a valid surface configured for rendering", + "EGL power management event has occurred", + }; + EGLenum error = eglGetError(); + fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]); + return error; +} + +QQnxGLContext::QQnxGLContext(QOpenGLContext *glContext) + : QPlatformOpenGLContext(), + m_glContext(glContext), + m_eglSurface(EGL_NO_SURFACE) +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + QSurfaceFormat format = m_glContext->format(); + + // Set current rendering API + EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); + if (eglResult != EGL_TRUE) { + qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); + } + + // Get colour channel sizes from window format + int alphaSize = format.alphaBufferSize(); + int redSize = format.redBufferSize(); + int greenSize = format.greenBufferSize(); + int blueSize = format.blueBufferSize(); + + // Check if all channels are don't care + if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) { + // Set colour channels based on depth of window's screen + QQnxScreen *screen = static_cast(QQnxScreen::screens().first()); + int depth = screen->depth(); + if (depth == 32) { + // SCREEN_FORMAT_RGBA8888 + alphaSize = 8; + redSize = 8; + greenSize = 8; + blueSize = 8; + } else { + // SCREEN_FORMAT_RGB565 + alphaSize = 0; + redSize = 5; + greenSize = 6; + blueSize = 5; + } + } else { + // Choose best match based on supported pixel formats + if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) { + // SCREEN_FORMAT_RGB565 + alphaSize = 0; + redSize = 5; + greenSize = 6; + blueSize = 5; + } else { + // SCREEN_FORMAT_RGBA8888 + alphaSize = 8; + redSize = 8; + greenSize = 8; + blueSize = 8; + } + } + + // Update colour channel sizes in window format + format.setAlphaBufferSize(alphaSize); + format.setRedBufferSize(redSize); + format.setGreenBufferSize(greenSize); + format.setBlueBufferSize(blueSize); + format.setSamples(2); + + // Select EGL config based on requested window format + m_eglConfig = q_configFromGLFormat(ms_eglDisplay, format); + if (m_eglConfig == 0) { + qFatal("QQNXQBBWindow: failed to find EGL config"); + } + + m_eglContext = eglCreateContext(ms_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttrs()); + if (m_eglContext == EGL_NO_CONTEXT) { + checkEGLError("eglCreateContext"); + qFatal("QQNXQBBWindow: failed to create EGL context, err=%d", eglGetError()); + } + + // Query/cache window format of selected EGL config + m_windowFormat = q_glFormatFromConfig(ms_eglDisplay, m_eglConfig); +} + +QQnxGLContext::~QQnxGLContext() +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + // Cleanup EGL context if it exists + if (m_eglContext != EGL_NO_CONTEXT) { + eglDestroyContext(ms_eglDisplay, m_eglContext); + } + + // Cleanup EGL surface if it exists + destroySurface(); +} + +void QQnxGLContext::initialize() +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // Initialize connection to EGL + ms_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (ms_eglDisplay == EGL_NO_DISPLAY) { + checkEGLError("eglGetDisplay"); + qFatal("QQNXQBBWindow: failed to obtain EGL display"); + } + + EGLBoolean eglResult = eglInitialize(ms_eglDisplay, 0, 0); + if (eglResult != EGL_TRUE) { + checkEGLError("eglInitialize"); + qFatal("QQNXQBBWindow: failed to initialize EGL display, err=%d", eglGetError()); + } +} + +void QQnxGLContext::shutdown() +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // Close connection to EGL + eglTerminate(ms_eglDisplay); +} + +bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // Set current rendering API + EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); + if (eglResult != EGL_TRUE) { + qFatal("QQNXQBBWindow: failed to set EGL API, err=%d", eglGetError()); + } + + if (m_eglSurface == EGL_NO_SURFACE) + createSurface(surface); + + eglResult = eglMakeCurrent(ms_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); + if (eglResult != EGL_TRUE) { + checkEGLError("eglMakeCurrent"); + qFatal("QQNX: failed to set current EGL context, err=%d", eglGetError()); + } + return (eglResult == EGL_TRUE); +} + +void QQnxGLContext::doneCurrent() +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // set current rendering API + EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); + if (eglResult != EGL_TRUE) { + qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); + } + + // clear curent EGL context and unbind EGL surface + eglResult = eglMakeCurrent(ms_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (eglResult != EGL_TRUE) { + qFatal("QQNX: failed to clear current EGL context, err=%d", eglGetError()); + } +} + +void QQnxGLContext::swapBuffers(QPlatformSurface *surface) +{ + Q_UNUSED(surface); +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + // Set current rendering API + EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); + if (eglResult != EGL_TRUE) { + qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); + } + + // Post EGL surface to window + eglResult = eglSwapBuffers(ms_eglDisplay, m_eglSurface); + if (eglResult != EGL_TRUE) { + qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError()); + } +} + +QFunctionPointer QQnxGLContext::getProcAddress(const QByteArray &procName) +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + // Set current rendering API + EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); + if (eglResult != EGL_TRUE) { + qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); + } + + // Lookup EGL extension function pointer + return static_cast(eglGetProcAddress(procName.constData())); +} + +EGLint *QQnxGLContext::contextAttrs() +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + // Choose EGL settings based on OpenGL version +#if defined(QT_OPENGL_ES_2) + static EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + return attrs; +#else + return 0; +#endif +} + +bool QQnxGLContext::isCurrent() const +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + return (eglGetCurrentContext() == m_eglContext); +} + +void QQnxGLContext::createSurface(QPlatformSurface *surface) +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // Get a pointer to the corresponding platform window + QQnxWindow *platformWindow = dynamic_cast(surface); + if (!platformWindow) { + qFatal("QQNX: unable to create EGLSurface without a QQnxWindow"); + } + + // If the platform window does not yet have any buffers, we create + // a temporary set of buffers with a size of 1x1 pixels. This will + // suffice until such time as the platform window has obtained + // buffers of the proper size + if (!platformWindow->hasBuffers()) { + platformWindow->setPlatformOpenGLContext(this); + m_surfaceSize = platformWindow->geometry().size(); + platformWindow->setBufferSize(m_surfaceSize); + } + + // Obtain the native handle for our window + screen_window_t handle = platformWindow->nativeHandle(); + + const EGLint eglSurfaceAttrs[] = + { + EGL_RENDER_BUFFER, EGL_BACK_BUFFER, + EGL_NONE + }; + + // Create EGL surface + m_eglSurface = eglCreateWindowSurface(ms_eglDisplay, m_eglConfig, (EGLNativeWindowType) handle, eglSurfaceAttrs); + if (m_eglSurface == EGL_NO_SURFACE) { + checkEGLError("eglCreateWindowSurface"); + qFatal("QQNX: failed to create EGL surface, err=%d", eglGetError()); + } +} + +void QQnxGLContext::destroySurface() +{ +#if defined(QQNXGLCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + // Destroy EGL surface if it exists + if (m_eglSurface != EGL_NO_SURFACE) { + EGLBoolean eglResult = eglDestroySurface(ms_eglDisplay, m_eglSurface); + if (eglResult != EGL_TRUE) { + qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError()); + } + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglcontext.h b/src/plugins/platforms/qnx/qqnxglcontext.h new file mode 100644 index 0000000000..36c439802a --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxglcontext.h @@ -0,0 +1,93 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXGLCONTEXT_H +#define QQNXGLCONTEXT_H + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QQnxWindow; + +class QQnxGLContext : public QPlatformOpenGLContext +{ +public: + QQnxGLContext(QOpenGLContext *glContext); + virtual ~QQnxGLContext(); + + static void initialize(); + static void shutdown(); + + virtual bool makeCurrent(QPlatformSurface *surface); + virtual void doneCurrent(); + virtual void swapBuffers(QPlatformSurface *surface); + virtual QFunctionPointer getProcAddress(const QByteArray &procName); + + virtual QSurfaceFormat format() const { return m_windowFormat; } + + bool isCurrent() const; + + void createSurface(QPlatformSurface *surface); + void destroySurface(); + +private: + /** \todo Should this be non-static so we can use additional displays? */ + static EGLDisplay ms_eglDisplay; + + QSurfaceFormat m_windowFormat; + QOpenGLContext *m_glContext; + + EGLConfig m_eglConfig; + EGLContext m_eglContext; + EGLSurface m_eglSurface; + QSize m_surfaceSize; + + static EGLint *contextAttrs(); +}; + +QT_END_NAMESPACE + +#endif // QQNXGLCONTEXT_H diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp new file mode 100644 index 0000000000..3f9d768ccc --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp @@ -0,0 +1,1696 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxinputcontext_imf.h" +#include "qqnxeventthread.h" +#include "qqnxvirtualkeyboard.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "imf/imf_client.h" +#include "imf/input_control.h" +#include +#include + +/** TODO: + Support inputMethodHints to restrict input (needs additional features in IMF). +*/ + +#define STRX(x) #x +#define STR(x) STRX(x) + +// Someone tell me why input_control methods are in this namespace, but the rest is not. +using namespace InputMethodSystem; + +#define qs(x) QString::fromLatin1(x) +#define iarg(name) event->mArgs[qs(#name)] = QVariant::fromValue(name) +#define parg(name) event->mArgs[qs(#name)] = QVariant::fromValue((void*)name) +namespace +{ + +spannable_string_t *toSpannableString(const QString &text); +static const input_session_t *sInputSession = 0; +bool isSessionOkay(input_session_t *ic) +{ + return ic !=0 && sInputSession != 0 && ic->component_id == sInputSession->component_id; +} + +enum ImfEventType +{ + ImfBeginBatchEdit, + ImfClearMetaKeyStates, + ImfCommitText, + ImfDeleteSurroundingText, + ImfEndBatchEdit, + ImfFinishComposingText, + ImfGetCursorCapsMode, + ImfGetCursorPosition, + ImfGetExtractedText, + ImfGetSelectedText, + ImfGetTextAfterCursor, + ImfGetTextBeforeCursor, + ImfPerformEditorAction, + ImfReportFullscreenMode, + ImfSendEvent, + ImfSendAsyncEvent, + ImfSetComposingRegion, + ImfSetComposingText, + ImfSetSelection +}; + +// We use this class as a round about way to support a posting synchronous event into +// Qt's main thread from the IMF thread. +class ImfEventResult +{ +public: + ImfEventResult() + { + m_mutex.lock(); + } + + ~ImfEventResult() + { + m_mutex.unlock(); + } + + void wait() + { + m_wait.wait(&m_mutex); + } + + void signal() + { + m_wait.wakeAll(); + } + + void setResult(const QVariant& result) + { + m_mutex.lock(); + m_retVal = result; + signal(); + m_mutex.unlock(); + } + + QVariant result() + { + return m_retVal; + } + +private: + QVariant m_retVal; + QMutex m_mutex; + QWaitCondition m_wait; +}; + +class ImfEvent : public QEvent +{ + public: + ImfEvent(input_session_t *session, ImfEventType type, ImfEventResult *result) : + QEvent((QEvent::Type)sUserEventType), + m_session(session), + m_imfType(type), + m_result(result) + { + } + ~ImfEvent() { } + + input_session_t *m_session; + ImfEventType m_imfType; + QVariantHash m_args; + ImfEventResult *m_result; + + static int sUserEventType; +}; +int ImfEvent::sUserEventType = QEvent::registerEventType(); + +static int32_t imfBeginBatchEdit(input_session_t *ic) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfBeginBatchEdit, &result); + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + + return ret; +} + +static int32_t imfClearMetaKeyStates(input_session_t *ic, int32_t states) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfClearMetaKeyStates, &result); + iarg(states); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + + return ret; +} + +static int32_t imfCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfCommitText, &result); + parg(text); + iarg(new_cursor_position); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + + return ret; +} + +static int32_t imfDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfDeleteSurroundingText, &result); + iarg(left_length); + iarg(right_length); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + + return ret; +} + +static int32_t imfEndBatchEdit(input_session_t *ic) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfEndBatchEdit, &result); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + + return ret; +} + +static int32_t imfFinishComposingText(input_session_t *ic) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfFinishComposingText, &result); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + + return ret; +} + +static int32_t imfGetCursorCapsMode(input_session_t *ic, int32_t req_modes) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfGetCursorCapsMode, &result); + iarg(req_modes); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + int32_t ret = result.result().value(); + return ret; +} + +static int32_t imfGetCursorPosition(input_session_t *ic) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfGetCursorPosition, &result); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + + return ret; +} + +static extracted_text_t *imfGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) { + extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1); + et->text = (spannable_string_t *)calloc(sizeof(spannable_string_t),1); + return et; + } + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfGetExtractedText, &result); + parg(request); + iarg(flags); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + return result.result().value(); +} + +static spannable_string_t *imfGetSelectedText(input_session_t *ic, int32_t flags) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return toSpannableString(""); + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfGetSelectedText, &result); + iarg(flags); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + return result.result().value(); +} + +static spannable_string_t *imfGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return toSpannableString(""); + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfGetTextAfterCursor, &result); + iarg(n); + iarg(flags); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + return result.result().value(); +} + +static spannable_string_t *imfGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return toSpannableString(""); + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfGetTextBeforeCursor, &result); + iarg(n); + iarg(flags); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + return result.result().value(); +} + +static int32_t imfPerformEditorAction(input_session_t *ic, int32_t editor_action) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfPerformEditorAction, &result); + iarg(editor_action); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + return ret; +} + +static int32_t imfReportFullscreenMode(input_session_t *ic, int32_t enabled) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfReportFullscreenMode, &result); + iarg(enabled); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + return ret; +} + +static int32_t imfSendEvent(input_session_t *ic, event_t *event) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEvent *imfEvent = new ImfEvent(ic, ImfSendEvent, 0); + imfEvent->m_args[qs("event")] = QVariant::fromValue(static_cast(event)); + + QCoreApplication::postEvent(QCoreApplication::instance(), imfEvent); + + return 0; +} + +static int32_t imfSendAsyncEvent(input_session_t *ic, event_t *event) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEvent *imfEvent = new ImfEvent(ic, ImfSendAsyncEvent, 0); + imfEvent->m_args[qs("event")] = QVariant::fromValue(static_cast(event)); + + QCoreApplication::postEvent(QCoreApplication::instance(), imfEvent); + + return 0; +} + +static int32_t imfSetComposingRegion(input_session_t *ic, int32_t start, int32_t end) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfSetComposingRegion, &result); + iarg(start); + iarg(end); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + return ret; +} + +static int32_t imfSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfSetComposingText, &result); + parg(text); + iarg(new_cursor_position); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + return ret; +} + +static int32_t imfSetSelection(input_session_t *ic, int32_t start, int32_t end) +{ +#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + ImfEventResult result; + ImfEvent *event = new ImfEvent(ic, ImfSetSelection, &result); + iarg(start); + iarg(end); + + QCoreApplication::postEvent(QCoreApplication::instance(), event); + + result.wait(); + int32_t ret = result.result().value(); + return ret; +} + +static connection_interface_t ic_funcs = { + imfBeginBatchEdit, + imfClearMetaKeyStates, + imfCommitText, + imfDeleteSurroundingText, + imfEndBatchEdit, + imfFinishComposingText, + imfGetCursorCapsMode, + imfGetCursorPosition, + imfGetExtractedText, + imfGetSelectedText, + imfGetTextAfterCursor, + imfGetTextBeforeCursor, + imfPerformEditorAction, + imfReportFullscreenMode, + NULL, //ic_send_key_event + imfSendEvent, + imfSendAsyncEvent, + imfSetComposingRegion, + imfSetComposingText, + imfSetSelection, + NULL, //ic_set_candidates, +}; + +static void +initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType, int eventId) +{ + static int s_transactionId; + + // Make sure structure is squeaky clean since it's not clear just what is significant. + memset(pEvent, 0, sizeof(event_t)); + pEvent->event_type = eventType; + pEvent->event_id = eventId; + pEvent->pid = getpid(); + pEvent->component_id = pSession->component_id; + pEvent->transaction_id = ++s_transactionId; +} + +spannable_string_t *toSpannableString(const QString &text) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << text; +#endif + + spannable_string_t *pString = reinterpret_cast(malloc(sizeof(spannable_string_t))); + pString->str = (wchar_t *)malloc(sizeof(wchar_t) * text.length() + 1); + pString->length = text.length(); + pString->spans = NULL; + pString->spans_count = 0; + + const QChar *pData = text.constData(); + wchar_t *pDst = pString->str; + + while (!pData->isNull()) + { + *pDst = pData->unicode(); + pDst++; + pData++; + } + *pDst = 0; + + return pString; +} + +} // namespace + +static const input_session_t *(*p_ictrl_open_session)(connection_interface_t *) = 0; +static void (*p_ictrl_close_session)(input_session_t *) = 0; +static int32_t (*p_ictrl_dispatch_event)(event_t*) = 0; +static int32_t (*p_imf_client_init)() = 0; +static void (*p_imf_client_disconnect)() = 0; +static int32_t (*p_vkb_init_selection_service)() = 0; +static int32_t (*p_ictrl_get_num_active_sessions)() = 0; +static bool s_imfInitFailed = false; + +static bool imfAvailable() +{ + static bool s_imfDisabled = getenv("DISABLE_IMF") != NULL; + static bool s_imfReady = false; + + if ( s_imfInitFailed || s_imfDisabled) { + return false; + } + else if ( s_imfReady ) { + return true; + } + + if ( p_imf_client_init == NULL ) { + void *handle = dlopen("libinput_client.so.1", 0); + if ( handle ) { + p_imf_client_init = (int32_t (*)()) dlsym(handle, "imf_client_init"); + p_imf_client_disconnect = (void (*)()) dlsym(handle, "imf_client_disconnect"); + p_ictrl_open_session = (const input_session_t *(*)(connection_interface_t *))dlsym(handle, "ictrl_open_session"); + p_ictrl_close_session = (void (*)(input_session_t *))dlsym(handle, "ictrl_close_session"); + p_ictrl_dispatch_event = (int32_t (*)(event_t *))dlsym(handle, "ictrl_dispatch_event"); + p_vkb_init_selection_service = (int32_t (*)())dlsym(handle, "vkb_init_selection_service"); + p_ictrl_get_num_active_sessions = (int32_t (*)())dlsym(handle, "ictrl_get_num_active_sessions"); + } + else + { + qCritical() << Q_FUNC_INFO << "libinput_client.so.1 is not present - IMF services are disabled."; + s_imfDisabled = true; + return false; + } + if ( p_imf_client_init && p_ictrl_open_session && p_ictrl_dispatch_event ) { + s_imfReady = true; + } + else { + p_ictrl_open_session = NULL; + p_ictrl_dispatch_event = NULL; + s_imfDisabled = true; + qCritical() << Q_FUNC_INFO << "libinput_client.so.1 did not contain the correct symbols, library mismatch? IMF services are disabled."; + return false; + } + } + + return s_imfReady; +} + +QQnxInputContext::QQnxInputContext(): + QPlatformInputContext(), + m_lastCaretPos(0), + m_isComposing(false), + m_inputPanelVisible(false), + m_inputPanelLocale(QLocale::c()) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!imfAvailable()) + return; + + if ( p_imf_client_init() != 0 ) { + s_imfInitFailed = true; + qCritical("imf_client_init failed - IMF services will be unavailable"); + } + + QCoreApplication::instance()->installEventFilter(this); + + // p_vkb_init_selection_service(); + + QQnxVirtualKeyboard &keyboard = QQnxVirtualKeyboard::instance(); + connect(&keyboard, SIGNAL(visibilityChanged(bool)), this, SLOT(keyboardVisibilityChanged(bool))); + connect(&keyboard, SIGNAL(localeChanged(QLocale)), this, SLOT(keyboardLocaleChanged(QLocale))); + keyboardVisibilityChanged(keyboard.isVisible()); + keyboardLocaleChanged(keyboard.locale()); + + QInputMethod *inputMethod = qApp->inputMethod(); + connect(inputMethod, SIGNAL(inputItemChanged()), this, SLOT(inputItemChanged())); + +} + +QQnxInputContext::~QQnxInputContext() +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!imfAvailable()) + return; + + QCoreApplication::instance()->removeEventFilter(this); + p_imf_client_disconnect(); +} + +#define getarg(type, name) type name = imfEvent->mArgs[qs(#name)].value() +#define getparg(type, name) type name = (type)(imfEvent->mArgs[qs(#name)].value()) + +bool QQnxInputContext::isValid() const +{ + return imfAvailable(); +} + +bool QQnxInputContext::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == ImfEvent::sUserEventType) { + // Forward the event to our real handler. + ImfEvent *imfEvent = static_cast(event); + switch (imfEvent->m_imfType) { + case ImfBeginBatchEdit: { + int32_t ret = onBeginBatchEdit(imfEvent->m_session); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfClearMetaKeyStates: { + getarg(int32_t, states); + int32_t ret = onClearMetaKeyStates(imfEvent->m_session, states); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfCommitText: { + getparg(spannable_string_t*, text); + getarg(int32_t, new_cursor_position); + int32_t ret = onCommitText(imfEvent->m_session, text, new_cursor_position); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfDeleteSurroundingText: { + getarg(int32_t, left_length); + getarg(int32_t, right_length); + int32_t ret = onDeleteSurroundingText(imfEvent->m_session, left_length, right_length); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfEndBatchEdit: { + int32_t ret = onEndBatchEdit(imfEvent->m_session); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfFinishComposingText: { + int32_t ret = onFinishComposingText(imfEvent->m_session); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfGetCursorCapsMode: { + getarg(int32_t, req_modes); + int32_t ret = onGetCursorCapsMode(imfEvent->m_session, req_modes); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfGetCursorPosition: { + int32_t ret = onGetCursorPosition(imfEvent->m_session); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfGetExtractedText: { + getparg(extracted_text_request_t*, request); + getarg(int32_t, flags); + extracted_text_t *ret = onGetExtractedText(imfEvent->m_session, request, flags); + imfEvent->m_result->setResult(QVariant::fromValue(static_cast(ret))); + break; + } + + case ImfGetSelectedText: { + getarg(int32_t, flags); + spannable_string_t *ret = onGetSelectedText(imfEvent->m_session, flags); + imfEvent->m_result->setResult(QVariant::fromValue(static_cast(ret))); + break; + } + + case ImfGetTextAfterCursor: { + getarg(int32_t, n); + getarg(int32_t, flags); + spannable_string_t *ret = onGetTextAfterCursor(imfEvent->m_session, n, flags); + imfEvent->m_result->setResult(QVariant::fromValue(static_cast(ret))); + break; + } + + case ImfGetTextBeforeCursor: { + getarg(int32_t, n); + getarg(int32_t, flags); + spannable_string_t *ret = onGetTextBeforeCursor(imfEvent->m_session, n, flags); + imfEvent->m_result->setResult(QVariant::fromValue((void*)ret)); + break; + } + + case ImfPerformEditorAction: { + getarg(int32_t, editor_action); + int32_t ret = onPerformEditorAction(imfEvent->m_session, editor_action); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfReportFullscreenMode: { + getarg(int32_t, enabled); + int32_t ret = onReportFullscreenMode(imfEvent->m_session, enabled); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfSendEvent: { + getparg(event_t*, event); + onSendEvent(imfEvent->m_session, event); + break; + } + + case ImfSendAsyncEvent: { + getparg(event_t*, event); + onSendAsyncEvent(imfEvent->m_session, event); + break; + } + + case ImfSetComposingRegion: { + getarg(int32_t, start); + getarg(int32_t, end); + int32_t ret = onSetComposingRegion(imfEvent->m_session, start, end); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfSetComposingText: { + getparg(spannable_string_t*, text); + getarg(int32_t, new_cursor_position); + int32_t ret = onSetComposingText(imfEvent->m_session, text, new_cursor_position); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + + case ImfSetSelection: { + getarg(int32_t, start); + getarg(int32_t, end); + int32_t ret = onSetSelection(imfEvent->m_session, start, end); + imfEvent->m_result->setResult(QVariant::fromValue(ret)); + break; + } + }; //switch + + return true; + } else { + // standard event processing + return QObject::eventFilter(obj, event); + } +} + +bool QQnxInputContext::filterEvent( const QEvent *event ) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << event; +#endif + switch (event->type()) { + case QEvent::CloseSoftwareInputPanel: { + return dispatchCloseSoftwareInputPanel(); + } + case QEvent::RequestSoftwareInputPanel: { + return dispatchRequestSoftwareInputPanel(); + } + default: + return false; + } +} + +void QQnxInputContext::reset() +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + endComposition(); +} + +void QQnxInputContext::update(Qt::InputMethodQueries queries) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + reset(); + + QPlatformInputContext::update(queries); +} + +void QQnxInputContext::closeSession() +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO +#endif + if (!imfAvailable()) + return; + + if (sInputSession) { + p_ictrl_close_session((input_session_t *)sInputSession); + sInputSession = 0; + } +} + +void QQnxInputContext::openSession() +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO +#endif + if (!imfAvailable()) + return; + + closeSession(); + sInputSession = p_ictrl_open_session(&ic_funcs); +} + +bool QQnxInputContext::hasSession() +{ + return sInputSession != 0; +} + +bool QQnxInputContext::hasSelectedText() +{ + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!input) + return false; + + QInputMethodQueryEvent query(Qt::ImCurrentSelection); + QCoreApplication::sendEvent(input, &query); + + return !query.value(Qt::ImCurrentSelection).toString().isEmpty(); +} + +bool QQnxInputContext::dispatchRequestSoftwareInputPanel() +{ + QQnxVirtualKeyboard::instance().showKeyboard(); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << "QQNX: requesting virtual keyboard"; +#endif + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return true; + + if (!hasSession()) + openSession(); + + // This also means that the caret position has moved + QInputMethodQueryEvent query(Qt::ImCursorPosition); + QCoreApplication::sendEvent(input, &query); + int caretPos = query.value(Qt::ImCursorPosition).toInt(); + caret_event_t caretEvent; + memset(&caretEvent, 0, sizeof(caret_event_t)); + initEvent(&caretEvent.event, sInputSession, EVENT_CARET, CARET_POS_CHANGED); + caretEvent.old_pos = m_lastCaretPos; + m_lastCaretPos = caretEvent.new_pos = caretPos; + p_ictrl_dispatch_event((event_t *)&caretEvent); + return true; +} + +bool QQnxInputContext::dispatchCloseSoftwareInputPanel() +{ + QQnxVirtualKeyboard::instance().hideKeyboard(); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << "QQNX: hiding virtual keyboard"; +#endif + + // This also means we are stopping composition, but we should already have done that. + return true; +} + +/** + * IMF Event Dispatchers. + */ +bool QQnxInputContext::dispatchFocusEvent(FocusEventId id, int hints) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!sInputSession) { + qWarning() << Q_FUNC_INFO << "Attempt to dispatch a focus event with no input session."; + return false; + } + + if (!imfAvailable()) + return false; + + // Set the last caret position to 0 since we don't really have one and we don't + // want to have the old one. + m_lastCaretPos = 0; + + focus_event_t focusEvent; + memset(&focusEvent, 0, sizeof(focusEvent)); + initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, id); + focusEvent.style = DEFAULT_STYLE; + + if (hints && Qt::ImhNoPredictiveText) + focusEvent.style |= NO_PREDICTION | NO_AUTO_CORRECTION; + if (hints && Qt::ImhNoAutoUppercase) + focusEvent.style |= NO_AUTO_TEXT; + + p_ictrl_dispatch_event((event_t *)&focusEvent); + + return true; +} + +bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap) +{ + if (!imfAvailable()) + return false; + + int key = (flags & KEY_SYM_VALID) ? sym : cap; + bool navKey = false; + switch ( key ) { + case KEYCODE_RETURN: + /* In a single line edit we should end composition because enter might be used by something. + endComposition(); + return false;*/ + break; + + case KEYCODE_BACKSPACE: + case KEYCODE_DELETE: + // If there is a selection range, then we want a delete key to operate on that (by + // deleting the contents of the select range) rather than operating on the composition + // range. + if (hasSelectedText()) + return false; + break; + case KEYCODE_LEFT: + key = NAVIGATE_LEFT; + navKey = true; + break; + case KEYCODE_RIGHT: + key = NAVIGATE_RIGHT; + navKey = true; + break; + case KEYCODE_UP: + key = NAVIGATE_UP; + navKey = true; + break; + case KEYCODE_DOWN: + key = NAVIGATE_DOWN; + navKey = true; + break; + case KEYCODE_CAPS_LOCK: + case KEYCODE_LEFT_SHIFT: + case KEYCODE_RIGHT_SHIFT: + case KEYCODE_LEFT_CTRL: + case KEYCODE_RIGHT_CTRL: + case KEYCODE_LEFT_ALT: + case KEYCODE_RIGHT_ALT: + case KEYCODE_MENU: + case KEYCODE_LEFT_HYPER: + case KEYCODE_RIGHT_HYPER: + case KEYCODE_INSERT: + case KEYCODE_HOME: + case KEYCODE_PG_UP: + case KEYCODE_END: + case KEYCODE_PG_DOWN: + // Don't send these + key = 0; + break; + } + + if ( mod & KEYMOD_CTRL ) { + // If CTRL is pressed, just let AIR handle it. But terminate any composition first + //endComposition(); + return false; + } + + // Pass the keys we don't know about on through + if ( key == 0 ) + return false; + + // IMF doesn't need key releases so just swallow them. + if (!(flags & KEY_DOWN)) + return true; + + if ( navKey ) { + // Even if we're forwarding up events, we can't do this for + // navigation keys. + if ( flags & KEY_DOWN ) { + navigation_event_t navEvent; + initEvent(&navEvent.event, sInputSession, EVENT_NAVIGATION, key); + navEvent.magnitude = 1; +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "dispatch navigation event " << key; +#endif + p_ictrl_dispatch_event(&navEvent.event); + } + } + else { + key_event_t keyEvent; + initEvent(&keyEvent.event, sInputSession, EVENT_KEY, flags & KEY_DOWN ? IMF_KEY_DOWN : IMF_KEY_UP); + keyEvent.key_code = key; + keyEvent.character = 0; + keyEvent.meta_key_state = 0; + + p_ictrl_dispatch_event(&keyEvent.event); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "dispatch key event " << key; +#endif + } + + scan = 0; + return true; +} + +void QQnxInputContext::endComposition() +{ + if (!m_isComposing) + return; + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return; + + QList attributes; + QInputMethodEvent event(QLatin1String(""), attributes); + event.setCommitString(m_composingText); + m_composingText = QString(); + m_isComposing = false; + QCoreApplication::sendEvent(input, &event); + + action_event_t actionEvent; + memset(&actionEvent, 0, sizeof(actionEvent)); + initEvent(&actionEvent.event, sInputSession, EVENT_ACTION, ACTION_END_COMPOSITION); + p_ictrl_dispatch_event(&actionEvent.event); +} + +void QQnxInputContext::setComposingText(QString const& composingText) +{ + m_composingText = composingText; + m_isComposing = true; + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return; + + QList attributes; + QTextCharFormat format; + format.setFontUnderline(true); + attributes.push_back(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, composingText.length(), format)); + + QInputMethodEvent event(composingText, attributes); + + QCoreApplication::sendEvent(input, &event); +} + +int32_t QQnxInputContext::processEvent(event_t *event) +{ + int32_t result = -1; + switch (event->event_type) { + case EVENT_SPELL_CHECK: { + #if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "EVENT_SPELL_CHECK"; + #endif + result = 0; + break; + } + + case EVENT_NAVIGATION: { + #if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "EVENT_NAVIGATION"; + #endif + + int key = event->event_id == NAVIGATE_UP ? KEYCODE_UP : + event->event_id == NAVIGATE_DOWN ? KEYCODE_DOWN : + event->event_id == NAVIGATE_LEFT ? KEYCODE_LEFT : + event->event_id == NAVIGATE_RIGHT ? KEYCODE_RIGHT : 0; + + QQnxEventThread::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, key, 0, 0, 0); + QQnxEventThread::injectKeyboardEvent(KEY_CAP_VALID, key, 0, 0, 0); + result = 0; + break; + } + + case EVENT_KEY: { + #if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "EVENT_KEY"; + #endif + key_event_t *kevent = static_cast(event); + + QQnxEventThread::injectKeyboardEvent(KEY_DOWN | KEY_SYM_VALID | KEY_CAP_VALID, kevent->key_code, 0, 0, kevent->key_code); + QQnxEventThread::injectKeyboardEvent(KEY_SYM_VALID | KEY_CAP_VALID, kevent->key_code, 0, 0, kevent->key_code); + + result = 0; + break; + } + + case EVENT_ACTION: + // Don't care, indicates that IMF is done. + break; + + case EVENT_CARET: + case EVENT_NOTHING: + case EVENT_FOCUS: + case EVENT_USER_ACTION: + case EVENT_STROKE: + case EVENT_INVOKE_LATER: + qCritical() << Q_FUNC_INFO << "Unsupported event type: " << event->event_type; + break; + default: + qCritical() << Q_FUNC_INFO << "Unknown event type: " << event->event_type; + } + return result; +} + +/** + * IMF Event Handlers + */ + +int32_t QQnxInputContext::onBeginBatchEdit(input_session_t *ic) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + // We don't care. + return 0; +} + +int32_t QQnxInputContext::onClearMetaKeyStates(input_session_t *ic, int32_t states) +{ + Q_UNUSED(states); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + // Should never get called. + qCritical() << Q_FUNC_INFO << "onClearMetaKeyStates is unsupported."; + return 0; +} + +int32_t QQnxInputContext::onCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) +{ + Q_UNUSED(new_cursor_position); // TODO: How can we set the cursor position it's not part of the API. + if (!isSessionOkay(ic)) + return 0; + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return 0; + + QString commitString = QString::fromWCharArray(text->str, text->length); + +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "Committing [" << commitString << "]"; +#endif + + QList attributes; + QInputMethodEvent event(QLatin1String(""), attributes); + event.setCommitString(commitString, 0, 0); + + QCoreApplication::sendEvent(input, &event); + m_composingText = QString(); + + return 0; +} + +int32_t QQnxInputContext::onDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "L:" << left_length << " R:" << right_length; +#endif + + if (!isSessionOkay(ic)) + return 0; + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return 0; + + if (hasSelectedText()) { + QQnxEventThread::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, KEYCODE_DELETE, 0, 0, 0); + QQnxEventThread::injectKeyboardEvent(KEY_CAP_VALID, KEYCODE_DELETE, 0, 0, 0); + reset(); + return 0; + } + + int replacementLength = left_length + right_length; + int replacementStart = -left_length; + + QList attributes; + QInputMethodEvent event(QLatin1String(""), attributes); + event.setCommitString(QLatin1String(""), replacementStart, replacementLength); + QCoreApplication::sendEvent(input, &event); + + return 0; +} + +int32_t QQnxInputContext::onEndBatchEdit(input_session_t *ic) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + return 0; +} + +int32_t QQnxInputContext::onFinishComposingText(input_session_t *ic) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return 0; + + // Only update the control, no need to send a message back to imf (don't call + // end composition) + QList attributes; + QInputMethodEvent event(QLatin1String(""), attributes); + event.setCommitString(m_composingText); + m_composingText = QString(); + m_isComposing = false; + QCoreApplication::sendEvent(input, &event); + + return 0; +} + +int32_t QQnxInputContext::onGetCursorCapsMode(input_session_t *ic, int32_t req_modes) +{ + Q_UNUSED(req_modes); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + // Should never get called. + qCritical() << Q_FUNC_INFO << "onGetCursorCapsMode is unsupported."; + + return 0; +} + +int32_t QQnxInputContext::onGetCursorPosition(input_session_t *ic) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return 0; + + QInputMethodQueryEvent query(Qt::ImCursorPosition); + QCoreApplication::sendEvent(input, &query); + m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); + + return m_lastCaretPos; +} + +extracted_text_t *QQnxInputContext::onGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags) +{ + Q_UNUSED(flags); + Q_UNUSED(request); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) { + extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1); + et->text = reinterpret_cast(calloc(sizeof(spannable_string_t),1)); + return et; + } + + // Used to update dictionaries, but not supported right now. + extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1); + et->text = reinterpret_cast(calloc(sizeof(spannable_string_t),1)); + + return et; +} + +spannable_string_t *QQnxInputContext::onGetSelectedText(input_session_t *ic, int32_t flags) +{ + Q_UNUSED(flags); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return toSpannableString(""); + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return 0; + + QInputMethodQueryEvent query(Qt::ImCurrentSelection); + QCoreApplication::sendEvent(input, &query); + QString text = query.value(Qt::ImCurrentSelection).toString(); + + return toSpannableString(text); +} + +spannable_string_t *QQnxInputContext::onGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags) +{ + Q_UNUSED(flags); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return toSpannableString(""); + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return toSpannableString(""); + + QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText); + QCoreApplication::sendEvent(input, &query); + QString text = query.value(Qt::ImSurroundingText).toString(); + m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); + + return toSpannableString(text.mid(m_lastCaretPos+1, n)); +} + +spannable_string_t *QQnxInputContext::onGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags) +{ + Q_UNUSED(flags); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return toSpannableString(""); + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return toSpannableString(""); + + QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText); + QCoreApplication::sendEvent(input, &query); + QString text = query.value(Qt::ImSurroundingText).toString(); + m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); + + if (n < m_lastCaretPos) { + return toSpannableString(text.mid(m_lastCaretPos - n, n)); + } else { + return toSpannableString(text.mid(0, m_lastCaretPos)); + } +} + +int32_t QQnxInputContext::onPerformEditorAction(input_session_t *ic, int32_t editor_action) +{ + Q_UNUSED(editor_action); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + // Should never get called. + qCritical() << Q_FUNC_INFO << "onPerformEditorAction is unsupported."; + + return 0; +} + +int32_t QQnxInputContext::onReportFullscreenMode(input_session_t *ic, int32_t enabled) +{ + Q_UNUSED(enabled); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + // Should never get called. + qCritical() << Q_FUNC_INFO << "onReportFullscreenMode is unsupported."; + + return 0; +} + +int32_t QQnxInputContext::onSendEvent(input_session_t *ic, event_t *event) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + return processEvent(event); +} + +int32_t QQnxInputContext::onSendAsyncEvent(input_session_t *ic, event_t *event) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + return processEvent(event); +} + +int32_t QQnxInputContext::onSetComposingRegion(input_session_t *ic, int32_t start, int32_t end) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return 0; + + QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText); + QCoreApplication::sendEvent(input, &query); + QString text = query.value(Qt::ImSurroundingText).toString(); + m_lastCaretPos = query.value(Qt::ImCursorPosition).toInt(); + + QString empty = QString::fromLatin1(""); + text = text.mid(start, end - start); + + // Delete the current text. + QList attributes; + QInputMethodEvent event(empty, attributes); + event.setCommitString(empty, start - m_lastCaretPos, end - start); + QCoreApplication::sendEvent(input, &event); + + // Move the specified text into a preedit string. + setComposingText(text); + + return 0; +} + +int32_t QQnxInputContext::onSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position) +{ + Q_UNUSED(new_cursor_position); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + QInputPanel *panel = qApp->inputPanel(); + QObject *input = panel->inputItem(); + if (!imfAvailable() || !input) + return 0; + + m_isComposing = true; + + QString preeditString = QString::fromWCharArray(text->str, text->length); + setComposingText(preeditString); + + return 0; +} + +int32_t QQnxInputContext::onSetSelection(input_session_t *ic, int32_t start, int32_t end) +{ + Q_UNUSED(start); + Q_UNUSED(end); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + + if (!isSessionOkay(ic)) + return 0; + + // Should never get called. + qCritical() << Q_FUNC_INFO << "onSetSelection is unsupported."; + + return 0; +} + +void QQnxInputContext::showInputPanel() +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + dispatchRequestSoftwareInputPanel(); +} + +void QQnxInputContext::hideInputPanel() +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + dispatchCloseSoftwareInputPanel(); +} + +bool QQnxInputContext::isInputPanelVisible() const +{ + return m_inputPanelVisible; +} + +QLocale QQnxInputContext::locale() const +{ + return m_inputPanelLocale; +} + +void QQnxInputContext::keyboardVisibilityChanged(bool visible) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "visible=" << visible; +#endif + if (m_inputPanelVisible != visible) { + m_inputPanelVisible = visible; + emitInputPanelVisibleChanged(); + } +} + +void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "locale=" << locale; +#endif + if (m_inputPanelLocale != locale) { + m_inputPanelLocale = locale; + emitLocaleChanged(); + } +} + +void QQnxInputContext::inputItemChanged() +{ + QInputMethod *inputMethod = qApp->inputMethod(); + QObject *inputItem = inputMethod->inputItem(); + +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "input item=" << inputItem; +#endif + + if (!inputItem) { + if (m_inputPanelVisible) + hideInputPanel(); + } else { + if (qobject_cast(inputItem)) { + QQnxVirtualKeyboard::instance().setKeyboardMode(QQnxVirtualKeyboard::NumPunc); + } else { + QQnxVirtualKeyboard::instance().setKeyboardMode(QQnxVirtualKeyboard::Default); + } + if (!m_inputPanelVisible) + showInputPanel(); + } +} diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.h b/src/plugins/platforms/qnx/qqnxinputcontext_imf.h new file mode 100644 index 0000000000..1fb55296a6 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.h @@ -0,0 +1,132 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXINPUTCONTEXT_H +#define QQNXINPUTCONTEXT_H + +#include + +#include +#include +#include + +#include "imf/imf_client.h" +#include "imf/input_control.h" + +QT_BEGIN_NAMESPACE + +class QQnxInputContext : public QPlatformInputContext +{ + Q_OBJECT +public: + QQnxInputContext(); + ~QQnxInputContext(); + + virtual bool isValid() const; + + virtual bool filterEvent(const QEvent *event); + virtual void reset(); + virtual void update(Qt::InputMethodQueries); + bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap); + + virtual void showInputPanel(); + virtual void hideInputPanel(); + virtual bool isInputPanelVisible() const; + + virtual QLocale locale() const; + +protected: + // Filters only for IMF events. + bool eventFilter(QObject *obj, QEvent *event); + +private Q_SLOTS: + void keyboardVisibilityChanged(bool visible); + void keyboardLocaleChanged(const QLocale &locale); + void inputItemChanged(); + +private: + // IMF Event dispatchers + bool dispatchFocusEvent(FocusEventId id, int hints = Qt::ImhNone); + bool dispatchRequestSoftwareInputPanel(); + bool dispatchCloseSoftwareInputPanel(); + int32_t processEvent(event_t *event); + + void closeSession(); + void openSession(); + bool hasSession(); + void endComposition(); + void setComposingText(QString const &composingText); + bool hasSelectedText(); + + // IMF Event handlers - these events will come in from QCoreApplication. + int32_t onBeginBatchEdit(input_session_t *ic); + int32_t onClearMetaKeyStates(input_session_t *ic, int32_t states); + int32_t onCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position); + int32_t onDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length); + int32_t onEndBatchEdit(input_session_t *ic); + int32_t onFinishComposingText(input_session_t *ic); + int32_t onGetCursorCapsMode(input_session_t *ic, int32_t req_modes); + int32_t onGetCursorPosition(input_session_t *ic); + extracted_text_t *onGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags); + spannable_string_t *onGetSelectedText(input_session_t *ic, int32_t flags); + spannable_string_t *onGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags); + spannable_string_t *onGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags); + int32_t onPerformEditorAction(input_session_t *ic, int32_t editor_action); + int32_t onReportFullscreenMode(input_session_t *ic, int32_t enabled); + int32_t onSendEvent(input_session_t *ic, event_t *event); + int32_t onSendAsyncEvent(input_session_t *ic, event_t *event); + int32_t onSetComposingRegion(input_session_t *ic, int32_t start, int32_t end); + int32_t onSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position); + int32_t onSetSelection(input_session_t *ic, int32_t start, int32_t end); + int32_t onForceUpdate(); + + int m_lastCaretPos; + bool m_isComposing; + QString m_composingText; + bool m_inputPanelVisible; + QLocale m_inputPanelLocale; +}; + +Q_DECLARE_METATYPE(extracted_text_t*) + +QT_END_NAMESPACE + +#endif // QQNXINPUTCONTEXT_H diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp new file mode 100644 index 0000000000..33b6c0e6f3 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp @@ -0,0 +1,187 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxinputcontext_noimf.h" +#include "qqnxvirtualkeyboard.h" + +#include +#include +#include + +QQnxInputContext::QQnxInputContext() : + QPlatformInputContext(), + m_inputPanelVisible(false), + m_inputPanelLocale(QLocale::c()) +{ + QQnxVirtualKeyboard &keyboard = QQnxVirtualKeyboard::instance(); + connect(&keyboard, SIGNAL(visibilityChanged(bool)), this, SLOT(keyboardVisibilityChanged(bool))); + connect(&keyboard, SIGNAL(localeChanged(QLocale)), this, SLOT(keyboardLocaleChanged(QLocale))); + keyboardVisibilityChanged(keyboard.isVisible()); + keyboardLocaleChanged(keyboard.locale()); + + QInputMethod *inputMethod = qApp->inputMethod(); + connect(inputMethod, SIGNAL(inputItemChanged()), this, SLOT(inputItemChanged())); +} + +QQnxInputContext::~QQnxInputContext() +{ +} + +bool QQnxInputContext::isValid() const +{ + return true; +} + +bool QQnxInputContext::hasPhysicalKeyboard() +{ + // TODO: This should query the system to check if a USB keyboard is connected. + return false; +} + +void QQnxInputContext::reset() +{ +} + +bool QQnxInputContext::filterEvent( const QEvent *event ) +{ + if (hasPhysicalKeyboard()) + return false; + + if (event->type() == QEvent::CloseSoftwareInputPanel) { + QQnxVirtualKeyboard::instance().hideKeyboard(); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << "QQNX: hiding virtual keyboard"; +#endif + return false; + } + + if (event->type() == QEvent::RequestSoftwareInputPanel) { + QQnxVirtualKeyboard::instance().showKeyboard(); +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << "QQNX: requesting virtual keyboard"; +#endif + return false; + } + + return false; + +} + +bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap) +{ + Q_UNUSED(flags); + Q_UNUSED(sym); + Q_UNUSED(mod); + Q_UNUSED(scan); + Q_UNUSED(cap); + return false; +} + +void QQnxInputContext::showInputPanel() +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + QQnxVirtualKeyboard::instance().showKeyboard(); +} + +void QQnxInputContext::hideInputPanel() +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + QQnxVirtualKeyboard::instance().hideKeyboard(); +} + +bool QQnxInputContext::isInputPanelVisible() const +{ + return m_inputPanelVisible; +} + +QLocale QQnxInputContext::locale() const +{ + return m_inputPanelLocale; +} + +void QQnxInputContext::keyboardVisibilityChanged(bool visible) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "visible=" << visible; +#endif + if (m_inputPanelVisible != visible) { + m_inputPanelVisible = visible; + emitInputPanelVisibleChanged(); + } +} + +void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale) +{ +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "locale=" << locale; +#endif + if (m_inputPanelLocale != locale) { + m_inputPanelLocale = locale; + emitLocaleChanged(); + } +} + +void QQnxInputContext::inputItemChanged() +{ + QInputMethod *inputMethod = qApp->inputMethod(); + QObject *inputItem = inputMethod->inputItem(); + +#if defined(QQNXINPUTCONTEXT_DEBUG) + qDebug() << Q_FUNC_INFO << "input item=" << inputItem; +#endif + + if (!inputItem) { + if (m_inputPanelVisible) + hideInputPanel(); + } else { + if (qobject_cast(inputItem)) { + QQnxVirtualKeyboard::instance().setKeyboardMode(QQnxVirtualKeyboard::NumPunc); + } else { + QQnxVirtualKeyboard::instance().setKeyboardMode(QQnxVirtualKeyboard::Default); + } + if (!m_inputPanelVisible) + showInputPanel(); + } +} diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h new file mode 100644 index 0000000000..33a4631d16 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.h @@ -0,0 +1,84 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXINPUTCONTEXT_H +#define QQNXINPUTCONTEXT_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQnxInputContext : public QPlatformInputContext +{ + Q_OBJECT +public: + explicit QQnxInputContext(); + ~QQnxInputContext(); + + virtual bool isValid() const; + + void reset(); + virtual bool filterEvent( const QEvent *event ); + bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap); + + virtual void showInputPanel(); + virtual void hideInputPanel(); + virtual bool isInputPanelVisible() const; + + virtual QLocale locale() const; + +private Q_SLOTS: + void keyboardVisibilityChanged(bool visible); + void keyboardLocaleChanged(const QLocale &locale); + void inputItemChanged(); + +private: + bool hasPhysicalKeyboard(); + + bool m_inputPanelVisible; + QLocale m_inputPanelLocale; +}; + +QT_END_NAMESPACE + +#endif // QQNXINPUTCONTEXT_H diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp new file mode 100644 index 0000000000..2811661269 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -0,0 +1,293 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxintegration.h" +#include "qqnxeventthread.h" +#include "qqnxglbackingstore.h" +#include "qqnxglcontext.h" +#include "qqnxnavigatorthread.h" +#include "qqnxrasterbackingstore.h" +#include "qqnxscreen.h" +#include "qqnxwindow.h" +#include "qqnxvirtualkeyboard.h" +#include "qqnxclipboard.h" +#include "qqnxglcontext.h" + +#if defined(QQnx_IMF) +#include "qqnxinputcontext_imf.h" +#else +#include "qqnxinputcontext_noimf.h" +#endif + +#include "private/qgenericunixfontdatabase_p.h" +#include "private/qgenericunixeventdispatcher_p.h" + +#include +#include +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +QQnxWindowMapper QQnxIntegration::ms_windowMapper; +QMutex QQnxIntegration::ms_windowMapperMutex; + +QQnxIntegration::QQnxIntegration() + : QPlatformIntegration() + , m_eventThread(0) + , m_navigatorThread(0) + , m_inputContext(0) + , m_fontDatabase(new QGenericUnixFontDatabase()) + , m_paintUsingOpenGL(false) + , m_eventDispatcher(createUnixEventDispatcher()) +#ifndef QT_NO_CLIPBOARD + , m_clipboard(0) +#endif +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // Open connection to QNX composition manager + errno = 0; + int result = screen_create_context(&m_screenContext, SCREEN_APPLICATION_CONTEXT); + if (result != 0) { + qFatal("QQnx: failed to connect to composition manager, errno=%d", errno); + } + + // Create displays for all possible screens (which may not be attached) + QQnxScreen::createDisplays(m_screenContext); + Q_FOREACH (QPlatformScreen *screen, QQnxScreen::screens()) { + screenAdded(screen); + } + + // Initialize global OpenGL resources + QQnxGLContext::initialize(); + + // Create/start event thread + m_eventThread = new QQnxEventThread(m_screenContext, *QQnxScreen::primaryDisplay()); + m_eventThread->start(); + + // Create/start navigator thread + m_navigatorThread = new QQnxNavigatorThread(*QQnxScreen::primaryDisplay()); + m_navigatorThread->start(); + + // Create/start the keyboard class. + QQnxVirtualKeyboard::instance(); + + // Set up the input context + m_inputContext = new QQnxInputContext; +} + +QQnxIntegration::~QQnxIntegration() +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << "QQnx: platform plugin shutdown begin"; +#endif + // Destroy the keyboard class. + QQnxVirtualKeyboard::destroy(); + +#ifndef QT_NO_CLIPBOARD + // Delete the clipboard + delete m_clipboard; +#endif + + // Stop/destroy event thread + delete m_eventThread; + + // Stop/destroy navigator thread + delete m_navigatorThread; + + // Destroy all displays + QQnxScreen::destroyDisplays(); + + // Close connection to QNX composition manager + screen_destroy_context(m_screenContext); + + // Cleanup global OpenGL resources + QQnxGLContext::shutdown(); + +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << "QQnx: platform plugin shutdown end"; +#endif +} + +bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + switch (cap) { + case ThreadedPixmaps: return true; +#if defined(QT_OPENGL_ES) + case OpenGL: + return true; +#endif + default: return QPlatformIntegration::hasCapability(cap); + } +} + +QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // New windows are created on the primary display. + return new QQnxWindow(window, m_screenContext); +} + +QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *window) const +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + if (paintUsingOpenGL()) + return new QQnxGLBackingStore(window); + else + return new QQnxRasterBackingStore(window); +} + +QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + return new QQnxGLContext(context); +} + +QPlatformInputContext *QQnxIntegration::inputContext() const +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + return m_inputContext; +} + +void QQnxIntegration::moveToScreen(QWindow *window, int screen) +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << "QQnxIntegration::moveToScreen - w=" << window << ", s=" << screen; +#endif + + // get platform window used by widget + QQnxWindow *platformWindow = static_cast(window->handle()); + + // lookup platform screen by index + QQnxScreen *platformScreen = static_cast(QQnxScreen::screens().at(screen)); + + // move the platform window to the platform screen + platformWindow->setScreen(platformScreen); +} + +QList QQnxIntegration::screens() const +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + return QQnxScreen::screens(); +} + +QAbstractEventDispatcher *QQnxIntegration::guiThreadEventDispatcher() const +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + return m_eventDispatcher; +} + +#ifndef QT_NO_CLIPBOARD +QPlatformClipboard *QQnxIntegration::clipboard() const +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + if (!m_clipboard) { + m_clipboard = new QQnxClipboard; + } + return m_clipboard; +} +#endif + +QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + if (hint == ShowIsFullScreen) + return true; + + return QPlatformIntegration::styleHint(hint); +} + +QWindow *QQnxIntegration::window(screen_window_t qnxWindow) +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + QMutexLocker locker(&ms_windowMapperMutex); + Q_UNUSED(locker); + return ms_windowMapper.value(qnxWindow, 0); +} + +void QQnxIntegration::addWindow(screen_window_t qnxWindow, QWindow *window) +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + QMutexLocker locker(&ms_windowMapperMutex); + Q_UNUSED(locker); + ms_windowMapper.insert(qnxWindow, window); +} + +void QQnxIntegration::removeWindow(screen_window_t qnxWindow) +{ +#if defined(QQNXINTEGRATION_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + QMutexLocker locker(&ms_windowMapperMutex); + Q_UNUSED(locker); + ms_windowMapper.remove(qnxWindow); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h new file mode 100644 index 0000000000..51d06bd0e6 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxintegration.h @@ -0,0 +1,119 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXINTEGRATION_H +#define QQNXINTEGRATION_H + +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QQnxEventThread; +class QQnxInputContext; +class QQnxNavigatorThread; +class QQnxWindow; + +#ifndef QT_NO_CLIPBOARD +class QQnxClipboard; +#endif + +template class QHash; +typedef QHash QQnxWindowMapper; + +class QQnxIntegration : public QPlatformIntegration +{ +public: + QQnxIntegration(); + virtual ~QQnxIntegration(); + + virtual bool hasCapability(QPlatformIntegration::Capability cap) const; + + virtual QPlatformWindow *createPlatformWindow(QWindow *window) const; + virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; + virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + + virtual QPlatformInputContext *inputContext() const; + + virtual QList screens() const; + virtual void moveToScreen(QWindow *window, int screen); + + virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const; + + virtual QPlatformFontDatabase *fontDatabase() const { return m_fontDatabase; } + +#ifndef QT_NO_CLIPBOARD + virtual QPlatformClipboard *clipboard() const; +#endif + + virtual QVariant styleHint(StyleHint hint) const; + + bool paintUsingOpenGL() const { return m_paintUsingOpenGL; } + + static QWindow *window(screen_window_t qnxWindow); + +private: + static void addWindow(screen_window_t qnxWindow, QWindow *window); + static void removeWindow(screen_window_t qnxWindow); + + screen_context_t m_screenContext; + QQnxEventThread *m_eventThread; + QQnxNavigatorThread *m_navigatorThread; + QQnxInputContext *m_inputContext; + QPlatformFontDatabase *m_fontDatabase; + bool m_paintUsingOpenGL; + QAbstractEventDispatcher *m_eventDispatcher; +#ifndef QT_NO_CLIPBOARD + mutable QQnxClipboard* m_clipboard; +#endif + + static QQnxWindowMapper ms_windowMapper; + static QMutex ms_windowMapperMutex; + + friend class QQnxWindow; +}; + +QT_END_NAMESPACE + +#endif // QQNXINTEGRATION_H diff --git a/src/plugins/platforms/qnx/qqnxkeytranslator.h b/src/plugins/platforms/qnx/qqnxkeytranslator.h new file mode 100644 index 0000000000..46bdfacd97 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxkeytranslator.h @@ -0,0 +1,269 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXKEYTRANSLATOR_H +#define QQNXKEYTRANSLATOR_H + +#include + +#if defined(QQNXEVENTTHREAD_DEBUG) +#include +#endif + +QT_BEGIN_NAMESPACE + +Qt::Key keyTranslator( int key ) +{ + switch (key) { + case KEYCODE_PAUSE: + return Qt::Key_Pause; + + case KEYCODE_SCROLL_LOCK: + return Qt::Key_ScrollLock; + + case KEYCODE_PRINT: + return Qt::Key_Print; + + case KEYCODE_SYSREQ: + return Qt::Key_SysReq; + +// case KEYCODE_BREAK: + + case KEYCODE_ESCAPE: + return Qt::Key_Escape; + + case KEYCODE_BACKSPACE: + return Qt::Key_Backspace; + + case KEYCODE_TAB: + return Qt::Key_Tab; + + case KEYCODE_BACK_TAB: + return Qt::Key_Backtab; + + case KEYCODE_RETURN: + return Qt::Key_Return; + + case KEYCODE_CAPS_LOCK: + return Qt::Key_CapsLock; + + case KEYCODE_LEFT_SHIFT: + case KEYCODE_RIGHT_SHIFT: + return Qt::Key_Shift; + + case KEYCODE_LEFT_CTRL: + case KEYCODE_RIGHT_CTRL: + return Qt::Key_Control; + + case KEYCODE_LEFT_ALT: + case KEYCODE_RIGHT_ALT: + return Qt::Key_Alt; + + case KEYCODE_MENU: + return Qt::Key_Menu; + + case KEYCODE_LEFT_HYPER: + return Qt::Key_Hyper_L; + + case KEYCODE_RIGHT_HYPER: + return Qt::Key_Hyper_R; + + case KEYCODE_INSERT: + return Qt::Key_Insert; + + case KEYCODE_HOME: + return Qt::Key_Home; + + case KEYCODE_PG_UP: + return Qt::Key_PageUp; + + case KEYCODE_DELETE: + return Qt::Key_Delete; + + case KEYCODE_END: + return Qt::Key_End; + + case KEYCODE_PG_DOWN: + return Qt::Key_PageDown; + + case KEYCODE_LEFT: + return Qt::Key_Left; + + case KEYCODE_RIGHT: + return Qt::Key_Right; + + case KEYCODE_UP: + return Qt::Key_Up; + + case KEYCODE_DOWN: + return Qt::Key_Down; + + case KEYCODE_NUM_LOCK: + return Qt::Key_NumLock; + + case KEYCODE_KP_PLUS: + return Qt::Key_Plus; + + case KEYCODE_KP_MINUS: + return Qt::Key_Minus; + + case KEYCODE_KP_MULTIPLY: + return Qt::Key_Asterisk; + + case KEYCODE_KP_DIVIDE: + return Qt::Key_Slash; + + case KEYCODE_KP_ENTER: + return Qt::Key_Enter; + + case KEYCODE_KP_HOME: + return Qt::Key_Home; + + case KEYCODE_KP_UP: + return Qt::Key_Up; + + case KEYCODE_KP_PG_UP: + return Qt::Key_PageUp; + + case KEYCODE_KP_LEFT: + return Qt::Key_Left; + + // Is this right? + case KEYCODE_KP_FIVE: + return Qt::Key_5; + + case KEYCODE_KP_RIGHT: + return Qt::Key_Right; + + case KEYCODE_KP_END: + return Qt::Key_End; + + case KEYCODE_KP_DOWN: + return Qt::Key_Down; + + case KEYCODE_KP_PG_DOWN: + return Qt::Key_PageDown; + + case KEYCODE_KP_INSERT: + return Qt::Key_Insert; + + case KEYCODE_KP_DELETE: + return Qt::Key_Delete; + + case KEYCODE_F1: + return Qt::Key_F1; + + case KEYCODE_F2: + return Qt::Key_F2; + + case KEYCODE_F3: + return Qt::Key_F3; + + case KEYCODE_F4: + return Qt::Key_F4; + + case KEYCODE_F5: + return Qt::Key_F5; + + case KEYCODE_F6: + return Qt::Key_F6; + + case KEYCODE_F7: + return Qt::Key_F7; + + case KEYCODE_F8: + return Qt::Key_F8; + + case KEYCODE_F9: + return Qt::Key_F9; + + case KEYCODE_F10: + return Qt::Key_F10; + + case KEYCODE_F11: + return Qt::Key_F11; + + case KEYCODE_F12: + return Qt::Key_F12; + + // See keycodes.h for more, but these are all the basics. And printables are already included. + + default: +#if defined(QQNXEVENTTHREAD_DEBUG) + qDebug() << "QQNX: unknown key for translation:" << key; +#endif + break; + } + + return Qt::Key_Escape; +} + +bool isKeypadKey( int key ) +{ + switch (key) + { + case KEYCODE_KP_PLUS: + case KEYCODE_KP_MINUS: + case KEYCODE_KP_MULTIPLY: + case KEYCODE_KP_DIVIDE: + case KEYCODE_KP_ENTER: + case KEYCODE_KP_HOME: + case KEYCODE_KP_UP: + case KEYCODE_KP_PG_UP: + case KEYCODE_KP_LEFT: + case KEYCODE_KP_FIVE: + case KEYCODE_KP_RIGHT: + case KEYCODE_KP_END: + case KEYCODE_KP_DOWN: + case KEYCODE_KP_PG_DOWN: + case KEYCODE_KP_INSERT: + case KEYCODE_KP_DELETE: + return true; + default: + break; + } + + return false; +} + +QT_END_NAMESPACE + +#endif // QQNXKEYTRANSLATOR_H diff --git a/src/plugins/platforms/qnx/qqnxnavigatorthread.cpp b/src/plugins/platforms/qnx/qqnxnavigatorthread.cpp new file mode 100644 index 0000000000..def4cb7eb1 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxnavigatorthread.cpp @@ -0,0 +1,280 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxnavigatorthread.h" +#include "qqnxscreen.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static const char *navigatorControlPath = "/pps/services/navigator/control"; +static const int ppsBufferSize = 4096; + +QQnxNavigatorThread::QQnxNavigatorThread(QQnxScreen& primaryScreen) + : m_primaryScreen(primaryScreen), + m_fd(-1), + m_readNotifier(0) +{ +} + +QQnxNavigatorThread::~QQnxNavigatorThread() +{ + // block until thread terminates + shutdown(); + + delete m_readNotifier; +} + +void QQnxNavigatorThread::run() +{ +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "QQNX: navigator thread started"; +#endif + + // open connection to navigator + errno = 0; + m_fd = open(navigatorControlPath, O_RDWR); + if (m_fd == -1) { + qWarning("QQNX: failed to open navigator pps, errno=%d", errno); + return; + } + + m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read); + // using direct connection to get the slot called in this thread's context + connect(m_readNotifier, SIGNAL(activated(int)), this, SLOT(readData()), Qt::DirectConnection); + + exec(); + + // close connection to navigator + close(m_fd); + +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "QQNX: navigator thread stopped"; +#endif +} + +void QQnxNavigatorThread::shutdown() +{ +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "QQNX: navigator thread shutdown begin"; +#endif + + // signal thread to terminate + quit(); + + // block until thread terminates + wait(); + +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "QQNX: navigator thread shutdown end"; +#endif +} + +void QQnxNavigatorThread::parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id) +{ +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "PPS: data=" << ppsData; +#endif + + // tokenize pps data into lines + QList lines = ppsData.split('\n'); + + // validate pps object + if (lines.size() == 0 || lines.at(0) != "@control") { + qFatal("QQNX: unrecognized pps object, data=%s", ppsData.constData()); + } + + // parse pps object attributes and extract values + for (int i = 1; i < lines.size(); i++) { + + // tokenize current attribute + const QByteArray &attr = lines.at(i); + +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "PPS: attr=" << attr; +#endif + + int firstColon = attr.indexOf(':'); + if (firstColon == -1) { + // abort - malformed attribute + continue; + } + + int secondColon = attr.indexOf(':', firstColon + 1); + if (secondColon == -1) { + // abort - malformed attribute + continue; + } + + QByteArray key = attr.left(firstColon); + QByteArray value = attr.mid(secondColon + 1); + +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "PPS: key=" << key; + qDebug() << "PPS: val=" << value; +#endif + + // save attribute value + if (key == "msg") { + msg = value; + } else if (key == "dat") { + dat = value; + } else if (key == "id") { + id = value; + } else { + qFatal("QQNX: unrecognized pps attribute, attr=%s", key.constData()); + } + } +} + +void QQnxNavigatorThread::replyPPS(const QByteArray &res, const QByteArray &id, const QByteArray &dat) +{ + // construct pps message + QByteArray ppsData = "res::"; + ppsData += res; + ppsData += "\nid::"; + ppsData += id; + if (!dat.isEmpty()) { + ppsData += "\ndat::"; + ppsData += dat; + } + ppsData += "\n"; + +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "PPS reply=" << ppsData; +#endif + + // send pps message to navigator + errno = 0; + int bytes = write(m_fd, ppsData.constData(), ppsData.size()); + if (bytes == -1) { + qFatal("QQNX: failed to write navigator pps, errno=%d", errno); + } +} + +void QQnxNavigatorThread::handleMessage(const QByteArray &msg, const QByteArray &dat, const QByteArray &id) +{ +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "PPS: msg=" << msg << ", dat=" << dat << ", id=" << id; +#endif + + // check message type + if (msg == "orientationCheck") { + + // reply to navigator that (any) orientation is acceptable +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "PPS: orientation check, o=" << dat; +#endif + replyPPS(msg, id, "true"); + + } else if (msg == "orientation") { + + // update screen geometry and reply to navigator that we're ready +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "PPS: orientation, o=" << dat; +#endif + m_primaryScreen.setRotation( dat.toInt() ); + QWindowSystemInterface::handleScreenGeometryChange(0, m_primaryScreen.geometry()); + replyPPS(msg, id, ""); + + } else if (msg == "SWIPE_DOWN") { + + // simulate menu key press +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "PPS: menu"; +#endif + QWindow *w = QGuiApplication::focusWindow(); + QWindowSystemInterface::handleKeyEvent(w, QEvent::KeyPress, Qt::Key_Menu, Qt::NoModifier); + QWindowSystemInterface::handleKeyEvent(w, QEvent::KeyRelease, Qt::Key_Menu, Qt::NoModifier); + + } else if (msg == "exit") { + + // shutdown everything +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "PPS: exit"; +#endif + QCoreApplication::quit(); + } +} + +void QQnxNavigatorThread::readData() +{ +#if defined(QQNXNAVIGATORTHREAD_DEBUG) + qDebug() << "QQNX: reading navigator data"; +#endif + // allocate buffer for pps data + char buffer[ppsBufferSize]; + + // attempt to read pps data + errno = 0; + int bytes = qt_safe_read(m_fd, buffer, ppsBufferSize - 1); + if (bytes == -1) { + qFatal("QQNX: failed to read navigator pps, errno=%d", errno); + } + + // check if pps data was received + if (bytes > 0) { + + // ensure data is null terminated + buffer[bytes] = '\0'; + + // process received message + QByteArray ppsData(buffer); + QByteArray msg; + QByteArray dat; + QByteArray id; + parsePPS(ppsData, msg, dat, id); + handleMessage(msg, dat, id); + } +} diff --git a/src/plugins/platforms/qnx/qqnxnavigatorthread.h b/src/plugins/platforms/qnx/qqnxnavigatorthread.h new file mode 100644 index 0000000000..40b217db73 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxnavigatorthread.h @@ -0,0 +1,78 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXNAVIGATORTHREAD_H +#define QQNXNAVIGATORTHREAD_H + +#include + +QT_BEGIN_NAMESPACE + +class QQnxScreen; +class QSocketNotifier; + +class QQnxNavigatorThread : public QThread +{ + Q_OBJECT +public: + QQnxNavigatorThread(QQnxScreen &primaryScreen); + virtual ~QQnxNavigatorThread(); + +protected: + virtual void run(); + +private Q_SLOTS: + void readData(); + +private: + void shutdown(); + void parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id); + void replyPPS(const QByteArray &res, const QByteArray &id, const QByteArray &dat); + void handleMessage(const QByteArray &msg, const QByteArray &dat, const QByteArray &id); + + QQnxScreen &m_primaryScreen; + int m_fd; + QSocketNotifier *m_readNotifier; +}; + +QT_END_NAMESPACE + +#endif // QQNXNAVIGATORTHREAD_H diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp new file mode 100644 index 0000000000..1d0da240b3 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp @@ -0,0 +1,166 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxrasterbackingstore.h" +#include "qqnxwindow.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +QQnxRasterBackingStore::QQnxRasterBackingStore(QWindow *window) + : QPlatformBackingStore(window) +{ +#if defined(QQNXRASTERBACKINGSTORE_DEBUG) + qDebug() << "QQnxRasterBackingStore::QQnxRasterBackingStore - w=" << window; +#endif + + // save platform window associated with widget + m_platformWindow = static_cast(window->handle()); +} + +QQnxRasterBackingStore::~QQnxRasterBackingStore() +{ +#if defined(QQnxRasterBackingStore_DEBUG) + qDebug() << "QQnxRasterBackingStore::~QQnxRasterBackingStore - w=" << window(); +#endif +} + +QPaintDevice *QQnxRasterBackingStore::paintDevice() +{ + return m_platformWindow->renderBuffer().image(); +} + +void QQnxRasterBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(window); + Q_UNUSED(offset); + +#if defined(QQNXRASTERBACKINGSTORE_DEBUG) + qDebug() << "QQnxRasterBackingStore::flush - w=" << this->window(); +#endif + + // visit all pending scroll operations + for (int i = m_scrollOpList.size() - 1; i >= 0; i--) { + + // do the scroll operation + ScrollOp &op = m_scrollOpList[i]; + QRegion srcArea = op.totalArea.intersected( op.totalArea.translated(-op.dx, -op.dy) ); + m_platformWindow->scroll(srcArea, op.dx, op.dy); + } + + // clear all pending scroll operations + m_scrollOpList.clear(); + + // update the display with newly rendered content + m_platformWindow->post(region); +} + +void QQnxRasterBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + Q_UNUSED(size); + Q_UNUSED(staticContents); +#if defined(QQNXRASTERBACKINGSTORE_DEBUG) + qDebug() << "QQnxRasterBackingStore::resize - w=" << window() << ", s=" << size; +#endif + + // NOTE: defer resizing window buffers until next paint as + // resize() can be called multiple times before a paint occurs +} + +bool QQnxRasterBackingStore::scroll(const QRegion &area, int dx, int dy) +{ +#if defined(QQNXRASTERBACKINGSTORE_DEBUG) + qDebug() << "QQnxRasterBackingStore::scroll - w=" << window(); +#endif + + // calculate entire region affected by scroll operation (src + dst) + QRegion totalArea = area.translated(dx, dy); + totalArea += area; + + // visit all pending scroll operations + for (int i = m_scrollOpList.size() - 1; i >= 0; i--) { + + ScrollOp &op = m_scrollOpList[i]; + if (op.totalArea == totalArea) { + // same area is being scrolled again - update delta + op.dx += dx; + op.dy += dy; + return true; + } else if (op.totalArea.intersects(totalArea)) { + // current scroll overlaps previous scroll but is + // not equal in area - just paint everything + qWarning("QQNX: pending scroll operations overlap but not equal"); + return false; + } + } + + // create new scroll operation + m_scrollOpList.append( ScrollOp(totalArea, dx, dy) ); + return true; +} + +void QQnxRasterBackingStore::beginPaint(const QRegion ®ion) +{ + Q_UNUSED(region); + +#if defined(QQNXRASTERBACKINGSTORE_DEBUG) + qDebug() << "QQnxRasterBackingStore::beginPaint - w=" << window(); +#endif + + // resize window buffers if surface resized + QSize s = window()->size(); + if (s != m_platformWindow->bufferSize()) { + m_platformWindow->setBufferSize(s); + } +} + +void QQnxRasterBackingStore::endPaint(const QRegion ®ion) +{ + Q_UNUSED(region); +#if defined(QQnxRasterBackingStore_DEBUG) + qDebug() << "QQnxRasterBackingStore::endPaint - w=" << window(); +#endif +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.h b/src/plugins/platforms/qnx/qqnxrasterbackingstore.h new file mode 100644 index 0000000000..fec51a19b9 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.h @@ -0,0 +1,81 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXRASTERWINDOWSURFACE_H +#define QQNXRASTERWINDOWSURFACE_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QQnxWindow; + +class QQnxRasterBackingStore : public QPlatformBackingStore +{ +public: + QQnxRasterBackingStore(QWindow *window); + virtual ~QQnxRasterBackingStore(); + + virtual QPaintDevice *paintDevice(); + virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); + virtual void resize(const QSize &size, const QRegion &staticContents); + virtual bool scroll(const QRegion &area, int dx, int dy); + virtual void beginPaint(const QRegion ®ion); + virtual void endPaint(const QRegion ®ion); + +private: + class ScrollOp { + public: + ScrollOp(const QRegion &a, int x, int y) : totalArea(a), dx(x), dy(y) {} + QRegion totalArea; + int dx; + int dy; + }; + + QQnxWindow *m_platformWindow; + QList m_scrollOpList; +}; + +QT_END_NAMESPACE + +#endif // QQNXRASTERWINDOWSURFACE_H diff --git a/src/plugins/platforms/qnx/qqnxrootwindow.cpp b/src/plugins/platforms/qnx/qqnxrootwindow.cpp new file mode 100644 index 0000000000..6f6b89a6d6 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxrootwindow.cpp @@ -0,0 +1,257 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxrootwindow.h" + +#include "qqnxscreen.h" + +#include + +#if defined(QQNXROOTWINDOW_DEBUG) +#include +#endif + +#include +#include + +static const int MAGIC_ZORDER_FOR_NO_NAV = 10; + +QQnxRootWindow::QQnxRootWindow(QQnxScreen *screen) + : m_screen(screen), + m_window(0), + m_windowGroupName() +{ +#if defined(QQNXROOTWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // Create one top-level QNX window to act as a container for child windows + // since navigator only supports one application window + errno = 0; + int result = screen_create_window(&m_window, m_screen->nativeContext()); + int val[2]; + if (result != 0) { + qFatal("QQnxRootWindow: failed to create window, errno=%d", errno); + } + + // Move window to proper display + errno = 0; + screen_display_t display = m_screen->nativeDisplay(); + result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window display, errno=%d", errno); + } + + // Make sure window is above navigator but below keyboard if running as root + // since navigator won't automatically set our z-order in this case + if (getuid() == 0) { + errno = 0; + val[0] = MAGIC_ZORDER_FOR_NO_NAV; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window z-order, errno=%d", errno); + } + } + + // Window won't be visible unless it has some buffers so make one dummy buffer that is 1x1 + errno = 0; + val[0] = SCREEN_USAGE_NATIVE; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window buffer usage, errno=%d", errno); + } + + errno = 0; + val[0] = m_screen->nativeFormat(); + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window pixel format, errno=%d", errno); + } + + errno = 0; + val[0] = 1; + val[1] = 1; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window buffer size, errno=%d", errno); + } + + errno = 0; + result = screen_create_window_buffers(m_window, 1); + if (result != 0) { + qFatal("QQNX: failed to create window buffer, errno=%d", errno); + } + + // Window is always the size of the display + errno = 0; + QRect geometry = m_screen->geometry(); + val[0] = geometry.width(); + val[1] = geometry.height(); + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window size, errno=%d", errno); + } + + // Fill the window with solid black + errno = 0; + val[0] = 0; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_COLOR, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window colour, errno=%d", errno); + } + + // Make the window opaque + errno = 0; + val[0] = SCREEN_TRANSPARENCY_NONE; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window transparency, errno=%d", errno); + } + + // Set the swap interval to 1 + errno = 0; + val[0] = 1; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window swap interval, errno=%d", errno); + } + + // Set viewport size equal to window size but move outside buffer so the fill colour is used exclusively + errno = 0; + val[0] = geometry.width(); + val[1] = geometry.height(); + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window source size, errno=%d", errno); + } + + errno = 0; + val[0] = 1; + val[1] = 0; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_POSITION, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window source position, errno=%d", errno); + } + + createWindowGroup(); + post(); +} + +QQnxRootWindow::~QQnxRootWindow() +{ + // Cleanup top-level QNX window + screen_destroy_window(m_window); +} + +void QQnxRootWindow::post() const +{ +#if defined(QQNXROOTWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + errno = 0; + screen_buffer_t buffer; + int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)&buffer); + if (result != 0) { + qFatal("QQnxRootWindow: failed to query window buffer, errno=%d", errno); + } + + errno = 0; + int dirtyRect[] = {0, 0, 1, 1}; + result = screen_post_window(m_window, buffer, 1, dirtyRect, 0); + if (result != 0) { + qFatal("QQNX: failed to post window buffer, errno=%d", errno); + } +} + +void QQnxRootWindow::flush() const +{ +#if defined(QQNXROOTWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // Force immediate display update + errno = 0; + int result = screen_flush_context(m_screen->nativeContext(), 0); + if (result != 0) { + qFatal("QQnxRootWindow: failed to flush context, errno=%d", errno); + } +} + +void QQnxRootWindow::setRotation(int rotation) +{ +#if defined(QQNXROOTWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "angle =" << rotation; +#endif + errno = 0; + int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window rotation, errno=%d", errno); + } +} + +void QQnxRootWindow::resize(const QSize &size) +{ + errno = 0; + int val[] = {size.width(), size.height()}; + int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window size, errno=%d", errno); + } + + errno = 0; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val); + if (result != 0) { + qFatal("QQnxRootWindow: failed to set window source size, errno=%d", errno); + } + + // NOTE: display will update when child windows relayout and repaint +} + +void QQnxRootWindow::createWindowGroup() +{ + // Generate a random window group name + m_windowGroupName = QUuid::createUuid().toString().toAscii(); + + // Create window group so child windows can be parented by container window + errno = 0; + int result = screen_create_window_group(m_window, m_windowGroupName.constData()); + if (result != 0) { + qFatal("QQnxRootWindow: failed to create app window group, errno=%d", errno); + } +} diff --git a/src/plugins/platforms/qnx/qqnxrootwindow.h b/src/plugins/platforms/qnx/qqnxrootwindow.h new file mode 100644 index 0000000000..80b10c65f0 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxrootwindow.h @@ -0,0 +1,81 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXROOTWINDOW_H +#define QQNXROOTWINDOW_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QQnxScreen; + +class QQnxRootWindow +{ +public: + QQnxRootWindow(QQnxScreen *screen); + ~QQnxRootWindow(); + + screen_window_t nativeHandle() const { return m_window; } + + void post() const; + void flush() const; + + void setRotation(int rotation); + + void resize(const QSize &size); + + QByteArray groupName() const { return m_windowGroupName; } + +private: + void createWindowGroup(); + + QQnxScreen *m_screen; + screen_window_t m_window; + QByteArray m_windowGroupName; +}; + +QT_END_NAMESPACE + +#endif // QQNXROOTWINDOW_H diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp new file mode 100644 index 0000000000..e0e3d6d57d --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -0,0 +1,315 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxscreen.h" +#include "qqnxvirtualkeyboard.h" +#include "qqnxwindow.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +QList QQnxScreen::ms_screens; +QList QQnxScreen::ms_childWindows; + +QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, bool primaryScreen) + : m_screenContext(screenContext), + m_display(display), + m_rootWindow(), + m_primaryScreen(primaryScreen), + m_posted(false), + m_platformContext(0) +{ +#if defined(QQNXSCREEN_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // Cache initial orientation of this display + // TODO: use ORIENTATION environment variable? + errno = 0; + int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION, &m_initialRotation); + if (result != 0) { + qFatal("QQnxScreen: failed to query display rotation, errno=%d", errno); + } + m_currentRotation = m_initialRotation; + + // Cache size of this display in pixels + // TODO: use WIDTH and HEIGHT environment variables? + errno = 0; + int val[2]; + result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_SIZE, val); + if (result != 0) { + qFatal("QQnxScreen: failed to query display size, errno=%d", errno); + } + + m_currentGeometry = m_initialGeometry = QRect(0, 0, val[0], val[1]); + + // Cache size of this display in millimeters + errno = 0; + result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_PHYSICAL_SIZE, val); + if (result != 0) { + qFatal("QQnxScreen: failed to query display physical size, errno=%d", errno); + } + + // Peg the DPI to 96 (for now) so fonts are a reasonable size. We'll want to match + // everything with a QStyle later, and at that point the physical size can be used + // instead. + { + static const int dpi = 96; + int width = m_currentGeometry.width() / dpi * qreal(25.4) ; + int height = m_currentGeometry.height() / dpi * qreal(25.4) ; + + m_currentPhysicalSize = m_initialPhysicalSize = QSize(width,height); + } + + // We only create the root window if we are the primary display. + if (primaryScreen) + m_rootWindow = QSharedPointer(new QQnxRootWindow(this)); +} + +QQnxScreen::~QQnxScreen() +{ +#if defined(QQNXSCREEN_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif +} + +/* static */ +void QQnxScreen::createDisplays(screen_context_t context) +{ +#if defined(QQNXSCREEN_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // Query number of displays + errno = 0; + int displayCount; + int result = screen_get_context_property_iv(context, SCREEN_PROPERTY_DISPLAY_COUNT, &displayCount); + if (result != 0) { + qFatal("QQnxScreen: failed to query display count, errno=%d", errno); + } + + // Get all displays + errno = 0; + screen_display_t *displays = (screen_display_t *)alloca(sizeof(screen_display_t) * displayCount); + result = screen_get_context_property_pv(context, SCREEN_PROPERTY_DISPLAYS, (void **)displays); + if (result != 0) { + qFatal("QQnxScreen: failed to query displays, errno=%d", errno); + } + + for (int i=0; iupdateZorder(topZorder); + + // After a hierarchy update, we need to force a flush on all screens. + // Right now, all screens share a context. + screen_flush_context( primaryDisplay()->m_screenContext, 0 ); +} + +void QQnxScreen::onWindowPost(QQnxWindow *window) +{ +#if defined(QQNXSCREEN_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + Q_UNUSED(window) + + // post app window (so navigator will show it) after first child window + // has posted; this only needs to happen once as the app window's content + // never changes + if (!m_posted && m_rootWindow) { + m_rootWindow->post(); + m_posted = true; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h new file mode 100644 index 0000000000..5749a66f5d --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxscreen.h @@ -0,0 +1,121 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QBBSCREEN_H +#define QBBSCREEN_H + +#include + +#include "qqnxrootwindow.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QQnxWindow; + +class QQnxScreen : public QPlatformScreen +{ +public: + static QList screens() { return ms_screens; } + static void createDisplays(screen_context_t context); + static void destroyDisplays(); + static QQnxScreen *primaryDisplay() { return static_cast(ms_screens.at(0)); } + static int defaultDepth(); + + virtual QRect geometry() const { return m_currentGeometry; } + virtual QRect availableGeometry() const; + virtual int depth() const { return defaultDepth(); } + virtual QImage::Format format() const { return (depth() == 32) ? QImage::Format_RGB32 : QImage::Format_RGB16; } + virtual QSizeF physicalSize() const { return m_currentPhysicalSize; } + + bool isPrimaryScreen() const { return m_primaryScreen; } + + int rotation() const { return m_currentRotation; } + void setRotation(int rotation); + + int nativeFormat() const { return (depth() == 32) ? SCREEN_FORMAT_RGBA8888 : SCREEN_FORMAT_RGB565; } + screen_display_t nativeDisplay() const { return m_display; } + screen_context_t nativeContext() const { return m_screenContext; } + const char *windowGroupName() const { return m_rootWindow->groupName().constData(); } + + /* Window hierarchy management */ + static void addWindow(QQnxWindow *child); + static void removeWindow(QQnxWindow *child); + static void raiseWindow(QQnxWindow *window); + static void lowerWindow(QQnxWindow *window); + static void updateHierarchy(); + + void onWindowPost(QQnxWindow *window); + + QSharedPointer rootWindow() const { return m_rootWindow; } + +private: + QQnxScreen(screen_context_t context, screen_display_t display, bool primaryScreen); + virtual ~QQnxScreen(); + + static bool orthogonal(int rotation1, int rotation2); + + screen_context_t m_screenContext; + screen_display_t m_display; + QSharedPointer m_rootWindow; + bool m_primaryScreen; + bool m_posted; + bool m_usingOpenGL; + + int m_initialRotation; + int m_currentRotation; + QSize m_initialPhysicalSize; + QSize m_currentPhysicalSize; + QRect m_initialGeometry; + QRect m_currentGeometry; + QPlatformOpenGLContext *m_platformContext; + + static QList ms_screens; + static QList ms_childWindows; +}; + +QT_END_NAMESPACE + +#endif // QBBSCREEN_H diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboard.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboard.cpp new file mode 100644 index 0000000000..9d7fe92660 --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboard.cpp @@ -0,0 +1,500 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxvirtualkeyboard.h" +#include "qqnxscreen.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char *QQnxVirtualKeyboard::ms_PPSPath = "/pps/services/input/control?wait"; +const size_t QQnxVirtualKeyboard::ms_bufferSize = 2048; + +static QQnxVirtualKeyboard *s_instance = 0; + +// Huge hack for keyboard shadow (see QNX PR 88400). Should be removed ASAP. +#define KEYBOARD_SHADOW_HEIGHT 8 + +QQnxVirtualKeyboard::QQnxVirtualKeyboard() : + m_encoder(NULL), + m_decoder(NULL), + m_buffer(NULL), + m_height(0), + m_fd(-1), + m_keyboardMode(Default), + m_visible(false), + m_locale(QLatin1String("en_US")) +{ + connect(); +} + +QQnxVirtualKeyboard::~QQnxVirtualKeyboard() +{ + close(); +} + +/* static */ +QQnxVirtualKeyboard& QQnxVirtualKeyboard::instance() +{ + if (!s_instance) { + s_instance = new QQnxVirtualKeyboard(); + s_instance->start(); + } + + return *s_instance; +} + +/* static */ +void QQnxVirtualKeyboard::destroy() +{ + if (s_instance) { + delete s_instance; + s_instance = 0; + } +} + +void QQnxVirtualKeyboard::close() +{ + if (m_fd) { + // any reads will fail after we close the fd, which is basically what we want. + ::close(m_fd); + } + + // Wait for the thread to die (should be immediate), then continue the cleanup. + wait(); + + if (m_fd) { + m_fd = -1; + } + + + if (m_decoder) + { + pps_decoder_cleanup(m_decoder); + delete m_decoder; + m_decoder = NULL; + } + + if (m_encoder) + { + pps_encoder_cleanup(m_encoder); + delete m_encoder; + m_encoder = NULL; + } + + delete [] m_buffer; + m_buffer = NULL; +} + +bool QQnxVirtualKeyboard::connect() +{ + close(); + + m_encoder = new pps_encoder_t; + m_decoder = new pps_decoder_t; + + pps_encoder_initialize(m_encoder, false); + pps_decoder_initialize(m_decoder, NULL); + + errno = 0; + m_fd = ::open(ms_PPSPath, O_RDWR); + if (m_fd == -1) + { + qCritical("QQnxVirtualKeyboard: Unable to open \"%s\" for keyboard: %s (%d).", + ms_PPSPath, strerror(errno), errno); + close(); + return false; + } + + m_buffer = new char[ms_bufferSize]; + if (!m_buffer) { + qCritical("QQnxVirtualKeyboard: Unable to allocate buffer of %d bytes. Size is unavailable.", ms_bufferSize); + return false; + } + + if (!queryPPSInfo()) + return false; + + start(); + + return true; +} + +bool QQnxVirtualKeyboard::queryPPSInfo() +{ + // Request info, requires id to regenerate res message. + pps_encoder_add_string(m_encoder, "msg", "info"); + pps_encoder_add_string(m_encoder, "id", "libWebView"); + + if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { + close(); + return false; + } + + pps_encoder_reset(m_encoder); + + return true; +} + +void QQnxVirtualKeyboard::notifyClientActiveStateChange(bool active) +{ + if (!active) + hideKeyboard(); +} + +void QQnxVirtualKeyboard::run() +{ + ppsDataReady(); +} + +void QQnxVirtualKeyboard::ppsDataReady() +{ + while (1) { + ssize_t nread = read(m_fd, m_buffer, ms_bufferSize - 1); + +#ifdef QQNXVIRTUALKEYBOARD_DEBUG + qDebug() << "QQNX: keyboardMessage size: " << nread; +#endif + if (nread < 0) + break; + + // nread is the real space necessary, not the amount read. + if (static_cast(nread) > ms_bufferSize - 1) { + qCritical("QQnxVirtualKeyboard: Keyboard buffer size too short; need %u.", nread + 1); + break; + } + + m_buffer[nread] = 0; + pps_decoder_parse_pps_str(m_decoder, m_buffer); + pps_decoder_push(m_decoder, NULL); +#ifdef QQNXVIRTUALKEYBOARD_DEBUG + pps_decoder_dump_tree(m_decoder, stderr); +#endif + + const char *value; + if (pps_decoder_get_string(m_decoder, "error", &value) == PPS_DECODER_OK) { + qCritical("QQnxVirtualKeyboard: Keyboard PPS decoder error: %s", value ? value : "[null]"); + continue; + } + + if (pps_decoder_get_string(m_decoder, "msg", &value) == PPS_DECODER_OK) { + if (strcmp(value, "show") == 0) { + const bool oldVisible = m_visible; + m_visible = true; + handleKeyboardStateChangeMessage(true); + if (oldVisible != m_visible) + emit visibilityChanged(m_visible); + } else if (strcmp(value, "hide") == 0) { + const bool oldVisible = m_visible; + m_visible = false; + handleKeyboardStateChangeMessage(false); + if (oldVisible != m_visible) + emit visibilityChanged(m_visible); + } else if (strcmp(value, "info") == 0) + handleKeyboardInfoMessage(); + else if (strcmp(value, "connect") == 0) { } + else + qCritical("QQnxVirtualKeyboard: Unexpected keyboard PPS msg value: %s", value ? value : "[null]"); + } else if (pps_decoder_get_string(m_decoder, "res", &value) == PPS_DECODER_OK) { + if (strcmp(value, "info") == 0) + handleKeyboardInfoMessage(); + else + qCritical("QQnxVirtualKeyboard: Unexpected keyboard PPS res value: %s", value ? value : "[null]"); + } else + qCritical("QQnxVirtualKeyboard: Unexpected keyboard PPS message type"); + } + +#ifdef QQNXVIRTUALKEYBOARD_DEBUG + qDebug() << "QQNX: exiting keyboard thread"; +#endif + + if (m_decoder) + pps_decoder_cleanup(m_decoder); +} + +void QQnxVirtualKeyboard::handleKeyboardInfoMessage() +{ + int newHeight = 0; + const char *value; + + if (pps_decoder_push(m_decoder, "dat") != PPS_DECODER_OK) { + qCritical("QQnxVirtualKeyboard: Keyboard PPS dat object not found"); + return; + } + if (pps_decoder_get_int(m_decoder, "size", &newHeight) != PPS_DECODER_OK) { + qCritical("QQnxVirtualKeyboard: Keyboard PPS size field not found"); + return; + } + if (pps_decoder_push(m_decoder, "locale") != PPS_DECODER_OK) { + qCritical("QQnxVirtualKeyboard: Keyboard PPS locale object not found"); + return; + } + if (pps_decoder_get_string(m_decoder, "languageId", &value) != PPS_DECODER_OK) { + qCritical("QQnxVirtualKeyboard: Keyboard PPS languageId field not found"); + return; + } + const QString languageId = QString::fromLatin1(value); + if (pps_decoder_get_string(m_decoder, "countryId", &value) != PPS_DECODER_OK) { + qCritical("QQnxVirtualKeyboard: Keyboard PPS size countryId not found"); + return; + } + const QString countryId = QString::fromLatin1(value); + + // HUGE hack, should be removed ASAP. + newHeight -= KEYBOARD_SHADOW_HEIGHT; // We want to ignore the 8 pixel shadow above the keyboard. (PR 88400) + + if (newHeight != m_height) { + m_height = newHeight; + updateAvailableScreenGeometry(); + } + + const QLocale locale = QLocale(languageId + QLatin1Char('_') + countryId); + if (locale != m_locale) { + m_locale = locale; + emit localeChanged(locale); + } + +#ifdef QQNXVIRTUALKEYBOARD_DEBUG + qDebug() << "QQNX: handleKeyboardInfoMessage size=" << m_height << "locale=" << m_locale; +#endif +} + +void QQnxVirtualKeyboard::handleKeyboardStateChangeMessage(bool visible) +{ + +#ifdef QQNXVIRTUALKEYBOARD_DEBUG + qDebug() << "QQNX: handleKeyboardStateChangeMessage " << visible; +#endif + updateAvailableScreenGeometry(); + + if (visible) + showKeyboard(); + else + hideKeyboard(); +} + +void QQnxVirtualKeyboard::updateAvailableScreenGeometry() +{ +#ifdef QQNXVIRTUALKEYBOARD_DEBUG + qDebug() << "QQNX: updateAvailableScreenGeometry: keyboard visible=" << m_visible << ", keyboard height=" << m_height; +#endif + + // TODO: What screen index should be used? I assume primaryScreen here because it works, and + // we do it for handleScreenGeometryChange elsewhere but since we have support + // for more than one screen, that's not going to always work. + QQnxScreen *platformScreen = QQnxScreen::primaryDisplay(); + QWindowSystemInterface::handleScreenAvailableGeometryChange(platformScreen->screen(), platformScreen->availableGeometry()); +} + +bool QQnxVirtualKeyboard::showKeyboard() +{ +#ifdef QQNXVIRTUALKEYBOARD_DEBUG + qDebug() << "QQNX: showKeyboard()"; +#endif + + // Try to connect. + if (m_fd == -1 && !connect()) + return false; + + // NOTE: This must be done everytime the keyboard is shown even if there is no change because + // hiding the keyboard wipes the setting. + applyKeyboardModeOptions(); + + pps_encoder_reset(m_encoder); + + // Send the show message. + pps_encoder_add_string(m_encoder, "msg", "show"); + + if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { + close(); + return false; + } + + pps_encoder_reset(m_encoder); + + // Return true if no error occurs. Sizing response will be triggered when confirmation of + // the change arrives. + return true; +} + +bool QQnxVirtualKeyboard::hideKeyboard() +{ +#ifdef QQNXVIRTUALKEYBOARD_DEBUG + qDebug() << "QQNX: hideKeyboard()"; +#endif + + if (m_fd == -1 && !connect()) + return false; + + pps_encoder_add_string(m_encoder, "msg", "hide"); + + if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { + close(); + + //Try again. + if (connect()) { + if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { + close(); + return false; + } + } + else + return false; + } + + pps_encoder_reset(m_encoder); + + // Return true if no error occurs. Sizing response will be triggered when confirmation of + // the change arrives. + return true; +} + +void QQnxVirtualKeyboard::setKeyboardMode(KeyboardMode mode) +{ + m_keyboardMode = mode; +} + +void QQnxVirtualKeyboard::applyKeyboardModeOptions() +{ + // Try to connect. + if (m_fd == -1 && !connect()) + return; + + // Send the options message. + pps_encoder_add_string(m_encoder, "msg", "options"); + + pps_encoder_start_object(m_encoder, "dat"); + switch (m_keyboardMode) { + case Url: + addUrlModeOptions(); + break; + case Email: + addEmailModeOptions(); + break; + case Web: + addWebModeOptions(); + break; + case NumPunc: + addNumPuncModeOptions(); + break; + case Symbol: + addSymbolModeOptions(); + break; + case Phone: + addPhoneModeOptions(); + break; + case Pin: + addPinModeOptions(); + break; + case Default: + default: + addDefaultModeOptions(); + break; + } + + pps_encoder_end_object(m_encoder); + + if (::write(m_fd, pps_encoder_buffer(m_encoder), pps_encoder_length(m_encoder)) == -1) { + close(); + } + + pps_encoder_reset(m_encoder); +} + +void QQnxVirtualKeyboard::addDefaultModeOptions() +{ + pps_encoder_add_string(m_encoder, "enter", "enter.default"); + pps_encoder_add_string(m_encoder, "type", "default"); +} + +void QQnxVirtualKeyboard::addUrlModeOptions() +{ + pps_encoder_add_string(m_encoder, "enter", "enter.default"); + pps_encoder_add_string(m_encoder, "type", "url"); +} + +void QQnxVirtualKeyboard::addEmailModeOptions() +{ + pps_encoder_add_string(m_encoder, "enter", "enter.default"); + pps_encoder_add_string(m_encoder, "type", "email"); +} + +void QQnxVirtualKeyboard::addWebModeOptions() +{ + pps_encoder_add_string(m_encoder, "enter", "enter.default"); + pps_encoder_add_string(m_encoder, "type", "web"); +} + +void QQnxVirtualKeyboard::addNumPuncModeOptions() +{ + pps_encoder_add_string(m_encoder, "enter", "enter.default"); + pps_encoder_add_string(m_encoder, "type", "numPunc"); +} + +void QQnxVirtualKeyboard::addPhoneModeOptions() +{ + pps_encoder_add_string(m_encoder, "enter", "enter.default"); + pps_encoder_add_string(m_encoder, "type", "phone"); +} + +void QQnxVirtualKeyboard::addPinModeOptions() +{ + pps_encoder_add_string(m_encoder, "enter", "enter.default"); + pps_encoder_add_string(m_encoder, "type", "pin"); +} + +void QQnxVirtualKeyboard::addSymbolModeOptions() +{ + pps_encoder_add_string(m_encoder, "enter", "enter.default"); + pps_encoder_add_string(m_encoder, "type", "symbol"); +} diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboard.h b/src/plugins/platforms/qnx/qqnxvirtualkeyboard.h new file mode 100644 index 0000000000..21b2e8736c --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboard.h @@ -0,0 +1,130 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 VIRTUALKEYBOARD_H_ +#define VIRTUALKEYBOARD_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/* Shamelessly copied from the browser - this should be rewritten once we have a proper PPS wrapper class */ +class QQnxVirtualKeyboard : public QThread +{ + Q_OBJECT +public: + // NOTE: Not all the following keyboard modes are currently used. + // Default - Regular Keyboard + // Url/Email - Enhanced keys for each types. + // Web - Regular keyboard with two blank keys, currently unused. + // NumPunc - Numbers & Punctionation, alternate to Symbol + // Symbol - All symbols, alternate to NumPunc, currently unused. + // Phone - Phone enhanced keyboard - currently unused as no alternate keyboard available to access a-zA-Z + // Pin - Keyboard for entering Pins (Hex values) currently unused. + // + // SPECIAL NOTE: Usage of NumPunc may have to be removed, ABC button is non-functional. + // + enum KeyboardMode { Default, Url, Email, Web, NumPunc, Symbol, Phone, Pin }; + + static QQnxVirtualKeyboard& instance(); + static void destroy(); + + bool showKeyboard(); + bool hideKeyboard(); + int height() { return m_visible ? m_height : 0; } + void setKeyboardMode(KeyboardMode); + void notifyClientActiveStateChange(bool); + bool isVisible() const { return m_visible; } + QLocale locale() const { return m_locale; } + +Q_SIGNALS: + void localeChanged(const QLocale &locale); + void visibilityChanged(bool visible); + +private: + QQnxVirtualKeyboard(); + virtual ~QQnxVirtualKeyboard(); + + // Will be called internally if needed. + bool connect(); + void close(); + void ppsDataReady(); + bool queryPPSInfo(); + void handleKeyboardInfoMessage(); + void handleKeyboardStateChangeMessage(bool visible); + void updateAvailableScreenGeometry(); + + void applyKeyboardModeOptions(); + void addDefaultModeOptions(); + void addUrlModeOptions(); + void addEmailModeOptions(); + void addWebModeOptions(); + void addNumPuncModeOptions(); + void addSymbolModeOptions(); + void addPhoneModeOptions(); + void addPinModeOptions(); + + // QThread overrides + virtual void run(); + + pps_encoder_t *m_encoder; + pps_decoder_t *m_decoder; + char *m_buffer; + int m_height; + int m_fd; + KeyboardMode m_keyboardMode; + bool m_visible; + QLocale m_locale; + + // Path to keyboardManager in PPS. + static const char *ms_PPSPath; + static const size_t ms_bufferSize; +}; + +#endif /* VIRTUALKEYBOARD_H_ */ diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp new file mode 100644 index 0000000000..cf45d062bd --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -0,0 +1,665 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 "qqnxwindow.h" +#include "qqnxglcontext.h" +#include "qqnxintegration.h" +#include "qqnxscreen.h" + +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context) + : QPlatformWindow(window), + m_screenContext(context), + m_window(0), + m_currentBufferIndex(-1), + m_previousBufferIndex(-1), + m_platformOpenGLContext(0), + m_screen(0), + m_parentWindow(0), + m_visible(true) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window << ", size =" << window->size(); +#endif + int result; + + // Create child QNX window + errno = 0; + result = screen_create_window_type(&m_window, m_screenContext, SCREEN_CHILD_WINDOW); + if (result != 0) { + qFatal("QQnxWindow: failed to create window, errno=%d", errno); + } + + // Set window buffer usage based on rendering API + int val; + QSurface::SurfaceType surfaceType = window->surfaceType(); + switch (surfaceType) { + case QSurface::RasterSurface: + val = SCREEN_USAGE_NATIVE | SCREEN_USAGE_READ | SCREEN_USAGE_WRITE; + break; + case QSurface::OpenGLSurface: + val = SCREEN_USAGE_OPENGL_ES2; + break; + default: + qFatal("QQnxWindow: unsupported window API"); + break; + } + + errno = 0; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_USAGE, &val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window buffer usage, errno=%d", errno); + } + + // Alpha channel is always pre-multiplied if present + errno = 0; + val = SCREEN_PRE_MULTIPLIED_ALPHA; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ALPHA_MODE, &val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window alpha mode, errno=%d", errno); + } + + // Make the window opaque + errno = 0; + val = SCREEN_TRANSPARENCY_NONE; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_TRANSPARENCY, &val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window transparency, errno=%d", errno); + } + + // Set the window swap interval + errno = 0; + val = 1; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SWAP_INTERVAL, &val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window swap interval, errno=%d", errno); + } + + // Assign the window to the primary display (this is the default specified by screen). + setScreen(QQnxScreen::primaryDisplay()); + + // Add the window to the root of the hierarchy + QQnxScreen::addWindow(this); + + // Add window to plugin's window mapper + QQnxIntegration::addWindow(m_window, window); +} + +QQnxWindow::~QQnxWindow() +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window(); +#endif + // Remove from plugin's window mapper + QQnxIntegration::removeWindow(m_window); + + // Remove from parent's Hierarchy. + removeFromParent(); + QQnxScreen::updateHierarchy(); + + // We shouldn't allow this case unless QT allows it. Does it? Or should we send the + // handleCloseEvent on all children when this window is deleted? + if (m_childWindows.size() > 0) + qFatal("QQnxWindow: window destroyed before children!"); + + // Cleanup QNX window and its buffers + screen_destroy_window(m_window); +} + +void QQnxWindow::setGeometry(const QRect &rect) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window() << ", (" << rect.x() << "," << rect.y() << "," << rect.width() << "," << rect.height() << ")"; +#endif + + QRect oldGeometry = geometry(); + + // Call base class method + QPlatformWindow::setGeometry(rect); + + // Set window geometry equal to widget geometry + errno = 0; + int val[2]; + val[0] = rect.x(); + val[1] = rect.y(); + int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window position, errno=%d", errno); + } + + errno = 0; + val[0] = rect.width(); + val[1] = rect.height(); + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SIZE, val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window size, errno=%d", errno); + } + + // Set viewport size equal to window size + errno = 0; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window source size, errno=%d", errno); + } + + // Now move all children. + QPoint offset; + if (!oldGeometry.isEmpty()) { + offset = rect.topLeft(); + offset -= oldGeometry.topLeft(); + + QList::iterator it; + for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) { + (*it)->offset(offset); + } + } +} + +void QQnxWindow::offset(const QPoint &offset) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window(); +#endif + // Move self and then children. + QRect newGeometry = geometry(); + newGeometry.translate(offset); + + // Call the base class + QPlatformWindow::setGeometry(newGeometry); + + int val[2]; + + errno = 0; + val[0] = newGeometry.x(); + val[1] = newGeometry.y(); + int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_POSITION, val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window position, errno=%d", errno); + } + + QList::iterator it; + for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) { + (*it)->offset(offset); + } +} + +void QQnxWindow::setVisible(bool visible) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window() << "visible =" << visible; +#endif + + m_visible = visible; + + QQnxWindow *root = this; + while (root->m_parentWindow) + root = root->m_parentWindow; + + root->updateVisibility(root->m_visible); + + window()->requestActivateWindow(); +} + +void QQnxWindow::updateVisibility(bool parentVisible) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "parentVisible =" << parentVisible << "window =" << window(); +#endif + // Set window visibility + errno = 0; + int val = (m_visible && parentVisible) ? 1 : 0; + int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window visibility, errno=%d", errno); + } + + QList::iterator it; + for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) { + (*it)->updateVisibility(m_visible && parentVisible); + } +} + +void QQnxWindow::setOpacity(qreal level) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window() << "opacity =" << level; +#endif + // Set window global alpha + errno = 0; + int val = (int)(level * 255); + int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window global alpha, errno=%d", errno); + } + + // TODO: How to handle children of this window? If we change all the visibilities, then + // the transparency will look wrong... +} + +void QQnxWindow::setBufferSize(const QSize &size) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window() << "size =" << size; +#endif + // Set window buffer size + errno = 0; + int val[2] = { size.width(), size.height() }; + int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_BUFFER_SIZE, val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window buffer size, errno=%d", errno); + } + + // Create window buffers if they do not exist + if (!hasBuffers()) { + // Get pixel format from EGL config if using OpenGL; + // otherwise inherit pixel format of window's screen + if (m_platformOpenGLContext != 0) { + val[0] = platformWindowFormatToNativeFormat(m_platformOpenGLContext->format()); + } else { + val[0] = m_screen->nativeFormat(); + } + + errno = 0; + result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_FORMAT, val); + if (result != 0) { + qFatal("QQnxWindow: failed to set window pixel format, errno=%d", errno); + } + + errno = 0; + result = screen_create_window_buffers(m_window, MAX_BUFFER_COUNT); + if (result != 0) { + qFatal("QQnxWindow: failed to create window buffers, errno=%d", errno); + } + } + + // Cache new buffer size + m_bufferSize = size; + + // Buffers were destroyed; reacquire them + m_currentBufferIndex = -1; + m_previousDirty = QRegion(); + m_scrolled = QRegion(); +} + +QQnxBuffer &QQnxWindow::renderBuffer() +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window(); +#endif + // Check if render buffer is invalid + if (m_currentBufferIndex == -1) { + // Get all buffers available for rendering + errno = 0; + screen_buffer_t buffers[MAX_BUFFER_COUNT]; + int result = screen_get_window_property_pv(m_window, SCREEN_PROPERTY_RENDER_BUFFERS, (void **)buffers); + if (result != 0) { + qFatal("QQnxWindow: failed to query window buffers, errno=%d", errno); + } + + // Wrap each buffer + for (int i = 0; i < MAX_BUFFER_COUNT; ++i) { + m_buffers[i] = QQnxBuffer(buffers[i]); + } + + // Use the first available render buffer + m_currentBufferIndex = 0; + m_previousBufferIndex = -1; + } + + return m_buffers[m_currentBufferIndex]; +} + +void QQnxWindow::scroll(const QRegion ®ion, int dx, int dy, bool flush) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window(); +#endif + copyBack(region, dx, dy, flush); + m_scrolled += region; +} + +void QQnxWindow::post(const QRegion &dirty) +{ + // Check if render buffer exists and something was rendered + if (m_currentBufferIndex != -1 && !dirty.isEmpty()) { +#if defined(QQNXWINDOW_DEBUG) + qDebug() << "QQnxWindow::post - window =" << window(); +#endif + QQnxBuffer ¤tBuffer = m_buffers[m_currentBufferIndex]; + + // Copy unmodified region from old render buffer to new render buffer; + // required to allow partial updates + QRegion preserve = m_previousDirty - dirty - m_scrolled; + copyBack(preserve, 0, 0); + + // Calculate region that changed + QRegion modified = preserve + dirty + m_scrolled; + QRect rect = modified.boundingRect(); + int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() }; + + // Update the display with contents of render buffer + errno = 0; + int result = screen_post_window(m_window, currentBuffer.nativeBuffer(), 1, dirtyRect, 0); + if (result != 0) { + qFatal("QQnxWindow: failed to post window buffer, errno=%d", errno); + } + + // Advance to next nender buffer + m_previousBufferIndex = m_currentBufferIndex++; + if (m_currentBufferIndex >= MAX_BUFFER_COUNT) { + m_currentBufferIndex = 0; + } + + // Save modified region and clear scrolled region + m_previousDirty = dirty; + m_scrolled = QRegion(); + + // Notify screen that window posted + if (m_screen != 0) { + m_screen->onWindowPost(this); + } + } +} + +void QQnxWindow::setScreen(QQnxScreen *platformScreen) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window() << "platformScreen =" << platformScreen; +#endif + + if (m_screen == platformScreen) + return; + + m_screen = platformScreen; + + // Move window to proper screen/display + errno = 0; + screen_display_t display = platformScreen->nativeDisplay(); + int result = screen_set_window_property_pv(m_window, SCREEN_PROPERTY_DISPLAY, (void **)&display); + if (result != 0) { + qFatal("QQnxWindow: failed to set window display, errno=%d", errno); + } + + // Add window to display's window group + errno = 0; + result = screen_join_window_group(m_window, platformScreen->windowGroupName()); + if (result != 0) { + qFatal("QQnxWindow: failed to join window group, errno=%d", errno); + } + + QList::iterator it; + for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) { + // Only subwindows and tooltips need necessarily be moved to another display with the window. + if ((window()->windowType() & Qt::WindowType_Mask) == Qt::SubWindow || + (window()->windowType() & Qt::WindowType_Mask) == Qt::ToolTip) + (*it)->setScreen(platformScreen); + } + + QQnxScreen::updateHierarchy(); +} + +void QQnxWindow::removeFromParent() +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window(); +#endif + // Remove from old Hierarchy position + if (m_parentWindow) { + if (m_parentWindow->m_childWindows.removeAll(this)) + m_parentWindow = 0; + else + qFatal("QQnxWindow: Window Hierarchy broken; window has parent, but parent hasn't got child."); + } else { + QQnxScreen::removeWindow(this); + } +} + +void QQnxWindow::setParent(const QPlatformWindow *window) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << this->window() << "platformWindow =" << window; +#endif + // Cast away the const, we need to modify the hierarchy. + QQnxWindow *newParent = 0; + + if (window) + newParent = static_cast((QPlatformWindow *)window); + + if (newParent == m_parentWindow) + return; + + removeFromParent(); + m_parentWindow = newParent; + + // Add to new hierarchy position. + if (m_parentWindow) { + if (m_parentWindow->m_screen != m_screen) + setScreen(m_parentWindow->m_screen); + + m_parentWindow->m_childWindows.push_back(this); + } else { + QQnxScreen::addWindow(this); + } + + QQnxScreen::updateHierarchy(); +} + +void QQnxWindow::raise() +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window(); +#endif + + QQnxWindow *oldParent = m_parentWindow; + if (oldParent) { + removeFromParent(); + oldParent->m_childWindows.push_back(this); + } else { + QQnxScreen::raiseWindow(this); + } + + QQnxScreen::updateHierarchy(); +} + +void QQnxWindow::lower() +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window(); +#endif + + QQnxWindow *oldParent = m_parentWindow; + if (oldParent) { + removeFromParent(); + oldParent->m_childWindows.push_front(this); + } else { + QQnxScreen::lowerWindow(this); + } + + QQnxScreen::updateHierarchy(); +} + +void QQnxWindow::requestActivateWindow() +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window(); +#endif + + // TODO: Tell screen to set keyboard focus to this window. + + // Notify that we gained focus. + gainedFocus(); +} + +void QQnxWindow::gainedFocus() +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window(); +#endif + + // Got focus + QWindowSystemInterface::handleWindowActivated(window()); +} + +void QQnxWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext) +{ + // This function does not take ownership of the platform gl context. + // It is owned by the frontend QOpenGLContext + m_platformOpenGLContext = platformOpenGLContext; +} + +void QQnxWindow::updateZorder(int &topZorder) +{ + errno = 0; + int result = screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ZORDER, &topZorder); + topZorder++; + + if (result != 0) + qFatal("QQnxWindow: failed to set window z-order=%d, errno=%d, mWindow=%p", topZorder, errno, m_window); + + QList::const_iterator it; + + for (it = m_childWindows.begin(); it != m_childWindows.end(); it++) + (*it)->updateZorder(topZorder); +} + +void QQnxWindow::copyBack(const QRegion ®ion, int dx, int dy, bool flush) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO << "window =" << window(); +#endif + int result; + + // Abort if previous buffer is invalid + if (m_previousBufferIndex == -1) { + return; + } + + // Abort if nothing to copy + if (region.isEmpty()) { + return; + } + + QQnxBuffer ¤tBuffer = m_buffers[m_currentBufferIndex]; + QQnxBuffer &previousBuffer = m_buffers[m_previousBufferIndex]; + + // Break down region into non-overlapping rectangles + QVector rects = region.rects(); + for (int i = rects.size() - 1; i >= 0; i--) { + // Clip rectangle to bounds of target + QRect rect = rects[i].intersected( currentBuffer.rect() ); + + if (rect.isEmpty()) + continue; + + // Setup blit operation + int attribs[] = { SCREEN_BLIT_SOURCE_X, rect.x(), + SCREEN_BLIT_SOURCE_Y, rect.y(), + SCREEN_BLIT_SOURCE_WIDTH, rect.width(), + SCREEN_BLIT_SOURCE_HEIGHT, rect.height(), + SCREEN_BLIT_DESTINATION_X, rect.x() + dx, + SCREEN_BLIT_DESTINATION_Y, rect.y() + dy, + SCREEN_BLIT_DESTINATION_WIDTH, rect.width(), + SCREEN_BLIT_DESTINATION_HEIGHT, rect.height(), + SCREEN_BLIT_END }; + + // Queue blit operation + errno = 0; + result = screen_blit(m_screenContext, currentBuffer.nativeBuffer(), previousBuffer.nativeBuffer(), attribs); + if (result != 0) { + qFatal("QQnxWindow: failed to blit buffers, errno=%d", errno); + } + } + + // Check if flush requested + if (flush) { + // Wait for all blits to complete + errno = 0; + result = screen_flush_blits(m_screenContext, SCREEN_WAIT_IDLE); + if (result != 0) { + qFatal("QQnxWindow: failed to flush blits, errno=%d", errno); + } + + // Buffer was modified outside the CPU + currentBuffer.invalidateInCache(); + } +} + +int QQnxWindow::platformWindowFormatToNativeFormat(const QSurfaceFormat &format) +{ +#if defined(QQNXWINDOW_DEBUG) + qDebug() << Q_FUNC_INFO; +#endif + // Extract size of colour channels from window format + int redSize = format.redBufferSize(); + if (redSize == -1) { + qFatal("QQnxWindow: red size not defined"); + } + + int greenSize = format.greenBufferSize(); + if (greenSize == -1) { + qFatal("QQnxWindow: green size not defined"); + } + + int blueSize = format.blueBufferSize(); + if (blueSize == -1) { + qFatal("QQnxWindow: blue size not defined"); + } + + // select matching native format + if (redSize == 5 && greenSize == 6 && blueSize == 5) { + return SCREEN_FORMAT_RGB565; + } else if (redSize == 8 && greenSize == 8 && blueSize == 8) { + return SCREEN_FORMAT_RGBA8888; + } else { + qFatal("QQnxWindow: unsupported pixel format"); + return 0; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h new file mode 100644 index 0000000000..9507b08ade --- /dev/null +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -0,0 +1,133 @@ +/*************************************************************************** +** +** Copyright (C) 2011 - 2012 Research In Motion +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins 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 QQNXWINDOW_H +#define QQNXWINDOW_H + +#include + +#include "qqnxbuffer.h" + +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +// all surfaces double buffered +#define MAX_BUFFER_COUNT 2 + +class QQnxGLContext; +class QQnxScreen; + +class QPlatformGLContext; +class QSurfaceFormat; + +class QQnxWindow : public QPlatformWindow +{ +friend class QQnxScreen; +public: + QQnxWindow(QWindow *window, screen_context_t context); + virtual ~QQnxWindow(); + + virtual void setGeometry(const QRect &rect); + virtual void setVisible(bool visible); + virtual void setOpacity(qreal level); + + virtual WId winId() const { return (WId)m_window; } + screen_window_t nativeHandle() const { return m_window; } + + void setBufferSize(const QSize &size); + QSize bufferSize() const { return m_bufferSize; } + bool hasBuffers() const { return !m_bufferSize.isEmpty(); } + + QQnxBuffer &renderBuffer(); + void scroll(const QRegion ®ion, int dx, int dy, bool flush=false); + void post(const QRegion &dirty); + + void setScreen(QQnxScreen *platformScreen); + + virtual void setParent(const QPlatformWindow *window); + virtual void raise(); + virtual void lower(); + virtual void requestActivateWindow(); + + void gainedFocus(); + + QQnxScreen *screen() const { return m_screen; } + const QList& children() const { return m_childWindows; } + + void setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext); + QQnxGLContext *platformOpenGLContext() const { return m_platformOpenGLContext; } + +private: + void removeFromParent(); + void offset(const QPoint &offset); + void updateVisibility(bool parentVisible); + void updateZorder(int &topZorder); + + void fetchBuffers(); + + void copyBack(const QRegion ®ion, int dx, int dy, bool flush=false); + + static int platformWindowFormatToNativeFormat(const QSurfaceFormat &format); + + screen_context_t m_screenContext; + screen_window_t m_window; + QSize m_bufferSize; + QQnxBuffer m_buffers[MAX_BUFFER_COUNT]; + int m_currentBufferIndex; + int m_previousBufferIndex; + QRegion m_previousDirty; + QRegion m_scrolled; + + QQnxGLContext *m_platformOpenGLContext; + QQnxScreen *m_screen; + QList m_childWindows; + QQnxWindow *m_parentWindow; + bool m_visible; +}; + +QT_END_NAMESPACE + +#endif // QQNXWINDOW_H -- cgit v1.2.3 From 31043e6b8d7581bfb34174387633da188dcbe538 Mon Sep 17 00:00:00 2001 From: Morten Johan Sorvig Date: Mon, 23 Jan 2012 14:55:48 +0100 Subject: Cocoa: Fix accessiiblityPerformAction Remove hardcoded pressAction(); Change-Id: Ie02e3f2f88a2cd311aec1b39daa160efb3b2b617 Reviewed-by: Frederik Gladhorn --- src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 06d75036bf..58284bcddb 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -204,8 +204,7 @@ static QAccessibleInterface *acast(void *ptr) - (void)accessibilityPerformAction:(NSString *)action { QAccessibleActionInterface *actionInterface = acast(accessibleInterface)->actionInterface(); if (actionInterface) { - QString qtAction = QCocoaAccessible::translateAction(action); - actionInterface->doAction(QAccessibleActionInterface::pressAction()); + actionInterface->doAction(QCocoaAccessible::translateAction(action)); } } -- cgit v1.2.3 From cff24b9fd5094ef1363a85fbf11761b449bd4d47 Mon Sep 17 00:00:00 2001 From: Morten Johan Sorvig Date: Tue, 21 Feb 2012 13:02:24 +0100 Subject: Remove Mac multiple-arch support. Change-Id: Iaad361301e4772c3d8be6186da88e494cb234801 Reviewed-by: Bradley T. Hughes --- src/gui/gui.pro | 58 ++++++--------------------------------------------------- 1 file changed, 6 insertions(+), 52 deletions(-) diff --git a/src/gui/gui.pro b/src/gui/gui.pro index a8a7df6e30..2cee31fce1 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -57,20 +57,10 @@ win32:!contains(QT_CONFIG, directwrite) { DEFINES += QT_NO_DIRECTWRITE } -contains(QMAKE_MAC_XARCH, no) { - DEFINES += QT_NO_MAC_XARCH -} else { win32-g++*|!win32:!win32-icc*:!macx-icc* { mmx { mmx_compiler.commands = $$QMAKE_CXX -c -Winline - - mac { - x86: mmx_compiler.commands += -Xarch_i386 -mmmx - x86_64: mmx_compiler.commands += -Xarch_x86_64 -mmmx - } else { - mmx_compiler.commands += -mmmx - } - + mmx_compiler.commands += -mmmx mmx_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} mmx_compiler.dependency_type = TYPE_C mmx_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} @@ -82,14 +72,7 @@ contains(QMAKE_MAC_XARCH, no) { } 3dnow { mmx3dnow_compiler.commands = $$QMAKE_CXX -c -Winline - - mac { - x86: mmx3dnow_compiler.commands += -Xarch_i386 -m3dnow -Xarch_i386 -mmmx - x86_64: mmx3dnow_compiler.commands += -Xarch_x86_64 -m3dnow -Xarch_x86_64 -mmmx - } else { - mmx3dnow_compiler.commands += -m3dnow -mmmx - } - + mmx3dnow_compiler.commands += -m3dnow -mmmx mmx3dnow_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} mmx3dnow_compiler.dependency_type = TYPE_C mmx3dnow_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} @@ -100,14 +83,7 @@ contains(QMAKE_MAC_XARCH, no) { QMAKE_EXTRA_COMPILERS += mmx3dnow_compiler sse { sse3dnow_compiler.commands = $$QMAKE_CXX -c -Winline - - mac { - x86: sse3dnow_compiler.commands += -Xarch_i386 -m3dnow -Xarch_i386 -msse - x86_64: sse3dnow_compiler.commands += -Xarch_x86_64 -m3dnow -Xarch_x86_64 -msse - } else { - sse3dnow_compiler.commands += -m3dnow -msse - } - + sse3dnow_compiler.commands += -m3dnow -msse sse3dnow_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} sse3dnow_compiler.dependency_type = TYPE_C sse3dnow_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} @@ -120,14 +96,7 @@ contains(QMAKE_MAC_XARCH, no) { } sse { sse_compiler.commands = $$QMAKE_CXX -c -Winline - - mac { - x86: sse_compiler.commands += -Xarch_i386 -msse - x86_64: sse_compiler.commands += -Xarch_x86_64 -msse - } else { - sse_compiler.commands += -msse - } - + sse_compiler.commands += -msse sse_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} sse_compiler.dependency_type = TYPE_C sse_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} @@ -139,14 +108,7 @@ contains(QMAKE_MAC_XARCH, no) { } sse2 { sse2_compiler.commands = $$QMAKE_CXX -c -Winline - - mac { - x86: sse2_compiler.commands += -Xarch_i386 -msse2 - x86_64: sse2_compiler.commands += -Xarch_x86_64 -msse2 - } else { - sse2_compiler.commands += -msse2 - } - + sse2_compiler.commands += -msse2 sse2_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} sse2_compiler.dependency_type = TYPE_C sse2_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} @@ -158,14 +120,7 @@ contains(QMAKE_MAC_XARCH, no) { } ssse3 { ssse3_compiler.commands = $$QMAKE_CXX -c -Winline - - mac { - x86: ssse3_compiler.commands += -Xarch_i386 -mssse3 - x86_64: ssse3_compiler.commands += -Xarch_x86_64 -mssse3 - } else { - ssse3_compiler.commands += -mssse3 - } - + ssse3_compiler.commands += -mssse3 ssse3_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} ssse3_compiler.dependency_type = TYPE_C ssse3_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} @@ -196,4 +151,3 @@ contains(QMAKE_MAC_XARCH, no) { ssse3: SOURCES += $$SSSE3_SOURCES iwmmxt: SOURCES += $$IWMMXT_SOURCES } -} -- cgit v1.2.3 From a5c1ffedb8aceaa69bb27f999cf3ead205a86a54 Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Sat, 10 Mar 2012 16:17:27 -0800 Subject: Convert xlib plugin to new format Change-Id: I00418a1eb7bf944ec360dbbb1f61f7703f3ecd37 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/xlib/main.cpp | 6 ++++-- src/plugins/platforms/xlib/xlib.json | 3 +++ src/plugins/platforms/xlib/xlib.pro | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 src/plugins/platforms/xlib/xlib.json diff --git a/src/plugins/platforms/xlib/main.cpp b/src/plugins/platforms/xlib/main.cpp index 6030a72236..95c4d9e4d8 100644 --- a/src/plugins/platforms/xlib/main.cpp +++ b/src/plugins/platforms/xlib/main.cpp @@ -46,6 +46,8 @@ QT_BEGIN_NAMESPACE class QXlibIntegrationPlugin : public QPlatformIntegrationPlugin { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPlatformIntegrationFactoryInterface" FILE "xlib.json") public: QStringList keys() const; QPlatformIntegration *create(const QString&, const QStringList&); @@ -67,6 +69,6 @@ QPlatformIntegration* QXlibIntegrationPlugin::create(const QString& system, cons return 0; } -Q_EXPORT_PLUGIN2(xlib, QXlibIntegrationPlugin) - QT_END_NAMESPACE + +#include "main.moc" diff --git a/src/plugins/platforms/xlib/xlib.json b/src/plugins/platforms/xlib/xlib.json new file mode 100644 index 0000000000..524be2fc6d --- /dev/null +++ b/src/plugins/platforms/xlib/xlib.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "xlib" ] +} diff --git a/src/plugins/platforms/xlib/xlib.pro b/src/plugins/platforms/xlib/xlib.pro index ea95ae83a1..463130a64b 100644 --- a/src/plugins/platforms/xlib/xlib.pro +++ b/src/plugins/platforms/xlib/xlib.pro @@ -32,6 +32,8 @@ HEADERS = \ qxlibdisplay.h \ qxlibnativeinterface.h +OTHER_FILES += xlib.json + LIBS += -lX11 -lXext mac { -- cgit v1.2.3 From 0a14ddfacb4b6089bdf561b4456e3578da329428 Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Mon, 12 Mar 2012 12:06:39 +0100 Subject: qdoc: Fix closing 'table class="generic"' tag Change-Id: I251ed6d4e5788b0816211e06f33ace03d2fa14e8 Reviewed-by: Martin Smith --- src/tools/qdoc/htmlgenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/qdoc/htmlgenerator.cpp b/src/tools/qdoc/htmlgenerator.cpp index dd3a0fcbfc..9b886564c4 100644 --- a/src/tools/qdoc/htmlgenerator.cpp +++ b/src/tools/qdoc/htmlgenerator.cpp @@ -1055,8 +1055,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, } out() << ""; - out() << "\n "; + out() << " width=\"" << width << "\""; + out() << ">\n "; numTableRows = 0; } break; -- cgit v1.2.3 From 4dfeb18758002f06679dae6584f165192cd04f86 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 9 Mar 2012 12:25:31 +1000 Subject: Add a movable type declaration to QGlyphRun. Allow it to take advantage of QList optimisations for pointer types. Change-Id: Iddbb9741efef43604e38fc3eeb08b522c0414e21 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qglyphrun.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/text/qglyphrun.h b/src/gui/text/qglyphrun.h index 847b7e4852..b590775d8b 100644 --- a/src/gui/text/qglyphrun.h +++ b/src/gui/text/qglyphrun.h @@ -124,6 +124,8 @@ private: QExplicitlySharedDataPointer d; }; +Q_DECLARE_TYPEINFO(QGlyphRun, Q_MOVABLE_TYPE); + QT_END_NAMESPACE QT_END_HEADER -- cgit v1.2.3 From 074508c2caf0417bf2cde7d1a55aadbbc88aa742 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Fri, 9 Mar 2012 13:50:19 +1000 Subject: Remove gcc 3.x-specific code from QtConcurrent and its tests. Change-Id: I4dd0ce50b70a47a0a00f4c7ec18077a1bcbe5705 Reviewed-by: Rohan McGovern --- src/concurrent/qtconcurrent_global.h | 7 ------- .../qtconcurrentfilter/tst_qtconcurrentfilter.cpp | 14 -------------- .../concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp | 14 -------------- 3 files changed, 35 deletions(-) diff --git a/src/concurrent/qtconcurrent_global.h b/src/concurrent/qtconcurrent_global.h index 1e26c2321d..897c34fe41 100644 --- a/src/concurrent/qtconcurrent_global.h +++ b/src/concurrent/qtconcurrent_global.h @@ -68,13 +68,6 @@ # endif #endif -// gcc 3 version has problems with some of the -// map/filter overloads. -#if defined(Q_CC_GNU) && (__GNUC__ < 4) -# define QT_NO_CONCURRENT_MAP -# define QT_NO_CONCURRENT_FILTER -#endif - #if defined (Q_CC_MSVC) && (_MSC_VER < 1300) # define QT_TYPENAME #else diff --git a/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp b/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp index 971a6992ff..eb1faab94f 100644 --- a/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp +++ b/tests/auto/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp @@ -51,9 +51,6 @@ class tst_QtConcurrentFilter : public QObject Q_OBJECT private slots: -#ifdef QT_NO_CONCURRENT_FILTER - void initTestCase(); -#else void filter(); void filtered(); void filteredReduced(); @@ -63,17 +60,8 @@ private slots: #ifndef QT_NO_STL void stlContainers(); #endif -#endif }; -#ifdef QT_NO_CONCURRENT_FILTER -void tst_QtConcurrentFilter::initTestCase() -{ - QSKIP("This test is skipped for gcc 3.x"); -} - -#else - void tst_QtConcurrentFilter::filter() { // functor @@ -1537,7 +1525,5 @@ void tst_QtConcurrentFilter::stlContainers() } #endif -#endif - QTEST_MAIN(tst_QtConcurrentFilter) #include "tst_qtconcurrentfilter.moc" diff --git a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp index 960511d87b..35ee0be326 100644 --- a/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp +++ b/tests/auto/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp @@ -59,9 +59,6 @@ class tst_QtConcurrentMap: public QObject { Q_OBJECT private slots: -#ifdef QT_NO_CONCURRENT_MAP - void initTestCase() -#else void map(); void blocking_map(); void mapped(); @@ -82,17 +79,8 @@ private slots: void stressTest(); public slots: void throttling(); -#endif }; -#ifdef QT_NO_CONCURRENT_FILTER -void tst_QtConcurrentFilter::initTestCase() -{ - QSKIP("This test is skipped for gcc 3.x"); -} - -#else - using namespace QtConcurrent; void multiplyBy2Immutable(int x) @@ -2420,7 +2408,5 @@ void tst_QtConcurrentMap::stressTest() } } -#endif - QTEST_MAIN(tst_QtConcurrentMap) #include "tst_qtconcurrentmap.moc" -- cgit v1.2.3 From 3d8e3421a5f4466b98f1747c7b72c8750a7688a7 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Fri, 9 Mar 2012 13:56:03 +1000 Subject: Remove MSVC 6 workaround from QtConcurrent. MSVC 6 is not supported by Qt 5. Change-Id: I2aef026eb2ad6a68cd9bcddcf6578cb1a019b21c Reviewed-by: Rohan McGovern --- src/concurrent/qtconcurrent_global.h | 6 --- src/concurrent/qtconcurrentrun.h | 72 ++++++++++++++++++------------------ 2 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/concurrent/qtconcurrent_global.h b/src/concurrent/qtconcurrent_global.h index 897c34fe41..422bca0258 100644 --- a/src/concurrent/qtconcurrent_global.h +++ b/src/concurrent/qtconcurrent_global.h @@ -68,10 +68,4 @@ # endif #endif -#if defined (Q_CC_MSVC) && (_MSC_VER < 1300) -# define QT_TYPENAME -#else -# define QT_TYPENAME typename -#endif - #endif // include guard diff --git a/src/concurrent/qtconcurrentrun.h b/src/concurrent/qtconcurrentrun.h index 0e46db868d..2ca5621f08 100644 --- a/src/concurrent/qtconcurrentrun.h +++ b/src/concurrent/qtconcurrentrun.h @@ -152,187 +152,187 @@ auto run(Functor functor, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, template QFuture run(FunctionObject functionObject) { - return (new StoredFunctorCall0(functionObject))->start(); + return (new StoredFunctorCall0(functionObject))->start(); } template QFuture run(FunctionObject functionObject, const Arg1 &arg1) { - return (new StoredFunctorCall1(functionObject, arg1))->start(); + return (new StoredFunctorCall1(functionObject, arg1))->start(); } template QFuture run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2) { - return (new StoredFunctorCall2(functionObject, arg1, arg2))->start(); + return (new StoredFunctorCall2(functionObject, arg1, arg2))->start(); } template QFuture run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { - return (new StoredFunctorCall3(functionObject, arg1, arg2, arg3))->start(); + return (new StoredFunctorCall3(functionObject, arg1, arg2, arg3))->start(); } template QFuture run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { - return (new StoredFunctorCall4(functionObject, arg1, arg2, arg3, arg4))->start(); + return (new StoredFunctorCall4(functionObject, arg1, arg2, arg3, arg4))->start(); } template QFuture run(FunctionObject functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { - return (new StoredFunctorCall5(functionObject, arg1, arg2, arg3, arg4, arg5))->start(); + return (new StoredFunctorCall5(functionObject, arg1, arg2, arg3, arg4, arg5))->start(); } template QFuture run(FunctionObject *functionObject) { - return (new QT_TYPENAME SelectStoredFunctorPointerCall0::type(functionObject))->start(); + return (new typename SelectStoredFunctorPointerCall0::type(functionObject))->start(); } template QFuture run(FunctionObject *functionObject, const Arg1 &arg1) { - return (new QT_TYPENAME SelectStoredFunctorPointerCall1::type(functionObject, arg1))->start(); + return (new typename SelectStoredFunctorPointerCall1::type(functionObject, arg1))->start(); } template QFuture run(FunctionObject *functionObject, const Arg1 &arg1, const Arg2 &arg2) { - return (new QT_TYPENAME SelectStoredFunctorPointerCall2::type(functionObject, arg1, arg2))->start(); + return (new typename SelectStoredFunctorPointerCall2::type(functionObject, arg1, arg2))->start(); } template QFuture run(FunctionObject *functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { - return (new QT_TYPENAME SelectStoredFunctorPointerCall3::type(functionObject, arg1, arg2, arg3))->start(); + return (new typename SelectStoredFunctorPointerCall3::type(functionObject, arg1, arg2, arg3))->start(); } template QFuture run(FunctionObject *functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { - return (new QT_TYPENAME SelectStoredFunctorPointerCall4::type(functionObject, arg1, arg2, arg3, arg4))->start(); + return (new typename SelectStoredFunctorPointerCall4::type(functionObject, arg1, arg2, arg3, arg4))->start(); } template QFuture run(FunctionObject *functionObject, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { - return (new QT_TYPENAME SelectStoredFunctorPointerCall5::type(functionObject, arg1, arg2, arg3, arg4, arg5))->start(); + return (new typename SelectStoredFunctorPointerCall5::type(functionObject, arg1, arg2, arg3, arg4, arg5))->start(); } template QFuture run(const Class &object, T (Class::*fn)()) { - return (new QT_TYPENAME SelectStoredMemberFunctionCall0::type(fn, object))->start(); + return (new typename SelectStoredMemberFunctionCall0::type(fn, object))->start(); } template QFuture run(const Class &object, T (Class::*fn)(Param1), const Arg1 &arg1) { - return (new QT_TYPENAME SelectStoredMemberFunctionCall1::type(fn, object, arg1))->start(); + return (new typename SelectStoredMemberFunctionCall1::type(fn, object, arg1))->start(); } template QFuture run(const Class &object, T (Class::*fn)(Param1, Param2), const Arg1 &arg1, const Arg2 &arg2) { - return (new QT_TYPENAME SelectStoredMemberFunctionCall2::type(fn, object, arg1, arg2))->start(); + return (new typename SelectStoredMemberFunctionCall2::type(fn, object, arg1, arg2))->start(); } template QFuture run(const Class &object, T (Class::*fn)(Param1, Param2, Param3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { - return (new QT_TYPENAME SelectStoredMemberFunctionCall3::type(fn, object, arg1, arg2, arg3))->start(); + return (new typename SelectStoredMemberFunctionCall3::type(fn, object, arg1, arg2, arg3))->start(); } template QFuture run(const Class &object, T (Class::*fn)(Param1, Param2, Param3, Param4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { - return (new QT_TYPENAME SelectStoredMemberFunctionCall4::type(fn, object, arg1, arg2, arg3, arg4))->start(); + return (new typename SelectStoredMemberFunctionCall4::type(fn, object, arg1, arg2, arg3, arg4))->start(); } template QFuture run(const Class &object, T (Class::*fn)(Param1, Param2, Param3, Param4, Param5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { - return (new QT_TYPENAME SelectStoredMemberFunctionCall5::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); + return (new typename SelectStoredMemberFunctionCall5::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); } template QFuture run(const Class &object, T (Class::*fn)() const) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionCall0::type(fn, object))->start(); + return (new typename SelectStoredConstMemberFunctionCall0::type(fn, object))->start(); } template QFuture run(const Class &object, T (Class::*fn)(Param1) const, const Arg1 &arg1) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionCall1::type(fn, object, arg1))->start(); + return (new typename SelectStoredConstMemberFunctionCall1::type(fn, object, arg1))->start(); } template QFuture run(const Class &object, T (Class::*fn)(Param1, Param2) const, const Arg1 &arg1, const Arg2 &arg2) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionCall2::type(fn, object, arg1, arg2))->start(); + return (new typename SelectStoredConstMemberFunctionCall2::type(fn, object, arg1, arg2))->start(); } template QFuture run(const Class &object, T (Class::*fn)(Param1, Param2, Param3) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionCall3::type(fn, object, arg1, arg2, arg3))->start(); + return (new typename SelectStoredConstMemberFunctionCall3::type(fn, object, arg1, arg2, arg3))->start(); } template QFuture run(const Class &object, T (Class::*fn)(Param1, Param2, Param3, Param4) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionCall4::type(fn, object, arg1, arg2, arg3, arg4))->start(); + return (new typename SelectStoredConstMemberFunctionCall4::type(fn, object, arg1, arg2, arg3, arg4))->start(); } template QFuture run(const Class &object, T (Class::*fn)(Param1, Param2, Param3, Param4, Param5) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionCall5::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); + return (new typename SelectStoredConstMemberFunctionCall5::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); } template QFuture run(Class *object, T (Class::*fn)()) { - return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall0::type(fn, object))->start(); + return (new typename SelectStoredMemberFunctionPointerCall0::type(fn, object))->start(); } template QFuture run(Class *object, T (Class::*fn)(Param1), const Arg1 &arg1) { - return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall1::type(fn, object, arg1))->start(); + return (new typename SelectStoredMemberFunctionPointerCall1::type(fn, object, arg1))->start(); } template QFuture run(Class *object, T (Class::*fn)(Param1, Param2), const Arg1 &arg1, const Arg2 &arg2) { - return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall2::type(fn, object, arg1, arg2))->start(); + return (new typename SelectStoredMemberFunctionPointerCall2::type(fn, object, arg1, arg2))->start(); } template QFuture run(Class *object, T (Class::*fn)(Param1, Param2, Param3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { - return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall3::type(fn, object, arg1, arg2, arg3))->start(); + return (new typename SelectStoredMemberFunctionPointerCall3::type(fn, object, arg1, arg2, arg3))->start(); } template QFuture run(Class *object, T (Class::*fn)(Param1, Param2, Param3, Param4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { - return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall4::type(fn, object, arg1, arg2, arg3, arg4))->start(); + return (new typename SelectStoredMemberFunctionPointerCall4::type(fn, object, arg1, arg2, arg3, arg4))->start(); } template QFuture run(Class *object, T (Class::*fn)(Param1, Param2, Param3, Param4, Param5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { - return (new QT_TYPENAME SelectStoredMemberFunctionPointerCall5::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); + return (new typename SelectStoredMemberFunctionPointerCall5::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); } template QFuture run(const Class *object, T (Class::*fn)() const) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall0::type(fn, object))->start(); + return (new typename SelectStoredConstMemberFunctionPointerCall0::type(fn, object))->start(); } template QFuture run(const Class *object, T (Class::*fn)(Param1) const, const Arg1 &arg1) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall1::type(fn, object, arg1))->start(); + return (new typename SelectStoredConstMemberFunctionPointerCall1::type(fn, object, arg1))->start(); } template QFuture run(const Class *object, T (Class::*fn)(Param1, Param2) const, const Arg1 &arg1, const Arg2 &arg2) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall2::type(fn, object, arg1, arg2))->start(); + return (new typename SelectStoredConstMemberFunctionPointerCall2::type(fn, object, arg1, arg2))->start(); } template QFuture run(const Class *object, T (Class::*fn)(Param1, Param2, Param3) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall3::type(fn, object, arg1, arg2, arg3))->start(); + return (new typename SelectStoredConstMemberFunctionPointerCall3::type(fn, object, arg1, arg2, arg3))->start(); } template QFuture run(const Class *object, T (Class::*fn)(Param1, Param2, Param3, Param4) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall4::type(fn, object, arg1, arg2, arg3, arg4))->start(); + return (new typename SelectStoredConstMemberFunctionPointerCall4::type(fn, object, arg1, arg2, arg3, arg4))->start(); } template QFuture run(const Class *object, T (Class::*fn)(Param1, Param2, Param3, Param4, Param5) const, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { - return (new QT_TYPENAME SelectStoredConstMemberFunctionPointerCall5::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); + return (new typename SelectStoredConstMemberFunctionPointerCall5::type(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); } } //namespace QtConcurrent -- cgit v1.2.3 From c4342ddea083baf0ba7a22df6ce672f0fbcc04c2 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Fri, 9 Mar 2012 14:11:26 +1000 Subject: Fix indentation of QWaitCondition autotest. No functional changes - cosmetic change only. Change-Id: I7332eaab31720776c70a7ef813d55db44bab83f7 Reviewed-by: Rohan McGovern --- .../thread/qwaitcondition/tst_qwaitcondition.cpp | 703 ++++++++++----------- 1 file changed, 351 insertions(+), 352 deletions(-) diff --git a/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp b/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp index 0e1fa47a3e..a9fbde8037 100644 --- a/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp +++ b/tests/auto/corelib/thread/qwaitcondition/tst_qwaitcondition.cpp @@ -73,10 +73,10 @@ public: void run() { - mutex.lock(); - cond.wakeOne(); - cond.wait(&mutex); - mutex.unlock(); + mutex.lock(); + cond.wakeOne(); + cond.wait(&mutex); + mutex.unlock(); } }; @@ -94,10 +94,10 @@ public: void run() { - mutex->lock(); - started.wakeOne(); - cond->wait(mutex); - mutex->unlock(); + mutex->lock(); + started.wakeOne(); + cond->wait(mutex); + mutex->unlock(); } }; @@ -112,10 +112,10 @@ public: void run() { - readWriteLock.lockForWrite(); - cond.wakeOne(); - cond.wait(&readWriteLock); - readWriteLock.unlock(); + readWriteLock.lockForWrite(); + cond.wakeOne(); + cond.wait(&readWriteLock); + readWriteLock.unlock(); } }; @@ -133,10 +133,10 @@ public: void run() { - readWriteLock->lockForRead(); - started.wakeOne(); - cond->wait(readWriteLock); - readWriteLock->unlock(); + readWriteLock->lockForRead(); + started.wakeOne(); + cond->wait(readWriteLock); + readWriteLock->unlock(); } }; @@ -144,80 +144,80 @@ void tst_QWaitCondition::wait_QMutex() { int x; for (int i = 0; i < iterations; ++i) { - { - QMutex mutex; - QWaitCondition cond; - - mutex.lock(); + { + QMutex mutex; + QWaitCondition cond; - cond.wakeOne(); - QVERIFY(!cond.wait(&mutex, 1)); - - cond.wakeAll(); - QVERIFY(!cond.wait(&mutex, 1)); + mutex.lock(); - mutex.unlock(); - } + cond.wakeOne(); + QVERIFY(!cond.wait(&mutex, 1)); - { - // test multiple threads waiting on separate wait conditions - wait_QMutex_Thread_1 thread[ThreadCount]; + cond.wakeAll(); + QVERIFY(!cond.wait(&mutex, 1)); - for (x = 0; x < ThreadCount; ++x) { - thread[x].mutex.lock(); - thread[x].start(); - // wait for thread to start - QVERIFY(thread[x].cond.wait(&thread[x].mutex, 1000)); - thread[x].mutex.unlock(); + mutex.unlock(); } - for (x = 0; x < ThreadCount; ++x) { - QVERIFY(thread[x].isRunning()); - QVERIFY(!thread[x].isFinished()); - } + { + // test multiple threads waiting on separate wait conditions + wait_QMutex_Thread_1 thread[ThreadCount]; - for (x = 0; x < ThreadCount; ++x) { - thread[x].mutex.lock(); - thread[x].cond.wakeOne(); - thread[x].mutex.unlock(); - } + for (x = 0; x < ThreadCount; ++x) { + thread[x].mutex.lock(); + thread[x].start(); + // wait for thread to start + QVERIFY(thread[x].cond.wait(&thread[x].mutex, 1000)); + thread[x].mutex.unlock(); + } - for (x = 0; x < ThreadCount; ++x) { - QVERIFY(thread[x].wait(1000)); - } - } + for (x = 0; x < ThreadCount; ++x) { + QVERIFY(thread[x].isRunning()); + QVERIFY(!thread[x].isFinished()); + } - { - // test multiple threads waiting on a wait condition - QMutex mutex; - QWaitCondition cond1, cond2; - wait_QMutex_Thread_2 thread[ThreadCount]; + for (x = 0; x < ThreadCount; ++x) { + thread[x].mutex.lock(); + thread[x].cond.wakeOne(); + thread[x].mutex.unlock(); + } - mutex.lock(); - for (x = 0; x < ThreadCount; ++x) { - thread[x].mutex = &mutex; - thread[x].cond = (x < ThreadCount / 2) ? &cond1 : &cond2; - thread[x].start(); - // wait for thread to start - QVERIFY(thread[x].started.wait(&mutex, 1000)); + for (x = 0; x < ThreadCount; ++x) { + QVERIFY(thread[x].wait(1000)); + } } - mutex.unlock(); - for (x = 0; x < ThreadCount; ++x) { - QVERIFY(thread[x].isRunning()); - QVERIFY(!thread[x].isFinished()); - } + { + // test multiple threads waiting on a wait condition + QMutex mutex; + QWaitCondition cond1, cond2; + wait_QMutex_Thread_2 thread[ThreadCount]; + + mutex.lock(); + for (x = 0; x < ThreadCount; ++x) { + thread[x].mutex = &mutex; + thread[x].cond = (x < ThreadCount / 2) ? &cond1 : &cond2; + thread[x].start(); + // wait for thread to start + QVERIFY(thread[x].started.wait(&mutex, 1000)); + } + mutex.unlock(); - mutex.lock(); - cond1.wakeAll(); - cond2.wakeAll(); - mutex.unlock(); + for (x = 0; x < ThreadCount; ++x) { + QVERIFY(thread[x].isRunning()); + QVERIFY(!thread[x].isFinished()); + } - for (x = 0; x < ThreadCount; ++x) { - QVERIFY(thread[x].wait(1000)); + mutex.lock(); + cond1.wakeAll(); + cond2.wakeAll(); + mutex.unlock(); + + for (x = 0; x < ThreadCount; ++x) { + QVERIFY(thread[x].wait(1000)); + } } } - } } void tst_QWaitCondition::wait_QReadWriteLock() @@ -263,96 +263,95 @@ void tst_QWaitCondition::wait_QReadWriteLock() int x; for (int i = 0; i < iterations; ++i) { - { - QReadWriteLock readWriteLock; - QWaitCondition waitCondition; + { + QReadWriteLock readWriteLock; + QWaitCondition waitCondition; - readWriteLock.lockForRead(); + readWriteLock.lockForRead(); - waitCondition.wakeOne(); - QVERIFY(!waitCondition.wait(&readWriteLock, 1)); - - waitCondition.wakeAll(); - QVERIFY(!waitCondition.wait(&readWriteLock, 1)); + waitCondition.wakeOne(); + QVERIFY(!waitCondition.wait(&readWriteLock, 1)); - readWriteLock.unlock(); - } - - { - QReadWriteLock readWriteLock; - QWaitCondition waitCondition; + waitCondition.wakeAll(); + QVERIFY(!waitCondition.wait(&readWriteLock, 1)); - readWriteLock.lockForWrite(); + readWriteLock.unlock(); + } - waitCondition.wakeOne(); - QVERIFY(!waitCondition.wait(&readWriteLock, 1)); + { + QReadWriteLock readWriteLock; + QWaitCondition waitCondition; - waitCondition.wakeAll(); - QVERIFY(!waitCondition.wait(&readWriteLock, 1)); + readWriteLock.lockForWrite(); - readWriteLock.unlock(); - } + waitCondition.wakeOne(); + QVERIFY(!waitCondition.wait(&readWriteLock, 1)); - { - // test multiple threads waiting on separate wait conditions - wait_QReadWriteLock_Thread_1 thread[ThreadCount]; + waitCondition.wakeAll(); + QVERIFY(!waitCondition.wait(&readWriteLock, 1)); - for (x = 0; x < ThreadCount; ++x) { - thread[x].readWriteLock.lockForRead(); - thread[x].start(); - // wait for thread to start - QVERIFY(thread[x].cond.wait(&thread[x].readWriteLock, 1000)); - thread[x].readWriteLock.unlock(); + readWriteLock.unlock(); } - for (x = 0; x < ThreadCount; ++x) { - QVERIFY(thread[x].isRunning()); - QVERIFY(!thread[x].isFinished()); - } + { + // test multiple threads waiting on separate wait conditions + wait_QReadWriteLock_Thread_1 thread[ThreadCount]; - for (x = 0; x < ThreadCount; ++x) { - thread[x].readWriteLock.lockForRead(); - thread[x].cond.wakeOne(); - thread[x].readWriteLock.unlock(); - } + for (x = 0; x < ThreadCount; ++x) { + thread[x].readWriteLock.lockForRead(); + thread[x].start(); + // wait for thread to start + QVERIFY(thread[x].cond.wait(&thread[x].readWriteLock, 1000)); + thread[x].readWriteLock.unlock(); + } - for (x = 0; x < ThreadCount; ++x) { - QVERIFY(thread[x].wait(1000)); - } - } + for (x = 0; x < ThreadCount; ++x) { + QVERIFY(thread[x].isRunning()); + QVERIFY(!thread[x].isFinished()); + } - { - // test multiple threads waiting on a wait condition - QReadWriteLock readWriteLock; - QWaitCondition cond1, cond2; - wait_QReadWriteLock_Thread_2 thread[ThreadCount]; + for (x = 0; x < ThreadCount; ++x) { + thread[x].readWriteLock.lockForRead(); + thread[x].cond.wakeOne(); + thread[x].readWriteLock.unlock(); + } - readWriteLock.lockForWrite(); - for (x = 0; x < ThreadCount; ++x) { - thread[x].readWriteLock = &readWriteLock; - thread[x].cond = (x < ThreadCount / 2) ? &cond1 : &cond2; - thread[x].start(); - // wait for thread to start - QVERIFY(thread[x].started.wait(&readWriteLock, 1000)); + for (x = 0; x < ThreadCount; ++x) { + QVERIFY(thread[x].wait(1000)); + } } - readWriteLock.unlock(); - for (x = 0; x < ThreadCount; ++x) { - QVERIFY(thread[x].isRunning()); - QVERIFY(!thread[x].isFinished()); - } + { + // test multiple threads waiting on a wait condition + QReadWriteLock readWriteLock; + QWaitCondition cond1, cond2; + wait_QReadWriteLock_Thread_2 thread[ThreadCount]; + + readWriteLock.lockForWrite(); + for (x = 0; x < ThreadCount; ++x) { + thread[x].readWriteLock = &readWriteLock; + thread[x].cond = (x < ThreadCount / 2) ? &cond1 : &cond2; + thread[x].start(); + // wait for thread to start + QVERIFY(thread[x].started.wait(&readWriteLock, 1000)); + } + readWriteLock.unlock(); - readWriteLock.lockForWrite(); - cond1.wakeAll(); - cond2.wakeAll(); - readWriteLock.unlock(); + for (x = 0; x < ThreadCount; ++x) { + QVERIFY(thread[x].isRunning()); + QVERIFY(!thread[x].isFinished()); + } - for (x = 0; x < ThreadCount; ++x) { - QVERIFY(thread[x].wait(1000)); + readWriteLock.lockForWrite(); + cond1.wakeAll(); + cond2.wakeAll(); + readWriteLock.unlock(); + + for (x = 0; x < ThreadCount; ++x) { + QVERIFY(thread[x].wait(1000)); + } } } - } - } class wake_Thread : public QThread @@ -375,14 +374,14 @@ public: void run() { - mutex->lock(); - ++count; + mutex->lock(); + ++count; dummy.wakeOne(); // this wakeup should be lost - started.wakeOne(); + started.wakeOne(); dummy.wakeAll(); // this one too - cond->wait(mutex); + cond->wait(mutex); --count; - mutex->unlock(); + mutex->unlock(); } }; @@ -408,14 +407,14 @@ public: void run() { - readWriteLock->lockForWrite(); - ++count; + readWriteLock->lockForWrite(); + ++count; dummy.wakeOne(); // this wakeup should be lost started.wakeOne(); dummy.wakeAll(); // this one too - cond->wait(readWriteLock); + cond->wait(readWriteLock); --count; - readWriteLock->unlock(); + readWriteLock->unlock(); } }; @@ -426,264 +425,264 @@ void tst_QWaitCondition::wakeOne() int x; // wake up threads, one at a time for (int i = 0; i < iterations; ++i) { - QMutex mutex; - QWaitCondition cond; - - // QMutex - wake_Thread thread[ThreadCount]; - bool thread_exited[ThreadCount]; - - mutex.lock(); - for (x = 0; x < ThreadCount; ++x) { - thread[x].mutex = &mutex; - thread[x].cond = &cond; - thread_exited[x] = false; - thread[x].start(); - // wait for thread to start - QVERIFY(thread[x].started.wait(&mutex, 1000)); - // make sure wakeups are not queued... if nothing is - // waiting at the time of the wakeup, nothing happens - QVERIFY(!thread[x].dummy.wait(&mutex, 1)); - } - mutex.unlock(); + QMutex mutex; + QWaitCondition cond; - QCOMPARE(wake_Thread::count, ThreadCount); + // QMutex + wake_Thread thread[ThreadCount]; + bool thread_exited[ThreadCount]; - // wake up threads one at a time - for (x = 0; x < ThreadCount; ++x) { mutex.lock(); - cond.wakeOne(); - QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME)); - QVERIFY(!thread[x].dummy.wait(&mutex, 1)); + for (x = 0; x < ThreadCount; ++x) { + thread[x].mutex = &mutex; + thread[x].cond = &cond; + thread_exited[x] = false; + thread[x].start(); + // wait for thread to start + QVERIFY(thread[x].started.wait(&mutex, 1000)); + // make sure wakeups are not queued... if nothing is + // waiting at the time of the wakeup, nothing happens + QVERIFY(!thread[x].dummy.wait(&mutex, 1)); + } mutex.unlock(); - int exited = 0; - for (int y = 0; y < ThreadCount; ++y) { - if (thread_exited[y]) - continue; - if (thread[y].wait(exited > 0 ? 10 : 1000)) { - thread_exited[y] = true; - ++exited; - } - } + QCOMPARE(wake_Thread::count, ThreadCount); - QCOMPARE(exited, 1); - QCOMPARE(wake_Thread::count, ThreadCount - (x + 1)); - } + // wake up threads one at a time + for (x = 0; x < ThreadCount; ++x) { + mutex.lock(); + cond.wakeOne(); + QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME)); + QVERIFY(!thread[x].dummy.wait(&mutex, 1)); + mutex.unlock(); + + int exited = 0; + for (int y = 0; y < ThreadCount; ++y) { + if (thread_exited[y]) + continue; + if (thread[y].wait(exited > 0 ? 10 : 1000)) { + thread_exited[y] = true; + ++exited; + } + } - QCOMPARE(wake_Thread::count, 0); + QCOMPARE(exited, 1); + QCOMPARE(wake_Thread::count, ThreadCount - (x + 1)); + } - // QReadWriteLock - QReadWriteLock readWriteLock; - wake_Thread_2 rwthread[ThreadCount]; - - readWriteLock.lockForWrite(); - for (x = 0; x < ThreadCount; ++x) { - rwthread[x].readWriteLock = &readWriteLock; - rwthread[x].cond = &cond; - thread_exited[x] = false; - rwthread[x].start(); - // wait for thread to start - QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000)); - // make sure wakeups are not queued... if nothing is - // waiting at the time of the wakeup, nothing happens - QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1)); - } - readWriteLock.unlock(); + QCOMPARE(wake_Thread::count, 0); - QCOMPARE(wake_Thread_2::count, ThreadCount); + // QReadWriteLock + QReadWriteLock readWriteLock; + wake_Thread_2 rwthread[ThreadCount]; - // wake up threads one at a time - for (x = 0; x < ThreadCount; ++x) { readWriteLock.lockForWrite(); - cond.wakeOne(); - QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME)); - QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1)); + for (x = 0; x < ThreadCount; ++x) { + rwthread[x].readWriteLock = &readWriteLock; + rwthread[x].cond = &cond; + thread_exited[x] = false; + rwthread[x].start(); + // wait for thread to start + QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000)); + // make sure wakeups are not queued... if nothing is + // waiting at the time of the wakeup, nothing happens + QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1)); + } readWriteLock.unlock(); - int exited = 0; - for (int y = 0; y < ThreadCount; ++y) { - if (thread_exited[y]) - continue; - if (rwthread[y].wait(exited > 0 ? 10 : 1000)) { - thread_exited[y] = true; - ++exited; + QCOMPARE(wake_Thread_2::count, ThreadCount); + + // wake up threads one at a time + for (x = 0; x < ThreadCount; ++x) { + readWriteLock.lockForWrite(); + cond.wakeOne(); + QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME)); + QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1)); + readWriteLock.unlock(); + + int exited = 0; + for (int y = 0; y < ThreadCount; ++y) { + if (thread_exited[y]) + continue; + if (rwthread[y].wait(exited > 0 ? 10 : 1000)) { + thread_exited[y] = true; + ++exited; + } } - } - QCOMPARE(exited, 1); - QCOMPARE(wake_Thread_2::count, ThreadCount - (x + 1)); - } + QCOMPARE(exited, 1); + QCOMPARE(wake_Thread_2::count, ThreadCount - (x + 1)); + } - QCOMPARE(wake_Thread_2::count, 0); + QCOMPARE(wake_Thread_2::count, 0); } // wake up threads, two at a time for (int i = 0; i < iterations; ++i) { - QMutex mutex; - QWaitCondition cond; + QMutex mutex; + QWaitCondition cond; // QMutex - wake_Thread thread[ThreadCount]; - bool thread_exited[ThreadCount]; - - mutex.lock(); - for (x = 0; x < ThreadCount; ++x) { - thread[x].mutex = &mutex; - thread[x].cond = &cond; - thread_exited[x] = false; - thread[x].start(); - // wait for thread to start - QVERIFY(thread[x].started.wait(&mutex, 1000)); - // make sure wakeups are not queued... if nothing is - // waiting at the time of the wakeup, nothing happens - QVERIFY(!thread[x].dummy.wait(&mutex, 1)); - } - mutex.unlock(); - - QCOMPARE(wake_Thread::count, ThreadCount); + wake_Thread thread[ThreadCount]; + bool thread_exited[ThreadCount]; - // wake up threads one at a time - for (x = 0; x < ThreadCount; x += 2) { mutex.lock(); - cond.wakeOne(); - cond.wakeOne(); - QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME)); - QVERIFY(!thread[x].dummy.wait(&mutex, 1)); - QVERIFY(!thread[x + 1].dummy.wait(&mutex, 1)); + for (x = 0; x < ThreadCount; ++x) { + thread[x].mutex = &mutex; + thread[x].cond = &cond; + thread_exited[x] = false; + thread[x].start(); + // wait for thread to start + QVERIFY(thread[x].started.wait(&mutex, 1000)); + // make sure wakeups are not queued... if nothing is + // waiting at the time of the wakeup, nothing happens + QVERIFY(!thread[x].dummy.wait(&mutex, 1)); + } mutex.unlock(); - int exited = 0; - for (int y = 0; y < ThreadCount; ++y) { - if (thread_exited[y]) - continue; - if (thread[y].wait(exited > 0 ? 10 : 1000)) { - thread_exited[y] = true; - ++exited; + QCOMPARE(wake_Thread::count, ThreadCount); + + // wake up threads one at a time + for (x = 0; x < ThreadCount; x += 2) { + mutex.lock(); + cond.wakeOne(); + cond.wakeOne(); + QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME)); + QVERIFY(!thread[x].dummy.wait(&mutex, 1)); + QVERIFY(!thread[x + 1].dummy.wait(&mutex, 1)); + mutex.unlock(); + + int exited = 0; + for (int y = 0; y < ThreadCount; ++y) { + if (thread_exited[y]) + continue; + if (thread[y].wait(exited > 0 ? 10 : 1000)) { + thread_exited[y] = true; + ++exited; + } } - } - QCOMPARE(exited, 2); - QCOMPARE(wake_Thread::count, ThreadCount - (x + 2)); - } + QCOMPARE(exited, 2); + QCOMPARE(wake_Thread::count, ThreadCount - (x + 2)); + } - QCOMPARE(wake_Thread::count, 0); + QCOMPARE(wake_Thread::count, 0); // QReadWriteLock QReadWriteLock readWriteLock; wake_Thread_2 rwthread[ThreadCount]; - readWriteLock.lockForWrite(); - for (x = 0; x < ThreadCount; ++x) { - rwthread[x].readWriteLock = &readWriteLock; - rwthread[x].cond = &cond; - thread_exited[x] = false; - rwthread[x].start(); - // wait for thread to start - QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000)); - // make sure wakeups are not queued... if nothing is - // waiting at the time of the wakeup, nothing happens - QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1)); - } - readWriteLock.unlock(); - - QCOMPARE(wake_Thread_2::count, ThreadCount); - - // wake up threads one at a time - for (x = 0; x < ThreadCount; x += 2) { readWriteLock.lockForWrite(); - cond.wakeOne(); - cond.wakeOne(); - QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME)); - QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1)); - QVERIFY(!rwthread[x + 1].dummy.wait(&readWriteLock, 1)); + for (x = 0; x < ThreadCount; ++x) { + rwthread[x].readWriteLock = &readWriteLock; + rwthread[x].cond = &cond; + thread_exited[x] = false; + rwthread[x].start(); + // wait for thread to start + QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000)); + // make sure wakeups are not queued... if nothing is + // waiting at the time of the wakeup, nothing happens + QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1)); + } readWriteLock.unlock(); - int exited = 0; - for (int y = 0; y < ThreadCount; ++y) { - if (thread_exited[y]) - continue; - if (rwthread[y].wait(exited > 0 ? 10 : 1000)) { - thread_exited[y] = true; - ++exited; + QCOMPARE(wake_Thread_2::count, ThreadCount); + + // wake up threads one at a time + for (x = 0; x < ThreadCount; x += 2) { + readWriteLock.lockForWrite(); + cond.wakeOne(); + cond.wakeOne(); + QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME)); + QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1)); + QVERIFY(!rwthread[x + 1].dummy.wait(&readWriteLock, 1)); + readWriteLock.unlock(); + + int exited = 0; + for (int y = 0; y < ThreadCount; ++y) { + if (thread_exited[y]) + continue; + if (rwthread[y].wait(exited > 0 ? 10 : 1000)) { + thread_exited[y] = true; + ++exited; + } } + + QCOMPARE(exited, 2); + QCOMPARE(wake_Thread_2::count, ThreadCount - (x + 2)); } - QCOMPARE(exited, 2); - QCOMPARE(wake_Thread_2::count, ThreadCount - (x + 2)); + QCOMPARE(wake_Thread_2::count, 0); } - - QCOMPARE(wake_Thread_2::count, 0); -} } void tst_QWaitCondition::wakeAll() { int x; for (int i = 0; i < iterations; ++i) { - QMutex mutex; - QWaitCondition cond; + QMutex mutex; + QWaitCondition cond; - // QMutex - wake_Thread thread[ThreadCount]; + // QMutex + wake_Thread thread[ThreadCount]; - mutex.lock(); - for (x = 0; x < ThreadCount; ++x) { - thread[x].mutex = &mutex; - thread[x].cond = &cond; - thread[x].start(); - // wait for thread to start - QVERIFY(thread[x].started.wait(&mutex, 1000)); - } - mutex.unlock(); + mutex.lock(); + for (x = 0; x < ThreadCount; ++x) { + thread[x].mutex = &mutex; + thread[x].cond = &cond; + thread[x].start(); + // wait for thread to start + QVERIFY(thread[x].started.wait(&mutex, 1000)); + } + mutex.unlock(); - QCOMPARE(wake_Thread::count, ThreadCount); + QCOMPARE(wake_Thread::count, ThreadCount); - // wake up all threads at once - mutex.lock(); - cond.wakeAll(); - QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME)); - mutex.unlock(); + // wake up all threads at once + mutex.lock(); + cond.wakeAll(); + QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME)); + mutex.unlock(); - int exited = 0; - for (x = 0; x < ThreadCount; ++x) { - if (thread[x].wait(1000)) - ++exited; - } + int exited = 0; + for (x = 0; x < ThreadCount; ++x) { + if (thread[x].wait(1000)) + ++exited; + } - QCOMPARE(exited, ThreadCount); - QCOMPARE(wake_Thread::count, 0); + QCOMPARE(exited, ThreadCount); + QCOMPARE(wake_Thread::count, 0); - // QReadWriteLock - QReadWriteLock readWriteLock; - wake_Thread_2 rwthread[ThreadCount]; - - readWriteLock.lockForWrite(); - for (x = 0; x < ThreadCount; ++x) { - rwthread[x].readWriteLock = &readWriteLock; - rwthread[x].cond = &cond; - rwthread[x].start(); - // wait for thread to start - QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000)); - } - readWriteLock.unlock(); + // QReadWriteLock + QReadWriteLock readWriteLock; + wake_Thread_2 rwthread[ThreadCount]; - QCOMPARE(wake_Thread_2::count, ThreadCount); + readWriteLock.lockForWrite(); + for (x = 0; x < ThreadCount; ++x) { + rwthread[x].readWriteLock = &readWriteLock; + rwthread[x].cond = &cond; + rwthread[x].start(); + // wait for thread to start + QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000)); + } + readWriteLock.unlock(); - // wake up all threads at once - readWriteLock.lockForWrite(); - cond.wakeAll(); - QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME)); - readWriteLock.unlock(); + QCOMPARE(wake_Thread_2::count, ThreadCount); - exited = 0; - for (x = 0; x < ThreadCount; ++x) { - if (rwthread[x].wait(1000)) - ++exited; - } + // wake up all threads at once + readWriteLock.lockForWrite(); + cond.wakeAll(); + QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME)); + readWriteLock.unlock(); + + exited = 0; + for (x = 0; x < ThreadCount; ++x) { + if (rwthread[x].wait(1000)) + ++exited; + } - QCOMPARE(exited, ThreadCount); - QCOMPARE(wake_Thread_2::count, 0); + QCOMPARE(exited, ThreadCount); + QCOMPARE(wake_Thread_2::count, 0); } } -- cgit v1.2.3 From 21c98e52c5aab6f063457729ac8344134071f0c5 Mon Sep 17 00:00:00 2001 From: Stefan Hundhammer Date: Thu, 1 Mar 2012 17:14:38 +0100 Subject: Line up underlines if fallback fonts are used (QTBUG-21832) Change-Id: Icecc514f6c47c0576af8cabd39cdc0987f8d93fa Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/painting/qpainter.cpp | 97 +++++++++++++++++++++++++----------------- src/gui/painting/qpainter.h | 2 + src/gui/painting/qpainter_p.h | 1 + src/gui/text/qtextengine.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++ src/gui/text/qtextengine_p.h | 32 ++++++++++++++ src/gui/text/qtextlayout.cpp | 13 +++--- 6 files changed, 200 insertions(+), 44 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 973dabc4cb..eafbe87b31 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -90,7 +90,7 @@ void qt_format_text(const QFont &font, const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect, int tabstops, int* tabarray, int tabarraylen, QPainter *painter); -static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, +static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextEngine *textEngine, QTextCharFormat::UnderlineStyle underlineStyle, QTextItem::RenderFlags flags, qreal width, const QTextCharFormat &charFormat); @@ -5641,6 +5641,7 @@ void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, QFixedPoint *positio drawTextItemDecoration(q, QPointF(leftMost.toReal(), baseLine.toReal()), fontEngine, + 0, // textEngine (underline ? QTextCharFormat::SingleUnderline : QTextCharFormat::NoUnderline), @@ -6177,7 +6178,7 @@ static QPixmap generateWavyPixmap(qreal maxRadius, const QPen &pen) return pixmap; } -static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, +static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe, QTextEngine *textEngine, QTextCharFormat::UnderlineStyle underlineStyle, QTextItem::RenderFlags flags, qreal width, const QTextCharFormat &charFormat) @@ -6222,15 +6223,17 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave); painter->restore(); } else if (underlineStyle != QTextCharFormat::NoUnderline) { - QLineF underLine(line.x1(), underlinePos, line.x2(), underlinePos); - QColor uc = charFormat.underlineColor(); if (uc.isValid()) pen.setColor(uc); pen.setStyle((Qt::PenStyle)(underlineStyle)); painter->setPen(pen); - painter->drawLine(underLine); + QLineF underline(line.x1(), underlinePos, line.x2(), underlinePos); + if (textEngine) + textEngine->addUnderline(painter, underline); + else + painter->drawLine(underline); } pen.setStyle(Qt::SolidLine); @@ -6240,14 +6243,20 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QLineF strikeOutLine = line; strikeOutLine.translate(0., - fe->ascent().toReal() / 3.); painter->setPen(pen); - painter->drawLine(strikeOutLine); + if (textEngine) + textEngine->addStrikeOut(painter, strikeOutLine); + else + painter->drawLine(strikeOutLine); } if (flags & QTextItem::Overline) { - QLineF overLine = line; - overLine.translate(0., - fe->ascent().toReal()); + QLineF overline = line; + overline.translate(0., - fe->ascent().toReal()); painter->setPen(pen); - painter->drawLine(overLine); + if (textEngine) + textEngine->addOverline(painter, overline); + else + painter->drawLine(overline); } painter->setPen(oldPen); @@ -6272,7 +6281,7 @@ Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t // We don't support glyphs that do not share a common baseline. If this turns out to // be a relevant use case, then we need to find clusters of glyphs that share a baseline - // and do a drawTextItemDecorations call per cluster. + // and do a drawTextItemDecoration call per cluster. if (i == 0 || baseLine < positions[i].y) baseLine = positions[i].y; @@ -6293,12 +6302,20 @@ Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t drawTextItemDecoration(painter, QPointF(leftMost.toReal(), baseLine.toReal()), fontEngine, + 0, // textEngine font.underline() ? QTextCharFormat::SingleUnderline : QTextCharFormat::NoUnderline, flags, width.toReal(), charFormat); } -void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti) +void QPainter::drawTextItem(const QPointF &p, const QTextItem &ti) +{ + Q_D(QPainter); + + d->drawTextItem(p, ti, static_cast(0)); +} + +void QPainterPrivate::drawTextItem(const QPointF &p, const QTextItem &_ti, QTextEngine *textEngine) { #ifdef QT_DEBUG_DRAW if (qt_show_painter_debug_output) @@ -6306,35 +6323,35 @@ void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti) p.x(), p.y(), qPrintable(_ti.text())); #endif - Q_D(QPainter); + Q_Q(QPainter); - if (!d->engine) + if (!engine) return; #ifndef QT_NO_DEBUG - qt_painter_thread_test(d->device->devType(), + qt_painter_thread_test(device->devType(), "text and fonts", QFontDatabase::supportsThreadedFontRendering()); #endif QTextItemInt &ti = const_cast(static_cast(_ti)); - if (!d->extended && d->state->bgMode == Qt::OpaqueMode) { + if (!extended && state->bgMode == Qt::OpaqueMode) { QRectF rect(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal()); - fillRect(rect, d->state->bgBrush); + q->fillRect(rect, state->bgBrush); } - if (pen().style() == Qt::NoPen) + if (q->pen().style() == Qt::NoPen) return; - const RenderHints oldRenderHints = d->state->renderHints; - if (!d->state->renderHints & QPainter::Antialiasing && d->state->matrix.type() >= QTransform::TxScale) { + const QPainter::RenderHints oldRenderHints = state->renderHints; + if (!state->renderHints & QPainter::Antialiasing && state->matrix.type() >= QTransform::TxScale) { // draw antialias decoration (underline/overline/strikeout) with // transformed text bool aa = true; - const QTransform &m = d->state->matrix; - if (d->state->matrix.type() < QTransform::TxShear) { + const QTransform &m = state->matrix; + if (state->matrix.type() < QTransform::TxShear) { bool isPlain90DegreeRotation = (qFuzzyIsNull(m.m11()) && qFuzzyIsNull(m.m12() - qreal(1)) @@ -6357,11 +6374,11 @@ void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti) aa = !isPlain90DegreeRotation; } if (aa) - setRenderHint(QPainter::Antialiasing, true); + q->setRenderHint(QPainter::Antialiasing, true); } - if (!d->extended) - d->updateState(d->state); + if (!extended) + updateState(state); if (!ti.glyphs.numGlyphs) { // nothing to do @@ -6397,7 +6414,7 @@ void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti) if (rtl) x -= ti2.width.toReal(); - d->engine->drawTextItem(QPointF(x, y), ti2); + engine->drawTextItem(QPointF(x, y), ti2); if (!rtl) x += ti2.width.toReal(); @@ -6424,10 +6441,10 @@ void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti) if (rtl) x -= ti2.width.toReal(); - if (d->extended) - d->extended->drawTextItem(QPointF(x, y), ti2); + if (extended) + extended->drawTextItem(QPointF(x, y), ti2); else - d->engine->drawTextItem(QPointF(x,y), ti2); + engine->drawTextItem(QPointF(x,y), ti2); // reset the high byte for all glyphs const int hi = which << 24; @@ -6435,20 +6452,20 @@ void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti) glyphs.glyphs[i] = hi | glyphs.glyphs[i]; } else { - if (d->extended) - d->extended->drawTextItem(p, ti); + if (extended) + extended->drawTextItem(p, ti); else - d->engine->drawTextItem(p, ti); + engine->drawTextItem(p, ti); } - drawTextItemDecoration(this, p, ti.fontEngine, ti.underlineStyle, ti.flags, ti.width.toReal(), - ti.charFormat); + drawTextItemDecoration(q, p, ti.fontEngine, textEngine, ti.underlineStyle, + ti.flags, ti.width.toReal(), ti.charFormat); - if (d->state->renderHints != oldRenderHints) { - d->state->renderHints = oldRenderHints; - if (d->extended) - d->extended->renderHintsChanged(); + if (state->renderHints != oldRenderHints) { + state->renderHints = oldRenderHints; + if (extended) + extended->renderHintsChanged(); else - d->state->dirtyFlags |= QPaintEngine::DirtyHints; + state->dirtyFlags |= QPaintEngine::DirtyHints; } } @@ -7545,11 +7562,12 @@ start_lengthVariant: for (int i = 0; i < textLayout.lineCount(); i++) { QTextLine line = textLayout.lineAt(i); + QTextEngine *eng = textLayout.engine(); + eng->enableDelayDecorations(); qreal advance = line.horizontalAdvance(); xoff = 0; if (tf & Qt::AlignRight) { - QTextEngine *eng = textLayout.engine(); xoff = r.width() - advance - eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal(); } @@ -7557,6 +7575,7 @@ start_lengthVariant: xoff = (r.width() - advance) / 2; line.draw(painter, QPointF(r.x() + xoff, r.y() + yoff)); + eng->drawDecorations(painter); } if (restore) { diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index 67b05eeca5..97c10a2764 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -74,6 +74,7 @@ class QPainterPrivate; class QPen; class QPolygon; class QTextItem; +class QTextEngine; class QMatrix; class QTransform; class QStaticText; @@ -487,6 +488,7 @@ private: friend class QRasterPaintEngine; friend class QAlphaPaintEngine; friend class QPreviewPaintEngine; + friend class QTextEngine; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QPainter::RenderHints) diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index fecf8bd960..3327860ac9 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -230,6 +230,7 @@ public: void draw_helper(const QPainterPath &path, DrawOperation operation = StrokeAndFillDraw); void drawStretchedGradient(const QPainterPath &path, DrawOperation operation); void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation); + void drawTextItem(const QPointF &p, const QTextItem &_ti, QTextEngine *textEngine); #if !defined(QT_NO_RAWFONT) void drawGlyphs(const quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount, diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index dae02def07..3d58d91169 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1174,6 +1174,7 @@ static void init(QTextEngine *e) e->cacheGlyphs = false; e->forceJustification = false; e->visualMovement = false; + e->delayDecorations = false; e->layoutData = 0; @@ -2913,6 +2914,104 @@ int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation return pos; } +void QTextEngine::addItemDecoration(QPainter *painter, const QLineF &line, ItemDecorationList *decorationList) +{ + if (delayDecorations) { + decorationList->append(ItemDecoration(line.x1(), line.x2(), line.y1(), painter->pen())); + } else { + painter->drawLine(line); + } +} + +void QTextEngine::addUnderline(QPainter *painter, const QLineF &line) +{ + // qDebug() << "Adding underline:" << line; + addItemDecoration(painter, line, &underlineList); +} + +void QTextEngine::addStrikeOut(QPainter *painter, const QLineF &line) +{ + addItemDecoration(painter, line, &strikeOutList); +} + +void QTextEngine::addOverline(QPainter *painter, const QLineF &line) +{ + addItemDecoration(painter, line, &overlineList); +} + +void QTextEngine::drawItemDecorationList(QPainter *painter, const ItemDecorationList &decorationList) +{ + // qDebug() << "Drawing" << decorationList.size() << "decorations"; + if (decorationList.isEmpty()) + return; + + foreach (const ItemDecoration decoration, decorationList) { + painter->setPen(decoration.pen); + QLineF line(decoration.x1, decoration.y, decoration.x2, decoration.y); + painter->drawLine(line); + } +} + +void QTextEngine::drawDecorations(QPainter *painter) +{ + QPen oldPen = painter->pen(); + + adjustUnderlines(); + drawItemDecorationList(painter, underlineList); + drawItemDecorationList(painter, strikeOutList); + drawItemDecorationList(painter, overlineList); + + painter->setPen(oldPen); + clearDecorations(); +} + +void QTextEngine::clearDecorations() +{ + underlineList.clear(); + strikeOutList.clear(); + overlineList.clear(); +} + +void QTextEngine::adjustUnderlines() +{ + // qDebug() << __PRETTY_FUNCTION__ << underlineList.count() << "underlines"; + if (underlineList.isEmpty()) + return; + + ItemDecorationList::iterator start = underlineList.begin(); + ItemDecorationList::iterator end = underlineList.end(); + ItemDecorationList::iterator it = start; + qreal underlinePos = start->y; + qreal penWidth = start->pen.widthF(); + qreal lastLineEnd = start->x1; + + while (it != end) { + if (qFuzzyCompare(lastLineEnd, it->x1)) { // no gap between underlines + underlinePos = qMax(underlinePos, it->y); + penWidth = qMax(penWidth, it->pen.widthF()); + } else { // gap between this and the last underline + adjustUnderlines(start, it, underlinePos, penWidth); + start = it; + underlinePos = start->y; + penWidth = start->pen.widthF(); + } + lastLineEnd = it->x2; + ++it; + } + + adjustUnderlines(start, end, underlinePos, penWidth); +} + +void QTextEngine::adjustUnderlines(ItemDecorationList::iterator start, + ItemDecorationList::iterator end, + qreal underlinePos, qreal penWidth) +{ + for (ItemDecorationList::iterator it = start; it != end; ++it) { + it->y = underlinePos; + it->pen.setWidth(penWidth); + } +} + QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f) : QTextEngine(string, f), _layoutData(string, _memory, MemSize) diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 6f1fd713f1..03581eb6a2 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -446,6 +446,18 @@ public: bool reallocate(int totalGlyphs); }; + struct ItemDecoration { + ItemDecoration(qreal x1, qreal x2, qreal y, const QPen &pen): + x1(x1), x2(x2), y(y), pen(pen) {} + + qreal x1; + qreal x2; + qreal y; + QPen pen; + }; + + typedef QList ItemDecorationList; + QTextEngine(LayoutData *data); QTextEngine(); QTextEngine(const QString &str, const QFont &f); @@ -597,6 +609,7 @@ public: uint stackEngine : 1; uint forceJustification : 1; uint visualMovement : 1; + uint delayDecorations: 1; #ifndef QT_NO_RAWFONT uint useRawFont : 1; #endif @@ -605,6 +618,10 @@ public: mutable LayoutData *layoutData; + ItemDecorationList underlineList; + ItemDecorationList strikeOutList; + ItemDecorationList overlineList; + inline bool hasFormats() const { return (block.docHandle() || specialData); } inline bool visualCursorMovement() const { @@ -639,7 +656,22 @@ public: void insertionPointsForLine(int lineNum, QVector &insertionPoints); void resetFontEngineCache(); + void enableDelayDecorations(bool enable = true) { delayDecorations = enable; } + + void addUnderline(QPainter *painter, const QLineF &line); + void addStrikeOut(QPainter *painter, const QLineF &line); + void addOverline(QPainter *painter, const QLineF &line); + + void drawDecorations(QPainter *painter); + void clearDecorations(); + void adjustUnderlines(); + private: + void addItemDecoration(QPainter *painter, const QLineF &line, ItemDecorationList *decorationList); + void adjustUnderlines(ItemDecorationList::iterator start, + ItemDecorationList::iterator end, + qreal underlinePos, qreal penWidth); + void drawItemDecorationList(QPainter *painter, const ItemDecorationList &decorationList); void setBoundary(int strPos) const; void addRequiredBoundaries() const; void shapeText(int item) const; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index d5b05a8957..56098b0bdb 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -60,6 +60,7 @@ #include #include "qfontengine_p.h" +#include QT_BEGIN_NAMESPACE @@ -2062,7 +2063,7 @@ static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si, if (rtl) x -= w; if (gf.num_chars) - p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf); + QPainterPrivate::get(p)->drawTextItem(QPointF(x.toReal(), y.toReal()), gf, eng); if (!rtl) x += w; if (ul && *ul != -1 && *ul < end) { @@ -2083,7 +2084,7 @@ static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si, gf.underlineStyle = QTextCharFormat::SingleUnderline; if (rtl) x -= w; - p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf); + QPainterPrivate::get(p)->drawTextItem(QPointF(x.toReal(), y.toReal()), gf, eng); if (!rtl) x += w; gf.underlineStyle = QTextCharFormat::NoUnderline; @@ -2379,6 +2380,8 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR QTextLineItemIterator iterator(eng, index, pos, selection); QFixed lineBase = line.base(); + eng->clearDecorations(); + eng->enableDelayDecorations(); const QFixed y = QFixed::fromReal(pos.y()) + line.y + lineBase; @@ -2451,7 +2454,7 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR gf.chars = 0; gf.num_chars = 0; gf.width = iterator.itemWidth; - p->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf); + QPainterPrivate::get(p)->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf, eng); if (eng->option.flags() & QTextOption::ShowTabsAndSpaces) { QChar visualTab(0x2192); int w = QFontMetrics(f).width(visualTab); @@ -2529,7 +2532,7 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR } else { if (noText) gf.glyphs.numGlyphs = 0; // slightly less elegant than it should be - p->drawTextItem(pos, gf); + QPainterPrivate::get(p)->drawTextItem(pos, gf, eng); } } if (si.analysis.flags == QScriptAnalysis::Space @@ -2542,7 +2545,7 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR p->setPen(pen); } } - + eng->drawDecorations(p); if (eng->hasFormats()) p->setPen(pen); -- cgit v1.2.3 From 4c0de07a0e555c52680c5a45aef0121721f242ea Mon Sep 17 00:00:00 2001 From: John Tapsell Date: Thu, 8 Mar 2012 23:10:30 +0000 Subject: Harfbuzz GPOS hinting- do not consider a subtable to be invalid if it is just empty Considering a subtable to be invalid when it was empty meant that it returned an error causing all further hinting to be aborted. This means that we get no hinting in certain cases with certain fonts. Change-Id: I840c016dc85935b4f2c4373c66a79b4bd8b3a30d Reviewed-by: Adrian Yanes Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/3rdparty/harfbuzz/src/harfbuzz-gpos.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-gpos.c b/src/3rdparty/harfbuzz/src/harfbuzz-gpos.c index 2a86cb21e9..8247875714 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-gpos.c +++ b/src/3rdparty/harfbuzz/src/harfbuzz-gpos.c @@ -1595,6 +1595,9 @@ static HB_Error Lookup_PairPos1( GPOS_Instance* gpi, if ( index >= ppf1->PairSetCount ) return ERR(HB_Err_Invalid_SubTable); + if (!ppf1->PairSet[index].PairValueCount) + return HB_Err_Not_Covered; + pvr = ppf1->PairSet[index].PairValueRecord; if ( !pvr ) return ERR(HB_Err_Invalid_SubTable); -- cgit v1.2.3 From cdc9422c2e8b3ebb711085c0813b4477863ec01f Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Thu, 8 Mar 2012 00:19:03 +0100 Subject: QSqlTableModel::indexInQuery: fix inserted row accounting Commit b979956ec46093e5668c2b264f9b68da3cbb0326 introduced a distinction between rows that have a pending INSERT operation and rows that have already been inserted in the database but still are in the change cache. Both cases are rows that are not in the underlying query. Unfortunately, we overlooked a case where the point of the test is whether the row is in the query. Change-Id: I0f58bed232d9336fed6e67c3d140fd580ec35868 Reviewed-by: Honglei Zhang --- src/sql/models/qsqltablemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index d39df1d710..5fed167070 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -1163,7 +1163,7 @@ int QSqlTableModel::rowCount(const QModelIndex &parent) const QModelIndex QSqlTableModel::indexInQuery(const QModelIndex &item) const { Q_D(const QSqlTableModel); - if (d->cache.value(item.row()).op() == QSqlTableModelPrivate::Insert) + if (d->cache.value(item.row()).insert()) return QModelIndex(); const int rowOffset = d->insertCount(item.row()); -- cgit v1.2.3 From 86dd4544612d620474dcdd36bc031a39eebe334c Mon Sep 17 00:00:00 2001 From: jian liang Date: Fri, 2 Mar 2012 00:07:49 +0800 Subject: Delete QPlatformDragPrivate object in QPlatformDrag's destructor Change-Id: Ib722df14123b24ca044f6e0846aa1435c7e0e201 Reviewed-by: Rohan McGovern --- src/gui/kernel/qplatformdrag_qpa.cpp | 1 + src/gui/kernel/qplatformdrag_qpa.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/gui/kernel/qplatformdrag_qpa.cpp b/src/gui/kernel/qplatformdrag_qpa.cpp index 832b91db7e..0e7b0f41cc 100644 --- a/src/gui/kernel/qplatformdrag_qpa.cpp +++ b/src/gui/kernel/qplatformdrag_qpa.cpp @@ -88,6 +88,7 @@ QPlatformDrag::QPlatformDrag() : d_ptr(new QPlatformDragPrivate) QPlatformDrag::~QPlatformDrag() { + delete d_ptr; } QDrag *QPlatformDrag::currentDrag() const diff --git a/src/gui/kernel/qplatformdrag_qpa.h b/src/gui/kernel/qplatformdrag_qpa.h index 7d22c69947..22133706d1 100644 --- a/src/gui/kernel/qplatformdrag_qpa.h +++ b/src/gui/kernel/qplatformdrag_qpa.h @@ -100,6 +100,8 @@ public: private: QPlatformDragPrivate *d_ptr; + + Q_DISABLE_COPY(QPlatformDrag) }; QT_END_NAMESPACE -- cgit v1.2.3 From 431eb30e9ec21c15d26d6f1b03d3bbd4cd36c30c Mon Sep 17 00:00:00 2001 From: Donald Carr Date: Fri, 9 Mar 2012 00:59:37 +0000 Subject: Remove stale references to Qtopia MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Idd9b5fae8f6a0273636a878325e82e5664a40d43 Reviewed-by: Donald Carr Reviewed-by: Samuel Rødal Reviewed-by: Oswald Buddenhagen Reviewed-by: Girish Ramakrishnan Reviewed-by: Jørgen Lind --- src/plugins/platforms/xcb/qxcbkeyboard.cpp | 36 ---------------------------- src/plugins/platforms/xlib/qxlibkeyboard.cpp | 36 ---------------------------- src/printsupport/dialogs/qprintdialog.h | 19 --------------- src/printsupport/kernel/qprinter.cpp | 2 -- 4 files changed, 93 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 03156dc544..c5e124ab45 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -247,24 +247,6 @@ // end of XF86keysyms.h -// Special keys used by Qtopia, mapped into the X11 private keypad range. -#define QTOPIAXK_Select 0x11000601 -#define QTOPIAXK_Yes 0x11000602 -#define QTOPIAXK_No 0x11000603 -#define QTOPIAXK_Cancel 0x11000604 -#define QTOPIAXK_Printer 0x11000605 -#define QTOPIAXK_Execute 0x11000606 -#define QTOPIAXK_Sleep 0x11000607 -#define QTOPIAXK_Play 0x11000608 -#define QTOPIAXK_Zoom 0x11000609 -#define QTOPIAXK_Context1 0x1100060A -#define QTOPIAXK_Context2 0x1100060B -#define QTOPIAXK_Context3 0x1100060C -#define QTOPIAXK_Context4 0x1100060D -#define QTOPIAXK_Call 0x1100060E -#define QTOPIAXK_Hangup 0x1100060F -#define QTOPIAXK_Flip 0x11000610 - QT_BEGIN_NAMESPACE // keyboard mapping table @@ -573,24 +555,6 @@ static const unsigned int KeyTbl[] = { XF86XK_LaunchE, Qt::Key_LaunchG, XF86XK_LaunchF, Qt::Key_LaunchH, - // Qtopia keys - QTOPIAXK_Select, Qt::Key_Select, - QTOPIAXK_Yes, Qt::Key_Yes, - QTOPIAXK_No, Qt::Key_No, - QTOPIAXK_Cancel, Qt::Key_Cancel, - QTOPIAXK_Printer, Qt::Key_Printer, - QTOPIAXK_Execute, Qt::Key_Execute, - QTOPIAXK_Sleep, Qt::Key_Sleep, - QTOPIAXK_Play, Qt::Key_Play, - QTOPIAXK_Zoom, Qt::Key_Zoom, - QTOPIAXK_Context1, Qt::Key_Context1, - QTOPIAXK_Context2, Qt::Key_Context2, - QTOPIAXK_Context3, Qt::Key_Context3, - QTOPIAXK_Context4, Qt::Key_Context4, - QTOPIAXK_Call, Qt::Key_Call, - QTOPIAXK_Hangup, Qt::Key_Hangup, - QTOPIAXK_Flip, Qt::Key_Flip, - 0, 0 }; diff --git a/src/plugins/platforms/xlib/qxlibkeyboard.cpp b/src/plugins/platforms/xlib/qxlibkeyboard.cpp index e2742c4c8d..590d582661 100644 --- a/src/plugins/platforms/xlib/qxlibkeyboard.cpp +++ b/src/plugins/platforms/xlib/qxlibkeyboard.cpp @@ -243,24 +243,6 @@ // end of XF86keysyms.h -// Special keys used by Qtopia, mapped into the X11 private keypad range. -#define QTOPIAXK_Select 0x11000601 -#define QTOPIAXK_Yes 0x11000602 -#define QTOPIAXK_No 0x11000603 -#define QTOPIAXK_Cancel 0x11000604 -#define QTOPIAXK_Printer 0x11000605 -#define QTOPIAXK_Execute 0x11000606 -#define QTOPIAXK_Sleep 0x11000607 -#define QTOPIAXK_Play 0x11000608 -#define QTOPIAXK_Zoom 0x11000609 -#define QTOPIAXK_Context1 0x1100060A -#define QTOPIAXK_Context2 0x1100060B -#define QTOPIAXK_Context3 0x1100060C -#define QTOPIAXK_Context4 0x1100060D -#define QTOPIAXK_Call 0x1100060E -#define QTOPIAXK_Hangup 0x1100060F -#define QTOPIAXK_Flip 0x11000610 - // keyboard mapping table static const unsigned int KeyTbl[] = { @@ -567,24 +549,6 @@ static const unsigned int KeyTbl[] = { XF86XK_LaunchE, Qt::Key_LaunchG, XF86XK_LaunchF, Qt::Key_LaunchH, - // Qtopia keys - QTOPIAXK_Select, Qt::Key_Select, - QTOPIAXK_Yes, Qt::Key_Yes, - QTOPIAXK_No, Qt::Key_No, - QTOPIAXK_Cancel, Qt::Key_Cancel, - QTOPIAXK_Printer, Qt::Key_Printer, - QTOPIAXK_Execute, Qt::Key_Execute, - QTOPIAXK_Sleep, Qt::Key_Sleep, - QTOPIAXK_Play, Qt::Key_Play, - QTOPIAXK_Zoom, Qt::Key_Zoom, - QTOPIAXK_Context1, Qt::Key_Context1, - QTOPIAXK_Context2, Qt::Key_Context2, - QTOPIAXK_Context3, Qt::Key_Context3, - QTOPIAXK_Context4, Qt::Key_Context4, - QTOPIAXK_Call, Qt::Key_Call, - QTOPIAXK_Hangup, Qt::Key_Hangup, - QTOPIAXK_Flip, Qt::Key_Flip, - 0, 0 }; diff --git a/src/printsupport/dialogs/qprintdialog.h b/src/printsupport/dialogs/qprintdialog.h index f563836548..af39a90d73 100644 --- a/src/printsupport/dialogs/qprintdialog.h +++ b/src/printsupport/dialogs/qprintdialog.h @@ -117,11 +117,6 @@ public: QPrinter *printer(); #endif -#ifdef QTOPIA_PRINTDIALOG -public: - bool eventFilter(QObject *, QEvent *); -#endif - #ifdef Q_NO_USING_KEYWORD #ifndef Q_QDOC void accepted() { QDialog::accepted(); } @@ -134,7 +129,6 @@ Q_SIGNALS: void accepted(QPrinter *printer); private: -#ifndef QTOPIA_PRINTDIALOG Q_PRIVATE_SLOT(d_func(), void _q_chbPrintLastFirstToggled(bool)) #if defined (Q_OS_UNIX) Q_PRIVATE_SLOT(d_func(), void _q_collapseOrExpandDialog()) @@ -142,19 +136,6 @@ private: # if defined(Q_OS_UNIX) && !defined(QT_NO_MESSAGEBOX) Q_PRIVATE_SLOT(d_func(), void _q_checkFields()) # endif -#else // QTOPIA_PRINTDIALOG - Q_PRIVATE_SLOT(d_func(), void _q_okClicked()) - Q_PRIVATE_SLOT(d_func(),void _q_printerOrFileSelected(QAbstractButton *b)) - Q_PRIVATE_SLOT(d_func(),void _q_paperSizeSelected(int)) - Q_PRIVATE_SLOT(d_func(), void _q_orientSelected(int)) - Q_PRIVATE_SLOT(d_func(), void _q_pageOrderSelected(int)) - Q_PRIVATE_SLOT(d_func(), void _q_colorModeSelected(QAbstractButton *)) - Q_PRIVATE_SLOT(d_func(), void _q_setNumCopies(int)) - Q_PRIVATE_SLOT(d_func(), void _q_printRangeSelected(int)) - Q_PRIVATE_SLOT(d_func(), void _q_setFirstPage(int)) - Q_PRIVATE_SLOT(d_func(), void _q_setLastPage(int)) - Q_PRIVATE_SLOT(d_func(), void _q_fileNameEditChanged(const QString &text)) -#endif // QTOPIA_PRINTDIALOG friend class QUnixPrintWidget; }; diff --git a/src/printsupport/kernel/qprinter.cpp b/src/printsupport/kernel/qprinter.cpp index f56d34975d..85dc59ff34 100644 --- a/src/printsupport/kernel/qprinter.cpp +++ b/src/printsupport/kernel/qprinter.cpp @@ -58,8 +58,6 @@ #if defined (Q_WS_WIN) #include -#elif defined (QTOPIA_PRINTENGINE) -#include #endif #if defined(Q_WS_X11) -- cgit v1.2.3 From ca737f566b1016712a0d90e8b5e55e49ce8748d2 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 7 Mar 2012 16:21:38 +0100 Subject: Use QAccessibleEvent in test. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I4f9c0f503543caa5704a29c8ccd7c4134b455625 Reviewed-by: Jan-Arve Sæther --- src/testlib/qtestaccessible.h | 50 +++++++++++----------- .../other/qaccessibility/tst_qaccessibility.cpp | 40 ++++++++--------- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/testlib/qtestaccessible.h b/src/testlib/qtestaccessible.h index d402cc8cf8..f9b1b97ac6 100644 --- a/src/testlib/qtestaccessible.h +++ b/src/testlib/qtestaccessible.h @@ -49,8 +49,8 @@ #ifndef QT_NO_ACCESSIBILITY -#define QVERIFY_EVENT(object, child, event) \ - QVERIFY(QTestAccessibility::verifyEvent(object, child, (int)event)) +#define QVERIFY_EVENT(event) \ + QVERIFY(QTestAccessibility::verifyEvent(event)) #include #include @@ -63,22 +63,21 @@ QT_BEGIN_NAMESPACE class QObject; -struct QTestAccessibilityEvent -{ - QTestAccessibilityEvent(QObject* o = 0, int c = 0, int e = 0) - : object(o), child(c), event(e) {} +typedef QList EventList; - bool operator==(const QTestAccessibilityEvent &o) const - { - return o.object == object && o.child == child && o.event == event; +bool operator==(const QAccessibleEvent &l, const QAccessibleEvent &r) +{ + if (l.type() != r.type() || + l.object() != r.object() || + l.child() != r.child()) + return false; + + if (l.type() == QAccessible::StateChanged) { + return static_cast(&l)->changedStates() + == static_cast(&r)->changedStates(); } - - QObject* object; - int child; - int event; -}; - -typedef QList EventList; + return true; +} class QTestAccessibility { @@ -90,6 +89,7 @@ public: qAddPostRoutine(cleanup); } } + static void cleanup() { delete instance(); @@ -97,18 +97,13 @@ public: } static void clearEvents() { eventList().clear(); } static EventList events() { return eventList(); } - static bool verifyEvent(const QTestAccessibilityEvent& ev) + static bool verifyEvent(const QAccessibleEvent& ev) { if (eventList().isEmpty()) return FALSE; return eventList().takeFirst() == ev; } - static bool verifyEvent(QObject *o, int c, int e) - { - return verifyEvent(QTestAccessibilityEvent(o, c, e)); - } - private: QTestAccessibility() { @@ -136,8 +131,15 @@ private: static void updateHandler(const QAccessibleEvent &event) { - // qDebug("updateHandler called: %p %d %d", o, c, (int)e); - eventList().append(QTestAccessibilityEvent(event.object(), event.child(), (int)event.type())); + eventList().append(copyEvent(event)); + } + + static QAccessibleEvent copyEvent(const QAccessibleEvent &event) + { + if (event.type() == QAccessible::StateChanged) + return QAccessibleStateChangeEvent(static_cast(&event)->changedStates(), + event.object(), event.child()); + return QAccessibleEvent(event.type(), event.object(), event.child()); } static EventList &eventList() diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp index b8649a6443..0edda96f2a 100644 --- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp @@ -403,8 +403,8 @@ void tst_QAccessibility::cleanup() qWarning("%d accessibility event(s) were not handled in testfunction '%s':", list.count(), QString(QTest::currentTestFunction()).toAscii().constData()); for (int i = 0; i < list.count(); ++i) - qWarning(" %d: Object: %p Event: '%s' (%d) Child: %d", i + 1, list.at(i).object, - eventName(list.at(i).event).toAscii().constData(), list.at(i).event, list.at(i).child); + qWarning(" %d: Object: %p Event: '%s' Child: %d", i + 1, list.at(i).object(), + eventName(list.at(i).type()).toAscii().constData(), list.at(i).child()); } QTestAccessibility::clearEvents(); } @@ -415,18 +415,18 @@ void tst_QAccessibility::eventTest() button->setObjectName(QString("Olaf")); button->show(); - QVERIFY_EVENT(button, -1, QAccessible::ObjectShow); + QVERIFY_EVENT(QAccessibleEvent(QAccessible::ObjectShow, button, -1)); button->setFocus(Qt::MouseFocusReason); QTestAccessibility::clearEvents(); QTest::mouseClick(button, Qt::LeftButton, 0); button->setAccessibleName("Olaf the second"); - QVERIFY_EVENT(button, -1, QAccessible::NameChanged); + QVERIFY_EVENT(QAccessibleEvent(QAccessible::NameChanged, button)); button->setAccessibleDescription("This is a button labeled Olaf"); - QVERIFY_EVENT(button, -1, QAccessible::DescriptionChanged); + QVERIFY_EVENT(QAccessibleEvent(QAccessible::DescriptionChanged, button)); button->hide(); - QVERIFY_EVENT(button, -1, QAccessible::ObjectHide); + QVERIFY_EVENT(QAccessibleEvent(QAccessible::ObjectHide, button)); delete button; } @@ -730,16 +730,16 @@ void tst_QAccessibility::hideShowTest() window->show(); QVERIFY(!state(window).invisible); QVERIFY(!state(child).invisible); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(window, -1, QAccessible::ObjectShow))); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(child, -1, QAccessible::ObjectShow))); + QVERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::ObjectShow, window))); + QVERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::ObjectShow, child))); QTestAccessibility::clearEvents(); // hide() and veryfy that both window and child are invisible and get ObjectHide events. window->hide(); QVERIFY(state(window).invisible); QVERIFY(state(child).invisible); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(window, -1, QAccessible::ObjectHide))); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(child, -1, QAccessible::ObjectHide))); + QVERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::ObjectHide, window))); + QVERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::ObjectHide, child))); QTestAccessibility::clearEvents(); delete window; @@ -820,7 +820,7 @@ void tst_QAccessibility::mainWindowTest() QLatin1String name = QLatin1String("I am the main window"); mw->setWindowTitle(name); QTest::qWaitForWindowShown(mw); - QVERIFY_EVENT(mw, -1, QAccessible::ObjectShow); + QVERIFY_EVENT(QAccessibleEvent(QAccessible::ObjectShow, mw)); QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(mw); QCOMPARE(interface->text(QAccessible::Name), name); @@ -1050,12 +1050,12 @@ void tst_QAccessibility::scrollBarTest() scrollBar->resize(200, 50); scrollBar->show(); QVERIFY(!scrollBarInterface->state().invisible); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(scrollBar, -1, QAccessible::ObjectShow))); + QVERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::ObjectShow, scrollBar))); QTestAccessibility::clearEvents(); scrollBar->hide(); QVERIFY(scrollBarInterface->state().invisible); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(scrollBar, -1, QAccessible::ObjectHide))); + QVERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::ObjectHide, scrollBar))); QTestAccessibility::clearEvents(); // Test that the left/right subcontrols are set to unavailable when the scrollBar is at the minimum/maximum. @@ -1496,7 +1496,7 @@ void tst_QAccessibility::spinBoxTest() QTest::keyPress(spinBox, Qt::Key_Up); QTest::qWait(200); EventList events = QTestAccessibility::events(); - QTestAccessibilityEvent expectedEvent(spinBox, -1, (int)QAccessible::ValueChanged); + QAccessibleEvent expectedEvent(QAccessible::ValueChanged, spinBox); QVERIFY(events.contains(expectedEvent)); delete spinBox; QTestAccessibility::clearEvents(); @@ -1767,7 +1767,7 @@ void tst_QAccessibility::lineEditTest() le->setFocus(Qt::TabFocusReason); QTestAccessibility::clearEvents(); le2->setFocus(Qt::TabFocusReason); - QTRY_VERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(le2, -1, QAccessible::Focus))); + QTRY_VERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::Focus, le2))); le->setText(QLatin1String("500")); le->setValidator(new QIntValidator()); @@ -1787,7 +1787,7 @@ void tst_QAccessibility::lineEditTest() le3->deselect(); le3->setCursorPosition(3); QCOMPARE(textIface->cursorPosition(), 3); - QTRY_VERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(le3, -1, QAccessible::TextCaretMoved))); + QTRY_VERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::TextCaretMoved, le3))); QCOMPARE(textIface->selectionCount(), 0); QTestAccessibility::clearEvents(); @@ -2158,11 +2158,11 @@ void tst_QAccessibility::listTest() // Check for events QTest::mouseClick(listView->viewport(), Qt::LeftButton, 0, listView->visualItemRect(listView->item(1)).center()); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(listView, 2, QAccessible::Selection))); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(listView, 2, QAccessible::Focus))); + QVERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::Selection, listView, 2))); + QVERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::Focus, listView, 2))); QTest::mouseClick(listView->viewport(), Qt::LeftButton, 0, listView->visualItemRect(listView->item(2)).center()); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(listView, 3, QAccessible::Selection))); - QVERIFY(QTestAccessibility::events().contains(QTestAccessibilityEvent(listView, 3, QAccessible::Focus))); + QVERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::Selection, listView, 3))); + QVERIFY(QTestAccessibility::events().contains(QAccessibleEvent(QAccessible::Focus, listView, 3))); listView->addItem("Munich"); QCOMPARE(iface->childCount(), 4); -- cgit v1.2.3 From 7738f96f09830f0b21a5834e9af3d4ae8473deab Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 7 Mar 2012 16:27:47 +0100 Subject: Add documenation about QAccessibleStateChange event. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Iea34d71d71a6dd58f761722ce20ae8ec2b81ae58 Reviewed-by: Jan-Arve Sæther --- src/gui/accessible/qaccessible.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp index 91b0b5fbe6..cb89fccc2d 100644 --- a/src/gui/accessible/qaccessible.cpp +++ b/src/gui/accessible/qaccessible.cpp @@ -697,8 +697,31 @@ void QAccessible::updateAccessibility(const QAccessibleEvent &event) This class should be created on the stack and used as parameter for \l QAccessible::updateAccessibility(). + \sa QAccessibleStateChangedEvent */ +/*! + \class QAccessibleStateChangedEvent + \brief This subclass of QAccessibleEvent is used to inform about state changes. + \internal + + \ingroup accessibility + \inmodule QtGui + + This class should be created on the stack and used as parameter for + \l QAccessible::updateAccessibility(). + In addition to the regular \l QAccessibleEvent it contains details about which states + changed. + \sa QAccessibleEvent +*/ + +/*! + \fn QAccessibleStateChangeEvent::changedStates() const + All states that have changed are set to true. This does not reflect the state of the object, + but indicates which states are changed. + Use the \l QAccessibleInterface::state() function to get the current state. + */ + /*! Returns the QAccessibleInterface associated with the event. -- cgit v1.2.3 From edea0e19173d92526b6f5378a6182f53d29f45e6 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 6 Mar 2012 12:14:51 +0100 Subject: tst_exceptionsafety_objects: add virtual ~AbstractTester GCC complained about undefined behaviour when deleting subclasses of AbstractTester through pointers to AbstractTester, and it's doing so correctly... Change-Id: Ie641281d8aafe32c5c9784e8aa39672ff0b699c7 Reviewed-by: Lars Knoll --- tests/auto/other/exceptionsafety_objects/tst_exceptionsafety_objects.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/other/exceptionsafety_objects/tst_exceptionsafety_objects.cpp b/tests/auto/other/exceptionsafety_objects/tst_exceptionsafety_objects.cpp index a426a90976..14628b2c8b 100644 --- a/tests/auto/other/exceptionsafety_objects/tst_exceptionsafety_objects.cpp +++ b/tests/auto/other/exceptionsafety_objects/tst_exceptionsafety_objects.cpp @@ -94,6 +94,7 @@ void tst_ExceptionSafety_Objects::initTestCase() // helper structs to create an arbitrary widget struct AbstractTester { + virtual ~AbstractTester() {} virtual void operator()(QObject *parent) = 0; }; Q_DECLARE_METATYPE(AbstractTester *) -- cgit v1.2.3 From 75218e08ab4f6a237d8adde68fbd039a6791600c Mon Sep 17 00:00:00 2001 From: Sean Harmer Date: Mon, 12 Mar 2012 11:03:47 +0000 Subject: Do not add -rpath-link directives with no library path Doing so works fine on Linux as g++ version there silently ignores this. However, the qcc toolchain for QNX barfs. Change-Id: Ia236910adc09dc1653e4169e20476b69c2de62ab Reviewed-by: Oswald Buddenhagen --- mkspecs/features/qt_functions.prf | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 370187b722..474a414003 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -132,9 +132,11 @@ defineTest(qtAddModule) { isEmpty(LINKAGE) { # Make sure we can link to uninstalled libraries - !isEqual(MODULE_LIBS, $$[QT_INSTALL_LIBS]) { ### XXX - QMAKE_LIBDIR *= $$MODULE_LIBS - unix:!mac:QMAKE_LFLAGS *= "-Wl,-rpath-link,$$MODULE_LIBS" + !isEmpty(MODULE_LIBS) { + !isEqual(MODULE_LIBS, $$[QT_INSTALL_LIBS]) { ### XXX + QMAKE_LIBDIR *= $$MODULE_LIBS + unix:!mac:QMAKE_LFLAGS *= "-Wl,-rpath-link,$$MODULE_LIBS" + } } if(!debug_and_release|build_pass):CONFIG(debug, debug|release) { win32:LINKAGE = -l$${MODULE_NAME}$${QT_LIBINFIX}d -- cgit v1.2.3 From 9f266efa8f0962c5769b90e3f79a5658fc9d3332 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 23 Jan 2012 23:09:51 +0000 Subject: QRegularExpression: add error strings for translation Added the error strings from PCRE to be picked up by lupdate, to enable translations. Change-Id: Iaeabde5d7a17f9a0273511e0741e67a097d23a98 Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira Reviewed-by: Lars Knoll --- src/corelib/tools/qregularexpression.cpp | 115 +++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp index c7e8e6ccb8..1db78519a3 100644 --- a/src/corelib/tools/qregularexpression.cpp +++ b/src/corelib/tools/qregularexpression.cpp @@ -2206,4 +2206,119 @@ QDebug operator<<(QDebug debug, const QRegularExpressionMatch &match) } #endif +// fool lupdate: make it extract those strings for translation, but don't put them +// inside Qt -- they're already inside libpcre (cf. man 3 pcreapi, pcre_compile.c). +#if 0 + +/* PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + + Written by Philip Hazel + Copyright (c) 1997-2012 University of Cambridge + +----------------------------------------------------------------------------- +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 the University of Cambridge 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. +----------------------------------------------------------------------------- +*/ + +static const char *pcreCompileErrorCodes[] = +{ + QT_TRANSLATE_NOOP("QRegularExpression", "no error"), + QT_TRANSLATE_NOOP("QRegularExpression", "\\ at end of pattern"), + QT_TRANSLATE_NOOP("QRegularExpression", "\\c at end of pattern"), + QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character follows \\"), + QT_TRANSLATE_NOOP("QRegularExpression", "numbers out of order in {} quantifier"), + QT_TRANSLATE_NOOP("QRegularExpression", "number too big in {} quantifier"), + QT_TRANSLATE_NOOP("QRegularExpression", "missing terminating ] for character class"), + QT_TRANSLATE_NOOP("QRegularExpression", "invalid escape sequence in character class"), + QT_TRANSLATE_NOOP("QRegularExpression", "range out of order in character class"), + QT_TRANSLATE_NOOP("QRegularExpression", "nothing to repeat"), + QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unexpected repeat"), + QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (? or (?-"), + QT_TRANSLATE_NOOP("QRegularExpression", "POSIX named classes are supported only within a class"), + QT_TRANSLATE_NOOP("QRegularExpression", "missing )"), + QT_TRANSLATE_NOOP("QRegularExpression", "reference to non-existent subpattern"), + QT_TRANSLATE_NOOP("QRegularExpression", "erroffset passed as NULL"), + QT_TRANSLATE_NOOP("QRegularExpression", "unknown option bit(s) set"), + QT_TRANSLATE_NOOP("QRegularExpression", "missing ) after comment"), + QT_TRANSLATE_NOOP("QRegularExpression", "regular expression is too large"), + QT_TRANSLATE_NOOP("QRegularExpression", "failed to get memory"), + QT_TRANSLATE_NOOP("QRegularExpression", "unmatched parentheses"), + QT_TRANSLATE_NOOP("QRegularExpression", "internal error: code overflow"), + QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?<"), + QT_TRANSLATE_NOOP("QRegularExpression", "lookbehind assertion is not fixed length"), + QT_TRANSLATE_NOOP("QRegularExpression", "malformed number or name after (?("), + QT_TRANSLATE_NOOP("QRegularExpression", "conditional group contains more than two branches"), + QT_TRANSLATE_NOOP("QRegularExpression", "assertion expected after (?("), + QT_TRANSLATE_NOOP("QRegularExpression", "(?R or (?[+-]digits must be followed by )"), + QT_TRANSLATE_NOOP("QRegularExpression", "unknown POSIX class name"), + QT_TRANSLATE_NOOP("QRegularExpression", "POSIX collating elements are not supported"), + QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE is not compiled with PCRE_UTF8 support"), + QT_TRANSLATE_NOOP("QRegularExpression", "character value in \\x{...} sequence is too large"), + QT_TRANSLATE_NOOP("QRegularExpression", "invalid condition (?(0)"), + QT_TRANSLATE_NOOP("QRegularExpression", "\\C not allowed in lookbehind assertion"), + QT_TRANSLATE_NOOP("QRegularExpression", "PCRE does not support \\L, \\l, \\N{name}, \\U, or \\u"), + QT_TRANSLATE_NOOP("QRegularExpression", "number after (?C is > 255"), + QT_TRANSLATE_NOOP("QRegularExpression", "closing ) for (?C expected"), + QT_TRANSLATE_NOOP("QRegularExpression", "recursive call could loop indefinitely"), + QT_TRANSLATE_NOOP("QRegularExpression", "unrecognized character after (?P"), + QT_TRANSLATE_NOOP("QRegularExpression", "syntax error in subpattern name (missing terminator)"), + QT_TRANSLATE_NOOP("QRegularExpression", "two named subpatterns have the same name"), + QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-8 string"), + QT_TRANSLATE_NOOP("QRegularExpression", "support for \\P, \\p, and \\X has not been compiled"), + QT_TRANSLATE_NOOP("QRegularExpression", "malformed \\P or \\p sequence"), + QT_TRANSLATE_NOOP("QRegularExpression", "unknown property name after \\P or \\p"), + QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name is too long (maximum 32 characters)"), + QT_TRANSLATE_NOOP("QRegularExpression", "too many named subpatterns (maximum 10000)"), + QT_TRANSLATE_NOOP("QRegularExpression", "octal value is greater than \\377 (not in UTF-8 mode)"), + QT_TRANSLATE_NOOP("QRegularExpression", "internal error: overran compiling workspace"), + QT_TRANSLATE_NOOP("QRegularExpression", "internal error: previously-checked referenced subpattern not found"), + QT_TRANSLATE_NOOP("QRegularExpression", "DEFINE group contains more than one branch"), + QT_TRANSLATE_NOOP("QRegularExpression", "repeating a DEFINE group is not allowed"), + QT_TRANSLATE_NOOP("QRegularExpression", "inconsistent NEWLINE options"), + QT_TRANSLATE_NOOP("QRegularExpression", "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number"), + QT_TRANSLATE_NOOP("QRegularExpression", "a numbered reference must not be zero"), + QT_TRANSLATE_NOOP("QRegularExpression", "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)"), + QT_TRANSLATE_NOOP("QRegularExpression", "(*VERB) not recognized"), + QT_TRANSLATE_NOOP("QRegularExpression", "number is too big"), + QT_TRANSLATE_NOOP("QRegularExpression", "subpattern name expected"), + QT_TRANSLATE_NOOP("QRegularExpression", "digit expected after (?+"), + QT_TRANSLATE_NOOP("QRegularExpression", "] is an invalid data character in JavaScript compatibility mode"), + QT_TRANSLATE_NOOP("QRegularExpression", "different names for subpatterns of the same number are not allowed"), + QT_TRANSLATE_NOOP("QRegularExpression", "(*MARK) must have an argument"), + QT_TRANSLATE_NOOP("QRegularExpression", "this version of PCRE is not compiled with PCRE_UCP support"), + QT_TRANSLATE_NOOP("QRegularExpression", "\\c must be followed by an ASCII character"), + QT_TRANSLATE_NOOP("QRegularExpression", "\\k is not followed by a braced, angle-bracketed, or quoted name"), + QT_TRANSLATE_NOOP("QRegularExpression", "internal error: unknown opcode in find_fixedlength()"), + QT_TRANSLATE_NOOP("QRegularExpression", "\\N is not supported in a class"), + QT_TRANSLATE_NOOP("QRegularExpression", "too many forward references"), + QT_TRANSLATE_NOOP("QRegularExpression", "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)"), + QT_TRANSLATE_NOOP("QRegularExpression", "invalid UTF-16 string") +}; +#endif // #if 0 + QT_END_NAMESPACE -- cgit v1.2.3 From db390d46c3a983f0270fb40be7f59297e9a77d64 Mon Sep 17 00:00:00 2001 From: Debao Zhang Date: Thu, 8 Mar 2012 16:48:17 -0800 Subject: Move the auto test of QPixmap::grabWidget() from QPixmap to QWidget Change-Id: Id565fa1eb8fe13c62a93a5afa39a5701ce7b20ea QPixmap::grabWidget is deprecated, which calls QWidget::grab() at present. Reviewed-by: Gunnar Sletta Reviewed-by: Friedemann Kleint --- tests/auto/gui/image/qpixmap/tst_qpixmap.cpp | 43 ------------- tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp | 75 +++++++++++++++++++++++ 2 files changed, 75 insertions(+), 43 deletions(-) diff --git a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp index 563baef486..c7652e445f 100644 --- a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp @@ -48,7 +48,6 @@ #include #include #include -#include #include #include @@ -111,7 +110,6 @@ private slots: void setGetMask(); void cacheKey(); void drawBitmap(); - void grabWidget(); void grabWindow(); void isNull(); void task_246446(); @@ -718,47 +716,6 @@ void tst_QPixmap::drawBitmap() QVERIFY(lenientCompare(pixmap, expected)); } -void tst_QPixmap::grabWidget() -{ - for (int opaque = 0; opaque < 2; ++opaque) { - QWidget widget; - QImage image(128, 128, opaque ? QImage::Format_RGB32 : QImage::Format_ARGB32_Premultiplied); - for (int row = 0; row < image.height(); ++row) { - QRgb *line = reinterpret_cast(image.scanLine(row)); - for (int col = 0; col < image.width(); ++col) - line[col] = qRgba(rand() & 255, row, col, opaque ? 255 : 127); - } - - QPalette pal = widget.palette(); - pal.setBrush(QPalette::Window, QBrush(image)); - widget.setPalette(pal); - widget.resize(128, 128); - - QPixmap expected(64, 64); - if (!opaque) - expected.fill(Qt::transparent); - - QPainter p(&expected); - p.translate(-64, -64); - p.drawTiledPixmap(0, 0, 128, 128, pal.brush(QPalette::Window).texture(), 0, 0); - p.end(); - - QPixmap actual = QPixmap::grabWidget(&widget, QRect(64, 64, 64, 64)); - QVERIFY(lenientCompare(actual, expected)); - - actual = QPixmap::grabWidget(&widget, 64, 64); - QVERIFY(lenientCompare(actual, expected)); - - // Make sure a widget that is not yet shown is grabbed correctly. - QTreeWidget widget2; - actual = QPixmap::grabWidget(&widget2); - widget2.show(); - expected = QPixmap::grabWidget(&widget2); - - QVERIFY(lenientCompare(actual, expected)); - } -} - void tst_QPixmap::grabWindow() { // ### fixme: Check platforms diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp index dab9dd7690..49c93f8f03 100644 --- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp +++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp @@ -68,6 +68,7 @@ #include #include #include +#include #include #include @@ -412,6 +413,7 @@ private slots: void taskQTBUG_17333_ResizeInfiniteRecursion(); void nativeChildFocus(); + void grab(); private: bool ensureScreenSize(int width, int height); @@ -9288,5 +9290,78 @@ void tst_QWidget::nativeChildFocus() QTest::qWait(1000); } +static bool lenientCompare(const QPixmap &actual, const QPixmap &expected) +{ + QImage expectedImage = expected.toImage().convertToFormat(QImage::Format_RGB32); + QImage actualImage = actual.toImage().convertToFormat(QImage::Format_RGB32); + + if (expectedImage.size() != actualImage.size()) { + qWarning("Image size comparison failed: expected: %dx%d, got %dx%d", + expectedImage.size().width(), expectedImage.size().height(), + actualImage.size().width(), actualImage.size().height()); + return false; + } + + const int size = actual.width() * actual.height(); + const int threshold = QPixmap::defaultDepth() == 16 ? 10 : 2; + + QRgb *a = (QRgb *)actualImage.bits(); + QRgb *e = (QRgb *)expectedImage.bits(); + for (int i = 0; i < size; ++i) { + const QColor ca(a[i]); + const QColor ce(e[i]); + if (qAbs(ca.red() - ce.red()) > threshold + || qAbs(ca.green() - ce.green()) > threshold + || qAbs(ca.blue() - ce.blue()) > threshold) { + qWarning("Color mismatch at pixel #%d: Expected: %d,%d,%d, got %d,%d,%d", + i, ce.red(), ce.green(), ce.blue(), ca.red(), ca.green(), ca.blue()); + return false; + } + } + + return true; +} + +void tst_QWidget::grab() +{ + for (int opaque = 0; opaque < 2; ++opaque) { + QWidget widget; + QImage image(128, 128, opaque ? QImage::Format_RGB32 : QImage::Format_ARGB32_Premultiplied); + for (int row = 0; row < image.height(); ++row) { + QRgb *line = reinterpret_cast(image.scanLine(row)); + for (int col = 0; col < image.width(); ++col) + line[col] = qRgba(rand() & 255, row, col, opaque ? 255 : 127); + } + + QPalette pal = widget.palette(); + pal.setBrush(QPalette::Window, QBrush(image)); + widget.setPalette(pal); + widget.resize(128, 128); + + QPixmap expected(64, 64); + if (!opaque) + expected.fill(Qt::transparent); + + QPainter p(&expected); + p.translate(-64, -64); + p.drawTiledPixmap(0, 0, 128, 128, pal.brush(QPalette::Window).texture(), 0, 0); + p.end(); + + QPixmap actual = widget.grab(QRect(64, 64, 64, 64)); + QVERIFY(lenientCompare(actual, expected)); + + actual = widget.grab(QRect(64, 64, -1, -1)); + QVERIFY(lenientCompare(actual, expected)); + + // Make sure a widget that is not yet shown is grabbed correctly. + QTreeWidget widget2; + actual = widget2.grab(QRect()); + widget2.show(); + expected = widget2.grab(QRect()); + + QVERIFY(lenientCompare(actual, expected)); + } +} + QTEST_MAIN(tst_QWidget) #include "tst_qwidget.moc" -- cgit v1.2.3 From 10e490499507bf902b39affe22a906406e22dc03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Mon, 12 Mar 2012 12:48:20 +0100 Subject: Fix the QMAKE_LIBS_WAYLAND variable This variable is there for documentation, but its not being used anymore. There are two libraries from wayland, libwayland-client and libwayland-server. Add two variables that will be picked up in the QtWayland module. Change-Id: I16219092a4ed2e48080921ce39f61192b6abb711 Reviewed-by: Oswald Buddenhagen --- mkspecs/common/linux.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mkspecs/common/linux.conf b/mkspecs/common/linux.conf index 384c013309..fd10785079 100644 --- a/mkspecs/common/linux.conf +++ b/mkspecs/common/linux.conf @@ -38,7 +38,8 @@ QMAKE_LIBS_LIBUDEV = -ludev QMAKE_CFLAGS_WAYLAND = QMAKE_INCDIR_WAYLAND = -QMAKE_LIBS_WAYLAND = +QMAKE_LIBS_WAYLAND_CLIENT = -lwayland-client +QMAKE_LIBS_WAYLAND_SERVER = -lwayland-server QMAKE_LIBDIR_WAYLAND = QMAKE_DEFINES_WAYLAND = QMAKE_WAYLAND_SCANNER = wayland-scanner -- cgit v1.2.3 From 53c97f83b41b3e047bd3b3e9a0d8ded6b644e31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Mon, 12 Mar 2012 12:16:13 +0100 Subject: Don't define QT_NO_CORESERVICES on all platforms. That's just annoying Change-Id: Id814bd0956b97c84ff0e6fcae8e5f22394c433e7 Reviewed-by: Oswald Buddenhagen --- configure | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/configure b/configure index aa1722d4a5..9a202357e8 100755 --- a/configure +++ b/configure @@ -5268,10 +5268,12 @@ if [ "$PLATFORM_QPA" = "yes" ]; then QMakeVar set QMAKE_DEFINES_XCB "$QMAKE_DEFINES_XCB" fi - if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/mac/coreservices "CoreServices" $L_FLAGS $I_FLAGS $l_FLAGS $MAC_CONFIG_TEST_COMMANDLINE; then - QT_CONFIG="$QT_CONFIG coreservices" - else - QMakeVar add DEFINES QT_NO_CORESERVICES + if [ "$BUILD_ON_MAC" = "yes" ]; then + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/mac/coreservices "CoreServices" $L_FLAGS $I_FLAGS $l_FLAGS $MAC_CONFIG_TEST_COMMANDLINE; then + QT_CONFIG="$QT_CONFIG coreservices" + else + QMakeVar add DEFINES QT_NO_CORESERVICES + fi fi if [ "$PLATFORM_QPA" = "yes" ] && [ "$BUILD_ON_MAC" = "no" ] && [ "$XPLATFORM_MINGW" = "no" ]; then -- cgit v1.2.3 From 6e278b868824db8e24b68d48fa0f6e154de1b2f6 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 9 Mar 2012 09:53:10 +0100 Subject: Implement QSystemTrayIcon for Windows. No longer base the implementation on a QWidget which is not necessary when all that is required is a message window listening to task-tray messages. Export a service function creating a message window from the Windows native interface and use that. Task-number: QTBUG-20978 Change-Id: I01d0faeac777df4eee802c51d2bc722fce814080 Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowsintegration.cpp | 22 ++ src/widgets/util/qsystemtrayicon_win.cpp | 227 ++++++++++++--------- src/widgets/util/util.pri | 9 +- .../util/qsystemtrayicon/tst_qsystemtrayicon.cpp | 12 +- 4 files changed, 164 insertions(+), 106 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index b43362c045..d03abe1d93 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -84,12 +84,17 @@ QT_BEGIN_NAMESPACE class QWindowsNativeInterface : public QPlatformNativeInterface { + Q_OBJECT public: virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); virtual void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *bs); virtual EventFilter setEventFilter(const QByteArray &eventType, EventFilter filter) { return QWindowsContext::instance()->setEventFilter(eventType, filter); } + + Q_INVOKABLE void *createMessageWindow(const QString &classNameTemplate, + const QString &windowName, + void *eventProc) const; }; void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window) @@ -140,6 +145,21 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour return 0; } +/*! + \brief Creates a non-visible window handle for filtering messages. +*/ + +void *QWindowsNativeInterface::createMessageWindow(const QString &classNameTemplate, + const QString &windowName, + void *eventProc) const +{ + QWindowsContext *ctx = QWindowsContext::instance(); + const HWND hwnd = ctx->createDummyWindow(classNameTemplate, + (wchar_t*)windowName.utf16(), + (WNDPROC)eventProc); + return hwnd; +} + /*! \class QWindowsIntegration \brief QPlatformIntegration implementation for Windows. @@ -347,3 +367,5 @@ QPlatformServices *QWindowsIntegration::services() const } QT_END_NAMESPACE + +#include "qwindowsintegration.moc" diff --git a/src/widgets/util/qsystemtrayicon_win.cpp b/src/widgets/util/qsystemtrayicon_win.cpp index fdb308c3d6..f3d4347986 100644 --- a/src/widgets/util/qsystemtrayicon_win.cpp +++ b/src/widgets/util/qsystemtrayicon_win.cpp @@ -50,13 +50,16 @@ #define _WIN32_IE 0x600 #endif -#include -#include -#include - #include -#include +#include +#include #include +#include +#include + +#include +#include +#include QT_BEGIN_NAMESPACE @@ -72,28 +75,12 @@ struct Q_NOTIFYICONIDENTIFIER { GUID guidItem; }; -#ifndef NOTIFYICON_VERSION_4 -#define NOTIFYICON_VERSION_4 4 -#endif - -#ifndef NIN_SELECT -#define NIN_SELECT (WM_USER + 0) -#endif - -#ifndef NIN_KEYSELECT -#define NIN_KEYSELECT (WM_USER + 1) -#endif - -#ifndef NIN_BALLOONTIMEOUT -#define NIN_BALLOONTIMEOUT (WM_USER + 4) -#endif - -#ifndef NIN_BALLOONUSERCLICK -#define NIN_BALLOONUSERCLICK (WM_USER + 5) -#endif - -#ifndef NIF_SHOWTIP -#define NIF_SHOWTIP 0x00000080 +#ifdef Q_CC_MINGW +# define NIN_SELECT (WM_USER + 0) +# define NIN_KEYSELECT (WM_USER + 1) +# define NIN_BALLOONTIMEOUT (WM_USER + 4) +# define NIN_BALLOONUSERCLICK (WM_USER + 5) +# define NIF_SHOWTIP 0x00000080 #endif #define Q_MSGFLT_ALLOW 1 @@ -102,23 +89,34 @@ typedef HRESULT (WINAPI *PtrShell_NotifyIconGetRect)(const Q_NOTIFYICONIDENTIFIE typedef BOOL (WINAPI *PtrChangeWindowMessageFilter)(UINT message, DWORD dwFlag); typedef BOOL (WINAPI *PtrChangeWindowMessageFilterEx)(HWND hWnd, UINT message, DWORD action, void* pChangeFilterStruct); -class QSystemTrayIconSys : QWidget +// Copy QString data to a limited wchar_t array including \0. +static inline void qStringToLimitedWCharArray(QString in, wchar_t *target, int maxLength) +{ + const int length = qMin(maxLength - 1, in.size()); + if (length < in.size()) + in.truncate(length); + in.toWCharArray(target); + target[length] = wchar_t(0); +} + +class QSystemTrayIconSys { public: - QSystemTrayIconSys(QSystemTrayIcon *object); + QSystemTrayIconSys(HWND hwnd, QSystemTrayIcon *object); ~QSystemTrayIconSys(); - bool winEvent( MSG *m, long *result ); bool trayMessage(DWORD msg); void setIconContents(NOTIFYICONDATA &data); bool showMessage(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, uint uSecs); QRect findIconGeometry(const int a_iButtonID); - void createIcon(); + HICON createIcon(); + bool winEvent(MSG *m, long *result); + +private: + const HWND m_hwnd; HICON hIcon; QPoint globalPos; QSystemTrayIcon *q; -private: uint notifyIconSize; - int maxTipLength; int version; bool ignoreNextMouseRelease; }; @@ -126,28 +124,68 @@ private: static bool allowsMessages() { #ifndef QT_NO_SETTINGS - QSettings settings(QLatin1String("HKEY_CURRENT_USER\\Software\\Microsoft" - "\\Windows\\CurrentVersion\\Explorer\\Advanced"), QSettings::NativeFormat); - return settings.value(QLatin1String("EnableBalloonTips"), true).toBool(); + const QString key = QStringLiteral("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"); + const QSettings settings(key, QSettings::NativeFormat); + return settings.value(QStringLiteral("EnableBalloonTips"), true).toBool(); #else return false; #endif } -QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *object) - : hIcon(0), q(object), ignoreNextMouseRelease(false) +typedef QHash HandleTrayIconHash; +Q_GLOBAL_STATIC(HandleTrayIconHash, handleTrayIconHash) + +extern "C" LRESULT QT_WIN_CALLBACK qWindowsTrayconWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { - notifyIconSize = sizeof(NOTIFYICONDATA); - version = NOTIFYICON_VERSION_4; - } else { + if (message == MYWM_TASKBARCREATED || message == MYWM_NOTIFYICON) { + if (QSystemTrayIconSys *trayIcon = handleTrayIconHash()->value(hwnd)) { + MSG msg; + msg.hwnd = hwnd; // re-create MSG structure + msg.message = message; // time and pt fields ignored + msg.wParam = wParam; + msg.lParam = lParam; + msg.pt.x = GET_X_LPARAM(lParam); + msg.pt.y = GET_Y_LPARAM(lParam); + long result = 0; + if (trayIcon->winEvent(&msg, &result)) + return result; + } + } + return DefWindowProc(hwnd, message, wParam, lParam); +} + +// Invoke a service of the native Windows interface to create +// a non-visible message window. +static inline HWND createTrayIconMessageWindow() +{ + if (QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface()) { + void *hwnd = 0; + void *wndProc = reinterpret_cast(qWindowsTrayconWndProc); + if (QMetaObject::invokeMethod(ni, "createMessageWindow", Qt::DirectConnection, + Q_RETURN_ARG(void *, hwnd), + Q_ARG(QString, QStringLiteral("QTrayIconMessageWindowClass")), + Q_ARG(QString, QStringLiteral("QTrayIconMessageWindow")), + Q_ARG(void *, wndProc)) && hwnd) { + return reinterpret_cast(hwnd); + } + } + return 0; +} + +QSystemTrayIconSys::QSystemTrayIconSys(HWND hwnd, QSystemTrayIcon *object) + : m_hwnd(hwnd), hIcon(0), q(object) + , notifyIconSize(NOTIFYICONDATA_V2_SIZE), version(NOTIFYICON_VERSION) + , ignoreNextMouseRelease(false) + +{ + handleTrayIconHash()->insert(m_hwnd, this); + + if (QSysInfo::windowsVersion() < QSysInfo::WV_VISTA) { notifyIconSize = NOTIFYICONDATA_V2_SIZE; version = NOTIFYICON_VERSION; } - maxTipLength = 128; - // For restoring the tray icon after explorer crashes if (!MYWM_TASKBARCREATED) { MYWM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated"); @@ -158,8 +196,8 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *object) (PtrChangeWindowMessageFilterEx)QSystemLibrary::resolve(QLatin1String("user32"), "ChangeWindowMessageFilterEx"); if (pChangeWindowMessageFilterEx) { - // Call the safer ChangeWindowMessageFilterEx API if available - pChangeWindowMessageFilterEx(winId(), MYWM_TASKBARCREATED, Q_MSGFLT_ALLOW, 0); + // Call the safer ChangeWindowMessageFilterEx API if available (Windows 7 onwards) + pChangeWindowMessageFilterEx(m_hwnd, MYWM_TASKBARCREATED, Q_MSGFLT_ALLOW, 0); } else { static PtrChangeWindowMessageFilter pChangeWindowMessageFilter = (PtrChangeWindowMessageFilter)QSystemLibrary::resolve(QLatin1String("user32"), "ChangeWindowMessageFilter"); @@ -173,8 +211,10 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *object) QSystemTrayIconSys::~QSystemTrayIconSys() { + handleTrayIconHash()->remove(m_hwnd); if (hIcon) DestroyIcon(hIcon); + DestroyWindow(m_hwnd); } void QSystemTrayIconSys::setIconContents(NOTIFYICONDATA &tnd) @@ -182,12 +222,9 @@ void QSystemTrayIconSys::setIconContents(NOTIFYICONDATA &tnd) tnd.uFlags |= NIF_MESSAGE | NIF_ICON | NIF_TIP; tnd.uCallbackMessage = MYWM_NOTIFYICON; tnd.hIcon = hIcon; - QString tip = q->toolTip(); - - if (!tip.isNull()) { - tip = tip.left(maxTipLength - 1) + QChar(); - memcpy(tnd.szTip, tip.utf16(), qMin(tip.length() + 1, maxTipLength) * sizeof(wchar_t)); - } + const QString tip = q->toolTip(); + if (!tip.isNull()) + qStringToLimitedWCharArray(tip, tnd.szTip, 64); } static int iconFlag( QSystemTrayIcon::MessageIcon icon ) @@ -211,19 +248,16 @@ bool QSystemTrayIconSys::showMessage(const QString &title, const QString &messag { NOTIFYICONDATA tnd; memset(&tnd, 0, notifyIconSize); - - memcpy(tnd.szInfo, message.utf16(), qMin(message.length() + 1, 256) * sizeof(wchar_t)); - memcpy(tnd.szInfoTitle, title.utf16(), qMin(title.length() + 1, 64) * sizeof(wchar_t)); + qStringToLimitedWCharArray(message, tnd.szInfo, 256); + qStringToLimitedWCharArray(title, tnd.szInfoTitle, 64); tnd.uID = q_uNOTIFYICONID; tnd.dwInfoFlags = iconFlag(type); tnd.cbSize = notifyIconSize; - tnd.hWnd = winId(); + tnd.hWnd = m_hwnd; tnd.uTimeout = uSecs; tnd.uFlags = NIF_INFO | NIF_SHOWTIP; - Q_ASSERT(testAttribute(Qt::WA_WState_Created)); - return Shell_NotifyIcon(NIM_MODIFY, &tnd); } @@ -234,12 +268,10 @@ bool QSystemTrayIconSys::trayMessage(DWORD msg) tnd.uID = q_uNOTIFYICONID; tnd.cbSize = notifyIconSize; - tnd.hWnd = winId(); + tnd.hWnd = m_hwnd; tnd.uFlags = NIF_SHOWTIP; tnd.uVersion = version; - Q_ASSERT(testAttribute(Qt::WA_WState_Created)); - if (msg == NIM_ADD || msg == NIM_MODIFY) { setIconContents(tnd); } @@ -252,25 +284,28 @@ bool QSystemTrayIconSys::trayMessage(DWORD msg) return success; } -void QSystemTrayIconSys::createIcon() +Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &); + +HICON QSystemTrayIconSys::createIcon() { + const HICON oldIcon = hIcon; hIcon = 0; - QIcon icon = q->icon(); + const QIcon icon = q->icon(); if (icon.isNull()) - return; - + return oldIcon; const int iconSizeX = GetSystemMetrics(SM_CXSMICON); const int iconSizeY = GetSystemMetrics(SM_CYSMICON); - QSize size = icon.actualSize(QSize(iconSizeX, iconSizeY)); - QPixmap pm = icon.pixmap(size); + const QSize size = icon.actualSize(QSize(iconSizeX, iconSizeY)); + const QPixmap pm = icon.pixmap(size); if (pm.isNull()) - return; - - hIcon = pm.toWinHICON(); + return oldIcon; + hIcon = qt_pixmapToWinHICON(pm); + return oldIcon; } bool QSystemTrayIconSys::winEvent( MSG *m, long *result ) { + *result = 0; switch(m->message) { case MYWM_NOTIFYICON: { @@ -324,22 +359,24 @@ bool QSystemTrayIconSys::winEvent( MSG *m, long *result ) break; } default: - if (m->message == MYWM_TASKBARCREATED) + if (m->message == MYWM_TASKBARCREATED) // self-registered message id. trayMessage(NIM_ADD); - else - return QWidget::winEvent(m, result); break; } - return 0; + return false; } void QSystemTrayIconPrivate::install_sys() { Q_Q(QSystemTrayIcon); if (!sys) { - sys = new QSystemTrayIconSys(q); - sys->createIcon(); - sys->trayMessage(NIM_ADD); + if (const HWND hwnd = createTrayIconMessageWindow()) { + sys = new QSystemTrayIconSys(hwnd, q); + sys->createIcon(); + sys->trayMessage(NIM_ADD); + } else { + qWarning("%s: The platform plugin failed to create a message window.", Q_FUNC_INFO); + } } } @@ -351,13 +388,14 @@ void QSystemTrayIconPrivate::install_sys() QRect QSystemTrayIconSys::findIconGeometry(const int iconId) { static PtrShell_NotifyIconGetRect Shell_NotifyIconGetRect = - (PtrShell_NotifyIconGetRect)QSystemLibrary::resolve(QLatin1String("shell32"), "Shell_NotifyIconGetRect"); + (PtrShell_NotifyIconGetRect)QSystemLibrary::resolve(QLatin1String("shell32"), + "Shell_NotifyIconGetRect"); if (Shell_NotifyIconGetRect) { Q_NOTIFYICONIDENTIFIER nid; memset(&nid, 0, sizeof(nid)); nid.cbSize = sizeof(nid); - nid.hWnd = winId(); + nid.hWnd = m_hwnd; nid.uID = iconId; RECT rect; @@ -421,7 +459,7 @@ QRect QSystemTrayIconSys::findIconGeometry(const int iconId) HWND currentIconHandle = (HWND) appData[0]; bool isHidden = buttonData.fsState & TBSTATE_HIDDEN; - if (currentIconHandle == winId() && + if (currentIconHandle == m_hwnd && currentIconId == iconId && !isHidden) { SendMessage(trayHandle, TB_GETITEMRECT, toolbarButton , (LPARAM)data); RECT iconRect = {0, 0}; @@ -441,27 +479,22 @@ QRect QSystemTrayIconSys::findIconGeometry(const int iconId) return ret; } -void QSystemTrayIconPrivate::showMessage_sys(const QString &title, const QString &message, QSystemTrayIcon::MessageIcon type, int timeOut) +void QSystemTrayIconPrivate::showMessage_sys(const QString &title, + const QString &messageIn, + QSystemTrayIcon::MessageIcon type, + int timeOut) { if (!sys || !allowsMessages()) return; - uint uSecs = 0; - if ( timeOut < 0) - uSecs = 10000; //10 sec default - else uSecs = (int)timeOut; - - //message is limited to 255 chars + NULL - QString messageString; + // 10 sec default + const uint uSecs = timeOut < 0 ? uint(10000) : uint(timeOut); + // For empty messages, ensures that they show when only title is set + QString message = messageIn; if (message.isEmpty() && !title.isEmpty()) - messageString = QLatin1Char(' '); //ensures that the message shows when only title is set - else - messageString = message.left(255) + QChar(); - - //title is limited to 63 chars + NULL - QString titleString = title.left(63) + QChar(); + message.append(QLatin1Char(' ')); - sys->showMessage(titleString, messageString, type, uSecs); + sys->showMessage(title, message, type, uSecs); } QRect QSystemTrayIconPrivate::geometry_sys() const @@ -487,9 +520,7 @@ void QSystemTrayIconPrivate::updateIcon_sys() if (!sys) return; - HICON hIconToDestroy = sys->hIcon; - - sys->createIcon(); + const HICON hIconToDestroy = sys->createIcon(); sys->trayMessage(NIM_MODIFY); if (hIconToDestroy) diff --git a/src/widgets/util/util.pri b/src/widgets/util/util.pri index abfb1d86fe..16765558f6 100644 --- a/src/widgets/util/util.pri +++ b/src/widgets/util/util.pri @@ -25,8 +25,13 @@ SOURCES += \ util/qflickgesture.cpp \ util/qundogroup.cpp \ util/qundostack.cpp \ - util/qundoview.cpp \ - util/qsystemtrayicon_qpa.cpp + util/qundoview.cpp + +win32:!wince* { + SOURCES += util/qsystemtrayicon_win.cpp +} else { + SOURCES += util/qsystemtrayicon_qpa.cpp +} # TODO false:!x11:mac { diff --git a/tests/auto/widgets/util/qsystemtrayicon/tst_qsystemtrayicon.cpp b/tests/auto/widgets/util/qsystemtrayicon/tst_qsystemtrayicon.cpp index cfafa9ea47..1f717727b0 100644 --- a/tests/auto/widgets/util/qsystemtrayicon/tst_qsystemtrayicon.cpp +++ b/tests/auto/widgets/util/qsystemtrayicon/tst_qsystemtrayicon.cpp @@ -120,14 +120,14 @@ void tst_QSystemTrayIcon::getSetCheck() void tst_QSystemTrayIcon::supportsMessages() { // ### fixme: Check platforms. - QEXPECT_FAIL("", "QTBUG-20978 QSystemTrayIcon is unimplemented for qpa", Abort); - -#if !defined(Q_WS_QWS) - QCOMPARE(QSystemTrayIcon::supportsMessages(), true ); +#if defined(Q_WS_QWS) + QCOMPARE(QSystemTrayIcon::supportsMessages(), false); +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + QCOMPARE(QSystemTrayIcon::supportsMessages(), true); #else - QCOMPARE(QSystemTrayIcon::supportsMessages(), false ); + QEXPECT_FAIL("", "QTBUG-20978 QSystemTrayIcon is unimplemented for qpa", Abort); + QCOMPARE(QSystemTrayIcon::supportsMessages(), true); #endif - } void tst_QSystemTrayIcon::lastWindowClosed() -- cgit v1.2.3 From cf36e571eea0c1befda2abfe2a177ee9f7fc2912 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 12 Mar 2012 17:16:35 +0100 Subject: Windows: Implement QWindowsIntegration::queryKeyboardModifiers() Use code from Qt 4.8. Change-Id: I32d220e04d13ee1e692c0c58268b827bcf519dc7 Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowsintegration.cpp | 6 ++++++ src/plugins/platforms/windows/qwindowsintegration.h | 2 ++ src/plugins/platforms/windows/qwindowskeymapper.cpp | 12 ++++++++++++ src/plugins/platforms/windows/qwindowskeymapper.h | 2 ++ 4 files changed, 22 insertions(+) diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index d03abe1d93..3c2ece58d0 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -56,6 +56,7 @@ #include "qwindowsdrag.h" #include "qwindowsinputcontext.h" #include "qwindowsaccessibility.h" +#include "qwindowskeymapper.h" #include #include @@ -321,6 +322,11 @@ QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) co return QPlatformIntegration::styleHint(hint); } +Qt::KeyboardModifiers QWindowsIntegration::queryKeyboardModifiers() const +{ + return QWindowsKeyMapper::queryKeyboardModifiers(); +} + QPlatformNativeInterface *QWindowsIntegration::nativeInterface() const { return &d->m_nativeInterface; diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index ba5fafbbb5..6dd65a02e4 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -73,6 +73,8 @@ public: QPlatformServices *services() const; virtual QVariant styleHint(StyleHint hint) const; + virtual Qt::KeyboardModifiers queryKeyboardModifiers() const; + static QWindowsIntegration *instance(); inline void emitScreenAdded(QPlatformScreen *s) { screenAdded(s); } diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 7b96603c44..4b5e95824a 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -1072,4 +1072,16 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms return result; } +Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers() +{ + Qt::KeyboardModifiers modifiers = Qt::NoModifier; + if (GetKeyState(VK_SHIFT) < 0) + modifiers |= Qt::ShiftModifier; + if (GetKeyState(VK_CONTROL) < 0) + modifiers |= Qt::ControlModifier; + if (GetKeyState(VK_MENU) < 0) + modifiers |= Qt::AltModifier; + return modifiers; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h index 483ff57942..b549422966 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.h +++ b/src/plugins/platforms/windows/qwindowskeymapper.h @@ -69,6 +69,8 @@ public: QWindow *keyGrabber() const { return m_keyGrabber; } void setKeyGrabber(QWindow *w) { m_keyGrabber = w; } + static Qt::KeyboardModifiers queryKeyboardModifiers(); + private: bool translateKeyEventInternal(QWindow *receiver, const MSG &msg, bool grab); void updateKeyMap(const MSG &msg); -- cgit v1.2.3 From 502673ab3a22938c5284b17c9abbb73d848c0005 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 9 Mar 2012 09:40:57 +0100 Subject: Re-add the Systray example. Remove its dependency on QtSvg by converting the icons to (optimized) png files. Change-Id: If63257938dc816d7ab76a3042b9ac88ef3d51b07 Reviewed-by: Friedemann Kleint --- examples/desktop/desktop.pro | 2 +- examples/desktop/systray/images/bad.png | Bin 0 -> 2496 bytes examples/desktop/systray/images/heart.png | Bin 0 -> 25780 bytes examples/desktop/systray/images/trash.png | Bin 0 -> 12128 bytes examples/desktop/systray/main.cpp | 63 +++++++ examples/desktop/systray/systray.pro | 14 ++ examples/desktop/systray/systray.qrc | 7 + examples/desktop/systray/window.cpp | 270 ++++++++++++++++++++++++++++++ examples/desktop/systray/window.h | 112 +++++++++++++ 9 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 examples/desktop/systray/images/bad.png create mode 100644 examples/desktop/systray/images/heart.png create mode 100644 examples/desktop/systray/images/trash.png create mode 100644 examples/desktop/systray/main.cpp create mode 100644 examples/desktop/systray/systray.pro create mode 100644 examples/desktop/systray/systray.qrc create mode 100644 examples/desktop/systray/window.cpp create mode 100644 examples/desktop/systray/window.h diff --git a/examples/desktop/desktop.pro b/examples/desktop/desktop.pro index fc232088e0..adfa51f130 100644 --- a/examples/desktop/desktop.pro +++ b/examples/desktop/desktop.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS = screenshot +SUBDIRS = screenshot systray # install target.path = $$[QT_INSTALL_EXAMPLES]/qtbase/desktop diff --git a/examples/desktop/systray/images/bad.png b/examples/desktop/systray/images/bad.png new file mode 100644 index 0000000000..c8701a241a Binary files /dev/null and b/examples/desktop/systray/images/bad.png differ diff --git a/examples/desktop/systray/images/heart.png b/examples/desktop/systray/images/heart.png new file mode 100644 index 0000000000..cee1302b7d Binary files /dev/null and b/examples/desktop/systray/images/heart.png differ diff --git a/examples/desktop/systray/images/trash.png b/examples/desktop/systray/images/trash.png new file mode 100644 index 0000000000..4c24db926d Binary files /dev/null and b/examples/desktop/systray/images/trash.png differ diff --git a/examples/desktop/systray/main.cpp b/examples/desktop/systray/main.cpp new file mode 100644 index 0000000000..6695113f71 --- /dev/null +++ b/examples/desktop/systray/main.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 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$ +** +****************************************************************************/ + +#include +#include + +#include "window.h" + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(systray); + + QApplication app(argc, argv); + + if (!QSystemTrayIcon::isSystemTrayAvailable()) { + QMessageBox::critical(0, QObject::tr("Systray"), + QObject::tr("I couldn't detect any system tray " + "on this system.")); + return 1; + } + QApplication::setQuitOnLastWindowClosed(false); + + Window window; + window.show(); + return app.exec(); +} diff --git a/examples/desktop/systray/systray.pro b/examples/desktop/systray/systray.pro new file mode 100644 index 0000000000..5fdcf1f9c8 --- /dev/null +++ b/examples/desktop/systray/systray.pro @@ -0,0 +1,14 @@ +HEADERS = window.h +SOURCES = main.cpp \ + window.cpp +RESOURCES = systray.qrc + +QT += widgets + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/qtbase/desktop/systray +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS systray.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qtbase/desktop/systray +INSTALLS += target sources + +simulator: warning(This example might not fully work on Simulator platform) diff --git a/examples/desktop/systray/systray.qrc b/examples/desktop/systray/systray.qrc new file mode 100644 index 0000000000..a8b6535849 --- /dev/null +++ b/examples/desktop/systray/systray.qrc @@ -0,0 +1,7 @@ + + + images/bad.png + images/heart.png + images/trash.png + + diff --git a/examples/desktop/systray/window.cpp b/examples/desktop/systray/window.cpp new file mode 100644 index 0000000000..73dc910d3b --- /dev/null +++ b/examples/desktop/systray/window.cpp @@ -0,0 +1,270 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "window.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//! [0] +Window::Window() +{ + createIconGroupBox(); + createMessageGroupBox(); + + iconLabel->setMinimumWidth(durationLabel->sizeHint().width()); + + createActions(); + createTrayIcon(); + + connect(showMessageButton, SIGNAL(clicked()), this, SLOT(showMessage())); + connect(showIconCheckBox, SIGNAL(toggled(bool)), + trayIcon, SLOT(setVisible(bool))); + connect(iconComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(setIcon(int))); + connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(messageClicked())); + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason))); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(iconGroupBox); + mainLayout->addWidget(messageGroupBox); + setLayout(mainLayout); + + iconComboBox->setCurrentIndex(1); + trayIcon->show(); + + setWindowTitle(tr("Systray")); + resize(400, 300); +} +//! [0] + +//! [1] +void Window::setVisible(bool visible) +{ + minimizeAction->setEnabled(visible); + maximizeAction->setEnabled(!isMaximized()); + restoreAction->setEnabled(isMaximized() || !visible); + QDialog::setVisible(visible); +} +//! [1] + +//! [2] +void Window::closeEvent(QCloseEvent *event) +{ + if (trayIcon->isVisible()) { + QMessageBox::information(this, tr("Systray"), + tr("The program will keep running in the " + "system tray. To terminate the program, " + "choose Quit in the context menu " + "of the system tray entry.")); + hide(); + event->ignore(); + } +} +//! [2] + +//! [3] +void Window::setIcon(int index) +{ + QIcon icon = iconComboBox->itemIcon(index); + trayIcon->setIcon(icon); + setWindowIcon(icon); + + trayIcon->setToolTip(iconComboBox->itemText(index)); +} +//! [3] + +//! [4] +void Window::iconActivated(QSystemTrayIcon::ActivationReason reason) +{ + switch (reason) { + case QSystemTrayIcon::Trigger: + case QSystemTrayIcon::DoubleClick: + iconComboBox->setCurrentIndex((iconComboBox->currentIndex() + 1) + % iconComboBox->count()); + break; + case QSystemTrayIcon::MiddleClick: + showMessage(); + break; + default: + ; + } +} +//! [4] + +//! [5] +void Window::showMessage() +{ + QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::MessageIcon( + typeComboBox->itemData(typeComboBox->currentIndex()).toInt()); + trayIcon->showMessage(titleEdit->text(), bodyEdit->toPlainText(), icon, + durationSpinBox->value() * 1000); +} +//! [5] + +//! [6] +void Window::messageClicked() +{ + QMessageBox::information(0, tr("Systray"), + tr("Sorry, I already gave what help I could.\n" + "Maybe you should try asking a human?")); +} +//! [6] + +void Window::createIconGroupBox() +{ + iconGroupBox = new QGroupBox(tr("Tray Icon")); + + iconLabel = new QLabel("Icon:"); + + iconComboBox = new QComboBox; + iconComboBox->addItem(QIcon(":/images/bad.svg"), tr("Bad")); + iconComboBox->addItem(QIcon(":/images/heart.svg"), tr("Heart")); + iconComboBox->addItem(QIcon(":/images/trash.svg"), tr("Trash")); + + showIconCheckBox = new QCheckBox(tr("Show icon")); + showIconCheckBox->setChecked(true); + + QHBoxLayout *iconLayout = new QHBoxLayout; + iconLayout->addWidget(iconLabel); + iconLayout->addWidget(iconComboBox); + iconLayout->addStretch(); + iconLayout->addWidget(showIconCheckBox); + iconGroupBox->setLayout(iconLayout); +} + +void Window::createMessageGroupBox() +{ + messageGroupBox = new QGroupBox(tr("Balloon Message")); + + typeLabel = new QLabel(tr("Type:")); + + typeComboBox = new QComboBox; + typeComboBox->addItem(tr("None"), QSystemTrayIcon::NoIcon); + typeComboBox->addItem(style()->standardIcon( + QStyle::SP_MessageBoxInformation), tr("Information"), + QSystemTrayIcon::Information); + typeComboBox->addItem(style()->standardIcon( + QStyle::SP_MessageBoxWarning), tr("Warning"), + QSystemTrayIcon::Warning); + typeComboBox->addItem(style()->standardIcon( + QStyle::SP_MessageBoxCritical), tr("Critical"), + QSystemTrayIcon::Critical); + typeComboBox->setCurrentIndex(1); + + durationLabel = new QLabel(tr("Duration:")); + + durationSpinBox = new QSpinBox; + durationSpinBox->setRange(5, 60); + durationSpinBox->setSuffix(" s"); + durationSpinBox->setValue(15); + + durationWarningLabel = new QLabel(tr("(some systems might ignore this " + "hint)")); + durationWarningLabel->setIndent(10); + + titleLabel = new QLabel(tr("Title:")); + + titleEdit = new QLineEdit(tr("Cannot connect to network")); + + bodyLabel = new QLabel(tr("Body:")); + + bodyEdit = new QTextEdit; + bodyEdit->setPlainText(tr("Don't believe me. Honestly, I don't have a " + "clue.\nClick this balloon for details.")); + + showMessageButton = new QPushButton(tr("Show Message")); + showMessageButton->setDefault(true); + + QGridLayout *messageLayout = new QGridLayout; + messageLayout->addWidget(typeLabel, 0, 0); + messageLayout->addWidget(typeComboBox, 0, 1, 1, 2); + messageLayout->addWidget(durationLabel, 1, 0); + messageLayout->addWidget(durationSpinBox, 1, 1); + messageLayout->addWidget(durationWarningLabel, 1, 2, 1, 3); + messageLayout->addWidget(titleLabel, 2, 0); + messageLayout->addWidget(titleEdit, 2, 1, 1, 4); + messageLayout->addWidget(bodyLabel, 3, 0); + messageLayout->addWidget(bodyEdit, 3, 1, 2, 4); + messageLayout->addWidget(showMessageButton, 5, 4); + messageLayout->setColumnStretch(3, 1); + messageLayout->setRowStretch(4, 1); + messageGroupBox->setLayout(messageLayout); +} + +void Window::createActions() +{ + minimizeAction = new QAction(tr("Mi&nimize"), this); + connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide())); + + maximizeAction = new QAction(tr("Ma&ximize"), this); + connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized())); + + restoreAction = new QAction(tr("&Restore"), this); + connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal())); + + quitAction = new QAction(tr("&Quit"), this); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); +} + +void Window::createTrayIcon() +{ + trayIconMenu = new QMenu(this); + trayIconMenu->addAction(minimizeAction); + trayIconMenu->addAction(maximizeAction); + trayIconMenu->addAction(restoreAction); + trayIconMenu->addSeparator(); + trayIconMenu->addAction(quitAction); + + trayIcon = new QSystemTrayIcon(this); + trayIcon->setContextMenu(trayIconMenu); +} diff --git a/examples/desktop/systray/window.h b/examples/desktop/systray/window.h new file mode 100644 index 0000000000..80b7a20754 --- /dev/null +++ b/examples/desktop/systray/window.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef WINDOW_H +#define WINDOW_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QAction; +class QCheckBox; +class QComboBox; +class QGroupBox; +class QLabel; +class QLineEdit; +class QMenu; +class QPushButton; +class QSpinBox; +class QTextEdit; +QT_END_NAMESPACE + +//! [0] +class Window : public QDialog +{ + Q_OBJECT + +public: + Window(); + + void setVisible(bool visible); + +protected: + void closeEvent(QCloseEvent *event); + +private slots: + void setIcon(int index); + void iconActivated(QSystemTrayIcon::ActivationReason reason); + void showMessage(); + void messageClicked(); + +private: + void createIconGroupBox(); + void createMessageGroupBox(); + void createActions(); + void createTrayIcon(); + + QGroupBox *iconGroupBox; + QLabel *iconLabel; + QComboBox *iconComboBox; + QCheckBox *showIconCheckBox; + + QGroupBox *messageGroupBox; + QLabel *typeLabel; + QLabel *durationLabel; + QLabel *durationWarningLabel; + QLabel *titleLabel; + QLabel *bodyLabel; + QComboBox *typeComboBox; + QSpinBox *durationSpinBox; + QLineEdit *titleEdit; + QTextEdit *bodyEdit; + QPushButton *showMessageButton; + + QAction *minimizeAction; + QAction *maximizeAction; + QAction *restoreAction; + QAction *quitAction; + + QSystemTrayIcon *trayIcon; + QMenu *trayIconMenu; +}; +//! [0] + +#endif -- cgit v1.2.3 From b5b41c18345719612e5411cc482466d2dbafdaf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lind?= Date: Mon, 12 Mar 2012 12:04:54 +0100 Subject: Remove redundant wayland stuff from QtBase Config checks are done in the module. We pick up the pkg-config stuff also in the module. There shouldn't be a need to do this in configure anyway Change-Id: I9ef73760511c6b684c6cd5dd13e7e581c588e7aa Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- config.tests/qpa/wayland/wayland.cpp | 46 ---------------------- config.tests/qpa/wayland/wayland.pro | 12 ------ configure | 74 +++++++++--------------------------- 3 files changed, 18 insertions(+), 114 deletions(-) delete mode 100644 config.tests/qpa/wayland/wayland.cpp delete mode 100644 config.tests/qpa/wayland/wayland.pro diff --git a/config.tests/qpa/wayland/wayland.cpp b/config.tests/qpa/wayland/wayland.cpp deleted file mode 100644 index c502d22ef3..0000000000 --- a/config.tests/qpa/wayland/wayland.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the config.tests 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 - -int main(int, char **) -{ - return 0; -} diff --git a/config.tests/qpa/wayland/wayland.pro b/config.tests/qpa/wayland/wayland.pro deleted file mode 100644 index 6d85073b91..0000000000 --- a/config.tests/qpa/wayland/wayland.pro +++ /dev/null @@ -1,12 +0,0 @@ -SOURCES = wayland.cpp -CONFIG -= qt - -for(d, QMAKE_INCDIR_WAYLAND) { - exists($$d):INCLUDEPATH += $$d -} - -for(p, QMAKE_LIBDIR_WAYLAND) { - exists($$p):LIBS += -L$$p -} - -LIBS += $$QMAKE_LIBS_WAYLAND diff --git a/configure b/configure index 9a202357e8..66c5f1a06d 100755 --- a/configure +++ b/configure @@ -702,8 +702,8 @@ CFG_XINPUT=runtime CFG_XKB=auto CFG_XCB=auto CFG_XCB_LIMITED=yes -CFG_WAYLAND=auto CFG_LIBUDEV=auto +CFG_OBSOLETE_WAYLAND=no CFG_EVDEV=auto CFG_NIS=auto CFG_CUPS=auto @@ -887,7 +887,7 @@ while [ "$#" -gt 0 ]; do VAL=no ;; #Qt style yes options - -profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-xinput2|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-xcb|-wayland|-nis|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-debug-and-release|-exceptions|-harfbuzz|-prefix-install|-silent|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-phonon-backend|-audio-backend|-declarative-debug|-javascript-jit|-rpath|-force-pkg-config|-icu|-force-asserts|-testcocoon) + -profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-xinput2|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-xcb|-nis|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-debug-and-release|-exceptions|-harfbuzz|-prefix-install|-silent|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-phonon-backend|-audio-backend|-declarative-debug|-javascript-jit|-rpath|-force-pkg-config|-icu|-force-asserts|-testcocoon) VAR=`echo $1 | sed "s,^-\(.*\),\1,"` VAL=yes ;; @@ -1655,11 +1655,7 @@ while [ "$#" -gt 0 ]; do fi ;; wayland) - if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then - CFG_WAYLAND="$VAL" - else - UNKNOWN_OPT=yes - fi + CFG_OBSOLETE_WAYLAND=yes ;; libudev) if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then @@ -3014,13 +3010,6 @@ if [ "$OPT_HELP" = "yes" ]; then XCBN=" " fi - if [ "$CFG_WAYLAND" = "no" ]; then - XWY=" " - XWN="*" - else - XWY="*" - XWN=" " - fi if [ "$CFG_XINPUT2" = "no" ]; then X2Y=" " X2N="*" @@ -3343,9 +3332,6 @@ if [ "$PLATFORM_X11" = "yes" -o "$PLATFORM_QPA" = "yes" ]; then $XCBN -no-xcb ............ Do not compile Xcb (X protocol C-language Binding) support. $XCBY -xcb ............... Compile Xcb support. - $XWN -no-wayland......... Do not compile Wayland support. - $XWY -wayland .......... Compile Wayland support. - EOF fi # X11 @@ -5108,28 +5094,8 @@ if [ "$PLATFORM_QPA" = "yes" ]; then fi # Save these for a check later - ORIG_CFG_WAYLAND="$CFG_WAYLAND" ORIG_CFG_XCB="$CFG_XCB" - if [ "$CFG_WAYLAND" != "no" ]; then - if [ -n "$PKG_CONFIG" ] && $PKG_CONFIG --exists wayland-client 2>/dev/null; then - QMAKE_CFLAGS_WAYLAND=`$PKG_CONFIG --cflags wayland-client 2>/dev/null` - QMAKE_LIBS_WAYLAND=`$PKG_CONFIG --libs wayland-client 2>/dev/null` - QMAKE_INCDIR_WAYLAND=`$PKG_CONFIG --cflags-only-I wayland-client 2>/dev/null | sed -e 's,^-I,,g' -e 's, -I, ,g'` - QMAKE_LIBDIR_WAYLAND=`$PKG_CONFIG --libs-only-L wayland-client 2>/dev/null | sed -e 's,^-L,,g' -e 's, -L, ,g'` - fi - if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/qpa/wayland "Wayland" $L_FLAGS $I_FLAGS $l_FLAGS $QMAKE_CFLAGS_WAYLAND $QMAKE_LIBS_WAYLAND; then - CFG_WAYLAND=yes - QT_CONFIG="$QT_CONFIG wayland" - elif [ "$CFG_WAYLAND" = "yes" ]; then - echo "The Wayland functionality test failed!" - exit 1 - else - CFG_WAYLAND=no - QMakeVar add DEFINES QT_NO_WAYLAND - fi - fi - if [ "$CFG_LIBUDEV" != "no" ]; then if [ -n "$PKG_CONFIG" ] && $PKG_CONFIG --exists libudev 2>/dev/null; then QMAKE_INCDIR_LIBUDEV=`$PKG_CONFIG --cflags-only-I libudev 2>/dev/null | sed -e 's,^-I,,g' -e 's, -I, ,g'` @@ -5240,28 +5206,12 @@ if [ "$PLATFORM_QPA" = "yes" ]; then if [ -n "$PKG_CONFIG" ] && $PKG_CONFIG --exists xkbcommon 2>/dev/null; then QMAKE_CFLAGS_XKBCOMMON="`$PKG_CONFIG --cflags xkbcommon 2>/dev/null`" QMAKE_LIBS_XKBCOMMON="`$PKG_CONFIG --libs xkbcommon 2>/dev/null`" - if [ "$CFG_WAYLAND" = "yes" ]; then - QMAKE_CFLAGS_WAYLAND="$QMAKE_CFLAGS_WAYLAND $QMAKE_CFLAGS_XKBCOMMON" - QMAKE_LIBS_WAYLAND="$QMAKE_LIBS_WAYLAND $QMAKE_LIBS_XKBCOMMON" - fi QMAKE_CFLAGS_XCB="$QMAKE_CFLAGS_XCB $QMAKE_CFLAGS_XKBCOMMON" QMAKE_LIBS_XCB="$QMAKE_LIBS_XCB $QMAKE_LIBS_XKBCOMMON" else - if [ "$CFG_WAYLAND" = "yes" ]; then - QMAKE_DEFINES_WAYLAND=QT_NO_WAYLAND_XKB - fi QMAKE_DEFINES_XCB=QT_NO_XCB_XKB fi - # QMake variables set here override those in the mkspec. Therefore we only set the variables here if they are not zero. - if [ -n "$QMAKE_CFLAGS_WAYLAND" ] || [ -n "$QMAKE_LIBS_WAYLAND" ]; then - QMakeVar set QMAKE_CFLAGS_WAYLAND "$QMAKE_CFLAGS_WAYLAND" - QMakeVar set QMAKE_INCDIR_WAYLAND "$QMAKE_INCDIR_WAYLAND" - QMakeVar set QMAKE_LIBS_WAYLAND "$QMAKE_LIBS_WAYLAND" - QMakeVar set QMAKE_LIBDIR_WAYLAND "$QMAKE_LIBDIR_WAYLAND" - QMakeVar set QMAKE_DEFINES_WAYLAND " $QMAKE_DEFINES_WAYLAND" - fi - if [ -n "$QMAKE_CFLAGS_XCB" ] || [ -n "$QMAKE_LIBS_XCB" ]; then QMakeVar set QMAKE_CFLAGS_XCB "$QMAKE_CFLAGS_XCB" QMakeVar set QMAKE_LIBS_XCB "$QMAKE_LIBS_XCB" @@ -5277,11 +5227,11 @@ if [ "$PLATFORM_QPA" = "yes" ]; then fi if [ "$PLATFORM_QPA" = "yes" ] && [ "$BUILD_ON_MAC" = "no" ] && [ "$XPLATFORM_MINGW" = "no" ]; then - if [ "$CFG_XCB" = "no" ] && [ "$CFG_WAYLAND" = "no" ]; then - if [ "$ORIG_CFG_XCB" = "auto" ] || [ "$ORIG_CFG_WAYLAND" = "auto" ]; then + if [ "$CFG_XCB" = "no" ]; then + if [ "$ORIG_CFG_XCB" = "auto" ]; then echo "No QPA platform plugin enabled!" echo " If you really want to build without a QPA platform plugin you must pass" - echo " -no-xcb and -no-wayland to configure. Doing this will produce a Qt that" + echo " -no-xcb. Doing this will produce a Qt that" echo " cannot run GUI applications." echo " The dependencies needed for xcb to build are listed in" echo " src/plugins/platforms/xcb/README" @@ -7080,6 +7030,18 @@ cat <