diff options
32 files changed, 1090 insertions, 89 deletions
@@ -7163,7 +7163,7 @@ if [ "$CFG_WEBKIT" = "auto" ]; then fi if [ "$CFG_WEBKIT" = "yes" ]; then - QT_CONFIG="$QT_CONFIG webkit" + # Don't add "webkit" to QT_CONFIG here - it injects itself via the module. # The reason we set CFG_WEBKIT, is such that the printed overview of what will be enabled, shows correctly. CFG_WEBKIT="yes" else diff --git a/doc/src/getting-started/examples.qdoc b/doc/src/getting-started/examples.qdoc index 708c44e..e8c85e6 100644 --- a/doc/src/getting-started/examples.qdoc +++ b/doc/src/getting-started/examples.qdoc @@ -255,6 +255,7 @@ \o \l{graphicsview/flowlayout}{Flow Layout} \o \l{graphicsview/simpleanchorlayout}{Simple Anchor Layout} \o \l{graphicsview/weatheranchorlayout}{Weather Anchor Layout} + \o \l{graphicsview/basicgraphicslayouts}{Basic Graphics Layouts} \endlist Some examples demonstrate the use of graphics effects with canvas items. @@ -471,6 +472,7 @@ \o \l{network/googlesuggest}{Google Suggest} \o \l{network/bearercloud}{Bearer Cloud}\raisedaster \o \l{network/bearermonitor}{Bearer Monitor} + \o \l{network/securesocketclient}{Secure Socket Client} \endlist Examples marked with an asterisk (*) are fully documented. @@ -609,6 +611,7 @@ \o \l{sql/querymodel}{Query Model} \o \l{sql/relationaltablemodel}{Relational Table Model} \o \l{sql/tablemodel}{Table Model} + \o \l{sql/masterdetail}{Master Detail} \o \l{sql/sqlwidgetmapper}{SQL Widget Mapper}\raisedaster \endlist @@ -633,6 +636,7 @@ \o \l{xml/streambookmarks}{QXmlStream Bookmarks}\raisedaster \o \l{xml/rsslisting}{RSS-Listing} \o \l{xml/xmlstreamlint}{XML Stream Lint Example}\raisedaster + \o \l{xml/htmlinfo}{XML HTML Info} \endlist The XQuery/XPath and XML Schema engines in the QtXmlPatterns modules diff --git a/doc/src/platforms/x11overlays.qdoc b/doc/src/platforms/x11overlays.qdoc index 1a03ea6..949a500 100644 --- a/doc/src/platforms/x11overlays.qdoc +++ b/doc/src/platforms/x11overlays.qdoc @@ -28,6 +28,7 @@ /*! \page x11overlays.html \title How to Use X11 Overlays with Qt + \ingroup best-practices X11 overlays are a powerful mechanism for drawing annotations etc., on top of an image without destroying it, thus saving diff --git a/mkspecs/modules/README b/mkspecs/modules/README new file mode 100644 index 0000000..f095982 --- /dev/null +++ b/mkspecs/modules/README @@ -0,0 +1,3 @@ +Externally provided Qt modules may drop a qmake file here to become part of +the current Qt configuration. The file name must follow the pattern +"qt_<module>.pri". It must contain a "QT_CONFIG += <module>" statement. diff --git a/mkspecs/modules/qt_webkit_version.pri b/mkspecs/modules/qt_webkit_version.pri deleted file mode 100644 index ffd192c..0000000 --- a/mkspecs/modules/qt_webkit_version.pri +++ /dev/null @@ -1,4 +0,0 @@ -QT_WEBKIT_VERSION = 4.7.0 -QT_WEBKIT_MAJOR_VERSION = 4 -QT_WEBKIT_MINOR_VERSION = 7 -QT_WEBKIT_PATCH_VERSION = 0 diff --git a/projects.pro b/projects.pro index 373b049..f94e1de 100644 --- a/projects.pro +++ b/projects.pro @@ -159,11 +159,13 @@ INSTALLS += qmake #mkspecs mkspecs.path=$$[QT_INSTALL_DATA]/mkspecs -mkspecs.files=$$QT_BUILD_TREE/mkspecs/qconfig.pri $$QT_SOURCE_TREE/mkspecs/* +mkspecs.files=$$QT_BUILD_TREE/mkspecs/qconfig.pri $$files($$QT_SOURCE_TREE/mkspecs/*) +mkspecs.files -= $$QT_SOURCE_TREE/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 } win32:!equals(QT_BUILD_TREE, $$QT_SOURCE_TREE) { # When shadow building on Windows, the default mkspec only exists in the build tree. diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 852471d..03732ba 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -466,14 +466,37 @@ MakefileGenerator::init() if(!project->isEmpty("QMAKE_SUBSTITUTES")) { const QStringList &subs = v["QMAKE_SUBSTITUTES"]; for(int i = 0; i < subs.size(); ++i) { - if(!subs.at(i).endsWith(".in")) { - warn_msg(WarnLogic, "Substitute '%s' does not end with '.in'", - subs.at(i).toLatin1().constData()); - continue; + QString inn = subs.at(i) + ".input", outn = subs.at(i) + ".output"; + if (v.contains(inn) || v.contains(outn)) { + if (!v.contains(inn) || !v.contains(outn)) { + warn_msg(WarnLogic, "Substitute '%s' has only one of .input and .output", + subs.at(i).toLatin1().constData()); + continue; + } + const QStringList &tinn = v[inn], &toutn = v[outn]; + if (tinn.length() != 1) { + warn_msg(WarnLogic, "Substitute '%s.input' does not have exactly one value", + subs.at(i).toLatin1().constData()); + continue; + } + if (toutn.length() != 1) { + warn_msg(WarnLogic, "Substitute '%s.output' does not have exactly one value", + subs.at(i).toLatin1().constData()); + continue; + } + inn = tinn.first(); + outn = toutn.first(); + } else { + inn = subs.at(i); + if(!inn.endsWith(".in")) { + warn_msg(WarnLogic, "Substitute '%s' does not end with '.in'", + inn.toLatin1().constData()); + continue; + } + outn = inn.left(inn.length()-3); } - QFile in(fileFixify(subs.at(i))); - QFile out(fileFixify(subs.at(i).left(subs.at(i).length()-3), - qmake_getpwd(), Option::output_dir)); + QFile in(fileFixify(inn)); + QFile out(fileFixify(outn, qmake_getpwd(), Option::output_dir)); if(in.open(QFile::ReadOnly)) { QString contents; QStack<int> state; diff --git a/src/3rdparty/webkit/WebCore/WebCore.pro b/src/3rdparty/webkit/WebCore/WebCore.pro index 2047143..ac0c47c 100644 --- a/src/3rdparty/webkit/WebCore/WebCore.pro +++ b/src/3rdparty/webkit/WebCore/WebCore.pro @@ -82,7 +82,7 @@ CONFIG(QTDIR_build) { symbian: TARGET =$$TARGET$${QT_LIBINFIX} } moduleFile=$$PWD/../WebKit/qt/qt_webkit_version.pri -include($$moduleFile) +isEmpty(QT_BUILD_TREE):include($$moduleFile) VERSION = $${QT_WEBKIT_MAJOR_VERSION}.$${QT_WEBKIT_MINOR_VERSION}.$${QT_WEBKIT_PATCH_VERSION} unix { diff --git a/src/3rdparty/webkit/WebKit.pro b/src/3rdparty/webkit/WebKit.pro index c7df391..ef251c5 100644 --- a/src/3rdparty/webkit/WebKit.pro +++ b/src/3rdparty/webkit/WebKit.pro @@ -34,3 +34,9 @@ symbian { } include(WebKit/qt/docs/docs.pri) + +!isEmpty(QT_BUILD_TREE) { + QMAKE_SUBSTITUTES += qt_webkit_version + qt_webkit_version.input = WebKit/qt/qt_webkit_version.pri + qt_webkit_version.output = $$QT_BUILD_TREE/mkspecs/modules/qt_webkit_version.pri +} diff --git a/src/3rdparty/webkit/WebKit/qt/qt_webkit_version.pri b/src/3rdparty/webkit/WebKit/qt/qt_webkit_version.pri index d8cf06c..4594d1e 100644 --- a/src/3rdparty/webkit/WebKit/qt/qt_webkit_version.pri +++ b/src/3rdparty/webkit/WebKit/qt/qt_webkit_version.pri @@ -2,4 +2,4 @@ QT_WEBKIT_VERSION = 4.7.0 QT_WEBKIT_MAJOR_VERSION = 4 QT_WEBKIT_MINOR_VERSION = 7 QT_WEBKIT_PATCH_VERSION = 0 -QT_CONFIG *= webkit +QT_CONFIG += webkit diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index a98ce6f..a02f3ac 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -5740,16 +5740,11 @@ void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent) } if (sceneTouchEvent->deviceType() == QTouchEvent::TouchScreen) { - // on touch-screens, combine this touch point with the closest one we find if it - // is a a direct descendent or ancestor ( + // on touch-screens, combine this touch point with the closest one we find int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos()); QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId); - if (!item - || (closestItem - && (item->isAncestorOf(closestItem) - || closestItem->isAncestorOf(item)))) { + if (!item || (closestItem && cachedItemsUnderMouse.contains(closestItem))) item = closestItem; - } } if (!item) continue; diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 8560214..8347626 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -782,6 +782,8 @@ static JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState*, JSC::JSOb static JSC::JSValue JSC_HOST_CALL functionQsTranslateNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&); static JSC::JSValue JSC_HOST_CALL functionQsTr(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&); static JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&); +static JSC::JSValue JSC_HOST_CALL functionQsTrId(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&); +static JSC::JSValue JSC_HOST_CALL functionQsTrIdNoOp(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&); JSC::JSValue JSC_HOST_CALL functionQsTranslate(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args) { @@ -892,6 +894,28 @@ JSC::JSValue JSC_HOST_CALL functionQsTrNoOp(JSC::ExecState *, JSC::JSObject*, JS return args.at(0); } +JSC::JSValue JSC_HOST_CALL functionQsTrId(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args) +{ + if (args.size() < 1) + return JSC::throwError(exec, JSC::GeneralError, "qsTrId() requires at least one argument"); + if (!args.at(0).isString()) + return JSC::throwError(exec, JSC::TypeError, "qsTrId(): first argument (id) must be a string"); + if ((args.size() > 1) && !args.at(1).isNumber()) + return JSC::throwError(exec, JSC::TypeError, "qsTrId(): second argument (n) must be a number"); + JSC::UString id = args.at(0).toString(exec); + int n = -1; + if (args.size() > 1) + n = args.at(1).toInt32(exec); + return JSC::jsString(exec, qtTrId(QScript::convertToLatin1(id).constData(), n)); +} + +JSC::JSValue JSC_HOST_CALL functionQsTrIdNoOp(JSC::ExecState *, JSC::JSObject*, JSC::JSValue, const JSC::ArgList &args) +{ + if (args.size() < 1) + return JSC::jsUndefined(); + return args.at(0); +} + static JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState*, JSC::JSObject*, JSC::JSValue, const JSC::ArgList&); JSC::JSValue JSC_HOST_CALL stringProtoFuncArg(JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisObject, const JSC::ArgList &args) @@ -3435,6 +3459,8 @@ void QScriptEngine::registerCustomType(int type, MarshalFunction mf, \row \o QT_TR_NOOP() \o QT_TR_NOOP() \row \o qsTranslate() \o QCoreApplication::translate() \row \o QT_TRANSLATE_NOOP() \o QT_TRANSLATE_NOOP() + \row \o qsTrId() (since 4.7) \o qtTrId() + \row \o QT_TRID_NOOP() (since 4.7) \o QT_TRID_NOOP() \endtable \sa {Internationalization with Qt} @@ -3453,6 +3479,8 @@ void QScriptEngine::installTranslatorFunctions(const QScriptValue &object) JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 2, JSC::Identifier(exec, "QT_TRANSLATE_NOOP"), QScript::functionQsTranslateNoOp)); JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 3, JSC::Identifier(exec, "qsTr"), QScript::functionQsTr)); JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "QT_TR_NOOP"), QScript::functionQsTrNoOp)); + JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "qsTrId"), QScript::functionQsTrId)); + JSC::asObject(jscObject)->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "QT_TRID_NOOP"), QScript::functionQsTrIdNoOp)); glob->stringPrototype()->putDirectFunction(exec, new (exec)JSC::NativeFunctionWrapper(exec, glob->prototypeFunctionStructure(), 1, JSC::Identifier(exec, "arg"), QScript::stringProtoFuncArg)); } diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs/main.js b/tests/auto/linguist/lupdate/testdata/good/parsejs/main.js new file mode 100644 index 0000000..9f61cea --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs/main.js @@ -0,0 +1,91 @@ +qsTr("One"); +qsTranslate("FooContext", "Two"); + +var greeting_strings = [ + QT_TR_NOOP("Hello"), + QT_TRANSLATE_NOOP("FooContext", "Goodbye") +]; + +qsTr("One", "not the same one"); + +//: My first comment. +qsTr("See comment"); + +//: My second comment. +qsTranslate("BarContext", "See other comment"); + +//: My third comment +//: spans two lines. +qsTr("The comment explains it all"); + +//: My fourth comment +//: spans a whopping +//: three lines. +qsTranslate("BazContext", "It should be clear by now"); + +/*: C-style comment. */ +qsTr("I love C++"); + +/*: Another C-style comment. */ +qsTranslate("FooContext", "I really love C++"); + +/*: C-style comment, followed by */ +/*: another one. */ +qsTr("Qt is the best"); + +/*: Another C-style comment, followed by */ +/*: yet another one. */ +qsTranslate("BarContext", "Qt is the very best"); + +// This comment doesn't have any effect. +qsTr("The comment had no effect"); + +// This comment doesn't have any effect either. +qsTranslate("BazContext", "The comment had no effect, really"); + +/* This C-style comment doesn't have any effect. */ +qsTr("No comment to your comment"); + +/* This C-style comment doesn't have any effect either. */ +qsTranslate("FooContext", "I refuse to comment on that"); + +//= id_foo +qsTr("This string has an identifier"); + +//= id_bar +qsTranslate("BarContext", "This string also has an identifier"); + +//~ loc-blank False +qsTr("This string has meta-data"); + +//~ loc-layout_id foo_dialog +qsTranslate("BazContext", "This string also has meta-data"); + +// This comment is to be ignored. +//: This is a comment for the translator. +//= id_baz +//~ foo 123 +//~ magic-stuff This means something special. +qsTr("This string has a lot of information"); + +// This comment is also to be ignored. +//: This is another comment for the translator. +//= id_babar +//~ foo-bar Important stuff +//~ needle-in-haystack Found +//~ overflow True +qsTranslate("FooContext", "This string has even more information"); + +qsTr("This string has disambiguation", "Disambiguation"); + +qsTranslate("BarContext", "This string also has disambiguation", "Another disambiguation"); + +qsTr("This string contains plurals", "", 10); + +qsTrId("qtn_foo_bar"); + +var more_greeting_strings = [ QT_TRID_NOOP("qtn_needle"), QT_TRID_NOOP("qtn_haystack") ]; + +//: qsTrId() with comment, meta-data and plurals. +//~ well-tested True +qsTrId("qtn_bar_baz", 10); diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs/project.pro b/tests/auto/linguist/lupdate/testdata/good/parsejs/project.pro new file mode 100644 index 0000000..d549039 --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs/project.pro @@ -0,0 +1,3 @@ +SOURCES += main.js + +TRANSLATIONS = project.ts diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parsejs/project.ts.result new file mode 100644 index 0000000..d03c713 --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs/project.ts.result @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0"> +<context> + <name></name> + <message id="qtn_foo_bar"> + <location filename="main.js" line="85"/> + <source></source> + <translation type="unfinished"></translation> + </message> + <message id="qtn_needle"> + <location filename="main.js" line="87"/> + <source></source> + <translation type="unfinished"></translation> + </message> + <message id="qtn_haystack"> + <location filename="main.js" line="87"/> + <source></source> + <translation type="unfinished"></translation> + </message> + <message id="qtn_bar_baz" numerus="yes"> + <location filename="main.js" line="91"/> + <source></source> + <extracomment>qsTrId() with comment, meta-data and plurals.</extracomment> + <translation type="unfinished"> + <numerusform></numerusform> + </translation> + <extra-well-tested>True</extra-well-tested> + </message> +</context> +<context> + <name>BarContext</name> + <message> + <location filename="main.js" line="15"/> + <source>See other comment</source> + <extracomment>My second comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="38"/> + <source>Qt is the very best</source> + <extracomment>Another C-style comment, followed by yet another one.</extracomment> + <translation type="unfinished"></translation> + </message> + <message id="id_bar"> + <location filename="main.js" line="56"/> + <source>This string also has an identifier</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="81"/> + <source>This string also has disambiguation</source> + <comment>Another disambiguation</comment> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>BazContext</name> + <message> + <location filename="main.js" line="24"/> + <source>It should be clear by now</source> + <extracomment>My fourth comment spans a whopping three lines.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="44"/> + <source>The comment had no effect, really</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="62"/> + <source>This string also has meta-data</source> + <translation type="unfinished"></translation> + <extra-loc-layout_id>foo_dialog</extra-loc-layout_id> + </message> +</context> +<context> + <name>FooContext</name> + <message> + <location filename="main.js" line="2"/> + <source>Two</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="6"/> + <source>Goodbye</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="30"/> + <source>I really love C++</source> + <extracomment>Another C-style comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="50"/> + <source>I refuse to comment on that</source> + <translation type="unfinished"></translation> + </message> + <message id="id_babar"> + <location filename="main.js" line="77"/> + <source>This string has even more information</source> + <extracomment>This is another comment for the translator.</extracomment> + <translation type="unfinished"></translation> + <extra-needle-in-haystack>Found</extra-needle-in-haystack> + <extra-overflow>True</extra-overflow> + <extra-foo-bar>Important stuff</extra-foo-bar> + </message> +</context> +<context> + <name>main</name> + <message> + <location filename="main.js" line="1"/> + <source>One</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="5"/> + <source>Hello</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="9"/> + <source>One</source> + <comment>not the same one</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="12"/> + <source>See comment</source> + <extracomment>My first comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="19"/> + <source>The comment explains it all</source> + <extracomment>My third comment spans two lines.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="27"/> + <source>I love C++</source> + <extracomment>C-style comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="34"/> + <source>Qt is the best</source> + <extracomment>C-style comment, followed by another one.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="41"/> + <source>The comment had no effect</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="47"/> + <source>No comment to your comment</source> + <translation type="unfinished"></translation> + </message> + <message id="id_foo"> + <location filename="main.js" line="53"/> + <source>This string has an identifier</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="59"/> + <source>This string has meta-data</source> + <translation type="unfinished"></translation> + <extra-loc-blank>False</extra-loc-blank> + </message> + <message id="id_baz"> + <location filename="main.js" line="69"/> + <source>This string has a lot of information</source> + <extracomment>This is a comment for the translator.</extracomment> + <translation type="unfinished"></translation> + <extra-foo>123</extra-foo> + <extra-magic-stuff>This means something special.</extra-magic-stuff> + </message> + <message> + <location filename="main.js" line="79"/> + <source>This string has disambiguation</source> + <comment>Disambiguation</comment> + <translation type="unfinished"></translation> + </message> + <message numerus="yes"> + <location filename="main.js" line="83"/> + <source>This string contains plurals</source> + <translation type="unfinished"> + <numerusform></numerusform> + </translation> + </message> +</context> +</TS> diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs2/expectedoutput.txt b/tests/auto/linguist/lupdate/testdata/good/parsejs2/expectedoutput.txt new file mode 100644 index 0000000..d6c977f --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs2/expectedoutput.txt @@ -0,0 +1,29 @@ +.*/lupdate/testdata/good/parsejs2/main.js:3: qsTranslate\(\) requires at least two arguments. +.*/lupdate/testdata/good/parsejs2/main.js:4: qsTranslate\(\) requires at least two arguments. +.*/lupdate/testdata/good/parsejs2/main.js:5: qsTranslate\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:6: qsTranslate\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:7: qsTranslate\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:9: QT_TRANSLATE_NOOP\(\) requires at least two arguments. +.*/lupdate/testdata/good/parsejs2/main.js:10: QT_TRANSLATE_NOOP\(\) requires at least two arguments. +.*/lupdate/testdata/good/parsejs2/main.js:11: QT_TRANSLATE_NOOP\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:12: QT_TRANSLATE_NOOP\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:13: QT_TRANSLATE_NOOP\(\): both arguments must be literal strings. +.*/lupdate/testdata/good/parsejs2/main.js:15: qsTr\(\) requires at least one argument. +.*/lupdate/testdata/good/parsejs2/main.js:16: qsTr\(\): text to translate must be a literal string. +.*/lupdate/testdata/good/parsejs2/main.js:18: QT_TR_NOOP\(\) requires at least one argument. +.*/lupdate/testdata/good/parsejs2/main.js:19: QT_TR_NOOP\(\): text to translate must be a literal string. +.*/lupdate/testdata/good/parsejs2/main.js:21: qsTrId\(\) requires at least one argument. +.*/lupdate/testdata/good/parsejs2/main.js:22: qsTrId\(\): identifier must be a literal string. +.*/lupdate/testdata/good/parsejs2/main.js:24: QT_TRID_NOOP\(\) requires at least one argument. +.*/lupdate/testdata/good/parsejs2/main.js:25: QT_TRID_NOOP\(\): identifier must be a literal string. +.*/lupdate/testdata/good/parsejs2/main.js:27: Unexpected character in meta string +.*/lupdate/testdata/good/parsejs2/main.js:28: Unexpected character in meta string +.*/lupdate/testdata/good/parsejs2/main.js:29: Unterminated meta string +.*/lupdate/testdata/good/parsejs2/main.js:30: Unterminated meta string +.*/lupdate/testdata/good/parsejs2/main.js:33: //% cannot be used with qsTranslate\(\). Ignoring +.*/lupdate/testdata/good/parsejs2/main.js:35: //% cannot be used with QT_TRANSLATE_NOOP\(\). Ignoring +.*/lupdate/testdata/good/parsejs2/main.js:37: //% cannot be used with qsTr\(\). Ignoring +.*/lupdate/testdata/good/parsejs2/main.js:39: //% cannot be used with QT_TR_NOOP\(\). Ignoring +.*/lupdate/testdata/good/parsejs2/main.js:42: Discarding unconsumed meta data +.*/lupdate/testdata/good/parsejs2/main.js:44: Discarding unconsumed meta data +.*/lupdate/testdata/good/parsejs2/main.js:46: Discarding unconsumed meta data diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs2/main.js b/tests/auto/linguist/lupdate/testdata/good/parsejs2/main.js new file mode 100644 index 0000000..ea02957 --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs2/main.js @@ -0,0 +1,56 @@ +// This script exercises lupdate errors and warnings. + +qsTranslate(); +qsTranslate(10); +qsTranslate(10, 20); +qsTranslate("10", 20); +qsTranslate(10, "20"); + +QT_TRANSLATE_NOOP(); +QT_TRANSLATE_NOOP(10); +QT_TRANSLATE_NOOP(10, 20); +QT_TRANSLATE_NOOP("10", 20); +QT_TRANSLATE_NOOP(10, "20"); + +qsTr(); +qsTr(10); + +QT_TR_NOOP(); +QT_TR_NOOP(10); + +qsTrId(); +qsTrId(10); + +QT_TRID_NOOP(); +QT_TRID_NOOP(10); + +//% This is wrong +//% "This is not wrong" This is wrong +//% "I forgot to close the meta string +//% "Being evil \ + +//% "Should cause a warning" +qsTranslate("FooContext", "Hello"); +//% "Should cause a warning" +QT_TRANSLATE_NOOP("FooContext", "World"); +//% "Should cause a warning" +qsTr("Hello"); +//% "Should cause a warning" +QT_TR_NOOP("World"); + +//: This comment will be discarded. +Math.sin(1); +//= id_foobar +Math.cos(2); +//~ underflow False +Math.tan(3); + +/* +Not tested for now, because these should perhaps not cause +translation entries to be generated at all; see QTBUG-11843. + +//= qtn_foo +qsTrId("qtn_foo"); +//= qtn_bar +QT_TRID_NOOP("qtn_bar"); +*/ diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.pro b/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.pro new file mode 100644 index 0000000..d549039 --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.pro @@ -0,0 +1,3 @@ +SOURCES += main.js + +TRANSLATIONS = project.ts diff --git a/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.ts.result new file mode 100644 index 0000000..bfa1b3d --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsejs2/project.ts.result @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0"> +<context> + <name>FooContext</name> + <message> + <location filename="main.js" line="33"/> + <source>Hello</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="35"/> + <source>World</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>main</name> + <message> + <location filename="main.js" line="37"/> + <source>Hello</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.js" line="39"/> + <source>World</source> + <translation type="unfinished"></translation> + </message> +</context> +</TS> diff --git a/tests/auto/qmake/testdata/substitutes/test.pro b/tests/auto/qmake/testdata/substitutes/test.pro index ddad93f..26b0272 100644 --- a/tests/auto/qmake/testdata/substitutes/test.pro +++ b/tests/auto/qmake/testdata/substitutes/test.pro @@ -1 +1,5 @@ -QMAKE_SUBSTITUTES += test.in sub/test2.in +QMAKE_SUBSTITUTES += test.in sub/test2.in indirect + +indirect.input = $$PWD/test3.txt +indirect.output = $$OUT_PWD/sub/indirect_test.txt + diff --git a/tests/auto/qmake/testdata/substitutes/test3.txt b/tests/auto/qmake/testdata/substitutes/test3.txt new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/tests/auto/qmake/testdata/substitutes/test3.txt @@ -0,0 +1 @@ +hello diff --git a/tests/auto/qmake/tst_qmake.cpp b/tests/auto/qmake/tst_qmake.cpp index 060fa01..277e9f8 100644 --- a/tests/auto/qmake/tst_qmake.cpp +++ b/tests/auto/qmake/tst_qmake.cpp @@ -484,12 +484,14 @@ void tst_qmake::substitutes() QVERIFY( test_compiler.qmake( workDir, "test" )); QVERIFY( test_compiler.exists( workDir, "test", Plain, "" )); QVERIFY( test_compiler.exists( workDir, "sub/test2", Plain, "" )); + QVERIFY( test_compiler.exists( workDir, "sub/indirect_test.txt", Plain, "" )); QVERIFY( test_compiler.makeDistClean( workDir )); QString buildDir = base_path + "/testdata/substitutes_build"; QVERIFY( test_compiler.qmake( workDir, "test", buildDir )); QVERIFY( test_compiler.exists( buildDir, "test", Plain, "" )); QVERIFY( test_compiler.exists( buildDir, "sub/test2", Plain, "" )); + QVERIFY( test_compiler.exists( buildDir, "sub/indirect_test.txt", Plain, "" )); QVERIFY( test_compiler.makeDistClean( buildDir )); } diff --git a/tests/auto/qscriptengine/idtranslatable.js b/tests/auto/qscriptengine/idtranslatable.js new file mode 100644 index 0000000..554ca88 --- /dev/null +++ b/tests/auto/qscriptengine/idtranslatable.js @@ -0,0 +1,5 @@ +qsTrId("qtn_foo_bar"); + +var more_greeting_strings = [ QT_TRID_NOOP("qtn_needle"), QT_TRID_NOOP("qtn_haystack") ]; + +qsTrId("qtn_bar_baz", 10); diff --git a/tests/auto/qscriptengine/qscriptengine.qrc b/tests/auto/qscriptengine/qscriptengine.qrc index b87f985..fa55a5b 100644 --- a/tests/auto/qscriptengine/qscriptengine.qrc +++ b/tests/auto/qscriptengine/qscriptengine.qrc @@ -1,5 +1,6 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>translations/translatable_la.qm</file> + <file>translations/idtranslatable_la.qm</file> </qresource> </RCC> diff --git a/tests/auto/qscriptengine/translations/idtranslatable_la.qm b/tests/auto/qscriptengine/translations/idtranslatable_la.qm Binary files differnew file mode 100644 index 0000000..c8c0b72 --- /dev/null +++ b/tests/auto/qscriptengine/translations/idtranslatable_la.qm diff --git a/tests/auto/qscriptengine/translations/idtranslatable_la.ts b/tests/auto/qscriptengine/translations/idtranslatable_la.ts new file mode 100644 index 0000000..b6d7053 --- /dev/null +++ b/tests/auto/qscriptengine/translations/idtranslatable_la.ts @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.0" language="nb_NO"> +<context> + <name></name> + <message id="qtn_foo_bar"> + <location filename="idtranslatable.js" line="1"/> + <source></source> + <translation>First string</translation> + </message> + <message id="qtn_needle"> + <location filename="idtranslatable.js" line="3"/> + <source></source> + <translation>Second string</translation> + </message> + <message id="qtn_haystack"> + <location filename="idtranslatable.js" line="3"/> + <source></source> + <translation>Third string</translation> + </message> + <message id="qtn_bar_baz" numerus="yes"> + <location filename="idtranslatable.js" line="5"/> + <source></source> + <translation> + <numerusform>Fourth string</numerusform> + <numerusform>%n fooish bar(s) found</numerusform> + </translation> + </message> +</context> +</TS> diff --git a/tests/auto/qscriptengine/tst_qscriptengine.cpp b/tests/auto/qscriptengine/tst_qscriptengine.cpp index 7a732cc..4cff043 100644 --- a/tests/auto/qscriptengine/tst_qscriptengine.cpp +++ b/tests/auto/qscriptengine/tst_qscriptengine.cpp @@ -162,6 +162,7 @@ private slots: void translateWithInvalidArgs(); void translationContext_data(); void translationContext(); + void translateScriptIdBased(); void functionScopes(); void nativeFunctionScopes(); void evaluateProgram(); @@ -4386,6 +4387,8 @@ void tst_QScriptEngine::installTranslatorFunctions() QVERIFY(!global.property("QT_TRANSLATE_NOOP").isValid()); QVERIFY(!global.property("qsTr").isValid()); QVERIFY(!global.property("QT_TR_NOOP").isValid()); + QVERIFY(!global.property("qsTrId").isValid()); + QVERIFY(!global.property("QT_TRID_NOOP").isValid()); QVERIFY(!globalOrig.property("String").property("prototype").property("arg").isValid()); eng.installTranslatorFunctions(); @@ -4393,6 +4396,8 @@ void tst_QScriptEngine::installTranslatorFunctions() QVERIFY(global.property("QT_TRANSLATE_NOOP").isFunction()); QVERIFY(global.property("qsTr").isFunction()); QVERIFY(global.property("QT_TR_NOOP").isFunction()); + QVERIFY(global.property("qsTrId").isFunction()); + QVERIFY(global.property("QT_TRID_NOOP").isFunction()); QVERIFY(globalOrig.property("String").property("prototype").property("arg").isFunction()); if (useCustomGlobalObject) { @@ -4400,6 +4405,8 @@ void tst_QScriptEngine::installTranslatorFunctions() QVERIFY(!globalOrig.property("QT_TRANSLATE_NOOP").isValid()); QVERIFY(!globalOrig.property("qsTr").isValid()); QVERIFY(!globalOrig.property("QT_TR_NOOP").isValid()); + QVERIFY(!globalOrig.property("qsTrId").isValid()); + QVERIFY(!globalOrig.property("QT_TRID_NOOP").isValid()); } { @@ -4427,6 +4434,17 @@ void tst_QScriptEngine::installTranslatorFunctions() QVERIFY(ret.isString()); QCOMPARE(ret.toString(), QString::fromLatin1("foobar")); } + + { + QScriptValue ret = eng.evaluate("qsTrId('foo')"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("foo")); + } + { + QScriptValue ret = eng.evaluate("QT_TRID_NOOP('foo')"); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QString::fromLatin1("foo")); + } } static QScriptValue callQsTr(QScriptContext *ctx, QScriptEngine *eng) @@ -4537,6 +4555,10 @@ void tst_QScriptEngine::translateWithInvalidArgs_data() QTest::newRow("qsTranslate('foo', 'bar', 'baz', 123)") << "qsTranslate('foo', 'bar', 'baz', 123)" << "Error: qsTranslate(): fourth argument (encoding) must be a string"; QTest::newRow("qsTranslate('foo', 'bar', 'baz', 'zab', 'rab')") << "qsTranslate('foo', 'bar', 'baz', 'zab', 'rab')" << "Error: qsTranslate(): fifth argument (n) must be a number"; QTest::newRow("qsTranslate('foo', 'bar', 'baz', 'zab', 123)") << "qsTranslate('foo', 'bar', 'baz', 'zab', 123)" << "Error: qsTranslate(): invalid encoding 'zab'"; + + QTest::newRow("qsTrId()") << "qsTrId()" << "Error: qsTrId() requires at least one argument"; + QTest::newRow("qsTrId(123)") << "qsTrId(123)" << "TypeError: qsTrId(): first argument (id) must be a string"; + QTest::newRow("qsTrId('foo', 'bar')") << "qsTrId('foo', 'bar')" << "TypeError: qsTrId(): second argument (n) must be a number"; } void tst_QScriptEngine::translateWithInvalidArgs() @@ -4598,6 +4620,53 @@ void tst_QScriptEngine::translationContext() QCoreApplication::instance()->removeTranslator(&translator); } +void tst_QScriptEngine::translateScriptIdBased() +{ + QScriptEngine engine; + + QTranslator translator; + translator.load(":/translations/idtranslatable_la"); + QCoreApplication::instance()->installTranslator(&translator); + engine.installTranslatorFunctions(); + + QString fileName = QString::fromLatin1("idtranslatable.js"); + + QHash<QString, QString> expectedTranslations; + expectedTranslations["qtn_foo_bar"] = "First string"; + expectedTranslations["qtn_needle"] = "Second string"; + expectedTranslations["qtn_haystack"] = "Third string"; + expectedTranslations["qtn_bar_baz"] = "Fourth string"; + + QHash<QString, QString>::const_iterator it; + for (it = expectedTranslations.constBegin(); it != expectedTranslations.constEnd(); ++it) { + for (int x = 0; x < 2; ++x) { + QString fn; + if (x) + fn = fileName; + // Top-level + QCOMPARE(engine.evaluate(QString::fromLatin1("qsTrId('%0')") + .arg(it.key()), fn).toString(), + it.value()); + QCOMPARE(engine.evaluate(QString::fromLatin1("QT_TRID_NOOP('%0')") + .arg(it.key()), fn).toString(), + it.key()); + // From function + QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return qsTrId('%0'); })()") + .arg(it.key()), fn).toString(), + it.value()); + QCOMPARE(engine.evaluate(QString::fromLatin1("(function() { return QT_TRID_NOOP('%0'); })()") + .arg(it.key()), fn).toString(), + it.key()); + } + } + + // Plural form + QCOMPARE(engine.evaluate("qsTrId('qtn_bar_baz', 10)").toString(), + QString::fromLatin1("10 fooish bar(s) found")); + QCOMPARE(engine.evaluate("qsTrId('qtn_foo_bar', 10)").toString(), + QString::fromLatin1("qtn_foo_bar")); // Doesn't have plural +} + void tst_QScriptEngine::functionScopes() { QScriptEngine eng; diff --git a/tests/auto/qtouchevent/tst_qtouchevent.cpp b/tests/auto/qtouchevent/tst_qtouchevent.cpp index bb80fde..4219ef4 100644 --- a/tests/auto/qtouchevent/tst_qtouchevent.cpp +++ b/tests/auto/qtouchevent/tst_qtouchevent.cpp @@ -109,6 +109,7 @@ class tst_QTouchEventGraphicsItem : public QGraphicsItem public: QList<QTouchEvent::TouchPoint> touchBeginPoints, touchUpdatePoints, touchEndPoints; bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; + int touchBeginCounter, touchUpdateCounter, touchEndCounter; bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; bool deleteInTouchBegin, deleteInTouchUpdate, deleteInTouchEnd; tst_QTouchEventGraphicsItem **weakpointer; @@ -131,6 +132,7 @@ public: touchUpdatePoints.clear(); touchEndPoints.clear(); seenTouchBegin = seenTouchUpdate = seenTouchEnd = false; + touchBeginCounter = touchUpdateCounter = touchEndCounter = 0; acceptTouchBegin = acceptTouchUpdate = acceptTouchEnd = true; deleteInTouchBegin = deleteInTouchUpdate = deleteInTouchEnd = false; } @@ -146,6 +148,7 @@ public: if (seenTouchUpdate) qWarning("TouchBegin: TouchUpdate cannot happen before TouchBegin"); if (seenTouchEnd) qWarning("TouchBegin: TouchEnd cannot happen before TouchBegin"); seenTouchBegin = !seenTouchBegin && !seenTouchUpdate && !seenTouchEnd; + ++touchBeginCounter; touchBeginPoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchBegin); if (deleteInTouchBegin) @@ -155,6 +158,7 @@ public: if (!seenTouchBegin) qWarning("TouchUpdate: have not seen TouchBegin"); if (seenTouchEnd) qWarning("TouchUpdate: TouchEnd cannot happen before TouchUpdate"); seenTouchUpdate = seenTouchBegin && !seenTouchEnd; + ++touchUpdateCounter; touchUpdatePoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchUpdate); if (deleteInTouchUpdate) @@ -164,6 +168,7 @@ public: if (!seenTouchBegin) qWarning("TouchEnd: have not seen TouchBegin"); if (seenTouchEnd) qWarning("TouchEnd: already seen a TouchEnd"); seenTouchEnd = seenTouchBegin && !seenTouchEnd; + ++touchEndCounter; touchEndPoints = static_cast<QTouchEvent *>(event)->touchPoints(); event->setAccepted(acceptTouchEnd); if (deleteInTouchEnd) @@ -194,6 +199,7 @@ private slots: void deleteInEventHandler(); void deleteInRawEventTranslation(); void crashInQGraphicsSceneAfterNotHandlingTouchBegin(); + void touchBeginWithGraphicsWidget(); }; void tst_QTouchEvent::touchDisabledByDefault() @@ -1334,6 +1340,59 @@ void tst_QTouchEvent::crashInQGraphicsSceneAfterNotHandlingTouchBegin() QTest::touchEvent(view.viewport()).release(0, view.mapFromScene(QPoint(10, 10))); } +void tst_QTouchEvent::touchBeginWithGraphicsWidget() +{ + QGraphicsScene scene; + QGraphicsView view(&scene); + tst_QTouchEventGraphicsItem *root; + root = new tst_QTouchEventGraphicsItem; + root->setAcceptTouchEvents(true); + scene.addItem(root); + + QGraphicsWidget *glassWidget = new QGraphicsWidget; + glassWidget->setMinimumSize(100, 100); + scene.addItem(glassWidget); + + view.resize(200, 200); + view.show(); + QTest::qWaitForWindowShown(&view); + view.fitInView(scene.sceneRect()); + + QTest::touchEvent() + .press(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()); + QTest::touchEvent() + .stationary(0) + .press(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + QTest::touchEvent() + .release(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()) + .release(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + + QCOMPARE(root->touchBeginCounter, 1); + QCOMPARE(root->touchUpdateCounter, 1); + QCOMPARE(root->touchEndCounter, 1); + QCOMPARE(root->touchUpdatePoints.size(), 2); + + root->reset(); + glassWidget->setWindowFlags(Qt::Window); // make the glassWidget a panel + + QTest::touchEvent() + .press(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()); + QTest::touchEvent() + .stationary(0) + .press(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + QTest::touchEvent() + .release(0, view.mapFromScene(root->mapToScene(3,3)), view.viewport()) + .release(1, view.mapFromScene(root->mapToScene(6,6)), view.viewport()); + + QCOMPARE(root->touchBeginCounter, 0); + QCOMPARE(root->touchUpdateCounter, 0); + QCOMPARE(root->touchEndCounter, 0); + + + delete root; + delete glassWidget; +} + QTEST_MAIN(tst_QTouchEvent) #include "tst_qtouchevent.moc" diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 0c716d1..3a0fcde 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -2667,8 +2667,7 @@ void Configure::generateOutputVars() qtConfig += "audio-backend"; } - if (dictionary["WEBKIT"] == "yes") - qtConfig += "webkit"; + // Don't add "webkit" to QT_CONFIG here - it injects itself via the module. if (dictionary["DECLARATIVE"] == "yes") { if (dictionary[ "SCRIPT" ] == "no") { diff --git a/tools/linguist/lupdate/qscript.cpp b/tools/linguist/lupdate/qscript.cpp index 188ac36..7ca0987 100644 --- a/tools/linguist/lupdate/qscript.cpp +++ b/tools/linguist/lupdate/qscript.cpp @@ -770,13 +770,16 @@ const int QScriptGrammar::action_check [] = { static void recordMessage( Translator *tor, const QString &context, const QString &text, const QString &comment, - const QString &extracomment, bool plural, const QString &fileName, int lineNo) + const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra, + bool plural, const QString &fileName, int lineNo) { TranslatorMessage msg( context, text, comment, QString(), fileName, lineNo, QStringList(), TranslatorMessage::Unfinished, plural); msg.setExtraComment(extracomment.simplified()); + msg.setId(msgid); + msg.setExtras(extra); tor->extend(msg); } @@ -784,15 +787,23 @@ static void recordMessage( namespace QScript { +class CommentProcessor +{ +public: + virtual ~CommentProcessor() {} + virtual void processComment(const QChar *chars, int length) = 0; +}; + class Lexer { public: - Lexer(); + Lexer(CommentProcessor *); ~Lexer(); - void setCode(const QString &c, int lineno); + void setCode(const QString &c, const QString &fileName, int lineno); int lex(); + QString fileName() const { return yyfilename; } int currentLineNo() const { return yylineno; } int currentColumnNo() const { return yycolumn; } @@ -872,6 +883,7 @@ public: { err = NoError; } private: + QString yyfilename; int yylineno; bool done; char *buffer8; @@ -925,6 +937,8 @@ private: void syncProhibitAutomaticSemicolon(); + void processComment(const QChar *, int); + const QChar *code; uint length; int yycolumn; @@ -951,6 +965,8 @@ private: ParenthesesState parenthesesState; int parenthesesCount; bool prohibitAutomaticSemicolon; + + CommentProcessor *commentProcessor; }; } // namespace QScript @@ -1027,7 +1043,7 @@ double integerFromString(const char *buf, int size, int radix) } // namespace QScript -QScript::Lexer::Lexer() +QScript::Lexer::Lexer(QScript::CommentProcessor *proc) : yylineno(0), size8(128), size16(128), restrKeyword(false), @@ -1038,7 +1054,8 @@ QScript::Lexer::Lexer() err(NoError), check_reserved(true), parenthesesState(IgnoreParentheses), - prohibitAutomaticSemicolon(false) + prohibitAutomaticSemicolon(false), + commentProcessor(proc) { // allocate space for read buffers buffer8 = new char[size8]; @@ -1053,9 +1070,10 @@ QScript::Lexer::~Lexer() delete [] buffer16; } -void QScript::Lexer::setCode(const QString &c, int lineno) +void QScript::Lexer::setCode(const QString &c, const QString &fileName, int lineno) { errmsg = QString(); + yyfilename = fileName; yylineno = lineno; yycolumn = 1; restrKeyword = false; @@ -1404,10 +1422,12 @@ int QScript::Lexer::lex() } else if (current == '/' && next1 == '/') { recordStartPos(); shift(1); + Q_ASSERT(pos16 == 0); state = InSingleLineComment; } else if (current == '/' && next1 == '*') { recordStartPos(); shift(1); + Q_ASSERT(pos16 == 0); state = InMultiLineComment; } else if (current == 0) { syncProhibitAutomaticSemicolon(); @@ -1547,9 +1567,12 @@ int QScript::Lexer::lex() break; case InSingleLineComment: if (isLineTerminator()) { + record16(current); // include newline + processComment(buffer16, pos16); shiftWindowsLineBreak(); yylineno++; yycolumn = 0; + pos16 = 0; terminator = true; bol = true; if (restrKeyword) { @@ -1559,6 +1582,8 @@ int QScript::Lexer::lex() state = Start; } else if (current == 0) { setDone(Eof); + } else { + record16(current); } break; case InMultiLineComment: @@ -1570,8 +1595,12 @@ int QScript::Lexer::lex() shiftWindowsLineBreak(); yylineno++; } else if (current == '*' && next1 == '/') { + processComment(buffer16, pos16); + pos16 = 0; state = Start; shift(1); + } else { + record16(current); } break; case InIdentifier: @@ -2033,10 +2062,15 @@ void QScript::Lexer::syncProhibitAutomaticSemicolon() } } +void QScript::Lexer::processComment(const QChar *chars, int length) +{ + commentProcessor->processComment(chars, length); +} + class Translator; -class QScriptParser: protected QScriptGrammar +class QScriptParser: protected QScriptGrammar, public QScript::CommentProcessor { public: QVariant val; @@ -2052,10 +2086,12 @@ public: QScriptParser(); ~QScriptParser(); - bool parse(QScript::Lexer *lexer, - const QString &fileName, - Translator *translator); + void setLexer(QScript::Lexer *); + + bool parse(Translator *translator); + QString fileName() const + { return lexer->fileName(); } inline QString errorMessage() const { return error_message; } inline int errorLineNumber() const @@ -2072,6 +2108,10 @@ protected: inline Location &loc(int index) { return location_stack [tos + index - 2]; } + std::ostream &yyMsg(int line = 0); + + virtual void processComment(const QChar *, int); + protected: int tos; int stack_size; @@ -2081,6 +2121,13 @@ protected: QString error_message; int error_lineno; int error_column; + +private: + QScript::Lexer *lexer; + QString extracomment; + QString msgid; + QString sourcetext; + TranslatorMessage::ExtraData extra; }; inline void QScriptParser::reallocateStack() @@ -2107,7 +2154,8 @@ QScriptParser::QScriptParser(): stack_size(0), sym_stack(0), state_stack(0), - location_stack(0) + location_stack(0), + lexer(0) { } @@ -2129,10 +2177,14 @@ static inline QScriptParser::Location location(QScript::Lexer *lexer) return loc; } -bool QScriptParser::parse(QScript::Lexer *lexer, - const QString &fileName, - Translator *translator) +void QScriptParser::setLexer(QScript::Lexer *lex) +{ + lexer = lex; +} + +bool QScriptParser::parse(Translator *translator) { + Q_ASSERT(lexer != 0); const int INITIAL_STATE = 0; int yytoken = -1; @@ -2214,44 +2266,70 @@ case 8: { case 66: { QString name = sym(1).toString(); if ((name == QLatin1String("qsTranslate")) || (name == QLatin1String("QT_TRANSLATE_NOOP"))) { + if (!sourcetext.isEmpty()) + yyMsg(identLineNo) << "//% cannot be used with " << qPrintable(name) << "(). Ignoring\n"; QVariantList args = sym(2).toList(); if (args.size() < 2) { - std::cerr << qPrintable(fileName) << ':' << identLineNo << ": " - << qPrintable(name) << "() requires at least two arguments.\n"; + yyMsg(identLineNo) << qPrintable(name) << "() requires at least two arguments.\n"; } else { if ((args.at(0).type() != QVariant::String) || (args.at(1).type() != QVariant::String)) { - std::cerr << qPrintable(fileName) << ':' << identLineNo << ": " - << qPrintable(name) << "(): both arguments must be literal strings.\n"; + yyMsg(identLineNo) << qPrintable(name) << "(): both arguments must be literal strings.\n"; } else { QString context = args.at(0).toString(); QString text = args.at(1).toString(); QString comment = args.value(2).toString(); - QString extracomment; bool plural = (args.size() > 4); recordMessage(translator, context, text, comment, extracomment, - plural, fileName, identLineNo); + msgid, extra, plural, fileName(), identLineNo); } } + sourcetext.clear(); + extracomment.clear(); + msgid.clear(); + extra.clear(); } else if ((name == QLatin1String("qsTr")) || (name == QLatin1String("QT_TR_NOOP"))) { + if (!sourcetext.isEmpty()) + yyMsg(identLineNo) << "//% cannot be used with " << qPrintable(name) << "(). Ignoring\n"; QVariantList args = sym(2).toList(); if (args.size() < 1) { - std::cerr << qPrintable(fileName) << ':' << identLineNo << ": " - << qPrintable(name) << "() requires at least one argument.\n"; + yyMsg(identLineNo) << qPrintable(name) << "() requires at least one argument.\n"; } else { if (args.at(0).type() != QVariant::String) { - std::cerr << qPrintable(fileName) << ':' << identLineNo << ": " - << qPrintable(name) << "(): text to translate must be a literal string.\n"; + yyMsg(identLineNo) << qPrintable(name) << "(): text to translate must be a literal string.\n"; } else { - QString context = QFileInfo(fileName).baseName(); + QString context = QFileInfo(fileName()).baseName(); QString text = args.at(0).toString(); QString comment = args.value(1).toString(); - QString extracomment; bool plural = (args.size() > 2); recordMessage(translator, context, text, comment, extracomment, - plural, fileName, identLineNo); + msgid, extra, plural, fileName(), identLineNo); } } + sourcetext.clear(); + extracomment.clear(); + msgid.clear(); + extra.clear(); + } else if ((name == QLatin1String("qsTrId")) || (name == QLatin1String("QT_TRID_NOOP"))) { + if (!msgid.isEmpty()) + yyMsg(identLineNo) << "//= cannot be used with " << qPrintable(name) << "(). Ignoring\n"; + QVariantList args = sym(2).toList(); + if (args.size() < 1) { + yyMsg(identLineNo) << qPrintable(name) << "() requires at least one argument.\n"; + } else { + if (args.at(0).type() != QVariant::String) { + yyMsg(identLineNo) << qPrintable(name) << "(): identifier must be a literal string.\n"; + } else { + msgid = args.at(0).toString(); + bool plural = (args.size() > 1); + recordMessage(translator, QString(), sourcetext, QString(), extracomment, + msgid, extra, plural, fileName(), identLineNo); + } + } + sourcetext.clear(); + extracomment.clear(); + msgid.clear(); + extra.clear(); } } break; @@ -2278,6 +2356,44 @@ case 94: { sym(1) = QVariant(); } break; + case 171: + + case 172: + + case 173: + + case 174: + + case 175: + + case 176: + + case 177: + + case 178: + + case 179: + + case 180: + + case 181: + + case 182: + + case 183: + + case 184: + + case 185: + if (!sourcetext.isEmpty() || !extracomment.isEmpty() || !msgid.isEmpty() || !extra.isEmpty()) { + yyMsg() << "Discarding unconsumed meta data\n"; + sourcetext.clear(); + extracomment.clear(); + msgid.clear(); + extra.clear(); + } + break; + } // switch state_stack [tos] = nt_action (act, lhs [r] - TERMINAL_COUNT); @@ -2356,6 +2472,63 @@ case 94: { return false; } +std::ostream &QScriptParser::yyMsg(int line) +{ + return std::cerr << qPrintable(fileName()) << ':' << (line ? line : lexer->startLineNo()) << ": "; +} + +void QScriptParser::processComment(const QChar *chars, int length) +{ + if (!length) + return; + // Try to match the logic of the C++ parser. + if (*chars == QLatin1Char(':') && chars[1].isSpace()) { + extracomment += QString(chars+2, length-2); + } else if (*chars == QLatin1Char('=') && chars[1].isSpace()) { + msgid = QString(chars+2, length-2).simplified(); + } else if (*chars == QLatin1Char('~') && chars[1].isSpace()) { + QString text = QString(chars+2, length-2).trimmed(); + int k = text.indexOf(QLatin1Char(' ')); + if (k > -1) + extra.insert(text.left(k), text.mid(k + 1).trimmed()); + } else if (*chars == QLatin1Char('%') && chars[1].isSpace()) { + sourcetext.reserve(sourcetext.length() + length-2); + ushort *ptr = (ushort *)sourcetext.data() + sourcetext.length(); + int p = 2, c; + forever { + if (p >= length) + break; + c = chars[p++].unicode(); + if (isspace(c)) + continue; + if (c != '"') { + yyMsg() << "Unexpected character in meta string\n"; + break; + } + forever { + if (p >= length) { + whoops: + yyMsg() << "Unterminated meta string\n"; + break; + } + c = chars[p++].unicode(); + if (c == '"') + break; + if (c == '\\') { + if (p >= length) + goto whoops; + c = chars[p++].unicode(); + if (c == '\n') + goto whoops; + *ptr++ = '\\'; + } + *ptr++ = c; + } + } + sourcetext.resize(ptr - (ushort *)sourcetext.data()); + } +} + bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd) { @@ -2375,10 +2548,11 @@ bool loadQScript(Translator &translator, const QString &filename, ConversionData ts.setAutoDetectUnicode(true); QString code = ts.readAll(); - QScript::Lexer lexer; - lexer.setCode(code, /*lineNumber=*/1); QScriptParser parser; - if (!parser.parse(&lexer, filename, &translator)) { + QScript::Lexer lexer(&parser); + lexer.setCode(code, filename, /*lineNumber=*/1); + parser.setLexer(&lexer); + if (!parser.parse(&translator)) { std::cerr << qPrintable(filename) << ':' << parser.errorLineNumber() << ": " << qPrintable(parser.errorMessage()) << std::endl; return false; diff --git a/tools/linguist/lupdate/qscript.g b/tools/linguist/lupdate/qscript.g index 857c58a..e4c2d22 100644 --- a/tools/linguist/lupdate/qscript.g +++ b/tools/linguist/lupdate/qscript.g @@ -101,13 +101,16 @@ QT_BEGIN_NAMESPACE static void recordMessage( Translator *tor, const QString &context, const QString &text, const QString &comment, - const QString &extracomment, bool plural, const QString &fileName, int lineNo) + const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra, + bool plural, const QString &fileName, int lineNo) { TranslatorMessage msg( context, text, comment, QString(), fileName, lineNo, QStringList(), TranslatorMessage::Unfinished, plural); msg.setExtraComment(extracomment.simplified()); + msg.setId(msgid); + msg.setExtras(extra); tor->extend(msg); } @@ -115,15 +118,23 @@ static void recordMessage( namespace QScript { +class CommentProcessor +{ +public: + virtual ~CommentProcessor() {} + virtual void processComment(const QChar *chars, int length) = 0; +}; + class Lexer { public: - Lexer(); + Lexer(CommentProcessor *); ~Lexer(); - void setCode(const QString &c, int lineno); + void setCode(const QString &c, const QString &fileName, int lineno); int lex(); + QString fileName() const { return yyfilename; } int currentLineNo() const { return yylineno; } int currentColumnNo() const { return yycolumn; } @@ -203,6 +214,7 @@ public: { err = NoError; } private: + QString yyfilename; int yylineno; bool done; char *buffer8; @@ -256,6 +268,8 @@ private: void syncProhibitAutomaticSemicolon(); + void processComment(const QChar *, int); + const QChar *code; uint length; int yycolumn; @@ -282,6 +296,8 @@ private: ParenthesesState parenthesesState; int parenthesesCount; bool prohibitAutomaticSemicolon; + + CommentProcessor *commentProcessor; }; } // namespace QScript @@ -358,7 +374,7 @@ double integerFromString(const char *buf, int size, int radix) } // namespace QScript -QScript::Lexer::Lexer() +QScript::Lexer::Lexer(QScript::CommentProcessor *proc) : yylineno(0), size8(128), size16(128), restrKeyword(false), @@ -369,7 +385,8 @@ QScript::Lexer::Lexer() err(NoError), check_reserved(true), parenthesesState(IgnoreParentheses), - prohibitAutomaticSemicolon(false) + prohibitAutomaticSemicolon(false), + commentProcessor(proc) { // allocate space for read buffers buffer8 = new char[size8]; @@ -384,9 +401,10 @@ QScript::Lexer::~Lexer() delete [] buffer16; } -void QScript::Lexer::setCode(const QString &c, int lineno) +void QScript::Lexer::setCode(const QString &c, const QString &fileName, int lineno) { errmsg = QString(); + yyfilename = fileName; yylineno = lineno; yycolumn = 1; restrKeyword = false; @@ -735,10 +753,12 @@ int QScript::Lexer::lex() } else if (current == '/' && next1 == '/') { recordStartPos(); shift(1); + Q_ASSERT(pos16 == 0); state = InSingleLineComment; } else if (current == '/' && next1 == '*') { recordStartPos(); shift(1); + Q_ASSERT(pos16 == 0); state = InMultiLineComment; } else if (current == 0) { syncProhibitAutomaticSemicolon(); @@ -878,9 +898,12 @@ int QScript::Lexer::lex() break; case InSingleLineComment: if (isLineTerminator()) { + record16(current); // include newline + processComment(buffer16, pos16); shiftWindowsLineBreak(); yylineno++; yycolumn = 0; + pos16 = 0; terminator = true; bol = true; if (restrKeyword) { @@ -890,6 +913,8 @@ int QScript::Lexer::lex() state = Start; } else if (current == 0) { setDone(Eof); + } else { + record16(current); } break; case InMultiLineComment: @@ -901,8 +926,12 @@ int QScript::Lexer::lex() shiftWindowsLineBreak(); yylineno++; } else if (current == '*' && next1 == '/') { + processComment(buffer16, pos16); + pos16 = 0; state = Start; shift(1); + } else { + record16(current); } break; case InIdentifier: @@ -1364,10 +1393,15 @@ void QScript::Lexer::syncProhibitAutomaticSemicolon() } } +void QScript::Lexer::processComment(const QChar *chars, int length) +{ + commentProcessor->processComment(chars, length); +} + class Translator; -class QScriptParser: protected $table +class QScriptParser: protected $table, public QScript::CommentProcessor { public: QVariant val; @@ -1383,10 +1417,12 @@ public: QScriptParser(); ~QScriptParser(); - bool parse(QScript::Lexer *lexer, - const QString &fileName, - Translator *translator); + void setLexer(QScript::Lexer *); + bool parse(Translator *translator); + + QString fileName() const + { return lexer->fileName(); } inline QString errorMessage() const { return error_message; } inline int errorLineNumber() const @@ -1403,6 +1439,10 @@ protected: inline Location &loc(int index) { return location_stack [tos + index - 2]; } + std::ostream &yyMsg(int line = 0); + + virtual void processComment(const QChar *, int); + protected: int tos; int stack_size; @@ -1412,6 +1452,13 @@ protected: QString error_message; int error_lineno; int error_column; + +private: + QScript::Lexer *lexer; + QString extracomment; + QString msgid; + QString sourcetext; + TranslatorMessage::ExtraData extra; }; inline void QScriptParser::reallocateStack() @@ -1438,7 +1485,8 @@ QScriptParser::QScriptParser(): stack_size(0), sym_stack(0), state_stack(0), - location_stack(0) + location_stack(0), + lexer(0) { } @@ -1460,10 +1508,14 @@ static inline QScriptParser::Location location(QScript::Lexer *lexer) return loc; } -bool QScriptParser::parse(QScript::Lexer *lexer, - const QString &fileName, - Translator *translator) +void QScriptParser::setLexer(QScript::Lexer *lex) { + lexer = lex; +} + +bool QScriptParser::parse(Translator *translator) +{ + Q_ASSERT(lexer != 0); const int INITIAL_STATE = 0; int yytoken = -1; @@ -1630,44 +1682,70 @@ CallExpression: MemberExpression Arguments ; case $rule_number: { QString name = sym(1).toString(); if ((name == QLatin1String("qsTranslate")) || (name == QLatin1String("QT_TRANSLATE_NOOP"))) { + if (!sourcetext.isEmpty()) + yyMsg(identLineNo) << "//% cannot be used with " << qPrintable(name) << "(). Ignoring\n"; QVariantList args = sym(2).toList(); if (args.size() < 2) { - std::cerr << qPrintable(fileName) << ':' << identLineNo << ": " - << qPrintable(name) << "() requires at least two arguments.\n"; + yyMsg(identLineNo) << qPrintable(name) << "() requires at least two arguments.\n"; } else { if ((args.at(0).type() != QVariant::String) || (args.at(1).type() != QVariant::String)) { - std::cerr << qPrintable(fileName) << ':' << identLineNo << ": " - << qPrintable(name) << "(): both arguments must be literal strings.\n"; + yyMsg(identLineNo) << qPrintable(name) << "(): both arguments must be literal strings.\n"; } else { QString context = args.at(0).toString(); QString text = args.at(1).toString(); QString comment = args.value(2).toString(); - QString extracomment; bool plural = (args.size() > 4); recordMessage(translator, context, text, comment, extracomment, - plural, fileName, identLineNo); + msgid, extra, plural, fileName(), identLineNo); } } + sourcetext.clear(); + extracomment.clear(); + msgid.clear(); + extra.clear(); } else if ((name == QLatin1String("qsTr")) || (name == QLatin1String("QT_TR_NOOP"))) { + if (!sourcetext.isEmpty()) + yyMsg(identLineNo) << "//% cannot be used with " << qPrintable(name) << "(). Ignoring\n"; QVariantList args = sym(2).toList(); if (args.size() < 1) { - std::cerr << qPrintable(fileName) << ':' << identLineNo << ": " - << qPrintable(name) << "() requires at least one argument.\n"; + yyMsg(identLineNo) << qPrintable(name) << "() requires at least one argument.\n"; } else { if (args.at(0).type() != QVariant::String) { - std::cerr << qPrintable(fileName) << ':' << identLineNo << ": " - << qPrintable(name) << "(): text to translate must be a literal string.\n"; + yyMsg(identLineNo) << qPrintable(name) << "(): text to translate must be a literal string.\n"; } else { - QString context = QFileInfo(fileName).baseName(); + QString context = QFileInfo(fileName()).baseName(); QString text = args.at(0).toString(); QString comment = args.value(1).toString(); - QString extracomment; bool plural = (args.size() > 2); recordMessage(translator, context, text, comment, extracomment, - plural, fileName, identLineNo); + msgid, extra, plural, fileName(), identLineNo); + } + } + sourcetext.clear(); + extracomment.clear(); + msgid.clear(); + extra.clear(); + } else if ((name == QLatin1String("qsTrId")) || (name == QLatin1String("QT_TRID_NOOP"))) { + if (!msgid.isEmpty()) + yyMsg(identLineNo) << "//= cannot be used with " << qPrintable(name) << "(). Ignoring\n"; + QVariantList args = sym(2).toList(); + if (args.size() < 1) { + yyMsg(identLineNo) << qPrintable(name) << "() requires at least one argument.\n"; + } else { + if (args.at(0).type() != QVariant::String) { + yyMsg(identLineNo) << qPrintable(name) << "(): identifier must be a literal string.\n"; + } else { + msgid = args.at(0).toString(); + bool plural = (args.size() > 1); + recordMessage(translator, QString(), sourcetext, QString(), extracomment, + msgid, extra, plural, fileName(), identLineNo); } } + sourcetext.clear(); + extracomment.clear(); + msgid.clear(); + extra.clear(); } } break; ./ @@ -1813,20 +1891,73 @@ ExpressionNotInOpt: ; ExpressionNotInOpt: ExpressionNotIn ; Statement: Block ; +/. + case $rule_number: +./ Statement: VariableStatement ; +/. + case $rule_number: +./ Statement: EmptyStatement ; +/. + case $rule_number: +./ Statement: ExpressionStatement ; +/. + case $rule_number: +./ Statement: IfStatement ; +/. + case $rule_number: +./ Statement: IterationStatement ; +/. + case $rule_number: +./ Statement: ContinueStatement ; +/. + case $rule_number: +./ Statement: BreakStatement ; +/. + case $rule_number: +./ Statement: ReturnStatement ; +/. + case $rule_number: +./ Statement: WithStatement ; +/. + case $rule_number: +./ Statement: LabelledStatement ; +/. + case $rule_number: +./ Statement: SwitchStatement ; +/. + case $rule_number: +./ Statement: ThrowStatement ; +/. + case $rule_number: +./ Statement: TryStatement ; +/. + case $rule_number: +./ Statement: DebuggerStatement ; +/. + case $rule_number: + if (!sourcetext.isEmpty() || !extracomment.isEmpty() || !msgid.isEmpty() || !extra.isEmpty()) { + yyMsg() << "Discarding unconsumed meta data\n"; + sourcetext.clear(); + extracomment.clear(); + msgid.clear(); + extra.clear(); + } + break; +./ Block: T_LBRACE StatementListOpt T_RBRACE ; StatementList: Statement ; @@ -1988,6 +2119,63 @@ PropertyNameAndValueListOpt: PropertyNameAndValueList ; return false; } +std::ostream &QScriptParser::yyMsg(int line) +{ + return std::cerr << qPrintable(fileName()) << ':' << (line ? line : lexer->startLineNo()) << ": "; +} + +void QScriptParser::processComment(const QChar *chars, int length) +{ + if (!length) + return; + // Try to match the logic of the C++ parser. + if (*chars == QLatin1Char(':') && chars[1].isSpace()) { + extracomment += QString(chars+2, length-2); + } else if (*chars == QLatin1Char('=') && chars[1].isSpace()) { + msgid = QString(chars+2, length-2).simplified(); + } else if (*chars == QLatin1Char('~') && chars[1].isSpace()) { + QString text = QString(chars+2, length-2).trimmed(); + int k = text.indexOf(QLatin1Char(' ')); + if (k > -1) + extra.insert(text.left(k), text.mid(k + 1).trimmed()); + } else if (*chars == QLatin1Char('%') && chars[1].isSpace()) { + sourcetext.reserve(sourcetext.length() + length-2); + ushort *ptr = (ushort *)sourcetext.data() + sourcetext.length(); + int p = 2, c; + forever { + if (p >= length) + break; + c = chars[p++].unicode(); + if (isspace(c)) + continue; + if (c != '"') { + yyMsg() << "Unexpected character in meta string\n"; + break; + } + forever { + if (p >= length) { + whoops: + yyMsg() << "Unterminated meta string\n"; + break; + } + c = chars[p++].unicode(); + if (c == '"') + break; + if (c == '\\') { + if (p >= length) + goto whoops; + c = chars[p++].unicode(); + if (c == '\n') + goto whoops; + *ptr++ = '\\'; + } + *ptr++ = c; + } + } + sourcetext.resize(ptr - (ushort *)sourcetext.data()); + } +} + bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd) { @@ -2007,10 +2195,11 @@ bool loadQScript(Translator &translator, const QString &filename, ConversionData ts.setAutoDetectUnicode(true); QString code = ts.readAll(); - QScript::Lexer lexer; - lexer.setCode(code, /*lineNumber=*/1); QScriptParser parser; - if (!parser.parse(&lexer, filename, &translator)) { + QScript::Lexer lexer(&parser); + lexer.setCode(code, filename, /*lineNumber=*/1); + parser.setLexer(&lexer); + if (!parser.parse(&translator)) { std::cerr << qPrintable(filename) << ':' << parser.errorLineNumber() << ": " << qPrintable(parser.errorMessage()) << std::endl; return false; diff --git a/tools/qdoc3/test/qt-html-templates.qdocconf b/tools/qdoc3/test/qt-html-templates.qdocconf index c70bcaf..8d4d27f 100644 --- a/tools/qdoc3/test/qt-html-templates.qdocconf +++ b/tools/qdoc3/test/qt-html-templates.qdocconf @@ -98,10 +98,13 @@ HTML.postheader = " <div class=\"header\" id=\"qtdocheader\">\n" \ " Qt Topics</h2>\n" \ " <div id=\"list002\" class=\"list\">\n" \ " <ul id=\"ul002\" >\n" \ - " <li class=\"defaultLink\"><a href=\"qt-basic-concepts.html\">Basic Qt architecture</a></li>\n" \ - " <li class=\"defaultLink\"><a href=\"qtquick.html\">Device UI's & Qt Quick</a></li>\n" \ - " <li class=\"defaultLink\"><a href=\"qt-gui-concepts.html\">Desktop UI components</a></li>\n" \ - " <li class=\"defaultLink\"><a href=\"platform-specific.html\">Platform-specific info</a></li>\n" \ + " <li><a href=\"qt-basic-concepts.html\">Programming with Qt</a></li> \n" \ + " <li><a href=\"qtquick.html\">Device UI's & Qt Quick</a></li> \n" \ + " <li><a href=\"qt-gui-concepts.html\">UI Design with Qt</a></li> \n" \ + " <li><a href=\"developing-with-qt.html\">Cross-platform and Platform-specific</a></li> \n" \ + " <li><a href=\"platform-specific.html\">Platform-specific info</a></li> \n" \ + " <li><a href=\"technology-apis.html\">Qt and Key Technologies</a></li> \n" \ + " <li><a href=\"best-practices.html\">How-To's and Best Practices</a></li> \n" \ " </ul> \n" \ " </div>\n" \ " </div>\n" \ |