diff options
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_win.cpp | 2 | ||||
-rw-r--r-- | src/corelib/tools/qringbuffer_p.h | 27 | ||||
-rw-r--r-- | src/corelib/tools/qstring.h | 1 | ||||
-rw-r--r-- | src/corelib/tools/qstringbuilder.cpp | 24 | ||||
-rw-r--r-- | src/corelib/tools/qstringbuilder.h | 58 | ||||
-rw-r--r-- | src/gui/text/qtextcontrol.cpp | 4 | ||||
-rw-r--r-- | src/network/socket/qlocalsocket_win.cpp | 3 | ||||
-rw-r--r-- | tests/auto/linguist/lrelease/tst_lrelease.cpp | 13 | ||||
-rw-r--r-- | tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.cpp | 49 | ||||
-rw-r--r-- | tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.h | 51 | ||||
-rw-r--r-- | tests/auto/linguist/lupdate/testdata/good/parsecpp2/project.ts.result | 24 | ||||
-rw-r--r-- | tests/auto/qstringbuilder1/stringbuilder.cpp | 26 | ||||
-rw-r--r-- | tools/assistant/tools/assistant/helpviewer.cpp | 32 | ||||
-rw-r--r-- | tools/linguist/lrelease/main.cpp | 83 | ||||
-rw-r--r-- | tools/linguist/lupdate/cpp.cpp | 76 | ||||
-rw-r--r-- | tools/linguist/shared/qm.cpp | 35 | ||||
-rw-r--r-- | tools/linguist/shared/translator.h | 1 |
17 files changed, 385 insertions, 124 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index d13e1d1..b608d85 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -550,7 +550,7 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t) Q_Q(QEventDispatcherWin32); int ok = 0; - if (t->interval > 15 || !t->interval || !qtimeSetEvent) { + if (t->interval > 20 || !t->interval || !qtimeSetEvent) { ok = 1; if (!t->interval) // optimization for single-shot-zero-timer QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId)); diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h index c44346c..7c766cb 100644 --- a/src/corelib/tools/qringbuffer_p.h +++ b/src/corelib/tools/qringbuffer_p.h @@ -287,6 +287,33 @@ public: return -1; } + inline int indexOf(char c, int maxLength) const { + int index = 0; + int remain = qMin(size(), maxLength); + for (int i = 0; remain && i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + if (remain < end - start) { + end = start + remain; + remain = 0; + } else { + remain -= end - start; + } + const char *ptr = buffers.at(i).data() + start; + for (int j = start; j < end; ++j) { + if (*ptr++ == c) + return index; + ++index; + } + } + return -1; + } + inline int read(char *data, int maxLength) { int bytesToRead = qMin(size(), maxLength); int readSoFar = 0; diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 6c9a3ca..be95211 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -631,6 +631,7 @@ private: friend class QCharRef; friend class QTextCodec; friend class QStringRef; + friend class QAbstractConcatenable; friend inline bool qStringComparisonHelper(const QString &s1, const char *s2); friend inline bool qStringComparisonHelper(const QStringRef &s1, const char *s2); public: diff --git a/src/corelib/tools/qstringbuilder.cpp b/src/corelib/tools/qstringbuilder.cpp index 0a13218..4a16488 100644 --- a/src/corelib/tools/qstringbuilder.cpp +++ b/src/corelib/tools/qstringbuilder.cpp @@ -41,6 +41,8 @@ #include "qstringbuilder.h" +QT_BEGIN_NAMESPACE + /*! \class QLatin1Literal \internal @@ -143,3 +145,25 @@ Converts the \c QLatin1Literal into a \c QString object. */ + +/*! \internal */ +void QAbstractConcatenable::convertFromAscii(const char *a, int len, QChar *&out) +{ +#ifndef QT_NO_TEXTCODEC + if (QString::codecForCStrings) { + QString tmp = QString::fromAscii(a); + memcpy(out, reinterpret_cast<const char *>(tmp.constData()), sizeof(QChar) * tmp.size()); + out += tmp.length(); + return; + } +#endif + if (len == -1) { + while (*a) + *out++ = QLatin1Char(*a++); + } else { + for (int i = 0; i < len - 1; ++i) + *out++ = QLatin1Char(a[i]); + } +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index efa39b5..798d097 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -66,7 +66,7 @@ public: const char *data() const { return m_data; } template <int N> - QLatin1Literal(const char (&str)[N]) + QLatin1Literal(const char (&str)[N]) : m_size(N - 1), m_data(str) {} private: @@ -74,6 +74,21 @@ private: const char *m_data; }; +struct Q_CORE_EXPORT QAbstractConcatenable +{ +protected: + static void convertFromAscii(const char *a, int len, QChar *&out); + + static inline void convertFromAscii(char a, QChar *&out) + { +#ifndef QT_NO_TEXTCODEC + if (QString::codecForCStrings) + *out++ = QChar::fromAscii(a); + else +#endif + *out++ = QLatin1Char(a); + } +}; template <typename T> struct QConcatenable {}; @@ -87,9 +102,12 @@ public: { QString s(QConcatenable< QStringBuilder<A, B> >::size(*this), Qt::Uninitialized); - + QChar *d = s.data(); QConcatenable< QStringBuilder<A, B> >::appendTo(*this, d); + // this resize is necessary since we allocate a bit too much + // when dealing with variable sized 8-bit encodings + s.resize(d - s.data()); return s; } QByteArray toLatin1() const { return QString(*this).toLatin1(); } @@ -99,13 +117,13 @@ public: }; -template <> struct QConcatenable<char> +template <> struct QConcatenable<char> : private QAbstractConcatenable { typedef char type; static int size(const char) { return 1; } static inline void appendTo(const char c, QChar *&out) { - *out++ = QLatin1Char(c); + QAbstractConcatenable::convertFromAscii(c, out); } }; @@ -170,7 +188,7 @@ template <> struct QConcatenable<QString> { const int n = a.size(); memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); - out += n; + out += n; } }; @@ -182,53 +200,51 @@ template <> struct QConcatenable<QStringRef> { const int n = a.size(); memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); - out += n; + out += n; } }; #ifndef QT_NO_CAST_FROM_ASCII -template <int N> struct QConcatenable<char[N]> +template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable { typedef char type[N]; - static int size(const char[N]) { return N - 1; } + static int size(const char[N]) + { + return N - 1; + } static inline void appendTo(const char a[N], QChar *&out) { - for (int i = 0; i < N - 1; ++i) - *out++ = QLatin1Char(a[i]); + QAbstractConcatenable::convertFromAscii(a, N, out); } }; -template <int N> struct QConcatenable<const char[N]> +template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable { typedef const char type[N]; static int size(const char[N]) { return N - 1; } static inline void appendTo(const char a[N], QChar *&out) { - for (int i = 0; i < N - 1; ++i) - *out++ = QLatin1Char(a[i]); + QAbstractConcatenable::convertFromAscii(a, N, out); } }; -template <> struct QConcatenable<const char *> +template <> struct QConcatenable<const char *> : private QAbstractConcatenable { typedef char const *type; static int size(const char *a) { return qstrlen(a); } static inline void appendTo(const char *a, QChar *&out) { - while (*a) - *out++ = QLatin1Char(*a++); + QAbstractConcatenable::convertFromAscii(a, -1, out); } }; -template <> struct QConcatenable<QByteArray> +template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable { typedef QByteArray type; static int size(const QByteArray &ba) { return qstrnlen(ba.constData(), ba.size()); } static inline void appendTo(const QByteArray &ba, QChar *&out) { - const char *data = ba.constData(); - while (*data) - *out++ = QLatin1Char(*data++); + QAbstractConcatenable::convertFromAscii(ba.constData(), -1, out); } }; #endif @@ -237,7 +253,7 @@ template <typename A, typename B> struct QConcatenable< QStringBuilder<A, B> > { typedef QStringBuilder<A, B> type; - static int size(const type &p) + static int size(const type &p) { return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b); } diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index 9497b6f..9ffedf9 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1296,7 +1296,9 @@ QVariant QTextControl::loadResource(int type, const QUrl &name) void QTextControlPrivate::_q_updateBlock(const QTextBlock &block) { Q_Q(QTextControl); - emit q->updateRequest(q->blockBoundingRect(block)); + QRectF br = q->blockBoundingRect(block); + br.setRight(qreal(INT_MAX)); // the block might have shrunk + emit q->updateRequest(br); } QRectF QTextControlPrivate::rectForPosition(int position) const diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp index 8a745ab..d812d88 100644 --- a/src/network/socket/qlocalsocket_win.cpp +++ b/src/network/socket/qlocalsocket_win.cpp @@ -363,7 +363,8 @@ bool QLocalSocket::canReadLine() const Q_D(const QLocalSocket); if (state() != ConnectedState) return false; - return (d->readBuffer.indexOf('\n') != -1 || QIODevice::canReadLine()); + return (QIODevice::canReadLine() + || d->readBuffer.indexOf('\n', d->actualReadBufferSize) != -1); } void QLocalSocket::close() diff --git a/tests/auto/linguist/lrelease/tst_lrelease.cpp b/tests/auto/linguist/lrelease/tst_lrelease.cpp index 39de8a1..93cb97c 100644 --- a/tests/auto/linguist/lrelease/tst_lrelease.cpp +++ b/tests/auto/linguist/lrelease/tst_lrelease.cpp @@ -60,6 +60,7 @@ private slots: void mixedcodecs(); void compressed(); void idbased(); + void markuntranslated(); void dupes(); private: @@ -210,6 +211,18 @@ void tst_lrelease::idbased() QCOMPARE(qtTrId("untranslated_id"), QString::fromAscii("This has no translation.")); } +void tst_lrelease::markuntranslated() +{ + QVERIFY(!QProcess::execute(binDir + "/lrelease -markuntranslated # -idbased testdata/idbased.ts")); + + QTranslator translator; + QVERIFY(translator.load("testdata/idbased.qm")); + qApp->installTranslator(&translator); + + QCOMPARE(qtTrId("test_id"), QString::fromAscii("This is a test string.")); + QCOMPARE(qtTrId("untranslated_id"), QString::fromAscii("#This has no translation.")); +} + void tst_lrelease::dupes() { QProcess proc; diff --git a/tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.cpp b/tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.cpp index eaa271a..7ddb68f 100644 --- a/tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.cpp +++ b/tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.cpp @@ -63,3 +63,52 @@ line c++ comment } (with brace) #define This is another // comment in } define \ something } comment } // complain here + + + +// Nested class in same file +class TopLevel { + Q_OBJECT + + class Nested; +}; + +class TopLevel::Nested { + void foo(); +}; + +TopLevel::Nested::foo() +{ + TopLevel::tr("TopLevel"); +} + +// Nested class in other file +#include "main.h" + +class TopLevel2::Nested { + void foo(); +}; + +TopLevel2::Nested::foo() +{ + TopLevel2::tr("TopLevel2"); +} + + + +namespace NameSpace { +class ToBeUsed; +} + +// using statement before class definition +using NameSpace::ToBeUsed; + +class NameSpace::ToBeUsed { + Q_OBJECT + void caller(); +}; + +void ToBeUsed::caller() +{ + tr("NameSpace::ToBeUsed"); +} diff --git a/tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.h b/tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.h new file mode 100644 index 0000000..54a76ab --- /dev/null +++ b/tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// IMPORTANT!!!! If you want to add testdata to this file, +// always add it to the end in order to not change the linenumbers of translations!!! + +class TopLevel2 { + Q_OBJECT + + class Nested; +}; + + diff --git a/tests/auto/linguist/lupdate/testdata/good/parsecpp2/project.ts.result b/tests/auto/linguist/lupdate/testdata/good/parsecpp2/project.ts.result index 07a7469..6f48e27 100644 --- a/tests/auto/linguist/lupdate/testdata/good/parsecpp2/project.ts.result +++ b/tests/auto/linguist/lupdate/testdata/good/parsecpp2/project.ts.result @@ -1,4 +1,28 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.0"> +<context> + <name>NameSpace::ToBeUsed</name> + <message> + <location filename="main.cpp" line="113"/> + <source>NameSpace::ToBeUsed</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TopLevel</name> + <message> + <location filename="main.cpp" line="82"/> + <source>TopLevel</source> + <translation type="unfinished"></translation> + </message> +</context> +<context> + <name>TopLevel2</name> + <message> + <location filename="main.cpp" line="94"/> + <source>TopLevel2</source> + <translation type="unfinished"></translation> + </message> +</context> </TS> diff --git a/tests/auto/qstringbuilder1/stringbuilder.cpp b/tests/auto/qstringbuilder1/stringbuilder.cpp index f35d4d2..9dc467e 100644 --- a/tests/auto/qstringbuilder1/stringbuilder.cpp +++ b/tests/auto/qstringbuilder1/stringbuilder.cpp @@ -41,8 +41,15 @@ #define LITERAL "some literal" +// "some literal", but replacing all vocals by their umlauted UTF-8 string :) +#define UTF8_LITERAL "s\xc3\xb6m\xc3\xab l\xc3\xaft\xc3\xabr\xc3\xa4l" + void runScenario() { + // set codec for C strings to 0, enforcing Latin1 + QTextCodec::setCodecForCStrings(0); + QVERIFY(!QTextCodec::codecForCStrings()); + QLatin1Literal l1literal(LITERAL); QLatin1String l1string(LITERAL); QString string(l1string); @@ -75,5 +82,24 @@ void runScenario() QCOMPARE(r, r2); r = string P ba; QCOMPARE(r, r2); + + // now test with codec for C strings set + QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); + QVERIFY(QTextCodec::codecForCStrings()); + QCOMPARE(QTextCodec::codecForCStrings()->name(), QByteArray("UTF-8")); + + string = QString::fromUtf8(UTF8_LITERAL); + r2 = QString::fromUtf8(UTF8_LITERAL UTF8_LITERAL); + ba = UTF8_LITERAL; + + r = string P UTF8_LITERAL; + QCOMPARE(r.size(), r2.size()); + QCOMPARE(r, r2); + r = UTF8_LITERAL P string; + QCOMPARE(r, r2); + r = ba P string; + QCOMPARE(r, r2); + r = string P ba; + QCOMPARE(r, r2); #endif } diff --git a/tools/assistant/tools/assistant/helpviewer.cpp b/tools/assistant/tools/assistant/helpviewer.cpp index 53f3822..c888a5f 100644 --- a/tools/assistant/tools/assistant/helpviewer.cpp +++ b/tools/assistant/tools/assistant/helpviewer.cpp @@ -137,24 +137,22 @@ QNetworkReply *HelpNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) { const QString& scheme = request.url().scheme(); - if (scheme == QLatin1String("qthelp") || scheme == QLatin1String("about")) { - const QUrl& url = request.url(); - QString mimeType = url.toString(); - if (mimeType.endsWith(QLatin1String(".svg")) - || mimeType.endsWith(QLatin1String(".svgz"))) { - mimeType = QLatin1String("image/svg+xml"); - } - else if (mimeType.endsWith(QLatin1String(".css"))) { - mimeType = QLatin1String("text/css"); - } - else if (mimeType.endsWith(QLatin1String(".js"))) { - mimeType = QLatin1String("text/javascript"); - } else { - mimeType = QLatin1String("text/html"); - } - return new HelpNetworkReply(request, helpEngine->fileData(url), mimeType); + const QUrl& url = request.url(); + QString mimeType = url.toString(); + if (mimeType.endsWith(QLatin1String(".svg")) + || mimeType.endsWith(QLatin1String(".svgz"))) { + mimeType = QLatin1String("image/svg+xml"); } - return QNetworkAccessManager::createRequest(op, request, outgoingData); + else if (mimeType.endsWith(QLatin1String(".css"))) { + mimeType = QLatin1String("text/css"); + } + else if (mimeType.endsWith(QLatin1String(".js"))) { + mimeType = QLatin1String("text/javascript"); + } else { + mimeType = QLatin1String("text/html"); + } + + return new HelpNetworkReply(request, helpEngine->fileData(url), mimeType); } class HelpPage : public QWebPage diff --git a/tools/linguist/lrelease/main.cpp b/tools/linguist/lrelease/main.cpp index 2867849..ecaed27 100644 --- a/tools/linguist/lrelease/main.cpp +++ b/tools/linguist/lrelease/main.cpp @@ -79,6 +79,9 @@ static void printUsage() " -removeidentical\n" " If the translated text is the same as\n" " the source text, do not include the message\n" + " -markuntranslated <prefix>\n" + " If a message has no real translation, use the source text\n" + " prefixed with the given string instead\n" " -silent\n" " Do not explain what is being done\n" " -version\n" @@ -100,15 +103,14 @@ static bool loadTsFile(Translator &tor, const QString &tsFileName, bool /* verbo } static bool releaseTranslator(Translator &tor, const QString &qmFileName, - bool verbose, bool ignoreUnfinished, - bool removeIdentical, bool idBased, TranslatorSaveMode mode) + ConversionData &cd, bool removeIdentical) { - Translator::reportDuplicates(tor.resolveDuplicates(), qmFileName, verbose); + Translator::reportDuplicates(tor.resolveDuplicates(), qmFileName, cd.isVerbose()); - if (verbose) + if (cd.isVerbose()) printOut(QCoreApplication::tr( "Updating '%1'...\n").arg(qmFileName)); if (removeIdentical) { - if ( verbose ) + if (cd.isVerbose()) printOut(QCoreApplication::tr( "Removing translations equal to source text in '%1'...\n").arg(qmFileName)); tor.stripIdenticalSourceTranslations(); } @@ -120,12 +122,7 @@ static bool releaseTranslator(Translator &tor, const QString &qmFileName, return false; } - ConversionData cd; tor.normalizeTranslations(cd); - cd.m_verbose = verbose; - cd.m_ignoreUnfinished = ignoreUnfinished; - cd.m_idBased = idBased; - cd.m_saveMode = mode; bool ok = tor.release(&file, cd); file.close(); @@ -139,11 +136,11 @@ static bool releaseTranslator(Translator &tor, const QString &qmFileName, return true; } -static bool releaseTsFile(const QString& tsFileName, bool verbose, - bool ignoreUnfinished, bool removeIdentical, bool idBased, TranslatorSaveMode mode) +static bool releaseTsFile(const QString& tsFileName, + ConversionData &cd, bool removeIdentical) { Translator tor; - if (!loadTsFile(tor, tsFileName, verbose)) + if (!loadTsFile(tor, tsFileName, cd.isVerbose())) return false; QString qmFileName = tsFileName; @@ -155,7 +152,7 @@ static bool releaseTsFile(const QString& tsFileName, bool verbose, } qmFileName += QLatin1String(".qm"); - return releaseTranslator(tor, qmFileName, verbose, ignoreUnfinished, removeIdentical, idBased, mode); + return releaseTranslator(tor, qmFileName, cd, removeIdentical); } int main(int argc, char **argv) @@ -166,37 +163,40 @@ int main(int argc, char **argv) if (translator.load(QLatin1String("lrelease_") + QLocale::system().name())) app.installTranslator(&translator); - bool verbose = true; // the default is true starting with Qt 4.2 - bool ignoreUnfinished = false; - bool idBased = false; - // the default mode is SaveEverything starting with Qt 4.2 - TranslatorSaveMode mode = SaveEverything; + ConversionData cd; + cd.m_verbose = true; // the default is true starting with Qt 4.2 bool removeIdentical = false; Translator tor; + QStringList inputFiles; QString outputFile; - int numFiles = 0; for (int i = 1; i < argc; ++i) { if (args[i] == QLatin1String("-compress")) { - mode = SaveStripped; + cd.m_saveMode = SaveStripped; continue; } else if (args[i] == QLatin1String("-idbased")) { - idBased = true; + cd.m_idBased = true; continue; } else if (args[i] == QLatin1String("-nocompress")) { - mode = SaveEverything; + cd.m_saveMode = SaveEverything; continue; } else if (args[i] == QLatin1String("-removeidentical")) { removeIdentical = true; continue; } else if (args[i] == QLatin1String("-nounfinished")) { - ignoreUnfinished = true; + cd.m_ignoreUnfinished = true; continue; + } else if (args[i] == QLatin1String("-markuntranslated")) { + if (i == argc - 1) { + printUsage(); + return 1; + } + cd.m_unTrPrefix = args[++i]; } else if (args[i] == QLatin1String("-silent")) { - verbose = false; + cd.m_verbose = false; continue; } else if (args[i] == QLatin1String("-verbose")) { - verbose = true; + cd.m_verbose = true; continue; } else if (args[i] == QLatin1String("-version")) { printOut(QCoreApplication::tr( "lrelease version %1\n").arg(QLatin1String(QT_VERSION_STR)) ); @@ -206,41 +206,37 @@ int main(int argc, char **argv) printUsage(); return 1; } - i++; - outputFile = args[i]; + outputFile = args[++i]; } else if (args[i] == QLatin1String("-help")) { printUsage(); return 0; - } else if (args[i][0] == QLatin1Char('-')) { + } else if (args[i].startsWith(QLatin1Char('-'))) { printUsage(); return 1; } else { - numFiles++; + inputFiles << args[i]; } } - if (numFiles == 0) { + if (inputFiles.isEmpty()) { printUsage(); return 1; } - for (int i = 1; i < argc; ++i) { - if (args[i][0] == QLatin1Char('-') || args[i] == outputFile) - continue; - - if (args[i].endsWith(QLatin1String(".pro"), Qt::CaseInsensitive) - || args[i].endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) { + foreach (const QString &inputFile, inputFiles) { + if (inputFile.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive) + || inputFile.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) { QHash<QByteArray, QStringList> varMap; - bool ok = evaluateProFile(args[i], verbose, &varMap ); + bool ok = evaluateProFile(inputFile, cd.isVerbose(), &varMap); if (ok) { QStringList translations = varMap.value("TRANSLATIONS"); if (translations.isEmpty()) { qWarning("lrelease warning: Met no 'TRANSLATIONS' entry in" " project file '%s'\n", - qPrintable(args[i])); + qPrintable(inputFile)); } else { foreach (const QString &trans, translations) - if (!releaseTsFile(trans, verbose, ignoreUnfinished, removeIdentical, idBased, mode)) + if (!releaseTsFile(trans, cd, removeIdentical)) return 1; } } else { @@ -251,18 +247,17 @@ int main(int argc, char **argv) } } else { if (outputFile.isEmpty()) { - if (!releaseTsFile(args[i], verbose, ignoreUnfinished, removeIdentical, idBased, mode)) + if (!releaseTsFile(inputFile, cd, removeIdentical)) return 1; } else { - if (!loadTsFile(tor, args[i], verbose)) + if (!loadTsFile(tor, inputFile, cd.isVerbose())) return 1; } } } if (!outputFile.isEmpty()) - return releaseTranslator(tor, outputFile, verbose, ignoreUnfinished, - removeIdentical, idBased, mode) ? 0 : 1; + return releaseTranslator(tor, outputFile, cd, removeIdentical) ? 0 : 1; return 0; } diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index 4d89156..fb95a95 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -135,6 +135,11 @@ struct Namespace { // Nested classes may be forward-declared inside a definition, and defined in another file. // The latter will detach the class' child list, so clones need a backlink to the original // definition (either one in case of multiple definitions). + // Namespaces can have tr() functions as well, so we need to track parent definitions for + // them as well. The complication is that we may have to deal with a forrest instead of + // a tree - in that case the parent will be arbitrary. However, it seem likely that + // Q_DECLARE_TR_FUNCTIONS would be used either in "class-like" namespaces with a central + // header or only locally in a file. Namespace *classDef; QString trQualification; @@ -256,17 +261,20 @@ private: bool qualifyOneCallbackUsing(const Namespace *ns, void *context) const; bool qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, NamespaceList *resolved) const; - bool fullyQualify(const NamespaceList &namespaces, const QList<HashString> &segments, - bool isDeclaration, + bool fullyQualify(const NamespaceList &namespaces, int nsCnt, + const QList<HashString> &segments, bool isDeclaration, NamespaceList *resolved, QStringList *unresolved) const; - bool fullyQualify(const NamespaceList &namespaces, const QString &segments, - bool isDeclaration, + bool fullyQualify(const NamespaceList &namespaces, + const QList<HashString> &segments, bool isDeclaration, + NamespaceList *resolved, QStringList *unresolved) const; + bool fullyQualify(const NamespaceList &namespaces, + const QString &segments, bool isDeclaration, NamespaceList *resolved, QStringList *unresolved) const; bool findNamespaceCallback(const Namespace *ns, void *context) const; const Namespace *findNamespace(const NamespaceList &namespaces, int nsCount = -1) const; void enterNamespace(NamespaceList *namespaces, const HashString &name); void truncateNamespaces(NamespaceList *namespaces, int lenght); - Namespace *modifyNamespace(NamespaceList *namespaces, bool tryOrigin = true); + Namespace *modifyNamespace(NamespaceList *namespaces, bool haveLast = true); enum { Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, @@ -780,7 +788,7 @@ uint CppParser::getToken() if (yyCh == EOF) { qWarning("%s:%d: Unterminated C++ comment\n", qPrintable(yyFileName), yyLineNo); - return Tok_Comment; + break; } *ptr++ = yyCh; @@ -958,7 +966,7 @@ void CppParser::loadState(const SavedState *state) pendingContext = state->pendingContext; } -Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool tryOrigin) +Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool haveLast) { Namespace *pns, *ns = &results->rootNamespace; for (int i = 1; i < namespaces->count(); ++i) { @@ -966,7 +974,7 @@ Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool tryOrigin) if (!(ns = pns->children.value(namespaces->at(i)))) { do { ns = new Namespace; - if (tryOrigin) + if (haveLast || i < namespaces->count() - 1) if (const Namespace *ons = findNamespace(*namespaces, i + 1)) ns->classDef = ons->classDef; pns->children.insert(namespaces->at(i), ns); @@ -1052,7 +1060,18 @@ bool CppParser::qualifyOneCallbackOwn(const Namespace *ns, void *context) const } QHash<HashString, NamespaceList>::ConstIterator nsai = ns->aliases.constFind(data->segment); if (nsai != ns->aliases.constEnd()) { - *data->resolved = *nsai; + const NamespaceList &nsl = *nsai; + if (nsl.last().value().isEmpty()) { // Delayed alias resolution + NamespaceList &nslIn = *const_cast<NamespaceList *>(&nsl); + nslIn.removeLast(); + NamespaceList nslOut; + if (!fullyQualify(data->namespaces, data->nsCount, nslIn, false, &nslOut, 0)) { + const_cast<Namespace *>(ns)->aliases.remove(data->segment); + return false; + } + nslIn = nslOut; + } + *data->resolved = nsl; return true; } return false; @@ -1081,8 +1100,8 @@ bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsCnt, const Has return visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackUsing, &data); } -bool CppParser::fullyQualify(const NamespaceList &namespaces, const QList<HashString> &segments, - bool isDeclaration, +bool CppParser::fullyQualify(const NamespaceList &namespaces, int nsCnt, + const QList<HashString> &segments, bool isDeclaration, NamespaceList *resolved, QStringList *unresolved) const { int nsIdx; @@ -1099,7 +1118,7 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QList<HashSt nsIdx = 0; } else { initSegIdx = 0; - nsIdx = namespaces.count() - 1; + nsIdx = nsCnt - 1; } do { @@ -1122,8 +1141,16 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QList<HashSt return false; } -bool CppParser::fullyQualify(const NamespaceList &namespaces, const QString &quali, - bool isDeclaration, +bool CppParser::fullyQualify(const NamespaceList &namespaces, + const QList<HashString> &segments, bool isDeclaration, + NamespaceList *resolved, QStringList *unresolved) const +{ + return fullyQualify(namespaces, namespaces.count(), + segments, isDeclaration, resolved, unresolved); +} + +bool CppParser::fullyQualify(const NamespaceList &namespaces, + const QString &quali, bool isDeclaration, NamespaceList *resolved, QStringList *unresolved) const { static QString strColons(QLatin1String("::")); @@ -1633,9 +1660,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } if (fullName.isEmpty()) break; - NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) - modifyNamespace(&namespaces, false)->aliases[ns] = nsl; + fullName.append(HashString(QString())); // Mark as unresolved + modifyNamespace(&namespaces)->aliases[ns] = fullName; } } else if (yyTok == Tok_LeftBrace) { // Anonymous namespace @@ -1661,7 +1687,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } NamespaceList nsl; if (fullyQualify(namespaces, fullName, false, &nsl, 0)) - modifyNamespace(&namespaces, false)->usings << HashStringList(nsl); + modifyNamespace(&namespaces)->usings << HashStringList(nsl); } else { QList<HashString> fullName; if (yyTok == Tok_ColonColon) @@ -1676,9 +1702,13 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } if (fullName.isEmpty()) break; - NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) - modifyNamespace(&namespaces, true)->aliases[nsl.last()] = nsl; + // using-declarations cannot rename classes, so the last element of + // fullName is already the resolved name we actually want. + // As we do no resolution here, we'll collect useless usings of data + // members and methods as well. This is no big deal. + HashString &ns = fullName.last(); + fullName.append(HashString(QString())); // Mark as unresolved + modifyNamespace(&namespaces)->aliases[ns] = fullName; } break; case Tok_tr: @@ -1875,7 +1905,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) break; case Tok_Q_DECLARE_TR_FUNCTIONS: if (getMacroArgs()) { - Namespace *ns = modifyNamespace(&namespaces, true); + Namespace *ns = modifyNamespace(&namespaces); ns->hasTrFunctions = true; ns->trQualification = yyWord; ns->trQualification.detach(); @@ -1883,7 +1913,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) yyTok = getToken(); break; case Tok_Q_OBJECT: - modifyNamespace(&namespaces, true)->hasTrFunctions = true; + modifyNamespace(&namespaces)->hasTrFunctions = true; yyTok = getToken(); break; case Tok_Ident: diff --git a/tools/linguist/shared/qm.cpp b/tools/linguist/shared/qm.cpp index 317a07e..5965aac 100644 --- a/tools/linguist/shared/qm.cpp +++ b/tools/linguist/shared/qm.cpp @@ -172,8 +172,8 @@ public: bool save(QIODevice *iod); - void insert(const TranslatorMessage &msg, bool forceComment); - void insertIdBased(const TranslatorMessage &message); + void insert(const TranslatorMessage &msg, const QStringList &tlns, bool forceComment); + void insertIdBased(const TranslatorMessage &message, const QStringList &tlns); void squeeze(TranslatorSaveMode mode); @@ -186,7 +186,8 @@ private: // on turn should be the same as passed to the actual tr(...) calls QByteArray originalBytes(const QString &str, bool isUtf8) const; - void insertInternal(const TranslatorMessage &message, bool forceComment, bool isUtf8); + void insertInternal(const TranslatorMessage &message, const QStringList &tlns, + bool forceComment, bool isUtf8); static Prefix commonPrefix(const ByteTranslatorMessage &m1, const ByteTranslatorMessage &m2); @@ -413,12 +414,13 @@ void Releaser::squeeze(TranslatorSaveMode mode) } } -void Releaser::insertInternal(const TranslatorMessage &message, bool forceComment, bool isUtf8) +void Releaser::insertInternal(const TranslatorMessage &message, const QStringList &tlns, + bool forceComment, bool isUtf8) { ByteTranslatorMessage bmsg(originalBytes(message.context(), isUtf8), originalBytes(message.sourceText(), isUtf8), originalBytes(message.comment(), isUtf8), - message.translations()); + tlns); if (!forceComment) { ByteTranslatorMessage bmsg2( bmsg.context(), bmsg.sourceText(), QByteArray(""), bmsg.translations()); @@ -430,20 +432,15 @@ void Releaser::insertInternal(const TranslatorMessage &message, bool forceCommen m_messages.insert(bmsg, 0); } -void Releaser::insert(const TranslatorMessage &message, bool forceComment) +void Releaser::insert(const TranslatorMessage &message, const QStringList &tlns, bool forceComment) { - insertInternal(message, forceComment, message.isUtf8()); + insertInternal(message, tlns, forceComment, message.isUtf8()); if (message.isUtf8() && message.isNonUtf8()) - insertInternal(message, forceComment, false); + insertInternal(message, tlns, forceComment, false); } -void Releaser::insertIdBased(const TranslatorMessage &message) +void Releaser::insertIdBased(const TranslatorMessage &message, const QStringList &tlns) { - QStringList tlns = message.translations(); - if (message.type() == TranslatorMessage::Unfinished) - for (int i = 0; i < tlns.size(); ++i) - if (tlns.at(i).isEmpty()) - tlns[i] = message.sourceText(); ByteTranslatorMessage bmsg("", originalBytes(message.id(), false), "", tlns); m_messages.insert(bmsg, 0); } @@ -725,10 +722,16 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData } else { ++finished; } + QStringList tlns = msg.translations(); + if (msg.type() == TranslatorMessage::Unfinished + && (cd.m_idBased || !cd.m_unTrPrefix.isEmpty())) + for (int j = 0; j < tlns.size(); ++j) + if (tlns.at(j).isEmpty()) + tlns[j] = cd.m_unTrPrefix + msg.sourceText(); if (cd.m_idBased) { if (!msg.context().isEmpty() || !msg.comment().isEmpty()) ++droppedData; - releaser.insertIdBased(msg); + releaser.insertIdBased(msg, tlns); } else { // Drop the comment in (context, sourceText, comment), // unless the context is empty, @@ -739,7 +742,7 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData msg.comment().isEmpty() || msg.context().isEmpty() || translator.contains(msg.context(), msg.sourceText(), QString()); - releaser.insert(msg, forceComment); + releaser.insert(msg, tlns, forceComment); } } } diff --git a/tools/linguist/shared/translator.h b/tools/linguist/shared/translator.h index 1dd6a59..ef81d2a 100644 --- a/tools/linguist/shared/translator.h +++ b/tools/linguist/shared/translator.h @@ -86,6 +86,7 @@ public: QString m_defaultContext; QByteArray m_codecForSource; // CPP, PO & QM specific QByteArray m_outputCodec; // PO specific + QString m_unTrPrefix; // QM specific QString m_sourceFileName; QString m_targetFileName; QDir m_sourceDir; |