diff options
Diffstat (limited to 'tools')
354 files changed, 16713 insertions, 7536 deletions
diff --git a/tools/activeqt/dumpcpp/main.cpp b/tools/activeqt/dumpcpp/main.cpp index 0a4aa06..de3ec57 100644 --- a/tools/activeqt/dumpcpp/main.cpp +++ b/tools/activeqt/dumpcpp/main.cpp @@ -969,7 +969,7 @@ bool generateTypeLibrary(const QByteArray &typeLib, const QByteArray &outname, O QString libName; BSTR nameString; typelib->GetDocumentation(-1, &nameString, 0, 0, 0); - libName = QString::fromUtf16((const ushort *)nameString); + libName = QString::fromWCharArray(nameString); SysFreeString(nameString); if (!nameSpace.isEmpty()) libName = QString(nameSpace); @@ -1086,7 +1086,7 @@ bool generateTypeLibrary(const QByteArray &typeLib, const QByteArray &outname, O BSTR bstr; if (S_OK != typeinfo->GetDocumentation(-1, &bstr, 0, 0, 0)) break; - className = QString::fromUtf16((const ushort *)bstr).toLatin1(); + className = QString::fromWCharArray(bstr).toLatin1(); SysFreeString(bstr); switch (typekind) { case TKIND_RECORD: @@ -1227,7 +1227,7 @@ bool generateTypeLibrary(const QByteArray &typeLib, const QByteArray &outname, O BSTR bstr; if (S_OK != typeinfo->GetDocumentation(-1, &bstr, 0, 0, 0)) break; - className = QString::fromUtf16((const ushort *)bstr).toLatin1(); + className = QString::fromWCharArray(bstr).toLatin1(); SysFreeString(bstr); declOut << "// stub for vtable-only interface" << endl; diff --git a/tools/assistant/compat/helpdialog.ui b/tools/assistant/compat/helpdialog.ui index 54acc30..6c95418 100644 --- a/tools/assistant/compat/helpdialog.ui +++ b/tools/assistant/compat/helpdialog.ui @@ -269,7 +269,7 @@ <item row="1" column="0" > <widget class="QLineEdit" name="termsEdit" > <property name="toolTip" > - <string>Enter searchword(s).</string> + <string>Enter searchword(s)</string> </property> <property name="whatsThis" > <string><b>Enter search word(s).</b><p>Enter here the word(s) you are looking for. The words may contain wildcards (*). For a sequence of words quote them.</p></string> @@ -307,7 +307,7 @@ <item> <widget class="QPushButton" name="helpButton" > <property name="toolTip" > - <string>Display the help page.</string> + <string>Display the help page</string> </property> <property name="whatsThis" > <string>Display the help page for the full text search.</string> @@ -336,7 +336,7 @@ <item> <widget class="QPushButton" name="searchButton" > <property name="toolTip" > - <string>Start searching.</string> + <string>Start searching</string> </property> <property name="whatsThis" > <string>Pressing this button starts the search.</string> diff --git a/tools/assistant/compat/mainwindow.cpp b/tools/assistant/compat/mainwindow.cpp index d3e74fe..670b144 100644 --- a/tools/assistant/compat/mainwindow.cpp +++ b/tools/assistant/compat/mainwindow.cpp @@ -312,21 +312,14 @@ void MainWindow::about() { QMessageBox box(this); - // TODO: Remove these variables for 4.6.0. Must keep this way for 4.5.x due to string freeze. - QString edition; - QString info; - QString moreInfo; - box.setText(QString::fromLatin1("<center><img src=\":/trolltech/assistant/images/assistant-128.png\">" "<h3>%1</h3>" - "<p>Version %2 %3</p></center>" - "<p>%4</p>" - "<p>%5</p>" + "<p>Version %2</p></center>" "<p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p>" "<p>The program is provided AS IS with NO WARRANTY OF ANY KIND," " INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A" " PARTICULAR PURPOSE.<p/>") - .arg(tr("Qt Assistant")).arg(QLatin1String(QT_VERSION_STR)).arg(edition).arg(info).arg(moreInfo)); + .arg(tr("Qt Assistant")).arg(QLatin1String(QT_VERSION_STR))); box.setWindowTitle(tr("Qt Assistant")); box.setIcon(QMessageBox::NoIcon); box.exec(); diff --git a/tools/assistant/lib/lib.pro b/tools/assistant/lib/lib.pro index bd9ed53..5d6d436 100644 --- a/tools/assistant/lib/lib.pro +++ b/tools/assistant/lib/lib.pro @@ -1,65 +1,71 @@ -QT += sql xml network +QT += sql \ + xml \ + network TEMPLATE = lib TARGET = QtHelp -DEFINES += QHELP_LIB QT_CLUCENE_SUPPORT -CONFIG += qt warn_on - +DEFINES += QHELP_LIB \ + QT_CLUCENE_SUPPORT +CONFIG += qt \ + warn_on include(../../../src/qbase.pri) - QMAKE_TARGET_PRODUCT = Help -QMAKE_TARGET_DESCRIPTION = Help application framework. +QMAKE_TARGET_DESCRIPTION = Help \ + application \ + framework. DEFINES -= QT_ASCII_CAST_WARNINGS - qclucene = QtCLucene$${QT_LIBINFIX} -if(!debug_and_release|build_pass):CONFIG(debug, debug|release) { +if(!debug_and_release|build_pass):CONFIG(debug, debug|release) { mac:qclucene = $${qclucene}_debug win32:qclucene = $${qclucene}d } linux-lsb-g++:LIBS += --lsb-shared-libs=$$qclucene -unix:QMAKE_PKGCONFIG_REQUIRES += QtNetwork QtSql QtXml +unix:QMAKE_PKGCONFIG_REQUIRES += QtNetwork \ + QtSql \ + QtXml LIBS += -l$$qclucene -unix:QMAKE_PKGCONFIG_REQUIRES += QtNetwork QtSql QtXml - +unix:QMAKE_PKGCONFIG_REQUIRES += QtNetwork \ + QtSql \ + QtXml RESOURCES += helpsystem.qrc - SOURCES += qhelpenginecore.cpp \ - qhelpengine.cpp \ - qhelpdbreader.cpp \ - qhelpcontentwidget.cpp \ - qhelpindexwidget.cpp \ - qhelpgenerator.cpp \ - qhelpdatainterface.cpp \ - qhelpprojectdata.cpp \ - qhelpcollectionhandler.cpp \ - qhelpsearchengine.cpp \ - qhelpsearchquerywidget.cpp \ - qhelpsearchresultwidget.cpp \ - qhelpsearchindex_default.cpp \ - qhelpsearchindexwriter_default.cpp \ - qhelpsearchindexreader_default.cpp + qhelpengine.cpp \ + qhelpdbreader.cpp \ + qhelpcontentwidget.cpp \ + qhelpindexwidget.cpp \ + qhelpgenerator.cpp \ + qhelpdatainterface.cpp \ + qhelpprojectdata.cpp \ + qhelpcollectionhandler.cpp \ + qhelpsearchengine.cpp \ + qhelpsearchquerywidget.cpp \ + qhelpsearchresultwidget.cpp \ + qhelpsearchindex_default.cpp \ + qhelpsearchindexwriter_default.cpp \ + qhelpsearchindexreader_default.cpp \ + qhelpsearchindexreader.cpp # access to clucene SOURCES += qhelpsearchindexwriter_clucene.cpp \ - qhelpsearchindexreader_clucene.cpp - + qhelpsearchindexreader_clucene.cpp HEADERS += qhelpenginecore.h \ - qhelpengine.h \ - qhelpengine_p.h \ - qhelp_global.h \ - qhelpdbreader_p.h \ - qhelpcontentwidget.h \ - qhelpindexwidget.h \ - qhelpgenerator_p.h \ - qhelpdatainterface_p.h \ - qhelpprojectdata_p.h \ - qhelpcollectionhandler_p.h \ - qhelpsearchengine.h \ - qhelpsearchquerywidget.h \ - qhelpsearchresultwidget.h \ - qhelpsearchindex_default_p.h \ - qhelpsearchindexwriter_default_p.h \ - qhelpsearchindexreader_default_p.h + qhelpengine.h \ + qhelpengine_p.h \ + qhelp_global.h \ + qhelpdbreader_p.h \ + qhelpcontentwidget.h \ + qhelpindexwidget.h \ + qhelpgenerator_p.h \ + qhelpdatainterface_p.h \ + qhelpprojectdata_p.h \ + qhelpcollectionhandler_p.h \ + qhelpsearchengine.h \ + qhelpsearchquerywidget.h \ + qhelpsearchresultwidget.h \ + qhelpsearchindex_default_p.h \ + qhelpsearchindexwriter_default_p.h \ + qhelpsearchindexreader_default_p.h \ + qhelpsearchindexreader_p.h # access to clucene HEADERS += qhelpsearchindexwriter_clucene_p.h \ - qhelpsearchindexreader_clucene_p.h + qhelpsearchindexreader_clucene_p.h diff --git a/tools/assistant/lib/qhelpprojectdata.cpp b/tools/assistant/lib/qhelpprojectdata.cpp index 8947a36..9412f1c 100644 --- a/tools/assistant/lib/qhelpprojectdata.cpp +++ b/tools/assistant/lib/qhelpprojectdata.cpp @@ -41,9 +41,11 @@ #include "qhelpprojectdata_p.h" +#include <QtCore/QDir> #include <QtCore/QFileInfo> #include <QtCore/QStack> #include <QtCore/QMap> +#include <QtCore/QRegExp> #include <QtCore/QVariant> #include <QtXml/QXmlStreamReader> @@ -73,6 +75,9 @@ private: void readKeywords(); void readFiles(); void raiseUnknownTokenError(); + void addMatchingFiles(const QString &pattern); + + QMap<QString, QStringList> dirEntriesCache; }; void QHelpProjectDataPrivate::raiseUnknownTokenError() @@ -161,7 +166,7 @@ void QHelpProjectDataPrivate::readFilterSection() readNext(); if (isStartElement()) { if (name() == QLatin1String("filterAttribute")) - filterSectionList.last().addFilterAttribute(readElementText()); + filterSectionList.last().addFilterAttribute(readElementText()); else if (name() == QLatin1String("toc")) readTOC(); else if (name() == QLatin1String("keywords")) @@ -244,7 +249,7 @@ void QHelpProjectDataPrivate::readFiles() readNext(); if (isStartElement()) { if (name() == QLatin1String("file")) - filterSectionList.last().addFile(readElementText()); + addMatchingFiles(readElementText()); else raiseUnknownTokenError(); } else if (isEndElement()) { @@ -258,7 +263,47 @@ void QHelpProjectDataPrivate::readFiles() } } +// Expand file pattern and add matches into list. If the pattern does not match +// any files, insert the pattern itself so the QHelpGenerator will emit a +// meaningful warning later. +void QHelpProjectDataPrivate::addMatchingFiles(const QString &pattern) +{ + // The pattern matching is expensive, so we skip it if no + // wildcard symbols occur in the string. + if (!pattern.contains('?') && !pattern.contains('*') + && !pattern.contains('[') && !pattern.contains(']')) { + filterSectionList.last().addFile(pattern); + return; + } + QFileInfo fileInfo(rootPath + '/' + pattern); + const QDir &dir = fileInfo.dir(); + const QString &path = dir.canonicalPath(); + + // QDir::entryList() is expensive, so we cache the results. + QMap<QString, QStringList>::ConstIterator it = dirEntriesCache.find(path); + const QStringList &entries = it != dirEntriesCache.constEnd() ? + it.value() : dir.entryList(QDir::Files); + if (it == dirEntriesCache.constEnd()) + dirEntriesCache.insert(path, entries); + + bool matchFound = false; +#ifdef Q_OS_WIN + Qt::CaseSensitivity cs = Qt::CaseInsensitive; +#else + Qt::CaseSensitivity cs = Qt::CaseSensitive; +#endif + QRegExp regExp(fileInfo.fileName(), cs, QRegExp::Wildcard); + foreach (const QString &file, entries) { + if (regExp.exactMatch(file)) { + matchFound = true; + filterSectionList.last(). + addFile(QFileInfo(pattern).dir().path() + '/' + file); + } + } + if (!matchFound) + filterSectionList.last().addFile(pattern); +} /*! \internal diff --git a/tools/assistant/lib/qhelpsearchengine.cpp b/tools/assistant/lib/qhelpsearchengine.cpp index 2a41d04..94c5f7e 100644 --- a/tools/assistant/lib/qhelpsearchengine.cpp +++ b/tools/assistant/lib/qhelpsearchengine.cpp @@ -44,6 +44,7 @@ #include "qhelpsearchquerywidget.h" #include "qhelpsearchresultwidget.h" +#include "qhelpsearchindexreader_p.h" #if defined(QT_CLUCENE_SUPPORT) # include "qhelpsearchindexreader_clucene_p.h" # include "qhelpsearchindexwriter_clucene_p.h" @@ -147,8 +148,11 @@ private: return; if (!indexReader) { - indexReader = new QHelpSearchIndexReader(); - +#if defined(QT_CLUCENE_SUPPORT) + indexReader = new QHelpSearchIndexReaderClucene(); +#else + indexReader = new QHelpSearchIndexReaderDefault(); +#endif // QT_CLUCENE_SUPPORT connect(indexReader, SIGNAL(searchingStarted()), this, SIGNAL(searchingStarted())); connect(indexReader, SIGNAL(searchingFinished(int)), this, SIGNAL(searchingFinished(int))); } @@ -181,7 +185,7 @@ private slots: { #if defined(QT_CLUCENE_SUPPORT) if (indexWriter && !helpEngine.isNull()) { - indexWriter->optimizeIndex(); + indexWriter->optimizeIndex(); } #endif } @@ -192,7 +196,7 @@ private: QHelpSearchQueryWidget *queryWidget; QHelpSearchResultWidget *resultWidget; - QHelpSearchIndexReader *indexReader; + qt::fulltextsearch::QHelpSearchIndexReader *indexReader; QHelpSearchIndexWriter *indexWriter; QPointer<QHelpEngineCore> helpEngine; @@ -321,7 +325,7 @@ QHelpSearchEngine::QHelpSearchEngine(QHelpEngineCore *helpEngine, QObject *paren : QObject(parent) { d = new QHelpSearchEnginePrivate(helpEngine); - + connect(helpEngine, SIGNAL(setupFinished()), this, SLOT(indexDocumentation())); connect(d, SIGNAL(indexingStarted()), this, SIGNAL(indexingStarted())); diff --git a/tools/assistant/lib/qhelpsearchindexreader.cpp b/tools/assistant/lib/qhelpsearchindexreader.cpp new file mode 100644 index 0000000..a0fcbe5 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexreader.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchindexreader_p.h" + +QT_BEGIN_NAMESPACE + +namespace qt { + namespace fulltextsearch { + +QHelpSearchIndexReader::QHelpSearchIndexReader() + : QThread() + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexReader::~QHelpSearchIndexReader() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexReader::cancelSearching() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexReader::search(const QString &collectionFile, const QString &indexFilesFolder, + const QList<QHelpSearchQuery> &queryList) +{ + wait(); + + this->hitList.clear(); + this->m_cancel = false; + this->m_query = queryList; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + + start(QThread::NormalPriority); +} + +int QHelpSearchIndexReader::hitsCount() const +{ + QMutexLocker lock(&mutex); + return hitList.count(); +} + +QList<QHelpSearchEngine::SearchHit> QHelpSearchIndexReader::hits(int start, + int end) const +{ + QList<QHelpSearchEngine::SearchHit> hits; + QMutexLocker lock(&mutex); + for (int i = start; i < end && i < hitList.count(); ++i) + hits.append(hitList.at(i)); + return hits; +} + + + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE diff --git a/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp b/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp index 89d6040..b417078 100644 --- a/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp +++ b/tools/assistant/lib/qhelpsearchindexreader_clucene.cpp @@ -59,60 +59,18 @@ namespace qt { namespace fulltextsearch { namespace clucene { -QHelpSearchIndexReader::QHelpSearchIndexReader() - : QThread() - , m_cancel(false) +QHelpSearchIndexReaderClucene::QHelpSearchIndexReaderClucene() + : QHelpSearchIndexReader() { // nothing todo } -QHelpSearchIndexReader::~QHelpSearchIndexReader() +QHelpSearchIndexReaderClucene::~QHelpSearchIndexReaderClucene() { - mutex.lock(); - this->m_cancel = true; - mutex.unlock(); - - wait(); } -void QHelpSearchIndexReader::cancelSearching() -{ - mutex.lock(); - this->m_cancel = true; - mutex.unlock(); -} -void QHelpSearchIndexReader::search(const QString &collectionFile, const QString &indexFilesFolder, - const QList<QHelpSearchQuery> &queryList) -{ - wait(); - - this->hitList.clear(); - this->m_cancel = false; - this->m_query = queryList; - this->m_collectionFile = collectionFile; - this->m_indexFilesFolder = indexFilesFolder; - - start(QThread::NormalPriority); -} - -int QHelpSearchIndexReader::hitsCount() const -{ - QMutexLocker lock(&mutex); - return hitList.count(); -} - -QList<QHelpSearchEngine::SearchHit> QHelpSearchIndexReader::hits(int start, - int end) const -{ - QList<QHelpSearchEngine::SearchHit> hits; - QMutexLocker lock(&mutex); - for (int i = start; i < end && i < hitList.count(); ++i) - hits.append(hitList.at(i)); - return hits; -} - -void QHelpSearchIndexReader::run() +void QHelpSearchIndexReaderClucene::run() { mutex.lock(); @@ -140,7 +98,7 @@ void QHelpSearchIndexReader::run() if(QCLuceneIndexReader::indexExists(indexPath)) { mutex.lock(); if (m_cancel) { - mutex.unlock(); + mutex.unlock(); return; } mutex.unlock(); @@ -227,7 +185,7 @@ void QHelpSearchIndexReader::run() } } -bool QHelpSearchIndexReader::defaultQuery(const QString &term, QCLuceneBooleanQuery &booleanQuery, +bool QHelpSearchIndexReaderClucene::defaultQuery(const QString &term, QCLuceneBooleanQuery &booleanQuery, QCLuceneStandardAnalyzer &analyzer) { const QLatin1String c("content"); @@ -244,7 +202,7 @@ bool QHelpSearchIndexReader::defaultQuery(const QString &term, QCLuceneBooleanQu return false; } -bool QHelpSearchIndexReader::buildQuery(QCLuceneBooleanQuery &booleanQuery, +bool QHelpSearchIndexReaderClucene::buildQuery(QCLuceneBooleanQuery &booleanQuery, const QList<QHelpSearchQuery> &queryList, QCLuceneStandardAnalyzer &analyzer) { foreach (const QHelpSearchQuery query, queryList) { @@ -344,7 +302,7 @@ bool QHelpSearchIndexReader::buildQuery(QCLuceneBooleanQuery &booleanQuery, return true; } -bool QHelpSearchIndexReader::buildTryHarderQuery(QCLuceneBooleanQuery &booleanQuery, +bool QHelpSearchIndexReaderClucene::buildTryHarderQuery(QCLuceneBooleanQuery &booleanQuery, const QList<QHelpSearchQuery> &queryList, QCLuceneStandardAnalyzer &analyzer) { bool retVal = false; @@ -367,7 +325,7 @@ bool QHelpSearchIndexReader::buildTryHarderQuery(QCLuceneBooleanQuery &booleanQu return retVal; } -void QHelpSearchIndexReader::boostSearchHits(const QHelpEngineCore &engine, +void QHelpSearchIndexReaderClucene::boostSearchHits(const QHelpEngineCore &engine, QList<QHelpSearchEngine::SearchHit> &hitList, const QList<QHelpSearchQuery> &queryList) { foreach (const QHelpSearchQuery query, queryList) { diff --git a/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h b/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h index 8876d80..93ac6a8 100644 --- a/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h +++ b/tools/assistant/lib/qhelpsearchindexreader_clucene_p.h @@ -53,44 +53,24 @@ // We mean it. // -#include "qhelpsearchengine.h" +#include "qhelpsearchindexreader_p.h" #include "fulltextsearch/qanalyzer_p.h" #include "fulltextsearch/qquery_p.h" -#include <QtCore/QList> -#include <QtCore/QMutex> -#include <QtCore/QObject> -#include <QtCore/QString> -#include <QtCore/QThread> -#include <QtCore/QWaitCondition> - -class QHelpEngineCore; - QT_BEGIN_NAMESPACE namespace qt { namespace fulltextsearch { namespace clucene { -class QHelpSearchIndexReader : public QThread +class QHelpSearchIndexReaderClucene : public QHelpSearchIndexReader { Q_OBJECT public: - QHelpSearchIndexReader(); - ~QHelpSearchIndexReader(); - - void cancelSearching(); - void search(const QString &collectionFile, - const QString &indexFilesFolder, - const QList<QHelpSearchQuery> &queryList); - int hitsCount() const; - QList<QHelpSearchEngine::SearchHit> hits(int start, int end) const; - -signals: - void searchingStarted(); - void searchingFinished(int hits); + QHelpSearchIndexReaderClucene(); + ~QHelpSearchIndexReaderClucene(); private: void run(); @@ -102,14 +82,6 @@ private: const QList<QHelpSearchQuery> &queryList, QCLuceneStandardAnalyzer &analyzer); void boostSearchHits(const QHelpEngineCore &engine, QList<QHelpSearchEngine::SearchHit> &hitList, const QList<QHelpSearchQuery> &queryList); - -private: - mutable QMutex mutex; - QList<QHelpSearchEngine::SearchHit> hitList; - bool m_cancel; - QString m_collectionFile; - QList<QHelpSearchQuery> m_query; - QString m_indexFilesFolder; }; } // namespace clucene diff --git a/tools/assistant/lib/qhelpsearchindexreader_default.cpp b/tools/assistant/lib/qhelpsearchindexreader_default.cpp index 91af925..fbf8a09 100644 --- a/tools/assistant/lib/qhelpsearchindexreader_default.cpp +++ b/tools/assistant/lib/qhelpsearchindexreader_default.cpp @@ -492,56 +492,17 @@ void Reader::cleanupIndex(EntryTable &entryTable) } -QHelpSearchIndexReader::QHelpSearchIndexReader() - : QThread() - , m_cancel(false) +QHelpSearchIndexReaderDefault::QHelpSearchIndexReaderDefault() + : QHelpSearchIndexReader() { // nothing todo } -QHelpSearchIndexReader::~QHelpSearchIndexReader() +QHelpSearchIndexReaderDefault::~QHelpSearchIndexReaderDefault() { - mutex.lock(); - this->m_cancel = true; - waitCondition.wakeOne(); - mutex.unlock(); - - wait(); -} - -void QHelpSearchIndexReader::cancelSearching() -{ - mutex.lock(); - this->m_cancel = true; - mutex.unlock(); -} - -void QHelpSearchIndexReader::search(const QString &collectionFile, - const QString &indexFilesFolder, - const QList<QHelpSearchQuery> &queryList) -{ - QMutexLocker lock(&mutex); - - this->hitList.clear(); - this->m_cancel = false; - this->m_query = queryList; - this->m_collectionFile = collectionFile; - this->m_indexFilesFolder = indexFilesFolder; - - start(QThread::NormalPriority); -} - -int QHelpSearchIndexReader::hitsCount() const -{ - return hitList.count(); } -QHelpSearchEngine::SearchHit QHelpSearchIndexReader::hit(int index) const -{ - return hitList.at(index); -} - -void QHelpSearchIndexReader::run() +void QHelpSearchIndexReaderDefault::run() { mutex.lock(); @@ -571,7 +532,7 @@ void QHelpSearchIndexReader::run() QHelpEngineCore engine(collectionFile, 0); if (!engine.setupData()) return; - + const QStringList registeredDocs = engine.registeredDocumentations(); const QStringList indexedNamespaces = engine.customValue(key).toString(). split(QLatin1String("|"), QString::SkipEmptyParts); diff --git a/tools/assistant/lib/qhelpsearchindexreader_default_p.h b/tools/assistant/lib/qhelpsearchindexreader_default_p.h index f0e59b4..d21fc08 100644 --- a/tools/assistant/lib/qhelpsearchindexreader_default_p.h +++ b/tools/assistant/lib/qhelpsearchindexreader_default_p.h @@ -54,19 +54,10 @@ // #include "qhelpsearchindex_default_p.h" -#include "qhelpsearchengine.h" +#include "qhelpsearchindexreader_p.h" #include <QtCore/QHash> #include <QtCore/QPair> -#include <QtCore/QList> -#include <QtCore/QMutex> -#include <QtCore/QString> -#include <QtCore/QThread> -#include <QtCore/QObject> -#include <QtCore/QVector> -#include <QtCore/QByteArray> -#include <QtCore/QStringList> -#include <QtCore/QWaitCondition> QT_BEGIN_NAMESPACE @@ -121,39 +112,19 @@ private: }; -class QHelpSearchIndexReader : public QThread +class QHelpSearchIndexReaderDefault : public QHelpSearchIndexReader { Q_OBJECT public: - QHelpSearchIndexReader(); - ~QHelpSearchIndexReader(); - - void cancelSearching(); - void search(const QString &collectionFile, - const QString &indexFilesFolder, - const QList<QHelpSearchQuery> &queryList); - - int hitsCount() const; - QHelpSearchEngine::SearchHit hit(int index) const; - -signals: - void searchingStarted(); - void searchingFinished(int hits); + QHelpSearchIndexReaderDefault(); + ~QHelpSearchIndexReaderDefault(); private: void run(); private: - QMutex mutex; Reader m_reader; - QWaitCondition waitCondition; - QList<QHelpSearchEngine::SearchHit> hitList; - - bool m_cancel; - QList<QHelpSearchQuery> m_query; - QString m_collectionFile; - QString m_indexFilesFolder; }; } // namespace std diff --git a/tools/assistant/lib/qhelpsearchindexreader_p.h b/tools/assistant/lib/qhelpsearchindexreader_p.h new file mode 100644 index 0000000..c8f2b44 --- /dev/null +++ b/tools/assistant/lib/qhelpsearchindexreader_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXREADER_H +#define QHELPSEARCHINDEXREADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpsearchengine.h" + +#include <QtCore/QList> +#include <QtCore/QMutex> +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QThread> +#include <QtCore/QWaitCondition> + +QT_BEGIN_NAMESPACE + +class QHelpEngineCore; + +namespace qt { + namespace fulltextsearch { + +class QHelpSearchIndexReader : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexReader(); + ~QHelpSearchIndexReader(); + + void cancelSearching(); + void search(const QString &collectionFile, + const QString &indexFilesFolder, + const QList<QHelpSearchQuery> &queryList); + int hitsCount() const; + QList<QHelpSearchEngine::SearchHit> hits(int start, int end) const; + +signals: + void searchingStarted(); + void searchingFinished(int hits); + +protected: + mutable QMutex mutex; + QList<QHelpSearchEngine::SearchHit> hitList; + bool m_cancel; + QString m_collectionFile; + QList<QHelpSearchQuery> m_query; + QString m_indexFilesFolder; + +private: + virtual void run()=0; +}; + + } // namespace fulltextsearch +} // namespace qt + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXREADER_H diff --git a/tools/assistant/lib/qhelpsearchquerywidget.cpp b/tools/assistant/lib/qhelpsearchquerywidget.cpp index 00444b1..110df4f 100644 --- a/tools/assistant/lib/qhelpsearchquerywidget.cpp +++ b/tools/assistant/lib/qhelpsearchquerywidget.cpp @@ -43,9 +43,12 @@ #include <QtCore/QDebug> +#include <QtCore/QAbstractListModel> #include <QtCore/QObject> #include <QtCore/QStringList> +#include <QtCore/QtGlobal> +#include <QtGui/QCompleter> #include <QtGui/QLabel> #include <QtGui/QLayout> #include <QtGui/QLineEdit> @@ -60,8 +63,46 @@ class QHelpSearchQueryWidgetPrivate : public QObject Q_OBJECT private: + struct QueryHistory { + explicit QueryHistory() : curQuery(-1) {} + QList<QList<QHelpSearchQuery> > queries; + int curQuery; + }; + + class CompleterModel : public QAbstractListModel + { + public: + explicit CompleterModel(QObject *parent) + : QAbstractListModel(parent) {} + + int rowCount(const QModelIndex &parent = QModelIndex()) const + { + return parent.isValid() ? 0 : termList.size(); + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const + { + if (!index.isValid() || index.row() >= termList.count()|| + (role != Qt::EditRole && role != Qt::DisplayRole)) + return QVariant(); + return termList.at(index.row()); + } + + void addTerm(const QString &term) + { + if (!termList.contains(term)) { + termList.append(term); + reset(); + } + } + + private: + QStringList termList; + }; + QHelpSearchQueryWidgetPrivate() - : QObject() + : QObject(), simpleSearch(true), + searchCompleter(new CompleterModel(this), this) { searchButton = 0; advancedSearchWidget = 0; @@ -136,11 +177,102 @@ private: return wordList; } + void saveQuery(const QList<QHelpSearchQuery> &query, QueryHistory &queryHist) + { + // We only add the query to the list if it is different from the last one. + bool insert = false; + if (queryHist.queries.empty()) + insert = true; + else { + const QList<QHelpSearchQuery> &lastQuery = queryHist.queries.last(); + if (lastQuery.size() != query.size()) { + insert = true; + } else { + for (int i = 0; i < query.size(); ++i) { + if (query.at(i).fieldName != lastQuery.at(i).fieldName + || query.at(i).wordList != lastQuery.at(i).wordList) { + insert = true; + break; + } + } + } + } + if (insert) { + queryHist.queries.append(query); + foreach (const QHelpSearchQuery &queryPart, query) { + static_cast<CompleterModel *>(searchCompleter.model())-> + addTerm(queryPart.wordList.join(" ")); + } + } + } + + void nextOrPrevQuery(int maxOrMinIndex, int addend, + QToolButton *thisButton, QToolButton *otherButton) + { + QueryHistory *queryHist; + QList<QLineEdit *> lineEdits; + if (simpleSearch) { + queryHist = &simpleQueries; + lineEdits << defaultQuery; + } else { + queryHist = &complexQueries; + lineEdits << allQuery << atLeastQuery << similarQuery + << withoutQuery << exactQuery; + } + foreach (QLineEdit *lineEdit, lineEdits) + lineEdit->clear(); + + // Otherwise, the respective button would be disabled. + Q_ASSERT(queryHist->curQuery != maxOrMinIndex); + + queryHist->curQuery += addend; + const QList<QHelpSearchQuery> &query = + queryHist->queries.at(queryHist->curQuery); + foreach (const QHelpSearchQuery &queryPart, query) { + QLineEdit *lineEdit; + switch (queryPart.fieldName) { + case QHelpSearchQuery::DEFAULT: + lineEdit = defaultQuery; + break; + case QHelpSearchQuery::ALL: + lineEdit = allQuery; + break; + case QHelpSearchQuery::ATLEAST: + lineEdit = atLeastQuery; + break; + case QHelpSearchQuery::FUZZY: + lineEdit = similarQuery; + break; + case QHelpSearchQuery::WITHOUT: + lineEdit = withoutQuery; + break; + case QHelpSearchQuery::PHRASE: + lineEdit = exactQuery; + break; + default: + Q_ASSERT(0); + } + lineEdit->setText(queryPart.wordList.join(" ")); + } + + if (queryHist->curQuery == maxOrMinIndex) + thisButton->setEnabled(false); + otherButton->setEnabled(true); + } + + void enableOrDisableToolButtons() + { + const QueryHistory &queryHist = + simpleSearch ? simpleQueries : complexQueries; + prevQueryButton->setEnabled(queryHist.curQuery > 0); + nextQueryButton->setEnabled(queryHist.curQuery < + queryHist.queries.size() - 1); + } + private slots: void showHideAdvancedSearch() { - bool hidden = advancedSearchWidget->isHidden(); - if (hidden) { + if (simpleSearch) { advancedSearchWidget->show(); showHideAdvancedSearchButton->setText((QLatin1String("-"))); } else { @@ -148,12 +280,86 @@ private slots: showHideAdvancedSearchButton->setText((QLatin1String("+"))); } - defaultQuery->setEnabled(!hidden); + simpleSearch = !simpleSearch; + defaultQuery->setEnabled(simpleSearch); + enableOrDisableToolButtons(); + } + + void searchRequested() + { + QList<QHelpSearchQuery> queryList; +#if !defined(QT_CLUCENE_SUPPORT) + queryList.append(QHelSearchQuery(QHelpSearchQuery::DEFAULT, + QStringList(defaultQuery->text()))); + +#else + if (defaultQuery->isEnabled()) { + queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, + buildTermList(escapeString(defaultQuery->text())))); + } else { + const QRegExp exp(QLatin1String("\\s+")); + QStringList lst = similarQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList fuzzy; + foreach (const QString term, lst) + fuzzy += buildTermList(escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::FUZZY, fuzzy)); + } + + lst = withoutQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList without; + foreach (const QString term, lst) + without.append(escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::WITHOUT, without)); + } + + if (!exactQuery->text().isEmpty()) { + QString phrase = exactQuery->text().remove(QLatin1Char('\"')); + phrase = escapeString(phrase.simplified()); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::PHRASE, QStringList(phrase))); + } + + lst = allQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList all; + foreach (const QString term, lst) + all.append(escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::ALL, all)); + } + + lst = atLeastQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList atLeast; + foreach (const QString term, lst) + atLeast += buildTermList(escapeString(term)); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::ATLEAST, atLeast)); + } + } +#endif + QueryHistory &queryHist = simpleSearch ? simpleQueries : complexQueries; + saveQuery(queryList, queryHist); + queryHist.curQuery = queryHist.queries.size() - 1; + if (queryHist.curQuery > 0) + prevQueryButton->setEnabled(true); + nextQueryButton->setEnabled(false); + } + + void nextQuery() + { + nextOrPrevQuery((simpleSearch ? simpleQueries : complexQueries).queries.size() - 1, + 1, nextQueryButton, prevQueryButton); + } + + void prevQuery() + { + nextOrPrevQuery(0, -1, prevQueryButton, nextQueryButton); } private: friend class QHelpSearchQueryWidget; + bool simpleSearch; QPushButton *searchButton; QWidget* advancedSearchWidget; QToolButton *showHideAdvancedSearchButton; @@ -163,6 +369,11 @@ private: QLineEdit *withoutQuery; QLineEdit *allQuery; QLineEdit *atLeastQuery; + QToolButton *nextQueryButton; + QToolButton *prevQueryButton; + QueryHistory simpleQueries; + QueryHistory complexQueries; + QCompleter searchCompleter; }; #include "qhelpsearchquerywidget.moc" @@ -199,13 +410,26 @@ QHelpSearchQueryWidget::QHelpSearchQueryWidget(QWidget *parent) QHBoxLayout* hBoxLayout = new QHBoxLayout(); QLabel *label = new QLabel(tr("Search for:"), this); d->defaultQuery = new QLineEdit(this); + d->defaultQuery->setCompleter(&d->searchCompleter); + d->prevQueryButton = new QToolButton(this); + d->prevQueryButton->setArrowType(Qt::LeftArrow); + d->prevQueryButton->setToolTip(tr("Previous search")); + d->prevQueryButton->setEnabled(false); + d->nextQueryButton = new QToolButton(this); + d->nextQueryButton->setArrowType(Qt::RightArrow); + d->nextQueryButton->setToolTip(tr("Next search")); + d->nextQueryButton->setEnabled(false); d->searchButton = new QPushButton(tr("Search"), this); hBoxLayout->addWidget(label); hBoxLayout->addWidget(d->defaultQuery); + hBoxLayout->addWidget(d->prevQueryButton); + hBoxLayout->addWidget(d->nextQueryButton); hBoxLayout->addWidget(d->searchButton); vLayout->addLayout(hBoxLayout); + connect(d->prevQueryButton, SIGNAL(clicked()), d, SLOT(prevQuery())); + connect(d->nextQueryButton, SIGNAL(clicked()), d, SLOT(nextQuery())); connect(d->searchButton, SIGNAL(clicked()), this, SIGNAL(search())); connect(d->defaultQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); @@ -236,26 +460,31 @@ QHelpSearchQueryWidget::QHelpSearchQueryWidget(QWidget *parent) label = new QLabel(tr("words <B>similar</B> to:"), this); gLayout->addWidget(label, 0, 0); d->similarQuery = new QLineEdit(this); + d->similarQuery->setCompleter(&d->searchCompleter); gLayout->addWidget(d->similarQuery, 0, 1); label = new QLabel(tr("<B>without</B> the words:"), this); gLayout->addWidget(label, 1, 0); d->withoutQuery = new QLineEdit(this); + d->withoutQuery->setCompleter(&d->searchCompleter); gLayout->addWidget(d->withoutQuery, 1, 1); label = new QLabel(tr("with <B>exact phrase</B>:"), this); gLayout->addWidget(label, 2, 0); d->exactQuery = new QLineEdit(this); + d->exactQuery->setCompleter(&d->searchCompleter); gLayout->addWidget(d->exactQuery, 2, 1); label = new QLabel(tr("with <B>all</B> of the words:"), this); gLayout->addWidget(label, 3, 0); d->allQuery = new QLineEdit(this); + d->allQuery->setCompleter(&d->searchCompleter); gLayout->addWidget(d->allQuery, 3, 1); label = new QLabel(tr("with <B>at least one</B> of the words:"), this); gLayout->addWidget(label, 4, 0); d->atLeastQuery = new QLineEdit(this); + d->atLeastQuery->setCompleter(&d->searchCompleter); gLayout->addWidget(d->atLeastQuery, 4, 1); vLayout->addWidget(d->advancedSearchWidget); @@ -269,6 +498,7 @@ QHelpSearchQueryWidget::QHelpSearchQueryWidget(QWidget *parent) connect(d->showHideAdvancedSearchButton, SIGNAL(clicked()), d, SLOT(showHideAdvancedSearch())); #endif + connect(this, SIGNAL(search()), d, SLOT(searchRequested())); } /*! @@ -285,59 +515,10 @@ QHelpSearchQueryWidget::~QHelpSearchQueryWidget() */ QList<QHelpSearchQuery> QHelpSearchQueryWidget::query() const { -#if !defined(QT_CLUCENE_SUPPORT) - QList<QHelpSearchQuery> queryList; - queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, - QStringList(d->defaultQuery->text()))); - - return queryList; -#else - QList<QHelpSearchQuery> queryList; - if (d->defaultQuery->isEnabled()) { - queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, - d->buildTermList(d->escapeString(d->defaultQuery->text())))); - } else { - const QRegExp exp(QLatin1String("\\s+")); - QStringList lst = d->similarQuery->text().split(exp, QString::SkipEmptyParts); - if (!lst.isEmpty()) { - QStringList fuzzy; - foreach (const QString term, lst) - fuzzy += d->buildTermList(d->escapeString(term)); - queryList.append(QHelpSearchQuery(QHelpSearchQuery::FUZZY, fuzzy)); - } - - lst = d->withoutQuery->text().split(exp, QString::SkipEmptyParts); - if (!lst.isEmpty()) { - QStringList without; - foreach (const QString term, lst) - without.append(d->escapeString(term)); - queryList.append(QHelpSearchQuery(QHelpSearchQuery::WITHOUT, without)); - } - - if (!d->exactQuery->text().isEmpty()) { - QString phrase = d->exactQuery->text().remove(QLatin1Char('\"')); - phrase = d->escapeString(phrase.simplified()); - queryList.append(QHelpSearchQuery(QHelpSearchQuery::PHRASE, QStringList(phrase))); - } - - lst = d->allQuery->text().split(exp, QString::SkipEmptyParts); - if (!lst.isEmpty()) { - QStringList all; - foreach (const QString term, lst) - all.append(d->escapeString(term)); - queryList.append(QHelpSearchQuery(QHelpSearchQuery::ALL, all)); - } - - lst = d->atLeastQuery->text().split(exp, QString::SkipEmptyParts); - if (!lst.isEmpty()) { - QStringList atLeast; - foreach (const QString term, lst) - atLeast += d->buildTermList(d->escapeString(term)); - queryList.append(QHelpSearchQuery(QHelpSearchQuery::ATLEAST, atLeast)); - } - } - return queryList; -#endif + const QHelpSearchQueryWidgetPrivate::QueryHistory &queryHist = + d->simpleSearch ? d->simpleQueries : d->complexQueries; + return queryHist.queries.isEmpty() ? + QList<QHelpSearchQuery>() : queryHist.queries.last(); } /*! \reimp diff --git a/tools/assistant/tools/assistant/assistant.qch b/tools/assistant/tools/assistant/assistant.qch Binary files differindex 99687ed..3e66bd9 100644 --- a/tools/assistant/tools/assistant/assistant.qch +++ b/tools/assistant/tools/assistant/assistant.qch diff --git a/tools/assistant/tools/assistant/assistant.rc b/tools/assistant/tools/assistant/assistant.rc index b4786ce..deaf40c 100644 --- a/tools/assistant/tools/assistant/assistant.rc +++ b/tools/assistant/tools/assistant/assistant.rc @@ -1 +1,32 @@ +#include "winver.h" + IDI_ICON1 ICON DISCARDABLE "assistant.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGS 0x0L + FILEFLAGSMASK 0x3fL + FILEOS 0x00040004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)" + VALUE "FileDescription", "Qt Assistant" + VALUE "FileVersion", "1.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)." + VALUE "InternalName", "assistant.exe" + VALUE "OriginalFilename", "assistant.exe" + VALUE "ProductName", "Qt Assistant" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/tools/assistant/tools/assistant/centralwidget.cpp b/tools/assistant/tools/assistant/centralwidget.cpp index 00a8893..23562db 100644 --- a/tools/assistant/tools/assistant/centralwidget.cpp +++ b/tools/assistant/tools/assistant/centralwidget.cpp @@ -43,6 +43,7 @@ #include "helpviewer.h" #include "searchwidget.h" #include "mainwindow.h" +#include "preferencesdialog.h" #include <QtCore/QDir> #include <QtCore/QEvent> @@ -423,6 +424,27 @@ void CentralWidget::setSource(const QUrl &url) tabWidget->setTabText(lastTabPage, quoteTabTitle(viewer->documentTitle())); } +void CentralWidget::setupWidget() +{ + int option = helpEngine->customValue(QLatin1String("StartOption"), + ShowLastPages).toInt(); + + if (option != ShowLastPages) { + QString homePage; + if (option == ShowHomePage) { + homePage = helpEngine->customValue(QLatin1String("defaultHomepage"), + QLatin1String("help")).toString(); + homePage = helpEngine->customValue(QLatin1String("homepage"), + homePage).toString(); + } + if (option == ShowBlankPage) + homePage = QLatin1String("about:blank"); + setSource(homePage); + } else { + setLastShownPages(); + } +} + void CentralWidget::setLastShownPages() { const QLatin1String key("LastShownPages"); diff --git a/tools/assistant/tools/assistant/centralwidget.h b/tools/assistant/tools/assistant/centralwidget.h index ca9caaf..f7ce1d5 100644 --- a/tools/assistant/tools/assistant/centralwidget.h +++ b/tools/assistant/tools/assistant/centralwidget.h @@ -111,7 +111,7 @@ public: CentralWidget(QHelpEngine *engine, MainWindow *parent); ~CentralWidget(); - void setLastShownPages(); + void setupWidget(); bool hasSelection() const; QUrl currentSource() const; QString currentTitle() const; @@ -188,6 +188,7 @@ private: void initPrinter(); QString quoteTabTitle(const QString &title) const; void highlightSearchTerms(); + void setLastShownPages(); private: int lastTabPage; diff --git a/tools/assistant/tools/assistant/doc/assistant.qhp b/tools/assistant/tools/assistant/doc/assistant.qhp index 7a26101..7ea4cdd 100644 --- a/tools/assistant/tools/assistant/doc/assistant.qhp +++ b/tools/assistant/tools/assistant/doc/assistant.qhp @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <QtHelpProject version="1.0"> <virtualFolder>assistant</virtualFolder> - <namespace>com.trolltech.com.assistantinternal_1.0.0</namespace> + <namespace>com.trolltech.com.assistantinternal-1.0.0</namespace> <filterSection> <files> <file>assistant.html</file> diff --git a/tools/assistant/tools/assistant/helpviewer.cpp b/tools/assistant/tools/assistant/helpviewer.cpp index 6799db3..5422bf46 100644 --- a/tools/assistant/tools/assistant/helpviewer.cpp +++ b/tools/assistant/tools/assistant/helpviewer.cpp @@ -306,7 +306,7 @@ void HelpViewer::setSource(const QUrl &url) loadFinished = false; if (url.toString() == QLatin1String("help")) { load(QUrl(QLatin1String("qthelp://com.trolltech.com." - "assistantinternal_1.0.0/assistant/assistant.html"))); + "assistantinternal-1.0.0/assistant/assistant.html"))); } else { load(url); } @@ -425,7 +425,7 @@ void HelpViewer::setSource(const QUrl &url) if (help) { QTextBrowser::setSource(QUrl(QLatin1String("qthelp://com.trolltech.com." - "assistantinternal_1.0.0/assistant/assistant.html"))); + "assistantinternal-1.0.0/assistant/assistant.html"))); } else { QTextBrowser::setSource(url); setHtml(tr("<title>Error 404...</title><div align=\"center\"><br><br>" diff --git a/tools/assistant/tools/assistant/main.cpp b/tools/assistant/tools/assistant/main.cpp index 55e929a..4af2570 100644 --- a/tools/assistant/tools/assistant/main.cpp +++ b/tools/assistant/tools/assistant/main.cpp @@ -181,7 +181,21 @@ QString indexFilesFolder(const QString &collectionFile) int main(int argc, char *argv[]) { - QApplication a(argc, argv); + // First do a quick search for arguments that imply command-line mode. + const char * cmdModeArgs[] = { + "-help", "-register", "-unregister", "-remove-search-index" + }; + bool useGui = true; + for (int i = 1; i < argc; ++i) { + for (size_t j = 0; j < sizeof cmdModeArgs/sizeof *cmdModeArgs; ++j) { + if(strcmp(argv[i], cmdModeArgs[j]) == 0) { + useGui = false; + break; + } + } + } + + QApplication a(argc, argv, useGui); a.addLibraryPath(a.applicationDirPath() + QLatin1String("/plugins")); CmdLineParser cmd; @@ -230,7 +244,7 @@ int main(int argc, char *argv[]) if (file.isEmpty()) file = MainWindow::defaultHelpCollectionFileName(); QString path = QFileInfo(file).path(); - path += QLatin1String("/") + indexFilesFolder(file); + path += QLatin1Char('/') + indexFilesFolder(file); QLocalSocket localSocket; localSocket.connectToServer(QString(QLatin1String("QtAssistant%1")) @@ -306,7 +320,7 @@ int main(int argc, char *argv[]) } } - QLatin1String intern("com.trolltech.com.assistantinternal_"); + QLatin1String intern("com.trolltech.com.assistantinternal-"); foreach (const QString &doc, userDocs) { if (!callerDocs.contains(doc) && !doc.startsWith(intern)) user.unregisterDocumentation(doc); diff --git a/tools/assistant/tools/assistant/mainwindow.cpp b/tools/assistant/tools/assistant/mainwindow.cpp index 0340297..bc73b80 100644 --- a/tools/assistant/tools/assistant/mainwindow.cpp +++ b/tools/assistant/tools/assistant/mainwindow.cpp @@ -93,6 +93,8 @@ MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) , m_qtDocInstaller(0) , m_connectedInitSignals(false) { + setToolButtonStyle(Qt::ToolButtonFollowStyle); + if (usesDefaultCollection()) { MainWindow::collectionFileDirectory(true); m_helpEngine = new QHelpEngine(MainWindow::defaultHelpCollectionFileName(), @@ -272,7 +274,7 @@ bool MainWindow::initHelpDB() return false; bool assistantInternalDocRegistered = false; - QString intern(QLatin1String("com.trolltech.com.assistantinternal_")); + QString intern(QLatin1String("com.trolltech.com.assistantinternal-")); foreach (const QString &ns, m_helpEngine->registeredDocumentations()) { if (ns.startsWith(intern)) { intern = ns; @@ -405,7 +407,7 @@ void MainWindow::insertLastPages() if (m_cmdLine->url().isValid()) m_centralWidget->setSource(m_cmdLine->url()); else - m_centralWidget->setLastShownPages(); + m_centralWidget->setupWidget(); if (m_cmdLine->search() == CmdLineParser::Activate) showSearch(); @@ -429,6 +431,7 @@ void MainWindow::setupActions() SLOT(printPreview())); m_printAction = menu->addAction(tr("&Print..."), m_centralWidget, SLOT(print())); + m_printAction->setPriority(QAction::LowPriority); m_printAction->setIcon(QIcon(resourcePath + QLatin1String("/print.png"))); m_printAction->setShortcut(QKeySequence::Print); @@ -442,18 +445,21 @@ void MainWindow::setupActions() m_closeTabAction->setShortcuts(QKeySequence::Close); QAction *tmp = menu->addAction(tr("&Quit"), this, SLOT(close())); - tmp->setShortcut(tr("CTRL+Q")); + tmp->setShortcut(QKeySequence::Quit); tmp->setMenuRole(QAction::QuitRole); menu = menuBar()->addMenu(tr("&Edit")); m_copyAction = menu->addAction(tr("&Copy selected Text"), m_centralWidget, SLOT(copySelection())); + m_copyAction->setPriority(QAction::LowPriority); + m_copyAction->setIconText("&Copy"); m_copyAction->setIcon(QIcon(resourcePath + QLatin1String("/editcopy.png"))); m_copyAction->setShortcuts(QKeySequence::Copy); m_copyAction->setEnabled(false); m_findAction = menu->addAction(tr("&Find in Text..."), m_centralWidget, SLOT(showTextSearch())); + m_findAction->setIconText("&Find"); m_findAction->setIcon(QIcon(resourcePath + QLatin1String("/find.png"))); m_findAction->setShortcuts(QKeySequence::Find); @@ -472,16 +478,19 @@ void MainWindow::setupActions() m_viewMenu = menuBar()->addMenu(tr("&View")); m_zoomInAction = m_viewMenu->addAction(tr("Zoom &in"), m_centralWidget, SLOT(zoomIn())); + m_zoomInAction->setPriority(QAction::LowPriority); m_zoomInAction->setIcon(QIcon(resourcePath + QLatin1String("/zoomin.png"))); m_zoomInAction->setShortcut(QKeySequence::ZoomIn); m_zoomOutAction = m_viewMenu->addAction(tr("Zoom &out"), m_centralWidget, SLOT(zoomOut())); + m_zoomOutAction->setPriority(QAction::LowPriority); m_zoomOutAction->setIcon(QIcon(resourcePath + QLatin1String("/zoomout.png"))); m_zoomOutAction->setShortcut(QKeySequence::ZoomOut); m_resetZoomAction = m_viewMenu->addAction(tr("Normal &Size"), m_centralWidget, SLOT(resetZoom())); + m_resetZoomAction->setPriority(QAction::LowPriority); m_resetZoomAction->setIcon(QIcon(resourcePath + QLatin1String("/resetzoom.png"))); m_resetZoomAction->setShortcut(tr("Ctrl+0")); @@ -507,12 +516,14 @@ void MainWindow::setupActions() m_backAction->setIcon(QIcon(resourcePath + QLatin1String("/previous.png"))); m_nextAction = menu->addAction(tr("&Forward"), m_centralWidget, SLOT(forward())); + m_nextAction->setPriority(QAction::LowPriority); m_nextAction->setEnabled(false); m_nextAction->setShortcuts(QKeySequence::Forward); m_nextAction->setIcon(QIcon(resourcePath + QLatin1String("/next.png"))); m_syncAction = menu->addAction(tr("Sync with Table of Contents"), this, SLOT(syncContents())); + m_syncAction->setIconText("Sync"); m_syncAction->setIcon(QIcon(resourcePath + QLatin1String("/synctoc.png"))); menu->addSeparator(); @@ -828,23 +839,16 @@ void MainWindow::showAboutDialog() aboutDia.setPixmap(pix); aboutDia.setWindowTitle(aboutDia.documentTitle()); } else { - // TODO: Remove these variables for 4.6.0. Must keep this way for 4.5.x due to string freeze. - QString edition; - QString info; - QString moreInfo; - QByteArray resources; aboutDia.setText(QString::fromLatin1("<center>" "<h3>%1</h3>" - "<p>Version %2 %3</p></center>" - "<p>%4</p>" - "<p>%5</p>" + "<p>Version %2</p></center>" "<p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)" ".</p><p>The program is provided AS IS with NO WARRANTY OF ANY KIND," " INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A" " PARTICULAR PURPOSE.<p/>") - .arg(tr("Qt Assistant")).arg(QLatin1String(QT_VERSION_STR)) - .arg(edition).arg(info).arg(moreInfo), resources); + .arg(tr("Qt Assistant")).arg(QLatin1String(QT_VERSION_STR)), + resources); QLatin1String path(":/trolltech/assistant/images/assistant-128.png"); aboutDia.setPixmap(QString(path)); } diff --git a/tools/assistant/tools/assistant/preferencesdialog.cpp b/tools/assistant/tools/assistant/preferencesdialog.cpp index fa70196..2b58c64 100644 --- a/tools/assistant/tools/assistant/preferencesdialog.cpp +++ b/tools/assistant/tools/assistant/preferencesdialog.cpp @@ -146,10 +146,13 @@ PreferencesDialog::~PreferencesDialog() emit updateBrowserFont(); } - if (!m_ui.homePageLineEdit->text().isEmpty()) { - key = QLatin1String("homepage"); - m_helpEngine->setCustomValue(key, m_ui.homePageLineEdit->text()); - } + QString homePage = m_ui.homePageLineEdit->text(); + if (homePage.isEmpty()) + homePage = QLatin1String("help"); + m_helpEngine->setCustomValue(QLatin1String("homepage"), homePage); + + int option = m_ui.helpStartComboBox->currentIndex(); + m_helpEngine->setCustomValue(QLatin1String("StartOption"), option); } void PreferencesDialog::showDialog() @@ -379,6 +382,8 @@ void PreferencesDialog::applyChanges() CentralWidget* widget = CentralWidget::instance(); for (int i = m_TabsToClose.count(); --i >= 0;) widget->closeTabAt(m_TabsToClose.at(i)); + if (widget->availableHelpViewer()== 0) + widget->setSource(QUrl(QLatin1String("about:blank"))); if (m_unregDocs.count()) { foreach (const QString &doc, m_unregDocs) @@ -483,22 +488,23 @@ void PreferencesDialog::updateOptionsPage() homepage = m_helpEngine->customValue(QLatin1String("defaultHomepage"), QLatin1String("help")).toString(); } - m_ui.homePageLineEdit->setText(homepage); - connect(m_ui.currentPageButton, SIGNAL(pressed()), this, - SLOT(currentHomepageChanged())); - connect(m_ui.restoreDefaultHomePageButton, SIGNAL(pressed()), this, - SLOT(restoreDefaultHomepage())); + + int option = m_helpEngine->customValue(QLatin1String("StartOption"), + ShowLastPages).toInt(); + m_ui.helpStartComboBox->setCurrentIndex(option); + + connect(m_ui.blankPageButton, SIGNAL(clicked()), this, SLOT(setBlankPage())); + connect(m_ui.currentPageButton, SIGNAL(clicked()), this, SLOT(setCurrentPage())); + connect(m_ui.defaultPageButton, SIGNAL(clicked()), this, SLOT(setDefaultPage())); } -void PreferencesDialog::restoreDefaultHomepage() +void PreferencesDialog::setBlankPage() { - QString homepage = m_helpEngine->customValue(QLatin1String("defaultHomepage"), - QLatin1String("help")).toString(); - m_ui.homePageLineEdit->setText(homepage); + m_ui.homePageLineEdit->setText(QLatin1String("about:blank")); } -void PreferencesDialog::currentHomepageChanged() +void PreferencesDialog::setCurrentPage() { QString homepage = CentralWidget::instance()->currentSource().toString(); if (homepage.isEmpty()) @@ -507,4 +513,11 @@ void PreferencesDialog::currentHomepageChanged() m_ui.homePageLineEdit->setText(homepage); } +void PreferencesDialog::setDefaultPage() +{ + QString homepage = m_helpEngine->customValue(QLatin1String("defaultHomepage"), + QLatin1String("help")).toString(); + m_ui.homePageLineEdit->setText(homepage); +} + QT_END_NAMESPACE diff --git a/tools/assistant/tools/assistant/preferencesdialog.h b/tools/assistant/tools/assistant/preferencesdialog.h index 5b8ffe8..4471b5f 100644 --- a/tools/assistant/tools/assistant/preferencesdialog.h +++ b/tools/assistant/tools/assistant/preferencesdialog.h @@ -50,6 +50,12 @@ QT_BEGIN_NAMESPACE class FontPanel; class QHelpEngineCore; +enum { + ShowHomePage = 0, + ShowBlankPage = 1, + ShowLastPages = 2 +}; + class PreferencesDialog : public QDialog { Q_OBJECT @@ -72,8 +78,10 @@ private slots: void appFontSettingChanged(int index); void browserFontSettingToggled(bool on); void browserFontSettingChanged(int index); - void restoreDefaultHomepage(); - void currentHomepageChanged(); + + void setBlankPage(); + void setCurrentPage(); + void setDefaultPage(); signals: void updateBrowserFont(); diff --git a/tools/assistant/tools/assistant/preferencesdialog.ui b/tools/assistant/tools/assistant/preferencesdialog.ui index d848b49..279084d 100644 --- a/tools/assistant/tools/assistant/preferencesdialog.ui +++ b/tools/assistant/tools/assistant/preferencesdialog.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>359</width> + <width>375</width> <height>266</height> </rect> </property> @@ -187,19 +187,90 @@ <attribute name="title"> <string>Options</string> </attribute> - <layout class="QVBoxLayout" name="verticalLayout_3"> + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QGroupBox" name="groupBox"> + <widget class="QGroupBox" name="groupBox_2"> <property name="title"> - <string>Homepage</string> + <string/> </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> <item> - <widget class="QLineEdit" name="homePageLineEdit"/> + <widget class="QLabel" name="label_5"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>On help start:</string> + </property> + </widget> </item> <item> + <widget class="QComboBox" name="helpStartComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <item> + <property name="text"> + <string>Show my home page</string> + </property> + </item> + <item> + <property name="text"> + <string>Show a blank page</string> + </property> + </item> + <item> + <property name="text"> + <string>Show my tabs from last session</string> + </property> + </item> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>54</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string/> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Homepage</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="homePageLineEdit"/> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -213,22 +284,25 @@ </spacer> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QPushButton" name="currentPageButton"> - <property name="text"> - <string>Current Page</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="restoreDefaultHomePageButton"> - <property name="text"> - <string>Restore to default</string> - </property> - </widget> - </item> - </layout> + <widget class="QPushButton" name="currentPageButton"> + <property name="text"> + <string>Current Page</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="blankPageButton"> + <property name="text"> + <string>Blank Page</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="defaultPageButton"> + <property name="text"> + <string>Restore to default</string> + </property> + </widget> </item> </layout> </item> diff --git a/tools/assistant/tools/qhelpconverter/adpreader.cpp b/tools/assistant/tools/qhelpconverter/adpreader.cpp index 35f8878..c427038 100644 --- a/tools/assistant/tools/qhelpconverter/adpreader.cpp +++ b/tools/assistant/tools/qhelpconverter/adpreader.cpp @@ -39,8 +39,16 @@ ** ****************************************************************************/ +#include <QRegExp> + #include "adpreader.h" +static bool versionIsAtLeast320(const QString &version) +{ + return QRegExp("\\d.\\d\\.\\d").exactMatch(version) + && (version[0] > '3' || (version[0] == '3' && version[2] >= '2')); +} + QT_BEGIN_NAMESPACE void AdpReader::readData(const QByteArray &contents) @@ -51,11 +59,11 @@ void AdpReader::readData(const QByteArray &contents) m_properties.clear(); m_files.clear(); addData(contents); - while (!atEnd()) { - readNext(); - if (isStartElement()) { + while (!atEnd()) { + readNext(); + if (isStartElement()) { if (name().toString().toLower() == QLatin1String("assistantconfig") - && attributes().value(QLatin1String("version")) == QLatin1String("3.2.0")) { + && versionIsAtLeast320(attributes().value(QLatin1String("version")).toString())) { readProject(); } else if (name().toString().toLower() == QLatin1String("dcf")) { QString ref = attributes().value(QLatin1String("ref")).toString(); @@ -66,8 +74,8 @@ void AdpReader::readData(const QByteArray &contents) } else { raiseError(); } - } - } + } + } } QList<ContentItem> AdpReader::contents() const diff --git a/tools/assistant/tools/qhelpconverter/adpreader.h b/tools/assistant/tools/qhelpconverter/adpreader.h index f2e7509..740a462 100644 --- a/tools/assistant/tools/qhelpconverter/adpreader.h +++ b/tools/assistant/tools/qhelpconverter/adpreader.h @@ -50,15 +50,15 @@ QT_BEGIN_NAMESPACE struct ContentItem { ContentItem(const QString &t, const QString &r, int d) - : title(t), reference(r), depth(d) {} + : title(t), reference(r), depth(d) {} QString title; QString reference; - int depth; + int depth; }; struct KeywordItem { KeywordItem(const QString &k, const QString &r) - : keyword(k), reference(r) {} + : keyword(k), reference(r) {} QString keyword; QString reference; }; diff --git a/tools/checksdk/cesdkhandler.cpp b/tools/checksdk/cesdkhandler.cpp index 48452a3..677d003 100644 --- a/tools/checksdk/cesdkhandler.cpp +++ b/tools/checksdk/cesdkhandler.cpp @@ -71,15 +71,15 @@ bool CeSdkHandler::parse() // look at the file at %VCInstallDir%/vcpackages/WCE.VCPlatform.config // and scan through all installed sdks... m_list.clear(); - VCInstallDir = qgetenv("VCInstallDir"); + VCInstallDir = QString::fromLatin1(qgetenv("VCInstallDir")); VCInstallDir += QLatin1String("\\"); - VSInstallDir = qgetenv("VSInstallDir"); + VSInstallDir = QString::fromLatin1(qgetenv("VSInstallDir")); VSInstallDir += QLatin1String("\\"); if (VCInstallDir.isEmpty() || VSInstallDir.isEmpty()) return false; QDir vStudioDir(VCInstallDir); - if (!vStudioDir.cd("vcpackages")) + if (!vStudioDir.cd(QLatin1String("vcpackages"))) return false; QFile configFile(vStudioDir.absoluteFilePath(QLatin1String("WCE.VCPlatform.config"))); @@ -118,6 +118,7 @@ bool CeSdkHandler::parse() qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString(); return false; } + return m_list.size() > 0 ? true : false; } diff --git a/tools/checksdk/cesdkhandler.h b/tools/checksdk/cesdkhandler.h index 04d3bdf..6ec26db 100644 --- a/tools/checksdk/cesdkhandler.h +++ b/tools/checksdk/cesdkhandler.h @@ -102,8 +102,8 @@ inline QList<CeSdkInfo> CeSdkHandler::listAll() const inline QString CeSdkHandler::fixPaths(QString path) const { - QString str = QDir::toNativeSeparators(QDir::cleanPath(path.replace(VCINSTALL_MACRO, VCInstallDir).replace(VSINSTALL_MACRO, VSInstallDir).replace(QLatin1String("$(PATH)"), QLatin1String("%PATH%")))); - if (str.endsWith(';')) + QString str = QDir::toNativeSeparators(QDir::cleanPath(path.replace(QLatin1String(VCINSTALL_MACRO), VCInstallDir).replace(QLatin1String(VSINSTALL_MACRO), VSInstallDir).replace(QLatin1String("$(PATH)"), QLatin1String("%PATH%")))); + if (str.endsWith(QLatin1Char(';'))) str.truncate(str.length() - 1); return str; } diff --git a/tools/checksdk/checksdk.pro b/tools/checksdk/checksdk.pro index e364f26..a513981 100644 --- a/tools/checksdk/checksdk.pro +++ b/tools/checksdk/checksdk.pro @@ -32,40 +32,5 @@ SOURCES += \ HEADERS += \ cesdkhandler.h -# Bootstrapped Input -SOURCES += \ - $$QT_SOURCE_TREE/src/corelib/kernel/qmetatype.cpp \ - $$QT_SOURCE_TREE/src/corelib/kernel/qvariant.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qstring.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qstringlist.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qfile.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qdir.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qabstractfileengine.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_win.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_iterator.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qfsfileengine_iterator_win.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qfileinfo.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qtemporaryfile.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qdiriterator.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qiodevice.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qbuffer.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qtextstream.cpp \ - $$QT_SOURCE_TREE/src/corelib/io/qurl.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qdatetime.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qlocale.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qbytearray.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qbytearraymatcher.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qvector.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qvsnprintf.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qlistdata.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qhash.cpp \ - $$QT_SOURCE_TREE/src/corelib/global/qglobal.cpp \ - $$QT_SOURCE_TREE/src/corelib/global/qmalloc.cpp \ - $$QT_SOURCE_TREE/src/corelib/global/qnumeric.cpp \ - $$QT_SOURCE_TREE/src/corelib/xml/qxmlstream.cpp \ - $$QT_SOURCE_TREE/src/corelib/xml/qxmlutils.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qregexp.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qmap.cpp \ - $$QT_SOURCE_TREE/src/corelib/tools/qbitarray.cpp \ - $$QT_BUILD_TREE/src/corelib/global/qconfig.cpp +include(../../src/tools/bootstrap/bootstrap.pri) + diff --git a/tools/checksdk/main.cpp b/tools/checksdk/main.cpp index 2dd7214..6322eb7 100644 --- a/tools/checksdk/main.cpp +++ b/tools/checksdk/main.cpp @@ -46,17 +46,17 @@ void usage() { - qDebug() << "SDK Scanner - Convenience Tool to setup your environment"; - qDebug() << " for crosscompilation to Windows CE"; - qDebug() << "Options:"; - qDebug() << "-help This output"; - qDebug() << "-list List all available SDKs"; - qDebug() << "-sdk <name> Select specified SDK."; - qDebug() << " Note: SDK names with spaces need to be"; - qDebug() << " specified in parenthesis"; - qDebug() << " default: Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"; - qDebug() << "-script <file> Create a script file which can be launched"; - qDebug() << " to setup your environment for specified SDK"; + printf("SDK Scanner - Convenience Tool to setup your environment\n"); + printf(" for crosscompilation to Windows CE\n"); + printf("Options:\n"); + printf("-help This output\n"); + printf("-list List all available SDKs\n"); + printf("-sdk <name> Select specified SDK.\n"); + printf(" Note: SDK names with spaces need to be\n"); + printf(" specified in parenthesis\n"); + printf(" default: Windows Mobile 5.0 Pocket PC SDK (ARMV4I)\n"); + printf("-script <file> Create a script file which can be launched\n"); + printf(" to setup your environment for specified SDK\n"); } int main(int argc, char **argv) @@ -106,9 +106,12 @@ int main(int argc, char **argv) QList<CeSdkInfo> list = handler.listAll(); if (operationList) { - qDebug() << "Available SDKs:"; - for (QList<CeSdkInfo>::iterator it = list.begin(); it != list.end(); ++it) - qDebug() << "SDK Name:" << it->name(); + printf("Available SDKs:\n"); + for (QList<CeSdkInfo>::iterator it = list.begin(); it != list.end(); ++it) { + printf("SDK Name: "); + printf(qPrintable(it->name())); + printf("\n"); + } return 0; } @@ -132,10 +135,13 @@ int main(int argc, char **argv) includePath = QString::fromLatin1("INCLUDE=") + it->includePath(); libPath = QString::fromLatin1("LIB=") + it->libPath(); if (scriptFile.isEmpty()) { - qDebug() << "Please set up your environment with the following paths:"; - qDebug() << qPrintable(binPath); - qDebug() << qPrintable(includePath); - qDebug() << qPrintable(libPath); + printf("Please set up your environment with the following paths:\n"); + printf(qPrintable(binPath)); + printf("\n"); + printf(qPrintable(includePath)); + printf("\n"); + printf(qPrintable(libPath)); + printf("\n"); return 0; } else { QFile file(scriptFile); diff --git a/tools/configure/configure.pro b/tools/configure/configure.pro index 1ce9a1b..eeec62a 100644 --- a/tools/configure/configure.pro +++ b/tools/configure/configure.pro @@ -3,7 +3,7 @@ DESTDIR = ../.. CONFIG += console flat CONFIG -= moc qt -DEFINES = QT_NODLL QT_NO_CODECS QT_NO_TEXTCODEC QT_NO_UNICODETABLES QT_LITE_COMPONENT QT_NO_STL QT_NO_COMPRESS QT_BUILD_QMAKE QT_NO_THREAD QT_NO_QOBJECT _CRT_SECURE_NO_DEPRECATE +DEFINES = UNICODE QT_NODLL QT_NO_CODECS QT_NO_TEXTCODEC QT_NO_UNICODETABLES QT_LITE_COMPONENT QT_NO_STL QT_NO_COMPRESS QT_BUILD_QMAKE QT_NO_THREAD QT_NO_QOBJECT _CRT_SECURE_NO_DEPRECATE win32 : LIBS += -lole32 -ladvapi32 @@ -32,6 +32,7 @@ HEADERS = configureapp.h environment.h tools.h\ $$QT_SOURCE_TREE/src/corelib/tools/qlist.h \ $$QT_SOURCE_TREE/src/corelib/tools/qlocale.h \ $$QT_SOURCE_TREE/src/corelib/tools/qvector.h \ + $$QT_SOURCE_TREE/src/corelib/codecs/qutfcodec_p.h \ $$QT_SOURCE_TREE/src/corelib/codecs/qtextcodec.h \ $$QT_SOURCE_TREE/src/corelib/global/qglobal.h \ $$QT_SOURCE_TREE/src/corelib/global/qnumeric.h \ @@ -64,6 +65,7 @@ SOURCES = main.cpp configureapp.cpp environment.cpp tools.cpp \ $$QT_SOURCE_TREE/src/corelib/tools/qlistdata.cpp \ $$QT_SOURCE_TREE/src/corelib/tools/qlocale.cpp \ $$QT_SOURCE_TREE/src/corelib/tools/qvector.cpp \ + $$QT_SOURCE_TREE/src/corelib/codecs/qutfcodec.cpp \ $$QT_SOURCE_TREE/src/corelib/codecs/qtextcodec.cpp \ $$QT_SOURCE_TREE/src/corelib/global/qglobal.cpp \ $$QT_SOURCE_TREE/src/corelib/global/qnumeric.cpp \ diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 1e501c5..f32e7dc 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -116,16 +116,9 @@ Configure::Configure( int& argc, char** argv ) // Get the path to the executable - QFileInfo sourcePathInfo; - QT_WA({ - unsigned short module_name[256]; - GetModuleFileNameW(0, reinterpret_cast<wchar_t *>(module_name), sizeof(module_name)); - sourcePathInfo = QString::fromUtf16(module_name); - }, { - char module_name[256]; - GetModuleFileNameA(0, module_name, sizeof(module_name)); - sourcePathInfo = QString::fromLocal8Bit(module_name); - }); + wchar_t module_name[MAX_PATH]; + GetModuleFileName(0, module_name, sizeof(module_name) / sizeof(wchar_t)); + QFileInfo sourcePathInfo = QString::fromWCharArray(module_name); sourcePath = sourcePathInfo.absolutePath(); sourceDir = sourcePathInfo.dir(); buildPath = QDir::currentPath(); @@ -252,6 +245,7 @@ Configure::Configure( int& argc, char** argv ) dictionary[ "XMLPATTERNS" ] = "auto"; dictionary[ "PHONON" ] = "auto"; dictionary[ "PHONON_BACKEND" ] = "yes"; + dictionary[ "MULTIMEDIA" ] = "yes"; dictionary[ "DIRECTSHOW" ] = "no"; dictionary[ "WEBKIT" ] = "auto"; dictionary[ "PLUGIN_MANIFESTS" ] = "yes"; @@ -314,7 +308,6 @@ Configure::Configure( int& argc, char** argv ) dictionary[ "QT3SUPPORT" ] = "yes"; dictionary[ "ACCESSIBILITY" ] = "yes"; dictionary[ "OPENGL" ] = "yes"; - dictionary[ "DIRECT3D" ] = "auto"; dictionary[ "IPV6" ] = "yes"; // Always, dynamicly loaded dictionary[ "OPENSSL" ] = "auto"; dictionary[ "DBUS" ] = "auto"; @@ -605,10 +598,13 @@ void Configure::parseCmdLine() // cetest --------------------------------------------------- else if (configCmdLine.at(i) == "-no-cetest") { dictionary[ "CETEST" ] = "no"; + dictionary[ "CETEST_REQUESTED" ] = "no"; } else if (configCmdLine.at(i) == "-cetest") { // although specified to use it, we stay at "auto" state // this is because checkAvailability() adds variables - // we need for crosscompilation + // we need for crosscompilation; but remember if we asked + // for it. + dictionary[ "CETEST_REQUESTED" ] = "yes"; } // Qt/CE - signing tool ------------------------------------- else if( configCmdLine.at(i) == "-signature") { @@ -824,11 +820,7 @@ void Configure::parseCmdLine() else if (configCmdLine.at(i) == "-iwmmxt") dictionary[ "IWMMXT" ] = "yes"; - else if (configCmdLine.at(i) == "-no-direct3d") { - dictionary["DIRECT3D"] = "no"; - }else if (configCmdLine.at(i) == "-direct3d") { - dictionary["DIRECT3D"] = "auto"; // have to pass auto detection to enable Direct3D - } else if( configCmdLine.at(i) == "-no-openssl" ) { + else if( configCmdLine.at(i) == "-no-openssl" ) { dictionary[ "OPENSSL"] = "no"; } else if( configCmdLine.at(i) == "-openssl" ) { dictionary[ "OPENSSL" ] = "yes"; @@ -852,6 +844,10 @@ void Configure::parseCmdLine() dictionary[ "XMLPATTERNS" ] = "no"; } else if( configCmdLine.at(i) == "-xmlpatterns" ) { dictionary[ "XMLPATTERNS" ] = "yes"; + } else if( configCmdLine.at(i) == "-no-multimedia" ) { + dictionary[ "MULTIMEDIA" ] = "no"; + } else if( configCmdLine.at(i) == "-multimedia" ) { + dictionary[ "MULTIMEDIA" ] = "yes"; } else if( configCmdLine.at(i) == "-no-phonon" ) { dictionary[ "PHONON" ] = "no"; } else if( configCmdLine.at(i) == "-phonon" ) { @@ -1144,6 +1140,10 @@ void Configure::parseCmdLine() useUnixSeparators = (dictionary["QMAKESPEC"] == "win32-g++"); + // Allow tests for private classes to be compiled against internal builds + if (dictionary["BUILDDEV"] == "yes") + qtConfig += "private_tests"; + #if !defined(EVAL) for( QStringList::Iterator dis = disabledModules.begin(); dis != disabledModules.end(); ++dis ) { @@ -1327,7 +1327,6 @@ void Configure::applySpecSpecifics() dictionary[ "MMX" ] = "no"; dictionary[ "IWMMXT" ] = "no"; dictionary[ "CE_CRT" ] = "yes"; - dictionary[ "DIRECT3D" ] = "no"; dictionary[ "WEBKIT" ] = "no"; dictionary[ "PHONON" ] = "yes"; dictionary[ "DIRECTSHOW" ] = "no"; @@ -1427,10 +1426,11 @@ bool Configure::displayHelp() "[-system-libtiff] [-no-libjpeg] [-qt-libjpeg] [-system-libjpeg]\n" "[-no-libmng] [-qt-libmng] [-system-libmng] [-no-qt3support] [-mmx]\n" "[-no-mmx] [-3dnow] [-no-3dnow] [-sse] [-no-sse] [-sse2] [-no-sse2]\n" - "[-no-iwmmxt] [-iwmmxt] [-direct3d] [-openssl] [-openssl-linked]\n" + "[-no-iwmmxt] [-iwmmxt] [-openssl] [-openssl-linked]\n" "[-no-openssl] [-no-dbus] [-dbus] [-dbus-linked] [-platform <spec>]\n" "[-qtnamespace <namespace>] [-qtlibinfix <infix>] [-no-phonon]\n" "[-phonon] [-no-phonon-backend] [-phonon-backend]\n" + "[-no-multimedia] [-multimedia]\n" "[-no-webkit] [-webkit]\n" "[-no-scripttools] [-scripttools]\n" "[-graphicssystem raster|opengl]\n\n", 0, 7); @@ -1595,7 +1595,6 @@ bool Configure::displayHelp() desc("SSE", "yes", "-sse", "Compile with use of SSE instructions"); desc("SSE2", "no", "-no-sse2", "Do not compile with use of SSE2 instructions"); desc("SSE2", "yes", "-sse2", "Compile with use of SSE2 instructions"); - desc("DIRECT3D", "yes", "-direct3d", "Compile in Direct3D support (experimental - see INSTALL for more info)"); desc("OPENSSL", "no", "-no-openssl", "Do not compile in OpenSSL support"); desc("OPENSSL", "yes", "-openssl", "Compile in run-time OpenSSL support"); desc("OPENSSL", "linked","-openssl-linked", "Compile in linked OpenSSL support"); @@ -1606,6 +1605,8 @@ bool Configure::displayHelp() desc("PHONON", "yes", "-phonon", "Compile the Phonon module (Phonon is built if a decent C++ compiler is used.)"); desc("PHONON_BACKEND","no", "-no-phonon-backend","Do not compile the platform-specific Phonon backend-plugin"); desc("PHONON_BACKEND","yes","-phonon-backend", "Compile in the platform-specific Phonon backend-plugin"); + desc("MULTIMEDIA", "no", "-no-multimedia", "Do not compile the multimedia module"); + desc("MULTIMEDIA", "yes","-multimedia", "Compile in multimedia module"); desc("WEBKIT", "no", "-no-webkit", "Do not compile in the WebKit module"); desc("WEBKIT", "yes", "-webkit", "Compile in the WebKit module (WebKit is built if a decent C++ compiler is used.)"); desc("SCRIPTTOOLS", "no", "-no-scripttools", "Do not build the QtScriptTools module."); @@ -1663,39 +1664,49 @@ bool Configure::displayHelp() return false; } -bool Configure::findFileInPaths(const QString &fileName, const QStringList &paths) +QString Configure::findFileInPaths(const QString &fileName, const QString &paths) { +#if defined(Q_OS_WIN32) + QRegExp splitReg("[;,]"); +#else + QRegExp splitReg("[:]"); +#endif + QStringList pathList = paths.split(splitReg, QString::SkipEmptyParts); QDir d; - for( QStringList::ConstIterator it = paths.begin(); it != paths.end(); ++it ) { + for( QStringList::ConstIterator it = pathList.begin(); it != pathList.end(); ++it ) { // Remove any leading or trailing ", this is commonly used in the environment // variables QString path = (*it); - if ( path.startsWith( "\"" ) ) + if ( path.startsWith( '\"' ) ) path = path.right( path.length() - 1 ); - if ( path.endsWith( "\"" ) ) + if ( path.endsWith( '\"' ) ) path = path.left( path.length() - 1 ); if( d.exists( path + QDir::separator() + fileName ) ) - return true; + return path; } - return false; + return QString(); } bool Configure::findFile( const QString &fileName ) { - QString file = fileName.toLower(); - QStringList paths; -#if defined(Q_OS_WIN32) - QRegExp splitReg("[;,]"); -#else - QRegExp splitReg("[:]"); -#endif - if (file.endsWith(".h")) - paths = QString::fromLocal8Bit(getenv("INCLUDE")).split(splitReg, QString::SkipEmptyParts); - else if ( file.endsWith( ".lib" ) ) - paths = QString::fromLocal8Bit(getenv("LIB")).split(splitReg, QString::SkipEmptyParts); - else - paths = QString::fromLocal8Bit(getenv("PATH")).split(splitReg, QString::SkipEmptyParts); - return findFileInPaths(file, paths); + const QString file = fileName.toLower(); + const QString pathEnvVar = QString::fromLocal8Bit(getenv("PATH")); + const QString mingwPath = dictionary["QMAKESPEC"].endsWith("-g++") ? + findFileInPaths("mingw32-g++.exe", pathEnvVar) : QString(); + + QString paths; + if (file.endsWith(".h")) { + if (!mingwPath.isNull() && !findFileInPaths(file, mingwPath + QLatin1String("/../include")).isNull()) + return true; + paths = QString::fromLocal8Bit(getenv("INCLUDE")); + } else if ( file.endsWith( ".lib" ) || file.endsWith( ".a" ) ) { + if (!mingwPath.isNull() && !findFileInPaths(file, mingwPath + QLatin1String("/../lib")).isNull()) + return true; + paths = QString::fromLocal8Bit(getenv("LIB")); + } else { + paths = pathEnvVar; + } + return !findFileInPaths(file, paths).isNull(); } /*! @@ -1765,7 +1776,7 @@ bool Configure::checkAvailability(const QString &part) { bool available = false; if (part == "STYLE_WINDOWSXP") - available = (dictionary.value("QMAKESPEC") == "win32-g++" || findFile("uxtheme.h")); + available = (findFile("uxtheme.h")); else if (part == "ZLIB") available = findFile("zlib.h"); @@ -1831,6 +1842,11 @@ bool Configure::checkAvailability(const QString &part) dictionary[ "QT_CE_RAPI_INC" ] += QLatin1String("\"") + rapiHeader + QLatin1String("\""); dictionary[ "QT_CE_RAPI_LIB" ] += QLatin1String("\"") + rapiLib + QLatin1String("\""); } + else if (dictionary[ "CETEST_REQUESTED" ] == "yes") { + cout << "cetest could not be enabled: rapi.h and rapi.lib could not be found." << endl; + cout << "Make sure the environment is set up for compiling with ActiveSync." << endl; + dictionary[ "DONE" ] = "error"; + } } else if (part == "INCREDIBUILD_XGE") available = findFile("BuildConsole.exe") && findFile("xgConsole.exe"); @@ -1841,56 +1857,26 @@ bool Configure::checkAvailability(const QString &part) && dictionary.value("QMAKESPEC") != "win32-msvc.net" // Leave for now, since we can't be sure if they are using 2002 or 2003 with this spec && dictionary.value("QMAKESPEC") != "win32-msvc2002" && dictionary.value("EXCEPTIONS") == "yes"; - } else if (part == "DIRECT3D") { - QString sdk_dir(QString::fromLocal8Bit(getenv("DXSDK_DIR"))); - QDir dir; - bool has_d3d = false; - - if (!sdk_dir.isEmpty() && dir.exists(sdk_dir)) - has_d3d = true; - - if (has_d3d && !QFile::exists(sdk_dir + QLatin1String("\\include\\d3d9.h"))) { - cout << "No Direct3D version 9 SDK found." << endl; - has_d3d = false; - } - - // find the first dxguid.lib in the current LIB paths, if it is NOT - // the D3D SDK one, we're most likely in trouble.. - if (has_d3d) { - has_d3d = false; - QString env_lib(QString::fromLocal8Bit(getenv("LIB"))); - QStringList lib_paths = env_lib.split(';'); - for (int i=0; i<lib_paths.size(); ++i) { - QString lib_path = lib_paths.at(i); - if (QFile::exists(lib_path + QLatin1String("\\dxguid.lib"))) - { - if (lib_path.startsWith(sdk_dir)) { - has_d3d = true; - } else { - cout << "Your D3D/Platform SDK library paths seem to appear in the wrong order." << endl; - } - break; - } - } - } - - available = has_d3d; - if (!has_d3d) { - cout << "Setting Direct3D to NO, since the proper Direct3D SDK was not detected." << endl - << "Make sure you have the Direct3D SDK installed, and that you have run" << endl - << "the <path to SDK>\\Utilities\\Bin\\dx_setenv.cmd script." << endl - << "The D3D SDK library path *needs* to appear before the Platform SDK library" << endl - << "path in your LIB environment variable." << endl; - } } else if (part == "PHONON") { - available = findFile("vmr9.h") && findFile("dshow.h") && findFile("strmiids.lib") && - findFile("dmoguids.lib") && findFile("msdmo.lib") && findFile("d3d9.h"); + available = findFile("vmr9.h") && findFile("dshow.h") && findFile("dmo.h") && findFile("dmodshow.h") + && (findFile("strmiids.lib") || findFile("libstrmiids.a")) + && (findFile("dmoguids.lib") || findFile("libdmoguids.a")) + && (findFile("msdmo.lib") || findFile("libmsdmo.a")) + && findFile("d3d9.h"); if (!available) { cout << "All the required DirectShow/Direct3D files couldn't be found." << endl - << "Make sure you have either the platform SDK AND the DirectX SDK or the Windows SDK installed." << endl - << "If you have the DirectX SDK installed, please make sure that you have run the <path to SDK>\\SetEnv.Cmd script." << endl; - } + << "Make sure you have either the platform SDK AND the DirectShow SDK or the Windows SDK installed." << endl + << "If you have the DirectShow SDK installed, please make sure that you have run the <path to SDK>\\SetEnv.Cmd script." << endl; + if (!findFile("vmr9.h")) cout << "vmr9.h not found" << endl; + if (!findFile("dshow.h")) cout << "dshow.h not found" << endl; + if (!findFile("strmiids.lib")) cout << "strmiids.lib not found" << endl; + if (!findFile("dmoguids.lib")) cout << "dmoguids.lib not found" << endl; + if (!findFile("msdmo.lib")) cout << "msdmo.lib not found" << endl; + if (!findFile("d3d9.h")) cout << "d3d9.h not found" << endl; + } + } else if (part == "MULTIMEDIA") { + available = true; } else if (part == "WEBKIT") { available = (dictionary.value("QMAKESPEC") == "win32-msvc2005") || (dictionary.value("QMAKESPEC") == "win32-msvc2008") || (dictionary.value("QMAKESPEC") == "win32-g++"); } else if (part == "SCRIPTTOOLS") { @@ -1975,8 +1961,6 @@ void Configure::autoDetection() dictionary["SCRIPTTOOLS"] = checkAvailability("SCRIPTTOOLS") ? "yes" : "no"; if (dictionary["XMLPATTERNS"] == "auto") dictionary["XMLPATTERNS"] = checkAvailability("XMLPATTERNS") ? "yes" : "no"; - if (dictionary["DIRECT3D"] == "auto") - dictionary["DIRECT3D"] = checkAvailability("DIRECT3D") ? "yes" : "no"; if (dictionary["PHONON"] == "auto") dictionary["PHONON"] = checkAvailability("PHONON") ? "yes" : "no"; if (dictionary["WEBKIT"] == "auto") @@ -2046,7 +2030,6 @@ bool Configure::verifyConfiguration() no-gif gif dll staticlib - internal nocrosscompiler GNUmake largefile @@ -2072,8 +2055,6 @@ void Configure::generateBuildKey() QStringList build_options; if (!dictionary["QCONFIG"].isEmpty()) build_options += dictionary["QCONFIG"] + "-config "; - if (dictionary["STL"] == "no") - build_options += "no-stl"; build_options.sort(); // Sorted defines that start with QT_NO_ @@ -2301,9 +2282,6 @@ void Configure::generateOutputVars() if ( dictionary["DIRECTSHOW"] == "yes" ) qtConfig += "directshow"; - if (dictionary[ "DIRECT3D" ] == "yes") - qtConfig += "direct3d"; - if (dictionary[ "OPENSSL" ] == "yes") qtConfig += "openssl"; else if (dictionary[ "OPENSSL" ] == "linked") @@ -2334,6 +2312,9 @@ void Configure::generateOutputVars() qtConfig += "phonon-backend"; } + if (dictionary["MULTIMEDIA"] == "yes") + qtConfig += "multimedia"; + if (dictionary["WEBKIT"] == "yes") qtConfig += "webkit"; @@ -2688,13 +2669,13 @@ void Configure::generateConfigfiles() if(dictionary["ACCESSIBILITY"] == "no") qconfigList += "QT_NO_ACCESSIBILITY"; if(dictionary["EXCEPTIONS"] == "no") qconfigList += "QT_NO_EXCEPTIONS"; if(dictionary["OPENGL"] == "no") qconfigList += "QT_NO_OPENGL"; - if(dictionary["DIRECT3D"] == "no") qconfigList += "QT_NO_DIRECT3D"; if(dictionary["OPENSSL"] == "no") qconfigList += "QT_NO_OPENSSL"; if(dictionary["OPENSSL"] == "linked") qconfigList += "QT_LINKED_OPENSSL"; if(dictionary["DBUS"] == "no") qconfigList += "QT_NO_DBUS"; if(dictionary["IPV6"] == "no") qconfigList += "QT_NO_IPV6"; if(dictionary["WEBKIT"] == "no") qconfigList += "QT_NO_WEBKIT"; if(dictionary["PHONON"] == "no") qconfigList += "QT_NO_PHONON"; + if(dictionary["MULTIMEDIA"] == "no") qconfigList += "QT_NO_MULTIMEDIA"; if(dictionary["XMLPATTERNS"] == "no") qconfigList += "QT_NO_XMLPATTERNS"; if(dictionary["SCRIPTTOOLS"] == "no") qconfigList += "QT_NO_SCRIPTTOOLS"; @@ -2779,7 +2760,7 @@ void Configure::generateConfigfiles() tmpFile.flush(); // Replace old qconfig.h with new one - ::SetFileAttributesA(outName.toLocal8Bit(), FILE_ATTRIBUTE_NORMAL); + ::SetFileAttributes((wchar_t*)outName.utf16(), FILE_ATTRIBUTE_NORMAL); QFile::remove(outName); tmpFile.copy(outName); tmpFile.close(); @@ -2815,7 +2796,7 @@ void Configure::generateConfigfiles() } outName = defSpec + "/qmake.conf"; - ::SetFileAttributesA(outName.toLocal8Bit(), FILE_ATTRIBUTE_NORMAL ); + ::SetFileAttributes((wchar_t*)outName.utf16(), FILE_ATTRIBUTE_NORMAL ); QFile qmakeConfFile(outName); if (qmakeConfFile.open(QFile::Append | QFile::WriteOnly | QFile::Text)) { QTextStream qmakeConfStream; @@ -2883,7 +2864,7 @@ void Configure::generateConfigfiles() tmpFile2.flush(); // Replace old qconfig.cpp with new one - ::SetFileAttributesA(outName.toLocal8Bit(), FILE_ATTRIBUTE_NORMAL ); + ::SetFileAttributes((wchar_t*)outName.utf16(), FILE_ATTRIBUTE_NORMAL ); QFile::remove( outName ); tmpFile2.copy(outName); tmpFile2.close(); @@ -2949,11 +2930,11 @@ void Configure::displayConfig() cout << "SSE2 support................" << dictionary[ "SSE2" ] << endl; cout << "IWMMXT support.............." << dictionary[ "IWMMXT" ] << endl; cout << "OpenGL support.............." << dictionary[ "OPENGL" ] << endl; - cout << "Direct3D support............" << dictionary[ "DIRECT3D" ] << endl; cout << "OpenSSL support............." << dictionary[ "OPENSSL" ] << endl; cout << "QtDBus support.............." << dictionary[ "DBUS" ] << endl; cout << "QtXmlPatterns support......." << dictionary[ "XMLPATTERNS" ] << endl; cout << "Phonon support.............." << dictionary[ "PHONON" ] << endl; + cout << "Multimedia support.........." << dictionary[ "MULTIMEDIA" ] << endl; cout << "WebKit support.............." << dictionary[ "WEBKIT" ] << endl; cout << "QtScriptTools support......." << dictionary[ "SCRIPTTOOLS" ] << endl; cout << "Graphics System............." << dictionary[ "GRAPHICS_SYSTEM" ] << endl; @@ -3141,6 +3122,9 @@ void Configure::buildQmake() void Configure::buildHostTools() { + if (dictionary[ "NOPROCESS" ] == "yes") + dictionary[ "DONE" ] = "yes"; + if (!dictionary.contains("XQMAKESPEC")) return; @@ -3364,7 +3348,6 @@ void Configure::generateMakefiles() } else { cout << "Processing of project files have been disabled." << endl; cout << "Only use this option if you really know what you're doing." << endl << endl; - dictionary[ "DONE" ] = "yes"; return; } } @@ -3372,8 +3355,16 @@ void Configure::generateMakefiles() void Configure::showSummary() { QString make = dictionary[ "MAKE" ]; - cout << endl << endl << "Qt is now configured for building. Just run " << qPrintable(make) << "." << endl; - cout << "To reconfigure, run " << qPrintable(make) << " confclean and configure." << endl << endl; + if (!dictionary.contains("XQMAKESPEC")) { + cout << endl << endl << "Qt is now configured for building. Just run " << qPrintable(make) << "." << endl; + cout << "To reconfigure, run " << qPrintable(make) << " confclean and configure." << endl << endl; + } else { + // we are cross compiling for Windows CE + cout << endl << endl << "Qt is now configured for building. To start the build run:" << endl + << "\tsetcepaths " << dictionary.value("XQMAKESPEC") << endl + << "\t" << qPrintable(make) << endl + << "To reconfigure, run " << qPrintable(make) << " confclean and configure." << endl << endl; + } } Configure::ProjectType Configure::projectType( const QString& proFileName ) diff --git a/tools/configure/configureapp.h b/tools/configure/configureapp.h index dc22ac9..03df28e 100644 --- a/tools/configure/configureapp.h +++ b/tools/configure/configureapp.h @@ -150,8 +150,8 @@ private: QString fixSeparators(QString somePath); bool filesDiffer(const QString &file1, const QString &file2); - static bool findFile(const QString &fileName); - static bool findFileInPaths(const QString &fileName, const QStringList &paths); + bool findFile(const QString &fileName); + static QString findFileInPaths(const QString &fileName, const QString &paths); #if !defined(EVAL) void reloadCmdLine(); void saveCmdLine(); diff --git a/tools/configure/environment.cpp b/tools/configure/environment.cpp index 6dc8940..b4c61f8 100644 --- a/tools/configure/environment.cpp +++ b/tools/configure/environment.cpp @@ -146,26 +146,14 @@ QString Environment::readRegistryKey(HKEY parentHandle, const QString &rSubkey) QString rSubkeyPath = keyPath(rSubkey); HKEY handle = 0; - LONG res; - QT_WA( { - res = RegOpenKeyExW(parentHandle, (WCHAR*)rSubkeyPath.utf16(), - 0, KEY_READ, &handle); - } , { - res = RegOpenKeyExA(parentHandle, rSubkeyPath.toLocal8Bit(), - 0, KEY_READ, &handle); - } ); - + LONG res = RegOpenKeyEx(parentHandle, (wchar_t*)rSubkeyPath.utf16(), 0, KEY_READ, &handle); if (res != ERROR_SUCCESS) return QString(); // get the size and type of the value DWORD dataType; DWORD dataSize; - QT_WA( { - res = RegQueryValueExW(handle, (WCHAR*)rSubkeyName.utf16(), 0, &dataType, 0, &dataSize); - }, { - res = RegQueryValueExA(handle, rSubkeyName.toLocal8Bit(), 0, &dataType, 0, &dataSize); - } ); + res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), 0, &dataType, 0, &dataSize); if (res != ERROR_SUCCESS) { RegCloseKey(handle); return QString(); @@ -173,13 +161,8 @@ QString Environment::readRegistryKey(HKEY parentHandle, const QString &rSubkey) // get the value QByteArray data(dataSize, 0); - QT_WA( { - res = RegQueryValueExW(handle, (WCHAR*)rSubkeyName.utf16(), 0, 0, - reinterpret_cast<unsigned char*>(data.data()), &dataSize); - }, { - res = RegQueryValueExA(handle, rSubkeyName.toLocal8Bit(), 0, 0, - reinterpret_cast<unsigned char*>(data.data()), &dataSize); - } ); + res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), 0, 0, + reinterpret_cast<unsigned char*>(data.data()), &dataSize); if (res != ERROR_SUCCESS) { RegCloseKey(handle); return QString(); @@ -189,11 +172,7 @@ QString Environment::readRegistryKey(HKEY parentHandle, const QString &rSubkey) switch (dataType) { case REG_EXPAND_SZ: case REG_SZ: { - QT_WA( { - result = QString::fromUtf16(((const ushort*)data.constData())); - }, { - result = QString::fromLatin1(data.constData()); - } ); + result = QString::fromWCharArray(((const wchar_t *)data.constData())); break; } @@ -201,29 +180,20 @@ QString Environment::readRegistryKey(HKEY parentHandle, const QString &rSubkey) QStringList l; int i = 0; for (;;) { - QString s; - QT_WA( { - s = QString::fromUtf16((const ushort*)data.constData() + i); - }, { - s = QString::fromLatin1(data.constData() + i); - } ); + QString s = QString::fromWCharArray((const wchar_t *)data.constData() + i); i += s.length() + 1; if (s.isEmpty()) break; l.append(s); } - result = l.join(", "); + result = l.join(", "); break; } case REG_NONE: case REG_BINARY: { - QT_WA( { - result = QString::fromUtf16((const ushort*)data.constData(), data.size()/2); - }, { - result = QString::fromLatin1(data.constData(), data.size()); - } ); + result = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2); break; } @@ -232,7 +202,7 @@ QString Environment::readRegistryKey(HKEY parentHandle, const QString &rSubkey) Q_ASSERT(data.size() == sizeof(int)); int i; memcpy((char*)&i, data.constData(), sizeof(int)); - result = QString::number(i); + result = QString::number(i); break; } @@ -350,29 +320,14 @@ bool Environment::detectExecutable(const QString &executable) PROCESS_INFORMATION procInfo; memset(&procInfo, 0, sizeof(procInfo)); - bool couldExecute; - QT_WA({ - // Unicode version - STARTUPINFOW startInfo; - memset(&startInfo, 0, sizeof(startInfo)); - startInfo.cb = sizeof(startInfo); - - couldExecute = CreateProcessW(0, (WCHAR*)executable.utf16(), - 0, 0, false, - CREATE_NO_WINDOW | CREATE_SUSPENDED, - 0, 0, &startInfo, &procInfo); - - }, { - // Ansi version - STARTUPINFOA startInfo; - memset(&startInfo, 0, sizeof(startInfo)); - startInfo.cb = sizeof(startInfo); + STARTUPINFO startInfo; + memset(&startInfo, 0, sizeof(startInfo)); + startInfo.cb = sizeof(startInfo); - couldExecute = CreateProcessA(0, executable.toLocal8Bit().data(), + bool couldExecute = CreateProcess(0, (wchar_t*)executable.utf16(), 0, 0, false, CREATE_NO_WINDOW | CREATE_SUSPENDED, 0, 0, &startInfo, &procInfo); - }) if (couldExecute) { CloseHandle(procInfo.hThread); @@ -421,61 +376,38 @@ static QString qt_create_commandline(const QString &program, const QStringList & } /*! - Creates a QByteArray of the \a environment in either UNICODE or - ansi representation. + Creates a QByteArray of the \a environment. */ static QByteArray qt_create_environment(const QStringList &environment) { QByteArray envlist; - if (!environment.isEmpty()) { - int pos = 0; - // add PATH if necessary (for DLL loading) - QByteArray path = qgetenv("PATH"); - QT_WA({ - if (environment.filter(QRegExp("^PATH=",Qt::CaseInsensitive)).isEmpty() - && !path.isNull()) { - QString tmp = QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path)); - uint tmpSize = sizeof(TCHAR) * (tmp.length()+1); - envlist.resize(envlist.size() + tmpSize ); - memcpy(envlist.data()+pos, tmp.utf16(), tmpSize); - pos += tmpSize; - } - // add the user environment - for (QStringList::ConstIterator it = environment.begin(); it != environment.end(); it++ ) { - QString tmp = *it; - uint tmpSize = sizeof(TCHAR) * (tmp.length()+1); - envlist.resize(envlist.size() + tmpSize); - memcpy(envlist.data()+pos, tmp.utf16(), tmpSize); - pos += tmpSize; - } - // add the 2 terminating 0 (actually 4, just to be on the safe side) - envlist.resize( envlist.size()+4 ); - envlist[pos++] = 0; - envlist[pos++] = 0; - envlist[pos++] = 0; - envlist[pos++] = 0; - }, { - if (environment.filter(QRegExp("^PATH=",Qt::CaseInsensitive)).isEmpty() && !path.isNull()) { - QByteArray tmp = QString("PATH=%1").arg(QString::fromLocal8Bit(path)).toLocal8Bit(); - uint tmpSize = tmp.length() + 1; - envlist.resize(envlist.size() + tmpSize); - memcpy(envlist.data()+pos, tmp.data(), tmpSize); - pos += tmpSize; - } - // add the user environment - for (QStringList::ConstIterator it = environment.begin(); it != environment.end(); it++) { - QByteArray tmp = (*it).toLocal8Bit(); - uint tmpSize = tmp.length() + 1; - envlist.resize(envlist.size() + tmpSize); - memcpy(envlist.data()+pos, tmp.data(), tmpSize); - pos += tmpSize; - } - // add the terminating 0 (actually 2, just to be on the safe side) - envlist.resize(envlist.size()+2); - envlist[pos++] = 0; - envlist[pos++] = 0; - }) + if (environment.isEmpty()) + return envlist; + + int pos = 0; + // add PATH if necessary (for DLL loading) + QByteArray path = qgetenv("PATH"); + if (environment.filter(QRegExp("^PATH=",Qt::CaseInsensitive)).isEmpty() && !path.isNull()) { + QString tmp = QString(QLatin1String("PATH=%1")).arg(QString::fromLocal8Bit(path)); + uint tmpSize = sizeof(wchar_t) * (tmp.length() + 1); + envlist.resize(envlist.size() + tmpSize); + memcpy(envlist.data() + pos, tmp.utf16(), tmpSize); + pos += tmpSize; } + // add the user environment + for (QStringList::ConstIterator it = environment.begin(); it != environment.end(); it++ ) { + QString tmp = *it; + uint tmpSize = sizeof(wchar_t) * (tmp.length() + 1); + envlist.resize(envlist.size() + tmpSize); + memcpy(envlist.data() + pos, tmp.utf16(), tmpSize); + pos += tmpSize; + } + // add the 2 terminating 0 (actually 4, just to be on the safe side) + envlist.resize(envlist.size() + 4); + envlist[pos++] = 0; + envlist[pos++] = 0; + envlist[pos++] = 0; + envlist[pos++] = 0; return envlist; } @@ -501,46 +433,24 @@ int Environment::execute(QStringList arguments, const QStringList &additionalEnv qDebug() << " " << additionalEnv; qDebug() << " " << removeEnv; #endif -// GetEnvironmentStrings is defined to GetEnvironmentStringsW when -// UNICODE is defined. We cannot use that, since we need to -// destinguish between unicode and ansi versions of the functions. -#if defined(UNICODE) && defined(GetEnvironmentStrings) -#undef GetEnvironmentStrings -#endif - // Create the full environment from the current environment and // the additionalEnv strings, then remove all variables defined // in removeEnv QMap<QString, QString> fullEnvMap; - QT_WA({ - LPWSTR envStrings = GetEnvironmentStringsW(); - if (envStrings) { - int strLen = 0; - for (LPWSTR envString = envStrings; *(envString); envString += strLen + 1) { - strLen = wcslen(envString); - QString str = QString((const QChar*)envString, strLen); - if (!str.startsWith("=")) { // These are added by the system - int sepIndex = str.indexOf('='); - fullEnvMap.insert(str.left(sepIndex).toUpper(), str.mid(sepIndex +1)); - } - } - } - FreeEnvironmentStringsW(envStrings); - }, { - LPSTR envStrings = GetEnvironmentStrings(); - if (envStrings) { - int strLen = 0; - for (LPSTR envString = envStrings; *(envString); envString += strLen + 1) { - strLen = strlen(envString); - QString str = QLatin1String(envString); - if (!str.startsWith("=")) { // These are added by the system - int sepIndex = str.indexOf('='); - fullEnvMap.insert(str.left(sepIndex).toUpper(), str.mid(sepIndex +1)); - } + LPWSTR envStrings = GetEnvironmentStrings(); + if (envStrings) { + int strLen = 0; + for (LPWSTR envString = envStrings; *(envString); envString += strLen + 1) { + strLen = wcslen(envString); + QString str = QString((const QChar*)envString, strLen); + if (!str.startsWith("=")) { // These are added by the system + int sepIndex = str.indexOf('='); + fullEnvMap.insert(str.left(sepIndex).toUpper(), str.mid(sepIndex +1)); } } - FreeEnvironmentStringsA(envStrings); - }) + } + FreeEnvironmentStrings(envStrings); + // Add additionalEnv variables for (int i = 0; i < additionalEnv.count(); ++i) { const QString &str = additionalEnv.at(i); @@ -569,28 +479,14 @@ int Environment::execute(QStringList arguments, const QStringList &additionalEnv PROCESS_INFORMATION procInfo; memset(&procInfo, 0, sizeof(procInfo)); - bool couldExecute; - QT_WA({ - // Unicode version - STARTUPINFOW startInfo; - memset(&startInfo, 0, sizeof(startInfo)); - startInfo.cb = sizeof(startInfo); + STARTUPINFO startInfo; + memset(&startInfo, 0, sizeof(startInfo)); + startInfo.cb = sizeof(startInfo); - couldExecute = CreateProcessW(0, (WCHAR*)args.utf16(), + bool couldExecute = CreateProcess(0, (wchar_t*)args.utf16(), 0, 0, true, CREATE_UNICODE_ENVIRONMENT, envlist.isEmpty() ? 0 : envlist.data(), 0, &startInfo, &procInfo); - }, { - // Ansi version - STARTUPINFOA startInfo; - memset(&startInfo, 0, sizeof(startInfo)); - startInfo.cb = sizeof(startInfo); - - couldExecute = CreateProcessA(0, args.toLocal8Bit().data(), - 0, 0, true, 0, - envlist.isEmpty() ? 0 : envlist.data(), - 0, &startInfo, &procInfo); - }) if (couldExecute) { WaitForSingleObject(procInfo.hProcess, INFINITE); @@ -654,7 +550,7 @@ bool Environment::cpdir(const QString &srcDir, const QString &destDir) #endif QFile::remove(destFile); intermediate = QFile::copy(entry.absoluteFilePath(), destFile); - SetFileAttributesA(destFile.toLocal8Bit(), FILE_ATTRIBUTE_NORMAL); + SetFileAttributes((wchar_t*)destFile.utf16(), FILE_ATTRIBUTE_NORMAL); } if(!intermediate) { qDebug() << "cpdir: Failure for " << entry.fileName() << entry.isDir(); diff --git a/tools/configure/main.cpp b/tools/configure/main.cpp index 4f379d7..e5c04cc 100644 --- a/tools/configure/main.cpp +++ b/tools/configure/main.cpp @@ -92,15 +92,15 @@ int runConfigure( int argc, char** argv ) app.generateHeaders(); if( !app.isDone() ) app.buildQmake(); - if( !app.isOk() ) - return 2; #endif if( !app.isDone() ) app.generateMakefiles(); - if( app.isOk() ) + if( !app.isDone() ) app.buildHostTools(); if( !app.isDone() ) app.showSummary(); + if( !app.isOk() ) + return 2; return 0; } diff --git a/tools/configure/tools.cpp b/tools/configure/tools.cpp index f60f72c..708a537 100644 --- a/tools/configure/tools.cpp +++ b/tools/configure/tools.cpp @@ -201,8 +201,8 @@ void Tools::checkLicense(QMap<QString,QString> &dictionary, QMap<QString,QString if (licenseFeatures == '5') //Floating dictionary["METERED LICENSE"] = "true"; - if (!CopyFileA(QDir::toNativeSeparators(fromLicenseFile).toLocal8Bit(), - QDir::toNativeSeparators(toLicenseFile).toLocal8Bit(), FALSE)) { + if (!CopyFile((wchar_t*)QDir::toNativeSeparators(fromLicenseFile).utf16(), + (wchar_t*)QDir::toNativeSeparators(toLicenseFile).utf16(), FALSE)) { cout << "Failed to copy license file (" << fromLicenseFile << ")"; dictionary["DONE"] = "error"; return; diff --git a/tools/designer/data/generate_shared.xsl b/tools/designer/data/generate_shared.xsl index f7859cd..ec95fe2 100644 --- a/tools/designer/data/generate_shared.xsl +++ b/tools/designer/data/generate_shared.xsl @@ -6,8 +6,8 @@ xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- Hack to make names camel case - All names in ui files are lowercase, while the element names are - capital case. To make the ui files conforming to the xsd file + keep + All names in UI files are lowercase, while the element names are + capital case. To make the UI files conforming to the XSD file + keep the DOM interface we rename them here --> <xsl:template name="camel-case"> <xsl:param name="text"/> diff --git a/tools/designer/data/ui4.xsd b/tools/designer/data/ui4.xsd index 703e497..de4253c 100644 --- a/tools/designer/data/ui4.xsd +++ b/tools/designer/data/ui4.xsd @@ -143,6 +143,7 @@ <xs:element name="script" type="Script" minOccurs="0" /> <xs:element name="properties" type="Properties" minOccurs="0" /> <xs:element name="slots" type="Slots" minOccurs="0" /> + <xs:element name="propertyspecifications" type="PropertySpecifications" minOccurs="0" /> </xs:all> </xs:complexType> @@ -571,4 +572,16 @@ </xs:sequence> </xs:complexType> + <xs:complexType name="PropertySpecifications"> + <xs:sequence maxOccurs="unbounded"> + <xs:element name="stringpropertyspecification" type="StringPropertySpecification" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="StringPropertySpecification"> + <xs:attribute name="name" type="xs:string" use="required" /> + <xs:attribute name="type" type="xs:string" use="required" /> + <xs:attribute name="notr" type="xs:string"/> + </xs:complexType> + </xs:schema> diff --git a/tools/designer/src/components/buddyeditor/buddyeditor.cpp b/tools/designer/src/components/buddyeditor/buddyeditor.cpp index 295b37f..9984b0d 100644 --- a/tools/designer/src/components/buddyeditor/buddyeditor.cpp +++ b/tools/designer/src/components/buddyeditor/buddyeditor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::BuddyEditor -*/ - #include "buddyeditor.h" #include <QtDesigner/QDesignerFormWindowInterface> diff --git a/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp b/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp index e79e4f2..ff0c3c6 100644 --- a/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp +++ b/tools/designer/src/components/buddyeditor/buddyeditor_plugin.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::BuddyEditorPlugin -*/ - #include <QtGui/QAction> #include "buddyeditor_plugin.h" diff --git a/tools/designer/src/components/buddyeditor/buddyeditor_tool.cpp b/tools/designer/src/components/buddyeditor/buddyeditor_tool.cpp index 75669aa..3cc63f7 100644 --- a/tools/designer/src/components/buddyeditor/buddyeditor_tool.cpp +++ b/tools/designer/src/components/buddyeditor/buddyeditor_tool.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::BuddyEditorTool -*/ - #include "buddyeditor_tool.h" #include "buddyeditor.h" diff --git a/tools/designer/src/components/formeditor/embeddedoptionspage.cpp b/tools/designer/src/components/formeditor/embeddedoptionspage.cpp index b11c4b2..7b66d8c 100644 --- a/tools/designer/src/components/formeditor/embeddedoptionspage.cpp +++ b/tools/designer/src/components/formeditor/embeddedoptionspage.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::EmbeddedOptionsControl -*/ - #include "embeddedoptionspage.h" #include "deviceprofiledialog.h" #include "widgetfactory_p.h" diff --git a/tools/designer/src/components/formeditor/formwindow.cpp b/tools/designer/src/components/formeditor/formwindow.cpp index 06fa40e..d556030 100644 --- a/tools/designer/src/components/formeditor/formwindow.cpp +++ b/tools/designer/src/components/formeditor/formwindow.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::FormWindow -*/ - #include "formwindow.h" #include "formeditor.h" #include "formwindow_dnditem.h" @@ -2140,7 +2136,10 @@ void FormWindow::layoutContainer(QWidget *w, int type) bool FormWindow::hasInsertedChildren(QWidget *widget) const // ### move { if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), widget)) { - widget = container->widget(container->currentIndex()); + const int index = container->currentIndex(); + if (index < 0) + return false; + widget = container->widget(index); } const QWidgetList l = widgets(widget); diff --git a/tools/designer/src/components/formeditor/formwindowcursor.cpp b/tools/designer/src/components/formeditor/formwindowcursor.cpp index e8480bc..717b679 100644 --- a/tools/designer/src/components/formeditor/formwindowcursor.cpp +++ b/tools/designer/src/components/formeditor/formwindowcursor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::FormWindowCursor -*/ - #include "formwindowcursor.h" #include "formwindow.h" diff --git a/tools/designer/src/components/formeditor/formwindowmanager.cpp b/tools/designer/src/components/formeditor/formwindowmanager.cpp index 1d48bad..993bae9 100644 --- a/tools/designer/src/components/formeditor/formwindowmanager.cpp +++ b/tools/designer/src/components/formeditor/formwindowmanager.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::FormWindowManager -*/ - // components/formeditor #include "formwindowmanager.h" #include "formwindow_dnditem.h" diff --git a/tools/designer/src/components/formeditor/qdesigner_resource.cpp b/tools/designer/src/components/formeditor/qdesigner_resource.cpp index f4f961a..ac03909 100644 --- a/tools/designer/src/components/formeditor/qdesigner_resource.cpp +++ b/tools/designer/src/components/formeditor/qdesigner_resource.cpp @@ -631,13 +631,13 @@ static bool readUiAttributes(QIODevice *dev, QString *errorMessage, *language = attributes.value(languageAttribute).toString(); return true; } else { - *errorMessage = QCoreApplication::translate("Designer", "Invalid ui file: The root element <ui> is missing."); + *errorMessage = QCoreApplication::translate("Designer", "Invalid UI file: The root element <ui> is missing."); return false; } } } - *errorMessage = QCoreApplication::translate("Designer", "An error has occurred while reading the ui file at line %1, column %2: %3") + *errorMessage = QCoreApplication::translate("Designer", "An error has occurred while reading the UI file at line %1, column %2: %3") .arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()); return false; } @@ -753,30 +753,10 @@ void QDesignerResource::setSaveRelative(bool relative) m_resourceBuilder->setSaveRelative(relative); } -static bool addFakeMethods(const DomSlots *domSlots, QStringList &fakeSlots, QStringList &fakeSignals) -{ - if (!domSlots) - return false; - - bool rc = false; - foreach (const QString &fakeSlot, domSlots->elementSlot()) - if (fakeSlots.indexOf(fakeSlot) == -1) { - fakeSlots += fakeSlot; - rc = true; - } - - foreach (const QString &fakeSignal, domSlots->elementSignal()) - if (fakeSignals.indexOf(fakeSignal) == -1) { - fakeSignals += fakeSignal; - rc = true; - } - return rc; -} - QWidget *QDesignerResource::create(DomUI *ui, QWidget *parentWidget) { // Load extra info extension. This is used by Jambi for preventing - // C++ ui files from being loaded + // C++ UI files from being loaded if (QDesignerExtraInfoExtension *extra = qt_extension<QDesignerExtraInfoExtension*>(core()->extensionManager(), core())) { if (!extra->loadUiExtraInfo(ui)) { const QString errorMessage = QApplication::translate("Designer", "This file cannot be read because the extra info extension failed to load."); @@ -1435,108 +1415,9 @@ DomLayoutItem *QDesignerResource::createDom(QLayoutItem *item, DomLayout *ui_lay return ui_item; } -static void addFakeMethodsToWidgetDataBase(const DomCustomWidget *domCustomWidget, WidgetDataBaseItem *item) -{ - const DomSlots *domSlots = domCustomWidget->elementSlots(); - if (!domSlots) - return; - - // Merge in new slots, signals - QStringList fakeSlots = item->fakeSlots(); - QStringList fakeSignals = item->fakeSignals(); - if (addFakeMethods(domSlots, fakeSlots, fakeSignals)) { - item->setFakeSlots(fakeSlots); - item->setFakeSignals(fakeSignals); - } -} - -void QDesignerResource::addCustomWidgetsToWidgetDatabase(DomCustomWidgetList& custom_widget_list) -{ - // Perform one iteration of adding the custom widgets to the database, - // looking up the base class and inheriting its data. - // Remove the succeeded custom widgets from the list. - // Classes whose base class could not be found are left in the list. - QDesignerWidgetDataBaseInterface *db = m_formWindow->core()->widgetDataBase(); - for (int i=0; i < custom_widget_list.size(); ) { - bool classInserted = false; - DomCustomWidget *custom_widget = custom_widget_list[i]; - const QString customClassName = custom_widget->elementClass(); - const QString base_class = custom_widget->elementExtends(); - QString includeFile; - IncludeType includeType = IncludeLocal; - if (const DomHeader *header = custom_widget->elementHeader()) { - includeFile = header->text(); - if (header->hasAttributeLocation() && header->attributeLocation() == QLatin1String("global")) - includeType = IncludeGlobal; - } - const bool domIsContainer = custom_widget->elementContainer(); - // Append a new item - if (base_class.isEmpty()) { - WidgetDataBaseItem *item = new WidgetDataBaseItem(customClassName); - item->setPromoted(false); - item->setGroup(QApplication::translate("Designer", "Custom Widgets")); - item->setIncludeFile(buildIncludeFile(includeFile, includeType)); - item->setContainer(domIsContainer); - item->setCustom(true); - addFakeMethodsToWidgetDataBase(custom_widget, item); - db->append(item); - custom_widget_list.removeAt(i); - classInserted = true; - } else { - // Create a new entry cloned from base class. Note that this will ignore existing - // classes, eg, plugin custom widgets. - QDesignerWidgetDataBaseItemInterface *item = - appendDerived(db, customClassName, QApplication::translate("Designer", "Promoted Widgets"), - base_class, - buildIncludeFile(includeFile, includeType), - true,true); - // Ok, base class found. - if (item) { - // Hack to accommodate for old UI-files in which "contains" is not set properly: - // Apply "contains" from DOM only if true (else, eg classes from QFrame might not accept - // dropping child widgets on them as container=false). This also allows for - // QWidget-derived stacked pages. - if (domIsContainer) - item->setContainer(domIsContainer); - - addFakeMethodsToWidgetDataBase(custom_widget, static_cast<WidgetDataBaseItem*>(item)); - custom_widget_list.removeAt(i); - classInserted = true; - } - } - // Skip failed item. - if (!classInserted) - i++; - } - -} void QDesignerResource::createCustomWidgets(DomCustomWidgets *dom_custom_widgets) { - if (dom_custom_widgets == 0) - return; - DomCustomWidgetList custom_widget_list = dom_custom_widgets->elementCustomWidget(); - // Attempt to insert each item derived from its base class. - // This should at most require two iterations in the event that the classes are out of order - // (derived first, max depth: promoted custom plugin = 2) - for (int iteration = 0; iteration < 2; iteration++) { - addCustomWidgetsToWidgetDatabase(custom_widget_list); - if (custom_widget_list.empty()) - return; - } - // Oops, there are classes left whose base class could not be found. - // Default them to QWidget with warnings. - const QString fallBackBaseClass = QLatin1String("QWidget"); - for (int i=0; i < custom_widget_list.size(); i++ ) { - DomCustomWidget *custom_widget = custom_widget_list[i]; - const QString customClassName = custom_widget->elementClass(); - const QString base_class = custom_widget->elementExtends(); - qDebug() << "** WARNING The base class " << base_class << " of the custom widget class " << customClassName - << " could not be found. Defaulting to " << fallBackBaseClass << '.'; - custom_widget->setElementExtends(fallBackBaseClass); - } - // One more pass. - addCustomWidgetsToWidgetDatabase(custom_widget_list); - Q_ASSERT(custom_widget_list.empty()); + QSimpleResource::handleDomCustomWidgets(core(), dom_custom_widgets); } DomTabStops *QDesignerResource::saveTabStops() diff --git a/tools/designer/src/components/formeditor/tool_widgeteditor.cpp b/tools/designer/src/components/formeditor/tool_widgeteditor.cpp index b4e52f5..967c6b7 100644 --- a/tools/designer/src/components/formeditor/tool_widgeteditor.cpp +++ b/tools/designer/src/components/formeditor/tool_widgeteditor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::WidgetEditorTool -*/ - #include "tool_widgeteditor.h" #include "formwindow.h" diff --git a/tools/designer/src/components/objectinspector/objectinspector.cpp b/tools/designer/src/components/objectinspector/objectinspector.cpp index a356d9b..c36a629 100644 --- a/tools/designer/src/components/objectinspector/objectinspector.cpp +++ b/tools/designer/src/components/objectinspector/objectinspector.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ObjectInspector -*/ - #include "objectinspector.h" #include "objectinspectormodel_p.h" #include "formwindow.h" diff --git a/tools/designer/src/components/objectinspector/objectinspectormodel.cpp b/tools/designer/src/components/objectinspector/objectinspectormodel.cpp index a86d4e8..c265539 100644 --- a/tools/designer/src/components/objectinspector/objectinspectormodel.cpp +++ b/tools/designer/src/components/objectinspector/objectinspectormodel.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ObjectInspector -*/ - #include "objectinspectormodel_p.h" #include <qlayout_widget_p.h> diff --git a/tools/designer/src/components/propertyeditor/designerpropertymanager.cpp b/tools/designer/src/components/propertyeditor/designerpropertymanager.cpp index 1092b92..ca55b15 100644 --- a/tools/designer/src/components/propertyeditor/designerpropertymanager.cpp +++ b/tools/designer/src/components/propertyeditor/designerpropertymanager.cpp @@ -2458,6 +2458,9 @@ void DesignerEditorFactory::slotStringTextChanged(const QString &value) if (val.userType() == DesignerPropertyManager::designerStringTypeId()) { PropertySheetStringValue strVal = qVariantValue<PropertySheetStringValue>(val); strVal.setValue(value); + // Disable translation if no translation subproperties exist. + if (varProp->subProperties().empty()) + strVal.setTranslatable(false); val = qVariantFromValue(strVal); } else { val = QVariant(value); diff --git a/tools/designer/src/components/propertyeditor/paletteeditor.cpp b/tools/designer/src/components/propertyeditor/paletteeditor.cpp index c44b514..ab105b3 100644 --- a/tools/designer/src/components/propertyeditor/paletteeditor.cpp +++ b/tools/designer/src/components/propertyeditor/paletteeditor.cpp @@ -39,13 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::PaletteEditor -*/ -/* -TRANSLATOR qdesigner_internal::PaletteModel -*/ - #include "paletteeditor.h" #include <iconloader_p.h> diff --git a/tools/designer/src/components/propertyeditor/paletteeditorbutton.cpp b/tools/designer/src/components/propertyeditor/paletteeditorbutton.cpp index 2ac1c3f..de96fea 100644 --- a/tools/designer/src/components/propertyeditor/paletteeditorbutton.cpp +++ b/tools/designer/src/components/propertyeditor/paletteeditorbutton.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::PaletteEditorButton -*/ - #include "paletteeditorbutton.h" #include "paletteeditor.h" diff --git a/tools/designer/src/components/propertyeditor/previewframe.cpp b/tools/designer/src/components/propertyeditor/previewframe.cpp index 8416a4e..33073e2 100644 --- a/tools/designer/src/components/propertyeditor/previewframe.cpp +++ b/tools/designer/src/components/propertyeditor/previewframe.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::PreviewWorkspace -*/ - #include "previewframe.h" #include "previewwidget.h" diff --git a/tools/designer/src/components/propertyeditor/propertyeditor.cpp b/tools/designer/src/components/propertyeditor/propertyeditor.cpp index 4c0565d..b20a5a8 100644 --- a/tools/designer/src/components/propertyeditor/propertyeditor.cpp +++ b/tools/designer/src/components/propertyeditor/propertyeditor.cpp @@ -137,13 +137,8 @@ void PropertyEditor::setupStringProperty(QtVariantProperty *property, bool isMai const bool hasComment = params.second; property->setAttribute(m_strings.m_validationModeAttribute, params.first); // assuming comment cannot appear or disappear for the same property in different object instance - if (!hasComment) { - QList<QtProperty *> commentProperties = property->subProperties(); - if (commentProperties.count() > 0) - delete commentProperties.at(0); - if (commentProperties.count() > 1) - delete commentProperties.at(1); - } + if (!hasComment) + qDeleteAll(property->subProperties()); } void PropertyEditor::setupPaletteProperty(QtVariantProperty *property) diff --git a/tools/designer/src/components/propertyeditor/stringlisteditorbutton.cpp b/tools/designer/src/components/propertyeditor/stringlisteditorbutton.cpp index d4bebb9..1b51376 100644 --- a/tools/designer/src/components/propertyeditor/stringlisteditorbutton.cpp +++ b/tools/designer/src/components/propertyeditor/stringlisteditorbutton.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::StringListEditorButton -*/ - #include "stringlisteditorbutton.h" #include "stringlisteditor.h" diff --git a/tools/designer/src/components/signalsloteditor/connectdialog.ui b/tools/designer/src/components/signalsloteditor/connectdialog.ui index bd062eb..568516a 100644 --- a/tools/designer/src/components/signalsloteditor/connectdialog.ui +++ b/tools/designer/src/components/signalsloteditor/connectdialog.ui @@ -13,7 +13,7 @@ <string>Configure Connection</string> </property> <layout class="QGridLayout" > - <item row="0" column="0" colspan="2" > + <item row="0" column="0" > <widget class="QGroupBox" name="signalGroupBox" > <property name="title" > <string>GroupBox</string> @@ -53,7 +53,7 @@ </layout> </widget> </item> - <item row="0" column="2" > + <item row="0" column="1" > <widget class="QGroupBox" name="slotGroupBox" > <property name="title" > <string>GroupBox</string> @@ -93,14 +93,14 @@ </layout> </widget> </item> - <item row="1" column="0" > + <item row="1" column="0" colspan="2" > <widget class="QCheckBox" name="showAllCheckBox" > <property name="text" > <string>Show signals and slots inherited from QWidget</string> </property> </widget> </item> - <item row="2" column="1" colspan="2" > + <item row="2" column="0" colspan="2" > <widget class="QDialogButtonBox" name="buttonBox" > <property name="orientation" > <enum>Qt::Horizontal</enum> diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp index fd90e67..e664ae7 100644 --- a/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::SignalSlotEditorPlugin -*/ - #include "signalsloteditor_plugin.h" #include "signalsloteditor_tool.h" diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp index d743d21..8b0dd7c 100644 --- a/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::SignalSlotEditorTool -*/ - #include "signalsloteditor_tool.h" #include "signalsloteditor.h" #include "ui4_p.h" diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp index e1126bd..9f27923 100644 --- a/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp +++ b/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ConnectionModel -*/ - #include "signalsloteditorwindow.h" #include "signalsloteditor_p.h" #include "signalsloteditor.h" diff --git a/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp b/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp index b6b93a9..9b051c9 100644 --- a/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp +++ b/tools/designer/src/components/tabordereditor/tabordereditor_plugin.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::TabOrderEditorPlugin -*/ - #include <QtGui/QAction> #include "tabordereditor_plugin.h" diff --git a/tools/designer/src/components/tabordereditor/tabordereditor_tool.cpp b/tools/designer/src/components/tabordereditor/tabordereditor_tool.cpp index 23e2f47..b94f7ff 100644 --- a/tools/designer/src/components/tabordereditor/tabordereditor_tool.cpp +++ b/tools/designer/src/components/tabordereditor/tabordereditor_tool.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::TabOrderEditorTool -*/ - #include "tabordereditor_tool.h" #include "tabordereditor.h" diff --git a/tools/designer/src/components/taskmenu/button_taskmenu.cpp b/tools/designer/src/components/taskmenu/button_taskmenu.cpp index c431024..5eb74cc 100644 --- a/tools/designer/src/components/taskmenu/button_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/button_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ButtonTaskMenu -*/ - #include "button_taskmenu.h" #include "inplace_editor.h" #include <qdesigner_formwindowcommand_p.h> diff --git a/tools/designer/src/components/taskmenu/combobox_taskmenu.cpp b/tools/designer/src/components/taskmenu/combobox_taskmenu.cpp index 600e9e4..f1d16a3 100644 --- a/tools/designer/src/components/taskmenu/combobox_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/combobox_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ComboBoxTaskMenu -*/ - #include "combobox_taskmenu.h" #include "listwidgeteditor.h" #include "qdesigner_utils_p.h" diff --git a/tools/designer/src/components/taskmenu/containerwidget_taskmenu.cpp b/tools/designer/src/components/taskmenu/containerwidget_taskmenu.cpp index 84d964b..14385ba 100644 --- a/tools/designer/src/components/taskmenu/containerwidget_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/containerwidget_taskmenu.cpp @@ -39,13 +39,8 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ContainerWidgetTaskMenu -*/ - #include "containerwidget_taskmenu.h" - #include <QtDesigner/QDesignerFormEditorInterface> #include <QtDesigner/QDesignerFormWindowInterface> #include <QtDesigner/QExtensionManager> diff --git a/tools/designer/src/components/taskmenu/groupbox_taskmenu.cpp b/tools/designer/src/components/taskmenu/groupbox_taskmenu.cpp index ce6b4ab..ba9651a 100644 --- a/tools/designer/src/components/taskmenu/groupbox_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/groupbox_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::GroupBoxTaskMenu -*/ - #include "groupbox_taskmenu.h" #include "inplace_editor.h" diff --git a/tools/designer/src/components/taskmenu/label_taskmenu.cpp b/tools/designer/src/components/taskmenu/label_taskmenu.cpp index 6a555c8..c7e8d72 100644 --- a/tools/designer/src/components/taskmenu/label_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/label_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::LabelTaskMenu -*/ - #include "label_taskmenu.h" #include "inplace_editor.h" diff --git a/tools/designer/src/components/taskmenu/layouttaskmenu.cpp b/tools/designer/src/components/taskmenu/layouttaskmenu.cpp index d7e5365..46d3497 100644 --- a/tools/designer/src/components/taskmenu/layouttaskmenu.cpp +++ b/tools/designer/src/components/taskmenu/layouttaskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::LayoutWidgetTaskMenu -*/ - #include "layouttaskmenu.h" #include <formlayoutmenu_p.h> #include <morphmenu_p.h> diff --git a/tools/designer/src/components/taskmenu/lineedit_taskmenu.cpp b/tools/designer/src/components/taskmenu/lineedit_taskmenu.cpp index db7327b..f2915ec 100644 --- a/tools/designer/src/components/taskmenu/lineedit_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/lineedit_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::LineEditTaskMenu -*/ - #include "lineedit_taskmenu.h" #include "inplace_editor.h" diff --git a/tools/designer/src/components/taskmenu/listwidget_taskmenu.cpp b/tools/designer/src/components/taskmenu/listwidget_taskmenu.cpp index 984fc8a..e70d985 100644 --- a/tools/designer/src/components/taskmenu/listwidget_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/listwidget_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ListWidgetTaskMenu -*/ - #include "listwidget_taskmenu.h" #include "listwidgeteditor.h" #include "qdesigner_utils_p.h" diff --git a/tools/designer/src/components/taskmenu/listwidgeteditor.cpp b/tools/designer/src/components/taskmenu/listwidgeteditor.cpp index 8edad6d..a40a345 100644 --- a/tools/designer/src/components/taskmenu/listwidgeteditor.cpp +++ b/tools/designer/src/components/taskmenu/listwidgeteditor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ListWidgetEditor -*/ - #include "listwidgeteditor.h" #include <designerpropertymanager.h> #include <abstractformbuilder.h> diff --git a/tools/designer/src/components/taskmenu/menutaskmenu.cpp b/tools/designer/src/components/taskmenu/menutaskmenu.cpp index 346a07f..3546cd1 100644 --- a/tools/designer/src/components/taskmenu/menutaskmenu.cpp +++ b/tools/designer/src/components/taskmenu/menutaskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::MenuTaskMenu -*/ - #include "menutaskmenu.h" #include <promotiontaskmenu_p.h> diff --git a/tools/designer/src/components/taskmenu/tablewidget_taskmenu.cpp b/tools/designer/src/components/taskmenu/tablewidget_taskmenu.cpp index f0fa680..c187a69 100644 --- a/tools/designer/src/components/taskmenu/tablewidget_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/tablewidget_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::TableWidgetTaskMenu -*/ - #include "tablewidget_taskmenu.h" #include "tablewidgeteditor.h" diff --git a/tools/designer/src/components/taskmenu/tablewidgeteditor.cpp b/tools/designer/src/components/taskmenu/tablewidgeteditor.cpp index 6115998..587e7d3 100644 --- a/tools/designer/src/components/taskmenu/tablewidgeteditor.cpp +++ b/tools/designer/src/components/taskmenu/tablewidgeteditor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::TableWidgetEditor -*/ - #include "tablewidgeteditor.h" #include <abstractformbuilder.h> #include <iconloader_p.h> diff --git a/tools/designer/src/components/taskmenu/textedit_taskmenu.cpp b/tools/designer/src/components/taskmenu/textedit_taskmenu.cpp index 55cd105..d052ced 100644 --- a/tools/designer/src/components/taskmenu/textedit_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/textedit_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::TextEditTaskMenu -*/ - #include "textedit_taskmenu.h" #include <QtDesigner/QDesignerFormWindowInterface> diff --git a/tools/designer/src/components/taskmenu/toolbar_taskmenu.cpp b/tools/designer/src/components/taskmenu/toolbar_taskmenu.cpp index 7c4c07d..a64de13 100644 --- a/tools/designer/src/components/taskmenu/toolbar_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/toolbar_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ToolBarTaskMenu -*/ - #include "toolbar_taskmenu.h" #include "qdesigner_toolbar_p.h" diff --git a/tools/designer/src/components/taskmenu/treewidget_taskmenu.cpp b/tools/designer/src/components/taskmenu/treewidget_taskmenu.cpp index 3784957..6643141 100644 --- a/tools/designer/src/components/taskmenu/treewidget_taskmenu.cpp +++ b/tools/designer/src/components/taskmenu/treewidget_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::TreeWidgetTaskMenu -*/ - #include "treewidget_taskmenu.h" #include "treewidgeteditor.h" diff --git a/tools/designer/src/components/taskmenu/treewidgeteditor.cpp b/tools/designer/src/components/taskmenu/treewidgeteditor.cpp index d0b6283..458eadb 100644 --- a/tools/designer/src/components/taskmenu/treewidgeteditor.cpp +++ b/tools/designer/src/components/taskmenu/treewidgeteditor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::TreeWidgetEditor -*/ - #include "treewidgeteditor.h" #include <formwindowbase_p.h> #include <iconloader_p.h> diff --git a/tools/designer/src/components/widgetbox/widgetbox_dnditem.cpp b/tools/designer/src/components/widgetbox/widgetbox_dnditem.cpp index 67e1184..045bfca 100644 --- a/tools/designer/src/components/widgetbox/widgetbox_dnditem.cpp +++ b/tools/designer/src/components/widgetbox/widgetbox_dnditem.cpp @@ -50,6 +50,7 @@ #include <formwindowbase_p.h> #include <qdesigner_utils_p.h> #include <qdesigner_dockwidget_p.h> +#include <qsimpleresource_p.h> #include <QtDesigner/QDesignerFormEditorInterface> #include <QtDesigner/QDesignerFormWindowManagerInterface> @@ -84,6 +85,7 @@ protected: virtual QWidget *create(DomWidget *ui_widget, QWidget *parents); virtual QWidget *createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name); + virtual void createCustomWidgets(DomCustomWidgets *); }; WidgetBoxResource::WidgetBoxResource(QDesignerFormEditorInterface *core) : @@ -120,6 +122,14 @@ QWidget *WidgetBoxResource::create(DomWidget *ui_widget, QWidget *parent) return result; } +void WidgetBoxResource::createCustomWidgets(DomCustomWidgets *dc) +{ + // Make a promotion entry in case someone has a promoted widget + // in the scratchpad. + QSimpleResource::handleDomCustomWidgets(core(), dc); + +} + /******************************************************************************* ** WidgetBoxResource */ diff --git a/tools/designer/src/designer/Info_mac.plist b/tools/designer/src/designer/Info_mac.plist index 8632a6d..f19176f 100644 --- a/tools/designer/src/designer/Info_mac.plist +++ b/tools/designer/src/designer/Info_mac.plist @@ -22,7 +22,7 @@ <string>ui</string> </array> <key>CFBundleTypeIconFile</key> - <string>@ICON@</string> + <string>uifile.icns</string> <key>CFBundleTypeRole</key> <string>Editor</string> <key>LSIsAppleDefaultForType</key> diff --git a/tools/designer/src/designer/designer.pro b/tools/designer/src/designer/designer.pro index e7fa038..aa6850c 100644 --- a/tools/designer/src/designer/designer.pro +++ b/tools/designer/src/designer/designer.pro @@ -78,6 +78,9 @@ mac { ICON = designer.icns QMAKE_INFO_PLIST = Info_mac.plist TARGET = Designer + FILETYPES.files = uifile.icns + FILETYPES.path = Contents/Resources + QMAKE_BUNDLE_DATA += FILETYPES } target.path=$$[QT_INSTALL_BINS] diff --git a/tools/designer/src/designer/designer.rc b/tools/designer/src/designer/designer.rc index 4b6324b..1f8bc0a 100644 --- a/tools/designer/src/designer/designer.rc +++ b/tools/designer/src/designer/designer.rc @@ -1,2 +1,32 @@ +#include "winver.h" + IDI_ICON1 ICON DISCARDABLE "designer.ico" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGS 0x0L + FILEFLAGSMASK 0x3fL + FILEOS 0x00040004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)" + VALUE "FileDescription", "Qt Designer" + VALUE "FileVersion", "1.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)." + VALUE "InternalName", "designer" + VALUE "OriginalFilename", "designer.exe" + VALUE "ProductName", "Qt Designer" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/tools/designer/src/designer/mainwindow.cpp b/tools/designer/src/designer/mainwindow.cpp index b72a790..a3ca234 100644 --- a/tools/designer/src/designer/mainwindow.cpp +++ b/tools/designer/src/designer/mainwindow.cpp @@ -155,7 +155,7 @@ DockedMdiArea::DockedMdiArea(const QString &extension, QWidget *parent) : QStringList DockedMdiArea::uiFiles(const QMimeData *d) const { - // Extract dropped ui files from Mime data. + // Extract dropped UI files from Mime data. QStringList rc; if (!d->hasFormat(QLatin1String(uriListMimeFormatC))) return rc; diff --git a/tools/designer/src/designer/qdesigner_actions.cpp b/tools/designer/src/designer/qdesigner_actions.cpp index 5151044..c671386 100644 --- a/tools/designer/src/designer/qdesigner_actions.cpp +++ b/tools/designer/src/designer/qdesigner_actions.cpp @@ -280,7 +280,7 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) m_fileActions->addAction(createSeparator(this)); - m_quitAction->setShortcut(tr("CTRL+Q")); + m_quitAction->setShortcuts(QKeySequence::Quit); m_quitAction->setMenuRole(QAction::QuitRole); connect(m_quitAction, SIGNAL(triggered()), this, SLOT(shutdown())); m_fileActions->addAction(m_quitAction); diff --git a/tools/designer/src/designer/qdesigner_workbench.cpp b/tools/designer/src/designer/qdesigner_workbench.cpp index c9d9fc4..2ac9e1f 100644 --- a/tools/designer/src/designer/qdesigner_workbench.cpp +++ b/tools/designer/src/designer/qdesigner_workbench.cpp @@ -961,7 +961,7 @@ QDesignerFormWindow * QDesignerWorkbench::loadForm(const QString &fileName, removeFormWindow(formWindow); formWindowManager->removeFormWindow(editor); m_core->metaDataBase()->remove(editor); - *errorMessage = tr("The file <b>%1</b> is not a valid Designer ui file.").arg(file.fileName()); + *errorMessage = tr("The file <b>%1</b> is not a valid Designer UI file.").arg(file.fileName()); return 0; } *uic3Converted = editor->fileName().isEmpty(); diff --git a/tools/designer/src/designer/uifile.icns b/tools/designer/src/designer/uifile.icns Binary files differnew file mode 100644 index 0000000..2473ea4 --- /dev/null +++ b/tools/designer/src/designer/uifile.icns diff --git a/tools/designer/src/designer/versiondialog.cpp b/tools/designer/src/designer/versiondialog.cpp index 101a3f3..388fb27 100644 --- a/tools/designer/src/designer/versiondialog.cpp +++ b/tools/designer/src/designer/versiondialog.cpp @@ -172,15 +172,11 @@ VersionDialog::VersionDialog(QWidget *parent) version = version.arg(tr("Qt Designer")).arg(QLatin1String(QT_VERSION_STR)); version.append(tr("<br/>Qt Designer is a graphical user interface designer for Qt applications.<br/>")); - // TODO: Remove this variable for 4.6.0. Must keep this way for 4.5.x due to string freeze - QString edition; - lbl->setText(tr("%1" - "<br/>%2" "<br/>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)." "<br/><br/>The program is provided AS IS with NO WARRANTY OF ANY KIND," " INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A" - " PARTICULAR PURPOSE.<br/> ").arg(version).arg(edition)); + " PARTICULAR PURPOSE.<br/> ").arg(version)); lbl->setWordWrap(true); lbl->setOpenExternalLinks(true); diff --git a/tools/designer/src/lib/sdk/abstractformeditor.cpp b/tools/designer/src/lib/sdk/abstractformeditor.cpp index 52f1ef1..48772b8 100644 --- a/tools/designer/src/lib/sdk/abstractformeditor.cpp +++ b/tools/designer/src/lib/sdk/abstractformeditor.cpp @@ -66,9 +66,21 @@ #include <grid_p.h> #include <QtDesigner/QDesignerPromotionInterface> +// Must be done outside of the Qt namespace static void initResources() { Q_INIT_RESOURCE(shared); + Q_INIT_RESOURCE(ClamshellPhone); + Q_INIT_RESOURCE(PDAPhone); + Q_INIT_RESOURCE(PortableMedia); + Q_INIT_RESOURCE(S60_nHD_Touchscreen); + Q_INIT_RESOURCE(S60_QVGA_Candybar); + Q_INIT_RESOURCE(SmartPhone2); + Q_INIT_RESOURCE(SmartPhone); + Q_INIT_RESOURCE(SmartPhoneWithButtons); + Q_INIT_RESOURCE(TouchscreenPhone); + Q_INIT_RESOURCE(Trolltech_Keypad); + Q_INIT_RESOURCE(Trolltech_Touchscreen); } QT_BEGIN_NAMESPACE diff --git a/tools/designer/src/lib/sdk/abstractformwindow.cpp b/tools/designer/src/lib/sdk/abstractformwindow.cpp index 89c1015..313b324 100644 --- a/tools/designer/src/lib/sdk/abstractformwindow.cpp +++ b/tools/designer/src/lib/sdk/abstractformwindow.cpp @@ -247,7 +247,7 @@ QDesignerFormWindowInterface *QDesignerFormWindowInterface::findFormWindow(QObje /*! \fn virtual QString QDesignerFormWindowInterface::fileName() const - Returns the file name of the .ui file that describes the form + Returns the file name of the UI file that describes the form currently being shown. \sa setFileName() @@ -399,11 +399,11 @@ QDesignerFormWindowInterface *QDesignerFormWindowInterface::findFormWindow(QObje \fn virtual QStringList QDesignerFormWindowInterface::includeHints() const Returns a list of the header files that will be included in the - form window's associated \c .ui file. + form window's associated UI file. Header files may be local, i.e. relative to the project's - directory,\c "mywidget.h", or global, i.e. part of Qt or the - compilers standard libraries:\c <QtGui/QWidget>. + directory, \c "mywidget.h", or global, i.e. part of Qt or the + compilers standard libraries: \c <QtGui/QWidget>. \sa setIncludeHints() */ @@ -412,11 +412,11 @@ QDesignerFormWindowInterface *QDesignerFormWindowInterface::findFormWindow(QObje \fn virtual void QDesignerFormWindowInterface::setIncludeHints(const QStringList &includeHints) Sets the header files that will be included in the form window's - associated \c .ui file to the specified \a includeHints. + associated UI file to the specified \a includeHints. Header files may be local, i.e. relative to the project's - directory,\c "mywidget.h", or global, i.e. part of Qt or the - compilers standard libraries:\c <QtGui/QWidget>. + directory, \c "mywidget.h", or global, i.e. part of Qt or the + compilers standard libraries: \c <QtGui/QWidget>. \sa includeHints() */ diff --git a/tools/designer/src/lib/sdk/script.cpp b/tools/designer/src/lib/sdk/script.cpp index 90b4c73..2eda3d1 100644 --- a/tools/designer/src/lib/sdk/script.cpp +++ b/tools/designer/src/lib/sdk/script.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE \since 4.3 On saving the form, the extension is queried for a script snippet - to be associated with the widget while saving the \c .ui file. + to be associated with the widget while saving the UI file. This script is then run after creating the widget by \l uic or QUiLoader. @@ -66,7 +66,7 @@ QT_BEGIN_NAMESPACE for which an editor is provided by the QDesignerTaskMenuExtension. While saving the form, the state is serialized as a QVariantMap of - \QD-supported properties, which is stored in the \c .ui file. This is + \QD-supported properties, which is stored in the UI file. This is handled by data() and setData(). For item view contents, there might be for example a key that determines @@ -97,7 +97,7 @@ QDesignerScriptExtension::~QDesignerScriptExtension() \fn virtual QVariantMap QDesignerScriptExtension::data() const Returns a map of variants describing the internal state to be - stored in the \c .ui file. + stored in the UI file. */ /*! diff --git a/tools/designer/src/lib/shared/actioneditor.cpp b/tools/designer/src/lib/shared/actioneditor.cpp index a89e47c..1a236d6 100644 --- a/tools/designer/src/lib/shared/actioneditor.cpp +++ b/tools/designer/src/lib/shared/actioneditor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ActionEditor -*/ - #include "actioneditor_p.h" #include "filterwidget_p.h" #include "actionrepository_p.h" diff --git a/tools/designer/src/lib/shared/codedialog.cpp b/tools/designer/src/lib/shared/codedialog.cpp index f379970..380566c 100644 --- a/tools/designer/src/lib/shared/codedialog.cpp +++ b/tools/designer/src/lib/shared/codedialog.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::CodeDialog -*/ - #include "codedialog_p.h" #include "qdesigner_utils_p.h" #include "iconloader_p.h" diff --git a/tools/designer/src/lib/shared/csshighlighter.cpp b/tools/designer/src/lib/shared/csshighlighter.cpp index d871d4d..cb7a78e 100644 --- a/tools/designer/src/lib/shared/csshighlighter.cpp +++ b/tools/designer/src/lib/shared/csshighlighter.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::StyleSheetEditorDialog -*/ - #include "csshighlighter_p.h" QT_BEGIN_NAMESPACE diff --git a/tools/designer/src/lib/shared/formwindowbase.cpp b/tools/designer/src/lib/shared/formwindowbase.cpp index ab96809..1d79ac4 100644 --- a/tools/designer/src/lib/shared/formwindowbase.cpp +++ b/tools/designer/src/lib/shared/formwindowbase.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::FormWindowBase -*/ - #include "formwindowbase_p.h" #include "connectionedit_p.h" #include "qdesigner_command_p.h" diff --git a/tools/designer/src/lib/shared/newformwidget.cpp b/tools/designer/src/lib/shared/newformwidget.cpp index e351ef0..c4d202e 100644 --- a/tools/designer/src/lib/shared/newformwidget.cpp +++ b/tools/designer/src/lib/shared/newformwidget.cpp @@ -310,9 +310,8 @@ QImage NewFormWidget::grabForm(QDesignerFormEditorInterface *core, const QString &workingDir, const qdesigner_internal::DeviceProfile &dp) { - qdesigner_internal::QDesignerFormBuilder formBuilder(core, - qdesigner_internal::QDesignerFormBuilder::DisableScripts, - dp); + qdesigner_internal::NewFormWidgetFormBuilder + formBuilder(core, qdesigner_internal::QDesignerFormBuilder::DisableScripts, dp); if (!workingDir.isEmpty()) formBuilder.setWorkingDirectory(workingDir); diff --git a/tools/designer/src/lib/shared/orderdialog.cpp b/tools/designer/src/lib/shared/orderdialog.cpp index 96963db..d7da5f2 100644 --- a/tools/designer/src/lib/shared/orderdialog.cpp +++ b/tools/designer/src/lib/shared/orderdialog.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::OrderDialog -*/ - #include "orderdialog_p.h" #include "iconloader_p.h" #include "ui_orderdialog.h" diff --git a/tools/designer/src/lib/shared/plaintexteditor.cpp b/tools/designer/src/lib/shared/plaintexteditor.cpp index 9b74ffd..3f9c5ed 100644 --- a/tools/designer/src/lib/shared/plaintexteditor.cpp +++ b/tools/designer/src/lib/shared/plaintexteditor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::PlainTextEditorDialog -*/ - #include "plaintexteditor_p.h" #include "abstractsettings_p.h" diff --git a/tools/designer/src/lib/shared/pluginmanager.cpp b/tools/designer/src/lib/shared/pluginmanager.cpp index d74f477..b8c1c40 100644 --- a/tools/designer/src/lib/shared/pluginmanager.cpp +++ b/tools/designer/src/lib/shared/pluginmanager.cpp @@ -72,6 +72,11 @@ static const char *classAttributeC = "class"; static const char *customwidgetElementC = "customwidget"; static const char *extendsElementC = "extends"; static const char *addPageMethodC = "addpagemethod"; +static const char *propertySpecsC = "propertyspecifications"; +static const char *stringPropertySpecC = "stringpropertyspecification"; +static const char *stringPropertyNameAttrC = "name"; +static const char *stringPropertyTypeAttrC = "type"; +static const char *stringPropertyNoTrAttrC = "notr"; static const char *jambiLanguageC = "jambi"; enum { debugPluginManager = 0 }; @@ -141,6 +146,10 @@ static inline QString getDesignerLanguage(QDesignerFormEditorInterface *core) class QDesignerCustomWidgetSharedData : public QSharedData { public: + // Type of a string property + typedef QPair<qdesigner_internal::TextPropertyValidationMode, bool> StringPropertyType; + typedef QHash<QString, StringPropertyType> StringPropertyTypeMap; + explicit QDesignerCustomWidgetSharedData(const QString &thePluginPath) : pluginPath(thePluginPath) {} void clearXML(); @@ -152,6 +161,7 @@ public: QString xmlAddPageMethod; QString xmlExtends; + StringPropertyTypeMap xmlStringPropertyTypeMap; }; void QDesignerCustomWidgetSharedData::clearXML() @@ -161,6 +171,7 @@ void QDesignerCustomWidgetSharedData::clearXML() xmlLanguage.clear(); xmlAddPageMethod.clear(); xmlExtends.clear(); + xmlStringPropertyTypeMap.clear(); } // ---------------- QDesignerCustomWidgetData @@ -220,6 +231,17 @@ QString QDesignerCustomWidgetData::pluginPath() const return m_d->pluginPath; } +bool QDesignerCustomWidgetData::xmlStringPropertyType(const QString &name, StringPropertyType *type) const +{ + QDesignerCustomWidgetSharedData::StringPropertyTypeMap::const_iterator it = m_d->xmlStringPropertyTypeMap.constFind(name); + if (it == m_d->xmlStringPropertyTypeMap.constEnd()) { + *type = StringPropertyType(qdesigner_internal::ValidationRichText, true); + return false; + } + *type = it.value(); + return true; +} + // Wind a QXmlStreamReader until it finds an element. Returns index or one of FindResult enum FindResult { FindError = -2, ElementNotFound = -1 }; @@ -249,6 +271,82 @@ static inline QString msgXmlError(const QString &name, const QString &errorMessa return QDesignerPluginManager::tr("An XML error was encountered when parsing the XML of the custom widget %1: %2").arg(name, errorMessage); } +static inline QString msgAttributeMissing(const QString &name) +{ + return QDesignerPluginManager::tr("A required attribute ('%1') is missing.").arg(name); +} + +static qdesigner_internal::TextPropertyValidationMode typeStringToType(const QString &v, bool *ok) +{ + *ok = true; + if (v == QLatin1String("multiline")) + return qdesigner_internal::ValidationMultiLine; + if (v == QLatin1String("richtext")) + return qdesigner_internal::ValidationRichText; + if (v == QLatin1String("stylesheet")) + return qdesigner_internal::ValidationStyleSheet; + if (v == QLatin1String("singleline")) + return qdesigner_internal::ValidationSingleLine; + if (v == QLatin1String("objectname")) + return qdesigner_internal::ValidationObjectName; + if (v == QLatin1String("objectnamescope")) + return qdesigner_internal::ValidationObjectNameScope; + if (v == QLatin1String("url")) + return qdesigner_internal::ValidationURL; + *ok = false; + return qdesigner_internal::ValidationRichText; +} + +static bool parsePropertySpecs(QXmlStreamReader &sr, + QDesignerCustomWidgetSharedData::StringPropertyTypeMap *rc, + QString *errorMessage) +{ + const QString propertySpecs = QLatin1String(propertySpecsC); + const QString stringPropertySpec = QLatin1String(stringPropertySpecC); + const QString stringPropertyTypeAttr = QLatin1String(stringPropertyTypeAttrC); + const QString stringPropertyNoTrAttr = QLatin1String(stringPropertyNoTrAttrC); + const QString stringPropertyNameAttr = QLatin1String(stringPropertyNameAttrC); + + while (!sr.atEnd()) { + switch(sr.readNext()) { + case QXmlStreamReader::StartElement: { + if (sr.name() != stringPropertySpec) { + *errorMessage = QDesignerPluginManager::tr("An invalid property specification ('%1') was encountered. Supported types: %2").arg(sr.name().toString(), stringPropertySpec); + return false; + } + const QXmlStreamAttributes atts = sr.attributes(); + const QString name = atts.value(stringPropertyNameAttr).toString(); + const QString type = atts.value(stringPropertyTypeAttr).toString(); + const QString notrS = atts.value(stringPropertyNoTrAttr).toString(); //Optional + + if (type.isEmpty()) { + *errorMessage = msgAttributeMissing(stringPropertyTypeAttr); + return false; + } + if (name.isEmpty()) { + *errorMessage = msgAttributeMissing(stringPropertyNameAttr); + return false; + } + bool typeOk; + const bool noTr = notrS == QLatin1String("true") || notrS == QLatin1String("1"); + QDesignerCustomWidgetSharedData::StringPropertyType v(typeStringToType(type, &typeOk), !noTr); + if (!typeOk) { + *errorMessage = QDesignerPluginManager::tr("'%1' is not a valid string property specification!").arg(type); + return false; + } + rc->insert(name, v); + } + break; + case QXmlStreamReader::EndElement: // Outer </stringproperties> + if (sr.name() == propertySpecs) + return true; + default: + break; + } + } + return true; +} + QDesignerCustomWidgetData::ParseResult QDesignerCustomWidgetData::parseXml(const QString &xml, const QString &name, QString *errorMessage) { @@ -311,10 +409,11 @@ QDesignerCustomWidgetData::ParseResult default: break; } - // Find <extends>, <addPageMethod> + // Find <extends>, <addPageMethod>, <stringproperties> elements.clear(); elements.push_back(QLatin1String(extendsElementC)); elements.push_back(QLatin1String(addPageMethodC)); + elements.push_back(QLatin1String(propertySpecsC)); while (true) { switch (findElement(elements, sr)) { case FindError: @@ -336,6 +435,12 @@ QDesignerCustomWidgetData::ParseResult return ParseError; } break; + case 2: // <stringproperties> + if (!parsePropertySpecs(sr, &m_d->xmlStringPropertyTypeMap, errorMessage)) { + *errorMessage = msgXmlError(name, *errorMessage); + return ParseError; + } + break; } } return rc; @@ -345,6 +450,8 @@ QDesignerCustomWidgetData::ParseResult class QDesignerPluginManagerPrivate { public: + typedef QPair<QString, QString> ClassNamePropertyNameKey; + QDesignerPluginManagerPrivate(QDesignerFormEditorInterface *core); void clearCustomWidgets(); @@ -562,7 +669,7 @@ bool QDesignerPluginManager::registerNewPlugins() const int before = m_d->m_registeredPlugins.size(); foreach (const QString &path, m_d->m_pluginPaths) - registerPath(path); + registerPath(path); const bool newPluginsFound = m_d->m_registeredPlugins.size() > before; // We force a re-initialize as Jambi collection might return // different widget lists when switching projects. @@ -654,6 +761,15 @@ QDesignerCustomWidgetData QDesignerPluginManager::customWidgetData(QDesignerCust return m_d->m_customWidgetData.at(index); } +QDesignerCustomWidgetData QDesignerPluginManager::customWidgetData(const QString &name) const +{ + const int count = m_d->m_customWidgets.size(); + for (int i = 0; i < count; i++) + if (m_d->m_customWidgets.at(i)->name() == name) + return m_d->m_customWidgetData.at(i); + return QDesignerCustomWidgetData(); +} + QObjectList QDesignerPluginManager::instances() const { QStringList plugins = registeredPlugins(); diff --git a/tools/designer/src/lib/shared/pluginmanager_p.h b/tools/designer/src/lib/shared/pluginmanager_p.h index 479e94d..4654280 100644 --- a/tools/designer/src/lib/shared/pluginmanager_p.h +++ b/tools/designer/src/lib/shared/pluginmanager_p.h @@ -54,9 +54,11 @@ #define PLUGINMANAGER_H #include "shared_global_p.h" +#include "shared_enums_p.h" #include <QtCore/QSharedDataPointer> #include <QtCore/QMap> +#include <QtCore/QPair> #include <QtCore/QStringList> QT_BEGIN_NAMESPACE @@ -70,6 +72,9 @@ class QDesignerCustomWidgetSharedData; /* Information contained in the Dom XML of a custom widget. */ class QDESIGNER_SHARED_EXPORT QDesignerCustomWidgetData { public: + // StringPropertyType: validation mode and translatable flag. + typedef QPair<qdesigner_internal::TextPropertyValidationMode, bool> StringPropertyType; + explicit QDesignerCustomWidgetData(const QString &pluginPath = QString()); enum ParseResult { ParseOk, ParseWarning, ParseError }; @@ -93,6 +98,8 @@ public: QString xmlExtends() const; // Optional. The name to be used in the widget box. QString xmlDisplayName() const; + // Type of a string property + bool xmlStringPropertyType(const QString &name, StringPropertyType *type) const; private: QSharedDataPointer<QDesignerCustomWidgetSharedData> m_d; @@ -128,6 +135,7 @@ public: CustomWidgetList registeredCustomWidgets() const; QDesignerCustomWidgetData customWidgetData(QDesignerCustomWidgetInterface *w) const; + QDesignerCustomWidgetData customWidgetData(const QString &className) const; bool registerNewPlugins(); diff --git a/tools/designer/src/lib/shared/previewconfigurationwidget.cpp b/tools/designer/src/lib/shared/previewconfigurationwidget.cpp index 54a5c20..0134788 100644 --- a/tools/designer/src/lib/shared/previewconfigurationwidget.cpp +++ b/tools/designer/src/lib/shared/previewconfigurationwidget.cpp @@ -65,43 +65,27 @@ #include <QtCore/QFileInfo> #include <QtCore/QSharedData> -// #define DEFAULT_SKINS_FROM_RESOURCE -#ifdef DEFAULT_SKINS_FROM_RESOURCE -QT_BEGIN_NAMESPACE + static const char *skinResourcePathC = ":/skins/"; -QT_END_NAMESPACE -#else -# include <QtCore/QLibraryInfo> -#endif QT_BEGIN_NAMESPACE static const char *skinExtensionC = "skin"; -namespace { - // Pair of skin name, path - typedef QPair<QString, QString> SkinNamePath; - typedef QList<SkinNamePath> Skins; - enum { SkinComboNoneIndex = 0 }; -} +// Pair of skin name, path +typedef QPair<QString, QString> SkinNamePath; +typedef QList<SkinNamePath> Skins; +enum { SkinComboNoneIndex = 0 }; // find default skins (resources) static const Skins &defaultSkins() { static Skins rc; if (rc.empty()) { -#ifdef DEFAULT_SKINS_FROM_RESOURCE const QString skinPath = QLatin1String(skinResourcePathC); -#else - QString skinPath = QLibraryInfo::location(QLibraryInfo::PrefixPath); - skinPath += QDir::separator(); - skinPath += QLatin1String("tools"); - skinPath += QDir::separator(); - skinPath += QLatin1String("qvfb"); -#endif QString pattern = QLatin1String("*."); pattern += QLatin1String(skinExtensionC); const QDir dir(skinPath, pattern); - const QFileInfoList list = dir.entryInfoList(); + const QFileInfoList list = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot, QDir::Name); if (list.empty()) return rc; const QFileInfoList::const_iterator lcend = list.constEnd(); diff --git a/tools/designer/src/lib/shared/previewmanager.cpp b/tools/designer/src/lib/shared/previewmanager.cpp index f972ffe..890bfc1 100644 --- a/tools/designer/src/lib/shared/previewmanager.cpp +++ b/tools/designer/src/lib/shared/previewmanager.cpp @@ -67,6 +67,7 @@ #include <QtGui/QAction> #include <QtGui/QActionGroup> #include <QtGui/QCursor> +#include <QtGui/QMatrix> #include <QtCore/QMap> #include <QtCore/QDebug> @@ -149,11 +150,16 @@ QGraphicsProxyWidget *DesignerZoomWidget::createProxyWidget(QGraphicsItem *paren return new DesignerZoomProxyWidget(parent, wFlags); } -// --------- Widget Preview skin: Forward the key events to the window +// PreviewDeviceSkin: Forwards the key events to the window and +// provides context menu with rotation options. Derived class +// can apply additional transformations to the skin. + class PreviewDeviceSkin : public DeviceSkin { Q_OBJECT public: + enum Direction { DirectionUp, DirectionLeft, DirectionRight }; + explicit PreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent); virtual void setPreview(QWidget *w); QSize screenSize() const { return m_screenSize; } @@ -164,15 +170,36 @@ private slots: void slotPopupMenu(); protected: - virtual void populateContextMenu(QMenu *m); + virtual void populateContextMenu(QMenu *) {} + +private slots: + void slotDirection(QAction *); + +protected: + // Fit the widget in case the orientation changes (transposing screensize) + virtual void fitWidget(const QSize &size); + // Calculate the complete transformation for the skin + // (base class implementation provides rotation). + virtual QMatrix skinTransform() const; private: const QSize m_screenSize; + Direction m_direction; + + QAction *m_directionUpAction; + QAction *m_directionLeftAction; + QAction *m_directionRightAction; + QAction *m_closeAction; }; PreviewDeviceSkin::PreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent) : - DeviceSkin(parameters, parent), - m_screenSize(parameters.screenSize()) + DeviceSkin(parameters, parent), + m_screenSize(parameters.screenSize()), + m_direction(DirectionUp), + m_directionUpAction(0), + m_directionLeftAction(0), + m_directionRightAction(0), + m_closeAction(0) { connect(this, SIGNAL(skinKeyPressEvent(int,QString,bool)), this, SLOT(slotSkinKeyPressEvent(int,QString,bool))); @@ -195,7 +222,6 @@ void PreviewDeviceSkin::slotSkinKeyPressEvent(int code, const QString& text, boo QKeyEvent e(QEvent::KeyPress,code,0,text,autorep); QApplication::sendEvent(focusWidget, &e); } - } void PreviewDeviceSkin::slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep) @@ -206,16 +232,83 @@ void PreviewDeviceSkin::slotSkinKeyReleaseEvent(int code, const QString& text, b } } +// Create a checkable action with integer data and +// set it checked if it matches the currentState. +static inline QAction + *createCheckableActionIntData(const QString &label, + int actionValue, int currentState, + QActionGroup *ag, QObject *parent) +{ + QAction *a = new QAction(label, parent); + a->setData(actionValue); + a->setCheckable(true); + if (actionValue == currentState) + a->setChecked(true); + ag->addAction(a); + return a; +} + void PreviewDeviceSkin::slotPopupMenu() { QMenu menu(this); + // Create actions + if (!m_directionUpAction) { + QActionGroup *directionGroup = new QActionGroup(this); + connect(directionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotDirection(QAction*))); + directionGroup->setExclusive(true); + m_directionUpAction = createCheckableActionIntData(tr("&Portrait"), DirectionUp, m_direction, directionGroup, this); + m_directionLeftAction = createCheckableActionIntData(tr("Landscape (&CCW)"), DirectionLeft, m_direction, directionGroup, this); + m_directionRightAction = createCheckableActionIntData(tr("&Landscape (CW)"), DirectionRight, m_direction, directionGroup, this); + m_closeAction = new QAction(tr("&Close"), this); + connect(m_closeAction, SIGNAL(triggered()), parentWidget(), SLOT(close())); + } + menu.addAction(m_directionUpAction); + menu.addAction(m_directionLeftAction); + menu.addAction(m_directionRightAction); + menu.addSeparator(); populateContextMenu(&menu); + menu.addAction(m_closeAction); menu.exec(QCursor::pos()); } -void PreviewDeviceSkin::populateContextMenu(QMenu *menu) +void PreviewDeviceSkin::slotDirection(QAction *a) +{ + const Direction newDirection = static_cast<Direction>(a->data().toInt()); + if (m_direction == newDirection) + return; + const Qt::Orientation newOrientation = newDirection == DirectionUp ? Qt::Vertical : Qt::Horizontal; + const Qt::Orientation oldOrientation = m_direction == DirectionUp ? Qt::Vertical : Qt::Horizontal; + m_direction = newDirection; + QApplication::setOverrideCursor(Qt::WaitCursor); + if (oldOrientation != newOrientation) { + QSize size = screenSize(); + if (newOrientation == Qt::Horizontal) + size.transpose(); + fitWidget(size); + } + setTransform(skinTransform()); + QApplication::restoreOverrideCursor(); +} + +void PreviewDeviceSkin::fitWidget(const QSize &size) +{ + view()->setFixedSize(size); +} + +QMatrix PreviewDeviceSkin::skinTransform() const { - connect(menu->addAction(tr("&Close")), SIGNAL(triggered()), parentWidget(), SLOT(close())); + QMatrix newTransform; + switch (m_direction) { + case DirectionUp: + break; + case DirectionLeft: + newTransform.rotate(270.0); + break; + case DirectionRight: + newTransform.rotate(90.0); + break; + } + return newTransform; } // ------------ PreviewConfigurationPrivate @@ -257,16 +350,20 @@ signals: void zoomPercentChanged(int); protected: - virtual void populateContextMenu(QMenu *m); + virtual void populateContextMenu(QMenu *m); + virtual QMatrix skinTransform() const; + virtual void fitWidget(const QSize &size); private: ZoomMenu *m_zoomMenu; + QAction *m_zoomSubMenuAction; ZoomWidget *m_zoomWidget; }; ZoomablePreviewDeviceSkin::ZoomablePreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent) : PreviewDeviceSkin(parameters, parent), m_zoomMenu(new ZoomMenu(this)), + m_zoomSubMenuAction(0), m_zoomWidget(new DesignerZoomWidget) { connect(m_zoomMenu, SIGNAL(zoomChanged(int)), this, SLOT(setZoomPercent(int))); @@ -279,10 +376,20 @@ ZoomablePreviewDeviceSkin::ZoomablePreviewDeviceSkin(const DeviceSkinParameters setView(m_zoomWidget); } -void ZoomablePreviewDeviceSkin::setPreview(QWidget *formWidget) +static inline qreal zoomFactor(int percent) { - formWidget->setFixedSize(screenSize()); + return qreal(percent) / 100.0; +} + +static inline QSize scaleSize(int zoomPercent, const QSize &size) +{ + return zoomPercent == 100 ? size : (QSizeF(size) * zoomFactor(zoomPercent)).toSize(); +} + +void ZoomablePreviewDeviceSkin::setPreview(QWidget *formWidget) +{ m_zoomWidget->setWidget(formWidget); + m_zoomWidget->resize(scaleSize(zoomPercent(), screenSize())); } int ZoomablePreviewDeviceSkin::zoomPercent() const @@ -290,32 +397,50 @@ int ZoomablePreviewDeviceSkin::zoomPercent() const return m_zoomWidget->zoom(); } -void ZoomablePreviewDeviceSkin::setZoomPercent(int z) +void ZoomablePreviewDeviceSkin::setZoomPercent(int zp) { - if (z == zoomPercent()) + if (zp == zoomPercent()) return; // If not triggered by the menu itself: Update it - if (m_zoomMenu->zoom() != z) - m_zoomMenu->setZoom(z); + if (m_zoomMenu->zoom() != zp) + m_zoomMenu->setZoom(zp); - const QCursor oldCursor = cursor(); - QApplication::setOverrideCursor(Qt::WaitCursor); - // DeviceSkin has double, not qreal. - const double hundred = 100.0; - setZoom(static_cast<double>(z) / hundred); - m_zoomWidget->setZoom(z); + QApplication::setOverrideCursor(Qt::WaitCursor); + m_zoomWidget->setZoom(zp); + setTransform(skinTransform()); QApplication::restoreOverrideCursor(); } void ZoomablePreviewDeviceSkin::populateContextMenu(QMenu *menu) { - m_zoomMenu->addActions(menu); - menu->addSeparator(); - PreviewDeviceSkin::populateContextMenu(menu); + if (!m_zoomSubMenuAction) { + m_zoomSubMenuAction = new QAction(tr("&Zoom"), this); + QMenu *zoomSubMenu = new QMenu; + m_zoomSubMenuAction->setMenu(zoomSubMenu); + m_zoomMenu->addActions(zoomSubMenu); + } + menu->addAction(m_zoomSubMenuAction); menu->addSeparator(); } +QMatrix ZoomablePreviewDeviceSkin::skinTransform() const +{ + // Complete transformation consisting of base class rotation and zoom. + QMatrix rc = PreviewDeviceSkin::skinTransform(); + const int zp = zoomPercent(); + if (zp != 100) { + const qreal factor = zoomFactor(zp); + rc.scale(factor, factor); + } + return rc; +} + +void ZoomablePreviewDeviceSkin::fitWidget(const QSize &size) +{ + m_zoomWidget->resize(scaleSize(zoomPercent(), size)); +} + // ------------- PreviewConfiguration static const char *styleKey = "Style"; diff --git a/tools/designer/src/lib/shared/promotionmodel.cpp b/tools/designer/src/lib/shared/promotionmodel.cpp index 7276195..4b4bc04 100644 --- a/tools/designer/src/lib/shared/promotionmodel.cpp +++ b/tools/designer/src/lib/shared/promotionmodel.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::PromotionModel -*/ - #include "promotionmodel_p.h" #include "widgetdatabase_p.h" diff --git a/tools/designer/src/lib/shared/qdesigner_formbuilder.cpp b/tools/designer/src/lib/shared/qdesigner_formbuilder.cpp index c4cdd9d..20e94dc 100644 --- a/tools/designer/src/lib/shared/qdesigner_formbuilder.cpp +++ b/tools/designer/src/lib/shared/qdesigner_formbuilder.cpp @@ -473,6 +473,20 @@ QPixmap QDesignerFormBuilder::createPreviewPixmap(const QDesignerFormWindowInter return rc; } +// ---------- NewFormWidgetFormBuilder + +NewFormWidgetFormBuilder::NewFormWidgetFormBuilder(QDesignerFormEditorInterface *core, + Mode mode, + const DeviceProfile &deviceProfile) : + QDesignerFormBuilder(core, mode, deviceProfile) +{ +} + +void NewFormWidgetFormBuilder::createCustomWidgets(DomCustomWidgets *dc) +{ + QSimpleResource::handleDomCustomWidgets(core(), dc); +} + } // namespace qdesigner_internal QT_END_NAMESPACE diff --git a/tools/designer/src/lib/shared/qdesigner_formbuilder_p.h b/tools/designer/src/lib/shared/qdesigner_formbuilder_p.h index 9564c55..f026ac5 100644 --- a/tools/designer/src/lib/shared/qdesigner_formbuilder_p.h +++ b/tools/designer/src/lib/shared/qdesigner_formbuilder_p.h @@ -75,7 +75,7 @@ namespace qdesigner_internal { class DesignerPixmapCache; class DesignerIconCache; -/* Form builder used for previewing forms, widget box and new form dialog. +/* Form builder used for previewing forms and widget box. * It applies the system settings to its toplevel window. */ class QDESIGNER_SHARED_EXPORT QDesignerFormBuilder: public QFormBuilder @@ -159,6 +159,21 @@ private: bool m_mainWidget; }; +// Form builder for a new form widget (preview). To allow for promoted +// widgets in the template, it implements the handling of custom widgets +// (adding of them to the widget database). + +class QDESIGNER_SHARED_EXPORT NewFormWidgetFormBuilder: public QDesignerFormBuilder { +public: + NewFormWidgetFormBuilder(QDesignerFormEditorInterface *core, + Mode mode, + const DeviceProfile &deviceProfile = DeviceProfile()); + +protected: + virtual void createCustomWidgets(DomCustomWidgets *); +}; + + } // namespace qdesigner_internal QT_END_NAMESPACE diff --git a/tools/designer/src/lib/shared/qdesigner_promotiondialog.cpp b/tools/designer/src/lib/shared/qdesigner_promotiondialog.cpp index caa3ef2..010cc17 100644 --- a/tools/designer/src/lib/shared/qdesigner_promotiondialog.cpp +++ b/tools/designer/src/lib/shared/qdesigner_promotiondialog.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::QDesignerPromotionDialog -*/ - #include "qdesigner_promotiondialog_p.h" #include "promotionmodel_p.h" #include "iconloader_p.h" diff --git a/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp b/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp index 5a435ba..96b51f0 100644 --- a/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp +++ b/tools/designer/src/lib/shared/qdesigner_propertyeditor.cpp @@ -40,16 +40,56 @@ ****************************************************************************/ #include "qdesigner_propertyeditor_p.h" -#ifdef Q_OS_WIN -# include <widgetfactory_p.h> -#endif -#include <QAction> -#include <QLineEdit> -#include <QAbstractButton> +#include "pluginmanager_p.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <widgetfactory_p.h> +#include <QtGui/QAction> +#include <QtGui/QLineEdit> +#include <QtGui/QAbstractButton> QT_BEGIN_NAMESPACE namespace qdesigner_internal { +typedef QDesignerPropertyEditor::StringPropertyParameters StringPropertyParameters; +// A map of property name to type +typedef QHash<QString, StringPropertyParameters> PropertyNameTypeMap; + +// Compile a map of hard-coded string property types +static const PropertyNameTypeMap &stringPropertyTypes() +{ + static PropertyNameTypeMap propertyNameTypeMap; + if (propertyNameTypeMap.empty()) { + const StringPropertyParameters richtext(ValidationRichText, true); + // Accessibility. Both are texts the narrator reads + propertyNameTypeMap.insert(QLatin1String("accessibleDescription"), richtext); + propertyNameTypeMap.insert(QLatin1String("accessibleName"), richtext); + // object names + const StringPropertyParameters objectName(ValidationObjectName, false); + propertyNameTypeMap.insert(QLatin1String("buddy"), objectName); + propertyNameTypeMap.insert(QLatin1String("currentItemName"), objectName); + propertyNameTypeMap.insert(QLatin1String("currentPageName"), objectName); + propertyNameTypeMap.insert(QLatin1String("currentTabName"), objectName); + propertyNameTypeMap.insert(QLatin1String("layoutName"), objectName); + propertyNameTypeMap.insert(QLatin1String("spacerName"), objectName); + // Style sheet + propertyNameTypeMap.insert(QLatin1String("styleSheet"), StringPropertyParameters(ValidationStyleSheet, false)); + // Buttons/ QCommandLinkButton + const StringPropertyParameters multiline(ValidationMultiLine, true); + propertyNameTypeMap.insert(QLatin1String("description"), multiline); + propertyNameTypeMap.insert(QLatin1String("iconText"), multiline); + // Tooltips, etc. + propertyNameTypeMap.insert(QLatin1String("toolTip"), richtext); + propertyNameTypeMap.insert(QLatin1String("whatsThis"), richtext); + propertyNameTypeMap.insert(QLatin1String("windowIconText"), richtext); + propertyNameTypeMap.insert(QLatin1String("html"), richtext); + // A QWizard page id + propertyNameTypeMap.insert(QLatin1String("pageId"), StringPropertyParameters(ValidationSingleLine, false)); + // QPlainTextEdit + propertyNameTypeMap.insert(QLatin1String("plainText"), StringPropertyParameters(ValidationMultiLine, true)); + } + return propertyNameTypeMap; +} QDesignerPropertyEditor::QDesignerPropertyEditor(QWidget *parent, Qt::WindowFlags flags) : QDesignerPropertyEditorInterface(parent, flags) @@ -68,33 +108,19 @@ QDesignerPropertyEditor::StringPropertyParameters QDesignerPropertyEditor::textP return StringPropertyParameters(vm, false); } - // Accessibility. Both are texts the narrator reads - if (propertyName == QLatin1String("accessibleDescription") || propertyName == QLatin1String("accessibleName")) - return StringPropertyParameters(ValidationRichText, true); - - // Names - if (propertyName == QLatin1String("buddy") - || propertyName == QLatin1String("currentItemName") - || propertyName == QLatin1String("currentPageName") - || propertyName == QLatin1String("currentTabName") - || propertyName == QLatin1String("layoutName") - || propertyName == QLatin1String("spacerName")) - return StringPropertyParameters(ValidationObjectName, false); - - if (propertyName.endsWith(QLatin1String("Name"))) - return StringPropertyParameters(ValidationSingleLine, true); - - // Multi line? - if (propertyName == QLatin1String("styleSheet")) - return StringPropertyParameters(ValidationStyleSheet, false); - - if (propertyName == QLatin1String("description") || propertyName == QLatin1String("iconText")) // QCommandLinkButton - return StringPropertyParameters(ValidationMultiLine, true); + // Check custom widgets by class. + const QString className = WidgetFactory::classNameOf(core, object); + const QDesignerCustomWidgetData customData = core->pluginManager()->customWidgetData(className); + if (!customData.isNull()) { + StringPropertyParameters customType; + if (customData.xmlStringPropertyType(propertyName, &customType)) + return customType; + } - if (propertyName == QLatin1String("toolTip") || propertyName.endsWith(QLatin1String("ToolTip")) || - propertyName == QLatin1String("whatsThis") || - propertyName == QLatin1String("windowIconText") || propertyName == QLatin1String("html")) - return StringPropertyParameters(ValidationRichText, true); + // Check hardcoded property ames + const PropertyNameTypeMap::const_iterator hit = stringPropertyTypes().constFind(propertyName); + if (hit != stringPropertyTypes().constEnd()) + return hit.value(); // text: Check according to widget type. if (propertyName == QLatin1String("text")) { @@ -104,17 +130,17 @@ QDesignerPropertyEditor::StringPropertyParameters QDesignerPropertyEditor::textP return StringPropertyParameters(ValidationMultiLine, true); return StringPropertyParameters(ValidationRichText, true); } - if (propertyName == QLatin1String("pageId")) // A QWizard page id - return StringPropertyParameters(ValidationSingleLine, false); - if (propertyName == QLatin1String("plainText")) // QPlainTextEdit - return StringPropertyParameters(ValidationMultiLine, true); + // Fuzzy matching + if (propertyName.endsWith(QLatin1String("Name"))) + return StringPropertyParameters(ValidationSingleLine, true); + + if (propertyName.endsWith(QLatin1String("ToolTip"))) + return StringPropertyParameters(ValidationRichText, true); #ifdef Q_OS_WIN // No translation for the active X "control" property - if (propertyName == QLatin1String("control") && WidgetFactory::classNameOf(core, object) == QLatin1String("QAxWidget")) + if (propertyName == QLatin1String("control") && className == QLatin1String("QAxWidget")) return StringPropertyParameters(ValidationSingleLine, false); -#else - Q_UNUSED(core); #endif // default to single diff --git a/tools/designer/src/lib/shared/qdesigner_stackedbox.cpp b/tools/designer/src/lib/shared/qdesigner_stackedbox.cpp index 38b1d7c..0b45b7b 100644 --- a/tools/designer/src/lib/shared/qdesigner_stackedbox.cpp +++ b/tools/designer/src/lib/shared/qdesigner_stackedbox.cpp @@ -315,7 +315,7 @@ QMenu *QStackedWidgetEventFilter::addContextMenuActions(QMenu *popup) QMenu *pageMenu = 0; const int count = stackedWidget()->count(); const bool hasSeveralPages = count > 1; - m_actionDeletePage->setEnabled(hasSeveralPages); + m_actionDeletePage->setEnabled(count); if (count) { const QString pageSubMenuLabel = tr("Page %1 of %2").arg(stackedWidget()->currentIndex() + 1).arg(count); pageMenu = popup->addMenu(pageSubMenuLabel); @@ -327,10 +327,13 @@ QMenu *QStackedWidgetEventFilter::addContextMenuActions(QMenu *popup) qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit, pageMenu); } + QMenu *insertPageMenu = popup->addMenu(tr("Insert Page")); + insertPageMenu->addAction(m_actionInsertPageAfter); + insertPageMenu->addAction(m_actionInsertPage); + } else { + QAction *insertPageAction = popup->addAction(tr("Insert Page")); + connect(insertPageAction, SIGNAL(triggered()), this, SLOT(addPage())); } - QMenu *insertPageMenu = popup->addMenu(tr("Insert Page")); - insertPageMenu->addAction(m_actionInsertPageAfter); - insertPageMenu->addAction(m_actionInsertPage); popup->addAction(m_actionNextPage); m_actionNextPage->setEnabled(hasSeveralPages); popup->addAction(m_actionPreviousPage); diff --git a/tools/designer/src/lib/shared/qdesigner_tabwidget.cpp b/tools/designer/src/lib/shared/qdesigner_tabwidget.cpp index 22833b3..eb4dfa2 100644 --- a/tools/designer/src/lib/shared/qdesigner_tabwidget.cpp +++ b/tools/designer/src/lib/shared/qdesigner_tabwidget.cpp @@ -368,7 +368,7 @@ QMenu *QTabWidgetEventFilter::addContextMenuActions(QMenu *popup) { QMenu *pageMenu = 0; const int count = m_tabWidget->count(); - m_actionDeletePage->setEnabled(count > 1); + m_actionDeletePage->setEnabled(count); if (count) { const int currentIndex = m_tabWidget->currentIndex(); const QString pageSubMenuLabel = tr("Page %1 of %2").arg(currentIndex + 1).arg(count); @@ -381,11 +381,13 @@ QMenu *QTabWidgetEventFilter::addContextMenuActions(QMenu *popup) qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit, pageMenu); } + QMenu *insertPageMenu = popup->addMenu(tr("Insert Page")); + insertPageMenu->addAction(m_actionInsertPageAfter); + insertPageMenu->addAction(m_actionInsertPage); + } else { + QAction *insertPageAction = popup->addAction(tr("Insert Page")); + connect(insertPageAction, SIGNAL(triggered()), this, SLOT(addPage())); } - - QMenu *insertPageMenu = popup->addMenu(tr("Insert Page")); - insertPageMenu->addAction(m_actionInsertPageAfter); - insertPageMenu->addAction(m_actionInsertPage); popup->addSeparator(); return pageMenu; } diff --git a/tools/designer/src/lib/shared/qdesigner_taskmenu.cpp b/tools/designer/src/lib/shared/qdesigner_taskmenu.cpp index 93b1fa6..ae31c33 100644 --- a/tools/designer/src/lib/shared/qdesigner_taskmenu.cpp +++ b/tools/designer/src/lib/shared/qdesigner_taskmenu.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::QDesignerTaskMenu -*/ - #include "qdesigner_taskmenu_p.h" #include "qdesigner_command_p.h" #include "richtexteditor_p.h" diff --git a/tools/designer/src/lib/shared/qdesigner_toolbar.cpp b/tools/designer/src/lib/shared/qdesigner_toolbar.cpp index f0e51de..2693452 100644 --- a/tools/designer/src/lib/shared/qdesigner_toolbar.cpp +++ b/tools/designer/src/lib/shared/qdesigner_toolbar.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::Sentinel -*/ - #include "qdesigner_toolbar_p.h" #include "qdesigner_command_p.h" #include "actionrepository_p.h" @@ -65,7 +61,6 @@ TRANSLATOR qdesigner_internal::Sentinel #include <QtGui/QMenu> #include <QtGui/qevent.h> #include <QtGui/QApplication> -#include <QtGui/private/qtoolbarlayout_p.h> #include <QtCore/QDebug> Q_DECLARE_METATYPE(QAction*) @@ -445,11 +440,17 @@ QAction *ToolBarEventFilter::actionAt(const QToolBar *tb, const QPoint &pos) return tb->actions().at(index); } +//that's a trick to get acces to the initStyleOption which is a protected member +class FriendlyToolBar : public QToolBar { +public: + friend class ToolBarEventFilter; +}; + QRect ToolBarEventFilter::handleArea(const QToolBar *tb) { - const QToolBarLayout *tbl = qobject_cast<QToolBarLayout *>(tb->layout()); - Q_ASSERT(tbl); - return tbl->handleRect(); + QStyleOptionToolBar opt; + static_cast<const FriendlyToolBar*>(tb)->initStyleOption(&opt); + return tb->style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, tb); } bool ToolBarEventFilter::withinHandleArea(const QToolBar *tb, const QPoint &pos) diff --git a/tools/designer/src/lib/shared/qdesigner_widgetbox.cpp b/tools/designer/src/lib/shared/qdesigner_widgetbox.cpp index 34f7016..e25b880 100644 --- a/tools/designer/src/lib/shared/qdesigner_widgetbox.cpp +++ b/tools/designer/src/lib/shared/qdesigner_widgetbox.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::QDesignerWidgetBox -*/ - #include "qdesigner_widgetbox_p.h" #include "qdesigner_utils_p.h" diff --git a/tools/designer/src/lib/shared/qsimpleresource.cpp b/tools/designer/src/lib/shared/qsimpleresource.cpp index 4a9c7fe..63dfb03 100644 --- a/tools/designer/src/lib/shared/qsimpleresource.cpp +++ b/tools/designer/src/lib/shared/qsimpleresource.cpp @@ -41,6 +41,7 @@ #include "qsimpleresource_p.h" #include "widgetfactory_p.h" +#include "widgetdatabase_p.h" #include <formscriptrunner_p.h> #include <properties_p.h> @@ -57,6 +58,8 @@ #include <QtGui/QWidget> #include <QtGui/QAction> #include <QtCore/QDebug> +#include <QtCore/QCoreApplication> + QT_BEGIN_NAMESPACE @@ -267,6 +270,136 @@ bool QSimpleResource::warningsEnabled() return m_warningsEnabled; } +// Custom widgets handling helpers + +// Add unique fake slots and signals to lists +bool QSimpleResource::addFakeMethods(const DomSlots *domSlots, QStringList &fakeSlots, QStringList &fakeSignals) +{ + if (!domSlots) + return false; + + bool rc = false; + foreach (const QString &fakeSlot, domSlots->elementSlot()) + if (fakeSlots.indexOf(fakeSlot) == -1) { + fakeSlots += fakeSlot; + rc = true; + } + + foreach (const QString &fakeSignal, domSlots->elementSignal()) + if (fakeSignals.indexOf(fakeSignal) == -1) { + fakeSignals += fakeSignal; + rc = true; + } + return rc; +} + +void QSimpleResource::addFakeMethodsToWidgetDataBase(const DomCustomWidget *domCustomWidget, WidgetDataBaseItem *item) +{ + const DomSlots *domSlots = domCustomWidget->elementSlots(); + if (!domSlots) + return; + + // Merge in new slots, signals + QStringList fakeSlots = item->fakeSlots(); + QStringList fakeSignals = item->fakeSignals(); + if (addFakeMethods(domSlots, fakeSlots, fakeSignals)) { + item->setFakeSlots(fakeSlots); + item->setFakeSignals(fakeSignals); + } +} + +// Perform one iteration of adding the custom widgets to the database, +// looking up the base class and inheriting its data. +// Remove the succeeded custom widgets from the list. +// Classes whose base class could not be found are left in the list. + +void QSimpleResource::addCustomWidgetsToWidgetDatabase(const QDesignerFormEditorInterface *core, + QList<DomCustomWidget*>& custom_widget_list) +{ + QDesignerWidgetDataBaseInterface *db = core->widgetDataBase(); + for (int i=0; i < custom_widget_list.size(); ) { + bool classInserted = false; + DomCustomWidget *custom_widget = custom_widget_list[i]; + const QString customClassName = custom_widget->elementClass(); + const QString base_class = custom_widget->elementExtends(); + QString includeFile; + IncludeType includeType = IncludeLocal; + if (const DomHeader *header = custom_widget->elementHeader()) { + includeFile = header->text(); + if (header->hasAttributeLocation() && header->attributeLocation() == QLatin1String("global")) + includeType = IncludeGlobal; + } + const bool domIsContainer = custom_widget->elementContainer(); + // Append a new item + if (base_class.isEmpty()) { + WidgetDataBaseItem *item = new WidgetDataBaseItem(customClassName); + item->setPromoted(false); + item->setGroup(QCoreApplication::translate("Designer", "Custom Widgets")); + item->setIncludeFile(buildIncludeFile(includeFile, includeType)); + item->setContainer(domIsContainer); + item->setCustom(true); + addFakeMethodsToWidgetDataBase(custom_widget, item); + db->append(item); + custom_widget_list.removeAt(i); + classInserted = true; + } else { + // Create a new entry cloned from base class. Note that this will ignore existing + // classes, eg, plugin custom widgets. + QDesignerWidgetDataBaseItemInterface *item = + appendDerived(db, customClassName, QCoreApplication::translate("Designer", "Promoted Widgets"), + base_class, + buildIncludeFile(includeFile, includeType), + true,true); + // Ok, base class found. + if (item) { + // Hack to accommodate for old UI-files in which "container" is not set properly: + // Apply "container" from DOM only if true (else, eg classes from QFrame might not accept + // dropping child widgets on them as container=false). This also allows for + // QWidget-derived stacked pages. + if (domIsContainer) + item->setContainer(domIsContainer); + + addFakeMethodsToWidgetDataBase(custom_widget, static_cast<WidgetDataBaseItem*>(item)); + custom_widget_list.removeAt(i); + classInserted = true; + } + } + // Skip failed item. + if (!classInserted) + i++; + } + +} + +void QSimpleResource::handleDomCustomWidgets(const QDesignerFormEditorInterface *core, + const DomCustomWidgets *dom_custom_widgets) +{ + if (dom_custom_widgets == 0) + return; + QList<DomCustomWidget*> custom_widget_list = dom_custom_widgets->elementCustomWidget(); + // Attempt to insert each item derived from its base class. + // This should at most require two iterations in the event that the classes are out of order + // (derived first, max depth: promoted custom plugin = 2) + for (int iteration = 0; iteration < 2; iteration++) { + addCustomWidgetsToWidgetDatabase(core, custom_widget_list); + if (custom_widget_list.empty()) + return; + } + // Oops, there are classes left whose base class could not be found. + // Default them to QWidget with warnings. + const QString fallBackBaseClass = QLatin1String("QWidget"); + for (int i=0; i < custom_widget_list.size(); i++ ) { + DomCustomWidget *custom_widget = custom_widget_list[i]; + const QString customClassName = custom_widget->elementClass(); + const QString base_class = custom_widget->elementExtends(); + qDebug() << "** WARNING The base class " << base_class << " of the custom widget class " << customClassName + << " could not be found. Defaulting to " << fallBackBaseClass << '.'; + custom_widget->setElementExtends(fallBackBaseClass); + } + // One more pass. + addCustomWidgetsToWidgetDatabase(core, custom_widget_list); +} + // ------------ FormBuilderClipboard FormBuilderClipboard::FormBuilderClipboard(QWidget *w) diff --git a/tools/designer/src/lib/shared/qsimpleresource_p.h b/tools/designer/src/lib/shared/qsimpleresource_p.h index 2608160..8569ef2 100644 --- a/tools/designer/src/lib/shared/qsimpleresource_p.h +++ b/tools/designer/src/lib/shared/qsimpleresource_p.h @@ -55,15 +55,21 @@ #include "shared_global_p.h" #include "abstractformbuilder.h" +#include <QtCore/QStringList> QT_BEGIN_NAMESPACE class DomScript; +class DomCustomWidgets; +class DomCustomWidget; +class DomSlots; class QDesignerFormEditorInterface; namespace qdesigner_internal { +class WidgetDataBaseItem; + class QDESIGNER_SHARED_EXPORT QSimpleResource : public QAbstractFormBuilder { public: @@ -92,6 +98,11 @@ public: static QString customWidgetScript(QDesignerFormEditorInterface *core, const QString &className); static bool hasCustomWidgetScript(QDesignerFormEditorInterface *core, QObject *object); + // Implementation for FormBuilder::createDomCustomWidgets() that adds + // the custom widgets to the widget database + static void handleDomCustomWidgets(const QDesignerFormEditorInterface *core, + const DomCustomWidgets *dom_custom_widgets); + protected: virtual QIcon nameToIcon(const QString &filePath, const QString &qrcPath); virtual QString iconToFilePath(const QIcon &pm) const; @@ -105,7 +116,13 @@ protected: typedef QList<DomScript*> DomScripts; static void addScript(const QString &script, ScriptSource source, DomScripts &domScripts); + static bool addFakeMethods(const DomSlots *domSlots, QStringList &fakeSlots, QStringList &fakeSignals); + private: + static void addCustomWidgetsToWidgetDatabase(const QDesignerFormEditorInterface *core, + QList<DomCustomWidget*>& custom_widget_list); + static void addFakeMethodsToWidgetDataBase(const DomCustomWidget *domCustomWidget, WidgetDataBaseItem *item); + static bool m_warningsEnabled; QDesignerFormEditorInterface *m_core; }; diff --git a/tools/designer/src/lib/shared/qtresourceview.cpp b/tools/designer/src/lib/shared/qtresourceview.cpp index b6c3612..40be3e6 100644 --- a/tools/designer/src/lib/shared/qtresourceview.cpp +++ b/tools/designer/src/lib/shared/qtresourceview.cpp @@ -44,6 +44,7 @@ #include "qtresourcemodel_p.h" #include "qtresourceeditordialog_p.h" #include "iconloader_p.h" +#include "filterwidget_p.h" // For FilterWidget #include <QtDesigner/QDesignerFormEditorInterface> @@ -144,6 +145,7 @@ public: void slotReloadResources(); void slotCopyResourcePath(); void slotListWidgetContextMenuRequested(const QPoint &pos); + void slotFilterChanged(const QString &pattern); void createPaths(); QTreeWidgetItem *createPath(const QString &path, QTreeWidgetItem *parent); void createResources(const QString &path); @@ -152,16 +154,20 @@ public: void restoreSettings(); void saveSettings(); void updateActions(); + void filterOutResources(); QPixmap makeThumbnail(const QPixmap &pix) const; QDesignerFormEditorInterface *m_core; QtResourceModel *m_resourceModel; QToolBar *m_toolBar; + qdesigner_internal::FilterWidget *m_filterWidget; QTreeWidget *m_treeWidget; QListWidget *m_listWidget; QSplitter *m_splitter; - QMap<QString, QStringList> m_pathToContents; // full path to contents file names + QMap<QString, QStringList> m_pathToContents; // full path to contents file names (full path to its resource filenames) + QMap<QString, QString> m_pathToParentPath; // full path to full parent path + QMap<QString, QStringList> m_pathToSubPaths; // full path to full sub paths QMap<QString, QTreeWidgetItem *> m_pathToItem; QMap<QTreeWidgetItem *, QString> m_itemToPath; QMap<QString, QListWidgetItem *> m_resourceToItem; @@ -175,6 +181,7 @@ public: bool m_ignoreGuiSignals; QString m_settingsKey; bool m_resourceEditingEnabled; + QString m_filterPattern; }; QtResourceViewPrivate::QtResourceViewPrivate(QDesignerFormEditorInterface *core) : @@ -251,6 +258,12 @@ void QtResourceViewPrivate::slotListWidgetContextMenuRequested(const QPoint &pos menu.exec(m_listWidget->mapToGlobal(pos)); } +void QtResourceViewPrivate::slotFilterChanged(const QString &pattern) +{ + m_filterPattern = pattern; + filterOutResources(); +} + void QtResourceViewPrivate::storeExpansionState() { QMapIterator<QString, QTreeWidgetItem *> it(m_pathToItem); @@ -294,6 +307,7 @@ void QtResourceViewPrivate::updateActions() m_editResourcesAction->setVisible(m_resourceEditingEnabled); m_editResourcesAction->setEnabled(resourceActive); m_reloadResourcesAction->setEnabled(resourceActive); + m_filterWidget->setEnabled(resourceActive); } void QtResourceViewPrivate::slotResourceSetActivated(QtResourceSet *resourceSet) @@ -307,6 +321,8 @@ void QtResourceViewPrivate::slotResourceSetActivated(QtResourceSet *resourceSet) const QString currentResource = m_itemToResource.value(m_listWidget->currentItem()); m_treeWidget->clear(); m_pathToContents.clear(); + m_pathToParentPath.clear(); + m_pathToSubPaths.clear(); m_pathToItem.clear(); m_itemToPath.clear(); m_listWidget->clear(); @@ -320,6 +336,7 @@ void QtResourceViewPrivate::slotResourceSetActivated(QtResourceSet *resourceSet) q_ptr->selectResource(currentResource); else if (!currentPath.isEmpty()) q_ptr->selectResource(currentPath); + filterOutResources(); } void QtResourceViewPrivate::slotCurrentPathChanged(QTreeWidgetItem *item) @@ -362,9 +379,6 @@ void QtResourceViewPrivate::createPaths() const QString root(QLatin1Char(':')); - QMap<QString, QString> pathToParentPath; // full path to full parent path - QMap<QString, QStringList> pathToSubPaths; // full path to full sub paths - QMap<QString, QString> contents = m_resourceModel->contents(); QMapIterator<QString, QString> itContents(contents); while (itContents.hasNext()) { @@ -372,11 +386,11 @@ void QtResourceViewPrivate::createPaths() const QFileInfo fi(filePath); QString dirPath = fi.absolutePath(); m_pathToContents[dirPath].append(fi.fileName()); - while (!pathToParentPath.contains(dirPath) && dirPath != root) { + while (!m_pathToParentPath.contains(dirPath) && dirPath != root) { // create all parent paths const QFileInfo fd(dirPath); const QString parentDirPath = fd.absolutePath(); - pathToParentPath[dirPath] = parentDirPath; - pathToSubPaths[parentDirPath].append(dirPath); + m_pathToParentPath[dirPath] = parentDirPath; + m_pathToSubPaths[parentDirPath].append(dirPath); dirPath = parentDirPath; } } @@ -387,13 +401,126 @@ void QtResourceViewPrivate::createPaths() QPair<QString, QTreeWidgetItem *> pathToParentItem = pathToParentItemQueue.dequeue(); const QString path = pathToParentItem.first; QTreeWidgetItem *item = createPath(path, pathToParentItem.second); - QStringList subPaths = pathToSubPaths.value(path); + QStringList subPaths = m_pathToSubPaths.value(path); QStringListIterator itSubPaths(subPaths); while (itSubPaths.hasNext()) pathToParentItemQueue.enqueue(qMakePair(itSubPaths.next(), item)); } } +void QtResourceViewPrivate::filterOutResources() +{ + QMap<QString, bool> pathToMatchingContents; // true means the path has any matching contents + QMap<QString, bool> pathToVisible; // true means the path has to be shown + + // 1) we go from root path recursively. + // 2) we check every path if it contains at least one matching resource - if empty we add it + // to pathToMatchingContents and pathToVisible with false, if non empty + // we add it with true and change every parent path in pathToVisible to true. + // 3) we hide these items which has pathToVisible value false. + + const bool matchAll = m_filterPattern.isEmpty(); + const QString root(QLatin1Char(':')); + + QQueue<QString> pathQueue; + pathQueue.enqueue(root); + while (!pathQueue.isEmpty()) { + const QString path = pathQueue.dequeue(); + + QStringList fileNames = m_pathToContents.value(path); + QStringListIterator it(fileNames); + bool hasContents = matchAll; + if (!matchAll) { // the case filter is not empty - we check if the path contains anything + while (it.hasNext()) { + QString fileName = it.next(); + hasContents = fileName.contains(m_filterPattern, Qt::CaseInsensitive); + if (hasContents) // the path contains at least one resource which matches the filter + break; + } + } + + pathToMatchingContents[path] = hasContents; + pathToVisible[path] = hasContents; + + if (hasContents) { // if the path is going to be shown we need to show all its parent paths + QString parentPath = m_pathToParentPath.value(path); + while (!parentPath.isEmpty()) { + QString p = parentPath; + if (pathToVisible.value(p)) // parent path is already shown, we break the loop + break; + pathToVisible[p] = true; + parentPath = m_pathToParentPath.value(p); + } + } + + QStringList subPaths = m_pathToSubPaths.value(path); // we do the same for children paths + QStringListIterator itSubPaths(subPaths); + while (itSubPaths.hasNext()) + pathQueue.enqueue(itSubPaths.next()); + } + + // we setup here new path and resource to be activated + const QString currentPath = m_itemToPath.value(m_treeWidget->currentItem()); + QString newCurrentPath = currentPath; + QString currentResource = m_itemToResource.value(m_listWidget->currentItem()); + if (!matchAll) { + bool searchForNewPathWithContents = true; + + if (!currentPath.isEmpty()) { // if the currentPath is empty we will search for a new path too + QMap<QString, bool>::ConstIterator it = pathToMatchingContents.constFind(currentPath); + if (it != pathToMatchingContents.constEnd() && it.value()) // the current item has contents, we don't need to search for another path + searchForNewPathWithContents = false; + } + + if (searchForNewPathWithContents) { + // we find the first path with the matching contents + QMap<QString, bool>::ConstIterator itContents = pathToMatchingContents.constBegin(); + while (itContents != pathToMatchingContents.constEnd()) { + if (itContents.value()) { + newCurrentPath = itContents.key(); // the new path will be activated + break; + } + + itContents++; + } + } + + QFileInfo fi(currentResource); + if (!fi.fileName().contains(m_filterPattern, Qt::CaseInsensitive)) { // the case when the current resource is filtered out + const QStringList fileNames = m_pathToContents.value(newCurrentPath); + QStringListIterator it(fileNames); + while (it.hasNext()) { // we try to select the first matching resource from the newCurrentPath + QString fileName = it.next(); + if (fileName.contains(m_filterPattern, Qt::CaseInsensitive)) { + QDir dirPath(newCurrentPath); + currentResource = dirPath.absoluteFilePath(fileName); // the new resource inside newCurrentPath will be activated + break; + } + } + } + } + + QTreeWidgetItem *newCurrentItem = m_pathToItem.value(newCurrentPath); + if (currentPath != newCurrentPath) + m_treeWidget->setCurrentItem(newCurrentItem); + else + slotCurrentPathChanged(newCurrentItem); // trigger filtering on the current path + + QListWidgetItem *currentResourceItem = m_resourceToItem.value(currentResource); + if (currentResourceItem) { + m_listWidget->setCurrentItem(currentResourceItem); + m_listWidget->scrollToItem(currentResourceItem); + } + + QMapIterator<QString, bool> it(pathToVisible); // hide all paths filtered out + while (it.hasNext()) { + const QString path = it.next().key(); + QTreeWidgetItem *item = m_pathToItem.value(path); + if (item) + item->setHidden(!it.value()); + } +} + QTreeWidgetItem *QtResourceViewPrivate::createPath(const QString &path, QTreeWidgetItem *parent) { QTreeWidgetItem *item = 0; @@ -417,27 +544,32 @@ QTreeWidgetItem *QtResourceViewPrivate::createPath(const QString &path, QTreeWid void QtResourceViewPrivate::createResources(const QString &path) { + const bool matchAll = m_filterPattern.isEmpty(); + QDir dir(path); - QStringList files = m_pathToContents.value(path); - QStringListIterator it(files); + QStringList fileNames = m_pathToContents.value(path); + QStringListIterator it(fileNames); while (it.hasNext()) { - QString file = it.next(); - QString filePath = dir.absoluteFilePath(file); - QFileInfo fi(filePath); - if (fi.isFile()) { - QListWidgetItem *item = new QListWidgetItem(fi.fileName(), m_listWidget); - const QPixmap pix = QPixmap(filePath); - if (pix.isNull()) { - item->setToolTip(filePath); - } else { - item->setIcon(QIcon(makeThumbnail(pix))); - const QSize size = pix.size(); - item->setToolTip(QtResourceView::tr("Size: %1 x %2\n%3").arg(size.width()).arg(size.height()).arg(filePath)); + QString fileName = it.next(); + const bool showProperty = matchAll || fileName.contains(m_filterPattern, Qt::CaseInsensitive); + if (showProperty) { + QString filePath = dir.absoluteFilePath(fileName); + QFileInfo fi(filePath); + if (fi.isFile()) { + QListWidgetItem *item = new QListWidgetItem(fi.fileName(), m_listWidget); + const QPixmap pix = QPixmap(filePath); + if (pix.isNull()) { + item->setToolTip(filePath); + } else { + item->setIcon(QIcon(makeThumbnail(pix))); + const QSize size = pix.size(); + item->setToolTip(QtResourceView::tr("Size: %1 x %2\n%3").arg(size.width()).arg(size.height()).arg(filePath)); + } + item->setFlags(item->flags() | Qt::ItemIsDragEnabled); + item->setData(Qt::UserRole, filePath); + m_itemToResource[item] = filePath; + m_resourceToItem[filePath] = item; } - item->setFlags(item->flags() | Qt::ItemIsDragEnabled); - item->setData(Qt::UserRole, filePath); - m_itemToResource[item] = filePath; - m_resourceToItem[filePath] = item; } } } @@ -464,6 +596,11 @@ QtResourceView::QtResourceView(QDesignerFormEditorInterface *core, QWidget *pare connect(d_ptr->m_copyResourcePathAction, SIGNAL(triggered()), this, SLOT(slotCopyResourcePath())); d_ptr->m_copyResourcePathAction->setEnabled(false); + //d_ptr->m_filterWidget = new qdesigner_internal::FilterWidget(0, qdesigner_internal::FilterWidget::LayoutAlignNone); + d_ptr->m_filterWidget = new qdesigner_internal::FilterWidget(d_ptr->m_toolBar); + d_ptr->m_toolBar->addWidget(d_ptr->m_filterWidget); + connect(d_ptr->m_filterWidget, SIGNAL(filterChanged(QString)), this, SLOT(slotFilterChanged(QString))); + d_ptr->m_splitter = new QSplitter; d_ptr->m_splitter->setChildrenCollapsible(false); d_ptr->m_splitter->addWidget(d_ptr->m_treeWidget); diff --git a/tools/designer/src/lib/shared/qtresourceview_p.h b/tools/designer/src/lib/shared/qtresourceview_p.h index 51a6353..fb8fb83 100644 --- a/tools/designer/src/lib/shared/qtresourceview_p.h +++ b/tools/designer/src/lib/shared/qtresourceview_p.h @@ -113,6 +113,7 @@ private: Q_PRIVATE_SLOT(d_func(), void slotReloadResources()) Q_PRIVATE_SLOT(d_func(), void slotCopyResourcePath()) Q_PRIVATE_SLOT(d_func(), void slotListWidgetContextMenuRequested(const QPoint &pos)) + Q_PRIVATE_SLOT(d_func(), void slotFilterChanged(const QString &pattern)) }; class QDESIGNER_SHARED_EXPORT QtResourceViewDialog : public QDialog diff --git a/tools/designer/src/lib/shared/richtexteditor.cpp b/tools/designer/src/lib/shared/richtexteditor.cpp index 6563358..a4df04f 100644 --- a/tools/designer/src/lib/shared/richtexteditor.cpp +++ b/tools/designer/src/lib/shared/richtexteditor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::RichTextEditorDialog -*/ - #include "richtexteditor_p.h" #include "htmlhighlighter_p.h" #include "iconselector_p.h" diff --git a/tools/designer/src/lib/shared/scriptdialog.cpp b/tools/designer/src/lib/shared/scriptdialog.cpp index 3cdf083..847afa3 100644 --- a/tools/designer/src/lib/shared/scriptdialog.cpp +++ b/tools/designer/src/lib/shared/scriptdialog.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ScriptDialog -*/ - #include "scriptdialog_p.h" #include "qscripthighlighter_p.h" diff --git a/tools/designer/src/lib/shared/scripterrordialog.cpp b/tools/designer/src/lib/shared/scripterrordialog.cpp index f41b444..629fc4e 100644 --- a/tools/designer/src/lib/shared/scripterrordialog.cpp +++ b/tools/designer/src/lib/shared/scripterrordialog.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::ScriptErrorDialog -*/ - #include "scripterrordialog_p.h" #include <QtGui/QTextEdit> diff --git a/tools/designer/src/lib/shared/stylesheeteditor.cpp b/tools/designer/src/lib/shared/stylesheeteditor.cpp index c4e54aa..2066ad8 100644 --- a/tools/designer/src/lib/shared/stylesheeteditor.cpp +++ b/tools/designer/src/lib/shared/stylesheeteditor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::StyleSheetEditorDialog -*/ - #include "stylesheeteditor_p.h" #include "csshighlighter_p.h" #include "iconselector_p.h" diff --git a/tools/designer/src/lib/shared/widgetfactory.cpp b/tools/designer/src/lib/shared/widgetfactory.cpp index 37c7677..7080ed3 100644 --- a/tools/designer/src/lib/shared/widgetfactory.cpp +++ b/tools/designer/src/lib/shared/widgetfactory.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::WidgetFactory -*/ - #include "widgetfactory_p.h" #include "widgetdatabase_p.h" #include "metadatabase_p.h" diff --git a/tools/designer/src/lib/shared/zoomwidget.cpp b/tools/designer/src/lib/shared/zoomwidget.cpp index d37e814..08d6082 100644 --- a/tools/designer/src/lib/shared/zoomwidget.cpp +++ b/tools/designer/src/lib/shared/zoomwidget.cpp @@ -143,9 +143,10 @@ ZoomView::ZoomView(QWidget *parent) : m_zoom(100), m_zoomFactor(1.0), m_zoomContextMenuEnabled(false), - m_autoScrollSuppressed(true), m_zoomMenu(0) { + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setFrameShape(QFrame::NoFrame); setScene(m_scene); if (debugZoomWidget) @@ -187,8 +188,6 @@ void ZoomView::setZoom(int percent) resetTransform(); scale(m_zoomFactor, m_zoomFactor); - if (m_autoScrollSuppressed) - scrollToOrigin(); } void ZoomView::applyZoom() @@ -210,16 +209,6 @@ void ZoomView::setZoomContextMenuEnabled(bool e) m_zoomContextMenuEnabled = e; } -bool ZoomView::isAutoScrollSuppressed() const -{ - return m_autoScrollSuppressed; -} - -void ZoomView::setAutoScrollSuppressed(bool s) -{ - m_autoScrollSuppressed = s; -} - ZoomMenu *ZoomView::zoomMenu() { if (!m_zoomMenu) { @@ -469,13 +458,16 @@ void ZoomWidget::resizeEvent(QResizeEvent *event) * and the use the size ZoomView::resizeEvent(event); */ if (m_proxy && !m_viewResizeBlocked) { if (debugZoomWidget > 1) - qDebug() << ">ZoomWidget (" << size() << ")::resizeEvent from " << event->oldSize() << " to " << event->size(); + qDebug() << '>' << Q_FUNC_INFO << size() << ")::resizeEvent from " << event->oldSize() << " to " << event->size(); const QSizeF newViewPortSize = size() - viewPortMargin(); const QSizeF widgetSizeF = newViewPortSize / zoomFactor() - widgetDecorationSizeF(); m_widgetResizeBlocked = true; m_proxy->widget()->resize(widgetSizeF.toSize()); + setSceneRect(QRectF(QPointF(0, 0), widgetSizeF)); scrollToOrigin(); m_widgetResizeBlocked = false; + if (debugZoomWidget > 1) + qDebug() << '<' << Q_FUNC_INFO << widgetSizeF << m_proxy->widget()->size() << m_proxy->size(); } } @@ -559,7 +551,7 @@ QGraphicsProxyWidget *ZoomWidget::createProxyWidget(QGraphicsItem *parent, Qt::W void ZoomWidget::dump() const { - qDebug() << "ZoomWidget " << geometry() << " Viewport " << viewport()->geometry() + qDebug() << "ZoomWidget::dump " << geometry() << " Viewport " << viewport()->geometry() << "Scroll: " << scrollPosition() << "Matrix: " << matrix() << " SceneRect: " << sceneRect(); if (m_proxy) { qDebug() << "Proxy Pos: " << m_proxy->pos() << "Proxy " << m_proxy->size() diff --git a/tools/designer/src/lib/shared/zoomwidget_p.h b/tools/designer/src/lib/shared/zoomwidget_p.h index 83b2972..8d5e07c 100644 --- a/tools/designer/src/lib/shared/zoomwidget_p.h +++ b/tools/designer/src/lib/shared/zoomwidget_p.h @@ -104,8 +104,6 @@ class QDESIGNER_SHARED_EXPORT ZoomView : public QGraphicsView { Q_PROPERTY(int zoom READ zoom WRITE setZoom DESIGNABLE true SCRIPTABLE true) Q_PROPERTY(bool zoomContextMenuEnabled READ isZoomContextMenuEnabled WRITE setZoomContextMenuEnabled DESIGNABLE true SCRIPTABLE true) - Q_PROPERTY(bool autoScrollSuppressed READ isAutoScrollSuppressed WRITE setAutoScrollSuppressed DESIGNABLE true SCRIPTABLE true) - Q_OBJECT Q_DISABLE_COPY(ZoomView) public: @@ -120,10 +118,6 @@ public: bool isZoomContextMenuEnabled() const; void setZoomContextMenuEnabled(bool e); - // Suppress scrolling when changing zoom. Default: on - bool isAutoScrollSuppressed() const; - void setAutoScrollSuppressed(bool s); - QGraphicsScene &scene() { return *m_scene; } const QGraphicsScene &scene() const { return *m_scene; } @@ -149,8 +143,7 @@ private: int m_zoom; qreal m_zoomFactor; - bool m_zoomContextMenuEnabled; - bool m_autoScrollSuppressed; + bool m_zoomContextMenuEnabled; bool m_resizeBlocked; ZoomMenu *m_zoomMenu; }; diff --git a/tools/designer/src/lib/uilib/abstractformbuilder.cpp b/tools/designer/src/lib/uilib/abstractformbuilder.cpp index e15e5ac..05e05c1 100644 --- a/tools/designer/src/lib/uilib/abstractformbuilder.cpp +++ b/tools/designer/src/lib/uilib/abstractformbuilder.cpp @@ -135,7 +135,7 @@ public: QAbstractFormBuilder provides a standard interface and a default implementation for constructing forms from user interface files. It is not intended to be instantiated directly. Use the - QFormBuilder class to create user interfaces from \c{.ui} files at + QFormBuilder class to create user interfaces from UI files at run-time. For example: \snippet doc/src/snippets/code/tools_designer_src_lib_uilib_abstractformbuilder.cpp 0 @@ -145,10 +145,10 @@ public: functions: \list - \o load() handles reading of \c{.ui} format files from arbitrary + \o load() handles reading of UI format files from arbitrary QIODevices, and construction of widgets from the XML data that they contain. - \o save() handles saving of widget details in \c{.ui} format to + \o save() handles saving of widget details in UI format to arbitrary QIODevices. \o workingDirectory() and setWorkingDirectory() control the directory in which forms are held. The form builder looks for @@ -208,13 +208,13 @@ QWidget *QAbstractFormBuilder::load(QIODevice *dev, QWidget *parentWidget) } } if (reader.hasError()) { - uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "An error has occurred while reading the ui file at line %1, column %2: %3") + uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "An error has occurred while reading the UI file at line %1, column %2: %3") .arg(reader.lineNumber()).arg(reader.columnNumber()) .arg(reader.errorString())); return 0; } if (!initialized) { - uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "Invalid ui file: The root element <ui> is missing.")); + uiLibWarning(QCoreApplication::translate("QAbstractFormBuilder", "Invalid UI file: The root element <ui> is missing.")); return 0; } @@ -403,6 +403,7 @@ QAction *QAbstractFormBuilder::create(DomAction *ui_action, QObject *parent) if (!a) return 0; + m_actions.insert(ui_action->attributeName(), a); applyProperties(a, ui_action->elementProperty()); return a; } @@ -415,7 +416,7 @@ QActionGroup *QAbstractFormBuilder::create(DomActionGroup *ui_action_group, QObj QActionGroup *a = createActionGroup(parent, ui_action_group->attributeName()); if (!a) return 0; - + m_actionGroups.insert(ui_action_group->attributeName(), a); applyProperties(a, ui_action_group->elementProperty()); foreach (DomAction *ui_action, ui_action_group->elementAction()) { @@ -656,7 +657,7 @@ void QAbstractFormBuilder::layoutInfo(DomLayout *ui_layout, QObject *parent, int spac = p->elementNumber(); #ifdef Q_OS_MAC - // here we recognize ui file < 4.3 (no we don't store margin property) + // here we recognize UI file < 4.3 (no we don't store margin property) if (mar != INT_MIN) { const int defaultMargin = parent->inherits("QLayoutWidget") ? 0 : 9; if (mar == defaultMargin) @@ -1184,8 +1185,6 @@ QAction *QAbstractFormBuilder::createAction(QObject *parent, const QString &name { QAction *action = new QAction(parent); action->setObjectName(name); - m_actions.insert(name, action); - return action; } @@ -1196,8 +1195,6 @@ QActionGroup *QAbstractFormBuilder::createActionGroup(QObject *parent, const QSt { QActionGroup *g = new QActionGroup(parent); g->setObjectName(name); - m_actionGroups.insert(name, g); - return g; } @@ -1205,7 +1202,7 @@ QActionGroup *QAbstractFormBuilder::createActionGroup(QObject *parent, const QSt \fn void QAbstractFormBuilder::save(QIODevice *device, QWidget *widget) Saves an XML representation of the given \a widget to the - specified \a device in the standard \c{.ui} file format. + specified \a device in the standard UI file format. \sa load()*/ void QAbstractFormBuilder::save(QIODevice *dev, QWidget *widget) diff --git a/tools/designer/src/lib/uilib/formbuilder.cpp b/tools/designer/src/lib/uilib/formbuilder.cpp index a627e74..f737311 100644 --- a/tools/designer/src/lib/uilib/formbuilder.cpp +++ b/tools/designer/src/lib/uilib/formbuilder.cpp @@ -57,12 +57,12 @@ namespace QFormInternal { \class QFormBuilder \brief The QFormBuilder class is used to dynamically construct - user interfaces from .ui files at run-time. + user interfaces from UI files at run-time. \inmodule QtDesigner The QFormBuilder class provides a mechanism for dynamically - creating user interfaces at run-time, based on \c{.ui} files + creating user interfaces at run-time, based on UI files created with \QD. For example: \snippet doc/src/snippets/code/tools_designer_src_lib_uilib_formbuilder.cpp 0 @@ -120,7 +120,10 @@ QFormBuilder::~QFormBuilder() */ QWidget *QFormBuilder::create(DomWidget *ui_widget, QWidget *parentWidget) { - QFormBuilderExtra::instance(this)->setProcessingLayoutWidget(false); + QFormBuilderExtra *fb = QFormBuilderExtra::instance(this); + if (!fb->parentWidgetIsSet()) + fb->setParentWidget(parentWidget); + fb->setProcessingLayoutWidget(false); if (ui_widget->attributeClass() == QFormBuilderStrings::instance().qWidgetClass && !ui_widget->hasAttributeNative() && parentWidget #ifndef QT_NO_MAINWINDOW @@ -145,7 +148,7 @@ QWidget *QFormBuilder::create(DomWidget *ui_widget, QWidget *parentWidget) && !qobject_cast<QDockWidget *>(parentWidget) #endif ) - QFormBuilderExtra::instance(this)->setProcessingLayoutWidget(true); + fb->setProcessingLayoutWidget(true); return QAbstractFormBuilder::create(ui_widget, parentWidget); } @@ -228,9 +231,6 @@ QWidget *QFormBuilder::createWidget(const QString &widgetName, QWidget *parentWi if (qobject_cast<QDialog *>(w)) w->setParent(parentWidget); - if (!fb->rootWidget()) - fb->setRootWidget(w); - return w; } @@ -369,9 +369,10 @@ QWidget *QFormBuilder::create(DomUI *ui, QWidget *parentWidget) */ QLayout *QFormBuilder::create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget) { + QFormBuilderExtra *fb = QFormBuilderExtra::instance(this); // Is this a temporary layout widget used to represent QLayout hierarchies in Designer? // Set its margins to 0. - bool layoutWidget = QFormBuilderExtra::instance(this)->processingLayoutWidget(); + bool layoutWidget = fb->processingLayoutWidget(); QLayout *l = QAbstractFormBuilder::create(ui_layout, layout, parentWidget); if (layoutWidget) { const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); @@ -392,7 +393,7 @@ QLayout *QFormBuilder::create(DomLayout *ui_layout, QLayout *layout, QWidget *pa bottom = prop->elementNumber(); l->setContentsMargins(left, top, right, bottom); - QFormBuilderExtra::instance(this)->setProcessingLayoutWidget(false); + fb->setProcessingLayoutWidget(false); } return l; } @@ -525,6 +526,7 @@ QList<QDesignerCustomWidgetInterface*> QFormBuilder::customWidgets() const /*! \internal */ + void QFormBuilder::applyProperties(QObject *o, const QList<DomProperty*> &properties) { typedef QList<DomProperty*> DomPropertyList; @@ -542,11 +544,12 @@ void QFormBuilder::applyProperties(QObject *o, const QList<DomProperty*> &proper continue; const QString attributeName = (*it)->attributeName(); - if (o == fb->rootWidget() && attributeName == strings.geometryProperty) { - // apply only the size for the rootWidget - fb->rootWidget()->resize(qvariant_cast<QRect>(v).size()); + const bool isWidget = o->isWidgetType(); + if (isWidget && o->parent() == fb->parentWidget() && attributeName == strings.geometryProperty) { + // apply only the size part of a geometry for the root widget + static_cast<QWidget*>(o)->resize(qvariant_cast<QRect>(v).size()); } else if (fb->applyPropertyInternally(o, attributeName, v)) { - } else if (!qstrcmp("QFrame", o->metaObject()->className ()) && attributeName == strings.orientationProperty) { + } else if (isWidget && !qstrcmp("QFrame", o->metaObject()->className ()) && attributeName == strings.orientationProperty) { // ### special-casing for Line (QFrame) -- try to fix me o->setProperty("frameShape", v); // v is of QFrame::Shape enum } else { diff --git a/tools/designer/src/lib/uilib/formbuilderextra.cpp b/tools/designer/src/lib/uilib/formbuilderextra.cpp index 87491b7..c07d253 100644 --- a/tools/designer/src/lib/uilib/formbuilderextra.cpp +++ b/tools/designer/src/lib/uilib/formbuilderextra.cpp @@ -81,7 +81,8 @@ QFormBuilderExtra::~QFormBuilderExtra() void QFormBuilderExtra::clear() { m_buddies.clear(); - m_rootWidget = 0; + m_parentWidget = 0; + m_parentWidgetIsSet = false; #ifndef QT_FORMBUILDER_NO_SCRIPT m_FormScriptRunner.clearErrors(); m_customWidgetScriptHash.clear(); @@ -136,14 +137,21 @@ bool QFormBuilderExtra::applyBuddy(const QString &buddyName, BuddyMode applyMode return false; } -const QPointer<QWidget> &QFormBuilderExtra::rootWidget() const +const QPointer<QWidget> &QFormBuilderExtra::parentWidget() const { - return m_rootWidget; + return m_parentWidget; } -void QFormBuilderExtra::setRootWidget(const QPointer<QWidget> &w) +bool QFormBuilderExtra::parentWidgetIsSet() const { - m_rootWidget = w; + return m_parentWidgetIsSet; +} + +void QFormBuilderExtra::setParentWidget(const QPointer<QWidget> &w) +{ + // Parent widget requires special handling of the geometry property. + m_parentWidget = w; + m_parentWidgetIsSet = true; } #ifndef QT_FORMBUILDER_NO_SCRIPT diff --git a/tools/designer/src/lib/uilib/formbuilderextra_p.h b/tools/designer/src/lib/uilib/formbuilderextra_p.h index ec06050..418c70c 100644 --- a/tools/designer/src/lib/uilib/formbuilderextra_p.h +++ b/tools/designer/src/lib/uilib/formbuilderextra_p.h @@ -101,8 +101,9 @@ public: void applyInternalProperties() const; static bool applyBuddy(const QString &buddyName, BuddyMode applyMode, QLabel *label); - const QPointer<QWidget> &rootWidget() const; - void setRootWidget(const QPointer<QWidget> &w); + const QPointer<QWidget> &parentWidget() const; + bool parentWidgetIsSet() const; + void setParentWidget(const QPointer<QWidget> &w); #ifndef QT_FORMBUILDER_NO_SCRIPT QFormScriptRunner &formScriptRunner(); @@ -182,7 +183,8 @@ private: QResourceBuilder *m_resourceBuilder; QTextBuilder *m_textBuilder; - QPointer<QWidget> m_rootWidget; + QPointer<QWidget> m_parentWidget; + bool m_parentWidgetIsSet; }; void uiLibWarning(const QString &message); diff --git a/tools/designer/src/lib/uilib/ui4.cpp b/tools/designer/src/lib/uilib/ui4.cpp index 7faee24..1578155 100644 --- a/tools/designer/src/lib/uilib/ui4.cpp +++ b/tools/designer/src/lib/uilib/ui4.cpp @@ -2368,6 +2368,7 @@ void DomCustomWidget::clear(bool clear_all) delete m_script; delete m_properties; delete m_slots; + delete m_propertyspecifications; if (clear_all) { m_text.clear(); @@ -2381,6 +2382,7 @@ void DomCustomWidget::clear(bool clear_all) m_script = 0; m_properties = 0; m_slots = 0; + m_propertyspecifications = 0; } DomCustomWidget::DomCustomWidget() @@ -2393,6 +2395,7 @@ DomCustomWidget::DomCustomWidget() m_script = 0; m_properties = 0; m_slots = 0; + m_propertyspecifications = 0; } DomCustomWidget::~DomCustomWidget() @@ -2403,6 +2406,7 @@ DomCustomWidget::~DomCustomWidget() delete m_script; delete m_properties; delete m_slots; + delete m_propertyspecifications; } void DomCustomWidget::read(QXmlStreamReader &reader) @@ -2468,6 +2472,12 @@ void DomCustomWidget::read(QXmlStreamReader &reader) setElementSlots(v); continue; } + if (tag == QLatin1String("propertyspecifications")) { + DomPropertySpecifications *v = new DomPropertySpecifications(); + v->read(reader); + setElementPropertyspecifications(v); + continue; + } reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -2548,6 +2558,12 @@ void DomCustomWidget::read(const QDomElement &node) setElementSlots(v); continue; } + if (tag == QLatin1String("propertyspecifications")) { + DomPropertySpecifications *v = new DomPropertySpecifications(); + v->read(e); + setElementPropertyspecifications(v); + continue; + } } m_text.clear(); for (QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) { @@ -2605,6 +2621,10 @@ void DomCustomWidget::write(QXmlStreamWriter &writer, const QString &tagName) co m_slots->write(writer, QLatin1String("slots")); } + if (m_children & Propertyspecifications) { + m_propertyspecifications->write(writer, QLatin1String("propertyspecifications")); + } + if (!m_text.isEmpty()) writer.writeCharacters(m_text); @@ -2731,6 +2751,21 @@ void DomCustomWidget::setElementSlots(DomSlots* a) m_slots = a; } +DomPropertySpecifications* DomCustomWidget::takeElementPropertyspecifications() +{ + DomPropertySpecifications* a = m_propertyspecifications; + m_propertyspecifications = 0; + m_children ^= Propertyspecifications; + return a; +} + +void DomCustomWidget::setElementPropertyspecifications(DomPropertySpecifications* a) +{ + delete m_propertyspecifications; + m_children |= Propertyspecifications; + m_propertyspecifications = a; +} + void DomCustomWidget::clearElementClass() { m_children &= ~Class; @@ -2798,6 +2833,13 @@ void DomCustomWidget::clearElementSlots() m_children &= ~Slots; } +void DomCustomWidget::clearElementPropertyspecifications() +{ + delete m_propertyspecifications; + m_propertyspecifications = 0; + m_children &= ~Propertyspecifications; +} + void DomProperties::clear(bool clear_all) { qDeleteAll(m_property); @@ -10883,5 +10925,208 @@ void DomSlots::setElementSlot(const QStringList& a) m_slot = a; } +void DomPropertySpecifications::clear(bool clear_all) +{ + qDeleteAll(m_stringpropertyspecification); + m_stringpropertyspecification.clear(); + + if (clear_all) { + m_text.clear(); + } + + m_children = 0; +} + +DomPropertySpecifications::DomPropertySpecifications() +{ + m_children = 0; +} + +DomPropertySpecifications::~DomPropertySpecifications() +{ + qDeleteAll(m_stringpropertyspecification); + m_stringpropertyspecification.clear(); +} + +void DomPropertySpecifications::read(QXmlStreamReader &reader) +{ + + for (bool finished = false; !finished && !reader.hasError();) { + switch (reader.readNext()) { + case QXmlStreamReader::StartElement : { + const QString tag = reader.name().toString().toLower(); + if (tag == QLatin1String("stringpropertyspecification")) { + DomStringPropertySpecification *v = new DomStringPropertySpecification(); + v->read(reader); + m_stringpropertyspecification.append(v); + continue; + } + reader.raiseError(QLatin1String("Unexpected element ") + tag); + } + break; + case QXmlStreamReader::EndElement : + finished = true; + break; + case QXmlStreamReader::Characters : + if (!reader.isWhitespace()) + m_text.append(reader.text().toString()); + break; + default : + break; + } + } +} + +#ifdef QUILOADER_QDOM_READ +void DomPropertySpecifications::read(const QDomElement &node) +{ + for (QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling()) { + if (!n.isElement()) + continue; + QDomElement e = n.toElement(); + QString tag = e.tagName().toLower(); + if (tag == QLatin1String("stringpropertyspecification")) { + DomStringPropertySpecification *v = new DomStringPropertySpecification(); + v->read(e); + m_stringpropertyspecification.append(v); + continue; + } + } + m_text.clear(); + for (QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) { + if (child.isText()) + m_text.append(child.nodeValue()); + } +} +#endif + +void DomPropertySpecifications::write(QXmlStreamWriter &writer, const QString &tagName) const +{ + writer.writeStartElement(tagName.isEmpty() ? QString::fromUtf8("propertyspecifications") : tagName.toLower()); + + for (int i = 0; i < m_stringpropertyspecification.size(); ++i) { + DomStringPropertySpecification* v = m_stringpropertyspecification[i]; + v->write(writer, QLatin1String("stringpropertyspecification")); + } + if (!m_text.isEmpty()) + writer.writeCharacters(m_text); + + writer.writeEndElement(); +} + +void DomPropertySpecifications::setElementStringpropertyspecification(const QList<DomStringPropertySpecification*>& a) +{ + m_children |= Stringpropertyspecification; + m_stringpropertyspecification = a; +} + +void DomStringPropertySpecification::clear(bool clear_all) +{ + + if (clear_all) { + m_text.clear(); + m_has_attr_name = false; + m_has_attr_type = false; + m_has_attr_notr = false; + } + + m_children = 0; +} + +DomStringPropertySpecification::DomStringPropertySpecification() +{ + m_children = 0; + m_has_attr_name = false; + m_has_attr_type = false; + m_has_attr_notr = false; +} + +DomStringPropertySpecification::~DomStringPropertySpecification() +{ +} + +void DomStringPropertySpecification::read(QXmlStreamReader &reader) +{ + + foreach (const QXmlStreamAttribute &attribute, reader.attributes()) { + QStringRef name = attribute.name(); + if (name == QLatin1String("name")) { + setAttributeName(attribute.value().toString()); + continue; + } + if (name == QLatin1String("type")) { + setAttributeType(attribute.value().toString()); + continue; + } + if (name == QLatin1String("notr")) { + setAttributeNotr(attribute.value().toString()); + continue; + } + reader.raiseError(QLatin1String("Unexpected attribute ") + name.toString()); + } + + for (bool finished = false; !finished && !reader.hasError();) { + switch (reader.readNext()) { + case QXmlStreamReader::StartElement : { + const QString tag = reader.name().toString().toLower(); + reader.raiseError(QLatin1String("Unexpected element ") + tag); + } + break; + case QXmlStreamReader::EndElement : + finished = true; + break; + case QXmlStreamReader::Characters : + if (!reader.isWhitespace()) + m_text.append(reader.text().toString()); + break; + default : + break; + } + } +} + +#ifdef QUILOADER_QDOM_READ +void DomStringPropertySpecification::read(const QDomElement &node) +{ + if (node.hasAttribute(QLatin1String("name"))) + setAttributeName(node.attribute(QLatin1String("name"))); + if (node.hasAttribute(QLatin1String("type"))) + setAttributeType(node.attribute(QLatin1String("type"))); + if (node.hasAttribute(QLatin1String("notr"))) + setAttributeNotr(node.attribute(QLatin1String("notr"))); + + for (QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling()) { + if (!n.isElement()) + continue; + QDomElement e = n.toElement(); + QString tag = e.tagName().toLower(); + } + m_text.clear(); + for (QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) { + if (child.isText()) + m_text.append(child.nodeValue()); + } +} +#endif + +void DomStringPropertySpecification::write(QXmlStreamWriter &writer, const QString &tagName) const +{ + writer.writeStartElement(tagName.isEmpty() ? QString::fromUtf8("stringpropertyspecification") : tagName.toLower()); + + if (hasAttributeName()) + writer.writeAttribute(QLatin1String("name"), attributeName()); + + if (hasAttributeType()) + writer.writeAttribute(QLatin1String("type"), attributeType()); + + if (hasAttributeNotr()) + writer.writeAttribute(QLatin1String("notr"), attributeNotr()); + + if (!m_text.isEmpty()) + writer.writeCharacters(m_text); + + writer.writeEndElement(); +} + QT_END_NAMESPACE diff --git a/tools/designer/src/lib/uilib/ui4_p.h b/tools/designer/src/lib/uilib/ui4_p.h index 505c61b..3c53d13 100644 --- a/tools/designer/src/lib/uilib/ui4_p.h +++ b/tools/designer/src/lib/uilib/ui4_p.h @@ -161,6 +161,8 @@ class DomScript; class DomWidgetData; class DomDesignerData; class DomSlots; +class DomPropertySpecifications; +class DomStringPropertySpecification; /******************************************************************************* ** Declarations @@ -1015,6 +1017,12 @@ public: inline bool hasElementSlots() const { return m_children & Slots; } void clearElementSlots(); + inline DomPropertySpecifications* elementPropertyspecifications() const { return m_propertyspecifications; } + DomPropertySpecifications* takeElementPropertyspecifications(); + void setElementPropertyspecifications(DomPropertySpecifications* a); + inline bool hasElementPropertyspecifications() const { return m_children & Propertyspecifications; } + void clearElementPropertyspecifications(); + private: QString m_text; void clear(bool clear_all = true); @@ -1033,6 +1041,7 @@ private: DomScript* m_script; DomProperties* m_properties; DomSlots* m_slots; + DomPropertySpecifications* m_propertyspecifications; enum Child { Class = 1, Extends = 2, @@ -1044,7 +1053,8 @@ private: Pixmap = 128, Script = 256, Properties = 512, - Slots = 1024 + Slots = 1024, + Propertyspecifications = 2048 }; DomCustomWidget(const DomCustomWidget &other); @@ -3686,6 +3696,91 @@ private: void operator = (const DomSlots&other); }; +class QDESIGNER_UILIB_EXPORT DomPropertySpecifications { +public: + DomPropertySpecifications(); + ~DomPropertySpecifications(); + + void read(QXmlStreamReader &reader); +#ifdef QUILOADER_QDOM_READ + void read(const QDomElement &node); +#endif + void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; + inline QString text() const { return m_text; } + inline void setText(const QString &s) { m_text = s; } + + // attribute accessors + // child element accessors + inline QList<DomStringPropertySpecification*> elementStringpropertyspecification() const { return m_stringpropertyspecification; } + void setElementStringpropertyspecification(const QList<DomStringPropertySpecification*>& a); + +private: + QString m_text; + void clear(bool clear_all = true); + + // attribute data + // child element data + uint m_children; + QList<DomStringPropertySpecification*> m_stringpropertyspecification; + enum Child { + Stringpropertyspecification = 1 + }; + + DomPropertySpecifications(const DomPropertySpecifications &other); + void operator = (const DomPropertySpecifications&other); +}; + +class QDESIGNER_UILIB_EXPORT DomStringPropertySpecification { +public: + DomStringPropertySpecification(); + ~DomStringPropertySpecification(); + + void read(QXmlStreamReader &reader); +#ifdef QUILOADER_QDOM_READ + void read(const QDomElement &node); +#endif + void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; + inline QString text() const { return m_text; } + inline void setText(const QString &s) { m_text = s; } + + // attribute accessors + inline bool hasAttributeName() const { return m_has_attr_name; } + inline QString attributeName() const { return m_attr_name; } + inline void setAttributeName(const QString& a) { m_attr_name = a; m_has_attr_name = true; } + inline void clearAttributeName() { m_has_attr_name = false; } + + inline bool hasAttributeType() const { return m_has_attr_type; } + inline QString attributeType() const { return m_attr_type; } + inline void setAttributeType(const QString& a) { m_attr_type = a; m_has_attr_type = true; } + inline void clearAttributeType() { m_has_attr_type = false; } + + inline bool hasAttributeNotr() const { return m_has_attr_notr; } + inline QString attributeNotr() const { return m_attr_notr; } + inline void setAttributeNotr(const QString& a) { m_attr_notr = a; m_has_attr_notr = true; } + inline void clearAttributeNotr() { m_has_attr_notr = false; } + + // child element accessors +private: + QString m_text; + void clear(bool clear_all = true); + + // attribute data + QString m_attr_name; + bool m_has_attr_name; + + QString m_attr_type; + bool m_has_attr_type; + + QString m_attr_notr; + bool m_has_attr_notr; + + // child element data + uint m_children; + + DomStringPropertySpecification(const DomStringPropertySpecification &other); + void operator = (const DomStringPropertySpecification&other); +}; + #ifdef QFORMINTERNAL_NAMESPACE } diff --git a/tools/designer/src/plugins/activeqt/qaxwidgettaskmenu.cpp b/tools/designer/src/plugins/activeqt/qaxwidgettaskmenu.cpp index 1158e35..1cbf1c1 100644 --- a/tools/designer/src/plugins/activeqt/qaxwidgettaskmenu.cpp +++ b/tools/designer/src/plugins/activeqt/qaxwidgettaskmenu.cpp @@ -162,7 +162,7 @@ void QAxWidgetTaskMenu::setActiveXControl() tr("The control requires a design-time license")); clsid = QUuid(); } else { - key = QString::fromUtf16((ushort *)bKey); + key = QString::fromWCharArray(bKey); } cf2->Release(); diff --git a/tools/designer/src/uitools/quiloader.cpp b/tools/designer/src/uitools/quiloader.cpp index 48e142b..1c7d1cc 100644 --- a/tools/designer/src/uitools/quiloader.cpp +++ b/tools/designer/src/uitools/quiloader.cpp @@ -574,20 +574,20 @@ void QUiLoaderPrivate::setupWidgetMap() const \brief The QUiLoader class enables standalone applications to dynamically create user interfaces at run-time using the - information stored in .ui files or specified in plugin paths. + information stored in UI files or specified in plugin paths. In addition, you can customize or create your own user interface by deriving your own loader class. If you have a custom component or an application that embeds \QD, you can also use the QFormBuilder class provided by the QtDesigner module to create - user interfaces from \c{.ui} files. + user interfaces from UI files. The QUiLoader class provides a collection of functions allowing you to - create widgets based on the information stored in \c .ui files (created + create widgets based on the information stored in UI files (created with \QD) or available in the specified plugin paths. The specified plugin paths can be retrieved using the pluginPaths() function. Similarly, the - contents of a \c{.ui} file can be retrieved using the load() function. For + contents of a UI file can be retrieved using the load() function. For example: \snippet doc/src/snippets/quiloader/mywidget.cpp 0 @@ -613,8 +613,7 @@ void QUiLoaderPrivate::setupWidgetMap() const reason, you can subclass the QUiLoader class and reimplement these functions to intervene the process of constructing a user interface. For example, you might want to have a list of the actions created when loading - a form or creating a custom widget. However, in your reimplementation, you - must call QUiLoader's original implementation of these functions first. + a form or creating a custom widget. For a complete example using the QUiLoader class, see the \l{Calculator Builder Example}. diff --git a/tools/kmap2qmap/kmap2qmap.pro b/tools/kmap2qmap/kmap2qmap.pro new file mode 100644 index 0000000..cc8200b --- /dev/null +++ b/tools/kmap2qmap/kmap2qmap.pro @@ -0,0 +1,12 @@ + +TEMPLATE = app +DESTDIR = ../../bin +QT = core +CONFIG += console +CONFIG -= app_bundle + +DEPENDPATH += $$QT_SOURCE_TREE/src/gui/embedded +INCLUDEPATH += $$QT_SOURCE_TREE/src/gui/embedded + +# Input +SOURCES += main.cpp diff --git a/tools/kmap2qmap/main.cpp b/tools/kmap2qmap/main.cpp new file mode 100644 index 0000000..b438a05 --- /dev/null +++ b/tools/kmap2qmap/main.cpp @@ -0,0 +1,991 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <cstdio> + +#include <QFile> +#include <QFileInfo> +#include <QDir> +#include <QTextCodec> +#include <QList> +#include <QVector> +#include <QByteArray> +#include <QStringList> +#include <QTextStream> + +#include "qkbd_qws_p.h" + +using namespace std; + + +struct modifier_map_t { + const char *symbol; + quint8 modifier; + quint32 qtmodifier; +}; + +static const struct modifier_map_t modifier_map[] = { + { "plain", QWSKeyboard::ModPlain, Qt::NoModifier }, + { "shift", QWSKeyboard::ModShift, Qt::ShiftModifier }, + { "altgr", QWSKeyboard::ModAltGr, Qt::AltModifier }, + { "control", QWSKeyboard::ModControl, Qt::ControlModifier }, + { "alt", QWSKeyboard::ModAlt, Qt::AltModifier }, + { "meta", QWSKeyboard::ModAlt, Qt::AltModifier }, + { "shiftl", QWSKeyboard::ModShiftL, Qt::ShiftModifier }, + { "shiftr", QWSKeyboard::ModShiftR, Qt::ShiftModifier }, + { "ctrll", QWSKeyboard::ModCtrlL, Qt::ControlModifier }, + { "ctrlr", QWSKeyboard::ModCtrlR, Qt::ControlModifier }, +}; + +static const int modifier_map_size = sizeof(modifier_map)/sizeof(modifier_map_t); + + +struct symbol_map_t { + const char *symbol; + quint32 qtcode; +}; + +static const struct symbol_map_t symbol_map[] = { + { "space", Qt::Key_Space }, + { "exclam", Qt::Key_Exclam }, + { "quotedbl", Qt::Key_QuoteDbl }, + { "numbersign", Qt::Key_NumberSign }, + { "dollar", Qt::Key_Dollar }, + { "percent", Qt::Key_Percent }, + { "ampersand", Qt::Key_Ampersand }, + { "apostrophe", Qt::Key_Apostrophe }, + { "parenleft", Qt::Key_ParenLeft }, + { "parenright", Qt::Key_ParenRight }, + { "asterisk", Qt::Key_Asterisk }, + { "plus", Qt::Key_Plus }, + { "comma", Qt::Key_Comma }, + { "minus", Qt::Key_Minus }, + { "period", Qt::Key_Period }, + { "slash", Qt::Key_Slash }, + { "zero", Qt::Key_0 }, + { "one", Qt::Key_1 }, + { "two", Qt::Key_2 }, + { "three", Qt::Key_3 }, + { "four", Qt::Key_4 }, + { "five", Qt::Key_5 }, + { "six", Qt::Key_6 }, + { "seven", Qt::Key_7 }, + { "eight", Qt::Key_8 }, + { "nine", Qt::Key_9 }, + { "colon", Qt::Key_Colon }, + { "semicolon", Qt::Key_Semicolon }, + { "less", Qt::Key_Less }, + { "equal", Qt::Key_Equal }, + { "greater", Qt::Key_Greater }, + { "question", Qt::Key_Question }, + { "at", Qt::Key_At }, + { "bracketleft", Qt::Key_BracketLeft }, + { "backslash", Qt::Key_Backslash }, + { "bracketright", Qt::Key_BracketRight }, + { "asciicircum", Qt::Key_AsciiCircum }, + { "underscore", Qt::Key_Underscore }, + { "grave", Qt::Key_QuoteLeft }, + { "braceleft", Qt::Key_BraceLeft }, + { "bar", Qt::Key_Bar }, + { "braceright", Qt::Key_BraceRight }, + { "asciitilde", Qt::Key_AsciiTilde }, + { "nobreakspace", Qt::Key_nobreakspace }, + { "exclamdown", Qt::Key_exclamdown }, + { "cent", Qt::Key_cent }, + { "sterling", Qt::Key_sterling }, + { "currency", Qt::Key_currency }, + { "yen", Qt::Key_yen }, + { "brokenbar", Qt::Key_brokenbar }, + { "section", Qt::Key_section }, + { "diaeresis", Qt::Key_diaeresis }, + { "copyright", Qt::Key_copyright }, + { "ordfeminine", Qt::Key_ordfeminine }, + { "guillemotleft", Qt::Key_guillemotleft }, + { "notsign", Qt::Key_notsign }, + { "hyphen", Qt::Key_hyphen }, + { "registered", Qt::Key_registered }, + { "macron", Qt::Key_macron }, + { "degree", Qt::Key_degree }, + { "plusminus", Qt::Key_plusminus }, + { "twosuperior", Qt::Key_twosuperior }, + { "threesuperior", Qt::Key_threesuperior }, + { "acute", Qt::Key_acute }, + { "mu", Qt::Key_mu }, + { "paragraph", Qt::Key_paragraph }, + { "periodcentered", Qt::Key_periodcentered }, + { "cedilla", Qt::Key_cedilla }, + { "onesuperior", Qt::Key_onesuperior }, + { "masculine", Qt::Key_masculine }, + { "guillemotright", Qt::Key_guillemotright }, + { "onequarter", Qt::Key_onequarter }, + { "onehalf", Qt::Key_onehalf }, + { "threequarters", Qt::Key_threequarters }, + { "questiondown", Qt::Key_questiondown }, + { "Agrave", Qt::Key_Agrave }, + { "Aacute", Qt::Key_Aacute }, + { "Acircumflex", Qt::Key_Acircumflex }, + { "Atilde", Qt::Key_Atilde }, + { "Adiaeresis", Qt::Key_Adiaeresis }, + { "Aring", Qt::Key_Aring }, + { "AE", Qt::Key_AE }, + { "Ccedilla", Qt::Key_Ccedilla }, + { "Egrave", Qt::Key_Egrave }, + { "Eacute", Qt::Key_Eacute }, + { "Ecircumflex", Qt::Key_Ecircumflex }, + { "Ediaeresis", Qt::Key_Ediaeresis }, + { "Igrave", Qt::Key_Igrave }, + { "Iacute", Qt::Key_Iacute }, + { "Icircumflex", Qt::Key_Icircumflex }, + { "Idiaeresis", Qt::Key_Idiaeresis }, + { "ETH", Qt::Key_ETH }, + { "Ntilde", Qt::Key_Ntilde }, + { "Ograve", Qt::Key_Ograve }, + { "Oacute", Qt::Key_Oacute }, + { "Ocircumflex", Qt::Key_Ocircumflex }, + { "Otilde", Qt::Key_Otilde }, + { "Odiaeresis", Qt::Key_Odiaeresis }, + { "multiply", Qt::Key_multiply }, + { "Ooblique", Qt::Key_Ooblique }, + { "Ugrave", Qt::Key_Ugrave }, + { "Uacute", Qt::Key_Uacute }, + { "Ucircumflex", Qt::Key_Ucircumflex }, + { "Udiaeresis", Qt::Key_Udiaeresis }, + { "Yacute", Qt::Key_Yacute }, + { "THORN", Qt::Key_THORN }, + { "ssharp", Qt::Key_ssharp }, + + { "agrave", 0xe0 /*Qt::Key_agrave*/ }, + { "aacute", 0xe1 /*Qt::Key_aacute*/ }, + { "acircumflex", 0xe2 /*Qt::Key_acircumflex*/ }, + { "atilde", 0xe3 /*Qt::Key_atilde*/ }, + { "adiaeresis", 0xe4 /*Qt::Key_adiaeresis*/ }, + { "aring", 0xe5 /*Qt::Key_aring*/ }, + { "ae", 0xe6 /*Qt::Key_ae*/ }, + { "ccedilla", 0xe7 /*Qt::Key_ccedilla*/ }, + { "egrave", 0xe8 /*Qt::Key_egrave*/ }, + { "eacute", 0xe9 /*Qt::Key_eacute*/ }, + { "ecircumflex", 0xea /*Qt::Key_ecircumflex*/ }, + { "ediaeresis", 0xeb /*Qt::Key_ediaeresis*/ }, + { "igrave", 0xec /*Qt::Key_igrave*/ }, + { "iacute", 0xed /*Qt::Key_iacute*/ }, + { "icircumflex", 0xee /*Qt::Key_icircumflex*/ }, + { "idiaeresis", 0xef /*Qt::Key_idiaeresis*/ }, + { "eth", 0xf0 /*Qt::Key_eth*/ }, + { "ntilde", 0xf1 /*Qt::Key_ntilde*/ }, + { "ograve", 0xf2 /*Qt::Key_ograve*/ }, + { "oacute", 0xf3 /*Qt::Key_oacute*/ }, + { "ocircumflex", 0xf4 /*Qt::Key_ocircumflex*/ }, + { "otilde", 0xf5 /*Qt::Key_otilde*/ }, + { "odiaeresis", 0xf6 /*Qt::Key_odiaeresis*/ }, + { "division", Qt::Key_division }, + { "oslash", 0xf8 /*Qt::Key_oslash*/ }, + { "ugrave", 0xf9 /*Qt::Key_ugrave*/ }, + { "uacute", 0xfa /*Qt::Key_uacute*/ }, + { "ucircumflex", 0xfb /*Qt::Key_ucircumflex*/ }, + { "udiaeresis", 0xfc /*Qt::Key_udiaeresis*/ }, + { "yacute", 0xfd /*Qt::Key_yacute*/ }, + { "thorn", 0xfe /*Qt::Key_thorn*/ }, + { "ydiaeresis", Qt::Key_ydiaeresis }, + + { "F1", Qt::Key_F1 }, + { "F2", Qt::Key_F2 }, + { "F3", Qt::Key_F3 }, + { "F4", Qt::Key_F4 }, + { "F5", Qt::Key_F5 }, + { "F6", Qt::Key_F6 }, + { "F7", Qt::Key_F7 }, + { "F8", Qt::Key_F8 }, + { "F9", Qt::Key_F9 }, + { "F10", Qt::Key_F10 }, + { "F11", Qt::Key_F11 }, + { "F12", Qt::Key_F12 }, + { "F13", Qt::Key_F13 }, + { "F14", Qt::Key_F14 }, + { "F15", Qt::Key_F15 }, + { "F16", Qt::Key_F16 }, + { "F17", Qt::Key_F17 }, + { "F18", Qt::Key_F18 }, + { "F19", Qt::Key_F19 }, + { "F20", Qt::Key_F20 }, + { "F21", Qt::Key_F21 }, + { "F22", Qt::Key_F22 }, + { "F23", Qt::Key_F23 }, + { "F24", Qt::Key_F24 }, + { "F25", Qt::Key_F25 }, + { "F26", Qt::Key_F26 }, + { "F27", Qt::Key_F27 }, + { "F28", Qt::Key_F28 }, + { "F29", Qt::Key_F29 }, + { "F30", Qt::Key_F30 }, + { "F31", Qt::Key_F31 }, + { "F32", Qt::Key_F32 }, + { "F33", Qt::Key_F33 }, + { "F34", Qt::Key_F34 }, + { "F35", Qt::Key_F35 }, + + { "BackSpace", Qt::Key_Backspace }, + { "Tab", Qt::Key_Tab }, + { "Escape", Qt::Key_Escape }, + { "Delete", Qt::Key_Backspace }, // what's the difference between "Delete" and "BackSpace"?? + { "Return", Qt::Key_Return }, + { "Break", Qt::Key_unknown }, //TODO: why doesn't Qt support the 'Break' key? + { "Caps_Lock", Qt::Key_CapsLock }, + { "Num_Lock", Qt::Key_NumLock }, + { "Scroll_Lock", Qt::Key_ScrollLock }, + { "Caps_On", Qt::Key_CapsLock }, + { "Compose", Qt::Key_Multi_key }, + { "Bare_Num_Lock", Qt::Key_NumLock }, + { "Find", Qt::Key_Home }, + { "Insert", Qt::Key_Insert }, + { "Remove", Qt::Key_Delete }, + { "Select", Qt::Key_End }, + { "Prior", Qt::Key_PageUp }, + { "Next", Qt::Key_PageDown }, + { "Help", Qt::Key_Help }, + { "Pause", Qt::Key_Pause }, + + { "KP_0", Qt::Key_0 | Qt::KeypadModifier }, + { "KP_1", Qt::Key_1 | Qt::KeypadModifier }, + { "KP_2", Qt::Key_2 | Qt::KeypadModifier }, + { "KP_3", Qt::Key_3 | Qt::KeypadModifier }, + { "KP_4", Qt::Key_4 | Qt::KeypadModifier }, + { "KP_5", Qt::Key_5 | Qt::KeypadModifier }, + { "KP_6", Qt::Key_6 | Qt::KeypadModifier }, + { "KP_7", Qt::Key_7 | Qt::KeypadModifier }, + { "KP_8", Qt::Key_8 | Qt::KeypadModifier }, + { "KP_9", Qt::Key_9 | Qt::KeypadModifier }, + { "KP_Add", Qt::Key_Plus | Qt::KeypadModifier }, + { "KP_Subtract", Qt::Key_Minus | Qt::KeypadModifier }, + { "KP_Multiply", Qt::Key_Asterisk | Qt::KeypadModifier }, + { "KP_Divide", Qt::Key_Slash | Qt::KeypadModifier }, + { "KP_Enter", Qt::Key_Enter | Qt::KeypadModifier }, + { "KP_Comma", Qt::Key_Comma | Qt::KeypadModifier }, + { "KP_Period", Qt::Key_Period | Qt::KeypadModifier }, + { "KP_MinPlus", Qt::Key_plusminus | Qt::KeypadModifier }, + + { "dead_grave", Qt::Key_Dead_Grave }, + { "dead_acute", Qt::Key_Dead_Acute }, + { "dead_circumflex", Qt::Key_Dead_Circumflex }, + { "dead_tilde", Qt::Key_Dead_Tilde }, + { "dead_diaeresis", Qt::Key_Dead_Diaeresis }, + { "dead_cedilla", Qt::Key_Dead_Cedilla }, + + { "Down", Qt::Key_Down }, + { "Left", Qt::Key_Left }, + { "Right", Qt::Key_Right }, + { "Up", Qt::Key_Up }, + { "Shift", Qt::Key_Shift }, + { "AltGr", Qt::Key_AltGr }, + { "Control", Qt::Key_Control }, + { "Alt", Qt::Key_Alt }, + { "ShiftL", Qt::Key_Shift }, + { "ShiftR", Qt::Key_Shift }, + { "CtrlL", Qt::Key_Control }, + { "CtrlR", Qt::Key_Control }, +}; + +static const int symbol_map_size = sizeof(symbol_map)/sizeof(symbol_map_t); + + +struct symbol_dead_unicode_t { + quint32 dead; + quint16 unicode; +}; + +static const symbol_dead_unicode_t symbol_dead_unicode[] = { + { Qt::Key_Dead_Grave, '`' }, + { Qt::Key_Dead_Acute, '\'' }, + { Qt::Key_Dead_Circumflex, '^' }, + { Qt::Key_Dead_Tilde, '~' }, + { Qt::Key_Dead_Diaeresis, '"' }, + { Qt::Key_Dead_Cedilla, ',' }, +}; + +static const int symbol_dead_unicode_size = sizeof(symbol_dead_unicode)/sizeof(symbol_dead_unicode_t); + + +struct symbol_synonyms_t { + const char *from; + const char *to; +}; + +static const symbol_synonyms_t symbol_synonyms[] = { + { "Control_h", "BackSpace" }, + { "Control_i", "Tab" }, + { "Control_j", "Linefeed" }, + { "Home", "Find" }, + { "End", "Select" }, + { "PageUp", "Prior" }, + { "PageDown", "Next" }, + { "multiplication", "multiply" }, + { "pound", "sterling" }, + { "pilcrow", "paragraph" }, + { "Oslash", "Ooblique" }, + { "Shift_L", "ShiftL" }, + { "Shift_R", "ShiftR" }, + { "Control_L", "CtrlL" }, + { "Control_R", "CtrlR" }, + { "AltL", "Alt" }, + { "AltR", "AltGr" }, + { "Alt_L", "Alt" }, + { "Alt_R", "AltGr" }, + { "AltGr_L", "Alt" }, + { "AltGr_R", "AltGr" }, + { "tilde", "asciitilde" }, + { "circumflex", "asciicircum" }, + { "dead_ogonek", "dead_cedilla" }, + { "dead_caron", "dead_circumflex" }, + { "dead_breve", "dead_tilde" }, + { "dead_doubleacute", "dead_tilde" }, + { "no-break_space", "nobreakspace" }, + { "paragraph_sign", "section" }, + { "soft_hyphen", "hyphen" }, + { "rightanglequote", "guillemotright" }, +}; + +static const int symbol_synonyms_size = sizeof(symbol_synonyms)/sizeof(symbol_synonyms_t); + +// makes the generated array in --header mode a bit more human readable +QT_BEGIN_NAMESPACE +static bool operator<(const QWSKeyboard::Mapping &m1, const QWSKeyboard::Mapping &m2) +{ + return m1.keycode != m2.keycode ? m1.keycode < m2.keycode : m1.modifiers < m2.modifiers; +} +QT_END_NAMESPACE + +class KeymapParser { +public: + KeymapParser(); + ~KeymapParser(); + + bool parseKmap(QFile *kmap); + bool generateQmap(QFile *qmap); + bool generateHeader(QFile *qmap); + + int parseWarningCount() const { return m_warning_count; } + +private: + bool parseSymbol(const QByteArray &str, const QTextCodec *codec, quint16 &unicode, quint32 &qtcode, quint8 &flags, quint16 &special); + bool parseCompose(const QByteArray &str, const QTextCodec *codec, quint16 &unicode); + bool parseModifier(const QByteArray &str, quint8 &modifier); + + void updateMapping(quint16 keycode = 0, quint8 modifiers = 0, quint16 unicode = 0xffff, quint32 qtcode = Qt::Key_unknown, quint8 flags = 0, quint16 = 0); + + static quint32 toQtModifiers(quint8 modifiers); + static QList<QByteArray> tokenize(const QByteArray &line); + + +private: + QList<QWSKeyboard::Mapping> m_keymap; + QList<QWSKeyboard::Composing> m_keycompose; + + int m_warning_count; +}; + + + +int main(int argc, char **argv) +{ + int header = 0; + if (argc >= 2 && !qstrcmp(argv[1], "--header")) + header = 1; + + if (argc < (3 + header)) { + fprintf(stderr, "Usage: kmap2qmap [--header] <kmap> [<additional kmaps> ...] <qmap>\n"); + fprintf(stderr, " --header can be used to generate Qt's default compiled in qmap.\n"); + return 1; + } + + QVector<QFile *> kmaps(argc - header - 2); + for (int i = 0; i < kmaps.size(); ++i) { + kmaps [i] = new QFile(QString::fromLocal8Bit(argv[i + 1 + header])); + + if (!kmaps[i]->open(QIODevice::ReadOnly)) { + fprintf(stderr, "Could not read from '%s'.\n", argv[i + 1 + header]); + return 2; + } + } + QFile *qmap = new QFile(QString::fromLocal8Bit(argv[argc - 1])); + + if (!qmap->open(QIODevice::WriteOnly)) { + fprintf(stderr, "Could not write to '%s'.\n", argv[argc - 1]); + return 3; + } + + KeymapParser p; + + for (int i = 0; i < kmaps.size(); ++i) { + if (!p.parseKmap(kmaps[i])) { + fprintf(stderr, "Parsing kmap '%s' failed.\n", qPrintable(kmaps[i]->fileName())); + return 4; + } + } + + if (p.parseWarningCount()) { + fprintf(stderr, "\nParsing the specified keymap(s) produced %d warning(s).\n" \ + "Your generated qmap might not be complete.\n", \ + p.parseWarningCount()); + } + if (!(header ? p.generateHeader(qmap) : p.generateQmap(qmap))) { + fprintf(stderr, "Generating the qmap failed.\n"); + return 5; + } + + qDeleteAll(kmaps); + delete qmap; + + return 0; +} + + +KeymapParser::KeymapParser() + : m_warning_count(0) +{ } + + +KeymapParser::~KeymapParser() +{ } + + +bool KeymapParser::generateHeader(QFile *f) +{ + QTextStream ts(f); + + ts << "#ifndef QWSKEYBOARDHANDLER_DEFAULTMAP_H" << endl; + ts << "#define QWSKEYBOARDHANDLER_DEFAULTMAP_H" << endl << endl; + + ts << "const QWSKeyboard::Mapping QWSKbPrivate::s_keymap_default[] = {" << endl; + + for (int i = 0; i < m_keymap.size(); ++i) { + const QWSKeyboard::Mapping &m = m_keymap.at(i); + QString s; + s.sprintf(" { %3d, 0x%04x, 0x%08x, 0x%02x, 0x%02x, 0x%04x },\n", m.keycode, m.unicode, m.qtcode, m.modifiers, m.flags, m.special); + ts << s; + } + + ts << "};" << endl << endl; + + ts << "const QWSKeyboard::Composing QWSKbPrivate::s_keycompose_default[] = {" << endl; + + for (int i = 0; i < m_keycompose.size(); ++i) { + const QWSKeyboard::Composing &c = m_keycompose.at(i); + QString s; + s.sprintf(" { 0x%04x, 0x%04x, 0x%04x },\n", c.first, c.second, c.result); + ts << s; + } + ts << "};" << endl << endl; + + ts << "#endif" << endl; + + return (ts.status() == QTextStream::Ok); +} + + +bool KeymapParser::generateQmap(QFile *f) +{ + QDataStream ds(f); + + ds << quint32(QWSKeyboard::FileMagic) << quint32(1 /* version */) << quint32(m_keymap.size()) << quint32(m_keycompose.size()); + + if (ds.status() != QDataStream::Ok) + return false; + + for (int i = 0; i < m_keymap.size(); ++i) + ds << m_keymap[i]; + + for (int i = 0; i < m_keycompose.size(); ++i) + ds << m_keycompose[i]; + + return (ds.status() == QDataStream::Ok); +} + + +QList<QByteArray> KeymapParser::tokenize(const QByteArray &line) +{ + bool quoted = false, separator = true; + QList<QByteArray> result; + QByteArray token; + + for (int i = 0; i < line.length(); ++i) { + QChar c = line.at(i); + + if (!quoted && c == '#' && separator) + break; + else if (!quoted && c == '"' && separator) + quoted = true; + else if (quoted && c == '"') + quoted = false; + else if (!quoted && c.isSpace()) { + separator = true; + if (!token.isEmpty()) { + result.append(token); + token.truncate(0); + } + } + else { + separator = false; + token.append(c); + } + } + if (!token.isEmpty()) + result.append(token); + return result; +} + + +#define parseWarning(s) do { qWarning("Warning: keymap file '%s', line %d: %s", qPrintable(f->fileName()), lineno, s); ++m_warning_count; } while (false) + +bool KeymapParser::parseKmap(QFile *f) +{ + QByteArray line; + int lineno = 0; + QList<int> keymaps; + QTextCodec *codec = QTextCodec::codecForName("iso8859-1"); + + for (int i = 0; i <= 256; ++i) + keymaps << i; + + while (!f->atEnd() && !f->error()) { + line = f->readLine(); + lineno++; + + QList<QByteArray> tokens = tokenize(line); + + if (tokens.isEmpty()) + continue; + + if (tokens[0] == "keymaps") { + keymaps.clear(); + + if (tokens.count() > 1) { + foreach (const QByteArray §ion, tokens[1].split(',')) { + int dashpos = section.indexOf('-'); + + //qWarning("Section %s", section.constData()); + int end = section.mid(dashpos + 1).toInt(); + int start = end; + if (dashpos > 0) + start = section.left(dashpos).toInt(); + + if (start <= end && start >=0 && end <= 256) { + for (int i = start; i <= end; ++i) { + //qWarning("appending keymap %d", i); + keymaps.append(i); + } + } + else + parseWarning("keymaps has an invalid range"); + } + qSort(keymaps); + } + else + parseWarning("keymaps with more than one argument"); + } + else if (tokens[0] == "alt_is_meta") { + // simply ignore it for now + } + else if (tokens[0] == "include") { + if (tokens.count() == 2) { + QString incname = QString::fromLocal8Bit(tokens[1]); + bool found = false; + QList<QDir> searchpath; + QFileInfo fi(*f); + + if (!incname.endsWith(QLatin1String(".kmap")) && !incname.endsWith(QLatin1String(".inc"))) + incname.append(QLatin1String(".inc")); + + QDir d = fi.dir(); + searchpath << d; + if (d.cdUp() && d.cd(QLatin1String("include"))) + searchpath << d; + searchpath << QDir::current(); + + foreach (const QDir &path, searchpath) { + QFile f2(path.filePath(incname)); + //qWarning(" -- trying to include %s", qPrintable(f2.fileName())); + if (f2.open(QIODevice::ReadOnly)) { + if (!parseKmap(&f2)) + parseWarning("could not parse keymap include"); + found = true; + } + } + + if (!found) + parseWarning("could not locate keymap include"); + } else + parseWarning("include doesn't have exactly one argument"); + } + else if (tokens[0] == "charset") { + if (tokens.count() == 2) { + codec = QTextCodec::codecForName(tokens[1]); + if (!codec) { + parseWarning("could not parse codec definition"); + codec = QTextCodec::codecForName("iso8859-1"); + } + } else + parseWarning("codec doesn't habe exactly one argument"); + } + else if (tokens[0] == "strings") { + // simply ignore those - they have no meaning for QWS + } + else if (tokens[0] == "compose") { + if (tokens.count() == 5 && tokens[3] == "to") { + QWSKeyboard::Composing c = { 0xffff, 0xffff, 0xffff }; + + if (!parseCompose(tokens[1], codec, c.first)) + parseWarning("could not parse first compose symbol"); + if (!parseCompose(tokens[2], codec, c.second)) + parseWarning("could not parse second compose symbol"); + if (!parseCompose(tokens[4], codec, c.result)) + parseWarning("could not parse resulting compose symbol"); + + if (c.first != 0xffff && c.second != 0xffff && c.result != 0xffff) { + m_keycompose << c; + } + } else + parseWarning("non-standard compose line"); + } + else { + int kcpos = tokens.indexOf("keycode"); + + if (kcpos >= 0 && kcpos < (tokens.count()-3) && tokens[kcpos+2] == "=") { + quint16 keycode = tokens[kcpos+1].toInt(); + + if (keycode <= 0 || keycode > 0x1ff /* KEY_MAX */) { + parseWarning("keycode out of range [0..0x1ff]"); + break; + } + + bool line_modifiers = (kcpos > 0); + + quint8 modifiers = 0; //, modifiers_mask = 0xff; + for (int i = 0; i < kcpos; ++i) { + quint8 mod; + if (!parseModifier(tokens[i], mod)) { + parseWarning("unknown modifier prefix for keycode"); + continue; + } + modifiers |= mod; + } + + int kccount = tokens.count() - kcpos - 3; // 3 : 'keycode' 'X' '=' + + if (line_modifiers && kccount > 1) { + parseWarning("line has modifiers, but more than one keycode"); + break; + } + + // only process one symbol when a prefix modifer was specified + for (int i = 0; i < (line_modifiers ? 1 : kccount); ++i) { + if (!line_modifiers) + modifiers = keymaps[i]; + + quint32 qtcode; + quint16 unicode; + quint16 special; + quint8 flags; + if (!parseSymbol(tokens[i + kcpos + 3], codec, unicode, qtcode, flags, special)) { + parseWarning((QByteArray("symbol could not be parsed: ") + tokens[i + kcpos + 3]).constData()); + break; + } + + if (qtcode == Qt::Key_unknown && unicode == 0xffff) // VoidSymbol + continue; + + if (!line_modifiers && kccount == 1) { + if ((unicode >= 'A' && unicode <= 'Z') || (unicode >= 'a' && unicode <= 'z')) { + quint16 other_unicode = (unicode >= 'A' && unicode <= 'Z') ? unicode - 'A' + 'a' : unicode - 'a' + 'A'; + quint16 lower_unicode = (unicode >= 'A' && unicode <= 'Z') ? unicode - 'A' + 'a' : unicode; + + // a single a-z|A-Z value results in a very flags mapping: see below + + updateMapping(keycode, QWSKeyboard::ModPlain, unicode, qtcode, flags, 0); + + updateMapping(keycode, QWSKeyboard::ModShift, other_unicode, qtcode, flags, 0); + + updateMapping(keycode, QWSKeyboard::ModAltGr, unicode, qtcode, flags, 0); + updateMapping(keycode, QWSKeyboard::ModAltGr | QWSKeyboard::ModShift, other_unicode, qtcode, flags, 0); + + updateMapping(keycode, QWSKeyboard::ModControl, lower_unicode, qtcode | Qt::ControlModifier, flags, 0); + updateMapping(keycode, QWSKeyboard::ModControl | QWSKeyboard::ModShift, lower_unicode, qtcode | Qt::ControlModifier, flags, 0); + updateMapping(keycode, QWSKeyboard::ModControl | QWSKeyboard::ModAltGr, lower_unicode, qtcode | Qt::ControlModifier, flags, 0); + updateMapping(keycode, QWSKeyboard::ModControl | QWSKeyboard::ModAltGr | QWSKeyboard::ModShift, lower_unicode, qtcode | Qt::ControlModifier, flags, 0); + + updateMapping(keycode, QWSKeyboard::ModAlt, unicode, qtcode | Qt::AltModifier, flags, 0); + updateMapping(keycode, QWSKeyboard::ModAlt | QWSKeyboard::ModShift, unicode, qtcode | Qt::AltModifier, flags, 0); + updateMapping(keycode, QWSKeyboard::ModAlt | QWSKeyboard::ModAltGr, unicode, qtcode | Qt::AltModifier, flags, 0); + updateMapping(keycode, QWSKeyboard::ModAlt | QWSKeyboard::ModAltGr | QWSKeyboard::ModShift, unicode, qtcode | Qt::AltModifier, flags, 0); + + updateMapping(keycode, QWSKeyboard::ModAlt | QWSKeyboard::ModControl, lower_unicode, qtcode | Qt::ControlModifier | Qt::AltModifier, flags, 0); + updateMapping(keycode, QWSKeyboard::ModAlt | QWSKeyboard::ModControl | QWSKeyboard::ModShift, lower_unicode, qtcode | Qt::ControlModifier | Qt::AltModifier, flags, 0); + updateMapping(keycode, QWSKeyboard::ModAlt | QWSKeyboard::ModControl | QWSKeyboard::ModAltGr, lower_unicode, qtcode | Qt::ControlModifier | Qt::AltModifier, flags, 0); + updateMapping(keycode, QWSKeyboard::ModAlt | QWSKeyboard::ModControl | QWSKeyboard::ModAltGr | QWSKeyboard::ModShift, lower_unicode, qtcode | Qt::ControlModifier | Qt::AltModifier, flags, 0); + } + else { + // a single value results in that mapping regardless of the modifier + //for (int mod = 0; mod <= 255; ++mod) + // updateMapping(keycode, quint8(mod), unicode, qtcode | toQtModifiers(mod), flags, special); + + // we can save a lot of space in the qmap, since we do that anyway in the kbd handler: + updateMapping(keycode, QWSKeyboard::ModPlain, unicode, qtcode, flags, special); + } + } + else { + // "normal" mapping + updateMapping(keycode, modifiers, unicode, qtcode, flags, special); + } + } + } + } + } + qSort(m_keymap); + return !m_keymap.isEmpty(); +} + + + +void KeymapParser::updateMapping(quint16 keycode, quint8 modifiers, quint16 unicode, quint32 qtcode, quint8 flags, quint16 special) +{ + for (int i = 0; i < m_keymap.size(); ++i) { + QWSKeyboard::Mapping &m = m_keymap[i]; + + if (m.keycode == keycode && m.modifiers == modifiers) { + m.unicode = unicode; + m.qtcode = qtcode; + m.flags = flags; + m.special = special; + return; + } + } + QWSKeyboard::Mapping m = { keycode, unicode, qtcode, modifiers, flags, special }; + m_keymap << m; +} + + +quint32 KeymapParser::toQtModifiers(quint8 modifiers) +{ + quint32 qtmodifiers = Qt::NoModifier; + + for (int i = 0; i < modifier_map_size; ++i) { + if (modifiers & modifier_map[i].modifier) + qtmodifiers |= modifier_map[i].qtmodifier; + } + return qtmodifiers; +} + + +bool KeymapParser::parseModifier(const QByteArray &str, quint8 &modifier) +{ + QByteArray lstr = str.toLower(); + + for (int i = 0; i < modifier_map_size; ++i) { + if (lstr == modifier_map[i].symbol) { + modifier = modifier_map[i].modifier; + return true; + } + } + return false; +} + + +bool KeymapParser::parseCompose(const QByteArray &str, const QTextCodec *codec, quint16 &unicode) +{ + if (str == "'\\''") { + unicode = '\''; + return true; + } else if (str.length() == 3 && str.startsWith('\'') && str.endsWith('\'')) { + QString temp = codec->toUnicode(str.constData() + 1, str.length() - 2); + if (temp.length() != 1) + return false; + unicode = temp[0].unicode(); + return true; + } else { + quint32 code = str.toUInt(); + if (code > 255) + return false; + char c[2]; + c[0] = char(code); + c[1] = 0; + QString temp = codec->toUnicode(c); + if (temp.length() != 1) + return false; + unicode = temp[0].unicode(); + return true; + } +} + + +bool KeymapParser::parseSymbol(const QByteArray &str, const QTextCodec * /*codec*/, quint16 &unicode, quint32 &qtcode, quint8 &flags, quint16 &special) +{ + flags = (str[0] == '+') ? QWSKeyboard::IsLetter : 0; + QByteArray sym = (flags & QWSKeyboard::IsLetter) ? str.right(str.length() - 1) : str; + + special = 0; + qtcode = Qt::Key_unknown; + unicode = 0xffff; + + if (sym == "VoidSymbol" || sym == "nul") + return true; + + bool try_to_find_qtcode = false; + + if (sym[0] >= '0' && sym[0] <= '9') { // kernel internal action number + return false; + } else if (sym.length() == 6 && sym[1] == '+' && (sym[0] == 'U' || sym[0] == 'u')) { // unicode + bool ok; + unicode = sym.mid(2).toUInt(&ok, 16); + if (!ok) + return false; + try_to_find_qtcode = true; + } else { // symbolic + for (int i = 0; i < symbol_synonyms_size; ++i) { + if (sym == symbol_synonyms[i].from) { + sym = symbol_synonyms[i].to; + break; + } + } + + quint32 qtmod = 0; + + // parse prepended modifiers + forever { + int underpos = sym.indexOf('_'); + + if (underpos <= 0) + break; + QByteArray modsym = sym.left(underpos); + QByteArray nomodsym = sym.mid(underpos + 1); + quint8 modifier = 0; + + if (!parseModifier(modsym, modifier)) + break; + + qtmod |= toQtModifiers(modifier); + sym = nomodsym; + } + + if (qtcode == Qt::Key_unknown) { + quint8 modcode; + // check if symbol is a modifier + if (parseModifier(sym, modcode)) { + special = modcode; + flags |= QWSKeyboard::IsModifier; + } + + // map symbol to Qt key code + for (int i = 0; i < symbol_map_size; ++i) { + if (sym == symbol_map[i].symbol) { + qtcode = symbol_map[i].qtcode; + break; + } + } + + // a-zA-Z is not in the table to save space + if (qtcode == Qt::Key_unknown && sym.length() == 1) { + char letter = sym.at(0); + + if (letter >= 'a' && letter <= 'z') { + qtcode = Qt::Key_A + letter - 'a'; + unicode = letter; + } + else if (letter >= 'A' && letter <= 'Z') { + qtcode = Qt::Key_A + letter - 'A'; + unicode = letter; + } + } + // System keys + if (qtcode == Qt::Key_unknown) { + quint16 sys = 0; + + if (sym == "Decr_Console") { + sys = QWSKeyboard::SystemConsolePrevious; + } else if (sym == "Incr_Console") { + sys = QWSKeyboard::SystemConsoleNext; + } else if (sym.startsWith("Console_")) { + int console = sym.mid(8).toInt() - 1; + if (console >= 0 && console <= (QWSKeyboard::SystemConsoleLast - QWSKeyboard::SystemConsoleFirst)) { + sys = QWSKeyboard::SystemConsoleFirst + console; + } + } else if (sym == "Boot") { + sys = QWSKeyboard::SystemReboot; + } else if (sym == "QtZap") { + sys = QWSKeyboard::SystemZap; + } + + if (sys) { + flags |= QWSKeyboard::IsSystem; + special = sys; + qtcode = Qt::Key_Escape; // just a dummy + } + } + + // map Qt key codes in the iso-8859-1 range to unicode + if (qtcode != Qt::Key_unknown && unicode == 0xffff) { + quint32 qtcode_no_mod = qtcode & ~(Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier | Qt::KeypadModifier); + if (qtcode_no_mod <= 0x000000ff) // iso-8859-1 + unicode = quint16(qtcode_no_mod); + } + + // flag dead keys + if (qtcode >= Qt::Key_Dead_Grave && qtcode <= Qt::Key_Dead_Horn) { + flags = QWSKeyboard::IsDead; + + for (int i = 0; i < symbol_dead_unicode_size; ++i) { + if (symbol_dead_unicode[i].dead == qtcode) { + unicode = symbol_dead_unicode[i].unicode; + break; + } + } + } + } + if ((qtcode == Qt::Key_unknown) && (unicode == 0xffff)) + return false; + + qtcode |= qtmod; + } + + // map unicode in the iso-8859-1 range to Qt key codes + if (unicode >= 0x0020 && unicode <= 0x00ff && qtcode == Qt::Key_unknown) + qtcode = unicode; // iso-8859-1 + + return true; +} + diff --git a/tools/linguist/lconvert/main.cpp b/tools/linguist/lconvert/main.cpp index fe8d529..1381595 100644 --- a/tools/linguist/lconvert/main.cpp +++ b/tools/linguist/lconvert/main.cpp @@ -51,21 +51,16 @@ static int usage(const QStringList &args) Q_UNUSED(args); QString loaders; - QString savers; - QString line = QString(QLatin1String(" %1 - %2\n")); - foreach (Translator::FileFormat format, Translator::registeredFileFormats()) { + QString line(QLatin1String(" %1 - %2\n")); + foreach (Translator::FileFormat format, Translator::registeredFileFormats()) loaders += line.arg(format.extension, -5).arg(format.description); - if (format.fileType != Translator::FileFormat::SourceCode) - savers += line.arg(format.extension, -5).arg(format.description); - } qWarning("%s", qPrintable(QString(QLatin1String("\nUsage:\n" " lconvert [options] <infile> [<infile>...]\n\n" "lconvert is part of Qt's Linguist tool chain. It can be used as a\n" - "stand-alone tool to convert translation data files from one of the\n" - "following input formats\n\n%1\n" - "to one of the following output formats\n\n%2\n" - "If multiple input files are specified the translations are merged with\n" + "stand-alone tool to convert and filter translation data files.\n" + "The following file formats are supported:\n\n%1\n" + "If multiple input files are specified, they are merged with\n" "translations from later files taking precedence.\n\n" "Options:\n" " -h\n" @@ -86,20 +81,20 @@ static int usage(const QStringList &args) " --output-format <outformat>\n" " Specify output format. See -if.\n\n" " --input-codec <codec>\n" - " Specify encoding for .qm and .po input files. Default is 'Latin1'\n" - " for .qm and 'UTF-8' for .po files. UTF-8 is always tried as well for\n" - " .qm, corresponding to the possible use of the trUtf8() function.\n\n" + " Specify encoding for QM and PO input files. Default is 'Latin1'\n" + " for QM and 'UTF-8' for PO files. UTF-8 is always tried as well for\n" + " QM, corresponding to the possible use of the trUtf8() function.\n\n" " --output-codec <codec>\n" - " Specify encoding for .po output files. Default is 'UTF-8'.\n\n" + " Specify encoding for PO output files. Default is 'UTF-8'.\n\n" " --drop-tags <regexp>\n" - " Drop named extra tags when writing 'ts' or 'xlf' files.\n" + " Drop named extra tags when writing TS or XLIFF files.\n" " May be specified repeatedly.\n\n" " --drop-translations\n" " Drop existing translations and reset the status to 'unfinished'.\n" " Note: this implies --no-obsolete.\n\n" " --source-language <language>[_<region>]\n" " Specify/override the language of the source strings. Defaults to\n" - " POSIX if not specified and the file does not name it yet.\n" + " POSIX if not specified and the file does not name it yet.\n\n" " --target-language <language>[_<region>]\n" " Specify/override the language of the translation.\n" " The target language is guessed from the file name if this option\n" @@ -108,6 +103,11 @@ static int usage(const QStringList &args) " Drop obsolete messages.\n\n" " --no-finished\n" " Drop finished messages.\n\n" + " --locations {absolute|relative|none}\n" + " Override how source code references are saved in TS files.\n" + " Default is absolute.\n\n" + " --no-ui-lines\n" + " Drop line numbers from references to UI files.\n\n" " --verbose\n" " be a bit more verbose\n\n" "Long options can be specified with only one leading dash, too.\n\n" @@ -115,7 +115,7 @@ static int usage(const QStringList &args) " 0 on success\n" " 1 on command line parse failures\n" " 2 on read failures\n" - " 3 on write failures\n")).arg(loaders).arg(savers))); + " 3 on write failures\n")).arg(loaders))); return 1; } @@ -140,6 +140,8 @@ int main(int argc, char *argv[]) bool noObsolete = false; bool noFinished = false; bool verbose = false; + bool noUiLines = false; + Translator::LocationsType locations = Translator::DefaultLocations; ConversionData cd; Translator tr; @@ -199,6 +201,19 @@ int main(int argc, char *argv[]) noObsolete = true; } else if (args[i] == QLatin1String("-no-finished")) { noFinished = true; + } else if (args[i] == QLatin1String("-locations")) { + if (++i >= args.size()) + return usage(args); + if (args[i] == QLatin1String("none")) + locations = Translator::NoLocations; + else if (args[i] == QLatin1String("relative")) + locations = Translator::RelativeLocations; + else if (args[i] == QLatin1String("absolute")) + locations = Translator::AbsoluteLocations; + else + return usage(args); + } else if (args[i] == QLatin1String("-no-ui-lines")) { + noUiLines = true; } else if (args[i] == QLatin1String("-verbose")) { verbose = true; } else if (args[i].startsWith(QLatin1Char('-'))) { @@ -243,6 +258,10 @@ int main(int argc, char *argv[]) tr.stripFinishedMessages(); if (dropTranslations) tr.dropTranslations(); + if (noUiLines) + tr.dropUiLines(); + if (locations != Translator::DefaultLocations) + tr.setLocationsType(locations); tr.normalizeTranslations(cd); if (!cd.errors().isEmpty()) { diff --git a/tools/linguist/linguist/batchtranslation.ui b/tools/linguist/linguist/batchtranslation.ui index 88b55e2..0f7fe4b 100644 --- a/tools/linguist/linguist/batchtranslation.ui +++ b/tools/linguist/linguist/batchtranslation.ui @@ -104,7 +104,7 @@ <item> <widget class="QCheckBox" name="ckTranslateFinished"> <property name="toolTip"> - <string>Note that the modified entries will be reset to unfinished if 'Set translated entries to finished' above is unchecked.</string> + <string>Note that the modified entries will be reset to unfinished if 'Set translated entries to finished' above is unchecked</string> </property> <property name="text"> <string>Translate also finished entries</string> @@ -189,7 +189,7 @@ <item> <widget class="QLabel" name="label"> <property name="text"> - <string>The batch translator will search through the selected phrase books in the order given above.</string> + <string>The batch translator will search through the selected phrase books in the order given above</string> </property> <property name="wordWrap"> <bool>true</bool> diff --git a/tools/linguist/linguist/globals.cpp b/tools/linguist/linguist/globals.cpp new file mode 100644 index 0000000..03062ba --- /dev/null +++ b/tools/linguist/linguist/globals.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Linguist 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "globals.h" + +const QString &settingsPrefix() +{ + static QString prefix = QString(QLatin1String("%1.%2/")) + .arg((QT_VERSION >> 16) & 0xff) + .arg((QT_VERSION >> 8) & 0xff); + return prefix; +} + +QString settingPath(const char *path) +{ + return settingsPrefix() + QLatin1String(path); +} diff --git a/tools/linguist/linguist/globals.h b/tools/linguist/linguist/globals.h new file mode 100644 index 0000000..b4bfb9c --- /dev/null +++ b/tools/linguist/linguist/globals.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Linguist 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GLOBALS_H +#define GLOBALS_H + +#include <QString> + +const QString &settingsPrefix(); +QString settingPath(const char *path); + +#endif // GLOBALS_H diff --git a/tools/linguist/linguist/images/minus.png b/tools/linguist/linguist/images/minus.png Binary files differnew file mode 100644 index 0000000..745b445 --- /dev/null +++ b/tools/linguist/linguist/images/minus.png diff --git a/tools/linguist/linguist/images/plus.png b/tools/linguist/linguist/images/plus.png Binary files differnew file mode 100644 index 0000000..ef43788 --- /dev/null +++ b/tools/linguist/linguist/images/plus.png diff --git a/tools/linguist/linguist/linguist.pro b/tools/linguist/linguist/linguist.pro index 9f16ced..890b252 100644 --- a/tools/linguist/linguist/linguist.pro +++ b/tools/linguist/linguist/linguist.pro @@ -26,6 +26,7 @@ SOURCES += \ errorsview.cpp \ finddialog.cpp \ formpreviewview.cpp \ + globals.cpp \ main.cpp \ mainwindow.cpp \ messageeditor.cpp \ @@ -49,6 +50,7 @@ HEADERS += \ errorsview.h \ finddialog.h \ formpreviewview.h \ + globals.h \ mainwindow.h \ messageeditor.h \ messageeditorwidgets.h \ diff --git a/tools/linguist/linguist/linguist.qrc b/tools/linguist/linguist/linguist.qrc index 42cf6e3..a43f0ce 100644 --- a/tools/linguist/linguist/linguist.qrc +++ b/tools/linguist/linguist/linguist.qrc @@ -32,6 +32,8 @@ <file>images/up.png</file> <file>images/down.png</file> <file>images/editdelete.png</file> + <file>images/minus.png</file> + <file>images/plus.png</file> <file>images/win/accelerator.png</file> <file>images/win/book.png</file> <file>images/win/doneandnext.png</file> diff --git a/tools/linguist/linguist/linguist.rc b/tools/linguist/linguist/linguist.rc index 865e021..5ff37ca 100644 --- a/tools/linguist/linguist/linguist.rc +++ b/tools/linguist/linguist/linguist.rc @@ -1 +1,32 @@ +#include "winver.h" + IDI_ICON1 ICON DISCARDABLE "linguist.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGS 0x0L + FILEFLAGSMASK 0x3fL + FILEOS 0x00040004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)" + VALUE "FileDescription", "Qt Linguist" + VALUE "FileVersion", "1.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)." + VALUE "InternalName", "linguist" + VALUE "OriginalFilename", "linguist.exe" + VALUE "ProductName", "Qt Linguist" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/tools/linguist/linguist/main.cpp b/tools/linguist/linguist/main.cpp index 865f0b7..e276ff1 100644 --- a/tools/linguist/linguist/main.cpp +++ b/tools/linguist/linguist/main.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "mainwindow.h" +#include "globals.h" #include <QtCore/QFile> #include <QtCore/QLibraryInfo> @@ -80,22 +81,23 @@ int main(int argc, char **argv) } QTranslator translator; - translator.load(QLatin1String("linguist_") + QLocale::system().name(), resourceDir); - app.installTranslator(&translator); - QTranslator qtTranslator; - qtTranslator.load(QLatin1String("qt_") + QLocale::system().name(), resourceDir); - app.installTranslator(&qtTranslator); + QString sysLocale = QLocale::system().name(); + if (translator.load(QLatin1String("linguist_") + sysLocale, resourceDir)) { + app.installTranslator(&translator); + if (qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir)) + app.installTranslator(&qtTranslator); + else + app.removeTranslator(&translator); + } app.setOrganizationName(QLatin1String("Trolltech")); app.setApplicationName(QLatin1String("Linguist")); - QString keybase(QString::number( (QT_VERSION >> 16) & 0xff ) + - QLatin1Char('.') + QString::number( (QT_VERSION >> 8) & 0xff ) + QLatin1Char('/') ); QSettings config; QWidget tmp; - tmp.restoreGeometry(config.value(keybase + QLatin1String("Geometry/WindowGeometry")).toByteArray()); + tmp.restoreGeometry(config.value(settingPath("Geometry/WindowGeometry")).toByteArray()); QSplashScreen *splash = 0; int screenId = QApplication::desktop()->screenNumber(tmp.geometry().center()); diff --git a/tools/linguist/linguist/mainwindow.cpp b/tools/linguist/linguist/mainwindow.cpp index a6ef7c7..bb79b19 100644 --- a/tools/linguist/linguist/mainwindow.cpp +++ b/tools/linguist/linguist/mainwindow.cpp @@ -50,6 +50,7 @@ #include "errorsview.h" #include "finddialog.h" #include "formpreviewview.h" +#include "globals.h" #include "messageeditor.h" #include "messagemodel.h" #include "phrasebookbox.h" @@ -81,6 +82,7 @@ #include <QMenuBar> #include <QMessageBox> #include <QPrintDialog> +#include <QPrinter> #include <QProcess> #include <QRegExp> #include <QSettings> @@ -96,14 +98,6 @@ QT_BEGIN_NAMESPACE static const int MessageMS = 2500; -const QString &settingsPrefix() -{ - static QString prefix = QString(QLatin1String("%1.%2/")) - .arg((QT_VERSION >> 16) & 0xff) - .arg((QT_VERSION >> 8) & 0xff); - return prefix; -} - enum Ending { End_None, End_FullStop, @@ -121,13 +115,12 @@ static bool hasFormPreview(const QString &fileName) static Ending ending(QString str, QLocale::Language lang) { str = str.simplified(); - int ch = 0; - if (!str.isEmpty()) - ch = str.right(1)[0].unicode(); + if (str.isEmpty()) + return End_None; - switch (ch) { + switch (str.at(str.length() - 1).unicode()) { case 0x002e: // full stop - if (str.endsWith(QString(QLatin1String("...")))) + if (str.endsWith(QLatin1String("..."))) return End_Ellipsis; else return End_FullStop; @@ -265,6 +258,7 @@ bool FocusWatcher::eventFilter(QObject *, QEvent *event) MainWindow::MainWindow() : QMainWindow(0, Qt::Window), m_assistantProcess(0), + m_printer(0), m_findMatchCase(Qt::CaseInsensitive), m_findIgnoreAccelerators(true), m_findWhere(DataModel::NoLocation), @@ -488,6 +482,10 @@ MainWindow::MainWindow() readConfig(); m_statistics = 0; + connect(m_ui.actionLenghtVariants, SIGNAL(toggled(bool)), + m_messageEditor, SLOT(setLenghtVariants(bool))); + m_messageEditor->setLenghtVariants(m_ui.actionLenghtVariants->isChecked()); + m_focusWatcher = new FocusWatcher(m_messageEditor, this); m_contextView->installEventFilter(m_focusWatcher); m_messageView->installEventFilter(m_focusWatcher); @@ -507,6 +505,7 @@ MainWindow::~MainWindow() qDeleteAll(m_phraseBooks); delete m_dataModel; delete m_statistics; + delete m_printer; } void MainWindow::modelCountChanged() @@ -874,15 +873,22 @@ void MainWindow::releaseAll() releaseInternal(i); } +QPrinter *MainWindow::printer() +{ + if (!m_printer) + m_printer = new QPrinter; + return m_printer; +} + void MainWindow::print() { int pageNum = 0; - QPrintDialog dlg(&m_printer, this); + QPrintDialog dlg(printer(), this); if (dlg.exec()) { QApplication::setOverrideCursor(Qt::WaitCursor); - m_printer.setDocName(m_dataModel->condensedSrcFileNames(true)); + printer()->setDocName(m_dataModel->condensedSrcFileNames(true)); statusBar()->showMessage(tr("Printing...")); - PrintOut pout(&m_printer); + PrintOut pout(printer()); for (int i = 0; i < m_dataModel->contextCount(); ++i) { MultiContextItem *mc = m_dataModel->multiContextItem(i); @@ -1233,11 +1239,11 @@ void MainWindow::printPhraseBook(QAction *action) int pageNum = 0; - QPrintDialog dlg(&m_printer, this); + QPrintDialog dlg(printer(), this); if (dlg.exec()) { - m_printer.setDocName(phraseBook->fileName()); + printer()->setDocName(phraseBook->fileName()); statusBar()->showMessage(tr("Printing...")); - PrintOut pout(&m_printer); + PrintOut pout(printer()); pout.setRule(PrintOut::ThinRule); foreach (const Phrase *p, phraseBook->phrases()) { pout.setGuide(p->source()); @@ -1342,17 +1348,13 @@ void MainWindow::about() QString version = tr("Version %1"); version = version.arg(QLatin1String(QT_VERSION_STR)); - // TODO: Remove this variable for 4.6.0. Must keep this way for 4.5.x due to string freeze. - QString edition; - box.setText(tr("<center><img src=\":/images/splash.png\"/></img><p>%1</p></center>" "<p>Qt Linguist is a tool for adding translations to Qt " "applications.</p>" - "<p>%2</p>" "<p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)." "</p><p>The program is provided AS IS with NO WARRANTY OF ANY KIND," " INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A" - " PARTICULAR PURPOSE.</p>").arg(version).arg(edition)); + " PARTICULAR PURPOSE.</p>").arg(version)); box.setWindowTitle(QApplication::translate("AboutDialog", "Qt Linguist")); box.setIcon(QMessageBox::NoIcon); @@ -2370,6 +2372,13 @@ void MainWindow::updateDanger(const MultiDataIndex &index, bool verbose) } QStringList translations = m->translations(); + // Truncated variants are permitted to be "denormalized" + for (int i = 0; i < translations.count(); ++i) { + int sep = translations.at(i).indexOf(QChar(Translator::BinaryVariantSeparator)); + if (sep >= 0) + translations[i].truncate(sep); + } + if (m_ui.actionAccelerators->isChecked()) { bool sk = !QKeySequence::mnemonic(source).isEmpty(); bool tk = true; @@ -2498,25 +2507,26 @@ void MainWindow::updateDanger(const MultiDataIndex &index, bool verbose) void MainWindow::readConfig() { - QString keybase = settingsPrefix(); QSettings config; QRect r(pos(), size()); - restoreGeometry(config.value(keybase + QLatin1String("Geometry/WindowGeometry")).toByteArray()); - restoreState(config.value(keybase + QLatin1String("MainWindowState")).toByteArray()); + restoreGeometry(config.value(settingPath("Geometry/WindowGeometry")).toByteArray()); + restoreState(config.value(settingPath("MainWindowState")).toByteArray()); m_ui.actionAccelerators->setChecked( - config.value(keybase + QLatin1String("Validators/Accelerator"), true).toBool()); + config.value(settingPath("Validators/Accelerator"), true).toBool()); m_ui.actionEndingPunctuation->setChecked( - config.value(keybase + QLatin1String("Validators/EndingPunctuation"), true).toBool()); + config.value(settingPath("Validators/EndingPunctuation"), true).toBool()); m_ui.actionPhraseMatches->setChecked( - config.value(keybase + QLatin1String("Validators/PhraseMatch"), true).toBool()); + config.value(settingPath("Validators/PhraseMatch"), true).toBool()); m_ui.actionPlaceMarkerMatches->setChecked( - config.value(keybase + QLatin1String("Validators/PlaceMarkers"), true).toBool()); + config.value(settingPath("Validators/PlaceMarkers"), true).toBool()); + m_ui.actionLenghtVariants->setChecked( + config.value(settingPath("Options/LengthVariants"), false).toBool()); recentFiles().readConfig(); - int size = config.beginReadArray(keybase + QLatin1String("OpenedPhraseBooks")); + int size = config.beginReadArray(settingPath("OpenedPhraseBooks")); for (int i = 0; i < size; ++i) { config.setArrayIndex(i); openPhraseBook(config.value(QLatin1String("FileName")).toString()); @@ -2526,23 +2536,24 @@ void MainWindow::readConfig() void MainWindow::writeConfig() { - QString keybase = settingsPrefix(); QSettings config; - config.setValue(keybase + QLatin1String("Geometry/WindowGeometry"), + config.setValue(settingPath("Geometry/WindowGeometry"), saveGeometry()); - config.setValue(keybase + QLatin1String("Validators/Accelerator"), + config.setValue(settingPath("Validators/Accelerator"), m_ui.actionAccelerators->isChecked()); - config.setValue(keybase + QLatin1String("Validators/EndingPunctuation"), + config.setValue(settingPath("Validators/EndingPunctuation"), m_ui.actionEndingPunctuation->isChecked()); - config.setValue(keybase + QLatin1String("Validators/PhraseMatch"), + config.setValue(settingPath("Validators/PhraseMatch"), m_ui.actionPhraseMatches->isChecked()); - config.setValue(keybase + QLatin1String("Validators/PlaceMarkers"), + config.setValue(settingPath("Validators/PlaceMarkers"), m_ui.actionPlaceMarkerMatches->isChecked()); - config.setValue(keybase + QLatin1String("MainWindowState"), + config.setValue(settingPath("Options/LengthVariants"), + m_ui.actionLenghtVariants->isChecked()); + config.setValue(settingPath("MainWindowState"), saveState()); recentFiles().writeConfig(); - config.beginWriteArray(keybase + QLatin1String("OpenedPhraseBooks"), + config.beginWriteArray(settingPath("OpenedPhraseBooks"), m_phraseBooks.size()); for (int i = 0; i < m_phraseBooks.size(); ++i) { config.setArrayIndex(i); diff --git a/tools/linguist/linguist/mainwindow.h b/tools/linguist/linguist/mainwindow.h index e7ec79b..3dedcb5 100644 --- a/tools/linguist/linguist/mainwindow.h +++ b/tools/linguist/linguist/mainwindow.h @@ -51,7 +51,6 @@ #include <QtCore/QLocale> #include <QtGui/QMainWindow> -#include <QtGui/QPrinter> QT_BEGIN_NAMESPACE @@ -60,6 +59,7 @@ class QAction; class QDialog; class QLabel; class QMenu; +class QPrinter; class QProcess; class QIcon; class QSortFilterProxyModel; @@ -79,8 +79,6 @@ class Statistics; class TranslateDialog; class TranslationSettingsDialog; -const QString &settingsPrefix(); - class MainWindow : public QMainWindow { Q_OBJECT @@ -202,6 +200,8 @@ private: void releaseInternal(int model); void saveInternal(int model); + QPrinter *printer(); + // FIXME: move to DataModel void updateDanger(const MultiDataIndex &index, bool verbose); @@ -228,7 +228,7 @@ private: QList<QHash<QString, QList<Phrase *> > > m_phraseDict; QList<PhraseBook *> m_phraseBooks; QMap<QAction *, PhraseBook *> m_phraseBookMenu[3]; - QPrinter m_printer; + QPrinter *m_printer; FindDialog *m_findDialog; QString m_findText; diff --git a/tools/linguist/linguist/mainwindow.ui b/tools/linguist/linguist/mainwindow.ui index 6d42db0..613241b 100644 --- a/tools/linguist/linguist/mainwindow.ui +++ b/tools/linguist/linguist/mainwindow.ui @@ -60,7 +60,7 @@ <x>0</x> <y>0</y> <width>673</width> - <height>30</height> + <height>28</height> </rect> </property> <widget class="QMenu" name="menuPhrases"> @@ -116,6 +116,7 @@ <addaction name="actionResetSorting"/> <addaction name="actionDisplayGuesses"/> <addaction name="actionStatistics"/> + <addaction name="actionLenghtVariants"/> <addaction name="separator"/> <addaction name="menuToolbars"/> <addaction name="menuViewViews"/> @@ -401,7 +402,7 @@ <string>&Prev Unfinished</string> </property> <property name="toolTip"> - <string>Previous unfinished item.</string> + <string>Previous unfinished item</string> </property> <property name="whatsThis"> <string>Move to the previous unfinished item.</string> @@ -418,7 +419,7 @@ <string>&Next Unfinished</string> </property> <property name="toolTip"> - <string>Next unfinished item.</string> + <string>Next unfinished item</string> </property> <property name="whatsThis"> <string>Move to the next unfinished item.</string> @@ -435,7 +436,7 @@ <string>P&rev</string> </property> <property name="toolTip"> - <string>Move to previous item.</string> + <string>Move to previous item</string> </property> <property name="whatsThis"> <string>Move to the previous item.</string> @@ -452,7 +453,7 @@ <string>Ne&xt</string> </property> <property name="toolTip"> - <string>Next item.</string> + <string>Next item</string> </property> <property name="whatsThis"> <string>Move to the next item.</string> @@ -472,7 +473,7 @@ <string>&Done and Next</string> </property> <property name="toolTip"> - <string>Mark item as done and move to the next unfinished item.</string> + <string>Mark item as done and move to the next unfinished item</string> </property> <property name="whatsThis"> <string>Mark this item as done and move to the next unfinished item.</string> @@ -492,7 +493,7 @@ <string>Copy from source text</string> </property> <property name="toolTip"> - <string>Copies the source text into the translation field.</string> + <string>Copies the source text into the translation field</string> </property> <property name="whatsThis"> <string>Copies the source text into the translation field.</string> @@ -512,7 +513,7 @@ <string>&Accelerators</string> </property> <property name="toolTip"> - <string>Toggle the validity check of accelerators.</string> + <string>Toggle the validity check of accelerators</string> </property> <property name="whatsThis"> <string>Toggle the validity check of accelerators, i.e. whether the number of ampersands in the source and translation text is the same. If the check fails, a message is shown in the warnings window.</string> @@ -529,7 +530,7 @@ <string>&Ending Punctuation</string> </property> <property name="toolTip"> - <string>Toggle the validity check of ending punctuation.</string> + <string>Toggle the validity check of ending punctuation</string> </property> <property name="whatsThis"> <string>Toggle the validity check of ending punctuation. If the check fails, a message is shown in the warnings window.</string> @@ -546,7 +547,7 @@ <string>&Phrase matches</string> </property> <property name="toolTip"> - <string>Toggle checking that phrase suggestions are used.</string> + <string>Toggle checking that phrase suggestions are used</string> </property> <property name="whatsThis"> <string>Toggle checking that phrase suggestions are used. If the check fails, a message is shown in the warnings window.</string> @@ -563,7 +564,7 @@ <string>Place &Marker Matches</string> </property> <property name="toolTip"> - <string>Toggle the validity check of place markers.</string> + <string>Toggle the validity check of place markers</string> </property> <property name="whatsThis"> <string>Toggle the validity check of place markers, i.e. whether %1, %2, ... are used consistently in the source text and translation text. If the check fails, a message is shown in the warnings window.</string> @@ -746,7 +747,7 @@ <string>Release As...</string> </property> <property name="whatsThis"> - <string>Create a Qt message file suitable for released applications from the current message file. The filename will automatically be determined from the name of the .ts file.</string> + <string>Create a Qt message file suitable for released applications from the current message file. The filename will automatically be determined from the name of the TS file.</string> </property> </action> <action name="actionFile"> @@ -877,6 +878,14 @@ <string>Ctrl+W</string> </property> </action> + <action name="actionLenghtVariants"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Lenght Variants</string> + </property> + </action> </widget> <resources/> <connections/> diff --git a/tools/linguist/linguist/messageeditor.cpp b/tools/linguist/linguist/messageeditor.cpp index 67fe651..9e598a8 100644 --- a/tools/linguist/linguist/messageeditor.cpp +++ b/tools/linguist/linguist/messageeditor.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -/* TRANSLATOR MsgEdit +/* TRANSLATOR MessageEditor This is the right panel of the main window. */ @@ -88,13 +88,13 @@ MessageEditor::MessageEditor(MultiDataModel *dataModel, QMainWindow *parent) m_dataModel(dataModel), m_currentModel(-1), m_currentNumerus(-1), + m_lengthVariants(false), m_undoAvail(false), m_redoAvail(false), m_cutAvail(false), m_copyAvail(false), - m_sourceSelected(false), - m_pluralSourceSelected(false), - m_currentSelected(false) + m_selectionHolder(0), + m_focusWidget(0) { setObjectName(QLatin1String("scroll area")); @@ -122,6 +122,9 @@ MessageEditor::MessageEditor(MultiDataModel *dataModel, QMainWindow *parent) connect(m_dataModel, SIGNAL(languageChanged(int)), SLOT(setTargetLanguage(int))); + m_tabOrderTimer.setSingleShot(true); + connect(&m_tabOrderTimer, SIGNAL(timeout()), SLOT(reallyFixTabOrder())); + clipboardChanged(); setWhatsThis(tr("This whole panel allows you to view and edit " @@ -145,12 +148,14 @@ void MessageEditor::setupEditorPage() m_source = new FormWidget(tr("Source text"), false); m_source->setHideWhenEmpty(true); m_source->setWhatsThis(tr("This area shows the source text.")); - connect(m_source, SIGNAL(selectionChanged()), SLOT(selectionChanged())); + connect(m_source, SIGNAL(selectionChanged(QTextEdit *)), + SLOT(selectionChanged(QTextEdit *))); m_pluralSource = new FormWidget(tr("Source text (Plural)"), false); m_pluralSource->setHideWhenEmpty(true); m_pluralSource->setWhatsThis(tr("This area shows the plural form of the source text.")); - connect(m_pluralSource, SIGNAL(selectionChanged()), SLOT(selectionChanged())); + connect(m_pluralSource, SIGNAL(selectionChanged(QTextEdit *)), + SLOT(selectionChanged(QTextEdit *))); m_commentText = new FormWidget(tr("Developer comments"), false); m_commentText->setHideWhenEmpty(true); @@ -217,10 +222,13 @@ void MessageEditor::messageModelAppended() ed.transCommentText->setWhatsThis(tr("Here you can enter comments for your own use." " They have no effect on the translated applications.") ); ed.transCommentText->getEditor()->installEventFilter(this); - connect(ed.transCommentText, SIGNAL(selectionChanged()), SLOT(selectionChanged())); - connect(ed.transCommentText, SIGNAL(textChanged()), SLOT(emitTranslatorCommentChanged())); - connect(ed.transCommentText, SIGNAL(textChanged()), SLOT(resetHoverSelection())); + connect(ed.transCommentText, SIGNAL(selectionChanged(QTextEdit *)), + SLOT(selectionChanged(QTextEdit *))); + connect(ed.transCommentText, SIGNAL(textChanged(QTextEdit *)), + SLOT(emitTranslatorCommentChanged(QTextEdit *))); + connect(ed.transCommentText, SIGNAL(textChanged(QTextEdit *)), SLOT(resetHoverSelection())); connect(ed.transCommentText, SIGNAL(cursorPositionChanged()), SLOT(resetHoverSelection())); + fixTabOrder(); QBoxLayout *box = new QVBoxLayout(ed.container); box->setMargin(5); box->addWidget(ed.transCommentText); @@ -251,7 +259,7 @@ void MessageEditor::messageModelDeleted(int model) if (m_currentModel >= 0) { if (m_currentNumerus >= m_editors[m_currentModel].transTexts.size()) m_currentNumerus = m_editors[m_currentModel].transTexts.size() - 1; - activeEditor()->getEditor()->setFocus(); + activeEditor()->setFocus(); } else { m_currentNumerus = -1; } @@ -266,26 +274,64 @@ void MessageEditor::messageModelDeleted(int model) void MessageEditor::addPluralForm(int model, const QString &label, bool writable) { - FormWidget *transEditor = new FormWidget(label, true); - QFont font; - font.setPointSize(static_cast<int>(m_editors[model].fontSize)); - transEditor->getEditor()->setFont(font); + FormMultiWidget *transEditor = new FormMultiWidget(label); + connect(transEditor, SIGNAL(editorCreated(QTextEdit *)), SLOT(editorCreated(QTextEdit *))); transEditor->setEditingEnabled(writable); transEditor->setHideWhenEmpty(!writable); if (!m_editors[model].transTexts.isEmpty()) transEditor->setVisible(false); + transEditor->setMultiEnabled(m_lengthVariants); static_cast<QBoxLayout *>(m_editors[model].container->layout())->insertWidget( m_editors[model].transTexts.count(), transEditor); - transEditor->getEditor()->installEventFilter(this); - connect(transEditor, SIGNAL(selectionChanged()), SLOT(selectionChanged())); - connect(transEditor, SIGNAL(textChanged()), SLOT(emitTranslationChanged())); - connect(transEditor, SIGNAL(textChanged()), SLOT(resetHoverSelection())); + connect(transEditor, SIGNAL(selectionChanged(QTextEdit *)), + SLOT(selectionChanged(QTextEdit *))); + connect(transEditor, SIGNAL(textChanged(QTextEdit *)), + SLOT(emitTranslationChanged(QTextEdit *))); + connect(transEditor, SIGNAL(textChanged(QTextEdit *)), SLOT(resetHoverSelection())); connect(transEditor, SIGNAL(cursorPositionChanged()), SLOT(resetHoverSelection())); m_editors[model].transTexts << transEditor; } +void MessageEditor::editorCreated(QTextEdit *te) +{ + FormMultiWidget *snd = static_cast<FormMultiWidget *>(sender()); + for (int model = 0; ; ++model) { + MessageEditorData med = m_editors.at(model); + if (med.transTexts.contains(snd)) { + QFont font; + font.setPointSize(static_cast<int>(med.fontSize)); + te->setFont(font); + + te->installEventFilter(this); + + fixTabOrder(); + return; + } + } +} + +void MessageEditor::fixTabOrder() +{ + m_tabOrderTimer.start(0); +} + +void MessageEditor::reallyFixTabOrder() +{ + QWidget *prev = this; + foreach (const MessageEditorData &med, m_editors) { + foreach (FormMultiWidget *fmw, med.transTexts) + foreach (QTextEdit *te, fmw->getEditors()) { + setTabOrder(prev, te); + prev = te; + } + QTextEdit *te = med.transCommentText->getEditor(); + setTabOrder(prev, te); + prev = te; + } +} + /*! internal Returns all translations for an item. The number of translations is dependent on if we have a plural form or not. @@ -301,69 +347,53 @@ QStringList MessageEditor::translations(int model) const return translations; } -static bool clearFormSelection(FormWidget *fw, FormWidget *te) +static void clearSelection(QTextEdit *t) { - if (fw != te) { - QTextEdit *t = fw->getEditor(); - bool oldBlockState = t->blockSignals(true); - QTextCursor c = t->textCursor(); - c.clearSelection(); - t->setTextCursor(c); - t->blockSignals(oldBlockState); - return true; - } - return false; + bool oldBlockState = t->blockSignals(true); + QTextCursor c = t->textCursor(); + c.clearSelection(); + t->setTextCursor(c); + t->blockSignals(oldBlockState); } -// Clear the selection for all textedits except the sender -void MessageEditor::selectionChanged() +void MessageEditor::selectionChanged(QTextEdit *te) { - if (!resetSelection(qobject_cast<FormWidget *>(sender()))) + if (te != m_selectionHolder) { + if (m_selectionHolder) + clearSelection(m_selectionHolder); + m_selectionHolder = (te->textCursor().hasSelection() ? te : 0); updateCanCutCopy(); + } } -bool MessageEditor::resetHoverSelection(FormWidget *fw) +void MessageEditor::resetHoverSelection() { - if (m_sourceSelected) { - if (clearFormSelection(m_source, fw)) { - updateCanCutCopy(); - return true; - } - } else if (m_pluralSourceSelected) { - if (clearFormSelection(m_pluralSource, fw)) { - updateCanCutCopy(); - return true; - } - } - return false; + if (m_selectionHolder && + (m_selectionHolder == m_source->getEditor() + || m_selectionHolder == m_pluralSource->getEditor())) + resetSelection(); } -bool MessageEditor::resetSelection(FormWidget *fw) +void MessageEditor::resetSelection() { - if (resetHoverSelection(fw)) - return true; - if (m_currentSelected) { - MessageEditorData &ed = m_editors[m_currentModel]; - FormWidget *cfw = (m_currentNumerus < 0) ? ed.transCommentText - : ed.transTexts[m_currentNumerus]; - if (clearFormSelection(cfw, fw)) { - updateCanCutCopy(); - return true; - } + if (m_selectionHolder) { + clearSelection(m_selectionHolder); + m_selectionHolder = 0; + updateCanCutCopy(); } - return false; } void MessageEditor::activeModelAndNumerus(int *model, int *numerus) const { for (int j = 0; j < m_editors.count(); ++j) { for (int i = 0; i < m_editors[j].transTexts.count(); ++i) - if (m_editors[j].transTexts[i]->getEditor()->hasFocus()) { - *model = j; - *numerus = i; - return; - } - if (m_editors[j].transCommentText->getEditor()->hasFocus()) { + foreach (QTextEdit *te, m_editors[j].transTexts[i]->getEditors()) + if (m_focusWidget == te) { + *model = j; + *numerus = i; + return; + } + if (m_focusWidget == m_editors[j].transCommentText->getEditor()) { *model = j; *numerus = -1; return; @@ -373,43 +403,46 @@ void MessageEditor::activeModelAndNumerus(int *model, int *numerus) const *numerus = -1; } -FormWidget *MessageEditor::activeTranslation() const +QTextEdit *MessageEditor::activeTranslation() const { if (m_currentNumerus < 0) return 0; - return m_editors[m_currentModel].transTexts[m_currentNumerus]; + foreach (QTextEdit *te, m_editors[m_currentModel].transTexts[m_currentNumerus]->getEditors()) + if (te->hasFocus()) + return te; + return 0; // This cannot happen } -FormWidget *MessageEditor::activeOr1stTranslation() const +QTextEdit *MessageEditor::activeOr1stTranslation() const { if (m_currentNumerus < 0) { for (int i = 0; i < m_editors.size(); ++i) if (m_editors[i].container->isVisible() - && !m_editors[i].transTexts[0]->getEditor()->isReadOnly()) - return m_editors[i].transTexts[0]; + && !m_editors[i].transTexts.first()->getEditors().first()->isReadOnly()) + return m_editors[i].transTexts.first()->getEditors().first(); return 0; } - return m_editors[m_currentModel].transTexts[m_currentNumerus]; + return activeTranslation(); } -FormWidget *MessageEditor::activeTransComment() const +QTextEdit *MessageEditor::activeTransComment() const { if (m_currentModel < 0 || m_currentNumerus >= 0) return 0; - return m_editors[m_currentModel].transCommentText; + return m_editors[m_currentModel].transCommentText->getEditor(); } -FormWidget *MessageEditor::activeEditor() const +QTextEdit *MessageEditor::activeEditor() const { - if (FormWidget *fw = activeTransComment()) - return fw; + if (QTextEdit *te = activeTransComment()) + return te; return activeTranslation(); } -FormWidget *MessageEditor::activeOr1stEditor() const +QTextEdit *MessageEditor::activeOr1stEditor() const { - if (FormWidget *fw = activeTransComment()) - return fw; + if (QTextEdit *te = activeTransComment()) + return te; return activeOr1stTranslation(); } @@ -417,25 +450,14 @@ void MessageEditor::setTargetLanguage(int model) { const QStringList &numerusForms = m_dataModel->model(model)->numerusForms(); const QString &langLocalized = m_dataModel->model(model)->localizedLanguage(); - bool added = false; for (int i = 0; i < numerusForms.count(); ++i) { const QString &label = tr("%1 translation (%2)").arg(langLocalized, numerusForms[i]); if (!i) m_editors[model].firstForm = label; - if (i >= m_editors[model].transTexts.count()) { + if (i >= m_editors[model].transTexts.count()) addPluralForm(model, label, m_dataModel->isModelWritable(model)); - QWidget *prev; - if (i > 0) - prev = m_editors[model].transTexts[i - 1]->getEditor(); - else if (model) - prev = m_editors[model - 1].transCommentText->getEditor(); - else - prev = this; - setTabOrder(prev, m_editors[model].transTexts[i]->getEditor()); - added = true; - } else { + else m_editors[model].transTexts[i]->setLabel(label); - } m_editors[model].transTexts[i]->setVisible(!i || m_editors[model].pluralEditMode); m_editors[model].transTexts[i]->setWhatsThis( tr("This is where you can enter or modify" @@ -445,16 +467,15 @@ void MessageEditor::setTargetLanguage(int model) delete m_editors[model].transTexts.takeLast(); m_editors[model].invariantForm = tr("%1 translation").arg(langLocalized); m_editors[model].transCommentText->setLabel(tr("%1 translator comments").arg(langLocalized)); - if (added) - setTabOrder(m_editors[model].transTexts.last()->getEditor(), m_editors[model].transCommentText->getEditor()); } MessageEditorData *MessageEditor::modelForWidget(const QObject *o) { for (int j = 0; j < m_editors.count(); ++j) { for (int i = 0; i < m_editors[j].transTexts.count(); ++i) - if (m_editors[j].transTexts[i]->getEditor() == o) - return &m_editors[j]; + foreach (QTextEdit *te, m_editors[j].transTexts[i]->getEditors()) + if (te == o) + return &m_editors[j]; if (m_editors[j].transCommentText->getEditor() == o) return &m_editors[j]; } @@ -466,7 +487,8 @@ static bool applyFont(MessageEditorData *med) QFont font; font.setPointSize(static_cast<int>(med->fontSize)); for (int i = 0; i < med->transTexts.count(); ++i) - med->transTexts[i]->getEditor()->setFont(font); + foreach (QTextEdit *te, med->transTexts[i]->getEditors()) + te->setFont(font); med->transCommentText->getEditor()->setFont(font); return true; } @@ -529,22 +551,39 @@ bool MessageEditor::eventFilter(QObject *o, QEvent *e) return decFont(modelForWidget(o)); } } else if (e->type() == QEvent::FocusIn) { - int model, numerus; - activeModelAndNumerus(&model, &numerus); - if (model != m_currentModel || numerus != m_currentNumerus) { - resetSelection(); - m_currentModel = model; - m_currentNumerus = numerus; - emit activeModelChanged(activeModel()); - updateBeginFromSource(); - updateUndoRedo(); - updateCanPaste(); - } + QWidget *widget = static_cast<QWidget *>(o); + if (widget != m_focusWidget) + trackFocus(widget); } return QScrollArea::eventFilter(o, e); } +void MessageEditor::grabFocus(QWidget *widget) +{ + if (widget != m_focusWidget) { + widget->setFocus(); + trackFocus(widget); + } +} + +void MessageEditor::trackFocus(QWidget *widget) +{ + m_focusWidget = widget; + + int model, numerus; + activeModelAndNumerus(&model, &numerus); + if (model != m_currentModel || numerus != m_currentNumerus) { + resetSelection(); + m_currentModel = model; + m_currentNumerus = numerus; + emit activeModelChanged(activeModel()); + updateBeginFromSource(); + updateUndoRedo(); + updateCanPaste(); + } +} + void MessageEditor::showNothing() { m_source->clearTranslation(); @@ -552,7 +591,7 @@ void MessageEditor::showNothing() m_commentText->clearTranslation(); for (int j = 0; j < m_editors.count(); ++j) { setEditingEnabled(j, false); - foreach (FormWidget *widget, m_editors[j].transTexts) + foreach (FormMultiWidget *widget, m_editors[j].transTexts) widget->clearTranslation(); m_editors[j].transCommentText->clearTranslation(); } @@ -639,7 +678,7 @@ void MessageEditor::setTranslation(int model, const QString &translation, int nu MessageEditorData &ed = m_editors[model]; if (numerus >= ed.transTexts.count()) numerus = 0; - FormWidget *transForm = ed.transTexts[numerus]; + FormMultiWidget *transForm = ed.transTexts[numerus]; transForm->setTranslation(translation, false); updateBeginFromSource(); @@ -654,8 +693,8 @@ void MessageEditor::setTranslation(int latestModel, const QString &translation) latestModel = m_currentModel; numerus = m_currentNumerus; } - FormWidget *transForm = m_editors[latestModel].transTexts[numerus]; - transForm->getEditor()->setFocus(); + FormMultiWidget *transForm = m_editors[latestModel].transTexts[numerus]; + transForm->getEditors().first()->setFocus(); transForm->setTranslation(translation, true); updateBeginFromSource(); @@ -664,29 +703,37 @@ void MessageEditor::setTranslation(int latestModel, const QString &translation) void MessageEditor::setEditingEnabled(int model, bool enabled) { MessageEditorData &ed = m_editors[model]; - foreach (FormWidget *widget, ed.transTexts) + foreach (FormMultiWidget *widget, ed.transTexts) widget->setEditingEnabled(enabled); ed.transCommentText->setEditingEnabled(enabled); updateCanPaste(); } +void MessageEditor::setLenghtVariants(bool on) +{ + m_lengthVariants = on; + foreach (const MessageEditorData &ed, m_editors) + foreach (FormMultiWidget *widget, ed.transTexts) + widget->setMultiEnabled(on); +} + void MessageEditor::undo() { - activeEditor()->getEditor()->document()->undo(); + activeEditor()->document()->undo(); } void MessageEditor::redo() { - activeEditor()->getEditor()->document()->redo(); + activeEditor()->document()->redo(); } void MessageEditor::updateUndoRedo() { bool newUndoAvail = false; bool newRedoAvail = false; - if (FormWidget *fw = activeEditor()) { - QTextDocument *doc = fw->getEditor()->document(); + if (QTextEdit *te = activeEditor()) { + QTextDocument *doc = te->document(); newUndoAvail = doc->isUndoAvailable(); newRedoAvail = doc->isRedoAvailable(); } @@ -704,18 +751,12 @@ void MessageEditor::updateUndoRedo() void MessageEditor::cut() { - QTextEdit *editor = activeEditor()->getEditor(); - if (editor->textCursor().hasSelection()) - editor->cut(); + m_selectionHolder->cut(); } void MessageEditor::copy() { - QTextEdit *te; - if ((te = m_source->getEditor())->textCursor().hasSelection() - || (te = m_pluralSource->getEditor())->textCursor().hasSelection() - || (te = activeEditor()->getEditor())->textCursor().hasSelection()) - te->copy(); + m_selectionHolder->copy(); } void MessageEditor::updateCanCutCopy() @@ -723,19 +764,9 @@ void MessageEditor::updateCanCutCopy() bool newCopyState = false; bool newCutState = false; - m_sourceSelected = m_source->getEditor()->textCursor().hasSelection(); - m_pluralSourceSelected = m_pluralSource->getEditor()->textCursor().hasSelection(); - m_currentSelected = false; - - if (m_sourceSelected || m_pluralSourceSelected) { + if (m_selectionHolder) { newCopyState = true; - } else if (FormWidget *fw = activeEditor()) { - QTextEdit *te = fw->getEditor(); - if (te->textCursor().hasSelection()) { - m_currentSelected = true; - newCopyState = true; - newCutState = !te->isReadOnly(); - } + newCutState = !m_selectionHolder->isReadOnly(); } if (newCopyState != m_copyAvail) { @@ -751,14 +782,14 @@ void MessageEditor::updateCanCutCopy() void MessageEditor::paste() { - activeEditor()->getEditor()->paste(); + activeEditor()->paste(); } void MessageEditor::updateCanPaste() { - FormWidget *fw; + QTextEdit *te; emit pasteAvailable(!m_clipboardEmpty - && (fw = activeEditor()) && !fw->getEditor()->isReadOnly()); + && (te = activeEditor()) && !te->isReadOnly()); } void MessageEditor::clipboardChanged() @@ -773,24 +804,23 @@ void MessageEditor::selectAll() // make sure we don't select the selection of a translator textedit, // if we really want the source text editor to be selected. QTextEdit *te; - FormWidget *fw; if ((te = m_source->getEditor())->underMouse() || (te = m_pluralSource->getEditor())->underMouse() - || ((fw = activeEditor()) && (te = fw->getEditor())->hasFocus())) + || ((te = activeEditor()) && te->hasFocus())) te->selectAll(); } -void MessageEditor::emitTranslationChanged() +void MessageEditor::emitTranslationChanged(QTextEdit *widget) { - static_cast<FormWidget *>(sender())->getEditor()->setFocus(); // DND proofness + grabFocus(widget); // DND proofness updateBeginFromSource(); updateUndoRedo(); emit translationChanged(translations(m_currentModel)); } -void MessageEditor::emitTranslatorCommentChanged() +void MessageEditor::emitTranslatorCommentChanged(QTextEdit *widget) { - static_cast<FormWidget *>(sender())->getEditor()->setFocus(); // DND proofness + grabFocus(widget); // DND proofness updateUndoRedo(); emit translatorCommentChanged(m_editors[m_currentModel].transCommentText->getTranslation()); } @@ -798,11 +828,9 @@ void MessageEditor::emitTranslatorCommentChanged() void MessageEditor::updateBeginFromSource() { bool overwrite = false; - if (FormWidget *transForm = activeTranslation()) { - QTextEdit *activeEditor = transForm->getEditor(); + if (QTextEdit *activeEditor = activeTranslation()) overwrite = !activeEditor->isReadOnly() && activeEditor->toPlainText().trimmed().isEmpty(); - } emit beginFromSourceAvailable(overwrite); } @@ -817,8 +845,8 @@ void MessageEditor::beginFromSource() void MessageEditor::setEditorFocus() { if (!widget()->hasFocus()) - if (FormWidget *transForm = activeOr1stEditor()) - transForm->getEditor()->setFocus(); + if (QTextEdit *activeEditor = activeOr1stEditor()) + activeEditor->setFocus(); } void MessageEditor::setEditorFocus(int model) @@ -828,12 +856,13 @@ void MessageEditor::setEditorFocus(int model) resetSelection(); m_currentNumerus = -1; m_currentModel = -1; + m_focusWidget = 0; emit activeModelChanged(activeModel()); updateBeginFromSource(); updateUndoRedo(); updateCanPaste(); } else { - m_editors[model].transTexts[0]->getEditor()->setFocus(); + m_editors[model].transTexts.first()->getEditors().first()->setFocus(); } } } @@ -844,7 +873,7 @@ bool MessageEditor::focusNextUnfinished(int start) if (m_dataModel->isModelWritable(j)) if (MessageItem *item = m_dataModel->messageItem(m_currentIndex, j)) if (item->type() == TranslatorMessage::Unfinished) { - m_editors[j].transTexts[0]->getEditor()->setFocus(); + m_editors[j].transTexts.first()->getEditors().first()->setFocus(); return true; } return false; diff --git a/tools/linguist/linguist/messageeditor.h b/tools/linguist/linguist/messageeditor.h index 8b0c45b..4106036 100644 --- a/tools/linguist/linguist/messageeditor.h +++ b/tools/linguist/linguist/messageeditor.h @@ -45,6 +45,7 @@ #include "messagemodel.h" #include <QtCore/QLocale> +#include <QtCore/QTimer> #include <QtGui/QFrame> #include <QtGui/QScrollArea> @@ -58,11 +59,12 @@ class QTextEdit; class MessageEditor; class FormatTextEdit; class FormWidget; +class FormMultiWidget; struct MessageEditorData { QWidget *container; FormWidget *transCommentText; - QList<FormWidget*> transTexts; + QList<FormMultiWidget *> transTexts; QString invariantForm; QString firstForm; float fontSize; @@ -108,30 +110,35 @@ public slots: void beginFromSource(); void setEditorFocus(); void setTranslation(int latestModel, const QString &translation); + void setLenghtVariants(bool on); private slots: - void selectionChanged(); - bool resetHoverSelection(FormWidget *fw = 0); - void emitTranslationChanged(); - void emitTranslatorCommentChanged(); + void editorCreated(QTextEdit *); + void selectionChanged(QTextEdit *); + void resetHoverSelection(); + void emitTranslationChanged(QTextEdit *); + void emitTranslatorCommentChanged(QTextEdit *); void updateCanPaste(); void clipboardChanged(); void messageModelAppended(); void messageModelDeleted(int model); void allModelsDeleted(); void setTargetLanguage(int model); + void reallyFixTabOrder(); private: void setupEditorPage(); void setEditingEnabled(int model, bool enabled); bool focusNextUnfinished(int start); - bool resetSelection(FormWidget *fw = 0); + void resetSelection(); + void grabFocus(QWidget *widget); + void trackFocus(QWidget *widget); void activeModelAndNumerus(int *model, int *numerus) const; - FormWidget *activeTranslation() const; - FormWidget *activeOr1stTranslation() const; - FormWidget *activeTransComment() const; - FormWidget *activeEditor() const; - FormWidget *activeOr1stEditor() const; + QTextEdit *activeTranslation() const; + QTextEdit *activeOr1stTranslation() const; + QTextEdit *activeTransComment() const; + QTextEdit *activeEditor() const; + QTextEdit *activeOr1stEditor() const; MessageEditorData *modelForWidget(const QObject *o); int activeTranslationNumerus() const; QStringList translations(int model) const; @@ -139,6 +146,7 @@ private: void updateUndoRedo(); void updateCanCutCopy(); void addPluralForm(int model, const QString &label, bool writable); + void fixTabOrder(); QPalette paletteForModel(int model) const; MultiDataModel *m_dataModel; @@ -147,21 +155,24 @@ private: int m_currentModel; int m_currentNumerus; + bool m_lengthVariants; + bool m_undoAvail; bool m_redoAvail; bool m_cutAvail; bool m_copyAvail; - bool m_sourceSelected; - bool m_pluralSourceSelected; - bool m_currentSelected; bool m_clipboardEmpty; + QTextEdit *m_selectionHolder; + QWidget *m_focusWidget; QBoxLayout *m_layout; FormWidget *m_source; FormWidget *m_pluralSource; FormWidget *m_commentText; QList<MessageEditorData> m_editors; + + QTimer m_tabOrderTimer; }; QT_END_NAMESPACE diff --git a/tools/linguist/linguist/messageeditorwidgets.cpp b/tools/linguist/linguist/messageeditorwidgets.cpp index b1eede2..f8e2dc2 100644 --- a/tools/linguist/linguist/messageeditorwidgets.cpp +++ b/tools/linguist/linguist/messageeditorwidgets.cpp @@ -42,6 +42,8 @@ #include "messageeditorwidgets.h" #include "messagehighlighter.h" +#include <translator.h> + #include <QAbstractTextDocumentLayout> #include <QAction> #include <QApplication> @@ -49,10 +51,12 @@ #include <QDebug> #include <QLayout> #include <QMenu> +#include <QMessageBox> #include <QPainter> #include <QScrollArea> #include <QTextBlock> #include <QTextDocumentFragment> +#include <QToolButton> #include <QVBoxLayout> QT_BEGIN_NAMESPACE @@ -145,16 +149,15 @@ void FormatTextEdit::setEditable(bool editable) void FormatTextEdit::setPlainText(const QString &text, bool userAction) { - bool oldBlockState = false; if (!userAction) { // Prevent contentsChanged signal - oldBlockState = document()->blockSignals(true); + bool oldBlockState = blockSignals(true); document()->setUndoRedoEnabled(false); ExpandingTextEdit::setPlainText(text); // highlighter is out of sync because of blocked signals m_highlighter->rehighlight(); document()->setUndoRedoEnabled(true); - document()->blockSignals(oldBlockState); + blockSignals(oldBlockState); } else { ExpandingTextEdit::setPlainText(text); } @@ -178,11 +181,21 @@ FormWidget::FormWidget(const QString &label, bool isEditable, QWidget *parent) setLayout(layout); - connect(m_editor->document(), SIGNAL(contentsChanged()), SIGNAL(textChanged())); - connect(m_editor, SIGNAL(selectionChanged()), SIGNAL(selectionChanged())); + connect(m_editor, SIGNAL(textChanged()), SLOT(slotTextChanged())); + connect(m_editor, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged())); connect(m_editor, SIGNAL(cursorPositionChanged()), SIGNAL(cursorPositionChanged())); } +void FormWidget::slotTextChanged() +{ + emit textChanged(m_editor); +} + +void FormWidget::slotSelectionChanged() +{ + emit selectionChanged(m_editor); +} + void FormWidget::setTranslation(const QString &text, bool userAction) { m_editor->setPlainText(text, userAction); @@ -198,4 +211,240 @@ void FormWidget::setEditingEnabled(bool enable) } +class ButtonWrapper : public QWidget +{ + // no Q_OBJECT: no need to, and don't want the useless moc file + +public: + ButtonWrapper(QWidget *wrapee, QWidget *relator) : m_wrapee(wrapee) + { + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); + QBoxLayout *box = new QVBoxLayout; + box->setMargin(0); + setLayout(box); + box->addWidget(wrapee, 0, Qt::AlignBottom); + if (relator) + relator->installEventFilter(this); + } + +protected: + virtual bool eventFilter(QObject *object, QEvent *event) + { + if (event->type() == QEvent::Resize) { + QWidget *relator = static_cast<QWidget *>(object); + setFixedHeight((relator->height() + layout()->spacing() + m_wrapee->height()) / 2); + } + return false; + } + +private: + QWidget *m_wrapee; +}; + +FormMultiWidget::FormMultiWidget(const QString &label, QWidget *parent) + : QWidget(parent), + m_hideWhenEmpty(false), + m_multiEnabled(false), + m_plusIcon(QIcon(QLatin1String(":/images/plus.png"))), // make static + m_minusIcon(QIcon(QLatin1String(":/images/minus.png"))) +{ + m_label = new QLabel(this); + m_label->setText(label); + + m_plusButtons.append( + new ButtonWrapper(makeButton(m_plusIcon, SLOT(plusButtonClicked())), 0)); +} + +QAbstractButton *FormMultiWidget::makeButton(const QIcon &icon, const char *slot) +{ + QAbstractButton *btn = new QToolButton(this); + btn->setIcon(icon); + btn->setFixedSize(icon.availableSizes().first() /* + something */); + btn->setFocusPolicy(Qt::NoFocus); + connect(btn, SIGNAL(clicked()), slot); + return btn; +} + +void FormMultiWidget::addEditor(int idx) +{ + FormatTextEdit *editor = new FormatTextEdit(this); + m_editors.insert(idx, editor); + + m_minusButtons.insert(idx, makeButton(m_minusIcon, SLOT(minusButtonClicked()))); + m_plusButtons.insert(idx + 1, + new ButtonWrapper(makeButton(m_plusIcon, SLOT(plusButtonClicked())), editor)); + + connect(editor, SIGNAL(textChanged()), SLOT(slotTextChanged())); + connect(editor, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged())); + connect(editor, SIGNAL(cursorPositionChanged()), SIGNAL(cursorPositionChanged())); + editor->installEventFilter(this); + + emit editorCreated(editor); +} + +bool FormMultiWidget::eventFilter(QObject *watched, QEvent *event) +{ + int i = 0; + while (m_editors.at(i) != watched) + if (++i >= m_editors.count()) // Happens when deleting an editor + return false; + if (event->type() == QEvent::FocusOut) { + m_minusButtons.at(i)->setToolTip(QString()); + m_plusButtons.at(i)->setToolTip(QString()); + m_plusButtons.at(i + 1)->setToolTip(QString()); + } else if (event->type() == QEvent::FocusIn) { + m_minusButtons.at(i)->setToolTip(/*: translate, but don't change */ tr("Alt+Delete")); + m_plusButtons.at(i)->setToolTip(/*: translate, but don't change */ tr("Shift+Alt+Insert")); + m_plusButtons.at(i + 1)->setToolTip(/*: translate, but don't change */ tr("Alt+Insert")); + } else if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast<QKeyEvent *>(event); + if (ke->modifiers() & Qt::AltModifier) { + if (ke->key() == Qt::Key_Delete) { + deleteEditor(i); + return true; + } else if (ke->key() == Qt::Key_Insert) { + if (!(ke->modifiers() & Qt::ShiftModifier)) + ++i; + insertEditor(i); + return true; + } + } + } + return false; +} + +void FormMultiWidget::updateLayout() +{ + delete layout(); + + QGridLayout *layout = new QGridLayout; + layout->setMargin(0); + setLayout(layout); + + bool variants = m_multiEnabled && m_label->isEnabled(); + + layout->addWidget(m_label, 0, 0, 1, variants ? 3 : 1); + + for (int i = 0; i < m_plusButtons.count(); ++i) { + if (variants) + layout->addWidget(m_plusButtons.at(i), 1 + i * 2, 0, 2, 1, Qt::AlignTop); + m_plusButtons.at(i)->setVisible(variants); + } + for (int j = 0; j < m_minusButtons.count(); ++j) { + if (variants) + layout->addWidget(m_minusButtons.at(j), 2 + j * 2, 2, 2, 1, Qt::AlignVCenter); + m_minusButtons.at(j)->setVisible(variants); + } + for (int k = 0; k < m_editors.count(); ++k) + layout->addWidget(m_editors.at(k), 2 + k * 2, variants ? 1 : 0, 2, 1, Qt::AlignVCenter); + + updateGeometry(); +} + +void FormMultiWidget::slotTextChanged() +{ + emit textChanged(static_cast<QTextEdit *>(sender())); +} + +void FormMultiWidget::slotSelectionChanged() +{ + emit selectionChanged(static_cast<QTextEdit *>(sender())); +} + +void FormMultiWidget::setTranslation(const QString &text, bool userAction) +{ + QStringList texts = text.split(QChar(Translator::BinaryVariantSeparator), QString::KeepEmptyParts); + + while (m_editors.count() > texts.count()) { + delete m_minusButtons.takeLast(); + delete m_plusButtons.takeLast(); + delete m_editors.takeLast(); + } + while (m_editors.count() < texts.count()) + addEditor(m_editors.count()); + updateLayout(); + + for (int i = 0; i < texts.count(); ++i) + // XXX this will emit n textChanged signals + m_editors.at(i)->setPlainText(texts.at(i), userAction); + + if (m_hideWhenEmpty) + setHidden(text.isEmpty()); +} + +QString FormMultiWidget::getTranslation() const +{ + QString ret; + for (int i = 0; i < m_editors.count(); ++i) { + if (i) + ret += QChar(Translator::BinaryVariantSeparator); + ret += m_editors.at(i)->toPlainText(); + } + return ret; +} + +void FormMultiWidget::setEditingEnabled(bool enable) +{ + // Use read-only state so that the text can still be copied + for (int i = 0; i < m_editors.count(); ++i) + m_editors.at(i)->setReadOnly(!enable); + m_label->setEnabled(enable); + if (m_multiEnabled) + updateLayout(); +} + +void FormMultiWidget::setMultiEnabled(bool enable) +{ + m_multiEnabled = enable; + if (m_label->isEnabled()) + updateLayout(); +} + +void FormMultiWidget::minusButtonClicked() +{ + int i = 0; + while (m_minusButtons.at(i) != sender()) + ++i; + deleteEditor(i); +} + +void FormMultiWidget::plusButtonClicked() +{ + QWidget *btn = static_cast<QAbstractButton *>(sender())->parentWidget(); + int i = 0; + while (m_plusButtons.at(i) != btn) + ++i; + insertEditor(i); +} + +void FormMultiWidget::deleteEditor(int idx) +{ + if (m_editors.count() == 1) { + // Don't just clear(), so the undo history is not lost + QTextCursor c = m_editors.first()->textCursor(); + c.select(QTextCursor::Document); + c.removeSelectedText(); + } else { + if (!m_editors.at(idx)->toPlainText().isEmpty()) { + if (QMessageBox::question(topLevelWidget(), tr("Confirmation - Qt Linguist"), + tr("Delete non-empty length variant?"), + QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes) + != QMessageBox::Yes) + return; + } + delete m_editors.takeAt(idx); + delete m_minusButtons.takeAt(idx); + delete m_plusButtons.takeAt(idx + 1); + updateLayout(); + emit textChanged(m_editors.at((m_editors.count() == idx) ? idx - 1 : idx)); + } +} + +void FormMultiWidget::insertEditor(int idx) +{ + addEditor(idx); + updateLayout(); + emit textChanged(m_editors.at(idx)); +} + QT_END_NAMESPACE diff --git a/tools/linguist/linguist/messageeditorwidgets.h b/tools/linguist/linguist/messageeditorwidgets.h index 3c54d73..c0b445c 100644 --- a/tools/linguist/linguist/messageeditorwidgets.h +++ b/tools/linguist/linguist/messageeditorwidgets.h @@ -42,6 +42,7 @@ #ifndef MESSAGEEDITORWIDGETS_H #define MESSAGEEDITORWIDGETS_H +#include <QIcon> #include <QImage> #include <QLabel> #include <QMap> @@ -51,6 +52,7 @@ QT_BEGIN_NAMESPACE +class QAbstractButton; class QAction; class QContextMenuEvent; class QKeyEvent; @@ -115,16 +117,68 @@ public: FormatTextEdit *getEditor() { return m_editor; } signals: - void textChanged(); - void selectionChanged(); + void textChanged(QTextEdit *); + void selectionChanged(QTextEdit *); void cursorPositionChanged(); +private slots: + void slotSelectionChanged(); + void slotTextChanged(); + private: QLabel *m_label; FormatTextEdit *m_editor; bool m_hideWhenEmpty; }; +/* + Displays text fields & associated label +*/ +class FormMultiWidget : public QWidget +{ + Q_OBJECT +public: + FormMultiWidget(const QString &label, QWidget *parent = 0); + void setLabel(const QString &label) { m_label->setText(label); } + void setTranslation(const QString &text, bool userAction = false); + void clearTranslation() { setTranslation(QString(), false); } + QString getTranslation() const; + void setEditingEnabled(bool enable); + void setMultiEnabled(bool enable); + void setHideWhenEmpty(bool optional) { m_hideWhenEmpty = optional; } + const QList<FormatTextEdit *> &getEditors() const { return m_editors; } + +signals: + void editorCreated(QTextEdit *); + void textChanged(QTextEdit *); + void selectionChanged(QTextEdit *); + void cursorPositionChanged(); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private slots: + void slotTextChanged(); + void slotSelectionChanged(); + void minusButtonClicked(); + void plusButtonClicked(); + +private: + void addEditor(int idx); + void updateLayout(); + QAbstractButton *makeButton(const QIcon &icon, const char *slot); + void insertEditor(int idx); + void deleteEditor(int idx); + + QLabel *m_label; + QList<FormatTextEdit *> m_editors; + QList<QWidget *> m_plusButtons; + QList<QAbstractButton *> m_minusButtons; + bool m_hideWhenEmpty; + bool m_multiEnabled; + QIcon m_plusIcon, m_minusIcon; +}; + QT_END_NAMESPACE #endif // MESSAGEEDITORWIDGETS_H diff --git a/tools/linguist/linguist/phrase.cpp b/tools/linguist/linguist/phrase.cpp index 0c21cce..463e699 100644 --- a/tools/linguist/linguist/phrase.cpp +++ b/tools/linguist/linguist/phrase.cpp @@ -152,10 +152,10 @@ bool QphHandler::startElement(const QString & /* namespaceURI */, const QString &qName, const QXmlAttributes &atts) { - if (qName == QString(QLatin1String("QPH"))) { + if (qName == QLatin1String("QPH")) { m_language = atts.value(QLatin1String("language")); m_sourceLanguage = atts.value(QLatin1String("sourcelanguage")); - } else if (qName == QString(QLatin1String("phrase"))) { + } else if (qName == QLatin1String("phrase")) { source.truncate(0); target.truncate(0); definition.truncate(0); @@ -168,13 +168,13 @@ bool QphHandler::endElement(const QString & /* namespaceURI */, const QString & /* localName */, const QString &qName) { - if (qName == QString(QLatin1String("source"))) + if (qName == QLatin1String("source")) source = accum; - else if (qName == QString(QLatin1String("target"))) + else if (qName == QLatin1String("target")) target = accum; - else if (qName == QString(QLatin1String("definition"))) + else if (qName == QLatin1String("definition")) definition = accum; - else if (qName == QString(QLatin1String("phrase"))) + else if (qName == QLatin1String("phrase")) pb->m_phrases.append(new Phrase(source, target, definition, pb)); return true; } diff --git a/tools/linguist/linguist/phrasebookbox.cpp b/tools/linguist/linguist/phrasebookbox.cpp index 67d996b..9a6819b 100644 --- a/tools/linguist/linguist/phrasebookbox.cpp +++ b/tools/linguist/linguist/phrasebookbox.cpp @@ -56,13 +56,15 @@ QT_BEGIN_NAMESPACE -#define NewPhrase tr("(New Entry)") - PhraseBookBox::PhraseBookBox(PhraseBook *phraseBook, QWidget *parent) : QDialog(parent), m_phraseBook(phraseBook), m_translationSettingsDialog(0) { + +// This definition needs to be within class context for lupdate to find it +#define NewPhrase tr("(New Entry)") + setupUi(this); setWindowTitle(tr("%1[*] - Qt Linguist").arg(m_phraseBook->friendlyPhraseBookName())); setWindowModified(m_phraseBook->isModified()); diff --git a/tools/linguist/linguist/phraseview.cpp b/tools/linguist/linguist/phraseview.cpp index 649b24d..a959b66 100644 --- a/tools/linguist/linguist/phraseview.cpp +++ b/tools/linguist/linguist/phraseview.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include "globals.h" #include "mainwindow.h" #include "messagemodel.h" #include "phrase.h" @@ -61,7 +62,7 @@ static const int MaxCandidates = 5; static QString phraseViewHeaderKey() { - return settingsPrefix() + QLatin1String("PhraseViewHeader"); + return settingPath("PhraseViewHeader"); } PhraseView::PhraseView(MultiDataModel *model, QList<QHash<QString, QList<Phrase *> > > *phraseDict, QWidget *parent) diff --git a/tools/linguist/linguist/recentfiles.cpp b/tools/linguist/linguist/recentfiles.cpp index 6e13b78..0dc14a4 100644 --- a/tools/linguist/linguist/recentfiles.cpp +++ b/tools/linguist/linguist/recentfiles.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "recentfiles.h" +#include "globals.h" #include <QtCore/QDebug> #include <QtCore/QFileInfo> @@ -49,11 +50,9 @@ QT_BEGIN_NAMESPACE -const QString &settingsPrefix(); - static QString configKey() { - return settingsPrefix() + QLatin1String("RecentlyOpenedFiles"); + return settingPath("RecentlyOpenedFiles"); } diff --git a/tools/linguist/lrelease/lrelease.1 b/tools/linguist/lrelease/lrelease.1 index 9e77504..8dd14b2 100644 --- a/tools/linguist/lrelease/lrelease.1 +++ b/tools/linguist/lrelease/lrelease.1 @@ -51,10 +51,10 @@ This page documents the tool for the Qt GUI toolkit. .B Lrelease reads a qmake/tmake project file (.pro file) and converts the -translation files (.ts files) specified in it into Qt message files -(.qm files) used by the application to translate. +translation files (TS files) specified in it into Qt message files +(QM files) used by the application to translate. .PP -The .qm file format is a compact binary format that provides +The QM file format is a compact binary format that provides extremely fast lookups for translations and that is used by Qt. .SH OPTIONS .TP @@ -62,7 +62,7 @@ extremely fast lookups for translations and that is used by Qt. Display the usage and exit. .TP .I "-compress" -Compress the .qm files. +Compress the QM files. .TP .I "-nounfinished" Do not include unfinished translations. @@ -72,7 +72,7 @@ If the translated text is the same as the source text, do not include the message. .TP .I "-silent" -Don't explain what is being done. +Do not explain what is being done. .TP .I "-version" Display the version of @@ -105,7 +105,7 @@ generated from gnomovision_dk.ts, gnomovision_fi.ts, gnomovision_no.ts and gnomovision_se.ts, respectively. .PP .B Lrelease -can also be invoked with a list of .ts files to convert: +can also be invoked with a list of TS files to convert: .PP .in +4 .nf diff --git a/tools/linguist/lrelease/main.cpp b/tools/linguist/lrelease/main.cpp index 843414d..5cb9e1a 100644 --- a/tools/linguist/lrelease/main.cpp +++ b/tools/linguist/lrelease/main.cpp @@ -40,7 +40,6 @@ ****************************************************************************/ #include "translator.h" -#include "translatortools.h" #include "proreader.h" #include <QtCore/QCoreApplication> @@ -67,19 +66,21 @@ static void printUsage() " lrelease [options] project-file\n" " lrelease [options] ts-files [-qm qm-file]\n\n" "lrelease is part of Qt's Linguist tool chain. It can be used as a\n" - "stand-alone tool to convert XML based translations files in the .ts\n" - "format into the 'compiled' .qm format used by QTranslator objects.\n\n" + "stand-alone tool to convert XML-based translations files in the TS\n" + "format into the 'compiled' QM format used by QTranslator objects.\n\n" "Options:\n" " -help Display this information and exit\n" + " -idbased\n" + " Use IDs instead of source strings for message keying\n" " -compress\n" - " Compress the .qm files\n" + " Compress the QM files\n" " -nounfinished\n" " Do not include unfinished translations\n" " -removeidentical\n" " If the translated text is the same as\n" " the source text, do not include the message\n" " -silent\n" - " Don't explain what is being done\n" + " Do not explain what is being done\n" " -version\n" " Display the version of lrelease and exit\n" )); @@ -100,7 +101,7 @@ static bool loadTsFile(Translator &tor, const QString &tsFileName, bool /* verbo static bool releaseTranslator(Translator &tor, const QString &qmFileName, bool verbose, bool ignoreUnfinished, - bool removeIdentical, TranslatorSaveMode mode) + bool removeIdentical, bool idBased, TranslatorSaveMode mode) { Translator::reportDuplicates(tor.resolveDuplicates(), qmFileName, verbose); @@ -123,6 +124,7 @@ static bool releaseTranslator(Translator &tor, const QString &qmFileName, 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(); @@ -138,7 +140,7 @@ static bool releaseTranslator(Translator &tor, const QString &qmFileName, } static bool releaseTsFile(const QString& tsFileName, bool verbose, - bool ignoreUnfinished, bool removeIdentical, TranslatorSaveMode mode) + bool ignoreUnfinished, bool removeIdentical, bool idBased, TranslatorSaveMode mode) { Translator tor; if (!loadTsFile(tor, tsFileName, verbose)) @@ -153,7 +155,7 @@ static bool releaseTsFile(const QString& tsFileName, bool verbose, } qmFileName += QLatin1String(".qm"); - return releaseTranslator(tor, qmFileName, verbose, ignoreUnfinished, removeIdentical, mode); + return releaseTranslator(tor, qmFileName, verbose, ignoreUnfinished, removeIdentical, idBased, mode); } int main(int argc, char **argv) @@ -166,6 +168,7 @@ int main(int argc, char **argv) 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; bool removeIdentical = false; @@ -177,6 +180,9 @@ int main(int argc, char **argv) if (args[i] == QLatin1String("-compress")) { mode = SaveStripped; continue; + } else if (args[i] == QLatin1String("-idbased")) { + idBased = true; + continue; } else if (args[i] == QLatin1String("-nocompress")) { mode = SaveEverything; continue; @@ -234,18 +240,18 @@ int main(int argc, char **argv) qPrintable(args[i])); } else { foreach (const QString &trans, translations) - if (!releaseTsFile(trans, verbose, ignoreUnfinished, removeIdentical, mode)) + if (!releaseTsFile(trans, verbose, ignoreUnfinished, removeIdentical, idBased, mode)) return 1; } } else { qWarning("error: lrelease encountered project file functionality that is currently not supported.\n" - "You might want to consider using .ts files as input instead of a project file.\n" + "You might want to consider using TS files as input instead of a project file.\n" "Try the following syntax:\n" " lrelease [options] ts-files [-qm qm-file]\n"); } } else { if (outputFile.isEmpty()) { - if (!releaseTsFile(args[i], verbose, ignoreUnfinished, removeIdentical, mode)) + if (!releaseTsFile(args[i], verbose, ignoreUnfinished, removeIdentical, idBased, mode)) return 1; } else { if (!loadTsFile(tor, args[i], verbose)) @@ -256,7 +262,7 @@ int main(int argc, char **argv) if (!outputFile.isEmpty()) return releaseTranslator(tor, outputFile, verbose, ignoreUnfinished, - removeIdentical, mode) ? 0 : 1; + removeIdentical, idBased, mode) ? 0 : 1; return 0; } diff --git a/tools/linguist/lupdate/cpp.cpp b/tools/linguist/lupdate/cpp.cpp new file mode 100644 index 0000000..21b230e --- /dev/null +++ b/tools/linguist/lupdate/cpp.cpp @@ -0,0 +1,1921 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Linguist 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "lupdate.h" + +#include <translator.h> + +#include <QtCore/QDebug> +#include <QtCore/QFileInfo> +#include <QtCore/QStack> +#include <QtCore/QString> +#include <QtCore/QTextCodec> +#include <QtCore/QTextStream> + +#include <ctype.h> // for isXXX() + +QT_BEGIN_NAMESPACE + +/* qmake ignore Q_OBJECT */ + +static const char MagicComment[] = "TRANSLATOR "; + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) +#define STRING(s) static QString str##s(QLatin1String(STRINGIFY(s))) + +//#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this + +uint qHash(const QStringList &qsl) +{ + uint hash = 0; + foreach (const QString &qs, qsl) { + hash ^= qHash(qs) ^ 0xa09df22f; + hash = (hash << 13) | (hash >> 19); + } + return hash; +} + +struct Namespace { + + Namespace() : + isClass(false), + hasTrFunctions(false), needsTrFunctions(false), complained(false) + {} + + QString name; + QMap<QString, Namespace *> children; + QMap<QString, QStringList> aliases; + QSet<QStringList> usings; + + int fileId; + + bool isClass; + + bool hasTrFunctions; + bool needsTrFunctions; + bool complained; // ... that tr functions are missing. +}; + +typedef QList<Namespace *> NamespaceList; + +struct ParseResults { + + ParseResults() + { + static int nextFileId; + rootNamespace.fileId = nextFileId++; + tor = 0; + } + bool detachNamespace(Namespace **that); + Namespace *include(Namespace *that, const Namespace *other); + void unite(const ParseResults *other); + + Namespace rootNamespace; + Translator *tor; + QSet<QString> allIncludes; +}; + +typedef QHash<QString, const ParseResults *> ParseResultHash; + +class CppFiles { + +public: + static const ParseResults *getResults(const QString &cleanFile); + static void setResults(const QString &cleanFile, const ParseResults *results); + static bool isBlacklisted(const QString &cleanFile); + static void setBlacklisted(const QString &cleanFile); + +private: + static ParseResultHash &parsedFiles(); + static QSet<QString> &blacklistedFiles(); +}; + +class CppParser { + +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 parse(const QString &initialContext, ConversionData &cd, QSet<QString> &inclusions); + void parseInternal(ConversionData &cd, QSet<QString> &inclusions); + const ParseResults *getResults() const { return results; } + void deleteResults() { delete results; } + + struct SavedState { + QStringList namespaces; + QStack<int> namespaceDepths; + QStringList functionContext; + QString functionContextUnresolved; + QString pendingContext; + }; + +private: + struct IfdefState { + IfdefState() {} + IfdefState(int _braceDepth, int _parenDepth) : + braceDepth(_braceDepth), + parenDepth(_parenDepth), + elseLine(-1) + {} + + SavedState state; + int braceDepth, braceDepth1st; + int parenDepth, parenDepth1st; + int elseLine; + }; + + uint getChar(); + uint getToken(); + bool match(uint t); + bool matchString(QString *s); + bool matchEncoding(bool *utf8); + bool matchInteger(qlonglong *number); + bool matchStringOrNull(QString *s); + bool matchExpression(); + + QString transcode(const QString &str, bool utf8); + void recordMessage( + int line, const QString &context, const QString &text, const QString &comment, + const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra, + bool utf8, bool plural); + + void processInclude(const QString &file, ConversionData &cd, + QSet<QString> &inclusions); + + void saveState(SavedState *state); + void loadState(const SavedState *state); + + 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, + bool isDeclaration, + NamespaceList *resolved, QStringList *unresolved); + void enterNamespace(NamespaceList *namespaces, const QString &name); + void truncateNamespaces(NamespaceList *namespaces, int lenght); + + enum { + Tok_Eof, Tok_class, Tok_friend, Tok_namespace, Tok_using, Tok_return, + Tok_tr = 10, Tok_trUtf8, Tok_translate, Tok_translateUtf8, Tok_trid, + Tok_Q_OBJECT = 20, Tok_Q_DECLARE_TR_FUNCTIONS, + 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_QuotedInclude = 50, Tok_AngledInclude, + Tok_Other = 99 + }; + + // Tokenizer state + QString yyFileName; + int yyCh; + bool yyAtNewline; + bool yyCodecIsUtf8; + bool yyForceUtf8; + QString yyIdent; + QString yyComment; + QString yyString; + qlonglong yyInteger; + QStack<IfdefState> yyIfdefStack; + int yyBraceDepth; + int yyParenDepth; + int yyLineNo; + int yyCurLineNo; + int yyBraceLineNo; + int yyParenLineNo; + + // the string to read from and current position in the string + QTextCodec *yySourceCodec; + bool yySourceIsUnicode; + QString yyInStr; + int yyInPos; + + // Parser state + uint yyTok; + + NamespaceList namespaces; + QStack<int> namespaceDepths; + NamespaceList functionContext; + QString functionContextUnresolved; + QString prospectiveContext; + QString pendingContext; + ParseResults *results; + bool directInclude; + + SavedState savedState; + int yyMinBraceDepth; + bool inDefine; +}; + +CppParser::CppParser(ParseResults *_results) +{ + if (_results) { + results = _results; + directInclude = true; + } else { + results = new ParseResults; + directInclude = false; + } + yyInPos = 0; + yyBraceDepth = 0; + yyParenDepth = 0; + yyCurLineNo = 1; + yyBraceLineNo = 1; + yyParenLineNo = 1; + yyAtNewline = true; + yyMinBraceDepth = 0; + inDefine = false; +} + +void CppParser::setInput(const QString &in) +{ + yyInStr = in; + yyFileName = QString(); + yySourceCodec = 0; + yySourceIsUnicode = true; + yyForceUtf8 = true; +} + +void CppParser::setInput(QTextStream &ts, const QString &fileName) +{ + yyInStr = ts.readAll(); + yyFileName = fileName; + yySourceCodec = ts.codec(); + yySourceIsUnicode = yySourceCodec->name().startsWith("UTF-"); + yyForceUtf8 = false; +} + +/* + The first part of this source file is the C++ tokenizer. We skip + most of C++; the only tokens that interest us are defined here. + Thus, the code fragment + + int main() + { + printf("Hello, world!\n"); + return 0; + } + + is broken down into the following tokens (Tok_ omitted): + + Ident Ident LeftParen RightParen + LeftBrace + Ident LeftParen String RightParen Semicolon + return Semicolon + RightBrace. + + The 0 doesn't produce any token. +*/ + +uint CppParser::getChar() +{ + forever { + if (yyInPos >= yyInStr.size()) + return EOF; + uint c = yyInStr[yyInPos++].unicode(); + if (c == '\\' && yyInPos < yyInStr.size()) { + if (yyInStr[yyInPos].unicode() == '\n') { + ++yyCurLineNo; + ++yyInPos; + continue; + } + if (yyInStr[yyInPos].unicode() == '\r') { + ++yyCurLineNo; + ++yyInPos; + if (yyInPos < yyInStr.size() && yyInStr[yyInPos].unicode() == '\n') + ++yyInPos; + continue; + } + } + if (c == '\r') { + if (yyInPos < yyInStr.size() && yyInStr[yyInPos].unicode() == '\n') + ++yyInPos; + c = '\n'; + ++yyCurLineNo; + yyAtNewline = true; + } else if (c == '\n') { + ++yyCurLineNo; + yyAtNewline = true; + } else if (c != ' ' && c != '\t' && c != '#') { + yyAtNewline = false; + } + return c; + } +} + +uint CppParser::getToken() +{ + restart: + yyIdent.clear(); + yyComment.clear(); + yyString.clear(); + + while (yyCh != EOF) { + yyLineNo = yyCurLineNo; + + if (yyCh == '#' && yyAtNewline) { + /* + Early versions of lupdate complained about + unbalanced braces in the following code: + + #ifdef ALPHA + while (beta) { + #else + while (gamma) { + #endif + delta; + } + + The code contains, indeed, two opening braces for + one closing brace; yet there's no reason to panic. + + The solution is to remember yyBraceDepth as it was + when #if, #ifdef or #ifndef was met, and to set + yyBraceDepth to that value when meeting #elif or + #else. + */ + do { + yyCh = getChar(); + } while (isspace(yyCh) && yyCh != '\n'); + + switch (yyCh) { + case 'd': // define + // Skip over the name of the define to avoid it being interpreted as c++ code + do { // Rest of "define" + yyCh = getChar(); + if (yyCh == EOF) + return Tok_Eof; + if (yyCh == '\n') + goto restart; + } while (!isspace(yyCh)); + do { // Space beween "define" and macro name + yyCh = getChar(); + if (yyCh == EOF) + return Tok_Eof; + if (yyCh == '\n') + goto restart; + } while (isspace(yyCh)); + do { // Macro name + if (yyCh == '(') { + // Argument list. Follows the name without a space, and no + // paren nesting is possible. + do { + yyCh = getChar(); + if (yyCh == EOF) + return Tok_Eof; + if (yyCh == '\n') + goto restart; + } while (yyCh != ')'); + break; + } + yyCh = getChar(); + if (yyCh == EOF) + return Tok_Eof; + if (yyCh == '\n') + goto restart; + } while (!isspace(yyCh)); + do { // Shortcut the immediate newline case if no comments follow. + yyCh = getChar(); + if (yyCh == EOF) + return Tok_Eof; + if (yyCh == '\n') + goto restart; + } while (isspace(yyCh)); + + saveState(&savedState); + yyMinBraceDepth = yyBraceDepth; + inDefine = true; + goto restart; + case 'i': + yyCh = getChar(); + if (yyCh == 'f') { + // if, ifdef, ifndef + yyIfdefStack.push(IfdefState(yyBraceDepth, yyParenDepth)); + yyCh = getChar(); + } else if (yyCh == 'n') { + // include + do { + yyCh = getChar(); + } while (yyCh != EOF && !isspace(yyCh)); + do { + yyCh = getChar(); + } while (isspace(yyCh)); + int tChar; + if (yyCh == '"') + tChar = '"'; + else if (yyCh == '<') + tChar = '>'; + else + break; + forever { + yyCh = getChar(); + if (yyCh == EOF || yyCh == '\n') + break; + if (yyCh == tChar) { + yyCh = getChar(); + break; + } + yyString += yyCh; + } + return (tChar == '"') ? Tok_QuotedInclude : Tok_AngledInclude; + } + break; + case 'e': + yyCh = getChar(); + if (yyCh == 'l') { + // elif, else + if (!yyIfdefStack.isEmpty()) { + IfdefState &is = yyIfdefStack.top(); + if (is.elseLine != -1) { + if (yyBraceDepth != is.braceDepth1st || yyParenDepth != is.parenDepth1st) + qWarning("%s:%d: Parenthesis/brace mismatch between " + "#if and #else branches; using #if branch\n", + qPrintable(yyFileName), is.elseLine); + } else { + is.braceDepth1st = yyBraceDepth; + is.parenDepth1st = yyParenDepth; + saveState(&is.state); + } + is.elseLine = yyLineNo; + yyBraceDepth = is.braceDepth; + yyParenDepth = is.parenDepth; + } + yyCh = getChar(); + } else if (yyCh == 'n') { + // endif + if (!yyIfdefStack.isEmpty()) { + IfdefState is = yyIfdefStack.pop(); + if (is.elseLine != -1) { + if (yyBraceDepth != is.braceDepth1st || yyParenDepth != is.parenDepth1st) + qWarning("%s:%d: Parenthesis/brace mismatch between " + "#if and #else branches; using #if branch\n", + qPrintable(yyFileName), is.elseLine); + yyBraceDepth = is.braceDepth1st; + yyParenDepth = is.parenDepth1st; + loadState(&is.state); + } + } + yyCh = getChar(); + } + break; + } + // Optimization: skip over rest of preprocessor directive + do { + if (yyCh == '/') { + yyCh = getChar(); + if (yyCh == '/') { + do { + yyCh = getChar(); + } while (yyCh != EOF && yyCh != '\n'); + break; + } else if (yyCh == '*') { + bool metAster = false; + + forever { + yyCh = getChar(); + if (yyCh == EOF) { + qWarning("%s:%d: Unterminated C++ comment\n", + qPrintable(yyFileName), yyLineNo); + break; + } + + if (yyCh == '*') { + metAster = true; + } else if (metAster && yyCh == '/') { + yyCh = getChar(); + break; + } else { + metAster = false; + } + } + } + } else { + yyCh = getChar(); + } + } while (yyCh != '\n' && yyCh != EOF); + yyCh = getChar(); + } else if (isalpha(yyCh) || yyCh == '_') { + do { + yyIdent += yyCh; + yyCh = getChar(); + } while (isalnum(yyCh) || yyCh == '_'); + + //qDebug() << "IDENT: " << yyIdent; + + switch (yyIdent.at(0).unicode()) { + case 'Q': + if (yyIdent == QLatin1String("Q_OBJECT")) + return Tok_Q_OBJECT; + if (yyIdent == QLatin1String("Q_DECLARE_TR_FUNCTIONS")) + return Tok_Q_DECLARE_TR_FUNCTIONS; + if (yyIdent == QLatin1String("QT_TR_NOOP")) + return Tok_tr; + if (yyIdent == QLatin1String("QT_TRID_NOOP")) + return Tok_trid; + if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP")) + return Tok_translate; + if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP3")) + return Tok_translate; + if (yyIdent == QLatin1String("QT_TR_NOOP_UTF8")) + return Tok_trUtf8; + if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP_UTF8")) + return Tok_translateUtf8; + if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP3_UTF8")) + return Tok_translateUtf8; + break; + case 'T': + // TR() for when all else fails + if (yyIdent.compare(QLatin1String("TR"), Qt::CaseInsensitive) == 0) { + return Tok_tr; + } + break; + case 'c': + if (yyIdent == QLatin1String("class")) + return Tok_class; + break; + case 'f': + /* + QTranslator::findMessage() has the same parameters as + QApplication::translate(). + */ + if (yyIdent == QLatin1String("findMessage")) + return Tok_translate; + if (yyIdent == QLatin1String("friend")) + return Tok_friend; + break; + case 'n': + if (yyIdent == QLatin1String("namespace")) + return Tok_namespace; + break; + case 'q': + if (yyIdent == QLatin1String("qtTrId")) + return Tok_trid; + break; + case 'r': + if (yyIdent == QLatin1String("return")) + return Tok_return; + break; + case 's': + if (yyIdent == QLatin1String("struct")) + return Tok_class; + break; + case 't': + if (yyIdent == QLatin1String("tr")) { + return Tok_tr; + } + if (yyIdent == QLatin1String("trUtf8")) { + return Tok_trUtf8; + } + if (yyIdent == QLatin1String("translate")) { + return Tok_translate; + } + break; + case 'u': + if (yyIdent == QLatin1String("using")) + return Tok_using; + break; + } + return Tok_Ident; + } else { + switch (yyCh) { + case '\n': + if (inDefine) { + loadState(&savedState); + prospectiveContext.clear(); + yyBraceDepth = yyMinBraceDepth; + yyMinBraceDepth = 0; + inDefine = false; + } + yyCh = getChar(); + break; + case '/': + yyCh = getChar(); + if (yyCh == '/') { + do { + yyCh = getChar(); + if (yyCh == EOF) + break; + yyComment.append(yyCh); + } while (yyCh != '\n'); + } else if (yyCh == '*') { + bool metAster = false; + + forever { + yyCh = getChar(); + if (yyCh == EOF) { + qWarning("%s:%d: Unterminated C++ comment\n", + qPrintable(yyFileName), yyLineNo); + return Tok_Comment; + } + yyComment.append(yyCh); + + if (yyCh == '*') + metAster = true; + else if (metAster && yyCh == '/') + break; + else + metAster = false; + } + yyCh = getChar(); + yyComment.chop(2); + } + return Tok_Comment; + case '"': + yyCh = getChar(); + while (yyCh != EOF && yyCh != '\n' && yyCh != '"') { + if (yyCh == '\\') { + yyCh = getChar(); + if (yyCh == EOF || yyCh == '\n') + break; + yyString.append(QLatin1Char('\\')); + } + yyString.append(yyCh); + yyCh = getChar(); + } + + if (yyCh != '"') + qWarning("%s:%d: Unterminated C++ string\n", + qPrintable(yyFileName), yyLineNo); + else + yyCh = getChar(); + return Tok_String; + case '-': + yyCh = getChar(); + if (yyCh == '>') { + yyCh = getChar(); + return Tok_Arrow; + } + break; + case ':': + yyCh = getChar(); + if (yyCh == ':') { + yyCh = getChar(); + return Tok_ColonColon; + } + return Tok_Colon; + // Incomplete: '<' might be part of '<=' or of template syntax. + // The main intent of not completely ignoring it is to break + // parsing of things like std::cout << QObject::tr() as + // context std::cout::QObject (see Task 161106) + case '=': + yyCh = getChar(); + return Tok_Equals; + case '>': + case '<': + yyCh = getChar(); + return Tok_Other; + case '\'': + yyCh = getChar(); + if (yyCh == '\\') + yyCh = getChar(); + + forever { + if (yyCh == EOF || yyCh == '\n') { + qWarning("%s:%d: Unterminated C++ character\n", + qPrintable(yyFileName), yyLineNo); + break; + } + yyCh = getChar(); + if (yyCh == '\'') { + yyCh = getChar(); + break; + } + } + break; + case '{': + if (yyBraceDepth == 0) + yyBraceLineNo = yyCurLineNo; + yyBraceDepth++; + yyCh = getChar(); + return Tok_LeftBrace; + case '}': + if (yyBraceDepth == yyMinBraceDepth) { + if (!inDefine) + qWarning("%s:%d: Excess closing brace in C++ code" + " (or abuse of the C++ preprocessor)\n", + qPrintable(yyFileName), yyCurLineNo); + // Avoid things getting messed up even more + yyCh = getChar(); + return Tok_Semicolon; + } + yyBraceDepth--; + yyCh = getChar(); + return Tok_RightBrace; + case '(': + if (yyParenDepth == 0) + yyParenLineNo = yyCurLineNo; + yyParenDepth++; + yyCh = getChar(); + return Tok_LeftParen; + case ')': + if (yyParenDepth == 0) + qWarning("%s:%d: Excess closing parenthesis in C++ code" + " (or abuse of the C++ preprocessor)\n", + qPrintable(yyFileName), yyCurLineNo); + else + yyParenDepth--; + yyCh = getChar(); + return Tok_RightParen; + case ',': + yyCh = getChar(); + return Tok_Comma; + case ';': + yyCh = getChar(); + return Tok_Semicolon; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + QByteArray ba; + ba += yyCh; + 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; + } + default: + yyCh = getChar(); + break; + } + } + } + return Tok_Eof; +} + +/* + The second part of this source file are namespace/class related + utilities for the third part. +*/ + +void CppParser::saveState(SavedState *state) +{ + state->namespaces = stringListifyNamespace(namespaces); + state->namespaceDepths = namespaceDepths; + state->functionContext = stringListifyNamespace(functionContext); + state->functionContextUnresolved = functionContextUnresolved; + state->pendingContext = pendingContext; +} + +void CppParser::loadState(const SavedState *state) +{ + namespaces = resolveNamespaces(state->namespaces); + namespaceDepths = state->namespaceDepths; + functionContext = resolveNamespaces(state->functionContext); + functionContextUnresolved = state->functionContextUnresolved; + pendingContext = state->pendingContext; +} + +bool ParseResults::detachNamespace(Namespace **that) +{ + 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; + pns = ns; + namespaces->replace(i, ns); + } +} + +QString CppParser::stringifyNamespace(const NamespaceList &namespaces) +{ + QString ret; + for (int i = 1; i < namespaces.count(); ++i) { + if (i > 1) + ret += QLatin1String("::"); + ret += namespaces.at(i)->name; + } + return ret; +} + +QStringList CppParser::stringListifyNamespace(const NamespaceList &namespaces) +{ + QStringList ret; + for (int i = 1; i < namespaces.count(); ++i) + ret << namespaces.at(i)->name; + return ret; +} + +// This function is called only with known-existing namespaces +NamespaceList CppParser::resolveNamespaces(const QStringList &segments) +{ + NamespaceList ret; + Namespace *ns = &results->rootNamespace; + ret << ns; + foreach (const QString &seg, segments) { + ns = ns->children.value(seg); + ret << ns; + } + return ret; +} + +bool CppParser::qualifyOne(const NamespaceList &namespaces, int nsIdx, const QString &segment, + NamespaceList *resolved) +{ + 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; + return true; + } + QMap<QString, QStringList>::ConstIterator nsai = ns->aliases.constFind(segment); + if (nsai != ns->aliases.constEnd()) { + *resolved = resolveNamespaces(*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 isDeclaration, + NamespaceList *resolved, QStringList *unresolved) +{ + int nsIdx; + int initSegIdx; + + if (segments.first().isEmpty()) { + // fully qualified + if (segments.count() == 1) { + resolved->clear(); + *resolved << &results->rootNamespace; + return true; + } + initSegIdx = 1; + nsIdx = 0; + } else { + initSegIdx = 0; + nsIdx = namespaces.count() - 1; + } + + do { + if (qualifyOne(namespaces, nsIdx, segments[initSegIdx], resolved)) { + int segIdx = initSegIdx; + while (++segIdx < segments.count()) { + if (!qualifyOne(*resolved, resolved->count() - 1, segments[segIdx], resolved)) { + if (unresolved) + *unresolved = segments.mid(segIdx); + return false; + } + } + return true; + } + } while (!isDeclaration && --nsIdx >= 0); + resolved->clear(); + *resolved << &results->rootNamespace; + if (unresolved) + *unresolved = segments.mid(initSegIdx); + return false; +} + +void CppParser::enterNamespace(NamespaceList *namespaces, const QString &name) +{ + 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; +} + +void CppParser::truncateNamespaces(NamespaceList *namespaces, int length) +{ + if (namespaces->count() > length) + namespaces->erase(namespaces->begin() + length, namespaces->end()); +} + +/* + Functions for processing include files. +*/ + +ParseResultHash &CppFiles::parsedFiles() +{ + static ParseResultHash parsed; + + return parsed; +} + +QSet<QString> &CppFiles::blacklistedFiles() +{ + static QSet<QString> blacklisted; + + return blacklisted; +} + +const ParseResults *CppFiles::getResults(const QString &cleanFile) +{ + ParseResultHash::ConstIterator it = parsedFiles().find(cleanFile); + if (it == parsedFiles().constEnd()) + return 0; + return *it; +} + +void CppFiles::setResults(const QString &cleanFile, const ParseResults *results) +{ + parsedFiles().insert(cleanFile, results); +} + +bool CppFiles::isBlacklisted(const QString &cleanFile) +{ + return blacklistedFiles().contains(cleanFile); +} + +void CppFiles::setBlacklisted(const QString &cleanFile) +{ + blacklistedFiles().insert(cleanFile); +} + +void CppParser::processInclude(const QString &file, ConversionData &cd, + QSet<QString> &inclusions) +{ + QString cleanFile = QDir::cleanPath(file); + + if (inclusions.contains(cleanFile)) { + qWarning("%s:%d: circular inclusion of %s\n", + qPrintable(yyFileName), yyLineNo, qPrintable(cleanFile)); + return; + } + + // If the #include is in any kind of namespace, has been blacklisted previously, + // or is not a header file (stdc++ extensionless or *.h*), then really include + // it. Otherwise it is safe to process it stand-alone and re-use the parsed + // namespace data for inclusion into other files. + 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); + + if (const ParseResults *res = CppFiles::getResults(cleanFile)) { + results->unite(res); + return; + } + + isIndirect = true; + } + } + + QFile f(cleanFile); + if (!f.open(QIODevice::ReadOnly)) { + qWarning("%s:%d: Cannot open %s: %s\n", + qPrintable(yyFileName), yyLineNo, + qPrintable(cleanFile), qPrintable(f.errorString())); + return; + } + + QTextStream ts(&f); + ts.setCodec(yySourceCodec); + ts.setAutoDetectUnicode(true); + + inclusions.insert(cleanFile); + if (isIndirect) { + CppParser parser; + foreach (const QString &projectRoot, cd.m_projectRoots) + if (cleanFile.startsWith(projectRoot)) { + parser.setTranslator(new Translator); + break; + } + parser.setInput(ts, cleanFile); + parser.parse(cd.m_defaultContext, cd, inclusions); + CppFiles::setResults(cleanFile, parser.getResults()); + results->unite(parser.results); + } else { + CppParser parser(results); + parser.namespaces = namespaces; + parser.functionContext = functionContext; + parser.functionContextUnresolved = functionContextUnresolved; + 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); + } + inclusions.remove(cleanFile); +} + +/* + The third part of this source file is the parser. It accomplishes + a very easy task: It finds all strings inside a tr() or translate() + call, and possibly finds out the context of the call. It supports + three cases: (1) the context is specified, as in + FunnyDialog::tr("Hello") or translate("FunnyDialog", "Hello"); + (2) the call appears within an inlined function; (3) the call + appears within a function defined outside the class definition. +*/ + +bool CppParser::match(uint t) +{ + bool matches = (yyTok == t); + if (matches) + yyTok = getToken(); + return matches; +} + +bool CppParser::matchString(QString *s) +{ + bool matches = (yyTok == Tok_String); + s->clear(); + while (yyTok == Tok_String) { + *s += yyString; + do { + yyTok = getToken(); + } while (yyTok == Tok_Comment); + } + return matches; +} + +bool CppParser::matchEncoding(bool *utf8) +{ + STRING(QApplication); + STRING(QCoreApplication); + STRING(UnicodeUTF8); + STRING(DefaultCodec); + STRING(CodecForTr); + + if (yyTok != Tok_Ident) + return false; + if (yyIdent == strQApplication || yyIdent == strQCoreApplication) { + yyTok = getToken(); + if (yyTok == Tok_ColonColon) + yyTok = getToken(); + } + if (yyIdent == strUnicodeUTF8) { + *utf8 = true; + yyTok = getToken(); + return true; + } + if (yyIdent == strDefaultCodec || yyIdent == strCodecForTr) { + *utf8 = false; + yyTok = getToken(); + 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; +} + +/* + * match any expression that can return a number, which can be + * 1. Literal number (e.g. '11') + * 2. simple identifier (e.g. 'm_count') + * 3. simple function call (e.g. 'size()' ) + * 4. function call on an object (e.g. 'list.size()') + * 5. function call on an object (e.g. 'list->size()') + * + * Other cases: + * size(2,4) + * list().size() + * list(a,b).size(2,4) + * etc... + */ +bool CppParser::matchExpression() +{ + if (match(Tok_Integer)) + return true; + + int parenlevel = 0; + while (match(Tok_Ident) || parenlevel > 0) { + if (yyTok == Tok_RightParen) { + if (parenlevel == 0) break; + --parenlevel; + yyTok = getToken(); + } else if (yyTok == Tok_LeftParen) { + yyTok = getToken(); + if (yyTok == Tok_RightParen) { + yyTok = getToken(); + } else { + ++parenlevel; + } + } else if (yyTok == Tok_Ident) { + continue; + } else if (yyTok == Tok_Arrow) { + yyTok = getToken(); + } else if (parenlevel == 0) { + return false; + } + } + return true; +} + +QString CppParser::transcode(const QString &str, bool utf8) +{ + static const char tab[] = "abfnrtv"; + static const char backTab[] = "\a\b\f\n\r\t\v"; + const QString in = (!utf8 || yySourceIsUnicode) + ? str : QString::fromUtf8(yySourceCodec->fromUnicode(str).data()); + QString out; + + out.reserve(in.length()); + for (int i = 0; i < in.length();) { + ushort c = in[i++].unicode(); + if (c == '\\') { + if (i >= in.length()) + break; + c = in[i++].unicode(); + + if (c == '\n') + continue; + + if (c == 'x') { + QByteArray hex; + while (i < in.length() && isxdigit((c = in[i].unicode()))) { + hex += c; + i++; + } + out += hex.toUInt(0, 16); + } else if (c >= '0' && c < '8') { + QByteArray oct; + int n = 0; + oct += c; + while (n < 2 && i < in.length() && (c = in[i].unicode()) >= '0' && c < '8') { + i++; + n++; + oct += c; + } + out += oct.toUInt(0, 8); + } else { + const char *p = strchr(tab, c); + out += QChar(QLatin1Char(!p ? c : backTab[p - tab])); + } + } else { + out += c; + } + } + return out; +} + +void CppParser::recordMessage( + int line, const QString &context, const QString &text, const QString &comment, + const QString &extracomment, const QString &msgid, const TranslatorMessage::ExtraData &extra, + bool utf8, bool plural) +{ + TranslatorMessage msg( + transcode(context, utf8), transcode(text, utf8), transcode(comment, utf8), QString(), + yyFileName, line, QStringList(), + TranslatorMessage::Unfinished, plural); + msg.setExtraComment(transcode(extracomment.simplified(), utf8)); + msg.setId(msgid); + msg.setExtras(extra); + if ((utf8 || yyForceUtf8) && !yyCodecIsUtf8 && msg.needs8Bit()) + msg.setUtf8(true); + results->tor->append(msg); +} + +void CppParser::parse(const QString &initialContext, ConversionData &cd, + QSet<QString> &inclusions) +{ + if (results->tor) + yyCodecIsUtf8 = (results->tor->codecName() == "UTF-8"); + + namespaces << &results->rootNamespace; + functionContext = namespaces; + functionContextUnresolved = initialContext; + + parseInternal(cd, inclusions); +} + +void CppParser::parseInternal(ConversionData &cd, QSet<QString> &inclusions) +{ + static QString strColons(QLatin1String("::")); + + QString context; + QString text; + QString comment; + QString extracomment; + QString msgid; + QString sourcetext; + TranslatorMessage::ExtraData extra; + QString prefix; +#ifdef DIAGNOSE_RETRANSLATABILITY + QString functionName; +#endif + int line; + bool utf8; + bool yyTokColonSeen = false; // Start of c'tor's initializer list + + yyCh = getChar(); + yyTok = getToken(); + while (yyTok != Tok_Eof) { + //qDebug() << "TOKEN: " << yyTok; + switch (yyTok) { + case Tok_QuotedInclude: { + text = QDir(QFileInfo(yyFileName).absolutePath()).absoluteFilePath(yyString); + if (QFileInfo(text).isFile()) { + processInclude(text, cd, inclusions); + yyTok = getToken(); + break; + } + } + /* fall through */ + case Tok_AngledInclude: { + QStringList cSources = cd.m_allCSources.values(yyString); + if (!cSources.isEmpty()) { + foreach (const QString &cSource, cSources) + processInclude(cSource, cd, inclusions); + goto incOk; + } + foreach (const QString &incPath, cd.m_includePath) { + text = QDir(incPath).absoluteFilePath(yyString); + if (QFileInfo(text).isFile()) { + processInclude(text, cd, inclusions); + goto incOk; + } + } + incOk: + yyTok = getToken(); + break; + } + case Tok_friend: + yyTok = getToken(); + // Ensure that these don't end up being interpreted as forward declarations + // (they are forwards, but with different namespacing). + if (yyTok == Tok_class) + yyTok = getToken(); + break; + case Tok_class: + yyTokColonSeen = false; + /* + Partial support for inlined functions. + */ + yyTok = getToken(); + if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) { + QStringList fct; + do { + /* + This code should execute only once, but we play + safe with impure definitions such as + 'class Q_EXPORT QMessageBox', in which case + 'QMessageBox' is the class name, not 'Q_EXPORT'. + */ + fct = QStringList(yyIdent); + yyTok = getToken(); + } while (yyTok == Tok_Ident); + while (yyTok == Tok_ColonColon) { + yyTok = getToken(); + if (yyTok != Tok_Ident) + break; // Oops ... + fct += yyIdent; + 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 + // 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()); + break; + } + } + + functionContext = namespaces; + functionContextUnresolved.clear(); // Pointless + prospectiveContext.clear(); + pendingContext.clear(); + } + break; + case Tok_namespace: + yyTokColonSeen = false; + yyTok = getToken(); + if (yyTok == Tok_Ident) { + QString ns = yyIdent; + yyTok = getToken(); + if (yyTok == Tok_LeftBrace) { + namespaceDepths.push(namespaces.count()); + enterNamespace(&namespaces, ns); + yyTok = getToken(); + } else if (yyTok == Tok_Equals) { + // e.g. namespace Is = OuterSpace::InnerSpace; + QStringList fullName; + yyTok = getToken(); + if (yyTok == Tok_ColonColon) + fullName.append(QString()); + while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { + if (yyTok == Tok_Ident) + fullName.append(yyIdent); + yyTok = getToken(); + } + if (fullName.isEmpty()) + break; + NamespaceList nsl; + if (fullyQualify(namespaces, fullName, false, &nsl, 0)) { + modifyNamespace(&namespaces); + namespaces.last()->aliases.insert(ns, stringListifyNamespace(nsl)); + } + } + } else if (yyTok == Tok_LeftBrace) { + // Anonymous namespace + namespaceDepths.push(namespaces.count()); + yyTok = getToken(); + } + break; + case Tok_using: + yyTok = getToken(); + if (yyTok == Tok_namespace) { + QStringList fullName; + yyTok = getToken(); + if (yyTok == Tok_ColonColon) + fullName.append(QString()); + while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { + if (yyTok == Tok_Ident) + fullName.append(yyIdent); + yyTok = getToken(); + } + NamespaceList nsl; + QStringList unresolved; + if (fullyQualify(namespaces, fullName, false, &nsl, &unresolved)) { + modifyNamespace(&namespaces); + namespaces.last()->usings.insert(stringListifyNamespace(nsl)); + } + } else { + QStringList fullName; + if (yyTok == Tok_ColonColon) + fullName.append(QString()); + while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { + if (yyTok == Tok_Ident) + fullName.append(yyIdent); + 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)); + } + } + break; + case Tok_tr: + case Tok_trUtf8: + if (!results->tor) + goto case_default; + if (!sourcetext.isEmpty()) + qWarning("%s:%d: //%% cannot be used with tr() / QT_TR_NOOP(). Ignoring\n", + qPrintable(yyFileName), yyLineNo); + utf8 = (yyTok == Tok_trUtf8); + line = yyLineNo; + yyTok = getToken(); + if (match(Tok_LeftParen) && matchString(&text) && !text.isEmpty()) { + comment.clear(); + bool plural = false; + + if (match(Tok_RightParen)) { + // no comment + } else if (match(Tok_Comma) && matchStringOrNull(&comment)) { //comment + if (match(Tok_RightParen)) { + // ok, + } else if (match(Tok_Comma)) { + plural = true; + } + } + if (!pendingContext.isEmpty()) { + QStringList unresolved; + if (!fullyQualify(namespaces, pendingContext.split(strColons), true, + &functionContext, &unresolved)) { + functionContextUnresolved = unresolved.join(strColons); + qWarning("%s:%d: Qualifying with unknown namespace/class %s::%s\n", + qPrintable(yyFileName), yyLineNo, + qPrintable(stringifyNamespace(functionContext)), + qPrintable(unresolved.first())); + } + pendingContext.clear(); + } + if (prefix.isEmpty()) { + if (functionContextUnresolved.isEmpty()) { + int idx = functionContext.length(); + if (idx < 2) { + qWarning("%s:%d: tr() cannot be called without context\n", + 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) { + qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", + qPrintable(yyFileName), yyLineNo, + qPrintable(stringifyNamespace(functionContext))); + functionContext.last()->complained = true; + } + break; + } + --idx; + } + context.clear(); + for (int i = 1;;) { + context += functionContext.at(i)->name; + if (++i == idx) + break; + context += strColons; + } + } else { + context = (stringListifyNamespace(functionContext) + << functionContextUnresolved).join(strColons); + } + } else { +#ifdef DIAGNOSE_RETRANSLATABILITY + int last = prefix.lastIndexOf(strColons); + QString className = prefix.mid(last == -1 ? 0 : last + 2); + if (!className.isEmpty() && className == functionName) { + qWarning("%s::%d: It is not recommended to call tr() from within a constructor '%s::%s' ", + qPrintable(yyFileName), yyLineNo, + className.constData(), functionName.constData()); + } +#endif + prefix.chop(2); + NamespaceList nsl; + QStringList unresolved; + if (fullyQualify(functionContext, prefix.split(strColons), false, &nsl, &unresolved)) { + if (!nsl.last()->hasTrFunctions && !nsl.last()->complained) { + qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro\n", + qPrintable(yyFileName), yyLineNo, + qPrintable(stringifyNamespace(nsl))); + nsl.last()->complained = true; + } + context = stringifyNamespace(nsl); + } else { + context = (stringListifyNamespace(nsl) + unresolved).join(strColons); + } + prefix.clear(); + } + + recordMessage(line, context, text, comment, extracomment, msgid, extra, utf8, plural); + } + extracomment.clear(); + msgid.clear(); + extra.clear(); + break; + case Tok_translateUtf8: + case Tok_translate: + if (!results->tor) + goto case_default; + if (!sourcetext.isEmpty()) + qWarning("%s:%d: //%% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring\n", + qPrintable(yyFileName), yyLineNo); + utf8 = (yyTok == Tok_translateUtf8); + line = yyLineNo; + yyTok = getToken(); + if (match(Tok_LeftParen) + && matchString(&context) + && match(Tok_Comma) + && matchString(&text) && !text.isEmpty()) + { + comment.clear(); + bool plural = false; + if (!match(Tok_RightParen)) { + // look for comment + if (match(Tok_Comma) && matchStringOrNull(&comment)) { + if (!match(Tok_RightParen)) { + // look for encoding + if (match(Tok_Comma)) { + if (matchEncoding(&utf8)) { + if (!match(Tok_RightParen)) { + // look for the plural quantifier, + // this can be a number, an identifier or + // a function call, + // so for simplicity we mark it as plural if + // we know we have a comma instead of an + // right parentheses. + plural = match(Tok_Comma); + } + } else { + // This can be a QTranslator::translate("context", + // "source", "comment", n) plural translation + if (matchExpression() && match(Tok_RightParen)) { + plural = true; + } else { + break; + } + } + } else { + break; + } + } + } else { + break; + } + } + recordMessage(line, context, text, comment, extracomment, msgid, extra, utf8, plural); + } + extracomment.clear(); + msgid.clear(); + extra.clear(); + break; + case Tok_trid: + if (!results->tor) + goto case_default; + if (sourcetext.isEmpty()) { + yyTok = getToken(); + } else { + if (!msgid.isEmpty()) + qWarning("%s:%d: //= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring\n", + qPrintable(yyFileName), yyLineNo); + //utf8 = false; // Maybe use //%% or something like that + line = yyLineNo; + yyTok = getToken(); + if (match(Tok_LeftParen) && matchString(&msgid) && !msgid.isEmpty()) { + bool plural = match(Tok_Comma); + recordMessage(line, QString(), sourcetext, QString(), extracomment, + msgid, extra, false, plural); + } + sourcetext.clear(); + } + extracomment.clear(); + msgid.clear(); + extra.clear(); + break; + case Tok_Q_DECLARE_TR_FUNCTIONS: + case Tok_Q_OBJECT: + namespaces.last()->hasTrFunctions = true; + yyTok = getToken(); + break; + case Tok_Ident: + prefix += yyIdent; + yyTok = getToken(); + if (yyTok != Tok_ColonColon) { + prefix.clear(); + if (yyTok == Tok_Ident && !yyParenDepth) + prospectiveContext.clear(); + } + break; + case Tok_Comment: + if (!results->tor) + goto case_default; + if (yyComment.startsWith(QLatin1Char(':'))) { + yyComment.remove(0, 1); + extracomment.append(yyComment); + } else if (yyComment.startsWith(QLatin1Char('='))) { + yyComment.remove(0, 1); + msgid = yyComment.simplified(); + } else if (yyComment.startsWith(QLatin1Char('~'))) { + yyComment.remove(0, 1); + yyComment = yyComment.trimmed(); + int k = yyComment.indexOf(QLatin1Char(' ')); + if (k > -1) + extra.insert(yyComment.left(k), yyComment.mid(k + 1).trimmed()); + } else if (yyComment.startsWith(QLatin1Char('%'))) { + int p = 1, c; + forever { + if (p >= yyComment.length()) + break; + c = yyComment.unicode()[p++].unicode(); + if (isspace(c)) + continue; + if (c != '"') { + qWarning("%s:%d: Unexpected character in meta string\n", + qPrintable(yyFileName), yyLineNo); + break; + } + forever { + if (p >= yyComment.length()) { + whoops: + qWarning("%s:%d: Unterminated meta string\n", + qPrintable(yyFileName), yyLineNo); + break; + } + c = yyComment.unicode()[p++].unicode(); + if (c == '"') + break; + if (c == '\\') { + if (p >= yyComment.length()) + goto whoops; + c = yyComment.unicode()[p++].unicode(); + if (c == '\n') + goto whoops; + sourcetext.append(QLatin1Char('\\')); + } + sourcetext.append(c); + } + } + } else { + comment = yyComment.simplified(); + if (comment.startsWith(QLatin1String(MagicComment))) { + comment.remove(0, sizeof(MagicComment) - 1); + int k = comment.indexOf(QLatin1Char(' ')); + if (k == -1) { + context = comment; + } else { + context = comment.left(k); + comment.remove(0, k + 1); + recordMessage(yyLineNo, context, QString(), comment, extracomment, + QString(), TranslatorMessage::ExtraData(), false, false); + extracomment.clear(); + results->tor->setExtras(extra); + extra.clear(); + } + } + } + yyTok = getToken(); + break; + case Tok_Arrow: + yyTok = getToken(); + if (yyTok == Tok_tr || yyTok == Tok_trUtf8) + qWarning("%s:%d: Cannot invoke tr() like this\n", + qPrintable(yyFileName), yyLineNo); + break; + case Tok_ColonColon: + if (yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0 && !yyTokColonSeen) + prospectiveContext = prefix; + prefix += strColons; + yyTok = getToken(); +#ifdef DIAGNOSE_RETRANSLATABILITY + if (yyTok == Tok_Ident && yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) + functionName = yyIdent; +#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; + } + truncateNamespaces(&namespaces, namespaceDepths.pop()); + } + if (yyBraceDepth == namespaceDepths.count()) { + // function, class or namespace + if (!yyBraceDepth && !directInclude) { + truncateNamespaces(&functionContext, 1); + functionContextUnresolved = cd.m_defaultContext; + } else { + functionContext = namespaces; + functionContextUnresolved.clear(); + } + pendingContext.clear(); + } + // fallthrough + case Tok_Semicolon: + prospectiveContext.clear(); + prefix.clear(); + extracomment.clear(); + msgid.clear(); + extra.clear(); + yyTokColonSeen = false; + yyTok = getToken(); + break; + case Tok_Colon: + if (!prospectiveContext.isEmpty() + && yyBraceDepth == namespaceDepths.count() && yyParenDepth == 0) + pendingContext = prospectiveContext; + yyTokColonSeen = true; + yyTok = getToken(); + break; + case Tok_LeftBrace: + if (!prospectiveContext.isEmpty() + && yyBraceDepth == namespaceDepths.count() + 1 && yyParenDepth == 0) + pendingContext = prospectiveContext; + // fallthrough + case Tok_LeftParen: + case Tok_RightParen: + yyTokColonSeen = false; + yyTok = getToken(); + break; + default: + if (!yyParenDepth) + prospectiveContext.clear(); + case_default: + yyTok = getToken(); + break; + } + } + + if (yyBraceDepth != 0) + qWarning("%s:%d: Unbalanced opening brace in C++ code" + " (or abuse of the C++ preprocessor)\n", + qPrintable(yyFileName), yyBraceLineNo); + else if (yyParenDepth != 0) + qWarning("%s:%d: Unbalanced opening parenthesis in C++ code" + " (or abuse of the C++ preprocessor)\n", + qPrintable(yyFileName), yyParenLineNo); +} + +/* + Fetches tr() calls in C++ code in UI files (inside "<function>" + tag). This mechanism is obsolete. +*/ +void fetchtrInlinedCpp(const QString &in, Translator &translator, const QString &context) +{ + CppParser parser; + parser.setInput(in); + ConversionData cd; + QSet<QString> inclusions; + parser.setTranslator(&translator); + parser.parse(context, cd, inclusions); + parser.deleteResults(); +} + +void loadCPP(Translator &translator, const QStringList &filenames, ConversionData &cd) +{ + QByteArray codecName = cd.m_codecForSource.isEmpty() + ? translator.codecName() : cd.m_codecForSource; + QTextCodec *codec = QTextCodec::codecForName(codecName); + + foreach (const QString &filename, filenames) { + if (CppFiles::getResults(filename) || CppFiles::isBlacklisted(filename)) + continue; + + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + cd.appendError(QString::fromLatin1("Cannot open %1: %2") + .arg(filename, file.errorString())); + continue; + } + + CppParser parser; + QTextStream ts(&file); + ts.setCodec(codec); + ts.setAutoDetectUnicode(true); + if (ts.codec()->name() == "UTF-16") + translator.setCodecName("System"); + parser.setInput(ts, filename); + Translator *tor = new Translator; + tor->setCodecName(translator.codecName()); + parser.setTranslator(tor); + QSet<QString> inclusions; + parser.parse(cd.m_defaultContext, cd, inclusions); + CppFiles::setResults(filename, parser.getResults()); + } + + foreach (const QString filename, filenames) + if (!CppFiles::isBlacklisted(filename)) + if (Translator *tor = CppFiles::getResults(filename)->tor) + foreach (const TranslatorMessage &msg, tor->messages()) + translator.extend(msg); +} + +QT_END_NAMESPACE diff --git a/tools/linguist/shared/java.cpp b/tools/linguist/lupdate/java.cpp index c91a55a..8a5d975 100644 --- a/tools/linguist/shared/java.cpp +++ b/tools/linguist/lupdate/java.cpp @@ -39,7 +39,9 @@ ** ****************************************************************************/ -#include "translator.h" +#include "lupdate.h" + +#include <translator.h> #include <QtCore/QDebug> #include <QtCore/QFile> @@ -373,22 +375,13 @@ static bool matchString( QString &s ) return true; } -static bool matchInteger( qlonglong *number) -{ - bool matches = (yyTok == Tok_Integer); - if (matches) { - yyTok = getToken(); - *number = yyInteger; - } - return matches; -} - static bool matchStringOrNull(QString &s) { bool matches = matchString(s); if (!matches) { matches = (yyTok == Tok_null); - if (matches) yyTok = getToken(); + if (matches) + yyTok = getToken(); } return matches; } @@ -606,14 +599,18 @@ static void parse( Translator *tor ) } -bool loadJava(Translator &translator, QIODevice &dev, ConversionData &cd) +bool loadJava(Translator &translator, const QString &filename, ConversionData &cd) { - //void LupdateApplication::fetchtr_java( const QString &fileName, Translator *tor, - //const QString &defaultContext, bool mustExist, const QByteArray &codecForSource ) + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + cd.appendError(QString::fromLatin1("Cannot open %1: %2") + .arg(filename, file.errorString())); + return false; + } yyDefaultContext = cd.m_defaultContext; yyInPos = -1; - yyFileName = cd.m_sourceFileName; + yyFileName = filename; yyPackage.clear(); yyScope.clear(); yyTok = -1; @@ -621,7 +618,7 @@ bool loadJava(Translator &translator, QIODevice &dev, ConversionData &cd) yyCurLineNo = 0; yyParenLineNo = 1; - QTextStream ts(&dev); + QTextStream ts(&file); QByteArray codecName; if (!cd.m_codecForSource.isEmpty()) codecName = cd.m_codecForSource; @@ -631,7 +628,7 @@ bool loadJava(Translator &translator, QIODevice &dev, ConversionData &cd) ts.setAutoDetectUnicode(true); yyInStr = ts.readAll(); yyInPos = 0; - yyFileName = cd.m_sourceFileName; + yyFileName = filename; yyCurLineNo = 1; yyParenLineNo = 1; yyCh = getChar(); @@ -643,19 +640,4 @@ bool loadJava(Translator &translator, QIODevice &dev, ConversionData &cd) return true; } -int initJava() -{ - Translator::FileFormat format; - format.extension = QLatin1String("java"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.description = QObject::tr("Java source files"); - format.loader = &loadJava; - format.saver = 0; - Translator::registerFileFormat(format); - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(initJava) - QT_END_NAMESPACE diff --git a/tools/linguist/lupdate/lupdate.1 b/tools/linguist/lupdate/lupdate.1 index 68958b9..b37e7b3 100644 --- a/tools/linguist/lupdate/lupdate.1 +++ b/tools/linguist/lupdate/lupdate.1 @@ -52,12 +52,12 @@ tool for the Qt GUI toolkit. .B Lupdate reads a qmake/tmake project file (.pro file), finds the translatable strings in the specified source, header and interface files, and -updates the translation files (.ts files) specified in it. The +updates the translation files (TS files) specified in it. The translation files are given to the translator who uses .B Qt Linguist to read the files and insert the translations. .PP -The .ts file format is a simple human-readable XML format that can be +The TS file format is a simple human-readable XML format that can be used with version control systems if required. .PP .SH OPTIONS @@ -74,7 +74,7 @@ Default: 'ui,c,c++,cc,cpp,cxx,ch,h,h++,hh,hpp,hxx'. Display the usage and exit. .TP .I "-locations {absolute|relative|none}" -Specify/override how source code references are saved in ts files. +Specify/override how source code references are saved in TS files. Default is absolute. .TP .I "-no-obsolete" @@ -84,7 +84,7 @@ Drop all obsolete strings. Do not recursively scan the following directories. .TP .I "-no-sort" -Do not sort contexts in .ts files. +Do not sort contexts in TS files. .TP .I "-pluralonly" Only include plural form messages. @@ -97,7 +97,7 @@ file syntax but different file suffix Recursively scan the following directories. .TP .I "-silent" -Don't explain what is being done. +Do not explain what is being done. .TP .I "-source-language <language>[_<region>]" Specify/override the language of the source strings. Defaults to @@ -139,8 +139,8 @@ translations will be reused as far as possible, and translated strings that have vanished from the source files are marked obsolete. .PP .B lupdate -can also be invoked with a list of C++ source files, .ui files -and .ts files: +can also be invoked with a list of C++ source files, UI files +and TS files: .PP .in +4 .nf diff --git a/tools/linguist/shared/translatortools.h b/tools/linguist/lupdate/lupdate.h index 25ba612..7e28cf5 100644 --- a/tools/linguist/shared/translatortools.h +++ b/tools/linguist/lupdate/lupdate.h @@ -48,7 +48,9 @@ QT_BEGIN_NAMESPACE +class ConversionData; class QString; +class QStringList; class Translator; class TranslatorMessage; @@ -72,6 +74,12 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(UpdateOptions) Translator merge(const Translator &tor, const Translator &virginTor, UpdateOptions options, QString &err); +void fetchtrInlinedCpp(const QString &in, Translator &translator, const QString &context); +void loadCPP(Translator &translator, const QStringList &filenames, ConversionData &cd); +bool loadJava(Translator &translator, const QString &filename, ConversionData &cd); +bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd); +bool loadUI(Translator &translator, const QString &filename, ConversionData &cd); + QT_END_NAMESPACE #endif diff --git a/tools/linguist/lupdate/lupdate.pro b/tools/linguist/lupdate/lupdate.pro index b05a4ef..ccc2d47 100644 --- a/tools/linguist/lupdate/lupdate.pro +++ b/tools/linguist/lupdate/lupdate.pro @@ -14,9 +14,20 @@ build_all:!build_pass { include(../shared/formats.pri) include(../shared/proparser.pri) -include(../shared/translatortools.pri) -SOURCES += main.cpp +SOURCES += \ + main.cpp \ + merge.cpp \ + ../shared/simtexth.cpp \ + \ + cpp.cpp \ + java.cpp \ + qscript.cpp \ + ui.cpp + +HEADERS += \ + lupdate.h \ + ../shared/simtexth.h DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII diff --git a/tools/linguist/lupdate/main.cpp b/tools/linguist/lupdate/main.cpp index 6b454ef..5a26774 100644 --- a/tools/linguist/lupdate/main.cpp +++ b/tools/linguist/lupdate/main.cpp @@ -39,10 +39,11 @@ ** ****************************************************************************/ -#include "translator.h" -#include "translatortools.h" -#include "profileevaluator.h" -#include "proreader.h" +#include "lupdate.h" + +#include <translator.h> +#include <profileevaluator.h> +#include <proreader.h> #include <QtCore/QCoreApplication> #include <QtCore/QDebug> @@ -84,12 +85,12 @@ static void printUsage() { printOut(QObject::tr( "Usage:\n" - " lupdate [options] [project-file]\n" + " lupdate [options] [project-file]...\n" " lupdate [options] [source-file|path]... -ts ts-files\n\n" - "lupdate is part of Qt's Linguist tool chain. It can be used as a\n" - "stand-alone tool to create XML based translations files in the .ts\n" - "format from translatable messages in C++ and Java source code.\n\n" - "lupdate can also merge such messages into existing .ts files.\n\n" + "lupdate is part of Qt's Linguist tool chain. It extracts translatable\n" + "messages from Qt UI files, C++, Java and JavaScript/QtScript source code.\n" + "Extracted messages are stored in textual translation source files (typically\n" + "Qt TS XML). New and modified messages can be merged into existing TS files.\n\n" "Options:\n" " -help Display this information and exit.\n" " -no-obsolete\n" @@ -103,16 +104,19 @@ static void printUsage() " -silent\n" " Do not explain what is being done.\n" " -no-sort\n" - " Do not sort contexts in .ts files.\n" + " Do not sort contexts in TS files.\n" " -no-recursive\n" " Do not recursively scan the following directories.\n" " -recursive\n" - " Recursively scan the following directories.\n" + " Recursively scan the following directories (default).\n" + " -I <includepath> or -I<includepath>\n" + " Additional location to look for include files.\n" + " May be specified multiple times.\n" " -locations {absolute|relative|none}\n" - " Specify/override how source code references are saved in ts files.\n" + " Specify/override how source code references are saved in TS files.\n" " Default is absolute.\n" " -no-ui-lines\n" - " Do not record line numbers in references to .ui files.\n" + " Do not record line numbers in references to UI files.\n" " -disable-heuristic {sametext|similartext|number}\n" " Disable the named merge heuristic. Can be specified multiple times.\n" " -pro <filename>\n" @@ -223,7 +227,10 @@ int main(int argc, char **argv) QByteArray codecForSource; QStringList tsFileNames; QStringList proFiles; + QMultiHash<QString, QString> allCSources; + QSet<QString> projectRoots; QStringList sourceFiles; + QStringList includePath; QString targetLanguage; QString sourceLanguage; @@ -350,6 +357,18 @@ int main(int argc, char **argv) proFiles += args[i]; numFiles++; continue; + } else if (arg.startsWith(QLatin1String("-I"))) { + if (arg.length() == 2) { + ++i; + if (i == argc) { + qWarning("The -I option should be followed by a path."); + return 1; + } + includePath += args[i]; + } else { + includePath += args[i].mid(2); + } + continue; } else if (arg.startsWith(QLatin1String("-")) && arg != QLatin1String("-")) { qWarning("Unrecognized option '%s'", qPrintable(arg)); return 1; @@ -394,33 +413,46 @@ int main(int argc, char **argv) if (options & Verbose) printOut(QObject::tr("Scanning directory '%1'...").arg(arg)); QDir dir = QDir(fi.filePath()); + projectRoots.insert(dir.absolutePath() + QLatin1Char('/')); if (extensionsNameFilters.isEmpty()) { - extensions = extensions.trimmed(); - // Remove the potential dot in front of each extension - if (extensions.startsWith(QLatin1Char('.'))) - extensions.remove(0,1); - extensions.replace(QLatin1String(",."), QLatin1String(",")); - - extensions.insert(0, QLatin1String("*.")); - extensions.replace(QLatin1Char(','), QLatin1String(",*.")); - extensionsNameFilters = extensions.split(QLatin1Char(',')); + foreach (QString ext, extensions.split(QLatin1Char(','))) { + ext = ext.trimmed(); + if (ext.startsWith(QLatin1Char('.'))) + ext.remove(0,1); + ext.insert(0, QLatin1String("*.")); + extensionsNameFilters << ext; + } } QDir::Filters filters = QDir::Files | QDir::NoSymLinks; QFileInfoList fileinfolist; recursiveFileInfoList(dir, extensionsNameFilters, filters, recursiveScan, &fileinfolist); - QFileInfoList::iterator ii; - QString fn; - for (ii = fileinfolist.begin(); ii != fileinfolist.end(); ++ii) { - // Make sure the path separator is stored with '/' in the ts file - sourceFiles << ii->canonicalFilePath().replace(QLatin1Char('\\'), QLatin1Char('/')); + int scanRootLen = dir.absolutePath().length(); + foreach (const QFileInfo &fi, fileinfolist) { + QString fn = QDir::cleanPath(fi.absoluteFilePath()); + sourceFiles << fn; + + if (!fn.endsWith(QLatin1String(".java")) + && !fn.endsWith(QLatin1String(".ui")) + && !fn.endsWith(QLatin1String(".js")) + && !fn.endsWith(QLatin1String(".qs"))) { + int offset = 0; + int depth = 0; + do { + offset = fn.lastIndexOf(QLatin1Char('/'), offset - 1); + QString ffn = fn.mid(offset + 1); + allCSources.insert(ffn, fn); + } while (++depth < 3 && offset > scanRootLen); + } } } else { - sourceFiles << fi.canonicalFilePath().replace(QLatin1Char('\\'), QLatin1Char('/')); + sourceFiles << QDir::cleanPath(fi.absoluteFilePath());; } } } // for args + foreach (const QString &proFile, proFiles) + projectRoots.insert(QDir::cleanPath(QFileInfo(proFile).absolutePath()) + QLatin1Char('/')); bool firstPass = true; bool fail = false; @@ -428,6 +460,9 @@ int main(int argc, char **argv) ConversionData cd; cd.m_defaultContext = defaultContext; cd.m_noUiLines = options & NoUiLines; + cd.m_projectRoots = projectRoots; + cd.m_includePath = includePath; + cd.m_allCSources = allCSources; QStringList tsFiles = tsFileNames; if (proFiles.count() > 0) { @@ -457,6 +492,8 @@ int main(int argc, char **argv) continue; } + cd.m_includePath += visitor.values(QLatin1String("INCLUDEPATH")); + evaluateProFile(visitor, &variables, pfi.absolutePath()); sourceFiles = variables.value("SOURCES"); @@ -479,30 +516,20 @@ int main(int argc, char **argv) tsFiles += variables.value("TRANSLATIONS"); } + QStringList sourceFilesCpp; for (QStringList::iterator it = sourceFiles.begin(); it != sourceFiles.end(); ++it) { - if (it->endsWith(QLatin1String(".java"), Qt::CaseInsensitive)) { - cd.m_sourceFileName = *it; - fetchedTor.load(*it, cd, QLatin1String("java")); - //fetchtr_java(*it, &fetchedTor, defaultContext, true, codecForSource); - } - else if (it->endsWith(QLatin1String(".jui"), Qt::CaseInsensitive)) { - fetchedTor.load(*it, cd, QLatin1String("jui")); - } - else if (it->endsWith(QLatin1String(".ui"), Qt::CaseInsensitive)) { - fetchedTor.load(*it, cd, QLatin1String("ui")); - //fetchedTor.load(*it + QLatin1String(".h"), cd, QLatin1String("cpp")); - //fetchtr_ui(*it, &fetchedTor, defaultContext, true); - //fetchtr_cpp(*it + QLatin1String(".h"), &fetchedTor, - // defaultContext, false, codecForSource); - } + if (it->endsWith(QLatin1String(".java"), Qt::CaseInsensitive)) + loadJava(fetchedTor, *it, cd); + else if (it->endsWith(QLatin1String(".ui"), Qt::CaseInsensitive) + || it->endsWith(QLatin1String(".jui"), Qt::CaseInsensitive)) + loadUI(fetchedTor, *it, cd); else if (it->endsWith(QLatin1String(".js"), Qt::CaseInsensitive) - || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive)) { - fetchedTor.load(*it, cd, QLatin1String("js")); - } else { - fetchedTor.load(*it, cd, QLatin1String("cpp")); - //fetchtr_cpp(*it, &fetchedTor, defaultContext, true, codecForSource); - } + || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive)) + loadQScript(fetchedTor, *it, cd); + else + sourceFilesCpp << *it; } + loadCPP(fetchedTor, sourceFilesCpp, cd); if (!cd.error().isEmpty()) printOut(cd.error()); diff --git a/tools/linguist/shared/translatortools.cpp b/tools/linguist/lupdate/merge.cpp index 01a1f48..7925fb2 100644 --- a/tools/linguist/shared/translatortools.cpp +++ b/tools/linguist/lupdate/merge.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "translatortools.h" +#include "lupdate.h" #include "simtexth.h" #include "translator.h" @@ -193,7 +193,7 @@ static QString translationAttempt(const QString &oldTranslation, */ for (k = 0; k < p; k++) { if (!met[k]) - attempt += QString(QLatin1String(" {")) + newNumbers[k] + QString(QLatin1String("?}")); + attempt += QLatin1String(" {") + newNumbers[k] + QLatin1String("?}"); } /* @@ -205,8 +205,8 @@ static QString translationAttempt(const QString &oldTranslation, for (ell = 0; ell < p; ell++) { if (k != ell && oldNumbers[k] == oldNumbers[ell] && newNumbers[k] < newNumbers[ell]) - attempt += QString(QLatin1String(" {")) + newNumbers[k] + QString(QLatin1String(" or ")) + - newNumbers[ell] + QString(QLatin1String("?}")); + attempt += QLatin1String(" {") + newNumbers[k] + QLatin1String(" or ") + + newNumbers[ell] + QLatin1String("?}"); } } return attempt; diff --git a/tools/linguist/shared/qscript.cpp b/tools/linguist/lupdate/qscript.cpp index bec1cf1..7a701ae 100644 --- a/tools/linguist/shared/qscript.cpp +++ b/tools/linguist/lupdate/qscript.cpp @@ -752,7 +752,7 @@ const int QScriptGrammar::action_check [] = { #define Q_SCRIPT_REGEXPLITERAL_RULE2 8 -#include "translator.h" +#include <translator.h> #include <QtCore/qdebug.h> #include <QtCore/qnumeric.h> @@ -2356,9 +2356,15 @@ case 94: { } -bool loadQScript(Translator &translator, QIODevice &dev, ConversionData &cd) +bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd) { - QTextStream ts(&dev); + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + cd.appendError(QString::fromLatin1("Cannot open %1: %2") + .arg(filename, file.errorString())); + return false; + } + QTextStream ts(&file); QByteArray codecName; if (!cd.m_codecForSource.isEmpty()) codecName = cd.m_codecForSource; @@ -2371,8 +2377,8 @@ bool loadQScript(Translator &translator, QIODevice &dev, ConversionData &cd) QScript::Lexer lexer; lexer.setCode(code, /*lineNumber=*/1); QScriptParser parser; - if (!parser.parse(&lexer, cd.m_sourceFileName, &translator)) { - qWarning("%s:%d: %s", qPrintable(cd.m_sourceFileName), parser.errorLineNumber(), + if (!parser.parse(&lexer, filename, &translator)) { + qWarning("%s:%d: %s", qPrintable(filename), parser.errorLineNumber(), qPrintable(parser.errorMessage())); return false; } @@ -2382,27 +2388,4 @@ bool loadQScript(Translator &translator, QIODevice &dev, ConversionData &cd) return true; } -bool saveQScript(const Translator &translator, QIODevice &dev, ConversionData &cd) -{ - Q_UNUSED(dev); - Q_UNUSED(translator); - cd.appendError(QLatin1String("Cannot save .js files")); - return false; -} - -int initQScript() -{ - Translator::FileFormat format; - format.extension = QLatin1String("js"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.description = QObject::tr("Qt Script source files"); - format.loader = &loadQScript; - format.saver = &saveQScript; - Translator::registerFileFormat(format); - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(initQScript) - QT_END_NAMESPACE diff --git a/tools/linguist/shared/qscript.g b/tools/linguist/lupdate/qscript.g index 128699d..4e36395 100644 --- a/tools/linguist/shared/qscript.g +++ b/tools/linguist/lupdate/qscript.g @@ -42,6 +42,10 @@ -- ---------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +-- Process with "qlalr --no-debug --no-lines qscript.g" to update qscript.cpp -- +-------------------------------------------------------------------------------- + %parser QScriptGrammar %merged_output qscript.cpp %expect 3 @@ -81,7 +85,7 @@ %start Program /. -#include "translator.h" +#include <translator.h> #include <QtCore/qdebug.h> #include <QtCore/qnumeric.h> @@ -1986,9 +1990,15 @@ PropertyNameAndValueListOpt: PropertyNameAndValueList ; } -bool loadQScript(Translator &translator, QIODevice &dev, ConversionData &cd) +bool loadQScript(Translator &translator, const QString &filename, ConversionData &cd) { - QTextStream ts(&dev); + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + cd.appendError(QString::fromLatin1("Cannot open %1: %2") + .arg(filename, file.errorString())); + return false; + } + QTextStream ts(&file); QByteArray codecName; if (!cd.m_codecForSource.isEmpty()) codecName = cd.m_codecForSource; @@ -2001,8 +2011,8 @@ bool loadQScript(Translator &translator, QIODevice &dev, ConversionData &cd) QScript::Lexer lexer; lexer.setCode(code, /*lineNumber=*/1); QScriptParser parser; - if (!parser.parse(&lexer, cd.m_sourceFileName, &translator)) { - qWarning("%s:%d: %s", qPrintable(cd.m_sourceFileName), parser.errorLineNumber(), + if (!parser.parse(&lexer, filename, &translator)) { + qWarning("%s:%d: %s", qPrintable(filename), parser.errorLineNumber(), qPrintable(parser.errorMessage())); return false; } @@ -2012,28 +2022,5 @@ bool loadQScript(Translator &translator, QIODevice &dev, ConversionData &cd) return true; } -bool saveQScript(const Translator &translator, QIODevice &dev, ConversionData &cd) -{ - Q_UNUSED(dev); - Q_UNUSED(translator); - cd.appendError(QLatin1String("Cannot save .js files")); - return false; -} - -int initQScript() -{ - Translator::FileFormat format; - format.extension = QLatin1String("js"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.description = QObject::tr("Qt Script source files"); - format.loader = &loadQScript; - format.saver = &saveQScript; - Translator::registerFileFormat(format); - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(initQScript) - QT_END_NAMESPACE ./ diff --git a/tools/linguist/shared/ui.cpp b/tools/linguist/lupdate/ui.cpp index cdecfd1..fb78b2a 100644 --- a/tools/linguist/shared/ui.cpp +++ b/tools/linguist/lupdate/ui.cpp @@ -39,7 +39,9 @@ ** ****************************************************************************/ -#include "translator.h" +#include "lupdate.h" + +#include <translator.h> #include <QtCore/QDebug> #include <QtCore/QFile> @@ -53,9 +55,6 @@ QT_BEGIN_NAMESPACE -// in cpp.cpp -void fetchtrInlinedCpp(const QString &in, Translator &tor, const QString &context); - class UiReader : public QXmlDefaultHandler { public: @@ -157,7 +156,7 @@ bool UiReader::fatalError(const QXmlParseException &exception) msg.sprintf("XML error: Parse error at line %d, column %d (%s).", exception.lineNumber(), exception.columnNumber(), exception.message().toLatin1().data()); - m_cd.appendError(msg); + m_cd.appendError(msg); return false; } @@ -177,9 +176,16 @@ void UiReader::flush() m_extracomment.clear(); } -bool loadUI(Translator &translator, QIODevice &dev, ConversionData &cd) +bool loadUI(Translator &translator, const QString &filename, ConversionData &cd) { - QXmlInputSource in(&dev); + cd.m_sourceFileName = filename; + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + cd.appendError(QString::fromLatin1("Cannot open %1: %2") + .arg(filename, file.errorString())); + return false; + } + QXmlInputSource in(&file); QXmlSimpleReader reader; reader.setFeature(QLatin1String("http://xml.org/sax/features/namespaces"), false); reader.setFeature(QLatin1String("http://xml.org/sax/features/namespace-prefixes"), true); @@ -196,39 +202,4 @@ bool loadUI(Translator &translator, QIODevice &dev, ConversionData &cd) return result; } -bool saveUI(const Translator &translator, QIODevice &dev, ConversionData &cd) -{ - Q_UNUSED(dev); - Q_UNUSED(translator); - cd.appendError(QLatin1String("Cannot save .ui files")); - return false; -} - -int initUI() -{ - Translator::FileFormat format; - - // "real" Qt Designer - format.extension = QLatin1String("ui"); - format.description = QObject::tr("Qt Designer form files"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.loader = &loadUI; - format.saver = &saveUI; - Translator::registerFileFormat(format); - - // same for jambi - format.extension = QLatin1String("jui"); - format.description = QObject::tr("Qt Jambi form files"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.loader = &loadUI; - format.saver = &saveUI; - Translator::registerFileFormat(format); - - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(initUI) - QT_END_NAMESPACE diff --git a/tools/linguist/phrasebooks/french.qph b/tools/linguist/phrasebooks/french.qph index f244013..d38da5a 100644 --- a/tools/linguist/phrasebooks/french.qph +++ b/tools/linguist/phrasebooks/french.qph @@ -1,4 +1,5 @@ -<!DOCTYPE QPH><QPH language="fr"> +<!DOCTYPE QPH> +<QPH language="fr"> <phrase> <source>About</source> <target>A propos</target> @@ -1101,4 +1102,228 @@ <source>Yes</source> <target>Oui</target> </phrase> +<phrase> + <source>Split</source> + <target>Scinder</target> +</phrase> +<phrase> + <source>&Edit</source> + <target>&Édition</target> +</phrase> +<phrase> + <source>&Redo</source> + <target>Re&faire</target> +</phrase> +<phrase> + <source>debugger</source> + <target>débogueur</target> +</phrase> +<phrase> + <source>Start Debugger</source> + <target>Lancer le débogueur</target> +</phrase> +<phrase> + <source>Executable:</source> + <target>Exécutable:</target> +</phrase> +<phrase> + <source>Filter:</source> + <target>Filtre:</target> +</phrase> +<phrase> + <source>Clear</source> + <target>Effacer</target> +</phrase> +<phrase> + <source>Host and port:</source> + <target>Hôte et port:</target> +</phrase> +<phrase> + <source>Architecture:</source> + <target>Architecture:</target> +</phrase> +<phrase> + <source>Server start script:</source> + <target>Script de démarrage du serveur:</target> +</phrase> +<phrase> + <source>&Undo</source> + <target>Annu&ler</target> +</phrase> +<phrase> + <source>Add Bookmark</source> + <target>Ajouter un signet</target> +</phrase> +<phrase> + <source>Bookmark:</source> + <target>Signet:</target> +</phrase> +<phrase> + <source>Add in Folder:</source> + <target>Ajouter dans le dossier:</target> +</phrase> +<phrase> + <source>+</source> + <target>+</target> +</phrase> +<phrase> + <source>New Folder</source> + <target>Nouveau dossier</target> +</phrase> +<phrase> + <source>Bookmarks</source> + <target>Signets</target> +</phrase> +<phrase> + <source>Rename Folder</source> + <target>Renommer le dossier</target> +</phrase> +<phrase> + <source>Bookmark</source> + <target>Signet</target> +</phrase> +<phrase> + <source>Remove</source> + <target>Retirer</target> +</phrase> +<phrase> + <source>Delete Folder</source> + <target>Supprimer le dossier</target> +</phrase> +<phrase> + <source>Add</source> + <target>Ajouter</target> +</phrase> +<phrase> + <source>Move Up</source> + <target>Vers le Haut</target> +</phrase> +<phrase> + <source>Move Down</source> + <target>Vers le Bas</target> +</phrase> +<phrase> + <source>Show Bookmark</source> + <target>Afficher le signet</target> +</phrase> +<phrase> + <source>Show Bookmark in New Tab</source> + <target>Afficher le signet dans un nouvel onglet</target> +</phrase> +<phrase> + <source>Delete Bookmark</source> + <target>Supprimer le signet</target> +</phrase> +<phrase> + <source>Rename Bookmark</source> + <target>Renommer le signet</target> +</phrase> +<phrase> + <source>Previous Bookmark</source> + <target>Signet précédent</target> +</phrase> +<phrase> + <source>Next Bookmark</source> + <target>Signet suivant</target> +</phrase> +<phrase> + <source>Condition:</source> + <target>Condition:</target> +</phrase> +<phrase> + <source>Working Directory:</source> + <target>Répertoire de travail:</target> +</phrase> +<phrase> + <source>Environment</source> + <target>Environnement</target> +</phrase> +<phrase> + <source>Arguments</source> + <target>Arguments</target> +</phrase> +<phrase> + <source>Build directory:</source> + <target>Répertoire de compilation:</target> +</phrase> +<phrase> + <source>Path:</source> + <target>Chemin:</target> +</phrase> +<phrase> + <source>General</source> + <target>Général</target> +</phrase> +<phrase> + <source>Username:</source> + <target>Nom d'utilisateur:</target> +</phrase> +<phrase> + <source>User interface</source> + <target>Interface utilisateur</target> +</phrase> +<phrase> + <source>Open Link</source> + <target>Ouvrir le lien</target> +</phrase> +<phrase> + <source> [read only]</source> + <target> [lecture seule]</target> +</phrase> +<phrase> + <source> [directory]</source> + <target> [répertoire]</target> +</phrase> +<phrase> + <source>Close All</source> + <target>Fermer tout</target> +</phrase> +<phrase> + <source>Failed!</source> + <target>Échec!</target> +</phrase> +<phrase> + <source>Proceed</source> + <target>Continuer</target> +</phrase> +<phrase> + <source>Make writable</source> + <target>Rendre inscriptible</target> +</phrase> +<phrase> + <source>Qt Creator</source> + <target>Qt Creator</target> +</phrase> +<phrase> + <source>&File</source> + <target>&Fichier</target> +</phrase> +<phrase> + <source>Activate %1</source> + <target>Activer %1</target> +</phrase> +<phrase> + <source>New Project</source> + <target>Nouveau projet</target> +</phrase> +<phrase> + <source>Close %1</source> + <target>Fermer %1</target> +</phrase> +<phrase> + <source>*</source> + <target>*</target> +</phrase> +<phrase> + <source>&Change</source> + <target>&Modifier</target> +</phrase> +<phrase> + <source>Close Other Editors</source> + <target>Fermer les autres éditeurs</target> +</phrase> +<phrase> + <source>Close All Except %1</source> + <target>Fermer tout sauf %1</target> +</phrase> </QPH> diff --git a/tools/linguist/shared/abstractproitemvisitor.h b/tools/linguist/shared/abstractproitemvisitor.h index 0691fdc..43e79e0 100644 --- a/tools/linguist/shared/abstractproitemvisitor.h +++ b/tools/linguist/shared/abstractproitemvisitor.h @@ -49,19 +49,23 @@ QT_BEGIN_NAMESPACE struct AbstractProItemVisitor { virtual ~AbstractProItemVisitor() {} - virtual bool visitBeginProBlock(ProBlock *block) = 0; - virtual bool visitEndProBlock(ProBlock *block) = 0; - virtual bool visitBeginProVariable(ProVariable *variable) = 0; - virtual bool visitEndProVariable(ProVariable *variable) = 0; + virtual ProItem::ProItemReturn visitBeginProBlock(ProBlock *block) = 0; + virtual void visitEndProBlock(ProBlock *block) = 0; - virtual bool visitBeginProFile(ProFile *value) = 0; - virtual bool visitEndProFile(ProFile *value) = 0; + virtual ProItem::ProItemReturn visitProLoopIteration() = 0; + virtual void visitProLoopCleanup() = 0; - virtual bool visitProValue(ProValue *value) = 0; - virtual bool visitProFunction(ProFunction *function) = 0; - virtual bool visitProOperator(ProOperator *function) = 0; - virtual bool visitProCondition(ProCondition *function) = 0; + virtual void visitBeginProVariable(ProVariable *variable) = 0; + virtual void visitEndProVariable(ProVariable *variable) = 0; + + virtual ProItem::ProItemReturn visitBeginProFile(ProFile *value) = 0; + virtual ProItem::ProItemReturn visitEndProFile(ProFile *value) = 0; + + virtual void visitProValue(ProValue *value) = 0; + virtual ProItem::ProItemReturn visitProFunction(ProFunction *function) = 0; + virtual void visitProOperator(ProOperator *function) = 0; + virtual void visitProCondition(ProCondition *function) = 0; }; QT_END_NAMESPACE diff --git a/tools/linguist/shared/cpp.cpp b/tools/linguist/shared/cpp.cpp deleted file mode 100644 index ac6bd33..0000000 --- a/tools/linguist/shared/cpp.cpp +++ /dev/null @@ -1,1098 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Linguist 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "translator.h" - -#include <QtCore/QDebug> -#include <QtCore/QStack> -#include <QtCore/QString> -#include <QtCore/QTextCodec> -#include <QtCore/QTextStream> - -#include <ctype.h> // for isXXX() - -QT_BEGIN_NAMESPACE - -/* qmake ignore Q_OBJECT */ - -static const char MagicComment[] = "TRANSLATOR "; - -static QSet<QString> needs_Q_OBJECT; -static QSet<QString> lacks_Q_OBJECT; - -static const int yyIdentMaxLen = 128; -static const int yyCommentMaxLen = 65536; -static const int yyStringMaxLen = 65536; - -#define STRINGIFY_INTERNAL(x) #x -#define STRINGIFY(x) STRINGIFY_INTERNAL(x) -#define STRING(s) static QString str##s(QLatin1String(STRINGIFY(s))) - -//#define DIAGNOSE_RETRANSLATABILITY -/* - The first part of this source file is the C++ tokenizer. We skip - most of C++; the only tokens that interest us are defined here. - Thus, the code fragment - - int main() - { - printf("Hello, world!\n"); - return 0; - } - - is broken down into the following tokens (Tok_ omitted): - - Ident Ident LeftParen RightParen - LeftBrace - Ident LeftParen String RightParen Semicolon - return Semicolon - RightBrace. - - The 0 doesn't produce any token. -*/ - -enum { - Tok_Eof, Tok_class, Tok_namespace, Tok_return, - Tok_tr = 10, Tok_trUtf8, Tok_translate, Tok_translateUtf8, - Tok_Q_OBJECT = 20, Tok_Q_DECLARE_TR_FUNCTIONS, - 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_Other -}; - -/* - The tokenizer maintains the following global variables. The names - should be self-explanatory. -*/ -static QString yyFileName; -static int yyCh; -static bool yyCodecIsUtf8; -static bool yyForceUtf8; -static QString yyIdent; -static QString yyComment; -static QString yyString; -static qlonglong yyInteger; -static QStack<int> yySavedBraceDepth; -static QStack<int> yySavedParenDepth; -static int yyBraceDepth; -static int yyParenDepth; -static int yyLineNo; -static int yyCurLineNo; -static int yyBraceLineNo; -static int yyParenLineNo; -static bool yyTokColonSeen = false; - -// the string to read from and current position in the string -static QTextCodec *yySourceCodec; -static bool yySourceIsUnicode; -static QString yyInStr; -static int yyInPos; - -static uint getChar() -{ - forever { - if (yyInPos >= yyInStr.size()) - return EOF; - uint c = yyInStr[yyInPos++].unicode(); - if (c == '\\' && yyInPos < yyInStr.size()) { - if (yyInStr[yyInPos].unicode() == '\n') { - ++yyCurLineNo; - ++yyInPos; - continue; - } - if (yyInStr[yyInPos].unicode() == '\r') { - ++yyCurLineNo; - ++yyInPos; - if (yyInPos < yyInStr.size() && yyInStr[yyInPos].unicode() == '\n') - ++yyInPos; - continue; - } - } - if (c == '\r') { - if (yyInPos < yyInStr.size() && yyInStr[yyInPos].unicode() == '\n') - ++yyInPos; - c = '\n'; - ++yyCurLineNo; - } else if (c == '\n') { - ++yyCurLineNo; - } - return c; - } -} - -static uint getToken() -{ - yyIdent.clear(); - yyComment.clear(); - yyString.clear(); - - while (yyCh != EOF) { - yyLineNo = yyCurLineNo; - - if (isalpha(yyCh) || yyCh == '_') { - do { - yyIdent += yyCh; - yyCh = getChar(); - } while (isalnum(yyCh) || yyCh == '_'); - - //qDebug() << "IDENT: " << yyIdent; - - switch (yyIdent.at(0).unicode()) { - case 'Q': - if (yyIdent == QLatin1String("Q_OBJECT")) - return Tok_Q_OBJECT; - if (yyIdent == QLatin1String("Q_DECLARE_TR_FUNCTIONS")) - return Tok_Q_DECLARE_TR_FUNCTIONS; - if (yyIdent == QLatin1String("QT_TR_NOOP")) - return Tok_tr; - if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP")) - return Tok_translate; - if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP3")) - return Tok_translate; - if (yyIdent == QLatin1String("QT_TR_NOOP_UTF8")) - return Tok_trUtf8; - if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP_UTF8")) - return Tok_translateUtf8; - if (yyIdent == QLatin1String("QT_TRANSLATE_NOOP3_UTF8")) - return Tok_translateUtf8; - break; - case 'T': - // TR() for when all else fails - if (yyIdent.compare(QLatin1String("TR"), Qt::CaseInsensitive) == 0) { - return Tok_tr; - } - break; - case 'c': - if (yyIdent == QLatin1String("class")) - return Tok_class; - break; - case 'f': - /* - QTranslator::findMessage() has the same parameters as - QApplication::translate(). - */ - if (yyIdent == QLatin1String("findMessage")) - return Tok_translate; - break; - case 'n': - if (yyIdent == QLatin1String("namespace")) - return Tok_namespace; - break; - case 'r': - if (yyIdent == QLatin1String("return")) - return Tok_return; - break; - case 's': - if (yyIdent == QLatin1String("struct")) - return Tok_class; - break; - case 't': - if (yyIdent == QLatin1String("tr")) { - return Tok_tr; - } - if (yyIdent == QLatin1String("trUtf8")) { - return Tok_trUtf8; - } - if (yyIdent == QLatin1String("translate")) { - return Tok_translate; - } - } - return Tok_Ident; - } else { - switch (yyCh) { - case '#': - /* - Early versions of lupdate complained about - unbalanced braces in the following code: - - #ifdef ALPHA - while (beta) { - #else - while (gamma) { - #endif - delta; - } - - The code contains, indeed, two opening braces for - one closing brace; yet there's no reason to panic. - - The solution is to remember yyBraceDepth as it was - when #if, #ifdef or #ifndef was met, and to set - yyBraceDepth to that value when meeting #elif or - #else. - */ - do { - yyCh = getChar(); - } while (isspace(yyCh) && yyCh != '\n'); - - switch (yyCh) { - case 'i': - yyCh = getChar(); - if (yyCh == 'f') { - // if, ifdef, ifndef - yySavedBraceDepth.push(yyBraceDepth); - yySavedParenDepth.push(yyParenDepth); - } - break; - case 'e': - yyCh = getChar(); - if (yyCh == 'l') { - // elif, else - if (!yySavedBraceDepth.isEmpty()) { - yyBraceDepth = yySavedBraceDepth.top(); - yyParenDepth = yySavedParenDepth.top(); - } - } else if (yyCh == 'n') { - // endif - if (!yySavedBraceDepth.isEmpty()) { - yySavedBraceDepth.pop(); - yySavedParenDepth.pop(); - } - } - } - while (isalnum(yyCh) || yyCh == '_') - yyCh = getChar(); - break; - case '/': - yyCh = getChar(); - if (yyCh == '/') { - do { - yyCh = getChar(); - if (yyCh == EOF) - break; - yyComment.append(yyCh); - } while (yyCh != '\n'); - } else if (yyCh == '*') { - bool metAster = false; - bool metAsterSlash = false; - - while (!metAsterSlash) { - yyCh = getChar(); - if (yyCh == EOF) { - qWarning("%s: Unterminated C++ comment starting at" - " line %d\n", - qPrintable(yyFileName), yyLineNo); - return Tok_Comment; - } - yyComment.append(yyCh); - - if (yyCh == '*') - metAster = true; - else if (metAster && yyCh == '/') - metAsterSlash = true; - else - metAster = false; - } - yyCh = getChar(); - yyComment.chop(2); - } - return Tok_Comment; - case '"': - yyCh = getChar(); - while (yyCh != EOF && yyCh != '\n' && yyCh != '"') { - if (yyCh == '\\') { - yyCh = getChar(); - if (yyString.size() < yyStringMaxLen) { - yyString.append(QLatin1Char('\\')); - yyString.append(yyCh); - } - } else { - if (yyString.size() < yyStringMaxLen) - yyString.append(yyCh); - } - yyCh = getChar(); - } - - if (yyCh != '"') - qWarning("%s:%d: Unterminated C++ string", - qPrintable(yyFileName), yyLineNo); - - if (yyCh == EOF) - return Tok_Eof; - yyCh = getChar(); - return Tok_String; - case '-': - yyCh = getChar(); - if (yyCh == '>') { - yyCh = getChar(); - return Tok_Arrow; - } - break; - case ':': - yyCh = getChar(); - if (yyCh == ':') { - yyCh = getChar(); - return Tok_ColonColon; - } - return Tok_Colon; - // Incomplete: '<' might be part of '<=' or of template syntax. - // The main intent of not completely ignoring it is to break - // parsing of things like std::cout << QObject::tr() as - // context std::cout::QObject (see Task 161106) - case '=': - yyCh = getChar(); - return Tok_Equals; - case '>': - case '<': - yyCh = getChar(); - return Tok_Other; - case '\'': - yyCh = getChar(); - if (yyCh == '\\') - yyCh = getChar(); - - do { - yyCh = getChar(); - } while (yyCh != EOF && yyCh != '\''); - yyCh = getChar(); - break; - case '{': - if (yyBraceDepth == 0) - yyBraceLineNo = yyCurLineNo; - yyBraceDepth++; - yyCh = getChar(); - return Tok_LeftBrace; - case '}': - if (yyBraceDepth == 0) - yyBraceLineNo = yyCurLineNo; - yyBraceDepth--; - yyCh = getChar(); - return Tok_RightBrace; - case '(': - if (yyParenDepth == 0) - yyParenLineNo = yyCurLineNo; - yyParenDepth++; - yyCh = getChar(); - return Tok_LeftParen; - case ')': - if (yyParenDepth == 0) - yyParenLineNo = yyCurLineNo; - yyParenDepth--; - yyCh = getChar(); - return Tok_RightParen; - case ',': - yyCh = getChar(); - return Tok_Comma; - case ';': - yyCh = getChar(); - return Tok_Semicolon; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - QByteArray ba; - ba += yyCh; - 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; - } - default: - yyCh = getChar(); - break; - } - } - } - return Tok_Eof; -} - -/* - The second part of this source file is the parser. It accomplishes - a very easy task: It finds all strings inside a tr() or translate() - call, and possibly finds out the context of the call. It supports - three cases: (1) the context is specified, as in - FunnyDialog::tr("Hello") or translate("FunnyDialog", "Hello"); - (2) the call appears within an inlined function; (3) the call - appears within a function defined outside the class definition. -*/ - -static uint yyTok; - -static bool match(uint t) -{ - bool matches = (yyTok == t); - if (matches) - yyTok = getToken(); - return matches; -} - -static bool matchString(QString *s) -{ - bool matches = (yyTok == Tok_String); - s->clear(); - while (yyTok == Tok_String) { - *s += yyString; - do { - yyTok = getToken(); - } while (yyTok == Tok_Comment); - } - return matches; -} - -static bool matchEncoding(bool *utf8) -{ - STRING(QApplication); - STRING(QCoreApplication); - STRING(UnicodeUTF8); - STRING(DefaultCodec); - STRING(CodecForTr); - - if (yyTok != Tok_Ident) - return false; - if (yyIdent == strQApplication || yyIdent == strQCoreApplication) { - yyTok = getToken(); - if (yyTok == Tok_ColonColon) - yyTok = getToken(); - } - if (yyIdent == strUnicodeUTF8) { - *utf8 = true; - yyTok = getToken(); - return true; - } - if (yyIdent == strDefaultCodec || yyIdent == strCodecForTr) { - *utf8 = false; - yyTok = getToken(); - return true; - } - return false; -} - -static bool matchInteger(qlonglong *number) -{ - bool matches = (yyTok == Tok_Integer); - if (matches) { - yyTok = getToken(); - *number = yyInteger; - } - return matches; -} - -static bool matchStringOrNull(QString *s) -{ - bool matches = matchString(s); - qlonglong num = 0; - if (!matches) - matches = matchInteger(&num); - return matches && num == 0; -} - -/* - * match any expression that can return a number, which can be - * 1. Literal number (e.g. '11') - * 2. simple identifier (e.g. 'm_count') - * 3. simple function call (e.g. 'size()' ) - * 4. function call on an object (e.g. 'list.size()') - * 5. function call on an object (e.g. 'list->size()') - * - * Other cases: - * size(2,4) - * list().size() - * list(a,b).size(2,4) - * etc... - */ -static bool matchExpression() -{ - if (match(Tok_Integer)) - return true; - - int parenlevel = 0; - while (match(Tok_Ident) || parenlevel > 0) { - if (yyTok == Tok_RightParen) { - if (parenlevel == 0) break; - --parenlevel; - yyTok = getToken(); - } else if (yyTok == Tok_LeftParen) { - yyTok = getToken(); - if (yyTok == Tok_RightParen) { - yyTok = getToken(); - } else { - ++parenlevel; - } - } else if (yyTok == Tok_Ident) { - continue; - } else if (yyTok == Tok_Arrow) { - yyTok = getToken(); - } else if (parenlevel == 0) { - return false; - } - } - return true; -} - -static QStringList resolveNamespaces( - const QStringList &namespaces, const QHash<QString, QStringList> &namespaceAliases) -{ - static QString strColons(QLatin1String("::")); - - QStringList ns; - foreach (const QString &cns, namespaces) { - ns << cns; - ns = namespaceAliases.value(ns.join(strColons), ns); - } - return ns; -} - -static QStringList getFullyQualifiedNamespaceName( - const QSet<QString> &allNamespaces, const QStringList &namespaces, - const QHash<QString, QStringList> &namespaceAliases, - const QStringList &segments) -{ - static QString strColons(QLatin1String("::")); - - if (segments.first().isEmpty()) { - // fully qualified - QStringList segs = segments; - segs.removeFirst(); - return resolveNamespaces(segs, namespaceAliases); - } else { - for (int n = namespaces.count(); --n >= -1; ) { - QStringList ns; - for (int i = 0; i <= n; ++i) // Note: n == -1 possible - ns << namespaces[i]; - foreach (const QString &cns, segments) { - ns << cns; - ns = namespaceAliases.value(ns.join(strColons), ns); - } - if (allNamespaces.contains(ns.join(strColons))) - return ns; - } - - // Fallback when the namespace was declared in a header, etc. - QStringList ns = namespaces; - ns += segments; - return ns; - } -} - -static QString getFullyQualifiedClassName( - const QSet<QString> &allClasses, const QStringList &namespaces, - const QHash<QString, QStringList> &namespaceAliases, - const QString &ident, bool hasPrefix) -{ - static QString strColons(QLatin1String("::")); - - QString context = ident; - QStringList segments = context.split(strColons); - if (segments.first().isEmpty()) { - // fully qualified - segments.removeFirst(); - context = resolveNamespaces(segments, namespaceAliases).join(strColons); - } else { - for (int n = namespaces.count(); --n >= -1; ) { - QStringList ns; - for (int i = 0; i <= n; ++i) // Note: n == -1 possible - ns.append(namespaces[i]); - foreach (const QString &cns, segments) { - ns.append(cns); - ns = namespaceAliases.value(ns.join(strColons), ns); - } - QString nctx = ns.join(strColons); - if (allClasses.contains(nctx)) { - context = nctx; - goto gotit; - } - } - - if (!hasPrefix && namespaces.count()) - context = namespaces.join(strColons) + strColons + context; - } -gotit: - //qDebug() << "CLASSES:" << allClasses << "NAMEPACES:" << namespaces - // << "IDENT:" << ident << "CONTEXT:" << context; - return context; -} - - -static QString transcode(const QString &str, bool utf8) -{ - static const char tab[] = "abfnrtv"; - static const char backTab[] = "\a\b\f\n\r\t\v"; - const QString in = (!utf8 || yySourceIsUnicode) - ? str : QString::fromUtf8(yySourceCodec->fromUnicode(str).data()); - QString out; - - out.reserve(in.length()); - for (int i = 0; i < in.length();) { - ushort c = in[i++].unicode(); - if (c == '\\') { - if (i >= in.length()) - break; - c = in[i++].unicode(); - - if (c == '\n') - continue; - - if (c == 'x') { - QByteArray hex; - while (i < in.length() && isxdigit((c = in[i].unicode()))) { - hex += c; - i++; - } - out += hex.toUInt(0, 16); - } else if (c >= '0' && c < '8') { - QByteArray oct; - int n = 0; - oct += c; - while (n < 2 && i < in.length() && (c = in[i].unicode()) >= '0' && c < '8') { - i++; - n++; - oct += c; - } - out += oct.toUInt(0, 8); - } else { - const char *p = strchr(tab, c); - out += QChar(QLatin1Char(!p ? c : backTab[p - tab])); - } - } else { - out += c; - } - } - return out; -} - -static void recordMessage( - Translator *tor, int line, const QString &context, const QString &text, const QString &comment, - const QString &extracomment, bool utf8, bool plural) -{ - TranslatorMessage msg( - transcode(context, utf8), transcode(text, utf8), transcode(comment, utf8), QString(), - yyFileName, line, QStringList(), - TranslatorMessage::Unfinished, plural); - msg.setExtraComment(transcode(extracomment.simplified(), utf8)); - if ((utf8 || yyForceUtf8) && !yyCodecIsUtf8 && msg.needs8Bit()) - msg.setUtf8(true); - tor->extend(msg); -} - -static void parse(Translator *tor, const QString &initialContext, const QString &defaultContext) -{ - static QString strColons(QLatin1String("::")); - - QMap<QString, QString> qualifiedContexts; - QSet<QString> allClasses; - QSet<QString> allNamespaces; - QHash<QString, QStringList> namespaceAliases; - QStringList namespaces; - QString context; - QString text; - QString comment; - QString extracomment; - QString functionContext = initialContext; - QString prefix; -#ifdef DIAGNOSE_RETRANSLATABILITY - QString functionName; -#endif - int line; - bool utf8 = false; - bool missing_Q_OBJECT = false; - - yyTok = getToken(); - while (yyTok != Tok_Eof) { - //qDebug() << "TOKEN: " << yyTok; - switch (yyTok) { - case Tok_class: - yyTokColonSeen = false; - /* - Partial support for inlined functions. - */ - yyTok = getToken(); - if (yyBraceDepth == namespaces.count() && yyParenDepth == 0) { - QStringList fct; - do { - /* - This code should execute only once, but we play - safe with impure definitions such as - 'class Q_EXPORT QMessageBox', in which case - 'QMessageBox' is the class name, not 'Q_EXPORT'. - */ - fct = QStringList(yyIdent); - yyTok = getToken(); - } while (yyTok == Tok_Ident); - while (yyTok == Tok_ColonColon) { - yyTok = getToken(); - if (yyTok != Tok_Ident) - break; // Oops ... - fct += yyIdent; - yyTok = getToken(); - } - functionContext = resolveNamespaces(namespaces + fct, namespaceAliases).join(strColons); - allClasses.insert(functionContext); - - if (yyTok == Tok_Colon) { - missing_Q_OBJECT = true; - // Skip any token until '{' since lupdate might do things wrong if it finds - // a '::' token here. - do { - yyTok = getToken(); - } while (yyTok != Tok_LeftBrace && yyTok != Tok_Eof); - } else { - //functionContext = defaultContext; - } - } - break; - case Tok_namespace: - yyTokColonSeen = false; - yyTok = getToken(); - if (yyTok == Tok_Ident) { - QString ns = yyIdent; - yyTok = getToken(); - if (yyTok == Tok_LeftBrace) { - if (yyBraceDepth == namespaces.count() + 1) { - namespaces.append(ns); - allNamespaces.insert(namespaces.join(strColons)); - } - } else if (yyTok == Tok_Equals) { - // e.g. namespace Is = OuterSpace::InnerSpace; - QStringList alias = namespaces; - alias.append(ns); - QStringList fullName; - yyTok = getToken(); - if (yyTok == Tok_ColonColon) - fullName.append(QString()); - while (yyTok == Tok_ColonColon || yyTok == Tok_Ident) { - if (yyTok == Tok_Ident) - fullName.append(yyIdent); - yyTok = getToken(); - } - namespaceAliases[alias.join(strColons)] = - getFullyQualifiedNamespaceName(allNamespaces, namespaces, namespaceAliases, fullName); - } - } - break; - case Tok_tr: - case Tok_trUtf8: - utf8 = (yyTok == Tok_trUtf8); - line = yyLineNo; - yyTok = getToken(); - if (match(Tok_LeftParen) && matchString(&text) && !text.isEmpty()) { - comment.clear(); - bool plural = false; - - if (match(Tok_RightParen)) { - // no comment - } else if (match(Tok_Comma) && matchStringOrNull(&comment)) { //comment - if (match(Tok_RightParen)) { - // ok, - } else if (match(Tok_Comma)) { - plural = true; - } - } - if (prefix.isEmpty()) { - context = functionContext; - } else { -#ifdef DIAGNOSE_RETRANSLATABILITY - int last = prefix.lastIndexOf(strColons); - QString className = prefix.mid(last == -1 ? 0 : last + 2); - if (!className.isEmpty() && className == functionName) { - qWarning("%s::%d: It is not recommended to call tr() from within a constructor '%s::%s' ", - qPrintable(yyFileName), yyLineNo, - className.constData(), functionName.constData()); - } -#endif - prefix.chop(2); - context = getFullyQualifiedClassName(allClasses, namespaces, namespaceAliases, prefix, true); - } - prefix.clear(); - if (qualifiedContexts.contains(context)) - context = qualifiedContexts[context]; - - if (!text.isEmpty()) - recordMessage(tor, line, context, text, comment, extracomment, utf8, plural); - - if (lacks_Q_OBJECT.contains(context)) { - qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro", - qPrintable(yyFileName), yyLineNo, - qPrintable(context)); - lacks_Q_OBJECT.remove(context); - } else { - needs_Q_OBJECT.insert(context); - } - } - extracomment.clear(); - break; - case Tok_translateUtf8: - case Tok_translate: - utf8 = (yyTok == Tok_translateUtf8); - line = yyLineNo; - yyTok = getToken(); - if (match(Tok_LeftParen) - && matchString(&context) - && match(Tok_Comma) - && matchString(&text)) - { - comment.clear(); - bool plural = false; - if (!match(Tok_RightParen)) { - // look for comment - if (match(Tok_Comma) && matchStringOrNull(&comment)) { - if (!match(Tok_RightParen)) { - // look for encoding - if (match(Tok_Comma)) { - if (matchEncoding(&utf8)) { - if (!match(Tok_RightParen)) { - // look for the plural quantifier, - // this can be a number, an identifier or - // a function call, - // so for simplicity we mark it as plural if - // we know we have a comma instead of an - // right parentheses. - plural = match(Tok_Comma); - } - } else { - // This can be a QTranslator::translate("context", - // "source", "comment", n) plural translation - if (matchExpression() && match(Tok_RightParen)) { - plural = true; - } else { - break; - } - } - } else { - break; - } - } - } else { - break; - } - } - if (!text.isEmpty()) - recordMessage(tor, line, context, text, comment, extracomment, utf8, plural); - } - extracomment.clear(); - break; - case Tok_Q_DECLARE_TR_FUNCTIONS: - case Tok_Q_OBJECT: - missing_Q_OBJECT = false; - yyTok = getToken(); - break; - case Tok_Ident: - prefix += yyIdent; - yyTok = getToken(); - if (yyTok != Tok_ColonColon) - prefix.clear(); - break; - case Tok_Comment: - if (yyComment.startsWith(QLatin1Char(':'))) { - yyComment.remove(0, 1); - extracomment.append(yyComment); - } else { - comment = yyComment.simplified(); - if (comment.startsWith(QLatin1String(MagicComment))) { - comment.remove(0, sizeof(MagicComment) - 1); - int k = comment.indexOf(QLatin1Char(' ')); - if (k == -1) { - context = comment; - } else { - context = comment.left(k); - comment.remove(0, k + 1); - recordMessage(tor, yyLineNo, context, QString(), comment, extracomment, false, false); - } - - /* - Provide a backdoor for people using "using - namespace". See the manual for details. - */ - k = 0; - while ((k = context.indexOf(strColons, k)) != -1) { - qualifiedContexts.insert(context.mid(k + 2), context); - k++; - } - } - } - yyTok = getToken(); - break; - case Tok_Arrow: - yyTok = getToken(); - if (yyTok == Tok_tr || yyTok == Tok_trUtf8) - qWarning("%s:%d: Cannot invoke tr() like this", - qPrintable(yyFileName), yyLineNo); - break; - case Tok_ColonColon: - if (yyBraceDepth == namespaces.count() && yyParenDepth == 0 && !yyTokColonSeen) - functionContext = getFullyQualifiedClassName(allClasses, namespaces, namespaceAliases, prefix, false); - prefix += strColons; - yyTok = getToken(); -#ifdef DIAGNOSE_RETRANSLATABILITY - if (yyTok == Tok_Ident && yyBraceDepth == namespaces.count() && yyParenDepth == 0) - functionName = yyIdent; -#endif - break; - case Tok_RightBrace: - case Tok_Semicolon: - prefix.clear(); - extracomment.clear(); - yyTokColonSeen = false; - if (yyBraceDepth >= 0 && yyBraceDepth + 1 == namespaces.count()) - namespaces.removeLast(); - if (yyBraceDepth == namespaces.count()) { - if (missing_Q_OBJECT) { - if (needs_Q_OBJECT.contains(functionContext)) { - qWarning("%s:%d: Class '%s' lacks Q_OBJECT macro", - qPrintable(yyFileName), yyLineNo, - qPrintable(functionContext)); - } else { - lacks_Q_OBJECT.insert(functionContext); - } - } - functionContext = defaultContext; - missing_Q_OBJECT = false; - } - yyTok = getToken(); - break; - case Tok_Colon: - yyTokColonSeen = true; - yyTok = getToken(); - break; - case Tok_LeftParen: - case Tok_RightParen: - case Tok_LeftBrace: - yyTokColonSeen = false; - yyTok = getToken(); - break; - default: - yyTok = getToken(); - break; - } - } - - if (yyBraceDepth != 0) - qWarning("%s:%d: Unbalanced braces in C++ code (or abuse of the C++" - " preprocessor)\n", - qPrintable(yyFileName), yyBraceLineNo); - else if (yyParenDepth != 0) - qWarning("%s:%d: Unbalanced parentheses in C++ code (or abuse of the C++" - " preprocessor)\n", - qPrintable(yyFileName), yyParenLineNo); -} - -/* - Fetches tr() calls in C++ code in UI files (inside "<function>" - tag). This mechanism is obsolete. -*/ -void fetchtrInlinedCpp(const QString &in, Translator &translator, const QString &context) -{ - yyInStr = in; - yyInPos = 0; - yyFileName = QString(); - yyCodecIsUtf8 = (translator.codecName() == "UTF-8"); - yyForceUtf8 = true; - yySourceIsUnicode = true; - yySavedBraceDepth.clear(); - yySavedParenDepth.clear(); - yyBraceDepth = 0; - yyParenDepth = 0; - yyCurLineNo = 1; - yyBraceLineNo = 1; - yyParenLineNo = 1; - yyCh = getChar(); - - parse(&translator, context, QString()); -} - - -bool loadCPP(Translator &translator, QIODevice &dev, ConversionData &cd) -{ - QString defaultContext = cd.m_defaultContext; - - yyCodecIsUtf8 = (translator.codecName() == "UTF-8"); - yyForceUtf8 = false; - QTextStream ts(&dev); - QByteArray codecName = cd.m_codecForSource.isEmpty() - ? translator.codecName() : cd.m_codecForSource; - ts.setCodec(QTextCodec::codecForName(codecName)); - ts.setAutoDetectUnicode(true); - yySourceCodec = ts.codec(); - if (yySourceCodec->name() == "UTF-16") - translator.setCodecName("System"); - yySourceIsUnicode = yySourceCodec->name().startsWith("UTF-"); - yyInStr = ts.readAll(); - yyInPos = 0; - yyFileName = cd.m_sourceFileName; - yySavedBraceDepth.clear(); - yySavedParenDepth.clear(); - yyBraceDepth = 0; - yyParenDepth = 0; - yyCurLineNo = 1; - yyBraceLineNo = 1; - yyParenLineNo = 1; - yyCh = getChar(); - - parse(&translator, defaultContext, defaultContext); - - return true; -} - -int initCPP() -{ - Translator::FileFormat format; - format.extension = QLatin1String("cpp"); - format.fileType = Translator::FileFormat::SourceCode; - format.priority = 0; - format.description = QObject::tr("C++ source files"); - format.loader = &loadCPP; - format.saver = 0; - Translator::registerFileFormat(format); - return 1; -} - -Q_CONSTRUCTOR_FUNCTION(initCPP) - -QT_END_NAMESPACE diff --git a/tools/linguist/shared/formats.pri b/tools/linguist/shared/formats.pri index 9c8072b..985f6db 100644 --- a/tools/linguist/shared/formats.pri +++ b/tools/linguist/shared/formats.pri @@ -19,8 +19,4 @@ SOURCES += \ $$PWD/qph.cpp \ $$PWD/po.cpp \ $$PWD/ts.cpp \ - $$PWD/ui.cpp \ - $$PWD/cpp.cpp \ - $$PWD/java.cpp \ - $$PWD/qscript.cpp \ $$PWD/xliff.cpp diff --git a/tools/linguist/shared/make-qscript.sh b/tools/linguist/shared/make-qscript.sh deleted file mode 100755 index 42cab7a..0000000 --- a/tools/linguist/shared/make-qscript.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -me=$(dirname $0) -mkdir -p $me/out -(cd $me/out && ${QLALR-qlalr} --no-debug --troll --no-lines ../qscript.g) - -for f in $me/out/*.{h,cpp}; do - n=$(basename $f) - p4 open $me/../$n - cp $f $me/../$n -done - -p4 revert -a $me/../... -p4 diff -du $me/../... diff --git a/tools/linguist/shared/po.cpp b/tools/linguist/shared/po.cpp index 4850cfd..a6795cb 100644 --- a/tools/linguist/shared/po.cpp +++ b/tools/linguist/shared/po.cpp @@ -359,7 +359,7 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) const QChar quote = QLatin1Char('"'); const QChar newline = QLatin1Char('\n'); QTextStream in(&dev); - in.setCodec(cd.m_codecForSource.isEmpty() ? "UTF-8" : cd.m_codecForSource); + in.setCodec(cd.m_codecForSource.isEmpty() ? QByteArray("UTF-8") : cd.m_codecForSource); bool error = false; // format of a .po file entry: @@ -396,7 +396,10 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) const QString prefix = QLatin1String(isObsolete ? "#~ " : ""); while (true) { int idx = line.indexOf(QLatin1Char(' '), prefix.length()); - item.msgStr.append(slurpEscapedString(lines, l, idx, prefix, cd)); + QString str = slurpEscapedString(lines, l, idx, prefix, cd); + str.replace(QChar(Translator::TextVariantSeparator), + QChar(Translator::BinaryVariantSeparator)); + item.msgStr.append(str); if (l + 1 >= lines.size() || !isTranslationLine(lines.at(l + 1))) break; ++l; @@ -552,7 +555,7 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &cd) { bool ok = true; QTextStream out(&dev); - out.setCodec(cd.m_outputCodec.isEmpty() ? "UTF-8" : cd.m_outputCodec); + out.setCodec(cd.m_outputCodec.isEmpty() ? QByteArray("UTF-8") : cd.m_outputCodec); bool first = true; if (translator.messages().isEmpty() || !translator.messages().first().sourceText().isEmpty()) { @@ -636,8 +639,11 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &cd) out << poEscapedString(prefix, QLatin1String("msgid_plural"), noWrap, plural); const QStringList &translations = msg.translations(); for (int i = 0; i != translations.size(); ++i) { + QString str = translations.at(i); + str.replace(QChar(Translator::BinaryVariantSeparator), + QChar(Translator::TextVariantSeparator)); out << poEscapedString(prefix, QString::fromLatin1("msgstr[%1]").arg(i), noWrap, - translations.at(i)); + str); } } first = false; diff --git a/tools/linguist/shared/profileevaluator.cpp b/tools/linguist/shared/profileevaluator.cpp index 3b8a1b8..5a9095a 100644 --- a/tools/linguist/shared/profileevaluator.cpp +++ b/tools/linguist/shared/profileevaluator.cpp @@ -44,6 +44,7 @@ #include "proitems.h" #include <QtCore/QByteArray> +#include <QtCore/QDateTime> #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFile> @@ -56,6 +57,15 @@ #include <QtCore/QStringList> #include <QtCore/QTextStream> +#ifdef Q_OS_UNIX +#include <unistd.h> +#include <sys/utsname.h> +#else +#include <Windows.h> +#endif +#include <stdio.h> +#include <stdlib.h> + #ifdef Q_OS_WIN32 #define QT_POPEN _popen #define QT_PCLOSE _pclose @@ -68,6 +78,58 @@ QT_BEGIN_NAMESPACE /////////////////////////////////////////////////////////////////////// // +// Option +// +/////////////////////////////////////////////////////////////////////// + +QString +Option::fixString(QString string, uchar flags) +{ + // XXX Ripped out caching, so this will be slow. Should not matter for current uses. + + //fix the environment variables + if (flags & Option::FixEnvVars) { + int rep; + QRegExp reg_variableName(QLatin1String("\\$\\(.*\\)")); + reg_variableName.setMinimal(true); + while ((rep = reg_variableName.indexIn(string)) != -1) + string.replace(rep, reg_variableName.matchedLength(), + QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_variableName.matchedLength() - 3).toLatin1().constData()).constData())); + } + + //canonicalize it (and treat as a path) + if (flags & Option::FixPathCanonicalize) { +#if 0 + string = QFileInfo(string).canonicalFilePath(); +#endif + string = QDir::cleanPath(string); + } + + if (string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':')) + string[0] = string[0].toLower(); + + //fix separators + Q_ASSERT(!((flags & Option::FixPathToLocalSeparators) && (flags & Option::FixPathToTargetSeparators))); + if (flags & Option::FixPathToLocalSeparators) { +#if defined(Q_OS_WIN32) + string = string.replace(QLatin1Char('/'), QLatin1Char('\\')); +#else + string = string.replace(QLatin1Char('\\'), QLatin1Char('/')); +#endif + } else if (flags & Option::FixPathToTargetSeparators) { + string = string.replace(QLatin1Char('/'), Option::dir_sep) + .replace(QLatin1Char('\\'), Option::dir_sep); + } + + if ((string.startsWith(QLatin1Char('"')) && string.endsWith(QLatin1Char('"'))) || + (string.startsWith(QLatin1Char('\'')) && string.endsWith(QLatin1Char('\'')))) + string = string.mid(1, string.length() - 2); + + return string; +} + +/////////////////////////////////////////////////////////////////////// +// // ProFileEvaluator::Private // /////////////////////////////////////////////////////////////////////// @@ -77,6 +139,12 @@ class ProFileEvaluator::Private : public AbstractProItemVisitor public: Private(ProFileEvaluator *q_); + ProFileEvaluator *q; + int m_lineNo; // Error reporting + bool m_verbose; + + /////////////// Reading pro file + bool read(ProFile *pro); ProBlock *currentBlock(); @@ -89,73 +157,128 @@ public: void leaveScope(); void finalizeBlock(); + QStack<ProBlock *> m_blockstack; + ProBlock *m_block; + + ProItem *m_commentItem; + QString m_proitem; + QString m_pendingComment; + bool m_syntaxError; + bool m_contNextLine; + bool m_inQuote; + int m_parens; + + /////////////// Evaluating pro file contents + // implementation of AbstractProItemVisitor - bool visitBeginProBlock(ProBlock *block); - bool visitEndProBlock(ProBlock *block); - bool visitBeginProVariable(ProVariable *variable); - bool visitEndProVariable(ProVariable *variable); - bool visitBeginProFile(ProFile *value); - bool visitEndProFile(ProFile *value); - bool visitProValue(ProValue *value); - bool visitProFunction(ProFunction *function); - bool visitProOperator(ProOperator *oper); - bool visitProCondition(ProCondition *condition); + ProItem::ProItemReturn visitBeginProBlock(ProBlock *block); + void visitEndProBlock(ProBlock *block); + ProItem::ProItemReturn visitProLoopIteration(); + void visitProLoopCleanup(); + void visitBeginProVariable(ProVariable *variable); + void visitEndProVariable(ProVariable *variable); + ProItem::ProItemReturn visitBeginProFile(ProFile *value); + ProItem::ProItemReturn visitEndProFile(ProFile *value); + void visitProValue(ProValue *value); + ProItem::ProItemReturn visitProFunction(ProFunction *function); + void visitProOperator(ProOperator *oper); + void visitProCondition(ProCondition *condition); QStringList valuesDirect(const QString &variableName) const { return m_valuemap[variableName]; } QStringList values(const QString &variableName) const; QStringList values(const QString &variableName, const ProFile *pro) const; + QStringList values(const QString &variableName, const QHash<QString, QStringList> &place, + const ProFile *pro) const; QString propertyValue(const QString &val) const; bool isActiveConfig(const QString &config, bool regex = false); QStringList expandVariableReferences(const QString &value); + void doVariableReplace(QString *str); QStringList evaluateExpandFunction(const QString &function, const QString &arguments); QString format(const char *format) const; QString currentFileName() const; - QString getcwd() const; + QString currentDirectory() const; ProFile *currentProFile() const; - bool evaluateConditionalFunction(const QString &function, const QString &arguments, bool *result); - bool evaluateFile(const QString &fileName, bool *result); - bool evaluateFeatureFile(const QString &fileName, bool *result); + ProItem::ProItemReturn evaluateConditionalFunction(const QString &function, const QString &arguments); + bool evaluateFile(const QString &fileName); + bool evaluateFeatureFile(const QString &fileName); - QStringList qmakeFeaturePaths(); + static inline ProItem::ProItemReturn returnBool(bool b) + { return b ? ProItem::ReturnTrue : ProItem::ReturnFalse; } - ProFileEvaluator *q; + QStringList evaluateFunction(ProBlock *funcPtr, const QStringList &argumentsList, bool *ok); - QStack<ProBlock *> m_blockstack; - ProBlock *m_block; + QStringList qmakeFeaturePaths(); - ProItem *m_commentItem; - QString m_proitem; - QString m_pendingComment; - bool m_syntaxError; - bool m_contNextLine; - bool m_condition; - bool m_invertNext; + struct State { + bool condition; + bool prevCondition; + } m_sts; + bool m_invertNext; // Short-lived, so not in State + int m_skipLevel; + bool m_cumulative; + bool m_isFirstVariableValue; QString m_lastVarName; ProVariable::VariableOperator m_variableOperator; - int m_lineNo; // Error reporting + QString m_origfile; QString m_oldPath; // To restore the current path to the path QStack<ProFile*> m_profileStack; // To handle 'include(a.pri), so we can track back to 'a.pro' when finished with 'a.pri' + struct ProLoop { + QString variable; + QStringList oldVarVal; + QStringList list; + int index; + bool infinite; + }; + QStack<ProLoop> m_loopStack; + + // we need the following two variables for handling + // CONFIG = foo bar $$CONFIG + QHash<QString, QStringList> m_tempValuemap; // used while evaluating (variable operator value1 value2 ...) + QHash<const ProFile*, QHash<QString, QStringList> > m_tempFilevaluemap; // used while evaluating (variable operator value1 value2 ...) QHash<QString, QStringList> m_valuemap; // VariableName must be us-ascii, the content however can be non-us-ascii. QHash<const ProFile*, QHash<QString, QStringList> > m_filevaluemap; // Variables per include file QHash<QString, QString> m_properties; - QString m_origfile; + QString m_outputDir; + + bool m_definingTest; + QString m_definingFunc; + QHash<QString, ProBlock *> m_testFunctions; + QHash<QString, ProBlock *> m_replaceFunctions; + QStringList m_returnValue; + QStack<QHash<QString, QStringList> > m_valuemapStack; + QStack<QHash<const ProFile*, QHash<QString, QStringList> > > m_filevaluemapStack; int m_prevLineNo; // Checking whether we're assigning the same TARGET ProFile *m_prevProFile; // See m_prevLineNo - - bool m_verbose; }; +#if (!defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)) && !defined(__SUNPRO_CC) +Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::State, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::ProLoop, Q_MOVABLE_TYPE); +#endif + ProFileEvaluator::Private::Private(ProFileEvaluator *q_) : q(q_) { + // Global parser state m_prevLineNo = 0; m_prevProFile = 0; + + // Configuration, more or less m_verbose = true; + m_cumulative = true; + + // Evaluator state + m_sts.condition = false; + m_sts.prevCondition = false; + m_invertNext = false; + m_skipLevel = 0; + m_isFirstVariableValue = true; + m_definingFunc.clear(); } bool ProFileEvaluator::Private::read(ProFile *pro) @@ -166,8 +289,11 @@ bool ProFileEvaluator::Private::read(ProFile *pro) return false; } + // Parser state m_block = 0; m_commentItem = 0; + m_inQuote = false; + m_parens = 0; m_contNextLine = false; m_syntaxError = false; m_lineNo = 1; @@ -191,71 +317,84 @@ bool ProFileEvaluator::Private::parseLine(const QString &line0) if (m_blockstack.isEmpty()) return false; - ushort quote = 0; - int parens = 0; - bool contNextLine = false; + int parens = m_parens; + bool inQuote = m_inQuote; + bool escaped = false; QString line = line0.simplified(); for (int i = 0; !m_syntaxError && i < line.length(); ++i) { ushort c = line.at(i).unicode(); - if (quote && c == quote) - quote = 0; - else if (c == '(') - ++parens; - else if (c == ')') - --parens; - else if (c == '"' && (i == 0 || line.at(i - 1).unicode() != '\\')) - quote = c; - else if (!parens && !quote) { - if (c == '#') { - insertComment(line.mid(i + 1)); - contNextLine = m_contNextLine; - break; - } - if (c == '\\' && i >= line.count() - 1) { - updateItem(); - contNextLine = true; - continue; - } - if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) { - if (c == ' ') - updateItem(); - else - m_proitem += c; - continue; - } - if (c == ':') { - enterScope(false); - continue; - } - if (c == '{') { - enterScope(true); - continue; - } - if (c == '}') { - leaveScope(); + if (c == '#') { // Yep - no escaping possible + insertComment(line.mid(i + 1)); + escaped = m_contNextLine; + break; + } + if (!escaped) { + if (c == '\\') { + escaped = true; + m_proitem += c; continue; - } - if (c == '=') { - insertVariable(line, &i); + } else if (c == '"') { + inQuote = !inQuote; + m_proitem += c; continue; } - if (c == '|' || c == '!') { - insertOperator(c); - continue; + } else { + escaped = false; + } + if (!inQuote) { + if (c == '(') { + ++parens; + } else if (c == ')') { + --parens; + } else if (!parens) { + if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) { + if (c == ' ') + updateItem(); + else + m_proitem += c; + continue; + } + if (c == ':') { + enterScope(false); + continue; + } + if (c == '{') { + enterScope(true); + continue; + } + if (c == '}') { + leaveScope(); + continue; + } + if (c == '=') { + insertVariable(line, &i); + continue; + } + if (c == '|' || c == '!') { + insertOperator(c); + continue; + } } } m_proitem += c; } - m_contNextLine = contNextLine; - - if (!m_syntaxError) { + m_inQuote = inQuote; + m_parens = parens; + m_contNextLine = escaped; + if (escaped) { + m_proitem.chop(1); updateItem(); - if (!m_contNextLine) + return true; + } else { + if (!m_syntaxError) { + updateItem(); finalizeBlock(); + return true; + } + return false; } - return !m_syntaxError; } void ProFileEvaluator::Private::finalizeBlock() @@ -451,85 +590,220 @@ void ProFileEvaluator::Private::updateItem() } -bool ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block) +ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block) +{ + if (block->blockKind() & ProBlock::ScopeContentsKind) { + if (!m_definingFunc.isEmpty()) { + if (!m_skipLevel || m_cumulative) { + QHash<QString, ProBlock *> *hash = + (m_definingTest ? &m_testFunctions : &m_replaceFunctions); + if (ProBlock *def = hash->value(m_definingFunc)) + def->deref(); + hash->insert(m_definingFunc, block); + block->ref(); + block->setBlockKind(block->blockKind() | ProBlock::FunctionBodyKind); + } + m_definingFunc.clear(); + return ProItem::ReturnSkip; + } else if (!(block->blockKind() & ProBlock::FunctionBodyKind)) { + if (!m_sts.condition) + ++m_skipLevel; + else + Q_ASSERT(!m_skipLevel); + } + } else { + if (!m_skipLevel) { + if (m_sts.condition) { + m_sts.prevCondition = true; + m_sts.condition = false; + } + } else { + Q_ASSERT(!m_sts.condition); + } + } + return ProItem::ReturnTrue; +} + +void ProFileEvaluator::Private::visitEndProBlock(ProBlock *block) +{ + if ((block->blockKind() & ProBlock::ScopeContentsKind) + && !(block->blockKind() & ProBlock::FunctionBodyKind)) { + if (m_skipLevel) { + Q_ASSERT(!m_sts.condition); + --m_skipLevel; + } else if (!(block->blockKind() & ProBlock::SingleLine)) { + // Conditionals contained inside this block may have changed the state. + // So we reset it here to make an else following us do the right thing. + m_sts.condition = true; + } + } +} + +ProItem::ProItemReturn ProFileEvaluator::Private::visitProLoopIteration() { - if (block->blockKind() == ProBlock::ScopeKind) { - m_invertNext = false; - m_condition = false; + ProLoop &loop = m_loopStack.top(); + + if (loop.infinite) { + if (!loop.variable.isEmpty()) + m_valuemap[loop.variable] = QStringList(QString::number(loop.index++)); + if (loop.index > 1000) { + q->errorMessage(format("ran into infinite loop (> 1000 iterations).")); + return ProItem::ReturnFalse; + } + } else { + QString val; + do { + if (loop.index >= loop.list.count()) + return ProItem::ReturnFalse; + val = loop.list.at(loop.index++); + } while (val.isEmpty()); // stupid, but qmake is like that + m_valuemap[loop.variable] = QStringList(val); } - return true; + return ProItem::ReturnTrue; } -bool ProFileEvaluator::Private::visitEndProBlock(ProBlock *block) +void ProFileEvaluator::Private::visitProLoopCleanup() { - Q_UNUSED(block); - return true; + ProLoop &loop = m_loopStack.top(); + m_valuemap[loop.variable] = loop.oldVarVal; + m_loopStack.pop_back(); } -bool ProFileEvaluator::Private::visitBeginProVariable(ProVariable *variable) +void ProFileEvaluator::Private::visitBeginProVariable(ProVariable *variable) { m_lastVarName = variable->variable(); m_variableOperator = variable->variableOperator(); - return true; + m_isFirstVariableValue = true; + m_tempValuemap = m_valuemap; + m_tempFilevaluemap = m_filevaluemap; } -bool ProFileEvaluator::Private::visitEndProVariable(ProVariable *variable) +void ProFileEvaluator::Private::visitEndProVariable(ProVariable *variable) { Q_UNUSED(variable); + m_valuemap = m_tempValuemap; + m_filevaluemap = m_tempFilevaluemap; m_lastVarName.clear(); - return true; } -bool ProFileEvaluator::Private::visitProOperator(ProOperator *oper) +void ProFileEvaluator::Private::visitProOperator(ProOperator *oper) { m_invertNext = (oper->operatorKind() == ProOperator::NotOperator); - return true; } -bool ProFileEvaluator::Private::visitProCondition(ProCondition *cond) +void ProFileEvaluator::Private::visitProCondition(ProCondition *cond) { - if (!m_condition) { - if (m_invertNext) - m_condition |= !isActiveConfig(cond->text(), true); - else - m_condition |= isActiveConfig(cond->text(), true); + if (!m_skipLevel) { + if (!cond->text().compare(QLatin1String("else"), Qt::CaseInsensitive)) { + m_sts.condition = !m_sts.prevCondition; + } else { + m_sts.prevCondition = false; + if (!m_sts.condition && isActiveConfig(cond->text(), true) ^ m_invertNext) + m_sts.condition = true; + } } - return true; + m_invertNext = false; } -bool ProFileEvaluator::Private::visitBeginProFile(ProFile * pro) +ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProFile(ProFile * pro) { PRE(pro); - bool ok = true; m_lineNo = pro->lineNumber(); + if (m_origfile.isEmpty()) + m_origfile = pro->fileName(); if (m_oldPath.isEmpty()) { // change the working directory for the initial profile we visit, since // that is *the* profile. All the other times we reach this function will be due to // include(file) or load(file) + m_oldPath = QDir::currentPath(); + m_profileStack.push(pro); - ok = QDir::setCurrent(pro->directoryName()); - } - if (m_origfile.isEmpty()) - m_origfile = pro->fileName(); + const QString mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS")); + if (!mkspecDirectory.isEmpty()) { + bool cumulative = m_cumulative; + m_cumulative = false; + // This is what qmake does, everything set in the mkspec is also set + // But this also creates a lot of problems + evaluateFile(mkspecDirectory + QLatin1String("/default/qmake.conf")); + evaluateFile(mkspecDirectory + QLatin1String("/features/default_pre.prf")); + m_cumulative = cumulative; + } - return ok; + return returnBool(QDir::setCurrent(pro->directoryName())); + } + + return ProItem::ReturnTrue; } -bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro) +ProItem::ProItemReturn ProFileEvaluator::Private::visitEndProFile(ProFile * pro) { PRE(pro); - bool ok = true; m_lineNo = pro->lineNumber(); if (m_profileStack.count() == 1 && !m_oldPath.isEmpty()) { + const QString &mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS")); + if (!mkspecDirectory.isEmpty()) { + bool cumulative = m_cumulative; + m_cumulative = false; + + evaluateFile(mkspecDirectory + QLatin1String("/features/default_post.prf")); + + QSet<QString> processed; + forever { + bool finished = true; + QStringList configs = valuesDirect(QLatin1String("CONFIG")); + for (int i = configs.size() - 1; i >= 0; --i) { + const QString config = configs[i].toLower(); + if (!processed.contains(config)) { + processed.insert(config); + if (evaluateFile(mkspecDirectory + QLatin1String("/features/") + + config + QLatin1String(".prf"))) { + finished = false; + break; + } + } + } + if (finished) + break; + } + + foreach (ProBlock *itm, m_replaceFunctions) + itm->deref(); + m_replaceFunctions.clear(); + foreach (ProBlock *itm, m_testFunctions) + itm->deref(); + m_testFunctions.clear(); + + m_cumulative = cumulative; + } + m_profileStack.pop(); - ok = QDir::setCurrent(m_oldPath); + return returnBool(QDir::setCurrent(m_oldPath)); + } + + return ProItem::ReturnTrue; +} + +static void replaceInList(QStringList *varlist, + const QRegExp ®exp, const QString &replace, bool global) +{ + for (QStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) { + if ((*varit).contains(regexp)) { + (*varit).replace(regexp, replace); + if ((*varit).isEmpty()) + varit = varlist->erase(varit); + else + ++varit; + if(!global) + break; + } else { + ++varit; + } } - return ok; } -bool ProFileEvaluator::Private::visitProValue(ProValue *value) +void ProFileEvaluator::Private::visitProValue(ProValue *value) { PRE(value); m_lineNo = value->lineNumber(); @@ -546,8 +820,8 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value) if (varName == QLatin1String("TARGET") && m_lineNo == m_prevLineNo && currentProFile() == m_prevProFile) { - QStringList targets = m_valuemap.value(QLatin1String("TARGET")); - m_valuemap.remove(QLatin1String("TARGET")); + QStringList targets = m_tempValuemap.value(QLatin1String("TARGET")); + m_tempValuemap.remove(QLatin1String("TARGET")); QStringList lastTarget(targets.takeLast()); lastTarget << v.join(QLatin1String(" ")); targets.push_back(lastTarget.join(QLatin1String(" "))); @@ -557,38 +831,59 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value) m_prevProFile = currentProFile(); switch (m_variableOperator) { - case ProVariable::UniqueAddOperator: // * - insertUnique(&m_valuemap, varName, v, true); - insertUnique(&m_filevaluemap[currentProFile()], varName, v, true); - break; case ProVariable::SetOperator: // = - case ProVariable::AddOperator: // + - insertUnique(&m_valuemap, varName, v, false); - insertUnique(&m_filevaluemap[currentProFile()], varName, v, false); + if (!m_cumulative) { + if (!m_skipLevel) { + if (m_isFirstVariableValue) { + m_tempValuemap[varName] = v; + m_tempFilevaluemap[currentProFile()][varName] = v; + } else { // handle lines "CONFIG = foo bar" + m_tempValuemap[varName] += v; + m_tempFilevaluemap[currentProFile()][varName] += v; + } + } + } else { + // We are greedy for values. + m_tempValuemap[varName] += v; + m_tempFilevaluemap[currentProFile()][varName] += v; + } + break; + case ProVariable::UniqueAddOperator: // *= + if (!m_skipLevel || m_cumulative) { + insertUnique(&m_tempValuemap, varName, v); + insertUnique(&m_tempFilevaluemap[currentProFile()], varName, v); + } break; - case ProVariable::RemoveOperator: // - - // fix me: interaction between AddOperator and RemoveOperator - insertUnique(&m_valuemap, varName.prepend(QLatin1Char('-')), v, false); - insertUnique(&m_filevaluemap[currentProFile()], - varName.prepend(QLatin1Char('-')), v, false); + case ProVariable::AddOperator: // += + if (!m_skipLevel || m_cumulative) { + m_tempValuemap[varName] += v; + m_tempFilevaluemap[currentProFile()][varName] += v; + } break; - case ProVariable::ReplaceOperator: // ~ + case ProVariable::RemoveOperator: // -= + if (!m_cumulative) { + if (!m_skipLevel) { + removeEach(&m_tempValuemap, varName, v); + removeEach(&m_tempFilevaluemap[currentProFile()], varName, v); + } + } else { + // We are stingy with our values, too. + } + break; + case ProVariable::ReplaceOperator: // ~= { // DEFINES ~= s/a/b/?[gqi] -/* Create a superset by executing replacement + adding items that have changed - to original list. We're not sure if this is really the right approach, so for - the time being we will just do nothing ... - + doVariableReplace(&val); + if (val.length() < 4 || val[0] != QLatin1Char('s')) { + q->logMessage(format("the ~= operator can handle only the s/// function.")); + break; + } QChar sep = val.at(1); QStringList func = val.split(sep); if (func.count() < 3 || func.count() > 4) { - q->logMessage(format("'~= operator '(function s///) expects 3 or 4 arguments.")); - return false; - } - if (func[0] != QLatin1String("s")) { - q->logMessage(format("~= operator can only handle s/// function.")); - return false; + q->logMessage(format("the s/// function expects 3 or 4 arguments.")); + break; } bool global = false, quote = false, case_sense = false; @@ -604,40 +899,41 @@ bool ProFileEvaluator::Private::visitProValue(ProValue *value) QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive); - QStringList replaceList = replaceInList(m_valuemap.value(varName), regexp, replace, - global); - // Add changed entries to list - foreach (const QString &entry, replaceList) - if (!m_valuemap.value(varName).contains(entry)) - insertUnique(&m_valuemap, varName, QStringList() << entry, false); - - replaceList = replaceInList(m_filevaluemap[currentProFile()].value(varName), regexp, - replace, global); - foreach (const QString &entry, replaceList) - if (!m_filevaluemap[currentProFile()].value(varName).contains(entry)) - insertUnique(&m_filevaluemap[currentProFile()], varName, - QStringList() << entry, false); */ + if (!m_skipLevel || m_cumulative) { + // We could make a union of modified and unmodified values, + // but this will break just as much as it fixes, so leave it as is. + replaceInList(&m_tempValuemap[varName], regexp, replace, global); + replaceInList(&m_tempFilevaluemap[currentProFile()][varName], regexp, replace, global); + } } break; } - return true; + m_isFirstVariableValue = false; } -bool ProFileEvaluator::Private::visitProFunction(ProFunction *func) +ProItem::ProItemReturn ProFileEvaluator::Private::visitProFunction(ProFunction *func) { - m_lineNo = func->lineNumber(); - bool result = true; - bool ok = true; - QString text = func->text(); - int lparen = text.indexOf(QLatin1Char('(')); - int rparen = text.lastIndexOf(QLatin1Char(')')); - Q_ASSERT(lparen < rparen); - - QString arguments = text.mid(lparen + 1, rparen - lparen - 1); - QString funcName = text.left(lparen); - ok &= evaluateConditionalFunction(funcName.trimmed(), arguments, &result); - return ok; + // Make sure that called subblocks don't inherit & destroy the state + bool invertThis = m_invertNext; + m_invertNext = false; + if (!m_skipLevel) + m_sts.prevCondition = false; + if (m_cumulative || !m_sts.condition) { + QString text = func->text(); + int lparen = text.indexOf(QLatin1Char('(')); + int rparen = text.lastIndexOf(QLatin1Char(')')); + Q_ASSERT(lparen < rparen); + QString arguments = text.mid(lparen + 1, rparen - lparen - 1); + QString funcName = text.left(lparen); + m_lineNo = func->lineNumber(); + ProItem::ProItemReturn result = evaluateConditionalFunction(funcName.trimmed(), arguments); + if (result != ProItem::ReturnFalse && result != ProItem::ReturnTrue) + return result; + if (!m_skipLevel && ((result == ProItem::ReturnTrue) ^ invertThis)) + m_sts.condition = true; + } + return ProItem::ReturnTrue; } @@ -645,7 +941,7 @@ QStringList ProFileEvaluator::Private::qmakeFeaturePaths() { QStringList concat; { - const QString base_concat = QDir::separator() + QString(QLatin1String("features")); + const QString base_concat = QDir::separator() + QLatin1String("features"); concat << base_concat + QDir::separator() + QLatin1String("mac"); concat << base_concat + QDir::separator() + QLatin1String("macx"); concat << base_concat + QDir::separator() + QLatin1String("unix"); @@ -654,7 +950,7 @@ QStringList ProFileEvaluator::Private::qmakeFeaturePaths() concat << base_concat + QDir::separator() + QLatin1String("qnx6"); concat << base_concat; } - const QString mkspecs_concat = QDir::separator() + QString(QLatin1String("mkspecs")); + const QString mkspecs_concat = QDir::separator() + QLatin1String("mkspecs"); QStringList feature_roots; QByteArray mkspec_path = qgetenv("QMAKEFEATURES"); if (!mkspec_path.isNull()) @@ -757,12 +1053,17 @@ QString ProFileEvaluator::Private::currentFileName() const return QString(); } -QString ProFileEvaluator::Private::getcwd() const +QString ProFileEvaluator::Private::currentDirectory() const { ProFile *cur = m_profileStack.top(); return cur->directoryName(); } +void ProFileEvaluator::Private::doVariableReplace(QString *str) +{ + *str = expandVariableReferences(*str).join(QString(Option::field_sep)); +} + QStringList ProFileEvaluator::Private::expandVariableReferences(const QString &str) { QStringList ret; @@ -977,10 +1278,49 @@ bool ProFileEvaluator::Private::isActiveConfig(const QString &config, bool regex return false; } +QStringList ProFileEvaluator::Private::evaluateFunction( + ProBlock *funcPtr, const QStringList &argumentsList, bool *ok) +{ + bool oki; + QStringList ret; + + if (m_valuemapStack.count() >= 100) { + q->errorMessage(format("ran into infinite recursion (depth > 100).")); + oki = false; + } else { + State sts = m_sts; + m_valuemapStack.push(m_valuemap); + m_filevaluemapStack.push(m_filevaluemap); + + QStringList args; + for (int i = 0; i < argumentsList.count(); ++i) { + QStringList theArgs = expandVariableReferences(argumentsList[i]); + args += theArgs; + m_valuemap[QString::number(i+1)] = theArgs; + } + m_valuemap[QLatin1String("ARGS")] = args; + oki = (funcPtr->Accept(this) != ProItem::ReturnFalse); // True || Return + ret = m_returnValue; + m_returnValue.clear(); + + m_valuemap = m_valuemapStack.pop(); + m_filevaluemap = m_filevaluemapStack.pop(); + m_sts = sts; + } + if (ok) + *ok = oki; + if (oki) + return ret; + return QStringList(); +} + QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &func, const QString &arguments) { QStringList argumentsList = split_arg_list(arguments); + if (ProBlock *funcPtr = m_replaceFunctions.value(func, 0)) + return evaluateFunction(funcPtr, argumentsList, 0); + QStringList args; for (int i = 0; i < argumentsList.count(); ++i) args += expandVariableReferences(argumentsList[i]).join(Option::field_sep); @@ -991,35 +1331,34 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun E_UPPER, E_LOWER, E_FILES, E_PROMPT, E_RE_ESCAPE, E_REPLACE }; - static QHash<QString, int> *expands = 0; - if (!expands) { - expands = new QHash<QString, int>; - expands->insert(QLatin1String("member"), E_MEMBER); //v (implemented) - expands->insert(QLatin1String("first"), E_FIRST); //v - expands->insert(QLatin1String("last"), E_LAST); //v - expands->insert(QLatin1String("cat"), E_CAT); - expands->insert(QLatin1String("fromfile"), E_FROMFILE); - expands->insert(QLatin1String("eval"), E_EVAL); - expands->insert(QLatin1String("list"), E_LIST); - expands->insert(QLatin1String("sprintf"), E_SPRINTF); - expands->insert(QLatin1String("join"), E_JOIN); //v - expands->insert(QLatin1String("split"), E_SPLIT); //v - expands->insert(QLatin1String("basename"), E_BASENAME); //v - expands->insert(QLatin1String("dirname"), E_DIRNAME); //v - expands->insert(QLatin1String("section"), E_SECTION); - expands->insert(QLatin1String("find"), E_FIND); - expands->insert(QLatin1String("system"), E_SYSTEM); //v - expands->insert(QLatin1String("unique"), E_UNIQUE); - expands->insert(QLatin1String("quote"), E_QUOTE); //v - expands->insert(QLatin1String("escape_expand"), E_ESCAPE_EXPAND); - expands->insert(QLatin1String("upper"), E_UPPER); - expands->insert(QLatin1String("lower"), E_LOWER); - expands->insert(QLatin1String("re_escape"), E_RE_ESCAPE); - expands->insert(QLatin1String("files"), E_FILES); - expands->insert(QLatin1String("prompt"), E_PROMPT); - expands->insert(QLatin1String("replace"), E_REPLACE); + static QHash<QString, int> expands; + if (expands.isEmpty()) { + expands.insert(QLatin1String("member"), E_MEMBER); + expands.insert(QLatin1String("first"), E_FIRST); + expands.insert(QLatin1String("last"), E_LAST); + expands.insert(QLatin1String("cat"), E_CAT); + expands.insert(QLatin1String("fromfile"), E_FROMFILE); // implementation disabled (see comment below) + expands.insert(QLatin1String("eval"), E_EVAL); + expands.insert(QLatin1String("list"), E_LIST); + expands.insert(QLatin1String("sprintf"), E_SPRINTF); + expands.insert(QLatin1String("join"), E_JOIN); + expands.insert(QLatin1String("split"), E_SPLIT); + expands.insert(QLatin1String("basename"), E_BASENAME); + expands.insert(QLatin1String("dirname"), E_DIRNAME); + expands.insert(QLatin1String("section"), E_SECTION); + expands.insert(QLatin1String("find"), E_FIND); + expands.insert(QLatin1String("system"), E_SYSTEM); + expands.insert(QLatin1String("unique"), E_UNIQUE); + expands.insert(QLatin1String("quote"), E_QUOTE); + expands.insert(QLatin1String("escape_expand"), E_ESCAPE_EXPAND); + expands.insert(QLatin1String("upper"), E_UPPER); + expands.insert(QLatin1String("lower"), E_LOWER); + expands.insert(QLatin1String("re_escape"), E_RE_ESCAPE); + expands.insert(QLatin1String("files"), E_FILES); + expands.insert(QLatin1String("prompt"), E_PROMPT); // interactive, so cannot be implemented + expands.insert(QLatin1String("replace"), E_REPLACE); } - ExpandFunc func_t = ExpandFunc(expands->value(func.toLower())); + ExpandFunc func_t = ExpandFunc(expands.value(func.toLower())); QStringList ret; @@ -1065,6 +1404,16 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun } break; } + case E_SPRINTF: + if(args.count() < 1) { + q->logMessage(format("sprintf(format, ...) requires at least one argument")); + } else { + QString tmp = args.at(0); + for (int i = 1; i < args.count(); ++i) + tmp = tmp.arg(args.at(i)); + ret = split_value_list(tmp); + } + break; case E_JOIN: { if (args.count() < 1 || args.count() > 4) { q->logMessage(format("join(var, glue, before, after) requires one to four arguments.")); @@ -1084,9 +1433,9 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun } case E_SPLIT: { if (args.count() != 2) { - q->logMessage(format("split(var, sep) requires two arguments")); + q->logMessage(format("split(var, sep) requires one or two arguments")); } else { - QString sep = args.at(1); + const QString &sep = (args.count() == 2) ? args[1] : QString(Option::field_sep); foreach (const QString &var, values(args.first())) foreach (const QString &splt, var.split(sep)) ret.append(splt); @@ -1157,8 +1506,82 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun } break; } - case E_SYSTEM: { - if (m_condition) { + case E_CAT: + if (args.count() < 1 || args.count() > 2) { + q->logMessage(format("cat(file, singleline=true) requires one or two arguments.")); + } else { + QString file = args[0]; + file = Option::fixPathToLocalOS(file); + + bool singleLine = true; + if (args.count() > 1) + singleLine = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive)); + + QFile qfile(file); + if (qfile.open(QIODevice::ReadOnly)) { + QTextStream stream(&qfile); + while (!stream.atEnd()) { + ret += split_value_list(stream.readLine().trimmed()); + if (!singleLine) + ret += QLatin1String("\n"); + } + qfile.close(); + } + } + break; +#if 0 // Used only by Qt's configure for caching + case E_FROMFILE: + if (args.count() != 2) { + q->logMessage(format("fromfile(file, variable) requires two arguments.")); + } else { + QString file = args[0], seek_variableName = args[1]; + + ProFile pro(Option::fixPathToLocalOS(file)); + + ProFileEvaluator visitor; + visitor.setVerbose(m_verbose); + visitor.setCumulative(m_cumulative); + + if (!visitor.queryProFile(&pro)) + break; + + if (!visitor.accept(&pro)) + break; + + ret = visitor.values(seek_variableName); + } + break; +#endif + case E_EVAL: { + if (args.count() != 1) { + q->logMessage(format("eval(variable) requires one argument")); + + } else { + ret += values(args.at(0)); + } + break; } + case E_LIST: { + static int x = 0; + QString tmp; + tmp.sprintf(".QMAKE_INTERNAL_TMP_variableName_%d", x++); + ret = QStringList(tmp); + QStringList lst; + foreach (const QString &arg, args) + lst += split_value_list(arg); + m_valuemap[tmp] = lst; + break; } + case E_FIND: + if (args.count() != 2) { + q->logMessage(format("find(var, str) requires two arguments.")); + } else { + QRegExp regx(args[1]); + foreach (const QString &val, values(args.first())) + if (regx.indexIn(val) != -1) + ret += val; + } + break; + case E_SYSTEM: + if (!m_skipLevel) { if (args.count() < 1 || args.count() > 2) { q->logMessage(format("system(execute) requires one or two arguments.")); } else { @@ -1166,7 +1589,7 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun FILE *proc = QT_POPEN(args[0].toLatin1(), "r"); bool singleLine = true; if (args.count() > 1) - singleLine = (args[1].toLower() == QLatin1String("true")); + singleLine = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive)); QString output; while (proc && !feof(proc)) { int read_in = int(fread(buff, 1, 255, proc)); @@ -1184,13 +1607,114 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun QT_PCLOSE(proc); } } - break; } + break; + case E_UNIQUE: + if(args.count() != 1) { + q->logMessage(format("unique(var) requires one argument.")); + } else { + foreach (const QString &var, values(args.first())) + if (!ret.contains(var)) + ret.append(var); + } + break; case E_QUOTE: for (int i = 0; i < args.count(); ++i) ret += QStringList(args.at(i)); break; + case E_ESCAPE_EXPAND: + for (int i = 0; i < args.size(); ++i) { + QChar *i_data = args[i].data(); + int i_len = args[i].length(); + for (int x = 0; x < i_len; ++x) { + if (*(i_data+x) == QLatin1Char('\\') && x < i_len-1) { + if (*(i_data+x+1) == QLatin1Char('\\')) { + ++x; + } else { + struct { + char in, out; + } mapped_quotes[] = { + { 'n', '\n' }, + { 't', '\t' }, + { 'r', '\r' }, + { 0, 0 } + }; + for (int i = 0; mapped_quotes[i].in; ++i) { + if (*(i_data+x+1) == QLatin1Char(mapped_quotes[i].in)) { + *(i_data+x) = QLatin1Char(mapped_quotes[i].out); + if (x < i_len-2) + memmove(i_data+x+1, i_data+x+2, (i_len-x-2)*sizeof(QChar)); + --i_len; + break; + } + } + } + } + } + ret.append(QString(i_data, i_len)); + } + break; + case E_RE_ESCAPE: + for (int i = 0; i < args.size(); ++i) + ret += QRegExp::escape(args[i]); + break; + case E_UPPER: + case E_LOWER: + for (int i = 0; i < args.count(); ++i) + if (func_t == E_UPPER) + ret += args[i].toUpper(); + else + ret += args[i].toLower(); + break; + case E_FILES: + if (args.count() != 1 && args.count() != 2) { + q->logMessage(format("files(pattern, recursive=false) requires one or two arguments")); + } else { + bool recursive = false; + if (args.count() == 2) + recursive = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive) || args[1].toInt()); + QStringList dirs; + QString r = Option::fixPathToLocalOS(args[0]); + int slash = r.lastIndexOf(QDir::separator()); + if (slash != -1) { + dirs.append(r.left(slash)); + r = r.mid(slash+1); + } else { + dirs.append(QString()); + } + + const QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard); + for (int d = 0; d < dirs.count(); d++) { + QString dir = dirs[d]; + if (!dir.isEmpty() && !dir.endsWith(Option::dir_sep)) + dir += QLatin1Char('/'); + + QDir qdir(dir); + for (int i = 0; i < (int)qdir.count(); ++i) { + if (qdir[i] == QLatin1String(".") || qdir[i] == QLatin1String("..")) + continue; + QString fname = dir + qdir[i]; + if (QFileInfo(fname).isDir()) { + if (recursive) + dirs.append(fname); + } + if (regex.exactMatch(qdir[i])) + ret += fname; + } + } + } + break; + case E_REPLACE: + if(args.count() != 3 ) { + q->logMessage(format("replace(var, before, after) requires three arguments")); + } else { + const QRegExp before(args[1]); + const QString after(args[2]); + foreach (QString val, values(args.first())) + ret += val.replace(before, after); + } + break; case 0: - q->logMessage(format("'%1' is not a function").arg(func)); + q->logMessage(format("'%1' is not a recognized replace function").arg(func)); break; default: q->logMessage(format("Function '%1' is not implemented").arg(func)); @@ -1200,64 +1724,323 @@ QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &fun return ret; } -bool ProFileEvaluator::Private::evaluateConditionalFunction(const QString &function, - const QString &arguments, bool *result) +ProItem::ProItemReturn ProFileEvaluator::Private::evaluateConditionalFunction( + const QString &function, const QString &arguments) { QStringList argumentsList = split_arg_list(arguments); + + if (ProBlock *funcPtr = m_testFunctions.value(function, 0)) { + bool ok; + QStringList ret = evaluateFunction(funcPtr, argumentsList, &ok); + if (ok) { + if (ret.isEmpty()) { + return ProItem::ReturnTrue; + } else { + if (ret.first() != QLatin1String("false")) { + if (ret.first() == QLatin1String("true")) { + return ProItem::ReturnTrue; + } else { + bool ok; + int val = ret.first().toInt(&ok); + if (ok) { + if (val) + return ProItem::ReturnTrue; + } else { + q->logMessage(format("Unexpected return value from test '%1': %2") + .arg(function).arg(ret.join(QLatin1String(" :: ")))); + } + } + } + } + } + return ProItem::ReturnFalse; + } + QString sep; sep.append(Option::field_sep); - QStringList args; for (int i = 0; i < argumentsList.count(); ++i) args += expandVariableReferences(argumentsList[i]).join(sep); - enum ConditionFunc { CF_CONFIG = 1, CF_CONTAINS, CF_COUNT, CF_EXISTS, CF_INCLUDE, - CF_LOAD, CF_ISEMPTY, CF_SYSTEM, CF_MESSAGE}; - - static QHash<QString, int> *functions = 0; - if (!functions) { - functions = new QHash<QString, int>; - functions->insert(QLatin1String("load"), CF_LOAD); //v - functions->insert(QLatin1String("include"), CF_INCLUDE); //v - functions->insert(QLatin1String("message"), CF_MESSAGE); //v - functions->insert(QLatin1String("warning"), CF_MESSAGE); //v - functions->insert(QLatin1String("error"), CF_MESSAGE); //v + enum TestFunc { T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS, + T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM, + T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE, + T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF, + T_FOR, T_DEFINE_TEST, T_DEFINE_REPLACE }; + + static QHash<QString, int> functions; + if (functions.isEmpty()) { + functions.insert(QLatin1String("requires"), T_REQUIRES); + functions.insert(QLatin1String("greaterThan"), T_GREATERTHAN); + functions.insert(QLatin1String("lessThan"), T_LESSTHAN); + functions.insert(QLatin1String("equals"), T_EQUALS); + functions.insert(QLatin1String("isEqual"), T_EQUALS); + functions.insert(QLatin1String("exists"), T_EXISTS); + functions.insert(QLatin1String("export"), T_EXPORT); + functions.insert(QLatin1String("clear"), T_CLEAR); + functions.insert(QLatin1String("unset"), T_UNSET); + functions.insert(QLatin1String("eval"), T_EVAL); + functions.insert(QLatin1String("CONFIG"), T_CONFIG); + functions.insert(QLatin1String("if"), T_IF); + functions.insert(QLatin1String("isActiveConfig"), T_CONFIG); + functions.insert(QLatin1String("system"), T_SYSTEM); + functions.insert(QLatin1String("return"), T_RETURN); + functions.insert(QLatin1String("break"), T_BREAK); + functions.insert(QLatin1String("next"), T_NEXT); + functions.insert(QLatin1String("defined"), T_DEFINED); + functions.insert(QLatin1String("contains"), T_CONTAINS); + functions.insert(QLatin1String("infile"), T_INFILE); + functions.insert(QLatin1String("count"), T_COUNT); + functions.insert(QLatin1String("isEmpty"), T_ISEMPTY); + functions.insert(QLatin1String("load"), T_LOAD); //v + functions.insert(QLatin1String("include"), T_INCLUDE); //v + functions.insert(QLatin1String("debug"), T_DEBUG); + functions.insert(QLatin1String("message"), T_MESSAGE); //v + functions.insert(QLatin1String("warning"), T_MESSAGE); //v + functions.insert(QLatin1String("error"), T_MESSAGE); //v + functions.insert(QLatin1String("for"), T_FOR); //v + functions.insert(QLatin1String("defineTest"), T_DEFINE_TEST); //v + functions.insert(QLatin1String("defineReplace"), T_DEFINE_REPLACE); //v } - bool cond = false; - bool ok = true; - - ConditionFunc func_t = (ConditionFunc)functions->value(function); + TestFunc func_t = (TestFunc)functions.value(function); switch (func_t) { - case CF_CONFIG: { + case T_DEFINE_TEST: + m_definingTest = true; + goto defineFunc; + case T_DEFINE_REPLACE: + m_definingTest = false; + defineFunc: + if (args.count() != 1) { + q->logMessage(format("%s(function) requires one argument.").arg(function)); + return ProItem::ReturnFalse; + } + m_definingFunc = args.first(); + return ProItem::ReturnTrue; + case T_DEFINED: + if (args.count() < 1 || args.count() > 2) { + q->logMessage(format("defined(function, [\"test\"|\"replace\"])" + " requires one or two arguments.")); + return ProItem::ReturnFalse; + } + if (args.count() > 1) { + if (args[1] == QLatin1String("test")) + return returnBool(m_testFunctions.contains(args[0])); + else if (args[1] == QLatin1String("replace")) + return returnBool(m_replaceFunctions.contains(args[0])); + q->logMessage(format("defined(function, type):" + " unexpected type [%1].\n").arg(args[1])); + return ProItem::ReturnFalse; + } + return returnBool(m_replaceFunctions.contains(args[0]) + || m_testFunctions.contains(args[0])); + case T_RETURN: + m_returnValue = args; + // It is "safe" to ignore returns - due to qmake brokeness + // they cannot be used to terminate loops anyway. + if (m_skipLevel || m_cumulative) + return ProItem::ReturnTrue; + if (m_valuemapStack.isEmpty()) { + q->logMessage(format("unexpected return().")); + return ProItem::ReturnFalse; + } + return ProItem::ReturnReturn; + case T_EXPORT: + if (m_skipLevel && !m_cumulative) + return ProItem::ReturnTrue; + if (args.count() != 1) { + q->logMessage(format("export(variable) requires one argument.")); + return ProItem::ReturnFalse; + } + for (int i = 0; i < m_valuemapStack.size(); ++i) { + m_valuemapStack[i][args[0]] = m_valuemap[args[0]]; + m_filevaluemapStack[i][currentProFile()][args[0]] = + m_filevaluemap[currentProFile()][args[0]]; + } + return ProItem::ReturnTrue; +#if 0 + case T_INFILE: + case T_REQUIRES: + case T_EVAL: +#endif + case T_FOR: { + if (m_cumulative) // This is a no-win situation, so just pretend it's no loop + return ProItem::ReturnTrue; + if (m_skipLevel) + return ProItem::ReturnFalse; + if (args.count() > 2 || args.count() < 1) { + q->logMessage(format("for({var, list|var, forever|ever})" + " requires one or two arguments.")); + return ProItem::ReturnFalse; + } + ProLoop loop; + loop.infinite = false; + loop.index = 0; + QString it_list; + if (args.count() == 1) { + doVariableReplace(&args[0]); + it_list = args[0]; + if (args[0] != QLatin1String("ever")) { + q->logMessage(format("for({var, list|var, forever|ever})" + " requires one or two arguments.")); + return ProItem::ReturnFalse; + } + it_list = QLatin1String("forever"); + } else { + loop.variable = args[0]; + loop.oldVarVal = m_valuemap.value(loop.variable); + doVariableReplace(&args[1]); + it_list = args[1]; + } + loop.list = m_valuemap[it_list]; + if (loop.list.isEmpty()) { + if (it_list == QLatin1String("forever")) { + loop.infinite = true; + } else { + int dotdot = it_list.indexOf(QLatin1String("..")); + if (dotdot != -1) { + bool ok; + int start = it_list.left(dotdot).toInt(&ok); + if (ok) { + int end = it_list.mid(dotdot+2).toInt(&ok); + if (ok) { + if (start < end) { + for (int i = start; i <= end; i++) + loop.list << QString::number(i); + } else { + for (int i = start; i >= end; i--) + loop.list << QString::number(i); + } + } + } + } + } + } + m_loopStack.push(loop); + m_sts.condition = true; + return ProItem::ReturnLoop; + } + case T_BREAK: + if (m_skipLevel) + return ProItem::ReturnFalse; + if (!m_loopStack.isEmpty()) + return ProItem::ReturnBreak; + // ### missing: breaking out of multiline blocks + q->logMessage(format("unexpected break().")); + return ProItem::ReturnFalse; + case T_NEXT: + if (m_skipLevel) + return ProItem::ReturnFalse; + if (!m_loopStack.isEmpty()) + return ProItem::ReturnNext; + q->logMessage(format("unexpected next().")); + return ProItem::ReturnFalse; + case T_IF: { + if (args.count() != 1) { + q->logMessage(format("if(condition) requires one argument.")); + return ProItem::ReturnFalse; + } + QString cond = args.first(); + bool escaped = false; // This is more than qmake does + bool quoted = false; + bool ret = true; + bool orOp = false; + bool invert = false; + bool isFunc = false; + int parens = 0; + QString test; + test.reserve(20); + QString args; + args.reserve(50); + const QChar *d = cond.unicode(); + const QChar *ed = d + cond.length(); + while (d < ed) { + ushort c = (d++)->unicode(); + if (!escaped) { + if (c == '\\') { + escaped = true; + args += c; // Assume no-one quotes the test name + continue; + } else if (c == '"') { + quoted = !quoted; + args += c; // Ditto + continue; + } + } else { + escaped = false; + } + if (quoted) { + args += c; // Ditto + } else { + bool isOp = false; + if (c == '(') { + isFunc = true; + if (parens) + args += c; + ++parens; + } else if (c == ')') { + --parens; + if (parens) + args += c; + } else if (!parens) { + if (c == ':' || c == '|') + isOp = true; + else if (c == '!') + invert = true; + else + test += c; + } else { + args += c; + } + if (!parens && (isOp || d == ed)) { + // Yes, qmake doesn't shortcut evaluations here. We can't, either, + // as some test functions have side effects. + bool success; + if (isFunc) { + success = evaluateConditionalFunction(test, args); + } else { + success = isActiveConfig(test, true); + } + success ^= invert; + if (orOp) + ret |= success; + else + ret &= success; + orOp = (c == '|'); + invert = false; + isFunc = false; + test.clear(); + args.clear(); + } + } + } + return returnBool(ret); + } + case T_CONFIG: { if (args.count() < 1 || args.count() > 2) { q->logMessage(format("CONFIG(config) requires one or two arguments.")); - ok = false; - break; + return ProItem::ReturnFalse; } if (args.count() == 1) { //cond = isActiveConfig(args.first()); XXX - break; + return ProItem::ReturnFalse; } const QStringList mutuals = args[1].split(QLatin1Char('|')); const QStringList &configs = valuesDirect(QLatin1String("CONFIG")); - for (int i = configs.size() - 1 && ok; i >= 0; i--) { + for (int i = configs.size() - 1; i >= 0; i--) { for (int mut = 0; mut < mutuals.count(); mut++) { if (configs[i] == mutuals[mut].trimmed()) { - cond = (configs[i] == args[0]); - goto done_T_CONFIG; + return returnBool(configs[i] == args[0]); } } } - done_T_CONFIG: - break; + return ProItem::ReturnFalse; } - case CF_CONTAINS: { + case T_CONTAINS: { if (args.count() < 2 || args.count() > 3) { q->logMessage(format("contains(var, val) requires two or three arguments.")); - ok = false; - break; + return ProItem::ReturnFalse; } QRegExp regx(args[1]); @@ -1266,8 +2049,7 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(const QString &funct for (int i = 0; i < l.size(); ++i) { const QString val = l[i]; if (regx.exactMatch(val) || val == args[1]) { - cond = true; - break; + return ProItem::ReturnTrue; } } } else { @@ -1276,178 +2058,320 @@ bool ProFileEvaluator::Private::evaluateConditionalFunction(const QString &funct const QString val = l[i]; for (int mut = 0; mut < mutuals.count(); mut++) { if (val == mutuals[mut].trimmed()) { - cond = (regx.exactMatch(val) || val == args[1]); - goto done_T_CONTAINS; + return returnBool(regx.exactMatch(val) || val == args[1]); } } } } - done_T_CONTAINS: - break; + return ProItem::ReturnFalse; } - case CF_COUNT: { + case T_COUNT: { if (args.count() != 2 && args.count() != 3) { - q->logMessage(format("count(var, count) requires two or three arguments.")); - ok = false; - break; + q->logMessage(format("count(var, count, op=\"equals\") requires two or three arguments.")); + return ProItem::ReturnFalse; } if (args.count() == 3) { QString comp = args[2]; if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) { - cond = values(args.first()).count() > args[1].toInt(); + return returnBool(values(args.first()).count() > args[1].toInt()); } else if (comp == QLatin1String(">=")) { - cond = values(args.first()).count() >= args[1].toInt(); + return returnBool(values(args.first()).count() >= args[1].toInt()); } else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) { - cond = values(args.first()).count() < args[1].toInt(); + return returnBool(values(args.first()).count() < args[1].toInt()); } else if (comp == QLatin1String("<=")) { - cond = values(args.first()).count() <= args[1].toInt(); - } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") || comp == QLatin1String("=") || comp == QLatin1String("==")) { - cond = values(args.first()).count() == args[1].toInt(); + return returnBool(values(args.first()).count() <= args[1].toInt()); + } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") + || comp == QLatin1String("=") || comp == QLatin1String("==")) { + return returnBool(values(args.first()).count() == args[1].toInt()); } else { - ok = false; q->logMessage(format("unexpected modifier to count(%2)").arg(comp)); + return ProItem::ReturnFalse; } - break; } - cond = values(args.first()).count() == args[1].toInt(); - break; + return returnBool(values(args.first()).count() == args[1].toInt()); + } + case T_GREATERTHAN: + case T_LESSTHAN: { + if (args.count() != 2) { + q->logMessage(format("%1(variable, value) requires two arguments.").arg(function)); + return ProItem::ReturnFalse; + } + QString rhs(args[1]), lhs(values(args[0]).join(QString(Option::field_sep))); + bool ok; + int rhs_int = rhs.toInt(&ok); + if (ok) { // do integer compare + int lhs_int = lhs.toInt(&ok); + if (ok) { + if (func_t == T_GREATERTHAN) + return returnBool(lhs_int > rhs_int); + return returnBool(lhs_int < rhs_int); + } + } + if (func_t == T_GREATERTHAN) + return returnBool(lhs > rhs); + return returnBool(lhs < rhs); + } + case T_EQUALS: + if (args.count() != 2) { + q->logMessage(format("%1(variable, value) requires two arguments.").arg(function)); + return ProItem::ReturnFalse; + } + return returnBool(values(args[0]).join(QString(Option::field_sep)) == args[1]); + case T_CLEAR: { + if (m_skipLevel && !m_cumulative) + return ProItem::ReturnFalse; + if (args.count() != 1) { + q->logMessage(format("%1(variable) requires one argument.").arg(function)); + return ProItem::ReturnFalse; + } + QHash<QString, QStringList>::Iterator it = m_valuemap.find(args[0]); + if (it == m_valuemap.end()) + return ProItem::ReturnFalse; + it->clear(); + return ProItem::ReturnTrue; + } + case T_UNSET: { + if (m_skipLevel && !m_cumulative) + return ProItem::ReturnFalse; + if (args.count() != 1) { + q->logMessage(format("%1(variable) requires one argument.").arg(function)); + return ProItem::ReturnFalse; + } + QHash<QString, QStringList>::Iterator it = m_valuemap.find(args[0]); + if (it == m_valuemap.end()) + return ProItem::ReturnFalse; + m_valuemap.erase(it); + return ProItem::ReturnTrue; } - case CF_INCLUDE: { + case T_INCLUDE: { + if (m_skipLevel && !m_cumulative) + return ProItem::ReturnFalse; QString parseInto; if (args.count() == 2) { parseInto = args[1]; } else if (args.count() != 1) { q->logMessage(format("include(file) requires one or two arguments.")); - ok = false; - break; + return ProItem::ReturnFalse; } QString fileName = args.first(); // ### this breaks if we have include(c:/reallystupid.pri) but IMHO that's really bad style. - QDir currentProPath(getcwd()); + QDir currentProPath(currentDirectory()); fileName = QDir::cleanPath(currentProPath.absoluteFilePath(fileName)); - ok = evaluateFile(fileName, &ok); - break; + State sts = m_sts; + bool ok = evaluateFile(fileName); + m_sts = sts; + return returnBool(ok); } - case CF_LOAD: { + case T_LOAD: { + if (m_skipLevel && !m_cumulative) + return ProItem::ReturnFalse; QString parseInto; bool ignore_error = false; if (args.count() == 2) { QString sarg = args[1]; - ignore_error = (sarg.toLower() == QLatin1String("true") || sarg.toInt()); + ignore_error = (!sarg.compare(QLatin1String("true"), Qt::CaseInsensitive) || sarg.toInt()); } else if (args.count() != 1) { q->logMessage(format("load(feature) requires one or two arguments.")); - ok = false; - break; + return ProItem::ReturnFalse; } - ok = evaluateFeatureFile( args.first(), &cond); - break; + // XXX ignore_error unused + return returnBool(evaluateFeatureFile(args.first())); } - case CF_MESSAGE: { + case T_DEBUG: + // Yup - do nothing. Nothing is going to enable debug output anyway. + return ProItem::ReturnFalse; + case T_MESSAGE: { if (args.count() != 1) { q->logMessage(format("%1(message) requires one argument.").arg(function)); - ok = false; - break; + return ProItem::ReturnFalse; } - QString msg = args.first(); - if (function == QLatin1String("error")) { - QStringList parents; - foreach (ProFile *proFile, m_profileStack) - parents.append(proFile->fileName()); - if (!parents.isEmpty()) - parents.takeLast(); - if (parents.isEmpty()) - q->fileMessage(format("Project ERROR: %1").arg(msg)); - else - q->fileMessage(format("Project ERROR: %1. File was included from: '%2'") - .arg(msg).arg(parents.join(QLatin1String("', '")))); - } else { - q->fileMessage(format("Project MESSAGE: %1").arg(msg)); - } - break; + QString msg = fixEnvVariables(args.first()); + q->fileMessage(QString::fromLatin1("Project %1: %2").arg(function.toUpper(), msg)); + // ### Consider real termination in non-cumulative mode + return returnBool(function != QLatin1String("error")); } - case CF_SYSTEM: { +#if 0 // Way too dangerous to enable. + case T_SYSTEM: { if (args.count() != 1) { q->logMessage(format("system(exec) requires one argument.")); - ok = false; - break; + ProItem::ReturnFalse; } - ok = system(args.first().toLatin1().constData()) == 0; - break; + return returnBool(system(args.first().toLatin1().constData()) == 0); } - case CF_ISEMPTY: { +#endif + case T_ISEMPTY: { if (args.count() != 1) { q->logMessage(format("isEmpty(var) requires one argument.")); - ok = false; - break; + return ProItem::ReturnFalse; } QStringList sl = values(args.first()); if (sl.count() == 0) { - cond = true; + return ProItem::ReturnTrue; } else if (sl.count() > 0) { QString var = sl.first(); - cond = (var.isEmpty()); + if (var.isEmpty()) + return ProItem::ReturnTrue; } - break; + return ProItem::ReturnFalse; } - case CF_EXISTS: { + case T_EXISTS: { if (args.count() != 1) { q->logMessage(format("exists(file) requires one argument.")); - ok = false; - break; + return ProItem::ReturnFalse; } QString file = args.first(); - - file = QDir::cleanPath(file); + file = Option::fixPathToLocalOS(file); if (QFile::exists(file)) { - cond = true; - break; + return ProItem::ReturnTrue; } //regular expression I guess - QString dirstr = getcwd(); + QString dirstr = currentDirectory(); int slsh = file.lastIndexOf(Option::dir_sep); if (slsh != -1) { dirstr = file.left(slsh+1); file = file.right(file.length() - slsh - 1); } - cond = QDir(dirstr).entryList(QStringList(file)).count(); + if (file.contains(QLatin1Char('*')) || file.contains(QLatin1Char('?'))) + if (!QDir(dirstr).entryList(QStringList(file)).isEmpty()) + return ProItem::ReturnTrue; - break; + return ProItem::ReturnFalse; } + case 0: + q->logMessage(format("'%1' is not a recognized test function").arg(function)); + return ProItem::ReturnFalse; + default: + q->logMessage(format("Function '%1' is not implemented").arg(function)); + return ProItem::ReturnFalse; } +} - if (result) - *result = cond; +QStringList ProFileEvaluator::Private::values(const QString &variableName, + const QHash<QString, QStringList> &place, + const ProFile *pro) const +{ + if (variableName == QLatin1String("LITERAL_WHITESPACE")) //a real space in a token + return QStringList(QLatin1String("\t")); + if (variableName == QLatin1String("LITERAL_DOLLAR")) //a real $ + return QStringList(QLatin1String("$")); + if (variableName == QLatin1String("LITERAL_HASH")) //a real # + return QStringList(QLatin1String("#")); + if (variableName == QLatin1String("OUT_PWD")) //the out going dir + return QStringList(m_outputDir); + if (variableName == QLatin1String("PWD") || //current working dir (of _FILE_) + variableName == QLatin1String("IN_PWD")) + return QStringList(currentDirectory()); + if (variableName == QLatin1String("DIR_SEPARATOR")) + return QStringList(Option::dir_sep); + if (variableName == QLatin1String("DIRLIST_SEPARATOR")) + return QStringList(Option::dirlist_sep); + if (variableName == QLatin1String("_LINE_")) //parser line number + return QStringList(QString::number(m_lineNo)); + if (variableName == QLatin1String("_FILE_")) //parser file; qmake is a bit weird here + return QStringList(m_profileStack.size() == 1 ? pro->fileName() : QFileInfo(pro->fileName()).fileName()); + if (variableName == QLatin1String("_DATE_")) //current date/time + return QStringList(QDateTime::currentDateTime().toString()); + if (variableName == QLatin1String("_PRO_FILE_")) + return QStringList(m_origfile); + if (variableName == QLatin1String("_PRO_FILE_PWD_")) + return QStringList(QFileInfo(m_origfile).absolutePath()); + if (variableName == QLatin1String("_QMAKE_CACHE_")) + return QStringList(); // FIXME? + if (variableName.startsWith(QLatin1String("QMAKE_HOST."))) { + QString ret, type = variableName.mid(11); +#if defined(Q_OS_WIN32) + if (type == QLatin1String("os")) { + ret = QLatin1String("Windows"); + } else if (type == QLatin1String("name")) { + DWORD name_length = 1024; + wchar_t name[1024]; + if (GetComputerName(name, &name_length)) + ret = QString::fromWCharArray(name); + } else if (type == QLatin1String("version") || type == QLatin1String("version_string")) { + QSysInfo::WinVersion ver = QSysInfo::WindowsVersion; + if (type == QLatin1String("version")) + ret = QString::number(ver); + else if (ver == QSysInfo::WV_Me) + ret = QLatin1String("WinMe"); + else if (ver == QSysInfo::WV_95) + ret = QLatin1String("Win95"); + else if (ver == QSysInfo::WV_98) + ret = QLatin1String("Win98"); + else if (ver == QSysInfo::WV_NT) + ret = QLatin1String("WinNT"); + else if (ver == QSysInfo::WV_2000) + ret = QLatin1String("Win2000"); + else if (ver == QSysInfo::WV_2000) + ret = QLatin1String("Win2003"); + else if (ver == QSysInfo::WV_XP) + ret = QLatin1String("WinXP"); + else if (ver == QSysInfo::WV_VISTA) + ret = QLatin1String("WinVista"); + else + ret = QLatin1String("Unknown"); + } else if (type == QLatin1String("arch")) { + SYSTEM_INFO info; + GetSystemInfo(&info); + switch(info.wProcessorArchitecture) { +#ifdef PROCESSOR_ARCHITECTURE_AMD64 + case PROCESSOR_ARCHITECTURE_AMD64: + ret = QLatin1String("x86_64"); + break; +#endif + case PROCESSOR_ARCHITECTURE_INTEL: + ret = QLatin1String("x86"); + break; + case PROCESSOR_ARCHITECTURE_IA64: +#ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: +#endif + ret = QLatin1String("IA64"); + break; + default: + ret = QLatin1String("Unknown"); + break; + } + } +#elif defined(Q_OS_UNIX) + struct utsname name; + if (!uname(&name)) { + if (type == QLatin1String("os")) + ret = QString::fromLatin1(name.sysname); + else if (type == QLatin1String("name")) + ret = QString::fromLatin1(name.nodename); + else if (type == QLatin1String("version")) + ret = QString::fromLatin1(name.release); + else if (type == QLatin1String("version_string")) + ret = QString::fromLatin1(name.version); + else if (type == QLatin1String("arch")) + ret = QString::fromLatin1(name.machine); + } +#endif + return QStringList(ret); + } - return ok; + QStringList result = place[variableName]; + if (result.isEmpty()) { + if (variableName == QLatin1String("TARGET")) { + result.append(QFileInfo(m_origfile).baseName()); + } else if (variableName == QLatin1String("TEMPLATE")) { + result.append(QLatin1String("app")); + } else if (variableName == QLatin1String("QMAKE_DIR_SEP")) { + result.append(Option::dirlist_sep); + } + } + return result; } QStringList ProFileEvaluator::Private::values(const QString &variableName) const { - if (variableName == QLatin1String("TARGET")) { - QStringList list = m_valuemap.value(variableName); - if (!m_origfile.isEmpty()) - list.append(QFileInfo(m_origfile).baseName()); - return list; - } - if (variableName == QLatin1String("PWD")) { - return QStringList(getcwd()); - } - return m_valuemap.value(variableName); + return values(variableName, m_valuemap, currentProFile()); } QStringList ProFileEvaluator::Private::values(const QString &variableName, const ProFile *pro) const { - if (variableName == QLatin1String("TARGET")) { - QStringList list = m_filevaluemap[pro].value(variableName); - if (!m_origfile.isEmpty()) - list.append(QFileInfo(m_origfile).baseName()); - return list; - } - if (variableName == QLatin1String("PWD")) { - return QStringList(QFileInfo(pro->fileName()).absoluteFilePath()); - } - return m_filevaluemap[pro].value(variableName); + return values(variableName, m_filevaluemap[pro], pro); } ProFile *ProFileEvaluator::parsedProFile(const QString &fileName) @@ -1473,27 +2397,21 @@ void ProFileEvaluator::releaseParsedProFile(ProFile *proFile) delete proFile; } -bool ProFileEvaluator::Private::evaluateFile(const QString &fileName, bool *result) +bool ProFileEvaluator::Private::evaluateFile(const QString &fileName) { - bool ok = true; ProFile *pro = q->parsedProFile(fileName); if (pro) { m_profileStack.push(pro); - ok = pro->Accept(this); + bool ok = (pro->Accept(this) == ProItem::ReturnTrue); m_profileStack.pop(); q->releaseParsedProFile(pro); - - if (result) - *result = true; + return ok; } else { - if (result) - *result = false; + return false; } - - return ok; } -bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName, bool *result) +bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName) { QString fn; foreach (const QString &path, qmakeFeaturePaths()) { @@ -1508,7 +2426,13 @@ bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName, boo break; } } - return fn.isEmpty() ? false : evaluateFile(fn, result); + if (fn.isEmpty()) + return false; + bool cumulative = m_cumulative; + m_cumulative = false; + bool ok = evaluateFile(fn); + m_cumulative = cumulative; + return ok; } QString ProFileEvaluator::Private::format(const char *fmt) const @@ -1542,14 +2466,23 @@ bool ProFileEvaluator::contains(const QString &variableName) const return d->m_valuemap.contains(variableName); } +inline QStringList fixEnvVariables(const QStringList &x) +{ + QStringList ret; + foreach (const QString &str, x) + ret << Option::fixString(str, Option::FixEnvVars); + return ret; +} + + QStringList ProFileEvaluator::values(const QString &variableName) const { - return d->values(variableName); + return fixEnvVariables(d->values(variableName)); } QStringList ProFileEvaluator::values(const QString &variableName, const ProFile *pro) const { - return d->values(variableName, pro); + return fixEnvVariables(d->values(variableName, pro)); } QStringList ProFileEvaluator::absolutePathValues( @@ -1609,12 +2542,14 @@ ProFileEvaluator::TemplateType ProFileEvaluator::templateType() { QStringList templ = values(QLatin1String("TEMPLATE")); if (templ.count() >= 1) { - QString t = templ.last().toLower(); - if (t == QLatin1String("app")) + const QString &t = templ.last(); + if (!t.compare(QLatin1String("app"), Qt::CaseInsensitive)) return TT_Application; - if (t == QLatin1String("lib")) + if (!t.compare(QLatin1String("lib"), Qt::CaseInsensitive)) return TT_Library; - if (t == QLatin1String("subdirs")) + if (!t.compare(QLatin1String("script"), Qt::CaseInsensitive)) + return TT_Script; + if (!t.compare(QLatin1String("subdirs"), Qt::CaseInsensitive)) return TT_Subdirs; } return TT_Unknown; @@ -1658,18 +2593,20 @@ void ProFileEvaluator::addProperties(const QHash<QString, QString> &properties) void ProFileEvaluator::logMessage(const QString &message) { - if (d->m_verbose) + if (d->m_verbose && !d->m_skipLevel) qWarning("%s", qPrintable(message)); } void ProFileEvaluator::fileMessage(const QString &message) { - qWarning("%s", qPrintable(message)); + if (!d->m_skipLevel) + qWarning("%s", qPrintable(message)); } void ProFileEvaluator::errorMessage(const QString &message) { - qWarning("%s", qPrintable(message)); + if (!d->m_skipLevel) + qWarning("%s", qPrintable(message)); } void ProFileEvaluator::setVerbose(bool on) @@ -1677,4 +2614,14 @@ void ProFileEvaluator::setVerbose(bool on) d->m_verbose = on; } +void ProFileEvaluator::setCumulative(bool on) +{ + d->m_cumulative = on; +} + +void ProFileEvaluator::setOutputDir(const QString &dir) +{ + d->m_outputDir = dir; +} + QT_END_NAMESPACE diff --git a/tools/linguist/shared/profileevaluator.h b/tools/linguist/shared/profileevaluator.h index ae09a59..f3498c1 100644 --- a/tools/linguist/shared/profileevaluator.h +++ b/tools/linguist/shared/profileevaluator.h @@ -59,6 +59,7 @@ public: TT_Unknown = 0, TT_Application, TT_Library, + TT_Script, TT_Subdirs }; @@ -67,7 +68,9 @@ public: ProFileEvaluator::TemplateType templateType(); virtual bool contains(const QString &variableName) const; - void setVerbose(bool on); + void setVerbose(bool on); // Default is false + void setCumulative(bool on); // Default is true! + void setOutputDir(const QString &dir); // Default is empty bool queryProFile(ProFile *pro); bool accept(ProFile *pro); @@ -92,6 +95,9 @@ public: private: class Private; Private *d; + + // This doesn't help gcc 3.3 and sunpro ... + template<typename T> friend class QTypeInfo; }; QT_END_NAMESPACE diff --git a/tools/linguist/shared/proitems.cpp b/tools/linguist/shared/proitems.cpp index 471417e..905c67e 100644 --- a/tools/linguist/shared/proitems.cpp +++ b/tools/linguist/shared/proitems.cpp @@ -58,15 +58,21 @@ QString ProItem::comment() const } // --------------- ProBlock ---------------- + ProBlock::ProBlock(ProBlock *parent) { m_blockKind = 0; m_parent = parent; + m_refCount = 1; } ProBlock::~ProBlock() { - qDeleteAll(m_proitems); + foreach (ProItem *itm, m_proitems) + if (itm->kind() == BlockKind) + static_cast<ProBlock *>(itm)->deref(); + else + delete itm; } void ProBlock::appendItem(ProItem *proitem) @@ -109,14 +115,37 @@ ProItem::ProItemKind ProBlock::kind() const return ProItem::BlockKind; } -bool ProBlock::Accept(AbstractProItemVisitor *visitor) -{ - visitor->visitBeginProBlock(this); - foreach (ProItem *item, m_proitems) { - if (!item->Accept(visitor)) - return false; +ProItem::ProItemReturn ProBlock::Accept(AbstractProItemVisitor *visitor) +{ + if (visitor->visitBeginProBlock(this) == ReturnSkip) + return ReturnTrue; + ProItemReturn rt = ReturnTrue; + for (int i = 0; i < m_proitems.count(); ++i) { + rt = m_proitems.at(i)->Accept(visitor); + if (rt != ReturnTrue && rt != ReturnFalse) { + if (rt == ReturnLoop) { + rt = ReturnTrue; + while (visitor->visitProLoopIteration()) + for (int j = i; ++j < m_proitems.count(); ) { + rt = m_proitems.at(j)->Accept(visitor); + if (rt != ReturnTrue && rt != ReturnFalse) { + if (rt == ReturnNext) { + rt = ReturnTrue; + break; + } + if (rt == ReturnBreak) + rt = ReturnTrue; + goto do_break; + } + } + do_break: + visitor->visitProLoopCleanup(); + } + break; + } } - return visitor->visitEndProBlock(this); + visitor->visitEndProBlock(this); + return rt; } // --------------- ProVariable ---------------- @@ -148,14 +177,13 @@ QString ProVariable::variable() const return m_variable; } -bool ProVariable::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProVariable::Accept(AbstractProItemVisitor *visitor) { visitor->visitBeginProVariable(this); - foreach (ProItem *item, m_proitems) { - if (!item->Accept(visitor)) - return false; - } - return visitor->visitEndProVariable(this); + foreach (ProItem *item, m_proitems) + item->Accept(visitor); // cannot fail + visitor->visitEndProVariable(this); + return ReturnTrue; } // --------------- ProValue ---------------- @@ -190,9 +218,10 @@ ProItem::ProItemKind ProValue::kind() const return ProItem::ValueKind; } -bool ProValue::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProValue::Accept(AbstractProItemVisitor *visitor) { - return visitor->visitProValue(this); + visitor->visitProValue(this); + return ReturnTrue; } // --------------- ProFunction ---------------- @@ -216,7 +245,7 @@ ProItem::ProItemKind ProFunction::kind() const return ProItem::FunctionKind; } -bool ProFunction::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProFunction::Accept(AbstractProItemVisitor *visitor) { return visitor->visitProFunction(this); } @@ -242,9 +271,10 @@ ProItem::ProItemKind ProCondition::kind() const return ProItem::ConditionKind; } -bool ProCondition::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProCondition::Accept(AbstractProItemVisitor *visitor) { - return visitor->visitProCondition(this); + visitor->visitProCondition(this); + return ReturnTrue; } // --------------- ProOperator ---------------- @@ -268,9 +298,10 @@ ProItem::ProItemKind ProOperator::kind() const return ProItem::OperatorKind; } -bool ProOperator::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProOperator::Accept(AbstractProItemVisitor *visitor) { - return visitor->visitProOperator(this); + visitor->visitProOperator(this); + return ReturnTrue; } // --------------- ProFile ---------------- @@ -315,13 +346,12 @@ bool ProFile::isModified() const return m_modified; } -bool ProFile::Accept(AbstractProItemVisitor *visitor) +ProItem::ProItemReturn ProFile::Accept(AbstractProItemVisitor *visitor) { - visitor->visitBeginProFile(this); - foreach (ProItem *item, m_proitems) { - if (!item->Accept(visitor)) - return false; - } + ProItemReturn rt; + if ((rt = visitor->visitBeginProFile(this)) != ReturnTrue) + return rt; + ProBlock::Accept(visitor); // cannot fail return visitor->visitEndProFile(this); } diff --git a/tools/linguist/shared/proitems.h b/tools/linguist/shared/proitems.h index aad0ba2..7833be1 100644 --- a/tools/linguist/shared/proitems.h +++ b/tools/linguist/shared/proitems.h @@ -60,6 +60,16 @@ public: BlockKind }; + enum ProItemReturn { + ReturnFalse, + ReturnTrue, + ReturnBreak, + ReturnNext, + ReturnLoop, + ReturnSkip, + ReturnReturn + }; + ProItem() : m_lineNumber(0) {} virtual ~ProItem() {} @@ -68,7 +78,7 @@ public: void setComment(const QString &comment); QString comment() const; - virtual bool Accept(AbstractProItemVisitor *visitor) = 0; + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor) = 0; int lineNumber() const { return m_lineNumber; } void setLineNumber(int lineNumber) { m_lineNumber = lineNumber; } @@ -86,7 +96,8 @@ public: ScopeContentsKind = 0x02, VariableKind = 0x04, ProFileKind = 0x08, - SingleLine = 0x10 + FunctionBodyKind = 0x10, + SingleLine = 0x80 }; ProBlock(ProBlock *parent); @@ -102,14 +113,18 @@ public: void setParent(ProBlock *parent); ProBlock *parent() const; + void ref() { ++m_refCount; } + void deref() { if (!--m_refCount) delete this; } + ProItem::ProItemKind kind() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); protected: QList<ProItem *> m_proitems; private: ProBlock *m_parent; int m_blockKind; + int m_refCount; }; class ProVariable : public ProBlock @@ -131,7 +146,7 @@ public: void setVariable(const QString &name); QString variable() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: VariableOperator m_variableKind; QString m_variable; @@ -150,7 +165,7 @@ public: ProItem::ProItemKind kind() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: QString m_value; ProVariable *m_variable; @@ -166,7 +181,7 @@ public: ProItem::ProItemKind kind() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: QString m_text; }; @@ -181,7 +196,7 @@ public: ProItem::ProItemKind kind() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: QString m_text; }; @@ -201,7 +216,7 @@ public: ProItem::ProItemKind kind() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: OperatorKind m_operatorKind; }; @@ -219,7 +234,7 @@ public: void setModified(bool modified); bool isModified() const; - virtual bool Accept(AbstractProItemVisitor *visitor); + virtual ProItemReturn Accept(AbstractProItemVisitor *visitor); private: QString m_fileName; diff --git a/tools/linguist/shared/proparserutils.h b/tools/linguist/shared/proparserutils.h index 1134c0b..0ffe4d2 100644 --- a/tools/linguist/shared/proparserutils.h +++ b/tools/linguist/shared/proparserutils.h @@ -93,6 +93,25 @@ struct Option Option::qmakespec = QString::fromLatin1(qgetenv("QMAKESPEC").data()); Option::field_sep = QLatin1Char(' '); } + + enum StringFixFlags { + FixNone = 0x00, + FixEnvVars = 0x01, + FixPathCanonicalize = 0x02, + FixPathToLocalSeparators = 0x04, + FixPathToTargetSeparators = 0x08 + }; + static QString fixString(QString string, uchar flags); + + inline static QString fixPathToLocalOS(const QString &in, bool fix_env = true, bool canonical = true) + { + uchar flags = FixPathToLocalSeparators; + if (fix_env) + flags |= FixEnvVars; + if (canonical) + flags |= FixPathCanonicalize; + return fixString(in, flags); + } }; #if defined(Q_OS_WIN32) Option::TARG_MODE Option::target_mode = Option::TARG_WIN_MODE; @@ -110,17 +129,20 @@ QString Option::dir_sep; QChar Option::field_sep; static void insertUnique(QHash<QString, QStringList> *map, - const QString &key, const QStringList &value, bool unique = true) + const QString &key, const QStringList &value) { QStringList &sl = (*map)[key]; - if (!unique) { - sl += value; - } else { - for (int i = 0; i < value.count(); ++i) { - if (!sl.contains(value.at(i))) - sl.append(value.at(i)); - } - } + foreach (const QString &str, value) + if (!sl.contains(str)) + sl.append(str); +} + +static void removeEach(QHash<QString, QStringList> *map, + const QString &key, const QStringList &value) +{ + QStringList &sl = (*map)[key]; + foreach (const QString &str, value) + sl.removeAll(str); } /* @@ -148,7 +170,12 @@ static QStringList replaceInList(const QStringList &varList, const QRegExp ®e } */ -inline QStringList splitPathList(const QString paths) +inline QString fixEnvVariables(const QString &x) +{ + return Option::fixString(x, Option::FixEnvVars); +} + +inline QStringList splitPathList(const QString &paths) { return paths.split(Option::dirlist_sep); } @@ -255,7 +282,7 @@ static QStringList split_value_list(const QString &vals, bool do_semicolon=false static QStringList qmake_mkspec_paths() { QStringList ret; - const QString concat = QDir::separator() + QString(QLatin1String("mkspecs")); + const QString concat = QDir::separator() + QLatin1String("mkspecs"); QByteArray qmakepath = qgetenv("QMAKEPATH"); if (!qmakepath.isEmpty()) { const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath)); diff --git a/tools/linguist/shared/qm.cpp b/tools/linguist/shared/qm.cpp index 381f5c5..dc681f5 100644 --- a/tools/linguist/shared/qm.cpp +++ b/tools/linguist/shared/qm.cpp @@ -173,6 +173,7 @@ public: bool save(QIODevice *iod); void insert(const TranslatorMessage &msg, bool forceComment); + void insertIdBased(const TranslatorMessage &message); void squeeze(TranslatorSaveMode mode); @@ -238,17 +239,13 @@ Prefix Releaser::commonPrefix(const ByteTranslatorMessage &m1, const ByteTransla void Releaser::writeMessage(const ByteTranslatorMessage &msg, QDataStream &stream, TranslatorSaveMode mode, Prefix prefix) const { - for (int i = 0; i < msg.translations().count(); ++i) { - QString str = msg.translations().at(i); - str.replace(QChar(Translator::DefaultVariantSeparator), - QChar(Translator::InternalVariantSeparator)); - stream << quint8(Tag_Translation) << str; - } + for (int i = 0; i < msg.translations().count(); ++i) + stream << quint8(Tag_Translation) << msg.translations().at(i); if (mode == SaveEverything) prefix = HashContextSourceTextComment; - // lrelease produces "wrong" .qm files for QByteArrays that are .isNull(). + // lrelease produces "wrong" QM files for QByteArrays that are .isNull(). switch (prefix) { default: case HashContextSourceTextComment: @@ -440,6 +437,16 @@ void Releaser::insert(const TranslatorMessage &message, bool forceComment) insertInternal(message, forceComment, false); } +void Releaser::insertIdBased(const TranslatorMessage &message) +{ + QStringList tlns = message.translations(); + 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); +} + void Releaser::setNumerusRules(const QByteArray &rules) { m_numerusRules = rules; @@ -546,7 +553,7 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) //qDebug() << "NUMITEMS: " << numItems; QTextCodec *codec = QTextCodec::codecForName( - cd.m_codecForSource.isEmpty() ? "Latin1" : cd.m_codecForSource); + cd.m_codecForSource.isEmpty() ? QByteArray("Latin1") : cd.m_codecForSource); QTextCodec *utf8Codec = 0; if (codec->name() != "UTF-8") utf8Codec = QTextCodec::codecForName("UTF-8"); @@ -593,8 +600,6 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) str[i] = QChar((str.at(i).unicode() >> 8) + ((str.at(i).unicode() << 8) & 0xff00)); } - str.replace(QChar(Translator::InternalVariantSeparator), - QChar(Translator::DefaultVariantSeparator)); translations << str; m += len; break; @@ -696,11 +701,17 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData int finished = 0; int unfinished = 0; int untranslated = 0; + int missingIds = 0; + int droppedData = 0; for (int i = 0; i != translator.messageCount(); ++i) { const TranslatorMessage &msg = translator.message(i); TranslatorMessage::Type typ = msg.type(); if (typ != TranslatorMessage::Obsolete) { + if (cd.m_idBased && msg.id().isEmpty()) { + ++missingIds; + continue; + } if (typ == TranslatorMessage::Unfinished) { if (msg.translation().isEmpty()) { ++untranslated; @@ -713,19 +724,34 @@ static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData } else { ++finished; } - // Drop the comment in (context, sourceText, comment), - // unless the context is empty, - // unless (context, sourceText, "") already exists or - // unless we already dropped the comment of (context, - // sourceText, comment0). - bool forceComment = - msg.comment().isEmpty() - || msg.context().isEmpty() - || translator.contains(msg.context(), msg.sourceText(), QString()); - releaser.insert(msg, forceComment); + if (cd.m_idBased) { + if (!msg.context().isEmpty() || !msg.comment().isEmpty()) + ++droppedData; + releaser.insertIdBased(msg); + } else { + // Drop the comment in (context, sourceText, comment), + // unless the context is empty, + // unless (context, sourceText, "") already exists or + // unless we already dropped the comment of (context, + // sourceText, comment0). + bool forceComment = + msg.comment().isEmpty() + || msg.context().isEmpty() + || translator.contains(msg.context(), msg.sourceText(), QString()); + releaser.insert(msg, forceComment); + } } } + if (missingIds) + cd.appendError(QCoreApplication::translate("LRelease", + "Dropped %n message(s) which had no ID.", 0, + QCoreApplication::CodecForTr, missingIds)); + if (droppedData) + cd.appendError(QCoreApplication::translate("LRelease", + "Excess context/disambiguation dropped from %n message(s).", 0, + QCoreApplication::CodecForTr, droppedData)); + releaser.squeeze(cd.m_saveMode); bool saved = releaser.save(&dev); if (saved && cd.isVerbose()) { diff --git a/tools/linguist/shared/qph.cpp b/tools/linguist/shared/qph.cpp index 076194c..4a29e0f 100644 --- a/tools/linguist/shared/qph.cpp +++ b/tools/linguist/shared/qph.cpp @@ -54,33 +54,19 @@ QT_BEGIN_NAMESPACE class QPHReader : public QXmlStreamReader { public: - QPHReader(QIODevice &dev, ConversionData &cd) - : QXmlStreamReader(&dev), m_cd(cd) + QPHReader(QIODevice &dev) + : QXmlStreamReader(&dev) {} // the "real thing" bool read(Translator &translator); private: - bool elementStarts(const QString &str) const - { - return isStartElement() && name() == str; - } - bool isWhiteSpace() const { return isCharacters() && text().toString().trimmed().isEmpty(); } - // needed to expand <byte ... /> - QString readContents(); - // needed to join <lengthvariant>s - QString readTransContents(); - - void handleError(); - - ConversionData &m_cd; - enum DataField { NoField, SourceField, TargetField, DefinitionField }; DataField m_currentField; QString m_currentSource; @@ -113,6 +99,8 @@ bool QPHReader::read(Translator &translator) else if (m_currentField == DefinitionField) m_currentDefinition += text(); } else if (isEndElement() && name() == QLatin1String("phrase")) { + m_currentTarget.replace(QChar(Translator::TextVariantSeparator), + QChar(Translator::BinaryVariantSeparator)); TranslatorMessage msg; msg.setSourceText(m_currentSource); msg.setTranslation(m_currentTarget); @@ -126,10 +114,10 @@ bool QPHReader::read(Translator &translator) return true; } -static bool loadQPH(Translator &translator, QIODevice &dev, ConversionData &cd) +static bool loadQPH(Translator &translator, QIODevice &dev, ConversionData &) { translator.setLocationsType(Translator::NoLocations); - QPHReader reader(dev, cd); + QPHReader reader(dev); return reader.read(translator); } @@ -173,7 +161,10 @@ static bool saveQPH(const Translator &translator, QIODevice &dev, ConversionData foreach (const TranslatorMessage &msg, translator.messages()) { t << "<phrase>\n"; t << " <source>" << protect(msg.sourceText()) << "</source>\n"; - t << " <target>" << protect(msg.translations().join(QLatin1String("@"))) + QString str = msg.translations().join(QLatin1String("@")); + str.replace(QChar(Translator::BinaryVariantSeparator), + QChar(Translator::TextVariantSeparator)); + t << " <target>" << protect(str) << "</target>\n"; if (!msg.context().isEmpty() || !msg.comment().isEmpty()) t << " <definition>" << msg.context() << msg.comment() diff --git a/tools/linguist/shared/translator.cpp b/tools/linguist/shared/translator.cpp index e5b8932..62f4d10 100644 --- a/tools/linguist/shared/translator.cpp +++ b/tools/linguist/shared/translator.cpp @@ -415,6 +415,26 @@ void Translator::dropTranslations() } } +void Translator::dropUiLines() +{ + QString uiXt = QLatin1String(".ui"); + QString juiXt = QLatin1String(".jui"); + for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ++it) { + QHash<QString, int> have; + QList<TranslatorMessage::Reference> refs; + foreach (const TranslatorMessage::Reference &itref, it->allReferences()) { + const QString &fn = itref.fileName(); + if (fn.endsWith(uiXt) || fn.endsWith(juiXt)) { + if (++have[fn] == 1) + refs.append(TranslatorMessage::Reference(fn, -1)); + } else { + refs.append(itref); + } + } + it->setReferences(refs); + } +} + QSet<TranslatorMessagePtr> Translator::resolveDuplicates() { QSet<TranslatorMessagePtr> dups; diff --git a/tools/linguist/shared/translator.h b/tools/linguist/shared/translator.h index 762a77ba..d0903a9 100644 --- a/tools/linguist/shared/translator.h +++ b/tools/linguist/shared/translator.h @@ -47,7 +47,9 @@ #include <QDir> #include <QList> #include <QLocale> +#include <QMultiHash> #include <QString> +#include <QSet> QT_BEGIN_NAMESPACE @@ -63,6 +65,7 @@ public: m_ignoreUnfinished(false), m_sortContexts(false), m_noUiLines(false), + m_idBased(false), m_saveMode(SaveEverything) {} @@ -86,13 +89,17 @@ public: QString m_sourceFileName; QString m_targetFileName; QDir m_sourceDir; - QDir m_targetDir; // FIXME: TS spefic + QDir m_targetDir; // FIXME: TS specific + QSet<QString> m_projectRoots; + QMultiHash<QString, QString> m_allCSources; + QStringList m_includePath; QStringList m_dropTags; // tags to be dropped QStringList m_errors; bool m_verbose; bool m_ignoreUnfinished; bool m_sortContexts; bool m_noUiLines; + bool m_idBased; TranslatorSaveMode m_saveMode; }; @@ -128,6 +135,7 @@ public: void stripNonPluralForms(); void stripIdenticalSourceTranslations(); void dropTranslations(); + void dropUiLines(); void makeFileNamesAbsolute(const QDir &originalPath); QSet<TranslatorMessagePtr> resolveDuplicates(); static void reportDuplicates(const QSet<TranslatorMessagePtr> &dupes, @@ -139,7 +147,7 @@ public: QString languageCode() const { return m_language; } QString sourceLanguageCode() const { return m_sourceLanguage; } - enum LocationsType { NoLocations, RelativeLocations, AbsoluteLocations }; + enum LocationsType { DefaultLocations, NoLocations, RelativeLocations, AbsoluteLocations }; void setLocationsType(LocationsType lt) { m_locationsType = lt; } LocationsType locationsType() const { return m_locationsType; } @@ -179,15 +187,15 @@ public: QString description; // human-readable description LoadFunction loader; SaveFunction saver; - enum FileType { SourceCode, TranslationSource, TranslationBinary } fileType; + enum FileType { TranslationSource, TranslationBinary } fileType; int priority; // 0 = highest, -1 = invisible }; static void registerFileFormat(const FileFormat &format); static QList<FileFormat> ®isteredFileFormats(); - enum VariantSeparators { - DefaultVariantSeparator = 0x2762, // some weird character nobody ever heard of :-D - InternalVariantSeparator = 0x9c // unicode "STRING TERMINATOR" + enum { + TextVariantSeparator = 0x2762, // some weird character nobody ever heard of :-D + BinaryVariantSeparator = 0x9c // unicode "STRING TERMINATOR" }; private: diff --git a/tools/linguist/shared/translatortools.pri b/tools/linguist/shared/translatortools.pri deleted file mode 100644 index 2b6de8c..0000000 --- a/tools/linguist/shared/translatortools.pri +++ /dev/null @@ -1,11 +0,0 @@ - - -INCLUDEPATH *= $$PWD - -SOURCES += \ - $$PWD/translatortools.cpp \ - $$PWD/simtexth.cpp - -HEADERS += \ - $$PWD/translatortools.h - diff --git a/tools/linguist/shared/ts.cpp b/tools/linguist/shared/ts.cpp index a0ce727..5884997 100644 --- a/tools/linguist/shared/ts.cpp +++ b/tools/linguist/shared/ts.cpp @@ -197,7 +197,7 @@ QString TSReader::readTransContents() // ignore these, just whitespace } else if (elementStarts(strlengthvariant)) { if (!result.isEmpty()) - result += QChar(Translator::DefaultVariantSeparator); + result += QChar(Translator::BinaryVariantSeparator); result += readContents(); } else { handleError(); @@ -514,7 +514,7 @@ static void writeExtras(QTextStream &t, const char *indent, static void writeVariants(QTextStream &t, const char *indent, const QString &input) { int offset; - if ((offset = input.indexOf(QChar(Translator::DefaultVariantSeparator))) >= 0) { + if ((offset = input.indexOf(QChar(Translator::BinaryVariantSeparator))) >= 0) { t << " variants=\"yes\">"; int start = 0; forever { @@ -524,7 +524,7 @@ static void writeVariants(QTextStream &t, const char *indent, const QString &inp if (offset == input.length()) break; start = offset + 1; - offset = input.indexOf(QChar(Translator::DefaultVariantSeparator), start); + offset = input.indexOf(QChar(Translator::BinaryVariantSeparator), start); if (offset < 0) offset = input.length(); } diff --git a/tools/linguist/shared/ts.dtd b/tools/linguist/shared/ts.dtd index ab77f64..4d2cdeb 100644 --- a/tools/linguist/shared/ts.dtd +++ b/tools/linguist/shared/ts.dtd @@ -34,7 +34,7 @@ version CDATA #IMPLIED sourcelanguage CDATA #IMPLIED language CDATA #IMPLIED> -<!-- The encoding to use in the .qm file by default. Default is ISO-8859-1. --> +<!-- The encoding to use in the QM file by default. Default is ISO-8859-1. --> <!ELEMENT defaultcodec (#PCDATA) > <!ELEMENT context (name?, comment?, (context|message)+) > <!ATTLIST context @@ -54,7 +54,7 @@ <!ELEMENT message (location*, source?, oldsource?, comment?, oldcomment?, extracomment?, translatorcomment?, translation?, userdata?, extra-**) > <!-- ! If utf8 is true, the defaultcodec is overridden and the message is encoded - ! in UTF-8 in the .qm file. + ! in UTF-8 in the QM file. --> <!ATTLIST message id CDATA #IMPLIED @@ -70,7 +70,7 @@ ! is omitted, the "current" one is used. For the 1st location in a message, ! "current" is the filename used for the 1st location of the previous message. ! For subsequent locations, it is the filename used for the previous location. - ! A single .ts file has either all absolute or all relative locations. + ! A single TS file has either all absolute or all relative locations. --> <!ATTLIST location filename CDATA #IMPLIED @@ -106,7 +106,7 @@ <!-- ! The translation variants have a priority between 1 ("highest") and 9 ("lowest") ! Typically longer translations get a higher priority. - ! If omitted, the order of appearance of the variants in the .ts files is used. + ! If omitted, the order of appearance of the variants in the TS files is used. --> <!ATTLIST lengthvariant priority (1|2|3|4|5|6|7|8|9) #IMPLIED> diff --git a/tools/linguist/shared/xliff.cpp b/tools/linguist/shared/xliff.cpp index 969d5d4..c222b8d 100644 --- a/tools/linguist/shared/xliff.cpp +++ b/tools/linguist/shared/xliff.cpp @@ -302,6 +302,8 @@ static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const QString translation; if (transit != transend) { translation = *transit; + translation.replace(QChar(Translator::BinaryVariantSeparator), + QChar(Translator::TextVariantSeparator)); ++transit; puttrans = true; } @@ -596,8 +598,11 @@ bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localN m_sources.append(accum); } } else if (localName == QLatin1String("target")) { - if (popContext(XC_restype_translation)) + if (popContext(XC_restype_translation)) { + accum.replace(QChar(Translator::TextVariantSeparator), + QChar(Translator::BinaryVariantSeparator)); m_translations.append(accum); + } } else if (localName == QLatin1String("context-group")) { if (popContext(XC_context_group)) { m_refs.append(TranslatorMessage::Reference( diff --git a/tools/macdeployqt/macchangeqt/main.cpp b/tools/macdeployqt/macchangeqt/main.cpp index 36793c9..519aab0 100644 --- a/tools/macdeployqt/macchangeqt/main.cpp +++ b/tools/macdeployqt/macchangeqt/main.cpp @@ -42,13 +42,35 @@ int main(int argc, char **argv) { - if (argc != 3) { - qDebug() << "Changeqt changes witch qt frameworks an application links against."; - qDebug() << "Usage: changeqt app-bundle qt-dir"; + // useDebugLibs should always be false because even if set all Qt + // libraries inside a binary to point to debug versions, as soon as + // one of them loads a Qt plugin, the plugin itself will load the + // release version of Qt, and as such, the app will crash. + bool useDebugLibs = false; + + int optionsSpecified = 0; + for (int i = 2; i < argc; ++i) { + QByteArray argument = QByteArray(argv[i]); + if (argument.startsWith(QByteArray("-verbose="))) { + LogDebug() << "Argument found:" << argument; + optionsSpecified++; + int index = argument.indexOf("="); + bool ok = false; + int number = argument.mid(index+1).toInt(&ok); + if (!ok) + LogError() << "Could not parse verbose level"; + else + logLevel = number; + } + } + + if (argc != (3 + optionsSpecified)) { + qDebug() << "Changeqt: changes witch Qt frameworks an application links against."; + qDebug() << "Usage: changeqt app-bundle qt-dir <-verbose=[0-3]>"; return 0; } - + const QString appPath = QString::fromLocal8Bit(argv[1]); const QString qtPath = QString::fromLocal8Bit(argv[2]); - changeQtFrameworks(appPath, qtPath); + changeQtFrameworks(appPath, qtPath, useDebugLibs); } diff --git a/tools/macdeployqt/macdeployqt/main.cpp b/tools/macdeployqt/macdeployqt/main.cpp index e5dde10..f57315b 100644 --- a/tools/macdeployqt/macdeployqt/main.cpp +++ b/tools/macdeployqt/macdeployqt/main.cpp @@ -51,9 +51,11 @@ int main(int argc, char **argv) qDebug() << "Usage: macdeployqt app-bundle [options]"; qDebug() << ""; qDebug() << "Options:"; - qDebug() << " -no-plugins: Skip plugin deployment"; - qDebug() << " -dmg : Create a .dmg disk image"; - qDebug() << " -no-strip : Don't run 'strip' on the binaries"; + qDebug() << " -verbose=<0-3> : 0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug"; + qDebug() << " -no-plugins : Skip plugin deployment"; + qDebug() << " -dmg : Create a .dmg disk image"; + qDebug() << " -no-strip : Don't run 'strip' on the binaries"; + qDebug() << " -use-debug-libs : Deploy with debug versions of frameworks and plugins (implies -no-strip)"; qDebug() << ""; qDebug() << "macdeployqt takes an application bundle as input and makes it"; qDebug() << "self-contained by copying in the Qt frameworks and plugins that"; @@ -68,10 +70,10 @@ int main(int argc, char **argv) return 0; } - + if (appBundlePath.endsWith("/")) appBundlePath.chop(1); - + if (QDir().exists(appBundlePath) == false) { qDebug() << "Error: Could not find app bundle" << appBundlePath; return 0; @@ -79,23 +81,40 @@ int main(int argc, char **argv) bool plugins = true; bool dmg = false; + bool useDebugLibs = false; extern bool runStripEnabled; for (int i = 2; i < argc; ++i) { QByteArray argument = QByteArray(argv[i]); if (argument == QByteArray("-no-plugins")) { + LogDebug() << "Argument found:" << argument; plugins = false; } else if (argument == QByteArray("-dmg")) { + LogDebug() << "Argument found:" << argument; dmg = true; } else if (argument == QByteArray("-no-strip")) { + LogDebug() << "Argument found:" << argument; runStripEnabled = false; + } else if (argument == QByteArray("-use-debug-libs")) { + LogDebug() << "Argument found:" << argument; + useDebugLibs = true; + runStripEnabled = false; + } else if (argument.startsWith(QByteArray("-verbose"))) { + LogDebug() << "Argument found:" << argument; + int index = argument.indexOf("="); + bool ok = false; + int number = argument.mid(index+1).toInt(&ok); + if (!ok) + LogError() << "Could not parse verbose level"; + else + logLevel = number; } else if (argument.startsWith("-")) { - qDebug() << "Error: Unknown option" << argument << "\n"; + LogError() << "Unknown argument" << argument << "\n"; return 0; } } - DeploymentInfo deploymentInfo = deployQtFrameworks(appBundlePath); + DeploymentInfo deploymentInfo = deployQtFrameworks(appBundlePath, useDebugLibs); if (plugins) { if (deploymentInfo.qtPath.isEmpty()) @@ -103,13 +122,13 @@ int main(int argc, char **argv) else deploymentInfo.pluginPath = deploymentInfo.qtPath + "/plugins"; - qDebug() << ""; - qDebug() << "Deploying plugins from" << deploymentInfo.pluginPath; - deployPlugins(appBundlePath, deploymentInfo); + LogNormal(); + deployPlugins(appBundlePath, deploymentInfo, useDebugLibs); createQtConf(appBundlePath); } if (dmg) { + LogNormal(); createDiskImage(appBundlePath); } } diff --git a/tools/macdeployqt/shared/shared.cpp b/tools/macdeployqt/shared/shared.cpp index b14debe..3e8c667 100644 --- a/tools/macdeployqt/shared/shared.cpp +++ b/tools/macdeployqt/shared/shared.cpp @@ -50,6 +50,7 @@ #include "shared.h" bool runStripEnabled = true; +int logLevel = 1; using std::cout; using std::endl; @@ -61,8 +62,8 @@ bool operator==(const FrameworkInfo &a, const FrameworkInfo &b) QDebug operator<<(QDebug debug, const FrameworkInfo &info) { - debug << "Framework directory" << info.frameworkDirectory << "\n"; debug << "Framework name" << info.frameworkName << "\n"; + debug << "Framework directory" << info.frameworkDirectory << "\n"; debug << "Framework path" << info.frameworkPath << "\n"; debug << "Binary directory" << info.binaryDirectory << "\n"; debug << "Binary name" << info.binaryName << "\n"; @@ -71,8 +72,8 @@ QDebug operator<<(QDebug debug, const FrameworkInfo &info) debug << "Install name" << info.installName << "\n"; debug << "Deployed install name" << info.deployedInstallName << "\n"; debug << "Source file Path" << info.sourceFilePath << "\n"; - debug << "Deployed Directtory (relative to bundle)" << info.destinationDirectory << "\n"; - + debug << "Deployed Directory (relative to bundle)" << info.destinationDirectory << "\n"; + return debug; } @@ -89,40 +90,41 @@ inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info) bool copyFilePrintStatus(const QString &from, const QString &to) { if (QFile::copy(from, to)) { - qDebug() << "copied" << from << "to" << to; + LogNormal() << " copied:" << from; + LogNormal() << " to" << to; return true; } else { - qDebug() << "ERROR: file copy failed from" << from << "to" << to; + LogError() << "file copy failed from" << from; + LogError() << " to" << to; return false; } } - -FrameworkInfo parseOtoolLibraryLine(const QString &line) +FrameworkInfo parseOtoolLibraryLine(const QString &line, bool useDebugLibs) { FrameworkInfo info; QString trimmed = line.trimmed(); if (trimmed.isEmpty()) return info; - + // Don't deploy system libraries. if (trimmed.startsWith("/System/Library/") || (trimmed.startsWith("/usr/lib/") && trimmed.contains("libQt") == false) // exception for libQtuitools and libQtlucene || trimmed.startsWith("@executable_path")) return info; - + enum State {QtPath, FrameworkName, DylibName, Version, End}; State state = QtPath; int part = 0; QString name; QString qtPath; + QString suffix = useDebugLibs ? "_debug" : ""; // Split the line into [Qt-path]/lib/qt[Module].framework/Versions/[Version]/ QStringList parts = trimmed.split("/"); while (part < parts.count()) { const QString currentPart = parts.at(part).simplified() ; -// qDebug() << "currentPart" << currentPart; ++part; if (currentPart == "") continue; @@ -148,13 +150,13 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line) info.frameworkDirectory = "/usr/lib/"; state = DylibName; } - + --part; continue; } qtPath += (currentPart + "/"); - - } if (state == FrameworkName) { + + } if (state == FrameworkName) { // remove ".framework" name = currentPart; name.chop(QString(".framework").length()); @@ -163,28 +165,29 @@ FrameworkInfo parseOtoolLibraryLine(const QString &line) ++part; continue; } if (state == DylibName) { - name = currentPart.split(" (compatibility").at(0); + name = currentPart.split(" (compatibility").at(0); info.frameworkName = name; - info.installName += info.frameworkName; - info.deployedInstallName = "@executable_path/../Frameworks/" + info.frameworkName; - info.binaryName = name; - info.frameworkPath = info.frameworkDirectory + info.frameworkName; + info.binaryName = name.left(name.indexOf('.')) + suffix + name.mid(name.indexOf('.')); + info.installName += name; + info.deployedInstallName = "@executable_path/../Frameworks/" + info.binaryName; + info.frameworkPath = info.frameworkDirectory + info.binaryName; info.sourceFilePath = info.frameworkPath; info.destinationDirectory = bundleFrameworkDirectory + "/"; + info.binaryDirectory = info.frameworkDirectory; + info.binaryPath = info.frameworkPath; state = End; ++part; continue; } else if (state == Version) { info.version = currentPart; - info.binaryDirectory = "Versions/" + info.version; - info.binaryName = name; + info.binaryDirectory = "Versions/" + info.version; + info.binaryName = name + suffix; info.binaryPath = "/" + info.binaryDirectory + "/" + info.binaryName; - info.installName += info.frameworkName + info.binaryPath; + info.installName += info.frameworkName + "/" + info.binaryDirectory + "/" + name; info.deployedInstallName = "@executable_path/../Frameworks/" + info.frameworkName + info.binaryPath; info.frameworkPath = info.frameworkDirectory + info.frameworkName; info.sourceFilePath = info.frameworkPath + info.binaryPath; info.destinationDirectory = bundleFrameworkDirectory + "/" + info.frameworkName + "/" + info.binaryDirectory; - state = End; } else if (state == End) { break; @@ -198,42 +201,46 @@ QString findAppBinary(const QString &appBundlePath) { QString appName = QFileInfo(appBundlePath).completeBaseName(); QString binaryPath = appBundlePath + "/Contents/MacOS/" + appName; - + if (QFile::exists(binaryPath)) return binaryPath; - qDebug() << "Error: Could not find bundle binary for" << appBundlePath; + LogError() << "Could not find bundle binary for" << appBundlePath; return QString(); } -QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines) +QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, bool useDebugLibs) { - QList<FrameworkInfo> libraries; + QList<FrameworkInfo> libraries; foreach(const QString line, otoolLines) { - FrameworkInfo info = parseOtoolLibraryLine(line); + FrameworkInfo info = parseOtoolLibraryLine(line, useDebugLibs); if (info.frameworkName.isEmpty() == false) { + LogDebug() << "Adding framework:"; + LogDebug() << info; libraries.append(info); } } return libraries; } -QList<FrameworkInfo> getQtFrameworks(const QString &path) +QList<FrameworkInfo> getQtFrameworks(const QString &path, bool useDebugLibs) { + LogDebug() << "Using otool:"; + LogDebug() << " inspecting" << path; QProcess otool; otool.start("otool", QStringList() << "-L" << path); otool.waitForFinished(); - + if (otool.exitCode() != 0) { - qDebug() << otool.readAllStandardError(); + LogError() << otool.readAllStandardError(); } - + QString output = otool.readAllStandardOutput(); QStringList outputLines = output.split("\n"); outputLines.removeFirst(); // remove line containing the binary path if (path.contains(".framework") || path.contains(".dylib")) outputLines.removeFirst(); // frameworks and dylibs lists themselves as a dependency. - return getQtFrameworks(outputLines); + return getQtFrameworks(outputLines, useDebugLibs); } // copies everything _inside_ sourcePath to destinationPath @@ -256,32 +263,31 @@ void recursiveCopy(const QString &sourcePath, const QString &destinationPath) QString copyFramework(const FrameworkInfo &framework, const QString path) { - const QString from = framework.sourceFilePath; - const QString toDir = path + "/" + framework.destinationDirectory; - const QString to = toDir + "/" + framework.binaryName; + QString from = framework.sourceFilePath; + QString toDir = path + "/" + framework.destinationDirectory; + QString to = toDir + "/" + framework.binaryName; if (QFile::exists(from) == false) { - qDebug() << "ERROR: no file at" << from; + LogError() << "no file at" << from; return QString(); } QDir dir; if (dir.mkpath(toDir) == false) { - qDebug() << "ERROR: could not create destination directory" << to; + LogError() << "could not create destination directory" << to; return QString(); } - + if (QFile::exists(to)) { -// qDebug() << framework.frameworkName << "already deployed, skip"; return QString(); } - + copyFilePrintStatus(from, to); - const QString resourcesSourcePath = framework.frameworkPath + "/Resources"; - const QString resourcesDestianationPath = path + "/Contents/Frameworks/" + framework.frameworkName + "/Resources"; + const QString resourcesSourcePath = framework.frameworkPath + "/Resources"; + const QString resourcesDestianationPath = path + "/Contents/Frameworks/" + framework.frameworkName + "/Resources"; recursiveCopy(resourcesSourcePath, resourcesDestianationPath); return to; @@ -293,20 +299,25 @@ void runInstallNameTool(QStringList options) installNametool.start("install_name_tool", options); installNametool.waitForFinished(); if (installNametool.exitCode() != 0) { - qDebug() << installNametool.readAllStandardError(); - qDebug() << installNametool.readAllStandardOutput(); + LogError() << installNametool.readAllStandardError(); + LogError() << installNametool.readAllStandardOutput(); } } void changeIdentification(const QString &id, const QString &binaryPath) { -// qDebug() << "change identification on" << binaryPath << id; + LogDebug() << "Using install_name_tool:"; + LogDebug() << " change identification in" << binaryPath; + LogDebug() << " to" << id; runInstallNameTool(QStringList() << "-id" << id << binaryPath); } void changeInstallName(const QString &oldName, const QString &newName, const QString &binaryPath) { -// qDebug() << "change install name on" << binaryPath << oldName << newName; + LogDebug() << "Using install_name_tool:"; + LogDebug() << " in" << binaryPath; + LogDebug() << " change reference" << oldName; + LogDebug() << " to" << newName; runInstallNameTool(QStringList() << "-change" << oldName << newName << binaryPath); } @@ -315,14 +326,14 @@ void runStrip(const QString &binaryPath) if (runStripEnabled == false) return; + LogDebug() << "Using strip:"; + LogDebug() << " stripped" << binaryPath; QProcess strip; strip.start("strip", QStringList() << "-x" << binaryPath); strip.waitForFinished(); if (strip.exitCode() != 0) { - qDebug() << strip.readAllStandardError(); - qDebug() << strip.readAllStandardOutput(); - } else { - qDebug() << "stripped" << binaryPath; + LogError() << strip.readAllStandardError(); + LogError() << strip.readAllStandardOutput(); } } @@ -333,15 +344,18 @@ void runStrip(const QString &binaryPath) Returns a DeploymentInfo structure containing the Qt path used and a a list of actually deployed frameworks. */ -DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks, const QString &bundlePath, const QString &binaryPath) +DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks, + const QString &bundlePath, const QString &binaryPath, bool useDebugLibs) { + LogNormal(); + LogNormal() << "Deploying Qt frameworks found inside:" << binaryPath; QStringList copiedFrameworks; DeploymentInfo deploymenInfo; - + while (frameworks.isEmpty() == false) { const FrameworkInfo framework = frameworks.takeFirst(); copiedFrameworks.append(framework.frameworkName); - + // Get the qt path from one of the Qt frameworks; if (deploymenInfo.qtPath.isNull() && framework.frameworkName.contains("Qt") && framework.frameworkDirectory.contains("/lib")) @@ -350,14 +364,11 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks, const QString deploymenInfo.qtPath.chop(5); // remove "/lib/" } -// qDebug() << ""; -// qDebug() << "deploy" << framework.frameworkName; - if (framework.installName.startsWith("/@executable_path/")) { - qDebug() << framework.frameworkName << "already deployed, skipping."; + LogError() << framework.frameworkName << "already deployed, skipping."; continue; } - + // Install_name_tool the new id into the binary changeInstallName(framework.installName, framework.deployedInstallName, binaryPath); @@ -366,18 +377,17 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks, const QString // Skip the rest if already was deployed. if (deployedBinaryPath.isNull()) continue; - + runStrip(deployedBinaryPath); // Install_name_tool it a new id. changeIdentification(framework.deployedInstallName, deployedBinaryPath); // Check for framework dependencies - QList<FrameworkInfo> dependencies = getQtFrameworks(deployedBinaryPath); + QList<FrameworkInfo> dependencies = getQtFrameworks(deployedBinaryPath, useDebugLibs); foreach (FrameworkInfo dependency, dependencies) { -// qDebug() << "dependent framework" << dependency.installName << deployedBinaryPath; changeInstallName(dependency.installName, dependency.deployedInstallName, deployedBinaryPath); - + // Deploy framework if neccesary. if (copiedFrameworks.contains(dependency.frameworkName) == false && frameworks.contains(dependency) == false) { frameworks.append(dependency); @@ -388,28 +398,39 @@ DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks, const QString return deploymenInfo; } -DeploymentInfo deployQtFrameworks(const QString &appBundlePath) +DeploymentInfo deployQtFrameworks(const QString &appBundlePath, bool useDebugLibs) { ApplicationBundleInfo applicationBundle; applicationBundle.path = appBundlePath; applicationBundle.binaryPath = findAppBinary(appBundlePath); - return deployQtFrameworks(getQtFrameworks(applicationBundle.binaryPath), applicationBundle.path, applicationBundle.binaryPath); + QList<FrameworkInfo> frameworks = getQtFrameworks(applicationBundle.binaryPath, useDebugLibs); + if (frameworks.isEmpty()) { + LogWarning(); + LogWarning() << "Could not find any external Qt frameworks to deploy in" << appBundlePath; + LogWarning() << "Perhaps macdeployqt was already used on" << appBundlePath << "?"; + LogWarning() << "If so, you will need to rebuild" << appBundlePath << "before trying again."; + return DeploymentInfo(); + } else { + return deployQtFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, useDebugLibs); + } } -void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pluginSourcePath, const QString pluginDestinationPath, DeploymentInfo deploymentInfo) +void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pluginSourcePath, + const QString pluginDestinationPath, DeploymentInfo deploymentInfo, bool useDebugLibs) { + LogNormal() << "Deploying plugins from" << pluginSourcePath; QStringList plugins = QDir(pluginSourcePath).entryList(QStringList() << "*.dylib"); foreach (QString pluginName, plugins) { - - // Skip some Qt plugins based on what frameworks were deployed: - //qDebug() << pluginSourcePath << deploymentInfo.pluginPath; - if (pluginSourcePath.contains(deploymentInfo.pluginPath)) { QStringList deployedFrameworks = deploymentInfo.deployedFrameworks; - // Skip the debug versions of the plugins - if (pluginName.endsWith("_debug.dylib")) + // Skip the debug versions of the plugins, unless specified otherwise. + if (!useDebugLibs && pluginName.endsWith("_debug.dylib")) + continue; + + // Skip the release versions of the plugins, unless specified otherwise. + if (useDebugLibs && !pluginName.endsWith("_debug.dylib")) continue; // Skip the designer plugins @@ -420,7 +441,7 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl // SKip the opengl graphicssystem plugin when not in use. if (pluginName.contains("libqglgraphicssystem")) continue; -#endif +#endif // Deploy accessibility for Qt3Support only if the Qt3Support.framework is in use if (deployedFrameworks.indexOf("Qt3Support.framework") == -1 && pluginName.contains("accessiblecompatwidgets")) continue; @@ -448,28 +469,25 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl const QString sourcePath = pluginSourcePath + "/" + pluginName; const QString destinationPath = pluginDestinationPath + "/" + pluginName; if (copyFilePrintStatus(sourcePath, destinationPath)) { - - runStrip(destinationPath); - - // Special case for the phonon plugin: CoreVideo is not available as a separate framework - // on panther, link against the QuartzCore framework instead. (QuartzCore contians CoreVideo.) - if (pluginName.contains("libphonon_qt7")) { - changeInstallName("/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo", - "/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore", - destinationPath); - } -// qDebug() << "deploy plugin depedencies:"; - QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath); -// qDebug() << frameworks; - deployQtFrameworks(frameworks, appBundleInfo.path, destinationPath); -// qDebug() << "deploy plugin depedencies done"; + runStrip(destinationPath); + + // Special case for the phonon plugin: CoreVideo is not available as a separate framework + // on panther, link against the QuartzCore framework instead. (QuartzCore contians CoreVideo.) + if (pluginName.contains("libphonon_qt7")) { + changeInstallName("/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo", + "/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore", + destinationPath); + } + + QList<FrameworkInfo> frameworks = getQtFrameworks(destinationPath, useDebugLibs); + deployQtFrameworks(frameworks, appBundleInfo.path, destinationPath, useDebugLibs); } } // foreach plugins QStringList subdirs = QDir(pluginSourcePath).entryList(QStringList() << "*", QDir::Dirs | QDir::NoDotAndDotDot); foreach (const QString &subdir, subdirs) - deployPlugins(appBundleInfo, pluginSourcePath + "/" + subdir, pluginDestinationPath + "/" + subdir, deploymentInfo); + deployPlugins(appBundleInfo, pluginSourcePath + "/" + subdir, pluginDestinationPath + "/" + subdir, deploymentInfo, useDebugLibs); } void createQtConf(const QString &appBundlePath) @@ -479,63 +497,64 @@ void createQtConf(const QString &appBundlePath) QString fileName = filePath + "qt.conf"; QDir().mkpath(filePath); - + QFile qtconf(fileName); if (qtconf.exists()) { - qDebug() << ""; - qDebug() << "Warning:" << fileName << "already exists, will not overwrite."; - qDebug() << "To make sure the plugins are loaded from the correct location,"; - qDebug() << "please make sure qt.conf contains the following lines:"; - qDebug() << contents; - qDebug() << ""; + LogWarning(); + LogWarning() << fileName << "already exists, will not overwrite."; + LogWarning() << "To make sure the plugins are loaded from the correct location,"; + LogWarning() << "please make sure qt.conf contains the following lines:"; + LogWarning() << "[Paths]"; + LogWarning() << " Plugins = PlugIns"; return; } qtconf.open(QIODevice::WriteOnly); if (qtconf.write(contents) != -1) { - qDebug() << ""; - qDebug() << "Created configuration file:" << fileName; - qDebug() << "This file sets the plugin search path to" << appBundlePath + "/Contents/PlugIns"; - qDebug() << ""; + LogNormal() << "Created configuration file:" << fileName; + LogNormal() << "This file sets the plugin search path to" << appBundlePath + "/Contents/PlugIns"; } } -void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo) +void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, bool useDebugLibs) { ApplicationBundleInfo applicationBundle; applicationBundle.path = appBundlePath; applicationBundle.binaryPath = findAppBinary(appBundlePath); - + const QString pluginDestinationPath = appBundlePath + "/" + "Contents/PlugIns"; - -// qDebug() << ""; -// qDebug() << "recursively copying plugins from" << deploymentInfo.pluginPath << "to" << pluginDestinationPath; - deployPlugins(applicationBundle, deploymentInfo.pluginPath, pluginDestinationPath, deploymentInfo); + deployPlugins(applicationBundle, deploymentInfo.pluginPath, pluginDestinationPath, deploymentInfo, useDebugLibs); } void changeQtFrameworks(const QList<FrameworkInfo> frameworks, const QString &appBinaryPath, const QString &absoluteQtPath) { - qDebug() << "Changing" << appBinaryPath << "to link against Qt in" << absoluteQtPath; + LogNormal() << "Changing" << appBinaryPath << "to link against"; + LogNormal() << "Qt in" << absoluteQtPath; QString finalQtPath = absoluteQtPath; - if (absoluteQtPath.startsWith("/Library/Frameworks") == false) + if (!absoluteQtPath.startsWith("/Library/Frameworks")) finalQtPath += "/lib/"; foreach (FrameworkInfo framework, frameworks) { const QString oldBinaryId = framework.installName; const QString newBinaryId = finalQtPath + framework.frameworkName + framework.binaryPath; - qDebug() << "Changing" << oldBinaryId << "to" << newBinaryId; changeInstallName(oldBinaryId, newBinaryId, appBinaryPath); } } -void changeQtFrameworks(const QString appPath, const QString &qtPath) +void changeQtFrameworks(const QString appPath, const QString &qtPath, bool useDebugLibs) { const QString appBinaryPath = findAppBinary(appPath); - const QList<FrameworkInfo> qtFrameworks = getQtFrameworks(appBinaryPath); - const QString absoluteQtPath = QDir(qtPath).absolutePath(); - changeQtFrameworks(qtFrameworks, appBinaryPath, absoluteQtPath); + const QList<FrameworkInfo> frameworks = getQtFrameworks(appBinaryPath, useDebugLibs); + if (frameworks.isEmpty()) { + LogWarning(); + LogWarning() << "Could not find any _external_ Qt frameworks to change in" << appPath; + return; + } else { + const QString absoluteQtPath = QDir(qtPath).absolutePath(); + changeQtFrameworks(frameworks, appBinaryPath, absoluteQtPath); + } } @@ -543,15 +562,15 @@ void createDiskImage(const QString &appBundlePath) { QString appBaseName = appBundlePath; appBaseName.chop(4); // remove ".app" from end - + QString dmgName = appBaseName + ".dmg"; QFile dmg(dmgName); if (dmg.exists()) { - qDebug() << "Disk image already exists, skipping .dmg creation for" << dmg.fileName(); + LogNormal() << "Disk image already exists, skipping .dmg creation for" << dmg.fileName(); } else { - qDebug() << "Creating disk image (.dmg) for" << appBundlePath; + LogNormal() << "Creating disk image (.dmg) for" << appBundlePath; } // More dmg options can be found in the hdiutil man page. diff --git a/tools/macdeployqt/shared/shared.h b/tools/macdeployqt/shared/shared.h index ed44a64..a7a09e0 100644 --- a/tools/macdeployqt/shared/shared.h +++ b/tools/macdeployqt/shared/shared.h @@ -45,6 +45,12 @@ #include <QStringList> #include <QDebug> +extern int logLevel; +#define LogError() if (logLevel < 1) {} else qDebug() << "ERROR:" +#define LogWarning() if (logLevel < 1) {} else qDebug() << "WARNING:" +#define LogNormal() if (logLevel < 2) {} else qDebug() << "Log:" +#define LogDebug() if (logLevel < 3) {} else qDebug() << "Log:" + extern bool runStripEnabled; class FrameworkInfo @@ -68,7 +74,7 @@ QDebug operator<<(QDebug debug, const FrameworkInfo &info); class ApplicationBundleInfo { -public: + public: QString path; QString binaryPath; }; @@ -84,18 +90,18 @@ public: inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info); -void changeQtFrameworks(const QString appPath, const QString &qtPath); +void changeQtFrameworks(const QString appPath, const QString &qtPath, bool useDebugLibs); void changeQtFrameworks(const QList<FrameworkInfo> frameworks, const QString &appBinaryPath, const QString &qtPath); -FrameworkInfo parseOtoolLibraryLine(const QString &line); +FrameworkInfo parseOtoolLibraryLine(const QString &line, bool useDebugLibs); QString findAppBinary(const QString &appBundlePath); -QList<FrameworkInfo> getQtFrameworks(const QString &path); -QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines); +QList<FrameworkInfo> getQtFrameworks(const QString &path, bool useDebugLibs); +QList<FrameworkInfo> getQtFrameworks(const QStringList &otoolLines, bool useDebugLibs); QString copyFramework(const FrameworkInfo &framework, const QString path); -DeploymentInfo deployQtFrameworks(const QString &appBundlePath); +DeploymentInfo deployQtFrameworks(const QString &appBundlePath, bool useDebugLibs); DeploymentInfo deployQtFrameworks(QList<FrameworkInfo> frameworks, const QString &bundlePath, const QString &binaryPath); void createQtConf(const QString &appBundlePath); -void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo); +void deployPlugins(const QString &appBundlePath, DeploymentInfo deploymentInfo, bool useDebugLibs); void changeIdentification(const QString &id, const QString &binaryPath); void changeInstallName(const QString &oldName, const QString &newName, const QString &binaryPath); QString findAppBinary(const QString &appBundlePath); diff --git a/tools/pixeltool/qpixeltool.cpp b/tools/pixeltool/qpixeltool.cpp index 0e9416c..beea85a 100644 --- a/tools/pixeltool/qpixeltool.cpp +++ b/tools/pixeltool/qpixeltool.cpp @@ -179,13 +179,13 @@ void QPixelTool::paintEvent(QPaintEvent *) if (m_displayZoom) { render_string(&p, w, h, - QString(QLatin1String("Zoom: x%1")).arg(m_zoom), + QString::fromLatin1("Zoom: x%1").arg(m_zoom), Qt::AlignTop | Qt::AlignRight); } if (m_displayGridSize) { render_string(&p, w, h, - QString(QLatin1String("Grid size: %1")).arg(m_gridSize), + QString::fromLatin1("Grid size: %1").arg(m_gridSize), Qt::AlignBottom | Qt::AlignLeft); } diff --git a/tools/porting/src/logger.cpp b/tools/porting/src/logger.cpp index 8727d65..8a38dd2 100644 --- a/tools/porting/src/logger.cpp +++ b/tools/porting/src/logger.cpp @@ -60,8 +60,8 @@ SourcePointLogEntry::SourcePointLogEntry(QString type, QString location, QString QString SourcePointLogEntry::description() const { return QLatin1String("In file ") + file + - QLatin1String(" at line ") + QString(QLatin1String("%1")).arg(line + 1) + //line count is zero based, adjust here. - QLatin1String(" column ") + QString(QLatin1String("%1")).arg(column) + + QLatin1String(" at line ") + QString::number(line + 1) + //line count is zero based, adjust here. + QLatin1String(" column ") + QString::number(column) + QLatin1String(": ") + text ; } @@ -127,7 +127,7 @@ QStringList Logger::fullReport() commitSection(); QStringList report; report << QLatin1String("Log for qt3to4 on ") + QDateTime::currentDateTime().toString() + - QLatin1String(". Number of log entries: ") + QString(QLatin1String("%1")).arg(logEntries.size()); + QLatin1String(". Number of log entries: ") + QString::number(logEntries.size()); foreach(LogEntry *logEntry, logEntries) { report << logEntry->description(); } diff --git a/tools/qdbus/qdbusviewer/qdbusviewer.cpp b/tools/qdbus/qdbusviewer/qdbusviewer.cpp index ca747c2..af37596 100644 --- a/tools/qdbus/qdbusviewer/qdbusviewer.cpp +++ b/tools/qdbus/qdbusviewer/qdbusviewer.cpp @@ -441,21 +441,14 @@ void QDBusViewer::about() { QMessageBox box(this); - // TODO: Remove these variables for 4.6.0. Must keep this way for 4.5.x due to string freeze. - QString edition; - QString info; - QString moreInfo; - box.setText(QString::fromLatin1("<center><img src=\":/trolltech/qdbusviewer/images/qdbusviewer-128.png\">" "<h3>%1</h3>" - "<p>Version %2 %3</p></center>" - "<p>%4</p>" - "<p>%5</p>" + "<p>Version %2</p></center>" "<p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).</p>" "<p>The program is provided AS IS with NO WARRANTY OF ANY KIND," " INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A" " PARTICULAR PURPOSE.<p/>") - .arg(tr("D-Bus Viewer")).arg(QLatin1String(QT_VERSION_STR)).arg(edition).arg(info).arg(moreInfo)); + .arg(tr("D-Bus Viewer")).arg(QLatin1String(QT_VERSION_STR))); box.setWindowTitle(tr("D-Bus Viewer")); box.exec(); } diff --git a/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp b/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp index 5d1ac32..b8b9338 100644 --- a/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp +++ b/tools/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp @@ -613,18 +613,15 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf // getter: if (property.access != QDBusIntrospection::Property::Write) { - hs << " inline " << type << " " << getter << "() const" << endl; - if (type != "QVariant") - hs << " { return qvariant_cast< " << type << " >(internalPropGet(\"" - << property.name << "\")); }" << endl; - else - hs << " { return internalPropGet(\"" << property.name << "\"); }" << endl; + hs << " inline " << type << " " << getter << "() const" << endl + << " { return qvariant_cast< " << type << " >(property(\"" + << property.name << "\")); }" << endl; } // setter: if (property.access != QDBusIntrospection::Property::Read) { hs << " inline void " << setter << "(" << constRefArg(type) << "value)" << endl - << " { internalPropSet(\"" << property.name + << " { setProperty(\"" << property.name << "\", qVariantFromValue(value)); }" << endl; } diff --git a/tools/qdoc3/atom.cpp b/tools/qdoc3/atom.cpp index a82a783..da32735 100644 --- a/tools/qdoc3/atom.cpp +++ b/tools/qdoc3/atom.cpp @@ -93,6 +93,7 @@ QString Atom::UPPERROMAN_ ("upperroman"); \value AbstractLeft \value AbstractRight + \value AnnotatedList \value AutoLink \value BaseName \value BriefLeft @@ -163,6 +164,7 @@ static const struct { } atms[] = { { "AbstractLeft", Atom::AbstractLeft }, { "AbstractRight", Atom::AbstractRight }, + { "AnnotatedList", Atom::AnnotatedList }, { "AutoLink", Atom::AutoLink }, { "BaseName", Atom::BaseName }, { "BriefLeft", Atom::BriefLeft }, diff --git a/tools/qdoc3/atom.h b/tools/qdoc3/atom.h index 6d5af0a..941ac70 100644 --- a/tools/qdoc3/atom.h +++ b/tools/qdoc3/atom.h @@ -58,6 +58,7 @@ class Atom enum Type { AbstractLeft, AbstractRight, + AnnotatedList, AutoLink, BaseName, BriefLeft, diff --git a/tools/qdoc3/codemarker.cpp b/tools/qdoc3/codemarker.cpp index 728f9fa..4c018d1 100644 --- a/tools/qdoc3/codemarker.cpp +++ b/tools/qdoc3/codemarker.cpp @@ -168,7 +168,8 @@ const Node *CodeMarker::nodeForString(const QString& string) { if (sizeof(const Node *) == sizeof(uint)) { return reinterpret_cast<const Node *>(string.toUInt()); - } else { + } + else { return reinterpret_cast<const Node *>(string.toULongLong()); } } @@ -177,7 +178,8 @@ QString CodeMarker::stringForNode(const Node *node) { if (sizeof(const Node *) == sizeof(ulong)) { return QString::number(reinterpret_cast<ulong>(node)); - } else { + } + else { return QString::number(reinterpret_cast<qulonglong>(node)); } } @@ -220,7 +222,8 @@ QString CodeMarker::typified(const QString &string) || ch.digitValue() >= 0 || ch == QLatin1Char('_') || ch == QLatin1Char(':')) { pendingWord += ch; - } else { + } + else { if (!pendingWord.isEmpty()) { bool isProbablyType = (pendingWord != QLatin1String("const")); if (isProbablyType) @@ -251,7 +254,7 @@ QString CodeMarker::typified(const QString &string) return result; } -QString CodeMarker::taggedNode(const Node *node) +QString CodeMarker::taggedNode(const Node* node) { QString tag; @@ -276,11 +279,35 @@ QString CodeMarker::taggedNode(const Node *node) break; default: tag = QLatin1String("@unknown"); + break; } return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name()) + QLatin1String("</") + tag + QLatin1Char('>'); } +#ifdef QDOC_QML +QString CodeMarker::taggedQmlNode(const Node* node) +{ + QString tag; + switch (node->type()) { + case Node::QmlProperty: + tag = QLatin1String("@property"); + break; + case Node::QmlSignal: + tag = QLatin1String("@signal"); + break; + case Node::QmlMethod: + tag = QLatin1String("@method"); + break; + default: + tag = QLatin1String("@unknown"); + break; + } + return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name()) + + QLatin1String("</") + tag + QLatin1Char('>'); +} +#endif + QString CodeMarker::linkTag(const Node *node, const QString& body) { return QLatin1String("<@link node=\"") + stringForNode(node) @@ -308,9 +335,11 @@ QString CodeMarker::sortName(const Node *node) QString sortNo; if (func->metaness() == FunctionNode::Ctor) { sortNo = QLatin1String("C"); - } else if (func->metaness() == FunctionNode::Dtor) { + } + else if (func->metaness() == FunctionNode::Dtor) { sortNo = QLatin1String("D"); - } else { + } + else { if (nodeName.startsWith(QLatin1String("operator")) && nodeName.length() > 8 && !nodeName[8].isLetterOrNumber()) @@ -331,20 +360,30 @@ QString CodeMarker::sortName(const Node *node) return QLatin1Char('B') + nodeName; } -void CodeMarker::insert(FastSection &fastSection, Node *node, SynopsisStyle style, Status status) +void CodeMarker::insert(FastSection &fastSection, + Node *node, + SynopsisStyle style, + Status status) { - bool inheritedMember = (!node->relates() && - (node->parent() != (const InnerNode *)fastSection.innerNode)); bool irrelevant = false; + bool inheritedMember = false; + if (!node->relates()) { + if (node->parent() != (const InnerNode*)fastSection.innerNode) { + if (node->type() != Node::QmlProperty) + inheritedMember = true; + } + } if (node->access() == Node::Private) { irrelevant = true; - } else if (node->type() == Node::Function) { + } + else if (node->type() == Node::Function) { FunctionNode *func = (FunctionNode *) node; irrelevant = (inheritedMember && (func->metaness() == FunctionNode::Ctor || func->metaness() == FunctionNode::Dtor)); - } else if (node->type() == Node::Class || node->type() == Node::Enum + } + else if (node->type() == Node::Class || node->type() == Node::Enum || node->type() == Node::Typedef) { irrelevant = (inheritedMember && style != SeparateList); if (!irrelevant && style == Detailed && node->type() == Node::Typedef) { @@ -357,9 +396,11 @@ void CodeMarker::insert(FastSection &fastSection, Node *node, SynopsisStyle styl if (!irrelevant) { if (status == Compat) { irrelevant = (node->status() != Node::Compat); - } else if (status == Obsolete) { + } + else if (status == Obsolete) { irrelevant = (node->status() != Node::Obsolete); - } else { + } + else { irrelevant = (node->status() == Node::Compat || node->status() == Node::Obsolete); } @@ -370,7 +411,8 @@ void CodeMarker::insert(FastSection &fastSection, Node *node, SynopsisStyle styl QString key = sortName(node); if (!fastSection.memberMap.contains(key)) fastSection.memberMap.insert(key, node); - } else { + } + else { if (node->parent()->type() == Node::Class) { if (fastSection.inherited.isEmpty() || fastSection.inherited.last().first != node->parent()) { @@ -383,16 +425,42 @@ void CodeMarker::insert(FastSection &fastSection, Node *node, SynopsisStyle styl } } -void CodeMarker::append(QList<Section>& sectionList, - const FastSection& fastSection) +/*! + Returns true if \a node represents a reimplemented member function. + If it is, then it is inserted in the reimplemented member map in the + section \a fs. And, the test is only performed if \a status is \e OK. + Otherwise, false is returned. + */ +bool CodeMarker::insertReimpFunc(FastSection& fs, Node* node, Status status) +{ + if (node->access() == Node::Private) + return false; + + const FunctionNode* fn = static_cast<const FunctionNode*>(node); + if ((fn->reimplementedFrom() != 0) && (status == Okay)) { + bool inherited = (!fn->relates() && (fn->parent() != (const InnerNode*)fs.innerNode)); + if (!inherited) { + QString key = sortName(fn); + if (!fs.reimpMemberMap.contains(key)) { + fs.reimpMemberMap.insert(key,node); + return true; + } + } + } + return false; + } + +/*! + If \a fs is not empty, convert it to a Section and append + the new Section to \a sectionList. + */ +void CodeMarker::append(QList<Section>& sectionList, const FastSection& fs) { - if (!fastSection.memberMap.isEmpty() || - !fastSection.inherited.isEmpty()) { - Section section(fastSection.name, - fastSection.singularMember, - fastSection.pluralMember); - section.members = fastSection.memberMap.values(); - section.inherited = fastSection.inherited; + if (!fs.isEmpty()) { + Section section(fs.name,fs.singularMember,fs.pluralMember); + section.members = fs.memberMap.values(); + section.reimpMembers = fs.reimpMemberMap.values(); + section.inherited = fs.inherited; sectionList.append(section); } } @@ -428,7 +496,8 @@ QStringList CodeMarker::macRefsForNode(const Node *node) #if 0 if (!classe->templateStuff().isEmpty()) { result += QLatin1String("tmplt/"); - } else + } + else #endif { result += QLatin1String("cl/"); @@ -465,14 +534,18 @@ QStringList CodeMarker::macRefsForNode(const Node *node) result += QLatin1String("macro/"); isMacro = true; #if 0 - } else if (!func->templateStuff().isEmpty()) { + } + else if (!func->templateStuff().isEmpty()) { result += QLatin1String("ftmplt/"); #endif - } else if (func->isStatic()) { + } + else if (func->isStatic()) { result += QLatin1String("clm/"); - } else if (!func->parent()->name().isEmpty()) { + } + else if (!func->parent()->name().isEmpty()) { result += QLatin1String("instm/"); - } else { + } + else { result += QLatin1String("func/"); } @@ -486,7 +559,8 @@ QStringList CodeMarker::macRefsForNode(const Node *node) result += "/" + QLatin1String(QMetaObject::normalizedSignature(func->returnType().toLatin1().constData())) + "/("; const QList<Parameter> ¶ms = func->parameters(); for (int i = 0; i < params.count(); ++i) { - QString type = params.at(i).leftType() + params.at(i).rightType(); + QString type = params.at(i).leftType() + + params.at(i).rightType(); type = QLatin1String(QMetaObject::normalizedSignature(type.toLatin1().constData())); if (i != 0) result += ","; @@ -529,10 +603,21 @@ QString CodeMarker::macName(const Node *node, const QString &name) if (node->name().isEmpty()) { return QLatin1Char('/') + myName; - } else { + } + else { return plainFullName(node) + QLatin1Char('/') + myName; } } +#ifdef QDOC_QML +/*! + Get the list of documentation sections for the children of + the specified QmlClassNode. + */ +QList<Section> CodeMarker::qmlSections(const QmlClassNode* , SynopsisStyle ) +{ + return QList<Section>(); +} +#endif QT_END_NAMESPACE diff --git a/tools/qdoc3/codemarker.h b/tools/qdoc3/codemarker.h index 483dc4d..91dc8b0 100644 --- a/tools/qdoc3/codemarker.h +++ b/tools/qdoc3/codemarker.h @@ -61,6 +61,7 @@ struct Section QString singularMember; QString pluralMember; NodeList members; + NodeList reimpMembers; QList<QPair<ClassNode *, int> > inherited; Section() { } @@ -79,6 +80,7 @@ struct FastSection QString singularMember; QString pluralMember; QMap<QString, Node *> memberMap; + QMap<QString, Node *> reimpMemberMap; QList<QPair<ClassNode *, int> > inherited; FastSection(const InnerNode *innerNode0, @@ -89,6 +91,11 @@ struct FastSection name(name0), singularMember(singularMember0), pluralMember(pluralMember0) { } + bool isEmpty() const { + return (memberMap.isEmpty() && inherited.isEmpty() && + reimpMemberMap.isEmpty()); + } + }; class CodeMarker @@ -114,6 +121,9 @@ class CodeMarker virtual QString markedUpSynopsis(const Node *node, const Node *relative, SynopsisStyle style) = 0; +#ifdef QDOC_QML + virtual QString markedUpQmlItem(const Node* , bool) { return QString(); } +#endif virtual QString markedUpName(const Node *node) = 0; virtual QString markedUpFullName(const Node *node, const Node *relative = 0) = 0; @@ -125,6 +135,10 @@ class CodeMarker virtual QList<Section> sections(const InnerNode *inner, SynopsisStyle style, Status status) = 0; +#ifdef QDOC_QML + virtual QList<Section> qmlSections(const QmlClassNode* qmlClassNode, + SynopsisStyle style); +#endif virtual const Node *resolveTarget(const QString& target, const Tree *tree, const Node *relative) = 0; @@ -144,12 +158,16 @@ class CodeMarker virtual QString sortName(const Node *node); QString protect(const QString &string); QString typified(const QString &string); - QString taggedNode(const Node *node); + QString taggedNode(const Node* node); +#ifdef QDOC_QML + QString taggedQmlNode(const Node* node); +#endif QString linkTag(const Node *node, const QString& body); void insert(FastSection &fastSection, Node *node, SynopsisStyle style, Status status); + bool insertReimpFunc(FastSection& fs, Node* node, Status status); void append(QList<Section>& sectionList, const FastSection& fastSection); private: diff --git a/tools/qdoc3/codeparser.cpp b/tools/qdoc3/codeparser.cpp index 2fedd67..92243fa 100644 --- a/tools/qdoc3/codeparser.cpp +++ b/tools/qdoc3/codeparser.cpp @@ -47,6 +47,7 @@ #include "codeparser.h" #include "node.h" #include "tree.h" +#include "config.h" QT_BEGIN_NAMESPACE @@ -67,6 +68,7 @@ QT_BEGIN_NAMESPACE #define COMMAND_TITLE Doc::alias(QLatin1String("title")) QList<CodeParser *> CodeParser::parsers; +bool CodeParser::showInternal = false; /*! The constructor adds this code parser to the static @@ -87,11 +89,11 @@ CodeParser::~CodeParser() } /*! - Initializing a code parser is trivial. + Initialize the code parser base class. */ -void CodeParser::initializeParser(const Config & /* config */) +void CodeParser::initializeParser(const Config& config) { - // nothing. + showInternal = config.getBool(QLatin1String(CONFIG_SHOWINTERNAL)); } /*! @@ -217,8 +219,10 @@ void CodeParser::processCommonMetaCommand(const Location &location, node->setStatus(Node::Preliminary); } else if (command == COMMAND_INTERNAL) { - node->setAccess(Node::Private); - node->setStatus(Node::Internal); + if (!showInternal) { + node->setAccess(Node::Private); + node->setStatus(Node::Internal); + } } else if (command == COMMAND_REENTRANT) { node->setThreadSafeness(Node::Reentrant); @@ -241,19 +245,6 @@ void CodeParser::processCommonMetaCommand(const Location &location, if (node->type() == Node::Fake) { FakeNode *fake = static_cast<FakeNode *>(node); fake->setTitle(arg); -#ifdef QDOC2DOX - /* qdoc -> doxygen. - I think this must be done here, because there can be multiple - "\externalpage" and "\title" metacommands in a single qdoc - comment, which means, among other things, that the "\title" - commands are not inserted into the metacommand map used by - the Doc class. I'm sure there4 is a better way to do this in - the DoxWriter class using the information in the FakeNode, - but I don't have time to figure it out right now. - */ - if (DoxWriter::isDoxPass(1)) - DoxWriter::insertTitle(fake,arg); -#endif } else location.warning(tr("Ignored '\\%1'").arg(COMMAND_TITLE)); diff --git a/tools/qdoc3/codeparser.h b/tools/qdoc3/codeparser.h index 8f5bd87..06603a9 100644 --- a/tools/qdoc3/codeparser.h +++ b/tools/qdoc3/codeparser.h @@ -87,6 +87,7 @@ class CodeParser private: static QList<CodeParser *> parsers; + static bool showInternal; }; QT_END_NAMESPACE diff --git a/tools/qdoc3/command.cpp b/tools/qdoc3/command.cpp index e51e235..bce262b 100644 --- a/tools/qdoc3/command.cpp +++ b/tools/qdoc3/command.cpp @@ -49,44 +49,46 @@ QT_BEGIN_NAMESPACE -void executeCommand( const Location& location, const QString& format, - const QStringList& args ) +void executeCommand(const Location& location, + const QString& format, + const QStringList& args) { QString actualCommand; - for ( int i = 0; i < (int) format.length(); i++ ) { + for (int i = 0; i < (int) format.length(); i++) { int ch = format[i].unicode(); - if ( ch > 0 && ch < 8 ) { + if (ch > 0 && ch < 8) { actualCommand += args[ch - 1]; - } else { + } + else { actualCommand += format[i]; } } QString toolName = actualCommand; - int space = toolName.indexOf( QLatin1Char(' ') ); - if ( space != -1 ) - toolName.truncate( space ); + int space = toolName.indexOf(QLatin1Char(' ')); + if (space != -1) + toolName.truncate(space); QProcess process; process.start(QLatin1String("sh"), - QStringList() << QLatin1String("-c") << actualCommand ); + QStringList() << QLatin1String("-c") << actualCommand); process.waitForFinished(); if (process.exitCode() == 127) - location.fatal( tr("Couldn't launch the '%1' tool") - .arg(toolName), - tr("Make sure the tool is installed and in the" - " path.") ); + location.fatal(tr("Couldn't launch the '%1' tool") + .arg(toolName), + tr("Make sure the tool is installed and in the" + " path.")); QString errors = QString::fromLocal8Bit(process.readAllStandardError()); - while ( errors.endsWith(QLatin1Char('\n')) ) - errors.truncate( errors.length() - 1 ); - if ( !errors.isEmpty() ) - location.fatal( tr("The '%1' tool encountered some problems") - .arg(toolName), - tr("The tool was invoked like this:\n%1\n" - "It emitted these errors:\n%2") - .arg(actualCommand).arg(errors) ); + while (errors.endsWith(QLatin1Char('\n'))) + errors.truncate(errors.length() - 1); + if (!errors.isEmpty()) + location.fatal(tr("The '%1' tool encountered some problems") + .arg(toolName), + tr("The tool was invoked like this:\n%1\n" + "It emitted these errors:\n%2") + .arg(actualCommand).arg(errors)); } QT_END_NAMESPACE diff --git a/tools/qdoc3/config.cpp b/tools/qdoc3/config.cpp index 20b0aa7..ad993d9 100644 --- a/tools/qdoc3/config.cpp +++ b/tools/qdoc3/config.cpp @@ -751,7 +751,7 @@ void Config::load(Location location, const QString& fileName) word += QChar(c.digitValue()); SKIP_CHAR(); } - else if ((metaCharPos = QString(QLatin1String("abfnrtv")).indexOf(c)) != -1) { + else if ((metaCharPos = QString::fromLatin1("abfnrtv").indexOf(c)) != -1) { word += "\a\b\f\n\r\t\v"[metaCharPos]; SKIP_CHAR(); } diff --git a/tools/qdoc3/config.h b/tools/qdoc3/config.h index 8f25340..22cb671 100644 --- a/tools/qdoc3/config.h +++ b/tools/qdoc3/config.h @@ -140,6 +140,7 @@ class Config #define CONFIG_INDEXES "indexes" #define CONFIG_LANGUAGE "language" #define CONFIG_MACRO "macro" +#define CONFIG_OBSOLETELINKS "obsoletelinks" #define CONFIG_OUTPUTDIR "outputdir" #define CONFIG_OUTPUTLANGUAGE "outputlanguage" #define CONFIG_OUTPUTFORMATS "outputformats" @@ -147,6 +148,7 @@ class Config #define CONFIG_QHP "qhp" #define CONFIG_QUOTINGINFORMATION "quotinginformation" #define CONFIG_SLOW "slow" +#define CONFIG_SHOWINTERNAL "showinternal" #define CONFIG_SOURCEDIRS "sourcedirs" #define CONFIG_SOURCES "sources" #define CONFIG_SPURIOUS "spurious" diff --git a/tools/qdoc3/cppcodemarker.cpp b/tools/qdoc3/cppcodemarker.cpp index 6760c65..0f8d1b7 100644 --- a/tools/qdoc3/cppcodemarker.cpp +++ b/tools/qdoc3/cppcodemarker.cpp @@ -43,6 +43,7 @@ cppcodemarker.cpp */ +#include <qdebug.h> #include "atom.h" #include "cppcodemarker.h" #include "node.h" @@ -283,7 +284,7 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, } else { for (int i = 0; i < documentedItems.size(); ++i) { - if (i < MaxEnumValues - 2 || i == documentedItems.size() - 1) { + if (i < MaxEnumValues-2 || i == documentedItems.size()-1) { if (i != 0) synopsis += ", "; synopsis += documentedItems.at(i); @@ -344,6 +345,43 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, return synopsis + extra; } +#ifdef QDOC_QML +/*! + */ +QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) +{ + QString name = taggedQmlNode(node); + if (summary) { + name = linkTag(node,name); + } + name = "<@name>" + name + "</@name>"; + QString synopsis = name; + if (node->type() == Node::QmlProperty) { + const QmlPropertyNode* pn = static_cast<const QmlPropertyNode*>(node); + synopsis += " : " + typified(pn->dataType()); + } + + QString extra; + if (summary) { + if (node->status() == Node::Preliminary) { + extra += " (preliminary)"; + } + else if (node->status() == Node::Deprecated) { + extra += " (deprecated)"; + } + else if (node->status() == Node::Obsolete) { + extra += " (obsolete)"; + } + } + + if (!extra.isEmpty()) { + extra.prepend("<@extra>"); + extra.append("</@extra>"); + } + return synopsis + extra; +} +#endif + QString CppCodeMarker::markedUpName(const Node *node) { QString name = linkTag(node, taggedNode(node)); @@ -411,6 +449,21 @@ QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */) return "^\\}$"; } +#if 0 + FastSection privateReimpFuncs(classe, + "Private Reimplemented Functions", + "private reimplemented function", + "private reimplemented functions"); + FastSection protectedReimpFuncs(classe, + "Protected Reimplemented Functions", + "protected reimplemented function", + "protected reimplemented functions"); + FastSection publicReimpFuncs(classe, + "Public Reimplemented Functions", + "public reimplemented function", + "public reimplemented functions"); +#endif + QList<Section> CppCodeMarker::sections(const InnerNode *inner, SynopsisStyle style, Status status) @@ -421,29 +474,55 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, const ClassNode *classe = static_cast<const ClassNode *>(inner); if (style == Summary) { - FastSection privateFunctions(classe, "Private Functions", "private function", + FastSection privateFunctions(classe, + "Private Functions", + "private function", "private functions"); FastSection privateSlots(classe, "Private Slots", "private slot", "private slots"); FastSection privateTypes(classe, "Private Types", "private type", "private types"); - FastSection protectedFunctions(classe, "Protected Functions", "protected function", + FastSection protectedFunctions(classe, + "Protected Functions", + "protected function", "protected functions"); - FastSection protectedSlots(classe, "Protected Slots", "protected slot", "protected slots"); - FastSection protectedTypes(classe, "Protected Types", "protected type", "protected types"); - FastSection protectedVariables(classe, "Protected Variables", "protected type", "protected variables"); - FastSection publicFunctions(classe, "Public Functions", "public function", - "public functions"); + FastSection protectedSlots(classe, + "Protected Slots", + "protected slot", + "protected slots"); + FastSection protectedTypes(classe, + "Protected Types", + "protected type", + "protected types"); + FastSection protectedVariables(classe, + "Protected Variables", + "protected type", + "protected variables"); + FastSection publicFunctions(classe, + "Public Functions", + "public function", + "public functions"); FastSection publicSignals(classe, "Signals", "signal", "signals"); FastSection publicSlots(classe, "Public Slots", "public slot", "public slots"); FastSection publicTypes(classe, "Public Types", "public type", "public types"); - FastSection publicVariables(classe, "Public Variables", "public type", "public variables"); + FastSection publicVariables(classe, + "Public Variables", + "public type", + "public variables"); FastSection properties(classe, "Properties", "property", "properties"); - FastSection relatedNonMembers(classe, "Related Non-Members", "related non-member", + FastSection relatedNonMembers(classe, + "Related Non-Members", + "related non-member", "related non-members"); - FastSection staticPrivateMembers(classe, "Static Private Members", "static private member", + FastSection staticPrivateMembers(classe, + "Static Private Members", + "static private member", "static private members"); - FastSection staticProtectedMembers(classe, "Static Protected Members", - "static protected member", "static protected members"); - FastSection staticPublicMembers(classe, "Static Public Members", "static public member", + FastSection staticProtectedMembers(classe, + "Static Protected Members", + "static protected member", + "static protected members"); + FastSection staticPublicMembers(classe, + "Static Public Members", + "static public member", "static public members"); FastSection macros(inner, "Macros", "macro", "macros"); @@ -495,7 +574,7 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, else if (isStatic) { if ((*c)->type() != Node::Variable || !(*c)->doc().isEmpty()) - insert(staticPublicMembers, *c, style, status); + insert(staticPublicMembers,*c,style,status); } else if ((*c)->type() == Node::Property) { insert(properties, *c, style, status); @@ -505,7 +584,8 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, insert(publicVariables, *c, style, status); } else if ((*c)->type() == Node::Function) { - insert(publicFunctions, *c, style, status); + if (!insertReimpFunc(publicFunctions,*c,status)) + insert(publicFunctions, *c, style, status); } else { insert(publicTypes, *c, style, status); @@ -518,14 +598,15 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, else if (isStatic) { if ((*c)->type() != Node::Variable || !(*c)->doc().isEmpty()) - insert(staticProtectedMembers, *c, style, status); + insert(staticProtectedMembers,*c,style,status); } else if ((*c)->type() == Node::Variable) { if (!(*c)->doc().isEmpty()) - insert(protectedVariables, *c, style, status); + insert(protectedVariables,*c,style,status); } else if ((*c)->type() == Node::Function) { - insert(protectedFunctions, *c, style, status); + if (!insertReimpFunc(protectedFunctions,*c,status)) + insert(protectedFunctions, *c, style, status); } else { insert(protectedTypes, *c, style, status); @@ -538,13 +619,14 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, else if (isStatic) { if ((*c)->type() != Node::Variable || !(*c)->doc().isEmpty()) - insert(staticPrivateMembers, *c, style, status); + insert(staticPrivateMembers,*c,style,status); } else if ((*c)->type() == Node::Function) { - insert(privateFunctions, *c, style, status); + if (!insertReimpFunc(privateFunctions,*c,status)) + insert(privateFunctions, *c, style, status); } else { - insert(privateTypes, *c, style, status); + insert(privateTypes,*c,style,status); } } ++c; @@ -661,17 +743,23 @@ QList<Section> CppCodeMarker::sections(const InnerNode *inner, "Namespaces", "namespace", "namespaces"); - FastSection classes(inner, "Classes", "class", "classes"); + FastSection classes(inner, + "Classes", + "class", + "classes"); FastSection types(inner, - style == Summary ? "Types" : "Type Documentation", + style == Summary ? + "Types" : "Type Documentation", "type", "types"); FastSection functions(inner, - style == Summary ? "Functions" : "Function Documentation", + style == Summary ? + "Functions" : "Function Documentation", "function", "functions"); FastSection macros(inner, - style == Summary ? "Macros" : "Macro Documentation", + style == Summary ? + "Macros" : "Macro Documentation", "macro", "macros"); @@ -1006,4 +1094,82 @@ QString CppCodeMarker::addMarkUp(const QString& protectedCode, return result; } +#ifdef QDOC_QML +/*! + This function is for documenting QML properties. It returns + the list of documentation sections for the children of the + \a qmlClassNode. + + Currently, it only handles QML property groups. + */ +QList<Section> CppCodeMarker::qmlSections(const QmlClassNode* qmlClassNode, + SynopsisStyle style) +{ + QList<Section> sections; + if (qmlClassNode) { + if (style == Summary) { + FastSection qmlproperties(qmlClassNode, + "QML Properties", + "property", + "properties"); + FastSection qmlsignals(qmlClassNode, + "QML Signals", + "signal", + "signals"); + FastSection qmlmethods(qmlClassNode, + "QML Methods", + "method", + "methods"); + + NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); + while (c != qmlClassNode->childNodes().end()) { + if ((*c)->subType() == Node::QmlPropertyGroup) { + const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(*c); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + while (p != qpgn->childNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + insert(qmlproperties,*p,style,Okay); + } + ++p; + } + } + else if ((*c)->type() == Node::QmlSignal) { + insert(qmlsignals,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlMethod) { + insert(qmlmethods,*c,style,Okay); + } + ++c; + } + append(sections,qmlproperties); + append(sections,qmlsignals); + append(sections,qmlmethods); + } + else if (style == Detailed) { + FastSection qmlproperties(qmlClassNode,"QML Property Documentation"); + FastSection qmlsignals(qmlClassNode,"QML Signal Documentation"); + FastSection qmlmethods(qmlClassNode,"QML Method Documentation"); + NodeList::ConstIterator c = qmlClassNode->childNodes().begin(); + while (c != qmlClassNode->childNodes().end()) { + if ((*c)->subType() == Node::QmlPropertyGroup) { + insert(qmlproperties,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlSignal) { + insert(qmlsignals,*c,style,Okay); + } + else if ((*c)->type() == Node::QmlMethod) { + insert(qmlmethods,*c,style,Okay); + } + ++c; + } + append(sections,qmlproperties); + append(sections,qmlsignals); + append(sections,qmlmethods); + } + } + + return sections; +} +#endif + QT_END_NAMESPACE diff --git a/tools/qdoc3/cppcodemarker.h b/tools/qdoc3/cppcodemarker.h index 2967dfe..fa3cb78 100644 --- a/tools/qdoc3/cppcodemarker.h +++ b/tools/qdoc3/cppcodemarker.h @@ -67,6 +67,9 @@ class CppCodeMarker : public CodeMarker QString markedUpSynopsis(const Node *node, const Node *relative, SynopsisStyle style); +#ifdef QDOC_QML + QString markedUpQmlItem(const Node *node, bool summary); +#endif QString markedUpName(const Node *node); QString markedUpFullName(const Node *node, const Node *relative); QString markedUpEnumValue(const QString &enumValue, const Node *relative); @@ -76,6 +79,8 @@ class CppCodeMarker : public CodeMarker QList<Section> sections(const InnerNode *innerNode, SynopsisStyle style, Status status); + QList<Section> qmlSections(const QmlClassNode* qmlClassNode, + SynopsisStyle style); const Node *resolveTarget(const QString& target, const Tree *tree, const Node *relative); diff --git a/tools/qdoc3/cppcodeparser.cpp b/tools/qdoc3/cppcodeparser.cpp index 204c6e5..562684b 100644 --- a/tools/qdoc3/cppcodeparser.cpp +++ b/tools/qdoc3/cppcodeparser.cpp @@ -87,6 +87,10 @@ QT_BEGIN_NAMESPACE #ifdef QDOC_QML #define COMMAND_QMLCLASS Doc::alias("qmlclass") #define COMMAND_QMLPROPERTY Doc::alias("qmlproperty") +#define COMMAND_QMLINHERITS Doc::alias("inherits") +#define COMMAND_QMLSIGNAL Doc::alias("qmlsignal") +#define COMMAND_QMLMETHOD Doc::alias("qmlmethod") +#define COMMAND_QMLDEFAULT Doc::alias("default") #endif QStringList CppCodeParser::exampleFiles; @@ -109,7 +113,8 @@ static void extractPageLinkAndDesc(const QString &arg, if (arg.contains(".html") && spaceAt != -1) { *link = arg.left(spaceAt).trimmed(); *desc = arg.mid(spaceAt).trimmed(); - } else { + } + else { *link = arg; *desc = arg; } @@ -202,11 +207,6 @@ void CppCodeParser::initializeParser(const Config &config) nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property); nodeTypeMap.insert(COMMAND_VARIABLE, Node::Variable); -#ifdef QDOC_QML - // nodeTypeMap.insert(COMMAND_QMLCLASS, Node::Class); - nodeTypeMap.insert(COMMAND_QMLPROPERTY, Node::Property); -#endif - exampleFiles = config.getStringList(CONFIG_EXAMPLES); exampleDirs = config.getStringList(CONFIG_EXAMPLEDIRS); QStringList exampleFilePatterns = config.getStringList( @@ -477,13 +477,15 @@ QSet<QString> CppCodeParser::topicCommands() << COMMAND_PROPERTY << COMMAND_SERVICE << COMMAND_TYPEDEF -#ifdef QDOC_QML +#ifdef QDOC_QML << COMMAND_VARIABLE << COMMAND_QMLCLASS - << COMMAND_QMLPROPERTY; -#else + << COMMAND_QMLPROPERTY + << COMMAND_QMLSIGNAL + << COMMAND_QMLMETHOD; +#else << COMMAND_VARIABLE; -#endif +#endif } /*! @@ -587,24 +589,8 @@ Node *CppCodeParser::processTopicCommand(const Doc& doc, The command was neither "fn" nor "macro" . */ // ### split(" ") hack is there to support header file syntax - QStringList paths = arg.split(" "); + QStringList paths = arg.split(" "); QStringList path = paths[0].split("::"); - -#if QDOC2DOX - // qdoc -> doxygen. - if (Doc::isDoxPass(1)) { - if (command == COMMAND_PROPERTY) { - Doc::insertProperty(path); - } - else if (command == COMMAND_VARIABLE) { - Doc::insertVariable(path); - } - else if (command == COMMAND_ENUM) { - // zzz - } - } -#endif - Node *node = 0; if (!usedNamespaces.isEmpty()) { foreach (const QString &usedNamespace, usedNamespaces) { @@ -643,49 +629,169 @@ Node *CppCodeParser::processTopicCommand(const Doc& doc, } } + if (command == COMMAND_CLASS) { + if (paths.size() > 1) { + if (!paths[1].endsWith(".h")) { + ClassNode*cnode = static_cast<ClassNode*>(node); + cnode->setQmlElement(paths[1]); + } + } + } return node; } else if (command == COMMAND_EXAMPLE) { - FakeNode *fake = new FakeNode(tre->root(), arg, FakeNode::Example); + FakeNode *fake = new FakeNode(tre->root(), arg, Node::Example); createExampleFileNodes(fake); return fake; } else if (command == COMMAND_EXTERNALPAGE) { - return new FakeNode(tre->root(), arg, FakeNode::ExternalPage); + return new FakeNode(tre->root(), arg, Node::ExternalPage); } else if (command == COMMAND_FILE) { - return new FakeNode(tre->root(), arg, FakeNode::File); + return new FakeNode(tre->root(), arg, Node::File); } else if (command == COMMAND_GROUP) { - return new FakeNode(tre->root(), arg, FakeNode::Group); + return new FakeNode(tre->root(), arg, Node::Group); } else if (command == COMMAND_HEADERFILE) { - return new FakeNode(tre->root(), arg, FakeNode::HeaderFile); + return new FakeNode(tre->root(), arg, Node::HeaderFile); } else if (command == COMMAND_MODULE) { - return new FakeNode(tre->root(), arg, FakeNode::Module); + return new FakeNode(tre->root(), arg, Node::Module); } else if (command == COMMAND_PAGE) { - return new FakeNode(tre->root(), arg, FakeNode::Page); + return new FakeNode(tre->root(), arg, Node::Page); } -#ifdef QDOC_QML +#ifdef QDOC_QML else if (command == COMMAND_QMLCLASS) { const ClassNode* classNode = 0; - QStringList names = arg.split(" "); - //qDebug() << "QMLCLASS" << names; + QStringList names = arg.split(" "); if (names.size() > 1) { Node* n = tre->findNode(names[1].split("::"),Node::Class); - if (n) { + if (n) classNode = static_cast<const ClassNode*>(n); - //qDebug() << "FOUND IT!" << classNode->name(); + } + return new QmlClassNode(tre->root(), names[0], classNode); + } + else if ((command == COMMAND_QMLSIGNAL) || + (command == COMMAND_QMLMETHOD)) { + QString element; + QString name; + QmlClassNode* qmlClass = 0; + if (splitQmlArg(doc,arg,element,name)) { + Node* n = tre->findNode(QStringList(element),Node::Fake); + if (n && n->subType() == Node::QmlClass) { + qmlClass = static_cast<QmlClassNode*>(n); + if (command == COMMAND_QMLSIGNAL) + return new QmlSignalNode(qmlClass,name); + else + return new QmlMethodNode(qmlClass,name); } } - return new QmlNode(tre->root(), names[0], classNode); } -#endif +#endif return 0; } +#ifdef QDOC_QML + +/*! + A QML property argument has the form... + + <type> <element>::<name> + + This function splits the argument into those three + parts, sets \a type, \a element, and \a property, + and returns true. If any of the parts isn't found, + a debug message is output and false is returned. + */ +bool CppCodeParser::splitQmlPropertyArg(const Doc& doc, + const QString& arg, + QString& type, + QString& element, + QString& property) +{ + QStringList blankSplit = arg.split(" "); + if (blankSplit.size() > 1) { + type = blankSplit[0]; + QStringList colonSplit(blankSplit[1].split("::")); + if (colonSplit.size() > 1) { + element = colonSplit[0]; + property = colonSplit[1]; + return true; + } + else + doc.location().warning(tr("Missing QML element name or property name")); + } + else + doc.location().warning(tr("Missing QML property type or property path")); + return false; +} + +/*! + A QML signal or method argument has the form... + + <element>::<name> + + This function splits the argument into those two + parts, sets \a element, and \a name, and returns + true. If either of the parts isn't found, a debug + message is output and false is returned. + */ +bool CppCodeParser::splitQmlArg(const Doc& doc, + const QString& arg, + QString& element, + QString& name) +{ + QStringList colonSplit(arg.split("::")); + if (colonSplit.size() > 1) { + element = colonSplit[0]; + name = colonSplit[1]; + return true; + } + else + doc.location().warning(tr("Missing QML element name or signal/method name")); + return false; +} + +/*! + Process the topic \a command group with arguments \a args. + + Currently, this function is called only for \e{qmlproperty}. + */ +Node *CppCodeParser::processTopicCommandGroup(const Doc& doc, + const QString& command, + const QStringList& args) +{ + QmlPropGroupNode* qmlPropGroup = 0; + if (command == COMMAND_QMLPROPERTY) { + QString type; + QString element; + QString property; + QStringList::ConstIterator arg = args.begin(); + if (splitQmlPropertyArg(doc,(*arg),type,element,property)) { + Node* n = tre->findNode(QStringList(element),Node::Fake); + if (n && n->subType() == Node::QmlClass) { + QmlClassNode* qmlClass = static_cast<QmlClassNode*>(n); + if (qmlClass) + qmlPropGroup = new QmlPropGroupNode(qmlClass,property); + } + } + if (qmlPropGroup) { + new QmlPropertyNode(qmlPropGroup,property,type); + ++arg; + while (arg != args.end()) { + if (splitQmlPropertyArg(doc,(*arg),type,element,property)) { + new QmlPropertyNode(qmlPropGroup,property,type); + } + ++arg; + } + } + } + return qmlPropGroup; +} +#endif + /*! Returns the set of strings representing the common metacommands plus some other metacommands. @@ -700,7 +806,13 @@ QSet<QString> CppCodeParser::otherMetaCommands() << COMMAND_NEXTPAGE << COMMAND_PREVIOUSPAGE << COMMAND_INDEXPAGE +#ifdef QDOC_QML + << COMMAND_STARTPAGE + << COMMAND_QMLINHERITS + << COMMAND_QMLDEFAULT; +#else << COMMAND_STARTPAGE; +#endif } /*! @@ -742,21 +854,29 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, tr("The function either doesn't exist in any base class " "with the same signature or it exists but isn't virtual.")); } -#if 0 // Ideally, we would enable this check to warn whenever \reimp is used - // incorrectly, and only make the node internal if the function is a - // reimplementation of another function in a base class. + /* + Ideally, we would enable this check to warn whenever + \reimp is used incorrectly, and only make the node + internal if the function is a reimplementation of + another function in a base class. + */ else if (from->access() == Node::Private || from->parent()->access() == Node::Private) { - doc.location().warning( - tr("Base function for '\\%1' in %2() is private or internal") + doc.location().warning(tr("'\\%1' in %2() should be '\\internal' because its base function is private or internal") .arg(COMMAND_REIMP).arg(node->name())); } -#endif - // Note: Setting the access to Private hides the documentation, - // but setting the status to Internal makes the node available - // in the XML output when the WebXMLGenerator is used. + +#if 0 + // Reimplemented functions now reported in separate sections. + /* + Note: Setting the access to Private hides the documentation, + but setting the status to Internal makes the node available + in the XML output when the WebXMLGenerator is used. + */ func->setAccess(Node::Private); func->setStatus(Node::Internal); +#endif + func->setReimp(true); } else { doc.location().warning(tr("Ignored '\\%1' in %2") @@ -767,14 +887,19 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, else if (command == COMMAND_RELATES) { InnerNode *pseudoParent; if (arg.startsWith("<") || arg.startsWith("\"")) { - pseudoParent = static_cast<InnerNode *>(tre->findNode(QStringList(arg), Node::Fake)); + pseudoParent = + static_cast<InnerNode *>(tre->findNode(QStringList(arg), + Node::Fake)); } else { QStringList newPath = arg.split("::"); - pseudoParent = static_cast<InnerNode *>(tre->findNode(QStringList(newPath), Node::Class)); + pseudoParent = + static_cast<InnerNode*>(tre->findNode(QStringList(newPath), + Node::Class)); if (!pseudoParent) - pseudoParent = static_cast<InnerNode *>(tre->findNode(QStringList(newPath), - Node::Namespace)); + pseudoParent = + static_cast<InnerNode*>(tre->findNode(QStringList(newPath), + Node::Namespace)); } if (!pseudoParent) { doc.location().warning(tr("Cannot find '%1' in '\\%2'") @@ -799,6 +924,15 @@ void CppCodeParser::processOtherMetaCommand(const Doc& doc, else if (command == COMMAND_STARTPAGE) { setLink(node, Node::StartLink, arg); } +#ifdef QDOC_QML + else if (command == COMMAND_QMLINHERITS) { + setLink(node, Node::InheritsLink, arg); + } + else if (command == COMMAND_QMLDEFAULT) { + QmlPropGroupNode* qpgn = static_cast<QmlPropGroupNode*>(node); + qpgn->setDefault(); + } +#endif else { processCommonMetaCommand(doc.location(),command,arg,node,tre); } @@ -878,9 +1012,8 @@ bool CppCodeParser::match(int target) readToken(); return true; } - else { + else return false; - } } /*! @@ -915,11 +1048,14 @@ bool CppCodeParser::matchTemplateAngles(CodeChunk *dataType) do { if (tok == Tok_LeftAngle) { leftAngleDepth++; - } else if (tok == Tok_RightAngle) { + } + else if (tok == Tok_RightAngle) { leftAngleDepth--; - } else if (tok == Tok_LeftParen || tok == Tok_LeftBrace) { + } + else if (tok == Tok_LeftParen || tok == Tok_LeftBrace) { ++parenAndBraceDepth; - } else if (tok == Tok_RightParen || tok == Tok_RightBrace) { + } + else if (tok == Tok_RightParen || tok == Tok_RightBrace) { if (--parenAndBraceDepth < 0) return false; } @@ -982,7 +1118,8 @@ bool CppCodeParser::matchDataType(CodeChunk *dataType, QString *var) dataType->append(previousLexeme()); else return false; - } else if (match(Tok_int) || match(Tok_char) || match(Tok_double)) { + } + else if (match(Tok_int) || match(Tok_char) || match(Tok_double)) { dataType->append(previousLexeme()); } @@ -1082,8 +1219,10 @@ bool CppCodeParser::matchParameter(FunctionNode *func) readToken(); } } - func->addParameter(Parameter(dataType.toString(), "", name, - defaultValue.toString())); // ### + func->addParameter(Parameter(dataType.toString(), + "", + name, + defaultValue.toString())); // ### return true; } @@ -1131,7 +1270,8 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent, compat = true; if (tok == Tok_operator && - (returnType.toString().isEmpty() || returnType.toString().endsWith("::"))) { + (returnType.toString().isEmpty() || + returnType.toString().endsWith("::"))) { // 'QString::operator const char *()' parentPath = returnType.toString().split(sep); parentPath.removeAll(QString()); @@ -1167,11 +1307,10 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent, name = previousLexeme(); matchTemplateAngles(); - if (match(Tok_Gulbrandsen)) { + if (match(Tok_Gulbrandsen)) parentPath.append(name); - } else { + else break; - } } if (tok == Tok_operator) { @@ -1184,7 +1323,9 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent, break; } } - if (parent && (tok == Tok_Semicolon || tok == Tok_LeftBracket || tok == Tok_Colon) + if (parent && (tok == Tok_Semicolon || + tok == Tok_LeftBracket || + tok == Tok_Colon) && access != Node::Private) { if (tok == Tok_LeftBracket) { returnType.appendHotspot(); @@ -1198,7 +1339,8 @@ bool CppCodeParser::matchFunctionDecl(InnerNode *parent, } if (tok != Tok_Semicolon) return false; - } else if (tok == Tok_Colon) { + } + else if (tok == Tok_Colon) { returnType.appendHotspot(); while (tok != Tok_Semicolon && tok != Tok_Eoi) { @@ -1390,7 +1532,7 @@ bool CppCodeParser::matchNamespaceDecl(InnerNode *parent) QString namespaceName = previousLexeme(); NamespaceNode *namespasse = 0; if (parent) - namespasse = static_cast<NamespaceNode *>(parent->findNode(namespaceName, Node::Namespace)); + namespasse = static_cast<NamespaceNode*>(parent->findNode(namespaceName, Node::Namespace)); if (!namespasse) { namespasse = new NamespaceNode(parent, namespaceName); namespasse->setAccess(access); @@ -1456,7 +1598,8 @@ bool CppCodeParser::matchEnumItem(InnerNode *parent, EnumNode *enume) if (strVal.isEmpty()) { if (enume->items().isEmpty()) { strVal = "0"; - } else { + } + else { QString last = enume->items().last().value(); bool ok; int n = last.toInt(&ok); @@ -1466,15 +1609,16 @@ bool CppCodeParser::matchEnumItem(InnerNode *parent, EnumNode *enume) strVal = last.left(2) + QString::number(n + 1, 16); else strVal = "0" + QString::number(n + 1, 8); - } else { - strVal = QString::number(n + 1); } + else + strVal = QString::number(n + 1); } } } enume->addItem(EnumItem(name, strVal)); - } else { + } + else { VariableNode *var = new VariableNode(parent, name); var->setAccess(access); var->setLocation(location()); @@ -1562,7 +1706,8 @@ bool CppCodeParser::matchProperty(InnerNode *parent) if (match(Tok_Ident)) { value = previousLexeme(); - } else if (match(Tok_LeftParen)) { + } + else if (match(Tok_LeftParen)) { int depth = 1; while (tok != Tok_Eoi) { if (tok == Tok_LeftParen) { @@ -1579,6 +1724,9 @@ bool CppCodeParser::matchProperty(InnerNode *parent) value = "?"; } + /* + Task 259071 requires work here. See gui/widgets/qdatetime.h, for example. + */ if (key == "READ") tre->addPropertyFunction(property, value, PropertyNode::Getter); else if (key == "WRITE") @@ -1753,12 +1901,6 @@ bool CppCodeParser::matchDocsAndStuff() readToken(); Doc::trimCStyleComment(start_loc,comment); - /* - qdoc --> doxygen - We must also remember the location of the end - of the comment, so we can construct a diff for - it. - */ Location end_loc(location()); /* @@ -1821,6 +1963,28 @@ bool CppCodeParser::matchDocsAndStuff() /* There is a topic command. Process it. */ +#ifdef QDOC_QML + if (topic == COMMAND_QMLPROPERTY) { + Doc nodeDoc = doc; + Node *node = processTopicCommandGroup(nodeDoc,topic,args); + if (node != 0) { + nodes.append(node); + docs.append(nodeDoc); + } + } + else { + QStringList::ConstIterator a = args.begin(); + while (a != args.end()) { + Doc nodeDoc = doc; + Node *node = processTopicCommand(nodeDoc,topic,*a); + if (node != 0) { + nodes.append(node); + docs.append(nodeDoc); + } + ++a; + } + } +#else QStringList::ConstIterator a = args.begin(); while (a != args.end()) { Doc nodeDoc = doc; @@ -1831,6 +1995,7 @@ bool CppCodeParser::matchDocsAndStuff() } ++a; } +#endif } NodeList::Iterator n = nodes.begin(); @@ -1838,7 +2003,8 @@ bool CppCodeParser::matchDocsAndStuff() while (n != nodes.end()) { processOtherMetaCommands(*d, *n); (*n)->setDoc(*d); - if ((*n)->isInnerNode() && ((InnerNode *)*n)->includes().isEmpty()) { + if ((*n)->isInnerNode() && + ((InnerNode *)*n)->includes().isEmpty()) { InnerNode *m = static_cast<InnerNode *>(*n); while (m->parent() != tre->root()) m = m->parent(); @@ -1926,7 +2092,8 @@ void CppCodeParser::parseQiteratorDotH(const Location &location, mutableSequentialIteratorDefinition = lines[1]; associativeIteratorDefinition = lines[2]; mutableAssociativeIteratorDefinition = lines[3]; - } else { + } + else { location.warning(tr("The qiterator.h hack failed")); } } @@ -2008,7 +2175,7 @@ void CppCodeParser::createExampleFileNodes(FakeNode *fake) foreach (const QString &exampleFile, exampleFiles) (void) new FakeNode(fake, exampleFile.mid(sizeOfBoringPartOfName), - FakeNode::File); + Node::File); } QT_END_NAMESPACE diff --git a/tools/qdoc3/cppcodeparser.h b/tools/qdoc3/cppcodeparser.h index 1f41318..cbb0149 100644 --- a/tools/qdoc3/cppcodeparser.h +++ b/tools/qdoc3/cppcodeparser.h @@ -90,6 +90,21 @@ class CppCodeParser : public CodeParser virtual Node *processTopicCommand(const Doc& doc, const QString& command, const QString& arg); +#ifdef QDOC_QML + // might need to implement this in QsCodeParser as well. + virtual Node *processTopicCommandGroup(const Doc& doc, + const QString& command, + const QStringList& args); + bool splitQmlPropertyArg(const Doc& doc, + const QString& arg, + QString& type, + QString& element, + QString& property); + bool splitQmlArg(const Doc& doc, + const QString& arg, + QString& element, + QString& name); +#endif virtual QSet<QString> otherMetaCommands(); virtual void processOtherMetaCommand(const Doc& doc, const QString& command, diff --git a/tools/qdoc3/doc.cpp b/tools/qdoc3/doc.cpp index f7007a0..e2f3525 100644 --- a/tools/qdoc3/doc.cpp +++ b/tools/qdoc3/doc.cpp @@ -73,20 +73,20 @@ struct Macro }; enum { - CMD_A, CMD_ABSTRACT, CMD_BADCODE, CMD_BASENAME, CMD_BOLD, - CMD_BRIEF, CMD_C, CMD_CAPTION, CMD_CHAPTER, CMD_CODE, - CMD_CODELINE, CMD_DOTS, CMD_ELSE, CMD_ENDABSTRACT, - CMD_ENDCHAPTER, CMD_ENDCODE, CMD_ENDFOOTNOTE, CMD_ENDIF, - CMD_ENDLEGALESE, CMD_ENDLINK, CMD_ENDLIST, CMD_ENDOMIT, - CMD_ENDPART, CMD_ENDQUOTATION, CMD_ENDRAW, CMD_ENDSECTION1, - CMD_ENDSECTION2, CMD_ENDSECTION3, CMD_ENDSECTION4, - CMD_ENDSIDEBAR, CMD_ENDTABLE, CMD_EXPIRE, CMD_FOOTNOTE, - CMD_GENERATELIST, CMD_GRANULARITY, CMD_HEADER, CMD_I, - CMD_IF, CMD_IMAGE, CMD_INCLUDE, CMD_INLINEIMAGE, CMD_INDEX, - CMD_KEYWORD, CMD_L, CMD_LEGALESE, CMD_LINK, CMD_LIST, - CMD_META, CMD_NEWCODE, CMD_O, CMD_OLDCODE, CMD_OMIT, - CMD_OMITVALUE, CMD_OVERLOAD, - CMD_PART, CMD_PRINTLINE, CMD_PRINTTO, + CMD_A, CMD_ABSTRACT, CMD_ANNOTATEDLIST, CMD_BADCODE, + CMD_BASENAME, CMD_BOLD, CMD_BRIEF, CMD_C, CMD_CAPTION, + CMD_CHAPTER, CMD_CODE, CMD_CODELINE, CMD_DOTS, CMD_ELSE, + CMD_ENDABSTRACT, CMD_ENDCHAPTER, CMD_ENDCODE, + CMD_ENDFOOTNOTE, CMD_ENDIF, CMD_ENDLEGALESE, CMD_ENDLINK, + CMD_ENDLIST, CMD_ENDOMIT, CMD_ENDPART, CMD_ENDQUOTATION, + CMD_ENDRAW, CMD_ENDSECTION1, CMD_ENDSECTION2, + CMD_ENDSECTION3, CMD_ENDSECTION4, CMD_ENDSIDEBAR, + CMD_ENDTABLE, CMD_EXPIRE, CMD_FOOTNOTE, CMD_GENERATELIST, + CMD_GRANULARITY, CMD_HEADER, CMD_I, CMD_IF, CMD_IMAGE, + CMD_INCLUDE, CMD_INLINEIMAGE, CMD_INDEX, CMD_KEYWORD, + CMD_L, CMD_LEGALESE, CMD_LINK, CMD_LIST, CMD_META, + CMD_NEWCODE, CMD_O, CMD_OLDCODE, CMD_OMIT, CMD_OMITVALUE, + CMD_OVERLOAD, CMD_PART, CMD_PRINTLINE, CMD_PRINTTO, CMD_PRINTUNTIL, CMD_QUOTATION, CMD_QUOTEFILE, CMD_QUOTEFROMFILE, CMD_QUOTEFUNCTION, CMD_RAW, CMD_ROW, CMD_SA, CMD_SECTION1, CMD_SECTION2, CMD_SECTION3, @@ -108,6 +108,7 @@ static struct { } cmds[] = { { "a", CMD_A, 0 }, { "abstract", CMD_ABSTRACT, 0 }, + { "annotatedlist", CMD_ANNOTATEDLIST, 0 }, { "badcode", CMD_BADCODE, 0 }, { "basename", CMD_BASENAME, 0 }, // ### don't document for now { "bold", CMD_BOLD, 0 }, @@ -515,14 +516,7 @@ void DocParser::parse(const QString& source, break; case CMD_BADCODE: leavePara(); -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) - append(Atom::CodeBad,getUnmarkedCode(CMD_BADCODE)); - else - append(Atom::CodeBad,getCode(CMD_BADCODE, marker)); -#else append(Atom::CodeBad,getCode(CMD_BADCODE, marker)); -#endif break; case CMD_BASENAME: leavePara(); @@ -538,17 +532,8 @@ void DocParser::parse(const QString& source, case CMD_C: enterPara(); x = untabifyEtc(getArgument(true)); -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) - append(Atom::C, x); - else { - marker = CodeMarker::markerForCode(x); - append(Atom::C, marker->markedUpCode(x, 0, "")); - } -#else marker = CodeMarker::markerForCode(x); append(Atom::C, marker->markedUpCode(x, 0, "")); -#endif break; case CMD_CAPTION: leavePara(); @@ -559,14 +544,7 @@ void DocParser::parse(const QString& source, break; case CMD_CODE: leavePara(); -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) - append(Atom::Code, getUnmarkedCode(CMD_CODE)); - else - append(Atom::Code, getCode(CMD_CODE, marker)); -#else append(Atom::Code, getCode(CMD_CODE, marker)); -#endif break; #ifdef QDOC_QML case CMD_QML: @@ -579,17 +557,6 @@ void DocParser::parse(const QString& source, #endif case CMD_CODELINE: { -#ifdef QDOC2DOX - if (!quoting && !DoxWriter::isDoxPass()) { - if (priv->text.lastAtom()->type() == Atom::Code - && priv->text.lastAtom()->string().endsWith("\n\n")) - priv->text.lastAtom()->chopString(); - appendToCode("\n"); - } lse { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, " "); - } -#else if (!quoting) { if (priv->text.lastAtom()->type() == Atom::Code && priv->text.lastAtom()->string().endsWith("\n\n")) @@ -600,37 +567,10 @@ void DocParser::parse(const QString& source, append(Atom::CodeQuoteCommand, cmdStr); append(Atom::CodeQuoteArgument, " "); } -#endif } break; case CMD_DOTS: { -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, " ..."); - } - else if (!quoting) { - if (priv->text.lastAtom()->type() == Atom::Code - && priv->text.lastAtom()->string().endsWith("\n\n")) - priv->text.lastAtom()->chopString(); - - QString arg = getOptionalArgument(); - int indent = 4; - if (!arg.isEmpty()) - indent = arg.toInt(); - for (int i = 0; i < indent; ++i) - appendToCode(" "); - appendToCode("...\n"); - } - else { - append(Atom::CodeQuoteCommand, cmdStr); - QString arg = getOptionalArgument(); - if (arg.isEmpty()) - arg = "4"; - append(Atom::CodeQuoteArgument, arg); - } -#else if (!quoting) { if (priv->text.lastAtom()->type() == Atom::Code && priv->text.lastAtom()->string().endsWith("\n\n")) @@ -651,7 +591,6 @@ void DocParser::parse(const QString& source, arg = "4"; append(Atom::CodeQuoteArgument, arg); } -#endif } break; case CMD_ELSE: @@ -785,6 +724,9 @@ void DocParser::parse(const QString& source, paraState = OutsidePara; // ### } break; + case CMD_ANNOTATEDLIST: + append(Atom::AnnotatedList, getArgument()); + break; case CMD_GENERATELIST: append(Atom::GeneratedList, getArgument()); break; @@ -953,19 +895,8 @@ void DocParser::parse(const QString& source, break; case CMD_OLDCODE: leavePara(); -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) { - append(Atom::CodeOld, getUnmarkedCode(CMD_OLDCODE)); - append(Atom::CodeNew, getUnmarkedCode(CMD_NEWCODE)); - } - else { - append(Atom::CodeOld, getCode(CMD_OLDCODE, marker)); - append(Atom::CodeNew, getCode(CMD_NEWCODE, marker)); - } -#else append(Atom::CodeOld, getCode(CMD_OLDCODE, marker)); append(Atom::CodeNew, getCode(CMD_NEWCODE, marker)); -#endif break; case CMD_OMIT: getUntilEnd(cmd); @@ -1147,18 +1078,6 @@ void DocParser::parse(const QString& source, { QString snippet = getArgument(); QString identifier = getRestOfLine(); -#ifdef QDOC2DOX - if (quoting || DoxWriter::isDoxPass()) { - append(Atom::SnippetCommand, cmdStr); - append(Atom::SnippetLocation, snippet); - append(Atom::SnippetIdentifier, identifier); - } - else { - Doc::quoteFromFile(location(),quoter,snippet); - appendToCode(quoter.quoteSnippet(location(), - identifier)); - } -#else if (quoting) { append(Atom::SnippetCommand, cmdStr); append(Atom::SnippetLocation, snippet); @@ -1169,7 +1088,6 @@ void DocParser::parse(const QString& source, appendToCode(quoter.quoteSnippet(location(), identifier)); } -#endif } break; case CMD_SUB: @@ -1251,7 +1169,7 @@ void DocParser::parse(const QString& source, append(Atom::FormattingRight, ATOM_FORMATTING_BOLD); append(Atom::String, " "); break; - case CMD_OVERLOAD: // qdoc --> doxygen + case CMD_OVERLOAD: priv->metacommandsUsed.insert(cmdStr); x.clear(); if (!isBlankLine()) @@ -1763,10 +1681,13 @@ void DocParser::startSection(Doc::SectioningUnit unit, int cmd) leavePara(); if (currentSectioningUnit == Doc::Book) { +#if 0 + // mws didn't think this was necessary. if (unit > Doc::Section1) location().warning(tr("Unexpected '\\%1' without '\\%2'") .arg(cmdName(cmd)) .arg(cmdName(CMD_SECTION1))); +#endif currentSectioningUnit = (Doc::SectioningUnit) (unit - 1); priv->constructExtra(); priv->extra->sectioningUnit = currentSectioningUnit; @@ -2343,7 +2264,7 @@ QString DocParser::getCode(int cmd, CodeMarker *marker) } /*! - Used only for generating doxygen output. + Was used only for generating doxygen output. */ QString DocParser::getUnmarkedCode(int cmd) { @@ -2579,36 +2500,6 @@ QString DocParser::slashed(const QString& str) #define COMMAND_QMLBRIEF Doc::alias("qmlbrief") #endif -#ifdef QDOC2DOX -#define DOXYGEN_INDENT 2 -#define DOXYGEN_TAB_SIZE 4 -#define DOXYGEN_INDENT_STRING " " -#define DOXYGEN_TAB_STRING " " - -static QRegExp ws_rx("\\s"); -static QRegExp not_ws_rx("\\S"); - -int DoxWriter::doxPass = 0; -QString DoxWriter::currentClass; -QSet<QString> DoxWriter::anchors; -QStringMap DoxWriter::exampleTitles; -QStringMap DoxWriter::headerFileTitles; -QStringMap DoxWriter::fileTitles; -QStringMap DoxWriter::groupTitles; -QStringMap DoxWriter::moduleTitles; -QStringMap DoxWriter::pageTitles; -QStringMap DoxWriter::externalPageTitles; -QStringMap DoxWriter::exampleTitlesInverse; -QStringMap DoxWriter::headerFileTitlesInverse; -QStringMap DoxWriter::fileTitlesInverse; -QStringMap DoxWriter::groupTitlesInverse; -QStringMap DoxWriter::moduleTitlesInverse; -QStringMap DoxWriter::pageTitlesInverse; -QStringMap DoxWriter::externalPageTitlesInverse; -QStringMultiMap DoxWriter::variables; -QStringMultiMap DoxWriter::properties; -QStringMultiMap DoxWriter::enums; -#endif Doc::Doc(const Location& start_loc, const Location& end_loc, @@ -2618,15 +2509,6 @@ Doc::Doc(const Location& start_loc, priv = new DocPrivate(start_loc,end_loc,source); DocParser parser; parser.parse(source,priv,metaCommandSet); -#ifdef QDOC2DOX - if (DoxWriter::isDoxPass()) { - DoxWriter doxWriter(source,priv); - if (DoxWriter::isDoxPass(1)) - doxWriter.pass1(); - else - doxWriter.pass2(); - } -#endif } Doc::Doc(const Doc& doc) @@ -3180,1855 +3062,4 @@ void Doc::detach() priv = newPriv; } -#ifdef QDOC2DOX -/*! - Sets the doxygen writer pass to \a pass. You can use - isDoxPass(), with or without a parameter, to test if - you are in a doxygen writer run or in a specific pass - of a doxygen writer run. - - This function is only called from main() if either the - \e doxygen1 or \e doxygen2 flag is passed to qdoc3 on - the command line. - */ -void DoxWriter::setDoxPass(int pass) -{ - qDebug() << "SETTING doxygen pass to " << pass - << " in DoxWriter::setDoxPass()"; - doxPass = pass; -} - -/*! - Returns true if the doxygen pass is set to \a pass, - which means we are in the specified \a pass of a doxygen - writer run of qdoc3. - */ -bool DoxWriter::isDoxPass(int pass) { return (doxPass == pass); } - -/*! - Returns true if the doxygen pass is 1 or 2, which - means this is a doxygen writer run to transform qdoc - comments into doxygen comments. - */ -bool DoxWriter::isDoxPass() { return (doxPass > 0); } - -bool DoxWriter::conversionRequired() const -{ - /* - Loop through all the topic commands searching for - one that must be transformed to doxygen format. If - one is found, return true. - */ - QCommandMap::const_iterator i; - i = priv->metaCommandMap.constBegin(); - while (i != priv->metaCommandMap.constEnd()) { - QString s = i.key(); - if (s == "enum") - return true; - else if (s == "example") - return true; - else if (s == "externalpage") - return true; - else if (s == "group") - return true; - else if (s == "headerfile") - return true; - else if (s == "module") - return true; - else if (s == "page") - return true; - else if (s == "property") - return true; - else if (s == "typedef") - return true; - else if (s == "variable") - return true; - else if (s == "overload") - return true; - else if (s == "reimp") - return true; - else if (s == "relates") - return true; - else if (s == "macro") - return true; - else { -#if 0 - if (s == "class") - else if (s == "namespace") - else if (s == "service") - else if (s == "inheaderfile") - else if (s == "file") - else if (s == "fn") - else if (s == "contentspage") - else if (s == "nextpage") - else if (s == "previous") - else if (s == "indexpage") - else if (s == "startpage") -#endif - } - ++i; - } - - /* - Loop through all the qdoc atoms searching for one - that must be transformed to doxygen format. If one - is found, return true. - */ - const Atom* next = priv->text.firstAtom(); - while (next != 0) { - Atom::Type atomType = next->type(); - switch (atomType) { - case Atom::C: - case Atom::CaptionLeft: - case Atom::Code: - case Atom::CodeBad: - case Atom::CodeNew: - case Atom::CodeOld: - case Atom::CodeQuoteArgument: - case Atom::CodeQuoteCommand: - case Atom::FootnoteLeft: - case Atom::FormatElse: - case Atom::FormatEndif: - case Atom::FormatIf: - case Atom::GeneratedList: - case Atom::Image: - case Atom::ImageText: - case Atom::InlineImage: - case Atom::LegaleseLeft: - case Atom::LineBreak: - case Atom::Link: - case Atom::LinkNode: - case Atom::ListLeft: - case Atom::ListItemNumber: - case Atom::ListTagLeft: - case Atom::ListItemLeft: - case Atom::QuotationLeft: - case Atom::RawString: - case Atom::SectionLeft: - case Atom::SectionHeadingLeft: - case Atom::SidebarLeft: - case Atom::SnippetCommand: - case Atom::SnippetIdentifier: - case Atom::SnippetLocation: - case Atom::TableLeft: - case Atom::TableHeaderLeft: - case Atom::TableRowLeft: - case Atom::TableItemLeft: - case Atom::TableOfContents: - case Atom::Target: - return true; - case Atom::AbstractLeft: - case Atom::AbstractRight: - case Atom::AutoLink: - case Atom::BaseName: - case Atom::BriefLeft: - case Atom::BriefRight: - case Atom::CaptionRight: - case Atom::FormattingLeft: - case Atom::FormattingRight: - case Atom::Nop: - case Atom::ParaLeft: - case Atom::ParaRight: - case Atom::FootnoteRight: - case Atom::LegaleseRight: - case Atom::ListTagRight: - case Atom::ListItemRight: - case Atom::ListRight: - case Atom::QuotationRight: - case Atom::SectionRight: - case Atom::SectionHeadingRight: - case Atom::SidebarRight: - case Atom::String: - case Atom::TableRight: - case Atom::TableHeaderRight: - case Atom::TableRowRight: - case Atom::TableItemRight: - default: - break; - } - next = next->next(); - } - return false; -} - -/*! - A convenience function to write a qdoc metacommand as a - doxygen command, without conversion. i.e., some of the - qdoc metacommands don't require conversion for doxygen. - */ -void DoxWriter::writeCommand(QCommandMap::const_iterator cmd) -{ - concatenate("\\" + cmd.key() + " " + cmd.value()[0]); - newLine(); -} - -/*! - Convert the qdoc commands in the metacommand map to - doxygen format. This function is called only in pass2(). - The metacommand map contains all the metacommands that - were found in the qdoc comment that is being converted. - The metacommands are the ones that begin with the '\'. - These are not considered part of the text of the comment. - The text is converted by convertText(). - */ -void DoxWriter::convertMetaCommands() -{ - QCommandMap& metaCmdMap = priv->metaCommandMap; - QCommandMap::iterator cmd; - int c; - - currentPage.clear(); - currentFn.clear(); - currentTitle.clear(); - currentEnum.clear(); - currentProperty.clear(); - currentVariable.clear(); - currentClass.clear(); - currentExample.clear(); - currentGroup.clear(); - currentModule.clear(); - currentMacro.clear(); - currentService.clear(); - currentTypedef.clear(); - currentHeaderFile.clear(); - commentType = OtherComment; - - if ((cmd = metaCmdMap.find("class")) != metaCmdMap.end()) { - currentClass = cmd.value()[0]; - if ((c = currentClass.indexOf(' ')) > 0) - currentClass = currentClass.left(c); - writeCommand(cmd); - metaCmdMap.erase(cmd); - commentType = ClassComment; - } - else if ((cmd = metaCmdMap.find("fn")) != metaCmdMap.end()) { - currentFn = cmd.value()[0]; - writeCommand(cmd); - metaCmdMap.erase(cmd); - commentType = FnComment; - } - else if ((cmd = metaCmdMap.find("enum")) != metaCmdMap.end()) { - currentEnum = cmd.value()[0]; - if ((c = currentEnum.lastIndexOf("::")) > 0) { - currentClass = currentEnum.left(c); - currentEnum = currentEnum.right(currentEnum.size()-c-2); - qDebug() << "currentEnum =" << currentEnum; - qDebug() << "currentClass =" << currentClass; - } - writeCommand(cmd); - metaCmdMap.erase(cmd); - commentType = EnumComment; - } - else if ((cmd = metaCmdMap.find("property")) != metaCmdMap.end()) { - currentClass = cmd.value()[0]; - if ((c = currentClass.lastIndexOf("::")) > 0) { - currentProperty = currentClass.right(currentClass.size()-c-2); - currentClass = currentClass.left(c); - qDebug() << "currentProperty =" << currentProperty; - qDebug() << "currentClass =" << currentClass; - } - writeCommand(cmd); - metaCmdMap.erase(cmd); - commentType = PropertyComment; - } - else if ((cmd = metaCmdMap.find("variable")) != metaCmdMap.end()) { - currentClass = cmd.value()[0]; - if ((c = currentClass.lastIndexOf("::")) > 0) { - currentVariable = currentClass.right(currentClass.size()-c-2); - currentClass = currentClass.left(c); - qDebug() << "currentVariable =" << currentVariable; - qDebug() << "currentClass =" << currentClass; - } - concatenate("\\var " + cmd.value()[0]); - newLine(); - metaCmdMap.erase(cmd); - commentType = VariableComment; - } - - if ((cmd = metaCmdMap.find("page")) != metaCmdMap.end()) { - currentPage = cmd.value()[0]; - QString htmlFile = currentPage; - const QString* title = getPageTitle(htmlFile); - QStringList parts = htmlFile.split('.'); - metaCmdMap.erase(cmd); - if (title) { - concatenate("\\page " + parts[0] + " " + *title); - newLine(); - } - commentType = PageComment; - qDebug() << "currentPage =" << currentPage; - } - - if ((cmd = metaCmdMap.find("example")) != metaCmdMap.end()) { - currentExample = cmd.value()[0]; - metaCmdMap.erase(cmd); - commentType = ExampleComment; - qDebug() << "currentExample =" << currentExample; - } - - if ((cmd = metaCmdMap.find("macro")) != metaCmdMap.end()) { - currentMacro = cmd.value()[0]; - metaCmdMap.erase(cmd); - commentType = MacroComment; - qDebug() << "currentMacro =" << currentMacro; - } - - if ((cmd = metaCmdMap.find("group")) != metaCmdMap.end()) { - currentGroup = cmd.value()[0]; - metaCmdMap.erase(cmd); - commentType = GroupComment; - qDebug() << "currentGroup =" << currentGroup; - } - - if ((cmd = metaCmdMap.find("module")) != metaCmdMap.end()) { - currentModule = cmd.value()[0]; - metaCmdMap.erase(cmd); - commentType = ModuleComment; - qDebug() << "currentModule =" << currentModule; - } - - if ((cmd = metaCmdMap.find("headerfile")) != metaCmdMap.end()) { - currentHeaderFile = cmd.value()[0]; - metaCmdMap.erase(cmd); - commentType = HeaderFileComment; - qDebug() << "currentHeaderFile =" << currentHeaderFile; - } - - if ((cmd = metaCmdMap.find("typedef")) != metaCmdMap.end()) { - currentClass = cmd.value()[0]; - if ((c = currentClass.lastIndexOf("::")) > 0) { - currentTypedef = currentClass.right(currentClass.size()-c-2); - currentClass = currentClass.left(c); - } - metaCmdMap.erase(cmd); - commentType = TypedefComment; - qDebug() << "currentTypedef =" << currentTypedef; - qDebug() << "currentClass =" << currentClass; - } - - cmd = priv->metaCommandMap.begin(); - while (cmd != priv->metaCommandMap.end()) { - for (int i=0; i<cmd.value().size(); i++) { - concatenate("\\" + cmd.key() + " " + cmd.value()[i]); - newLine(); - } - //qDebug() << " " << cmd.key() << ": " << cmd.value(); - ++cmd; - } -} - -/*! - Convert the qdoc text to doxygen format. The metacommands - are converted by convertMetaCommands(). This function is - called in pass2(). - */ -void DoxWriter::convertText() -{ - const Atom* prev = 0; - const Atom* next = priv->text.firstAtom(); - while (next != 0) { - next->dump(); - Atom::Type atomType = next->type(); - switch (atomType) { - case Atom::AbstractLeft: - break; - case Atom::AbstractRight: - break; - case Atom::AutoLink: - concatenate(next->string()); - break; - case Atom::BaseName: - break; - case Atom::BriefLeft: - concatenate("\\brief "); - break; - case Atom::BriefRight: - newLine(); - break; - case Atom::C: - tt(next); - break; - case Atom::CaptionLeft: - unhandled(next); - break; - case Atom::CaptionRight: - unhandled(next); - break; - case Atom::Code: - code(next); - break; - case Atom::CodeBad: - code(next); - break; - case Atom::CodeNew: - newLine(); - concatenate("you can rewrite it as"); - code(next); - break; - case Atom::CodeOld: - newLine(); - concatenate("For example, if you have code like"); - code(next); - break; - case Atom::CodeQuoteArgument: - unhandled(next); - break; - case Atom::CodeQuoteCommand: - next = codeQuoteCommand(next); - break; - case Atom::FootnoteLeft: - break; - case Atom::FootnoteRight: - break; - case Atom::FormatElse: - formatElse(); - break; - case Atom::FormatEndif: - formatEndif(); - break; - case Atom::FormatIf: - formatIf(next); - break; - case Atom::FormattingLeft: - formattingLeft(next,next->next()); - break; - case Atom::FormattingRight: - formattingRight(next,prev); - break; - case Atom::GeneratedList: - break; - case Atom::Image: - break; - case Atom::ImageText: - break; - case Atom::InlineImage: - break; - case Atom::LegaleseLeft: - break; - case Atom::LegaleseRight: - break; - case Atom::LineBreak: - break; - case Atom::Link: - next = link(next); - break; - case Atom::LinkNode: - break; - case Atom::ListLeft: - { - bool nested = false; - if (structs.isEmpty()) { - const Atom* i = next->next(); - while (i->type() != Atom::ListRight) { - if ((i->type() == Atom::ListLeft) || - (i->type() == Atom::TableLeft)) { - nested = true; - break; - } - i = i->next(); - } - } - else - nested = true; - StructDesc d(BulletList,nested); - if (next->string() == "numeric") - d.structType = NumericList; - else if (next->string() == "value") { - d.structType = ValueList; - } - else if (next->string() != "bullet") - qDebug() << "UNKNOWN LIST TYPE" << next->string(); - structs.push(d); - if (nested || (d.structType != BulletList)) { - if (d.structType == BulletList) - concatenate("<ul>"); - else if (d.structType == NumericList) - concatenate("<ol>"); - else if (d.structType == ValueList) - concatenate("<dl>"); - newLine(); - } - } - break; - case Atom::ListItemNumber: - structs.top().count = next->string().toInt(); - break; - case Atom::ListTagLeft: - { - structs.top().count++; - concatenate("<dt>"); - const Atom* n = next->next(); - if (n->type() == Atom::String) { - qDebug() << "ENUM VALUE" << n->string(); - } - else - qDebug() << "NOT EN ENUM"; - } - break; - case Atom::ListTagRight: - concatenate("</dt>"); - break; - case Atom::ListItemLeft: - { - newLine(); - const StructDesc& d = structs.top(); - if (d.structType == BulletList) { - if (!d.nested) - concatenate("\\arg "); - else - concatenate("<li>"); - } - else if (d.structType == NumericList) - concatenate("<li>"); - else if (d.structType == ValueList) - concatenate("<dd>"); - } - break; - case Atom::ListItemRight: - { - const StructDesc& d = structs.top(); - if (d.structType == BulletList) { - if (d.nested) { - concatenate("</li>"); - newLine(); - } - } - else if (d.structType == NumericList) { - concatenate("</li>"); - newLine(); - } - else if (d.structType == ValueList) { - concatenate("</dd>"); - newLine(); - } - } - break; - case Atom::ListRight: - { - if (!structs.isEmpty()) { - const StructDesc& d = structs.top(); - if (d.nested || (d.structType != BulletList)) { - if (d.structType == BulletList) - concatenate("</ul>"); - else if (d.structType == NumericList) - concatenate("</ol>"); - else if (d.structType == ValueList) - concatenate("</dl>"); - newLine(); - } - structs.pop(); - } - } - break; - case Atom::Nop: - // nothing. - break; - case Atom::ParaLeft: - if (structs.isEmpty()) - newLine(); - break; - case Atom::ParaRight: - { - if (structs.isEmpty()) - newLine(); - else { - const StructDesc& d = structs.top(); - if (d.nested || (d.structType != BulletList)) { - Atom::Type t = next->next()->type(); - if ((t != Atom::ListItemRight) && - (t != Atom::TableItemRight)) - newLine(); - } - else - newLine(); - } - } - break; - case Atom::QuotationLeft: - break; - case Atom::QuotationRight: - break; - case Atom::RawString: - concatenate(next->string()); - break; - case Atom::SectionLeft: - // nothing. - break; - case Atom::SectionRight: - // nothing. - break; - case Atom::SectionHeadingLeft: - next = sectionHeading(next); - break; - case Atom::SectionHeadingRight: - newLine(); - break; - case Atom::SidebarLeft: - break; - case Atom::SidebarRight: - break; - case Atom::SnippetCommand: - newLine(); - concatenate("\\snippet "); - break; - case Atom::SnippetIdentifier: - newText += next->string(); - lineLength += next->string().size(); - newLine(); - break; - case Atom::SnippetLocation: - newText += next->string() + " "; - lineLength += next->string().size() + 1; - break; - case Atom::String: - wrap(next->string()); - break; - case Atom::TableLeft: - { - bool nested = false; - if (structs.isEmpty()) { - const Atom* i = next->next(); - while (i->type() != Atom::TableRight) { - if ((i->type() == Atom::ListLeft) || - (i->type() == Atom::TableLeft)) { - nested = true; - break; - } - i = i->next(); - } - } - else - nested = true; - StructDesc d(Table,nested); - structs.push(d); - if (next->string().isEmpty()) - concatenate("<table>"); - else { - QString attrs = "width=\"" + next->string() + "\""; - attrs += " align=\"center\""; - concatenate("<table " + attrs + ">"); - } - newLine(); - } - break; - case Atom::TableRight: - concatenate("</table>"); - if (!structs.isEmpty()) - structs.pop(); - newLine(); - break; - case Atom::TableHeaderLeft: - concatenate("<tr>"); - if (!structs.isEmpty()) - structs.top().inTableHeader = true; - newLine(); - break; - case Atom::TableHeaderRight: - concatenate("</tr>"); - if (!structs.isEmpty()) - structs.top().inTableHeader = false; - newLine(); - break; - case Atom::TableRowLeft: - if (!structs.isEmpty()) { - structs.top().inTableRow = true; - concatenate("<tr valign=\"top\" class=\""); - if (structs.top().odd) - concatenate("odd\">"); - else - concatenate("even\">"); - structs.top().odd = !structs.top().odd; - } - newLine(); - break; - case Atom::TableRowRight: - concatenate("</tr>"); - if (!structs.isEmpty()) - structs.top().inTableRow = false; - newLine(); - break; - case Atom::TableItemLeft: - if (!structs.isEmpty()) { - structs.top().inTableItem = true; - concatenate("<td>"); - if (structs.top().inTableHeader) - concatenate("<b> "); - } - break; - case Atom::TableItemRight: - if (!structs.isEmpty()) { - structs.top().inTableItem = false; - if (structs.top().inTableHeader) - concatenate(" </b>"); - concatenate("</td>"); - } - newLine(); - break; - case Atom::TableOfContents: - break; - case Atom::Target: - { - QString text = next->string(); - text.remove(ws_rx); - newLine(); - concatenate("\\anchor "); - newText += text; - lineLength += text.size(); - newLine(); - } - break; - case Atom::UnhandledFormat: - unhandled(next); - break; - case Atom::UnknownCommand: - unhandled(next); - break; - default: - //next->dump(); - break; - } - prev = next; - next = next->next(); - } -} - -/*! - - Pass one looks for topic commands and target and section - commands, and maybe other stuff. These are serialized to - text files, which are read back in by pass2(). - */ -void DoxWriter::pass1() -{ - QCommandMap& metaCmdMap = priv->metaCommandMap; - if (!metaCmdMap.isEmpty()) { - int c; - QCommandMap::iterator cmd; - if ((cmd = metaCmdMap.find("enum")) != metaCmdMap.end()) { - commentType = EnumComment; - currentEnum = cmd.value()[0]; - if ((c = currentEnum.lastIndexOf("::")) > 0) { - currentClass = currentEnum.left(c); - currentEnum = currentEnum.right(currentEnum.size()-c-2); - qDebug() << "currentEnum =" << currentEnum; - qDebug() << "currentClass =" << currentClass; - if (enums.contains(currentEnum,currentClass)) { - qWarning() << "DoxWriter::pass1():" - << "Duplicate enum:" - << currentClass << currentEnum; - } - else - enums.insert(currentEnum,currentClass); - } - } - else if ((cmd = metaCmdMap.find("property")) != metaCmdMap.end()) { - commentType = PropertyComment; - currentClass = cmd.value()[0]; - if ((c = currentClass.lastIndexOf("::")) > 0) { - currentProperty = currentClass.right(currentClass.size()-c-2); - currentClass = currentClass.left(c); - qDebug() << "currentProperty =" << currentProperty; - qDebug() << "currentClass =" << currentClass; - if (properties.contains(currentProperty,currentClass)) { - qWarning() << "DoxWriter::pass1():" - << "Duplicate property:" - << currentClass << currentProperty; - } - else - properties.insert(currentProperty,currentClass); - } - } - else if ((cmd = metaCmdMap.find("variable")) != metaCmdMap.end()) { - commentType = VariableComment; - currentClass = cmd.value()[0]; - if ((c = currentClass.lastIndexOf("::")) > 0) { - currentVariable = currentClass.right(currentClass.size()-c-2); - currentClass = currentClass.left(c); - qDebug() << "currentVariable =" << currentVariable; - qDebug() << "currentClass =" << currentClass; - if (variables.contains(currentVariable,currentClass)) { - qWarning() << "DoxWriter::pass1():" - << "Duplicate variable:" - << currentClass << currentVariable; - } - else - variables.insert(currentVariable,currentClass); - } - } - } - - /* - */ - const Atom* next = priv->text.firstAtom(); - while (next != 0) { - switch (next->type()) { - case Atom::SectionHeadingLeft: - { - QString text; - next = next->next(); - while (next) { - if (next->type() == Atom::SectionHeadingRight) - break; - else - text += next->string(); - next = next->next(); - } - //text.remove(ws_rx); - insertAnchor(text); - } - break; - case Atom::Target: - { - QString text = next->string(); - //text.remove(ws_rx); - insertAnchor(text); - } - default: - break; - } - next = next->next(); - } -} - -/*! - Output a parsed, tokenized qdoc comment as a doxygen - comment in diff format for input to the patch command. - */ -void DoxWriter::pass2() -{ - if (!conversionRequired()) { - qDebug() << "NO CONVERSION - FILE:" << priv->start_loc.fileName() - << "START:" << priv->start_loc.lineNo() - << "END:" << priv->end_loc.lineNo() - 1; - return; - } - - /* - Transformation to doxygen required... - */ - newText = "\n/*! \n"; - convertMetaCommands(); - convertText(); - if (newText[newText.size()-1] == ' ') - newText.remove(newText.size()-1,1); - newText += " */\n"; - qDebug() << "CONVERTED COMMENT - FILE:" << priv->start_loc.fileName() - << "START:" << priv->start_loc.lineNo() - << "END:" << priv->end_loc.lineNo() - 1; - qDebug() << newText; -} - -/*! - Unparse the second parameter of a "\l" command. - */ -const Atom* DoxWriter::link(const Atom* atom) -{ - QString first_text = atom->string(); - QString second_text; - const QString* value = 0; - - const Atom* next = atom->next(Atom::FormattingLeft,Atom::LINK_); - if (next) { - next->dump(); - while (1) { - next = next->next(); - next->dump(); - if (next->type() == Atom::FormattingRight) { - if (next->string() == Atom::LINK_) - break; - else { - // ignore it. - } - } - else - second_text += next->string(); - } - int i = first_text.indexOf('#'); - if (i >= 0) - first_text = first_text.right(first_text.size() - i - 1); - //newLine(); - if ((value = getExternalPage(first_text))) { - //qDebug() << "USED AN EXTERNAL PAGE TITLE" << first_text; - QString href = "<a href=\""+*value+"\">"+first_text+"</a>"; - concatenate(href); - } - else if (first_text.startsWith("http:",Qt::CaseInsensitive)) { - if (first_text == second_text) { - concatenate(first_text); - } - else { - QString href = "<a href=\""+first_text+"\">"+second_text+"</a>"; - concatenate(href); - } - } - else if ((value = getPageFile(first_text))) { - //qDebug() << "USED A PAGE TITLE" << first_text; - QStringList parts = (*value).split('.'); - QString ref = "\\ref " + parts[0] + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getGroup(first_text))) { - //qDebug() << "USED A GROUP TITLE" << first_text; - concatenate("\\ref " + *value + " \"" + second_text + "\""); - } - else if ((value = getModule(first_text))) { - //qDebug() << "USED A MODULE TITLE" << first_text; - concatenate("\\ref " + *value + " \"" + second_text + "\""); - } - else if ((value = getExamplePath(first_text))) { - //qDebug() << "USED AN EXAMPLE TITLE" << first_text; - first_text.remove(ws_rx); - QString ref = "\\ref " + first_text + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getFile(first_text))) { - //qDebug() << "USED A FILE TITLE" << first_text; - // I think this command is no longer available. - first_text.remove(ws_rx); - QString ref = "\\ref " + first_text + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getHeaderFile(first_text))) { - //qDebug() << "USED A HEADER FILE TITLE" << first_text; - first_text.remove(ws_rx); - QString ref = "\\ref " + first_text + " \"" + second_text + "\""; - concatenate(ref); - } - else if (isAnchor(first_text)) { - //qDebug() << "USED AN ANCHOR" << first_text; - first_text.remove(ws_rx); - QString ref = "\\ref " + first_text + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getPageTitle(first_text))) { - //qDebug() << "USED AN INVERSE PAGE TITLE" << first_text; - QStringList parts = first_text.split('.'); - QString ref = "\\ref " + parts[0] + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getExampleTitle(first_text))) { - //qDebug() << "USED AN INVERSE EXAMPLE TITLE" << first_text; - QString title = *value; - title.remove(ws_rx); - QString ref = "\\ref " + title + " \"" + second_text + "\""; - concatenate(ref); - } - else if ((value = getGroupTitle(first_text))) { - //qDebug() << "USED AN INVERSE GROUP TITLE" << first_text; - concatenate("\\ref " + first_text + " \"" + second_text + "\""); - } - else if ((value = getModuleTitle(first_text))) { - //qDebug() << "USED AN INVERSE MODULE TITLE" << first_text; - concatenate("\\ref " + first_text + " \"" + second_text + "\""); - } - else if ((value = getFileTitle(first_text))) { - qDebug() << "USED AN INVERSE FILE TITLE" << first_text; - } - else if ((value = getHeaderFileTitle(first_text))) { - qDebug() << "USED AN INVERSE HEADER FILE TITLE" << first_text; - } - else if ((first_text.indexOf("::") >= 0) || - (first_text.indexOf("()") >= 0) || - (first_text[0] == 'Q')) { - //qDebug() << "AUTO-LINKABLE" << first_text; - if (first_text == second_text) - concatenate(first_text); - else { - QString link = first_text + " " + second_text; - concatenate("\\link " + link + "\\endlink"); - } - } - else { - QString link; - QStringList propertyClasses; - QStringList variableClasses; - QStringList enumClasses; - bool p = isProperty(first_text,propertyClasses); - bool v = isVariable(first_text,variableClasses); - bool e = isEnum(first_text,enumClasses); - if (e) { - if (enumClasses.size() == 1) - link = enumClasses[0]; - else if (enumClasses.contains(currentClass)) - link = currentClass; - else { - QString msg = "Unqualified enum name: " + first_text; - QString details = "Classes: " + enumClasses.join(", "); - priv->start_loc.error(msg,details); - } - if (!link.isEmpty()) - qDebug() << "FOUND ENUM" << link << first_text; - } - else if (p && v) { - if (propertyClasses.size() == 1) { - if (variableClasses.size() == 1) { - if (propertyClasses[0] == variableClasses[0]) - link = propertyClasses[0]; - } - } - if (link.isEmpty()) { - if (propertyClasses.contains(currentClass) || - variableClasses.contains(currentClass)) - link = currentClass; - else { - propertyClasses += variableClasses; - QString msg = "Unqualified property or variable name: " - + first_text; - QString details = "Classes: " + - propertyClasses.join(", "); - priv->start_loc.error(msg,details); - } - } - } - else if (p) { - if (propertyClasses.size() == 1) - link = propertyClasses[0]; - else if (propertyClasses.contains(currentClass)) - link = currentClass; - else { - QString msg = "Unqualified property name: " + first_text; - QString details = "Classes: " + propertyClasses.join(", "); - priv->start_loc.error(msg,details); - } - } - else if (v) { - if (variableClasses.size() == 1) - link = variableClasses[0]; - else if (variableClasses.contains(currentClass)) - link = currentClass; - else { - QString msg = "Unqualified variable name: " + first_text; - QString details = "Classes: " + variableClasses.join(", "); - priv->start_loc.error(msg,details); - } - } - else { - qDebug() << "NOT AUTO-LINKABLE" << first_text; - QString s = first_text + " " + second_text; - concatenate("\\link " + s + "\\endlink"); - } - if (!link.isEmpty()) { - link += "::" + first_text + " " + second_text; - concatenate("\\link " + link + "\\endlink"); - } - } - } - else - qDebug() << "LINK with no second parameter!!!!"; - return next? next : atom; -} - -/*! - If the current line length is 0, the current line is - indented according to the context. - */ -void DoxWriter::indentLine() -{ - if (lineLength == 0) { - newText += DOXYGEN_INDENT_STRING; - lineLength = DOXYGEN_INDENT; - if (!structs.isEmpty()) { - for (int i=1; i<structs.size(); ++i) { - newText += DOXYGEN_TAB_STRING; - lineLength += DOXYGEN_TAB_SIZE; - } - } - } -} - -/*! - Concatenates a newline to the doxygen text, increments the - line count, and resets the line length to 0. - */ -void DoxWriter::newLine() -{ - newText += "\n"; - ++lineCount; - lineLength = 0; -} - -static const int maxLineLength = 70; - -/*! - Concatenate the \a text to the doxygen comment currently - under construction and increment the current line length - by the size of the \a text. - - If incrementing the current line length by the \a text size - would make the current line length longer than the maximum - line length, then call newLine() and indentLine() \e before - concatenating the \a text. - */ -void DoxWriter::concatenate(QString text) -{ - if ((lineLength + text.size()) > maxLineLength) - newLine(); - indentLine(); - newText += text; - lineLength += text.size(); -} - -static bool punctuation(QChar c) -{ - switch (c.toAscii()) { - case '.': - case ',': - case ':': - case ';': - case '/': - case '+': - case '-': - case '?': - case '!': - case '\"': - return true; - default: - break; - } - return false; -} - -/*! - Concatenate the \a text string to the doxygen text, doing - line wrapping where necessary. - */ -void DoxWriter::wrap(QString text) -{ - int from = 0; - int to = -1; - - if ((lineLength == 0) || (lineLength >= maxLineLength)) { - if (!text.isEmpty() && (text[0] == ' ')) - text = text.right(text.size() - 1); - } - - indentLine(); - while (text.size()) { - int avail = maxLineLength - lineLength; - from = text.indexOf(' ',from); - if (from >= 0) { - if (from < avail) - to = from++; - else if (from == 1 && punctuation(text[0])) - to = from++; - else { - if (to >= 0) { - newText += text.left(to+1); - lineLength += to + 1; - text = text.right(text.size() - to - 1); - } - else { - newLine(); - indentLine(); - newText += text.left(from+1); - lineLength += from + 1; - text = text.right(text.size() - from - 1); - } - from = 0; - to = -1; - if (text.size() && (lineLength > maxLineLength)) { - newLine(); - indentLine(); - } - } - } - else - break; - } - if (text.size()) { - if (lineLength >= maxLineLength) { - newLine(); - indentLine(); - } - newText += text; - lineLength += text.size(); - } -} - -/*! - This will output something, but it depends on what the - \a atom string and the \a next atom string are. - */ -void DoxWriter::formattingLeft(const Atom* atom, const Atom* next) -{ - if (atom->string() == "parameter") { - concatenate("\\a "); - return; - } - else if (atom->string() == "underline") { - concatenate("<u>"); - return; - } - else if (atom->string() == "superscript") { - concatenate("<sup>"); - return; - } - else if (atom->string() == "subscript") { - concatenate("<sub>"); - return; - } - int ws = -1; - if (next) - ws = next->string().indexOf(ws_rx); - if (atom->string() == "bold") { - if (ws < 0) - concatenate("\\b "); - else - concatenate("<b>"); - } - else if (atom->string() == "italic") { - if (ws < 0) - concatenate("\\e "); - else - concatenate("<i>"); - } - else if (atom->string() == "teletype") { - if (ws < 0) - concatenate("\\c "); - else - concatenate("<tt>"); - } - else - qDebug() << "UNHANDLED FormattingLeft: " << atom->string(); -} - -/*! - This will output something, but it depends on what the - \a atom string and the \a prev atom string are. - */ -void DoxWriter::formattingRight(const Atom* atom, const Atom* prev) -{ - if (atom->string() == "parameter") - return; - else if (atom->string() == "underline") { - concatenate("</u>"); - return; - } - else if (atom->string() == "superscript") { - concatenate("</sup>"); - return; - } - else if (atom->string() == "subscript") { - concatenate("</sub>"); - return; - } - int ws = -1; - if (prev) - ws = prev->string().indexOf(ws_rx); - if (ws < 0) - return; - if (atom->string() == "bold") - concatenate("</b>"); - else if (atom->string() == "italic") - concatenate("</i>"); - else if (atom->string() == "teletype") - concatenate("</tt>"); - else - qDebug() << "UNHANDLED FormattingRight: " << atom->string(); -} - -/*! - Output a \c or a <tt>...</tt>. - */ -void DoxWriter::tt(const Atom* atom) -{ - if (atom->string().indexOf(ws_rx) < 0) { - concatenate("\\c "); - concatenate(atom->string()); - } - else { - concatenate("<tt>"); - concatenate(atom->string()); - concatenate("</tt>"); - } -} - -/*! - */ -void DoxWriter::formatIf(const Atom* atom) -{ - if (atom->string() == "HTML") { - newLine(); - concatenate("\\htmlonly"); - newLine(); - } -} - -/*! - */ -void DoxWriter::formatEndif() -{ - newLine(); - concatenate("\\endhtmlonly"); - newLine(); -} - -/*! - */ -void DoxWriter::formatElse() -{ - // nothing. -} - -/*! - Pass 1: Construct a section identifier and insert it into - the anchor set. - - Pass 2: Convert section1, section2, and section3 commands - to section, subsection, and subsubsection respectively. - Warn if a section command higher than 3 is seen. - */ -const Atom* DoxWriter::sectionHeading(const Atom* atom) -{ - QString heading_level = atom->string(); - QString heading_text; - const Atom* next = atom->next(); - while (next) { - next->dump(); - if (next->type() == Atom::SectionHeadingRight) { - if (next->string() == heading_level) - break; - else { - qDebug() << "WRONG SectionHeading number!!!!"; - } - } - else - heading_text += next->string(); - next = next->next(); - } - - QString heading_identifier = heading_text; - heading_identifier.remove(ws_rx); - - newLine(); - if (heading_level == "1") - heading_level = "\\section "; - else if (heading_level == "2") - heading_level = "\\subsection "; - else if (heading_level == "3") - heading_level = "\\subsubsection "; - else if (heading_level == "4") { - heading_level = "\\subsubsection "; - qDebug() << "WARNING section4 converted to \\subsubsection"; - } - else { - heading_level = "\\subsubsection "; - qDebug() << "WARNING section5 converted to \\subsubsection"; - } - concatenate(heading_level); - newText += heading_identifier + " "; - lineLength += heading_identifier.size() + 1; - newText += heading_text; - lineLength += heading_text.size(); - newLine(); - return next? next : atom; -} - -/*! - Report an unhandled atom. - */ -void DoxWriter::unhandled(const Atom* atom) -{ - qDebug() << "UNHANDLED ATOM"; - atom->dump(); -} - -/*! - Output a code/endcode block. - */ -void DoxWriter::code(const Atom* atom) -{ - newLine(); - concatenate("\\code"); - writeCode(atom->string()); - concatenate("\\endcode"); - newLine(); -} - -/*! - Output a code/endcode block depending on the - CodeQuote Command and CodeQuoteArgument parameters. - */ -const Atom* DoxWriter::codeQuoteCommand(const Atom* atom) -{ - QString command = atom->string(); - atom = atom->next(); - concatenate("\\code"); - if (command == "codeline") { - newLine(); - concatenate(atom->string()); - newLine(); - } - else if (command == "dots") { - newLine(); - concatenate(atom->string()); - newLine(); - } - else { - writeCode(atom->string()); - } - concatenate("\\endcode"); - return atom; -} - -/*! - Appends a block of code to the comment. - */ -void DoxWriter::writeCode(QString text) -{ - int cr_count = text.count('\n') - 1; - if (cr_count >= 0) { - int last_cr = text.lastIndexOf('\n'); - newText += text.left(last_cr); - lineCount += cr_count; - } - else - newText += text; - newLine(); -} - -/*! - Inserts \a text into the anchor set. This function is called - during doxygen pass 1. - */ -void DoxWriter::insertAnchor(const QString& text) -{ - anchors.insert(text); -} - -/*! - Returns true if \a text identifies an anchor, section, - subsection, subsubsection, or page. - */ -bool DoxWriter::isAnchor(const QString& text) -{ - return anchors.contains(text); -} - -/*! - Write the set of anchors to a file, one per line. - */ -void DoxWriter::writeAnchors() -{ - QFile file("anchors.txt"); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning("Unable to open anchors.txt for writing."); - return; - } - - QTextStream out(&file); - QSet<QString>::const_iterator i = anchors.constBegin(); - while (i != anchors.constEnd()) { - out << *i << "\n"; - ++i; - } - file.close(); -} - -/*! - Read the set of anchors from the anchors file, one per line, - and insert each one into the anchor set. - */ -void DoxWriter::readAnchors() -{ - QFile file("anchors.txt"); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning("Unable to open anchors.txt for reading."); - return; - } - - QTextStream in(&file); - while (!in.atEnd()) { - QString line = in.readLine(); - anchors.insert(line); - } - file.close(); -#if 0 - QSet<QString>::const_iterator i = anchors.constBegin(); - while (i != anchors.constEnd()) { - qDebug() << *i; - ++i; - } -#endif -} - -/*! - Inserts \a title into one of the title maps. \a title is - mapped to the \a node name. This function is called during - doxygen pass 1. - */ -void DoxWriter::insertTitle(FakeNode* node, const QString& title) -{ - switch (node->subType()) { - case FakeNode::Example: - if (exampleTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate example title:" - << title; - } - else { - exampleTitles[title] = node->name(); - exampleTitlesInverse[node->name()] = title; - } - break; - case FakeNode::HeaderFile: - if (headerFileTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate header file title:" - << title; - } - else { - headerFileTitles[title] = node->name(); - headerFileTitlesInverse[node->name()] = title; - } - break; - case FakeNode::File: - if (fileTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate file title:" - << title; - } - else { - fileTitles[title] = node->name(); - fileTitlesInverse[node->name()] = title; - } - break; - case FakeNode::Group: - if (groupTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate group title:" - << title; - } - else { - groupTitles[title] = node->name(); - groupTitlesInverse[node->name()] = title; - } - break; - case FakeNode::Module: - if (moduleTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate module title:" - << title; - } - else { - moduleTitles[title] = node->name(); - moduleTitlesInverse[node->name()] = title; - } - break; - case FakeNode::Page: - if (pageTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate page title:" - << title; - } - else { - pageTitles[title] = node->name(); - pageTitlesInverse[node->name()] = title; - } - break; - case FakeNode::ExternalPage: - if (externalPageTitles.contains(title)) { - qWarning() << "DoxWriter::insertTitle():" - << "Duplicate external page title:" - << title; - } - else { - externalPageTitles[title] = node->name(); - externalPageTitlesInverse[node->name()] = title; - } - break; - default: - break; - } -} - -/*! - */ -const QString* DoxWriter::getPageFile(const QString& title) -{ - QStringMapEntry entry = pageTitles.find(title); - return (entry == pageTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getExamplePath(const QString& title) -{ - QStringMapEntry entry = exampleTitles.find(title); - return (entry == exampleTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getFile(const QString& title) -{ - QStringMapEntry entry = fileTitles.find(title); - return (entry == fileTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getHeaderFile(const QString& title) -{ - QStringMapEntry entry = headerFileTitles.find(title); - return (entry == headerFileTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getGroup(const QString& title) -{ - QStringMapEntry entry = groupTitles.find(title); - return (entry == groupTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getModule(const QString& title) -{ - QStringMapEntry entry = moduleTitles.find(title); - return (entry == moduleTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getExternalPage(const QString& title) -{ - QStringMapEntry entry = externalPageTitles.find(title); - return (entry == externalPageTitles.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getPageTitle(const QString& text) -{ - QStringMapEntry entry = pageTitlesInverse.find(text); - return (entry == pageTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getExampleTitle(const QString& text) -{ - QStringMapEntry entry = exampleTitlesInverse.find(text); - return (entry == exampleTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getFileTitle(const QString& text) -{ - QStringMapEntry entry = fileTitlesInverse.find(text); - return (entry == fileTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getHeaderFileTitle(const QString& text) -{ - QStringMapEntry entry = headerFileTitlesInverse.find(text); - return (entry == headerFileTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getGroupTitle(const QString& text) -{ - QStringMapEntry entry = groupTitlesInverse.find(text); - return (entry == groupTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getModuleTitle(const QString& text) -{ - QStringMapEntry entry = moduleTitlesInverse.find(text); - return (entry == moduleTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - */ -const QString* DoxWriter::getExternalPageTitle(const QString& text) -{ - QStringMapEntry entry = externalPageTitlesInverse.find(text); - return (entry == externalPageTitlesInverse.end()) ? 0 : &entry.value(); -} - -/*! - Serialize \a map to file \a name. - */ -void DoxWriter::writeMap(const QStringMap& map, const QString& name) -{ - - QFile file(name); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning() << "Unable to open" << name << "for writing."; - return; - } - - QTextStream out(&file); - QStringMap::const_iterator i = map.constBegin(); - while (i != map.constEnd()) { - out << i.key() << "\n"; - out << i.value() << "\n"; - ++i; - } - file.close(); -} - -/*! - Read file \a name into the \a map. - */ -void DoxWriter::readMap(QStringMap& map, QStringMap& inverseMap, const QString& name) -{ - QFile file(name); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning() << "Unable to open" << name << "for reading."; - return; - } - - QTextStream in(&file); - while (!in.atEnd()) { - QString title = in.readLine(); - QString value = in.readLine(); - map[title] = value; - inverseMap[value] = title; - } - file.close(); -} - -/*! - Write the sets of titles to text files, one per line. - */ -void DoxWriter::writeTitles() -{ - if (!pageTitles.isEmpty()) - writeMap(pageTitles,"pagetitles.txt"); - if (!fileTitles.isEmpty()) - writeMap(fileTitles,"filetitles.txt"); - if (!headerFileTitles.isEmpty()) - writeMap(headerFileTitles,"headerfiletitles.txt"); - if (!exampleTitles.isEmpty()) - writeMap(exampleTitles,"exampletitles.txt"); - if (!moduleTitles.isEmpty()) - writeMap(moduleTitles,"moduletitles.txt"); - if (!groupTitles.isEmpty()) - writeMap(groupTitles,"grouptitles.txt"); - if (!externalPageTitles.isEmpty()) - writeMap(externalPageTitles,"externalpagetitles.txt"); -} - -/*! - Read the sets of titles from the titles files, one per line, - and insert each one into the appropriate title set. - */ -void DoxWriter::readTitles() -{ - readMap(pageTitles,pageTitlesInverse,"pagetitles.txt"); - readMap(fileTitles,fileTitlesInverse,"filetitles.txt"); - readMap(headerFileTitles,headerFileTitlesInverse,"headerfiletitles.txt"); - readMap(exampleTitles,exampleTitlesInverse,"exampletitles.txt"); - readMap(moduleTitles,moduleTitlesInverse,"moduletitles.txt"); - readMap(groupTitles,groupTitlesInverse,"grouptitles.txt"); - readMap(externalPageTitles, - externalPageTitlesInverse, - "externalpagetitles.txt"); -} - -/*! - Serialize \a map to file \a name. - */ -void DoxWriter::writeMultiMap(const QStringMultiMap& map, const QString& name) -{ - - QFile file(name); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning() << "Unable to open" << name << "for writing."; - return; - } - - QTextStream out(&file); - QStringMultiMap::const_iterator i = map.constBegin(); - while (i != map.constEnd()) { - out << i.key() << "\n"; - out << i.value() << "\n"; - ++i; - } - file.close(); -} - -/*! - Write the4 property names and variable names to text files. - */ -void DoxWriter::writeMembers() -{ - if (!variables.isEmpty()) - writeMultiMap(variables,"variables.txt"); - if (!properties.isEmpty()) - writeMultiMap(properties,"properties.txt"); - if (!enums.isEmpty()) - writeMultiMap(enums,"enums.txt"); -} - -/*! - Read file \a name into the \a map. - */ -void DoxWriter::readMultiMap(QStringMultiMap& map, const QString& name) -{ - QFile file(name); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qWarning() << "Unable to open" << name << "for reading."; - return; - } - - QTextStream in(&file); - while (!in.atEnd()) { - QString member = in.readLine(); - QString className = in.readLine(); - map.insert(member,className); - } - file.close(); -} - -/*! - Read the property names and variable names from the test files. - */ -void DoxWriter::readMembers() -{ - readMultiMap(variables,"variables.txt"); - readMultiMap(properties,"properties.txt"); - readMultiMap(enums,"enums.txt"); -} - -/*! - Return true if \a name is a property. Loads \a classes with - the names of all the classes in which \a name is a property. - */ -bool DoxWriter::isProperty(const QString& name, QStringList& classes) -{ - classes = properties.values(name); - return !classes.isEmpty(); -} - -/*! - Return true if \a name is a variable. Loads \a classes with - the names of all the classes in which \a name is a variable. - */ -bool DoxWriter::isVariable(const QString& name, QStringList& classes) -{ - classes = variables.values(name); - return !classes.isEmpty(); -} - -/*! - Return true if \a name is an enum type. Loads \a classes with - the names of all the classes in which \a name is an enum type. - */ -bool DoxWriter::isEnum(const QString& name, QStringList& classes) -{ - classes = enums.values(name); - return !classes.isEmpty(); -} -#endif - QT_END_NAMESPACE diff --git a/tools/qdoc3/doc.h b/tools/qdoc3/doc.h index dbba6e4..d58167f 100644 --- a/tools/qdoc3/doc.h +++ b/tools/qdoc3/doc.h @@ -133,183 +133,6 @@ class Doc DocPrivate *priv; }; -#ifdef QDOC2DOX - -class DoxWriter -{ - public: - DoxWriter(const QString& source, DocPrivate* docPrivate) - : commentType(OtherComment), - lineLength(0), - lineCount(0), - priv(docPrivate), - oldText(source) {} - ~DoxWriter() {} - - void pass1(); - void pass2(); - - static void setDoxPass(int pass); - static bool isDoxPass(int pass); - static bool isDoxPass(); - static void insertTitle(FakeNode* node, const QString& title); - static void writeTitles(); - static void readTitles(); - static void writeMembers(); - static void readMembers(); - static void writeAnchors(); - static void readAnchors(); - - private: - void indentLine(); - void newLine(); - void concatenate(QString text); - void wrap(QString text); - bool conversionRequired() const; - void convertMetaCommands(); - void convertText(); - const Atom* link(const Atom* atom); - void formattingLeft(const Atom* atom, const Atom* next); - void formattingRight(const Atom* atom, const Atom* prev); - void tt(const Atom* atom); - void formatIf(const Atom* atom); - void formatEndif(); - void formatElse(); - const Atom* sectionHeading(const Atom* atom); - void unhandled(const Atom* atom); - void code(const Atom* atom); - const Atom* codeQuoteCommand(const Atom* atom); - void writeCode(QString text); - void writeCommand(QCommandMap::const_iterator cmd); - - static void insertAnchor(const QString& text); - static bool isAnchor(const QString& text); - - static const QString* getPageFile(const QString& title); - static const QString* getFile(const QString& title); - static const QString* getExamplePath(const QString& title); - static const QString* getHeaderFile(const QString& title); - static const QString* getGroup(const QString& title); - static const QString* getModule(const QString& title); - static const QString* getExternalPage(const QString& title); - static const QString* getPageTitle(const QString& text); - static const QString* getFileTitle(const QString& text); - static const QString* getExampleTitle(const QString& text); - static const QString* getHeaderFileTitle(const QString& text); - static const QString* getGroupTitle(const QString& text); - static const QString* getModuleTitle(const QString& text); - static const QString* getExternalPageTitle(const QString& text); - - static bool isProperty(const QString& title, QStringList& classes); - static bool isVariable(const QString& title, QStringList& classes); - static bool isEnum(const QString& title, QStringList& classes); - - private: - static void writeMap(const QStringMap& map, const QString& name); - static void readMap(QStringMap& map, - QStringMap& inverseMap, - const QString& name); - static void writeMultiMap(const QStringMultiMap& map, const QString& name); - static void readMultiMap(QStringMultiMap& map, const QString& name); - - public: // VS 6, SunCC need this to be public - enum StructType { BulletList, NumericList, ValueList, Table }; - private: - struct StructDesc { - StructType structType; - int count; - bool nested; - bool inTableHeader; - bool inTableRow; - bool inTableItem; - bool odd; - - StructDesc() - : structType(BulletList), - count(0), - nested(false), - inTableHeader(false), - inTableRow(false), - inTableItem(false), - odd(true) { } - - StructDesc(StructType t, bool n) - : structType(t), - count(0), - nested(n), - inTableHeader(false), - inTableRow(false), - inTableItem(false), - odd(true) { } - }; - - typedef QStack<StructDesc> StructStack; - - enum CommentType { - ClassComment, - EnumComment, - ExampleComment, - FnComment, - GroupComment, - HeaderFileComment, - MacroComment, - ModuleComment, - PageComment, - PropertyComment, - ServiceComment, - TypedefComment, - VariableComment, - OtherComment - }; - - private: - CommentType commentType; - int lineLength; - int lineCount; - DocPrivate* priv; - QString oldText; - QString newText; - StructStack structs; - - QString currentPage; - QString currentFn; - QString currentTitle; - QString currentEnum; - QString currentProperty; - QString currentVariable; - QString currentExample; - QString currentGroup; - QString currentModule; - QString currentMacro; - QString currentService; - QString currentTypedef; - QString currentHeaderFile; - static QString currentClass; - - static int doxPass; - static QSet<QString> anchors; - static QStringMap exampleTitles; - static QStringMap headerFileTitles; - static QStringMap fileTitles; - static QStringMap groupTitles; - static QStringMap moduleTitles; - static QStringMap pageTitles; - static QStringMap externalPageTitles; - static QStringMap exampleTitlesInverse; - static QStringMap headerFileTitlesInverse; - static QStringMap fileTitlesInverse; - static QStringMap groupTitlesInverse; - static QStringMap moduleTitlesInverse; - static QStringMap pageTitlesInverse; - static QStringMap externalPageTitlesInverse; - - static QStringMultiMap variables; - static QStringMultiMap properties; - static QStringMultiMap enums; -}; - -#endif - QT_END_NAMESPACE #endif diff --git a/tools/qdoc3/generator.cpp b/tools/qdoc3/generator.cpp index 3652071..e92f53b 100644 --- a/tools/qdoc3/generator.cpp +++ b/tools/qdoc3/generator.cpp @@ -42,9 +42,9 @@ /* generator.cpp */ - +#include <QtCore> #include <qdir.h> - +#include <qdebug.h> #include "codemarker.h" #include "config.h" #include "doc.h" @@ -68,14 +68,20 @@ QStringList Generator::imageDirs; QString Generator::outDir; QString Generator::project; -static Text stockLink(const QString &target) +static void singularPlural(Text& text, const NodeList& nodes) { - return Text() << Atom(Atom::Link, target) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << target << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + if (nodes.count() == 1) + text << " is"; + else + text << " are"; } Generator::Generator() - : amp("&"), lt("<"), gt(">"), quot("""), tag("</?@[^>]*>") + : amp("&"), + lt("<"), + gt(">"), + quot("""), + tag("</?@[^>]*>") { generators.prepend(this); } @@ -123,7 +129,8 @@ void Generator::initialize(const Config &config) QSet<QString> formats = config.subVars(imagesDotFileExtensions); QSet<QString>::ConstIterator f = formats.begin(); while (f != formats.end()) { - imgFileExts[*f] = config.getStringList(imagesDotFileExtensions + Config::dot + *f); + imgFileExts[*f] = config.getStringList(imagesDotFileExtensions + + Config::dot + *f); ++f; } @@ -131,16 +138,22 @@ void Generator::initialize(const Config &config) while (g != generators.end()) { if (outputFormats.contains((*g)->format())) { (*g)->initializeGenerator(config); - QStringList extraImages = config.getStringList(CONFIG_EXTRAIMAGES + Config::dot - + (*g)->format()); + QStringList extraImages = config.getStringList(CONFIG_EXTRAIMAGES + + Config::dot + + (*g)->format()); QStringList::ConstIterator e = extraImages.begin(); while (e != extraImages.end()) { QString userFriendlyFilePath; - QString filePath = Config::findFile(config.lastLocation(), imageFiles, imageDirs, *e, - imgFileExts[(*g)->format()], userFriendlyFilePath); + QString filePath = Config::findFile(config.lastLocation(), + imageFiles, imageDirs, *e, + imgFileExts[(*g)->format()], + userFriendlyFilePath); if (!filePath.isEmpty()) - Config::copyFile(config.lastLocation(), filePath, userFriendlyFilePath, - (*g)->outputDir() + "/images"); + Config::copyFile(config.lastLocation(), + filePath, + userFriendlyFilePath, + (*g)->outputDir() + + "/images"); ++e; } } @@ -156,20 +169,23 @@ void Generator::initialize(const Config &config) QSet<QString> formats = config.subVars(formattingDotName); QSet<QString>::ConstIterator f = formats.begin(); while (f != formats.end()) { - QString def = config.getString(formattingDotName + Config::dot + - *f); + QString def = config.getString(formattingDotName + + Config::dot + *f); if (!def.isEmpty()) { int numParams = Config::numParams(def); int numOccs = def.count("\1"); if (numParams != 1) { - config.lastLocation().warning(tr("Formatting '%1' must have exactly one" - " parameter (found %2)") - .arg(*n).arg(numParams)); + config.lastLocation().warning(tr("Formatting '%1' must " + "have exactly one " + "parameter (found %2)") + .arg(*n).arg(numParams)); } else if (numOccs > 1) { - config.lastLocation().fatal(tr("Formatting '%1' must contain exactly one" - " occurrence of '\\1' (found %2)") + config.lastLocation().fatal(tr("Formatting '%1' must " + "contain exactly one " + "occurrence of '\\1' " + "(found %2)") .arg(*n).arg(numOccs)); } else { @@ -241,7 +257,7 @@ void Generator::generateFakeNode(const FakeNode * /* fake */, { } -void Generator::generateText(const Text& text, +bool Generator::generateText(const Text& text, const Node *relative, CodeMarker *marker) { @@ -254,31 +270,40 @@ void Generator::generateText(const Text& text, true, numAtoms); endText(relative, marker); + return true; } + return false; } #ifdef QDOC_QML -void Generator::generateQmlText(const Text& text, +/*! + Extract sections of markup text surrounded by \e qmltext + and \e endqmltext and output them. + */ +bool Generator::generateQmlText(const Text& text, const Node *relative, - CodeMarker *marker) + CodeMarker *marker, + const QString& qmlName) { - if (text.firstAtom() != 0) { - startText(relative, marker); - const Atom *atom = text.firstAtom(); - while (atom) { - if (atom->type() != Atom::QmlText) - atom = atom->next(); - else { - atom = atom->next(); - while (atom && (atom->type() != Atom::EndQmlText)) { - int n = 1 + generateAtom(atom, relative, marker); - while (n-- > 0) - atom = atom->next(); - } + const Atom* atom = text.firstAtom(); + if (atom == 0) + return false; + + startText(relative, marker); + while (atom) { + if (atom->type() != Atom::QmlText) + atom = atom->next(); + else { + atom = atom->next(); + while (atom && (atom->type() != Atom::EndQmlText)) { + int n = 1 + generateAtom(atom, relative, marker); + while (n-- > 0) + atom = atom->next(); } } - endText(relative, marker); } + endText(relative, marker); + return true; } #endif @@ -295,19 +320,27 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) } else if (node->type() == Node::Fake) { const FakeNode *fake = static_cast<const FakeNode *>(node); - if (fake->subType() == FakeNode::Example) + if (fake->subType() == Node::Example) generateExampleFiles(fake, marker); - else if (fake->subType() == FakeNode::File) + else if (fake->subType() == Node::File) quiet = true; } if (node->doc().isEmpty()) { - if (!quiet) // ### might be unnecessary + if (!quiet && !node->isReimp()) // ### might be unnecessary node->location().warning(tr("No documentation for '%1'") .arg(marker->plainFullName(node))); } else { - generateText(node->doc().body(), node, marker); + if (node->type() == Node::Function) { + const FunctionNode *func = static_cast<const FunctionNode *>(node); + if (func->reimplementedFrom() != 0) + generateReimplementedFrom(func, marker); + } + + if (!generateText(node->doc().body(), node, marker)) + if (node->isReimp()) + return; if (node->type() == Node::Enum) { const EnumNode *enume = (const EnumNode *) node; @@ -345,7 +378,6 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) } else if (node->type() == Node::Function) { const FunctionNode *func = static_cast<const FunctionNode *>(node); - QSet<QString> definedParams; QList<Parameter>::ConstIterator p = func->parameters().begin(); while (p != func->parameters().end()) { @@ -382,7 +414,8 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) FunctionNode *primaryFunc = func->parent()->findFunctionNode(func->name()); if (primaryFunc) { - foreach (const Parameter ¶m, primaryFunc->parameters()) { + foreach (const Parameter ¶m, + primaryFunc->parameters()) { if (param.name() == *a) { needWarning = false; break; @@ -390,9 +423,10 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) } } } - if (needWarning) + if (needWarning && !func->isReimp()) node->doc().location().warning( - tr("Undocumented parameter '%1' in %2").arg(*a).arg(marker->plainFullName(node))); + tr("Undocumented parameter '%1' in %2") + .arg(*a).arg(marker->plainFullName(node))); } ++a; } @@ -404,15 +438,17 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) if (!body.contains("return", Qt::CaseInsensitive)) node->doc().location().warning(tr("Undocumented return value")); } - +#if 0 + // Now we put this at the top, before the other text. if (func->reimplementedFrom() != 0) generateReimplementedFrom(func, marker); +#endif } } if (node->type() == Node::Fake) { const FakeNode *fake = static_cast<const FakeNode *>(node); - if (fake->subType() == FakeNode::File) { + if (fake->subType() == Node::File) { Text text; Quoter quoter; Doc::quoteFromFile(fake->doc().location(), quoter, fake->name()); @@ -459,7 +495,8 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker) if ((*r).access == Node::Protected) { text << " (protected)"; - } else if ((*r).access == Node::Private) { + } + else if ((*r).access == Node::Private) { text << " (private)"; } text << separator(index++, classe->baseClasses().count()); @@ -470,6 +507,15 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker) } } +#ifdef QDOC_QML +/*! + */ +void Generator::generateQmlInherits(const QmlClassNode* , CodeMarker* ) +{ + // stub. +} +#endif + void Generator::generateInheritedBy(const ClassNode *classe, CodeMarker *marker) { @@ -497,18 +543,21 @@ void Generator::generateExampleFiles(const FakeNode *fake, CodeMarker *marker) QString exampleFile = child->name(); openedList.next(); text << Atom(Atom::ListItemNumber, openedList.numberString()) - << Atom(Atom::ListItemLeft, openedList.styleString()) << Atom::ParaLeft + << Atom(Atom::ListItemLeft, openedList.styleString()) + << Atom::ParaLeft << Atom(Atom::Link, exampleFile) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << exampleFile << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom::ParaRight << Atom(Atom::ListItemRight, openedList.styleString()); + << Atom::ParaRight + << Atom(Atom::ListItemRight, openedList.styleString()); } text << Atom(Atom::ListRight, openedList.styleString()); generateText(text, fake, marker); } -void Generator::generateModuleWarning(const ClassNode *classe, CodeMarker *marker) +void Generator::generateModuleWarning(const ClassNode *classe, + CodeMarker *marker) { QString module = classe->moduleName(); if (!module.isEmpty()) { @@ -529,8 +578,10 @@ void Generator::generateModuleWarning(const ClassNode *classe, CodeMarker *marke << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << Atom::ParaRight; } - else if (module == "Qt3Support" && Tokenizer::isTrue("defined(opensourceedition)")) { - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + else if (module == "Qt3Support" && + Tokenizer::isTrue("defined(opensourceedition)")) { + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "Note to Qt Desktop Light Edition users:" << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " This class is only available in the " @@ -558,10 +609,12 @@ QString Generator::indent(int level, const QString& markedCode) if (markedCode.at(i - 1) == QLatin1Char('>')) break; } - } else { + } + else { if (markedCode.at(i) == QLatin1Char('\n')) { column = 0; - } else { + } + else { if (column == 0) { for (int j = 0; j < level; j++) t += QLatin1Char(' '); @@ -630,7 +683,7 @@ void Generator::setImageFileExtensions(const QStringList& extensions) void Generator::unknownAtom(const Atom *atom) { Location::internalError(tr("unknown atom type '%1' in %2 generator") - .arg(atom->typeString()).arg(format())); + .arg(atom->typeString()).arg(format())); } bool Generator::matchAhead(const Atom *atom, Atom::Type expectedAtomType) @@ -659,7 +712,8 @@ void Generator::supplementAlsoList(const Node *node, QList<Text> &alsoList) alternateFunc = func->parent()->findFunctionNode(alternateName); } } - } else if (!func->name().isEmpty()) { + } + else if (!func->name().isEmpty()) { alternateName = "set"; alternateName += func->name()[0].toUpper(); alternateName += func->name().mid(1); @@ -715,9 +769,13 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker) case Node::Main: break; case Node::Preliminary: - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This " - << typeString(node) << " is under development and is subject to change." - << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << Atom::ParaRight; + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "This " + << typeString(node) + << " is under development and is subject to change." + << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) + << Atom::ParaRight; break; case Node::Deprecated: text << Atom::ParaLeft; @@ -735,16 +793,21 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker) text << "This " << typeString(node) << " is obsolete."; if (node->isInnerNode()) text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD); - text << " It is provided to keep old source code working. We strongly advise against " + text << " It is provided to keep old source code working. " + << "We strongly advise against " << "using it in new code." << Atom::ParaRight; break; case Node::Compat: // reimplemented in HtmlGenerator subclass if (node->isInnerNode()) { - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This " - << typeString(node) << " is part of the Qt 3 compatibility layer." + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "This " + << typeString(node) + << " is part of the Qt 3 compatibility layer." << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) - << " It is provided to keep old source code working. We strongly advise against " + << " It is provided to keep old source code working. " + << "We strongly advise against " << "using it in new code. See " << Atom(Atom::AutoLink, "Porting to Qt 4") << " for more information." @@ -762,71 +825,147 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker) { Text text; Text theStockLink; - Node::ThreadSafeness parent = node->parent()->inheritedThreadSafeness(); + Node::ThreadSafeness threadSafeness = node->threadSafeness(); - switch (node->threadSafeness()) { + Text rlink; + rlink << Atom(Atom::Link,"reentrant") + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << "reentrant" + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + + Text tlink; + tlink << Atom(Atom::Link,"thread-safe") + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << "thread-safe" + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + + switch (threadSafeness) { case Node::UnspecifiedSafeness: break; case Node::NonReentrant: - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "Warning:" - << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " This " - << typeString(node) << " is not " << stockLink("reentrant") << "." << Atom::ParaRight; + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) + << "Warning:" + << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD) + << " This " + << typeString(node) + << " is not " + << rlink + << "." + << Atom::ParaRight; break; case Node::Reentrant: case Node::ThreadSafe: - text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD); - if (parent == Node::ThreadSafe) { - text << "Warning:"; - } else { - text << "Note:"; - } - text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " "; - - if (node->threadSafeness() == Node::ThreadSafe) - theStockLink = stockLink("thread-safe"); - else - theStockLink = stockLink("reentrant"); + text << Atom::ParaLeft + << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) + << "Note:" + << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD) + << " "; if (node->isInnerNode()) { - const InnerNode *innerNode = static_cast<const InnerNode *>(node); - text << "All the functions in this " << typeString(node) << " are " - << theStockLink; - - NodeList except; + const InnerNode* innerNode = static_cast<const InnerNode*>(node); + text << "All functions in this " + << typeString(node) + << " are "; + if (threadSafeness == Node::ThreadSafe) + text << tlink; + else + text << rlink; + + bool exceptions = false; + NodeList reentrant; + NodeList threadsafe; + NodeList nonreentrant; NodeList::ConstIterator c = innerNode->childNodes().begin(); while (c != innerNode->childNodes().end()) { - if ((*c)->threadSafeness() != Node::UnspecifiedSafeness) - except.append(*c); + switch ((*c)->threadSafeness()) { + case Node::Reentrant: + reentrant.append(*c); + if (threadSafeness == Node::ThreadSafe) + exceptions = true; + break; + case Node::ThreadSafe: + threadsafe.append(*c); + if (threadSafeness == Node::Reentrant) + exceptions = true; + break; + case Node::NonReentrant: + nonreentrant.append(*c); + exceptions = true; + break; + default: + break; + } ++c; } - if (except.isEmpty()) { + if (!exceptions) text << "."; + else if (threadSafeness == Node::Reentrant) { + if (nonreentrant.isEmpty()) { + if (!threadsafe.isEmpty()) { + text << ", but "; + appendFullNames(text,threadsafe,innerNode,marker); + singularPlural(text,threadsafe); + text << " also " << tlink << "."; + } + else + text << "."; + } + else { + text << ", except for "; + appendFullNames(text,nonreentrant,innerNode,marker); + text << ", which"; + singularPlural(text,nonreentrant); + text << " nonreentrant."; + if (!threadsafe.isEmpty()) { + text << " "; + appendFullNames(text,threadsafe,innerNode,marker); + singularPlural(text,threadsafe); + text << " " << tlink << "."; + } + } } - else { - text << ", except "; - - NodeList::ConstIterator e = except.begin(); - int index = 0; - while (e != except.end()) { - appendFullName(text, *e, innerNode, marker); - text << separator(index++, except.count()); - ++e; + else { // thread-safe + if (!nonreentrant.isEmpty() || !reentrant.isEmpty()) { + text << ", except for "; + if (!reentrant.isEmpty()) { + appendFullNames(text,reentrant,innerNode,marker); + text << ", which"; + singularPlural(text,reentrant); + text << " only " << rlink; + if (!nonreentrant.isEmpty()) + text << ", and "; + } + if (!nonreentrant.isEmpty()) { + appendFullNames(text,nonreentrant,innerNode,marker); + text << ", which"; + singularPlural(text,nonreentrant); + text << " nonreentrant."; + } + text << "."; } } } else { - text << "This " << typeString(node) << " is " << theStockLink << "."; + text << "This " << typeString(node) << " is "; + if (threadSafeness == Node::ThreadSafe) + text << tlink; + else + text << rlink; + text << "."; } text << Atom::ParaRight; } - generateText(text, node, marker); + generateText(text,node,marker); } void Generator::generateSince(const Node *node, CodeMarker *marker) { if (!node->since().isEmpty()) { Text text; - text << Atom::ParaLeft << "This " << typeString(node) + text << Atom::ParaLeft + << "This " + << typeString(node) << " was introduced in "; if (project.isEmpty()) text << "version"; @@ -856,10 +995,12 @@ void Generator::generateReimplementedFrom(const FunctionNode *func, { if (func->reimplementedFrom() != 0) { const FunctionNode *from = func->reimplementedFrom(); - if (from->access() != Node::Private && from->parent()->access() != Node::Private) { + if (from->access() != Node::Private && + from->parent()->access() != Node::Private) { Text text; text << Atom::ParaLeft << "Reimplemented from "; - appendFullName(text, from->parent(), func, marker, from); + QString fullName = from->parent()->name() + "::" + from->name() + "()"; + appendFullName(text, from->parent(), fullName, from); text << "." << Atom::ParaRight; generateText(text, func, marker); } @@ -897,8 +1038,8 @@ const Atom *Generator::generateAtomList(const Atom *atom, if (atom->type() == Atom::FormatEndif) { if (generate && numAtoms0 == numAtoms) { - relative->location().warning(tr("Output format %1 not handled"). - arg(format())); + relative->location().warning(tr("Output format %1 not handled") + .arg(format())); Atom unhandledFormatAtom(Atom::UnhandledFormat, format()); generateAtomList(&unhandledFormatAtom, relative, @@ -909,7 +1050,8 @@ const Atom *Generator::generateAtomList(const Atom *atom, atom = atom->next(); } } - else if (atom->type() == Atom::FormatElse || atom->type() == Atom::FormatEndif) { + else if (atom->type() == Atom::FormatElse || + atom->type() == Atom::FormatEndif) { return atom; } else { @@ -939,6 +1081,33 @@ void Generator::appendFullName(Text& text, << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); } +void Generator::appendFullName(Text& text, + const Node *apparentNode, + const QString& fullName, + const Node *actualNode) +{ + if (actualNode == 0) + actualNode = apparentNode; + text << Atom(Atom::LinkNode, CodeMarker::stringForNode(actualNode)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, fullName) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); +} + +void Generator::appendFullNames(Text& text, + const NodeList& nodes, + const Node* relative, + CodeMarker* marker) +{ + NodeList::ConstIterator n = nodes.begin(); + int index = 0; + while (n != nodes.end()) { + appendFullName(text,*n,relative,marker); + text << comma(index++,nodes.count()); + ++n; + } +} + void Generator::appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes, @@ -950,7 +1119,8 @@ void Generator::appendSortedNames(Text& text, r = classes.begin(); while (r != classes.end()) { - if ((*r).node->access() == Node::Public && (*r).node->status() != Node::Internal + if ((*r).node->access() == Node::Public && + (*r).node->status() != Node::Internal && !(*r).node->doc().isEmpty()) { Text className; appendFullName(className, (*r).node, classe, marker); diff --git a/tools/qdoc3/generator.h b/tools/qdoc3/generator.h index d0909a6..8e3c57e 100644 --- a/tools/qdoc3/generator.h +++ b/tools/qdoc3/generator.h @@ -93,13 +93,16 @@ class Generator virtual void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker); virtual void generateFakeNode(const FakeNode *fake, CodeMarker *marker); - virtual void generateText(const Text& text, + virtual bool generateText(const Text& text, const Node *relative, CodeMarker *marker); #ifdef QDOC_QML - virtual void generateQmlText(const Text& text, + virtual bool generateQmlText(const Text& text, const Node *relative, - CodeMarker *marker); + CodeMarker *marker, + const QString& qmlName); + virtual void generateQmlInherits(const QmlClassNode* cn, + CodeMarker* marker); #endif virtual void generateBody(const Node *node, CodeMarker *marker); virtual void generateAlsoList(const Node *node, CodeMarker *marker); @@ -150,6 +153,14 @@ class Generator const Node *relative, CodeMarker *marker, const Node *actualNode = 0); + void appendFullName(Text& text, + const Node *apparentNode, + const QString& fullName, + const Node *actualNode); + void appendFullNames(Text& text, + const NodeList& nodes, + const Node* relative, + CodeMarker* marker); void appendSortedNames(Text& text, const ClassNode *classe, const QList<RelatedClass> &classes, diff --git a/tools/qdoc3/helpprojectwriter.cpp b/tools/qdoc3/helpprojectwriter.cpp index cf7c618..f862e55 100644 --- a/tools/qdoc3/helpprojectwriter.cpp +++ b/tools/qdoc3/helpprojectwriter.cpp @@ -118,16 +118,19 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList typeHash["variable"] = Node::Variable; typeHash["target"] = Node::Target; - QHash<QString, FakeNode::SubType> subTypeHash; - subTypeHash["example"] = FakeNode::Example; - subTypeHash["headerfile"] = FakeNode::HeaderFile; - subTypeHash["file"] = FakeNode::File; - subTypeHash["group"] = FakeNode::Group; - subTypeHash["module"] = FakeNode::Module; - subTypeHash["page"] = FakeNode::Page; - subTypeHash["externalpage"] = FakeNode::ExternalPage; - - QSet<FakeNode::SubType> allSubTypes = QSet<FakeNode::SubType>::fromList(subTypeHash.values()); + QHash<QString, Node::SubType> subTypeHash; + subTypeHash["example"] = Node::Example; + subTypeHash["headerfile"] = Node::HeaderFile; + subTypeHash["file"] = Node::File; + subTypeHash["group"] = Node::Group; + subTypeHash["module"] = Node::Module; + subTypeHash["page"] = Node::Page; + subTypeHash["externalpage"] = Node::ExternalPage; +#ifdef QDOC_QML + subTypeHash["qmlclass"] = Node::QmlClass; +#endif + + QSet<Node::SubType> allSubTypes = QSet<Node::SubType>::fromList(subTypeHash.values()); foreach (const QString &selector, selectors) { QStringList pieces = selector.split(":"); @@ -139,7 +142,7 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList QString lower = pieces[0].toLower(); pieces = pieces[1].split(","); if (typeHash.contains(lower)) { - QSet<FakeNode::SubType> subTypes; + QSet<Node::SubType> subTypes; for (int i = 0; i < pieces.size(); ++i) { QString lower = pieces[i].toLower(); if (subTypeHash.contains(lower)) @@ -235,7 +238,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, // mask. const FakeNode *fakeNode = static_cast<const FakeNode *>(node); if (subproject.selectors[node->type()].contains(fakeNode->subType()) && - fakeNode->subType() != FakeNode::ExternalPage && + fakeNode->subType() != Node::ExternalPage && !fakeNode->fullTitle().isEmpty()) project.subprojects[name].nodes[objName] = node; @@ -324,10 +327,10 @@ bool HelpProjectWriter::generateSection(HelpProject &project, // attributes. case Node::Fake: { const FakeNode *fakeNode = static_cast<const FakeNode*>(node); - if (fakeNode->subType() != FakeNode::ExternalPage && + if (fakeNode->subType() != Node::ExternalPage && !fakeNode->fullTitle().isEmpty()) { - if (fakeNode->subType() != FakeNode::File) { + if (fakeNode->subType() != Node::File) { if (fakeNode->doc().hasKeywords()) { foreach (const Atom *keyword, fakeNode->doc().keywords()) { if (!keyword->string().isEmpty()) { @@ -485,7 +488,7 @@ void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer writer.writeAttribute("title", fakeNode->fullTitle()); // qDebug() << "Title:" << fakeNode->fullTitle(); - if (fakeNode->subType() == FakeNode::HeaderFile) { + if (fakeNode->subType() == Node::HeaderFile) { // Write subsections for all members, obsolete members and Qt 3 // members. @@ -609,7 +612,7 @@ void HelpProjectWriter::generateProject(HelpProject &project) while (nextPage) { writeNode(project, writer, nextPage); nextTitle = nextPage->links().value(Node::NextLink).first; - if (nextTitle.isEmpty()) + if(nextTitle.isEmpty()) break; nextPage = const_cast<FakeNode *>(tree->findFakeNodeByTitle(nextTitle)); } diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 543975e..df63138 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -61,11 +61,132 @@ QT_BEGIN_NAMESPACE static bool showBrokenLinks = false; +static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); +static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)(</@func>)"); +static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)"); +static QRegExp spanTag("</@(?:comment|preprocessor|string|char)>"); +static QRegExp unknownTag("</?@[^>]*>"); + +bool parseArg(const QString &src, + const QString &tag, + int *pos, + int n, + QStringRef *contents, + QStringRef *par1 = 0, + bool debug = false) +{ +#define SKIP_CHAR(c) \ + if (debug) \ + qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \ + if (i >= n || src[i] != c) { \ + if (debug) \ + qDebug() << " char '" << c << "' not found"; \ + return false; \ + } \ + ++i; + + +#define SKIP_SPACE \ + while (i < n && src[i] == ' ') \ + ++i; + + int i = *pos; + int j = i; + + // assume "<@" has been parsed outside + //SKIP_CHAR('<'); + //SKIP_CHAR('@'); + + if (tag != QStringRef(&src, i, tag.length())) { + if (0 && debug) + qDebug() << "tag " << tag << " not found at " << i; + return false; + } + + if (debug) + qDebug() << "haystack:" << src << "needle:" << tag << "i:" <<i; + + // skip tag + i += tag.length(); + + // parse stuff like: linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); + if (par1) { + SKIP_SPACE; + // read parameter name + j = i; + while (i < n && src[i].isLetter()) + ++i; + if (src[i] == '=') { + if (debug) + qDebug() << "read parameter" << QString(src.data() + j, i - j); + SKIP_CHAR('='); + SKIP_CHAR('"'); + // skip parameter name + j = i; + while (i < n && src[i] != '"') + ++i; + *par1 = QStringRef(&src, j, i - j); + SKIP_CHAR('"'); + SKIP_SPACE; + } else { + if (debug) + qDebug() << "no optional parameter found"; + } + } + SKIP_SPACE; + SKIP_CHAR('>'); + + // find contents up to closing "</@tag> + j = i; + for (; true; ++i) { + if (i + 4 + tag.length() > n) + return false; + if (src[i] != '<') + continue; + if (src[i + 1] != '/') + continue; + if (src[i + 2] != '@') + continue; + if (tag != QStringRef(&src, i + 3, tag.length())) + continue; + if (src[i + 3 + tag.length()] != '>') + continue; + break; + } + + *contents = QStringRef(&src, j, i - j); + + i += tag.length() + 4; + + *pos = i; + if (debug) + qDebug() << " tag " << tag << " found: pos now: " << i; + return true; +#undef SKIP_CHAR +} + +static void addLink(const QString &linkTarget, + const QStringRef &nestedStuff, + QString *res) +{ + if (!linkTarget.isEmpty()) { + *res += "<a href=\""; + *res += linkTarget; + *res += "\">"; + *res += nestedStuff; + *res += "</a>"; + } + else { + *res += nestedStuff; + } +} + + HtmlGenerator::HtmlGenerator() : helpProjectWriter(0), inLink(false), inContents(false), inSectionHeading(false), inTableHeader(false), numTableRows(0), threeColumnEnumValueTable(true), funcLeftParen("\\S(\\()"), - tre(0), slow(false) + tre(0), slow(false), obsoleteLinks(false) { } @@ -94,6 +215,7 @@ void HtmlGenerator::initializeGenerator(const Config &config) }; Generator::initializeGenerator(config); + obsoleteLinks = config.getBool(QLatin1String(CONFIG_OBSOLETELINKS)); setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif"); int i = 0; while (defaults[i].key) { @@ -102,11 +224,21 @@ void HtmlGenerator::initializeGenerator(const Config &config) i++; } - style = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_STYLE); - postHeader = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_POSTHEADER); - footer = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_FOOTER); - address = config.getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_ADDRESS); - pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_GENERATEMACREFS); + style = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_STYLE); + postHeader = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_POSTHEADER); + footer = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_FOOTER); + address = config.getString(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_ADDRESS); + pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_GENERATEMACREFS); project = config.getString(CONFIG_PROJECT); @@ -120,10 +252,16 @@ void HtmlGenerator::initializeGenerator(const Config &config) QSet<QString>::ConstIterator edition = editionNames.begin(); while (edition != editionNames.end()) { QString editionName = *edition; - QStringList editionModules = config.getStringList( - CONFIG_EDITION + Config::dot + editionName + Config::dot + "modules"); - QStringList editionGroups = config.getStringList( - CONFIG_EDITION + Config::dot + editionName + Config::dot + "groups"); + QStringList editionModules = config.getStringList(CONFIG_EDITION + + Config::dot + + editionName + + Config::dot + + "modules"); + QStringList editionGroups = config.getStringList(CONFIG_EDITION + + Config::dot + + editionName + + Config::dot + + "groups"); if (!editionModules.isEmpty()) editionModuleMap[editionName] = editionModules; @@ -135,11 +273,17 @@ void HtmlGenerator::initializeGenerator(const Config &config) slow = config.getBool(CONFIG_SLOW); - stylesheets = config.getStringList(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_STYLESHEETS); - customHeadElements = config.getStringList(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_CUSTOMHEADELEMENTS); + stylesheets = config.getStringList(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_STYLESHEETS); + customHeadElements = config.getStringList(HtmlGenerator::format() + + Config::dot + + HTMLGENERATOR_CUSTOMHEADELEMENTS); codeIndent = config.getInt(CONFIG_CODEINDENT); - helpProjectWriter = new HelpProjectWriter(config, project.toLower() + ".qhp"); + helpProjectWriter = new HelpProjectWriter(config, + project.toLower() + + ".qhp"); } void HtmlGenerator::terminateGenerator() @@ -173,6 +317,7 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) nonCompatClasses.clear(); mainClasses.clear(); compatClasses.clear(); + obsoleteClasses.clear(); moduleClassMap.clear(); moduleNamespaceMap.clear(); funcIndex.clear(); @@ -182,9 +327,9 @@ void HtmlGenerator::generateTree(const Tree *tree, CodeMarker *marker) findAllFunctions(tree->root()); findAllLegaleseTexts(tree->root()); findAllNamespaces(tree->root()); -#ifdef ZZZ_QDOC_QML +#ifdef ZZZ_QDOC_QML findAllQmlClasses(tree->root()); -#endif +#endif PageGenerator::generateTree(tree, marker); @@ -260,7 +405,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::AutoLink: if (!inLink && !inContents && !inSectionHeading) { const Node *node = 0; - QString link = getLink(atom, relative, marker, node); + QString link = getLink(atom, relative, marker, &node); if (!link.isEmpty()) { beginLink(link, node, relative, marker); generateLink(atom, relative, marker); @@ -288,7 +433,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, QString str; atom = atom->next(); while (atom != 0 && atom->type() != Atom::BriefRight) { - if (atom->type() == Atom::String || atom->type() == Atom::AutoLink) + if (atom->type() == Atom::String || + atom->type() == Atom::AutoLink) str += atom->string(); skipAhead++; atom = atom->next(); @@ -326,21 +472,24 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; break; case Atom::Code: - out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()), - marker, relative)) + out() << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), + marker,relative)) << "</pre>\n"; break; -#ifdef QDOC_QML +#ifdef QDOC_QML case Atom::Qml: - out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()), - marker, relative)) + out() << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), + marker,relative)) << "</pre>\n"; break; -#endif +#endif case Atom::CodeNew: out() << "<p>you can rewrite it as</p>\n" - << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, atom->string()), - marker, relative)) + << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()), + marker,relative)) << "</pre>\n"; break; case Atom::CodeOld: @@ -348,7 +497,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, // fallthrough case Atom::CodeBad: out() << "<pre><font color=\"#404040\">" - << trimmedTrailing(protect(plainCode(indent(codeIndent, atom->string())))) + << trimmedTrailing(protect(plainCode(indent(codeIndent,atom->string())))) << "</font></pre>\n"; break; case Atom::FootnoteLeft: @@ -388,6 +537,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, out() << formattingRightMap()[atom->string()]; } break; + case Atom::AnnotatedList: + { + QList<Node*> values = tre->groups().values(atom->string()); + QMap<QString, const Node*> nodeMap; + for (int i = 0; i < values.size(); ++i) { + const Node* n = values.at(i); + nodeMap.insert(n->name(),n); + } + generateAnnotatedList(relative, marker, nodeMap); + } + break; case Atom::GeneratedList: if (atom->string() == "annotatedclasses") { generateAnnotatedList(relative, marker, nonCompatClasses); @@ -443,6 +603,9 @@ int HtmlGenerator::generateAtom(const Atom *atom, else if (atom->string() == "compatclasses") { generateCompactList(relative, marker, compatClasses); } + else if (atom->string() == "obsoleteclasses") { + generateCompactList(relative, marker, obsoleteClasses); + } else if (atom->string() == "functionindex") { generateFunctionIndex(relative, marker); } @@ -524,11 +687,12 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::Link: { const Node *node = 0; - QString myLink = getLink(atom, relative, marker, node); - if (myLink.isEmpty()) + QString myLink = getLink(atom, relative, marker, &node); + if (myLink.isEmpty()) { relative->doc().location().warning(tr("Cannot link to '%1' in %2") .arg(atom->string()) .arg(marker->plainFullName(relative))); + } beginLink(myLink, node, relative, marker); skipAhead = 1; } @@ -554,13 +718,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, else if (atom->string() == ATOM_LIST_VALUE) { threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom); if (threeColumnEnumValueTable) { - out() << "<p><table border=\"1\" cellpadding=\"2\" cellspacing=\"1\" width=\"100%\">\n" - "<tr><th width=\"25%\">Constant</th><th width=\"15%\">Value</th>" - "<th width=\"60%\">Description</th></tr>\n"; + out() << "<p><table class=\"valuelist\" border=\"1\" cellpadding=\"2\" " + << "cellspacing=\"1\" width=\"100%\">\n" + << "<tr><th width=\"25%\">Constant</th>" + << "<th width=\"15%\">Value</th>" + << "<th width=\"60%\">Description</th></tr>\n"; } else { - out() << "<p><table border=\"1\" cellpadding=\"2\" cellspacing=\"1\" width=\"40%\">\n" - << "<tr><th width=\"60%\">Constant</th><th width=\"40%\">Value</th></tr>\n"; + out() << "<p><table class=\"valuelist\" border=\"1\" cellpadding=\"2\" " + << "cellspacing=\"1\" width=\"40%\">\n" + << "<tr><th width=\"60%\">Constant</th><th " + << "width=\"40%\">Value</th></tr>\n"; } } else { @@ -734,14 +902,17 @@ int HtmlGenerator::generateAtom(const Atom *atom, } if (!atom->string().isEmpty()) { if (atom->string().contains("%")) - out() << "<p><table width=\"" << atom->string() << "\" " + out() << "<p><table class=\"generic\" width=\"" << atom->string() << "\" " << "align=\"center\" cellpadding=\"2\" " << "cellspacing=\"1\" border=\"0\">\n"; - else - out() << "<p><table align=\"center\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n"; + else { + out() << "<p><table class=\"generic\" align=\"center\" cellpadding=\"2\" " + << "cellspacing=\"1\" border=\"0\">\n"; + } } else { - out() << "<p><table align=\"center\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n"; + out() << "<p><table class=\"generic\" align=\"center\" cellpadding=\"2\" " + << "cellspacing=\"1\" border=\"0\">\n"; } numTableRows = 0; break; @@ -840,7 +1011,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, case Atom::EndQmlText: // don't do anything with these. They are just tags. break; -#endif +#endif default: unknownAtom(atom); } @@ -906,6 +1077,12 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, generateHeader(title, inner, marker, true); generateTitle(title, subtitleText, SmallSubTitle, inner, marker); +#ifdef QDOC_QML + if (classe && !classe->qmlElement().isEmpty()) { + generateInstantiatedBy(classe,marker); + } +#endif + generateBrief(inner, marker); generateIncludes(inner, marker); generateStatus(inner, marker); @@ -924,12 +1101,16 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, out() << "<li><a href=\"" << membersLink << "\">" << "List of all members, including inherited members</a></li>\n"; - QString obsoleteLink = generateLowStatusMemberFile(inner, marker, CodeMarker::Obsolete); + QString obsoleteLink = generateLowStatusMemberFile(inner, + marker, + CodeMarker::Obsolete); if (!obsoleteLink.isEmpty()) out() << "<li><a href=\"" << obsoleteLink << "\">" << "Obsolete members</a></li>\n"; - QString compatLink = generateLowStatusMemberFile(inner, marker, CodeMarker::Compat); + QString compatLink = generateLowStatusMemberFile(inner, + marker, + CodeMarker::Compat); if (!compatLink.isEmpty()) out() << "<li><a href=\"" << compatLink << "\">" << "Qt 3 support members</a></li>\n"; @@ -941,14 +1122,34 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, sections = marker->sections(inner, CodeMarker::Summary, CodeMarker::Okay); s = sections.begin(); while (s != sections.end()) { - if (s->members.isEmpty()) { + if (s->members.isEmpty() && s->reimpMembers.isEmpty()) { if (!s->inherited.isEmpty()) needOtherSection = true; - } else { - out() << "<a name=\"" << registerRef((*s).name.toLower()) << "\"></a>\n"; - out() << "<h3>" << protect((*s).name) << "</h3>\n"; + } + else { + if (!s->members.isEmpty()) { + out() << "<hr />\n"; + out() << "<a name=\"" + << registerRef((*s).name.toLower()) + << "\"></a>\n"; + out() << "<h2>" << protect((*s).name) << "</h2>\n"; + generateSection(s->members, inner, marker, CodeMarker::Summary); + } + if (!s->reimpMembers.isEmpty()) { + QString name = QString("Reimplemented ") + (*s).name; + out() << "<hr />\n"; + out() << "<a name=\"" + << registerRef(name.toLower()) + << "\"></a>\n"; + out() << "<h2>" << protect(name) << "</h2>\n"; + generateSection(s->reimpMembers, inner, marker, CodeMarker::Summary); + } - generateSectionList(*s, inner, marker, CodeMarker::Summary); + if (!s->inherited.isEmpty()) { + out() << "<ul>\n"; + generateSectionInheritedList(*s, inner, marker, true); + out() << "</ul>\n"; + } } ++s; } @@ -997,29 +1198,34 @@ void HtmlGenerator::generateClassLikeNode(const InnerNode *inner, names << (*m)->name(); if ((*m)->type() == Node::Function) { const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m); - if (func->metaness() == FunctionNode::Ctor || func->metaness() == FunctionNode::Dtor - || func->overloadNumber() != 1) + if (func->metaness() == FunctionNode::Ctor || + func->metaness() == FunctionNode::Dtor || + func->overloadNumber() != 1) names.clear(); - } else if ((*m)->type() == Node::Property) { + } + else if ((*m)->type() == Node::Property) { const PropertyNode *prop = reinterpret_cast<const PropertyNode *>(*m); - if (!prop->getters().isEmpty() && !names.contains(prop->getters().first()->name())) + if (!prop->getters().isEmpty() && + !names.contains(prop->getters().first()->name())) names << prop->getters().first()->name(); if (!prop->setters().isEmpty()) names << prop->setters().first()->name(); if (!prop->resetters().isEmpty()) names << prop->resetters().first()->name(); - } else if ((*m)->type() == Node::Enum) { - const EnumNode *enume = reinterpret_cast<const EnumNode *>(*m); + } + else if ((*m)->type() == Node::Enum) { + const EnumNode *enume = reinterpret_cast<const EnumNode*>(*m); if (enume->flagsType()) names << enume->flagsType()->name(); foreach (const QString &enumName, - enume->doc().enumItemNames().toSet() - - enume->doc().omitEnumItemNames().toSet()) - names << plainCode(marker->markedUpEnumValue(enumName, enume)); + enume->doc().enumItemNames().toSet() - + enume->doc().omitEnumItemNames().toSet()) + names << plainCode(marker->markedUpEnumValue(enumName, + enume)); } foreach (const QString &name, names) - classSection.keywords += qMakePair(name, linkForNode(*m, 0)); + classSection.keywords += qMakePair(name,linkForNode(*m,0)); } ++m; } @@ -1060,16 +1266,19 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) QList<Section>::const_iterator s; QString htmlTitle = fake->fullTitle(); - if (fake->subType() == FakeNode::File && !fake->subTitle().isEmpty()) { + if (fake->subType() == Node::File && !fake->subTitle().isEmpty()) { subTitleSize = SmallSubTitle; htmlTitle += " (" + fake->subTitle() + ")"; } generateHeader(htmlTitle, fake, marker, true); - generateTitle(fake->fullTitle(), Text() << fake->subTitle(), subTitleSize, - fake, marker); + generateTitle(fake->fullTitle(), + Text() << fake->subTitle(), + subTitleSize, + fake, + marker); - if (fake->subType() == FakeNode::Module) { + if (fake->subType() == Node::Module) { // Generate brief text and status for modules. generateBrief(fake, marker); generateStatus(fake, marker); @@ -1083,7 +1292,7 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) generateAnnotatedList(fake, marker, moduleClassMap[fake->name()]); } } - else if (fake->subType() == FakeNode::HeaderFile) { + else if (fake->subType() == Node::HeaderFile) { // Generate brief text and status for modules. generateBrief(fake, marker); generateStatus(fake, marker); @@ -1095,12 +1304,16 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) out() << "<li><a href=\"" << membersLink << "\">" << "List of all members, including inherited members</a></li>\n"; - QString obsoleteLink = generateLowStatusMemberFile(fake, marker, CodeMarker::Obsolete); + QString obsoleteLink = generateLowStatusMemberFile(fake, + marker, + CodeMarker::Obsolete); if (!obsoleteLink.isEmpty()) out() << "<li><a href=\"" << obsoleteLink << "\">" << "Obsolete members</a></li>\n"; - QString compatLink = generateLowStatusMemberFile(fake, marker, CodeMarker::Compat); + QString compatLink = generateLowStatusMemberFile(fake, + marker, + CodeMarker::Compat); if (!compatLink.isEmpty()) out() << "<li><a href=\"" << compatLink << "\">" << "Qt 3 support members</a></li>\n"; @@ -1126,35 +1339,65 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) appendDcfSubSection(&fakeSection, compatSection); } } +#ifdef QDOC_QML + else if (fake->subType() == Node::QmlClass) { + const QmlClassNode* qml_cn = static_cast<const QmlClassNode*>(fake); + const ClassNode* cn = qml_cn->classNode(); + generateQmlInherits(qml_cn, marker); + generateQmlInstantiates(qml_cn, marker); + generateBrief(qml_cn, marker); + sections = marker->qmlSections(qml_cn,CodeMarker::Summary); + s = sections.begin(); + while (s != sections.end()) { + out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; + out() << "<h2>" << protect((*s).name) << "</h2>\n"; + generateQmlSummary(*s,fake,marker); + ++s; + } + + out() << "<a name=\"" << registerRef("details") << "\"></a>\n"; + out() << "<h2>" << "Detailed Description" << "</h2>\n"; + generateBody(fake, marker); + if (cn) + generateQmlText(cn->doc().body(), cn, marker, fake->name()); + generateAlsoList(fake, marker); + out() << "<hr />\n"; + sections = marker->qmlSections(qml_cn,CodeMarker::Detailed); + s = sections.begin(); + while (s != sections.end()) { + out() << "<h2>" << protect((*s).name) << "</h2>\n"; + NodeList::ConstIterator m = (*s).members.begin(); + while (m != (*s).members.end()) { + generateDetailedQmlMember(*m, fake, marker); + out() << "<br />\n"; + fakeSection.keywords += qMakePair((*m)->name(), + linkForNode(*m,0)); + ++m; + } + ++s; + } + generateFooter(fake); + return; + } +#endif + sections = marker->sections(fake, CodeMarker::Summary, CodeMarker::Okay); s = sections.begin(); while (s != sections.end()) { out() << "<a name=\"" << registerRef((*s).name) << "\"></a>\n"; - out() << "<h3>" << protect((*s).name) << "</h3>\n"; + out() << "<h2>" << protect((*s).name) << "</h2>\n"; generateSectionList(*s, fake, marker, CodeMarker::Summary); ++s; } Text brief = fake->doc().briefText(); - if (fake->subType() == FakeNode::Module && !brief.isEmpty()) { + if (fake->subType() == Node::Module && !brief.isEmpty()) { out() << "<a name=\"" << registerRef("details") << "\"></a>\n"; out() << "<h2>" << "Detailed Description" << "</h2>\n"; } generateBody(fake, marker); -#ifdef QDOC_QML - if (fake->subType() == FakeNode::QmlClass) { - //qDebug() << "generateFakeNode(): QML CLASS" << fake->name(); - const QmlNode* qmlNode = static_cast<const QmlNode*>(fake); - const ClassNode* cn = qmlNode->classNode(); - if (cn) { - //qDebug() << " CPP CLASS" << cn->name(); - generateQmlText(cn->doc().body(), cn, marker); - } - } -#endif - generateAlsoList(fake, marker); if (!fake->groupMembers().isEmpty()) { @@ -1184,10 +1427,10 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) } generateFooter(fake); - if (fake->subType() == FakeNode::Example) { + if (fake->subType() == Node::Example) { appendDcfSubSection(&dcfExamplesRoot, fakeSection); } - else if (fake->subType() != FakeNode::File) { + else if (fake->subType() != Node::File) { QString contentsPage = fake->links().value(Node::ContentsLink).first; if (contentsPage == "Qt Designer Manual") { @@ -1407,17 +1650,19 @@ void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, void HtmlGenerator::generateIncludes(const InnerNode *inner, CodeMarker *marker) { if (!inner->includes().isEmpty()) { - out() << "<pre>" << trimmedTrailing(highlightedCode(indent(codeIndent, - marker->markedUpIncludes( - inner->includes())), - marker, inner)) + out() << "<pre>" + << trimmedTrailing(highlightedCode(indent(codeIndent, + marker->markedUpIncludes(inner->includes())), + marker,inner)) << "</pre>"; } } -void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker, +void HtmlGenerator::generateTableOfContents(const Node *node, + CodeMarker *marker, Doc::SectioningUnit sectioningUnit, - int numColumns, const Node *relative) + int numColumns, + const Node *relative) { if (!node->doc().hasTableOfContents()) @@ -1436,7 +1681,8 @@ void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker QString tdTag; if (numColumns > 1) { tdTag = "<td width=\"" + QString::number((100 + numColumns - 1) / numColumns) + "%\">"; - out() << "<p><table width=\"100%\">\n<tr valign=\"top\">" << tdTag << "\n"; + out() << "<p><table class=\"toc\" width=\"100%\">\n<tr valign=\"top\">" + << tdTag << "\n"; } // disable nested links in table of contents @@ -1455,7 +1701,8 @@ void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker out() << "<ul>"; sectionNumber.append("1"); } while (sectionNumber.size() < nextLevel); - } else { + } + else { while (sectionNumber.size() > nextLevel) { out() << "</ul>\n"; sectionNumber.removeLast(); @@ -1470,7 +1717,10 @@ void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker columnSize = 0; } out() << "<li>"; - out() << "<a href=\"" << nodeName << "#" << Doc::canonicalTitle(headingText.toString()) + out() << "<a href=\"" + << nodeName + << "#" + << Doc::canonicalTitle(headingText.toString()) << "\">"; generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); out() << "</a></li>\n"; @@ -1520,12 +1770,15 @@ void HtmlGenerator::generateNavigationBar(const NavigationBar& bar, } #endif -QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeMarker *marker) +QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, + CodeMarker *marker) { QList<Section> sections; QList<Section>::ConstIterator s; - sections = marker->sections(inner, CodeMarker::SeparateList, CodeMarker::Okay); + sections = marker->sections(inner, + CodeMarker::SeparateList, + CodeMarker::Okay); if (sections.isEmpty()) return QString(); @@ -1546,10 +1799,13 @@ QString HtmlGenerator::generateListOfAllMemberFile(const InnerNode *inner, CodeM return fileName; } -QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeMarker *marker, +QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, + CodeMarker *marker, CodeMarker::Status status) { - QList<Section> sections = marker->sections(inner, CodeMarker::Summary, status); + QList<Section> sections = marker->sections(inner, + CodeMarker::Summary, + status); QMutableListIterator<Section> j(sections); while (j.hasNext()) { if (j.next().members.size() == 0) @@ -1566,7 +1822,8 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeM if (status == CodeMarker::Compat) { title = "Qt 3 Support Members for " + inner->name(); fileName = fileBase(inner) + "-qt3." + fileExtension(inner); - } else { + } + else { title = "Obsolete Members for " + inner->name(); fileName = fileBase(inner) + "-obsolete." + fileExtension(inner); } @@ -1580,18 +1837,20 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeM "<a href=\"qt3support.html\">Qt 3 support layer</a>.</b> " "They are provided to help you port old code to Qt 4. We advise against " "using them in new code.</p>\n"; - } else { - out() << "<p><b>The following class members are obsolete.</b> They are provided to keep " - "old source code working. We strongly advise against using them in new " - "code.</p>\n"; + } + else { + out() << "<p><b>The following class members are obsolete.</b> " + << "They are provided to keep old source code working. " + << "We strongly advise against using them in new code.</p>\n"; } - out() << "<p><ul><li><a href=\"" << linkForNode(inner, 0) << "\">" << protect(inner->name()) + out() << "<p><ul><li><a href=\"" + << linkForNode(inner, 0) << "\">" + << protect(inner->name()) << " class reference</a></li></ul></p>\n"; for (i = 0; i < sections.size(); ++i) { - out() << "<h3>" << protect(sections.at(i).name) << "</h3>\n"; - + out() << "<h2>" << protect(sections.at(i).name) << "</h2>\n"; generateSectionList(sections.at(i), inner, marker, CodeMarker::Summary); } @@ -1613,8 +1872,9 @@ QString HtmlGenerator::generateLowStatusMemberFile(const InnerNode *inner, CodeM return fileName; } -void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *marker, - const QMap<QString, const Node *> &classMap) +void HtmlGenerator::generateClassHierarchy(const Node *relative, + CodeMarker *marker, + const QMap<QString,const Node*> &classMap) { if (classMap.isEmpty()) return; @@ -1636,8 +1896,10 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *mar if (stack.top().isEmpty()) { stack.pop(); out() << "</ul>\n"; - } else { - const ClassNode *child = static_cast<const ClassNode *>(*stack.top().begin()); + } + else { + const ClassNode *child = + static_cast<const ClassNode *>(*stack.top().begin()); out() << "<li>"; generateFullName(child, relative, marker); out() << "</li>\n"; @@ -1656,15 +1918,20 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, CodeMarker *mar } } -void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *marker, - const QMap<QString, const Node *> &nodeMap) +void HtmlGenerator::generateAnnotatedList(const Node *relative, + CodeMarker *marker, + const QMap<QString, const Node *> &nodeMap) { - out() << "<p><table width=\"100%\" class=\"annotated\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\">\n"; + out() << "<p><table width=\"100%\" class=\"annotated\" cellpadding=\"2\" " + << "cellspacing=\"1\" border=\"0\">\n"; int row = 0; foreach (const QString &name, nodeMap.keys()) { const Node *node = nodeMap[name]; + if (node->status() == Node::Obsolete) + continue; + if (++row % 2 == 1) out() << "<tr valign=\"top\" class=\"odd\">"; else @@ -1680,7 +1947,8 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *mark generateText(brief, node, marker); out() << "</td>"; } - } else { + } + else { out() << "<td>"; out() << protect(node->doc().briefText().toString()); out() << "</td>"; @@ -1690,7 +1958,8 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *mark out() << "</table></p>\n"; } -void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker, +void HtmlGenerator::generateCompactList(const Node *relative, + CodeMarker *marker, const QMap<QString, const Node *> &classMap) { const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_' @@ -1734,8 +2003,9 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker last = classMap.begin().key(); if (classMap.size() > 1) { - while (commonPrefixLen < first.length() + 1 && commonPrefixLen < last.length() + 1 - && first[commonPrefixLen] == last[commonPrefixLen]) + while (commonPrefixLen < first.length() + 1 && + commonPrefixLen < last.length() + 1 && + first[commonPrefixLen] == last[commonPrefixLen]) ++commonPrefixLen; } @@ -1764,7 +2034,8 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker if (key[0].digitValue() != -1) { paragraphNo = key[0].digitValue(); - } else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) { + } + else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) { paragraphNo = 10 + key[0].unicode() - 'a'; } @@ -1812,45 +2083,56 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker } firstOffset[NumColumns] = classMap.count(); - out() << "<p><table width=\"100%\">\n"; + out() << "<p><table class=\"generic\" width=\"100%\">\n"; for (k = 0; k < numRows; k++) { out() << "<tr>\n"; for (i = 0; i < NumColumns; i++) { if (currentOffset[i] >= firstOffset[i + 1]) { // this column is finished out() << "<td>\n</td>\n"; - } else { + } + else { while (currentOffsetInParagraph[i] == paragraph[currentParagraphNo[i]].count()) { ++currentParagraphNo[i]; currentOffsetInParagraph[i] = 0; } + if (currentParagraphNo[i] >= NumParagraphs) { + qDebug() << "### Internal error ###" << __FILE__ << __LINE__; + currentParagraphNo[i] = NumParagraphs - 1; + } + out() << "<td align=\"right\">"; if (currentOffsetInParagraph[i] == 0) { // start a new paragraph - out() << "<b>" << paragraphName[currentParagraphNo[i]] << " </b>"; - } - out() << "</td>\n"; - - // bad loop - QMap<QString, const Node *>::Iterator it; - it = paragraph[currentParagraphNo[i]].begin(); - for (j = 0; j < currentOffsetInParagraph[i]; j++) - ++it; - - out() << "<td>"; - // Previously, we used generateFullName() for this, but we - // require some special formatting. - out() << "<a href=\"" << linkForNode(it.value(), relative) << "\">"; - QStringList pieces = fullName(it.value(), relative, marker).split("::"); - out() << protect(pieces.last()); - out() << "</a>"; - if (pieces.size() > 1) { - out() << " ("; - generateFullName(it.value()->parent(), relative, marker); - out() << ")"; + out() << "<b>" + << paragraphName[currentParagraphNo[i]] + << " </b>"; } out() << "</td>\n"; + + if (!paragraphName[currentParagraphNo[i]].isEmpty()) { + QMap<QString, const Node *>::Iterator it; + it = paragraph[currentParagraphNo[i]].begin(); + for (j = 0; j < currentOffsetInParagraph[i]; j++) + ++it; + + out() << "<td>"; + // Previously, we used generateFullName() for this, but we + // require some special formatting. + out() << "<a href=\"" + << linkForNode(it.value(), relative) + << "\">"; + QStringList pieces = fullName(it.value(), relative, marker).split("::"); + out() << protect(pieces.last()); + out() << "</a>"; + if (pieces.size() > 1) { + out() << " ("; + generateFullName(it.value()->parent(), relative, marker); + out() << ")"; + } + out() << "</td>\n"; + } currentOffset[i]++; currentOffsetInParagraph[i]++; @@ -1861,7 +2143,8 @@ void HtmlGenerator::generateCompactList(const Node *relative, CodeMarker *marker out() << "</table></p>\n"; } -void HtmlGenerator::generateFunctionIndex(const Node *relative, CodeMarker *marker) +void HtmlGenerator::generateFunctionIndex(const Node *relative, + CodeMarker *marker) { out() << "<p align=\"center\"><font size=\"+1\"><b>"; for (int i = 0; i < 26; i++) { @@ -1910,7 +2193,8 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative, CodeMarker *mark #endif } -void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marker) +void HtmlGenerator::generateLegaleseList(const Node *relative, + CodeMarker *marker) { QMap<Text, const Node *>::ConstIterator it = legaleseTexts.begin(); while (it != legaleseTexts.end()) { @@ -1928,8 +2212,10 @@ void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marke } } -void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, - CodeMarker *marker, CodeMarker::SynopsisStyle style) +/*void HtmlGenerator::generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) { QString marked = marker->markedUpSynopsis(node, relative, style); QRegExp templateTag("(<[^@>]*>)"); @@ -1939,7 +2225,8 @@ void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, marked.replace(templateTag.pos(1), templateTag.cap(1).length(), contents); } - marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), "<i>\\1<sub>\\2</sub></i>"); + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), + "<i>\\1<sub>\\2</sub></i>"); marked.replace("<@param>", "<i>"); marked.replace("</@param>", "</i>"); @@ -1950,7 +2237,8 @@ void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, QRegExp extraRegExp("<@extra>.*</@extra>"); extraRegExp.setMinimal(true); marked.replace(extraRegExp, ""); - } else { + } + else { marked.replace("<@extra>", " <tt>"); marked.replace("</@extra>", "</tt>"); } @@ -1960,7 +2248,40 @@ void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, marked.replace("</@type>", ""); } out() << highlightedCode(marked, marker, relative); +}*/ + +#ifdef QDOC_QML +void HtmlGenerator::generateQmlItem(const Node *node, + const Node *relative, + CodeMarker *marker, + bool summary) +{ + QString marked = marker->markedUpQmlItem(node,summary); + QRegExp templateTag("(<[^@>]*>)"); + if (marked.indexOf(templateTag) != -1) { + QString contents = protect(marked.mid(templateTag.pos(1), + templateTag.cap(1).length())); + marked.replace(templateTag.pos(1), templateTag.cap(1).length(), + contents); + } + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), + "<i>\\1<sub>\\2</sub></i>"); + marked.replace("<@param>", "<i>"); + marked.replace("</@param>", "</i>"); + + if (summary) + marked.replace("@name>", "b>"); + + marked.replace("<@extra>", " <tt>"); + marked.replace("</@extra>", "</tt>"); + + if (summary) { + marked.replace("<@type>", ""); + marked.replace("</@type>", ""); + } + out() << highlightedCode(marked, marker, relative); } +#endif void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* marker */) { @@ -1984,7 +2305,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m } // there are too many examples; they would clutter the list - if (fakeNode->subType() == FakeNode::Example) + if (fakeNode->subType() == Node::Example) continue; // not interested either in individual (Qt Designer etc.) manual chapters @@ -1992,7 +2313,7 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m continue; // Discard external nodes. - if (fakeNode->subType() == FakeNode::ExternalPage) + if (fakeNode->subType() == Node::ExternalPage) continue; QString sortKey = fakeNode->fullTitle().toLower(); @@ -2017,7 +2338,8 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m groupTitlesMap[fakeNode->fullTitle()] = const_cast<const FakeNode *>(fakeNode); } } - } else if (!isGroupPage) { + } + else if (!isGroupPage) { // If we encounter a page that belongs to a group then // we add that page to the list for that group. const FakeNode *groupNode = static_cast<const FakeNode *>(tre->root()->findNode(group, Node::Fake)); @@ -2075,21 +2397,100 @@ void HtmlGenerator::generateOverviewList(const Node *relative, CodeMarker * /* m } } -void HtmlGenerator::generateSectionList(const Section& section, const Node *relative, - CodeMarker *marker, CodeMarker::SynopsisStyle style) +#ifdef QDOC_NAME_ALIGNMENT +void HtmlGenerator::generateSection(const NodeList& nl, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) { + bool name_alignment = true; + if (!nl.isEmpty()) { + bool twoColumn = false; + if (style == CodeMarker::SeparateList) { + name_alignment = false; + twoColumn = (nl.count() >= 16); + } + else if (nl.first()->type() == Node::Property) { + twoColumn = (nl.count() >= 5); + name_alignment = false; + } + if (name_alignment) { + out() << "<table class=\"alignedsummary\" border=\"0\" cellpadding=\"0\" " + << "cellspacing=\"0\" width=\"100%\">\n"; + } + else { + if (twoColumn) + out() << "<p><table class=\"propsummary\" width=\"100%\" " + << "border=\"0\" cellpadding=\"0\"" + << " cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; + } + + int i = 0; + NodeList::ConstIterator m = nl.begin(); + while (m != nl.end()) { + if ((*m)->access() == Node::Private) { + ++m; + continue; + } + + if (name_alignment) { + out() << "<tr><td class=\"memItemLeft\" " + << "align=\"right\" valign=\"top\">"; + } + else { + if (twoColumn && i == (int) (nl.count() + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; + out() << "<li><div class=\"fn\">"; + } + + generateSynopsis(*m, relative, marker, style, name_alignment); + if (name_alignment) + out() << "</td></tr>\n"; + else + out() << "</div></li>\n"; + i++; + ++m; + } + if (name_alignment) + out() << "</table>\n"; + else { + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; + } + } +} + +void HtmlGenerator::generateSectionList(const Section& section, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) +{ + bool name_alignment = true; if (!section.members.isEmpty()) { bool twoColumn = false; if (style == CodeMarker::SeparateList) { + name_alignment = false; twoColumn = (section.members.count() >= 16); - } else if (section.members.first()->type() == Node::Property) { + } + else if (section.members.first()->type() == Node::Property) { twoColumn = (section.members.count() >= 5); + name_alignment = false; + } + if (name_alignment) { + out() << "<table class=\"alignedsummary\" border=\"0\" cellpadding=\"0\" " + << "cellspacing=\"0\" width=\"100%\">\n"; + } + else { + if (twoColumn) + out() << "<p><table class=\"propsummary\" width=\"100%\" " + << "border=\"0\" cellpadding=\"0\"" + << " cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; } - if (twoColumn) - out() << "<p><table width=\"100%\" border=\"0\" cellpadding=\"0\"" - " cellspacing=\"0\">\n" - << "<tr><td width=\"45%\" valign=\"top\">"; - out() << "<ul>\n"; int i = 0; NodeList::ConstIterator m = section.members.begin(); @@ -2099,41 +2500,56 @@ void HtmlGenerator::generateSectionList(const Section& section, const Node *rela continue; } - if (twoColumn && i == (int) (section.members.count() + 1) / 2) - out() << "</ul></td><td valign=\"top\"><ul>\n"; + if (name_alignment) { + out() << "<tr><td class=\"memItemLeft\" " + << "align=\"right\" valign=\"top\">"; + } + else { + if (twoColumn && i == (int) (section.members.count() + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; + out() << "<li><div class=\"fn\">"; + } - out() << "<li><div class=\"fn\"></div>"; - if (style == CodeMarker::Accessors) - out() << "<b>"; - generateSynopsis(*m, relative, marker, style); - if (style == CodeMarker::Accessors) - out() << "</b>"; - out() << "</li>\n"; + generateSynopsis(*m, relative, marker, style, name_alignment); + if (name_alignment) + out() << "</td></tr>\n"; + else + out() << "</div></li>\n"; i++; ++m; } - out() << "</ul>\n"; - if (twoColumn) - out() << "</td></tr>\n</table></p>\n"; + if (name_alignment) + out() << "</table>\n"; + else { + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; + } } if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { out() << "<ul>\n"; - generateSectionInheritedList(section, relative, marker); + generateSectionInheritedList(section, relative, marker, name_alignment); out() << "</ul>\n"; } } -void HtmlGenerator::generateSectionInheritedList(const Section& section, const Node *relative, - CodeMarker *marker) +void HtmlGenerator::generateSectionInheritedList(const Section& section, + const Node *relative, + CodeMarker *marker, + bool nameAlignment) { QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin(); while (p != section.inherited.end()) { - out() << "<li><div class=\"fn\"></div>"; + if (nameAlignment) + out() << "<li><div bar=\"2\" class=\"fn\"></div>"; + else + out() << "<li><div class=\"fn\"></div>"; out() << (*p).second << " "; if ((*p).second == 1) { out() << section.singularMember; - } else { + } + else { out() << section.pluralMember; } out() << " inherited from <a href=\"" << fileName((*p).first) @@ -2144,270 +2560,324 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, const N } } -void HtmlGenerator::generateLink(const Atom *atom, const Node * /* relative */, CodeMarker *marker) +void HtmlGenerator::generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style, + bool nameAlignment) { - static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_"); - - if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { - // hack for C++: move () outside of link - int k = funcLeftParen.pos(1); - out() << protect(atom->string().left(k)); - if (link.isEmpty()) { - if (showBrokenLinks) - out() << "</i>"; - } else { - out() << "</a>"; - } - inLink = false; - out() << protect(atom->string().mid(k)); - } else if (marker->recognizeLanguage("Java")) { - // hack for Java: remove () and use <tt> when appropriate - bool func = atom->string().endsWith("()"); - bool tt = (func || atom->string().contains(camelCase)); - if (tt) - out() << "<tt>"; - if (func) { - out() << protect(atom->string().left(atom->string().length() - 2)); - } else { - out() << protect(atom->string()); - } - out() << "</tt>"; - } else { - out() << protect(atom->string()); + QString marked = marker->markedUpSynopsis(node, relative, style); + QRegExp templateTag("(<[^@>]*>)"); + if (marked.indexOf(templateTag) != -1) { + QString contents = protect(marked.mid(templateTag.pos(1), + templateTag.cap(1).length())); + marked.replace(templateTag.pos(1), templateTag.cap(1).length(), + contents); } -} - -QString HtmlGenerator::cleanRef(const QString& ref) -{ - QString clean; - - if (ref.isEmpty()) - return clean; + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), + "<i>\\1<sub>\\2</sub></i>"); + marked.replace("<@param>", "<i>"); + marked.replace("</@param>", "</i>"); - clean.reserve(ref.size() + 20); - const QChar c = ref[0]; - const uint u = c.unicode(); + if (style == CodeMarker::Summary) { + marked.replace("<@name>", ""); // was "<b>" + marked.replace("</@name>", ""); // was "</b>" + } - if ((u >= 'a' && u <= 'z') || - (u >= 'A' && u <= 'Z') || - (u >= '0' && u <= '9')) { - clean += c; - } else if (u == '~') { - clean += "dtor."; - } else if (u == '_') { - clean += "underscore."; + if (style == CodeMarker::SeparateList) { + QRegExp extraRegExp("<@extra>.*</@extra>"); + extraRegExp.setMinimal(true); + marked.replace(extraRegExp, ""); } else { - clean += "A"; + marked.replace("<@extra>", " <tt>"); + marked.replace("</@extra>", "</tt>"); } - for (int i = 1; i < (int) ref.length(); i++) { - const QChar c = ref[i]; - const uint u = c.unicode(); - if ((u >= 'a' && u <= 'z') || - (u >= 'A' && u <= 'Z') || - (u >= '0' && u <= '9') || u == '-' || - u == '_' || u == ':' || u == '.') { - clean += c; - } else if (c.isSpace()) { - clean += "-"; - } else if (u == '!') { - clean += "-not"; - } else if (u == '&') { - clean += "-and"; - } else if (u == '<') { - clean += "-lt"; - } else if (u == '=') { - clean += "-eq"; - } else if (u == '>') { - clean += "-gt"; - } else if (u == '#') { - clean += "#"; - } else { - clean += "-"; - clean += QString::number((int)u, 16); - } + if (style != CodeMarker::Detailed) { + marked.replace("<@type>", ""); + marked.replace("</@type>", ""); } - return clean; + out() << highlightedCode(marked, marker, relative, style, nameAlignment); } -QString HtmlGenerator::registerRef(const QString& ref) +QString HtmlGenerator::highlightedCode(const QString& markedCode, + CodeMarker *marker, + const Node *relative, + CodeMarker::SynopsisStyle , + bool nameAlignment) { - QString clean = HtmlGenerator::cleanRef(ref); + QString src = markedCode; + QString html; + QStringRef arg; + QStringRef par1; - for (;;) { - QString& prevRef = refMap[clean.toLower()]; - if (prevRef.isEmpty()) { - prevRef = ref; - break; - } else if (prevRef == ref) { - break; + const QChar charLangle = '<'; + const QChar charAt = '@'; + + // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*(</@link>)" + static const QString linkTag("link"); + bool done = false; + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle && src.at(i + 1).unicode() == '@') { + if (nameAlignment && !done) {// && (i != 0)) Why was this here? + html += "</td><td class=\"memItemRight\" valign=\"bottom\">"; + done = true; + } + i += 2; + if (parseArg(src, linkTag, &i, n, &arg, &par1)) { + html += "<b>"; + QString link = linkForNode( + CodeMarker::nodeForString(par1.toString()), relative); + addLink(link, arg, &html); + html += "</b>"; + } + else { + html += charLangle; + html += charAt; + } + } + else { + html += src.at(i++); } - clean += "x"; } - return clean; -} - -QString HtmlGenerator::protect(const QString& string) -{ -#define APPEND(x) \ - if (html.isEmpty()) { \ - html = string; \ - html.truncate(i); \ - } \ - html += (x); - QString html; - int n = string.length(); - for (int i = 0; i < n; ++i) { - QChar ch = string.at(i); + if (slow) { + // is this block ever used at all? + // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)" + src = html; + html = QString(); + static const QString funcTag("func"); + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle && src.at(i + 1) == charAt) { + i += 2; + if (parseArg(src, funcTag, &i, n, &arg, &par1)) { + QString link = linkForNode( + marker->resolveTarget(par1.toString(), + tre, + relative), + relative); + addLink(link, arg, &html); + par1 = QStringRef(); + } + else { + html += charLangle; + html += charAt; + } + } + else { + html += src.at(i++); + } + } + } - if (ch == QLatin1Char('&')) { - APPEND("&"); - } else if (ch == QLatin1Char('<')) { - APPEND("<"); - } else if (ch == QLatin1Char('>')) { - APPEND(">"); - } else if (ch == QLatin1Char('"')) { - APPEND("""); - } else if (ch.unicode() > 0x007F - || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) - || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { - // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator - APPEND("&#x"); - html += QString::number(ch.unicode(), 16); - html += QLatin1Char(';'); - } else { - if (!html.isEmpty()) - html += ch; + // replace all "(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)" tags + src = html; + html = QString(); + static const QString typeTags[] = { "type", "headerfile", "func" }; + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle && src.at(i + 1) == charAt) { + i += 2; + bool handled = false; + for (int k = 0; k != 3; ++k) { + if (parseArg(src, typeTags[k], &i, n, &arg, &par1)) { + par1 = QStringRef(); + QString link = linkForNode( + marker->resolveTarget(arg.toString(), tre, relative), + relative); + addLink(link, arg, &html); + handled = true; + break; + } + } + if (!handled) { + html += charLangle; + html += charAt; + } + } + else { + html += src.at(i++); } } - if (!html.isEmpty()) - return html; - return string; + // replace all + // "<@comment>" -> "<span class=\"comment\">"; + // "<@preprocessor>" -> "<span class=\"preprocessor\">"; + // "<@string>" -> "<span class=\"string\">"; + // "<@char>" -> "<span class=\"char\">"; + // "</@(?:comment|preprocessor|string|char)>" -> "</span>" + src = html; + html = QString(); + static const QString spanTags[] = { + "<@comment>", "<span class=\"comment\">", + "<@preprocessor>", "<span class=\"preprocessor\">", + "<@string>", "<span class=\"string\">", + "<@char>", "<span class=\"char\">", + "</@comment>", "</span>", + "</@preprocessor>","</span>", + "</@string>", "</span>", + "</@char>", "</span>" + // "<@char>", "<font color=blue>", + // "</@char>", "</font>", + // "<@func>", "<font color=green>", + // "</@func>", "</font>", + // "<@id>", "<i>", + // "</@id>", "</i>", + // "<@keyword>", "<b>", + // "</@keyword>", "</b>", + // "<@number>", "<font color=yellow>", + // "</@number>", "</font>", + // "<@op>", "<b>", + // "</@op>", "</b>", + // "<@param>", "<i>", + // "</@param>", "</i>", + // "<@string>", "<font color=green>", + // "</@string>", "</font>", + }; + for (int i = 0, n = src.size(); i < n;) { + if (src.at(i) == charLangle) { + bool handled = false; + for (int k = 0; k != 8; ++k) { + const QString & tag = spanTags[2 * k]; + if (tag == QStringRef(&src, i, tag.length())) { + html += spanTags[2 * k + 1]; + i += tag.length(); + handled = true; + break; + } + } + if (!handled) { + ++i; + if (src.at(i) == charAt || + (src.at(i) == QLatin1Char('/') && src.at(i + 1) == charAt)) { + // drop 'our' unknown tags (the ones still containing '@') + while (i < n && src.at(i) != QLatin1Char('>')) + ++i; + ++i; + } + else { + // retain all others + html += charLangle; + } + } + } + else { + html += src.at(i); + ++i; + } + } -#undef APPEND + return html; } -static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); -static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)(</@func>)"); -static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)(</@\\2>)"); -static QRegExp spanTag("</@(?:comment|preprocessor|string|char)>"); -static QRegExp unknownTag("</?@[^>]*>"); - -bool parseArg(const QString &src, - const QString &tag, - int *pos, - int n, - QStringRef *contents, - QStringRef *par1 = 0, - bool debug = false) +#else +void HtmlGenerator::generateSectionList(const Section& section, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) { -#define SKIP_CHAR(c) \ - if (debug) \ - qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \ - if (i >= n || src[i] != c) { \ - if (debug) \ - qDebug() << " char '" << c << "' not found"; \ - return false; \ - } \ - ++i; - - -#define SKIP_SPACE \ - while (i < n && src[i] == ' ') \ - ++i; + if (!section.members.isEmpty()) { + bool twoColumn = false; + if (style == CodeMarker::SeparateList) { + twoColumn = (section.members.count() >= 16); + } + else if (section.members.first()->type() == Node::Property) { + twoColumn = (section.members.count() >= 5); + } + if (twoColumn) + out() << "<p><table class=\"generic\" width=\"100%\" border=\"0\" " + << "cellpadding=\"0\" cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; - int i = *pos; - int j = i; + int i = 0; + NodeList::ConstIterator m = section.members.begin(); + while (m != section.members.end()) { + if ((*m)->access() == Node::Private) { + ++m; + continue; + } - // assume "<@" has been parsed outside - //SKIP_CHAR('<'); - //SKIP_CHAR('@'); + if (twoColumn && i == (int) (section.members.count() + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; - if (tag != QStringRef(&src, i, tag.length())) { - if (0 && debug) - qDebug() << "tag " << tag << " not found at " << i; - return false; + out() << "<li><div class=\"fn\"></div>"; + if (style == CodeMarker::Accessors) + out() << "<b>"; + generateSynopsis(*m, relative, marker, style); + if (style == CodeMarker::Accessors) + out() << "</b>"; + out() << "</li>\n"; + i++; + ++m; + } + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; } - if (debug) - qDebug() << "haystack:" << src << "needle:" << tag << "i:" <<i; - - // skip tag - i += tag.length(); + if (style == CodeMarker::Summary && !section.inherited.isEmpty()) { + out() << "<ul>\n"; + generateSectionInheritedList(section, relative, marker); + out() << "</ul>\n"; + } +} - // parse stuff like: linkTag("(<@link node=\"([^\"]+)\">).*(</@link>)"); - if (par1) { - SKIP_SPACE; - // read parameter name - j = i; - while (i < n && src[i].isLetter()) - ++i; - if (src[i] == '=') { - if (debug) - qDebug() << "read parameter" << QString(src.data() + j, i - j); - SKIP_CHAR('='); - SKIP_CHAR('"'); - // skip parameter name - j = i; - while (i < n && src[i] != '"') - ++i; - *par1 = QStringRef(&src, j, i - j); - SKIP_CHAR('"'); - SKIP_SPACE; +void HtmlGenerator::generateSectionInheritedList(const Section& section, + const Node *relative, + CodeMarker *marker) +{ + QList<QPair<ClassNode *, int> >::ConstIterator p = section.inherited.begin(); + while (p != section.inherited.end()) { + out() << "<li><div bar=\"2\" class=\"fn\"></div>"; + out() << (*p).second << " "; + if ((*p).second == 1) { + out() << section.singularMember; } else { - if (debug) - qDebug() << "no optional parameter found"; + out() << section.pluralMember; } + out() << " inherited from <a href=\"" << fileName((*p).first) + << "#" << HtmlGenerator::cleanRef(section.name.toLower()) << "\">" + << protect(marker->plainFullName((*p).first, relative)) + << "</a></li>\n"; + ++p; } - SKIP_SPACE; - SKIP_CHAR('>'); +} - // find contents up to closing "</@tag> - j = i; - for (; true; ++i) { - if (i + 4 + tag.length() > n) - return false; - if (src[i] != '<') - continue; - if (src[i + 1] != '/') - continue; - if (src[i + 2] != '@') - continue; - if (tag != QStringRef(&src, i + 3, tag.length())) - continue; - if (src[i + 3 + tag.length()] != '>') - continue; - break; +void HtmlGenerator::generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style) +{ + QString marked = marker->markedUpSynopsis(node, relative, style); + QRegExp templateTag("(<[^@>]*>)"); + if (marked.indexOf(templateTag) != -1) { + QString contents = protect(marked.mid(templateTag.pos(1), + templateTag.cap(1).length())); + marked.replace(templateTag.pos(1), templateTag.cap(1).length(), + contents); } + marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])</@param>"), "<i>\\1<sub>\\2</sub></i>"); + marked.replace("<@param>", "<i>"); + marked.replace("</@param>", "</i>"); - *contents = QStringRef(&src, j, i - j); - - i += tag.length() + 4; - - *pos = i; - if (debug) - qDebug() << " tag " << tag << " found: pos now: " << i; - return true; -#undef SKIP_CHAR -} + if (style == CodeMarker::Summary) + marked.replace("@name>", "b>"); -static void addLink(const QString &linkTarget, - const QStringRef &nestedStuff, - QString *res) -{ - if (!linkTarget.isEmpty()) { - *res += "<a href=\""; - *res += linkTarget; - *res += "\">"; - *res += nestedStuff; - *res += "</a>"; + if (style == CodeMarker::SeparateList) { + QRegExp extraRegExp("<@extra>.*</@extra>"); + extraRegExp.setMinimal(true); + marked.replace(extraRegExp, ""); + } else { + marked.replace("<@extra>", " <tt>"); + marked.replace("</@extra>", "</tt>"); } - else { - *res += nestedStuff; + + if (style != CodeMarker::Detailed) { + marked.replace("<@type>", ""); + marked.replace("</@type>", ""); } + out() << highlightedCode(marked, marker, relative); } QString HtmlGenerator::highlightedCode(const QString& markedCode, @@ -2428,8 +2898,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, if (src.at(i) == charLangle && src.at(i + 1) == charAt) { i += 2; if (parseArg(src, linkTag, &i, n, &arg, &par1)) { - QString link = linkForNode( - CodeMarker::nodeForString(par1.toString()), relative); + const Node* node = CodeMarker::nodeForString(par1.toString()); + QString link = linkForNode(node, relative); addLink(link, arg, &html); } else { @@ -2442,7 +2912,6 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, } } - if (slow) { // is this block ever used at all? // replace all <@func> tags: "(<@func target=\"([^\"]*)\">)(.*)(</@func>)" @@ -2570,6 +3039,155 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, return html; } +#endif + +void HtmlGenerator::generateLink(const Atom* atom, + const Node* /* relative */, + CodeMarker* marker) +{ + static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_"); + + if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { + // hack for C++: move () outside of link + int k = funcLeftParen.pos(1); + out() << protect(atom->string().left(k)); + if (link.isEmpty()) { + if (showBrokenLinks) + out() << "</i>"; + } else { + out() << "</a>"; + } + inLink = false; + out() << protect(atom->string().mid(k)); + } else if (marker->recognizeLanguage("Java")) { + // hack for Java: remove () and use <tt> when appropriate + bool func = atom->string().endsWith("()"); + bool tt = (func || atom->string().contains(camelCase)); + if (tt) + out() << "<tt>"; + if (func) { + out() << protect(atom->string().left(atom->string().length() - 2)); + } else { + out() << protect(atom->string()); + } + out() << "</tt>"; + } else { + out() << protect(atom->string()); + } +} + +QString HtmlGenerator::cleanRef(const QString& ref) +{ + QString clean; + + if (ref.isEmpty()) + return clean; + + clean.reserve(ref.size() + 20); + const QChar c = ref[0]; + const uint u = c.unicode(); + + if ((u >= 'a' && u <= 'z') || + (u >= 'A' && u <= 'Z') || + (u >= '0' && u <= '9')) { + clean += c; + } else if (u == '~') { + clean += "dtor."; + } else if (u == '_') { + clean += "underscore."; + } else { + clean += "A"; + } + + for (int i = 1; i < (int) ref.length(); i++) { + const QChar c = ref[i]; + const uint u = c.unicode(); + if ((u >= 'a' && u <= 'z') || + (u >= 'A' && u <= 'Z') || + (u >= '0' && u <= '9') || u == '-' || + u == '_' || u == ':' || u == '.') { + clean += c; + } else if (c.isSpace()) { + clean += "-"; + } else if (u == '!') { + clean += "-not"; + } else if (u == '&') { + clean += "-and"; + } else if (u == '<') { + clean += "-lt"; + } else if (u == '=') { + clean += "-eq"; + } else if (u == '>') { + clean += "-gt"; + } else if (u == '#') { + clean += "#"; + } else { + clean += "-"; + clean += QString::number((int)u, 16); + } + } + return clean; +} + +QString HtmlGenerator::registerRef(const QString& ref) +{ + QString clean = HtmlGenerator::cleanRef(ref); + + for (;;) { + QString& prevRef = refMap[clean.toLower()]; + if (prevRef.isEmpty()) { + prevRef = ref; + break; + } else if (prevRef == ref) { + break; + } + clean += "x"; + } + return clean; +} + +QString HtmlGenerator::protect(const QString& string) +{ +#define APPEND(x) \ + if (html.isEmpty()) { \ + html = string; \ + html.truncate(i); \ + } \ + html += (x); + + QString html; + int n = string.length(); + + for (int i = 0; i < n; ++i) { + QChar ch = string.at(i); + + if (ch == QLatin1Char('&')) { + APPEND("&"); + } else if (ch == QLatin1Char('<')) { + APPEND("<"); + } else if (ch == QLatin1Char('>')) { + APPEND(">"); + } else if (ch == QLatin1Char('"')) { + APPEND("""); + } else if (ch.unicode() > 0x007F + || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) + || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { + // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator + APPEND("&#x"); + html += QString::number(ch.unicode(), 16); + html += QLatin1Char(';'); + } else { + if (!html.isEmpty()) + html += ch; + } + } + + if (!html.isEmpty()) + return html; + return string; + +#undef APPEND +} QString HtmlGenerator::fileBase(const Node *node) { @@ -2618,10 +3236,9 @@ QString HtmlGenerator::fileBase(const Node *node, QString HtmlGenerator::fileName(const Node *node) { if (node->type() == Node::Fake) { - if (static_cast<const FakeNode *>(node)->subType() == FakeNode::ExternalPage) + if (static_cast<const FakeNode *>(node)->subType() == Node::ExternalPage) return node->name(); } - return PageGenerator::fileName(node); } @@ -2643,7 +3260,8 @@ QString HtmlGenerator::refForNode(const Node *node) typedeffe = static_cast<const TypedefNode *>(node); if (typedeffe->associatedEnum()) { return refForNode(typedeffe->associatedEnum()); - } else { + } + else { ref = node->name() + "-typedef"; } break; @@ -2651,15 +3269,27 @@ QString HtmlGenerator::refForNode(const Node *node) func = static_cast<const FunctionNode *>(node); if (func->associatedProperty()) { return refForNode(func->associatedProperty()); - } else { + } + else { ref = func->name(); if (func->overloadNumber() != 1) ref += "-" + QString::number(func->overloadNumber()); } break; case Node::Property: +#ifdef QDOC_QML + case Node::QmlProperty: +#endif ref = node->name() + "-prop"; break; +#ifdef QDOC_QML + case Node::QmlSignal: + ref = node->name() + "-signal"; + break; + case Node::QmlMethod: + ref = node->name() + "-method"; + break; +#endif case Node::Variable: ref = node->name() + "-var"; break; @@ -2708,9 +3338,11 @@ QString HtmlGenerator::refForAtom(Atom *atom, const Node * /* node */) { if (atom->type() == Atom::SectionLeft) { return Doc::canonicalTitle(Text::sectionHeading(atom).toString()); - } else if (atom->type() == Atom::Target) { + } + else if (atom->type() == Atom::Target) { return Doc::canonicalTitle(atom->string()); - } else { + } + else { return QString(); } } @@ -2754,7 +3386,10 @@ void HtmlGenerator::generateDetailedMember(const Node *node, out() << "<a name=\"" + refForNode(node) + "\"></a>"; generateSynopsis(enume, relative, marker, CodeMarker::Detailed); out() << "<br />"; - generateSynopsis(enume->flagsType(), relative, marker, CodeMarker::Detailed); + generateSynopsis(enume->flagsType(), + relative, + marker, + CodeMarker::Detailed); out() << "</h3>\n"; } else { @@ -2778,7 +3413,7 @@ void HtmlGenerator::generateDetailedMember(const Node *node, section.members += property->resetters(); if (!section.members.isEmpty()) { - out() << "<p>Access functions:</p>\n"; + out() << "<p><b>Access functions:</b></p>\n"; generateSectionList(section, node, marker, CodeMarker::Accessors); } } @@ -2789,7 +3424,8 @@ void HtmlGenerator::generateDetailedMember(const Node *node, << " type is a typedef for " << "<a href=\"qflags.html\">QFlags</a><" << protect(enume->name()) - << ">. It stores an OR combination of " << protect(enume->name()) + << ">. It stores an OR combination of " + << protect(enume->name()) << " values.</p>\n"; } } @@ -2803,7 +3439,8 @@ void HtmlGenerator::findAllClasses(const InnerNode *node) if ((*c)->access() != Node::Private && (*c)->url().isEmpty()) { if ((*c)->type() == Node::Class && !(*c)->doc().isEmpty()) { QString className = (*c)->name(); - if ((*c)->parent() && (*c)->parent()->type() == Node::Namespace && + if ((*c)->parent() && + (*c)->parent()->type() == Node::Namespace && !(*c)->parent()->name().isEmpty()) className = (*c)->parent()->name()+"::"+className; @@ -2811,6 +3448,9 @@ void HtmlGenerator::findAllClasses(const InnerNode *node) if ((*c)->status() == Node::Compat) { compatClasses.insert(className, *c); } + else if ((*c)->status() == Node::Obsolete) { + obsoleteClasses.insert(className, *c); + } else { nonCompatClasses.insert(className, *c); if ((*c)->status() == Node::Main) @@ -2851,7 +3491,7 @@ void HtmlGenerator::findAllFunctions(const InnerNode *node) const FunctionNode *func = static_cast<const FunctionNode *>(*c); if (func->status() > Node::Obsolete && func->metaness() != FunctionNode::Ctor && func->metaness() != FunctionNode::Dtor) { - funcIndex[(*c)->name()].insert((*c)->parent()->name(), *c); + funcIndex[(*c)->name()].insert(tre->fullDocumentName((*c)->parent()), *c); } } } @@ -2901,7 +3541,7 @@ void HtmlGenerator::findAllNamespaces(const InnerNode *node) } } -#ifdef ZZZ_QDOC_QML +#ifdef ZZZ_QDOC_QML /*! This function finds all the qml element nodes and stores them in a map for later use. @@ -2912,24 +3552,16 @@ void HtmlGenerator::findAllQmlClasses(const InnerNode *node) while (c != node->childNodes().constEnd()) { if ((*c)->type() == Node::Fake) { const FakeNode* fakeNode = static_cast<const FakeNode *>(*c); - if (fakeNode->subType() == FakeNode::QmlClass) { - const QmlNode* qmlNode = static_cast<const QmlNode*>(fakeNode); - //qDebug() << "HtmlGenerator: QML CLASS" << qmlNode->name(); + if (fakeNode->subType() == Node::QmlClass) { + const QmlClassNode* qmlNode = + static_cast<const QmlClassNode*>(fakeNode); const Node* n = qmlNode->classNode(); - if (n) - //qDebug() << " FOUND IT!" << n->name(); } qmlClasses.insert(fakeNode->name(),*c); } ++c; } } -#endif - -#if 0 - else if ((*c)->isInnerNode()) { - findAllClasses(static_cast<InnerNode *>(*c)); - } #endif int HtmlGenerator::hOffset(const Node *node) @@ -3007,10 +3639,11 @@ const QPair<QString,QString> HtmlGenerator::anchorForNode(const Node *node) QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, CodeMarker *marker, - const Node *node) + const Node** node) { QString link; - node = 0; + *node = 0; + inObsoleteLink = false; if (atom->string().contains(":") && (atom->string().startsWith("file:") @@ -3034,40 +3667,86 @@ QString HtmlGenerator::getLink(const Atom *atom, QString first = path.first().trimmed(); if (first.isEmpty()) { - node = relative; + *node = relative; } else if (first.endsWith(".html")) { - node = tre->root()->findNode(first, Node::Fake); + *node = tre->root()->findNode(first, Node::Fake); } else { - node = marker->resolveTarget(first, tre, relative); - if (!node) - node = tre->findFakeNodeByTitle(first); - if (!node) - node = tre->findUnambiguousTarget(first, targetAtom); + *node = marker->resolveTarget(first, tre, relative); + if (!*node) + *node = tre->findFakeNodeByTitle(first); + if (!*node) + *node = tre->findUnambiguousTarget(first, targetAtom); } - if (node) { - if (!node->url().isEmpty()) - return node->url(); + if (*node) { + if (!(*node)->url().isEmpty()) + return (*node)->url(); else path.removeFirst(); } else { - node = relative; + *node = relative; + } + + if (*node) { + if ((*node)->status() == Node::Obsolete) { + if (relative) { + if (relative->parent() != *node) { + if (relative->status() != Node::Obsolete) { + bool porting = false; + if (relative->type() == Node::Fake) { + const FakeNode* fake = static_cast<const FakeNode*>(relative); + if (fake->title().startsWith("Porting")) + porting = true; + } + QString name = marker->plainFullName(relative); + if (!porting && !name.startsWith("Q3")) { + if (obsoleteLinks) { + relative->doc().location().warning(tr("Link to obsolete item '%1' in %2") + .arg(atom->string()) + .arg(name)); + } + inObsoleteLink = true; + } +#if 0 + qDebug() << "Link to Obsolete entity" + << (*node)->name(); + qDebug() << " relative entity" + << relative->name(); +#endif + } + } + } + else { + qDebug() << "Link to Obsolete entity" + << (*node)->name() << "no relative"; + } + } +#if 0 + else if ((*node)->status() == Node::Deprecated) { + qDebug() << "Link to Deprecated entity"; + } + else if ((*node)->status() == Node::Internal) { + qDebug() << "Link to Internal entity"; + } + //else + //qDebug() << "Node Status:" << (*node)->status(); +#endif } while (!path.isEmpty()) { - targetAtom = tre->findTarget(path.first(), node); + targetAtom = tre->findTarget(path.first(), *node); if (targetAtom == 0) break; path.removeFirst(); } if (path.isEmpty()) { - link = linkForNode(node, relative); + link = linkForNode(*node, relative); if (targetAtom) - link += "#" + refForAtom(targetAtom, node); + link += "#" + refForAtom(targetAtom, *node); } } return link; @@ -3186,10 +3865,225 @@ void HtmlGenerator::endLink() out() << "</i>"; } else { + if (inObsoleteLink) { + out() << "<sup>(obsolete)</sup>"; + } out() << "</a>"; } } inLink = false; + inObsoleteLink = false; } QT_END_NAMESPACE + +#ifdef QDOC_QML + +/*! + Generates the summary for for the \a section. Only used for + sections of QML element documentation. + + Currently handles only the QML property group. + */ +void HtmlGenerator::generateQmlSummary(const Section& section, + const Node *relative, + CodeMarker *marker) +{ + if (!section.members.isEmpty()) { + NodeList::ConstIterator m; + int count = section.members.size(); + bool twoColumn = false; + if (section.members.first()->type() == Node::QmlProperty) { + twoColumn = (count >= 5); + } + if (twoColumn) + out() << "<p><table width=\"100%\" border=\"0\" cellpadding=\"0\"" + " cellspacing=\"0\">\n" + << "<tr><td width=\"45%\" valign=\"top\">"; + out() << "<ul>\n"; + + int row = 0; + m = section.members.begin(); + while (m != section.members.end()) { + if (twoColumn && row == (int) (count + 1) / 2) + out() << "</ul></td><td valign=\"top\"><ul>\n"; + out() << "<li><div class=\"fn\"></div>"; + generateQmlItem(*m,relative,marker,true); + out() << "</li>\n"; + row++; + ++m; + } + out() << "</ul>\n"; + if (twoColumn) + out() << "</td></tr>\n</table></p>\n"; + } +} + +/*! + Outputs the html detailed documentation for a section + on a QML element reference page. + */ +void HtmlGenerator::generateDetailedQmlMember(const Node *node, + const InnerNode *relative, + CodeMarker *marker) +{ + const QmlPropertyNode* qpn = 0; + generateMacRef(node, marker); + out() << "<div class=\"qmlitem\">"; + if (node->subType() == Node::QmlPropertyGroup) { + const QmlPropGroupNode* qpgn = static_cast<const QmlPropGroupNode*>(node); + NodeList::ConstIterator p = qpgn->childNodes().begin(); + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + + while (p != qpgn->childNodes().end()) { + if ((*p)->type() == Node::QmlProperty) { + qpn = static_cast<const QmlPropertyNode*>(*p); + out() << "<tr><td>"; + out() << "<a name=\"" + refForNode(qpn) + "\"></a>"; + generateQmlItem(qpn, relative, marker, false); + out() << "</td></tr>"; + if (qpgn->isDefault()) { + out() << "</table>" + << "</div></div>" + << "<div class=\"qmlitem\">" + << "<div class=\"qmlproto\">" + << "<table class=\"qmlname\">" + << "<tr><td><font color=\"green\">" + << "default</font></td></tr>"; + } + } + ++p; + } + out() << "</table>"; + out() << "</div>"; + } + else if (node->type() == Node::QmlSignal) { + const QmlSignalNode* qsn = static_cast<const QmlSignalNode*>(node); + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + out() << "<tr><td>"; + out() << "<a name=\"" + refForNode(qsn) + "\"></a>"; + generateQmlItem(qsn,relative,marker,false); + out() << "</td></tr>"; + out() << "</table>"; + out() << "</div>"; + } + else if (node->type() == Node::QmlMethod) { + const QmlMethodNode* qmn = static_cast<const QmlMethodNode*>(node); + out() << "<div class=\"qmlproto\">"; + out() << "<table class=\"qmlname\">"; + out() << "<tr><td>"; + out() << "<a name=\"" + refForNode(qmn) + "\"></a>"; + generateQmlItem(qmn,relative,marker,false); + out() << "</td></tr>"; + out() << "</table>"; + out() << "</div>"; + } + out() << "<div class=\"qmldoc\">"; + generateStatus(node, marker); + generateBody(node, marker); + generateThreadSafeness(node, marker); + generateSince(node, marker); + generateAlsoList(node, marker); + out() << "</div>"; + out() << "</div>"; +} + +/*! + Output the "Inherits" line for the QML element, + if there should be one. + */ +void HtmlGenerator::generateQmlInherits(const QmlClassNode* cn, + CodeMarker* marker) +{ + if (cn && !cn->links().empty()) { + if (cn->links().contains(Node::InheritsLink)) { + QPair<QString,QString> linkPair; + linkPair = cn->links()[Node::InheritsLink]; + QStringList strList(linkPair.first); + const Node* n = tre->findNode(strList,Node::Fake); + if (n && n->subType() == Node::QmlClass) { + const QmlClassNode* qcn = static_cast<const QmlClassNode*>(n); + out() << "<p style=\"text-align: center\">"; + Text text; + text << "[Inherits "; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, linkPair.second); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << "]"; + generateText(text, cn, marker); + out() << "</p>"; + } +// else +// qDebug() << "generateQmlInherits(): " +// << "Inherited element not documented -->" +// << linkPair.first; + } + } +} + +/*! + Output the "[Xxx instantiates the C++ class QFxXxx]" + line for the QML element, if there should be one. + + If there is no class node, or if the class node status + is set to Node::Internal, do nothing. + */ +void HtmlGenerator::generateQmlInstantiates(const QmlClassNode* qcn, + CodeMarker* marker) +{ + const ClassNode* cn = qcn->classNode(); + if (cn && (cn->status() != Node::Internal)) { + out() << "<p style=\"text-align: center\">"; + Text text; + text << "["; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, qcn->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << " instantiates the C++ class "; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, cn->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << "]"; + generateText(text, qcn, marker); + out() << "</p>"; + } +} + +/*! + Output the "[QFxXxx is instantiated by QML element Xxx]" + line for the class, if there should be one. + + If there is no QML element, or if the class node status + is set to Node::Internal, do nothing. + */ +void HtmlGenerator::generateInstantiatedBy(const ClassNode* cn, + CodeMarker* marker) +{ + if (cn && cn->status() != Node::Internal && !cn->qmlElement().isEmpty()) { + const Node* n = tre->root()->findNode(cn->qmlElement(),Node::Fake); + if (n && n->subType() == Node::QmlClass) { + out() << "<p style=\"text-align: center\">"; + Text text; + text << "["; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, cn->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << " is instantiated by QML element "; + text << Atom(Atom::LinkNode,CodeMarker::stringForNode(n)); + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + text << Atom(Atom::String, n->name()); + text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << "]"; + generateText(text, cn, marker); + out() << "</p>"; + } + } +} + +#endif diff --git a/tools/qdoc3/htmlgenerator.h b/tools/qdoc3/htmlgenerator.h index 8ff32f8..c22fe20 100644 --- a/tools/qdoc3/htmlgenerator.h +++ b/tools/qdoc3/htmlgenerator.h @@ -46,6 +46,8 @@ #ifndef HTMLGENERATOR_H #define HTMLGENERATOR_H +#define QDOC_NAME_ALIGNMENT + #include <qmap.h> #include <qregexp.h> @@ -139,27 +141,69 @@ class HtmlGenerator : public PageGenerator void generateFunctionIndex(const Node *relative, CodeMarker *marker); void generateLegaleseList(const Node *relative, CodeMarker *marker); void generateOverviewList(const Node *relative, CodeMarker *marker); - void generateSynopsis(const Node *node, - const Node *relative, - CodeMarker *marker, - CodeMarker::SynopsisStyle style); void generateSectionList(const Section& section, const Node *relative, CodeMarker *marker, CodeMarker::SynopsisStyle style); +#ifdef QDOC_QML + void generateQmlSummary(const Section& section, + const Node *relative, + CodeMarker *marker); + void generateQmlItem(const Node *node, + const Node *relative, + CodeMarker *marker, + bool summary); + void generateDetailedQmlMember(const Node *node, + const InnerNode *relative, + CodeMarker *marker); + void generateQmlInherits(const QmlClassNode* cn, CodeMarker* marker); + void generateQmlInstantiates(const QmlClassNode* qcn, CodeMarker* marker); + void generateInstantiatedBy(const ClassNode* cn, CodeMarker* marker); +#endif +#ifdef QDOC_NAME_ALIGNMENT + void generateSection(const NodeList& nl, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style); + void generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style, + bool nameAlignment = false); + void generateSectionInheritedList(const Section& section, + const Node *relative, + CodeMarker *marker, + bool nameAlignment = false); + QString highlightedCode(const QString& markedCode, + CodeMarker *marker, + const Node *relative, + CodeMarker::SynopsisStyle style = CodeMarker::Accessors, + bool nameAlignment = false); +#else + void generateSynopsis(const Node *node, + const Node *relative, + CodeMarker *marker, + CodeMarker::SynopsisStyle style); void generateSectionInheritedList(const Section& section, const Node *relative, CodeMarker *marker); + QString highlightedCode(const QString& markedCode, + CodeMarker *marker, + const Node *relative); +#endif void generateFullName(const Node *apparentNode, const Node *relative, CodeMarker *marker, const Node *actualNode = 0); - void generateDetailedMember(const Node *node, const InnerNode *relative, CodeMarker *marker); - void generateLink(const Atom *atom, const Node *relative, CodeMarker *marker); + void generateDetailedMember(const Node *node, + const InnerNode *relative, + CodeMarker *marker); + void generateLink(const Atom *atom, + const Node *relative, + CodeMarker *marker); void generateStatus(const Node *node, CodeMarker *marker); QString registerRef(const QString& ref); - QString highlightedCode(const QString& markedCode, CodeMarker *marker, const Node *relative); QString fileBase(const Node *node); #if 0 QString fileBase(const Node *node, const SectionIterator& section); @@ -177,7 +221,7 @@ class HtmlGenerator : public PageGenerator virtual QString getLink(const Atom *atom, const Node *relative, CodeMarker *marker, - const Node *node = 0); + const Node** node); virtual void generateDcf(const QString &fileBase, const QString &startPage, const QString &title, DcfSection &dcfRoot); @@ -205,6 +249,7 @@ class HtmlGenerator : public PageGenerator DcfSection dcfQmakeRoot; HelpProjectWriter *helpProjectWriter; bool inLink; + bool inObsoleteLink; bool inContents; bool inSectionHeading; bool inTableHeader; @@ -226,11 +271,13 @@ class HtmlGenerator : public PageGenerator QStringList customHeadElements; const Tree *tre; bool slow; + bool obsoleteLinks; QMap<QString, QMap<QString, const Node *> > moduleClassMap; QMap<QString, QMap<QString, const Node *> > moduleNamespaceMap; QMap<QString, const Node *> nonCompatClasses; QMap<QString, const Node *> mainClasses; QMap<QString, const Node *> compatClasses; + QMap<QString, const Node *> obsoleteClasses; QMap<QString, const Node *> namespaceIndex; QMap<QString, const Node *> serviceClasses; #ifdef QDOC_QML diff --git a/tools/qdoc3/jambiapiparser.cpp b/tools/qdoc3/jambiapiparser.cpp index f981e6d..70e9260 100644 --- a/tools/qdoc3/jambiapiparser.cpp +++ b/tools/qdoc3/jambiapiparser.cpp @@ -234,8 +234,9 @@ void JambiApiParser::doneParsingSourceFiles(Tree * /* tree */) foreach (Node *cppNode, cppTre->root()->childNodes()) { if (cppNode->type() == Node::Fake) { FakeNode *cppFake = static_cast<FakeNode *>(cppNode); - if (cppFake->subType() == FakeNode::Page) { - FakeNode *javaFake = new FakeNode(javaTre->root(), cppFake->name(), + if (cppFake->subType() == Node::Page) { + FakeNode *javaFake = new FakeNode(javaTre->root(), + cppFake->name(), cppFake->subType()); javaFake->setModuleName("com.trolltech.qt"); // ### hard-coded javaFake->setTitle(cppFake->title()); diff --git a/tools/qdoc3/javadocgenerator.cpp b/tools/qdoc3/javadocgenerator.cpp index b32425c..294877b 100644 --- a/tools/qdoc3/javadocgenerator.cpp +++ b/tools/qdoc3/javadocgenerator.cpp @@ -272,9 +272,10 @@ void JavadocGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker HtmlGenerator::generateFakeNode(fake, marker); } -void JavadocGenerator::generateText(const Text& text, const Node *relative, CodeMarker *marker) +bool JavadocGenerator::generateText(const Text& text, const Node *relative, CodeMarker *marker) { HtmlGenerator::generateText(text, relative, marker); + return true; } void JavadocGenerator::generateBody(const Node *node, CodeMarker *marker) diff --git a/tools/qdoc3/javadocgenerator.h b/tools/qdoc3/javadocgenerator.h index ba9b15d..5431c38 100644 --- a/tools/qdoc3/javadocgenerator.h +++ b/tools/qdoc3/javadocgenerator.h @@ -68,7 +68,7 @@ protected: void generateClassLikeNode(const InnerNode *inner, CodeMarker *marker); void generateFakeNode( const FakeNode *fake, CodeMarker *marker ); - void generateText( const Text& text, const Node *relative, CodeMarker *marker ); + bool generateText( const Text& text, const Node *relative, CodeMarker *marker ); void generateBody( const Node *node, CodeMarker *marker ); void generateAlsoList( const Node *node, CodeMarker *marker ); diff --git a/tools/qdoc3/main.cpp b/tools/qdoc3/main.cpp index e3b2f08..9338203 100644 --- a/tools/qdoc3/main.cpp +++ b/tools/qdoc3/main.cpp @@ -95,11 +95,11 @@ static const struct { }; static bool slow = false; +static bool showInternal = false; +static bool obsoleteLinks = false; static QStringList defines; static QHash<QString, Tree *> trees; -//static int doxygen = 0; - /*! Find the Tree for language \a lang and return a pointer to it. If there is no Tree for language \a lang in the Tree table, add @@ -122,14 +122,18 @@ static void printHelp() { Location::information(tr("Usage: qdoc [options] file1.qdocconf ...\n" "Options:\n" - " -help " + " -help " "Display this information and exit\n" - " -version " + " -version " "Display version of qdoc and exit\n" - " -D<name> " + " -D<name> " "Define <name> as a macro while parsing sources\n" - " -slow " - "Turn on features that slow down qdoc") ); + " -slow " + "Turn on features that slow down qdoc\n" + " -showinternal " + "Include stuff marked internal\n" + " -obsoletelinks " + "Report links from obsolete items to non-obsolete items") ); } /*! @@ -162,6 +166,10 @@ static void processQdocconfFile(const QString &fileName) ++i; } config.setStringList(CONFIG_SLOW, QStringList(slow ? "true" : "false")); + config.setStringList(CONFIG_SHOWINTERNAL, + QStringList(showInternal ? "true" : "false")); + config.setStringList(CONFIG_OBSOLETELINKS, + QStringList(obsoleteLinks ? "true" : "false")); /* With the default configuration values in place, load @@ -224,18 +232,6 @@ static void processQdocconfFile(const QString &fileName) QString lang = config.getString(CONFIG_LANGUAGE); Location langLocation = config.lastLocation(); -#ifdef QDOC2DOX - // qdoc -> doxygen - if (doxygen == 2) { - qDebug() << "READING anchors.txt"; - DoxWriter::readAnchors(); - qDebug() << "READING title maps"; - DoxWriter::readTitles(); - qDebug() << "READING member multimaps"; - DoxWriter::readMembers(); - } -#endif - /* Initialize the tree where all the parsed sources will be stored. The tree gets built as the source files are parsed, and then the @@ -322,17 +318,6 @@ static void processQdocconfFile(const QString &fileName) tree->resolveGroups(); tree->resolveTargets(); -#ifdef QDOC2DOX - // qdoc -> doxygen - if (doxygen == 1) { - DoxWriter::writeAnchors(); - DoxWriter::writeTitles(); - DoxWriter::writeMembers(); - } - - if (doxygen == 0) { -#endif - /* Now the tree has been built, and all the stuff that needed resolving has been resolved. Now it is time to traverse @@ -351,17 +336,13 @@ 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); - + tree->setVersion(""); Generator::terminate(); - -#ifdef QDOC2DOX - } -#endif - CodeParser::terminate(); CodeMarker::terminate(); CppToQsConverter::terminate(); @@ -372,7 +353,6 @@ static void processQdocconfFile(const QString &fileName) foreach (QTranslator *translator, translators) delete translator; - delete tree; } @@ -456,26 +436,12 @@ int main(int argc, char **argv) else if (opt == "-slow") { slow = true; } - -#ifdef QDOC2DOX - else if (opt == "-doxygen1") { - // qdoc -> doxygen - // Don't use this; it isn't ready yet. - // Now it's a fossil. - qDebug() << "doxygen pass 1"; - doxygen = 1; - DoxWriter::setDoxPass(1); + else if (opt == "-showinternal") { + showInternal = true; } - else if (opt == "-doxygen2") { - // qdoc -> doxygen - // Don't use this; it isn't ready yet. - // Now it's a fossil. - qDebug() << "doxygen pass 2"; - doxygen = 2; - DoxWriter::setDoxPass(2); + else if (opt == "-obsoletelinks") { + obsoleteLinks = true; } -#endif - else { qdocFiles.append(opt); } diff --git a/tools/qdoc3/node.cpp b/tools/qdoc3/node.cpp index 0f9468a..610249d 100644 --- a/tools/qdoc3/node.cpp +++ b/tools/qdoc3/node.cpp @@ -43,6 +43,7 @@ node.cpp */ +#include <QtCore> #include "node.h" QT_BEGIN_NAMESPACE @@ -113,6 +114,9 @@ void Node::setRelates(InnerNode *pseudoParent) } /*! + This function creates a pair that describes a link. + The pair is composed from \a link and \a desc. The + \a linkType is the map index the pair is filed under. */ void Node::setLink(LinkType linkType, const QString &link, const QString &desc) { @@ -623,7 +627,7 @@ void InnerNode::removeRelated(Node *pseudoChild) */ /*! - Returns false because this is an InnerNode. + Returns false because this is a LeafNode. */ bool LeafNode::isInnerNode() const { @@ -713,9 +717,11 @@ void ClassNode::fixBaseClasses() */ /*! + The type of a FakeNode is Fake, and it has a \a subtype, + which specifies the type of FakeNode. */ -FakeNode::FakeNode(InnerNode *parent, const QString& name, SubType subType) - : InnerNode(Fake, parent, name), sub(subType) +FakeNode::FakeNode(InnerNode *parent, const QString& name, SubType subtype) + : InnerNode(Fake, parent, name), sub(subtype) { } @@ -868,6 +874,18 @@ void FunctionNode::setOverload(bool overlode) } /*! + Sets the function node's reimplementation flag to \a r. + When \a r is true, it is supposed to mean that this function + is a reimplementation of a virtual function in a base class, + but it really just means the \e reimp command was seen in the + qdoc comment. + */ +void FunctionNode::setReimp(bool r) +{ + reimp = r; +} + +/*! */ void FunctionNode::addParameter(const Parameter& parameter) { @@ -1021,4 +1039,98 @@ bool TargetNode::isInnerNode() const return false; } +#ifdef QDOC_QML +/*! + Constructor for the Qml class node. + */ +QmlClassNode::QmlClassNode(InnerNode *parent, + const QString& name, + const ClassNode* cn) + : FakeNode(parent, name, QmlClass), cnode(cn) +{ + setTitle("QML " + name + " Element Reference"); +} + +/*! + The base file name for this kind of node has "qml_" + prepended to it. + + But not yet. Still testing. + */ +QString QmlClassNode::fileBase() const +{ +#if 0 + if (Node::fileBase() == "item") + qDebug() << "FILEBASE: qmlitem" << name(); + return "qml_" + Node::fileBase(); +#endif + return Node::fileBase(); +} + +/*! + Constructor for the Qml property group node. \a parent is + always a QmlClassNode. + */ +QmlPropGroupNode::QmlPropGroupNode(QmlClassNode* parent, const QString& name) + : FakeNode(parent, name, QmlPropertyGroup), isdefault(false) +{ + // nothing. +} + +/*! + Constructor for the QML property node. + */ +QmlPropertyNode::QmlPropertyNode(QmlPropGroupNode *parent, + const QString& name, + const QString& type) + : LeafNode(QmlProperty, parent, name), + dt(type), + sto(Trool_Default), + des(Trool_Default) +{ + // nothing. +} + +/*! + I don't know what this is. + */ +QmlPropertyNode::Trool QmlPropertyNode::toTrool(bool boolean) +{ + return boolean ? Trool_True : Trool_False; +} + +/*! + I don't know what this is either. + */ +bool QmlPropertyNode::fromTrool(Trool troolean, bool defaultValue) +{ + switch (troolean) { + case Trool_True: + return true; + case Trool_False: + return false; + default: + return defaultValue; + } +} + +/*! + Constructor for the QML signal node. + */ +QmlSignalNode::QmlSignalNode(QmlClassNode *parent, const QString& name) + : LeafNode(QmlSignal, parent, name) +{ + // nothing. +} + +/*! + Constructor for the QML method node. + */ +QmlMethodNode::QmlMethodNode(QmlClassNode *parent, const QString& name) + : LeafNode(QmlMethod, parent, name) +{ + // nothing. +} +#endif + QT_END_NAMESPACE diff --git a/tools/qdoc3/node.h b/tools/qdoc3/node.h index 0a671b37d..17ec447 100644 --- a/tools/qdoc3/node.h +++ b/tools/qdoc3/node.h @@ -72,7 +72,31 @@ class Node Function, Property, Variable, +#ifdef QDOC_QML + Target, + QmlProperty, + QmlSignal, + QmlMethod +#else Target +#endif + }; + + enum SubType { + NoSubType, + Example, + HeaderFile, + File, + Group, + Module, + Page, +#ifdef QDOC_QML + ExternalPage, + QmlClass, + QmlPropertyGroup +#else + ExternalPage +#endif }; enum Access { Public, Protected, Private }; @@ -99,7 +123,8 @@ class Node NextLink, PreviousLink, ContentsLink, - IndexLink /*, + IndexLink, + InheritsLink /*, GlossaryLink, CopyrightLink, ChapterLink, @@ -123,7 +148,9 @@ class Node void setTemplateStuff(const QString &templateStuff) { tpl = templateStuff; } virtual bool isInnerNode() const = 0; + virtual bool isReimp() const { return false; } Type type() const { return typ; } + virtual SubType subType() const { return NoSubType; } InnerNode *parent() const { return par; } InnerNode *relates() const { return rel; } const QString& name() const { return nam; } @@ -143,7 +170,7 @@ class Node void clearRelated() { rel = 0; } - QString fileBase() const; + virtual QString fileBase() const; protected: Node(Type type, InnerNode *parent, const QString& name); @@ -180,7 +207,7 @@ typedef QList<Node *> NodeList; class InnerNode : public Node { public: - ~InnerNode(); + virtual ~InnerNode(); Node *findNode(const QString& name); Node *findNode(const QString& name, Type type); @@ -202,6 +229,7 @@ class InnerNode : public Node const EnumNode *findEnumNodeForValue(const QString &enumValue) const; const NodeList & childNodes() const { return children; } const NodeList & relatedNodes() const { return related; } + int count() const { return children.size(); } int overloadNumber(const FunctionNode *func) const; int numOverloads(const QString& funcName) const; NodeList overloads(const QString &funcName) const; @@ -231,17 +259,19 @@ class LeafNode : public Node { public: LeafNode(); + virtual ~LeafNode() { } virtual bool isInnerNode() const; protected: - LeafNode(Type type, InnerNode *parent, const QString& name); + LeafNode(Type type, InnerNode* parent, const QString& name); }; class NamespaceNode : public InnerNode { public: NamespaceNode(InnerNode *parent, const QString& name); + virtual ~NamespaceNode() { } }; class ClassNode; @@ -265,6 +295,7 @@ class ClassNode : public InnerNode { public: ClassNode(InnerNode *parent, const QString& name); + virtual ~ClassNode() { } void addBaseClass(Access access, ClassNode *node, @@ -279,29 +310,23 @@ class ClassNode : public InnerNode QString serviceName() const { return sname; } void setServiceName(const QString& value) { sname = value; } + QString qmlElement() const { return qmlelement; } + void setQmlElement(const QString& value) { qmlelement = value; } private: QList<RelatedClass> bas; QList<RelatedClass> der; bool hidden; QString sname; + QString qmlelement; }; class FakeNode : public InnerNode { public: - enum SubType { - Example, - HeaderFile, - File, - Group, - Module, - Page, - ExternalPage, - QmlClass - }; FakeNode(InnerNode *parent, const QString& name, SubType subType); + virtual ~FakeNode() { } void setTitle(const QString &title) { tle = title; } void setSubTitle(const QString &subTitle) { stle = subTitle; } @@ -320,18 +345,85 @@ class FakeNode : public InnerNode NodeList gr; }; -class QmlNode : public FakeNode +#ifdef QDOC_QML +class QmlClassNode : public FakeNode { public: - QmlNode(InnerNode *parent, const QString& name, const ClassNode* cn) - : FakeNode(parent, name, QmlClass), cnode(cn) { } + QmlClassNode(InnerNode *parent, + const QString& name, + const ClassNode* cn); + virtual ~QmlClassNode() { } const ClassNode* classNode() const { return cnode; } + virtual QString fileBase() const; private: const ClassNode* cnode; }; +class QmlPropGroupNode : public FakeNode +{ + public: + QmlPropGroupNode(QmlClassNode* parent, const QString& name); + virtual ~QmlPropGroupNode() { } + + const QString& element() const { return name(); } + void setDefault() { isdefault = true; } + bool isDefault() const { return isdefault; } + + private: + bool isdefault; +}; + +class QmlPropertyNode : public LeafNode +{ + public: + QmlPropertyNode(QmlPropGroupNode* parent, + const QString& name, + const QString& type); + virtual ~QmlPropertyNode() { } + + void setDataType(const QString& dataType) { dt = dataType; } + void setStored(bool stored) { sto = toTrool(stored); } + void setDesignable(bool designable) { des = toTrool(designable); } + + const QString &dataType() const { return dt; } + QString qualifiedDataType() const { return dt; } + bool isStored() const { return fromTrool(sto,true); } + bool isDesignable() const { return fromTrool(des,false); } + + const QString& element() const { return parent()->name(); } + + private: + enum Trool { Trool_True, Trool_False, Trool_Default }; + + static Trool toTrool(bool boolean); + static bool fromTrool(Trool troolean, bool defaultValue); + + QString dt; + Trool sto; + Trool des; +}; + +class QmlSignalNode : public LeafNode +{ + public: + QmlSignalNode(QmlClassNode* parent, const QString& name); + virtual ~QmlSignalNode() { } + + const QString& element() const { return parent()->name(); } +}; + +class QmlMethodNode : public LeafNode +{ + public: + QmlMethodNode(QmlClassNode* parent, const QString& name); + virtual ~QmlMethodNode() { } + + const QString& element() const { return parent()->name(); } +}; +#endif + class EnumItem { public: @@ -357,6 +449,7 @@ class EnumNode : public LeafNode { public: EnumNode(InnerNode *parent, const QString& name); + virtual ~EnumNode() { } void addItem(const EnumItem& item); void setFlagsType(TypedefNode *typedeff); @@ -377,6 +470,7 @@ class TypedefNode : public LeafNode { public: TypedefNode(InnerNode *parent, const QString& name); + virtual ~TypedefNode() { } const EnumNode *associatedEnum() const { return ae; } @@ -437,6 +531,7 @@ class FunctionNode : public LeafNode enum Virtualness { NonVirtual, ImpureVirtual, PureVirtual }; FunctionNode(InnerNode *parent, const QString &name); + virtual ~FunctionNode() { } void setReturnType(const QString& returnType) { rt = returnType; } void setMetaness(Metaness metaness) { met = metaness; } @@ -444,6 +539,7 @@ class FunctionNode : public LeafNode void setConst(bool conste) { con = conste; } void setStatic(bool statique) { sta = statique; } void setOverload(bool overlode); + void setReimp(bool r); void addParameter(const Parameter& parameter); inline void setParameters(const QList<Parameter>& parameters); void borrowParameterNames(const FunctionNode *source); @@ -458,6 +554,7 @@ class FunctionNode : public LeafNode bool isConst() const { return con; } bool isStatic() const { return sta; } bool isOverload() const { return ove; } + bool isReimp() const { return reimp; } int overloadNumber() const; int numOverloads() const; const QList<Parameter>& parameters() const { return params; } @@ -483,6 +580,7 @@ class FunctionNode : public LeafNode bool con : 1; bool sta : 1; bool ove : 1; + bool reimp: 1; QList<Parameter> params; const FunctionNode *rf; const PropertyNode *ap; @@ -496,6 +594,7 @@ class PropertyNode : public LeafNode enum { NumFunctionRoles = Resetter + 1 }; PropertyNode(InnerNode *parent, const QString& name); + virtual ~PropertyNode() { } void setDataType(const QString& dataType) { dt = dataType; } void addFunction(FunctionNode *function, FunctionRole role); @@ -553,6 +652,7 @@ class VariableNode : public LeafNode { public: VariableNode(InnerNode *parent, const QString &name); + virtual ~VariableNode() { } void setLeftType(const QString &leftType) { lt = leftType; } void setRightType(const QString &rightType) { rt = rightType; } @@ -578,6 +678,7 @@ class TargetNode : public LeafNode { public: TargetNode(InnerNode *parent, const QString& name); + virtual ~TargetNode() { } virtual bool isInnerNode() const; }; diff --git a/tools/qdoc3/pagegenerator.cpp b/tools/qdoc3/pagegenerator.cpp index 06ff398..8715f4a 100644 --- a/tools/qdoc3/pagegenerator.cpp +++ b/tools/qdoc3/pagegenerator.cpp @@ -81,30 +81,50 @@ QString PageGenerator::fileBase(const Node *node) { if (node->relates()) node = node->relates(); - else if (!node->isInnerNode()) + else if (!node->isInnerNode()) { node = node->parent(); +#ifdef QDOC_QML + if (node->subType() == Node::QmlPropertyGroup) { + node = node->parent(); + } +#endif + } QString base = node->doc().baseName(); if (!base.isEmpty()) return base; - const Node *p = node; - - forever { - base.prepend(p->name()); + const Node *p = node; + + forever { + base.prepend(p->name()); +#ifdef QDOC_QML + /* + To avoid file name conflicts in the html directory, + we prepend "qml-" to the file name of QML element doc + files. + */ + if ((p->subType() == Node::QmlClass) || + (p->subType() == Node::QmlPropertyGroup)) + base.prepend("qml-"); + else if ((p->type() == Node::QmlProperty) || + (p->type() == Node::QmlSignal) || + (p->type() == Node::QmlMethod)) + base.prepend("qml-"); +#endif const Node *pp = p->parent(); if (!pp || pp->name().isEmpty() || pp->type() == Node::Fake) - break; + break; base.prepend(QLatin1Char('-')); p = pp; - } - - if (node->type() == Node::Fake) { + } + + if (node->type() == Node::Fake) { #ifdef QDOC2_COMPAT - if (base.endsWith(".html")) - base.truncate(base.length() - 5); + if (base.endsWith(".html")) + base.truncate(base.length() - 5); #endif - } + } // the code below is effectively equivalent to: // base.replace(QRegExp("[^A-Za-z0-9]+"), " "); @@ -126,7 +146,8 @@ QString PageGenerator::fileBase(const Node *node) if ((u >= 'a' && u <= 'z') || (u >= '0' && u <= '9')) { res += QLatin1Char(u); begun = true; - } else if (begun) { + } + else if (begun) { res += QLatin1Char('-'); begun = false; } @@ -187,8 +208,12 @@ void PageGenerator::generateInnerNode(const InnerNode *node, if (node->type() == Node::Fake) { const FakeNode *fakeNode = static_cast<const FakeNode *>(node); - if (fakeNode->subType() == FakeNode::ExternalPage) + if (fakeNode->subType() == Node::ExternalPage) + return; +#ifdef QDOC_QML + if (fakeNode->subType() == Node::QmlPropertyGroup) return; +#endif } if (node->parent() != 0) { @@ -197,12 +222,6 @@ void PageGenerator::generateInnerNode(const InnerNode *node, generateClassLikeNode(node, marker); } else if (node->type() == Node::Fake) { - const FakeNode* fakeNode = static_cast<const FakeNode *>(node); -#ifdef QDOC_QML - if (fakeNode->subType() == FakeNode::QmlClass) { - //qDebug() << "FILENAME:" << fileName(node); - } -#endif generateFakeNode(static_cast<const FakeNode *>(node), marker); } endSubPage(); diff --git a/tools/qdoc3/qdoc3.pro b/tools/qdoc3/qdoc3.pro index 2bba8fb..49a16e6 100644 --- a/tools/qdoc3/qdoc3.pro +++ b/tools/qdoc3/qdoc3.pro @@ -1,12 +1,17 @@ DEFINES += QDOC2_COMPAT -#DEFINES += QT_NO_CAST_TO_ASCII +DEFINES += QT_NO_CAST_TO_ASCII #DEFINES += QT_NO_CAST_FROM_ASCII +#DEFINES += QT_USE_FAST_OPERATOR_PLUS +#DEFINES += QT_USE_FAST_CONCATENATION QT = core xml CONFIG += console +CONFIG -= debug_and_release_target +#CONFIG += debug build_all:!build_pass { CONFIG -= build_all CONFIG += release +# CONFIG += debug } mac:CONFIG -= app_bundle HEADERS += apigenerator.h \ diff --git a/tools/qdoc3/separator.cpp b/tools/qdoc3/separator.cpp index 8f27f90..60674be 100644 --- a/tools/qdoc3/separator.cpp +++ b/tools/qdoc3/separator.cpp @@ -48,22 +48,30 @@ QT_BEGIN_NAMESPACE -QString separator( int index, int count ) +QString separator(int index, int count) { - if ( index == count - 1 ) - return tr( ".", "terminator" ); + if (index == count - 1) + return tr(".", "terminator"); + if (count == 2) + return tr(" and ", "separator when N = 2"); + if (index == 0) + return tr(", ", "first separator when N > 2"); + if (index < count - 2) + return tr(", ", "general separator when N > 2"); + return tr(", and ", "last separator when N > 2"); +} - if ( count == 2 ) { - return tr( " and ", "separator when N = 2" ); - } else { - if ( index == 0 ) { - return tr( ", ", "first separator when N > 2" ); - } else if ( index < count - 2 ) { - return tr( ", ", "general separator when N > 2" ); - } else { - return tr( ", and ", "last separator when N > 2" ); - } - } +QString comma(int index, int count) +{ + if (index == count - 1) + return QString(""); + if (count == 2) + return tr(" and ", "separator when N = 2"); + if (index == 0) + return tr(", ", "first separator when N > 2"); + if (index < count - 2) + return tr(", ", "general separator when N > 2"); + return tr(", and ", "last separator when N > 2"); } QT_END_NAMESPACE diff --git a/tools/qdoc3/separator.h b/tools/qdoc3/separator.h index 70ba624..2336d94 100644 --- a/tools/qdoc3/separator.h +++ b/tools/qdoc3/separator.h @@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE QString separator( int index, int count ); +QString comma( int index, int count ); QT_END_NAMESPACE diff --git a/tools/qdoc3/test/assistant.qdocconf b/tools/qdoc3/test/assistant.qdocconf index 71de998..44815ff 100644 --- a/tools/qdoc3/test/assistant.qdocconf +++ b/tools/qdoc3/test/assistant.qdocconf @@ -6,18 +6,18 @@ include(qt-defines.qdocconf) project = Qt Assistant description = Qt Assistant Manual -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = Assistant qhp.Assistant.file = assistant.qhp -qhp.Assistant.namespace = com.trolltech.assistant.453 +qhp.Assistant.namespace = com.trolltech.assistant.460 qhp.Assistant.virtualFolder = qdoc qhp.Assistant.indexTitle = Qt Assistant Manual qhp.Assistant.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.Assistant.filterAttributes = qt 4.5.3 tools assistant +qhp.Assistant.filterAttributes = qt 4.6.0 tools assistant qhp.Assistant.customFilters.Assistant.name = Qt Assistant Manual qhp.Assistant.customFilters.Assistant.filterAttributes = qt tools assistant qhp.Assistant.subprojects = manual examples diff --git a/tools/qdoc3/test/classic.css b/tools/qdoc3/test/classic.css index f22a77a..4225a1b 100644 --- a/tools/qdoc3/test/classic.css +++ b/tools/qdoc3/test/classic.css @@ -1,12 +1,82 @@ +BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { + font-family: Arial, Geneva, Helvetica, sans-serif; +} +H1 { + text-align: center; + font-size: 160%; +} +H2 { + font-size: 120%; +} +H3 { + font-size: 100%; +} + h3.fn,span.fn { - margin-left: 1cm; - text-indent: -1cm; + background-color: #eee; + border-width: 1px; + border-style: solid; + border-color: #ddd; + font-weight: bold; + padding: 6px 0px 6px 10px; + margin: 42px 0px 0px 0px; +} + +hr { + border: 0; + color: #a0a0a0; + background-color: #ccc; + height: 1px; + width: 100%; + text-align: left; + margin: 34px 0px 34px 0px; +} + +table.valuelist { + border-width: 1px 1px 1px 1px; + border-style: solid; + border-color: #dddddd; + border-collapse: collapse; + background-color: #f0f0f0; +} + +table.indextable { + border-width: 1px 1px 1px 1px; + border-collapse: collapse; + background-color: #f0f0f0; + border-color:#555; +} + + +table.valuelist th { + border-width: 1px 1px 1px 2px; + padding: 4px; + border-style: solid; + border-color: #666; + color:white; + background-color:#666; +} + +th.titleheader { + border-width: 1px 0px 1px 0px; + padding: 4px; + border-style: solid; + border-color: #444; + color:white; + background-color:#555555; +} + +p { + + margin-left: 4px; + margin-top: 8px; + margin-bottom: 8px; } a:link { - color: #004faf; + color: #0046ad; text-decoration: none } @@ -40,20 +110,38 @@ a.compat:visited text-decoration: none } -td.postheader +body { - font-family: sans-serif + background: #ffffff; + color: black } -tr.address +table.generic, table.annotated { - font-family: sans-serif + border-width: 1px; + border-color:#bbb; + border-style:solid; + border-collapse:collapse; } -body -{ - background: #ffffff; - color: black +table td.memItemLeft { + width: 180px; + padding: 2px 0px 0px 8px; + margin: 4px; + border-width: 1px; + border-color: #E0E0E0; + border-style: none; + font-size: 100%; + white-space: nowrap +} + +table td.memItemRight { + padding: 2px 8px 0px 8px; + margin: 4px; + border-width: 1px; + border-color: #E0E0E0; + border-style: none; + font-size: 100%; } table tr.odd { @@ -137,3 +225,52 @@ span.string,span.char { font-size: 0.65em } + +.qmlitem { + padding: 0; +} + +.qmlname { + white-space: nowrap; + font-weight: bold; + font-size: 125%; +} + +.qmltype { + font-weight: bold; + font-size: 125%; +} + +.qmlproto, .qmldoc { + // border-top: 1px solid #84b0c7; +} + +.qmlproto { + padding: 0; + //background-color: #e4e4e4;//#d5e1e8; + //font-weight: bold; + //-webkit-border-top-left-radius: 8px; + //-webkit-border-top-right-radius: 8px; + //-moz-border-radius-topleft: 8px; + //-moz-border-radius-topright: 8px; +} + +.qmldoc { + border-top: 1px solid #e4e4e4; + //padding: 2px 5px; + //background-color: #eef3f5; + //border-top-width: 0; + //-webkit-border-bottom-left-radius: 8px; + //-webkit-border-bottom-right-radius: 8px; + //-moz-border-radius-bottomleft: 8px; + //-moz-border-radius-bottomright: 8px; +} + +.qmldoc p, .qmldoc dl, .qmldoc ul { + //margin: 6px 0; +} + +*.qmlitem p { + //margin-top: 0px; + //margin-bottom: 0px; +} diff --git a/tools/qdoc3/test/designer.qdocconf b/tools/qdoc3/test/designer.qdocconf index 0c39bb8..88f8dc9 100644 --- a/tools/qdoc3/test/designer.qdocconf +++ b/tools/qdoc3/test/designer.qdocconf @@ -6,18 +6,18 @@ include(qt-defines.qdocconf) project = Qt Designer description = Qt Designer Manual -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = Designer qhp.Designer.file = designer.qhp -qhp.Designer.namespace = com.trolltech.designer.453 +qhp.Designer.namespace = com.trolltech.designer.460 qhp.Designer.virtualFolder = qdoc qhp.Designer.indexTitle = Qt Designer Manual qhp.Designer.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.Designer.filterAttributes = qt 4.5.3 tools designer +qhp.Designer.filterAttributes = qt 4.6.0 tools designer qhp.Designer.customFilters.Designer.name = Qt Designer Manual qhp.Designer.customFilters.Designer.filterAttributes = qt tools designer qhp.Designer.subprojects = manual examples diff --git a/tools/qdoc3/test/linguist.qdocconf b/tools/qdoc3/test/linguist.qdocconf index b6bd375..1c0a585 100644 --- a/tools/qdoc3/test/linguist.qdocconf +++ b/tools/qdoc3/test/linguist.qdocconf @@ -6,18 +6,18 @@ include(qt-defines.qdocconf) project = Qt Linguist description = Qt Linguist Manual -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = Linguist qhp.Linguist.file = linguist.qhp -qhp.Linguist.namespace = com.trolltech.linguist.453 +qhp.Linguist.namespace = com.trolltech.linguist.460 qhp.Linguist.virtualFolder = qdoc qhp.Linguist.indexTitle = Qt Linguist Manual qhp.Linguist.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.Linguist.filterAttributes = qt 4.5.3 tools linguist +qhp.Linguist.filterAttributes = qt 4.6.0 tools linguist qhp.Linguist.customFilters.Linguist.name = Qt Linguist Manual qhp.Linguist.customFilters.Linguist.filterAttributes = qt tools linguist qhp.Linguist.subprojects = manual examples diff --git a/tools/qdoc3/test/macros.qdocconf b/tools/qdoc3/test/macros.qdocconf index 85fe1db..f7dcdc0 100644 --- a/tools/qdoc3/test/macros.qdocconf +++ b/tools/qdoc3/test/macros.qdocconf @@ -1,14 +1,15 @@ +macro.aacute.HTML = "á" macro.Aring.HTML = "Å" macro.aring.HTML = "å" macro.Auml.HTML = "Ä" macro.author = "\\bold{Author:}" macro.br.HTML = "<br />" macro.BR.HTML = "<br />" -macro.aacute.HTML = "á" +macro.copyright.HTML = "©" macro.eacute.HTML = "é" -macro.iacute.HTML = "í" macro.gui = "\\bold" macro.hr.HTML = "<hr />" +macro.iacute.HTML = "í" macro.key = "\\bold" macro.menu = "\\bold" macro.note = "\\bold{Note:}" diff --git a/tools/qdoc3/test/qmake.qdocconf b/tools/qdoc3/test/qmake.qdocconf index 83220ae..0f98132 100644 --- a/tools/qdoc3/test/qmake.qdocconf +++ b/tools/qdoc3/test/qmake.qdocconf @@ -6,18 +6,18 @@ include(qt-defines.qdocconf) project = QMake description = QMake Manual -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 indexes = $QT_BUILD_TREE/doc-build/html-qt/qt.index qhp.projects = qmake qhp.qmake.file = qmake.qhp -qhp.qmake.namespace = com.trolltech.qmake.453 +qhp.qmake.namespace = com.trolltech.qmake.460 qhp.qmake.virtualFolder = qdoc qhp.qmake.indexTitle = QMake Manual qhp.qmake.extraFiles = classic.css images/qt-logo.png images/trolltech-logo.png -qhp.qmake.filterAttributes = qt 4.5.3 tools qmake +qhp.qmake.filterAttributes = qt 4.6.0 tools qmake qhp.qmake.customFilters.qmake.name = qmake Manual qhp.qmake.customFilters.qmake.filterAttributes = qt tools qmake qhp.qmake.subprojects = manual diff --git a/tools/qdoc3/test/qt-build-docs.qdocconf b/tools/qdoc3/test/qt-build-docs.qdocconf index 5169714..b4f0c7a 100644 --- a/tools/qdoc3/test/qt-build-docs.qdocconf +++ b/tools/qdoc3/test/qt-build-docs.qdocconf @@ -6,7 +6,7 @@ include(qt-defines.qdocconf) project = Qt description = Qt Reference Documentation -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \ QtXmlPatterns QtTest @@ -20,7 +20,7 @@ edition.DesktopLight.groups = -graphicsview-api qhp.projects = Qt qhp.Qt.file = qt.qhp -qhp.Qt.namespace = com.trolltech.qt.453 +qhp.Qt.namespace = com.trolltech.qt.460 qhp.Qt.virtualFolder = qdoc qhp.Qt.indexTitle = Qt Reference Documentation qhp.Qt.indexRoot = @@ -34,9 +34,9 @@ qhp.Qt.extraFiles = classic.css \ images/dynamiclayouts-example.png \ images/stylesheet-coffee-plastique.png -qhp.Qt.filterAttributes = qt 4.5.3 qtrefdoc -qhp.Qt.customFilters.Qt.name = Qt 4.5.3 -qhp.Qt.customFilters.Qt.filterAttributes = qt 4.5.3 +qhp.Qt.filterAttributes = qt 4.6.0 qtrefdoc +qhp.Qt.customFilters.Qt.name = Qt 4.6.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.6.0 qhp.Qt.subprojects = classes overviews examples qhp.Qt.subprojects.classes.title = Classes qhp.Qt.subprojects.classes.indexTitle = Qt's Classes diff --git a/tools/qdoc3/test/qt-cpp-ignore.qdocconf b/tools/qdoc3/test/qt-cpp-ignore.qdocconf index 107c692..709e336 100644 --- a/tools/qdoc3/test/qt-cpp-ignore.qdocconf +++ b/tools/qdoc3/test/qt-cpp-ignore.qdocconf @@ -12,6 +12,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ QM_EXPORT_ICONVIEW \ QM_EXPORT_NETWORK \ QM_EXPORT_OPENGL \ + QM_EXPORT_OPENVG \ QM_EXPORT_SQL \ QM_EXPORT_TABLE \ QM_EXPORT_WORKSPACE \ @@ -50,6 +51,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ Q_INTERNAL_WIN_NO_THROW \ Q_NETWORK_EXPORT \ Q_OPENGL_EXPORT \ + Q_OPENVG_EXPORT \ Q_OUTOFLINE_TEMPLATE \ Q_SQL_EXPORT \ Q_SVG_EXPORT \ @@ -65,7 +67,9 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ QT_BEGIN_INCLUDE_NAMESPACE \ QT_END_NAMESPACE \ QT_END_INCLUDE_NAMESPACE \ - PHONON_EXPORT + PHONON_EXPORT \ + Q_GADGET \ + QWEBKIT_EXPORT Cpp.ignoredirectives = Q_DECLARE_HANDLE \ Q_DECLARE_INTERFACE \ Q_DECLARE_METATYPE \ diff --git a/tools/qdoc3/test/qt-inc.qdocconf b/tools/qdoc3/test/qt-inc.qdocconf index d6cb0e6..379511f 100644 --- a/tools/qdoc3/test/qt-inc.qdocconf +++ b/tools/qdoc3/test/qt-inc.qdocconf @@ -3,7 +3,7 @@ include(macros.qdocconf) project = Qt description = Qt Reference Documentation -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 edition.Console = QtCore QtNetwork QtSql QtXml QtScript QtTest edition.Desktop = QtCore QtGui QtNetwork QtOpenGL QtSql QtSvg QtXml QtScript \ @@ -99,7 +99,9 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ Q_TESTLIB_EXPORT \ Q_TYPENAME \ Q_XML_EXPORT \ - QDBUS_EXPORT + QDBUS_EXPORT \ + Q_GADGET \ + QWEBKIT_EXPORT Cpp.ignoredirectives = Q_DECLARE_HANDLE \ Q_DECLARE_INTERFACE \ Q_DECLARE_METATYPE \ diff --git a/tools/qdoc3/test/qt.qdocconf b/tools/qdoc3/test/qt.qdocconf index f1fd8a2..10e0fcd 100644 --- a/tools/qdoc3/test/qt.qdocconf +++ b/tools/qdoc3/test/qt.qdocconf @@ -8,7 +8,7 @@ project = Qt versionsym = version = %VERSION% description = Qt Reference Documentation -url = http://doc.qtsoftware.com/4.5 +url = http://doc.qtsoftware.com/4.6 edition.Console.modules = QtCore QtDBus QtNetwork QtScript QtSql QtXml \ QtXmlPatterns QtTest @@ -22,7 +22,7 @@ edition.DesktopLight.groups = -graphicsview-api qhp.projects = Qt qhp.Qt.file = qt.qhp -qhp.Qt.namespace = com.trolltech.qt.453 +qhp.Qt.namespace = com.trolltech.qt.460 qhp.Qt.virtualFolder = qdoc qhp.Qt.indexTitle = Qt Reference Documentation qhp.Qt.indexRoot = @@ -36,9 +36,9 @@ qhp.Qt.extraFiles = classic.css \ images/dynamiclayouts-example.png \ images/stylesheet-coffee-plastique.png -qhp.Qt.filterAttributes = qt 4.5.3 qtrefdoc -qhp.Qt.customFilters.Qt.name = Qt 4.5.3 -qhp.Qt.customFilters.Qt.filterAttributes = qt 4.5.3 +qhp.Qt.filterAttributes = qt 4.6.0 qtrefdoc +qhp.Qt.customFilters.Qt.name = Qt 4.6.0 +qhp.Qt.customFilters.Qt.filterAttributes = qt 4.6.0 qhp.Qt.subprojects = classes overviews examples qhp.Qt.subprojects.classes.title = Classes qhp.Qt.subprojects.classes.indexTitle = Qt's Classes diff --git a/tools/qdoc3/tree.cpp b/tools/qdoc3/tree.cpp index c992688..f832062 100644 --- a/tools/qdoc3/tree.cpp +++ b/tools/qdoc3/tree.cpp @@ -176,6 +176,8 @@ const Node *Tree::findNode(const QStringList &path, } /*! + Find the node with the specified \a path name of the + specified \a type. */ Node *Tree::findNode(const QStringList &path, Node::Type type, @@ -189,6 +191,8 @@ Node *Tree::findNode(const QStringList &path, } /*! + Find the node with the specified \a path name of the + specified \a type. */ const Node *Tree::findNode(const QStringList &path, Node::Type type, @@ -208,7 +212,9 @@ FunctionNode *Tree::findFunctionNode(const QStringList& path, int findFlags) { return const_cast<FunctionNode *>( - const_cast<const Tree *>(this)->findFunctionNode(path, relative, findFlags)); + const_cast<const Tree *>(this)->findFunctionNode(path, + relative, + findFlags)); } /*! @@ -233,7 +239,8 @@ const FunctionNode *Tree::findFunctionNode(const QStringList &path, else next = ((InnerNode *) node)->findNode(path.at(i)); - if (!next && node->type() == Node::Class && (findFlags & SearchBaseClasses)) { + if (!next && node->type() == Node::Class && + (findFlags & SearchBaseClasses)) { NodeList baseClasses = allBaseClasses(static_cast<const ClassNode *>(node)); foreach (const Node *baseClass, baseClasses) { if (i == path.size() - 1) @@ -412,6 +419,8 @@ void Tree::addPropertyFunction(PropertyNode *property, } /*! + This function adds the \a node to the \a group. The group + can be listed anywhere using the \e{annotated list} command. */ void Tree::addToGroup(Node *node, const QString &group) { @@ -563,13 +572,15 @@ void Tree::resolveGroups() FakeNode *fake = static_cast<FakeNode*>(findNode(QStringList(i.key()),Node::Fake)); - if (fake && fake->subType() == FakeNode::Group) { + if (fake && fake->subType() == Node::Group) { fake->addGroupMember(i.value()); } +#if 0 else { if (prevGroup != i.key()) i.value()->doc().location().warning(tr("No such group '%1'").arg(i.key())); } +#endif prevGroup = i.key(); } @@ -770,21 +781,21 @@ void Tree::readIndexSection(const QDomElement &element, } else if (element.nodeName() == "page") { - FakeNode::SubType subtype; + Node::SubType subtype; if (element.attribute("subtype") == "example") - subtype = FakeNode::Example; + subtype = Node::Example; else if (element.attribute("subtype") == "header") - subtype = FakeNode::HeaderFile; + subtype = Node::HeaderFile; else if (element.attribute("subtype") == "file") - subtype = FakeNode::File; + subtype = Node::File; else if (element.attribute("subtype") == "group") - subtype = FakeNode::Group; + subtype = Node::Group; else if (element.attribute("subtype") == "module") - subtype = FakeNode::Module; + subtype = Node::Module; else if (element.attribute("subtype") == "page") - subtype = FakeNode::Page; + subtype = Node::Page; else if (element.attribute("subtype") == "externalpage") - subtype = FakeNode::ExternalPage; + subtype = Node::ExternalPage; else return; @@ -1226,25 +1237,25 @@ bool Tree::generateIndexSection(QXmlStreamWriter &writer, const FakeNode *fakeNode = static_cast<const FakeNode*>(node); switch (fakeNode->subType()) { - case FakeNode::Example: + case Node::Example: writer.writeAttribute("subtype", "example"); break; - case FakeNode::HeaderFile: + case Node::HeaderFile: writer.writeAttribute("subtype", "header"); break; - case FakeNode::File: + case Node::File: writer.writeAttribute("subtype", "file"); break; - case FakeNode::Group: + case Node::Group: writer.writeAttribute("subtype", "group"); break; - case FakeNode::Module: + case Node::Module: writer.writeAttribute("subtype", "module"); break; - case FakeNode::Page: + case Node::Page: writer.writeAttribute("subtype", "page"); break; - case FakeNode::ExternalPage: + case Node::ExternalPage: writer.writeAttribute("subtype", "externalpage"); break; default: @@ -1383,7 +1394,7 @@ bool Tree::generateIndexSection(QXmlStreamWriter &writer, bool external = false; if (inner->type() == Node::Fake) { const FakeNode *fakeNode = static_cast<const FakeNode *>(inner); - if (fakeNode->subType() == FakeNode::ExternalPage) + if (fakeNode->subType() == Node::ExternalPage) external = true; } @@ -1863,7 +1874,7 @@ void Tree::generateTagFile(const QString &fileName) const */ void Tree::addExternalLink(const QString &url, const Node *relative) { - FakeNode *fakeNode = new FakeNode(root(), url, FakeNode::ExternalPage); + FakeNode *fakeNode = new FakeNode(root(), url, Node::ExternalPage); fakeNode->setAccess(Node::Public); // Create some content for the node. @@ -1884,23 +1895,30 @@ QString Tree::fullDocumentLocation(const Node *node) const if (!node->url().isEmpty()) return node->url(); + QString parentName; + QString anchorRef; + if (node->type() == Node::Namespace) { // The root namespace has no name - check for this before creating // an attribute containing the location of any documentation. if (!node->fileBase().isEmpty()) - return node->fileBase() + ".html"; + parentName = node->fileBase() + ".html"; else return ""; } else if (node->type() == Node::Fake) { - return node->fileBase() + ".html"; +#ifdef QDOC_QML + if (node->subType() == Node::QmlClass) + return "qml-" + node->fileBase() + ".html"; + else +#endif + parentName = node->fileBase() + ".html"; } else if (node->fileBase().isEmpty()) return ""; - QString parentName; Node *parentNode = 0; if ((parentNode = node->relates())) @@ -1912,10 +1930,11 @@ QString Tree::fullDocumentLocation(const Node *node) const case Node::Class: case Node::Namespace: if (parentNode && !parentNode->name().isEmpty()) - return parentName.replace(".html", "") + "-" - + node->fileBase().toLower() + ".html"; + parentName = parentName.replace(".html", "") + "-" + + node->fileBase().toLower() + ".html"; else - return node->fileBase() + ".html"; + parentName = node->fileBase() + ".html"; + break; case Node::Function: { /* @@ -1925,29 +1944,17 @@ QString Tree::fullDocumentLocation(const Node *node) const const FunctionNode *functionNode = static_cast<const FunctionNode *>(node); - // Functions can be compatibility functions or be obsolete. - switch (node->status()) { - case Node::Compat: - parentName.replace(".html", "-qt3.html"); - break; - case Node::Obsolete: - parentName.replace(".html", "-obsolete.html"); - break; - default: - ; - } - if (functionNode->metaness() == FunctionNode::Dtor) - return parentName + "#dtor." + functionNode->name().mid(1); + anchorRef = "#dtor." + functionNode->name().mid(1); - if (functionNode->associatedProperty()) + else if (functionNode->associatedProperty()) return fullDocumentLocation(functionNode->associatedProperty()); - if (functionNode->overloadNumber() > 1) - return parentName + "#" + functionNode->name() - + "-" + QString::number(functionNode->overloadNumber()); + else if (functionNode->overloadNumber() > 1) + anchorRef = "#" + functionNode->name() + + "-" + QString::number(functionNode->overloadNumber()); else - return parentName + "#" + functionNode->name(); + anchorRef = "#" + functionNode->name(); } /* @@ -1955,27 +1962,52 @@ QString Tree::fullDocumentLocation(const Node *node) const the latter returns the name in lower-case. For HTML anchors, we need to preserve the case. */ + break; case Node::Enum: - return parentName + "#" + node->name() + "-enum"; + anchorRef = "#" + node->name() + "-enum"; + break; case Node::Typedef: - return parentName + "#" + node->name() + "-typedef"; + anchorRef = "#" + node->name() + "-typedef"; + break; case Node::Property: - return parentName + "#" + node->name() + "-prop"; + anchorRef = "#" + node->name() + "-prop"; + break; case Node::Variable: - return parentName + "#" + node->name() + "-var"; + anchorRef = "#" + node->name() + "-var"; + break; case Node::Target: - return parentName + "#" + Doc::canonicalTitle(node->name()); + anchorRef = "#" + Doc::canonicalTitle(node->name()); + break; case Node::Fake: { - QString pageName = node->name(); - return pageName.replace("/", "-").replace(".", "-") + ".html"; + /* + Use node->fileBase() for fake nodes because they are represented + by pages whose file names are lower-case. + */ + parentName = node->fileBase(); + parentName.replace("/", "-").replace(".", "-"); + parentName += ".html"; } break; default: break; } - return ""; + // Various objects can be compat (deprecated) or obsolete. + if (node->type() != Node::Class && node->type() != Node::Namespace) { + switch (node->status()) { + case Node::Compat: + parentName.replace(".html", "-qt3.html"); + break; + case Node::Obsolete: + parentName.replace(".html", "-obsolete.html"); + break; + default: + ; + } + } + + return parentName.toLower() + anchorRef; } /*! diff --git a/tools/qdoc3/webxmlgenerator.cpp b/tools/qdoc3/webxmlgenerator.cpp index c5209b8..e87e812 100644 --- a/tools/qdoc3/webxmlgenerator.cpp +++ b/tools/qdoc3/webxmlgenerator.cpp @@ -191,7 +191,7 @@ void WebXMLGenerator::generateIndexSections(QXmlStreamWriter &writer, generateRelations(writer, node, marker); - if (fake->subType() == FakeNode::Module) { + if (fake->subType() == Node::Module) { writer.writeStartElement("generatedlist"); writer.writeAttribute("contents", "classesbymodule"); @@ -264,7 +264,7 @@ void WebXMLGenerator::generateInnerNode(const InnerNode *node, CodeMarker *marke if (node->type() == Node::Fake) { const FakeNode *fakeNode = static_cast<const FakeNode *>(node); - if (fakeNode->subType() == FakeNode::ExternalPage) + if (fakeNode->subType() == Node::ExternalPage) return; } diff --git a/tools/qtconfig/mainwindow.cpp b/tools/qtconfig/mainwindow.cpp index eabaec6..a59f790 100644 --- a/tools/qtconfig/mainwindow.cpp +++ b/tools/qtconfig/mainwindow.cpp @@ -829,7 +829,7 @@ void MainWindow::removeSubstitute() int item = sublistbox->currentItem(); QStringList subs = QFont::substitutes(familysubcombo->currentText()); - subs.remove(subs.at(sublistbox->currentItem())); + subs.removeAt(sublistbox->currentItem()); sublistbox->clear(); sublistbox->insertStringList(subs); if (uint(item) > sublistbox->count()) @@ -909,7 +909,7 @@ void MainWindow::removeFontpath() return; int item = fontpathlistbox->currentItem(); - fontpaths.remove(fontpaths.at(fontpathlistbox->currentItem())); + fontpaths.removeAt(fontpathlistbox->currentItem()); fontpathlistbox->clear(); fontpathlistbox->insertStringList(fontpaths); if (uint(item) > fontpathlistbox->count()) diff --git a/tools/qtconfig/paletteeditoradvanced.cpp b/tools/qtconfig/paletteeditoradvanced.cpp index 45f6a45..36cbd89 100644 --- a/tools/qtconfig/paletteeditoradvanced.cpp +++ b/tools/qtconfig/paletteeditoradvanced.cpp @@ -55,7 +55,7 @@ PaletteEditorAdvanced::PaletteEditorAdvanced( QWidget * parent, const char * name, bool modal, Qt::WindowFlags f ) : PaletteEditorAdvancedBase( parent, name, modal, f ), selectedPalette(0) { - // work around buggy ui file + // work around buggy UI file comboEffect->setEnabled(false); buttonEffect->setEnabled(false); onToggleBuildEffects(true); diff --git a/tools/qtestlib/chart/3rdparty/excanvas.js b/tools/qtestlib/chart/3rdparty/excanvas.js new file mode 100644 index 0000000..e77763a --- /dev/null +++ b/tools/qtestlib/chart/3rdparty/excanvas.js @@ -0,0 +1,14 @@ +// Copyright 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +if(!window.CanvasRenderingContext2D){(function(){var N=Math;var O=N.round;var L=N.sin;var U=N.cos;var A=10;var I=A/2;var G={init:function(W){var X=W||document;if(/MSIE/.test(navigator.userAgent)&&!window.opera){var V=this;X.attachEvent("onreadystatechange",function(){V.init_(X)})}},init_:function(Y){if(Y.readyState=="complete"){if(!Y.namespaces.g_vml_){Y.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml")}var X=Y.createStyleSheet();X.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}";var W=Y.getElementsByTagName("canvas");for(var V=0;V<W.length;V++){if(!W[V].getContext){this.initElement(W[V])}}}},fixElement_:function(X){var Z=X.outerHTML;var Y=X.ownerDocument.createElement(Z);if(Z.slice(-2)!="/>"){var V="/"+X.tagName;var W;while((W=X.nextSibling)&&W.tagName!=V){W.removeNode()}if(W){W.removeNode()}}X.parentNode.replaceChild(Y,X);return Y},initElement:function(W){W=this.fixElement_(W);W.getContext=function(){if(this.context_){return this.context_}return this.context_=new J(this)};W.attachEvent("onpropertychange",T);W.attachEvent("onresize",B);var V=W.attributes;if(V.width&&V.width.specified){W.style.width=V.width.nodeValue+"px"}else{W.width=W.clientWidth}if(V.height&&V.height.specified){W.style.height=V.height.nodeValue+"px"}else{W.height=W.clientHeight}return W}};function T(W){var V=W.srcElement;switch(W.propertyName){case"width":V.style.width=V.attributes.width.nodeValue+"px";V.getContext().clearRect();break;case"height":V.style.height=V.attributes.height.nodeValue+"px";V.getContext().clearRect();break}}function B(W){var V=W.srcElement;if(V.firstChild){V.firstChild.style.width=V.clientWidth+"px";V.firstChild.style.height=V.clientHeight+"px"}}G.init();var D=[];for(var R=0;R<16;R++){for(var Q=0;Q<16;Q++){D[R*16+Q]=R.toString(16)+Q.toString(16)}}function K(){return[[1,0,0],[0,1,0],[0,0,1]]}function E(Y,X){var W=K();for(var V=0;V<3;V++){for(var b=0;b<3;b++){var Z=0;for(var a=0;a<3;a++){Z+=Y[V][a]*X[a][b]}W[V][b]=Z}}return W}function P(W,V){V.fillStyle=W.fillStyle;V.lineCap=W.lineCap;V.lineJoin=W.lineJoin;V.lineWidth=W.lineWidth;V.miterLimit=W.miterLimit;V.shadowBlur=W.shadowBlur;V.shadowColor=W.shadowColor;V.shadowOffsetX=W.shadowOffsetX;V.shadowOffsetY=W.shadowOffsetY;V.strokeStyle=W.strokeStyle;V.arcScaleX_=W.arcScaleX_;V.arcScaleY_=W.arcScaleY_}function C(W){var Z,Y=1;W=String(W);if(W.substring(0,3)=="rgb"){var b=W.indexOf("(",3);var V=W.indexOf(")",b+1);var a=W.substring(b+1,V).split(",");Z="#";for(var X=0;X<3;X++){Z+=D[Number(a[X])]}if((a.length==4)&&(W.substr(3,1)=="a")){Y=a[3]}}else{Z=W}return[Z,Y]}function M(V){switch(V){case"butt":return"flat";case"round":return"round";case"square":default:return"square"}}function J(W){this.m_=K();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle="#000";this.fillStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=A*1;this.globalAlpha=1;this.canvas=W;var V=W.ownerDocument.createElement("div");V.style.width=W.clientWidth+"px";V.style.height=W.clientHeight+"px";V.style.overflow="hidden";V.style.position="absolute";W.appendChild(V);this.element_=V;this.arcScaleX_=1;this.arcScaleY_=1}var H=J.prototype;H.clearRect=function(){this.element_.innerHTML="";this.currentPath_=[]};H.beginPath=function(){this.currentPath_=[]};H.moveTo=function(W,V){this.currentPath_.push({type:"moveTo",x:W,y:V});this.currentX_=W;this.currentY_=V};H.lineTo=function(W,V){this.currentPath_.push({type:"lineTo",x:W,y:V});this.currentX_=W;this.currentY_=V};H.bezierCurveTo=function(X,V,a,Z,Y,W){this.currentPath_.push({type:"bezierCurveTo",cp1x:X,cp1y:V,cp2x:a,cp2y:Z,x:Y,y:W});this.currentX_=Y;this.currentY_=W};H.quadraticCurveTo=function(c,b,a,Z){var W=this.currentX_+2/3*(c-this.currentX_);var V=this.currentY_+2/3*(b-this.currentY_);var Y=W+(a-this.currentX_)/3;var X=V+(Z-this.currentY_)/3;this.bezierCurveTo(W,V,Y,X,a,Z)};H.arc=function(b,Z,a,Y,W,X){a*=A;var f=X?"at":"wa";var c=b+(U(Y)*a)-I;var e=Z+(L(Y)*a)-I;var V=b+(U(W)*a)-I;var d=Z+(L(W)*a)-I;if(c==V&&!X){c+=0.125}this.currentPath_.push({type:f,x:b,y:Z,radius:a,xStart:c,yStart:e,xEnd:V,yEnd:d})};H.rect=function(X,W,V,Y){this.moveTo(X,W);this.lineTo(X+V,W);this.lineTo(X+V,W+Y);this.lineTo(X,W+Y);this.closePath()};H.strokeRect=function(X,W,V,Y){this.beginPath();this.moveTo(X,W);this.lineTo(X+V,W);this.lineTo(X+V,W+Y);this.lineTo(X,W+Y);this.closePath();this.stroke()};H.fillRect=function(X,W,V,Y){this.beginPath();this.moveTo(X,W);this.lineTo(X+V,W);this.lineTo(X+V,W+Y);this.lineTo(X,W+Y);this.closePath();this.fill()};H.createLinearGradient=function(W,Y,V,X){var Z=new S("gradient");return Z};H.createRadialGradient=function(Y,a,X,W,Z,V){var b=new S("gradientradial");b.radius1_=X;b.radius2_=V;b.focus_.x=Y;b.focus_.y=a;return b};H.drawImage=function(n,Y){var f,c,i,u,l,j,p,x;var g=n.runtimeStyle.width;var m=n.runtimeStyle.height;n.runtimeStyle.width="auto";n.runtimeStyle.height="auto";var e=n.width;var s=n.height;n.runtimeStyle.width=g;n.runtimeStyle.height=m;if(arguments.length==3){f=arguments[1];c=arguments[2];l=j=0;p=i=e;x=u=s}else{if(arguments.length==5){f=arguments[1];c=arguments[2];i=arguments[3];u=arguments[4];l=j=0;p=e;x=s}else{if(arguments.length==9){l=arguments[1];j=arguments[2];p=arguments[3];x=arguments[4];f=arguments[5];c=arguments[6];i=arguments[7];u=arguments[8]}else{throw"Invalid number of arguments"}}}var v=this.getCoords_(f,c);var Z=p/2;var X=x/2;var t=[];var V=10;var b=10;t.push(" <g_vml_:group",' coordsize="',A*V,",",A*b,'"',' coordorigin="0,0"',' style="width:',V,";height:",b,";position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]){var a=[];a.push("M11='",this.m_[0][0],"',","M12='",this.m_[1][0],"',","M21='",this.m_[0][1],"',","M22='",this.m_[1][1],"',","Dx='",O(v.x/A),"',","Dy='",O(v.y/A),"'");var r=v;var q=this.getCoords_(f+i,c);var o=this.getCoords_(f,c+u);var k=this.getCoords_(f+i,c+u);r.x=Math.max(r.x,q.x,o.x,k.x);r.y=Math.max(r.y,q.y,o.y,k.y);t.push("padding:0 ",O(r.x/A),"px ",O(r.y/A),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",a.join(""),", sizingmethod='clip');")}else{t.push("top:",O(v.y/A),"px;left:",O(v.x/A),"px;")}t.push(' ">','<g_vml_:image src="',n.src,'"',' style="width:',A*i,";"," height:",A*u,';"',' cropleft="',l/e,'"',' croptop="',j/s,'"',' cropright="',(e-l-p)/e,'"',' cropbottom="',(s-j-x)/s,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",t.join(""))};H.stroke=function(y){var e=[];var d=false;var AB=C(y?this.fillStyle:this.strokeStyle);var u=AB[0];var Y=AB[1]*this.globalAlpha;var X=10;var j=10;e.push("<g_vml_:shape",' fillcolor="',u,'"',' filled="',Boolean(y),'"',' style="position:absolute;width:',X,";height:",j,';"',' coordorigin="0 0" coordsize="',A*X," ",A*j,'"',' stroked="',!y,'"',' strokeweight="',this.lineWidth,'"',' strokecolor="',u,'"',' path="');var h=false;var t={x:null,y:null};var v={x:null,y:null};for(var w=0;w<this.currentPath_.length;w++){var o=this.currentPath_[w];if(o.type=="moveTo"){e.push(" m ");var AA=this.getCoords_(o.x,o.y);e.push(O(AA.x),",",O(AA.y))}else{if(o.type=="lineTo"){e.push(" l ");var AA=this.getCoords_(o.x,o.y);e.push(O(AA.x),",",O(AA.y))}else{if(o.type=="close"){e.push(" x ")}else{if(o.type=="bezierCurveTo"){e.push(" c ");var AA=this.getCoords_(o.x,o.y);var s=this.getCoords_(o.cp1x,o.cp1y);var q=this.getCoords_(o.cp2x,o.cp2y);e.push(O(s.x),",",O(s.y),",",O(q.x),",",O(q.y),",",O(AA.x),",",O(AA.y))}else{if(o.type=="at"||o.type=="wa"){e.push(" ",o.type," ");var AA=this.getCoords_(o.x,o.y);var k=this.getCoords_(o.xStart,o.yStart);var b=this.getCoords_(o.xEnd,o.yEnd);e.push(O(AA.x-this.arcScaleX_*o.radius),",",O(AA.y-this.arcScaleY_*o.radius)," ",O(AA.x+this.arcScaleX_*o.radius),",",O(AA.y+this.arcScaleY_*o.radius)," ",O(k.x),",",O(k.y)," ",O(b.x),",",O(b.y))}}}}}if(AA){if(t.x==null||AA.x<t.x){t.x=AA.x}if(v.x==null||AA.x>v.x){v.x=AA.x}if(t.y==null||AA.y<t.y){t.y=AA.y}if(v.y==null||AA.y>v.y){v.y=AA.y}}}e.push(' ">');if(typeof this.fillStyle=="object"){var n={x:"50%",y:"50%"};var r=(v.x-t.x);var l=(v.y-t.y);var z=(r>l)?r:l;n.x=O((this.fillStyle.focus_.x/r)*100+50)+"%";n.y=O((this.fillStyle.focus_.y/l)*100+50)+"%";var g=[];if(this.fillStyle.type_=="gradientradial"){var x=(this.fillStyle.radius1_/z*100);var m=(this.fillStyle.radius2_/z*100)-x}else{var x=0;var m=100}var V={offset:null,color:null};var Z={offset:null,color:null};this.fillStyle.colors_.sort(function(a,W){return a.offset-W.offset});for(var w=0;w<this.fillStyle.colors_.length;w++){var f=this.fillStyle.colors_[w];g.push((f.offset*m)+x,"% ",f.color,",");if(f.offset>V.offset||V.offset==null){V.offset=f.offset;V.color=f.color}if(f.offset<Z.offset||Z.offset==null){Z.offset=f.offset;Z.color=f.color}}g.pop();e.push("<g_vml_:fill",' color="',Z.color,'"',' color2="',V.color,'"',' type="',this.fillStyle.type_,'"',' focusposition="',n.x,", ",n.y,'"',' colors="',g.join(""),'"',' opacity="',Y,'" />')}else{if(y){e.push('<g_vml_:fill color="',u,'" opacity="',Y,'" />')}else{e.push("<g_vml_:stroke",' opacity="',Y,'"',' joinstyle="',this.lineJoin,'"',' miterlimit="',this.miterLimit,'"',' endcap="',M(this.lineCap),'"',' weight="',this.lineWidth,'px"',' color="',u,'" />')}}e.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",e.join(""))};H.fill=function(){this.stroke(true)};H.closePath=function(){this.currentPath_.push({type:"close"})};H.getCoords_=function(W,V){return{x:A*(W*this.m_[0][0]+V*this.m_[1][0]+this.m_[2][0])-I,y:A*(W*this.m_[0][1]+V*this.m_[1][1]+this.m_[2][1])-I}};H.save=function(){var V={};P(this,V);this.aStack_.push(V);this.mStack_.push(this.m_);this.m_=E(K(),this.m_)};H.restore=function(){P(this.aStack_.pop(),this);this.m_=this.mStack_.pop()};H.translate=function(X,W){var V=[[1,0,0],[0,1,0],[X,W,1]];this.m_=E(V,this.m_)};H.rotate=function(W){var Y=U(W);var X=L(W);var V=[[Y,X,0],[-X,Y,0],[0,0,1]];this.m_=E(V,this.m_)};H.scale=function(X,W){this.arcScaleX_*=X;this.arcScaleY_*=W;var V=[[X,0,0],[0,W,0],[0,0,1]];this.m_=E(V,this.m_)};H.clip=function(){};H.arcTo=function(){};H.createPattern=function(){return new F};function S(V){this.type_=V;this.radius1_=0;this.radius2_=0;this.colors_=[];this.focus_={x:0,y:0}}S.prototype.addColorStop=function(W,V){V=C(V);this.colors_.push({offset:1-W,color:V})};function F(){}G_vmlCanvasManager=G;CanvasRenderingContext2D=J;CanvasGradient=S;CanvasPattern=F})()};
\ No newline at end of file diff --git a/tools/qtestlib/chart/3rdparty/flotr.js b/tools/qtestlib/chart/3rdparty/flotr.js new file mode 100644 index 0000000..80bb506 --- /dev/null +++ b/tools/qtestlib/chart/3rdparty/flotr.js @@ -0,0 +1,2 @@ +//Flotr 0.1.0alpha Copyright (c) 2008 Bas Wenneker, <http://solutoire.com>, MIT License. +var Flotr=(function(){var C=0;function L(M){return M.collect(function(N){return(N.data)?Object.clone(N):{data:N}})}function G(P,N){var M=N||{};for(var O in P){M[O]=(typeof (P[O])=="object"&&!(P[O].constructor==Array||P[O].constructor==RegExp))?G(P[O],N[O]):M[O]=P[O]}return M}function I(Q,P,M,N){var T=(M-P)/Q;var S=H(T);var O=T/S;var R=10;if(O<1.5){R=1}else{if(O<2.25){R=2}else{if(O<3){R=2.5}else{if(O<7.5){R=5}}}}if(R==2.5&&N==0){R=2}R*=S;return R}function E(M){return M.toString()}function F(M){return"("+M.x+", "+M.y+")"}function H(M){return Math.pow(10,Math.floor(Math.log(M)/Math.LN10))}function K(O){var M;if((M=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(O))){return new B(parseInt(M[1]),parseInt(M[2]),parseInt(M[3]))}if((M=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(O))){return new B(parseInt(M[1]),parseInt(M[2]),parseInt(M[3]),parseFloat(M[4]))}if((M=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(O))){return new B(parseFloat(M[1])*2.55,parseFloat(M[2])*2.55,parseFloat(M[3])*2.55)}if((M=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(O))){return new B(parseFloat(M[1])*2.55,parseFloat(M[2])*2.55,parseFloat(M[3])*2.55,parseFloat(M[4]))}if((M=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(O))){return new B(parseInt(M[1],16),parseInt(M[2],16),parseInt(M[3],16))}if((M=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(O))){return new B(parseInt(M[1]+M[1],16),parseInt(M[2]+M[2],16),parseInt(M[3]+M[3],16))}var N=O.strip().toLowerCase();if(N=="transparent"){return new B(255,255,255,0)}M=D[N];return new B(M[0],M[1],M[2])}function A(N){var M;do{M=N.getStyle("background-color").toLowerCase();if(M!=""&&M!="transparent"){break}N=N.up(0)}while(N.nodeName.toLowerCase()!="body");if(M=="rgba(0, 0, 0, 0)"){return"transparent"}return M}function B(S,R,N,P){var Q=["r","g","b","a"];var M=4;while(-1<--M){this[Q[M]]=arguments[M]||((M==3)?1:0)}this.toString=function(){return(this.a>=1)?"rgb("+[this.r,this.g,this.b].join(",")+")":"rgba("+[this.r,this.g,this.b,this.a].join(",")+")"};this.scale=function(V,U,W,T){M=4;while(-1<--M){if(arguments[M]!=null){this[Q[M]]*=arguments[M]}}return this.normalize()};this.adjust=function(V,U,W,T){M=4;while(-1<--M){if(arguments[M]!=null){this[Q[M]]+=arguments[M]}}return this.normalize()};this.clone=function(){return new B(this.r,this.b,this.g,this.a)};var O=function(U,T,V){return Math.max(Math.min(U,V),T)};this.normalize=function(){this.r=O(parseInt(this.r),0,255);this.g=O(parseInt(this.g),0,255);this.b=O(parseInt(this.b),0,255);this.a=O(this.a,0,1);return this};this.normalize()}var D={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]};function J(y,AO,p){var o,S,AL,h,AS;var z="flotr-"+C++;var R=L(AO);var N=y;var u={},c={};var l={left:0,right:0,top:0,bottom:0};var AA=0;var d=0;var AH=0;var U=0;var P=0;var AD=0;var AC=0;var AB=0;g(p);k();AN();q();AK(u,o.xaxis);Z();AK(c,o.yaxis);m(u,o.xaxis);m(c,o.yaxis);Y();AP();AQ();this.getCanvas=function(){return S};this.getPlotOffset=function(){return l};this.clearSelection=M;this.setSelection=AF;function g(AV){o=G(AV,{colors:["#00A8F0","#C0D800","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:0.85},xaxis:{ticks:null,noTicks:5,tickFormatter:E,tickDecimals:null,min:null,max:null,autoscaleMargin:0},yaxis:{ticks:null,noTicks:5,tickFormatter:E,tickDecimals:null,min:null,max:null,autoscaleMargin:0},points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff"},lines:{show:false,lineWidth:2,fill:false,fillColor:null},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null},grid:{color:"#545454",backgroundColor:null,tickColor:"#dddddd",labelMargin:3},selection:{mode:null,color:"#B6D9FF",fps:10},mouse:{track:null,position:"se",trackFormatter:F,margin:3,color:"#ff3f19",trackDecimals:1,sensibility:2,radius:3},shadowSize:4});var Ah=R.length;var AT=[];var AZ=[];for(var Ac=0;Ac<R.length;++Ac){var Ag=R[Ac].color;if(Ag!=null){--Ah;if(Object.isNumber(Ag)){AZ.push(Ag)}else{AT.push(K(R[Ac].color))}}}for(var Ab=0;Ab<AZ.length;++Ab){Ah=Math.max(Ah,AZ[Ab]+1)}var AU=[];var AY=0;var Aa=0;while(AU.length<Ah){var Af=(o.colors.length==Aa)?new B(100,100,100):K(o.colors[Aa]);var AW=AY%2==1?-1:1;var Ae=1+AW*Math.ceil(AY/2)*0.2;Af.scale(Ae,Ae,Ae);AU.push(Af);if(++Aa>=o.colors.length){Aa=0;++AY}}var Ad=0;for(var AX=0,Ai;AX<R.length;++AX){Ai=R[AX];if(Ai.color==null){Ai.color=AU[Ad].toString();++Ad}else{if(Object.isNumber(Ai.color)){Ai.color=AU[Ai.color].toString()}}Ai.lines=Object.extend(Object.clone(o.lines),Ai.lines);Ai.points=Object.extend(Object.clone(o.points),Ai.points);Ai.bars=Object.extend(Object.clone(o.bars),Ai.bars);Ai.mouse=Object.extend(Object.clone(o.mouse),Ai.mouse);if(Ai.shadowSize==null){Ai.shadowSize=o.shadowSize}}}function k(){AH=N.getWidth();U=N.getHeight();N.innerHTML="";N.setStyle({position:"relative"});if(AH<=0||U<=0){throw"Invalid dimensions for plot, width = "+AH+", height = "+U}S=$(document.createElement("canvas")).writeAttribute({width:AH,height:U});N.appendChild(S);if(Prototype.Browser.IE){S=$(window.G_vmlCanvasManager.initElement(S))}h=S.getContext("2d");AL=$(document.createElement("canvas")).writeAttribute({width:AH,height:U}).setStyle({position:"absolute",left:"0px",top:"0px"});N.setStyle({cursor:"default"}).appendChild(AL);if(Prototype.Browser.IE){AL=$(window.G_vmlCanvasManager.initElement(AL))}AS=AL.getContext("2d")}function AN(){if(o.selection.mode!=null){AL.observe("mousedown",r)}AL.observe("mousemove",e);AL.observe("click",f)}function q(){c.datamin=u.datamin=0;u.datamax=c.datamax=1;if(R.length==0){return }var AY=false;for(var AV=0;AV<R.length;++AV){if(R[AV].data.length>0){u.datamin=u.datamax=R[AV].data[0][0];c.datamin=c.datamax=R[AV].data[0][1];AY=true;break}}if(!AY){return }for(var AU=0;AU<R.length;++AU){var AX=R[AU].data;for(var AW=0;AW<AX.length;++AW){var AT=AX[AW][0];var AZ=AX[AW][1];if(AT<u.datamin){u.datamin=AT}else{if(AT>u.datamax){u.datamax=AT}}if(AZ<c.datamin){c.datamin=AZ}else{if(AZ>c.datamax){c.datamax=AZ}}}}}function AK(AW,AY){var AV=AY.min!=null?AY.min:AW.datamin;var AT=AY.max!=null?AY.max:AW.datamax;if(AT-AV==0){var AU=(AT==0)?1:0.01;AV-=AU;AT+=AU}AW.tickSize=I(AY.noTicks,AV,AT,AY.tickDecimals);var AX;if(AY.min==null){AX=AY.autoscaleMargin;if(AX!=0){AV-=AW.tickSize*AX;if(AV<0&&AW.datamin>=0){AV=0}AV=AW.tickSize*Math.floor(AV/AW.tickSize)}}if(AY.max==null){AX=AY.autoscaleMargin;if(AX!=0){AT+=AW.tickSize*AX;if(AT>0&&AW.datamax<=0){AT=0}AT=AW.tickSize*Math.ceil(AT/AW.tickSize)}}AW.min=AV;AW.max=AT}function Z(){if(o.xaxis.max==null){var AU=u.max;for(var AT=0;AT<R.length;++AT){if(R[AT].bars.show&&R[AT].bars.barWidth+u.datamax>AU){AU=u.max+R[AT].bars.barWidth}}u.max=AU}}function m(AV,AW){AV.ticks=[];if(AW.ticks){var AZ=AW.ticks;if(Object.isFunction(AZ)){AZ=AZ({min:AV.min,max:AV.max})}for(var AX=0,Aa,AY;AX<AZ.length;++AX){var Ab=AZ[AX];if(typeof (Ab)=="object"){Aa=Ab[0];AY=(Ab.length>1)?Ab[1]:AW.tickFormatter(Aa)}else{Aa=Ab;AY=AW.tickFormatter(Aa)}AV.ticks[AX]={v:Aa,label:AY}}}else{var AT=AV.tickSize*Math.ceil(AV.min/AV.tickSize);for(AX=0;AT+AX*AV.tickSize<=AV.max;++AX){Aa=AT+AX*AV.tickSize;var AU=AW.tickDecimals;if(AU==null){AU=1-Math.floor(Math.log(AV.tickSize)/Math.LN10)}if(AU<0){AU=0}Aa=Aa.toFixed(AU);AV.ticks.push({v:Aa,label:AW.tickFormatter(Aa)})}}}function Y(){var AX="";for(var AW=0;AW<c.ticks.length;++AW){var AU=c.ticks[AW].label.length;if(AU>AX.length){AX=c.ticks[AW].label}}var AT=N.insert('<div style="position:absolute;top:-10000px;font-size:smaller" class="flotr-grid-label">'+AX+"</div>").down(0).next(1);AA=AT.getWidth();d=AT.getHeight();AT.remove();var AY=2;if(o.points.show){AY=Math.max(AY,o.points.radius+o.points.lineWidth/2)}for(var AV=0;AV<R.length;++AV){if(R[AV].points.show){AY=Math.max(AY,R[AV].points.radius+R[AV].points.lineWidth/2)}}l.left=l.right=l.top=l.bottom=AY;l.left+=AA+o.grid.labelMargin;l.bottom+=d+o.grid.labelMargin;P=AH-l.left-l.right;AD=U-l.bottom-l.top;AC=P/(u.max-u.min);AB=AD/(c.max-c.min)}function AP(){V();AR();for(var AT=0;AT<R.length;AT++){AI(R[AT])}}function AE(AT){return(AT-u.min)*AC}function j(AT){return AD-(AT-c.min)*AB}function V(){h.save();h.translate(l.left,l.top);if(o.grid.backgroundColor!=null){h.fillStyle=o.grid.backgroundColor;h.fillRect(0,0,P,AD)}h.lineWidth=1;h.strokeStyle=o.grid.tickColor;h.beginPath();for(var AV=0,AT=null;AV<u.ticks.length;++AV){AT=u.ticks[AV].v;if(AT==u.min||AT==u.max){continue}h.moveTo(Math.floor(AE(AT))+h.lineWidth/2,0);h.lineTo(Math.floor(AE(AT))+h.lineWidth/2,AD)}for(var AU=0,AT=null;AU<c.ticks.length;++AU){AT=c.ticks[AU].v;if(AT==c.min||AT==c.max){continue}h.moveTo(0,Math.floor(j(AT))+h.lineWidth/2);h.lineTo(P,Math.floor(j(AT))+h.lineWidth/2)}h.stroke();h.lineWidth=2;h.strokeStyle=o.grid.color;h.lineJoin="round";h.strokeRect(0,0,P,AD);h.restore()}function AR(){var AZ=0;for(var AY=0;AY<u.ticks.length;++AY){if(u.ticks[AY].label){++AZ}}var AU=P/AZ;var AX='<div style="font-size:smaller;color:'+o.grid.color+'">';for(var AV=0,AW=null;AV<u.ticks.length;++AV){AW=u.ticks[AV];if(!AW.label){continue}AX+='<div style="position:absolute;top:'+(l.top+AD+o.grid.labelMargin)+"px;left:"+(l.left+AE(AW.v)-AU/2)+"px;width:"+AU+'px;text-align:center" class="flotr-grid-label">'+AW.label+"</div>"}for(var AT=0,AW=null;AT<c.ticks.length;++AT){AW=c.ticks[AT];if(!AW.label||AW.label.length==0){continue}AX+='<div style="position:absolute;top:'+(l.top+j(AW.v)-d/2)+"px;left:0;width:"+AA+'px;text-align:right" class="flotr-grid-label">'+AW.label+"</div>"}AX+="</div>";N.insert(AX)}function AI(AT){if(AT.lines.show||(!AT.bars.show&&!AT.points.show)){i(AT)}if(AT.bars.show){v(AT)}if(AT.points.show){w(AT)}}function i(AV){function AU(Ad,Ac){if(Ad.length<2){return }var Ab=AE(Ad[0][0]),Aa=j(Ad[0][1])+Ac;h.beginPath();h.moveTo(Ab,Aa);for(var Ae=0;Ae<Ad.length-1;++Ae){var AZ=Ad[Ae][0],Ag=Ad[Ae][1],AY=Ad[Ae+1][0],Af=Ad[Ae+1][1];if(Ag<=Af&&Ag<c.min){if(Af<c.min){continue}AZ=(c.min-Ag)/(Af-Ag)*(AY-AZ)+AZ;Ag=c.min}else{if(Af<=Ag&&Af<c.min){if(Ag<c.min){continue}AY=(c.min-Ag)/(Af-Ag)*(AY-AZ)+AZ;Af=c.min}}if(Ag>=Af&&Ag>c.max){if(Af>c.max){continue}AZ=(c.max-Ag)/(Af-Ag)*(AY-AZ)+AZ;Ag=c.max}else{if(Af>=Ag&&Af>c.max){if(Ag>c.max){continue}AY=(c.max-Ag)/(Af-Ag)*(AY-AZ)+AZ;Af=c.max}}if(AZ<=AY&&AZ<u.min){if(AY<u.min){continue}Ag=(u.min-AZ)/(AY-AZ)*(Af-Ag)+Ag;AZ=u.min}else{if(AY<=AZ&&AY<u.min){if(AZ<u.min){continue}Af=(u.min-AZ)/(AY-AZ)*(Af-Ag)+Ag;AY=u.min}}if(AZ>=AY&&AZ>u.max){if(AY>u.max){continue}Ag=(u.max-AZ)/(AY-AZ)*(Af-Ag)+Ag;AZ=u.max}else{if(AY>=AZ&&AY>u.max){if(AZ>u.max){continue}Af=(u.max-AZ)/(AY-AZ)*(Af-Ag)+Ag;AY=u.max}}if(Ab!=AE(AZ)||Aa!=j(Ag)+Ac){h.moveTo(AE(AZ),j(Ag)+Ac)}Ab=AE(AY);Aa=j(Af)+Ac;h.lineTo(Ab,Aa)}h.stroke()}function AW(Ac){if(Ac.length<2){return }var AY=Math.min(Math.max(0,c.min),c.max);var Ah,Aa=0;var Ae=true;h.beginPath();for(var Ad=0;Ad<Ac.length-1;++Ad){var Ab=Ac[Ad][0],Ai=Ac[Ad][1],AZ=Ac[Ad+1][0],Ag=Ac[Ad+1][1];if(Ab<=AZ&&Ab<u.min){if(AZ<u.min){continue}Ai=(u.min-Ab)/(AZ-Ab)*(Ag-Ai)+Ai;Ab=u.min}else{if(AZ<=Ab&&AZ<u.min){if(Ab<u.min){continue}Ag=(u.min-Ab)/(AZ-Ab)*(Ag-Ai)+Ai;AZ=u.min}}if(Ab>=AZ&&Ab>u.max){if(AZ>u.max){continue}Ai=(u.max-Ab)/(AZ-Ab)*(Ag-Ai)+Ai;Ab=u.max}else{if(AZ>=Ab&&AZ>u.max){if(Ab>u.max){continue}Ag=(u.max-Ab)/(AZ-Ab)*(Ag-Ai)+Ai;AZ=u.max}}if(Ae){h.moveTo(AE(Ab),j(AY));Ae=false}if(Ai>=c.max&&Ag>=c.max){h.lineTo(AE(Ab),j(c.max));h.lineTo(AE(AZ),j(c.max));continue}else{if(Ai<=c.min&&Ag<=c.min){h.lineTo(AE(Ab),j(c.min));h.lineTo(AE(AZ),j(c.min));continue}}var Aj=Ab,Af=AZ;if(Ai<=Ag&&Ai<c.min&&Ag>=c.min){Ab=(c.min-Ai)/(Ag-Ai)*(AZ-Ab)+Ab;Ai=c.min}else{if(Ag<=Ai&&Ag<c.min&&Ai>=c.min){AZ=(c.min-Ai)/(Ag-Ai)*(AZ-Ab)+Ab;Ag=c.min}}if(Ai>=Ag&&Ai>c.max&&Ag<=c.max){Ab=(c.max-Ai)/(Ag-Ai)*(AZ-Ab)+Ab;Ai=c.max}else{if(Ag>=Ai&&Ag>c.max&&Ai<=c.max){AZ=(c.max-Ai)/(Ag-Ai)*(AZ-Ab)+Ab;Ag=c.max}}if(Ab!=Aj){Ah=(Ai<=c.min)?Ah=c.min:c.max;h.lineTo(AE(Aj),j(Ah));h.lineTo(AE(Ab),j(Ah))}h.lineTo(AE(Ab),j(Ai));h.lineTo(AE(AZ),j(Ag));if(AZ!=Af){Ah=(Ag<=c.min)?c.min:c.max;h.lineTo(AE(Af),j(Ah));h.lineTo(AE(AZ),j(Ah))}Aa=Math.max(AZ,Af)}h.lineTo(AE(Aa),j(AY));h.closePath();h.fill()}h.save();h.translate(l.left,l.top);h.lineJoin="round";var AX=AV.lines.lineWidth;var AT=AV.shadowSize;if(AT>0){h.lineWidth=AT/2;h.strokeStyle="rgba(0,0,0,0.1)";AU(AV.data,AX/2+AT/2+h.lineWidth/2);h.lineWidth=AT/2;h.strokeStyle="rgba(0,0,0,0.2)";AU(AV.data,AX/2+h.lineWidth/2)}h.lineWidth=AX;h.strokeStyle=AV.color;if(AV.lines.fill){h.fillStyle=AV.lines.fillColor!=null?AV.lines.fillColor:K(AV.color).scale(null,null,null,0.4).toString();AW(AV.data,0)}AU(AV.data,0);h.restore()}function w(AU){function AX(Ab,AZ,Ac){for(var Aa=0;Aa<Ab.length;++Aa){var AY=Ab[Aa][0],Ad=Ab[Aa][1];if(AY<u.min||AY>u.max||Ad<c.min||Ad>c.max){continue}h.beginPath();h.arc(AE(AY),j(Ad),AZ,0,2*Math.PI,true);if(Ac){h.fill()}h.stroke()}}function AW(Ab,Ac,AZ){for(var Aa=0;Aa<Ab.length;++Aa){var AY=Ab[Aa][0],Ad=Ab[Aa][1];if(AY<u.min||AY>u.max||Ad<c.min||Ad>c.max){continue}h.beginPath();h.arc(AE(AY),j(Ad)+Ac,AZ,0,Math.PI,false);h.stroke()}}h.save();h.translate(l.left,l.top);var AV=AU.lines.lineWidth;var AT=AU.shadowSize;if(AT>0){h.lineWidth=AT/2;h.strokeStyle="rgba(0,0,0,0.1)";AW(AU.data,AT/2+h.lineWidth/2,AU.points.radius);h.lineWidth=AT/2;h.strokeStyle="rgba(0,0,0,0.2)";AW(AU.data,h.lineWidth/2,AU.points.radius)}h.lineWidth=AU.points.lineWidth;h.strokeStyle=AU.color;h.fillStyle=AU.points.fillColor!=null?AU.points.fillColor:AU.color;AX(AU.data,AU.points.radius,AU.points.fill);h.restore()}function v(AU){function AT(Ab,Ak,AZ,Aj){if(Ab.length<2){return }for(var Ac=0;Ac<Ab.length;Ac++){var Ag=Ab[Ac][0],Af=Ab[Ac][1];var Ai=true,Aa=true,Ad=true;var AY=Ag,Ah=Ag+Ak,AX=0,Ae=Af;if(Ah<u.min||AY>u.max||Ae<c.min||AX>c.max){continue}if(AY<u.min){AY=u.min;Ai=false}if(Ah>u.max){Ah=u.max;Ad=false}if(AX<c.min){AX=c.min}if(Ae>c.max){Ae=c.max;Aa=false}if(Aj){h.beginPath();h.moveTo(AE(AY),j(AX)+AZ);h.lineTo(AE(AY),j(Ae)+AZ);h.lineTo(AE(Ah),j(Ae)+AZ);h.lineTo(AE(Ah),j(AX)+AZ);h.fill()}if(Ai||Ad||Aa){h.beginPath();h.moveTo(AE(AY),j(AX)+AZ);if(Ai){h.lineTo(AE(AY),j(Ae)+AZ)}else{h.moveTo(AE(AY),j(Ae)+AZ)}if(Aa){h.lineTo(AE(Ah),j(Ae)+AZ)}else{h.moveTo(AE(Ah),j(Ae)+AZ)}if(Ad){h.lineTo(AE(Ah),j(AX)+AZ)}else{h.moveTo(AE(Ah),j(AX)+AZ)}h.stroke()}}}h.save();h.translate(l.left,l.top);h.lineJoin="round";var AW=AU.bars.barWidth;var AV=Math.min(AU.bars.lineWidth,AW);h.lineWidth=AV;h.strokeStyle=AU.color;if(AU.bars.fill){h.fillStyle=AU.bars.fillColor!=null?AU.bars.fillColor:K(AU.color).scale(null,null,null,0.4).toString()}AT(AU.data,AW,0,AU.bars.fill);h.restore()}function AQ(){if(!o.legend.show){return }var Aa=[];var AY=false;for(var AX=0;AX<R.length;++AX){if(!R[AX].label){continue}if(AX%o.legend.noColumns==0){Aa.push((AY)?"</tr><tr>":"<tr>");AY=true}var Ac=R[AX].label;if(o.legend.labelFormatter!=null){Ac=o.legend.labelFormatter(Ac)}Aa.push('<td class="flotr-legend-color-box"><div style="border:1px solid '+o.legend.labelBoxBorderColor+';padding:1px"><div style="width:14px;height:10px;background-color:'+R[AX].color+'"></div></div></td><td class="flotr-legend-label">'+Ac+"</td>")}if(AY){Aa.push("</tr>")}if(Aa.length>0){var Ad='<table style="font-size:smaller;color:'+o.grid.color+'">'+Aa.join("")+"</table>";if(o.legend.container!=null){o.legend.container.append(Ad)}else{var Ab="";var AU=o.legend.position,AV=o.legend.margin;if(AU.charAt(0)=="n"){Ab+="top:"+(AV+l.top)+"px;"}else{if(AU.charAt(0)=="s"){Ab+="bottom:"+(AV+l.bottom)+"px;"}}if(AU.charAt(1)=="e"){Ab+="right:"+(AV+l.right)+"px;"}else{if(AU.charAt(1)=="w"){Ab+="left:"+(AV+l.bottom)+"px;"}}var AT=N.insert('<div class="flotr-legend" style="position:absolute;z-index:2;'+Ab+'">'+Ad+"</div>").getElementsBySelector("div.flotr-legend").first();if(o.legend.backgroundOpacity!=0){var AZ=o.legend.backgroundColor;if(AZ==null){var AW=(o.grid.backgroundColor!=null)?o.grid.backgroundColor:A(AT);AZ=K(AW).adjust(null,null,null,1).toString()}N.insert('<div class="flotr-legend-bg" style="position:absolute;width:'+AT.getWidth()+"px;height:"+AT.getHeight()+"px;"+Ab+"background-color:"+AZ+';"> </div>').select("div.flotr-legend-bg").first().setStyle({opacity:o.legend.backgroundOpacity})}}}}var AG={pageX:null,pageY:null};var b={first:{x:-1,y:-1},second:{x:-1,y:-1}};var T=null;var x=null;var t=false;var Q=null;function f(AT){if(t){t=false;return }var AU=AL.cumulativeOffset();N.fire("flotr:click",[{x:u.min+(AT.pageX-AU.left-l.left)/AC,y:c.max-(AT.pageY-AU.top-l.top)/AB}])}function e(AU){if(AU.pageX==null&&AU.clientX!=null){var AX=document.documentElement,AT=document.body;AG.pageX=AU.clientX+(AX&&AX.scrollLeft||AT.scrollLeft||0);AG.pageY=AU.clientY+(AX&&AX.scrollTop||AT.scrollTop||0)}else{AG.pageX=AU.pageX;AG.pageY=AU.pageY}var AV=AL.cumulativeOffset();var AW={x:u.min+(AU.pageX-AV.left-l.left)/AC,y:c.max-(AU.pageY-AV.top-l.top)/AB};if(o.mouse.track&&x==null){n(AW)}N.fire("flotr:mousemove",[AU,AW])}function r(AT){if(!AT.isLeftClick()){return }AM(b.first,AT);if(x!=null){clearInterval(x)}AG.pageX=null;x=setInterval(AJ,1000/o.selection.fps);$(document).observe("mouseup",O)}function a(){var AU=(b.first.x<=b.second.x)?b.first.x:b.second.x;var AT=(b.first.x<=b.second.x)?b.second.x:b.first.x;var AW=(b.first.y>=b.second.y)?b.first.y:b.second.y;var AV=(b.first.y>=b.second.y)?b.second.y:b.first.y;AU=u.min+AU/AC;AT=u.min+AT/AC;AW=c.max-AW/AB;AV=c.max-AV/AB;N.fire("flotr:select",[{x1:AU,y1:AW,x2:AT,y2:AV}])}function O(AT){$(document).stopObserving("mouseup",O);if(x!=null){clearInterval(x);x=null}AM(b.second,AT);M();if(W()||AT.isLeftClick()){X();a();t=true}Event.stop(AT)}function AM(AV,AT){var AU=$(AL).cumulativeOffset();if(o.selection.mode=="y"){AV.x=(AV==b.first)?0:P}else{AV.x=AT.pageX-AU.left-l.left;AV.x=Math.min(Math.max(0,AV.x),P)}if(o.selection.mode=="x"){AV.y=(AV==b.first)?0:AD}else{AV.y=AT.pageY-AU.top-l.top;AV.y=Math.min(Math.max(0,AV.y),AD)}}function AJ(){if(AG.pageX==null){return }AM(b.second,AG);M();if(W()){X()}}function M(){if(T==null){return }var AT=Math.min(T.first.x,T.second.x),AW=Math.min(T.first.y,T.second.y),AU=Math.abs(T.second.x-T.first.x),AV=Math.abs(T.second.y-T.first.y);AS.clearRect(AT+l.left-AS.lineWidth,AW+l.top-AS.lineWidth,AU+AS.lineWidth*2,AV+AS.lineWidth*2);T=null}function AF(AT){M();b.first.y=(o.selection.mode=="x")?0:(c.max-AT.y1)*AB;b.second.y=(o.selection.mode=="x")?AD:(c.max-AT.y2)*AB;b.first.x=(o.selection.mode=="y")?0:(AT.x1-u.min)*AC;b.second.x=(o.selection.mode=="y")?P:(AT.x2-u.min)*AC;X();a()}function X(){if(T!=null&&b.first.x==T.first.x&&b.first.y==T.first.y&&b.second.x==T.second.x&&b.second.y==T.second.y){return }AS.strokeStyle=K(o.selection.color).scale(null,null,null,0.8).toString();AS.lineWidth=1;h.lineJoin="round";AS.fillStyle=K(o.selection.color).scale(null,null,null,0.4).toString();T={first:{x:b.first.x,y:b.first.y},second:{x:b.second.x,y:b.second.y}};var AT=Math.min(b.first.x,b.second.x),AW=Math.min(b.first.y,b.second.y),AU=Math.abs(b.second.x-b.first.x),AV=Math.abs(b.second.y-b.first.y);AS.fillRect(AT+l.left,AW+l.top,AU,AV);AS.strokeRect(AT+l.left,AW+l.top,AU,AV)}function W(){var AT=5;return Math.abs(b.second.x-b.first.x)>=AT&&Math.abs(b.second.y-b.first.y)>=AT}function s(){if(Q){AS.clearRect(AE(Q.x)+l.left-o.points.radius*2,j(Q.y)+l.top-o.points.radius*2,o.points.radius*3+o.points.lineWidth*3,o.points.radius*3+o.points.lineWidth*3);Q=null}}function n(Ae){var AX={dist:Number.MAX_VALUE,x:null,y:null,mouse:null};for(var Ad=0,Ac,AZ,AV;Ad<R.length;Ad++){if(!R[Ad].mouse.track){continue}Ac=R[Ad].data;AZ=(AC*R[Ad].mouse.sensibility);AV=(AB*R[Ad].mouse.sensibility);for(var Aa=0,Af,Ab;Aa<Ac.length;Aa++){Af=AC*Math.abs(Ac[Aa][0]-Ae.x);Ab=AB*Math.abs(Ac[Aa][1]-Ae.y);if(Af<AZ&&Ab<AV&&(Af+Ab)<AX.dist){AX.dist=(Af+Ab);AX.x=Ac[Aa][0];AX.y=Ac[Aa][1];AX.mouse=R[Ad].mouse}}}if(AX.mouse&&AX.mouse.track&&!Q||(Q&&AX.x!=Q.x&&AX.y!=Q.y)){var AU=N.select(".flotr-mouse-value").first();if(!AU){var Ag="",AT=o.mouse.position,AY=o.mouse.margin;if(AT.charAt(0)=="n"){Ag+="top:"+(AY+l.top)+"px;"}else{if(AT.charAt(0)=="s"){Ag+="bottom:"+(AY+l.bottom)+"px;"}}if(AT.charAt(1)=="e"){Ag+="right:"+(AY+l.right)+"px;"}else{if(AT.charAt(1)=="w"){Ag+="left:"+(AY+l.bottom)+"px;"}}N.insert('<div class="flotr-mouse-value" style="opacity:0.7;background-color:#000;color:#fff;display:none;position:absolute;'+Ag+'"></div>');return }if(AX.x!==null&&AX.y!==null){AU.setStyle({display:"block"});s();if(AX.mouse.lineColor!=null){AS.save();AS.translate(l.left,l.top);AS.lineWidth=o.points.lineWidth;AS.strokeStyle=AX.mouse.lineColor;AS.fillStyle="#ffffff";AS.beginPath();AS.arc(AE(AX.x),j(AX.y),o.points.radius,0,2*Math.PI,true);AS.fill();AS.stroke();AS.restore()}Q=AX;var AW=AX.mouse.trackDecimals;if(AW==null||AW<0){AW=0}AU.innerHTML=AX.mouse.trackFormatter({x:AX.x.toFixed(AW),y:AX.y.toFixed(AW)});N.fire("flotr:hit",[AX])}else{if(Q){AU.setStyle({display:"none"});s()}}}}}return{clean:function(M){M.innerHTML=""},draw:function(P,N,M){var O=new J(P,N,M);return O}}})();
\ No newline at end of file diff --git a/tools/qtestlib/chart/3rdparty/prototype.js b/tools/qtestlib/chart/3rdparty/prototype.js new file mode 100644 index 0000000..e580ae5 --- /dev/null +++ b/tools/qtestlib/chart/3rdparty/prototype.js @@ -0,0 +1,8 @@ +/* Prototype JavaScript framework, version 1.6.0.2 + * (c) 2005-2008 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ +eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('G 1g={9D:\'1.6.0.2\',1W:{3X:!!(1A.7b&&!1A.9e),58:!!1A.9e,4u:5e.5d.47(\'hE/\')>-1,7H:5e.5d.47(\'7H\')>-1&&5e.5d.47(\'ch\')==-1,d5:!!5e.5d.1f(/hD.*hC.*ci/)},3U:{72:!!1b.2S,6H:!!1A.6G,7x:1b.43(\'1T\').4U&&1b.43(\'1T\').4U!==1b.43(\'1x\').4U},84:\'<4S[^>]*>([\\\\S\\\\s]*?)<\\/4S>\',cM:/^\\/\\*-hB-([\\s\\S]*)\\*\\/\\s*$/,3q:q(){},K:q(x){o x}};E(1g.1W.d5)1g.3U.7x=1r;G 2b={2p:q(){G 2T=1k,3k=$A(1p);E(M.2w(3k[0]))2T=3k.5i();q 1N(){C.2I.3R(C,1p)}M.15(1N,2b.1d);1N.9Z=2T;1N.d4=[];E(2T){G a0=q(){};a0.1l=2T.1l;1N.1l=1s a0;2T.d4.1h(1N)}17(G i=0;i<3k.O;i++)1N.6a(3k[i]);E(!1N.1l.2I)1N.1l.2I=1g.3q;1N.1l.hA=1N;o 1N}};2b.1d={6a:q(22){G 3b=C.9Z&&C.9Z.1l;G 3k=M.4b(22);E(!M.4b({2H:1u}).O)3k.1h("2H","d3");17(G i=0,O=3k.O;i<O;i++){G 1y=3k[i],I=22[1y];E(3b&&M.2w(I)&&I.d1().3K()=="$4d"){G 1F=I,I=M.15((q(m){o q(){o 3b[m].3R(C,1p)}})(1y).5g(1F),{d3:q(){o 1F},2H:q(){o 1F.2H()}})}C.1l[1y]=I}o C}};G 4Y={};M.15=q(5L,22){17(G 1y 1Q 22)5L[1y]=22[1y];o 5L};M.15(M,{2C:q(Y){2s{E(M.2D(Y))o\'4z\';E(Y===1k)o\'1k\';o Y.2C?Y.2C():24(Y)}2E(e){E(e d2 hz)o\'...\';4q e}},3D:q(Y){G 1B=3Z Y;5y(1B){2r\'4z\':2r\'q\':2r\'hy\':o;2r\'hx\':o Y.2H()}E(Y===1k)o\'1k\';E(Y.3D)o Y.3D();E(M.4j(Y))o;G V=[];17(G 1y 1Q Y){G I=M.3D(Y[1y]);E(!M.2D(I))V.1h(1y.3D()+\': \'+I)}o\'{\'+V.2o(\', \')+\'}\'},4r:q(Y){o $H(Y).4r()},4i:q(Y){o Y&&Y.4i?Y.4i():24.62(Y)},4b:q(Y){G 4b=[];17(G 1y 1Q Y)4b.1h(1y);o 4b},1S:q(Y){G 1S=[];17(G 1y 1Q Y)1S.1h(Y[1y]);o 1S},2A:q(Y){o M.15({},Y)},4j:q(Y){o Y&&Y.3r==1},4x:q(Y){o Y!=1k&&3Z Y=="Y"&&\'hw\'1Q Y&&\'2o\'1Q Y},9G:q(Y){o Y d2 3V},2w:q(Y){o 3Z Y=="q"},3f:q(Y){o 3Z Y=="3h"},53:q(Y){o 3Z Y=="4M"},2D:q(Y){o 3Z Y=="4z"}});M.15(9X.1l,{d1:q(){G 3A=C.2H().1f(/^[\\s\\(]*q[^(]*\\((.*?)\\)/)[1].49(",").7k("3T");o 3A.O==1&&!3A[0]?[]:3A},1L:q(){E(1p.O<2&&M.2D(1p[0]))o C;G 3n=C,21=$A(1p),Y=21.5i();o q(){o 3n.3R(Y,21.20($A(1p)))}},hv:q(){G 3n=C,21=$A(1p),Y=21.5i();o q(1c){o 3n.3R(Y,[1c||1A.1c].20(21))}},7T:q(){E(!1p.O)o C;G 3n=C,21=$A(1p);o q(){o 3n.3R(C,21.20($A(1p)))}},9l:q(){G 3n=C,21=$A(1p),d0=21.5i()*cY;o 1A.hu(q(){o 3n.3R(3n,21)},d0)},5g:q(1K){G 3n=C;o q(){o 1K.3R(C,[3n.1L(C)].20($A(1p)))}},4v:q(){E(C.9Y)o C.9Y;G 3n=C;o C.9Y=q(){o 3n.3R(1k,[C].20($A(1p)))}}});9X.1l.4s=9X.1l.9l.7T(0.ht);hs.1l.3D=q(){o\'"\'+C.hr()+\'-\'+(C.hq()+1).4L(2)+\'-\'+C.hp().4L(2)+\'T\'+C.ho().4L(2)+\':\'+C.hn().4L(2)+\':\'+C.hm().4L(2)+\'Z"\'};G cp={co:q(){G 7d;17(G i=0,O=1p.O;i<O;i++){G cZ=1p[i];2s{7d=cZ();2d}2E(e){}}o 7d}};4k.1l.1f=4k.1l.2L;4k.c3=q(68){o 24(68).1Y(/([.*+?^=!:${}()|[\\]\\/\\\\])/g,\'\\\\$1\')};G aB=2b.2p({2I:q(2X,4c){C.2X=2X;C.4c=4c;C.85=1r;C.6s()},6s:q(){C.3W=ae(C.6N.1L(C),C.4c*cY)},8t:q(){C.2X(C)},8p:q(){E(!C.3W)o;af(C.3W);C.3W=1k},6N:q(){E(!C.85){2s{C.85=1u;C.8t()}hl{C.85=1r}}}});M.15(24,{62:q(I){o I==1k?\'\':24(I)},cQ:{\'\\b\':\'\\\\b\',\'\\t\':\'\\\\t\',\'\\n\':\'\\\\n\',\'\\f\':\'\\\\f\',\'\\r\':\'\\\\r\',\'\\\\\':\'\\\\\\\\\'}});M.15(24.1l,{3m:q(28,3F){G 1q=\'\',22=C,1f;3F=1p.5v.9S(3F);1P(22.O>0){E(1f=22.1f(28)){1q+=22.3B(0,1f.1i);1q+=24.62(3F(1f));22=22.3B(1f.1i+1f[0].O)}1m{1q+=22,22=\'\'}}o 1q},cN:q(28,3F,3x){3F=C.3m.9S(3F);3x=M.2D(3x)?1:3x;o C.3m(28,q(1f){E(--3x<0)o 1f[0];o 3F(1f)})},aN:q(28,W){C.3m(28,W);o 24(C)},hk:q(O,69){O=O||30;69=M.2D(69)?\'...\':69;o C.O>O?C.3B(0,O-69.O)+69:24(C)},3T:q(){o C.1Y(/^\\s+/,\'\').1Y(/\\s+$/,\'\')},cS:q(){o C.1Y(/<\\/?[^>]+>/gi,\'\')},4h:q(){o C.1Y(1s 4k(1g.84,\'cX\'),\'\')},cT:q(){G cW=1s 4k(1g.84,\'cX\');G cU=1s 4k(1g.84,\'hj\');o(C.1f(cW)||[]).2M(q(cV){o(cV.1f(cU)||[\'\',\'\'])[1]})},59:q(){o C.cT().2M(q(4S){o 7u(4S)})},82:q(){G 5J=1p.5v;5J.3Y.7n=C;o 5J.1T.4C},cJ:q(){G 1T=1s J(\'1T\');1T.4C=C.cS();o 1T.3g[0]?(1T.3g.O>1?$A(1T.3g).3H(\'\',q(2O,L){o 2O+L.4f}):1T.3g[0].4f):\'\'},7g:q(cR){G 1f=C.3T().1f(/([^?#]*)(#.*)?$/);E(!1f)o{};o 1f[1].49(cR||\'&\').3H({},q(3w,1H){E((1H=1H.49(\'=\'))[0]){G 1w=9p(1H.5i());G I=1H.O>1?1H.2o(\'=\'):1H[0];E(I!=4z)I=9p(I);E(1w 1Q 3w){E(!M.4x(3w[1w]))3w[1w]=[3w[1w]];3w[1w].1h(I)}1m 3w[1w]=I}o 3w})},3E:q(){o C.49(\'\')},9I:q(){o C.3B(0,C.O-1)+24.hi(C.cP(C.O-1)+1)},7E:q(3x){o 3x<1?\'\':1s 2m(3x+1).2o(C)},95:q(){G 4N=C.49(\'-\'),9W=4N.O;E(9W==1)o 4N[0];G 9V=C.83(0)==\'-\'?4N[0].83(0).2R()+4N[0].5H(1):4N[0];17(G i=1;i<9W;i++)9V+=4N[i].83(0).2R()+4N[i].5H(1);o 9V},6F:q(){o C.83(0).2R()+C.5H(1).2e()},hh:q(){o C.3m(/::/,\'/\').3m(/([A-Z]+)([A-Z][a-z])/,\'#{1}6T#{2}\').3m(/([a-z\\d])([A-Z])/,\'#{1}6T#{2}\').3m(/-/,\'6T\').2e()},hg:q(){o C.3m(/6T/,\'-\')},2C:q(cO){G 9T=C.3m(/[\\hf-\\he\\\\]/,q(1f){G 9U=24.cQ[1f[0]];o 9U?9U:\'\\\\hd\'+1f[0].cP().4L(2,16)});E(cO)o\'"\'+9T.1Y(/"/g,\'\\\\"\')+\'"\';o"\'"+9T.1Y(/\'/g,\'\\\\\\\'\')+"\'"},3D:q(){o C.2C(1u)},9w:q(2h){o C.cN(2h||1g.cM,\'#{1}\')},cK:q(){G 68=C;E(68.4O())o 1r;68=C.1Y(/\\\\./g,\'@\').1Y(/"[^"\\\\\\n\\r]*"/g,\'\');o(/^[,:{}\\[\\]0-9.\\-+hc-u \\n\\r\\t]*$/).2L(68)},60:q(cL){G 3l=C.9w();2s{E(!cL||3l.cK())o 7u(\'(\'+3l+\')\')}2E(e){}4q 1s hb(\'ha h9 c4 3h: \'+C.2C())},1J:q(28){o C.47(28)>-1},8F:q(28){o C.47(28)===0},aO:q(28){G d=C.O-28.O;o d>=0&&C.9L(28)===d},5E:q(){o C==\'\'},4O:q(){o/^\\s*$/.2L(C)},cb:q(Y,28){o 1s 32(C,28).2S(Y)}});E(1g.1W.4u||1g.1W.3X)M.15(24.1l,{82:q(){o C.1Y(/&/g,\'&cI;\').1Y(/</g,\'&cH;\').1Y(/>/g,\'>\')},cJ:q(){o C.1Y(/&cI;/g,\'&\').1Y(/&cH;/g,\'<\').1Y(/>/g,\'>\')}});24.1l.3m.9S=q(3F){E(M.2w(3F))o 3F;G 67=1s 32(3F);o q(1f){o 67.2S(1f)}};24.1l.h8=24.1l.7g;M.15(24.1l.82,{1T:1b.43(\'1T\'),3Y:1b.bm(\'\')});b0(24.1l.82)1T.5O(3Y);G 32=2b.2p({2I:q(67,28){C.67=67.2H();C.28=28||32.cE},2S:q(Y){E(M.2w(Y.9J))Y=Y.9J();o C.67.3m(C.28,q(1f){E(Y==1k)o\'\';G 4R=1f[1]||\'\';E(4R==\'\\\\\')o 1f[2];G 6X=Y,6Y=1f[3];G 28=/^([^.[]+|\\[((?:.*?[^\\\\])?)\\])(\\.|\\[|$)/;1f=28.cF(6Y);E(1f==1k)o 4R;1P(1f!=1k){G cG=1f[1].8F(\'[\')?1f[2].3m(\'\\\\\\\\]\',\']\'):1f[1];6X=6X[cG];E(1k==6X||\'\'==1f[3])2d;6Y=6Y.5H(\'[\'==1f[3]?1f[1].O:1f[0].O);1f=28.cF(6Y)}o 4R+24.62(6X)})}});32.cE=/(^|.|\\r|\\n)(#\\{(.*?)\\})/;G $2d={};G 2G={1E:q(W,1M){G 1i=0;W=W.1L(1M);2s{C.48(q(I){W(I,1i++)})}2E(e){E(e!=$2d)4q e}o C},cD:q(4M,W,1M){W=W?W.1L(1M):1g.K;G 1i=-4M,9R=[],2F=C.3E();1P((1i+=4M)<2F.O)9R.1h(2F.3B(1i,1i+4M));o 9R.9N(W,1M)},88:q(W,1M){W=W?W.1L(1M):1g.K;G 1q=1u;C.1E(q(I,1i){1q=1q&&!!W(I,1i);E(!1q)4q $2d});o 1q},cB:q(W,1M){W=W?W.1L(1M):1g.K;G 1q=1r;C.1E(q(I,1i){E(1q=!!W(I,1i))4q $2d});o 1q},9N:q(W,1M){W=W?W.1L(1M):1g.K;G V=[];C.1E(q(I,1i){V.1h(W(I,1i))});o V},81:q(W,1M){W=W.1L(1M);G 1q;C.1E(q(I,1i){E(W(I,1i)){1q=I;4q $2d}});o 1q},5C:q(W,1M){W=W.1L(1M);G V=[];C.1E(q(I,1i){E(W(I,1i))V.1h(I)});o V},h7:q(2h,W,1M){W=W?W.1L(1M):1g.K;G V=[];E(M.3f(2h))2h=1s 4k(2h);C.1E(q(I,1i){E(2h.1f(I))V.1h(W(I,1i))});o V},1J:q(Y){E(M.2w(C.47))E(C.47(Y)!=-1)o 1u;G 9Q=1r;C.1E(q(I){E(I==Y){9Q=1u;4q $2d}});o 9Q},h6:q(4M,6W){6W=M.2D(6W)?1k:6W;o C.cD(4M,q(3B){1P(3B.O<4M)3B.1h(6W);o 3B})},3H:q(2O,W,1M){W=W.1L(1M);C.1E(q(I,1i){2O=W(2O,I,1i)});o 2O},7k:q(1F){G 21=$A(1p).3B(1);o C.2M(q(I){o I[1F].3R(I,21)})},h5:q(W,1M){W=W?W.1L(1M):1g.K;G 1q;C.1E(q(I,1i){I=W(I,1i);E(1q==1k||I>=1q)1q=I});o 1q},h4:q(W,1M){W=W?W.1L(1M):1g.K;G 1q;C.1E(q(I,1i){I=W(I,1i);E(1q==1k||I<1q)1q=I});o 1q},h3:q(W,1M){W=W?W.1L(1M):1g.K;G 9P=[],9O=[];C.1E(q(I,1i){(W(I,1i)?9P:9O).1h(I)});o[9P,9O]},5u:q(1y){G V=[];C.1E(q(I){V.1h(I[1y])});o V},h2:q(W,1M){W=W.1L(1M);G V=[];C.1E(q(I,1i){E(!W(I,1i))V.1h(I)});o V},aK:q(W,1M){W=W.1L(1M);o C.2M(q(I,1i){o{I:I,6D:W(I,1i)}}).h1(q(2x,5U){G a=2x.6D,b=5U.6D;o a<b?-1:a>b?1:0}).5u(\'I\')},3E:q(){o C.2M()},h0:q(){G W=1g.K,21=$A(1p);E(M.2w(21.2u()))W=21.gZ();G cC=[C].20(21).2M($A);o C.2M(q(I,1i){o W(cC.5u(1i))})},cw:q(){o C.3E().O},2C:q(){o\'#<2G:\'+C.3E().2C()+\'>\'}};M.15(2G,{2M:2G.9N,8l:2G.81,2z:2G.5C,2h:2G.5C,gY:2G.1J,gX:2G.3E,gW:2G.88,gV:2G.cB});q $A(3d){E(!3d)o[];E(3d.3E)o 3d.3E();G O=3d.O||0,V=1s 2m(O);1P(O--)V[O]=3d[O];o V}E(1g.1W.4u){$A=q(3d){E(!3d)o[];E(!(M.2w(3d)&&3d==\'[Y gU]\')&&3d.3E)o 3d.3E();G O=3d.O||0,V=1s 2m(O);1P(O--)V[O]=3d[O];o V}}2m.cr=$A;M.15(2m.1l,2G);E(!2m.1l.9M)2m.1l.9M=2m.1l.4e;M.15(2m.1l,{48:q(W){17(G i=0,O=C.O;i<O;i++)W(C[i])},aH:q(){C.O=0;o C},3K:q(){o C[0]},2u:q(){o C[C.O-1]},gT:q(){o C.2z(q(I){o I!=1k})},cA:q(){o C.3H([],q(2F,I){o 2F.20(M.4x(I)?I.cA():[I])})},6b:q(){G 1S=$A(1p);o C.2z(q(I){o!1S.1J(I)})},4e:q(cz){o(cz!==1r?C:C.3E()).9M()},gS:q(){o C.O>1?C:C[0]},cx:q(cy){o C.3H([],q(2F,I,1i){E(0==1i||(cy?2F.2u()!=I:!2F.1J(I)))2F.1h(I);o 2F})},gR:q(2F){o C.cx().5C(q(66){o 2F.81(q(I){o 66===I})})},2A:q(){o[].20(C)},cw:q(){o C.O},2C:q(){o\'[\'+C.2M(M.2C).2o(\', \')+\']\'},3D:q(){G V=[];C.1E(q(Y){G I=M.3D(Y);E(!M.2D(I))V.1h(I)});o\'[\'+V.2o(\', \')+\']\'}});E(M.2w(2m.1l.cv))2m.1l.48=2m.1l.cv;E(!2m.1l.47)2m.1l.47=q(66,i){i||(i=0);G O=C.O;E(i<0)i=O+i;17(;i<O;i++)E(C[i]===66)o i;o-1};E(!2m.1l.9L)2m.1l.9L=q(66,i){i=gQ(i)?C.O:(i<0?C.O+i:i)+1;G n=C.3B(0,i).4e().47(66);o(n<0)?n:i-n-1};2m.1l.3E=2m.1l.2A;q $w(3h){E(!M.3f(3h))o[];3h=3h.3T();o 3h?3h.49(/\\s+/):[]}E(1g.1W.58){2m.1l.20=q(){G 2F=[];17(G i=0,O=C.O;i<O;i++)2F.1h(C[i]);17(G i=0,O=1p.O;i<O;i++){E(M.4x(1p[i])){17(G j=0,cu=1p[i].O;j<cu;j++)2F.1h(1p[i][j])}1m{2F.1h(1p[i])}}o 2F}}M.15(54.1l,{gP:q(){o C.4L(2,16)},9I:q(){o C+1},7E:q(W){$R(0,C,1u).1E(W);o C},4L:q(O,ct){G 3h=C.2H(ct||10);o\'0\'.7E(O-3h.O)+3h},3D:q(){o gO(C)?C.2H():\'1k\'}});$w(\'gN gM gL gK\').1E(q(1F){54.1l[1F]=gJ[1F].4v()});q $H(Y){o 1s 3V(Y)};G 3V=2b.2p(2G,(q(){q 9K(1w,I){E(M.2D(I))o 1w;o 1w+\'=\'+cs(24.62(I))}o{2I:q(Y){C.4K=M.9G(Y)?Y.6U():M.2A(Y)},48:q(W){17(G 1w 1Q C.4K){G I=C.4K[1w],1H=[1w,I];1H.1w=1w;1H.I=I;W(1H)}},6c:q(1w,I){o C.4K[1w]=I},9F:q(1w){o C.4K[1w]},gI:q(1w){G I=C.4K[1w];8R C.4K[1w];o I},6U:q(){o M.2A(C.4K)},4b:q(){o C.5u(\'1w\')},1S:q(){o C.5u(\'I\')},1i:q(I){G 1f=C.81(q(1H){o 1H.I===I});o 1f&&1f.1w},gH:q(Y){o C.2A().5a(Y)},5a:q(Y){o 1s 3V(Y).3H(C,q(1q,1H){1q.6c(1H.1w,1H.I);o 1q})},4r:q(){o C.2M(q(1H){G 1w=cs(1H.1w),1S=1H.I;E(1S&&3Z 1S==\'Y\'){E(M.4x(1S))o 1S.2M(9K.7T(1w)).2o(\'&\')}o 9K(1w,1S)}).2o(\'&\')},2C:q(){o\'#<3V:{\'+C.2M(q(1H){o 1H.2M(M.2C).2o(\': \')}).2o(\', \')+\'}>\'},3D:q(){o M.3D(C.6U())},2A:q(){o 1s 3V(C)}}})());3V.1l.9J=3V.1l.6U;3V.cr=$H;G cq=2b.2p(2G,{2I:q(4l,5o,65){C.4l=4l;C.5o=5o;C.65=65},48:q(W){G I=C.4l;1P(C.1J(I)){W(I);I=I.9I()}},1J:q(I){E(I<C.4l)o 1r;E(C.65)o I<C.5o;o I<=C.5o}});G $R=q(4l,5o,65){o 1s cq(4l,5o,65)};G 1R={cj:q(){o cp.co(q(){o 1s cf()},q(){o 1s cm(\'gG.cl\')},q(){o 1s cm(\'gF.cl\')})||1r},9H:0};1R.63={6V:[],48:q(W){C.6V.48(W)},ck:q(4m){E(!C.1J(4m))C.6V.1h(4m)},gE:q(4m){C.6V=C.6V.6b(4m)},7X:q(2X,2Q,1Z,3l){C.1E(q(4m){E(M.2w(4m[2X])){2s{4m[2X].3R(4m,[2Q,1Z,3l])}2E(e){}}})}};M.15(1R.63,2G);1R.63.ck({80:q(){1R.9H++},3S:q(){1R.9H--}});1R.9m=2b.2p({2I:q(U){C.U={1F:\'6S\',7Z:1u,6R:\'7V/x-gD-1x-gC\',9C:\'gB-8\',3v:\'\',60:1u,9z:1u};M.15(C.U,U||{});C.U.1F=C.U.1F.2e();E(M.3f(C.U.3v))C.U.3v=C.U.3v.7g();1m E(M.9G(C.U.3v))C.U.3v=C.U.3v.6U()}});1R.50=2b.2p(1R.9m,{9A:1r,2I:q($4d,2U,U){$4d(U);C.1Z=1R.cj();C.2Q(2U)},2Q:q(2U){C.2U=2U;C.1F=C.U.1F;G 2Y=M.2A(C.U.3v);E(![\'9F\',\'6S\'].1J(C.1F)){2Y[\'gA\']=C.1F;C.1F=\'6S\'}C.3v=2Y;E(2Y=M.4r(2Y)){E(C.1F==\'9F\')C.2U+=(C.2U.1J(\'?\')?\'&\':\'?\')+2Y;1m E(/gz|ci|ch/.2L(5e.5d))2Y+=\'&6T=\'}2s{G 2y=1s 1R.9t(C);E(C.U.80)C.U.80(2y);1R.63.7X(\'80\',C,2y);C.1Z.gy(C.1F.2R(),C.2U,C.U.7Z);E(C.U.7Z)C.9B.1L(C).4s(1);C.1Z.77=C.9E.1L(C);C.cg();C.2q=C.1F==\'6S\'?(C.U.gx||2Y):1k;C.1Z.gw(C.2q);E(!C.U.7Z&&C.1Z.ce)C.9E()}2E(e){C.5m(e)}},9E:q(){G 2N=C.1Z.2N;E(2N>1&&!((2N==4)&&C.9A))C.9B(C.1Z.2N)},cg:q(){G 5n={\'X-gv-gu\':\'cf\',\'X-1g-9D\':1g.9D,\'gs\':\'3Y/gr, 3Y/7D, 7V/6P, 3Y/6P, */*\'};E(C.1F==\'6S\'){5n[\'9o-1B\']=C.U.6R+(C.U.9C?\'; gq=\'+C.U.9C:\'\');E(C.1Z.ce&&(5e.5d.1f(/7H\\/(\\d{4})/)||[0,cd])[1]<cd)5n[\'gp\']=\'go\'}E(3Z C.U.cc==\'Y\'){G 64=C.U.cc;E(M.2w(64.1h))17(G i=0,O=64.O;i<O;i+=2)5n[64[i]]=64[i+1];1m $H(64).1E(q(1H){5n[1H.1w]=1H.I})}17(G 1e 1Q 5n)C.1Z.gn(1e,5n[1e])},5l:q(){G 4J=C.6O();o!4J||(4J>=gm&&4J<gl)},6O:q(){2s{o C.1Z.4J||0}2E(e){o 0}},9B:q(2N){G 6Q=1R.50.c8[2N],2y=1s 1R.9t(C);E(6Q==\'9u\'){2s{C.9A=1u;(C.U[\'5t\'+2y.4J]||C.U[\'5t\'+(C.5l()?\'gk\':\'gj\')]||1g.3q)(2y,2y.7W)}2E(e){C.5m(e)}G 6R=2y.61(\'9o-1B\');E(C.U.9z==\'c1\'||(C.U.9z&&C.7U()&&6R&&6R.1f(/^\\s*(3Y|7V)\\/(x-)?(gh|gg)4S(;.*)?\\s*$/i)))C.ca()}2s{(C.U[\'5t\'+6Q]||1g.3q)(2y,2y.7W);1R.63.7X(\'5t\'+6Q,C,2y,2y.7W)}2E(e){C.5m(e)}E(6Q==\'9u\'){C.1Z.77=1g.3q}},7U:q(){G m=C.2U.1f(/^\\s*gf?:\\/\\/[^\\/]*/);o!m||(m[0]==\'#{9y}//#{9x}#{7Y}\'.cb({9y:7h.9y,9x:1b.9x,7Y:7h.7Y?\':\'+7h.7Y:\'\'}))},61:q(1e){2s{o C.1Z.9r(1e)||1k}2E(e){o 1k}},ca:q(){2s{o 7u((C.1Z.3c||\'\').9w())}2E(e){C.5m(e)}},5m:q(9v){(C.U.c9||1g.3q)(C,9v);1R.63.7X(\'c9\',C,9v)}});1R.50.c8=[\'ge\',\'gd\',\'gc\',\'gb\',\'9u\'];1R.9t=2b.2p({2I:q(2Q){C.2Q=2Q;G 1Z=C.1Z=2Q.1Z,2N=C.2N=1Z.2N;E((2N>2&&!1g.1W.3X)||2N==4){C.4J=C.6O();C.9s=C.c6();C.3c=24.62(1Z.3c);C.7W=C.c5()}E(2N==4){G 6P=1Z.c7;C.c7=M.2D(6P)?1k:6P;C.ga=C.c2()}},4J:0,9s:\'\',6O:1R.50.1l.6O,c6:q(){2s{o C.1Z.9s||\'\'}2E(e){o\'\'}},61:1R.50.1l.61,g9:q(){2s{o C.9q()}2E(e){o 1k}},9r:q(1e){o C.1Z.9r(1e)},9q:q(){o C.1Z.9q()},c5:q(){G 3l=C.61(\'X-c4\');E(!3l)o 1k;3l=9p(c3(3l));2s{o 3l.60(C.2Q.U.c0||!C.2Q.7U())}2E(e){C.2Q.5m(e)}},c2:q(){G U=C.2Q.U;E(!U.60||(U.60!=\'c1\'&&!(C.61(\'9o-1B\')||\'\').1J(\'7V/3l\'))||C.3c.4O())o 1k;2s{o C.3c.60(U.c0||!C.2Q.7U())}2E(e){C.2Q.5m(e)}}});1R.bW=2b.2p(1R.50,{2I:q($4d,3C,2U,U){C.3C={5l:(3C.5l||3C),9n:(3C.9n||(3C.5l?1k:3C))};U=M.2A(U);G 3S=U.3S;U.3S=(q(2y,3l){C.bZ(2y.3c);E(M.2w(3S))3S(2y,3l)}).1L(C);$4d(2U,U)},bZ:q(3c){G 5Z=C.3C[C.5l()?\'5l\':\'9n\'],U=C.U;E(!U.59)3c=3c.4h();E(5Z=$(5Z)){E(U.5k){E(M.3f(U.5k)){G 5k={};5k[U.5k]=3c;5Z.3o(5k)}1m U.5k(5Z,3c)}1m 5Z.5a(3c)}}});1R.g8=2b.2p(1R.9m,{2I:q($4d,3C,2U,U){$4d(U);C.3S=C.U.3S;C.4c=(C.U.4c||2);C.5j=(C.U.5j||1);C.9k={};C.3C=3C;C.2U=2U;C.4l()},4l:q(){C.U.3S=C.bY.1L(C);C.6N()},8p:q(){C.9k.U.3S=4z;g7(C.3W);(C.3S||1g.3q).3R(C,1p)},bY:q(2y){E(C.U.5j){C.5j=(2y.3c==C.bX?C.5j*C.U.5j:1);C.bX=2y.3c}C.3W=C.6N.1L(C).9l(C.5j*C.4c)},6N:q(){C.9k=1s 1R.bW(C.3C,C.2U,C.U)}});q $(k){E(1p.O>1){17(G i=0,1V=[],O=1p.O;i<O;i++)1V.1h($(1p[i]));o 1V}E(M.3f(k))k=1b.g6(k);o J.15(k)}E(1g.3U.72){1b.8a=q(1t,71){G V=[];G 9j=1b.2S(1t,$(71)||1b,1k,g5.g4,1k);17(G i=0,O=9j.g3;i<O;i++)V.1h(J.15(9j.g2(i)));o V}}E(!1A.6o)G 6o={};E(!6o.bV){M.15(6o,{bV:1,g1:2,au:3,g0:4,fZ:5,fY:6,fX:7,fW:8,fV:9,fU:10,fT:11,fS:12})}(q(){G k=C.J;C.J=q(1a,2l){2l=2l||{};1a=1a.2e();G 2P=J.2P;E(1g.1W.3X&&2l.1e){1a=\'<\'+1a+\' 1e="\'+2l.1e+\'">\';8R 2l.1e;o J.6M(1b.43(1a),2l)}E(!2P[1a])2P[1a]=J.15(1b.43(1a));o J.6M(2P[1a].fR(1r),2l)};M.15(C.J,k||{})}).8m(1A);J.2P={};J.1d={99:q(k){o $(k).14.3p!=\'7L\'},aa:q(k){k=$(k);J[J.99(k)?\'bU\':\'bT\'](k);o k},bU:q(k){$(k).14.3p=\'7L\';o k},bT:q(k){$(k).14.3p=\'\';o k},a1:q(k){k=$(k);k.1O.6I(k);o k},5a:q(k,18){k=$(k);E(18&&18.3s)18=18.3s();E(M.4j(18))o k.5a().3o(18);18=M.4i(18);k.4C=18.4h();18.59.1L(18).4s();o k},1Y:q(k,18){k=$(k);E(18&&18.3s)18=18.3s();1m E(!M.4j(18)){18=M.4i(18);G 9i=k.fQ.fP();9i.fO(k);18.59.1L(18).4s();18=9i.fN(18.4h())}k.1O.8Z(18,k);o k},3o:q(k,3Q){k=$(k);E(M.3f(3Q)||M.53(3Q)||M.4j(3Q)||(3Q&&(3Q.3s||3Q.4i)))3Q={4Q:3Q};G 18,3o,1a,3g;17(G 1v 1Q 3Q){18=3Q[1v];1v=1v.2e();3o=J.5M[1v];E(18&&18.3s)18=18.3s();E(M.4j(18)){3o(k,18);3G}18=M.4i(18);1a=((1v==\'4R\'||1v==\'75\')?k.1O:k).1a.2R();3g=J.7F(1a,18.4h());E(1v==\'2i\'||1v==\'75\')3g.4e();3g.1E(3o.7T(k));18.59.1L(18).4s()}o k},5g:q(k,1K,2l){k=$(k);E(M.4j(1K))$(1K).6M(2l||{});1m E(M.3f(1K))1K=1s J(1K,2l);1m 1K=1s J(\'1T\',1K);E(k.1O)k.1O.8Z(1K,k);1K.5O(k);o 1K},2C:q(k){k=$(k);G 1q=\'<\'+k.1a.2e();$H({\'1o\':\'1o\',\'1j\':\'6e\'}).1E(q(1H){G 1y=1H.3K(),1U=1H.2u();G I=(k[1y]||\'\').2H();E(I)1q+=\' \'+1U+\'=\'+I.2C(1u)});o 1q+\'>\'},7S:q(k,1y){k=$(k);G 1V=[];1P(k=k[1y])E(k.3r==1)1V.1h(J.15(k));o 1V},5x:q(k){o $(k).7S(\'1O\')},bR:q(k){o $(k).2z("*")},bS:q(k){k=$(k).5D;1P(k&&k.3r!=1)k=k.3M;o $(k)},br:q(k){E(!(k=$(k).5D))o[];1P(k&&k.3r!=1)k=k.3M;E(k)o[k].20($(k).4E());o[]},5Y:q(k){o $(k).7S(\'aY\')},4E:q(k){o $(k).7S(\'3M\')},fM:q(k){k=$(k);o k.5Y().4e().20(k.4E())},1f:q(k,41){E(M.3f(41))41=1s 19(41);o 41.1f($(k))},fL:q(k,1t,1i){k=$(k);E(1p.O==1)o $(k.1O);G 5x=k.5x();o M.53(1t)?5x[1t]:19.5w(5x,1t,1i)},fK:q(k,1t,1i){k=$(k);E(1p.O==1)o k.bS();o M.53(1t)?k.bR()[1t]:k.2z(1t)[1i||0]},fJ:q(k,1t,1i){k=$(k);E(1p.O==1)o $(19.25.6x(k));G 5Y=k.5Y();o M.53(1t)?5Y[1t]:19.5w(5Y,1t,1i)},6B:q(k,1t,1i){k=$(k);E(1p.O==1)o $(19.25.6w(k));G 4E=k.4E();o M.53(1t)?4E[1t]:19.5w(4E,1t,1i)},2z:q(){G 21=$A(1p),k=$(21.5i());o 19.7o(k,21)},55:q(){G 21=$A(1p),k=$(21.5i());o 19.7o(k.1O,21).6b(k)},bt:q(k){k=$(k);G 1o=k.51(\'1o\'),5J=1p.5v;E(1o)o 1o;do{1o=\'fI\'+5J.bs++}1P($(1o));k.6M(\'1o\',1o);o 1o},51:q(k,1e){k=$(k);E(1g.1W.3X){G t=J.3O.7I;E(t.1S[1e])o t.1S[1e](k,1e);E(t.3A[1e])1e=t.3A[1e];E(1e.1J(\':\')){o(!k.2l||!k.2l[1e])?1k:k.2l[1e].I}}o k.91(1e)},6M:q(k,1e,I){k=$(k);G 2l={},t=J.3O.6l;E(3Z 1e==\'Y\')2l=1e;1m 2l[1e]=M.2D(I)?1u:I;17(G 29 1Q 2l){1e=t.3A[29]||29;I=2l[29];E(t.1S[29])1e=t.1S[29](k,I);E(I===1r||I===1k)k.8D(1e);1m E(I===1u)k.bQ(1e,1e);1m k.bQ(1e,I)}o k},b5:q(k){o $(k).5I().3a},b6:q(k){o $(k).5I().2g},6d:q(k){o 1s J.6Z(k)},7s:q(k,1j){E(!(k=$(k)))o;G 7R=k.1j;o(7R.O>0&&(7R==1j||1s 4k("(^|\\\\s)"+1j+"(\\\\s|$)").2L(7R)))},bO:q(k,1j){E(!(k=$(k)))o;E(!k.7s(1j))k.1j+=(k.1j?\' \':\'\')+1j;o k},bP:q(k,1j){E(!(k=$(k)))o;k.1j=k.1j.1Y(1s 4k("(^|\\\\s+)"+1j+"(\\\\s+|$)"),\' \').3T();o k},fH:q(k,1j){E(!(k=$(k)))o;o k[k.7s(1j)?\'bP\':\'bO\'](1j)},fG:q(k){k=$(k);G L=k.5D;1P(L){G bN=L.3M;E(L.3r==3&&!/\\S/.2L(L.4f))k.6I(L);L=bN}o k},5E:q(k){o $(k).4C.4O()},76:q(k,3b){k=$(k),3b=$(3b);G bL=3b;E(k.bM)o(k.bM(3b)&8)===8;E(k.6L&&!1g.1W.58){G e=k.6L,a=3b.6L,5X=3b.3M;E(!5X){do{3b=3b.1O}1P(!(5X=3b.3M)&&3b.1O)}E(5X&&5X.6L)o(e>a&&e<5X.6L)}1P(k=k.1O)E(k==bL)o 1u;o 1r},bK:q(k){k=$(k);G 5W=k.4P();1A.bK(5W[0],5W[1]);o k},2a:q(k,14){k=$(k);14=14==\'97\'?\'7N\':14.95();G I=k.14[14];E(!I){G 9h=1b.fF.fE(k,1k);I=9h?9h[14]:1k}E(14==\'3P\')o I?5R(I):1.0;o I==\'7M\'?1k:I},fD:q(k){o $(k).2a(\'3P\')},5S:q(k,4I){k=$(k);G 9g=k.14,1f;E(M.3f(4I)){k.14.90+=\';\'+4I;o 4I.1J(\'3P\')?k.5Q(4I.1f(/3P:\\s*(\\d?\\.?\\d*)/)[1]):k}17(G 1y 1Q 4I)E(1y==\'3P\')k.5Q(4I[1y]);1m 9g[(1y==\'97\'||1y==\'7N\')?(M.2D(9g.96)?\'7N\':\'96\'):1y]=4I[1y];o k},5Q:q(k,I){k=$(k);k.14.3P=(I==1||I===\'\')?\'\':(I<0.7G)?0:I;o k},5I:q(k){k=$(k);G 3p=$(k).2a(\'3p\');E(3p!=\'7L\'&&3p!=1k)o{2g:k.5q,3a:k.5r};G 44=k.14;G bH=44.9f;G bI=44.1v;G bJ=44.3p;44.9f=\'7j\';44.1v=\'5P\';44.3p=\'fC\';G bG=k.bE;G bF=k.bD;44.3p=bJ;44.1v=bI;44.9f=bH;o{2g:bG,3a:bF}},fB:q(k){k=$(k);G 5W=J.2a(k,\'1v\');E(5W==\'5T\'||!5W){k.9d=1u;k.14.1v=\'6K\';E(1A.9e){k.14.2i=0;k.14.2x=0}}o k},fA:q(k){k=$(k);E(k.9d){k.9d=4z;k.14.1v=k.14.2i=k.14.2x=k.14.4Q=k.14.5U=\'\'}o k},fz:q(k){k=$(k);E(k.5h)o k;k.5h=J.2a(k,\'9c\')||\'7M\';E(k.5h!==\'7j\')k.14.9c=\'7j\';o k},fy:q(k){k=$(k);E(!k.5h)o k;k.14.9c=k.5h==\'7M\'?\'\':k.5h;k.5h=1k;o k},4P:q(k){G 2J=0,2K=0;do{2J+=k.5c||0;2K+=k.5b||0;k=k.3e}1P(k);o J.57(2K,2J)},6h:q(k){G 2J=0,2K=0;do{2J+=k.5c||0;2K+=k.5b||0;k=k.3e;E(k){E(k.1a==\'by\')2d;G p=J.2a(k,\'1v\');E(p!==\'5T\')2d}}1P(k);o J.57(2K,2J)},8g:q(k){k=$(k);E(k.2a(\'1v\')==\'5P\')o;G 9b=k.6h();G 2i=9b[1];G 2x=9b[0];G 2g=k.bE;G 3a=k.bD;k.bB=2x-5R(k.14.2x||0);k.bC=2i-5R(k.14.2i||0);k.bz=k.14.2g;k.bA=k.14.3a;k.14.1v=\'5P\';k.14.2i=2i+\'3i\';k.14.2x=2x+\'3i\';k.14.2g=2g+\'3i\';k.14.3a=3a+\'3i\';o k},8d:q(k){k=$(k);E(k.2a(\'1v\')==\'6K\')o;k.14.1v=\'6K\';G 2i=5R(k.14.2i||0)-(k.bC||0);G 2x=5R(k.14.2x||0)-(k.bB||0);k.14.2i=2i+\'3i\';k.14.2x=2x+\'3i\';k.14.3a=k.bA;k.14.2g=k.bz;o k},8c:q(k){G 2J=0,2K=0;do{2J+=k.4n||0;2K+=k.4p||0;k=k.1O}1P(k);o J.57(2K,2J)},5p:q(k){E(k.3e)o $(k.3e);E(k==1b.2q)o $(k);1P((k=k.1O)&&k!=1b.2q)E(J.2a(k,\'1v\')!=\'5T\')o $(k);o $(1b.2q)},6g:q(9a){G 2J=0,2K=0;G k=9a;do{2J+=k.5c||0;2K+=k.5b||0;E(k.3e==1b.2q&&J.2a(k,\'1v\')==\'5P\')2d}1P(k=k.3e);k=9a;do{E(!1g.1W.58||k.1a==\'by\'){2J-=k.4n||0;2K-=k.4p||0}}1P(k=k.1O);o J.57(2K,2J)},a3:q(k,22){G U=M.15({bx:1u,bw:1u,bv:1u,bu:1u,5c:0,5b:0},1p[2]||{});22=$(22);G p=22.6g();k=$(k);G 5V=[0,0];G 2T=1k;E(J.2a(k,\'1v\')==\'5P\'){2T=k.5p();5V=2T.6g()}E(2T==1b.2q){5V[0]-=1b.2q.5b;5V[1]-=1b.2q.5c}E(U.bx)k.14.2x=(p[0]-5V[0]+U.5b)+\'3i\';E(U.bw)k.14.2i=(p[1]-5V[1]+U.5c)+\'3i\';E(U.bv)k.14.2g=22.5q+\'3i\';E(U.bu)k.14.3a=22.5r+\'3i\';o k}};J.1d.bt.bs=1;M.15(J.1d,{fx:J.1d.2z,fw:J.1d.br});J.3O={6l:{3A:{1j:\'6e\',bo:\'17\'},1S:{}}};E(1g.1W.58){J.1d.2a=J.1d.2a.5g(q(3j,k,14){5y(14){2r\'2x\':2r\'2i\':2r\'5U\':2r\'4Q\':E(3j(k,\'1v\')===\'5T\')o 1k;2r\'3a\':2r\'2g\':E(!J.99(k))o 1k;G 7O=bq(3j(k,14),10);E(7O!==k[\'2V\'+14.6F()])o 7O+\'3i\';G 3k;E(14===\'3a\'){3k=[\'7P-2i-2g\',\'7Q-2i\',\'7Q-4Q\',\'7P-4Q-2g\']}1m{3k=[\'7P-2x-2g\',\'7Q-2x\',\'7Q-5U\',\'7P-5U-2g\']}o 3k.3H(7O,q(2O,1y){G 98=3j(k,1y);o 98===1k?2O:2O-bq(98,10)})+\'3i\';6p:o 3j(k,14)}});J.1d.51=J.1d.51.5g(q(3j,k,1U){E(1U===\'7K\')o k.7K;o 3j(k,1U)})}1m E(1g.1W.3X){J.1d.5p=J.1d.5p.5g(q(3j,k){k=$(k);G 1v=k.2a(\'1v\');E(1v!==\'5T\')o 3j(k);k.5S({1v:\'6K\'});G I=3j(k);k.5S({1v:1v});o I});$w(\'6h 6g\').1E(q(1F){J.1d[1F]=J.1d[1F].5g(q(3j,k){k=$(k);G 1v=k.2a(\'1v\');E(1v!==\'5T\')o 3j(k);G 3e=k.5p();E(3e&&3e.2a(\'1v\')===\'fv\')3e.5S({94:1});k.5S({1v:\'6K\'});G I=3j(k);k.5S({1v:1v});o I})});J.1d.2a=q(k,14){k=$(k);14=(14==\'97\'||14==\'7N\')?\'96\':14.95();G I=k.14[14];E(!I&&k.5f)I=k.5f[14];E(14==\'3P\'){E(I=(k.2a(\'2h\')||\'\').1f(/92\\(3P=(.*)\\)/))E(I[1])o 5R(I[1])/bp;o 1.0}E(I==\'7M\'){E((14==\'2g\'||14==\'3a\')&&(k.2a(\'3p\')!=\'7L\'))o k[\'2V\'+14.6F()]+\'3i\';o 1k}o I};J.1d.5Q=q(k,I){q 93(2h){o 2h.1Y(/92\\([^\\)]*\\)/gi,\'\')}k=$(k);G 5f=k.5f;E((5f&&!5f.fu)||(!5f&&k.14.94==\'ft\'))k.14.94=1;G 2h=k.2a(\'2h\'),14=k.14;E(I==1||I===\'\'){(2h=93(2h))?14.2h=2h:14.8D(\'2h\');o k}1m E(I<0.7G)I=0;14.2h=93(2h)+\'92(3P=\'+(I*bp)+\')\';o k};J.3O={7I:{3A:{\'6e\':\'1j\',\'17\':\'bo\'},1S:{7J:q(k,1U){o k.91(1U,2)},bn:q(k,1U){G L=k.bj(1U);o L?L.I:""},2k:q(k,1U){1U=k.91(1U);o 1U?1U.2H().3B(23,-2):1k},6J:q(k,1U){o $(k).3I(1U)?1U:1k},14:q(k){o k.14.90.2e()},7K:q(k){o k.7K}}}};J.3O.6l={3A:M.15({fs:\'fr\',fq:\'fp\'},J.3O.7I.3A),1S:{3J:q(k,I){k.3J=!!I},14:q(k,I){k.14.90=I?I:\'\'}}};J.3O.8X={};$w(\'fo fn fm fl fk 7i \'+\'fj fi fh fg\').1E(q(29){J.3O.6l.3A[29.2e()]=29;J.3O.8X[29.2e()]=29});(q(v){M.15(v,{aI:v.7J,ad:v.7J,1B:v.7J,5B:v.bn,3u:v.6J,3J:v.6J,ff:v.6J,fe:v.6J,fd:v.2k,ao:v.2k,fc:v.2k,fb:v.2k,fa:v.2k,f9:v.2k,f8:v.2k,f7:v.2k,f6:v.2k,f5:v.2k,f4:v.2k,f3:v.2k,f2:v.2k,f1:v.2k,f0:v.2k,eZ:v.2k,eY:v.2k,eX:v.2k})})(J.3O.7I.1S)}1m E(1g.1W.7H&&/eW:1\\.8\\.0/.2L(5e.5d)){J.1d.5Q=q(k,I){k=$(k);k.14.3P=(I==1)?0.eV:(I===\'\')?\'\':(I<0.7G)?0:I;o k}}1m E(1g.1W.4u){J.1d.5Q=q(k,I){k=$(k);k.14.3P=(I==1||I===\'\')?\'\':(I<0.7G)?0:I;E(I==1)E(k.1a==\'bf\'&&k.2g){k.2g++;k.2g--}1m 2s{G n=1b.bm(\' \');k.5O(n);k.6I(n)}2E(e){}o k};J.1d.4P=q(k){G 2J=0,2K=0;do{2J+=k.5c||0;2K+=k.5b||0;E(k.3e==1b.2q)E(J.2a(k,\'1v\')==\'5P\')2d;k=k.3e}1P(k);o J.57(2K,2J)}}E(1g.1W.3X||1g.1W.58){J.1d.5a=q(k,18){k=$(k);E(18&&18.3s)18=18.3s();E(M.4j(18))o k.5a().3o(18);18=M.4i(18);G 1a=k.1a.2R();E(1a 1Q J.5M.4G){$A(k.3g).1E(q(L){k.6I(L)});J.7F(1a,18.4h()).1E(q(L){k.5O(L)})}1m k.4C=18.4h();18.59.1L(18).4s();o k}}E(\'bl\'1Q 1b.43(\'1T\')){J.1d.1Y=q(k,18){k=$(k);E(18&&18.3s)18=18.3s();E(M.4j(18)){k.1O.8Z(18,k);o k}18=M.4i(18);G 2T=k.1O,1a=2T.1a.2R();E(J.5M.4G[1a]){G 3M=k.6B();G 8Y=J.7F(1a,18.4h());2T.6I(k);E(3M)8Y.1E(q(L){2T.7C(L,3M)});1m 8Y.1E(q(L){2T.5O(L)})}1m k.bl=18.4h();18.59.1L(18).4s();o k}}J.57=q(l,t){G 1q=[l,t];1q.2x=l;1q.2i=t;o 1q};J.7F=q(1a,7D){G 1T=1s J(\'1T\'),t=J.5M.4G[1a];E(t){1T.4C=t[0]+7D+t[1];t[2].7E(q(){1T=1T.5D})}1m 1T.4C=7D;o $A(1T.3g)};J.5M={4R:q(k,L){k.1O.7C(L,k)},2i:q(k,L){k.7C(L,k.5D)},4Q:q(k,L){k.5O(L)},75:q(k,L){k.1O.7C(L,k.3M)},4G:{eU:[\'<4H>\',\'</4H>\',1],7z:[\'<4H><5N>\',\'</5N></4H>\',2],bb:[\'<4H><5N><7B>\',\'</7B></5N></4H>\',3],8V:[\'<4H><5N><7B><bk>\',\'</bk></7B></5N></4H>\',4],bi:[\'<2z>\',\'</2z>\',1]}};(q(){M.15(C.4G,{bd:C.4G.7z,bc:C.4G.7z,ba:C.4G.8V})}).8m(J.5M);J.1d.7y={3I:q(k,1U){1U=J.3O.8X[1U]||1U;G L=$(k).bj(1U);o L&&L.eT}};J.1d.3z={};M.15(J,J.1d);E(!1g.3U.6H&&1b.43(\'1T\').4U){1A.6G={};1A.6G.1l=1b.43(\'1T\').4U;1g.3U.6H=1u}J.15=(q(){E(1g.3U.7x)o 1g.K;G 1d={},3z=J.1d.3z;G 15=M.15(q(k){E(!k||k.7c||k.3r!=1||k==1A)o k;G 2B=M.2A(1d),1a=k.1a,1y,I;E(3z[1a])M.15(2B,3z[1a]);17(1y 1Q 2B){I=2B[1y];E(M.2w(I)&&!(1y 1Q k))k[1y]=I.4v()}k.7c=1g.3q;o k},{7v:q(){E(!1g.3U.6H){M.15(1d,J.1d);M.15(1d,J.1d.7y)}}});15.7v();o 15})();J.3I=q(k,1U){E(k.3I)o k.3I(1U);o J.1d.7y.3I(k,1U)};J.6a=q(2B){G F=1g.3U,T=J.1d.3z;E(!2B){M.15(1C,1C.1d);M.15(1C.J,1C.J.1d);M.15(J.1d.3z,{"eS":M.2A(1C.1d),"eR":M.2A(1C.J.1d),"bi":M.2A(1C.J.1d),"bh":M.2A(1C.J.1d)})}E(1p.O==2){G 1a=2B;2B=1p[1]}E(!1a)M.15(J.1d,2B||{});1m{E(M.4x(1a))1a.1E(15);1m 15(1a)}q 15(1a){1a=1a.2R();E(!J.1d.3z[1a])J.1d.3z[1a]={};M.15(J.1d.3z[1a],2B)}q 7w(2B,5L,7A){7A=7A||1r;17(G 1y 1Q 2B){G I=2B[1y];E(!M.2w(I))3G;E(!7A||!(1y 1Q 5L))5L[1y]=I.4v()}}q b8(1a){G 1N;G 8U={"eQ":"eP","bh":"eO","P":"eN","eM":"eL","eK":"eJ","eI":"eH","eG":"eF","eE":"eD","eC":"5K","eB":"5K","eA":"5K","ez":"5K","ey":"5K","ex":"5K","Q":"ew","ev":"bg","eu":"bg","A":"et","bf":"es","er":"eq","ep":"be","eo":"be","bd":"8W","bc":"8W","7z":"8W","bb":"em","ba":"b9","8V":"b9","el":"ek","ej":"ei"};E(8U[1a])1N=\'8T\'+8U[1a]+\'J\';E(1A[1N])o 1A[1N];1N=\'8T\'+1a+\'J\';E(1A[1N])o 1A[1N];1N=\'8T\'+1a.6F()+\'J\';E(1A[1N])o 1A[1N];1A[1N]={};1A[1N].1l=1b.43(1a).4U;o 1A[1N]}E(F.6H){7w(J.1d,6G.1l);7w(J.1d.7y,6G.1l,1u)}E(F.7x){17(G 8S 1Q J.1d.3z){G 1N=b8(8S);E(M.2D(1N))3G;7w(T[8S],1N.1l)}}M.15(J,J.1d);8R J.3z;E(J.15.7v)J.15.7v();J.2P={}};1b.eh={5I:q(){G 8Q={};G B=1g.1W;$w(\'2g 3a\').1E(q(d){G D=d.6F();8Q[d]=(B.4u&&!1b.2S)?5J[\'eg\'+D]:(B.58)?1b.2q[\'b7\'+D]:1b.4o[\'b7\'+D]});o 8Q},b6:q(){o C.5I().2g},b5:q(){o C.5I().3a},ef:q(){o J.57(1A.a9||1b.4o.4p||1b.2q.4p,1A.a8||1b.4o.4n||1b.2q.4n)}};G 19=2b.2p({2I:q(1t){C.1t=1t.3T();C.b4()},b3:q(){E(!1g.3U.72)o 1r;G e=C.1t;E(1g.1W.4u&&(e.1J("-2t-1B")||e.1J(":5E")))o 1r;E((/(\\[[\\w-]*?:|:3J)/).2L(C.1t))o 1r;o 1u},b4:q(){E(C.b3())o C.b2();G e=C.1t,4g=19.6C,h=19.25,c=19.6D,3y,p,m;E(19.56[e]){C.3N=19.56[e];o}C.3N=["C.3N = q(1n) {","G r = 1n, h = 19.25, c = 1r, n;"];1P(e&&3y!=e&&(/\\S/).2L(e)){3y=e;17(G i 1Q 4g){p=4g[i];E(m=e.1f(p)){C.3N.1h(M.2w(c[i])?c[i](m):1s 32(c[i]).2S(m));e=e.1Y(m[0],\'\');2d}}}C.3N.1h("o h.8E(n);\\n}");7u(C.3N.2o(\'\\n\'));19.56[C.1t]=C.3N},b2:q(){G e=C.1t,4g=19.6C,x=19.2v,3y,m;E(19.56[e]){C.2v=19.56[e];o}C.3N=[\'.//*\'];1P(e&&3y!=e&&(/\\S/).2L(e)){3y=e;17(G i 1Q 4g){E(m=e.1f(4g[i])){C.3N.1h(M.2w(x[i])?x[i](m):1s 32(x[i]).2S(m));e=e.1Y(m[0],\'\');2d}}}C.2v=C.3N.2o(\'\');19.56[C.1t]=C.2v},7p:q(1n){1n=1n||1b;E(C.2v)o 1b.8a(C.2v,1n);o C.3N(1n)},1f:q(k){C.8P=[];G e=C.1t,4g=19.6C,as=19.8J;G 3y,p,m;1P(e&&3y!==e&&(/\\S/).2L(e)){3y=e;17(G i 1Q 4g){p=4g[i];E(m=e.1f(p)){E(as[i]){C.8P.1h([i,M.2A(m)]);e=e.1Y(m[0],\'\')}1m{o C.7p(1b).1J(k)}}}}G 1f=1u,1e,2j;17(G i=0,7t;7t=C.8P[i];i++){1e=7t[0],2j=7t[1];E(!19.8J[1e](k,2j)){1f=1r;2d}}o 1f},2H:q(){o C.1t},2C:q(){o"#<19:"+C.1t.2C()+">"}});M.15(19,{56:{},2v:{4D:"//*",1G:"/*",55:"/6E-4F::*[1]",6A:\'/6E-4F::*\',1a:q(m){E(m[1]==\'*\')o\'\';o"[b1-1e()=\'"+m[1].2e()+"\' 8O b1-1e()=\'"+m[1].2R()+"\']"},1j:"[6f(20(\' \', @6e, \' \'), \' #{1} \')]",1o:"[@1o=\'#{1}\']",5F:q(m){m[1]=m[1].2e();o 1s 32("[@#{1}]").2S(m)},29:q(m){m[1]=m[1].2e();m[3]=m[5]||m[6];o 1s 32(19.2v.6t[m[2]]).2S(m)},6y:q(m){G h=19.2v.2f[m[1]];E(!h)o\'\';E(M.2w(h))o h(m);o 1s 32(19.2v.2f[m[1]]).2S(m)},6t:{\'=\':"[@#{1}=\'#{3}\']",\'!=\':"[@#{1}!=\'#{3}\']",\'^=\':"[ee-b0(@#{1}, \'#{3}\')]",\'$=\':"[5H(@#{1}, (3h-O(@#{1}) - 3h-O(\'#{3}\') + 1))=\'#{3}\']",\'*=\':"[6f(@#{1}, \'#{3}\')]",\'~=\':"[6f(20(\' \', @#{1}, \' \'), \' #{3} \')]",\'|=\':"[6f(20(\'-\', @#{1}, \'-\'), \'-#{3}-\')]"},2f:{\'3K-1G\':\'[4B(8M-4F::*)]\',\'2u-1G\':\'[4B(6E-4F::*)]\',\'6v-1G\':\'[4B(8M-4F::* 8O 6E-4F::*)]\',\'5E\':"[3x(*) = 0 8L (3x(3Y()) = 0 8O ed(3Y(), \' \\t\\r\\n\', \'\') = \'\')]",\'3J\':"[@3J]",\'3u\':"[@3u]",\'aP\':"[4B(@3u)]",\'4B\':q(m){G e=m[6],p=19.6C,x=19.2v,3y,v;G 8N=[];1P(e&&3y!=e&&(/\\S/).2L(e)){3y=e;17(G i 1Q p){E(m=e.1f(p[i])){v=M.2w(x[i])?x[i](m):1s 32(x[i]).2S(m);8N.1h("("+v.5H(1,v.O-1)+")");e=e.1Y(m[0],\'\');2d}}}o"[4B("+8N.2o(" 8L ")+")]"},\'1X-1G\':q(m){o 19.2v.2f.1X("(3x(./8M-4F::*) + 1) ",m)},\'1X-2u-1G\':q(m){o 19.2v.2f.1X("(3x(./6E-4F::*) + 1) ",m)},\'1X-2t-1B\':q(m){o 19.2v.2f.1X("1v() ",m)},\'1X-2u-2t-1B\':q(m){o 19.2v.2f.1X("(2u() + 1 - 1v()) ",m)},\'3K-2t-1B\':q(m){m[6]="1";o 19.2v.2f[\'1X-2t-1B\'](m)},\'2u-2t-1B\':q(m){m[6]="1";o 19.2v.2f[\'1X-2u-2t-1B\'](m)},\'6v-2t-1B\':q(m){G p=19.2v.2f;o p[\'3K-2t-1B\'](m)+p[\'2u-2t-1B\'](m)},1X:q(5G,m){G 42,1I=m[6],8K;E(1I==\'aS\')1I=\'2n+0\';E(1I==\'aR\')1I=\'2n+1\';E(42=1I.1f(/^(\\d+)$/))o\'[\'+5G+"= "+42[1]+\']\';E(42=1I.1f(/^(-?\\d*)?n(([+-])(\\d+))?/)){E(42[1]=="-")42[1]=-1;G a=42[1]?54(42[1]):1;G b=42[2]?54(42[2]):0;8K="[((#{5G} - #{b}) ec #{a} = 0) 8L "+"((#{5G} - #{b}) 1T #{a} >= 0)]";o 1s 32(8K).2S({5G:5G,a:a,b:b})}}}},6D:{1a:\'n = h.1a(n, r, "#{1}", c); c = 1r;\',1j:\'n = h.1j(n, r, "#{1}", c); c = 1r;\',1o:\'n = h.1o(n, r, "#{1}", c); c = 1r;\',5F:\'n = h.5F(n, r, "#{1}", c); c = 1r;\',29:q(m){m[3]=(m[5]||m[6]);o 1s 32(\'n = h.29(n, r, "#{1}", "#{3}", "#{2}", c); c = 1r;\').2S(m)},6y:q(m){E(m[6])m[6]=m[6].1Y(/"/g,\'\\\\"\');o 1s 32(\'n = h.6y(n, "#{1}", "#{6}", r, c); c = 1r;\').2S(m)},4D:\'c = "4D";\',1G:\'c = "1G";\',55:\'c = "55";\',6A:\'c = "6A";\'},6C:{6A:/^\\s*~\\s*/,1G:/^\\s*>\\s*/,55:/^\\s*\\+\\s*/,4D:/^\\s/,1a:/^\\s*(\\*|[\\w\\-]+)(\\b|$)?/,1o:/^#([\\w\\-\\*]+)(\\b|$)/,1j:/^\\.([\\w\\-\\*]+)(\\b|$)/,6y:/^:((3K|2u|1X|1X-2u|6v)(-1G|-2t-1B)|5E|3J|(en|eb)ea|4B)(\\((.*?)\\))?(\\b|$|(?=\\s|[:+~>]))/,5F:/^\\[([\\w]+)\\]/,29:/\\[((?:[\\w-]*:)?[\\w-]+)\\s*(?:([!^$*~|]?=)\\s*(([\'"])([^\\4]*?)\\4|([^\'"][^\\]]*?)))?\\]/},8J:{1a:q(k,2j){o 2j[1].2R()==k.1a.2R()},1j:q(k,2j){o J.7s(k,2j[1])},1o:q(k,2j){o k.1o===2j[1]},5F:q(k,2j){o J.3I(k,2j[1])},29:q(k,2j){G 4f=J.51(k,2j[1]);o 4f&&19.6t[2j[2]](4f,2j[5]||2j[6])}},25:{20:q(a,b){17(G i=0,L;L=b[i];i++)a.1h(L);o a},7q:q(N){G aZ=1g.3q;17(G i=0,L;L=N[i];i++)L.3L=aZ;o N},52:q(N){17(G i=0,L;L=N[i];i++)L.3L=4z;o N},1i:q(1O,4e,6u){1O.3L=1g.3q;E(4e){17(G N=1O.3g,i=N.O-1,j=1;i>=0;i--){G L=N[i];E(L.3r==1&&(!6u||L.3L))L.7r=j++}}1m{17(G i=0,j=1,N=1O.3g;L=N[i];i++)E(L.3r==1&&(!6u||L.3L))L.7r=j++}},8E:q(N){E(N.O==0)o N;G V=[],n;17(G i=0,l=N.O;i<l;i++)E(!(n=N[i]).3L){n.3L=1g.3q;V.1h(J.15(n))}o 19.25.52(V)},4D:q(N){G h=19.25;17(G i=0,V=[],L;L=N[i];i++)h.20(V,L.4a(\'*\'));o V},1G:q(N){G h=19.25;17(G i=0,V=[],L;L=N[i];i++){17(G j=0,1G;1G=L.3g[j];j++)E(1G.3r==1&&1G.1a!=\'!\')V.1h(1G)}o V},55:q(N){17(G i=0,V=[],L;L=N[i];i++){G 6B=C.6w(L);E(6B)V.1h(6B)}o V},6A:q(N){G h=19.25;17(G i=0,V=[],L;L=N[i];i++)h.20(V,J.4E(L));o V},6w:q(L){1P(L=L.3M)E(L.3r==1)o L;o 1k},6x:q(L){1P(L=L.aY)E(L.3r==1)o L;o 1k},1a:q(N,1n,1a,26){G aX=1a.2R();G V=[],h=19.25;E(N){E(26){E(26=="4D"){17(G i=0,L;L=N[i];i++)h.20(V,L.4a(1a));o V}1m N=C[26](N);E(1a=="*")o N}17(G i=0,L;L=N[i];i++)E(L.1a.2R()===aX)V.1h(L);o V}1m o 1n.4a(1a)},1o:q(N,1n,1o,26){G 31=$(1o),h=19.25;E(!31)o[];E(!N&&1n==1b)o[31];E(N){E(26){E(26==\'1G\'){17(G i=0,L;L=N[i];i++)E(31.1O==L)o[31]}1m E(26==\'4D\'){17(G i=0,L;L=N[i];i++)E(J.76(31,L))o[31]}1m E(26==\'55\'){17(G i=0,L;L=N[i];i++)E(19.25.6x(31)==L)o[31]}1m N=h[26](N)}17(G i=0,L;L=N[i];i++)E(L==31)o[31];o[]}o(31&&J.76(31,1n))?[31]:[]},1j:q(N,1n,1j,26){E(N&&26)N=C[26](N);o 19.25.aW(N,1n,1j)},aW:q(N,1n,1j){E(!N)N=19.25.4D([1n]);G aV=\' \'+1j+\' \';17(G i=0,V=[],L,6z;L=N[i];i++){6z=L.1j;E(6z.O==0)3G;E(6z==1j||(\' \'+6z+\' \').1J(aV))V.1h(L)}o V},5F:q(N,1n,29,26){E(!N)N=1n.4a("*");E(N&&26)N=C[26](N);G V=[];17(G i=0,L;L=N[i];i++)E(J.3I(L,29))V.1h(L);o V},29:q(N,1n,29,I,aU,26){E(!N)N=1n.4a("*");E(N&&26)N=C[26](N);G 2c=19.6t[aU],V=[];17(G i=0,L;L=N[i];i++){G 4f=J.51(L,29);E(4f===1k)3G;E(2c(4f,I))V.1h(L)}o V},6y:q(N,1e,I,1n,26){E(N&&26)N=C[26](N);E(!N)N=1n.4a("*");o 19.2f[1e](N,I,1n)}},2f:{\'3K-1G\':q(N,I,1n){17(G i=0,V=[],L;L=N[i];i++){E(19.25.6x(L))3G;V.1h(L)}o V},\'2u-1G\':q(N,I,1n){17(G i=0,V=[],L;L=N[i];i++){E(19.25.6w(L))3G;V.1h(L)}o V},\'6v-1G\':q(N,I,1n){G h=19.25;17(G i=0,V=[],L;L=N[i];i++)E(!h.6x(L)&&!h.6w(L))V.1h(L);o V},\'1X-1G\':q(N,1I,1n){o 19.2f.1X(N,1I,1n)},\'1X-2u-1G\':q(N,1I,1n){o 19.2f.1X(N,1I,1n,1u)},\'1X-2t-1B\':q(N,1I,1n){o 19.2f.1X(N,1I,1n,1r,1u)},\'1X-2u-2t-1B\':q(N,1I,1n){o 19.2f.1X(N,1I,1n,1u,1u)},\'3K-2t-1B\':q(N,1I,1n){o 19.2f.1X(N,"1",1n,1r,1u)},\'2u-2t-1B\':q(N,1I,1n){o 19.2f.1X(N,"1",1n,1u,1u)},\'6v-2t-1B\':q(N,1I,1n){G p=19.2f;o p[\'2u-2t-1B\'](p[\'3K-2t-1B\'](N,1I,1n),1I,1n)},aQ:q(a,b,aT){E(a==0)o b>0?[b]:[];o $R(1,aT).3H([],q(2O,i){E(0==(i-b)%a&&(i-b)/a>=0)2O.1h(i);o 2O})},1X:q(N,1I,1n,4e,6u){E(N.O==0)o[];E(1I==\'aS\')1I=\'2n+0\';E(1I==\'aR\')1I=\'2n+1\';G h=19.25,V=[],8H=[],m;h.7q(N);17(G i=0,L;L=N[i];i++){E(!L.1O.3L){h.1i(L.1O,4e,6u);8H.1h(L.1O)}}E(1I.1f(/^\\d+$/)){1I=54(1I);17(G i=0,L;L=N[i];i++)E(L.7r==1I)V.1h(L)}1m E(m=1I.1f(/^(-?\\d*)?n(([+-])(\\d+))?/)){E(m[1]=="-")m[1]=-1;G a=m[1]?54(m[1]):1;G b=m[2]?54(m[2]):0;G 8I=19.2f.aQ(a,b,N.O);17(G i=0,L,l=8I.O;L=N[i];i++){17(G j=0;j<l;j++)E(L.7r==8I[j])V.1h(L)}}h.52(N);h.52(8H);o V},\'5E\':q(N,I,1n){17(G i=0,V=[],L;L=N[i];i++){E(L.1a==\'!\'||(L.5D&&!L.4C.1f(/^\\s*$/)))3G;V.1h(L)}o V},\'4B\':q(N,41,1n){G h=19.25,e9,m;G 8G=1s 19(41).7p(1n);h.7q(8G);17(G i=0,V=[],L;L=N[i];i++)E(!L.3L)V.1h(L);h.52(8G);o V},\'aP\':q(N,I,1n){17(G i=0,V=[],L;L=N[i];i++)E(!L.3u)V.1h(L);o V},\'3u\':q(N,I,1n){17(G i=0,V=[],L;L=N[i];i++)E(L.3u)V.1h(L);o V},\'3J\':q(N,I,1n){17(G i=0,V=[],L;L=N[i];i++)E(L.3J)V.1h(L);o V}},6t:{\'=\':q(2Z,v){o 2Z==v},\'!=\':q(2Z,v){o 2Z!=v},\'^=\':q(2Z,v){o 2Z.8F(v)},\'$=\':q(2Z,v){o 2Z.aO(v)},\'*=\':q(2Z,v){o 2Z.1J(v)},\'~=\':q(2Z,v){o(\' \'+2Z+\' \').1J(\' \'+v+\' \')},\'|=\':q(2Z,v){o(\'-\'+2Z.2R()+\'-\').1J(\'-\'+v.2R()+\'-\')}},49:q(1t){G 4A=[];1t.aN(/(([\\w#:.~>+()\\s-]+|\\*|\\[.*?\\])+)\\s*(,|$)/,q(m){4A.1h(m[1].3T())});o 4A},aM:q(1V,1t){G 2j=$$(1t),h=19.25;h.7q(2j);17(G i=0,V=[],k;k=1V[i];i++)E(k.3L)V.1h(k);h.52(2j);o V},5w:q(1V,1t,1i){E(M.53(1t)){1i=1t;1t=1r}o 19.aM(1V,1t||\'*\')[1i||0]},7o:q(k,4A){4A=19.49(4A.2o(\',\'));G V=[],h=19.25;17(G i=0,l=4A.O,41;i<l;i++){41=1s 19(4A[i].3T());h.20(V,41.7p(k))}o(l>1)?h.8E(V):V}});E(1g.1W.3X){M.15(19.25,{20:q(a,b){17(G i=0,L;L=b[i];i++)E(L.1a!=="!")a.1h(L);o a},52:q(N){17(G i=0,L;L=N[i];i++)L.8D(\'3L\');o N}})}q $$(){o 19.7o(1b,$A(1p))}G 1C={8y:q(1x){$(1x).8y();o 1x},aL:q(1V,U){E(3Z U!=\'Y\')U={3w:!!U};1m E(M.2D(U.3w))U.3w=1u;G 1w,I,8C=1r,4Z=U.4Z;G 7n=1V.3H({},q(1q,k){E(!k.3u&&k.1e){1w=k.1e;I=$(k).2W();E(I!=1k&&(k.1B!=\'4Z\'||(!8C&&4Z!==1r&&(!4Z||1w==4Z)&&(8C=1u)))){E(1w 1Q 1q){E(!M.4x(1q[1w]))1q[1w]=[1q[1w]];1q[1w].1h(I)}1m 1q[1w]=I}}o 1q});o U.3w?7n:M.4r(7n)}};1C.1d={6q:q(1x,U){o 1C.aL(1C.5z(1x),U)},5z:q(1x){o $A($(1x).4a(\'*\')).3H([],q(1V,1G){E(1C.J.5A[1G.1a.2e()])1V.1h(J.15(1G));o 1V})},e8:q(1x,7l,1e){1x=$(1x);G 7m=1x.4a(\'4y\');E(!7l&&!1e)o $A(7m).2M(J.15);17(G i=0,8B=[],O=7m.O;i<O;i++){G 4y=7m[i];E((7l&&4y.1B!=7l)||(1e&&4y.1e!=1e))3G;8B.1h(J.15(4y))}o 8B},8x:q(1x){1x=$(1x);1C.5z(1x).7k(\'8x\');o 1x},8w:q(1x){1x=$(1x);1C.5z(1x).7k(\'8w\');o 1x},aJ:q(1x){G 1V=$(1x).5z().5C(q(k){o\'7j\'!=k.1B&&!k.3u});G 8A=1V.5C(q(k){o k.3I(\'7i\')&&k.7i>=0}).aK(q(k){o k.7i}).3K();o 8A?8A:1V.8l(q(k){o[\'4y\',\'2z\',\'8v\'].1J(k.1a.2e())})},e7:q(1x){1x=$(1x);1x.aJ().aG();o 1x},2Q:q(1x,U){1x=$(1x),U=M.2A(U||{});G 2Y=U.3v,5B=1x.51(\'5B\')||\'\';E(5B.4O())5B=1A.7h.aI;U.3v=1x.6q(1u);E(2Y){E(M.3f(2Y))2Y=2Y.7g();M.15(U.3v,2Y)}E(1x.3I(\'1F\')&&!U.1F)U.1F=1x.1F;o 1s 1R.50(5B,U)}};1C.J={8z:q(k){$(k).8z();o k},2z:q(k){$(k).2z();o k}};1C.J.1d={6q:q(k){k=$(k);E(!k.3u&&k.1e){G I=k.2W();E(I!=4z){G 1H={};1H[k.1e]=I;o M.4r(1H)}}o\'\'},2W:q(k){k=$(k);G 1F=k.1a.2e();o 1C.J.5A[1F](k)},e6:q(k,I){k=$(k);G 1F=k.1a.2e();1C.J.5A[1F](k,I);o k},aH:q(k){$(k).I=\'\';o k},e5:q(k){o $(k).I!=\'\'},aG:q(k){k=$(k);2s{k.8z();E(k.2z&&(k.1a.2e()!=\'4y\'||![\'8q\',\'8y\',\'4Z\'].1J(k.1B)))k.2z()}2E(e){}o k},8x:q(k){k=$(k);k.e4();k.3u=1u;o k},8w:q(k){k=$(k);k.3u=1r;o k}};G e3=1C.J;G $F=1C.J.1d.2W;1C.J.5A={4y:q(k,I){5y(k.1B.2e()){2r\'ay\':2r\'ax\':o 1C.J.5A.aF(k,I);6p:o 1C.J.5A.8v(k,I)}},aF:q(k,I){E(M.2D(I))o k.3J?k.I:1k;1m k.3J=!!I},8v:q(k,I){E(M.2D(I))o k.I;1m k.I=I},2z:q(k,1i){E(M.2D(1i))o C[k.1B==\'2z-e2\'?\'aD\':\'aC\'](k);1m{G 3t,I,aE=!M.4x(1i);17(G i=0,O=k.O;i<O;i++){3t=k.U[i];I=C.7f(3t);E(aE){E(I==1i){3t.8u=1u;o}}1m 3t.8u=1i.1J(I)}}},aD:q(k){G 1i=k.e1;o 1i>=0?C.7f(k.U[1i]):1k},aC:q(k){G 1S,O=k.O;E(!O)o 1k;17(G i=0,1S=[];i<O;i++){G 3t=k.U[i];E(3t.8u)1S.1h(C.7f(3t))}o 1S},7f:q(3t){o J.15(3t).3I(\'I\')?3t.I:3t.3Y}};4Y.8s=2b.2p(aB,{2I:q($4d,k,4c,2X){$4d(2X,4c);C.k=$(k);C.4w=C.2W()},8t:q(){G I=C.2W();E(M.3f(C.4w)&&M.3f(I)?C.4w!=I:24(C.4w)!=24(I)){C.2X(C.k,I);C.4w=I}}});1C.J.aA=2b.2p(4Y.8s,{2W:q(){o 1C.J.2W(C.k)}});1C.aA=2b.2p(4Y.8s,{2W:q(){o 1C.6q(C.k)}});4Y.6r=2b.2p({2I:q(k,2X){C.k=$(k);C.2X=2X;C.4w=C.2W();E(C.k.1a.2e()==\'1x\')C.az();1m C.6s(C.k)},8r:q(){G I=C.2W();E(C.4w!=I){C.2X(C.k,I);C.4w=I}},az:q(){1C.5z(C.k).1E(C.6s,C)},6s:q(k){E(k.1B){5y(k.1B.2e()){2r\'ay\':2r\'ax\':1D.4t(k,\'e0\',C.8r.1L(C));2d;6p:1D.4t(k,\'dZ\',C.8r.1L(C));2d}}}});1C.J.6r=2b.2p(4Y.6r,{2W:q(){o 1C.J.2W(C.k)}});1C.6r=2b.2p(4Y.6r,{2W:q(){o 1C.6q(C.k)}});E(!1A.1D)G 1D={};M.15(1D,{dY:8,dX:9,dW:13,dV:27,dU:37,dT:38,dS:39,dR:40,dQ:46,dP:36,dO:35,dN:33,dM:34,dL:45,2P:{},8o:q(1c){G k;5y(1c.1B){2r\'dK\':k=1c.dJ;2d;2r\'dI\':k=1c.3s;2d;6p:o 1k}o J.15(k)}});1D.1d=(q(){G 4W;E(1g.1W.3X){G aw={0:1,1:4,2:2};4W=q(1c,4X){o 1c.8q==aw[4X]}}1m E(1g.1W.4u){4W=q(1c,4X){5y(4X){2r 0:o 1c.7e==1&&!1c.av;2r 1:o 1c.7e==1&&1c.av;6p:o 1r}}}1m{4W=q(1c,4X){o 1c.7e?(1c.7e===4X+1):(1c.8q===4X)}}o{dH:q(1c){o 4W(1c,0)},dG:q(1c){o 4W(1c,1)},dF:q(1c){o 4W(1c,2)},k:q(1c){G L=1D.15(1c).73;o J.15(L.3r==6o.au?L.1O:L)},5w:q(1c,1t){G k=1D.k(1c);E(!1t)o k;G 1V=[k].20(k.5x());o 19.5w(1V,1t,0)},4V:q(1c){o{x:1c.aq||(1c.dE+(1b.4o.4p||1b.2q.4p)),y:1c.ap||(1c.dD+(1b.4o.4n||1b.2q.4n))}},dC:q(1c){o 1D.4V(1c).x},dB:q(1c){o 1D.4V(1c).y},8p:q(1c){1D.15(1c);1c.ar();1c.at();1c.dA=1u}}})();1D.15=(q(){G 2B=M.4b(1D.1d).3H({},q(m,1e){m[1e]=1D.1d[1e].4v();o m});E(1g.1W.3X){M.15(2B,{at:q(){C.dz=1u},ar:q(){C.7d=1r},2C:q(){o"[Y 1D]"}});o q(1c){E(!1c)o 1r;E(1c.7c)o 1c;1c.7c=1g.3q;G 4V=1D.4V(1c);M.15(1c,{73:1c.dy,8o:1D.8o(1c),aq:4V.x,ap:4V.y});o M.15(1c,2B)}}1m{1D.1l=1D.1l||1b.6n("aj").4U;M.15(1D.1l,2B);o 1g.K}})();M.15(1D,(q(){G 2P=1D.2P;q 8k(k){E(k.8n)o k.8n[0];1p.5v.1o=1p.5v.1o||1;o k.8n=[++1p.5v.1o]}q 8j(1z){E(1z&&1z.1J(\':\'))o"ai";o 1z}q 79(1o){o 2P[1o]=2P[1o]||{}}q 7a(1o,1z){G c=79(1o);o c[1z]=c[1z]||[]}q am(k,1z,2c){G 1o=8k(k);G c=7a(1o,1z);E(c.5u("2c").1J(2c))o 1r;G 1K=q(1c){E(!1D||!1D.15||(1c.1z&&1c.1z!=1z))o 1r;1D.15(1c);2c.8m(k,1c)};1K.2c=2c;c.1h(1K);o 1K}q 8i(1o,1z,2c){G c=7a(1o,1z);o c.8l(q(1K){o 1K.2c==2c})}q ak(1o,1z,2c){G c=79(1o);E(!c[1z])o 1r;c[1z]=c[1z].6b(8i(1o,1z,2c))}q an(){17(G 1o 1Q 2P)17(G 1z 1Q 2P[1o])2P[1o][1z]=1k}E(1A.7b){1A.7b("ao",an)}o{4t:q(k,1z,2c){k=$(k);G 1e=8j(1z);G 1K=am(k,1z,2c);E(!1K)o k;E(k.78){k.78(1e,1K,1r)}1m{k.7b("5t"+1e,1K)}o k},4T:q(k,1z,2c){k=$(k);G 1o=8k(k),1e=8j(1z);E(!2c&&1z){7a(1o,1z).1E(q(1K){k.4T(1z,1K.2c)});o k}1m E(!1z){M.4b(79(1o)).1E(q(1z){k.4T(1z)});o k}G 1K=8i(1o,1z,2c);E(!1K)o k;E(k.al){k.al(1e,1K,1r)}1m{k.dx("5t"+1e,1K)}ak(1o,1z,2c);o k},5s:q(k,1z,2O){k=$(k);E(k==1b&&1b.6n&&!k.ah)k=1b.4o;G 1c;E(1b.6n){1c=1b.6n("aj");1c.dw("ai",1u,1u)}1m{1c=1b.dv();1c.ag="du"}1c.1z=1z;1c.2O=2O||{};E(1b.6n){k.ah(1c)}1m{k.dt(1c.ag,1c)}o 1D.15(1c)}}})());M.15(1D,1D.1d);J.6a({5s:1D.5s,4t:1D.4t,4T:1D.4T});M.15(1b,{5s:J.1d.5s.4v(),4t:J.1d.4t.4v(),4T:J.1d.4T.4v(),6m:1r});(q(){G 3W;q 6k(){E(1b.6m)o;E(3W)1A.af(3W);1b.5s("ds:6m");1b.6m=1u}E(1b.78){E(1g.1W.4u){3W=1A.ae(q(){E(/6m|ab/.2L(1b.2N))6k()},0);1D.4t(1A,"dr",6k)}1m{1b.78("dq",6k,1r)}}1m{1b.6l("<4S 1o=ac 4s ad=//:><\\/4S>");$("ac").77=q(){E(C.2N=="ab"){C.77=1k;6k()}}}})();3V.4r=M.4r;G dp={3p:J.aa};J.1d.dn=J.1d.76;G dm={dl:q(k,18){o J.3o(k,{4R:18})},dk:q(k,18){o J.3o(k,{2i:18})},dj:q(k,18){o J.3o(k,{4Q:18})},di:q(k,18){o J.3o(k,{75:18})}};G $3G=1s dh(\'"4q $3G" dg df, de "o" dd\');G 8f={a7:1r,8e:q(){C.a5=1A.a9||1b.4o.4p||1b.2q.4p||0;C.a4=1A.a8||1b.4o.4n||1b.2q.4n||0},dc:q(k,x,y){E(C.a7)o C.a6(k,x,y);C.6i=x;C.6j=y;C.2V=J.4P(k);o(y>=C.2V[1]&&y<C.2V[1]+k.5r&&x>=C.2V[0]&&x<C.2V[0]+k.5q)},a6:q(k,x,y){G 8h=J.8c(k);C.6i=x+8h[0]-C.a5;C.6j=y+8h[1]-C.a4;C.2V=J.4P(k);o(C.6j>=C.2V[1]&&C.6j<C.2V[1]+k.5r&&C.6i>=C.2V[0]&&C.6i<C.2V[0]+k.5q)},db:q(74,k){E(!74)o 0;E(74==\'da\')o((C.2V[1]+k.5r)-C.6j)/k.5r;E(74==\'d9\')o((C.2V[0]+k.5q)-C.6i)/k.5q},4P:J.1d.4P,6h:J.1d.6h,8g:q(k){8f.8e();o J.8g(k)},8d:q(k){8f.8e();o J.8d(k)},d8:J.1d.8c,3e:J.1d.5p,d7:J.1d.6g,2A:q(22,73,U){U=U||{};o J.a3(73,22,U)}};E(!1b.70)1b.70=q(a2){q 8b(1e){o 1e.4O()?1k:"[6f(20(\' \', @6e, \' \'), \' "+1e+" \')]"}a2.70=1g.3U.72?q(k,1j){1j=1j.2H().3T();G 89=/\\s/.2L(1j)?$w(1j).2M(8b).2o(\'\'):8b(1j);o 89?1b.8a(\'.//*\'+89,k):[]}:q(k,1j){1j=1j.2H().3T();G 1V=[],6d=(/\\s/.2L(1j)?$w(1j):1k);E(!6d&&!1j)o 1V;G N=$(k).4a(\'*\');1j=\' \'+1j+\' \';17(G i=0,1G,cn;1G=N[i];i++){E(1G.1j&&(cn=\' \'+1G.1j+\' \')&&(cn.1J(1j)||(6d&&6d.88(q(1e){o!1e.2H().4O()&&cn.1J(\' \'+1e+\' \')}))))1V.1h(J.15(1G))}o 1V};o q(1j,71){o $(71||1b.2q).70(1j)}}(J.1d);J.6Z=2b.2p();J.6Z.1l={2I:q(k){C.k=$(k)},48:q(W){C.k.1j.49(/\\s+/).2z(q(1e){o 1e.O>0}).48(W)},6c:q(1j){C.k.1j=1j},d6:q(87){E(C.1J(87))o;C.6c($A(C).20(87).2o(\' \'))},a1:q(86){E(!C.1J(86))o;C.6c($A(C).6b(86).2o(\' \'))},2H:q(){o $A(C).2o(\' \')}};M.15(J.6Z.1l,2G);J.6a();',62,1095,'||||||||||||||||||||element||||return||function||||||||||||this||if||var||value|Element||node|Object|nodes|length||||||options|results|iterator||object||||||style|extend||for|content|Selector|tagName|document|event|Methods|name|match|Prototype|push|index|className|null|prototype|else|root|id|arguments|result|false|new|expression|true|position|key|form|property|eventName|window|type|Form|Event|each|method|child|pair|formula|include|wrapper|bind|context|klass|parentNode|while|in|Ajax|values|div|attribute|elements|Browser|nth|replace|transport|concat|args|source||String|handlers|combinator||pattern|attr|getStyle|Class|handler|break|toLowerCase|pseudos|width|filter|top|matches|_getEv|attributes|Array||join|create|body|case|try|of|last|xpath|isFunction|left|response|select|clone|methods|inspect|isUndefined|catch|array|Enumerable|toString|initialize|valueT|valueL|test|map|readyState|memo|cache|request|toUpperCase|evaluate|parent|url|offset|getValue|callback|params|nv||targetNode|Template||||||||height|ancestor|responseText|iterable|offsetParent|isString|childNodes|string|px|proceed|properties|json|gsub|__method|insert|display|emptyFunction|nodeType|toElement|opt|disabled|parameters|hash|count|le|ByTag|names|slice|container|toJSON|toArray|replacement|continue|inject|hasAttribute|checked|first|_countedByPrototype|nextSibling|matcher|_attributeTranslations|opacity|insertions|apply|onComplete|strip|BrowserFeatures|Hash|timer|IE|text|typeof||selector|mm|createElement|els|||indexOf|_each|split|getElementsByTagName|keys|frequency|super|reverse|nodeValue|ps|stripScripts|toHTML|isElement|RegExp|start|responder|scrollTop|documentElement|scrollLeft|throw|toQueryString|defer|observe|WebKit|methodize|lastValue|isArray|input|undefined|expressions|not|innerHTML|descendant|nextSiblings|sibling|tags|table|styles|status|_object|toPaddedString|number|parts|blank|cumulativeOffset|bottom|before|script|stopObserving|__proto__|pointer|isButton|code|Abstract|submit|Request|readAttribute|unmark|isNumber|Number|adjacent|_cache|_returnOffset|Opera|evalScripts|update|offsetLeft|offsetTop|userAgent|navigator|currentStyle|wrap|_overflow|shift|decay|insertion|success|dispatchException|headers|end|getOffsetParent|offsetWidth|offsetHeight|fire|on|pluck|callee|findElement|ancestors|switch|getElements|Serializers|action|findAll|firstChild|empty|attrPresence|fragment|substring|getDimensions|self|Heading|destination|_insertionTranslations|tbody|appendChild|absolute|setOpacity|parseFloat|setStyle|static|right|delta|pos|nextAncestor|previousSiblings|receiver|evalJSON|getHeader|interpret|Responders|extras|exclusive|item|template|str|truncation|addMethods|without|set|classNames|class|contains|viewportOffset|positionedOffset|xcomp|ycomp|fireContentLoadedEvent|write|loaded|createEvent|Node|default|serialize|EventObserver|registerCallback|operators|ofType|only|nextElementSibling|previousElementSibling|pseudo|nodeClassName|laterSibling|next|patterns|criteria|following|capitalize|HTMLElement|ElementExtensions|removeChild|_flag|relative|sourceIndex|writeAttribute|onTimerEvent|getStatus|xml|state|contentType|post|_|toObject|responders|fillWith|ctx|expr|ClassNames|getElementsByClassName|parentElement|XPath|target|mode|after|descendantOf|onreadystatechange|addEventListener|getCacheForID|getWrappersForEventName|attachEvent|_extendedByPrototype|returnValue|which|optionValue|toQueryParams|location|tabIndex|hidden|invoke|typeName|inputs|data|findChildElements|findElements|mark|nodeIndex|hasClassName|token|eval|refresh|copy|SpecificElementExtensions|Simulated|TBODY|onlyIfAbsent|tr|insertBefore|html|times|_getContentFromAnonymousElement|00001|Gecko|read|_getAttr|title|none|auto|cssFloat|dim|border|padding|elementClassName|recursivelyCollect|curry|isSameOrigin|application|headerJSON|dispatch|port|asynchronous|onCreate|detect|escapeHTML|charAt|ScriptFragment|currentlyExecuting|classNameToRemove|classNameToAdd|all|cond|_getElementsByXPath|iter|cumulativeScrollOffset|relativize|prepare|Position|absolutize|offsetcache|findWrapper|getDOMEventName|getEventID|find|call|_prototypeEventID|relatedTarget|stop|button|onElementEvent|TimedObserver|execute|selected|textarea|enable|disable|reset|focus|firstByIndex|matchingInputs|submitted|removeAttribute|unique|startsWith|exclusions|indexed|indices|assertions|predicate|and|preceding|exclusion|or|tokens|dimensions|delete|tag|HTML|trans|TD|TableSection|has|fragments|replaceChild|cssText|getAttribute|alpha|stripAlpha|zoom|camelize|styleFloat|float|val|visible|forElement|offsets|overflow|_madePositioned|opera|visibility|elementStyle|css|range|query|updater|delay|Base|failure|Content|decodeURIComponent|getAllResponseHeaders|getResponseHeader|statusText|Response|Complete|exception|unfilterJSON|domain|protocol|evalJS|_complete|respondToReadyState|encoding|Version|onStateChange|get|isHash|activeRequestCount|succ|toTemplateReplacements|toQueryPair|lastIndexOf|_reverse|collect|falses|trues|found|slices|prepareReplacement|escapedString|character|camelized|len|Function|_methodized|superclass|subclass|remove|instanceMethods|clonePosition|deltaY|deltaX|withinIncludingScrolloffsets|includeScrollOffsets|pageYOffset|pageXOffset|toggle|complete|__onDOMContentLoaded|src|setInterval|clearInterval|eventType|dispatchEvent|dataavailable|HTMLEvents|destroyWrapper|removeEventListener|createWrapper|destroyCache|onunload|pageY|pageX|preventDefault||stopPropagation|TEXT_NODE|metaKey|buttonMap|radio|checkbox|registerFormCallbacks|Observer|PeriodicalExecuter|selectMany|selectOne|single|inputSelector|activate|clear|href|findFirstElement|sortBy|serializeElements|matchElements|scan|endsWith|enabled|getIndices|odd|even|total|operator|needle|byClassName|uTagName|previousSibling|_true|with|local|compileXPathMatcher|shouldUseXPath|compileMatcher|getHeight|getWidth|client|findDOMClass|TableCell|TH|TR|TFOOT|THEAD|TableCol|IMG|Mod|TEXTAREA|SELECT|getAttributeNode|td|outerHTML|createTextNode|_getAttrNode|htmlFor|100|parseInt|immediateDescendants|counter|identify|setHeight|setWidth|setTop|setLeft|BODY|_originalWidth|_originalHeight|_originalLeft|_originalTop|clientHeight|clientWidth|originalHeight|originalWidth|originalVisibility|originalPosition|originalDisplay|scrollTo|originalAncestor|compareDocumentPosition|nextNode|addClassName|removeClassName|setAttribute|descendants|firstDescendant|show|hide|ELEMENT_NODE|Updater|lastText|updateComplete|updateContent|sanitizeJSON|force|_getResponseJSON|escape|JSON|_getHeaderJSON|getStatusText|responseXML|Events|onException|evalResponse|interpolate|requestHeaders|2005|overrideMimeType|XMLHttpRequest|setRequestHeaders|KHTML|Safari|getTransport|register|XMLHTTP|ActiveXObject||these|Try|ObjectRange|from|encodeURIComponent|radix|arrayLength|forEach|size|uniq|sorted|inline|flatten|any|collections|eachSlice|Pattern|exec|comp|lt|amp|unescapeHTML|isJSON|sanitize|JSONFilter|sub|useDoubleQuotes|charCodeAt|specialChar|separator|stripTags|extractScripts|matchOne|scriptTag|matchAll|img|1000|lambda|timeout|argumentNames|instanceof|valueOf|subclasses|MobileSafari|add|page|realOffset|horizontal|vertical|overlap|within|instead|use|deprecated|is|Error|After|Bottom|Top|Before|Insertion|childOf||Toggle|DOMContentLoaded|load|dom|fireEvent|ondataavailable|createEventObject|initEvent|detachEvent|srcElement|cancelBubble|stopped|pointerY|pointerX|clientY|clientX|isRightClick|isMiddleClick|isLeftClick|mouseout|fromElement|mouseover|KEY_INSERT|KEY_PAGEDOWN|KEY_PAGEUP|KEY_END|KEY_HOME|KEY_DELETE|KEY_DOWN|KEY_RIGHT|KEY_UP|KEY_LEFT|KEY_ESC|KEY_RETURN|KEY_TAB|KEY_BACKSPACE|change|click|selectedIndex|one|Field|blur|present|setValue|focusFirstElement|getInputs|selectorType|abled|dis|mod|translate|starts|getScrollOffsets|inner|viewport|IFrame|IFRAME|FrameSet|FRAMESET|TableRow||COLGROUP|COL|TableCaption|CAPTION|Image|Anchor|DEL|INS|Quote|H6|H5|H4|H3|H2|H1|Directory|DIR|DList|DL|OList|OL|UList|UL|FieldSet|FIELDSET|Paragraph|TextArea|OptGroup|OPTGROUP|INPUT|FORM|specified|TABLE|999999|rv|onchange|onselect|onreset|onsubmit|onkeyup|onkeydown|onkeypress|onblur|onfocus|onmouseout|onmousemove|onmouseover|onmouseup|onmousedown|ondblclick|onclick|onload|multiple|readonly|longDesc|readOnly|maxLength|encType|accessKey|dateTime|vAlign|rowSpan|colSpan|cellSpacing|cellspacing|cellPadding|cellpadding|normal|hasLayout|fixed|childElements|getElementsBySelector|undoClipping|makeClipping|undoPositioned|makePositioned|block|getOpacity|getComputedStyle|defaultView|cleanWhitespace|toggleClassName|anonymous_element_|previous|down|up|siblings|createContextualFragment|selectNode|createRange|ownerDocument|cloneNode|NOTATION_NODE|DOCUMENT_FRAGMENT_NODE|DOCUMENT_TYPE_NODE|DOCUMENT_NODE|COMMENT_NODE|PROCESSING_INSTRUCTION_NODE|ENTITY_NODE|ENTITY_REFERENCE_NODE|CDATA_SECTION_NODE|ATTRIBUTE_NODE|snapshotItem|snapshotLength|ORDERED_NODE_SNAPSHOT_TYPE|XPathResult|getElementById|clearTimeout|PeriodicalUpdater|getAllHeaders|responseJSON|Interactive|Loaded|Loading|Uninitialized|https|ecma|java||Failure|Success|300|200|setRequestHeader|close|Connection|charset|javascript|Accept||With|Requested|send|postBody|open|Konqueror|_method|UTF|urlencoded|www|unregister|Microsoft|Msxml2|merge|unset|Math|floor|ceil|round|abs|isFinite|toColorPart|isNaN|intersect|reduce|compact|NodeList|some|every|entries|member|pop|zip|sort|reject|partition|min|max|inGroupsOf|grep|parseQuery|formed|Badly|SyntaxError|Eaeflnr|u00|x1f|x00|dasherize|underscore|fromCharCode|im|truncate|finally|getUTCSeconds|getUTCMinutes|getUTCHours|getUTCDate|getUTCMonth|getUTCFullYear|Date|01|setTimeout|bindAsEventListener|splice|boolean|unknown|RangeError|constructor|secure|Mobile|Apple|AppleWebKit'.split('|'),0,{}))
\ No newline at end of file diff --git a/tools/qtestlib/chart/benchmark_template.html b/tools/qtestlib/chart/benchmark_template.html new file mode 100644 index 0000000..a7e48be --- /dev/null +++ b/tools/qtestlib/chart/benchmark_template.html @@ -0,0 +1,202 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> + <title>Title</title> + <! Javascript Here> + + <script type="text/javascript"> + +function offsetLabels(labels, offset) +{ + var copy = new Array(); + for (key in labels) { + copy[key] = new Array(labels[key][0] + 0.25, labels[key][1]); + } + return copy; +} + +function createLogDataSet(inDataSet) +{ + var logDataSet = {}; + logDataSet.label = inDataSet.label; + logDataSet.data = []; + + if (!inDataSet.data) + return logDataSet; + + var length = inDataSet.data.length; + + for (var i = 0; i < length; i++) { + logDataSet.data[i] = []; + logDataSet.data[i][0] = inDataSet.data[i][0]; + logDataSet.data[i][1] = Math.log(inDataSet.data[i][1]); + } + return logDataSet; +} + + +function createLogData(inData) +{ + var logData = []; + + // foreach data set; + var length = inData.length; + for (var i = 0; i < length; ++i) { + logData[i] = createLogDataSet(inData[i]); + } + return logData; +} + +function createChart() { +// alert("create chart" + this.chartId) + + var dataSet; + + if (this.useLinearScale) + dataSet = this.selectedDataset; + else + dataSet = createLogData(this.selectedDataset); + + if (this.useLineChart) { + var f = Flotr.draw($(this.chartId), + dataSet, + { legend:{ backgroundColor: '#D2E8FF' } + , xaxis: { ticks: this.labels, noTicks : 10 } + , mouse: { + track: true, + lineColor: 'purple', + sensibility: 1, + trackDecimals: 2, + trackFormatter: function(obj){ return 'x = ' + obj.x +', y = ' + obj.y; } + } + }); + + } else { + var f = Flotr.draw($(this.chartId), + dataSet, + { legend:{ backgroundColor: '#D2E8FF'} + , bars: { show: true, lineWidth: 1, barWidth: this.barWidth } + , xaxis: { ticks: offsetLabels(this.labels, chartOptions.tickOffset), noTicks : 10 } + }); + } +} + +function checkform() +{ +// alert("check form " + this.form.id + " " + this.chartId); + var field = this.form.list + + // Apparently list of lenght one is not a list... + // Display the entire chart if there is only one data series. + if (!field.length) { + this.createChart(); + return; + } + + this.selectedDataset = []; + var data = []; + var index = 0; + + for (i = 0; i < field.length; i++) { + if (field[i].checked == true) { + this.selectedDataset[index++] = this.dataset[i]; + } else { + this.selectedDataset[index++] = []; + } + } + this.createChart(); +} + +function createElement(nodeName, name) { + var node; + try { + node = document.createElement("<"+nodeName+" name="+name+">"); + } catch (e) { + node = document.createElement(nodeName); + node.name = name; + } + return node; +} + +function createFormSelector(form, value, text, type) +{ + var selector = createElement('input', 'list'); + selector.type = type; + selector.defaultChecked = true; + selector.value = value; + + form.appendChild(selector); + form.appendChild(document.createTextNode(text)); + form.appendChild(document.createElement("BR")); +} + +function createCheckBox(form, value, text) +{ + createFormSelector(form, value, text, "checkbox"); +} + +function createRadioButton(form, value, text) +{ + createFormSelector(form, value, text, "radio"); +} + +function buildSeriesSelector(form, chartOptions) +{ +// alert("form" + form.id + " " + chartOptions.chartId); + var series = chartOptions.seriesLabels; + form.onclick = function() { /*alert("fn " + chartOptions.chartId);*/ chartOptions.checkform() }; + for (s = 0; s < series.length; ++s) { + createCheckBox(form, s, series[s]); + } +} + +function buildChartTypeSelector() +{ + createRadioButton(this.chartTypeForm, 0, "Bar Chart"); + createRadioButton(this.chartTypeForm, 1, "Line Chart"); + + var field = this.chartTypeForm.list; + if (this.useLineChart) + field[1].checked = true; + else + field[0].checked = true; + + var chartOptions = this; + this.chartTypeForm.onclick = function() { + var field = chartOptions.chartTypeForm.list; + + chartOptions.useLineChart = (field[1].checked == true); + chartOptions.checkform(); + }; +} + +function buildScaleSelector() +{ + createRadioButton(this.scaleForm, 0, "Linear Scale"); + createRadioButton(this.scaleForm, 1, "Logarithmic Scale"); + + var field = this.scaleForm.list; + field[0].checked = true; + field[1].checked = false; + + var chartOptions = this; + this.scaleForm.onclick = function() { + var field = chartOptions.scaleForm.list; + + chartOptions.useLinearScale = (field[0].checked == true); + chartOptions.checkform(); + }; +} + + + </script> + </head> + <body> + <h2> + <! Title Here> + </h2> + <! Description Here> + <! Chart Here> + </body> +</html> diff --git a/tools/qtestlib/chart/chart.pro b/tools/qtestlib/chart/chart.pro new file mode 100644 index 0000000..7328e5d --- /dev/null +++ b/tools/qtestlib/chart/chart.pro @@ -0,0 +1,16 @@ +HEADERS += $$PWD/database.h $$PWD/reportgenerator.h +SOURCES += $$PWD/database.cpp $$PWD/reportgenerator.cpp +SOURCES += main.cpp +RESOURCES = $$PWD/chart.qrc + +QT += sql xml +CONFIG += console +CONFIG -= app_bundle + + +TEMPLATE = app +DEPENDPATH += . +INCLUDEPATH += . +TARGET = chart + + diff --git a/tools/qtestlib/chart/chart.qrc b/tools/qtestlib/chart/chart.qrc new file mode 100644 index 0000000..90f782e --- /dev/null +++ b/tools/qtestlib/chart/chart.qrc @@ -0,0 +1,9 @@ + <!DOCTYPE RCC><RCC version="1.0"> + <qresource> + <file>chart_template.html</file> + <file>benchmark_template.html</file> + <file>3rdparty/excanvas.js</file> + <file>3rdparty/flotr.js</file> + <file>3rdparty/prototype.js</file> + </qresource> + </RCC>
\ No newline at end of file diff --git a/tools/qtestlib/chart/chart_template.html b/tools/qtestlib/chart/chart_template.html new file mode 100644 index 0000000..0a4b81a --- /dev/null +++ b/tools/qtestlib/chart/chart_template.html @@ -0,0 +1,110 @@ + <div> + <h3> + <! Test Name Here> + </h3> + <div id= + <! Chart ID Here> + style="width:900px;height:350px;"></div> + + <table cellspacing = "10"><tr> + + <td valign = "top"> + <form id= + <! Form ID Here> + <b> Data series </b><br> + </form> + </td> + + <td valign = "top"> + <form id= + <! ChartTypeForm ID Here> + <b> Chart Type </b><br> + </form> + </td> + + <td valign = "top"> + <form id= + <! ScaleForm ID Here> + <b> Scale </b><br> + </form> + </td> + + </tr></table> + + </div> + <script type="text/javascript"> + var chartId = + <! Chart ID Here> + ; + + var chartType = + <! Chart Type Here> + ; + + var seriesLabels = + <! Series Labels Here> + + var dataset = []; + <! Data Goes Here> + + var labels = [ + <! Labels Go Here> + ]; + + var colors = new Hash({ + <! ColorScheme Here> + }); + + var shouldFill = + <! Fill Setting Here> + ; + + var form = document.getElementById( + <! Form ID Here> + ); + + var chartTypeForm = document.getElementById( + <! ChartTypeForm ID Here> + ); + + var scaleForm = document.getElementById( + <! ScaleForm ID Here> + ); + + + + var chartOptions = new Object(); + chartOptions.chartId = chartId; + chartOptions.chartType = chartType; + chartOptions.dataset = dataset; + chartOptions.colors = colors; + chartOptions.shouldFill = shouldFill; + chartOptions.labels = labels; + chartOptions.seriesLabels = seriesLabels; + chartOptions.useLineChart = true; + chartOptions.useLinearScale = true; + chartOptions.createChart = createChart; + + chartOptions.ticks = labels; + chartOptions.barWidth = 0.5; + chartOptions.tickOffset = 0.25; + + chartOptions.useLineChart = + <! Use Line Chart Here> + + chartOptions.chartTypeForm = chartTypeForm; + chartOptions.buildChartTypeSelector = buildChartTypeSelector; + chartOptions.buildChartTypeSelector(); + + chartOptions.scaleForm = scaleForm; + chartOptions.buildScaleSelector = buildScaleSelector; + chartOptions.buildScaleSelector(); + + chartOptions.selectedDataset = dataset; + chartOptions.checkform = checkform; + chartOptions.form = form; + chartOptions.buildSeriesSelector = buildSeriesSelector; + chartOptions.buildSeriesSelector(form, chartOptions); + chartOptions.checkform(); + </script> + diff --git a/tools/qtestlib/chart/database.cpp b/tools/qtestlib/chart/database.cpp new file mode 100644 index 0000000..ba0a31a --- /dev/null +++ b/tools/qtestlib/chart/database.cpp @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "database.h" +#include <QtGui> +#include <QtXml> + +// Database schema definition and open/create functions + +QString resultsTable = QString("(TestName varchar, TestCaseName varchar, Series varchar, Idx varchar, ") + + QString("Result varchar, ChartType varchar, Title varchar, ChartWidth varchar, ") + + QString("ChartHeight varchar, TestTitle varchar, QtVersion varchar, Iterations varchar") + + QString(")"); + +void execQuery(QSqlQuery query, bool warnOnFail) +{ + bool ok = query.exec(); + if (!ok && warnOnFail) { + qDebug() << "FAIL:" << query.lastQuery() << query.lastError().text(); + } +} + +void execQuery(const QString &spec, bool warnOnFail) +{ + QSqlQuery query; + query.prepare(spec); + execQuery(query, warnOnFail); +} + +QSqlDatabase openDataBase(const QString &databaseFile) +{ +// qDebug() << "open data base"; + QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); + db.setDatabaseName(databaseFile); + bool ok = db.open(); + if (!ok) + qDebug() << "FAIL: could not open database"; + return db; +} + +QSqlDatabase createDataBase(const QString &databaseFile) +{ +// qDebug() << "create data base"; + QSqlDatabase db = openDataBase(databaseFile); + + execQuery("DROP TABLE Results", false); + execQuery("CREATE TABLE Results " + resultsTable); + + return db; +} + +struct Tag +{ + Tag(QString key, QString value) + : key(key.trimmed()), value(value.trimmed()) + { + + } + + QString key; + QString value; +}; + +QList<Tag> parseTag(const QString &tag) +{ + // Format: key1=value ; key2=value + // key1=value key2=value + // value--value + + QList<Tag> keyValues; + + QString keyValuePairSeparator(""); + if (tag.contains(";")) + keyValuePairSeparator = ';'; + if (tag.contains("--")) + keyValuePairSeparator = "--"; + + foreach (QString keyValue, tag.split(keyValuePairSeparator)) { + if (keyValue.contains("=")) { + QStringList parts = keyValue.split("="); + keyValues.append(Tag(parts.at(0), parts.at(1))); + } else { + keyValues.append(Tag(QString(), keyValue)); // no key, just a value. + } + } + + return keyValues; +} + +void loadXml(const QStringList &fileNames) +{ + foreach(const QString &fileName, fileNames) { + QFileInfo fi( fileName ); + loadXml(fileName, fi.fileName()); + } +} + +void loadXml(const QString &fileName, const QString &context) +{ + QFile f(fileName); + f.open(QIODevice::ReadOnly); + loadXml(f.readAll(), context); +} + +void loadXml(const QByteArray &xml, const QString& context) +{ + QDomDocument doc; + + int line; + int col; + QString errorMsg; + if (doc.setContent(xml, &errorMsg, &line, &col) == false) { + qDebug() << "dom setContent failed" << line << col << errorMsg; + } + + // Grab "Value" from <Environment><QtVersion>Value</QtVersion></Environment> + QString qtVersion = doc.elementsByTagName("Environment").at(0).toElement().elementsByTagName("QtVersion") + .at(0).toElement().childNodes().at(0).nodeValue(); + QString testCase = doc.elementsByTagName("TestCase").at(0).toElement().attributeNode("name").value(); + +// qDebug() << "qt version" << qtVersion; +// qDebug() << "test case" << testCase; + + DataBaseWriter writer; + writer.testName = testCase; // testCaseName and testName is mixed up in the database writer class + writer.qtVersion = qtVersion; + + QDomNodeList testFunctions = doc.elementsByTagName("TestFunction"); + for (int i = 0; i < testFunctions.count(); ++i) { + QDomElement function = testFunctions.at(i).toElement(); + QString functionName = function.attributeNode("name").value(); + writer.testCaseName = functionName; // testCaseName and testName is mixed up in the database writer class + +// qDebug() << "fn" << functionName; + + QDomNodeList results = function.elementsByTagName("BenchmarkResult"); + for (int j = 0; j < results.count(); ++j) { + QDomElement result = results.at(j).toElement(); + QString tag = result.attributeNode("tag").value(); + + Q_UNUSED(context); +// if (!context.isEmpty()) +// tag += QString(" (%1)").arg(context); + + QString series; + QString index; + + // By convention, "--" separates series and indexes in tags. + if (tag.contains("--")) { + QStringList parts = tag.split("--"); + series = parts.at(0); + index = parts.at(1); + } else { + series = tag; + } + + QString resultString = result.attributeNode("value").value(); + QString iterationCount = result.attributeNode("iterations").value(); + double resultNumber = resultString.toDouble() / iterationCount.toDouble(); + writer.addResult(series, index, QString::number(resultNumber), iterationCount); +// qDebug() << "result" << series << index << tag << resultString << iterationCount; + } + } +} + +void displayTable(const QString &table) +{ + QSqlTableModel *model = new QSqlTableModel(); + model->setTable(table); + model->select(); + QTableView *view = new QTableView(); + view->setModel(model); + view->show(); +} + +void printDataBase() +{ + QSqlQuery query; + query.prepare("SELECT TestName, TestCaseName, Result FROM Results;"); + bool ok = query.exec(); + qDebug() << "printDataBase ok?" << ok; + + query.next(); + qDebug() << ""; + qDebug() << "Benchmark" << query.value(0).toString(); + query.previous(); + + while (query.next()) { + // QString country = query.value(fieldNo).toString(); + // doSomething(country); + qDebug() << "result for" << query.value(1).toString() << query.value(2).toString(); + } +} + +// TempTable implementation + +static int tempTableIdentifier = 0; +TempTable::TempTable(const QString &spec) +{ + m_name = "TempTable" + QString::number(tempTableIdentifier++); + execQuery("CREATE TEMP TABLE " + m_name + " " + spec); +} + +TempTable::~TempTable() +{ + // ref count and drop it? +} + +QString TempTable::name() +{ + return m_name; +} + +// DataBaseWriter implementation + +DataBaseWriter::DataBaseWriter() +{ + disable = false; + chartSize = QSize(800, 400); + databaseFileName = ":memory:"; + qtVersion = QT_VERSION_STR; +} + +void DataBaseWriter::openDatabase() +{ + db = openDataBase(databaseFileName); +} + +void DataBaseWriter::createDatabase() +{ + db = createDataBase(databaseFileName); +} + +void DataBaseWriter::beginTransaction() +{ + if (db.transaction() == false) { + qDebug() << db.lastError(); + qFatal("no transaction support"); + } +} + +void DataBaseWriter::commitTransaction() +{ + db.commit(); +} + +void DataBaseWriter::rollbackTransaction() +{ + db.rollback(); +} + +void DataBaseWriter::addResult(const QString &result) +{ + return addResult(QString(), QString(), result); +} + +void DataBaseWriter::addResult(const QString &series, const QString &index, const QString &result, const QString &iterations) +{ + if (disable) + return; + + QSqlQuery query; + + query.prepare("INSERT INTO Results (TestName, TestCaseName, Series, Idx, Result, ChartWidth, ChartHeight, Title, TestTitle, ChartType, QtVersion, Iterations) " + "VALUES (:TestName, :TestCaseName, :Series, :Idx, :Result, :ChartWidth, :ChartHeight, :Title, :TestTitle, :ChartType, :QtVersion, :Iterations)"); + query.bindValue(":TestName", testName); + query.bindValue(":TestCaseName", testCaseName); + query.bindValue(":Series", series); + query.bindValue(":Idx", index); + query.bindValue(":Result", result); + query.bindValue(":ChartWidth", chartSize.width()); + query.bindValue(":ChartHeight", chartSize.height()); + query.bindValue(":Title", chartTitle); + query.bindValue(":TestTitle", testTitle); + query.bindValue(":QtVersion", qtVersion); + query.bindValue(":Iterations", iterations); + + + if (chartType == LineChart) + query.bindValue(":ChartType", "LineChart"); + else + query.bindValue(":ChartType", "BarChart"); + execQuery(query); +} diff --git a/tools/qtestlib/chart/database.h b/tools/qtestlib/chart/database.h new file mode 100644 index 0000000..df3dde2 --- /dev/null +++ b/tools/qtestlib/chart/database.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef DATABASE_H +#define DATABASE_H + +#include <QtCore> +#include <QtSql> + +extern QString resultsTable; +QSqlDatabase openDataBase(const QString &databaseFile = "database"); +QSqlDatabase createDataBase(const QString &databaseFile = "database"); + +void loadXml(const QStringList &fileNames); +void loadXml(const QString &fileName, const QString &context=QString::null); +void loadXml(const QByteArray &xml, const QString &context=QString::null); + +void execQuery(QSqlQuery query, bool warnOnFail = true); +void execQuery(const QString &spec, bool warnOnFail = true); +void printDataBase(); +void displayTable(const QString &table); + +class TempTable +{ +public: + TempTable(const QString &spec); + ~TempTable(); + QString name(); +private: + QString m_name; +}; + +enum ChartType { BarChart, LineChart }; +class DataBaseWriter +{ +public: + DataBaseWriter(); + QString databaseFileName; + QString testTitle; + QString testName; + QString testCaseName; + ChartType chartType; + QSize chartSize; + QString chartTitle; + QString qtVersion; + bool disable; + + void openDatabase(); + void createDatabase(); + + void beginTransaction(); + void commitTransaction(); + void rollbackTransaction(); + + void addResult(const QString &result); + void addResult(const QString &series , const QString &index, const QString &result, const QString &iterations = QLatin1String("1")); + + QSqlDatabase db; +}; + + +#endif diff --git a/tools/qtestlib/chart/main.cpp b/tools/qtestlib/chart/main.cpp new file mode 100644 index 0000000..7069330 --- /dev/null +++ b/tools/qtestlib/chart/main.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <QtCore> +#include <QtSql> +#include <database.h> +#include <reportgenerator.h> + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QSqlDatabase db = createDataBase(":memory:"); + + if (argc < 2) { + + // Try stdin + QFile in; + in.open(stdin, QIODevice::ReadOnly); + QByteArray xml = in.readAll(); + + if (xml.isEmpty()) { + qDebug() << "Usage: chart xml-file [xml-file2 xml-file3 ...]"; + qDebug() << "See also QTestLib's \"-chart\" option"; + return 0; + } else { + loadXml(xml, QString()); + } + } + + QStringList files; + for (int i = 1; i < argc; i++) { + QString file = QString::fromLocal8Bit(argv[i]); + files += file; + } + + if (files.isEmpty() == false) + loadXml(files); + + ReportGenerator reportGenerator; + reportGenerator.writeReports(); + + db.close(); +} + diff --git a/tools/qtestlib/chart/reportgenerator.cpp b/tools/qtestlib/chart/reportgenerator.cpp new file mode 100644 index 0000000..0b5eb6f --- /dev/null +++ b/tools/qtestlib/chart/reportgenerator.cpp @@ -0,0 +1,561 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "reportgenerator.h" + +// Report generator file utility functions + +QList<QByteArray> readLines(const QString &fileName) +{ + QList<QByteArray> lines; + QFile f(fileName); + f.open(QIODevice::ReadOnly | QIODevice::Text); + while(!f.atEnd()) + lines.append(f.readLine()); + return lines; +} + +void writeLines(const QString &fileName, const QList<QByteArray> &lines) +{ + QFile f(fileName); + f.open(QIODevice::WriteOnly | QIODevice::Text); + foreach(const QByteArray line, lines) + f.write(line); +} + +void writeFile(const QString &fileName, const QByteArray &contents) +{ + QFile f(fileName); + f.open(QIODevice::WriteOnly | QIODevice::Append); + f.write(contents); +} + +// Report generator database utility functions + +QStringList select(const QString &field, const QString &tableName) +{ + QSqlQuery query; + query.prepare("SELECT DISTINCT " + field +" FROM " + tableName); + bool ok = query.exec(); + Q_UNUSED(ok); +// if (!ok) +// qDebug() << "select unique ok" << ok; + + QStringList values; + while (query.next()) { + values += query.value(0).toString(); + } + return values; +} + +QStringList selectUnique(const QString &field, const QString &tableName) +{ + QSqlQuery query; + query.prepare("SELECT DISTINCT " + field +" FROM " + tableName); + bool ok = query.exec(); + Q_UNUSED(ok); +// if (!ok) +// qDebug() << "select unique ok" << ok; + + QStringList values; + while (query.next()) { + values += query.value(0).toString(); + } + return values; +} + +QSqlQuery selectFromSeries(const QString &serie, const QString &column, const QString &tableName, const QString &seriesName) +{ + QSqlQuery query; + if (serie == QString()) + query.prepare("SELECT " + column + " FROM " + tableName); + else + query.prepare("SELECT " + column + " FROM " + tableName + " WHERE " + seriesName + "='" + serie + "'"); + /*bool ok =*/ query.exec(); + + +// qDebug() << "selectDataFromSeries ok?" << ok << query.size(); + return query; +} + +int countDataFromSeries(const QString &serie, const QString &tableName, const QString &seriesName) +{ +// qDebug() << "count" << serie << "in" << tableName; + QSqlQuery query; + query.prepare("SELECT COUNT(Result) FROM " + tableName + " WHERE" + seriesName + "='" + serie + "'"); + bool ok = query.exec(); + if (!ok) { + qDebug() << "query fail" << query.lastError(); + } + + qDebug() << "countDataFromSeries ok?" << ok << query.size(); + query.next(); + return query.value(0).toInt(); +} + +// Report generator output utility functions + +QList<QByteArray> printData(const QString &tableName, const QString &seriesName, const QString &indexName) +{ + QList<QByteArray> output; + QStringList series = selectUnique(seriesName, tableName); +// qDebug() << "series" << series; + if (series.isEmpty()) + series+=QString(); + + foreach (QString serie, series) { + QSqlQuery data = selectFromSeries(serie, "Result", tableName, seriesName); + QSqlQuery labels = selectFromSeries(serie, indexName, tableName, seriesName); + + QByteArray dataLine = "dataset.push({ data: ["; + int i = 0; + while (data.next() && labels.next()) { + QString label = labels.value(0).toString(); + + QString labelString; + bool ok; + label.toInt(&ok); + if (ok) + labelString = label; + // else + labelString = QString::number(i); + + dataLine += ("[" + labelString + ", " + data.value(0).toString() + "]"); + + ++i; + if (data.next()) { + dataLine += ", "; + data.previous(); + } + } + dataLine += "], label : \"" + serie + "\" });\n"; + output.append(dataLine); + } + return output; +} + +// Determines if a line chart should be used. Returns true if the first label is numerical. +bool useLineChart(const QString &tableName, const QString &seriesName, const QString &indexName) +{ + QList<QByteArray> output; + QStringList series = selectUnique(seriesName, tableName); + if (series.isEmpty()) + return false; + + QSqlQuery data = selectFromSeries(series[0], indexName, tableName, seriesName); + + if (data.next()) { + QString label = data.value(0).toString(); + bool ok; + label.toDouble(&ok); + return ok; + } + + return false; +} + +int countLabels(const QString &tableName, const QString &seriesName, const QString &indexName) +{ + QStringList series = selectUnique(seriesName, tableName); + if (series.isEmpty()) + return 0; + QSqlQuery data = selectFromSeries(series[0], indexName, tableName, seriesName); + int count = 0; + while (data.next()) + count++; + + return count; +} + + +QList<QByteArray> printLabels(const QString &tableName, const QString &seriesName, const QString &indexName) +{ + QList<QByteArray> output; + QStringList series = selectUnique(seriesName, tableName); + if (series.isEmpty()) + return QList<QByteArray>(); + + QSqlQuery data = selectFromSeries(series[0], indexName, tableName, seriesName); + + int count = 0; + while (data.next()) + count++; + + data.first(); data.previous(); + + const int labelCount = 10; + int skip = count / labelCount; + + QByteArray dataLine; + int i = 0; + while (data.next()) { + dataLine += ("[" + QByteArray::number(i) + ",\"" + data.value(0).toString() + "\"]"); + ++i; + if (data.next()) { + dataLine += ", "; + data.previous(); + } + + // skip labels. + i += skip; + for (int j = 0; j < skip; ++j) + data.next(); + } + dataLine += "\n"; + output.append(dataLine); + return output; +} + +QByteArray printSeriesLabels(const QString &tableName, const QString &seriesColumnName) +{ + QByteArray output; + QStringList series = selectUnique(seriesColumnName, tableName); + if (series.isEmpty()) + return "[];\n"; + + output += "["; + + foreach(const QString &serie, series) { + output += "\"" + serie.toLocal8Bit() + "\","; + } + output.chop(1); //remove last comma + output += "]\n"; + return output; +} + +void addJavascript(QList<QByteArray> *output, const QString &fileName) +{ + output->append("<script type=\"text/javascript\">\n"); + (*output) += readLines(fileName); + output->append("</script>\n"); +} + +void addJavascript(QList<QByteArray> *output) +{ + addJavascript(output, ":3rdparty/prototype.js"); + addJavascript(output, ":3rdparty/excanvas.js"); + addJavascript(output, ":3rdparty/flotr.js"); +} + +TempTable selectRows(const QString &sourceTable, const QString &column, const QString &value) +{ + TempTable tempTable(resultsTable); + + QSqlQuery query; + query.prepare("INSERT INTO " + tempTable.name() + " SELECT * FROM " + sourceTable + + " WHERE " + column + "='" + value + "'"); + execQuery(query); + +// displayTable(tempTable.name()); + + return tempTable; +} + +TempTable mergeVersions(const QString &) +{ + +// QtVersion - As series +// Result - (free) +// Idx - match +// TestName - match +// CaseName - match + +// (Series - average) +/* + TempTable tempTable(resultsTable); + QStringlist versions = selectUnique("QtVersions", sourceTable); + + QSqlQuery oneVersion = select(WHERE QtVersions = versions.at(0)) + while (oneVersion.next) { + QSqlQuery otherversions = selectMatches(QStringList() << "TestName" << "TestCaseName" << "Idx") + while (otherversions.next) { + insert(temptable + } + } +*/ + return TempTable(""); +} + +QStringList fieldPriorityList = QStringList() << "Idx" << "Series" << "QtVersion"; + +struct IndexSeriesFields +{ + QString index; + QString series; +}; + +IndexSeriesFields selectFields(const QString &table) +{ + IndexSeriesFields fields; + foreach (QString field, fieldPriorityList) { +// qDebug() << "unique" << field << selectUnique(field, table).count(); + QStringList rows = selectUnique(field, table); + + if (rows.count() <= 1 && rows.join("") == QString("")) + continue; + + if (fields.index.isEmpty()) { + fields.index = field; + continue; + } + + if (fields.series.isEmpty()) { + fields.series = field; + break; + } + } + return fields; +} + +TempTable selectTestCase(const QString &testCase, const QString &sourceTable) +{ + return selectRows(sourceTable, QLatin1String("TestCaseName"), testCase); +} + +QString field(const QSqlQuery &query, const QString &name) +{ + return query.value(query.record().indexOf(name)).toString(); +} + +QSqlQuery selectAllResults(const QString &tableName) +{ + QSqlQuery query; + query.prepare("SELECT * FROM " + tableName); + execQuery(query); + return query; +} + +void printTestCaseResults(const QString &testCaseName) +{ +// QStringList testCases = selectUnique("TestCaseName", "Results"); + qDebug() << ""; + qDebug() << "Results for benchmark" << testCaseName; + TempTable temptable = selectTestCase(testCaseName, "Results"); + QSqlQuery query = selectAllResults(temptable.name()); + if (query.isActive() == false) { + qDebug() << "No results"; + return; + } + + query.next(); + + if (field(query, "Idx") == QString()) { + do { + qDebug() << "Result:" << field(query, "result"); + } while (query.next()); + } else if (field(query, "Series") == QString()) { + do { + qDebug() << field(query, "Idx") << " : " << field(query, "result"); + } while (query.next()); + } else { + do { + qDebug() << field(query, "Series") << " - " << field(query, "Idx") << " : " << field(query, "result"); + } while (query.next()); + } + + qDebug() << ""; +} + + +// ReportGenerator implementation + +ReportGenerator::ReportGenerator() +{ + m_colorScheme = QList<QByteArray>() << "#a03b3c" << "#3ba03a" << "#3a3ba0" << "#3aa09f" << "#39a06b" << "#a09f39"; +} + + +void ReportGenerator::writeReport(const QString &tableName, const QString &fileName, bool combineQtVersions) +{ + QStringList testCases = selectUnique("TestCaseName", tableName); + QList<QByteArray> lines = readLines(":benchmark_template.html"); + QList<QByteArray> output; + + foreach(QByteArray line, lines) { + if (line.contains("<! Chart Here>")) { + foreach (const QString testCase, testCases) { + TempTable testCaseTable = selectTestCase(testCase, tableName); + output += writeChart(testCaseTable.name(), combineQtVersions); + } + } else if (line.contains("<! Title Here>")) { + QStringList name = selectUnique("TestName", tableName); + output += "Test: " + name.join("").toLocal8Bit(); + } else if (line.contains("<! Description Here>")) { + output += selectUnique("TestTitle", tableName).join("").toLocal8Bit(); + } else if (line.contains("<! Javascript Here>")){ + addJavascript(&output); + } else { + output.append(line); + } + } + + m_fileName = fileName; + + writeLines(m_fileName, output); + qDebug() << "Wrote report to" << m_fileName; +} + +void ReportGenerator::writeReports() +{ +/* + QStringList versions = selectUnique("QtVersion", "Results"); + + // qDebug() << "versions" << versions; + + foreach (QString version, versions) { + QString fileName = "results-" + version + ".html"; + TempTable versionTable = selectRows("Results", "QtVersion", version); + writeReport(versionTable.name(), fileName, false); + } +*/ + writeReport("Results", "results.html", false); +} + +QString ReportGenerator::fileName() +{ + return m_fileName; +} + +QList<QByteArray> ReportGenerator::writeChart(const QString &tableName, bool combineQtVersions) +{ + QSqlQuery query; + query.prepare("SELECT TestName, Series, Idx, Result, ChartWidth, ChartHeight, Title, TestCaseName, ChartType, QtVersion FROM " + tableName); + execQuery(query); + + QString seriesName; + QString indexName; + + if (combineQtVersions) { + IndexSeriesFields fields = selectFields(tableName); + seriesName = fields.series; + indexName = fields.index; + } else { + seriesName = "Series"; + indexName = "Idx"; + } + + QList<QByteArray> data = printData(tableName, seriesName, indexName); + QList<QByteArray> labels = printLabels(tableName, seriesName, indexName); + QByteArray seriesLabels = printSeriesLabels(tableName, seriesName); + QByteArray useLineChartString = useLineChart(tableName, seriesName, indexName) ? "true" : "false" ; + + query.next(); + QString testName = query.value(0).toString(); + QSize size(query.value(4).toInt(), query.value(5).toInt()); +// QString title = "Test Function: " + query.value(7).toString() + " - " + query.value(6).toString(); + QString title = "Test Function: " + query.value(7).toString(); + QString chartId = "\"" + query.value(7).toString() + "\""; + QString formId = "\"" + query.value(7).toString() + "form\""; + QString chartTypeFormId = "\"" + query.value(7).toString() + "chartTypeform\""; + QString scaleFormId = "\"" + query.value(7).toString() + "scaleform\""; + QString type = query.value(8).toString(); + + // Skip chart generation if there isn't enough data. + if (countLabels(tableName, seriesName, indexName) < 2) { + qDebug() << title.toAscii() << "No chartable data. (See the \"series\" test function" + << "in examples/qtestlib/tutorial5 for an example.) "; + return QList<QByteArray>() << title.toAscii() << " (no chartable data)"; // TODO: genrate text table here. + } + +// QString qtVersion = query.value(9).toString(); + query.previous(); + + QString sizeString = "height=\"" + QString::number(size.height()) + "\" width=\"" + QString::number(size.width()) + "\""; + + QString fillString; + if (type == "LineChart") + fillString = "false"; + else + fillString = "true"; + + QByteArray colors = printColors(tableName, seriesName); + + QList<QByteArray> lines = readLines(":chart_template.html"); + QList<QByteArray> output; + + foreach(QByteArray line, lines) { + if (line.contains("<! Test Name Here>")) { + output.append(title.toLocal8Bit()); + } else if (line.contains("<! Chart ID Here>")) { + output += chartId.toLocal8Bit(); + } else if (line.contains("<! Form ID Here>")) { + output += formId.toLocal8Bit(); + } else if (line.contains("<! ChartTypeForm ID Here>")) { + output += chartTypeFormId.toLocal8Bit(); + } else if (line.contains("<! ScaleForm ID Here>")) { + output += scaleFormId.toLocal8Bit(); + } else if (line.contains("<! Size>")) { + output += sizeString.toLocal8Bit(); + } else if (line.contains("<! ColorScheme Here>")) { + output += colors; + } else if (line.contains("<! Data Goes Here>")) { + output += data; + } else if (line.contains("<! Labels Go Here>")) { + output += labels; + } else if (line.contains("<! Use Line Chart Here>")) { + output += useLineChartString + ";"; + } else if (line.contains("<! Chart Type Here>")) { + output += "\"" + type.toLocal8Bit() + "\""; + } else if (line.contains("<! Fill Setting Here>")) { + output += fillString.toLocal8Bit(); + } else if (line.contains("<! Series Labels Here>")) { + output += seriesLabels; + } else { + output.append(line); + } + } + + return output; +} + +QByteArray ReportGenerator::printColors(const QString &tableName, const QString &seriesName) +{ + QByteArray colors; + int i = 0; + QStringList series = selectUnique(seriesName, tableName); + foreach (const QString &serie, series) { + colors.append("'" + serie.toLocal8Bit() + "': '" + m_colorScheme.at(i % m_colorScheme.count()) + "',\n"); + ++ i; + } + colors.chop(2); // remove last comma + colors.append("\n"); + return colors; +} + diff --git a/tools/qtestlib/chart/reportgenerator.h b/tools/qtestlib/chart/reportgenerator.h new file mode 100644 index 0000000..bef9cdd --- /dev/null +++ b/tools/qtestlib/chart/reportgenerator.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef REPORTGENERATOR_H +#define REPORTGENERATOR_H + +#include "database.h" + +class ReportGenerator +{ +public: + ReportGenerator(); + QByteArray printColors(const QString &tableName, const QString &seriesName); + QList<QByteArray> writeChart(const QString &tableName, bool combineVersions); + void writeReport(const QString &tableName, const QString &filename, bool combineVersions = false); + void writeReports(); + QString fileName(); +private: + QList<QByteArray> m_colorScheme; + QString m_fileName; +}; + +void printTestCaseResults(const QString &testCaseName); + +#endif + diff --git a/tools/qtestlib/qtestlib.pro b/tools/qtestlib/qtestlib.pro index da94e81..9ff7360 100644 --- a/tools/qtestlib/qtestlib.pro +++ b/tools/qtestlib/qtestlib.pro @@ -1,4 +1,4 @@ TEMPLATE = subdirs -!wince*: SUBDIRS += updater +!wince*: SUBDIRS += updater chart wince*: contains(QT_CONFIG, cetest): SUBDIRS += wince CONFIG += ordered diff --git a/tools/qtestlib/wince/cetcpsync/cetcpsync.pro b/tools/qtestlib/wince/cetcpsync/cetcpsync.pro new file mode 100644 index 0000000..d1d7c99 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/cetcpsync.pro @@ -0,0 +1,22 @@ +TARGET = cetcpsync +DESTDIR = ../../../../bin +CONFIG += console +CONFIG -= app_bundle +QT += network +QT -= gui +TEMPLATE = app + +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} + +INCLUDEPATH += ../cetcpsyncserver + +SOURCES += main.cpp \ + remoteconnection.cpp \ + qtcesterconnection.cpp + +HEADERS += \ + remoteconnection.h \ + qtcesterconnection.h diff --git a/tools/qtestlib/wince/cetcpsync/main.cpp b/tools/qtestlib/wince/cetcpsync/main.cpp new file mode 100644 index 0000000..73c7350 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/main.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <iostream> +#include "qtcesterconnection.h" + +using namespace std; + +static void showUsage() +{ + cout << "cetcpsync is meant to be used by cetest internally." << endl + << "For usage instructions remoteconnection.h could be useful." << endl; +} + +const int debugLevel = 0; +void debugOutput(const QString& text, int level) +{ + if (level <= debugLevel) + cout << qPrintable(text) << endl; +} + +class Exception +{ +public: + Exception(const QString& msg = QString()) + : m_message(msg) + {} + + QString message() { return m_message; } + +protected: + QString m_message; +}; + +class TooFewParametersException : public Exception +{ +public: + TooFewParametersException(const QLatin1String& cmd, int expectedParameterCount) + { + m_message = QLatin1String("Command ") + cmd + QLatin1String(" needs at least "); + m_message.append(QString::number(expectedParameterCount)); + m_message.append(QLatin1String(" parameters.")); + } +}; + +static void fileTimeFromString(FILETIME& ft, const QString& str) +{ + int idx = str.indexOf("*"); + if (idx <= 0) + return; + ft.dwLowDateTime = str.left(idx).toULong(); + ft.dwHighDateTime = str.mid(idx+1).toULong(); +} + +static QString fileTimeToString(FILETIME& ft) +{ + return QString::number(ft.dwLowDateTime) + "*" + QString::number(ft.dwHighDateTime); +} + +static int execCommand(const QLatin1String& cmd, int argc, char* argv[]) +{ + int retval = 0; + bool success = true; + QtCesterConnection connection; + if (cmd == "copyFileToDevice") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyFileToDevice(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "copyDirectoryToDevice") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyDirectoryToDevice(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "copyFileFromDevice") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyFileFromDevice(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "copyDirectoryFromDevice") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyDirectoryFromDevice(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "timeStampForLocalFileTime") { + if (argc < 1) + throw TooFewParametersException(cmd, 1); + FILETIME ft; + fileTimeFromString(ft, argv[0]); + success = connection.timeStampForLocalFileTime(&ft); + if (success) + cout << qPrintable(fileTimeToString(ft)); + } else if (cmd == "fileCreationTime") { + if (argc < 1) + throw TooFewParametersException(cmd, 1); + FILETIME ft; + success = connection.fileCreationTime(argv[0], &ft); + if (success) + cout << qPrintable(fileTimeToString(ft)); + } else if (cmd == "copyFile") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyFile(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "copyDirectory") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.copyDirectory(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "deleteFile") { + if (argc < 1) + throw TooFewParametersException(cmd, 1); + success = connection.deleteFile(argv[0]); + } else if (cmd == "deleteDirectory") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.deleteDirectory(argv[0], argv[1] == "true", argv[2] == "true"); + } else if (cmd == "moveFile") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.moveFile(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "moveDirectory") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + success = connection.moveDirectory(argv[0], argv[1], argv[2] == "true"); + } else if (cmd == "createDirectory") { + if (argc < 2) + throw TooFewParametersException(cmd, 2); + success = connection.createDirectory(argv[0], argv[1] == "true"); + } else if (cmd == "execute") { + if (argc < 3) + throw TooFewParametersException(cmd, 3); + int timeout = QString(argv[2]).toInt(); + success = connection.execute(argv[0], argv[1], timeout, &retval); + } else if (cmd == "noop") { + // do nothing :) + success = true; + } else { + throw Exception("unknown command"); + } + + return success ? retval : 1; +} + +int main(int argc, char *argv[]) +{ + if (argc <= 1) { + showUsage(); + return 0; + } + + QLatin1String param(argv[1]); + int result = 1; + try { + result = execCommand(param, argc - 2, argv + 2); + } catch (Exception e) { + cerr << "Error: " << qPrintable(e.message()); + } + return result; +} diff --git a/tools/qtestlib/wince/cetcpsync/qtcesterconnection.cpp b/tools/qtestlib/wince/cetcpsync/qtcesterconnection.cpp new file mode 100644 index 0000000..76d3b4b --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/qtcesterconnection.cpp @@ -0,0 +1,552 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qtcesterconnection.h" +#include <transfer_global.h> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtNetwork/QTcpSocket> +#include <QtNetwork/QHostAddress> + +extern void debugOutput(const QString& text, int level); + +#pragma warning(disable:4996) + +#define END_ERROR(s, a) \ + if(a) qDebug() << a; \ + _freeSocket(s); \ + return false; + +QtCesterConnection::QtCesterConnection() + : AbstractRemoteConnection() +{ +} + +QtCesterConnection::~QtCesterConnection() +{ +} + +bool QtCesterConnection::connect(QVariantList&) +{ + // We connect with each command, so this is always true + // The command itself will fail then + connected = true; + return true; +} + +void QtCesterConnection::disconnect() +{ + connected = false; +} + +bool QtCesterConnection::isConnected() const +{ + return connected; +} + +bool QtCesterConnection::copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists) +{ + debugOutput( qPrintable(QString::fromLatin1("Copy File: %1 -> %2").arg(localSource).arg(deviceDest)),0); + QFile localFile(localSource); + QFileInfo info(localSource); + if (!localFile.exists() || !localFile.open(QIODevice::ReadOnly)) { + qDebug() << "Could not open File!"; + return false; + } + + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_CREATE_FILE)) { + END_ERROR(socket, "Could not initialized command"); + } + + CreateFileOptions option; + strcpy(option.fileName, qPrintable(deviceDest)); +#ifdef Q_OS_WIN + // Copy FileTime for update verification + FILETIME creationTime, accessTime, writeTime; + HANDLE localHandle = CreateFile(localSource.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + if (localHandle != INVALID_HANDLE_VALUE) { + if (GetFileTime(localHandle, &creationTime, &accessTime, &writeTime)) { + LocalFileTimeToFileTime(&writeTime, &writeTime); + option.fileTime = writeTime; + } + CloseHandle(localHandle); + } + DWORD attributes = GetFileAttributes(localSource.utf16()); + if (attributes != -1 ) + option.fileAttributes = attributes; +#endif + option.fileSize = info.size(); + option.overwriteExisting = !failIfExists; + + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send options..."); + } + + if (!_checkResult(socket)) { + END_ERROR(socket, "Server did not accept configuration"); + } + + int bytesWritten = 0; + const int bufferSize = 1024; + QByteArray data; + while (bytesWritten < option.fileSize) { + data = localFile.read(bufferSize); + bytesWritten += data.size(); +#ifdef Q_OS_WIN + wprintf( L"%s -> %s (%d / %d) %d %%\r", localSource.utf16() , deviceDest.utf16(), + bytesWritten , option.fileSize, (100*bytesWritten)/option.fileSize ); +#endif + if (!_sendData(socket, data.constData(), data.size())) { + END_ERROR(socket, "Error during file transfer"); + } + if (!_checkResult(socket)) { + END_ERROR(socket, "Got some strange result"); + } + } +#ifdef Q_OS_WIN + wprintf( L"\n"); // We should jump to next line... +#endif + if (bytesWritten != option.fileSize) { + END_ERROR(socket, "Did not send sufficient data"); + } + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive) +{ + QTcpSocket* socket = NULL; + QFileInfo info(localSource); + if (!info.exists() || !info.isDir()) { + END_ERROR(socket, "Input directory invalid"); + } + + createDirectory(deviceDest, true); + QDir dir(localSource); + QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + foreach(QFileInfo item, list) { + QString targetName = deviceDest + QLatin1String("\\") + item.fileName(); + if (item.isDir()) { + if (recursive) { + if (!copyDirectoryToDevice(item.absoluteFilePath() , targetName, recursive)) + return false; + } + } else { + if (!copyFileToDevice(item.absoluteFilePath(), targetName)) + return false; + } + } + return true; +} + +bool QtCesterConnection::copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists) +{ + QFile targetFile(localDest); + QTcpSocket* socket = 0; + if (targetFile.exists() && failIfExists) { + END_ERROR(socket, "Local file not supposed to be overwritten"); + } + + if (!targetFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + END_ERROR(socket, "Could not open local file for writing"); + } + + if (!_initCommand(socket, COMMAND_READ_FILE)) { + END_ERROR(socket, "Could not establish connection"); + } + + ReadFileOptions option; + strcpy(option.fileName, qPrintable(deviceSource)); + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send options"); + } + + QByteArray data; + if (!_receiveData(socket, data)) { + END_ERROR(socket, "Did not receive any data"); + } + + ReadFileReply* reply = (ReadFileReply*) data.data(); + if (!reply->fileValid) { + END_ERROR(socket, "Requested file invalid"); + } + + int fileSize = reply->fileSize; + int currentSize = 0; + // ### TODO: make a little bit more error-prone + do { + _sendData(socket, COMMAND_SUCCESS, strlen(COMMAND_SUCCESS)); + _receiveData(socket, data); + currentSize += data.size(); + targetFile.write(data); + } while(currentSize < fileSize); + + _freeSocket(socket); + targetFile.close(); + return true; +} + +bool QtCesterConnection::copyDirectoryFromDevice(const QString& /*deviceSource*/ + , const QString& /*localDest*/ + , bool /*recursive*/) +{ + qDebug() << "To be implemented!! Should not be needed for autotest system"; + exit(-1); + return false; +} + +bool QtCesterConnection::copyFile(const QString &srcFile, const QString &destFile, bool failIfExists) +{ + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_COPY_FILE)) { + END_ERROR(socket, "Could not establish connection for copy"); + } + + CopyFileOptions option; + strcpy(option.from, qPrintable(srcFile)); + strcpy(option.to, qPrintable(destFile)); + option.overwriteExisting = !failIfExists; + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send copy options"); + } + + if (!_checkResult(socket)) { + END_ERROR(socket, "Copy failed"); + } + + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::copyDirectory(const QString &srcDirectory, const QString &destDirectory, + bool recursive) +{ + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_COPY_DIRECTORY)) { + END_ERROR(socket, "Could not establish connection for dir copy"); + } + + CopyDirectoryOptions option; + strcpy(option.from, qPrintable(srcDirectory)); + strcpy(option.to, qPrintable(destDirectory)); + option.recursive = recursive; + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send dir copy options"); + } + + if (!_checkResult(socket)) { + END_ERROR(socket, "Dir Copy failed"); + } + + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::deleteFile(const QString &fileName) +{ + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_DELETE_FILE)) { + END_ERROR(socket, "Could not establish connection for file deletion"); + } + + DeleteFileOptions option; + strcpy(option.fileName, qPrintable(fileName)); + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send file options"); + } + + if (!_checkResult(socket)) { + //END_ERROR(socket, "File Deletion failed"); + // This is actually not an error so ignore it. + } + + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::deleteDirectory(const QString &directory, bool recursive, bool failIfContentExists) +{ + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_DELETE_DIRECTORY)) { + END_ERROR(socket, "Could not establish connection for dir deletion"); + } + + DeleteDirectoryOptions option; + strcpy(option.dirName, qPrintable(directory)); + option.recursive = recursive; + option.failIfContentExists = failIfContentExists; + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send dir options"); + } + + if (!_checkResult(socket)) { + // we do not write an error as this will fail a lot on recursive. + END_ERROR(socket, 0); + } + + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::execute(QString program, + QString arguments, + int timeout, + int *returnValue) +{ + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_EXECUTE)) { + END_ERROR(socket, "Could not establish connection for dir deletion"); + } + + ExecuteOptions options; + strcpy(options.appName, qPrintable(program)); + QStringList argList = arguments.split(QLatin1Char(' ')); + options.argumentsCount = qMin(argList.size(), MAX_ARGUMENTS); + options.waitForFinished = true; + options.timeout = timeout; + if (!_sendData(socket, (char*) &options, sizeof(options))) { + END_ERROR(socket, "Could not send dir options"); + } + if (!_checkResult(socket)) { + END_ERROR(socket, "Did not receive an answer"); + } + + for (int i=0; i < options.argumentsCount; ++i) { + char someData[MAX_NAME_LENGTH]; + strcpy(someData, qPrintable(argList[i])); + if (!_sendData(socket, someData, MAX_NAME_LENGTH)) { + END_ERROR(socket, "Could not send argument"); + } + if (!_checkResult(socket)) { + END_ERROR(socket, "Failure in argument send"); + } + } + + // trigger the startup + if (!_sendData(socket, COMMAND_SUCCESS, strlen(COMMAND_SUCCESS))) { + END_ERROR(socket, "Could not trigger startup"); + } + + const int waitTime = 60 * 60 * 1000; + if (!socket->waitForReadyRead(waitTime)) { + END_ERROR(socket, "Process timed out"); + } + + QByteArray result = socket->readAll(); + if (result != COMMAND_SUCCESS) { + if (returnValue) + *returnValue = -1; // just some at least + END_ERROR(socket, "Application did not start or returned error"); + } + + if (returnValue) + *returnValue = 0; + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::createDirectory(const QString &path, bool deleteBefore) +{ + if (deleteBefore) + deleteDirectory(path, true, true); + + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_CREATE_DIRECTORY)) { + END_ERROR(socket, "Could not establish connection for dir creation"); + } + + CreateDirectoryOptions option; + strcpy(option.dirName, qPrintable(path)); + option.recursively = true; + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send dir options"); + } + + if (!_checkResult(socket)) { + END_ERROR(socket, "Dir creation failed"); + } + + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::timeStampForLocalFileTime(FILETIME* fTime) const +{ + if (!fTime) + return false; + + FILETIME copyTime = *fTime; + LocalFileTimeToFileTime(©Time, ©Time); + + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_TIME_STAMP)) { + END_ERROR(socket, "Could not establish time stamp connection"); + } + + if (!_sendData(socket, (char*) ©Time, sizeof(copyTime))) { + END_ERROR(socket, "Could not send stamp time"); + } + + QByteArray data; + if (!_receiveData(socket, data)) { + END_ERROR(socket, "Did not receive time stamp or connection interrupted"); + } + + copyTime = *((FILETIME*)data.data()); + if (copyTime.dwLowDateTime == -1 && copyTime.dwHighDateTime == -1) { + END_ERROR(socket, "remote Time stamp failed!"); + } + + *fTime = copyTime; + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::fileCreationTime(const QString &fileName, FILETIME* deviceCreationTime) const +{ + if (!deviceCreationTime) + return false; + + QTcpSocket* socket = 0; + if (!_initCommand(socket, COMMAND_FILE_TIME)) { + END_ERROR(socket, "Could not establish connection for file time access"); + } + + FileTimeOptions option; + strcpy(option.fileName, qPrintable(fileName)); + if (!_sendData(socket, (char*) &option, sizeof(option))) { + END_ERROR(socket, "Could not send file time name"); + } + + QByteArray data; + if (!_receiveData(socket, data)) { + END_ERROR(socket, "File Time request failed"); + } + + FILETIME* resultTime = (FILETIME*) data.data(); + if (resultTime->dwLowDateTime == -1 && resultTime->dwHighDateTime == -1) { + END_ERROR(socket, 0); + debugOutput("Could not access file time", 0); + } + + *deviceCreationTime = *resultTime; + _freeSocket(socket); + return true; +} + +bool QtCesterConnection::_createSocket(QTcpSocket*& result) const +{ + QTcpSocket* sock = new QTcpSocket(); + QByteArray ipAddress = qgetenv("DEVICE_IP"); + if (ipAddress.isEmpty()) { + qWarning("Error: You need to have DEVICE_IP set"); + exit(0); + } + sock->connectToHost(QHostAddress(QString(ipAddress)), 12145); + + if (!sock->waitForConnected()) { + qDebug() << "connection timeout..."; + result = NULL; + return false; + } + result = sock; + return true; +} + +void QtCesterConnection::_freeSocket(QTcpSocket*& sock) const +{ + if (!sock) + return; + if (sock->state() == QAbstractSocket::ConnectedState) { + sock->disconnectFromHost(); + // seems like no need to wait + //sock->waitForDisconnected(); + } + delete sock; + sock = NULL; +#ifdef Q_OS_WIN + Sleep(100); +#endif +} + +bool QtCesterConnection::_initCommand(QTcpSocket*& sock, const char* command) const +{ + QTcpSocket* socket = NULL; + if (!_createSocket(socket)) { + END_ERROR(socket, "Could not connect to server"); + } + + if (!_sendData(socket, command, strlen(command)) || + !_checkResult(socket)) { + END_ERROR(socket, "Cound not send command"); + } + sock = socket; + return true; +} + +bool QtCesterConnection::_sendData(QTcpSocket*& sock, const char* data, int dataSize) const +{ + int amount = sock->write(data, dataSize); + if (amount != dataSize) { + fprintf(stderr, "*******COULD NOT SEND ENOUGH DATA*************\n"); + } + return sock->waitForBytesWritten(); +} + +bool QtCesterConnection::_receiveData(QTcpSocket*& sock, QByteArray& data) const +{ + if (!sock->waitForReadyRead()) { + qDebug() << "did not receive any data"; + return false; + } + data = sock->readAll(); + return true; +} + +bool QtCesterConnection::_checkResult(QTcpSocket*& sock) const +{ + QByteArray response; + if (!_receiveData(sock, response) || response != COMMAND_SUCCESS) + return false; + return true; +} + diff --git a/tools/qtestlib/wince/cetcpsync/qtcesterconnection.h b/tools/qtestlib/wince/cetcpsync/qtcesterconnection.h new file mode 100644 index 0000000..d7b8393 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/qtcesterconnection.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef ACTIVESYNC_REMOTECONNECTION_H +#define ACTIVESYNC_REMOTECONNECTION_H + +#include "remoteconnection.h" + +class QTcpSocket; + +class QtCesterConnection : public AbstractRemoteConnection +{ +public: + QtCesterConnection(); + virtual ~QtCesterConnection(); + + bool connect(QVariantList &list = QVariantList()); + void disconnect(); + bool isConnected() const; + + // These functions are designed for transfer between desktop and device + // Caution: deviceDest path has to be device specific (eg. no drive letters for CE) + bool copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists = false); + bool copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive = true); + bool copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists = false); + bool copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive = true); + + bool timeStampForLocalFileTime(FILETIME*) const; + bool fileCreationTime(const QString &fileName, FILETIME*) const; + + // These functions only work on files existing on the device + bool copyFile(const QString&, const QString&, bool failIfExists = false); + bool copyDirectory(const QString&, const QString&, bool recursive = true); + bool deleteFile(const QString&); + bool deleteDirectory(const QString&, bool recursive = true, bool failIfContentExists = false); + bool createDirectory(const QString&, bool deleteBefore=false); + + bool execute(QString program, QString arguments = QString(), int timeout = -1, int *returnValue = NULL); +private: + bool _createSocket(QTcpSocket*&) const; + void _freeSocket(QTcpSocket*&) const; + bool _initCommand(QTcpSocket*&, const char*) const; + bool _sendData(QTcpSocket*&, const char* data, int dataSize) const; + bool _receiveData(QTcpSocket*&, QByteArray&) const; + bool _checkResult(QTcpSocket*&) const; + bool connected; +}; + +#endif diff --git a/tools/qtestlib/wince/cetcpsync/remoteconnection.cpp b/tools/qtestlib/wince/cetcpsync/remoteconnection.cpp new file mode 100644 index 0000000..b197c5c --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/remoteconnection.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "remoteconnection.h" + +AbstractRemoteConnection::AbstractRemoteConnection() +{ +} + +AbstractRemoteConnection::~AbstractRemoteConnection() +{ +} + +// Slow but should be ok... +bool AbstractRemoteConnection::moveFile(const QString &src, const QString &dest, bool FailIfExists) +{ + bool result = copyFile(src, dest, FailIfExists); + deleteFile(src); + return result; +} + +// Slow but should be ok... +bool AbstractRemoteConnection::moveDirectory(const QString &src, const QString &dest, bool recursive) +{ + bool result = copyDirectory(src, dest, true); + deleteDirectory(src, recursive); + return result; +} diff --git a/tools/qtestlib/wince/cetcpsync/remoteconnection.h b/tools/qtestlib/wince/cetcpsync/remoteconnection.h new file mode 100644 index 0000000..fae6f7f --- /dev/null +++ b/tools/qtestlib/wince/cetcpsync/remoteconnection.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef REMOTECONNECTION_H +#define REMOTECONNECTION_H + +#include <QtCore/QString> +#include <QtCore/QVariant> +#include <windows.h> +class AbstractRemoteConnection +{ +public: + AbstractRemoteConnection(); + virtual ~AbstractRemoteConnection(); + + virtual bool connect(QVariantList&) = 0; + virtual void disconnect() = 0; + virtual bool isConnected() const = 0; + + // These functions are designed for transfer between desktop and device + // Caution: deviceDest path has to be device specific (eg. no drive letters for CE) + virtual bool copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists = false) = 0; + virtual bool copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive = true) = 0; + virtual bool copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists = false) = 0; + virtual bool copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive = true) = 0; + + // For "intelligent deployment" we need to investigate on filetimes on the device + virtual bool timeStampForLocalFileTime(FILETIME*) const = 0; + virtual bool fileCreationTime(const QString &fileName, FILETIME*) const = 0; + + // These functions only work on files existing on the device + virtual bool copyFile(const QString&, const QString&, bool failIfExists = false) = 0; + virtual bool copyDirectory(const QString&, const QString&, bool recursive = true) = 0; + virtual bool deleteFile(const QString&) = 0; + virtual bool deleteDirectory(const QString&, bool recursive = true, bool failIfContentExists = false) = 0; + bool moveFile(const QString&, const QString&, bool FailIfExists = false); + bool moveDirectory(const QString&, const QString&, bool recursive = true); + + virtual bool createDirectory(const QString&, bool deleteBefore=false) = 0; + + virtual bool execute(QString program, QString arguments = QString(), int timeout = -1, int *returnValue = NULL) = 0; +}; + +#endif diff --git a/tools/qtestlib/wince/cetcpsyncserver/cetcpsyncserver.pro b/tools/qtestlib/wince/cetcpsyncserver/cetcpsyncserver.pro new file mode 100644 index 0000000..bd01d2d --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/cetcpsyncserver.pro @@ -0,0 +1,17 @@ +TEMPLATE = app +TARGET = cetcpsyncsvr +DEPENDPATH += . +QT -= gui +QT += network + +CONFIG += console + +HEADERS += \ + connectionmanager.h \ + commands.h \ + transfer_global.h + +SOURCES += \ + connectionmanager.cpp \ + commands.cpp \ + main.cpp diff --git a/tools/qtestlib/wince/cetcpsyncserver/commands.cpp b/tools/qtestlib/wince/cetcpsyncserver/commands.cpp new file mode 100644 index 0000000..0c4d3bc --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/commands.cpp @@ -0,0 +1,686 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "commands.h" +#include <QtCore/QDebug> +#include <QtCore/QFileInfo> +#include <QtCore/QDir> +#include <QtCore/QProcess> + +#ifdef Q_OS_WINCE +#include <windows.h> +#endif + +///////////////////////////////////////////////////// +// Abstract Command Implementation // +///////////////////////////////////////////////////// +AbstractCommand::AbstractCommand() +: m_socket(0) +{ +} + +AbstractCommand::~AbstractCommand() +{ +} + +void AbstractCommand::reportSuccess() +{ + m_socket->write(COMMAND_SUCCESS, strlen(COMMAND_SUCCESS)); + m_socket->waitForBytesWritten(); +} + +void AbstractCommand::reportError() +{ + m_socket->write(COMMAND_ERROR, strlen(COMMAND_ERROR)); + m_socket->waitForBytesWritten(); +} + +void AbstractCommand::dataReceived(QByteArray&) +{ + debugOutput(1, "AbstractCommand::dataReceived NOT SUPPOSED TO BE HERE"); +} + +void AbstractCommand::commandFinished() +{ + debugOutput(1, "AbstractCommand::commandFinished()NOT SUPPOSED TO BE HERE"); +} + +void AbstractCommand::setSocket(QTcpSocket* socket) +{ + debugOutput(0, "AbstractCommand::setSocket()"); + Q_ASSERT(socket); + m_socket = socket; + connect(m_socket, SIGNAL(readyRead()), this, SLOT(_readData())); + reportSuccess(); +} + +QTcpSocket* AbstractCommand::socket() +{ + return m_socket; +} + +void AbstractCommand::_readData() +{ + QByteArray arr = m_socket->readAll(); + dataReceived(arr); +} + +void AbstractCommand::_disconnect() +{ +} + +///////////////////////////////////////////////////// +// Create File Command Implementation // +///////////////////////////////////////////////////// +CreateFileCommand::CreateFileCommand() +: m_dataCount(0) +{ + debugOutput(0, "CreateFileCommand::CreateFileCommand"); + m_options.fileSize= -1; +} + +CreateFileCommand::~CreateFileCommand() +{ + debugOutput(0, "CreateFileCommand::~CreateFileCommand"); + if (m_file.isOpen()) { + fprintf(stderr, "****************FILE IS STILL OPENED AND HAVENT FINISHED WRITING**********************\n"); + fprintf(stderr, "Current: %d Expected: %d\n", m_dataCount , m_options.fileSize); + m_file.close(); + } +} + +void CreateFileCommand::dataReceived(QByteArray &data) +{ + bool successful = true; + // If we haven't received the options yet + if (m_options.fileSize == -1) { + CreateFileOptions* opt = (CreateFileOptions*) data.data(); + memcpy(&m_options , opt , sizeof(CreateFileOptions)); + + if (QFileInfo(QString::fromLatin1(m_options.fileName)).exists()) { + if (m_options.overwriteExisting) { +#ifdef Q_OS_WINCE + SetFileAttributes(QFileInfo(m_options.fileName).absoluteFilePath().utf16(), FILE_ATTRIBUTE_NORMAL); +#endif + QFile::remove(m_options.fileName); + } else + successful = false; + } + m_file.setFileName(QString::fromLatin1(m_options.fileName)); + if (!m_file.open(QIODevice::WriteOnly)) + successful = false; + else + debugOutput(3, QString::fromLatin1("Creating file: %1").arg(m_options.fileName)); + } else { // write buffer on disc + if (!m_file.isOpen()) + return; + m_file.write(data); + m_dataCount += data.size(); + if (m_dataCount >= m_options.fileSize) { + // We do not care about more data than announced + m_file.close(); + } + } + + if (successful) + reportSuccess(); + else + reportError(); +} + +void CreateFileCommand::commandFinished() +{ + debugOutput(0, "CreateFileCommand::commandFinished"); +#ifdef Q_OS_WIN + // We need to set the file attributes for intelligent time comparisons + QString tmpFile = QString::fromLatin1(m_options.fileName); + HANDLE handle = CreateFile(tmpFile.utf16(), GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (handle != INVALID_HANDLE_VALUE) { + SetFileTime(handle, &(m_options.fileTime), NULL, NULL); + CloseHandle(handle); + } + SetFileAttributes(tmpFile.utf16(), m_options.fileAttributes); +#endif +} + +///////////////////////////////////////////////////// +// Create Directory Command Implementation // +///////////////////////////////////////////////////// +CreateDirectoryCommand::CreateDirectoryCommand() + : AbstractCommand() +{ + debugOutput(0, "CreateDirectoryCommand::CreateDirectoryCommand"); +} + +CreateDirectoryCommand::~CreateDirectoryCommand() +{ + debugOutput(0, "CreateDirectoryCommand::~CreateDirectoryCommand()"); +} + +void CreateDirectoryCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "CreateDirectoryCommand::dataReceived()"); + CreateDirectoryOptions* options = (CreateDirectoryOptions*) data.data(); + debugOutput(3, QString::fromLatin1("Creating directory: %1").arg(options->dirName)); + bool success = true; + QDir dir; + if (options->recursively) + success = dir.mkpath(options->dirName); + else + success = dir.mkdir(options->dirName); + + if (success) + reportSuccess(); + else + reportError(); +} + +void CreateDirectoryCommand::commandFinished() +{ + debugOutput(0, "CreateDirectoryCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Copy File Command Implementation // +///////////////////////////////////////////////////// +CopyFileCommand::CopyFileCommand() + : AbstractCommand() +{ + debugOutput(0, "CopyFileCommand::CopyFileCommand()"); +} + +CopyFileCommand::~CopyFileCommand() +{ + debugOutput(0, "CopyFileCommand::~CopyFileCommand()"); +} + +void CopyFileCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "CopyFileCommand::dataReceived()"); + CopyFileOptions* options = (CopyFileOptions*) data.data(); + debugOutput(3, QString::fromLatin1("Copy File: %1 -> %2").arg(options->from).arg(options->to)); + bool success = true; + if (QFileInfo(options->to).exists()) { + if (options->overwriteExisting) + QFile::remove(options->to); + else + success = false; + } + if (success) + if (!QFile::copy(options->from , options->to)) + success = false; + + if (success) + reportSuccess(); + else + reportError(); +} + +void CopyFileCommand::commandFinished() +{ + debugOutput(0, "CopyFileCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Copy Directory Command Implementation // +///////////////////////////////////////////////////// +CopyDirectoryCommand::CopyDirectoryCommand() + : AbstractCommand() +{ + debugOutput(0, "CopyDirectoryCommand::CopyDirectoryCommand()"); +} + +CopyDirectoryCommand::~CopyDirectoryCommand() +{ + debugOutput(0, "CopyDirectoryCommand::~CopyDirectoryCommand()"); +} + +void CopyDirectoryCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "CopyDirectoryCommand::dataReceived()"); + CopyDirectoryOptions* options = (CopyDirectoryOptions*) data.data(); + debugOutput(3, QString::fromLatin1("Copy Directory: %1 %2").arg(options->from).arg(options->to)); + if (copyDir(QLatin1String(options->from) , QLatin1String(options->to) , options->recursive)) + reportSuccess(); + else + reportError(); +} + +void CopyDirectoryCommand::commandFinished() +{ + debugOutput(0, "CopyDirectoryCommand::commandFinished()"); +} + +bool CopyDirectoryCommand::copyDir(const QString &from, const QString &to, bool recursive) +{ + QDir().mkpath(to); + QDir sourceDir(from); + QDir destDir(to); + QStringList entries = sourceDir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); + foreach (QString item , entries) { + QString itemFrom = sourceDir.absoluteFilePath(item); + QString itemTo = destDir.absoluteFilePath(item); + if (QFileInfo(item).isDir()) { + if (recursive && !copyDir(itemFrom, itemTo, recursive)) + return false; + } else { + if (!QFile::copy(itemFrom, itemTo)) + return false; + } + } + return true; +} + +///////////////////////////////////////////////////// +// Delete File Command Implementation // +///////////////////////////////////////////////////// +DeleteFileCommand::DeleteFileCommand() + : AbstractCommand() +{ + debugOutput(0, "DeleteFileCommand::DeleteFileCommand()"); +} + +DeleteFileCommand::~DeleteFileCommand() +{ + debugOutput(0, "DeleteFileCommand::~DeleteFileCommand()"); +} + +void DeleteFileCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "DeleteFileCommand::dataReceived()"); + DeleteFileOptions* options = (DeleteFileOptions*) data.data(); + debugOutput(3, QString::fromLatin1("Delete File: %1").arg(options->fileName)); + bool success = true; + QFile file(options->fileName); + if (file.exists()) { +#ifdef Q_OS_WINCE + SetFileAttributes(QFileInfo(options->fileName).absoluteFilePath().utf16(), FILE_ATTRIBUTE_NORMAL); +#endif + success = file.remove(); + } else + success = false; + + if (success) + reportSuccess(); + else + reportError(); +} + +void DeleteFileCommand::commandFinished() +{ + debugOutput(0, "DeleteFileCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Delete Directory Command Implementation // +///////////////////////////////////////////////////// +DeleteDirectoryCommand::DeleteDirectoryCommand() + : AbstractCommand() +{ + debugOutput(0, "DeleteDirectoryCommand::DeleteDirectoryCommand()"); +} + +DeleteDirectoryCommand::~DeleteDirectoryCommand() +{ + debugOutput(0, "DeleteDirectoryCommand::~DeleteDirectoryCommand()"); +} + +void DeleteDirectoryCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "DeleteDirectoryCommand::dataReceived()"); + DeleteDirectoryOptions* options = (DeleteDirectoryOptions*) data.data(); + debugOutput(3, QString::fromLatin1("Delete directory: %1").arg(options->dirName)); + if (deleteDirectory(QLatin1String(options->dirName), options->recursive, options->failIfContentExists)) + reportSuccess(); + else + reportError(); +} + +void DeleteDirectoryCommand::commandFinished() +{ + debugOutput(0, "DeleteDirectoryCommand::commandFinished()"); +} + +bool DeleteDirectoryCommand::deleteDirectory(const QString &dirName, bool recursive, bool failIfContentExists) +{ + QDir dir(dirName); + if (!dir.exists()) + return false; + + QStringList itemList = dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); + if (itemList.size() > 0 && failIfContentExists) + return false; + + foreach (QString item, itemList) { + QString itemName = dir.absoluteFilePath(item); + if (QFileInfo(itemName).isDir()) { + if (recursive && !deleteDirectory(itemName, recursive, failIfContentExists)) + return false; + } else { + if (!dir.remove(item)) + return false; + } + } + QString lastName = dir.dirName(); + dir.cdUp(); + dir.rmpath(lastName); + return true; +} + +///////////////////////////////////////////////////// +// Execute Command Implementation // +///////////////////////////////////////////////////// +ExecuteCommand::ExecuteCommand() + : AbstractCommand() + , m_argumentCount(0) + , m_timeout(-1) +{ + debugOutput(0, "ExecuteCommand::ExecuteCommand()"); +} + +ExecuteCommand::~ExecuteCommand() +{ + debugOutput(0, "ExecuteCommand::~ExecuteCommand()"); +} + +void ExecuteCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "ExecuteCommand::dataReceived()"); + + if (m_argumentCount == 0) { + ExecuteOptions* options = (ExecuteOptions*) data.data(); + if (!QFileInfo(options->appName).exists()) { + debugOutput(1, "Error execute: application does not exist"); + reportError(); + return; + } + + m_program = QLatin1String(options->appName); + m_argumentCount = options->argumentsCount; + m_waitFinished = options->waitForFinished; + m_timeout = options->timeout; + if (m_argumentCount == 0) + m_argumentCount = -1; // to trigger startup on next receive + reportSuccess(); + } else if (m_arguments.size() < m_argumentCount) { + m_arguments += data; + reportSuccess(); + } else { // do the execution + if (data == COMMAND_SUCCESS) + _doExecute(); + } +} + +void ExecuteCommand::_doExecute() +{ + debugOutput(0, "ExecuteCommand::_doExecute()"); + debugOutput(3, QString::fromLatin1("Execute: %1 %2").arg(m_program).arg(m_arguments.join(" "))); + if (m_waitFinished) { + QProcess process; + process.start(m_program, m_arguments); + if (process.waitForFinished(m_timeout) == false || process.exitCode() < 0) + reportError(); + else + reportSuccess(); + } else { + if (QProcess::startDetached(m_program, m_arguments)) + reportSuccess(); + else + reportError(); + } +} +void ExecuteCommand::commandFinished() +{ + debugOutput(0,"ExecuteCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Read File Implementation // +///////////////////////////////////////////////////// +ReadFileCommand::ReadFileCommand() + : AbstractCommand() + , m_currentPos(0) +{ + debugOutput(0, "ReadFileCommand::ReadFileCommand()"); + m_fileName.clear(); +} + +ReadFileCommand::~ReadFileCommand() +{ + debugOutput(0, "ReadFileCommand::~ReadFileCommand()"); + if (m_file.isOpen()) + m_file.close(); +} + +void ReadFileCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "ReadFileCommand::dataReceived()"); + if (m_fileName.isEmpty()) { + ReadFileOptions* option = (ReadFileOptions*) data.data(); + m_fileName = QLatin1String(option->fileName); + QFileInfo info(m_fileName); + m_file.setFileName(m_fileName); + ReadFileReply reply; + if (!info.exists() || !info.isFile() || !m_file.open(QIODevice::ReadOnly)) + reply.fileValid = false; + else + reply.fileValid = true; + reply.fileSize = info.size(); + m_fileSize = reply.fileSize; + socket()->write((char*) &reply, sizeof(reply)); + debugOutput(3, QString::fromLatin1("Reading file: %1").arg(m_fileName)); + } else { + QTcpSocket* sock = socket(); // design failure??? + if (data != COMMAND_SUCCESS || m_currentPos >= m_fileSize) { + sock->disconnectFromHost(); + return; + } + const int bufferSize = 1024; + QByteArray buffer = m_file.read(bufferSize); + m_currentPos += buffer.size(); + sock->write(buffer); + sock->waitForBytesWritten(); + } +} + +void ReadFileCommand::commandFinished() +{ + debugOutput(0, "ReadFileCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Read Directory Implementation // +///////////////////////////////////////////////////// +ReadDirectoryCommand::ReadDirectoryCommand() + : AbstractCommand() + , m_iterator(0) +{ + debugOutput(0, "ReadDirectoryCommand::ReadDirectoryCommand"); + m_dirName.clear(); +} + +ReadDirectoryCommand::~ReadDirectoryCommand() +{ + debugOutput(0, "ReadDirectoryCommand::~ReadDirectoryCommand()"); + delete m_iterator; +} + +void ReadDirectoryCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "ReadDirectoryCommand::dataReceived()"); + QTcpSocket* sock = socket(); + if (m_dirName.isEmpty()) { + ReadDirectoryOptions* option = (ReadDirectoryOptions*) data.data(); + QFileInfo info(QLatin1String(option->dirName)); + debugOutput(3, QString::fromLatin1("Reading Directory entries: %1").arg(option->dirName)); + ReadDirectoryReply reply; + if (!info.exists() || !info.isDir()) { + reply.itemCount = -1; + reply.entryValid = false; + } else { + m_dirName = QLatin1String(option->dirName); + m_dir.setPath(m_dirName); + m_iterator = new QDirIterator(m_dir); + reply.itemCount = m_dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot).size(); + reply.entryValid = true; + } + sock->write((char*) &reply, sizeof(reply)); + sock->waitForBytesWritten(); + } else { + if (data != COMMAND_SUCCESS) { + qDebug() << "Something went wrong in the meantime"; + return; + } + ReadDirectoryItem reply; + if (m_iterator->hasNext()) { + m_iterator->next(); + QFileInfo info = m_iterator->fileInfo(); + strcpy(reply.name, qPrintable(info.absoluteFilePath())); + reply.isDirectory = info.isDir(); + if (!reply.isDirectory) + reply.size = info.size(); + } + reply.hasMore = m_iterator->hasNext(); + sock->write((char*) &reply, sizeof(reply)); + sock->waitForBytesWritten(); + } +} + +void ReadDirectoryCommand::commandFinished() +{ + debugOutput(0, "ReadDirectoryCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// File Time Implementation // +///////////////////////////////////////////////////// +FileTimeCommand::FileTimeCommand() + : AbstractCommand() +{ + debugOutput(0, "FileTimeCommand::FileTimeCommand()"); +} + +FileTimeCommand::~FileTimeCommand() +{ + debugOutput(0, "FileTimeCommand::~FileTimeCommand()"); +} + +void FileTimeCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "FileTimeCommand::dataReceived()"); + FileTimeOptions* option = (FileTimeOptions*) data.data(); + + FILETIME resultTime; + resultTime.dwLowDateTime = -1; + resultTime.dwHighDateTime = -1; + +#ifdef Q_OS_WIN + QString fileName = QLatin1String(option->fileName); + HANDLE deviceHandle = CreateFile(fileName.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + debugOutput(3, QString::fromLatin1("Asking FileTime: %1").arg(fileName)); + if (deviceHandle != INVALID_HANDLE_VALUE) { + FILETIME deviceCreationTime; + if (GetFileTime(deviceHandle, &deviceCreationTime, NULL, NULL)) { + resultTime = deviceCreationTime; + } + CloseHandle(deviceHandle); + } +#endif + QTcpSocket* sock = socket(); + sock->write((char*) &resultTime, sizeof(resultTime)); + sock->waitForBytesWritten(); +} + +void FileTimeCommand::commandFinished() +{ + debugOutput(0, "FileTimeCommand::commandFinished()"); +} + +///////////////////////////////////////////////////// +// Time Stamp Implementation // +///////////////////////////////////////////////////// +TimeStampCommand::TimeStampCommand() + : AbstractCommand() +{ + debugOutput(0, "TimeStampCommand::TimeStampCommand()"); +} + +TimeStampCommand::~TimeStampCommand() +{ + debugOutput(0, "TimeStampCommand::~TimeStampCommand()"); +} + +void TimeStampCommand::dataReceived(QByteArray &data) +{ + debugOutput(0, "TimeStampCommand::dataReceived()"); + FILETIME resultTime; + resultTime.dwLowDateTime = -1; + resultTime.dwHighDateTime = -1; + +#ifdef Q_OS_WIN + FILETIME stampTime = *((FILETIME*)data.data()); + + QString tmpFile = QString::fromLatin1("\\qt_tmp_ftime_convert"); + HANDLE remoteHandle = CreateFile(tmpFile.utf16(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (remoteHandle != INVALID_HANDLE_VALUE) { + if (!SetFileTime(remoteHandle, &stampTime, NULL, NULL)) { + CloseHandle(remoteHandle); + } else { + CloseHandle(remoteHandle); + remoteHandle = CreateFile(tmpFile.utf16(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (remoteHandle != INVALID_HANDLE_VALUE) { + if (GetFileTime(remoteHandle, &stampTime, NULL, NULL)) + resultTime = stampTime; + CloseHandle(remoteHandle); + DeleteFile(tmpFile.utf16()); + } + } + } + debugOutput(3, QString::fromLatin1("Asking TimeStamp")); +#endif + QTcpSocket* sock = socket(); + sock->write((char*) &resultTime, sizeof(resultTime)); + sock->waitForBytesWritten(); +} + +void TimeStampCommand::commandFinished() +{ + debugOutput(0, "TimeStampCommand::commandFinished()"); +} diff --git a/tools/qtestlib/wince/cetcpsyncserver/commands.h b/tools/qtestlib/wince/cetcpsyncserver/commands.h new file mode 100644 index 0000000..356c1aa --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/commands.h @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef COMMANDS_INCL +#define COMMANDS_INCL + +#include "transfer_global.h" + +#include <QtNetwork/QTcpSocket> +#include <QtCore/QString> +#include <QtCore/QFile> +#include <QtCore/QDir> +#include <QtCore/QDirIterator> +#include <windows.h> + +// debug output +#define DEBUG_LEVEL 2 +inline void debugOutput(int level, const char* text) +{ + if (level >= DEBUG_LEVEL) + qDebug() << text; +} + +inline void debugOutput(int level, const QString &text) +{ + if (level >= DEBUG_LEVEL) + qDebug() << text; +} +// Basic abtract command class +class AbstractCommand : public QObject +{ + Q_OBJECT +public: + AbstractCommand(); + virtual ~AbstractCommand(); + + void setSocket(QTcpSocket*); + QTcpSocket* socket(); + + void reportSuccess(); + void reportError(); + +public slots: + virtual void dataReceived(QByteArray&); + virtual void commandFinished(); + +private slots: + void _readData(); + void _disconnect(); + +private: + QTcpSocket* m_socket; +}; + +// File Creation class +class CreateFileCommand : public AbstractCommand +{ + Q_OBJECT +public: + CreateFileCommand(); + ~CreateFileCommand(); + +public slots: + void dataReceived(QByteArray&); + void commandFinished(); + +private: + CreateFileOptions m_options; + QFile m_file; + int m_dataCount; +}; + +inline AbstractCommand* instCreateFile() { return new CreateFileCommand(); } + +// Directory Creation class +class CreateDirectoryCommand : public AbstractCommand +{ + Q_OBJECT +public: + CreateDirectoryCommand(); + ~CreateDirectoryCommand(); + +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +}; +inline AbstractCommand* instCreateDirectory() { return new CreateDirectoryCommand(); } + +// File copy class +class CopyFileCommand : public AbstractCommand +{ + Q_OBJECT +public: + CopyFileCommand(); + ~CopyFileCommand(); + +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +}; +inline AbstractCommand* instCopyFile() { return new CopyFileCommand(); } + +// Copy directory class +class CopyDirectoryCommand : public AbstractCommand +{ + Q_OBJECT +public: + CopyDirectoryCommand(); + ~CopyDirectoryCommand(); + +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +private: + bool copyDir(const QString &from, const QString &to, bool recursive); +}; +inline AbstractCommand* instCopyDirectory() { return new CopyDirectoryCommand(); } + +// Delete File class +class DeleteFileCommand : public AbstractCommand +{ + Q_OBJECT +public: + DeleteFileCommand(); + ~DeleteFileCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +}; +inline AbstractCommand* instDeleteFile() { return new DeleteFileCommand(); } + +// Delete Directory class +class DeleteDirectoryCommand : public AbstractCommand +{ + Q_OBJECT +public: + DeleteDirectoryCommand(); + ~DeleteDirectoryCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +private: + bool deleteDirectory(const QString &dirName, bool recursive, bool failIfContentExists); +}; +inline AbstractCommand* instDeleteDirectory() { return new DeleteDirectoryCommand(); } + +// Execute application class +class ExecuteCommand : public AbstractCommand +{ + Q_OBJECT +public: + ExecuteCommand(); + ~ExecuteCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +private: + void _doExecute(); + QString m_program; + QStringList m_arguments; + int m_argumentCount; + bool m_waitFinished; + int m_timeout; +}; +inline AbstractCommand* instExecution() { return new ExecuteCommand(); } + +// Read File class +class ReadFileCommand : public AbstractCommand +{ + Q_OBJECT +public: + ReadFileCommand(); + ~ReadFileCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +private: + QString m_fileName; + QFile m_file; + qint64 m_currentPos; + qint64 m_fileSize; +}; +inline AbstractCommand* instReadFile() { return new ReadFileCommand(); } + +// Read Directory class +class ReadDirectoryCommand : public AbstractCommand +{ + Q_OBJECT +public: + ReadDirectoryCommand(); + ~ReadDirectoryCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +private: + QString m_dirName; + QDir m_dir; + QDirIterator* m_iterator; +}; +inline AbstractCommand* instReadDirectory() { return new ReadDirectoryCommand(); } + +// Read File Time class +class FileTimeCommand : public AbstractCommand +{ + Q_OBJECT +public: + FileTimeCommand(); + ~FileTimeCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +}; +inline AbstractCommand* instFileTime() { return new FileTimeCommand(); } + +// Time stamp class +class TimeStampCommand : public AbstractCommand +{ + Q_OBJECT +public: + TimeStampCommand(); + ~TimeStampCommand(); +public slots: + void dataReceived(QByteArray&); + void commandFinished(); +}; +inline AbstractCommand* instTimeStamp() { return new TimeStampCommand(); } + +// Access part +typedef AbstractCommand* (*instantiator)(); + +struct CommandInfo +{ + CommandInfo(const QString &name, instantiator func) : commandName(name) , commandFunc(func) { } + QString commandName; + instantiator commandFunc; +}; + +inline QList<CommandInfo> availableCommands() +{ + QList<CommandInfo> list; + list.append(CommandInfo(QLatin1String(COMMAND_CREATE_FILE), instCreateFile)); + list.append(CommandInfo(QLatin1String(COMMAND_CREATE_DIRECTORY), instCreateDirectory)); + list.append(CommandInfo(QLatin1String(COMMAND_COPY_FILE), instCopyFile)); + list.append(CommandInfo(QLatin1String(COMMAND_COPY_DIRECTORY), instCopyDirectory)); + list.append(CommandInfo(QLatin1String(COMMAND_DELETE_FILE), instDeleteFile)); + list.append(CommandInfo(QLatin1String(COMMAND_DELETE_DIRECTORY), instDeleteDirectory)); + list.append(CommandInfo(QLatin1String(COMMAND_EXECUTE), instExecution)); + list.append(CommandInfo(QLatin1String(COMMAND_READ_FILE), instReadFile)); + list.append(CommandInfo(QLatin1String(COMMAND_READ_DIRECTORY), instReadDirectory)); + list.append(CommandInfo(QLatin1String(COMMAND_FILE_TIME), instFileTime)); + list.append(CommandInfo(QLatin1String(COMMAND_TIME_STAMP), instTimeStamp)); + return list; +} + +#endif diff --git a/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.cpp b/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.cpp new file mode 100644 index 0000000..901cd12 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "connectionmanager.h" +#include "commands.h" +#include <QtCore/QDebug> + +ConnectionManager::ConnectionManager() + : QObject() + , m_server(0) +{ + debugOutput(0, "ConnectionManager::ConnectionManager()"); +} + +ConnectionManager::~ConnectionManager() +{ + debugOutput(0, "ConnectionManager::~ConnectionManager()"); + cleanUp(); +} + +bool ConnectionManager::init() +{ + debugOutput(0, "ConnectionManager::init()"); + debugOutput(3, "Initializing server..."); + cleanUp(); + m_server = new QTcpServer(this); + connect(m_server, SIGNAL(newConnection()), this, SLOT(newConnection())); + bool result = m_server->listen(QHostAddress::Any, SERVER_PORT); + if (!result) + debugOutput(3, QString::fromLatin1(" Error: Server start failed:") + m_server->errorString()); + debugOutput(3, " Waiting for action"); + return result; +} + +void ConnectionManager::cleanUp() +{ + debugOutput(0, "ConnectionManager::cleanUp()"); + + if (m_server) { + debugOutput(1, "Removing server instance..."); + disconnect(m_server, SIGNAL(newConnection()), this, SLOT(newConnection())); + delete m_server; + m_server = 0; + } +} + +void ConnectionManager::newConnection() +{ + debugOutput(0, "ConnectionManager::newConnection()"); + + QTcpSocket* connection = m_server->nextPendingConnection(); + if (!connection) { + debugOutput(3, "Received connection has empty socket"); + return; + } + debugOutput(0, QString::fromLatin1(" received a connection: %1").arg((int) connection)); + new Connection(connection); +} + +Connection::Connection(QTcpSocket *socket) + : QObject() + , m_connection(socket) + , m_command(0) +{ + connect(m_connection, SIGNAL(readyRead()), this, SLOT(receiveCommand())); + connect(m_connection, SIGNAL(disconnected()), this, SLOT(closedConnection())); +} + +Connection::~Connection() +{ + if (m_command) { + m_command->commandFinished(); + delete m_command; + m_command = 0; + } + delete m_connection; +} + +void Connection::receiveCommand() +{ + QByteArray arr = m_connection->readAll(); + debugOutput(1, QString::fromLatin1("Command received: ") + (arr)); + QList<CommandInfo> commands = availableCommands(); + for(QList<CommandInfo>::iterator it = commands.begin(); it != commands.end(); ++it) { + if (it->commandName == QString::fromLatin1(arr)) { + debugOutput(1, "Found command in list"); + disconnect(m_connection, SIGNAL(readyRead()), this, SLOT(receiveCommand())); + AbstractCommand* command = (*it).commandFunc(); + command->setSocket(m_connection); + m_command = command; + return; + } + } + debugOutput(2, QString::fromLatin1("Unknown command received: ") + (arr)); +} + +void Connection::closedConnection() +{ + debugOutput(0, "connection being closed..."); + this->deleteLater(); +} diff --git a/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.h b/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.h new file mode 100644 index 0000000..21183ac --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/connectionmanager.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef CONNECTION_MANAGER_INCL +#define CONNECTION_MANAGER_INCL + +#include "transfer_global.h" +#include "commands.h" + +#include <QtNetwork/QTcpServer> +#include <QtNetwork/QTcpSocket> + +class Connection : public QObject +{ + Q_OBJECT +public: + Connection(QTcpSocket* socket); + ~Connection(); + +public slots: + void receiveCommand(); + void closedConnection(); + +private: + QTcpSocket* m_connection; + AbstractCommand* m_command; +}; + +class ConnectionManager : public QObject +{ + Q_OBJECT +public: + ConnectionManager(); + ~ConnectionManager(); + + bool init(); + +public slots: + void cleanUp(); + void newConnection(); + +private: + QTcpServer* m_server; +}; + +#endif diff --git a/tools/qtestlib/wince/cetcpsyncserver/main.cpp b/tools/qtestlib/wince/cetcpsyncserver/main.cpp new file mode 100644 index 0000000..19d38ea --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/main.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "connectionmanager.h" + +#include <QtCore> +#include <QtNetwork> + +void messageOutput(QtMsgType type, const char *msg) +{ + switch(type) { + case QtDebugMsg: fprintf(stderr, "Debug: %s\n", msg); break; + case QtWarningMsg: fprintf(stderr, "Warning: %s\n", msg); break; + default: fprintf(stderr, "Some Msg: %s\n", msg); break; + } +} + +int main(int argc, char **argv) +{ + qInstallMsgHandler(messageOutput); + + QCoreApplication app(argc, argv); + ConnectionManager manager; + manager.init(); + return app.exec(); +} diff --git a/tools/qtestlib/wince/cetcpsyncserver/transfer_global.h b/tools/qtestlib/wince/cetcpsyncserver/transfer_global.h new file mode 100644 index 0000000..5b6ff23 --- /dev/null +++ b/tools/qtestlib/wince/cetcpsyncserver/transfer_global.h @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef TRANSFER_GLOBAL_H +#define TRANSFER_GLOBAL_H + +#include <QtCore/qglobal.h> +#ifdef Q_OS_WIN +#include <windows.h> +#endif + +#define SERVER_PORT 12145 + +#define MAX_NAME_LENGTH 512 +#define MAX_ARGUMENTS 10 + +// Defines for commands sent/received +#define COMMAND_CREATE_FILE "CREATEFILE" +#define COMMAND_CREATE_DIRECTORY "CREATEDIR" +#define COMMAND_COPY_FILE "COPYFILE" +#define COMMAND_COPY_DIRECTORY "COPYDIR" +#define COMMAND_DELETE_FILE "DELETEFILE" +#define COMMAND_DELETE_DIRECTORY "DELETEDIR" +#define COMMAND_EXECUTE "EXECUTE" +#define COMMAND_QUIT_SERVER "QUIT" +#define COMMAND_FILE_TIME "FILETIME" +#define COMMAND_TIME_STAMP "TIMESTAMP" + +// Report back commands +#define COMMAND_SUCCESS "SUCCESS" +#define COMMAND_ERROR "ERROR" + +// Defines for commands that send data back to requester +#define COMMAND_READ_FILE "READFILE" +#define COMMAND_READ_DIRECTORY "READDIR" + +#include <QtCore/qglobal.h> +// Option-Structures for commands + +struct CreateFileOptions +{ + char fileName[MAX_NAME_LENGTH]; +#ifdef Q_OS_WIN + FILETIME fileTime; + DWORD fileAttributes; +#endif + int fileSize; + bool overwriteExisting; +}; + +struct CreateDirectoryOptions +{ + char dirName[MAX_NAME_LENGTH]; + bool recursively; // in case of \foo\bar create \foo if it does not exist +}; + +struct CopyFileOptions +{ + char from[MAX_NAME_LENGTH]; + char to[MAX_NAME_LENGTH]; + bool overwriteExisting; +}; + +struct CopyDirectoryOptions +{ + char from[MAX_NAME_LENGTH]; + char to[MAX_NAME_LENGTH]; + bool recursive; +}; + +struct DeleteFileOptions +{ + char fileName[MAX_NAME_LENGTH]; +}; + +struct DeleteDirectoryOptions +{ + char dirName[MAX_NAME_LENGTH]; + bool recursive; + bool failIfContentExists; +}; + +struct ExecuteOptions +{ + char appName[MAX_NAME_LENGTH]; + int argumentsCount; + bool waitForFinished; + int timeout; +}; + +struct ReadFileOptions +{ + char fileName[MAX_NAME_LENGTH]; +}; + +struct ReadFileReply +{ + qint64 fileSize; + bool fileValid; +}; + +struct ReadDirectoryOptions +{ + char dirName[MAX_NAME_LENGTH]; +}; + +struct ReadDirectoryItem +{ + char name[MAX_NAME_LENGTH]; + qint64 size; + bool isDirectory; + bool hasMore; +}; + +#define FileTimeOptions ReadFileOptions + +struct ReadDirectoryReply +{ + bool entryValid; + int itemCount; // might change during iteration +}; +#endif diff --git a/tools/qtestlib/wince/cetest/activesyncconnection.cpp b/tools/qtestlib/wince/cetest/activesyncconnection.cpp index f047b79..1080477 100644 --- a/tools/qtestlib/wince/cetest/activesyncconnection.cpp +++ b/tools/qtestlib/wince/cetest/activesyncconnection.cpp @@ -113,6 +113,8 @@ bool ActiveSyncConnection::copyFileToDevice(const QString &localSource, const QS CeCloseHandle(deviceHandle); return true; } + } else { + qWarning("Could not open %s: %s", qPrintable(localSource), qPrintable(file.errorString())); } return false; } @@ -120,7 +122,7 @@ bool ActiveSyncConnection::copyFileToDevice(const QString &localSource, const QS deleteFile(deviceDest); HANDLE deviceHandle = CeCreateFile(deviceDest.utf16(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (deviceHandle == INVALID_HANDLE_VALUE) { - debugOutput(QString::fromLatin1(" Could not create target file"), 2); + qWarning("Could not create %s: %s", qPrintable(deviceDest), strwinerror(CeGetLastError()).constData()); return false; } @@ -144,7 +146,7 @@ bool ActiveSyncConnection::copyFileToDevice(const QString &localSource, const QS if (toWrite == 0) break; if (!CeWriteFile(deviceHandle, data.data() , toWrite, &written, NULL)) { - debugOutput(QString::fromLatin1(" Could not write File"), 2); + qWarning("Could not write to %s: %s", qPrintable(deviceDest), strwinerror(CeGetLastError()).constData()); return false; } currentPos += written; @@ -270,8 +272,8 @@ bool ActiveSyncConnection::copyDirectoryFromDevice(const QString &deviceSource, } do { - QString srcFile = deviceSource + "\\" + QString::fromUtf16(data.cFileName); - QString destFile = localDest + "\\" + QString::fromUtf16(data.cFileName); + QString srcFile = deviceSource + "\\" + QString::fromWCharArray(data.cFileName); + QString destFile = localDest + "\\" + QString::fromWCharArray(data.cFileName); if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if (recursive && !copyDirectoryFromDevice(srcFile, destFile, recursive)) { wprintf(L"Copy of subdirectory(%s) failed\n", srcFile.utf16()); @@ -306,8 +308,8 @@ bool ActiveSyncConnection::copyDirectory(const QString &srcDirectory, const QStr } do { - QString srcFile = srcDirectory + "\\" + QString::fromUtf16(data.cFileName); - QString destFile = destDirectory + "\\" + QString::fromUtf16(data.cFileName); + QString srcFile = srcDirectory + "\\" + QString::fromWCharArray(data.cFileName); + QString destFile = destDirectory + "\\" + QString::fromWCharArray(data.cFileName); if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if (recursive && !copyDirectory(srcFile, destFile, recursive)) { wprintf(L"Copy of subdirectory(%s) failed\n", srcFile.utf16()); @@ -341,7 +343,7 @@ bool ActiveSyncConnection::deleteDirectory(const QString &directory, bool recurs return false; do { - QString FileName = directory + "\\" + QString::fromUtf16(FindFileData.cFileName); + QString FileName = directory + "\\" + QString::fromWCharArray(FindFileData.cFileName); if((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { if (recursive) if (!deleteDirectory(FileName, recursive, failIfContentExists)) @@ -380,12 +382,17 @@ bool ActiveSyncConnection::execute(QString program, QString arguments, int timeo BYTE* output; IRAPIStream *stream; int returned = 0; + DWORD error = 0; HRESULT res = CeRapiInvoke(dllLocation.utf16(), functionName.utf16(), 0, 0, &outputSize, &output, &stream, 0); if (S_OK != res) { - if (S_OK != CeGetLastError()) - debugOutput(QString::fromLatin1("Error: Could not invoke method on QtRemote"),1); - else - debugOutput(QString::fromLatin1("Error: QtRemote return unexpectedly with error Code %1").arg(res), 1); + DWORD ce_error = CeGetLastError(); + if (S_OK != ce_error) { + qWarning("Error invoking %s on %s: %s", qPrintable(functionName), + qPrintable(dllLocation), strwinerror(ce_error).constData()); + } else { + qWarning("Error: %s on %s unexpectedly returned %d", qPrintable(functionName), + qPrintable(dllLocation), res); + } } else { DWORD written; int strSize = program.length(); @@ -414,9 +421,18 @@ bool ActiveSyncConnection::execute(QString program, QString arguments, int timeo if (S_OK != stream->Read(&returned, sizeof(returned), &written)) { qWarning(" Could not access return value of process"); } - result = true; - } + if (S_OK != stream->Read(&error, sizeof(error), &written)) { + qWarning(" Could not access error code"); + } + if (error) { + qWarning("Error on target: %s", strwinerror(error).constData()); + result = false; + } + else { + result = true; + } + } if (returnValue) *returnValue = returned; diff --git a/tools/qtestlib/wince/cetest/bootstrapped.pri b/tools/qtestlib/wince/cetest/bootstrapped.pri index 39f24c2..a31374e 100644 --- a/tools/qtestlib/wince/cetest/bootstrapped.pri +++ b/tools/qtestlib/wince/cetest/bootstrapped.pri @@ -35,4 +35,5 @@ SOURCES += \ $$QT_SOURCE_TREE/src/corelib/tools/qmap.cpp \ $$QT_SOURCE_TREE/src/corelib/tools/qbitarray.cpp \ $$QT_SOURCE_TREE/src/corelib/kernel/qmetatype.cpp \ - $$QT_SOURCE_TREE/src/corelib/kernel/qvariant.cpp + $$QT_SOURCE_TREE/src/corelib/kernel/qvariant.cpp \ + $$QT_SOURCE_TREE/src/corelib/codecs/qutfcodec.cpp diff --git a/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp b/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp new file mode 100644 index 0000000..621a6ac --- /dev/null +++ b/tools/qtestlib/wince/cetest/cetcpsyncconnection.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "CeTcpSyncConnection.h" +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo> + +static const QString ceTcpSyncProgram = "cetcpsync"; +extern void debugOutput(const QString& text, int level); + +CeTcpSyncConnection::CeTcpSyncConnection() + : AbstractRemoteConnection() + , connected(false) +{ +} + +CeTcpSyncConnection::~CeTcpSyncConnection() +{ + if (isConnected()) + disconnect(); +} + +bool CeTcpSyncConnection::connect(QVariantList&) +{ + // We connect with each command, so this is always true + // The command itself will fail then + const QString cmd = ceTcpSyncProgram + " noop"; + if (system(qPrintable(cmd)) != 0) + return false; + connected = true; + return true; +} + +void CeTcpSyncConnection::disconnect() +{ + connected = false; +} + +bool CeTcpSyncConnection::isConnected() const +{ + return connected; +} + +inline QString boolToString(bool b) +{ + return b ? "true" : "false"; +} + +static bool fileTimeFromString(FILETIME& ft, const QString& str) +{ + int idx = str.indexOf("*"); + if (idx <= 0) + return false; + bool ok; + ft.dwLowDateTime = str.left(idx).toULong(&ok); + if (!ok) + return false; + ft.dwHighDateTime = str.mid(idx+1).toULong(&ok); + return ok; +} + +static QString fileTimeToString(FILETIME& ft) +{ + return QString::number(ft.dwLowDateTime) + "*" + QString::number(ft.dwHighDateTime); +} + +bool CeTcpSyncConnection::copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists) +{ + QString cmd = ceTcpSyncProgram + " copyFileToDevice \"" + localSource + "\" \"" + deviceDest + "\" " + boolToString(failIfExists); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive) +{ + QString cmd = ceTcpSyncProgram + " copyDirectoryToDevice \"" + localSource + "\" \"" + deviceDest + "\" " + boolToString(recursive); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists) +{ + QString cmd = ceTcpSyncProgram + " copyFileFromDevice \"" + deviceSource + "\" \"" + localDest + "\" " + boolToString(failIfExists); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive) +{ + QString cmd = ceTcpSyncProgram + " copyDirectoryFromDevice \"" + deviceSource + "\" \"" + localDest + "\" " + boolToString(recursive); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::copyFile(const QString &srcFile, const QString &destFile, bool failIfExists) +{ + QString cmd = ceTcpSyncProgram + " copyFile \"" + srcFile + "\" \"" + destFile + "\" " + boolToString(failIfExists); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::copyDirectory(const QString &srcDirectory, const QString &destDirectory, + bool recursive) +{ + QString cmd = ceTcpSyncProgram + " copyDirectory \"" + srcDirectory + "\" \"" + destDirectory + "\" " + boolToString(recursive); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::deleteFile(const QString &fileName) +{ + QString cmd = ceTcpSyncProgram + " deleteFile \"" + fileName + "\""; + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::deleteDirectory(const QString &directory, bool recursive, bool failIfContentExists) +{ + QString cmd = ceTcpSyncProgram + " deleteDirectory \"" + directory + "\" " + boolToString(recursive) + " " + boolToString(failIfContentExists); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::execute(QString program, QString arguments, int timeout, int *returnValue) +{ + QString cmd = ceTcpSyncProgram + " execute \"" + program + "\" \"" + arguments + "\" " + QString::number(timeout); + int exitCode = system(qPrintable(cmd)); + if (returnValue) + *returnValue = exitCode; + return true; +} + +bool CeTcpSyncConnection::createDirectory(const QString &path, bool deleteBefore) +{ + QString cmd = ceTcpSyncProgram + " createDirectory \"" + path + "\" " + boolToString(deleteBefore); + return system(qPrintable(cmd)) == 0; +} + +bool CeTcpSyncConnection::timeStampForLocalFileTime(FILETIME* fTime) const +{ + QString cmd = ceTcpSyncProgram + " timeStampForLocalFileTime " + fileTimeToString(*fTime) + " >qt_cetcpsyncdata.txt"; + if (system(qPrintable(cmd)) != 0) + return false; + + QFile file("qt_cetcpsyncdata.txt"); + if (!file.open(QIODevice::ReadOnly)) + return false; + + bool result = fileTimeFromString(*fTime, file.readLine()); + file.close(); + file.remove(); + return result; +} + +bool CeTcpSyncConnection::fileCreationTime(const QString &fileName, FILETIME* deviceCreationTime) const +{ + QString cmd = ceTcpSyncProgram + " fileCreationTime \"" + fileName + "\" >qt_cetcpsyncdata.txt"; + if (system(qPrintable(cmd)) != 0) + return false; + + QFile file("qt_cetcpsyncdata.txt"); + if (!file.open(QIODevice::ReadOnly)) + return false; + + bool result = fileTimeFromString(*deviceCreationTime, file.readLine()); + file.close(); + file.remove(); + return result; +} diff --git a/tools/qtestlib/wince/cetest/cetcpsyncconnection.h b/tools/qtestlib/wince/cetest/cetcpsyncconnection.h new file mode 100644 index 0000000..1ef8423 --- /dev/null +++ b/tools/qtestlib/wince/cetest/cetcpsyncconnection.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CETCPSYNC_REMOTECONNECTION_H +#define CETCPSYNC_REMOTECONNECTION_H + +#include "remoteconnection.h" + +class CeTcpSyncConnection : public AbstractRemoteConnection +{ +public: + CeTcpSyncConnection(); + virtual ~CeTcpSyncConnection(); + + bool connect(QVariantList &list = QVariantList()); + void disconnect(); + bool isConnected() const; + + // These functions are designed for transfer between desktop and device + // Caution: deviceDest path has to be device specific (eg. no drive letters for CE) + bool copyFileToDevice(const QString &localSource, const QString &deviceDest, bool failIfExists = false); + bool copyDirectoryToDevice(const QString &localSource, const QString &deviceDest, bool recursive = true); + bool copyFileFromDevice(const QString &deviceSource, const QString &localDest, bool failIfExists = false); + bool copyDirectoryFromDevice(const QString &deviceSource, const QString &localDest, bool recursive = true); + + bool timeStampForLocalFileTime(FILETIME*) const; + bool fileCreationTime(const QString &fileName, FILETIME*) const; + + // These functions only work on files existing on the device + bool copyFile(const QString&, const QString&, bool failIfExists = false); + bool copyDirectory(const QString&, const QString&, bool recursive = true); + bool deleteFile(const QString&); + bool deleteDirectory(const QString&, bool recursive = true, bool failIfContentExists = false); + bool moveFile(const QString&, const QString&, bool FailIfExists = false); + bool moveDirectory(const QString&, const QString&, bool recursive = true); + + bool createDirectory(const QString&, bool deleteBefore=false); + + bool execute(QString program, QString arguments = QString(), int timeout = -1, int *returnValue = NULL); +private: + bool connected; +}; + +#endif diff --git a/tools/qtestlib/wince/cetest/cetest.pro b/tools/qtestlib/wince/cetest/cetest.pro index d66fa33..a6b79da 100644 --- a/tools/qtestlib/wince/cetest/cetest.pro +++ b/tools/qtestlib/wince/cetest/cetest.pro @@ -28,20 +28,27 @@ DEPENDPATH += $$QT_BUILD_TREE/src/corelib/tools $$QT_BUILD_TREE/src/corelib/io # Input HEADERS += \ remoteconnection.h \ - activesyncconnection.h \ deployment.h SOURCES += \ remoteconnection.cpp \ - activesyncconnection.cpp \ deployment.cpp \ main.cpp -win32-msvc*:LIBS += ole32.lib advapi32.lib rapi.lib +LIBS += ole32.lib advapi32.lib + +isEmpty(QT_CE_RAPI_INC) { + DEFINES += QT_CETEST_NO_ACTIVESYNC + HEADERS += cetcpsyncconnection.h + SOURCES += cetcpsyncconnection.cpp +} else { + HEADERS += activesyncconnection.h + SOURCES += activesyncconnection.cpp + LIBS += rapi.lib + INCLUDEPATH += $$QT_CE_RAPI_INC + LIBS += -L$$QT_CE_RAPI_LIB +} include(qmake_include.pri) include(bootstrapped.pri) include($$QT_SOURCE_TREE/src/script/script.pri) - -INCLUDEPATH += $$QT_CE_RAPI_INC -LIBS += -L$$QT_CE_RAPI_LIB diff --git a/tools/qtestlib/wince/cetest/deployment.cpp b/tools/qtestlib/wince/cetest/deployment.cpp index fec2735..c64ae26 100644 --- a/tools/qtestlib/wince/cetest/deployment.cpp +++ b/tools/qtestlib/wince/cetest/deployment.cpp @@ -125,13 +125,37 @@ void DeploymentHandler::initQtDeploy(QMakeProject *project, DeploymentList &depl if (!project->values("QMAKE_QT_DLL").isEmpty() && !project->values("QMAKE_LIBDIR").isEmpty()) { QStringList libs = project->values("LIBS"); QStringList qtLibs; + QStringList libPaths; foreach (QString item, libs) { - if (item.startsWith("-lQt")) { - qtLibs += project->values("QMAKE_LIBDIR").at(0) + QDir::separator() + item.mid(2) + QLatin1String("4.dll"); + + if (item.startsWith("-L")) { + // -L -> a directory containing DLLs + libPaths << item.mid(2); + continue; + } + + QStringList libCandidates; + + if (item.startsWith("-l")) { + // -l -> a library located within one of the standard library paths + QString lib = item.mid(2); + + // Check if it's a Qt library first, then check in all paths given with -L. + // Note Qt libraries get a `4' appended to them, others don't. + libCandidates << project->values("QMAKE_LIBDIR").at(0) + QDir::separator() + lib + QLatin1String("4.dll"); + foreach (QString const& libPath, libPaths) { + libCandidates << libPath + QDir::separator() + lib + QLatin1String(".dll"); + } } else { - QFileInfo info(item); - if (info.exists() && info.isAbsolute() && info.fileName().startsWith(QLatin1String("Qt"))) - qtLibs += info.dir().absoluteFilePath(info.fileName().replace(QLatin1String(".lib"), QLatin1String(".dll"))); + libCandidates << item.replace(".lib",".dll"); + } + + foreach (QString const& file, libCandidates) { + QFileInfo info(file); + if (info.exists()) { + qtLibs += info.dir().absoluteFilePath(info.fileName()); + break; + } } } for (QStringList::ConstIterator it = qtLibs.constBegin(); it != qtLibs.constEnd(); ++it) { @@ -144,6 +168,7 @@ void DeploymentHandler::initQtDeploy(QMakeProject *project, DeploymentList &depl } } +#ifndef QT_CETEST_NO_ACTIVESYNC // QtRemote deployment. We always deploy to \Windows if (!project->values("QMAKE_LIBDIR").isEmpty()) { QString remoteLibName = QLatin1String("QtRemote.dll"); @@ -153,6 +178,7 @@ void DeploymentHandler::initQtDeploy(QMakeProject *project, DeploymentList &depl else debugOutput(QString::fromLatin1("Could not find QtRemote. Might not be able to launch target executable"),0); } +#endif // C-runtime deployment QString runtime = project->values("QT_CE_C_RUNTIME").join(QLatin1String(" ")); diff --git a/tools/qtestlib/wince/cetest/main.cpp b/tools/qtestlib/wince/cetest/main.cpp index ba3ef8d..e0e475c 100644 --- a/tools/qtestlib/wince/cetest/main.cpp +++ b/tools/qtestlib/wince/cetest/main.cpp @@ -39,7 +39,12 @@ ** ****************************************************************************/ -#include "activesyncconnection.h" +#ifdef QT_CETEST_NO_ACTIVESYNC +# include "cetcpsyncconnection.h" +#else +# include "activesyncconnection.h" +#endif + #include "deployment.h" #include <option.h> #include <project.h> @@ -290,7 +295,11 @@ int main(int argc, char **argv) projectDeploymentList.append(CopyItem(TestConfiguration::localExecutable , TestConfiguration::remoteExecutable)); // deploy +#ifdef QT_CETEST_NO_ACTIVESYNC + CeTcpSyncConnection connection; +#else ActiveSyncConnection connection; +#endif if (!connection.connect()) { cout << "Error: Could not connect to device!" << endl; return -1; @@ -320,6 +329,7 @@ int main(int argc, char **argv) cout << endl << "Remote Launch:" << qPrintable(TestConfiguration::remoteExecutable) << " " << qPrintable(launchArguments.join(" ")) << endl; if (!connection.execute(TestConfiguration::remoteExecutable, launchArguments.join(" "), timeout)) { cout << "Error: Could not execute target file" << endl; + return -1; } diff --git a/tools/qtestlib/wince/cetest/remoteconnection.cpp b/tools/qtestlib/wince/cetest/remoteconnection.cpp index 547b211..3d0c3f3 100644 --- a/tools/qtestlib/wince/cetest/remoteconnection.cpp +++ b/tools/qtestlib/wince/cetest/remoteconnection.cpp @@ -41,6 +41,38 @@ #include "remoteconnection.h" +QByteArray strwinerror(DWORD errorcode) +{ + QByteArray out(512, 0); + + DWORD ok = FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM, + 0, + errorcode, + 0, + out.data(), + out.size(), + 0 + ); + + if (!ok) { + qsnprintf(out.data(), out.size(), + "(error %d; additionally, error %d while looking up error string)", + (int)errorcode, (int)GetLastError()); + } + else { + out.resize(qstrlen(out.constData())); + if (out.endsWith("\r\n")) + out.chop(2); + + /* Append error number to error message for good measure */ + out.append(" (0x"); + out.append(QByteArray::number(uint(errorcode), 16).rightJustified(8, '0')); + out.append(")"); + } + return out; +} + AbstractRemoteConnection::AbstractRemoteConnection() { } diff --git a/tools/qtestlib/wince/cetest/remoteconnection.h b/tools/qtestlib/wince/cetest/remoteconnection.h index 9c3e63d..f517009 100644 --- a/tools/qtestlib/wince/cetest/remoteconnection.h +++ b/tools/qtestlib/wince/cetest/remoteconnection.h @@ -79,4 +79,6 @@ public: virtual bool execute(QString program, QString arguments = QString(), int timeout = -1, int *returnValue = NULL) = 0; }; +QByteArray strwinerror(DWORD); + #endif diff --git a/tools/qtestlib/wince/remotelib/commands.cpp b/tools/qtestlib/wince/remotelib/commands.cpp index 3aed2d6..f2176dd 100644 --- a/tools/qtestlib/wince/remotelib/commands.cpp +++ b/tools/qtestlib/wince/remotelib/commands.cpp @@ -56,6 +56,7 @@ int qRemoteLaunch(DWORD, BYTE*, DWORD*, BYTE**, IRAPIStream* stream) wchar_t* arguments = 0; int timeout = -1; int returnValue = -2; + DWORD error = 0; if (S_OK != stream->Read(&appLength, sizeof(appLength), &bytesRead)) CLEAN_FAIL(-2); @@ -74,11 +75,13 @@ int qRemoteLaunch(DWORD, BYTE*, DWORD*, BYTE**, IRAPIStream* stream) if (S_OK != stream->Read(&timeout, sizeof(timeout), &bytesRead)) CLEAN_FAIL(-2); - bool result = qRemoteExecute(appName, arguments, &returnValue, timeout); + bool result = qRemoteExecute(appName, arguments, &returnValue, &error, timeout); if (timeout != 0) { if (S_OK != stream->Write(&returnValue, sizeof(returnValue), &bytesRead)) CLEAN_FAIL(-4); + if (S_OK != stream->Write(&error, sizeof(error), &bytesRead)) + CLEAN_FAIL(-5); } delete appName; delete arguments; @@ -90,13 +93,16 @@ int qRemoteLaunch(DWORD, BYTE*, DWORD*, BYTE**, IRAPIStream* stream) } -bool qRemoteExecute(const wchar_t* program, const wchar_t* arguments, int *returnValue, int timeout) +bool qRemoteExecute(const wchar_t* program, const wchar_t* arguments, int *returnValue, DWORD* error, int timeout) { + *error = 0; + if (!program) return false; PROCESS_INFORMATION pid; if (!CreateProcess(program, arguments, NULL, NULL, false, 0, NULL, NULL, NULL, &pid)) { + *error = GetLastError(); wprintf(L"Could not launch: %s\n", program); return false; } diff --git a/tools/qtestlib/wince/remotelib/commands.h b/tools/qtestlib/wince/remotelib/commands.h index 9f0b2e3..5275f2c 100644 --- a/tools/qtestlib/wince/remotelib/commands.h +++ b/tools/qtestlib/wince/remotelib/commands.h @@ -45,7 +45,7 @@ extern "C" { int __declspec(dllexport) qRemoteLaunch(DWORD, BYTE*, DWORD*, BYTE**, IRAPIStream*); - bool __declspec(dllexport) qRemoteExecute(const wchar_t* program, const wchar_t* arguments = NULL, int *returnValue = NULL , int timeout = -1); + bool __declspec(dllexport) qRemoteExecute(const wchar_t* program, const wchar_t* arguments = NULL, int *returnValue = NULL , DWORD* error = NULL, int timeout = -1); } #endif diff --git a/tools/qvfb/PDAPhone.skin/pda_up.png b/tools/qvfb/PDAPhone.skin/pda_up.png Binary files differdeleted file mode 100644 index 541e3c4..0000000 --- a/tools/qvfb/PDAPhone.skin/pda_up.png +++ /dev/null diff --git a/tools/qvfb/config.ui b/tools/qvfb/config.ui index 5a2eca0..182682e 100644 --- a/tools/qvfb/config.ui +++ b/tools/qvfb/config.ui @@ -1,4 +1,5 @@ -<ui version="4.0" > +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> <comment>********************************************************************* ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). @@ -40,181 +41,145 @@ ** *********************************************************************</comment> <class>Config</class> - <widget class="QDialog" name="Config" > - <property name="geometry" > + <widget class="QDialog" name="Config"> + <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>600</width> - <height>650</height> + <height>665</height> </rect> </property> - <property name="windowTitle" > + <property name="windowTitle"> <string>Configure</string> </property> - <property name="sizeGripEnabled" > + <property name="sizeGripEnabled"> <bool>true</bool> </property> - <layout class="QVBoxLayout" > - <property name="spacing" > + <layout class="QVBoxLayout"> + <property name="spacing"> <number>6</number> </property> - <property name="leftMargin" > - <number>8</number> - </property> - <property name="topMargin" > - <number>8</number> - </property> - <property name="rightMargin" > - <number>8</number> - </property> - <property name="bottomMargin" > + <property name="margin"> <number>8</number> </property> <item> - <layout class="QHBoxLayout" > - <property name="spacing" > + <layout class="QHBoxLayout"> + <property name="spacing"> <number>6</number> </property> - <property name="leftMargin" > - <number>0</number> - </property> - <property name="topMargin" > - <number>0</number> - </property> - <property name="rightMargin" > - <number>0</number> - </property> - <property name="bottomMargin" > + <property name="margin"> <number>0</number> </property> <item> - <widget class="QGroupBox" name="ButtonGroup1" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <widget class="QGroupBox" name="ButtonGroup1"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="title" > + <property name="title"> <string>Size</string> </property> - <layout class="QVBoxLayout" > - <property name="spacing" > + <layout class="QVBoxLayout"> + <property name="spacing"> <number>6</number> </property> - <property name="leftMargin" > - <number>11</number> - </property> - <property name="topMargin" > - <number>11</number> - </property> - <property name="rightMargin" > - <number>11</number> - </property> - <property name="bottomMargin" > + <property name="margin"> <number>11</number> </property> <item> - <widget class="QRadioButton" name="size_176_220" > - <property name="text" > - <string>176x220 "SmartPhone"</string> + <widget class="QRadioButton" name="size_176_220"> + <property name="text"> + <string>176x220 "SmartPhone"</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="size_240_320" > - <property name="text" > - <string>240x320 "PDA"</string> + <widget class="QRadioButton" name="size_240_320"> + <property name="text"> + <string>240x320 "PDA"</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="size_320_240" > - <property name="text" > - <string>320x240 "TV" / "QVGA"</string> + <widget class="QRadioButton" name="size_320_240"> + <property name="text"> + <string>320x240 "TV" / "QVGA"</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="size_640_480" > - <property name="text" > - <string>640x480 "VGA"</string> + <widget class="QRadioButton" name="size_640_480"> + <property name="text"> + <string>640x480 "VGA"</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="size_800_600" > - <property name="text" > + <widget class="QRadioButton" name="size_800_600"> + <property name="text"> <string>800x600</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="size_1024_768" > - <property name="text" > + <widget class="QRadioButton" name="size_1024_768"> + <property name="text"> <string>1024x768</string> </property> </widget> </item> <item> - <layout class="QHBoxLayout" > - <property name="spacing" > + <layout class="QHBoxLayout"> + <property name="spacing"> <number>6</number> </property> - <property name="leftMargin" > - <number>0</number> - </property> - <property name="topMargin" > - <number>0</number> - </property> - <property name="rightMargin" > - <number>0</number> - </property> - <property name="bottomMargin" > + <property name="margin"> <number>0</number> </property> <item> - <widget class="QRadioButton" name="size_custom" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Fixed" hsizetype="Fixed" > + <widget class="QRadioButton" name="size_custom"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="text" > + <property name="text"> <string>Custom</string> </property> </widget> </item> <item> - <widget class="QSpinBox" name="size_width" > - <property name="minimum" > + <widget class="QSpinBox" name="size_width"> + <property name="minimum"> <number>1</number> </property> - <property name="maximum" > + <property name="maximum"> <number>1280</number> </property> - <property name="singleStep" > + <property name="singleStep"> <number>16</number> </property> - <property name="value" > + <property name="value"> <number>400</number> </property> </widget> </item> <item> - <widget class="QSpinBox" name="size_height" > - <property name="minimum" > + <widget class="QSpinBox" name="size_height"> + <property name="minimum"> <number>1</number> </property> - <property name="maximum" > + <property name="maximum"> <number>1024</number> </property> - <property name="singleStep" > + <property name="singleStep"> <number>16</number> </property> - <property name="value" > + <property name="value"> <number>300</number> </property> </widget> @@ -225,135 +190,128 @@ </widget> </item> <item> - <widget class="QGroupBox" name="ButtonGroup2" > - <property name="title" > + <widget class="QGroupBox" name="ButtonGroup2"> + <property name="title"> <string>Depth</string> </property> - <layout class="QVBoxLayout" > - <property name="spacing" > - <number>6</number> - </property> - <property name="leftMargin" > - <number>11</number> - </property> - <property name="topMargin" > - <number>11</number> - </property> - <property name="rightMargin" > - <number>11</number> - </property> - <property name="bottomMargin" > - <number>11</number> - </property> + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QRadioButton" name="depth_1" > - <property name="text" > + <widget class="QRadioButton" name="depth_1"> + <property name="text"> <string>1 bit monochrome</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="depth_4gray" > - <property name="text" > + <widget class="QRadioButton" name="depth_2gray"> + <property name="text"> + <string>2 bit grayscale</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="depth_4gray"> + <property name="text"> <string>4 bit grayscale</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="depth_8" > - <property name="text" > + <widget class="QRadioButton" name="depth_8"> + <property name="text"> <string>8 bit</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="depth_12" > - <property name="text" > + <widget class="QRadioButton" name="depth_12"> + <property name="text"> <string>12 (16) bit</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="depth_15" > - <property name="text" > + <widget class="QRadioButton" name="depth_15"> + <property name="text"> <string>15 bit</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="depth_16" > - <property name="text" > + <widget class="QRadioButton" name="depth_16"> + <property name="text"> <string>16 bit</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="depth_18" > - <property name="text" > + <widget class="QRadioButton" name="depth_18"> + <property name="text"> <string>18 bit</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="depth_24" > - <property name="text" > + <widget class="QRadioButton" name="depth_24"> + <property name="text"> <string>24 bit</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="depth_32" > - <property name="text" > + <widget class="QRadioButton" name="depth_32"> + <property name="text"> <string>32 bit</string> </property> </widget> </item> <item> - <widget class="QRadioButton" name="depth_32_argb" > - <property name="text" > + <widget class="QRadioButton" name="depth_32_argb"> + <property name="text"> <string>32 bit ARGB</string> </property> </widget> </item> + <item> + <widget class="QCheckBox" name="rgbSwapped"> + <property name="toolTip"> + <string>Swap red and blue channels</string> + </property> + <property name="text"> + <string>BGR format</string> + </property> + </widget> + </item> </layout> </widget> </item> </layout> </item> <item> - <layout class="QHBoxLayout" > - <property name="spacing" > + <layout class="QHBoxLayout"> + <property name="spacing"> <number>6</number> </property> - <property name="leftMargin" > - <number>0</number> - </property> - <property name="topMargin" > - <number>0</number> - </property> - <property name="rightMargin" > - <number>0</number> - </property> - <property name="bottomMargin" > + <property name="margin"> <number>0</number> </property> <item> - <widget class="QLabel" name="TextLabel1_3" > - <property name="text" > + <widget class="QLabel" name="TextLabel1_3"> + <property name="text"> <string>Skin</string> </property> </widget> </item> <item> - <widget class="QComboBox" name="skin" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Fixed" hsizetype="Expanding" > + <widget class="QComboBox" name="skin"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <item> - <property name="text" > + <property name="text"> <string>None</string> </property> </item> @@ -362,25 +320,25 @@ </layout> </item> <item> - <widget class="QCheckBox" name="touchScreen" > - <property name="text" > + <widget class="QCheckBox" name="touchScreen"> + <property name="text"> <string>Emulate touch screen (no mouse move)</string> </property> </widget> </item> <item> - <widget class="QCheckBox" name="lcdScreen" > - <property name="text" > + <widget class="QCheckBox" name="lcdScreen"> + <property name="text"> <string>Emulate LCD screen (Only with fixed zoom of 3.0 times magnification)</string> </property> </widget> </item> <item> <spacer> - <property name="orientation" > + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" > + <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>10</height> @@ -389,204 +347,192 @@ </spacer> </item> <item> - <widget class="QLabel" name="TextLabel1" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > + <widget class="QLabel" name="TextLabel1"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="text" > - <string><p>Note that any applications using the virtual framebuffer will be terminated if you change the Size or Depth <i>above</i>. You may freely modify the Gamma <i>below</i>.</string> + <property name="text"> + <string><p>Note that any applications using the virtual framebuffer will be terminated if you change the Size or Depth <i>above</i>. You may freely modify the Gamma <i>below</i>.</string> </property> - <property name="wordWrap" > + <property name="wordWrap"> <bool>true</bool> </property> </widget> </item> <item> - <widget class="QGroupBox" name="GroupBox1" > - <property name="title" > + <widget class="QGroupBox" name="GroupBox1"> + <property name="title"> <string>Gamma</string> </property> - <layout class="QGridLayout" > - <property name="leftMargin" > - <number>11</number> - </property> - <property name="topMargin" > - <number>11</number> - </property> - <property name="rightMargin" > - <number>11</number> - </property> - <property name="bottomMargin" > + <layout class="QGridLayout"> + <property name="margin"> <number>11</number> </property> - <property name="horizontalSpacing" > + <property name="spacing"> <number>6</number> </property> - <property name="verticalSpacing" > - <number>6</number> - </property> - <item row="6" column="0" > - <widget class="QLabel" name="TextLabel3" > - <property name="text" > + <item row="6" column="0"> + <widget class="QLabel" name="TextLabel3"> + <property name="text"> <string>Blue</string> </property> </widget> </item> - <item row="6" column="1" > - <widget class="QSlider" name="bslider" > - <property name="palette" > + <item row="6" column="1"> + <widget class="QSlider" name="bslider"> + <property name="palette"> <palette> <active> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>127</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>38</red> <green>38</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>170</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -595,153 +541,153 @@ </colorrole> </active> <inactive> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>127</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>38</red> <green>38</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>170</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -750,153 +696,153 @@ </colorrole> </inactive> <disabled> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>127</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>38</red> <green>38</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>170</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -906,183 +852,183 @@ </disabled> </palette> </property> - <property name="maximum" > + <property name="maximum"> <number>400</number> </property> - <property name="value" > + <property name="value"> <number>100</number> </property> - <property name="orientation" > + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="6" column="2" > - <widget class="QLabel" name="blabel" > - <property name="text" > + <item row="6" column="2"> + <widget class="QLabel" name="blabel"> + <property name="text"> <string>1.0</string> </property> </widget> </item> - <item row="4" column="0" > - <widget class="QLabel" name="TextLabel2" > - <property name="text" > + <item row="4" column="0"> + <widget class="QLabel" name="TextLabel2"> + <property name="text"> <string>Green</string> </property> </widget> </item> - <item row="4" column="1" > - <widget class="QSlider" name="gslider" > - <property name="palette" > + <item row="4" column="1"> + <widget class="QSlider" name="gslider"> + <property name="palette"> <palette> <active> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>255</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>255</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>38</red> <green>255</green> <blue>38</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>127</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>170</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -1091,153 +1037,153 @@ </colorrole> </active> <inactive> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>255</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>255</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>38</red> <green>255</green> <blue>38</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>127</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>170</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -1246,153 +1192,153 @@ </colorrole> </inactive> <disabled> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>255</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>255</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>38</red> <green>255</green> <blue>38</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>127</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>170</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -1402,190 +1348,190 @@ </disabled> </palette> </property> - <property name="maximum" > + <property name="maximum"> <number>400</number> </property> - <property name="value" > + <property name="value"> <number>100</number> </property> - <property name="orientation" > + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="4" column="2" > - <widget class="QLabel" name="glabel" > - <property name="text" > + <item row="4" column="2"> + <widget class="QLabel" name="glabel"> + <property name="text"> <string>1.0</string> </property> </widget> </item> - <item row="0" column="0" > - <widget class="QLabel" name="TextLabel7" > - <property name="text" > + <item row="0" column="0"> + <widget class="QLabel" name="TextLabel7"> + <property name="text"> <string>All</string> </property> </widget> </item> - <item row="0" column="2" > - <widget class="QLabel" name="TextLabel8" > - <property name="text" > + <item row="0" column="2"> + <widget class="QLabel" name="TextLabel8"> + <property name="text"> <string>1.0</string> </property> </widget> </item> - <item row="0" column="1" > - <widget class="QSlider" name="gammaslider" > - <property name="palette" > + <item row="0" column="1"> + <widget class="QSlider" name="gammaslider"> + <property name="palette"> <palette> <active> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>127</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>170</red> <green>170</green> <blue>170</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -1594,153 +1540,153 @@ </colorrole> </active> <inactive> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>127</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>170</red> <green>170</green> <blue>170</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -1749,153 +1695,153 @@ </colorrole> </inactive> <disabled> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>127</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>170</red> <green>170</green> <blue>170</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -1905,183 +1851,183 @@ </disabled> </palette> </property> - <property name="maximum" > + <property name="maximum"> <number>400</number> </property> - <property name="value" > + <property name="value"> <number>100</number> </property> - <property name="orientation" > + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="2" column="0" > - <widget class="QLabel" name="TextLabel1_2" > - <property name="text" > + <item row="2" column="0"> + <widget class="QLabel" name="TextLabel1_2"> + <property name="text"> <string>Red</string> </property> </widget> </item> - <item row="2" column="2" > - <widget class="QLabel" name="rlabel" > - <property name="text" > + <item row="2" column="2"> + <widget class="QLabel" name="rlabel"> + <property name="text"> <string>1.0</string> </property> </widget> </item> - <item row="2" column="1" > - <widget class="QSlider" name="rslider" > - <property name="palette" > + <item row="2" column="1"> + <widget class="QSlider" name="rslider"> + <property name="palette"> <palette> <active> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>127</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>38</green> <blue>38</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>170</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -2090,153 +2036,153 @@ </colorrole> </active> <inactive> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>127</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>38</green> <blue>38</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>170</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -2245,153 +2191,153 @@ </colorrole> </inactive> <disabled> - <colorrole role="WindowText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="WindowText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Button" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Button"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Light" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Light"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>127</green> <blue>127</blue> </color> </brush> </colorrole> - <colorrole role="Midlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Midlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>38</green> <blue>38</blue> </color> </brush> </colorrole> - <colorrole role="Dark" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Dark"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>127</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Mid" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Mid"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>170</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Text" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Text"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="BrightText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="BrightText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="ButtonText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="ButtonText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>128</red> <green>128</green> <blue>128</blue> </color> </brush> </colorrole> - <colorrole role="Base" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Base"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Window" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Window"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>220</red> <green>220</green> <blue>220</blue> </color> </brush> </colorrole> - <colorrole role="Shadow" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Shadow"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="Highlight" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Highlight"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>10</red> <green>95</green> <blue>137</blue> </color> </brush> </colorrole> - <colorrole role="HighlightedText" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="HighlightedText"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>255</red> <green>255</green> <blue>255</blue> </color> </brush> </colorrole> - <colorrole role="Link" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="Link"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="LinkVisited" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="LinkVisited"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>0</red> <green>0</green> <blue>0</blue> </color> </brush> </colorrole> - <colorrole role="AlternateBase" > - <brush brushstyle="SolidPattern" > - <color alpha="255" > + <colorrole role="AlternateBase"> + <brush brushstyle="SolidPattern"> + <color alpha="255"> <red>232</red> <green>232</green> <blue>232</blue> @@ -2401,53 +2347,44 @@ </disabled> </palette> </property> - <property name="maximum" > + <property name="maximum"> <number>400</number> </property> - <property name="value" > + <property name="value"> <number>100</number> </property> - <property name="orientation" > + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> - <item row="8" column="0" colspan="3" > - <widget class="QPushButton" name="PushButton3" > - <property name="text" > + <item row="8" column="0" colspan="3"> + <widget class="QPushButton" name="PushButton3"> + <property name="text"> <string>Set all to 1.0</string> </property> </widget> </item> - <item rowspan="9" row="0" column="3" > - <widget class="GammaView" native="1" name="MyCustomWidget1" /> + <item row="0" column="3" rowspan="9"> + <widget class="GammaView" name="MyCustomWidget1" native="true"/> </item> </layout> </widget> </item> <item> - <layout class="QHBoxLayout" > - <property name="spacing" > + <layout class="QHBoxLayout"> + <property name="spacing"> <number>6</number> </property> - <property name="leftMargin" > - <number>0</number> - </property> - <property name="topMargin" > - <number>0</number> - </property> - <property name="rightMargin" > - <number>0</number> - </property> - <property name="bottomMargin" > + <property name="margin"> <number>0</number> </property> <item> <spacer> - <property name="orientation" > + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="sizeHint" > + <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> @@ -2456,24 +2393,24 @@ </spacer> </item> <item> - <widget class="QPushButton" name="buttonOk" > - <property name="text" > + <widget class="QPushButton" name="buttonOk"> + <property name="text"> <string>&OK</string> </property> - <property name="autoDefault" > + <property name="autoDefault"> <bool>true</bool> </property> - <property name="default" > + <property name="default"> <bool>true</bool> </property> </widget> </item> <item> - <widget class="QPushButton" name="buttonCancel" > - <property name="text" > + <widget class="QPushButton" name="buttonCancel"> + <property name="text"> <string>&Cancel</string> </property> - <property name="autoDefault" > + <property name="autoDefault"> <bool>true</bool> </property> </widget> @@ -2482,7 +2419,7 @@ </item> </layout> </widget> - <layoutdefault spacing="6" margin="11" /> + <layoutdefault spacing="6" margin="11"/> <customwidgets> <customwidget> <class>GammaView</class> @@ -2498,11 +2435,11 @@ <receiver>size_custom</receiver> <slot>click()</slot> <hints> - <hint type="sourcelabel" > + <hint type="sourcelabel"> <x>152</x> <y>193</y> </hint> - <hint type="destinationlabel" > + <hint type="destinationlabel"> <x>94</x> <y>199</y> </hint> @@ -2514,11 +2451,11 @@ <receiver>size_custom</receiver> <slot>click()</slot> <hints> - <hint type="sourcelabel" > + <hint type="sourcelabel"> <x>259</x> <y>196</y> </hint> - <hint type="destinationlabel" > + <hint type="destinationlabel"> <x>64</x> <y>188</y> </hint> diff --git a/tools/qvfb/pda.qrc b/tools/qvfb/pda.qrc deleted file mode 100644 index b14e7b3..0000000 --- a/tools/qvfb/pda.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource prefix="/skins"> - <file>pda.skin</file> -</qresource> -</RCC> diff --git a/tools/qvfb/pda.skin b/tools/qvfb/pda.skin deleted file mode 100644 index 037f750..0000000 --- a/tools/qvfb/pda.skin +++ /dev/null @@ -1,14 +0,0 @@ -pda_up.png pda_down.png -57 81 -240 320 -11 -"Power" 0x0100000a 277 36 302 57 -"F1" 0x01000030 52 439 81 470 -"F2" 0x01000031 101 422 130 451 -"F3" 0x01000032 232 423 260 452 -"F4" 0x01000033 279 445 309 473 -"Left" 0x01000012 155 438 176 472 -"Down" 0x01000015 169 471 203 486 -"Right" 0x01000014 193 448 215 472 -"Up" 0x01000013 166 427 199 451 -"Enter" 0x01000005 177 448 193 468 diff --git a/tools/qvfb/pda_down.png b/tools/qvfb/pda_down.png Binary files differdeleted file mode 100644 index 0ea157d..0000000 --- a/tools/qvfb/pda_down.png +++ /dev/null diff --git a/tools/qvfb/qvfb.cpp b/tools/qvfb/qvfb.cpp index 073124d..6f89ece 100644 --- a/tools/qvfb/qvfb.cpp +++ b/tools/qvfb/qvfb.cpp @@ -635,6 +635,7 @@ void QVFb::configure() config->touchScreen->setChecked(view->touchScreenEmulation()); config->lcdScreen->setChecked(view->lcdScreenEmulation()); chooseDepth(view->displayDepth(), view->displayFormat()); + config->rgbSwapped->setChecked(view->rgbSwapped()); connect(config->skin, SIGNAL(activated(int)), this, SLOT(skinConfigChosen(int))); if ( view->gammaRed() == view->gammaGreen() && view->gammaGreen() == view->gammaBlue() ) { config->gammaslider->setValue(int(view->gammaRed()*400)); @@ -678,6 +679,8 @@ void QVFb::configure() int d; if ( config->depth_1->isChecked() ) d=1; + else if ( config->depth_2gray->isChecked() ) + d=2; else if ( config->depth_4gray->isChecked() ) d=4; else if ( config->depth_8->isChecked() ) @@ -708,6 +711,16 @@ void QVFb::configure() } view->setViewFormat(displayFormat); view->setTouchscreenEmulation( config->touchScreen->isChecked() ); + if (view->rgbSwapped() != config->rgbSwapped->isChecked()) { + //### the windowTitle logic is inside init(), and init isn't always invoked + QString caption = windowTitle(); + if (!config->rgbSwapped->isChecked()) + caption.replace(QLatin1String(" BGR"), QString()); + else + caption.append(QLatin1String(" BGR")); + setWindowTitle(caption); + view->setRgbSwapped(config->rgbSwapped->isChecked()); + } bool lcdEmulation = config->lcdScreen->isChecked(); view->setLcdScreenEmulation( lcdEmulation ); if ( lcdEmulation ) @@ -741,6 +754,7 @@ void QVFb::chooseSize(const QSize& sz) void QVFb::chooseDepth(int depth, QVFbView::PixelFormat displayFormat) { config->depth_1->setChecked(depth==1); + config->depth_2gray->setChecked(depth==2); config->depth_4gray->setChecked(depth==4); config->depth_8->setChecked(depth==8); config->depth_12->setChecked(depth==12); diff --git a/tools/qvfb/qvfb.pro b/tools/qvfb/qvfb.pro index a3b55ab..247337a 100644 --- a/tools/qvfb/qvfb.pro +++ b/tools/qvfb/qvfb.pro @@ -60,14 +60,4 @@ unix:x11 { LIBS += -lXtst } -RESOURCES += qvfb.qrc \ - ClamshellPhone.qrc \ - PDAPhone.qrc \ - SmartPhone2.qrc \ - SmartPhone.qrc \ - SmartPhoneWithButtons.qrc \ - TouchscreenPhone.qrc \ - Trolltech-Keypad.qrc \ - Trolltech-Touchscreen.qrc \ - PortableMedia.qrc - +RESOURCES += qvfb.qrc diff --git a/tools/qvfb/qvfbview.cpp b/tools/qvfb/qvfbview.cpp index 25e93e0..c00c554 100644 --- a/tools/qvfb/qvfbview.cpp +++ b/tools/qvfb/qvfbview.cpp @@ -89,7 +89,7 @@ QVFbAbstractView::~QVFbAbstractView() QVFbView::QVFbView(int id, int w, int h, int d, Rotation r, QWidget *parent) : QVFbAbstractView(parent), - viewdepth(d), viewFormat(DefaultFormat), rsh(0), gsh(0), bsh(0), rmax(15), gmax(15), bmax(15), + viewdepth(d), viewFormat(DefaultFormat), rgb_swapped(0), rsh(0), gsh(0), bsh(0), rmax(15), gmax(15), bmax(15), contentsWidth(w), contentsHeight(h), gred(1.0), ggreen(1.0), gblue(1.0), gammatable(0), refreshRate(30), animation(0), hzm(0.0), vzm(0.0), mView(0), @@ -457,6 +457,67 @@ QImage QVFbView::getBuffer(const QRect &r, int &leading) const } break; } + + case 2: { + if (requiredSize > buffer.size()) + buffer.resize(requiredSize); + + // XXX: hw: replace by drawhelper functionality + + const int pixelsPerByte = 4; + quint8 *src = reinterpret_cast<quint8*>(mView->data()) + + r.y() * mView->linestep() + r.x() / pixelsPerByte; + const int align = qMin(r.width(), (4 - (r.x() & 3)) & 3); + const int doAlign = (align > 0 ? 1 : 0); + const int tail = qMin(r.width(), (r.width() - align) & 3); + const int doTail = (tail > 0 ? 1 : 0); + const int width8 = (r.width() - align) / pixelsPerByte; + const int stride = mView->linestep() - (width8 + doAlign); + + uchar *b = reinterpret_cast<uchar*>(buffer.data()); + img = QImage(b, r.width(), r.height(), QImage::Format_RGB32); + for (int y = 0; y < r.height(); ++y) { + quint32 *dest = reinterpret_cast<quint32*>(img.scanLine(y)); + quint8 c; + + if (doAlign) { + switch (align) { + case 3: c = ((*src & 0x30) >> 4) * 0x55; + *dest++ = qRgb(c, c, c); + case 2: c = ((*src & 0x0c) >> 2) * 0x55; + *dest++ = qRgb(c, c, c); + case 1: c = ((*src & 0x03)) * 0x55; + *dest++ = qRgb(c, c, c); + } + ++src; + } + for (int i = 0; i < width8; ++i) { + c = ((*src & 0xc0) >> 6) * 0x55; + *dest++ = qRgb(c, c, c); + c = ((*src & 0x30) >> 4) * 0x55; + *dest++ = qRgb(c, c, c); + c = ((*src & 0x0c) >> 2) * 0x55; + *dest++ = qRgb(c, c, c); + c = ((*src & 0x03)) * 0x55; + *dest++ = qRgb(c, c, c); + + ++src; + } + if (doTail) { + switch (tail) { + case 3: c = ((*src & 0x0c) >> 2) * 0x55; + dest[2] = qRgb(c, c, c); + case 2: c = ((*src & 0x30) >> 4) * 0x55; + dest[1] = qRgb(c, c, c); + case 1: c = ((*src & 0xc0) >> 6) * 0x55; + dest[0] = qRgb(c, c, c); + } + } + src += stride; + } + break; + } + case 4: { if (requiredSize > buffer.size()) buffer.resize(requiredSize); @@ -540,6 +601,9 @@ QImage QVFbView::getBuffer(const QRect &r, int &leading) const break; } + if (rgb_swapped) + img = img.rgbSwapped(); + if ( brightness != 255 ) { if (img.format() == QImage::Format_Indexed8) { QVector<QRgb> c = img.colorTable(); diff --git a/tools/qvfb/qvfbview.h b/tools/qvfb/qvfbview.h index 4893830..cd6fc89 100644 --- a/tools/qvfb/qvfbview.h +++ b/tools/qvfb/qvfbview.h @@ -77,6 +77,7 @@ public: virtual int displayHeight() const = 0; virtual int displayDepth() const = 0; virtual PixelFormat displayFormat() const { return DefaultFormat; } + virtual bool rgbSwapped() const { return false; } virtual Rotation displayRotation() const = 0; virtual void setGamma(double gr, double gg, double gb) = 0; @@ -105,6 +106,7 @@ public slots: virtual void skinKeyPressEvent( int code, const QString& text, bool autorep=FALSE ) = 0; virtual void skinKeyReleaseEvent( int code, const QString& text, bool autorep=FALSE ) = 0; virtual void setViewFormat(PixelFormat) {} + virtual void setRgbSwapped( bool ) {}; virtual void embedDisplay(WId) {} }; @@ -120,6 +122,7 @@ public: int displayHeight() const; int displayDepth() const; PixelFormat displayFormat() const; + bool rgbSwapped() const { return rgb_swapped; } Rotation displayRotation() const; bool touchScreenEmulation() const { return emulateTouchscreen; } @@ -151,6 +154,7 @@ public slots: void skinKeyPressEvent(int code, const QString& text, bool autorep=FALSE); void skinKeyReleaseEvent(int code, const QString& text, bool autorep=FALSE); void setViewFormat(PixelFormat); + void setRgbSwapped(bool b) { rgb_swapped = b; } #ifdef Q_WS_X11 void embedDisplay(WId id); #endif @@ -180,6 +184,7 @@ private: void setDirty(const QRect&); int viewdepth; // "faked" depth PixelFormat viewFormat; + bool rgb_swapped; int rsh; int gsh; int bsh; diff --git a/tools/shared/deviceskin/deviceskin.pri b/tools/shared/deviceskin/deviceskin.pri index e4c9ef7..2552c92 100644 --- a/tools/shared/deviceskin/deviceskin.pri +++ b/tools/shared/deviceskin/deviceskin.pri @@ -1,3 +1,15 @@ INCLUDEPATH += $$PWD HEADERS += $$PWD/deviceskin.h SOURCES += $$PWD/deviceskin.cpp +RESOURCES += $$PWD/skins/ClamshellPhone.qrc \ + $$PWD/skins/PDAPhone.qrc \ + $$PWD/skins/SmartPhone2.qrc \ + $$PWD/skins/SmartPhone.qrc \ + $$PWD/skins/SmartPhoneWithButtons.qrc \ + $$PWD/skins/TouchscreenPhone.qrc \ + $$PWD/skins/Trolltech-Keypad.qrc \ + $$PWD/skins/Trolltech-Touchscreen.qrc \ + $$PWD/skins/PortableMedia.qrc \ + $$PWD/skins/S60-QVGA-Candybar.qrc \ + $$PWD/skins/S60-nHD-Touchscreen.qrc + diff --git a/tools/qvfb/ClamshellPhone.qrc b/tools/shared/deviceskin/skins/ClamshellPhone.qrc index 39cd422..39cd422 100644 --- a/tools/qvfb/ClamshellPhone.qrc +++ b/tools/shared/deviceskin/skins/ClamshellPhone.qrc diff --git a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone.skin b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone.skin index cb24a8e..cb24a8e 100644 --- a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone.skin +++ b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone.skin diff --git a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5-closed.png b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5-closed.png Binary files differindex 88ba3a1..88ba3a1 100644 --- a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5-closed.png +++ b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5-closed.png diff --git a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5-pressed.png b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5-pressed.png Binary files differindex 971cdef..971cdef 100644 --- a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5-pressed.png +++ b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5-pressed.png diff --git a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5.png b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5.png Binary files differindex f3550ee..f3550ee 100644 --- a/tools/qvfb/ClamshellPhone.skin/ClamshellPhone1-5.png +++ b/tools/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5.png diff --git a/tools/qvfb/ClamshellPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/ClamshellPhone.skin/defaultbuttons.conf index e349dbc..e349dbc 100644 --- a/tools/qvfb/ClamshellPhone.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/ClamshellPhone.skin/defaultbuttons.conf diff --git a/tools/qvfb/DualScreenPhone.skin/DualScreen-pressed.png b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen-pressed.png Binary files differindex d62ef4a..d62ef4a 100644 --- a/tools/qvfb/DualScreenPhone.skin/DualScreen-pressed.png +++ b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen-pressed.png diff --git a/tools/qvfb/DualScreenPhone.skin/DualScreen.png b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen.png Binary files differindex cb3d1a7..cb3d1a7 100644 --- a/tools/qvfb/DualScreenPhone.skin/DualScreen.png +++ b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreen.png diff --git a/tools/qvfb/DualScreenPhone.skin/DualScreenPhone.skin b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreenPhone.skin index a82ef23..a82ef23 100644 --- a/tools/qvfb/DualScreenPhone.skin/DualScreenPhone.skin +++ b/tools/shared/deviceskin/skins/DualScreenPhone.skin/DualScreenPhone.skin diff --git a/tools/qvfb/SmartPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/DualScreenPhone.skin/defaultbuttons.conf index 1103350..1103350 100644 --- a/tools/qvfb/SmartPhone.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/DualScreenPhone.skin/defaultbuttons.conf diff --git a/tools/qvfb/PDAPhone.qrc b/tools/shared/deviceskin/skins/PDAPhone.qrc index 1a1c35a..1a1c35a 100644 --- a/tools/qvfb/PDAPhone.qrc +++ b/tools/shared/deviceskin/skins/PDAPhone.qrc diff --git a/tools/qvfb/PDAPhone.skin/PDAPhone.skin b/tools/shared/deviceskin/skins/PDAPhone.skin/PDAPhone.skin index d6a1966..d6a1966 100644 --- a/tools/qvfb/PDAPhone.skin/PDAPhone.skin +++ b/tools/shared/deviceskin/skins/PDAPhone.skin/PDAPhone.skin diff --git a/tools/qvfb/PDAPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/PDAPhone.skin/defaultbuttons.conf index e3ae813..e3ae813 100644 --- a/tools/qvfb/PDAPhone.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/PDAPhone.skin/defaultbuttons.conf diff --git a/tools/qvfb/PDAPhone.skin/finger.png b/tools/shared/deviceskin/skins/PDAPhone.skin/finger.png Binary files differindex 24cf0cb..24cf0cb 100644 --- a/tools/qvfb/PDAPhone.skin/finger.png +++ b/tools/shared/deviceskin/skins/PDAPhone.skin/finger.png diff --git a/tools/qvfb/PDAPhone.skin/pda_down.png b/tools/shared/deviceskin/skins/PDAPhone.skin/pda_down.png Binary files differindex f65c059..f65c059 100644 --- a/tools/qvfb/PDAPhone.skin/pda_down.png +++ b/tools/shared/deviceskin/skins/PDAPhone.skin/pda_down.png diff --git a/tools/qvfb/pda_up.png b/tools/shared/deviceskin/skins/PDAPhone.skin/pda_up.png Binary files differindex 541e3c4..541e3c4 100644 --- a/tools/qvfb/pda_up.png +++ b/tools/shared/deviceskin/skins/PDAPhone.skin/pda_up.png diff --git a/tools/qvfb/PortableMedia.qrc b/tools/shared/deviceskin/skins/PortableMedia.qrc index a902f1a..a902f1a 100644 --- a/tools/qvfb/PortableMedia.qrc +++ b/tools/shared/deviceskin/skins/PortableMedia.qrc diff --git a/tools/qvfb/PortableMedia.skin/PortableMedia.skin b/tools/shared/deviceskin/skins/PortableMedia.skin/PortableMedia.skin index b76e5cf..b76e5cf 100644 --- a/tools/qvfb/PortableMedia.skin/PortableMedia.skin +++ b/tools/shared/deviceskin/skins/PortableMedia.skin/PortableMedia.skin diff --git a/tools/qvfb/PortableMedia.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/PortableMedia.skin/defaultbuttons.conf index 514e881..514e881 100644 --- a/tools/qvfb/PortableMedia.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/PortableMedia.skin/defaultbuttons.conf diff --git a/tools/qvfb/PortableMedia.skin/portablemedia-pressed.png b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia-pressed.png Binary files differindex 730e762..730e762 100644 --- a/tools/qvfb/PortableMedia.skin/portablemedia-pressed.png +++ b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia-pressed.png diff --git a/tools/qvfb/PortableMedia.skin/portablemedia.png b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia.png Binary files differindex e44cbe1..e44cbe1 100644 --- a/tools/qvfb/PortableMedia.skin/portablemedia.png +++ b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia.png diff --git a/tools/qvfb/PortableMedia.skin/portablemedia.xcf b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia.xcf Binary files differindex 127e07c..127e07c 100644 --- a/tools/qvfb/PortableMedia.skin/portablemedia.xcf +++ b/tools/shared/deviceskin/skins/PortableMedia.skin/portablemedia.xcf diff --git a/tools/shared/deviceskin/skins/S60-QVGA-Candybar.qrc b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.qrc new file mode 100644 index 0000000..8138484 --- /dev/null +++ b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/skins"> + <file>S60-QVGA-Candybar.skin</file> +</qresource> +</RCC> diff --git a/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar-down.png b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar-down.png Binary files differnew file mode 100644 index 0000000..89d40cb --- /dev/null +++ b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar-down.png diff --git a/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.png b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.png Binary files differnew file mode 100644 index 0000000..0d0e598 --- /dev/null +++ b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.png diff --git a/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.skin b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.skin new file mode 100644 index 0000000..4f8fe5d --- /dev/null +++ b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.skin @@ -0,0 +1,15 @@ +[SkinFile] +Up=S60-QVGA-Candybar.png +Down=S60-QVGA-Candybar-down.png +Screen=61 93 240 320 +Areas=7 +HasMouseHover=false + + +"Context1" 0x01100000 54 469 151 469 140 483 88 485 81 496 54 498 +"Back" 0x01000061 211 468 307 467 307 498 278 497 219 486 +"Select" 0x01010000 165 491 196 522 +"Left" 0x1000012 149 474 166 492 163 519 143 538 142 481 +"Down" 0x1000015 164 521 195 522 212 539 204 545 154 544 145 536 +"Right" 0x1000014 214 475 219 487 219 528 212 539 196 522 197 492 +"Up" 0x1000013 150 474 156 467 209 467 213 476 197 489 165 489 diff --git a/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/defaultbuttons.conf new file mode 100644 index 0000000..e349dbc --- /dev/null +++ b/tools/shared/deviceskin/skins/S60-QVGA-Candybar.skin/defaultbuttons.conf @@ -0,0 +1,78 @@ +[Translation] +File=QtopiaDefaults +Context=Buttons +[Menu] +Rows=4 +Columns=3 +Map=123456789*0# +Default=5 +1=Applications/camera.desktop +2=Applications/datebook.desktop +3=Applications +4=Applications/qtmail.desktop +5=Applications/addressbook.desktop +6=Games +7=Settings/Beaming.desktop +8=Applications/simapp.desktop,Applications/calculator.desktop +9=Settings +*=Applications/mediarecorder.desktop +0=Applications/todolist.desktop +#=Documents +Animator=Bounce +AnimatorBackground=Radial +[SoftKeys] +Count=3 +Key0=Context1 +Key1=Select +Key2=Back +[SystemButtons] +Count=5 +Key0=Context1 +Key1=Select +Key2=Back +Key3=Flip +Key4=Backspace +[TextButtons] +Buttons=0123456789*# +Hold0='0 +Hold1='1 +Hold2='2 +Hold3='3 +Hold4='4 +Hold5='5 +Hold6='6 +Hold7='7 +Hold8='8 +Hold9='9 +Hold*=symbol +Hold#=mode +Tap0=space +Tap1="\".,'?!-@:1" +Tap2="\"a\xe4\xe5\xe6\xe0\xe1\xe2\x62\x63\xe7\x32" +Tap3="\"de\xe8\xe9\xea\x66\x33" +Tap4="\"ghi\xec\xed\xee\x34" +Tap5="\"jkl5" +Tap6="\"mn\xf1o\xf6\xf8\xf2\xf3\x36" +Tap7="\"pqrs\xdf\x37" +Tap8="\"tu\xfc\xf9\xfav8" +Tap9="\"wxyz9" +Tap*=modify +Tap#=shift +[LocaleTextButtons] +Buttons=23456789 +Tap2[]='abc +Tap3[]='def +Tap4[]='ghi +Tap5[]='jkl +Tap6[]='mno +Tap7[]='pqrs +Tap8[]='tuv +Tap9[]='wxyz +[PhoneTextButtons] +Buttons=*# +Tap*='*+pw +Hold*=+ +Tap#=# +Hold#=mode +[Device] +PrimaryInput=Keypad diff --git a/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.qrc b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.qrc new file mode 100644 index 0000000..daf0cc3 --- /dev/null +++ b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/skins"> + <file>S60-nHD-Touchscreen.skin</file> +</qresource> +</RCC> diff --git a/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen-down.png b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen-down.png Binary files differnew file mode 100644 index 0000000..7253e38 --- /dev/null +++ b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen-down.png diff --git a/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.png b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.png Binary files differnew file mode 100644 index 0000000..675563e --- /dev/null +++ b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.png diff --git a/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.skin b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.skin new file mode 100644 index 0000000..ed25d0e --- /dev/null +++ b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.skin @@ -0,0 +1,10 @@ +[SkinFile] +Up=S60-nHD-Touchscreen.png +Down=S60-nHD-Touchscreen-down.png +Screen=53 183 360 640 +Areas=3 +HasMouseHover=false + +"Call" 0x01100004 76 874 171 899 +"Hangup" 0x01100005 300 876 393 899 +"Home" 0x1000010 174 878 298 899 diff --git a/tools/qvfb/Trolltech-Touchscreen.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/defaultbuttons.conf index 6665125..6665125 100644 --- a/tools/qvfb/Trolltech-Touchscreen.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/defaultbuttons.conf diff --git a/tools/qvfb/SmartPhone.qrc b/tools/shared/deviceskin/skins/SmartPhone.qrc index 8bb5325..8bb5325 100644 --- a/tools/qvfb/SmartPhone.qrc +++ b/tools/shared/deviceskin/skins/SmartPhone.qrc diff --git a/tools/qvfb/SmartPhone.skin/SmartPhone-pressed.png b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone-pressed.png Binary files differindex d0db2ed..d0db2ed 100644 --- a/tools/qvfb/SmartPhone.skin/SmartPhone-pressed.png +++ b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone-pressed.png diff --git a/tools/qvfb/SmartPhone.skin/SmartPhone.png b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone.png Binary files differindex e6ac5a0..e6ac5a0 100644 --- a/tools/qvfb/SmartPhone.skin/SmartPhone.png +++ b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone.png diff --git a/tools/qvfb/SmartPhone.skin/SmartPhone.skin b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone.skin index 2f44c5a..2f44c5a 100644 --- a/tools/qvfb/SmartPhone.skin/SmartPhone.skin +++ b/tools/shared/deviceskin/skins/SmartPhone.skin/SmartPhone.skin diff --git a/tools/qvfb/DualScreenPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/SmartPhone.skin/defaultbuttons.conf index 1103350..1103350 100644 --- a/tools/qvfb/DualScreenPhone.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/SmartPhone.skin/defaultbuttons.conf diff --git a/tools/qvfb/SmartPhone2.qrc b/tools/shared/deviceskin/skins/SmartPhone2.qrc index 751e985..751e985 100644 --- a/tools/qvfb/SmartPhone2.qrc +++ b/tools/shared/deviceskin/skins/SmartPhone2.qrc diff --git a/tools/qvfb/SmartPhone2.skin/SmartPhone2-pressed.png b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2-pressed.png Binary files differindex d4eb5b0..d4eb5b0 100644 --- a/tools/qvfb/SmartPhone2.skin/SmartPhone2-pressed.png +++ b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2-pressed.png diff --git a/tools/qvfb/SmartPhone2.skin/SmartPhone2.png b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2.png Binary files differindex 48ccc1c..48ccc1c 100644 --- a/tools/qvfb/SmartPhone2.skin/SmartPhone2.png +++ b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2.png diff --git a/tools/qvfb/SmartPhone2.skin/SmartPhone2.skin b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2.skin index 16884bf..16884bf 100644 --- a/tools/qvfb/SmartPhone2.skin/SmartPhone2.skin +++ b/tools/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2.skin diff --git a/tools/qvfb/SmartPhone2.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/SmartPhone2.skin/defaultbuttons.conf index b083203..b083203 100644 --- a/tools/qvfb/SmartPhone2.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/SmartPhone2.skin/defaultbuttons.conf diff --git a/tools/qvfb/SmartPhoneWithButtons.qrc b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.qrc index f3393ba..f3393ba 100644 --- a/tools/qvfb/SmartPhoneWithButtons.qrc +++ b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.qrc diff --git a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons-pressed.png b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons-pressed.png Binary files differindex 456a068..456a068 100644 --- a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons-pressed.png +++ b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons-pressed.png diff --git a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.png b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.png Binary files differindex 5ffbd6e..5ffbd6e 100644 --- a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.png +++ b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.png diff --git a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.skin b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.skin index 9afa67f..9afa67f 100644 --- a/tools/qvfb/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.skin +++ b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.skin diff --git a/tools/qvfb/SmartPhoneWithButtons.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/defaultbuttons.conf index ebd6926..ebd6926 100644 --- a/tools/qvfb/SmartPhoneWithButtons.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/SmartPhoneWithButtons.skin/defaultbuttons.conf diff --git a/tools/qvfb/TouchscreenPhone.qrc b/tools/shared/deviceskin/skins/TouchscreenPhone.qrc index 023144d..023144d 100644 --- a/tools/qvfb/TouchscreenPhone.qrc +++ b/tools/shared/deviceskin/skins/TouchscreenPhone.qrc diff --git a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone-pressed.png b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone-pressed.png Binary files differindex 01acb86..01acb86 100644 --- a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone-pressed.png +++ b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone-pressed.png diff --git a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone.png b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone.png Binary files differindex e90de0d..e90de0d 100644 --- a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone.png +++ b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone.png diff --git a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone.skin b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone.skin index 24316a1..24316a1 100644 --- a/tools/qvfb/TouchscreenPhone.skin/TouchscreenPhone.skin +++ b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone.skin diff --git a/tools/qvfb/TouchscreenPhone.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/defaultbuttons.conf index a13dfdc..a13dfdc 100644 --- a/tools/qvfb/TouchscreenPhone.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/TouchscreenPhone.skin/defaultbuttons.conf diff --git a/tools/qvfb/Trolltech-Keypad.qrc b/tools/shared/deviceskin/skins/Trolltech-Keypad.qrc index 4775068..4775068 100644 --- a/tools/qvfb/Trolltech-Keypad.qrc +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.qrc diff --git a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png Binary files differindex 8dd5719..8dd5719 100644 --- a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-closed.png diff --git a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad-down.png b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-down.png Binary files differindex 5e1e6be..5e1e6be 100644 --- a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad-down.png +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad-down.png diff --git a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad.png b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.png Binary files differindex fb3d549..fb3d549 100644 --- a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad.png +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.png diff --git a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad.skin b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.skin index 4d90321..4d90321 100644 --- a/tools/qvfb/Trolltech-Keypad.skin/Trolltech-Keypad.skin +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/Trolltech-Keypad.skin diff --git a/tools/qvfb/Trolltech-Keypad.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/defaultbuttons.conf index 6a78e67..6a78e67 100644 --- a/tools/qvfb/Trolltech-Keypad.skin/defaultbuttons.conf +++ b/tools/shared/deviceskin/skins/Trolltech-Keypad.skin/defaultbuttons.conf diff --git a/tools/qvfb/Trolltech-Touchscreen.qrc b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.qrc index 40fafeb..40fafeb 100644 --- a/tools/qvfb/Trolltech-Touchscreen.qrc +++ b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.qrc diff --git a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png Binary files differindex c1a422f..c1a422f 100644 --- a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png +++ b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen-down.png diff --git a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png Binary files differindex 544a425..544a425 100644 --- a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png +++ b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.png diff --git a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin index 5de882e..5de882e 100644 --- a/tools/qvfb/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin +++ b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/Trolltech-Touchscreen.skin diff --git a/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/defaultbuttons.conf b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/defaultbuttons.conf new file mode 100644 index 0000000..6665125 --- /dev/null +++ b/tools/shared/deviceskin/skins/Trolltech-Touchscreen.skin/defaultbuttons.conf @@ -0,0 +1,53 @@ +[Translation] +File=QtopiaDefaults +Context=Buttons +[Menu] +Rows=4 +Columns=3 +Map=123456789*0# +Default=5 +1=Applications/camera.desktop +2=Applications/mediaplayer.desktop +3=Applications/simapp.desktop,Applications/calculator.desktop +4=Applications/qtmail.desktop +5=Applications/addressbook.desktop +6=Applications/datebook.desktop +7=Games +8=Settings/beaming.desktop +9=Applications/todolist.desktop +*=Settings +0=Applications +#=Documents +Animator=Bounce +AnimatorBackground=Radial +[SoftKeys] +Count=3 +Key0=Context1 +Key1=Select +Key2=Back +[SystemButtons] +Count=5 +Key0=Context1 +Key1=Back +Key2=Select +Key3=Call +Key4=Hangup +[Device] +PrimaryInput=Touchscreen +[Button] +Count=2 +[Button0] +Name[]=Home Button +Key=Home +PressedActionMappable=0 +PressedActionService=TaskManager +PressedActionMessage=multitask() +HeldActionMappable=0 +HeldActionService=TaskManager +HeldActionMessage=showRunningTasks() +[Button1] +Name=Power Button +Key=Hangup +HeldActionService=Launcher +HeldActionMessage=execute(QString) +HeldActionArgs=@ByteArray(\0\0\0\x1\0\0\0\n\0\0\0\0\x10\0s\0h\0u\0t\0\x64\0o\0w\0n) diff --git a/tools/shared/qtgradienteditor/qtgradientdialog.cpp b/tools/shared/qtgradienteditor/qtgradientdialog.cpp index 9605403..6c2deff 100644 --- a/tools/shared/qtgradienteditor/qtgradientdialog.cpp +++ b/tools/shared/qtgradienteditor/qtgradientdialog.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::QtGradientDialog -*/ - #include "qtgradientdialog.h" #include "ui_qtgradientdialog.h" #include <QtGui/QPushButton> diff --git a/tools/shared/qtgradienteditor/qtgradienteditor.cpp b/tools/shared/qtgradienteditor/qtgradienteditor.cpp index 0671176..76562c4 100644 --- a/tools/shared/qtgradienteditor/qtgradienteditor.cpp +++ b/tools/shared/qtgradienteditor/qtgradienteditor.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::QtGradientEditor -*/ - #include "qtgradienteditor.h" #include "qtgradientstopscontroller.h" #include "ui_qtgradienteditor.h" diff --git a/tools/shared/qtgradienteditor/qtgradientstopscontroller.cpp b/tools/shared/qtgradienteditor/qtgradientstopscontroller.cpp index 35e77e8..4e6639a 100644 --- a/tools/shared/qtgradienteditor/qtgradientstopscontroller.cpp +++ b/tools/shared/qtgradienteditor/qtgradientstopscontroller.cpp @@ -39,10 +39,6 @@ ** ****************************************************************************/ -/* -TRANSLATOR qdesigner_internal::QtGradientStopsController -*/ - #include "qtgradientstopscontroller.h" #include "ui_qtgradienteditor.h" #include "qtgradientstopsmodel.h" diff --git a/tools/shared/qttoolbardialog/qttoolbardialog.cpp b/tools/shared/qttoolbardialog/qttoolbardialog.cpp index e1c92b8..c313709 100644 --- a/tools/shared/qttoolbardialog/qttoolbardialog.cpp +++ b/tools/shared/qttoolbardialog/qttoolbardialog.cpp @@ -637,10 +637,10 @@ QToolBar *QtFullToolBarManager::createToolBar(const QString &toolBarName) return 0; QToolBar *toolBar = new QToolBar(toolBarName, mainWindow()); int i = 1; - const QString prefix = QLatin1String("_Custom_Toolbar_"); - QString name = QString(QLatin1String("%1%2")).arg(prefix).arg(i); + const QString prefix = QLatin1String("_Custom_Toolbar_%1"); + QString name = prefix.arg(i); while (d_ptr->toolBarByName(name)) - name = QString(QLatin1String("%1%2")).arg(prefix).arg(++i); + name = prefix.arg(++i); toolBar->setObjectName(name); mainWindow()->addToolBar(toolBar); d_ptr->customToolBars.append(toolBar); diff --git a/tools/tools.pro b/tools/tools.pro index 3325a57..eab9d48 100644 --- a/tools/tools.pro +++ b/tools/tools.pro @@ -22,8 +22,10 @@ mac { SUBDIRS += macdeployqt } +embedded:SUBDIRS += kmap2qmap + contains(QT_CONFIG, dbus):SUBDIRS += qdbus -!wince*:contains(QT_CONFIG, xmlpatterns): SUBDIRS += xmlpatterns +!wince*:contains(QT_CONFIG, xmlpatterns): SUBDIRS += xmlpatterns xmlpatternsvalidator embedded: SUBDIRS += makeqpf CONFIG+=ordered diff --git a/tools/xmlpatterns/main.cpp b/tools/xmlpatterns/main.cpp index a5c2c41..2405d5d 100644 --- a/tools/xmlpatterns/main.cpp +++ b/tools/xmlpatterns/main.cpp @@ -194,7 +194,7 @@ protected: /* If we don't open stdout in "binary" mode on Windows, it will translate * 0xA into 0xD 0xA. See Trolltech task 173619, for an example. */ _setmode(_fileno(stdout), _O_BINARY); - m_stdout = QT_WA_INLINE(_wfdopen(_fileno(stdout), L"wb"),_fdopen(_fileno(stdout), "wb")); + m_stdout = _wfdopen(_fileno(stdout), L"wb"); out->open(m_stdout, QIODevice::WriteOnly); #else out->open(stdout, QIODevice::WriteOnly); diff --git a/tools/xmlpatternsvalidator/main.cpp b/tools/xmlpatternsvalidator/main.cpp new file mode 100644 index 0000000..75ea8b4 --- /dev/null +++ b/tools/xmlpatternsvalidator/main.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Patternist project on Trolltech Labs. +** +** $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "main.h" + +#include <QtCore/QDebug> +#include <QtCore/QFile> +#include <QtCore/QUrl> +#include <QtXmlPatterns/QXmlSchema> +#include <QtXmlPatterns/QXmlSchemaValidator> + +QT_USE_NAMESPACE + +int main(int argc, char **argv) +{ + enum ExitCode + { + Valid = 0, + Invalid, + ParseError + }; + + enum ExecutionMode + { + InvalidMode, + SchemaOnlyMode, + SchemaAndInstanceMode, + InstanceOnlyMode + }; + + const QCoreApplication app(argc, argv); + QCoreApplication::setApplicationName(QLatin1String("xmlpatternsvalidator")); + + if (argc != 2 && argc != 3) { + qDebug() << QXmlPatternistCLI::tr("usage: xmlpatternsvalidator (<schema url> | <instance url> <schema url> | <instance url>)"); + return ParseError; + } + + // parse command line arguments + ExecutionMode mode = InvalidMode; + + if (argc == 2) { + // either it is a schema or instance document + + 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; + } + } else if (argc == 3) { + mode = SchemaAndInstanceMode; + } + + // do validation + 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 (!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); + + return Invalid; +} diff --git a/tools/xmlpatternsvalidator/main.h b/tools/xmlpatternsvalidator/main.h new file mode 100644 index 0000000..a0eff3b --- /dev/null +++ b/tools/xmlpatternsvalidator/main.h @@ -0,0 +1,76 @@ +/**************************************************************************** + ** + ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + ** Contact: Qt Software Information (qt-info@nokia.com) + ** + ** This file is part of the Patternist project on Trolltech Labs. * ** + ** $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_main_h +#define Patternist_main_h + +#include <QtCore/QCoreApplication> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlPatternistCLI +{ +public: + Q_DECLARE_TR_FUNCTIONS(QXmlPatternistCLI) +private: + inline QXmlPatternistCLI(); + Q_DISABLE_COPY(QXmlPatternistCLI) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/tools/xmlpatternsvalidator/xmlpatternsvalidator.pro b/tools/xmlpatternsvalidator/xmlpatternsvalidator.pro new file mode 100644 index 0000000..dd5bd37 --- /dev/null +++ b/tools/xmlpatternsvalidator/xmlpatternsvalidator.pro @@ -0,0 +1,19 @@ +TEMPLATE = app +TARGET = xmlpatternsvalidator +DESTDIR = ../../bin +QT -= gui +QT += xmlpatterns + +target.path = $$[QT_INSTALL_BINS] +INSTALLS += target + +# This ensures we get stderr and stdout on Windows. +CONFIG += console + +# This ensures that this is a command-line program on OS X and not a GUI application. +CONFIG -= app_bundle + +SOURCES = main.cpp +HEADERS = main.h + +include(../src/common.pri) |