diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2009-09-29 04:09:01 (GMT) |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2009-09-29 04:09:01 (GMT) |
commit | 575ad2c60482b279f828cfa87186b5fbb10f76c6 (patch) | |
tree | 101df52cd4b769dc8d10ef60714f25d819636e70 /tools | |
parent | a913e326409062bbc1cad4d5898181c7b81cba23 (diff) | |
parent | 638f46a96b68d21137c4903c68015752ebdf58dc (diff) | |
download | Qt-575ad2c60482b279f828cfa87186b5fbb10f76c6.zip Qt-575ad2c60482b279f828cfa87186b5fbb10f76c6.tar.gz Qt-575ad2c60482b279f828cfa87186b5fbb10f76c6.tar.bz2 |
Merge branch '4.6' of git@scm.dev.nokia.troll.no:qt/qt into kinetic-declarativeui
Conflicts:
configure.exe
mkspecs/features/qt.prf
Diffstat (limited to 'tools')
23 files changed, 747 insertions, 438 deletions
diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 3bbc607..afb2dec 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1169,7 +1169,7 @@ void Configure::parseCmdLine() dictionary["QTBUILDINSTRUCTION"] = dictionary["MAKE"]; if (dictionary.contains("XQMAKESPEC")) { if (dictionary["XQMAKESPEC"].startsWith("symbian")) { - dictionary["QTBUILDINSTRUCTION"] = dictionary["MAKE"] + QString(" debug-winscw|debug-armv5|release-armv5"); + dictionary["QTBUILDINSTRUCTION"] = QString("make debug-winscw|debug-armv5|release-armv5"); } else if (dictionary["XQMAKESPEC"].startsWith("wince")) { dictionary["QTBUILDINSTRUCTION"] = QString("setcepaths.bat ") + dictionary["XQMAKESPEC"] + QString(" && ") + dictionary["MAKE"]; diff --git a/tools/designer/src/lib/shared/qdesigner_menubar.cpp b/tools/designer/src/lib/shared/qdesigner_menubar.cpp index 6d231ca..80c7b53 100644 --- a/tools/designer/src/lib/shared/qdesigner_menubar.cpp +++ b/tools/designer/src/lib/shared/qdesigner_menubar.cpp @@ -104,6 +104,8 @@ QDesignerMenuBar::QDesignerMenuBar(QWidget *parent) : setContextMenuPolicy(Qt::DefaultContextMenu); setAcceptDrops(true); // ### fake + // Fake property: Keep the menu bar editable in the form even if a native menu bar is used. + setNativeMenuBar(false); m_addMenu->setText(tr("Type Here")); addAction(m_addMenu); diff --git a/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp b/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp index 851bfc1..7574fdd 100644 --- a/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp +++ b/tools/designer/src/lib/shared/qdesigner_propertysheet.cpp @@ -63,6 +63,7 @@ #include <QtGui/QApplication> #include <QtGui/QToolBar> #include <QtGui/QMainWindow> +#include <QtGui/QMenuBar> QT_BEGIN_NAMESPACE @@ -611,9 +612,15 @@ QDesignerPropertySheet::QDesignerPropertySheet(QObject *object, QObject *parent) createFakeProperty(QLatin1String("dragEnabled")); // windowModality is visible only for the main container, in which case the form windows enables it on loading setVisible(createFakeProperty(QLatin1String("windowModality")), false); - if (qobject_cast<const QToolBar *>(d->m_object)) // prevent toolbars from being dragged off + if (qobject_cast<const QToolBar *>(d->m_object)) { // prevent toolbars from being dragged off createFakeProperty(QLatin1String("floatable"), QVariant(true)); - + } else { + if (qobject_cast<const QMenuBar *>(d->m_object)) { + // Keep the menu bar editable in the form even if a native menu bar is used. + const bool nativeMenuBarDefault = !qApp->testAttribute(Qt::AA_DontUseNativeMenuBar); + createFakeProperty(QLatin1String("nativeMenuBar"), QVariant(nativeMenuBarDefault)); + } + } if (d->m_canHaveLayoutAttributes) { static const QString layoutGroup = QLatin1String("Layout"); const char* fakeLayoutProperties[] = { diff --git a/tools/designer/src/lib/shared/qdesigner_utils_p.h b/tools/designer/src/lib/shared/qdesigner_utils_p.h index 0b9f925..a860b61 100644 --- a/tools/designer/src/lib/shared/qdesigner_utils_p.h +++ b/tools/designer/src/lib/shared/qdesigner_utils_p.h @@ -1,4 +1,3 @@ - /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). diff --git a/tools/designer/translations/translations.pro b/tools/designer/translations/translations.pro index 8395259..c8cd76d 100644 --- a/tools/designer/translations/translations.pro +++ b/tools/designer/translations/translations.pro @@ -133,7 +133,7 @@ HEADERS += ../../shared/findwidget/abstractfindwidget.h \ TRANSLATIONS=$$[QT_INSTALL_TRANSLATIONS]/designer_de.ts \ $$[QT_INSTALL_TRANSLATIONS]/designer_ja.ts \ $$[QT_INSTALL_TRANSLATIONS]/designer_pl.ts \ + $$[QT_INSTALL_TRANSLATIONS]/designer_ru.ts \ $$[QT_INSTALL_TRANSLATIONS]/designer_zh_CN.ts \ $$[QT_INSTALL_TRANSLATIONS]/designer_zh_TW.ts \ $$[QT_INSTALL_TRANSLATIONS]/designer_untranslated.ts - diff --git a/tools/linguist/lconvert/main.cpp b/tools/linguist/lconvert/main.cpp index fb869ec..67553a0 100644 --- a/tools/linguist/lconvert/main.cpp +++ b/tools/linguist/lconvert/main.cpp @@ -103,6 +103,8 @@ static int usage(const QStringList &args) " Drop obsolete messages.\n\n" " --no-finished\n" " Drop finished messages.\n\n" + " --sort-contexts\n" + " Sort contexts in output TS file alphabetically.\n\n" " --locations {absolute|relative|none}\n" " Override how source code references are saved in TS files.\n" " Default is absolute.\n\n" @@ -201,6 +203,8 @@ int main(int argc, char *argv[]) noObsolete = true; } else if (args[i] == QLatin1String("-no-finished")) { noFinished = true; + } else if (args[i] == QLatin1String("-sort-contexts")) { + cd.m_sortContexts = true; } else if (args[i] == QLatin1String("-locations")) { if (++i >= args.size()) return usage(args); diff --git a/tools/linguist/linguist/linguist.pro b/tools/linguist/linguist/linguist.pro index 314163c..00ebec1 100644 --- a/tools/linguist/linguist/linguist.pro +++ b/tools/linguist/linguist/linguist.pro @@ -81,9 +81,6 @@ PROJECTNAME = Qt \ Linguist target.path = $$[QT_INSTALL_BINS] INSTALLS += target -linguisttranslations.files = *.qm -linguisttranslations.path = $$[QT_INSTALL_TRANSLATIONS] -INSTALLS += linguisttranslations phrasebooks.path = $$[QT_INSTALL_DATA]/phrasebooks # ## will this work on windows? diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp index be86c93..ed41edb 100644 --- a/tools/linguist/lupdate/cpp.cpp +++ b/tools/linguist/lupdate/cpp.cpp @@ -43,6 +43,7 @@ #include <translator.h> +#include <QtCore/QBitArray> #include <QtCore/QDebug> #include <QtCore/QFileInfo> #include <QtCore/QStack> @@ -56,74 +57,133 @@ QT_BEGIN_NAMESPACE /* qmake ignore Q_OBJECT */ -static const char MagicComment[] = "TRANSLATOR "; +static QString MagicComment(QLatin1String("TRANSLATOR")); #define STRING(s) static QString str##s(QLatin1String(#s)) //#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this -uint qHash(const QStringList &qsl) +class HashString { +public: + HashString() : m_hashed(false) {} + explicit HashString(const QString &str) : m_str(str), m_hashed(false) {} + void setValue(const QString &str) { m_str = str; m_hashed = false; } + const QString &value() const { return m_str; } + bool operator==(const HashString &other) const { return m_str == other.m_str; } +private: + QString m_str; + mutable uint m_hash; + mutable bool m_hashed; + friend uint qHash(const HashString &str); +}; + +uint qHash(const HashString &str) { - uint hash = 0; - foreach (const QString &qs, qsl) { - hash ^= qHash(qs) ^ 0xa09df22f; - hash = (hash << 13) | (hash >> 19); + if (!str.m_hashed) { + str.m_hashed = true; + str.m_hash = qHash(str.m_str); + } + return str.m_hash; +} + +class HashStringList { +public: + explicit HashStringList(const QList<HashString> &list) : m_list(list), m_hashed(false) {} + const QList<HashString> &value() const { return m_list; } + bool operator==(const HashStringList &other) const { return m_list == other.m_list; } +private: + QList<HashString> m_list; + mutable uint m_hash; + mutable bool m_hashed; + friend uint qHash(const HashStringList &list); +}; + +uint qHash(const HashStringList &list) +{ + if (!list.m_hashed) { + list.m_hashed = true; + uint hash = 0; + foreach (const HashString &qs, list.m_list) { + hash ^= qHash(qs) ^ 0xa09df22f; + hash = (hash << 13) | (hash >> 19); + } + list.m_hash = hash; } - return hash; + return list.m_hash; } +typedef QList<HashString> NamespaceList; + struct Namespace { Namespace() : - isClass(false), - hasTrFunctions(false), needsTrFunctions(false), complained(false) + classDef(this), + hasTrFunctions(false), complained(false) {} + ~Namespace() + { + qDeleteAll(children); + } - QString name; - QMap<QString, Namespace *> children; - QMap<QString, QStringList> aliases; - QSet<QStringList> usings; + QHash<HashString, Namespace *> children; + QHash<HashString, NamespaceList> aliases; + QList<HashStringList> usings; - int fileId; + // Class declarations set no flags and create no namespaces, so they are ignored. + // Class definitions may appear multiple times - but only because we are trying to + // "compile" all sources irrespective of build configuration. + // 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). + Namespace *classDef; - bool isClass; + QString trQualification; bool hasTrFunctions; - bool needsTrFunctions; bool complained; // ... that tr functions are missing. }; -typedef QList<Namespace *> NamespaceList; +static int nextFileId; -struct ParseResults { - - ParseResults() +class VisitRecorder { +public: + VisitRecorder() { - static int nextFileId; - rootNamespace.fileId = nextFileId++; - tor = 0; + m_ba.resize(nextFileId); } - bool detachNamespace(Namespace **that); - Namespace *include(Namespace *that, const Namespace *other); - void unite(const ParseResults *other); + bool tryVisit(int fileId) + { + if (m_ba.at(fileId)) + return false; + m_ba[fileId] = true; + return true; + } +private: + QBitArray m_ba; +}; +struct ParseResults { + int fileId; Namespace rootNamespace; - Translator *tor; - QSet<QString> allIncludes; + QSet<const ParseResults *> includes; }; typedef QHash<QString, const ParseResults *> ParseResultHash; +typedef QHash<QString, const Translator *> TranslatorHash; class CppFiles { public: static const ParseResults *getResults(const QString &cleanFile); static void setResults(const QString &cleanFile, const ParseResults *results); + static const Translator *getTranslator(const QString &cleanFile); + static void setTranslator(const QString &cleanFile, const Translator *results); static bool isBlacklisted(const QString &cleanFile); static void setBlacklisted(const QString &cleanFile); private: static ParseResultHash &parsedFiles(); + static TranslatorHash &translatedFiles(); static QSet<QString> &blacklistedFiles(); }; @@ -133,16 +193,16 @@ public: CppParser(ParseResults *results = 0); void setInput(const QString &in); void setInput(QTextStream &ts, const QString &fileName); - void setTranslator(Translator *tor) { results->tor = tor; } + void setTranslator(Translator *_tor) { tor = _tor; } void parse(const QString &initialContext, ConversionData &cd, QSet<QString> &inclusions); void parseInternal(ConversionData &cd, QSet<QString> &inclusions); - const ParseResults *getResults() const { return results; } + const ParseResults *recordResults(bool isHeader); void deleteResults() { delete results; } struct SavedState { - QStringList namespaces; + NamespaceList namespaces; QStack<int> namespaceDepths; - QStringList functionContext; + NamespaceList functionContext; QString functionContextUnresolved; QString pendingContext; }; @@ -164,10 +224,10 @@ private: uint getChar(); uint getToken(); + bool getMacroArgs(); bool match(uint t); bool matchString(QString *s); bool matchEncoding(bool *utf8); - bool matchInteger(qlonglong *number); bool matchStringOrNull(QString *s); bool matchExpression(); @@ -185,15 +245,28 @@ private: static QString stringifyNamespace(const NamespaceList &namespaces); static QStringList stringListifyNamespace(const NamespaceList &namespaces); - void modifyNamespace(NamespaceList *namespaces); - NamespaceList resolveNamespaces(const QStringList &segments); - bool qualifyOne(const NamespaceList &namespaces, int nsIdx, const QString &segment, - NamespaceList *resolved); - bool fullyQualify(const NamespaceList &namespaces, const QStringList &segments, + typedef bool (CppParser::*VisitNamespaceCallback)(const Namespace *ns, void *context) const; + bool visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context, + VisitRecorder &vr, const ParseResults *rslt) const; + bool visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context) const; + static QStringList stringListifySegments(const QList<HashString> &namespaces); + bool qualifyOneCallbackOwn(const Namespace *ns, void *context) const; + 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, + NamespaceList *resolved, QStringList *unresolved) const; + bool fullyQualify(const NamespaceList &namespaces, const QString &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved); - void enterNamespace(NamespaceList *namespaces, const QString &name); + 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); enum { Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, @@ -202,7 +275,7 @@ private: Tok_Ident, Tok_Comment, Tok_String, Tok_Arrow, Tok_Colon, Tok_ColonColon, Tok_Equals, Tok_LeftBrace = 30, Tok_RightBrace, Tok_LeftParen, Tok_RightParen, Tok_Comma, Tok_Semicolon, - Tok_Integer = 40, + Tok_Null = 40, Tok_Integer, Tok_QuotedInclude = 50, Tok_AngledInclude, Tok_Other = 99 }; @@ -227,7 +300,7 @@ private: QTextCodec *yySourceCodec; bool yySourceIsUnicode; QString yyInStr; - int yyInPos; + const ushort *yyInPtr; // Parser state uint yyTok; @@ -239,6 +312,7 @@ private: QString prospectiveContext; QString pendingContext; ParseResults *results; + Translator *tor; bool directInclude; SavedState savedState; @@ -248,6 +322,7 @@ private: CppParser::CppParser(ParseResults *_results) { + tor = 0; if (_results) { results = _results; directInclude = true; @@ -255,7 +330,6 @@ CppParser::CppParser(ParseResults *_results) results = new ParseResults; directInclude = false; } - yyInPos = 0; yyBraceDepth = 0; yyParenDepth = 0; yyCurLineNo = 1; @@ -308,29 +382,32 @@ void CppParser::setInput(QTextStream &ts, const QString &fileName) uint CppParser::getChar() { - int len = yyInStr.size(); - const ushort *uc = (const ushort *)yyInStr.unicode(); + const ushort *uc = yyInPtr; forever { - if (yyInPos >= len) + ushort c = *uc; + if (!c) { + yyInPtr = uc; return EOF; - uint c = uc[yyInPos++]; - if (c == '\\' && yyInPos < len) { - if (uc[yyInPos] == '\n') { + } + ++uc; + if (c == '\\') { + ushort cc = *uc; + if (cc == '\n') { ++yyCurLineNo; - ++yyInPos; + ++uc; continue; } - if (uc[yyInPos] == '\r') { + if (cc == '\r') { ++yyCurLineNo; - ++yyInPos; - if (yyInPos < len && uc[yyInPos] == '\n') - ++yyInPos; + ++uc; + if (*uc == '\n') + ++uc; continue; } } if (c == '\r') { - if (yyInPos < len && uc[yyInPos] == '\n') - ++yyInPos; + if (*uc == '\n') + ++uc; c = '\n'; ++yyCurLineNo; yyAtNewline = true; @@ -340,10 +417,39 @@ uint CppParser::getChar() } else if (c != ' ' && c != '\t' && c != '#') { yyAtNewline = false; } + yyInPtr = uc; return c; } } +// This ignores commas, parens and comments. +// IOW, it understands only a single, simple argument. +bool CppParser::getMacroArgs() +{ + // Failing this assertion would mean losing the preallocated buffer. + Q_ASSERT(yyWord.isDetached()); + yyWord.resize(0); + + while (isspace(yyCh)) + yyCh = getChar(); + if (yyCh != '(') + return false; + do { + yyCh = getChar(); + } while (isspace(yyCh)); + ushort *ptr = (ushort *)yyWord.unicode(); + while (yyCh != ')') { + if (yyCh == EOF) + return false; + *ptr++ = yyCh; + yyCh = getChar(); + } + yyCh = getChar(); + for (; ptr != (ushort *)yyWord.unicode() && isspace(*(ptr - 1)); --ptr) ; + yyWord.resize(ptr - (ushort *)yyWord.unicode()); + return true; +} + STRING(Q_OBJECT); STRING(Q_DECLARE_TR_FUNCTIONS); STRING(QT_TR_NOOP); @@ -561,12 +667,13 @@ uint CppParser::getToken() } } while (yyCh != '\n' && yyCh != EOF); yyCh = getChar(); - } else if (isalpha(yyCh) || yyCh == '_') { + } else if ((yyCh >= 'A' && yyCh <= 'Z') || (yyCh >= 'a' && yyCh <= 'z') || yyCh == '_') { ushort *ptr = (ushort *)yyWord.unicode(); do { *ptr++ = yyCh; yyCh = getChar(); - } while (isalnum(yyCh) || yyCh == '_'); + } while ((yyCh >= 'A' && yyCh <= 'Z') || (yyCh >= 'a' && yyCh <= 'z') + || (yyCh >= '0' && yyCh <= '9') || yyCh == '_'); yyWord.resize(ptr - (ushort *)yyWord.unicode()); //qDebug() << "IDENT: " << yyWord; @@ -795,6 +902,17 @@ uint CppParser::getToken() yyCh = getChar(); return Tok_Semicolon; case '0': + yyCh = getChar(); + if (yyCh == 'x') { + do { + yyCh = getChar(); + } while ((yyCh >= '0' && yyCh <= '9') + || (yyCh >= 'a' && yyCh <= 'f') || (yyCh >= 'A' && yyCh <= 'F')); + return Tok_Integer; + } + if (yyCh < '0' || yyCh > '9') + return Tok_Null; + // Fallthrough case '1': case '2': case '3': @@ -804,25 +922,10 @@ uint CppParser::getToken() case '7': case '8': case '9': - { - QByteArray ba; - ba += yyCh; + do { yyCh = getChar(); - bool hex = yyCh == 'x'; - if (hex) { - ba += yyCh; - yyCh = getChar(); - } - while (hex ? isxdigit(yyCh) : isdigit(yyCh)) { - ba += yyCh; - yyCh = getChar(); - } - bool ok; - yyInteger = ba.toLongLong(&ok); - if (ok) - return Tok_Integer; - break; - } + } while (yyCh >= '0' && yyCh <= '9'); + return Tok_Integer; default: yyCh = getChar(); break; @@ -839,86 +942,40 @@ uint CppParser::getToken() void CppParser::saveState(SavedState *state) { - state->namespaces = stringListifyNamespace(namespaces); + state->namespaces = namespaces; state->namespaceDepths = namespaceDepths; - state->functionContext = stringListifyNamespace(functionContext); + state->functionContext = functionContext; state->functionContextUnresolved = functionContextUnresolved; state->pendingContext = pendingContext; } void CppParser::loadState(const SavedState *state) { - namespaces = resolveNamespaces(state->namespaces); + namespaces = state->namespaces; namespaceDepths = state->namespaceDepths; - functionContext = resolveNamespaces(state->functionContext); + functionContext = state->functionContext; functionContextUnresolved = state->functionContextUnresolved; pendingContext = state->pendingContext; } -bool ParseResults::detachNamespace(Namespace **that) +Namespace *CppParser::modifyNamespace(NamespaceList *namespaces, bool tryOrigin) { - if ((*that)->fileId != rootNamespace.fileId) { - Namespace *newThat = new Namespace; - *newThat = **that; - newThat->fileId = rootNamespace.fileId; - *that = newThat; - return true; - } - return false; -} - -Namespace *ParseResults::include(Namespace *that, const Namespace *other) -{ - Namespace *origThat = that; - foreach (Namespace *otherSub, other->children) { - if (Namespace *thisSub = that->children.value(otherSub->name)) { - // Don't make these cause a detach - it's best - // (though not necessary) if they are shared - thisSub->isClass |= otherSub->isClass; - thisSub->hasTrFunctions |= otherSub->hasTrFunctions; - thisSub->needsTrFunctions |= otherSub->needsTrFunctions; - thisSub->complained |= otherSub->complained; - - if (Namespace *newSub = include(thisSub, otherSub)) { - thisSub = newSub; - detachNamespace(&that); - that->children[thisSub->name] = thisSub; - } - } else { - detachNamespace(&that); - that->children[otherSub->name] = otherSub; - } - } - if ((that->aliases != other->aliases && !other->aliases.isEmpty()) - || (that->usings != other->usings && !other->usings.isEmpty())) { - detachNamespace(&that); - that->aliases.unite(other->aliases); - that->usings.unite(other->usings); - } - return (that != origThat) ? that : 0; -} - -void ParseResults::unite(const ParseResults *other) -{ - allIncludes.unite(other->allIncludes); - include(&rootNamespace, &other->rootNamespace); -} - -void CppParser::modifyNamespace(NamespaceList *namespaces) -{ - Namespace *pns = 0; - int i = namespaces->count(); - forever { - --i; - Namespace *ns = namespaces->at(i); - bool detached = results->detachNamespace(&ns); - if (pns) - ns->children[pns->name] = pns; - if (!detached) // Known to be true for root namespace - return; + Namespace *pns, *ns = &results->rootNamespace; + for (int i = 1; i < namespaces->count(); ++i) { pns = ns; - namespaces->replace(i, ns); + if (!(ns = pns->children.value(namespaces->at(i)))) { + do { + ns = new Namespace; + if (tryOrigin) + if (const Namespace *ons = findNamespace(*namespaces, i + 1)) + ns->classDef = ons->classDef; + pns->children.insert(namespaces->at(i), ns); + pns = ns; + } while (++i < namespaces->count()); + break; + } } + return ns; } QString CppParser::stringifyNamespace(const NamespaceList &namespaces) @@ -927,7 +984,7 @@ QString CppParser::stringifyNamespace(const NamespaceList &namespaces) for (int i = 1; i < namespaces.count(); ++i) { if (i > 1) ret += QLatin1String("::"); - ret += namespaces.at(i)->name; + ret += namespaces.at(i).value(); } return ret; } @@ -936,58 +993,102 @@ QStringList CppParser::stringListifyNamespace(const NamespaceList &namespaces) { QStringList ret; for (int i = 1; i < namespaces.count(); ++i) - ret << namespaces.at(i)->name; + ret << namespaces.at(i).value(); return ret; } -// This function is called only with known-existing namespaces -NamespaceList CppParser::resolveNamespaces(const QStringList &segments) +bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context, + VisitRecorder &vr, const ParseResults *rslt) const { - NamespaceList ret; - Namespace *ns = &results->rootNamespace; - ret << ns; - foreach (const QString &seg, segments) { - ns = ns->children.value(seg); - ret << ns; - } + const Namespace *ns = &rslt->rootNamespace; + for (int i = 1; i < nsCount; ++i) + if (!(ns = ns->children.value(namespaces.at(i)))) + goto supers; + if ((this->*callback)(ns, context)) + return true; +supers: + foreach (const ParseResults *sup, rslt->includes) + if (vr.tryVisit(sup->fileId) + && visitNamespace(namespaces, nsCount, callback, context, vr, sup)) + return true; + return false; +} + +bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, + VisitNamespaceCallback callback, void *context) const +{ + VisitRecorder vr; + return visitNamespace(namespaces, nsCount, callback, context, vr, results); +} + +QStringList CppParser::stringListifySegments(const QList<HashString> &segments) +{ + QStringList ret; + for (int i = 0; i < segments.count(); ++i) + ret << segments.at(i).value(); return ret; } -bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsIdx, const QString &segment, - NamespaceList *resolved) +struct QualifyOneData { + const NamespaceList &namespaces; + int nsCount; + const HashString &segment; + NamespaceList *resolved; + QSet<HashStringList> visitedUsings; +}; + +bool CppParser::qualifyOneCallbackOwn(const Namespace *ns, void *context) const { - const Namespace *ns = namespaces.at(nsIdx); - QMap<QString, Namespace *>::ConstIterator cnsi = ns->children.constFind(segment); - if (cnsi != ns->children.constEnd()) { - *resolved = namespaces.mid(0, nsIdx + 1); - *resolved << *cnsi; + QualifyOneData *data = (QualifyOneData *)context; + if (ns->children.contains(data->segment)) { + *data->resolved = data->namespaces.mid(0, data->nsCount); + *data->resolved << data->segment; return true; } - QMap<QString, QStringList>::ConstIterator nsai = ns->aliases.constFind(segment); + QHash<HashString, NamespaceList>::ConstIterator nsai = ns->aliases.constFind(data->segment); if (nsai != ns->aliases.constEnd()) { - *resolved = resolveNamespaces(*nsai); + *data->resolved = *nsai; return true; } - foreach (const QStringList &use, ns->usings) { - NamespaceList usedNs = resolveNamespaces(use); - if (qualifyOne(usedNs, usedNs.count() - 1, segment, resolved)) - return true; - } return false; } -bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList &segments, +bool CppParser::qualifyOneCallbackUsing(const Namespace *ns, void *context) const +{ + QualifyOneData *data = (QualifyOneData *)context; + foreach (const HashStringList &use, ns->usings) + if (!data->visitedUsings.contains(use)) { + data->visitedUsings.insert(use); + if (qualifyOne(use.value(), use.value().count(), data->segment, data->resolved)) + return true; + } + return false; +} + +bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsCnt, const HashString &segment, + NamespaceList *resolved) const +{ + QualifyOneData data = { namespaces, nsCnt, segment, resolved, QSet<HashStringList>() }; + + if (visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackOwn, &data)) + return true; + + return visitNamespace(namespaces, nsCnt, &CppParser::qualifyOneCallbackUsing, &data); +} + +bool CppParser::fullyQualify(const NamespaceList &namespaces, const QList<HashString> &segments, bool isDeclaration, - NamespaceList *resolved, QStringList *unresolved) + NamespaceList *resolved, QStringList *unresolved) const { int nsIdx; int initSegIdx; - if (segments.first().isEmpty()) { + if (segments.first().value().isEmpty()) { // fully qualified if (segments.count() == 1) { resolved->clear(); - *resolved << &results->rootNamespace; + *resolved << HashString(QString()); return true; } initSegIdx = 1; @@ -998,12 +1099,12 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList } do { - if (qualifyOne(namespaces, nsIdx, segments[initSegIdx], resolved)) { + if (qualifyOne(namespaces, nsIdx + 1, segments[initSegIdx], resolved)) { int segIdx = initSegIdx; while (++segIdx < segments.count()) { - if (!qualifyOne(*resolved, resolved->count() - 1, segments[segIdx], resolved)) { + if (!qualifyOne(*resolved, resolved->count(), segments[segIdx], resolved)) { if (unresolved) - *unresolved = segments.mid(segIdx); + *unresolved = stringListifySegments(segments.mid(segIdx)); return false; } } @@ -1011,23 +1112,44 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, const QStringList } } while (!isDeclaration && --nsIdx >= 0); resolved->clear(); - *resolved << &results->rootNamespace; + *resolved << HashString(QString()); if (unresolved) - *unresolved = segments.mid(initSegIdx); + *unresolved = stringListifySegments(segments.mid(initSegIdx)); return false; } -void CppParser::enterNamespace(NamespaceList *namespaces, const QString &name) +bool CppParser::fullyQualify(const NamespaceList &namespaces, const QString &quali, + bool isDeclaration, + NamespaceList *resolved, QStringList *unresolved) const { - Namespace *ns = namespaces->last()->children.value(name); - if (!ns) { - ns = new Namespace; - ns->fileId = results->rootNamespace.fileId; - ns->name = name; - modifyNamespace(namespaces); - namespaces->last()->children[name] = ns; - } - *namespaces << ns; + static QString strColons(QLatin1String("::")); + + QList<HashString> segments; + foreach (const QString &str, quali.split(strColons)) // XXX slow, but needs to be fast(?) + segments << HashString(str); + return fullyQualify(namespaces, segments, isDeclaration, resolved, unresolved); +} + +bool CppParser::findNamespaceCallback(const Namespace *ns, void *context) const +{ + *((const Namespace **)context) = ns; + return true; +} + +const Namespace *CppParser::findNamespace(const NamespaceList &namespaces, int nsCount) const +{ + const Namespace *ns = 0; + if (nsCount == -1) + nsCount = namespaces.count(); + visitNamespace(namespaces, nsCount, &CppParser::findNamespaceCallback, &ns); + return ns; +} + +void CppParser::enterNamespace(NamespaceList *namespaces, const HashString &name) +{ + *namespaces << name; + if (!findNamespace(*namespaces)) + modifyNamespace(namespaces, false); } void CppParser::truncateNamespaces(NamespaceList *namespaces, int length) @@ -1047,6 +1169,13 @@ ParseResultHash &CppFiles::parsedFiles() return parsed; } +TranslatorHash &CppFiles::translatedFiles() +{ + static TranslatorHash tors; + + return tors; +} + QSet<QString> &CppFiles::blacklistedFiles() { static QSet<QString> blacklisted; @@ -1056,10 +1185,7 @@ QSet<QString> &CppFiles::blacklistedFiles() const ParseResults *CppFiles::getResults(const QString &cleanFile) { - ParseResultHash::ConstIterator it = parsedFiles().find(cleanFile); - if (it == parsedFiles().constEnd()) - return 0; - return *it; + return parsedFiles().value(cleanFile); } void CppFiles::setResults(const QString &cleanFile, const ParseResults *results) @@ -1067,6 +1193,16 @@ void CppFiles::setResults(const QString &cleanFile, const ParseResults *results) parsedFiles().insert(cleanFile, results); } +const Translator *CppFiles::getTranslator(const QString &cleanFile) +{ + return translatedFiles().value(cleanFile); +} + +void CppFiles::setTranslator(const QString &cleanFile, const Translator *tor) +{ + translatedFiles().insert(cleanFile, tor); +} + bool CppFiles::isBlacklisted(const QString &cleanFile) { return blacklistedFiles().contains(cleanFile); @@ -1077,6 +1213,12 @@ void CppFiles::setBlacklisted(const QString &cleanFile) blacklistedFiles().insert(cleanFile); } +static bool isHeader(const QString &name) +{ + QString fileExt = QFileInfo(name).suffix(); + return fileExt.isEmpty() || fileExt.startsWith(QLatin1Char('h'), Qt::CaseInsensitive); +} + void CppParser::processInclude(const QString &file, ConversionData &cd, QSet<QString> &inclusions) { @@ -1095,21 +1237,15 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, bool isIndirect = false; if (namespaces.count() == 1 && functionContext.count() == 1 && functionContextUnresolved.isEmpty() && pendingContext.isEmpty() - && !CppFiles::isBlacklisted(cleanFile)) { - QString fileExt = QFileInfo(cleanFile).suffix(); - if (fileExt.isEmpty() || fileExt.startsWith(QLatin1Char('h'), Qt::CaseInsensitive)) { - - if (results->allIncludes.contains(cleanFile)) - return; - results->allIncludes.insert(cleanFile); + && !CppFiles::isBlacklisted(cleanFile) + && isHeader(cleanFile)) { - if (const ParseResults *res = CppFiles::getResults(cleanFile)) { - results->unite(res); - return; - } - - isIndirect = true; + if (const ParseResults *res = CppFiles::getResults(cleanFile)) { + results->includes.insert(res); + return; } + + isIndirect = true; } QFile f(cleanFile); @@ -1134,8 +1270,7 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, } parser.setInput(ts, cleanFile); parser.parse(cd.m_defaultContext, cd, inclusions); - CppFiles::setResults(cleanFile, parser.getResults()); - results->unite(parser.results); + results->includes.insert(parser.recordResults(true)); } else { CppParser parser(results); parser.namespaces = namespaces; @@ -1144,12 +1279,6 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, parser.pendingContext = pendingContext; parser.setInput(ts, cleanFile); parser.parseInternal(cd, inclusions); - // Don't wreak havoc if not enough braces were found. - truncateNamespaces(&parser.namespaces, namespaces.count()); - truncateNamespaces(&parser.functionContext, functionContext.count()); - // Copy them back - the pointers might have changed. - namespaces = parser.namespaces; - functionContext = parser.functionContext; // Avoid that messages obtained by direct scanning are used CppFiles::setBlacklisted(cleanFile); } @@ -1176,26 +1305,28 @@ bool CppParser::match(uint t) bool CppParser::matchString(QString *s) { - bool matches = (yyTok == Tok_String); + bool matches = false; s->clear(); - while (yyTok == Tok_String) { + forever { + while (yyTok == Tok_Comment) + yyTok = getToken(); + if (yyTok != Tok_String) + return matches; + matches = true; *s += yyWord; s->detach(); - do { - yyTok = getToken(); - } while (yyTok == Tok_Comment); + yyTok = getToken(); } - return matches; } +STRING(QApplication); +STRING(QCoreApplication); +STRING(UnicodeUTF8); +STRING(DefaultCodec); +STRING(CodecForTr); + bool CppParser::matchEncoding(bool *utf8) { - STRING(QApplication); - STRING(QCoreApplication); - STRING(UnicodeUTF8); - STRING(DefaultCodec); - STRING(CodecForTr); - if (yyTok != Tok_Ident) return false; if (yyWord == strQApplication || yyWord == strQCoreApplication) { @@ -1211,28 +1342,14 @@ bool CppParser::matchEncoding(bool *utf8) if (yyWord == strDefaultCodec || yyWord == strCodecForTr) { *utf8 = false; yyTok = getToken(); - return true; + return true; } return false; } -bool CppParser::matchInteger(qlonglong *number) -{ - bool matches = (yyTok == Tok_Integer); - if (matches) { - yyTok = getToken(); - *number = yyInteger; - } - return matches; -} - bool CppParser::matchStringOrNull(QString *s) { - bool matches = matchString(s); - qlonglong num = 0; - if (!matches) - matches = matchInteger(&num); - return matches && num == 0; + return matchString(s) || match(Tok_Null); } /* @@ -1251,7 +1368,7 @@ bool CppParser::matchStringOrNull(QString *s) */ bool CppParser::matchExpression() { - if (match(Tok_Integer)) + if (match(Tok_Null) || match(Tok_Integer)) return true; int parenlevel = 0; @@ -1339,16 +1456,16 @@ void CppParser::recordMessage( msg.setExtras(extra); if ((utf8 || yyForceUtf8) && !yyCodecIsUtf8 && msg.needs8Bit()) msg.setUtf8(true); - results->tor->append(msg); + tor->append(msg); } void CppParser::parse(const QString &initialContext, ConversionData &cd, QSet<QString> &inclusions) { - if (results->tor) - yyCodecIsUtf8 = (results->tor->codecName() == "UTF-8"); + if (tor) + yyCodecIsUtf8 = (tor->codecName() == "UTF-8"); - namespaces << &results->rootNamespace; + namespaces << HashString(); functionContext = namespaces; functionContextUnresolved = initialContext; @@ -1375,6 +1492,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) bool yyTokColonSeen = false; // Start of c'tor's initializer list yyWord.reserve(yyInStr.size()); // Rather insane. That's because we do no length checking. + yyInPtr = (const ushort *)yyInStr.unicode(); yyCh = getChar(); yyTok = getToken(); while (yyTok != Tok_Eof) { @@ -1411,8 +1529,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } case Tok_friend: yyTok = getToken(); - // Ensure that these don't end up being interpreted as forward declarations - // (they are forwards, but with different namespacing). + // These are forward declarations, so ignore them. if (yyTok == Tok_class) yyTok = getToken(); break; @@ -1423,7 +1540,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) */ yyTok = getToken(); if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) { - QStringList fct; + QList<HashString> quali; + HashString fct; do { /* This code should execute only once, but we play @@ -1433,50 +1551,50 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) */ text = yyWord; text.detach(); - fct = QStringList(text); + fct.setValue(text); yyTok = getToken(); } while (yyTok == Tok_Ident); while (yyTok == Tok_ColonColon) { yyTok = getToken(); if (yyTok != Tok_Ident) break; // Oops ... + quali << fct; text = yyWord; text.detach(); - fct += text; + fct.setValue(text); yyTok = getToken(); } - if (fct.count() > 1) { - // Forward-declared class definitions can be namespaced - NamespaceList nsl; - if (!fullyQualify(namespaces, fct, true, &nsl, 0)) { - qWarning("%s:%d: Ignoring definition of undeclared qualified class\n", - qPrintable(yyFileName), yyLineNo); - break; - } - namespaceDepths.push(namespaces.count()); - namespaces = nsl; - } else { - namespaceDepths.push(namespaces.count()); - enterNamespace(&namespaces, fct.first()); - } - namespaces.last()->isClass = true; - while (yyTok == Tok_Comment) yyTok = getToken(); if (yyTok == Tok_Colon) { - // Skip any token until '{' since lupdate might do things wrong if it finds + // Skip any token until '{' since we might do things wrong if we find // a '::' token here. do { yyTok = getToken(); } while (yyTok != Tok_LeftBrace && yyTok != Tok_Eof); } else { if (yyTok != Tok_LeftBrace) { - // Obviously a forward decl - truncateNamespaces(&namespaces, namespaceDepths.pop()); + // Obviously a forward declaration. We skip those, as they + // don't create actually usable namespaces. break; } } + if (!quali.isEmpty()) { + // Forward-declared class definitions can be namespaced. + NamespaceList nsl; + if (!fullyQualify(namespaces, quali, true, &nsl, 0)) { + qWarning("%s:%d: Ignoring definition of undeclared qualified class\n", + qPrintable(yyFileName), yyLineNo); + break; + } + namespaceDepths.push(namespaces.count()); + namespaces = nsl; + } else { + namespaceDepths.push(namespaces.count()); + } + enterNamespace(&namespaces, fct); + functionContext = namespaces; functionContextUnresolved.clear(); // Pointless prospectiveContext.clear(); @@ -1487,8 +1605,9 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) yyTokColonSeen = false; yyTok = getToken(); if (yyTok == Tok_Ident) { - QString ns = yyWord; - ns.detach(); + text = yyWord; + text.detach(); + HashString ns = HashString(text); yyTok = getToken(); if (yyTok == Tok_LeftBrace) { namespaceDepths.push(namespaces.count()); @@ -1496,25 +1615,23 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) yyTok = getToken(); } else if (yyTok == Tok_Equals) { // e.g. namespace Is = OuterSpace::InnerSpace; - QStringList fullName; + QList<HashString> fullName; yyTok = getToken(); if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } if (fullName.isEmpty()) break; NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { - modifyNamespace(&namespaces); - namespaces.last()->aliases.insert(ns, stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, false)->aliases[ns] = nsl; } } else if (yyTok == Tok_LeftBrace) { // Anonymous namespace @@ -1524,49 +1641,45 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) break; case Tok_using: yyTok = getToken(); + // XXX this should affect only the current scope, not the entire current namespace if (yyTok == Tok_namespace) { - QStringList fullName; + QList<HashString> fullName; yyTok = getToken(); if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } NamespaceList nsl; - QStringList unresolved; - if (fullyQualify(namespaces, fullName, false, &nsl, &unresolved)) { - modifyNamespace(&namespaces); - namespaces.last()->usings.insert(stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, false)->usings << HashStringList(nsl); } else { - QStringList fullName; + QList<HashString> fullName; if (yyTok == Tok_ColonColon) - fullName.append(QString()); + fullName.append(HashString(QString())); while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { if (yyTok == Tok_Ident) { text = yyWord; text.detach(); - fullName.append(text); + fullName.append(HashString(text)); } yyTok = getToken(); } if (fullName.isEmpty()) break; NamespaceList nsl; - if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { - modifyNamespace(&namespaces); - namespaces.last()->aliases.insert(nsl.last()->name, stringListifyNamespace(nsl)); - } + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) + modifyNamespace(&namespaces, true)->aliases[nsl.last()] = nsl; } break; case Tok_tr: case Tok_trUtf8: - if (!results->tor) + if (!tor) goto case_default; if (!sourcetext.isEmpty()) qWarning("%s:%d: //%% cannot be used with tr() / QT_TR_NOOP(). Ignoring\n", @@ -1589,8 +1702,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } if (!pendingContext.isEmpty()) { QStringList unresolved; - if (!fullyQualify(namespaces, pendingContext.split(strColons), true, - &functionContext, &unresolved)) { + if (!fullyQualify(namespaces, pendingContext, true, &functionContext, &unresolved)) { functionContextUnresolved = unresolved.join(strColons); qWarning("%s:%d: Qualifying with unknown namespace/class %s::%s\n", qPrintable(yyFileName), yyLineNo, @@ -1607,25 +1719,32 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) qPrintable(yyFileName), yyLineNo); break; } - while (!functionContext.at(idx - 1)->hasTrFunctions) { - if (idx == 1 || !functionContext.at(idx - 2)->isClass) { - idx = functionContext.length(); - if (!functionContext.last()->complained) { + Namespace *fctx; + while (!(fctx = findNamespace(functionContext, idx)->classDef)->hasTrFunctions) { + if (idx == 1) { + context = stringifyNamespace(functionContext); + fctx = findNamespace(functionContext)->classDef; + if (!fctx->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, - qPrintable(stringifyNamespace(functionContext))); - functionContext.last()->complained = true; + qPrintable(context)); + fctx->complained = true; } - break; + goto gotctx; } --idx; } - context.clear(); - for (int i = 1;;) { - context += functionContext.at(i)->name; - if (++i == idx) - break; - context += strColons; + if (fctx->trQualification.isEmpty()) { + context.clear(); + for (int i = 1;;) { + context += functionContext.at(i).value(); + if (++i == idx) + break; + context += strColons; + } + fctx->trQualification = context; + } else { + context = fctx->trQualification; } } else { context = (stringListifyNamespace(functionContext) @@ -1644,20 +1763,27 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) prefix.chop(2); NamespaceList nsl; QStringList unresolved; - if (fullyQualify(functionContext, prefix.split(strColons), false, &nsl, &unresolved)) { - if (!nsl.last()->hasTrFunctions && !nsl.last()->complained) { + if (fullyQualify(functionContext, prefix, false, &nsl, &unresolved)) { + Namespace *fctx = findNamespace(nsl)->classDef; + if (fctx->trQualification.isEmpty()) { + context = stringifyNamespace(nsl); + fctx->trQualification = context; + } else { + context = fctx->trQualification; + } + if (!fctx->hasTrFunctions && !fctx->complained) { qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", qPrintable(yyFileName), yyLineNo, - qPrintable(stringifyNamespace(nsl))); - nsl.last()->complained = true; + qPrintable(context)); + fctx->complained = true; } - context = stringifyNamespace(nsl); } else { context = (stringListifyNamespace(nsl) + unresolved).join(strColons); } prefix.clear(); } + gotctx: recordMessage(line, context, text, comment, extracomment, msgid, extra, utf8, plural); } extracomment.clear(); @@ -1666,7 +1792,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) break; case Tok_translateUtf8: case Tok_translate: - if (!results->tor) + if (!tor) goto case_default; if (!sourcetext.isEmpty()) qWarning("%s:%d: //%% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n", @@ -1721,7 +1847,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) extra.clear(); break; case Tok_trid: - if (!results->tor) + if (!tor) goto case_default; if (sourcetext.isEmpty()) { yyTok = getToken(); @@ -1744,8 +1870,16 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) extra.clear(); break; case Tok_Q_DECLARE_TR_FUNCTIONS: + if (getMacroArgs()) { + Namespace *ns = modifyNamespace(&namespaces, true); + ns->hasTrFunctions = true; + ns->trQualification = yyWord; + ns->trQualification.detach(); + } + yyTok = getToken(); + break; case Tok_Q_OBJECT: - namespaces.last()->hasTrFunctions = true; + modifyNamespace(&namespaces, true)->hasTrFunctions = true; yyTok = getToken(); break; case Tok_Ident: @@ -1759,7 +1893,7 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } break; case Tok_Comment: - if (!results->tor) + if (!tor) goto case_default; if (yyWord.startsWith(QLatin1Char(':'))) { yyWord.remove(0, 1); @@ -1814,9 +1948,15 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) } sourcetext.resize(ptr - (ushort *)sourcetext.data()); } else { - comment = yyWord.simplified(); - if (comment.startsWith(QLatin1String(MagicComment))) { - comment.remove(0, sizeof(MagicComment) - 1); + const ushort *uc = (const ushort *)yyWord.unicode(); // Is zero-terminated + int idx = 0; + ushort c; + while ((c = uc[idx]) == ' ' || c == '\t' || c == '\n') + ++idx; + if (!memcmp(uc + idx, MagicComment.unicode(), MagicComment.length() * 2)) { + idx += MagicComment.length(); + comment = QString::fromRawData(yyWord.unicode() + idx, + yyWord.length() - idx).simplified(); int k = comment.indexOf(QLatin1Char(' ')); if (k == -1) { context = comment; @@ -1826,11 +1966,9 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) recordMessage(yyLineNo, context, QString(), comment, extracomment, QString(), TranslatorMessage::ExtraData(), false, false); extracomment.clear(); - results->tor->setExtras(extra); + tor->setExtras(extra); extra.clear(); } - } else { - comment.detach(); } } yyTok = getToken(); @@ -1854,17 +1992,8 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) #endif break; case Tok_RightBrace: - if (yyBraceDepth + 1 == namespaceDepths.count()) { - // class or namespace - Namespace *ns = namespaces.last(); - if (ns->needsTrFunctions && !ns->hasTrFunctions && !ns->complained) { - qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", - qPrintable(yyFileName), yyLineNo, - qPrintable(stringifyNamespace(namespaces))); - ns->complained = true; - } + if (yyBraceDepth + 1 == namespaceDepths.count()) // class or namespace truncateNamespaces(&namespaces, namespaceDepths.pop()); - } if (yyBraceDepth == namespaceDepths.count()) { // function, class or namespace if (!yyBraceDepth && !directInclude) { @@ -1922,6 +2051,37 @@ void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) qPrintable(yyFileName), yyParenLineNo); } +const ParseResults *CppParser::recordResults(bool isHeader) +{ + if (tor) { + if (tor->messageCount()) { + CppFiles::setTranslator(yyFileName, tor); + } else { + delete tor; + tor = 0; + } + } + if (isHeader) { + const ParseResults *pr; + if (!tor && results->includes.count() == 1 + && results->rootNamespace.children.isEmpty() + && results->rootNamespace.aliases.isEmpty() + && results->rootNamespace.usings.isEmpty()) { + // This is a forwarding header. Slash it. + pr = *results->includes.begin(); + delete results; + } else { + results->fileId = nextFileId++; + pr = results; + } + CppFiles::setResults(yyFileName, pr); + return pr; + } else { + delete results; + return 0; + } +} + /* Fetches tr() calls in C++ code in UI files (inside "<function>" tag). This mechanism is obsolete. @@ -1966,12 +2126,12 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat parser.setTranslator(tor); QSet<QString> inclusions; parser.parse(cd.m_defaultContext, cd, inclusions); - CppFiles::setResults(filename, parser.getResults()); + parser.recordResults(isHeader(filename)); } - foreach (const QString filename, filenames) + foreach (const QString &filename, filenames) if (!CppFiles::isBlacklisted(filename)) - if (Translator *tor = CppFiles::getResults(filename)->tor) + if (const Translator *tor = CppFiles::getTranslator(filename)) foreach (const TranslatorMessage &msg, tor->messages()) translator.extend(msg); } diff --git a/tools/linguist/lupdate/main.cpp b/tools/linguist/lupdate/main.cpp index f867a45..24da253 100644 --- a/tools/linguist/lupdate/main.cpp +++ b/tools/linguist/lupdate/main.cpp @@ -62,23 +62,14 @@ static void printOut(const QString & out) } static void recursiveFileInfoList(const QDir &dir, - const QStringList &nameFilters, QDir::Filters filter, bool recursive, + const QSet<QString> &nameFilters, QDir::Filters filter, QFileInfoList *fileinfolist) { - if (recursive) - filter |= QDir::AllDirs; - QFileInfoList entries = dir.entryInfoList(nameFilters, filter); - - QFileInfoList::iterator it; - for (it = entries.begin(); it != entries.end(); ++it) { - QString fname = it->fileName(); - if (fname != QLatin1String(".") && fname != QLatin1String("..")) { - if (it->isDir()) - recursiveFileInfoList(QDir(it->absoluteFilePath()), nameFilters, filter, recursive, fileinfolist); - else - fileinfolist->append(*it); - } - } + foreach (const QFileInfo &fi, dir.entryInfoList(filter)) + if (fi.isDir()) + recursiveFileInfoList(QDir(fi.absoluteFilePath()), nameFilters, filter, fileinfolist); + else if (nameFilters.contains(fi.suffix())) + fileinfolist->append(fi); } static void printUsage() @@ -243,7 +234,7 @@ int main(int argc, char **argv) bool recursiveScan = true; QString extensions = m_defaultExtensions; - QStringList extensionsNameFilters; + QSet<QString> extensionsNameFilters; for (int i = 1; i < argc; ++i) { if (args.at(i) == QLatin1String("-ts")) @@ -418,15 +409,15 @@ int main(int argc, char **argv) foreach (QString ext, extensions.split(QLatin1Char(','))) { ext = ext.trimmed(); if (ext.startsWith(QLatin1Char('.'))) - ext.remove(0,1); - ext.insert(0, QLatin1String("*.")); - extensionsNameFilters << ext; + ext.remove(0, 1); + extensionsNameFilters.insert(ext); } } QDir::Filters filters = QDir::Files | QDir::NoSymLinks; + if (recursiveScan) + filters |= QDir::AllDirs | QDir::NoDotAndDotDot; QFileInfoList fileinfolist; - recursiveFileInfoList(dir, extensionsNameFilters, filters, - recursiveScan, &fileinfolist); + recursiveFileInfoList(dir, extensionsNameFilters, filters, &fileinfolist); int scanRootLen = dir.absolutePath().length(); foreach (const QFileInfo &fi, fileinfolist) { QString fn = QDir::cleanPath(fi.absoluteFilePath()); diff --git a/tools/linguist/phrasebooks/russian.qph b/tools/linguist/phrasebooks/russian.qph index 69af041..9d40bd3 100644 --- a/tools/linguist/phrasebooks/russian.qph +++ b/tools/linguist/phrasebooks/russian.qph @@ -201,10 +201,6 @@ <target>разделить выбранные элементы</target> </phrase> <phrase> - <source>dock</source> - <target>док</target> -</phrase> -<phrase> <source>document</source> <target>документ</target> </phrase> @@ -302,7 +298,7 @@ </phrase> <phrase> <source>font style</source> - <target>стиль шрифта</target> + <target>начертание</target> </phrase> <phrase> <source>function key</source> @@ -510,7 +506,7 @@ </phrase> <phrase> <source>OK</source> - <target>Готово</target> + <target>ОК</target> </phrase> <phrase> <source>OLE</source> @@ -1038,10 +1034,6 @@ </phrase> <phrase> <source>OK</source> - <target>Выбрать</target> -</phrase> -<phrase> - <source>OK</source> <target>Закрыть</target> </phrase> <phrase> @@ -1092,4 +1084,84 @@ <source>Checkable</source> <target>Переключаемое</target> </phrase> +<phrase> + <source>Style</source> + <target>Начертание</target> +</phrase> +<phrase> + <source>Point size</source> + <target>Размер</target> +</phrase> +<phrase> + <source>Family</source> + <target>Шрифт</target> +</phrase> +<phrase> + <source>Writing system</source> + <target>Система письма</target> +</phrase> +<phrase> + <source>OK</source> + <target>Удалить</target> +</phrase> +<phrase> + <source>Style</source> + <target>Стиль</target> +</phrase> +<phrase> + <source>Edit</source> + <target>Изменить</target> +</phrase> +<phrase> + <source>Invalid</source> + <target>Некорректный</target> +</phrase> +<phrase> + <source>Invalid</source> + <target>Некорректная</target> +</phrase> +<phrase> + <source>Invalid</source> + <target>Некорректное</target> +</phrase> +<phrase> + <source>tag</source> + <target>тэг</target> +</phrase> +<phrase> + <source>tab order</source> + <target>порядок обхода</target> +</phrase> +<phrase> + <source>Ascending</source> + <target>По возрастанию</target> +</phrase> +<phrase> + <source>Descending</source> + <target>По убыванию</target> +</phrase> +<phrase> + <source>Reset</source> + <target>Сбросить</target> +</phrase> +<phrase> + <source>Sort order</source> + <target>Порядок сортировки</target> +</phrase> +<phrase> + <source>Appearance</source> + <target>Внешний вид</target> +</phrase> +<phrase> + <source>View</source> + <target>Просмотр</target> +</phrase> +<phrase> + <source>Actions</source> + <target>Действия</target> +</phrase> +<phrase> + <source>Table of Contents</source> + <target>Оглавление</target> +</phrase> </QPH> diff --git a/tools/qdoc3/atom.cpp b/tools/qdoc3/atom.cpp index 69204d4..834a5d7 100644 --- a/tools/qdoc3/atom.cpp +++ b/tools/qdoc3/atom.cpp @@ -143,6 +143,7 @@ QString Atom::UPPERROMAN_ ("upperroman"); \value SectionHeadingRight \value SidebarLeft \value SidebarRight + \value SinceList \value String \value TableLeft \value TableRight @@ -220,6 +221,7 @@ static const struct { { "SectionHeadingRight", Atom::SectionHeadingRight }, { "SidebarLeft", Atom::SidebarLeft }, { "SidebarRight", Atom::SidebarRight }, + { "SinceList", Atom::SinceList }, { "SnippetCommand", Atom::SnippetCommand }, { "SnippetIdentifier", Atom::SnippetIdentifier }, { "SnippetLocation", Atom::SnippetLocation }, diff --git a/tools/qdoc3/atom.h b/tools/qdoc3/atom.h index 95faa8f..99f9b57 100644 --- a/tools/qdoc3/atom.h +++ b/tools/qdoc3/atom.h @@ -112,7 +112,9 @@ class Atom SectionRight, SectionHeadingLeft, SectionHeadingRight, - SidebarLeft, SidebarRight, + SidebarLeft, + SidebarRight, + SinceList, SnippetCommand, SnippetIdentifier, SnippetLocation, diff --git a/tools/qdoc3/doc.cpp b/tools/qdoc3/doc.cpp index b918fa5..c202d71 100644 --- a/tools/qdoc3/doc.cpp +++ b/tools/qdoc3/doc.cpp @@ -90,10 +90,10 @@ enum { CMD_PRINTUNTIL, CMD_QUOTATION, CMD_QUOTEFILE, CMD_QUOTEFROMFILE, CMD_QUOTEFUNCTION, CMD_RAW, CMD_ROW, CMD_SA, CMD_SECTION1, CMD_SECTION2, CMD_SECTION3, - CMD_SECTION4, CMD_SIDEBAR, CMD_SKIPLINE, CMD_SKIPTO, - CMD_SKIPUNTIL, CMD_SNIPPET, CMD_SUB, CMD_SUP, CMD_TABLE, - CMD_TABLEOFCONTENTS, CMD_TARGET, CMD_TT, CMD_UNDERLINE, - CMD_UNICODE, CMD_VALUE, CMD_WARNING, + CMD_SECTION4, CMD_SIDEBAR, CMD_SINCELIST, CMD_SKIPLINE, + CMD_SKIPTO, CMD_SKIPUNTIL, CMD_SNIPPET, CMD_SUB, CMD_SUP, + CMD_TABLE, CMD_TABLEOFCONTENTS, CMD_TARGET, CMD_TT, + CMD_UNDERLINE, CMD_UNICODE, CMD_VALUE, CMD_WARNING, #ifdef QDOC_QML CMD_QML, CMD_ENDQML, CMD_CPP, CMD_ENDCPP, CMD_QMLTEXT, CMD_ENDQMLTEXT, CMD_CPPTEXT, CMD_ENDCPPTEXT, @@ -177,6 +177,7 @@ static struct { { "section3", CMD_SECTION3, 0 }, { "section4", CMD_SECTION4, 0 }, { "sidebar", CMD_SIDEBAR, 0 }, // ### don't document for now + { "sincelist", CMD_SINCELIST, 0 }, { "skipline", CMD_SKIPLINE, 0 }, { "skipto", CMD_SKIPTO, 0 }, { "skipuntil", CMD_SKIPUNTIL, 0 }, @@ -727,6 +728,9 @@ void DocParser::parse(const QString& source, case CMD_ANNOTATEDLIST: append(Atom::AnnotatedList, getArgument()); break; + case CMD_SINCELIST: + append(Atom::SinceList, getArgument()); + break; case CMD_GENERATELIST: append(Atom::GeneratedList, getArgument()); break; @@ -2664,13 +2668,18 @@ Text Doc::trimmedBriefText(const QString &className) const standardWording = false; } - if (!w.isEmpty() && (w.first() == "class" || w.first() == "widget" - || w.first() == "namespace" || w.first() == "header")) + if (!w.isEmpty() && ((w.first() == "class") || + (w.first() == "function") || + (w.first() == "macro") || + (w.first() == "widget") || + (w.first() == "namespace") || + (w.first() == "header"))) w.removeFirst(); else { location().warning( tr("Nonstandard wording in '\\%1' text for '%2' (" - "expected 'class', 'widget', 'namespace' or 'header')") + "expected 'class', 'function', 'macro', 'widget', " + "'namespace' or 'header')") .arg(COMMAND_BRIEF).arg(className)); standardWording = false; } diff --git a/tools/qdoc3/generator.cpp b/tools/qdoc3/generator.cpp index 2d03860..47fe4b5 100644 --- a/tools/qdoc3/generator.cpp +++ b/tools/qdoc3/generator.cpp @@ -562,24 +562,21 @@ void Generator::generateModuleWarning(const ClassNode *classe, QString module = classe->moduleName(); if (!module.isEmpty()) { Text text; - if (Tokenizer::isTrue("defined(consoleedition)") - && !editionModuleMap["Console"].contains(module)) { + if (!editionModuleMap["Console"].contains(module)) { text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This class is not part of the Qt Console Edition." << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << Atom::ParaRight; } - else if (Tokenizer::isTrue("defined(desktoplightedition)") - && !editionModuleMap["DesktopLight"].contains(module)) { + else if (!editionModuleMap["DesktopLight"].contains(module)) { text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This class is not part of the Qt Desktop Light Edition." << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << Atom::ParaRight; } - else if (module == "Qt3Support" && - Tokenizer::isTrue("defined(opensourceedition)")) { + else if (module == "Qt3Support") { text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "Note to Qt Desktop Light Edition users:" diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index b7ed702..5406017 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -330,6 +330,7 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) #ifdef ZZZ_QDOC_QML findAllQmlClasses(tree->root()); #endif + findAllSince(tree->root(),tree->version()); PageGenerator::generateTree(tree, marker); @@ -539,7 +540,6 @@ int HtmlGenerator::generateAtom(const Atom *atom, break; case Atom::AnnotatedList: { - //qDebug() << "ANNOTATED LIS:"; QList<Node*> values = tre->groups().values(atom->string()); QMap<QString, const Node*> nodeMap; for (int i = 0; i < values.size(); ++i) { @@ -653,7 +653,26 @@ int HtmlGenerator::generateAtom(const Atom *atom, } } break; - case Atom::Image: + case Atom::SinceList: + { + QList<Node*> values; + if (atom->string() == "classes") { + values = sinceClasses.values(); + } + else if (atom->string() == "functions") { + values = sinceFunctions.values(); + } + if (!values.isEmpty()) { + QMap<QString, const Node*> nodeMap; + for (int i=0; i<values.size(); ++i) { + const Node* n = values.at(i); + nodeMap.insert(n->nameForLists(),n); + } + generateAnnotatedList(relative, marker, nodeMap); + } + } + break; +case Atom::Image: case Atom::InlineImage: { QString fileName = imageFileName(relative, atom->string()); @@ -1475,7 +1494,7 @@ void HtmlGenerator::generateHeader(const QString& title, if ((project != "Qtopia") && (project != "Qt Extended")) { shortVersion = project + " " + shortVersion + ": "; if (node && !node->doc().location().isEmpty()) - out() << "<!-- " << node->doc().location().filePath() << " -->\n"; + out() << "<!-- " << node->doc().location().fileName() << " -->\n"; shortVersion = tre->version(); if (shortVersion.count(QChar('.')) == 2) @@ -3495,6 +3514,45 @@ void HtmlGenerator::findAllClasses(const InnerNode *node) } } +/*! + For generating the "Since x.y" page. + */ +void HtmlGenerator::findAllSince(const InnerNode *node, QString version) +{ + const QRegExp versionSeparator("[\\-\\.]"); + const int minorIndex = version.indexOf(versionSeparator); + const int patchIndex = version.indexOf(versionSeparator, minorIndex+1); + version = version.left(patchIndex); + + NodeList::const_iterator c = node->childNodes().constBegin(); + while (c != node->childNodes().constEnd()) { + if (((*c)->access() != Node::Private) && ((*c)->since() == version)) { + if ((*c)->type() == Node::Function) { + FunctionNode *func = static_cast<FunctionNode *>(*c); + if ((func->status() > Node::Obsolete) && + (func->metaness() != FunctionNode::Ctor) && + (func->metaness() != FunctionNode::Dtor)) { + sinceFunctions.insert(func->name(), func); + } + } + else if ((*c)->url().isEmpty()) { + if ((*c)->type() == Node::Class && !(*c)->doc().isEmpty()) { + QString className = (*c)->name(); + if ((*c)->parent() && + (*c)->parent()->type() == Node::Namespace && + !(*c)->parent()->name().isEmpty()) + className = (*c)->parent()->name()+"::"+className; + sinceClasses.insert(className, *c); + } + } + if ((*c)->isInnerNode()) { + findAllSince(static_cast<InnerNode *>(*c),version); + } + } + ++c; + } +} + void HtmlGenerator::findAllFunctions(const InnerNode *node) { NodeList::ConstIterator c = node->childNodes().begin(); diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h index fabe585..24e2986 100644 --- a/tools/qdoc3/htmlgenerator.h +++ b/tools/qdoc3/htmlgenerator.h @@ -216,6 +216,7 @@ class HtmlGenerator : public PageGenerator #ifdef ZZZ_QDOC_QML void findAllQmlClasses(const InnerNode *node); #endif + void findAllSince(const InnerNode *node, QString version); static int hOffset(const Node *node); static bool isThreeColumnEnumValueTable(const Atom *atom); virtual QString getLink(const Atom *atom, @@ -285,6 +286,8 @@ class HtmlGenerator : public PageGenerator #endif QMap<QString, QMap<QString, const Node *> > funcIndex; QMap<Text, const Node *> legaleseTexts; + QMap<QString, Node*> sinceClasses; + QMap<QString, Node*> sinceFunctions; }; #define HTMLGENERATOR_ADDRESS "address" diff --git a/tools/qdoc3/main.cpp b/tools/qdoc3/main.cpp index aac4ee8..8658428 100644 --- a/tools/qdoc3/main.cpp +++ b/tools/qdoc3/main.cpp @@ -336,7 +336,6 @@ static void processQdocconfFile(const QString &fileName) /* Generate the XML tag file, if it was requested. */ - QString tagFile = config.getString(CONFIG_TAGFILE); if (!tagFile.isEmpty()) tree->generateTagFile(tagFile); diff --git a/tools/qdoc3/test/macros.qdocconf b/tools/qdoc3/test/macros.qdocconf index f7dcdc0..dbb8ab8 100644 --- a/tools/qdoc3/test/macros.qdocconf +++ b/tools/qdoc3/test/macros.qdocconf @@ -28,3 +28,8 @@ macro.begincomment = "\\c{/*}" macro.endcomment = "\\c{*/}" macro.uuml.HTML = "ü" macro.mdash.HTML = "—" + +macro.beginfloatleft.HTML = "<div style=\"float: left; margin-right: 2em\">" +macro.beginfloatright.HTML = "<div style=\"float: right; margin-left: 2em\">" +macro.endfloat.HTML = "</div>" +macro.clearfloat.HTML = "<div style=\"clear: both\">" diff --git a/tools/qdoc3/test/qt-build-docs.qdocconf b/tools/qdoc3/test/qt-build-docs.qdocconf index deaf8a8..c0b8334 100644 --- a/tools/qdoc3/test/qt-build-docs.qdocconf +++ b/tools/qdoc3/test/qt-build-docs.qdocconf @@ -112,3 +112,5 @@ imagedirs = $QT_SOURCE_TREE/doc/src/images \ outputdir = $QT_BUILD_TREE/doc/html tagfile = $QT_BUILD_TREE/doc/html/qt.tags base = file:$QT_BUILD_TREE/doc/html + +HTML.generatemacrefs = "true" diff --git a/tools/qdoc3/test/qt-cpp-ignore.qdocconf b/tools/qdoc3/test/qt-cpp-ignore.qdocconf index 5be9fa5..dcf33dc 100644 --- a/tools/qdoc3/test/qt-cpp-ignore.qdocconf +++ b/tools/qdoc3/test/qt-cpp-ignore.qdocconf @@ -26,6 +26,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ QT_WIDGET_PLUGIN_EXPORT \ Q_COMPAT_EXPORT \ Q_CORE_EXPORT \ + Q_CORE_EXPORT_INLINE \ Q_EXPLICIT \ Q_EXPORT \ Q_EXPORT_CODECS_CN \ diff --git a/tools/qdoc3/test/qt.qdocconf b/tools/qdoc3/test/qt.qdocconf index 7bd4e52..9b5937d 100644 --- a/tools/qdoc3/test/qt.qdocconf +++ b/tools/qdoc3/test/qt.qdocconf @@ -114,3 +114,5 @@ imagedirs = $QTDIR/doc/src/images \ outputdir = $QTDIR/doc/html tagfile = $QTDIR/doc/html/qt.tags base = file:$QTDIR/doc/html + +HTML.generatemacrefs = "true" diff --git a/tools/xmlpatternsvalidator/main.cpp b/tools/xmlpatternsvalidator/main.cpp index 2fbe176..eef8132 100644 --- a/tools/xmlpatternsvalidator/main.cpp +++ b/tools/xmlpatternsvalidator/main.cpp @@ -43,6 +43,7 @@ #include <QtCore/QDebug> #include <QtCore/QFile> +#include <QtCore/QStringList> #include <QtCore/QUrl> #include <QtXmlPatterns/QXmlSchema> #include <QtXmlPatterns/QXmlSchemaValidator> @@ -62,14 +63,15 @@ int main(int argc, char **argv) { InvalidMode, SchemaOnlyMode, - SchemaAndInstanceMode, - InstanceOnlyMode + InstanceOnlyMode, + SchemaAndInstanceMode }; const QCoreApplication app(argc, argv); QCoreApplication::setApplicationName(QLatin1String("xmlpatternsvalidator")); - if (argc != 2 && argc != 3) { + QStringList arguments = QCoreApplication::arguments(); + if (arguments.size() != 2 && arguments.size() != 3) { qDebug() << QXmlPatternistCLI::tr("usage: xmlpatternsvalidator (<schema url> | <instance url> <schema url> | <instance url>)"); return ParseError; } @@ -77,57 +79,52 @@ int main(int argc, char **argv) // parse command line arguments ExecutionMode mode = InvalidMode; - if (argc == 2) { - // either it is a schema or instance document + QUrl schemaUri; + QUrl instanceUri; - QString url = QFile::decodeName(argv[1]); - if (url.toLower().endsWith(QLatin1String(".xsd"))) { - mode = SchemaOnlyMode; - } else { - // as we could validate all types of xml documents, don't check the extension here - mode = InstanceOnlyMode; + { + QUrl url = arguments[1]; + + if (url.isRelative()) + url = QUrl::fromLocalFile(arguments[1]); + + if (arguments.size() == 2) { + // either it is a schema or instance document + + if (arguments[1].toLower().endsWith(QLatin1String(".xsd"))) { + schemaUri = url; + mode = SchemaOnlyMode; + } else { + // as we could validate all types of xml documents, don't check the extension here + instanceUri = url; + mode = InstanceOnlyMode; + } + } else if (arguments.size() == 3) { + instanceUri = url; + schemaUri = arguments[2]; + + if (schemaUri.isRelative()) + schemaUri = QUrl::fromLocalFile(schemaUri.toString()); + + mode = SchemaAndInstanceMode; } - } else if (argc == 3) { - mode = SchemaAndInstanceMode; } - // do validation + // Validate schema QXmlSchema schema; - - if (mode == SchemaOnlyMode) { - const QString schemaUri = QFile::decodeName(argv[1]); - - schema.load(QUrl(schemaUri)); - - if (schema.isValid()) - return Valid; - else - return Invalid; - } else if (mode == SchemaAndInstanceMode) { - const QString instanceUri = QFile::decodeName(argv[1]); - const QString schemaUri = QFile::decodeName(argv[2]); - - schema.load(QUrl(schemaUri)); - + if (InstanceOnlyMode != mode) { + schema.load(schemaUri); if (!schema.isValid()) return Invalid; - - QXmlSchemaValidator validator(schema); - if (validator.validate(QUrl(instanceUri))) - return Valid; - else - return Invalid; - } else if (mode == InstanceOnlyMode) { - const QString instanceUri = QFile::decodeName(argv[1]); - - QXmlSchemaValidator validator(schema); - if (validator.validate(QUrl(instanceUri))) - return Valid; - else - return Invalid; } - Q_ASSERT(false); + if (SchemaOnlyMode == mode) + return Valid; + + // Validate instance + QXmlSchemaValidator validator(schema); + if (validator.validate(instanceUri)) + return Valid; return Invalid; } diff --git a/tools/xmlpatternsvalidator/main.h b/tools/xmlpatternsvalidator/main.h index 6dd9a1b..f2c607e 100644 --- a/tools/xmlpatternsvalidator/main.h +++ b/tools/xmlpatternsvalidator/main.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the Patternist project on Qt Labs. +** This file is part of the QtXmlPatterns module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage |