diff options
16 files changed, 531 insertions, 64 deletions
diff --git a/doc/src/declarative/qml-intro.qdoc b/doc/src/declarative/qml-intro.qdoc index 63d6825..9130be0 100644 --- a/doc/src/declarative/qml-intro.qdoc +++ b/doc/src/declarative/qml-intro.qdoc @@ -58,7 +58,12 @@ would be a property. The basic syntax of an \l{QML Elements}{element} is -\snippet doc/src/snippets/declarative/qml-intro/basic-syntax.qml basic syntax +\code +SomeElement { + id: myObject + ... some other things here ... +} +\endcode Here we are defining a new object. We specify its 'type' first as SomeElement. Then within matching braces { ... } we specify the various parts of our diff --git a/doc/src/declarative/qmlruntime.qdoc b/doc/src/declarative/qmlruntime.qdoc index d44e774..9a84237 100644 --- a/doc/src/declarative/qmlruntime.qdoc +++ b/doc/src/declarative/qmlruntime.qdoc @@ -104,20 +104,22 @@ can be constructed directly instead. In this case, \c application.qml is loaded as a QDeclarativeComponent instance rather than placed into a view: \code - #include <QCoreApplication> + #include <QApplication> #include <QDeclarativeEngine> + #include <QDeclarativeContext> + #include <QDeclarativeComponent> int main(int argc, char *argv[]) { - QCoreApplication app(argc, argv); + QApplication app(argc, argv); QDeclarativeEngine engine; - QDeclarativeContext *windowContext = new QDeclarativeContext(engine.rootContext()); + QDeclarativeContext *objectContext = new QDeclarativeContext(engine.rootContext()); QDeclarativeComponent component(&engine, "application.qml"); - QObject *window = component.create(windowContext); + QObject *object = component.create(objectContext); - // ... delete window and windowContext when necessary + // ... delete object and objectContext when necessary return app.exec(); } diff --git a/doc/src/snippets/declarative/qml-intro/basic-syntax.qml b/doc/src/snippets/declarative/qml-intro/basic-syntax.qml deleted file mode 100644 index 686a927..0000000 --- a/doc/src/snippets/declarative/qml-intro/basic-syntax.qml +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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$ -** -****************************************************************************/ - -// Note: this file is not intended to be run. - -//! [basic syntax] -SomeElement { - id: myObject - ... some other things here ... -} -//! [basic syntax] diff --git a/doc/src/snippets/declarative/qml-intro/sequential-animation3.qml b/doc/src/snippets/declarative/qml-intro/sequential-animation3.qml index f83a966..6926f8a 100644 --- a/doc/src/snippets/declarative/qml-intro/sequential-animation3.qml +++ b/doc/src/snippets/declarative/qml-intro/sequential-animation3.qml @@ -39,6 +39,8 @@ ****************************************************************************/ //! [document] +import Qt 4.7 + Rectangle { id: mainRec width: 600 diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp index 63a2a77..b302393 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp @@ -1258,6 +1258,7 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event) if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) { d->clearDelayedPress(); d->stealMouse = false; + d->pressed = false; } return false; } diff --git a/src/declarative/qml/parser/qdeclarativejslexer.cpp b/src/declarative/qml/parser/qdeclarativejslexer.cpp index cd08658..1eb42e4 100644 --- a/src/declarative/qml/parser/qdeclarativejslexer.cpp +++ b/src/declarative/qml/parser/qdeclarativejslexer.cpp @@ -677,9 +677,9 @@ int Lexer::lex() setDone(Other); } else state = Start; - if (driver) driver->addComment(startpos, tokenLength(), startlineno, startcolumn); + if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2); } else if (current == 0) { - if (driver) driver->addComment(startpos, tokenLength(), startlineno, startcolumn); + if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2); setDone(Eof); } @@ -689,14 +689,14 @@ int Lexer::lex() setDone(Bad); err = UnclosedComment; errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed comment at end of file"); - if (driver) driver->addComment(startpos, tokenLength(), startlineno, startcolumn); + if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2); } else if (isLineTerminator()) { shiftWindowsLineBreak(); yylineno++; } else if (current == '*' && next1 == '/') { state = Start; shift(1); - if (driver) driver->addComment(startpos, tokenLength(), startlineno, startcolumn); + if (driver) driver->addComment(startpos+2, tokenLength()-3, startlineno, startcolumn+2); } break; diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index 3af892d..f439151 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -192,7 +192,7 @@ QDeclarativeObjectScriptClass::queryProperty(QObject *obj, const Identifier &nam if (!(hints & ImplicitObject)) { local.coreIndex = -1; lastData = &local; - return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; + return QScriptClass::HandlesWriteAccess; } return 0; diff --git a/src/declarative/qml/qdeclarativevmemetaobject.cpp b/src/declarative/qml/qdeclarativevmemetaobject.cpp index 689ed92..3e32006 100644 --- a/src/declarative/qml/qdeclarativevmemetaobject.cpp +++ b/src/declarative/qml/qdeclarativevmemetaobject.cpp @@ -707,11 +707,19 @@ void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QScriptValue &val void QDeclarativeVMEMetaObject::writeVarProperty(int id, const QVariant &value) { - if (value.userType() == QMetaType::QObjectStar) + bool needActivate = false; + if (value.userType() == QMetaType::QObjectStar) { + QObject *o = qvariant_cast<QObject *>(value); + needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o); data[id].setValue(qvariant_cast<QObject *>(value)); - else + } else { + needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() || + data[id].asQVariant().userType() != value.userType() || + data[id].asQVariant() != value); data[id].setValue(value); - activate(object, methodOffset + id, 0); + } + if (needActivate) + activate(object, methodOffset + id, 0); } void QDeclarativeVMEMetaObject::listChanged(int id) diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/in.qml b/tests/auto/declarative/qdeclarativeecmascript/data/in.qml new file mode 100644 index 0000000..0b5b0ba --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/in.qml @@ -0,0 +1,7 @@ +import Qt 4.7 + +Item { + id: root + property bool test1: "x" in root + property bool test2: !("foo" in root) +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 496cc05..76ca964 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -159,6 +159,7 @@ private slots: void qtbug_11600(); void nonscriptable(); void deleteLater(); + void in(); void include(); @@ -2553,6 +2554,16 @@ void tst_qdeclarativeecmascript::deleteLater() delete o; } +void tst_qdeclarativeecmascript::in() +{ + QDeclarativeComponent component(&engine, TEST_FILE("in.qml")); + QObject *o = component.create(); + QVERIFY(o != 0); + QCOMPARE(o->property("test1").toBool(), true); + QCOMPARE(o->property("test2").toBool(), true); + delete o; +} + QTEST_MAIN(tst_qdeclarativeecmascript) #include "tst_qdeclarativeecmascript.moc" diff --git a/tests/auto/declarative/qdeclarativelanguage/data/variantNotify.qml b/tests/auto/declarative/qdeclarativelanguage/data/variantNotify.qml new file mode 100644 index 0000000..e7aaf16 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/variantNotify.qml @@ -0,0 +1,13 @@ +import Qt 4.7 + +QtObject { + property int notifyCount: 0 + + property variant foo + onFooChanged: notifyCount++ + + Component.onCompleted: { + foo = 1; + foo = 1; + } +} diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index fc78663..dc00e16 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -142,8 +142,8 @@ private slots: void importsOrder(); void qmlAttachedPropertiesObjectMethod(); - void customOnProperty(); + void variantNotify(); // regression tests for crashes void crash1(); @@ -1685,6 +1685,20 @@ void tst_qdeclarativelanguage::customOnProperty() delete object; } +// QTBUG-12601 +void tst_qdeclarativelanguage::variantNotify() +{ + QDeclarativeComponent component(&engine, TEST_FILE("variantNotify.qml")); + + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("notifyCount").toInt(), 1); + + delete object; +} + void tst_qdeclarativelanguage::initTestCase() { registerTypes(); diff --git a/tests/auto/linguist/lupdate/testdata/good/parseqml/main.qml b/tests/auto/linguist/lupdate/testdata/good/parseqml/main.qml new file mode 100644 index 0000000..172bd65 --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parseqml/main.qml @@ -0,0 +1,97 @@ +import Qt 4.7 + +QtObject { + function translate() { + 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/parseqml/project.pro b/tests/auto/linguist/lupdate/testdata/good/parseqml/project.pro new file mode 100644 index 0000000..1040e22 --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parseqml/project.pro @@ -0,0 +1,3 @@ +SOURCES += main.qml + +TRANSLATIONS = project.ts diff --git a/tests/auto/linguist/lupdate/testdata/good/parseqml/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parseqml/project.ts.result new file mode 100644 index 0000000..7dac8cb --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parseqml/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.qml" line="89"/> + <source></source> + <translation type="unfinished"></translation> + </message> + <message id="qtn_needle"> + <location filename="main.qml" line="91"/> + <source></source> + <translation type="unfinished"></translation> + </message> + <message id="qtn_haystack"> + <location filename="main.qml" line="91"/> + <source></source> + <translation type="unfinished"></translation> + </message> + <message id="qtn_bar_baz" numerus="yes"> + <location filename="main.qml" line="95"/> + <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.qml" line="19"/> + <source>See other comment</source> + <extracomment>My second comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="42"/> + <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.qml" line="60"/> + <source>This string also has an identifier</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="85"/> + <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.qml" line="28"/> + <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.qml" line="48"/> + <source>The comment had no effect, really</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="66"/> + <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.qml" line="6"/> + <source>Two</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="10"/> + <source>Goodbye</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="34"/> + <source>I really love C++</source> + <extracomment>Another C-style comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="54"/> + <source>I refuse to comment on that</source> + <translation type="unfinished"></translation> + </message> + <message id="id_babar"> + <location filename="main.qml" line="81"/> + <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.qml" line="5"/> + <source>One</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="9"/> + <source>Hello</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="13"/> + <source>One</source> + <comment>not the same one</comment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="16"/> + <source>See comment</source> + <extracomment>My first comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="23"/> + <source>The comment explains it all</source> + <extracomment>My third comment spans two lines.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="31"/> + <source>I love C++</source> + <extracomment>C-style comment.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="38"/> + <source>Qt is the best</source> + <extracomment>C-style comment, followed by another one.</extracomment> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="45"/> + <source>The comment had no effect</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="51"/> + <source>No comment to your comment</source> + <translation type="unfinished"></translation> + </message> + <message id="id_foo"> + <location filename="main.qml" line="57"/> + <source>This string has an identifier</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="main.qml" line="63"/> + <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.qml" line="73"/> + <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.qml" line="83"/> + <source>This string has disambiguation</source> + <comment>Disambiguation</comment> + <translation type="unfinished"></translation> + </message> + <message numerus="yes"> + <location filename="main.qml" line="87"/> + <source>This string contains plurals</source> + <translation type="unfinished"> + <numerusform></numerusform> + </translation> + </message> +</context> +</TS> diff --git a/tools/linguist/lupdate/qdeclarative.cpp b/tools/linguist/lupdate/qdeclarative.cpp index ffcbf20..01b9a1d 100644 --- a/tools/linguist/lupdate/qdeclarative.cpp +++ b/tools/linguist/lupdate/qdeclarative.cpp @@ -71,6 +71,20 @@ class LU { using namespace QDeclarativeJS; +class Comment +{ +public: + Comment() : lastLine(-1) {} + QString extracomment; + QString msgid; + TranslatorMessage::ExtraData extra; + QString sourcetext; + int lastLine; + + bool isValid() const + { return !extracomment.isEmpty() || !msgid.isEmpty() || !sourcetext.isEmpty() || !extra.isEmpty(); } +}; + class FindTrCalls: protected AST::Visitor { public: @@ -82,6 +96,8 @@ public: accept(node); } + QList<Comment> comments; + protected: using AST::Visitor::visit; using AST::Visitor::endVisit; @@ -118,10 +134,23 @@ protected: plural = true; } + QString id; + QString extracomment; + TranslatorMessage::ExtraData extra; + Comment scomment = findComment(node->firstSourceLocation().startLine); + if (scomment.isValid()) { + extracomment = scomment.extracomment; + extra = scomment.extra; + id = scomment.msgid; + } + TranslatorMessage msg(m_component, source, comment, QString(), m_fileName, node->firstSourceLocation().startLine, QStringList(), TranslatorMessage::Unfinished, plural); + msg.setExtraComment(extracomment.simplified()); + msg.setId(id); + msg.setExtras(extra); m_translator->extend(msg); } } else if (idExpr->name->asString() == QLatin1String("qsTranslate") || @@ -144,6 +173,17 @@ protected: } if (!literal && m_bSource.isEmpty()) return; + + QString id; + QString extracomment; + TranslatorMessage::ExtraData extra; + Comment scomment = findComment(node->firstSourceLocation().startLine); + if (scomment.isValid()) { + extracomment = scomment.extracomment; + extra = scomment.extra; + id = scomment.msgid; + } + source = literal ? literal->value->asString() : m_bSource; AST::ArgumentList *commentNode = sourceNode->next; if (commentNode && AST::cast<AST::StringLiteral *>(commentNode->expression)) { @@ -159,15 +199,48 @@ protected: comment, QString(), m_fileName, node->firstSourceLocation().startLine, QStringList(), TranslatorMessage::Unfinished, plural); + msg.setExtraComment(extracomment.simplified()); + msg.setId(id); + msg.setExtras(extra); m_translator->extend(msg); } + } else if (idExpr->name->asString() == QLatin1String("qsTrId") || + idExpr->name->asString() == QLatin1String("QT_TRID_NOOP")) { + if (!node->arguments) + return; + AST::StringLiteral *literal = AST::cast<AST::StringLiteral *>(node->arguments->expression); + if (literal) { + + QString extracomment; + QString sourcetext; + TranslatorMessage::ExtraData extra; + Comment comment = findComment(node->firstSourceLocation().startLine); + if (comment.isValid()) { + extracomment = comment.extracomment; + sourcetext = comment.sourcetext; + extra = comment.extra; + } + + const QString id = literal->value->asString(); + bool plural = node->arguments->next; + + TranslatorMessage msg(QString(), QString(), + QString(), QString(), m_fileName, + node->firstSourceLocation().startLine, QStringList(), + TranslatorMessage::Unfinished, plural); + msg.setExtraComment(extracomment.simplified()); + msg.setId(id); + msg.setExtras(extra); + m_translator->extend(msg); + } } } } private: - bool createString(AST::BinaryExpression *b) { + bool createString(AST::BinaryExpression *b) + { if (!b || b->op != 0) return false; AST::BinaryExpression *l = AST::cast<AST::BinaryExpression *>(b->left); @@ -191,6 +264,23 @@ private: return true; } + Comment findComment(int loc) + { + if (comments.isEmpty()) + return Comment(); + + int i = 0; + int commentLoc = comments.at(i).lastLine; + while (commentLoc <= loc) { + if (commentLoc == loc) + return comments.at(i); + if (i == comments.count()-1) + break; + commentLoc = comments.at(++i).lastLine; + } + return Comment(); + } + Translator *m_translator; QString m_fileName; QString m_component; @@ -240,6 +330,54 @@ QString createErrorString(const QString &filename, const QString &code, Parser & return errorString; } +bool processComment(const QChar *chars, int length, Comment &comment) +{ + // Try to match the logic of the QtScript parser. + if (!length) + return comment.isValid(); + if (*chars == QLatin1Char(':') && chars[1].isSpace()) { + comment.extracomment += QString(chars+1, length-1); + } else if (*chars == QLatin1Char('=') && chars[1].isSpace()) { + comment.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) + comment.extra.insert(text.left(k), text.mid(k + 1).trimmed()); + } else if (*chars == QLatin1Char('%') && chars[1].isSpace()) { + comment.sourcetext.reserve(comment.sourcetext.length() + length-2); + ushort *ptr = (ushort *)comment.sourcetext.data() + comment.sourcetext.length(); + int p = 2, c; + forever { + if (p >= length) + break; + c = chars[p++].unicode(); + if (isspace(c)) + continue; + if (c != '"') + break; + forever { + if (p >= length) + break; + c = chars[p++].unicode(); + if (c == '"') + break; + if (c == '\\') { + if (p >= length) + break; + c = chars[p++].unicode(); + if (c == '\n') + break; + *ptr++ = '\\'; + } + *ptr++ = c; + } + } + comment.sourcetext.resize(ptr - (ushort *)comment.sourcetext.data()); + } + return comment.isValid(); +} + bool loadQml(Translator &translator, const QString &filename, ConversionData &cd) { cd.m_sourceFileName = filename; @@ -263,6 +401,25 @@ bool loadQml(Translator &translator, const QString &filename, ConversionData &cd if (parser.parse()) { FindTrCalls trCalls; + + // build up a list of comments that contain translation information. + for (int i = 0; i < driver.comments().size(); ++i) { + AST::SourceLocation loc = driver.comments().at(i); + QString commentStr = code.mid(loc.offset, loc.length); + + if (trCalls.comments.isEmpty() || trCalls.comments.last().lastLine != int(loc.startLine)) { + Comment comment; + comment.lastLine = loc.startLine+1; + if (processComment(commentStr.constData(), commentStr.length(), comment)) + trCalls.comments.append(comment); + } else { + Comment &lastComment = trCalls.comments.last(); + lastComment.lastLine += 1; + processComment(commentStr.constData(), commentStr.length(), lastComment); + } + } + + //find all tr calls in the code trCalls(&translator, filename, parser.ast()); } else { QString error = createErrorString(filename, code, parser); |