aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/qmlplugindump/Info.plist16
-rw-r--r--tools/qmlplugindump/main.cpp598
-rw-r--r--tools/qmlplugindump/qmlplugindump.pro20
-rw-r--r--tools/qmlplugindump/qmlstreamwriter.cpp183
-rw-r--r--tools/qmlplugindump/qmlstreamwriter.h79
-rw-r--r--tools/qmlscene/main.cpp574
-rw-r--r--tools/qmlscene/qmlscene.pro20
-rw-r--r--tools/qmlviewer/main.cpp7
-rw-r--r--tools/qmlviewer/qmlruntime.cpp1
-rw-r--r--tools/tools.pro2
10 files changed, 1496 insertions, 4 deletions
diff --git a/tools/qmlplugindump/Info.plist b/tools/qmlplugindump/Info.plist
new file mode 100644
index 0000000000..f35846d048
--- /dev/null
+++ b/tools/qmlplugindump/Info.plist
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>@TYPEINFO@</string>
+ <key>CFBundleExecutable</key>
+ <string>@EXECUTABLE@</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.nokia.qt.qmlplugindump</string>
+ <key>LSUIElement</key>
+ <string>1</string>
+</dict>
+</plist>
diff --git a/tools/qmlplugindump/main.cpp b/tools/qmlplugindump/main.cpp
new file mode 100644
index 0000000000..c2d2681b42
--- /dev/null
+++ b/tools/qmlplugindump/main.cpp
@@ -0,0 +1,598 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtDeclarative/QtDeclarative>
+#include <QtDeclarative/private/qdeclarativemetatype_p.h>
+#include <QtDeclarative/private/qdeclarativeopenmetaobject_p.h>
+#include <QtDeclarative/QDeclarativeView>
+
+#include <QtGui/QApplication>
+
+#include <QtCore/QSet>
+#include <QtCore/QMetaObject>
+#include <QtCore/QMetaProperty>
+#include <QtCore/QDebug>
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/private/qmetaobject_p.h>
+
+#include <iostream>
+
+#include "qmlstreamwriter.h"
+
+#ifdef QT_SIMULATOR
+#include <QtGui/private/qsimulatorconnection_p.h>
+#endif
+
+#ifdef Q_OS_UNIX
+#include <signal.h>
+#endif
+
+QString pluginImportPath;
+
+void collectReachableMetaObjects(const QMetaObject *meta, QSet<const QMetaObject *> *metas)
+{
+ if (! meta || metas->contains(meta))
+ return;
+
+ // dynamic meta objects break things badly, so just ignore them
+ const QMetaObjectPrivate *mop = reinterpret_cast<const QMetaObjectPrivate *>(meta->d.data);
+ if (!(mop->flags & DynamicMetaObject))
+ metas->insert(meta);
+
+ collectReachableMetaObjects(meta->superClass(), metas);
+}
+
+QString currentProperty;
+
+void collectReachableMetaObjects(QObject *object, QSet<const QMetaObject *> *metas)
+{
+ if (! object)
+ return;
+
+ const QMetaObject *meta = object->metaObject();
+ qDebug() << "Processing object" << meta->className();
+ collectReachableMetaObjects(meta, metas);
+
+ for (int index = 0; index < meta->propertyCount(); ++index) {
+ QMetaProperty prop = meta->property(index);
+ if (QDeclarativeMetaType::isQObject(prop.userType())) {
+ qDebug() << " Processing property" << prop.name();
+ currentProperty = QString("%1::%2").arg(meta->className(), prop.name());
+
+ // if the property was not initialized during construction,
+ // accessing a member of oo is going to cause a segmentation fault
+ QObject *oo = QDeclarativeMetaType::toQObject(prop.read(object));
+ if (oo && !metas->contains(oo->metaObject()))
+ collectReachableMetaObjects(oo, metas);
+ currentProperty.clear();
+ }
+ }
+}
+
+void collectReachableMetaObjects(const QDeclarativeType *ty, QSet<const QMetaObject *> *metas)
+{
+ collectReachableMetaObjects(ty->metaObject(), metas);
+ if (ty->attachedPropertiesType())
+ collectReachableMetaObjects(ty->attachedPropertiesType(), metas);
+}
+
+/* We want to add the MetaObject for 'Qt' to the list, this is a
+ simple way to access it.
+*/
+class FriendlyQObject: public QObject
+{
+public:
+ static const QMetaObject *qtMeta() { return &staticQtMetaObject; }
+};
+
+/* When we dump a QMetaObject, we want to list all the types it is exported as.
+ To do this, we need to find the QDeclarativeTypes associated with this
+ QMetaObject.
+*/
+static QHash<QByteArray, QSet<const QDeclarativeType *> > qmlTypesByCppName;
+
+static QHash<QByteArray, QByteArray> cppToId;
+
+/* Takes a C++ type name, such as Qt::LayoutDirection or QString and
+ maps it to how it should appear in the description file.
+
+ These names need to be unique globally, so we don't change the C++ symbol's
+ name much. It is mostly used to for explicit translations such as
+ QString->string and translations for extended QML objects.
+*/
+QByteArray convertToId(const QByteArray &cppName)
+{
+ return cppToId.value(cppName, cppName);
+}
+
+QSet<const QMetaObject *> collectReachableMetaObjects(const QString &importCode, QDeclarativeEngine *engine)
+{
+ QSet<const QMetaObject *> metas;
+ metas.insert(FriendlyQObject::qtMeta());
+
+ QHash<QByteArray, QSet<QByteArray> > extensions;
+ foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
+ qmlTypesByCppName[ty->metaObject()->className()].insert(ty);
+ if (ty->isExtendedType()) {
+ extensions[ty->typeName()].insert(ty->metaObject()->className());
+ }
+ collectReachableMetaObjects(ty, &metas);
+ }
+
+ // Adjust ids of extended objects.
+ // The chain ends up being:
+ // __extended__.originalname - the base object
+ // __extension_0_.originalname - first extension
+ // ..
+ // __extension_n-2_.originalname - second to last extension
+ // originalname - last extension
+ // ### does this actually work for multiple extensions? it seems like the prototypes might be wrong
+ foreach (const QByteArray &extendedCpp, extensions.keys()) {
+ cppToId.remove(extendedCpp);
+ const QByteArray extendedId = convertToId(extendedCpp);
+ cppToId.insert(extendedCpp, "__extended__." + extendedId);
+ QSet<QByteArray> extensionCppNames = extensions.value(extendedCpp);
+ int c = 0;
+ foreach (const QByteArray &extensionCppName, extensionCppNames) {
+ if (c != extensionCppNames.size() - 1) {
+ QByteArray adjustedName = QString("__extension__%1.%2").arg(QString::number(c), QString(extendedId)).toAscii();
+ cppToId.insert(extensionCppName, adjustedName);
+ } else {
+ cppToId.insert(extensionCppName, extendedId);
+ }
+ ++c;
+ }
+ }
+
+ // find even more QMetaObjects by instantiating QML types and running
+ // over the instances
+ foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
+ if (ty->isExtendedType())
+ continue;
+
+ QByteArray tyName = ty->qmlTypeName();
+ tyName = tyName.mid(tyName.lastIndexOf('/') + 1);
+
+ QByteArray code = importCode.toUtf8();
+ code += tyName;
+ code += " {}\n";
+
+ QDeclarativeComponent c(engine);
+ c.setData(code, QUrl::fromLocalFile(pluginImportPath + "/typeinstance.qml"));
+
+ QObject *object = c.create();
+ if (object)
+ collectReachableMetaObjects(object, &metas);
+ else
+ qDebug() << "Could not create" << tyName << ":" << c.errorString();
+ }
+
+ return metas;
+}
+
+
+class Dumper
+{
+ QmlStreamWriter *qml;
+ QString relocatableModuleUri;
+
+public:
+ Dumper(QmlStreamWriter *qml) : qml(qml) {}
+
+ void setRelocatableModuleUri(const QString &uri)
+ {
+ relocatableModuleUri = uri;
+ }
+
+ void dump(const QMetaObject *meta)
+ {
+ qml->writeStartObject("Component");
+
+ QByteArray id = convertToId(meta->className());
+ qml->writeScriptBinding(QLatin1String("name"), enquote(id));
+
+ for (int index = meta->classInfoCount() - 1 ; index >= 0 ; --index) {
+ QMetaClassInfo classInfo = meta->classInfo(index);
+ if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) {
+ qml->writeScriptBinding(QLatin1String("defaultProperty"), enquote(QLatin1String(classInfo.value())));
+ break;
+ }
+ }
+
+ if (meta->superClass())
+ qml->writeScriptBinding(QLatin1String("prototype"), enquote(convertToId(meta->superClass()->className())));
+
+ QSet<const QDeclarativeType *> qmlTypes = qmlTypesByCppName.value(meta->className());
+ if (!qmlTypes.isEmpty()) {
+ QStringList exports;
+
+ foreach (const QDeclarativeType *qmlTy, qmlTypes) {
+ QString qmlTyName = qmlTy->qmlTypeName();
+ // some qmltype names are missing the actual names, ignore that import
+ if (qmlTyName.endsWith('/'))
+ continue;
+ if (qmlTyName.startsWith(relocatableModuleUri + QLatin1Char('/'))) {
+ qmlTyName.remove(0, relocatableModuleUri.size() + 1);
+ }
+ exports += enquote(QString("%1 %2.%3").arg(
+ qmlTyName,
+ QString::number(qmlTy->majorVersion()),
+ QString::number(qmlTy->minorVersion())));
+ }
+
+ // ensure exports are sorted and don't change order when the plugin is dumped again
+ exports.removeDuplicates();
+ qSort(exports);
+
+ qml->writeArrayBinding(QLatin1String("exports"), exports);
+
+ if (const QMetaObject *attachedType = (*qmlTypes.begin())->attachedPropertiesType()) {
+ qml->writeScriptBinding(QLatin1String("attachedType"), enquote(
+ convertToId(attachedType->className())));
+ }
+ }
+
+ for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
+ dump(meta->enumerator(index));
+
+ for (int index = meta->propertyOffset(); index < meta->propertyCount(); ++index)
+ dump(meta->property(index));
+
+ for (int index = meta->methodOffset(); index < meta->methodCount(); ++index)
+ dump(meta->method(index));
+
+ qml->writeEndObject();
+ }
+
+ void writeEasingCurve()
+ {
+ qml->writeStartObject("Component");
+ qml->writeScriptBinding(QLatin1String("name"), enquote(QLatin1String("QEasingCurve")));
+ qml->writeScriptBinding(QLatin1String("prototype"), enquote(QLatin1String("QDeclarativeEasingValueType")));
+ qml->writeEndObject();
+ }
+
+private:
+ static QString enquote(const QString &string)
+ {
+ return QString("\"%1\"").arg(string);
+ }
+
+ /* Removes pointer and list annotations from a type name, returning
+ what was removed in isList and isPointer
+ */
+ static void removePointerAndList(QByteArray *typeName, bool *isList, bool *isPointer)
+ {
+ static QByteArray declListPrefix = "QDeclarativeListProperty<";
+
+ if (typeName->endsWith('*')) {
+ *isPointer = true;
+ typeName->truncate(typeName->length() - 1);
+ removePointerAndList(typeName, isList, isPointer);
+ } else if (typeName->startsWith(declListPrefix)) {
+ *isList = true;
+ typeName->truncate(typeName->length() - 1); // get rid of the suffix '>'
+ *typeName = typeName->mid(declListPrefix.size());
+ removePointerAndList(typeName, isList, isPointer);
+ }
+
+ *typeName = convertToId(*typeName);
+ }
+
+ void writeTypeProperties(QByteArray typeName, bool isWritable)
+ {
+ bool isList = false, isPointer = false;
+ removePointerAndList(&typeName, &isList, &isPointer);
+
+ qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
+ if (isList)
+ qml->writeScriptBinding(QLatin1String("isList"), QLatin1String("true"));
+ if (!isWritable)
+ qml->writeScriptBinding(QLatin1String("isReadonly"), QLatin1String("true"));
+ if (isPointer)
+ qml->writeScriptBinding(QLatin1String("isPointer"), QLatin1String("true"));
+ }
+
+ void dump(const QMetaProperty &prop)
+ {
+ qml->writeStartObject("Property");
+
+ qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(prop.name())));
+ writeTypeProperties(prop.typeName(), prop.isWritable());
+
+ qml->writeEndObject();
+ }
+
+ void dump(const QMetaMethod &meth)
+ {
+ if (meth.methodType() == QMetaMethod::Signal) {
+ if (meth.access() != QMetaMethod::Protected)
+ return; // nothing to do.
+ } else if (meth.access() != QMetaMethod::Public) {
+ return; // nothing to do.
+ }
+
+ QByteArray name = meth.signature();
+ int lparenIndex = name.indexOf('(');
+ if (lparenIndex == -1) {
+ return; // invalid signature
+ }
+ name = name.left(lparenIndex);
+
+ if (meth.methodType() == QMetaMethod::Signal)
+ qml->writeStartObject(QLatin1String("Signal"));
+ else
+ qml->writeStartObject(QLatin1String("Method"));
+
+ qml->writeScriptBinding(QLatin1String("name"), enquote(name));
+
+ const QString typeName = convertToId(meth.typeName());
+ if (! typeName.isEmpty())
+ qml->writeScriptBinding(QLatin1String("type"), enquote(typeName));
+
+ for (int i = 0; i < meth.parameterTypes().size(); ++i) {
+ QByteArray argName = meth.parameterNames().at(i);
+
+ qml->writeStartObject(QLatin1String("Parameter"));
+ if (! argName.isEmpty())
+ qml->writeScriptBinding(QLatin1String("name"), enquote(argName));
+ writeTypeProperties(meth.parameterTypes().at(i), true);
+ qml->writeEndObject();
+ }
+
+ qml->writeEndObject();
+ }
+
+ void dump(const QMetaEnum &e)
+ {
+ qml->writeStartObject(QLatin1String("Enum"));
+ qml->writeScriptBinding(QLatin1String("name"), enquote(QString::fromUtf8(e.name())));
+
+ QList<QPair<QString, QString> > namesValues;
+ for (int index = 0; index < e.keyCount(); ++index) {
+ namesValues.append(qMakePair(enquote(QString::fromUtf8(e.key(index))), QString::number(e.value(index))));
+ }
+
+ qml->writeScriptObjectLiteralBinding(QLatin1String("values"), namesValues);
+ qml->writeEndObject();
+ }
+};
+
+
+enum ExitCode {
+ EXIT_INVALIDARGUMENTS = 1,
+ EXIT_SEGV = 2,
+ EXIT_IMPORTERROR = 3
+};
+
+#ifdef Q_OS_UNIX
+void sigSegvHandler(int) {
+ fprintf(stderr, "Error: SEGV\n");
+ if (!currentProperty.isEmpty())
+ fprintf(stderr, "While processing the property '%s', which probably has uninitialized data.\n", currentProperty.toLatin1().constData());
+ exit(EXIT_SEGV);
+}
+#endif
+
+void printUsage(const QString &appName)
+{
+ qWarning() << qPrintable(QString(
+ "Usage: %1 [-notrelocatable] module.uri version [module/import/path]\n"
+ " %1 -path path/to/qmldir/directory [version]\n"
+ " %1 -builtins\n"
+ "Example: %1 Qt.labs.particles 4.7 /home/user/dev/qt-install/imports").arg(
+ appName));
+}
+
+int main(int argc, char *argv[])
+{
+#ifdef Q_OS_UNIX
+ // qmldump may crash, but we don't want any crash handlers to pop up
+ // therefore we intercept the segfault and just exit() ourselves
+ struct sigaction action;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = &sigSegvHandler;
+ action.sa_flags = 0;
+
+ sigaction(SIGSEGV, &action, 0);
+#endif
+
+#ifdef QT_SIMULATOR
+ // Running this application would bring up the Qt Simulator (since it links QtGui), avoid that!
+ QtSimulatorPrivate::SimulatorConnection::createStubInstance();
+#endif
+ QApplication app(argc, argv);
+ const QStringList args = app.arguments();
+ const QString appName = QFileInfo(app.applicationFilePath()).baseName();
+ if (!(args.size() >= 3
+ || (args.size() == 2
+ && (args.at(1) == QLatin1String("--builtins")
+ || args.at(1) == QLatin1String("-builtins"))))) {
+ printUsage(appName);
+ return EXIT_INVALIDARGUMENTS;
+ }
+
+ QString pluginImportUri;
+ QString pluginImportVersion;
+ bool relocatable = true;
+ bool pathImport = false;
+ if (args.size() >= 3) {
+ QStringList positionalArgs;
+ foreach (const QString &arg, args) {
+ if (!arg.startsWith(QLatin1Char('-'))) {
+ positionalArgs.append(arg);
+ continue;
+ }
+
+ if (arg == QLatin1String("--notrelocatable")
+ || arg == QLatin1String("-notrelocatable")) {
+ relocatable = false;
+ } else if (arg == QLatin1String("--path")
+ || arg == QLatin1String("-path")) {
+ pathImport = true;
+ } else {
+ qWarning() << "Invalid argument: " << arg;
+ return EXIT_INVALIDARGUMENTS;
+ }
+ }
+
+ if (!pathImport) {
+ if (positionalArgs.size() != 3 && positionalArgs.size() != 4) {
+ qWarning() << "Incorrect number of positional arguments";
+ return EXIT_INVALIDARGUMENTS;
+ }
+ pluginImportUri = positionalArgs[1];
+ pluginImportVersion = positionalArgs[2];
+ if (positionalArgs.size() >= 4)
+ pluginImportPath = positionalArgs[3];
+ } else {
+ if (positionalArgs.size() != 2 && positionalArgs.size() != 3) {
+ qWarning() << "Incorrect number of positional arguments";
+ return EXIT_INVALIDARGUMENTS;
+ }
+ pluginImportPath = QDir::fromNativeSeparators(positionalArgs[1]);
+ if (positionalArgs.size() == 3)
+ pluginImportVersion = positionalArgs[2];
+ }
+ }
+
+ QDeclarativeView view;
+ QDeclarativeEngine *engine = view.engine();
+ if (!pluginImportPath.isEmpty())
+ engine->addImportPath(pluginImportPath);
+
+ // find all QMetaObjects reachable from the builtin module
+ QByteArray importCode("import QtQuick 1.0\n");
+ QSet<const QMetaObject *> defaultReachable = collectReachableMetaObjects(importCode, engine);
+
+ // this will hold the meta objects we want to dump information of
+ QSet<const QMetaObject *> metas;
+
+ if (pluginImportUri.isEmpty() && !pathImport) {
+ metas = defaultReachable;
+ } else {
+ // find all QMetaObjects reachable when the specified module is imported
+ if (!pathImport) {
+ importCode += QString("import %0 %1\n").arg(pluginImportUri, pluginImportVersion).toAscii();
+ } else {
+ // pluginImportVersion can be empty
+ importCode += QString("import \".\" %2\n").arg(pluginImportVersion).toAscii();
+ }
+
+ // create a component with these imports to make sure the imports are valid
+ // and to populate the declarative meta type system
+ {
+ QByteArray code = importCode;
+ code += "QtObject {}";
+ QDeclarativeComponent c(engine);
+
+ c.setData(code, QUrl::fromLocalFile(pluginImportPath + "/typelist.qml"));
+ c.create();
+ if (!c.errors().isEmpty()) {
+ foreach (const QDeclarativeError &error, c.errors())
+ qWarning() << error.toString();
+ return EXIT_IMPORTERROR;
+ }
+ }
+
+ QSet<const QMetaObject *> candidates = collectReachableMetaObjects(importCode, engine);
+ candidates.subtract(defaultReachable);
+
+ // 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) {
+ if (!defaultReachableNames.contains(mo->className()))
+ metas.insert(mo);
+ }
+ }
+
+ // setup static rewrites of type names
+ cppToId.insert("QString", "string");
+ cppToId.insert("QDeclarativeEasingValueType::Type", "Type");
+
+ // start dumping data
+ QByteArray bytes;
+ QmlStreamWriter qml(&bytes);
+
+ qml.writeStartDocument();
+ qml.writeLibraryImport(QLatin1String("QtQuick.tooling"), 1, 0);
+ qml.write("\n"
+ "// This file describes the plugin-supplied types contained in the library.\n"
+ "// It is used for QML tooling purposes only.\n"
+ "\n");
+ qml.writeStartObject("Module");
+
+ // 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->className()), meta);
+
+ Dumper dumper(&qml);
+ if (relocatable)
+ dumper.setRelocatableModuleUri(pluginImportUri);
+ foreach (const QMetaObject *meta, nameToMeta) {
+ dumper.dump(meta);
+ }
+
+ // define QEasingCurve as an extension of QDeclarativeEasingValueType, this way
+ // properties using the QEasingCurve type get useful type information.
+ if (pluginImportUri.isEmpty())
+ dumper.writeEasingCurve();
+
+ qml.writeEndObject();
+ qml.writeEndDocument();
+
+ std::cout << bytes.constData();
+
+ // workaround to avoid crashes on exit
+ QTimer timer;
+ timer.setSingleShot(true);
+ timer.setInterval(0);
+ QObject::connect(&timer, SIGNAL(timeout()), &app, SLOT(quit()));
+ timer.start();
+
+ return app.exec();
+}
diff --git a/tools/qmlplugindump/qmlplugindump.pro b/tools/qmlplugindump/qmlplugindump.pro
new file mode 100644
index 0000000000..53827e2f40
--- /dev/null
+++ b/tools/qmlplugindump/qmlplugindump.pro
@@ -0,0 +1,20 @@
+TEMPLATE = app
+CONFIG += qt uic console
+DESTDIR = ../../bin
+
+QT += declarative
+
+TARGET = qmlplugindump
+
+SOURCES += \
+ main.cpp \
+ qmlstreamwriter.cpp
+
+HEADERS += \
+ qmlstreamwriter.h
+
+OTHER_FILES += Info.plist
+macx: QMAKE_INFO_PLIST = Info.plist
+
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
diff --git a/tools/qmlplugindump/qmlstreamwriter.cpp b/tools/qmlplugindump/qmlstreamwriter.cpp
new file mode 100644
index 0000000000..d083f7b64c
--- /dev/null
+++ b/tools/qmlplugindump/qmlstreamwriter.cpp
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlstreamwriter.h"
+
+#include <QtCore/QBuffer>
+#include <QtCore/QStringList>
+
+QmlStreamWriter::QmlStreamWriter(QByteArray *array)
+ : m_indentDepth(0)
+ , m_pendingLineLength(0)
+ , m_maybeOneline(false)
+ , m_stream(new QBuffer(array))
+{
+ m_stream->open(QIODevice::WriteOnly);
+}
+
+void QmlStreamWriter::writeStartDocument()
+{
+}
+
+void QmlStreamWriter::writeEndDocument()
+{
+}
+
+void QmlStreamWriter::writeLibraryImport(const QString &uri, int majorVersion, int minorVersion, const QString &as)
+{
+ m_stream->write(QString("import %1 %2.%3").arg(uri, QString::number(majorVersion), QString::number(minorVersion)).toUtf8());
+ if (!as.isEmpty())
+ m_stream->write(QString(" as %1").arg(as).toUtf8());
+ m_stream->write("\n");
+}
+
+void QmlStreamWriter::writeStartObject(const QString &component)
+{
+ flushPotentialLinesWithNewlines();
+ writeIndent();
+ m_stream->write(QString("%1 {").arg(component).toUtf8());
+ ++m_indentDepth;
+ m_maybeOneline = true;
+}
+
+void QmlStreamWriter::writeEndObject()
+{
+ if (m_maybeOneline && !m_pendingLines.isEmpty()) {
+ --m_indentDepth;
+ for (int i = 0; i < m_pendingLines.size(); ++i) {
+ m_stream->write(" ");
+ m_stream->write(m_pendingLines.at(i).trimmed());
+ if (i != m_pendingLines.size() - 1)
+ m_stream->write(";");
+ }
+ m_stream->write(" }\n");
+ m_pendingLines.clear();
+ m_pendingLineLength = 0;
+ m_maybeOneline = false;
+ } else {
+ if (m_maybeOneline)
+ flushPotentialLinesWithNewlines();
+ --m_indentDepth;
+ writeIndent();
+ m_stream->write("}\n");
+ }
+}
+
+void QmlStreamWriter::writeScriptBinding(const QString &name, const QString &rhs)
+{
+ writePotentialLine(QString("%1: %2").arg(name, rhs).toUtf8());
+}
+
+void QmlStreamWriter::writeArrayBinding(const QString &name, const QStringList &elements)
+{
+ flushPotentialLinesWithNewlines();
+ writeIndent();
+ m_stream->write(QString("%1: [\n").arg(name).toUtf8());
+ ++m_indentDepth;
+ for (int i = 0; i < elements.size(); ++i) {
+ writeIndent();
+ m_stream->write(elements.at(i).toUtf8());
+ if (i != elements.size() - 1) {
+ m_stream->write(",\n");
+ } else {
+ m_stream->write("\n");
+ }
+ }
+ --m_indentDepth;
+ writeIndent();
+ m_stream->write("]\n");
+}
+
+void QmlStreamWriter::write(const QString &data)
+{
+ flushPotentialLinesWithNewlines();
+ m_stream->write(data.toUtf8());
+}
+
+void QmlStreamWriter::writeScriptObjectLiteralBinding(const QString &name, const QList<QPair<QString, QString> > &keyValue)
+{
+ flushPotentialLinesWithNewlines();
+ writeIndent();
+ m_stream->write(QString("%1: {\n").arg(name).toUtf8());
+ ++m_indentDepth;
+ for (int i = 0; i < keyValue.size(); ++i) {
+ const QString key = keyValue.at(i).first;
+ const QString value = keyValue.at(i).second;
+ writeIndent();
+ m_stream->write(QString("%1: %2").arg(key, value).toUtf8());
+ if (i != keyValue.size() - 1) {
+ m_stream->write(",\n");
+ } else {
+ m_stream->write("\n");
+ }
+ }
+ --m_indentDepth;
+ writeIndent();
+ m_stream->write("}\n");
+}
+
+void QmlStreamWriter::writeIndent()
+{
+ m_stream->write(QByteArray(m_indentDepth * 4, ' '));
+}
+
+void QmlStreamWriter::writePotentialLine(const QByteArray &line)
+{
+ m_pendingLines.append(line);
+ m_pendingLineLength += line.size();
+ if (m_pendingLineLength >= 80) {
+ flushPotentialLinesWithNewlines();
+ }
+}
+
+void QmlStreamWriter::flushPotentialLinesWithNewlines()
+{
+ if (m_maybeOneline)
+ m_stream->write("\n");
+ foreach (const QByteArray &line, m_pendingLines) {
+ writeIndent();
+ m_stream->write(line);
+ m_stream->write("\n");
+ }
+ m_pendingLines.clear();
+ m_pendingLineLength = 0;
+ m_maybeOneline = false;
+}
diff --git a/tools/qmlplugindump/qmlstreamwriter.h b/tools/qmlplugindump/qmlstreamwriter.h
new file mode 100644
index 0000000000..cd73aad8f2
--- /dev/null
+++ b/tools/qmlplugindump/qmlstreamwriter.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLSTREAMWRITER_H
+#define QMLSTREAMWRITER_H
+
+#include <QtCore/QIODevice>
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QPair>
+
+class QmlStreamWriter
+{
+public:
+ QmlStreamWriter(QByteArray *array);
+
+ void writeStartDocument();
+ void writeEndDocument();
+ void writeLibraryImport(const QString &uri, int majorVersion, int minorVersion, const QString &as = QString());
+ //void writeFilesystemImport(const QString &file, const QString &as = QString());
+ void writeStartObject(const QString &component);
+ void writeEndObject();
+ void writeScriptBinding(const QString &name, const QString &rhs);
+ void writeScriptObjectLiteralBinding(const QString &name, const QList<QPair<QString, QString> > &keyValue);
+ void writeArrayBinding(const QString &name, const QStringList &elements);
+ void write(const QString &data);
+
+private:
+ void writeIndent();
+ void writePotentialLine(const QByteArray &line);
+ void flushPotentialLinesWithNewlines();
+
+ int m_indentDepth;
+ QList<QByteArray> m_pendingLines;
+ int m_pendingLineLength;
+ bool m_maybeOneline;
+ QScopedPointer<QIODevice> m_stream;
+};
+
+#endif // QMLSTREAMWRITER_H
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
new file mode 100644
index 0000000000..765a9dc2fb
--- /dev/null
+++ b/tools/qmlscene/main.cpp
@@ -0,0 +1,574 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qabstractanimation.h>
+#include <QtGui/qapplication.h>
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativeengine.h>
+#include <QtDeclarative/qdeclarativecomponent.h>
+#include <QtDeclarative/qdeclarativeview.h>
+#include <QtCore/qdir.h>
+#include <QtGui/QFormLayout>
+#include <QtGui/QComboBox>
+#include <QtGui/QCheckBox>
+#include <QtGui/QDialog>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QFileDialog>
+#include <QtGui/QGraphicsView>
+
+#include <QtDeclarative/qdeclarativeitem.h>
+#include <QtDeclarative/qdeclarativecontext.h>
+#include <private/qdeclarativedebughelper_p.h>
+
+// ### This should be private API
+#include <qsgitem.h>
+#include <qsgview.h>
+
+#define QT_NO_SCENEGRAPHITEM
+
+#ifndef QT_NO_SCENEGRAPHITEM
+#include "scenegraphitem.h"
+#endif
+
+#include <QtCore/qmath.h>
+
+#ifdef QML_RUNTIME_TESTING
+class RenderStatistics
+{
+public:
+ static void updateStats();
+ static void printTotalStats();
+private:
+ static QVector<qreal> timePerFrame;
+ static QVector<int> timesPerFrames;
+};
+
+QVector<qreal> RenderStatistics::timePerFrame;
+QVector<int> RenderStatistics::timesPerFrames;
+
+void RenderStatistics::updateStats()
+{
+ static QTime time;
+ static int frames;
+ static int lastTime;
+
+ if (frames == 0) {
+ time.start();
+ } else {
+ int elapsed = time.elapsed();
+ timesPerFrames.append(elapsed - lastTime);
+ lastTime = elapsed;
+
+ if (elapsed > 5000) {
+ qreal avgtime = elapsed / (qreal) frames;
+ qreal var = 0;
+ for (int i = 0; i < timesPerFrames.size(); ++i) {
+ qreal diff = timesPerFrames.at(i) - avgtime;
+ var += diff * diff;
+ }
+ var /= timesPerFrames.size();
+
+ qDebug("Average time per frame: %f ms (%i fps), std.dev: %f ms", avgtime, qRound(1000. / avgtime), qSqrt(var));
+
+ timePerFrame.append(avgtime);
+ timesPerFrames.clear();
+ time.start();
+ lastTime = 0;
+ frames = 0;
+ }
+ }
+ ++frames;
+}
+
+void RenderStatistics::printTotalStats()
+{
+ int count = timePerFrame.count();
+ if (count == 0)
+ return;
+
+ qreal minTime = 0;
+ qreal maxTime = 0;
+ qreal avg = 0;
+ for (int i = 0; i < count; ++i) {
+ minTime = minTime == 0 ? timePerFrame.at(i) : qMin(minTime, timePerFrame.at(i));
+ maxTime = qMax(maxTime, timePerFrame.at(i));
+ avg += timePerFrame.at(i);
+ }
+ avg /= count;
+
+ qDebug(" ");
+ qDebug("----- Statistics -----");
+ qDebug("Average time per frame: %f ms (%i fps)", avg, qRound(1000. / avg));
+ qDebug("Best time per frame: %f ms (%i fps)", minTime, int(1000 / minTime));
+ qDebug("Worst time per frame: %f ms (%i fps)", maxTime, int(1000 / maxTime));
+ qDebug("----------------------");
+ qDebug(" ");
+}
+#endif
+
+
+static QGLFormat getFormat()
+{
+ QGLFormat f = QGLFormat::defaultFormat();
+ f.setSampleBuffers(!qApp->arguments().contains("--no-multisample"));
+ f.setSwapInterval(qApp->arguments().contains("--nonblocking-swap") ? 0 : 1);
+ f.setStereo(qApp->arguments().contains("--stereo"));
+ return f;
+}
+
+class MyQSGView : public QSGView
+{
+public:
+ MyQSGView() : QSGView(getFormat())
+ {
+ setResizeMode(QSGView::SizeRootObjectToView);
+ }
+
+protected:
+ void paintEvent(QPaintEvent *e) {
+ QSGView::paintEvent(e);
+
+#ifdef QML_RUNTIME_TESTING
+// RenderStatistics::updateStats();
+#endif
+
+ static bool continuousUpdate = qApp->arguments().contains("--continuous-update");
+ if (continuousUpdate)
+ update();
+ }
+};
+
+class MyDeclarativeView: public QDeclarativeView
+{
+public:
+ MyDeclarativeView(QWidget *parent = 0) : QDeclarativeView(parent)
+ {
+ setResizeMode(QDeclarativeView::SizeRootObjectToView);
+ }
+
+protected:
+ void paintEvent(QPaintEvent *event)
+ {
+ QDeclarativeView::paintEvent(event);
+
+#ifdef QML_RUNTIME_TESTING
+ RenderStatistics::updateStats();
+#endif
+
+ static bool continuousUpdate = qApp->arguments().contains("--continuous-update");
+ if (continuousUpdate)
+ scene()->update();
+ }
+};
+
+#ifndef QT_NO_SCENEGRAPHITEM
+class MyGraphicsView: public QGraphicsView
+{
+public:
+ MyGraphicsView(bool clip, QWidget *parent = 0) : QGraphicsView(parent)
+ {
+ setViewport(new QGLWidget(getFormat()));
+ setScene(&scene);
+ scene.addItem(&item);
+ item.setFlag(QGraphicsItem::ItemClipsToShape, clip);
+ QGraphicsTextItem *text;
+ text = scene.addText(QLatin1String("Scene graph on graphics view."), QFont(QLatin1String("Times"), 10));
+ text->setX(5);
+ text->setY(5);
+ text->setDefaultTextColor(Qt::black);
+ text = scene.addText(QLatin1String("Scene graph on graphics view."), QFont(QLatin1String("Times"), 10));
+ text->setX(4);
+ text->setY(4);
+ text->setDefaultTextColor(Qt::yellow);
+ }
+
+ SceneGraphItem *sceneGraphItem() { return &item; }
+
+protected:
+ void paintEvent(QPaintEvent *event)
+ {
+ QGraphicsView::paintEvent(event);
+
+#ifdef QML_RUNTIME_TESTING
+ RenderStatistics::updateStats();
+#endif
+
+ static bool continuousUpdate = qApp->arguments().contains("--continuous-update");
+ if (continuousUpdate)
+ QGraphicsView::scene()->update();
+ }
+
+ QGraphicsScene scene;
+ SceneGraphItem item;
+};
+#endif
+
+struct Options
+{
+ Options()
+ : originalQml(false)
+ , originalQmlRaster(false)
+ , maximized(false)
+ , fullscreen(false)
+ , scenegraphOnGraphicsview(false)
+ , clip(false)
+ , versionDetection(true)
+ {
+ }
+
+ QUrl file;
+ bool originalQml;
+ bool originalQmlRaster;
+ bool maximized;
+ bool fullscreen;
+ bool scenegraphOnGraphicsview;
+ bool clip;
+ bool versionDetection;
+};
+
+#if defined(QMLSCENE_BUNDLE)
+Q_DECLARE_METATYPE(QFileInfo);
+QFileInfoList findQmlFiles(const QString &dirName)
+{
+ QDir dir(dirName);
+
+ QFileInfoList ret;
+ if (dir.exists()) {
+ QFileInfoList fileInfos = dir.entryInfoList(QStringList() << "*.qml",
+ QDir::Files | QDir::AllDirs | QDir::NoDotAndDotDot);
+
+ foreach (QFileInfo fileInfo, fileInfos) {
+ if (fileInfo.isDir())
+ ret += findQmlFiles(fileInfo.filePath());
+ else if (fileInfo.fileName().length() > 0 && fileInfo.fileName().at(0).isLower())
+ ret.append(fileInfo);
+ }
+ }
+
+ return ret;
+}
+
+static int displayOptionsDialog(Options *options)
+{
+ QDialog dialog;
+
+ QFormLayout *layout = new QFormLayout(&dialog);
+
+ QComboBox *qmlFileComboBox = new QComboBox(&dialog);
+ QFileInfoList fileInfos = findQmlFiles(":/bundle") + findQmlFiles("./qmlscene-resources");
+
+ foreach (QFileInfo fileInfo, fileInfos)
+ qmlFileComboBox->addItem(fileInfo.dir().dirName() + "/" + fileInfo.fileName(), QVariant::fromValue(fileInfo));
+
+ QCheckBox *originalCheckBox = new QCheckBox(&dialog);
+ originalCheckBox->setText("Use original QML viewer");
+ originalCheckBox->setChecked(options->originalQml);
+
+ QCheckBox *fullscreenCheckBox = new QCheckBox(&dialog);
+ fullscreenCheckBox->setText("Start fullscreen");
+ fullscreenCheckBox->setChecked(options->fullscreen);
+
+ QCheckBox *maximizedCheckBox = new QCheckBox(&dialog);
+ maximizedCheckBox->setText("Start maximized");
+ maximizedCheckBox->setChecked(options->maximized);
+
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
+ Qt::Horizontal,
+ &dialog);
+ QObject::connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ QObject::connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
+
+ layout->addRow("Qml file:", qmlFileComboBox);
+ layout->addWidget(originalCheckBox);
+ layout->addWidget(maximizedCheckBox);
+ layout->addWidget(fullscreenCheckBox);
+ layout->addWidget(buttonBox);
+
+ int result = dialog.exec();
+ if (result == QDialog::Accepted) {
+ QVariant variant = qmlFileComboBox->itemData(qmlFileComboBox->currentIndex());
+ QFileInfo fileInfo = variant.value<QFileInfo>();
+
+ if (fileInfo.canonicalFilePath().startsWith(":"))
+ options->file = QUrl("qrc" + fileInfo.canonicalFilePath());
+ else
+ options->file = QUrl::fromLocalFile(fileInfo.canonicalFilePath());
+ options->originalQml = originalCheckBox->isChecked();
+ options->maximized = maximizedCheckBox->isChecked();
+ options->fullscreen = fullscreenCheckBox->isChecked();
+ }
+ return result;
+}
+#endif
+
+static void checkAndAdaptVersion(const QUrl &url)
+{
+ if (!qgetenv("QMLSCENE_IMPORT_NAME").isEmpty()) {
+ return;
+ }
+
+ QString fileName = url.toLocalFile();
+ if (fileName.isEmpty())
+ return;
+
+ QFile f(fileName);
+ if (!f.open(QFile::ReadOnly | QFile::Text)) {
+ qWarning("qmlscene: failed to check version of file '%s', could not open...",
+ qPrintable(fileName));
+ return;
+ }
+
+ QRegExp quick1("import +QtQuick +1\\.");
+ QRegExp qt47("import +Qt +4\\.7");
+
+ QString envToWrite;
+ QString compat;
+
+ QTextStream stream(&f);
+ bool codeFound= false;
+ while (!codeFound && envToWrite.isEmpty()) {
+ QString line = stream.readLine();
+ if (line.contains("{"))
+ codeFound = true;
+ if (quick1.indexIn(line) >= 0) {
+ envToWrite = QLatin1String("quick1");
+ compat = QLatin1String("QtQuick 1.0");
+ } else if (qt47.indexIn(line) >= 0) {
+ envToWrite = QLatin1String("qt");
+ compat = QLatin1String("Qt 4.7");
+ }
+ }
+
+ if (!envToWrite.isEmpty()) {
+ qWarning("qmlscene: Autodetecting compatibility import \"%s\"...", qPrintable(compat));
+ if (qgetenv("QMLSCENE_IMPORT_NAME").isEmpty())
+ qputenv("QMLSCENE_IMPORT_NAME", envToWrite.toLatin1().constData());
+ }
+}
+
+static void displayFileDialog(Options *options)
+{
+ QString fileName = QFileDialog::getOpenFileName(0, "Open QML file", QString(), "QML Files (*.qml)");
+ if (!fileName.isEmpty()) {
+ QFileInfo fi(fileName);
+ options->file = QUrl::fromLocalFile(fi.canonicalFilePath());
+ }
+}
+
+static void loadDummyDataFiles(QDeclarativeEngine &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();
+ QDeclarativeComponent comp(&engine);
+ comp.setData(data, QUrl());
+ QObject *dummyData = comp.create();
+
+ if(comp.isError()) {
+ QList<QDeclarativeError> errors = comp.errors();
+ foreach (const QDeclarativeError &error, errors) {
+ qWarning() << error;
+ }
+ }
+
+ if (dummyData) {
+ qWarning() << "Loaded dummy data:" << dir.filePath(qml);
+ qml.truncate(qml.length()-4);
+ engine.rootContext()->setContextProperty(qml, dummyData);
+ dummyData->setParent(&engine);
+ }
+ }
+}
+
+static void usage()
+{
+ qWarning("Usage: qmlscene [options] <filename>");
+ qWarning(" ");
+ qWarning(" options:");
+ qWarning(" --maximized ............................... run maximized");
+ qWarning(" --fullscreen .............................. run fullscreen");
+ qWarning(" --original-qml ............................ run using QGraphicsView instead of scenegraph (OpenGL engine)");
+ qWarning(" --original-qml-raster ..................... run using QGraphicsView instead of scenegraph (Raster engine)");
+ qWarning(" --no-multisample .......................... Disable multisampling (anti-aliasing)");
+ qWarning(" --continuous-update ....................... Continuously render the scene");
+ qWarning(" --nonblocking-swap ........................ Do not wait for v-sync to swap buffers");
+ qWarning(" --stereo .................................. Enable stereo on the GL context");
+#ifndef QT_NO_SCENEGRAPHITEM
+ qWarning(" --sg-on-gv [--clip] ....................... Scenegraph on graphicsview (and clip to item)");
+#endif
+ qWarning(" --no-version-detection .................... Do not try to detect the version of the .qml file");
+
+ qWarning(" ");
+ exit(1);
+}
+
+int main(int argc, char ** argv)
+{
+#ifdef Q_WS_X11
+ QApplication::setAttribute(Qt::AA_X11InitThreads);
+#endif
+
+ Options options;
+
+ QDeclarativeDebugHelper::enableDebugging();
+ QStringList imports;
+ for (int i = 1; i < argc; ++i) {
+ if (*argv[i] != '-' && QFileInfo(argv[i]).exists())
+ options.file = QUrl::fromLocalFile(argv[i]);
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--original-qml"))
+ options.originalQml = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--original-qml-raster"))
+ options.originalQmlRaster = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--maximized"))
+ options.maximized = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--fullscreen"))
+ options.fullscreen = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--sg-on-gv"))
+ options.scenegraphOnGraphicsview = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--clip"))
+ options.clip = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--no-version-detection"))
+ options.versionDetection = false;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("-i") && i + 1 < argc)
+ imports.append(QString::fromLatin1(argv[++i]));
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--help")
+ || QString::fromLatin1(argv[i]).toLower() == QLatin1String("-help")
+ || QString::fromLatin1(argv[i]).toLower() == QLatin1String("--h")
+ || QString::fromLatin1(argv[i]).toLower() == QLatin1String("-h"))
+ usage();
+ }
+
+ QApplication::setGraphicsSystem("raster");
+
+ QApplication app(argc, argv);
+ app.setApplicationName("QtQmlViewer");
+ app.setOrganizationName("Nokia");
+ app.setOrganizationDomain("nokia.com");
+
+ if (options.file.isEmpty())
+#if defined(QMLSCENE_BUNDLE)
+ displayOptionsDialog(&options);
+#else
+ displayFileDialog(&options);
+#endif
+
+ QWidget *view = 0;
+ QDeclarativeEngine *engine = 0;
+
+ int exitCode = 0;
+
+ if (!options.file.isEmpty()) {
+#ifndef QT_NO_SCENEGRAPHITEM
+ if (options.scenegraphOnGraphicsview) {
+ MyGraphicsView *gvView = new MyGraphicsView(options.clip);
+ SceneGraphItem *item = gvView->sceneGraphItem();
+ engine = item->engine();
+ for (int i = 0; i < imports.size(); ++i)
+ engine->addImportPath(imports.at(i));
+ view = gvView;
+ if (options.file.isLocalFile()) {
+ QFileInfo fi(options.file.toLocalFile());
+ loadDummyDataFiles(*engine, fi.path());
+ }
+ item->setSource(options.file);
+ } else
+#endif
+ if (!options.originalQml && !options.originalQmlRaster) {
+ if (options.versionDetection)
+ checkAndAdaptVersion(options.file);
+ QSGView *qxView = new MyQSGView();
+ engine = qxView->engine();
+ for (int i = 0; i < imports.size(); ++i)
+ engine->addImportPath(imports.at(i));
+ view = qxView;
+ if (options.file.isLocalFile()) {
+ QFileInfo fi(options.file.toLocalFile());
+ loadDummyDataFiles(*engine, fi.path());
+ }
+ qxView->setSource(options.file);
+
+ } else {
+ MyDeclarativeView *gvView = new MyDeclarativeView();
+ engine = gvView->engine();
+ for (int i = 0; i < imports.size(); ++i)
+ engine->addImportPath(imports.at(i));
+ view = gvView;
+ if (options.file.isLocalFile()) {
+ QFileInfo fi(options.file.toLocalFile());
+ loadDummyDataFiles(*engine, fi.path());
+ }
+ gvView->setSource(options.file);
+ if (!options.originalQmlRaster) {
+ QGLWidget *viewport = new QGLWidget(getFormat());
+ gvView->setViewport(viewport);
+ }
+ }
+
+ QObject::connect(engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
+
+ if (options.fullscreen)
+ view->showFullScreen();
+ else if (options.maximized)
+ view->showMaximized();
+ else
+ view->show();
+
+#ifdef Q_WS_MAC
+ view->raise();
+#endif
+
+ exitCode = app.exec();
+
+ delete view;
+
+#ifdef QML_RUNTIME_TESTING
+ RenderStatistics::printTotalStats();
+#endif
+ }
+
+ return exitCode;
+}
+
diff --git a/tools/qmlscene/qmlscene.pro b/tools/qmlscene/qmlscene.pro
new file mode 100644
index 0000000000..3849336fc8
--- /dev/null
+++ b/tools/qmlscene/qmlscene.pro
@@ -0,0 +1,20 @@
+TEMPLATE = app
+TARGET = qmlscene
+DESTDIR= ../../bin
+
+QT += declarative
+
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
+
+macx: CONFIG -= app_bundle
+
+SOURCES += main.cpp
+
+CONFIG += console
+
+symbian {
+ TARGET.EPOCHEAPSIZE = 0x20000 0x5000000
+}
+
+DEFINES += QML_RUNTIME_TESTING
diff --git a/tools/qmlviewer/main.cpp b/tools/qmlviewer/main.cpp
index b2c7f4f730..b1a10ff6c4 100644
--- a/tools/qmlviewer/main.cpp
+++ b/tools/qmlviewer/main.cpp
@@ -156,7 +156,9 @@ void usage()
qWarning(" -P <directory> ........................... prepend to the plugin search path");
#if defined(Q_WS_MAC)
qWarning(" -no-opengl ............................... don't use a QGLWidget for the viewport");
+ qWarning(" -opengl .................................. use a QGLWidget for the viewport (default)");
#else
+ qWarning(" -no-opengl ............................... don't use a QGLWidget for the viewport (default)");
qWarning(" -opengl .................................. use a QGLWidget for the viewport");
#endif
qWarning(" -script <path> ........................... set the script to use");
@@ -375,13 +377,10 @@ static void parseCommandLineOptions(const QStringList &arguments)
} else if (arg == "-translation") {
if (lastArg) usage();
opts.translationFile = arguments.at(++i);
-#if defined(Q_WS_MAC)
} else if (arg == "-no-opengl") {
opts.useGL = false;
-#else
} else if (arg == "-opengl") {
opts.useGL = true;
-#endif
} else if (arg == "-qmlbrowser") {
opts.useNativeFileBrowser = false;
} else if (arg == "-warnings") {
@@ -522,6 +521,8 @@ QDeclarativeViewer *openFile(const QString &fileName)
int main(int argc, char ** argv)
{
+ QDeclarativeDebugHelper::enableDebugging();
+
systemMsgOutput = qInstallMsgHandler(myMessageOutput);
#if defined (Q_WS_X11) || defined (Q_WS_MAC)
diff --git a/tools/qmlviewer/qmlruntime.cpp b/tools/qmlviewer/qmlruntime.cpp
index 36915d12bf..4bae7f3ec0 100644
--- a/tools/qmlviewer/qmlruntime.cpp
+++ b/tools/qmlviewer/qmlruntime.cpp
@@ -1477,6 +1477,7 @@ void QDeclarativeViewer::setUseGL(bool useGL)
QGLFormat format = QGLFormat::defaultFormat();
#ifdef Q_WS_MAC
format.setSampleBuffers(true);
+ format.setSwapInterval(1);
#else
format.setSampleBuffers(false);
#endif
diff --git a/tools/tools.pro b/tools/tools.pro
index 2035460ce2..ec83a1e76a 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -1,2 +1,2 @@
TEMPLATE = subdirs
-SUBDIRS += qmlviewer
+SUBDIRS += qmlviewer qmlscene qmlplugindump