diff options
Diffstat (limited to 'tools/qml/main.cpp')
-rw-r--r-- | tools/qml/main.cpp | 370 |
1 files changed, 198 insertions, 172 deletions
diff --git a/tools/qml/main.cpp b/tools/qml/main.cpp index 166c6aabdf..1e367d91bf 100644 --- a/tools/qml/main.cpp +++ b/tools/qml/main.cpp @@ -44,9 +44,12 @@ #include <QQmlApplicationEngine> #include <QQmlComponent> +#include <QCommandLineOption> +#include <QCommandLineParser> #include <QDir> #include <QFile> #include <QFileInfo> +#include <QLoggingCategory> #include <QStringList> #include <QScopedPointer> #include <QDebug> @@ -66,22 +69,39 @@ #include <cstring> #include <cstdlib> -#define VERSION_MAJ 1 -#define VERSION_MIN 1 -#define VERSION_STR "1.1" - #define FILE_OPEN_EVENT_WAIT_TIME 3000 // ms +enum QmlApplicationType { + QmlApplicationTypeUnknown + , QmlApplicationTypeCore +#ifdef QT_GUI_LIB + , QmlApplicationTypeGui +#ifdef QT_WIDGETS_LIB + , QmlApplicationTypeWidget +#endif // QT_WIDGETS_LIB +#endif // QT_GUI_LIB +}; + +static QmlApplicationType applicationType = +#ifndef QT_GUI_LIB + QmlApplicationTypeCore; +#else + QmlApplicationTypeGui; +#endif // QT_GUI_LIB + static Config *conf = nullptr; static QQmlApplicationEngine *qae = nullptr; #if defined(Q_OS_DARWIN) || defined(QT_GUI_LIB) static int exitTimerId = -1; #endif -bool verboseMode = false; +static const QString iconResourcePath(QStringLiteral(":/qt-project.org/QmlRuntime/resources/qml-64.png")); +static const QString confResourcePath(QStringLiteral(":/qt-project.org/QmlRuntime/conf/")); +static bool verboseMode = false; +static bool quietMode = false; static void loadConf(const QString &override, bool quiet) // Terminates app on failure { - const QString defaultFileName = QLatin1String("configuration.qml"); + const QString defaultFileName = QLatin1String("default.qml"); QUrl settingsUrl; bool builtIn = false; //just for keeping track of the warning if (override.isEmpty()) { @@ -91,29 +111,38 @@ static void loadConf(const QString &override, bool quiet) // Terminates app on f 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); + fi.setFile(confResourcePath + defaultFileName); + settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath()); builtIn = true; } } else { QFileInfo fi; - fi.setFile(override); - if (!fi.exists()) { - printf("qml: Couldn't find required configuration file: %s\n", - qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath()))); - exit(1); + fi.setFile(confResourcePath + override + QLatin1String(".qml")); + if (fi.exists()) { + settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath()); + builtIn = true; + } else { + fi.setFile(override); + if (!fi.exists()) { + printf("qml: Couldn't find required configuration file: %s\n", + qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath()))); + exit(1); + } + settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath()); } - settingsUrl = QUrl::fromLocalFile(fi.absoluteFilePath()); } if (!quiet) { printf("qml: %s\n", QLibraryInfo::build()); - if (builtIn) - printf("qml: Using built-in configuration.\n"); - else - printf("qml: Using configuration file: %s\n", + if (builtIn) { + printf("qml: Using built-in configuration: %s\n", + qPrintable(override.isEmpty() ? defaultFileName : override)); + } else { + printf("qml: Using configuration: %s\n", qPrintable(settingsUrl.isLocalFile() ? QDir::toNativeSeparators(settingsUrl.toLocalFile()) : settingsUrl.toString())); + } } // TODO: When we have better engine control, ban QtQuick* imports on this engine @@ -127,15 +156,32 @@ static void loadConf(const QString &override, bool quiet) // Terminates app on f } } -#ifdef QT_GUI_LIB +void noFilesGiven() +{ + if (!quietMode) + printf("qml: No files specified. Terminating.\n"); + exit(1); +} + +static void listConfFiles() +{ + QDir confResourceDir(confResourcePath); + printf("%s\n", qPrintable(QCoreApplication::translate("main", "Built-in configurations:"))); + for (const QFileInfo &fi : confResourceDir.entryInfoList(QDir::Files)) + printf(" %s\n", qPrintable(fi.baseName())); + exit(0); +} -void noFilesGiven(); +#ifdef QT_GUI_LIB // Loads qml after receiving a QFileOpenEvent class LoaderApplication : public QGuiApplication { public: - LoaderApplication(int& argc, char **argv) : QGuiApplication(argc, argv) {} + LoaderApplication(int& argc, char **argv) : QGuiApplication(argc, argv) + { + setWindowIcon(QIcon(iconResourcePath)); + } bool event(QEvent *ev) override { @@ -175,8 +221,8 @@ public: connect(e, &QQmlEngine::exit, this, &LoadWatcher::exit); } - bool earlyExit = false; int returnCode = 0; + bool earlyExit = false; public Q_SLOTS: void checkFinished(QObject *o, const QUrl &url) @@ -217,8 +263,8 @@ private: void checkForWindow(QObject *o); private: - int expectedFileCount; bool haveWindow = false; + int expectedFileCount; }; void LoadWatcher::contain(QObject *o, const QUrl &containPath) @@ -278,93 +324,18 @@ void quietMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, const Q exit(-1); case QtCriticalMsg: case QtDebugMsg: + case QtInfoMsg: case QtWarningMsg: - default: ; } } - -// ### Should command line arguments have translations? Qt creator doesn't, so maybe it's not worth it. -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 -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] [-- args]\n"); - printf("\n"); - printf("Any unknown argument before '--' 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("'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"); - 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"); -#ifdef QT_GUI_LIB -#ifndef QT_WIDGETS_LIB - printf("\t-apptype [core|gui] .......... Select which application class to use. Default is gui.\n"); -#else - printf("\t-apptype [core|gui|widget] ... Select which application class to use. Default is gui.\n"); -#endif // QT_WIDGETS_LIB -#endif // QT_GUI_LIB - 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("\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"); - printf("\t-scaling.......................Enable High DPI scaling (AA_EnableHighDpiScaling)\n"); - printf("\t-no-scaling....................Disable High DPI scaling (AA_DisableHighDpiScaling)\n"); - printf("\tDebugging options:\n"); - printf("\t-verbose ..................... Print information about what qml is doing, like specific file urls being loaded.\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); -} - -void noFilesGiven() -{ - if (!quietMode) - printf("qml: No files specified. Terminating.\n"); - exit(1); -} - // Called before application initialization, removes arguments it uses void getAppFlags(int &argc, char **argv) { #ifdef QT_GUI_LIB for (int i=0; i<argc; i++) { - if (!strcmp(argv[i], "-apptype")) { // Must be done before application, as it selects application + if (!strcmp(argv[i], "--apptype") || !strcmp(argv[i], "-a") || !strcmp(argv[i], "-apptype")) { applicationType = QmlApplicationTypeUnknown; if (i+1 < argc) { if (!strcmp(argv[i+1], "core")) @@ -376,15 +347,6 @@ void getAppFlags(int &argc, char **argv) applicationType = QmlApplicationTypeWidget; #endif // QT_WIDGETS_LIB } - - if (applicationType == QmlApplicationTypeUnknown) { -#ifndef QT_WIDGETS_LIB - printf("-apptype must be followed by one of the following: core gui\n"); -#else - printf("-apptype must be followed by one of the following: core gui widget\n"); -#endif // QT_WIDGETS_LIB - printUsage(); - } for (int j=i; j<argc-2; j++) argv[j] = argv[j+2]; argc -= 2; @@ -438,9 +400,6 @@ int main(int argc, char *argv[]) getAppFlags(argc, argv); QCoreApplication *app = nullptr; switch (applicationType) { - case QmlApplicationTypeCore: - app = new QCoreApplication(argc, argv); - break; #ifdef QT_GUI_LIB case QmlApplicationTypeGui: app = new LoaderApplication(argc, argv); @@ -448,11 +407,14 @@ int main(int argc, char *argv[]) #ifdef QT_WIDGETS_LIB case QmlApplicationTypeWidget: app = new QApplication(argc, argv); + static_cast<QApplication *>(app)->setWindowIcon(QIcon(iconResourcePath)); break; #endif // QT_WIDGETS_LIB #endif // QT_GUI_LIB - default: - Q_ASSERT_X(false, Q_FUNC_INFO, "impossible case"); + case QmlApplicationTypeCore: + Q_FALLTHROUGH(); + default: // QmlApplicationTypeUnknown: not allowed, but we'll exit after checking apptypeOption below + app = new QCoreApplication(argc, argv); break; } @@ -470,68 +432,130 @@ int main(int argc, char *argv[]) QString dummyDir; // Handle main arguments - const QStringList argList = app->arguments(); - for (int i = 1; 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("-verbose")) - verboseMode = true; + QCommandLineParser parser; + parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); + parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments); + const QCommandLineOption helpOption = parser.addHelpOption(); + const QCommandLineOption versionOption = parser.addVersionOption(); +#ifdef QT_GUI_LIB + QCommandLineOption apptypeOption(QStringList() << QStringLiteral("a") << QStringLiteral("apptype"), + QCoreApplication::translate("main", "Select which application class to use. Default is gui."), +#ifdef QT_WIDGETS_LIB + QStringLiteral("core|gui|widget")); +#else + QStringLiteral("core|gui")); +#endif // QT_WIDGETS_LIB + parser.addOption(apptypeOption); // Just for the help text... we've already handled this argument above +#endif // QT_GUI_LIB + QCommandLineOption importOption(QStringLiteral("I"), + QCoreApplication::translate("main", "Prepend the given path to the import paths."), QStringLiteral("path")); + parser.addOption(importOption); + QCommandLineOption qmlFileOption(QStringLiteral("f"), + QCoreApplication::translate("main", "Load the given file as a QML file."), QStringLiteral("file")); + parser.addOption(qmlFileOption); + QCommandLineOption configOption(QStringList() << QStringLiteral("c") << QStringLiteral("config"), + QCoreApplication::translate("main", "Load the given built-in configuration or configuration file."), QStringLiteral("file")); + parser.addOption(configOption); + QCommandLineOption listConfOption(QStringList() << QStringLiteral("list-conf"), + QCoreApplication::translate("main", "List the built-in configurations.")); + parser.addOption(listConfOption); + QCommandLineOption translationOption(QStringLiteral("translation"), + QCoreApplication::translate("main", "Load the given file as the translations file."), QStringLiteral("file")); + parser.addOption(translationOption); + QCommandLineOption dummyDataOption(QStringLiteral("dummy-data"), + QCoreApplication::translate("main", "Load QML files from the given directory as context properties."), QStringLiteral("file")); + parser.addOption(dummyDataOption); + // OpenGL options + QCommandLineOption glDesktopOption(QStringLiteral("desktop"), + QCoreApplication::translate("main", "Force use of desktop OpenGL (AA_UseDesktopOpenGL).")); + parser.addOption(glDesktopOption); + QCommandLineOption glEsOption(QStringLiteral("gles"), + QCoreApplication::translate("main", "Force use of GLES (AA_UseOpenGLES).")); + parser.addOption(glEsOption); + QCommandLineOption glSoftwareOption(QStringLiteral("software"), + QCoreApplication::translate("main", "Force use of software rendering (AA_UseSoftwareOpenGL).")); + parser.addOption(glSoftwareOption); + QCommandLineOption scalingOption(QStringLiteral("scaling"), + QCoreApplication::translate("main", "Enable High DPI scaling (AA_EnableHighDpiScaling).")); + parser.addOption(scalingOption); + QCommandLineOption noScalingOption(QStringLiteral("no-scaling"), + QCoreApplication::translate("main", "Disable High DPI scaling (AA_DisableHighDpiScaling).")); + parser.addOption(noScalingOption); + // Debugging and verbosity options + QCommandLineOption quietOption(QStringLiteral("quiet"), + QCoreApplication::translate("main", "Suppress all output.")); + parser.addOption(quietOption); + QCommandLineOption verboseOption(QStringLiteral("verbose"), + QCoreApplication::translate("main", "Print information about what qml is doing, like specific file URLs being loaded.")); + parser.addOption(verboseOption); + QCommandLineOption slowAnimationsOption(QStringLiteral("slow-animations"), + QCoreApplication::translate("main", "Run all animations in slow motion.")); + parser.addOption(slowAnimationsOption); + QCommandLineOption fixedAnimationsOption(QStringLiteral("fixed-animations"), + QCoreApplication::translate("main", "Run animations off animation tick rather than wall time.")); + parser.addOption(fixedAnimationsOption); + // Positional arguments + parser.addPositionalArgument("files", + QCoreApplication::translate("main", "Any number of QML files can be loaded. They will share the same engine."), "[files...]"); + parser.addPositionalArgument("args", + QCoreApplication::translate("main", "Arguments after '--' are ignored, but passed through to the application.arguments variable in QML."), "[-- args...]"); + + if (!parser.parse(QCoreApplication::arguments())) { + qWarning() << parser.errorText(); + exit(1); + } + if (parser.isSet(versionOption)) + parser.showVersion(); + if (parser.isSet(helpOption)) + parser.showHelp(); + if (parser.isSet(listConfOption)) + listConfFiles(); + if (applicationType == QmlApplicationTypeUnknown) { +#ifdef QT_WIDGETS_LIB + qWarning() << QCoreApplication::translate("main", "--apptype must be followed by one of the following: core gui widget\n"); +#else + qWarning() << QCoreApplication::translate("main", "--apptype must be followed by one of the following: core gui\n"); +#endif // QT_WIDGETS_LIB + parser.showHelp(); + } + if (parser.isSet(verboseOption)) + verboseMode = true; + if (parser.isSet(quietOption)) { + quietMode = true; + verboseMode = false; + } #if QT_CONFIG(qml_animation) - else if (arg == QLatin1String("-slow-animations")) - QUnifiedTimer::instance()->setSlowModeEnabled(true); - else if (arg == QLatin1String("-fixed-animations")) - QUnifiedTimer::instance()->setConsistentTiming(true); + if (parser.isSet(slowAnimationsOption)) + QUnifiedTimer::instance()->setSlowModeEnabled(true); + if (parser.isSet(fixedAnimationsOption)) + QUnifiedTimer::instance()->setConsistentTiming(true); #endif - 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 (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); - } else if (arg == QLatin1String("-scaling")) { - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - } else if (arg == QLatin1String("-no-scaling")) { - QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); - } else { - files << arg; - } + if (parser.isSet(glEsOption)) + QCoreApplication::setAttribute(Qt::AA_UseOpenGLES); + if (parser.isSet(glSoftwareOption)) + QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL); + if (parser.isSet(glDesktopOption)) + QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL); + if (parser.isSet(scalingOption)) + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + if (parser.isSet(noScalingOption)) + QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); + for (const QString &importPath : parser.values(importOption)) + e.addImportPath(importPath); + files << parser.values(qmlFileOption); + if (parser.isSet(configOption)) + confFile = parser.value(configOption); + if (parser.isSet(translationOption)) + translationFile = parser.value(translationOption); + if (parser.isSet(dummyDataOption)) + dummyDir = parser.value(dummyDataOption); + for (QString posArg : parser.positionalArguments()) { + if (posArg == QLatin1String("--")) + break; + else + files << posArg; } - if (quietMode && verboseMode) - verboseMode = false; - #if QT_CONFIG(translation) // Need to be installed before QQmlApplicationEngine's automatic translation loading // (qt_ translations are loaded there) @@ -552,8 +576,10 @@ int main(int argc, char *argv[]) printf("qml: Translation file specified, but Qt built without translation support.\n"); #endif - if (quietMode) + if (quietMode) { qInstallMessageHandler(quietMessageHandler); + QLoggingCategory::setFilterRules(QStringLiteral("*=false")); + } if (files.count() <= 0) { #if defined(Q_OS_DARWIN) |