diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-09-20 08:21:42 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2013-09-20 08:29:17 +0200 |
commit | bbb78a92a910d32b2886af62c218db87325eb6ce (patch) | |
tree | 0e4b55352bb9f083826d0e80747982823f2894ed /tools | |
parent | 4b5a7b15fc6d3650c8e9b7bf619804a0a953eeba (diff) | |
parent | 8ed38c70fd29680f7981d9d23581d46cf32139d0 (diff) |
Merge branch 'dev' of ssh://codereview.qt-project.org/qt/qtdeclarative into HEAD
Conflicts:
src/qml/compiler/qv4isel_masm.cpp
src/qml/jsruntime/qv4script.cpp
src/qml/qml/qml.pri
src/qml/qml/qqmltypeloader_p.h
Change-Id: Ia784d855a2131e3289454f12d841ca2c65be15c1
Diffstat (limited to 'tools')
-rw-r--r-- | tools/qml/Info.plist | 49 | ||||
-rw-r--r-- | tools/qml/conf.h | 99 | ||||
-rw-r--r-- | tools/qml/conf/configuration.qml | 47 | ||||
-rw-r--r-- | tools/qml/conf/qtquick.qml | 55 | ||||
-rw-r--r-- | tools/qml/main.cpp | 466 | ||||
-rw-r--r-- | tools/qml/qml.icns | bin | 0 -> 196156 bytes | |||
-rw-r--r-- | tools/qml/qml.pro | 14 | ||||
-rw-r--r-- | tools/qml/qml.qrc | 6 | ||||
-rw-r--r-- | tools/qmlplugindump/main.cpp | 240 | ||||
-rw-r--r-- | tools/qmlprofiler/qmlprofilerdata.cpp | 6 | ||||
-rw-r--r-- | tools/qmlprofiler/qpacketprotocol.cpp | 1 | ||||
-rw-r--r-- | tools/tools.pro | 1 | ||||
-rw-r--r-- | tools/v4/main.cpp | 25 |
13 files changed, 934 insertions, 75 deletions
diff --git a/tools/qml/Info.plist b/tools/qml/Info.plist new file mode 100644 index 0000000000..42d074a3af --- /dev/null +++ b/tools/qml/Info.plist @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> +<plist version="0.1"> +<dict> + <key>CFBundleIconFile</key> + <string>@ICON@</string> + <key>CFBundleIdentifier</key> + <string>org.qt-project.qml</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleGetInfoString</key> + <string>Created by Qt/QMake</string> + <key>CFBundleSignature</key> + <string>@TYPEINFO@</string> + <key>CFBundleExecutable</key> + <string>@EXECUTABLE@</string> + <key>UTExportedTypeDeclarations</key> + <array> + <dict> + <key>UTTypeIdentifier</key> + <string>org.qt-project.qml</string> + <key>UTTypeDescription</key> + <string>Qt Markup Language</string> + <key>UTTypeConformsTo</key> + <array> + <string>public.plain-text</string> + </array> + <key>UTTypeTagSpecification</key> + <dict> + <key>public.filename-extension</key> + <array> + <string>qml</string> + </array> + </dict> + </dict> + </array> + <key>CFBundleDocumentTypes</key> + <array> + <dict> + <key>LSItemContentTypes</key> + <array> + <string>org.qt-project.qml</string> + </array> + <key>CFBundleTypeRole</key> + <string>Viewer</string> + </dict> + </array> +</dict> +</plist> diff --git a/tools/qml/conf.h b/tools/qml/conf.h new file mode 100644 index 0000000000..24ea44edb9 --- /dev/null +++ b/tools/qml/conf.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef CONF_H +#define CONF_H + +#include <QtQml> +#include <QObject> +#include <QUrl> + +class PartialScene : public QObject +{ + Q_OBJECT + Q_PROPERTY(QUrl container READ container WRITE setContainer NOTIFY containerChanged) + Q_PROPERTY(QString itemType READ itemType WRITE setItemType NOTIFY itemTypeChanged) +public: + PartialScene(QObject *parent = 0) : QObject(parent) + {} + + const QUrl container() const { return m_container; } + const QString itemType() const { return m_itemType; } + + void setContainer(const QUrl &a) { + if (a==m_container) + return; + m_container = a; + emit containerChanged(); + } + void setItemType(const QString &a) { + if (a==m_itemType) + return; + m_itemType = a; + emit itemTypeChanged(); + } + +signals: + void containerChanged(); + void itemTypeChanged(); + +private: + QUrl m_container; + QString m_itemType; +}; + +class Config : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty<PartialScene> sceneCompleters READ sceneCompleters) + Q_CLASSINFO("DefaultProperty", "sceneCompleters") +public: + Config (QObject* parent=0) : QObject(parent) + {} + + QQmlListProperty<PartialScene> sceneCompleters() + { + return QQmlListProperty<PartialScene>(this, completers); + } + + QList<PartialScene*> completers; +}; + +#endif diff --git a/tools/qml/conf/configuration.qml b/tools/qml/conf/configuration.qml new file mode 100644 index 0000000000..4a9494e8b5 --- /dev/null +++ b/tools/qml/conf/configuration.qml @@ -0,0 +1,47 @@ +/***************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +*****************************************************************************/ +import QmlRuntime.Config 1.0 + +Configuration { + PartialScene { + itemType: "QQuickItem" + container: "qtquick.qml" + } +} diff --git a/tools/qml/conf/qtquick.qml b/tools/qml/conf/qtquick.qml new file mode 100644 index 0000000000..3da5c09d41 --- /dev/null +++ b/tools/qml/conf/qtquick.qml @@ -0,0 +1,55 @@ +/***************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +*****************************************************************************/ +import QtQuick.Window 2.0 +import QtQuick 2.0 + +Window { + property Item containedObject: null + onContainedObjectChanged: { + if (containedObject == undefined || containedObject == null) { + visible = false; + return; + } + width = containedObject.width; + height = containedObject.height; + containedObject.parent = contentItem; + visible = true; + } +} diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp new file mode 100644 index 0000000000..c059373143 --- /dev/null +++ b/tools/qml/main.cpp @@ -0,0 +1,466 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Research In Motion. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "conf.h" + +#include <QCoreApplication> +#include <QGuiApplication> +#ifdef QT_WIDGETS_LIB +#include <QApplication> +#endif +#include <QWindow> +#include <QQmlApplicationEngine> +#include <QFileOpenEvent> +#include <QFile> +#include <QFileInfo> +#include <QRegularExpression> +#include <QStringList> +#include <QDebug> +#include <QStandardPaths> +#include <QtGlobal> +#include <qqml.h> +#include <qqmldebug.h> +#include <private/qabstractanimation_p.h> + +#include <cstdio> +#include <cstring> +#include <cstdlib> + +#define VERSION_MAJ 1 +#define VERSION_MIN 0 +#define VERSION_STR "1.0" + +static Config *conf = 0; +static QQmlApplicationEngine *qae = 0; + +static void loadConf(const QString &override, bool quiet) // Terminates app on failure +{ + const QString defaultFileName = QLatin1String("configuration.qml"); + QUrl settingsUrl; + bool builtIn = false; //just for keeping track of the warning + if (override.isEmpty()) { + QFileInfo fi; + fi.setFile(QStandardPaths::locate(QStandardPaths::DataLocation, defaultFileName)); + if (fi.exists()) { + settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath()); + } else { + // ### If different built-in configs are needed per-platform, just apply QFileSelector to the qrc conf.qml path + settingsUrl = QUrl(QLatin1String("qrc:///qt-project.org/QmlRuntime/conf/") + defaultFileName); + builtIn = true; + } + } else { + QFileInfo fi; + fi.setFile(override); + if (!fi.exists()) { + qCritical() << QObject::tr("qml: Couldn't find required configuration file:") << fi.absoluteFilePath(); + exit(1); + } + settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath()); + } + + if (!quiet) { + if (builtIn) + qWarning() << QObject::tr("qml: Using built-in configuration."); + else + qWarning() << QObject::tr("qml: Using configuration file:") << settingsUrl; + } + + // TODO: When we have better engine control, ban QtQuick* imports on this engine + QQmlEngine e2; + QQmlComponent c2(&e2, settingsUrl); + conf = qobject_cast<Config*>(c2.create()); + + if (!conf){ + qCritical() << QObject::tr("qml: Error loading configuration file:") << c2.errorString(); + exit(1); + } +} + +void contain(QObject *o, const QUrl &containPath) +{ + QQmlComponent c(qae, containPath); + QObject *o2 = c.create(); + if (!o2) + return; + bool success = false; + int idx; + if ((idx = o2->metaObject()->indexOfProperty("containedObject")) != -1) + success = o2->metaObject()->property(idx).write(o2, QVariant::fromValue<QObject*>(o)); + if (!success) + o->setParent(o2); //Set QObject parent, and assume container will react as needed +} + +// Loads qml after receiving a QFileOpenEvent +class LoaderApplication : public QGuiApplication +{ +public: + LoaderApplication(int& argc, char **argv) : QGuiApplication(argc, argv) {} + + bool event(QEvent *ev) + { + if (ev->type() == QEvent::FileOpen) + qae->load(static_cast<QFileOpenEvent *>(ev)->url()); + else + return QGuiApplication::event(ev); + return true; + } +}; + +// Listens to the appEngine signals to determine if all files failed to load +class LoadWatcher : public QObject +{ + Q_OBJECT +public: + LoadWatcher(QQmlApplicationEngine *e, int expected) + : QObject(e) + , expect(expected) + , haveOne(false) + { + connect(e, SIGNAL(objectCreated(QObject*,QUrl)), + this, SLOT(checkFinished(QObject*))); + } + +private: + int expect; + bool haveOne; + +public Q_SLOTS: + void checkFinished(QObject *o) + { + if (o) { + haveOne = true; + if (conf && qae) + foreach (PartialScene *ps, conf->completers) + if (o->inherits(ps->itemType().toUtf8().constData())) + contain(o, ps->container()); + } + if (haveOne) + return; + + if (! --expect) { + qCritical() << QObject::tr("qml: Did not load any objects, exiting."); + exit(2);//Different return code from qFatal + } + } +}; + +void quietMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, const QString &msg) +{ + Q_UNUSED(ctxt); + Q_UNUSED(msg); + //Doesn't print anything + switch (type) { + case QtFatalMsg: + abort(); + case QtCriticalMsg: + case QtDebugMsg: + case QtWarningMsg: + ; + } +} + + +// ### Should command line arguments have translations? Qt creator doesn't, so maybe it's not worth it. +bool useCoreApp = false; +bool useWidgetApp = false; +bool quietMode = false; +void printVersion() +{ + printf("qml binary version "); + printf(VERSION_STR); + printf("\nbuilt with Qt version "); + printf(QT_VERSION_STR); + printf("\n"); + exit(0); +} + +void printUsage() +{ + printf("Usage: qml [options] [files]\n"); + printf("\n"); + printf("Any argument ending in .qml will be treated as a QML file to be loaded.\n"); + printf("Any number of QML files can be loaded. They will share the same engine.\n"); + printf("Any argument which is not a recognized option and which does not end in .qml will be ignored.\n"); + printf("'widget' application type is only available if the QtWidgets module is avaialble.\n"); + printf("\n"); + printf("General Options:\n"); + printf("\t-h, -help..................... Print this usage information and exit.\n"); + printf("\t-v, -version.................. Print the version information and exit.\n"); + printf("\t-apptype [core|gui|widget] ... Select which application class to use. Default is gui.\n"); + printf("\t-quiet ....................... Suppress all output.\n"); + printf("\t-I [path] .................... Prepend the given path to the import paths.\n"); + printf("\t-f [file] .................... Load the given file as a QML file.\n"); + printf("\t-config [file] ............... Load the given file as the configuration file.\n"); + printf("\t-- ........................... Arguments after this one are ignored by the launcher, but may be used within the QML application.\n"); + printf("\tDebugging options:\n"); + printf("\t-enable-debugger ............. Allow the QML debugger to connect to the application (also requires debugger arguments).\n"); + printf("\t-translation [file] .......... Load the given file as the translations file.\n"); + printf("\t-dummy-data [directory] ...... Load QML files from the given directory as context properties.\n"); + printf("\t-slow-animations ............. Run all animations in slow motion.\n"); + printf("\t-fixed-animations ............ Run animations off animation tick rather than wall time.\n"); + exit(0); +} + +//Called before application initialization, removes arguments it uses +void getAppFlags(int &argc, char **argv) +{ + for (int i=0; i<argc; i++) { + if (!strcmp(argv[i], "-apptype")) { // Must be done before application, as it selects application + int type = 0; + if (i+1 < argc) { + if (!strcmp(argv[i+1], "core")) + type = 1; + else if (!strcmp(argv[i+1], "gui")) + type = 2; +#ifdef QT_WIDGETS_LIB + else if (!strcmp(argv[i+1], "widget")) + type = 3; +#endif + } + + if (!type) { +#ifdef QT_WIDGETS_LIB + printf("-apptype must be followed by one of the following: core gui widget\n"); +#else + printf("-apptype must be followed by one of the following: core gui\n"); +#endif + printUsage(); + } + + switch (type) { + case 1: useCoreApp = true; break; + case 2: useCoreApp = false; break; +#ifdef QT_WIDGETS_LIB + case 3: useWidgetApp = true; break; +#endif + } + for (int j=i; j<argc-2; j++) + argv[j] = argv[j+2]; + argc -= 2; + } else if (!strcmp(argv[i], "-enable-debugger")) { // Normally done via a define in the include, so expects to be before application (and must be before engine) + static QQmlDebuggingEnabler qmlEnableDebuggingHelper(true); + for (int j=i; j<argc-1; j++) + argv[j] = argv[j+1]; + argc --; + } + } +} + +void getFileSansBangLine(const QString &path, QByteArray &output) +{ + QFile f(path); + if (!f.open(QFile::ReadOnly | QFile::Text)) + return; + output = f.readAll(); + if (output.startsWith("#!"))//Remove first line in this case (except \n, to avoid disturbing line count) + output.remove(0, output.indexOf('\n')); +} + +static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory) +{ + QDir dir(directory+"/dummydata", "*.qml"); + QStringList list = dir.entryList(); + for (int i = 0; i < list.size(); ++i) { + QString qml = list.at(i); + QFile f(dir.filePath(qml)); + f.open(QIODevice::ReadOnly); + QByteArray data = f.readAll(); + QQmlComponent comp(&engine); + comp.setData(data, QUrl()); + QObject *dummyData = comp.create(); + + if (comp.isError()) { + QList<QQmlError> errors = comp.errors(); + foreach (const QQmlError &error, errors) + qWarning() << error; + } + + if (dummyData && !quietMode) { + qWarning() << QObject::tr("qml: Loaded dummy data:") << dir.filePath(qml); + qml.truncate(qml.length()-4); + engine.rootContext()->setContextProperty(qml, dummyData); + dummyData->setParent(&engine); + } + } +} + +int main(int argc, char *argv[]) +{ + getAppFlags(argc, argv); + QCoreApplication *app; + if (useCoreApp) + app = new QCoreApplication(argc, argv); +#ifdef QT_WIDGETS_LIB + else if (useWidgetApp) + app = new QApplication(argc, argv); +#endif + else + app = new LoaderApplication(argc, argv); + + app->setApplicationName("Qml Runtime"); + app->setOrganizationName("Qt Project"); + app->setOrganizationDomain("qt-project.org"); + + qmlRegisterType<Config>("QmlRuntime.Config", VERSION_MAJ, VERSION_MIN, "Configuration"); + qmlRegisterType<PartialScene>("QmlRuntime.Config", VERSION_MAJ, VERSION_MIN, "PartialScene"); + QQmlApplicationEngine e; + QStringList files; + QString confFile; + QString translationFile; + QString dummyDir; + + //Handle main arguments + QStringList argList = app->arguments(); + for (int i = 0; i < argList.count(); i++) { + const QString &arg = argList[i]; + if (arg == QLatin1String("-quiet")) + quietMode = true; + else if (arg == QLatin1String("-v") || arg == QLatin1String("-version")) + printVersion(); + else if (arg == QLatin1String("-h") || arg == QLatin1String("-help")) + printUsage(); + else if (arg == QLatin1String("--")) + break; + else if (arg == QLatin1String("-slow-animations")) + QUnifiedTimer::instance()->setSlowModeEnabled(true); + else if (arg == QLatin1String("-fixed-animations")) + QUnifiedTimer::instance()->setConsistentTiming(true); + else if (arg == QLatin1String("-I")) { + if (i+1 == argList.count()) + continue;//Invalid usage, but just ignore it + e.addImportPath(argList[i+1]); + i++; + } else if (arg == QLatin1String("-f")) { + if (i+1 == argList.count()) + continue;//Invalid usage, but just ignore it + files << argList[i+1]; + i++; + } else if (arg == QLatin1String("-config")){ + if (i+1 == argList.count()) + continue;//Invalid usage, but just ignore it + confFile = argList[i+1]; + i++; + } else if (arg == QLatin1String("-translation")){ + if (i+1 == argList.count()) + continue;//Invalid usage, but just ignore it + translationFile = argList[i+1]; + i++; + } else if (arg == QLatin1String("-dummy-data")){ + if (i+1 == argList.count()) + continue;//Invalid usage, but just ignore it + dummyDir = argList[i+1]; + i++; + } else { + //If it ends in .qml, treat it as a file. Else ignore it + if (arg.endsWith(".qml")) + files << arg; + } + } + +#ifndef QT_NO_TRANSLATION + //qt_ translations loaded by QQmlApplicationEngine + QTranslator qmlTranslator; + QString sysLocale = QLocale::system().name(); + if (qmlTranslator.load(QLatin1String("qml_") + sysLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + app->installTranslator(&qmlTranslator); + + if (!translationFile.isEmpty()) { //Note: installed before QQmlApplicationEngine's automatic translation loading + QTranslator translator; + + if (translator.load(translationFile)) { + app->installTranslator(&translator); + } else { + if (!quietMode) + qWarning() << "qml: Could not load the translation file" << translationFile; + } + } +#else + if (!translationFile.isEmpty() && !quietMode) + qWarning() << "qml: Translation file specified, but Qt built without translation support."; +#endif + + if (quietMode) + qInstallMessageHandler(quietMessageHandler); + + if (files.count() <= 0) { + if (!quietMode) + qCritical() << QObject::tr("qml: No files specified. Terminating."); + exit(1); + } + + qae = &e; + loadConf(confFile, quietMode); + + //Load files + LoadWatcher lw(&e, files.count()); + + foreach (const QString &path, files) { + //QUrl::fromUserInput doesn't treat no scheme as relative file paths + QRegularExpression urlRe("[[:word:]]+://.*"); + if (urlRe.match(path).hasMatch()) { //Treat as a URL + QUrl url = QUrl::fromUserInput(path); + if (!quietMode) + qDebug() << QObject::tr("qml: loading ") << url; + e.load(url); + } else { //Local file path + if (!quietMode) { + qDebug() << QObject::tr("qml: loading ") << path; + QByteArray strippedFile; + getFileSansBangLine(path, strippedFile); + if (strippedFile.isEmpty()) + // If there's an error opening the file, this will give us the right error message + e.load(path); + else + e.loadData(strippedFile, QUrl::fromLocalFile(path)); + } else { + e.load(path); + } + } + } + + + if (!dummyDir.isEmpty() && QFileInfo (dummyDir).isDir()) + loadDummyDataFiles(e, dummyDir); + + return app->exec(); +} + +#include "main.moc" diff --git a/tools/qml/qml.icns b/tools/qml/qml.icns Binary files differnew file mode 100644 index 0000000000..c76051626a --- /dev/null +++ b/tools/qml/qml.icns diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro new file mode 100644 index 0000000000..fd4021c340 --- /dev/null +++ b/tools/qml/qml.pro @@ -0,0 +1,14 @@ +QT += qml gui core-private +qtHaveModule(widgets): QT += widgets + +HEADERS += conf.h +SOURCES += main.cpp +RESOURCES += qml.qrc + +mac { + OTHER_FILES += Info.plist + QMAKE_INFO_PLIST = Info.plist + ICON = qml.icns +} + +load(qt_tool) diff --git a/tools/qml/qml.qrc b/tools/qml/qml.qrc new file mode 100644 index 0000000000..1f0ffdace2 --- /dev/null +++ b/tools/qml/qml.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="qt-project.org/QmlRuntime"> + <file>conf/configuration.qml</file> + <file>conf/qtquick.qml</file> + </qresource> +</RCC> diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp index 4337db1689..6939ce92e2 100644 --- a/tools/qmlplugindump/main.cpp +++ b/tools/qmlplugindump/main.cpp @@ -58,6 +58,7 @@ #include <QtCore/private/qmetaobject_p.h> #include <iostream> +#include <algorithm> #include "qmlstreamwriter.h" @@ -139,6 +140,9 @@ public: */ static QHash<QByteArray, QSet<const QQmlType *> > qmlTypesByCppName; +// No different versioning possible for a composite type. +static QMap<QString, const QQmlType * > qmlTypesByCompositeName; + static QHash<QByteArray, QByteArray> cppToId; /* Takes a C++ type name, such as Qt::LayoutDirection or QString and @@ -190,8 +194,9 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const if (ty->isExtendedType()) extensions[ty->typeName()].insert(ty->metaObject()->className()); collectReachableMetaObjects(ty, &metas); + } else { + qmlTypesByCompositeName[ty->elementName()] = ty; } - // TODO actually handle composite types } // Adjust exports of the base object if there are extensions. @@ -249,7 +254,16 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const if (ty->isSingleton()) { QQmlType::SingletonInstanceInfo *siinfo = ty->singletonInstanceInfo(); + if (!siinfo) { + qWarning() << "Internal error, " << tyName + << "(" << QString::fromUtf8(ty->typeName()) << ")" + << " is singleton, but has no singletonInstanceInfo"; + continue; + } if (siinfo->qobjectCallback) { + if (verbose) + qDebug() << "Trying to get singleton for " << tyName + << " (" << siinfo->typeName << ")"; siinfo->init(engine); collectReachableMetaObjects(object, &metas); object = siinfo->qobjectApi(engine); @@ -258,15 +272,22 @@ QSet<const QMetaObject *> collectReachableMetaObjects(QQmlEngine *engine, const continue; // we don't handle QJSValue singleton types. } } else { + if (verbose) + qDebug() << "Trying to create object " << tyName + << " (" << QString::fromUtf8(ty->typeName()) << ")"; object = ty->create(); } inObjectInstantiation.clear(); - if (object) + if (object) { + if (verbose) + qDebug() << "Got " << tyName + << " (" << QString::fromUtf8(ty->typeName()) << ")"; collectReachableMetaObjects(object, &metas); - else + } else { qWarning() << "Could not create" << tyName; + } } } @@ -287,6 +308,135 @@ public: relocatableModuleUri = uri; } + const QString getExportString(QString qmlTyName, int majorVersion, int minorVersion) + { + if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) { + qmlTyName.remove(0, relocatableModuleUri.size() + 1); + } + if (qmlTyName.startsWith("./")) { + qmlTyName.remove(0, 2); + } + if (qmlTyName.startsWith("/")) { + qmlTyName.remove(0, 1); + } + const QString exportString = enquote( + QString("%1 %2.%3").arg( + qmlTyName, + QString::number(majorVersion), + QString::number(minorVersion))); + return exportString; + } + + void writeMetaContent(const QMetaObject *meta) + { + QSet<QString> implicitSignals; + for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) { + const QMetaProperty &property = meta->property(index); + dump(property); + implicitSignals.insert(QString("%1Changed").arg(QString::fromUtf8(property.name()))); + } + + if (meta == &QObject::staticMetaObject) { + // for QObject, hide deleteLater() and onDestroyed + for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) { + QMetaMethod method = meta->method(index); + QByteArray signature = method.methodSignature(); + if (signature == QByteArrayLiteral("destroyed(QObject*)") + || signature == QByteArrayLiteral("destroyed()") + || signature == QByteArrayLiteral("deleteLater()")) + continue; + dump(method, implicitSignals); + } + + // and add toString(), destroy() and destroy(int) + qml->writeStartObject(QLatin1String("Method")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("toString"))); + qml->writeEndObject(); + qml->writeStartObject(QLatin1String("Method")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); + qml->writeEndObject(); + qml->writeStartObject(QLatin1String("Method")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); + qml->writeStartObject(QLatin1String("Parameter")); + qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("delay"))); + qml->writeScriptBinding(QLatin1String("type"), enquote(QLatin1String("int"))); + qml->writeEndObject(); + qml->writeEndObject(); + } else { + for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) + dump(meta->method(index), implicitSignals); + } + } + + QString getPrototypeNameForCompositeType(const QMetaObject *metaObject, QSet<QByteArray> &defaultReachableNames) + { + QString prototypeName; + if (!defaultReachableNames.contains(metaObject->className())) { + const QMetaObject *superMetaObject = metaObject->superClass(); + if (!superMetaObject) + prototypeName = "QObject"; + else + prototypeName = getPrototypeNameForCompositeType(superMetaObject, defaultReachableNames); + } else { + prototypeName = convertToId(metaObject->className()); + } + return prototypeName; + } + + void dumpComposite(QQmlEngine *engine, const QQmlType *compositeType, QSet<QByteArray> &defaultReachableNames) + { + QQmlComponent e(engine, compositeType->sourceUrl()); + QObject *object = e.create(); + + if (!object) + return; + + qml->writeStartObject("Component"); + + const QMetaObject *mainMeta = object->metaObject(); + + // Get C++ base class name for the composite type + QString prototypeName = getPrototypeNameForCompositeType(mainMeta, defaultReachableNames); + qml->writeScriptBinding(QLatin1String("prototype"), enquote(prototypeName)); + + QString qmlTyName = compositeType->qmlTypeName(); + // name should be unique + qml->writeScriptBinding(QLatin1String("name"), enquote(qmlTyName)); + const QString exportString = getExportString(qmlTyName, compositeType->majorVersion(), compositeType->minorVersion()); + qml->writeArrayBinding(QLatin1String("exports"), QStringList() << exportString); + qml->writeArrayBinding(QLatin1String("exportMetaObjectRevisions"), QStringList() << QString::number(compositeType->minorVersion())); + + for (int index = mainMeta->classInfoCount() - 1 ; index >= 0 ; --index) { + QMetaClassInfo classInfo = mainMeta->classInfo(index); + if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) { + qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(QLatin1String(classInfo.value()))); + break; + } + } + + QSet<const QMetaObject *> metas; + QSet<const QMetaObject *> candidatesComposite; + collectReachableMetaObjects(mainMeta, &candidatesComposite); + + // Also eliminate meta objects with the same classname. + // This is required because extended objects seem not to share + // a single meta object instance. + foreach (const QMetaObject *mo, candidatesComposite) { + if (!defaultReachableNames.contains(mo->className())) + metas.insert(mo); + } + + // put the metaobjects into a map so they are always dumped in the same order + QMap<QString, const QMetaObject *> nameToMeta; + foreach (const QMetaObject *meta, metas) + nameToMeta.insert(convertToId(meta), meta); + + foreach (const QMetaObject *meta, nameToMeta) + writeMetaContent(meta); + + qml->writeEndObject(); + } + void dump(const QMetaObject *meta) { qml->writeStartObject("Component"); @@ -310,27 +460,13 @@ public: QHash<QString, const QQmlType *> exports; foreach (const QQmlType *qmlTy, qmlTypes) { - QString qmlTyName = qmlTy->qmlTypeName(); - if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) { - qmlTyName.remove(0, relocatableModuleUri.size() + 1); - } - if (qmlTyName.startsWith("./")) { - qmlTyName.remove(0, 2); - } - if (qmlTyName.startsWith("/")) { - qmlTyName.remove(0, 1); - } - const QString exportString = enquote( - QString("%1 %2.%3").arg( - qmlTyName, - QString::number(qmlTy->majorVersion()), - QString::number(qmlTy->minorVersion()))); + const QString exportString = getExportString(qmlTy->qmlTypeName(), qmlTy->majorVersion(), qmlTy->minorVersion()); exports.insert(exportString, qmlTy); } // ensure exports are sorted and don't change order when the plugin is dumped again QStringList exportStrings = exports.keys(); - qSort(exportStrings); + std::sort(exportStrings.begin(), exportStrings.end()); qml->writeArrayBinding(QLatin1String("exports"), exportStrings); // write meta object revisions @@ -354,43 +490,7 @@ public: for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index) dump(meta->enumerator(index)); - QSet<QString> implicitSignals; - for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index) { - const QMetaProperty &property = meta->property(index); - dump(property); - implicitSignals.insert(QString("%1Changed").arg(QString::fromUtf8(property.name()))); - } - - if (meta == &QObject::staticMetaObject) { - // for QObject, hide deleteLater() and onDestroyed - for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) { - QMetaMethod method = meta->method(index); - QByteArray signature = method.methodSignature(); - if (signature == QByteArrayLiteral("destroyed(QObject*)") - || signature == QByteArrayLiteral("destroyed()") - || signature == QByteArrayLiteral("deleteLater()")) - continue; - dump(method, implicitSignals); - } - - // and add toString(), destroy() and destroy(int) - qml->writeStartObject(QLatin1String("Method")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("toString"))); - qml->writeEndObject(); - qml->writeStartObject(QLatin1String("Method")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); - qml->writeEndObject(); - qml->writeStartObject(QLatin1String("Method")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("destroy"))); - qml->writeStartObject(QLatin1String("Parameter")); - qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("delay"))); - qml->writeScriptBinding(QLatin1String("type"), enquote(QLatin1String("int"))); - qml->writeEndObject(); - qml->writeEndObject(); - } else { - for (int index = meta->methodOffset(); index < meta->methodCount(); ++index) - dump(meta->method(index), implicitSignals); - } + writeMetaContent(meta); qml->writeEndObject(); } @@ -461,7 +561,7 @@ private: void dump(const QMetaMethod &meth, const QSet<QString> &implicitSignals) { if (meth.methodType() == QMetaMethod::Signal) { - if (meth.access() != QMetaMethod::Protected) + if (meth.access() != QMetaMethod::Public) return; // nothing to do. } else if (meth.access() != QMetaMethod::Public) { return; // nothing to do. @@ -543,7 +643,7 @@ void sigSegvHandler(int) { void printUsage(const QString &appName) { qWarning() << qPrintable(QString( - "Usage: %1 [-v] [-noinstantiate] [-[non]relocatable] module.uri version [module/import/path]\n" + "Usage: %1 [-v] [-noinstantiate] [-defaultplatform] [-[non]relocatable] module.uri version [module/import/path]\n" " %1 [-v] [-noinstantiate] -path path/to/qmldir/directory [version]\n" " %1 [-v] -builtins\n" "Example: %1 Qt.labs.folderlistmodel 2.0 /home/user/dev/qt-install/imports").arg( @@ -570,7 +670,17 @@ int main(int argc, char *argv[]) #endif // don't require a window manager even though we're a QGuiApplication - qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("minimal")); + bool requireWindowManager = false; + for (int index = 1; index < argc; ++index) { + if (QString::fromLocal8Bit(argv[index]) == "--defaultplatform" + || QString::fromLocal8Bit(argv[index]) == "-defaultplatform") { + requireWindowManager = true; + break; + } + } + + if (!requireWindowManager) + qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("minimal")); QGuiApplication app(argc, argv); const QStringList args = app.arguments(); @@ -612,6 +722,9 @@ int main(int argc, char *argv[]) action = Builtins; } else if (arg == QLatin1String("-v")) { verbose = true; + } else if (arg == QLatin1String("--defaultplatform") + || arg == QLatin1String("-defaultplatform")) { + continue; } else { qWarning() << "Invalid argument: " << arg; return EXIT_INVALIDARGUMENTS; @@ -672,6 +785,7 @@ int main(int argc, char *argv[]) // add some otherwise unreachable QMetaObjects defaultReachable.insert(&QQuickMouseEvent::staticMetaObject); // QQuickKeyEvent, QQuickPinchEvent, QQuickDropEvent are not exported + QSet<QByteArray> defaultReachableNames; // this will hold the meta objects we want to dump information of QSet<const QMetaObject *> metas; @@ -723,7 +837,6 @@ int main(int argc, char *argv[]) // Also eliminate meta objects with the same classname. // This is required because extended objects seem not to share // a single meta object instance. - QSet<QByteArray> defaultReachableNames; foreach (const QMetaObject *mo, defaultReachable) defaultReachableNames.insert(QByteArray(mo->className())); foreach (const QMetaObject *mo, candidates) { @@ -746,8 +859,9 @@ int main(int argc, char *argv[]) "// This file describes the plugin-supplied types contained in the library.\n" "// It is used for QML tooling purposes only.\n" "//\n" - "// This file was auto-generated with the command '%1'.\n" - "\n").arg(args.join(QLatin1String(" ")))); + "// This file was auto-generated by:\n" + "// '%1 %2'\n" + "\n").arg(QFileInfo(args.at(0)).fileName()).arg(QStringList(args.mid(1)).join(QLatin1String(" ")))); qml.writeStartObject("Module"); // put the metaobjects into a map so they are always dumped in the same order @@ -761,6 +875,8 @@ int main(int argc, char *argv[]) foreach (const QMetaObject *meta, nameToMeta) { dumper.dump(meta); } + foreach (const QQmlType *compositeType, qmlTypesByCompositeName) + dumper.dumpComposite(&engine, compositeType, defaultReachableNames); // define QEasingCurve as an extension of QQmlEasingValueType, this way // properties using the QEasingCurve type get useful type information. diff --git a/tools/qmlprofiler/qmlprofilerdata.cpp b/tools/qmlprofiler/qmlprofilerdata.cpp index 5d387d6234..038d2177f9 100644 --- a/tools/qmlprofiler/qmlprofilerdata.cpp +++ b/tools/qmlprofiler/qmlprofilerdata.cpp @@ -47,6 +47,8 @@ #include <QFile> #include <QXmlStreamReader> +#include <algorithm> + namespace Constants { const char TYPE_PAINTING_STR[] = "Painting"; const char TYPE_COMPILING_STR[] = "Compiling"; @@ -437,9 +439,9 @@ void QmlProfilerData::sortStartTimes() itFrom--; if (itTo->startTime <= itFrom->startTime) - qSort(itFrom, itTo + 1, compareStartTimes); + std::sort(itFrom, itTo + 1, compareStartTimes); else - qSort(itFrom + 1, itTo + 1, compareStartTimes); + std::sort(itFrom + 1, itTo + 1, compareStartTimes); // move to next block itTo = itFrom; diff --git a/tools/qmlprofiler/qpacketprotocol.cpp b/tools/qmlprofiler/qpacketprotocol.cpp index b0cb289c10..e0fe08740d 100644 --- a/tools/qmlprofiler/qpacketprotocol.cpp +++ b/tools/qmlprofiler/qpacketprotocol.cpp @@ -288,6 +288,7 @@ void QPacketProtocol::send(const QPacket & p) d->sendingPackets.append(sendSize); qint32 sendSize32 = sendSize; qint64 writeBytes = d->dev->write((char *)&sendSize32, sizeof(qint32)); + Q_UNUSED(writeBytes); Q_ASSERT(writeBytes == sizeof(qint32)); writeBytes = d->dev->write(p.b); Q_ASSERT(writeBytes == p.b.size()); diff --git a/tools/tools.pro b/tools/tools.pro index 43b6c14022..ecca12d266 100644 --- a/tools/tools.pro +++ b/tools/tools.pro @@ -2,6 +2,7 @@ TEMPLATE = subdirs qtHaveModule(quick): SUBDIRS += qmlscene qmlplugindump qtHaveModule(qmltest): SUBDIRS += qmltestrunner SUBDIRS += \ + qml \ qmlmin \ qmlprofiler \ qmlbundle \ diff --git a/tools/v4/main.cpp b/tools/v4/main.cpp index a49c7093cf..3404de2c30 100644 --- a/tools/v4/main.cpp +++ b/tools/v4/main.cpp @@ -77,16 +77,16 @@ struct Print: FunctionObject name = scope->engine->newString("print"); } - static Value call(Managed *, CallData *callData) + static ReturnedValue call(Managed *, CallData *callData) { for (int i = 0; i < callData->argc; ++i) { - QString s = callData->args[i].toQString(); + QString s = callData->args[i].toQStringNoThrow(); if (i) std::cout << ' '; std::cout << qPrintable(s); } std::cout << std::endl; - return Value::undefinedValue(); + return Value::undefinedValue().asReturnedValue(); } static const ManagedVTable static_vtbl; @@ -102,10 +102,10 @@ struct GC: public FunctionObject vtbl = &static_vtbl; name = scope->engine->newString("gc"); } - static Value call(Managed *m, CallData *) + static ReturnedValue call(Managed *m, CallData *) { m->engine()->memoryManager->runGC(); - return Value::undefinedValue(); + return Value::undefinedValue().asReturnedValue(); } static const ManagedVTable static_vtbl; @@ -117,11 +117,13 @@ DEFINE_MANAGED_VTABLE(GC); static void showException(QV4::ExecutionContext *ctx, const QV4::Exception &exception) { - QV4::ErrorObject *e = exception.value().asErrorObject(); + QV4::Scope scope(ctx); + QV4::ScopedValue ex(scope, exception.value()); + QV4::ErrorObject *e = ex->asErrorObject(); if (!e) { - std::cerr << "Uncaught exception: " << qPrintable(exception.value().toString(ctx)->toQString()) << std::endl; + std::cerr << "Uncaught exception: " << qPrintable(ex->toString(ctx)->toQString()) << std::endl; } else { - std::cerr << "Uncaught exception: " << qPrintable(e->get(ctx->engine->newString(QStringLiteral("message")), 0).toString(ctx)->toQString()) << std::endl; + std::cerr << "Uncaught exception: " << qPrintable(QV4::Value::fromReturnedValue(e->get(ctx->engine->newString(QStringLiteral("message")), 0)).toString(ctx)->toQString()) << std::endl; } foreach (const QV4::ExecutionEngine::StackFrame &frame, exception.stackTrace()) { @@ -187,6 +189,7 @@ int main(int argc, char *argv[]) QV4::ExecutionEngine vm(iSelFactory); QV4::ExecutionContext *ctx = vm.rootContext; + QV4::Scope scope(ctx); QV4::Object *globalObject = vm.globalObject; QV4::Object *print = new (ctx->engine->memoryManager) builtins::Print(ctx); @@ -204,10 +207,10 @@ int main(int argc, char *argv[]) QV4::Script script(ctx, code, fn); script.parseAsBinding = runAsQml; script.parse(); - QV4::Value result = script.run(); - if (!result.isUndefined()) { + QV4::ScopedValue result(scope, script.run()); + if (!result->isUndefined()) { if (! qgetenv("SHOW_EXIT_VALUE").isEmpty()) - std::cout << "exit value: " << qPrintable(result.toString(ctx)->toQString()) << std::endl; + std::cout << "exit value: " << qPrintable(result->toString(ctx)->toQString()) << std::endl; } } catch (QV4::Exception& ex) { ex.accept(ctx); |