2012-12-21 23:42:47 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2016-01-19 11:23:05 +00:00
|
|
|
** Copyright (C) 2016 Research In Motion.
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2012-12-21 23:42:47 +00:00
|
|
|
**
|
|
|
|
** This file is part of the tools applications of the Qt Toolkit.
|
|
|
|
**
|
2016-01-19 11:23:05 +00:00
|
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
2012-12-21 23:42:47 +00:00
|
|
|
** 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
|
2015-01-28 11:55:39 +00:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
2016-01-19 11:23:05 +00:00
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2012-12-21 23:42:47 +00:00
|
|
|
**
|
2016-01-19 11:23:05 +00:00
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2012-12-21 23:42:47 +00:00
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "conf.h"
|
|
|
|
|
|
|
|
#include <QCoreApplication>
|
2013-10-12 02:59:09 +00:00
|
|
|
|
|
|
|
#ifdef QT_GUI_LIB
|
2012-12-21 23:42:47 +00:00
|
|
|
#include <QGuiApplication>
|
2013-10-12 02:59:09 +00:00
|
|
|
#include <QWindow>
|
|
|
|
#include <QFileOpenEvent>
|
2015-06-03 09:05:12 +00:00
|
|
|
#include <QOpenGLContext>
|
|
|
|
#include <QOpenGLFunctions>
|
2012-12-21 23:42:47 +00:00
|
|
|
#ifdef QT_WIDGETS_LIB
|
|
|
|
#include <QApplication>
|
2013-10-12 02:59:09 +00:00
|
|
|
#endif // QT_WIDGETS_LIB
|
|
|
|
#endif // QT_GUI_LIB
|
|
|
|
|
2012-12-21 23:42:47 +00:00
|
|
|
#include <QQmlApplicationEngine>
|
2014-03-09 21:27:34 +00:00
|
|
|
#include <QQmlComponent>
|
|
|
|
#include <QDir>
|
2012-12-21 23:42:47 +00:00
|
|
|
#include <QFile>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QStringList>
|
2015-03-11 05:25:14 +00:00
|
|
|
#include <QScopedPointer>
|
2012-12-21 23:42:47 +00:00
|
|
|
#include <QDebug>
|
|
|
|
#include <QStandardPaths>
|
2014-03-09 21:27:34 +00:00
|
|
|
#include <QTranslator>
|
2012-12-21 23:42:47 +00:00
|
|
|
#include <QtGlobal>
|
2015-06-03 09:05:12 +00:00
|
|
|
#include <QLibraryInfo>
|
2012-12-21 23:42:47 +00:00
|
|
|
#include <qqml.h>
|
|
|
|
#include <qqmldebug.h>
|
2017-12-19 15:37:24 +00:00
|
|
|
|
|
|
|
#include <private/qtqmlglobal_p.h>
|
|
|
|
#if QT_CONFIG(qml_animation)
|
2012-12-21 23:42:47 +00:00
|
|
|
#include <private/qabstractanimation_p.h>
|
2017-03-30 08:41:52 +00:00
|
|
|
#endif
|
2012-12-21 23:42:47 +00:00
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
#define VERSION_MAJ 1
|
2015-03-05 10:46:46 +00:00
|
|
|
#define VERSION_MIN 1
|
|
|
|
#define VERSION_STR "1.1"
|
2012-12-21 23:42:47 +00:00
|
|
|
|
2013-11-18 14:57:08 +00:00
|
|
|
#define FILE_OPEN_EVENT_WAIT_TIME 3000 // ms
|
|
|
|
|
2018-02-21 09:41:54 +00:00
|
|
|
static Config *conf = nullptr;
|
|
|
|
static QQmlApplicationEngine *qae = nullptr;
|
2017-04-12 13:45:18 +00:00
|
|
|
#if defined(Q_OS_DARWIN) || defined(QT_GUI_LIB)
|
2013-11-18 14:57:08 +00:00
|
|
|
static int exitTimerId = -1;
|
2017-04-12 13:45:18 +00:00
|
|
|
#endif
|
2015-06-03 09:05:12 +00:00
|
|
|
bool verboseMode = false;
|
2012-12-21 23:42:47 +00:00
|
|
|
|
|
|
|
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()) {
|
2013-10-23 22:37:16 +00:00
|
|
|
printf("qml: Couldn't find required configuration file: %s\n",
|
|
|
|
qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath())));
|
2012-12-21 23:42:47 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!quiet) {
|
2015-06-03 09:05:12 +00:00
|
|
|
printf("qml: %s\n", QLibraryInfo::build());
|
2012-12-21 23:42:47 +00:00
|
|
|
if (builtIn)
|
2013-10-23 22:37:16 +00:00
|
|
|
printf("qml: Using built-in configuration.\n");
|
2012-12-21 23:42:47 +00:00
|
|
|
else
|
2013-10-23 22:37:16 +00:00
|
|
|
printf("qml: Using configuration file: %s\n",
|
|
|
|
qPrintable(settingsUrl.isLocalFile()
|
|
|
|
? QDir::toNativeSeparators(settingsUrl.toLocalFile())
|
|
|
|
: settingsUrl.toString()));
|
2012-12-21 23:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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){
|
2013-10-23 22:37:16 +00:00
|
|
|
printf("qml: Error loading configuration file: %s\n", qPrintable(c2.errorString()));
|
2012-12-21 23:42:47 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-12 02:59:09 +00:00
|
|
|
#ifdef QT_GUI_LIB
|
|
|
|
|
2013-11-18 14:57:08 +00:00
|
|
|
void noFilesGiven();
|
|
|
|
|
2012-12-21 23:42:47 +00:00
|
|
|
// Loads qml after receiving a QFileOpenEvent
|
|
|
|
class LoaderApplication : public QGuiApplication
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
LoaderApplication(int& argc, char **argv) : QGuiApplication(argc, argv) {}
|
|
|
|
|
2016-12-07 22:53:14 +00:00
|
|
|
bool event(QEvent *ev) override
|
2012-12-21 23:42:47 +00:00
|
|
|
{
|
2013-11-18 14:57:08 +00:00
|
|
|
if (ev->type() == QEvent::FileOpen) {
|
|
|
|
if (exitTimerId >= 0) {
|
|
|
|
killTimer(exitTimerId);
|
|
|
|
exitTimerId = -1;
|
|
|
|
}
|
2012-12-21 23:42:47 +00:00
|
|
|
qae->load(static_cast<QFileOpenEvent *>(ev)->url());
|
2013-11-18 14:57:08 +00:00
|
|
|
}
|
2012-12-21 23:42:47 +00:00
|
|
|
else
|
|
|
|
return QGuiApplication::event(ev);
|
|
|
|
return true;
|
|
|
|
}
|
2013-11-18 14:57:08 +00:00
|
|
|
|
2016-12-07 22:53:14 +00:00
|
|
|
void timerEvent(QTimerEvent *) override {
|
2013-11-18 14:57:08 +00:00
|
|
|
noFilesGiven();
|
|
|
|
}
|
2012-12-21 23:42:47 +00:00
|
|
|
};
|
|
|
|
|
2013-10-12 02:59:09 +00:00
|
|
|
#endif // QT_GUI_LIB
|
|
|
|
|
2012-12-21 23:42:47 +00:00
|
|
|
// 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)
|
2015-03-11 05:25:14 +00:00
|
|
|
, earlyExit(false)
|
2016-08-03 14:54:26 +00:00
|
|
|
, returnCode(0)
|
2012-12-21 23:42:47 +00:00
|
|
|
, expect(expected)
|
|
|
|
, haveOne(false)
|
|
|
|
{
|
|
|
|
connect(e, SIGNAL(objectCreated(QObject*,QUrl)),
|
|
|
|
this, SLOT(checkFinished(QObject*)));
|
2015-03-11 05:25:14 +00:00
|
|
|
// QQmlApplicationEngine also connects quit() to QCoreApplication::quit
|
2016-08-03 14:54:26 +00:00
|
|
|
// and exit() to QCoreApplication::exit but if called before exec()
|
|
|
|
// then QCoreApplication::quit or QCoreApplication::exit does nothing
|
2015-03-11 05:25:14 +00:00
|
|
|
connect(e, SIGNAL(quit()),
|
|
|
|
this, SLOT(quit()));
|
2016-08-03 14:54:26 +00:00
|
|
|
connect(e, &QQmlEngine::exit,
|
|
|
|
this, &LoadWatcher::exit);
|
2012-12-21 23:42:47 +00:00
|
|
|
}
|
|
|
|
|
2015-03-11 05:25:14 +00:00
|
|
|
bool earlyExit;
|
2016-08-03 14:54:26 +00:00
|
|
|
int returnCode;
|
2015-03-11 05:25:14 +00:00
|
|
|
|
2012-12-21 23:42:47 +00:00
|
|
|
private:
|
2015-06-03 09:05:12 +00:00
|
|
|
void contain(QObject *o, const QUrl &containPath);
|
|
|
|
void checkForWindow(QObject *o);
|
|
|
|
|
2012-12-21 23:42:47 +00:00
|
|
|
int expect;
|
|
|
|
bool haveOne;
|
|
|
|
|
|
|
|
public Q_SLOTS:
|
|
|
|
void checkFinished(QObject *o)
|
|
|
|
{
|
|
|
|
if (o) {
|
2015-06-03 09:05:12 +00:00
|
|
|
checkForWindow(o);
|
2012-12-21 23:42:47 +00:00
|
|
|
haveOne = true;
|
|
|
|
if (conf && qae)
|
2016-08-11 10:08:00 +00:00
|
|
|
for (PartialScene *ps : qAsConst(conf->completers))
|
2012-12-21 23:42:47 +00:00
|
|
|
if (o->inherits(ps->itemType().toUtf8().constData()))
|
|
|
|
contain(o, ps->container());
|
|
|
|
}
|
|
|
|
if (haveOne)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (! --expect) {
|
2013-10-23 22:37:16 +00:00
|
|
|
printf("qml: Did not load any objects, exiting.\n");
|
2016-08-03 14:54:26 +00:00
|
|
|
std::exit(2);//Different return code from qFatal
|
2012-12-21 23:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-11 05:25:14 +00:00
|
|
|
|
|
|
|
void quit() {
|
|
|
|
//Will be checked before calling exec()
|
|
|
|
earlyExit = true;
|
2016-08-03 14:54:26 +00:00
|
|
|
returnCode = 0;
|
2015-03-11 05:25:14 +00:00
|
|
|
}
|
2016-08-03 14:54:26 +00:00
|
|
|
void exit(int retCode) {
|
|
|
|
earlyExit = true;
|
|
|
|
returnCode = retCode;
|
|
|
|
}
|
|
|
|
|
2016-11-16 13:22:36 +00:00
|
|
|
#if defined(QT_GUI_LIB) && QT_CONFIG(opengl)
|
2015-06-03 09:05:12 +00:00
|
|
|
void onOpenGlContextCreated(QOpenGLContext *context);
|
|
|
|
#endif
|
2012-12-21 23:42:47 +00:00
|
|
|
};
|
|
|
|
|
2015-06-03 09:05:12 +00:00
|
|
|
void LoadWatcher::contain(QObject *o, const QUrl &containPath)
|
|
|
|
{
|
|
|
|
QQmlComponent c(qae, containPath);
|
|
|
|
QObject *o2 = c.create();
|
|
|
|
if (!o2)
|
|
|
|
return;
|
|
|
|
checkForWindow(o2);
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
void LoadWatcher::checkForWindow(QObject *o)
|
|
|
|
{
|
2016-11-16 13:22:36 +00:00
|
|
|
#if defined(QT_GUI_LIB) && QT_CONFIG(opengl)
|
2015-06-03 09:05:12 +00:00
|
|
|
if (verboseMode && o->isWindowType() && o->inherits("QQuickWindow")) {
|
|
|
|
connect(o, SIGNAL(openglContextCreated(QOpenGLContext*)),
|
|
|
|
this, SLOT(onOpenGlContextCreated(QOpenGLContext*)));
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
Q_UNUSED(o)
|
2015-08-18 13:54:41 +00:00
|
|
|
#endif // QT_GUI_LIB && !QT_NO_OPENGL
|
2015-06-03 09:05:12 +00:00
|
|
|
}
|
|
|
|
|
2016-11-16 13:22:36 +00:00
|
|
|
#if defined(QT_GUI_LIB) && QT_CONFIG(opengl)
|
2015-06-03 09:05:12 +00:00
|
|
|
void LoadWatcher::onOpenGlContextCreated(QOpenGLContext *context)
|
|
|
|
{
|
|
|
|
context->makeCurrent(qobject_cast<QWindow *>(sender()));
|
|
|
|
QOpenGLFunctions functions(context);
|
|
|
|
QByteArray output = "Vendor : ";
|
|
|
|
output += reinterpret_cast<const char *>(functions.glGetString(GL_VENDOR));
|
|
|
|
output += "\nRenderer: ";
|
|
|
|
output += reinterpret_cast<const char *>(functions.glGetString(GL_RENDERER));
|
|
|
|
output += "\nVersion : ";
|
|
|
|
output += reinterpret_cast<const char *>(functions.glGetString(GL_VERSION));
|
|
|
|
output += "\nLanguage: ";
|
|
|
|
output += reinterpret_cast<const char *>(functions.glGetString(GL_SHADING_LANGUAGE_VERSION));
|
|
|
|
puts(output.constData());
|
|
|
|
context->doneCurrent();
|
|
|
|
}
|
2015-08-18 13:54:41 +00:00
|
|
|
#endif // QT_GUI_LIB && !QT_NO_OPENGL
|
2015-06-03 09:05:12 +00:00
|
|
|
|
2012-12-21 23:42:47 +00:00
|
|
|
void quietMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, const QString &msg)
|
|
|
|
{
|
|
|
|
Q_UNUSED(ctxt);
|
|
|
|
Q_UNUSED(msg);
|
|
|
|
//Doesn't print anything
|
|
|
|
switch (type) {
|
|
|
|
case QtFatalMsg:
|
2013-09-25 16:11:34 +00:00
|
|
|
exit(-1);
|
2012-12-21 23:42:47 +00:00
|
|
|
case QtCriticalMsg:
|
|
|
|
case QtDebugMsg:
|
|
|
|
case QtWarningMsg:
|
2013-09-23 08:42:16 +00:00
|
|
|
default:
|
2012-12-21 23:42:47 +00:00
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ### Should command line arguments have translations? Qt creator doesn't, so maybe it's not worth it.
|
2013-10-12 02:59:09 +00:00
|
|
|
enum QmlApplicationType {
|
|
|
|
QmlApplicationTypeUnknown
|
|
|
|
, QmlApplicationTypeCore
|
|
|
|
#ifdef QT_GUI_LIB
|
|
|
|
, QmlApplicationTypeGui
|
|
|
|
#ifdef QT_WIDGETS_LIB
|
|
|
|
, QmlApplicationTypeWidget
|
|
|
|
#endif // QT_WIDGETS_LIB
|
|
|
|
#endif // QT_GUI_LIB
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifndef QT_GUI_LIB
|
|
|
|
QmlApplicationType applicationType = QmlApplicationTypeCore;
|
|
|
|
#else
|
|
|
|
QmlApplicationType applicationType = QmlApplicationTypeGui;
|
|
|
|
#endif // QT_GUI_LIB
|
2012-12-21 23:42:47 +00:00
|
|
|
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()
|
|
|
|
{
|
2015-03-05 10:46:46 +00:00
|
|
|
printf("Usage: qml [options] [files] [-- args]\n");
|
2012-12-21 23:42:47 +00:00
|
|
|
printf("\n");
|
2015-03-05 10:46:46 +00:00
|
|
|
printf("Any unknown argument before '--' will be treated as a QML file to be loaded.\n");
|
2012-12-21 23:42:47 +00:00
|
|
|
printf("Any number of QML files can be loaded. They will share the same engine.\n");
|
2014-05-08 20:37:14 +00:00
|
|
|
printf("'gui' application type is only available if the QtGui module is available.\n");
|
|
|
|
printf("'widget' application type is only available if the QtWidgets module is available.\n");
|
2012-12-21 23:42:47 +00:00
|
|
|
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");
|
2013-10-12 02:59:09 +00:00
|
|
|
#ifdef QT_GUI_LIB
|
|
|
|
#ifndef QT_WIDGETS_LIB
|
|
|
|
printf("\t-apptype [core|gui] .......... Select which application class to use. Default is gui.\n");
|
|
|
|
#else
|
2012-12-21 23:42:47 +00:00
|
|
|
printf("\t-apptype [core|gui|widget] ... Select which application class to use. Default is gui.\n");
|
2013-10-12 02:59:09 +00:00
|
|
|
#endif // QT_WIDGETS_LIB
|
|
|
|
#endif // QT_GUI_LIB
|
2012-12-21 23:42:47 +00:00
|
|
|
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");
|
2015-06-03 08:04:54 +00:00
|
|
|
printf("\tGL options:\n");
|
|
|
|
printf("\t-desktop.......................Force use of desktop GL (AA_UseDesktopOpenGL)\n");
|
|
|
|
printf("\t-gles..........................Force use of GLES (AA_UseOpenGLES)\n");
|
|
|
|
printf("\t-software......................Force use of software rendering (AA_UseOpenGLES)\n");
|
2015-11-05 14:42:01 +00:00
|
|
|
printf("\t-scaling.......................Enable High DPI scaling (AA_EnableHighDpiScaling)\n");
|
|
|
|
printf("\t-no-scaling....................Disable High DPI scaling (AA_DisableHighDpiScaling)\n");
|
2012-12-21 23:42:47 +00:00
|
|
|
printf("\tDebugging options:\n");
|
2013-10-23 22:37:16 +00:00
|
|
|
printf("\t-verbose ..................... Print information about what qml is doing, like specific file urls being loaded.\n");
|
2012-12-21 23:42:47 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-11-18 14:57:08 +00:00
|
|
|
void noFilesGiven()
|
|
|
|
{
|
|
|
|
if (!quietMode)
|
|
|
|
printf("qml: No files specified. Terminating.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2012-12-21 23:42:47 +00:00
|
|
|
//Called before application initialization, removes arguments it uses
|
|
|
|
void getAppFlags(int &argc, char **argv)
|
|
|
|
{
|
2013-10-12 02:59:09 +00:00
|
|
|
#ifdef QT_GUI_LIB
|
2013-11-14 11:38:25 +00:00
|
|
|
for (int i=0; i<argc; i++) {
|
|
|
|
if (!strcmp(argv[i], "-apptype")) { // Must be done before application, as it selects application
|
2013-10-12 02:59:09 +00:00
|
|
|
applicationType = QmlApplicationTypeUnknown;
|
2012-12-21 23:42:47 +00:00
|
|
|
if (i+1 < argc) {
|
|
|
|
if (!strcmp(argv[i+1], "core"))
|
2013-10-12 02:59:09 +00:00
|
|
|
applicationType = QmlApplicationTypeCore;
|
2012-12-21 23:42:47 +00:00
|
|
|
else if (!strcmp(argv[i+1], "gui"))
|
2013-10-12 02:59:09 +00:00
|
|
|
applicationType = QmlApplicationTypeGui;
|
2012-12-21 23:42:47 +00:00
|
|
|
#ifdef QT_WIDGETS_LIB
|
|
|
|
else if (!strcmp(argv[i+1], "widget"))
|
2013-10-12 02:59:09 +00:00
|
|
|
applicationType = QmlApplicationTypeWidget;
|
|
|
|
#endif // QT_WIDGETS_LIB
|
2012-12-21 23:42:47 +00:00
|
|
|
}
|
|
|
|
|
2013-10-12 02:59:09 +00:00
|
|
|
if (applicationType == QmlApplicationTypeUnknown) {
|
|
|
|
#ifndef QT_WIDGETS_LIB
|
2012-12-21 23:42:47 +00:00
|
|
|
printf("-apptype must be followed by one of the following: core gui\n");
|
2013-10-12 02:59:09 +00:00
|
|
|
#else
|
|
|
|
printf("-apptype must be followed by one of the following: core gui widget\n");
|
|
|
|
#endif // QT_WIDGETS_LIB
|
2012-12-21 23:42:47 +00:00
|
|
|
printUsage();
|
|
|
|
}
|
|
|
|
for (int j=i; j<argc-2; j++)
|
|
|
|
argv[j] = argv[j+2];
|
|
|
|
argc -= 2;
|
|
|
|
}
|
|
|
|
}
|
2017-04-12 13:45:18 +00:00
|
|
|
#else
|
|
|
|
Q_UNUSED(argc)
|
|
|
|
Q_UNUSED(argv)
|
2013-11-14 11:38:25 +00:00
|
|
|
#endif // QT_GUI_LIB
|
2012-12-21 23:42:47 +00:00
|
|
|
}
|
|
|
|
|
2013-10-23 22:31:10 +00:00
|
|
|
bool getFileSansBangLine(const QString &path, QByteArray &output)
|
2012-12-21 23:42:47 +00:00
|
|
|
{
|
|
|
|
QFile f(path);
|
|
|
|
if (!f.open(QFile::ReadOnly | QFile::Text))
|
2013-10-23 22:31:10 +00:00
|
|
|
return false;
|
2012-12-21 23:42:47 +00:00
|
|
|
output = f.readAll();
|
2013-10-23 22:31:10 +00:00
|
|
|
if (output.startsWith("#!")) {//Remove first line in this case (except \n, to avoid disturbing line count)
|
2012-12-21 23:42:47 +00:00
|
|
|
output.remove(0, output.indexOf('\n'));
|
2013-10-23 22:31:10 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2012-12-21 23:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2014-03-01 06:28:29 +00:00
|
|
|
QQmlComponent comp(&engine, dir.filePath(qml));
|
2012-12-21 23:42:47 +00:00
|
|
|
QObject *dummyData = comp.create();
|
|
|
|
|
|
|
|
if (comp.isError()) {
|
2016-08-11 10:08:00 +00:00
|
|
|
const QList<QQmlError> errors = comp.errors();
|
|
|
|
for (const QQmlError &error : errors)
|
2012-12-21 23:42:47 +00:00
|
|
|
qWarning() << error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dummyData && !quietMode) {
|
2013-10-23 22:37:16 +00:00
|
|
|
printf("qml: Loaded dummy data: %s\n", qPrintable(dir.filePath(qml)));
|
2012-12-21 23:42:47 +00:00
|
|
|
qml.truncate(qml.length()-4);
|
|
|
|
engine.rootContext()->setContextProperty(qml, dummyData);
|
|
|
|
dummyData->setParent(&engine);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
getAppFlags(argc, argv);
|
2018-02-21 09:41:54 +00:00
|
|
|
QCoreApplication *app = nullptr;
|
2013-10-12 02:59:09 +00:00
|
|
|
switch (applicationType) {
|
|
|
|
case QmlApplicationTypeCore:
|
2012-12-21 23:42:47 +00:00
|
|
|
app = new QCoreApplication(argc, argv);
|
2013-10-12 02:59:09 +00:00
|
|
|
break;
|
|
|
|
#ifdef QT_GUI_LIB
|
|
|
|
case QmlApplicationTypeGui:
|
|
|
|
app = new LoaderApplication(argc, argv);
|
|
|
|
break;
|
2012-12-21 23:42:47 +00:00
|
|
|
#ifdef QT_WIDGETS_LIB
|
2013-10-12 02:59:09 +00:00
|
|
|
case QmlApplicationTypeWidget:
|
2012-12-21 23:42:47 +00:00
|
|
|
app = new QApplication(argc, argv);
|
2013-10-12 02:59:09 +00:00
|
|
|
break;
|
|
|
|
#endif // QT_WIDGETS_LIB
|
|
|
|
#endif // QT_GUI_LIB
|
|
|
|
default:
|
|
|
|
Q_ASSERT_X(false, Q_FUNC_INFO, "impossible case");
|
|
|
|
break;
|
|
|
|
}
|
2012-12-21 23:42:47 +00:00
|
|
|
|
|
|
|
app->setApplicationName("Qml Runtime");
|
2014-06-27 10:59:14 +00:00
|
|
|
app->setOrganizationName("QtProject");
|
2012-12-21 23:42:47 +00:00
|
|
|
app->setOrganizationDomain("qt-project.org");
|
2016-11-08 12:09:54 +00:00
|
|
|
QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
|
2012-12-21 23:42:47 +00:00
|
|
|
|
2015-03-17 01:49:46 +00:00
|
|
|
qmlRegisterType<Config>("QmlRuntime.Config", 1, 0, "Configuration");
|
|
|
|
qmlRegisterType<PartialScene>("QmlRuntime.Config", 1, 0, "PartialScene");
|
2012-12-21 23:42:47 +00:00
|
|
|
QQmlApplicationEngine e;
|
|
|
|
QStringList files;
|
|
|
|
QString confFile;
|
|
|
|
QString translationFile;
|
|
|
|
QString dummyDir;
|
|
|
|
|
|
|
|
//Handle main arguments
|
2016-08-15 10:30:48 +00:00
|
|
|
const QStringList argList = app->arguments();
|
2015-03-05 10:46:38 +00:00
|
|
|
for (int i = 1; i < argList.count(); i++) {
|
2012-12-21 23:42:47 +00:00
|
|
|
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;
|
2013-10-23 22:37:16 +00:00
|
|
|
else if (arg == QLatin1String("-verbose"))
|
|
|
|
verboseMode = true;
|
2017-12-19 15:37:24 +00:00
|
|
|
#if QT_CONFIG(qml_animation)
|
2012-12-21 23:42:47 +00:00
|
|
|
else if (arg == QLatin1String("-slow-animations"))
|
|
|
|
QUnifiedTimer::instance()->setSlowModeEnabled(true);
|
|
|
|
else if (arg == QLatin1String("-fixed-animations"))
|
|
|
|
QUnifiedTimer::instance()->setConsistentTiming(true);
|
2017-03-30 08:41:52 +00:00
|
|
|
#endif
|
2012-12-21 23:42:47 +00:00
|
|
|
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++;
|
2015-06-03 08:04:54 +00:00
|
|
|
} else if (arg == QLatin1String("-gles")) {
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
|
|
|
} else if (arg == QLatin1String("-software")) {
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
|
|
|
|
} else if (arg == QLatin1String("-desktop")) {
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
|
2015-11-05 14:42:01 +00:00
|
|
|
} else if (arg == QLatin1String("-scaling")) {
|
|
|
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
2015-08-31 09:35:21 +00:00
|
|
|
} else if (arg == QLatin1String("-no-scaling")) {
|
2015-11-05 14:42:01 +00:00
|
|
|
QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
|
2012-12-21 23:42:47 +00:00
|
|
|
} else {
|
2015-03-05 10:46:46 +00:00
|
|
|
files << arg;
|
2012-12-21 23:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-23 22:37:16 +00:00
|
|
|
if (quietMode && verboseMode)
|
|
|
|
verboseMode = false;
|
|
|
|
|
2016-11-16 13:22:36 +00:00
|
|
|
#if QT_CONFIG(translation)
|
2018-06-28 14:47:11 +00:00
|
|
|
// Need to be installed before QQmlApplicationEngine's automatic translation loading
|
|
|
|
// (qt_ translations are loaded there)
|
|
|
|
if (!translationFile.isEmpty()) {
|
2012-12-21 23:42:47 +00:00
|
|
|
QTranslator translator;
|
|
|
|
|
|
|
|
if (translator.load(translationFile)) {
|
|
|
|
app->installTranslator(&translator);
|
2013-10-23 22:37:16 +00:00
|
|
|
if (verboseMode)
|
|
|
|
printf("qml: Loaded translation file %s\n", qPrintable(QDir::toNativeSeparators(translationFile)));
|
2012-12-21 23:42:47 +00:00
|
|
|
} else {
|
|
|
|
if (!quietMode)
|
2013-10-23 22:37:16 +00:00
|
|
|
printf("qml: Could not load the translation file %s\n", qPrintable(QDir::toNativeSeparators(translationFile)));
|
2012-12-21 23:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (!translationFile.isEmpty() && !quietMode)
|
2013-10-23 22:37:16 +00:00
|
|
|
printf("qml: Translation file specified, but Qt built without translation support.\n");
|
2012-12-21 23:42:47 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (quietMode)
|
|
|
|
qInstallMessageHandler(quietMessageHandler);
|
|
|
|
|
|
|
|
if (files.count() <= 0) {
|
2017-04-12 13:45:18 +00:00
|
|
|
#if defined(Q_OS_DARWIN)
|
2013-11-18 14:57:08 +00:00
|
|
|
if (applicationType == QmlApplicationTypeGui)
|
|
|
|
exitTimerId = static_cast<LoaderApplication *>(app)->startTimer(FILE_OPEN_EVENT_WAIT_TIME);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
noFilesGiven();
|
2012-12-21 23:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
qae = &e;
|
2013-10-23 22:37:16 +00:00
|
|
|
loadConf(confFile, !verboseMode);
|
2012-12-21 23:42:47 +00:00
|
|
|
|
|
|
|
//Load files
|
2015-03-11 05:25:14 +00:00
|
|
|
QScopedPointer<LoadWatcher> lw(new LoadWatcher(&e, files.count()));
|
2012-12-21 23:42:47 +00:00
|
|
|
|
2014-03-01 06:28:29 +00:00
|
|
|
// Load dummy data before loading QML-files
|
|
|
|
if (!dummyDir.isEmpty() && QFileInfo (dummyDir).isDir())
|
|
|
|
loadDummyDataFiles(e, dummyDir);
|
|
|
|
|
2016-08-11 10:08:00 +00:00
|
|
|
for (const QString &path : qAsConst(files)) {
|
2017-03-15 10:16:20 +00:00
|
|
|
QUrl url = QUrl::fromUserInput(path, QDir::currentPath(), QUrl::AssumeLocalFile);
|
2017-01-02 13:04:48 +00:00
|
|
|
if (verboseMode)
|
|
|
|
printf("qml: loading %s\n", qPrintable(url.toString()));
|
|
|
|
QByteArray strippedFile;
|
|
|
|
if (getFileSansBangLine(path, strippedFile))
|
|
|
|
e.loadData(strippedFile, e.baseUrl().resolved(url)); //QQmlComponent won't resolve it for us, it doesn't know it's a valid file if we loadData
|
|
|
|
else //Errors or no bang line
|
2012-12-21 23:42:47 +00:00
|
|
|
e.load(url);
|
|
|
|
}
|
|
|
|
|
2015-03-11 05:25:14 +00:00
|
|
|
if (lw->earlyExit)
|
2016-08-03 14:54:26 +00:00
|
|
|
return lw->returnCode;
|
2015-03-11 05:25:14 +00:00
|
|
|
|
2012-12-21 23:42:47 +00:00
|
|
|
return app->exec();
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "main.moc"
|