forked from qt-creator/qt-creator
QmlDesigner: add support for multiple qml backends
This patch includes; * Fork of original QML runtime as an alternative QML backend for QDS * Flexible structure for adding/removing different types of QML interpreters Note: When forking the original QML the config.h is renamed as qmlconfiguration.h because it was clashing with sqlite and QmlRuntime.QmlConfiguration uses "magic" name matching. QmlConfiguration/qmlconfiguration is unlikely to conflict with anything. Task-number: QDS-8373 Change-Id: Ifaa1b766c717ce12d6b3c9ddbbc0665669797e36 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -35,7 +35,7 @@ QProcessUniquePointer puppetProcess(const QString &puppetPath,
|
|||||||
processFinishCallback);
|
processFinishCallback);
|
||||||
|
|
||||||
if (forwardOutput == puppetMode || forwardOutput == "all") {
|
if (forwardOutput == puppetMode || forwardOutput == "all") {
|
||||||
puppetProcess->setProcessChannelMode(QProcess::MergedChannels);
|
puppetProcess->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
QObject::connect(puppetProcess.get(), &QProcess::readyRead, processOutputCallback);
|
QObject::connect(puppetProcess.get(), &QProcess::readyRead, processOutputCallback);
|
||||||
}
|
}
|
||||||
puppetProcess->setWorkingDirectory(workingDirectory);
|
puppetProcess->setWorkingDirectory(workingDirectory);
|
||||||
@@ -46,7 +46,6 @@ QProcessUniquePointer puppetProcess(const QString &puppetPath,
|
|||||||
else
|
else
|
||||||
processArguments = {socketToken, puppetMode};
|
processArguments = {socketToken, puppetMode};
|
||||||
|
|
||||||
processArguments.push_back("-graphicssystem raster");
|
|
||||||
processArguments.push_back(freeTypeOption);
|
processArguments.push_back(freeTypeOption);
|
||||||
|
|
||||||
puppetProcess->start(puppetPath, processArguments);
|
puppetProcess->start(puppetPath, processArguments);
|
||||||
|
@@ -35,12 +35,22 @@ add_qtc_executable(qml2puppet
|
|||||||
Qt5::QuickPrivate Qt5::Network Qt5::GuiPrivate
|
Qt5::QuickPrivate Qt5::Network Qt5::GuiPrivate
|
||||||
QmlPuppetCommunication
|
QmlPuppetCommunication
|
||||||
SOURCES
|
SOURCES
|
||||||
qml2puppet/qml2puppetmain.cpp
|
qml2puppet/main.cpp
|
||||||
qmlpuppet.qrc
|
qmlpuppet.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(qml2puppet PROPERTIES OUTPUT_NAME qml2puppet-${IDE_VERSION})
|
set_target_properties(qml2puppet PROPERTIES OUTPUT_NAME qml2puppet-${IDE_VERSION})
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND git describe --tags --always --dirty=+
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
RESULT_VARIABLE GIT_SHA_RESULT
|
||||||
|
OUTPUT_VARIABLE GIT_SHA_OUTPUT
|
||||||
|
ERROR_VARIABLE GIT_SHA_ERROR
|
||||||
|
)
|
||||||
|
|
||||||
|
add_definitions( -D GIT_SHA=${GIT_SHA_OUTPUT} )
|
||||||
|
|
||||||
extend_qtc_executable(qml2puppet
|
extend_qtc_executable(qml2puppet
|
||||||
CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 6.0.0
|
CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 6.0.0
|
||||||
SOURCES
|
SOURCES
|
||||||
@@ -166,6 +176,16 @@ extend_qtc_executable(qml2puppet
|
|||||||
animationdriver.cpp animationdriver.h
|
animationdriver.cpp animationdriver.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
extend_qtc_executable(qml2puppet
|
||||||
|
DEPENDS app_version
|
||||||
|
SOURCES_PREFIX qml2puppet/runner
|
||||||
|
SOURCES
|
||||||
|
runtime/qmlruntime.h runtime/qmlruntime.cpp
|
||||||
|
runtime/qmlconfiguration.h runtime/loadwatcher.h
|
||||||
|
puppet/qmlpuppet.h puppet/qmlpuppet.cpp puppet/configcrashpad.h
|
||||||
|
qmlbase.h appmetadata.h
|
||||||
|
)
|
||||||
|
|
||||||
extend_qtc_executable(qml2puppet
|
extend_qtc_executable(qml2puppet
|
||||||
SOURCES_PREFIX qmlprivategate
|
SOURCES_PREFIX qmlprivategate
|
||||||
SOURCES
|
SOURCES
|
||||||
@@ -186,11 +206,21 @@ extend_qtc_executable(qml2puppet
|
|||||||
PUBLIC_INCLUDES src/libs
|
PUBLIC_INCLUDES src/libs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
extend_qtc_executable(qml2puppet
|
||||||
|
PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/qml2puppet/runner/runtime
|
||||||
|
)
|
||||||
|
|
||||||
extend_qtc_executable(qml2puppet
|
extend_qtc_executable(qml2puppet
|
||||||
CONDITION TARGET Nanotrace
|
CONDITION TARGET Nanotrace
|
||||||
DEPENDS Nanotrace
|
DEPENDS Nanotrace
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Turn the tool into its own self-contained qml module
|
||||||
|
qt6_add_qml_module(qml2puppet
|
||||||
|
URI QmlRuntime.QmlConfiguration
|
||||||
|
VERSION 1.0
|
||||||
|
)
|
||||||
|
|
||||||
if (QTC_STATIC_BUILD AND Qt5_VERSION VERSION_GREATER_EQUAL 6.0.0)
|
if (QTC_STATIC_BUILD AND Qt5_VERSION VERSION_GREATER_EQUAL 6.0.0)
|
||||||
qt6_import_qml_plugins(qml2puppet PATH_TO_SCAN ${SRCDIR})
|
qt6_import_qml_plugins(qml2puppet PATH_TO_SCAN ${SRCDIR})
|
||||||
endif()
|
endif()
|
||||||
|
28
src/tools/qml2puppet/qml2puppet/main.cpp
Normal file
28
src/tools/qml2puppet/qml2puppet/main.cpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (C) 2016 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "runner/puppet/qmlpuppet.h"
|
||||||
|
#include "runner/runtime/qmlruntime.h"
|
||||||
|
|
||||||
|
QmlBase *getQmlRunner(int &argc, char **argv)
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
if (!strcmp(argv[i], "--qml-runtime")){
|
||||||
|
qInfo() << "Starting QML Runtime";
|
||||||
|
return new QmlRuntime(argc, argv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
qInfo() << "Starting QML Puppet";
|
||||||
|
return new QmlPuppet(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QDSMeta::Logging::registerMessageHandler();
|
||||||
|
QDSMeta::AppInfo::registerAppInfo("Qml2Puppet");
|
||||||
|
|
||||||
|
QmlBase *qmlRunner = getQmlRunner(argc, argv);
|
||||||
|
return qmlRunner->run();
|
||||||
|
}
|
@@ -1,267 +0,0 @@
|
|||||||
// Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
|
||||||
|
|
||||||
#include "iconrenderer/iconrenderer.h"
|
|
||||||
#include "import3d/import3d.h"
|
|
||||||
|
|
||||||
#include <qt5nodeinstanceclientproxy.h>
|
|
||||||
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
|
|
||||||
#include <sqlitelibraryinitializer.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <QQmlComponent>
|
|
||||||
#include <QQmlEngine>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QFileInfo>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#ifdef ENABLE_QT_BREAKPAD
|
|
||||||
#include <qtsystemexceptionhandler.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
|
||||||
#define NOMINMAX
|
|
||||||
#include "client/crashpad_client.h"
|
|
||||||
#include "client/crash_report_database.h"
|
|
||||||
#include "client/settings.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
|
||||||
{
|
|
||||||
QByteArray localMsg = msg.toLocal8Bit();
|
|
||||||
switch (type) {
|
|
||||||
case QtDebugMsg:
|
|
||||||
fprintf(stderr,
|
|
||||||
"Debug: %s (%s:%u, %s)\n",
|
|
||||||
localMsg.constData(),
|
|
||||||
context.file,
|
|
||||||
context.line,
|
|
||||||
context.function);
|
|
||||||
break;
|
|
||||||
case QtInfoMsg:
|
|
||||||
fprintf(stderr,
|
|
||||||
"Info: %s (%s:%u, %s)\n",
|
|
||||||
localMsg.constData(),
|
|
||||||
context.file,
|
|
||||||
context.line,
|
|
||||||
context.function);
|
|
||||||
break;
|
|
||||||
case QtWarningMsg:
|
|
||||||
fprintf(stderr,
|
|
||||||
"Warning: %s (%s:%u, %s)\n",
|
|
||||||
localMsg.constData(),
|
|
||||||
context.file,
|
|
||||||
context.line,
|
|
||||||
context.function);
|
|
||||||
break;
|
|
||||||
case QtCriticalMsg:
|
|
||||||
fprintf(stderr,
|
|
||||||
"Critical: %s (%s:%u, %s)\n",
|
|
||||||
localMsg.constData(),
|
|
||||||
context.file,
|
|
||||||
context.line,
|
|
||||||
context.function);
|
|
||||||
break;
|
|
||||||
case QtFatalMsg:
|
|
||||||
fprintf(stderr,
|
|
||||||
"Fatal: %s (%s:%u, %s)\n",
|
|
||||||
localMsg.constData(),
|
|
||||||
context.file,
|
|
||||||
context.line,
|
|
||||||
context.function);
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
|
||||||
bool startCrashpad()
|
|
||||||
{
|
|
||||||
using namespace crashpad;
|
|
||||||
|
|
||||||
// Cache directory that will store crashpad information and minidumps
|
|
||||||
base::FilePath database(L"crashpad_reports");
|
|
||||||
base::FilePath handler(L"crashpad_handler.exe");
|
|
||||||
|
|
||||||
// URL used to submit minidumps to
|
|
||||||
std::string url(CRASHPAD_BACKEND_URL);
|
|
||||||
|
|
||||||
// Optional annotations passed via --annotations to the handler
|
|
||||||
std::map<std::string, std::string> annotations;
|
|
||||||
annotations["qt-version"] = QT_VERSION_STR;
|
|
||||||
|
|
||||||
// Optional arguments to pass to the handler
|
|
||||||
std::vector<std::string> arguments;
|
|
||||||
arguments.push_back("--no-rate-limit");
|
|
||||||
|
|
||||||
CrashpadClient *client = new CrashpadClient();
|
|
||||||
bool success = client->StartHandler(
|
|
||||||
handler,
|
|
||||||
database,
|
|
||||||
database,
|
|
||||||
url,
|
|
||||||
annotations,
|
|
||||||
arguments,
|
|
||||||
/* restartable */ true,
|
|
||||||
/* asynchronous_start */ true
|
|
||||||
);
|
|
||||||
// TODO: research using this method, should avoid creating a separate CrashpadClient for the
|
|
||||||
// puppet (needed only on windows according to docs).
|
|
||||||
// client->SetHandlerIPCPipe(L"\\\\.\\pipe\\qml2puppet");
|
|
||||||
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int internalMain(QGuiApplication *application)
|
|
||||||
{
|
|
||||||
QCoreApplication::setOrganizationName("QtProject");
|
|
||||||
QCoreApplication::setOrganizationDomain("qt-project.org");
|
|
||||||
QCoreApplication::setApplicationName("Qml2Puppet");
|
|
||||||
QCoreApplication::setApplicationVersion("1.0.0");
|
|
||||||
|
|
||||||
if (application->arguments().count() < 2
|
|
||||||
|| (application->arguments().at(1) == "--readcapturedstream" && application->arguments().count() < 3)
|
|
||||||
|| (application->arguments().at(1) == "--rendericon" && application->arguments().count() < 5)
|
|
||||||
|| (application->arguments().at(1) == "--import3dAsset" && application->arguments().count() < 6)) {
|
|
||||||
qDebug() << "Usage:\n";
|
|
||||||
qDebug() << "--test";
|
|
||||||
qDebug() << "--version";
|
|
||||||
qDebug() << "--readcapturedstream <stream file> [control stream file]";
|
|
||||||
qDebug() << "--rendericon <icon size> <icon file name> <icon source qml>";
|
|
||||||
qDebug() << "--import3dAsset <source asset file name> <output dir> <id number> <import options JSON>";
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (application->arguments().at(1) == "--readcapturedstream" && application->arguments().count() > 2) {
|
|
||||||
QFileInfo inputStreamFileInfo(application->arguments().at(2));
|
|
||||||
if (!inputStreamFileInfo.exists()) {
|
|
||||||
qDebug() << "Input stream does not exist:" << inputStreamFileInfo.absoluteFilePath();
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (application->arguments().count() > 3) {
|
|
||||||
QFileInfo controlStreamFileInfo(application->arguments().at(3));
|
|
||||||
if (!controlStreamFileInfo.exists()) {
|
|
||||||
qDebug() << "Output stream does not exist:" << controlStreamFileInfo.absoluteFilePath();
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (application->arguments().count() == 2 && application->arguments().at(1) == "--test") {
|
|
||||||
qDebug() << QCoreApplication::applicationVersion();
|
|
||||||
QQmlEngine engine;
|
|
||||||
|
|
||||||
QQmlComponent component(&engine);
|
|
||||||
component.setData("import QtQuick 2.0\nItem {\n}\n", QUrl::fromLocalFile("test.qml"));
|
|
||||||
|
|
||||||
QObject *object = component.create();
|
|
||||||
|
|
||||||
if (object) {
|
|
||||||
qDebug() << "Basic QtQuick 2.0 working...";
|
|
||||||
} else {
|
|
||||||
qDebug() << "Basic QtQuick 2.0 not working...";
|
|
||||||
qDebug() << component.errorString();
|
|
||||||
}
|
|
||||||
delete object;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (application->arguments().count() == 2 && application->arguments().at(1) == "--version") {
|
|
||||||
std::cout << 2;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (application->arguments().at(1) != "--readcapturedstream" && application->arguments().count() < 4) {
|
|
||||||
qDebug() << "Wrong argument count: " << application->arguments().count();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (application->arguments().at(1) == "--rendericon") {
|
|
||||||
int size = application->arguments().at(2).toInt();
|
|
||||||
QString iconFileName = application->arguments().at(3);
|
|
||||||
QString iconSource = application->arguments().at(4);
|
|
||||||
|
|
||||||
IconRenderer *iconRenderer = new IconRenderer(size, iconFileName, iconSource);
|
|
||||||
iconRenderer->setupRender();
|
|
||||||
|
|
||||||
return application->exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (application->arguments().at(1) == "--import3dAsset") {
|
|
||||||
QString sourceAsset = application->arguments().at(2);
|
|
||||||
QString outDir = application->arguments().at(3);
|
|
||||||
QString options = application->arguments().at(4);
|
|
||||||
|
|
||||||
Import3D::import3D(sourceAsset, outDir, options);
|
|
||||||
|
|
||||||
return application->exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_QT_BREAKPAD
|
|
||||||
const QString libexecPath = QCoreApplication::applicationDirPath() + '/' + RELATIVE_LIBEXEC_PATH;
|
|
||||||
QtSystemExceptionHandler systemExceptionHandler(libexecPath);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
|
||||||
/* startCrashpad(); */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
new QmlDesigner::Qt5NodeInstanceClientProxy(application);
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN) && defined(QT_NO_DEBUG)
|
|
||||||
SetErrorMode(SEM_NOGPFAULTERRORBOX); //We do not want to see any message boxes
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (application->arguments().at(1) == "--readcapturedstream")
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return application->exec();
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
qInstallMessageHandler(myMessageOutput);
|
|
||||||
#endif
|
|
||||||
// Since we always render text into an FBO, we need to globally disable
|
|
||||||
// subpixel antialiasing and instead use gray.
|
|
||||||
qputenv("QSG_DISTANCEFIELD_ANTIALIASING", "gray");
|
|
||||||
#ifdef Q_OS_MACOS
|
|
||||||
qputenv("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM", "true");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//If a style different from Desktop is set we have to use QGuiApplication
|
|
||||||
bool useGuiApplication = (!qEnvironmentVariableIsSet("QMLDESIGNER_FORCE_QAPPLICATION")
|
|
||||||
|| qgetenv("QMLDESIGNER_FORCE_QAPPLICATION") != "true")
|
|
||||||
&& qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_STYLE")
|
|
||||||
&& qgetenv("QT_QUICK_CONTROLS_STYLE") != "Desktop";
|
|
||||||
|
|
||||||
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
|
|
||||||
Sqlite::LibraryInitializer::initialize();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (useGuiApplication) {
|
|
||||||
QGuiApplication application(argc, argv);
|
|
||||||
return internalMain(&application);
|
|
||||||
} else {
|
|
||||||
QApplication application(argc, argv);
|
|
||||||
return internalMain(&application);
|
|
||||||
}
|
|
||||||
}
|
|
99
src/tools/qml2puppet/qml2puppet/runner/appmetadata.h
Normal file
99
src/tools/qml2puppet/qml2puppet/runner/appmetadata.h
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH
|
||||||
|
// Qt-GPL-exception-1.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
|
#include <app/app_version.h>
|
||||||
|
|
||||||
|
// Common functions can be used in all QDS apps
|
||||||
|
namespace QDSMeta {
|
||||||
|
|
||||||
|
namespace Logging {
|
||||||
|
inline Q_LOGGING_CATEGORY(deprecated, "qt.tools.qds.deprecated");
|
||||||
|
inline Q_LOGGING_CATEGORY(verbose1, "qt.tools.qds.verbose1");
|
||||||
|
inline Q_LOGGING_CATEGORY(verbose2, "qt.tools.qds.verbose2");
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
|
inline void registerMessageHandler()
|
||||||
|
{
|
||||||
|
qInstallMessageHandler(
|
||||||
|
[](QtMsgType type, const QMessageLogContext &context, const QString &msg) {
|
||||||
|
auto tPrinter = [&](const QString &msgPrefix) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: %s (%s:%u, %s)\n",
|
||||||
|
msgPrefix.toLocal8Bit().constData(),
|
||||||
|
msg.toLocal8Bit().constData(),
|
||||||
|
context.file,
|
||||||
|
context.line,
|
||||||
|
context.function);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (type == QtDebugMsg)
|
||||||
|
tPrinter("Debug");
|
||||||
|
else if (type == QtInfoMsg)
|
||||||
|
tPrinter("Info");
|
||||||
|
else if (type == QtWarningMsg)
|
||||||
|
tPrinter("Warning");
|
||||||
|
else if (type == QtCriticalMsg)
|
||||||
|
tPrinter("Critical");
|
||||||
|
else if (type == QtFatalMsg) {
|
||||||
|
tPrinter("Fatal");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Logging
|
||||||
|
|
||||||
|
namespace AppInfo {
|
||||||
|
|
||||||
|
#define STRINGIFY_INTERNAL(x) #x
|
||||||
|
#define QDS_STRINGIFY(x) STRINGIFY_INTERNAL(x)
|
||||||
|
|
||||||
|
inline void printAppInfo()
|
||||||
|
{
|
||||||
|
qInfo() << Qt::endl
|
||||||
|
<< "<< QDS Meta Info >>" << Qt::endl
|
||||||
|
<< "App Info" << Qt::endl
|
||||||
|
<< " - Name :" << Core::Constants::IDE_ID << Qt::endl
|
||||||
|
<< " - Version :" << Core::Constants::IDE_VERSION_DISPLAY << Qt::endl
|
||||||
|
<< " - Author :" << Core::Constants::IDE_AUTHOR << Qt::endl
|
||||||
|
<< " - Year :" << Core::Constants::IDE_YEAR << Qt::endl
|
||||||
|
<< " - App :" << QCoreApplication::applicationName() << Qt::endl
|
||||||
|
<< "Build Info " << Qt::endl
|
||||||
|
<< " - Date :" << __DATE__ << Qt::endl
|
||||||
|
<< " - Commit :" << QStringLiteral(QDS_STRINGIFY(GIT_SHA)) << Qt::endl
|
||||||
|
<< " - Qt Version :" << QT_VERSION_STR << Qt::endl
|
||||||
|
<< "Compiler Info " << Qt::endl
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
<< " - GCC :" << __GNUC__ << Qt::endl
|
||||||
|
<< " - GCC Minor :" << __GNUC_MINOR__ << Qt::endl
|
||||||
|
<< " - GCC Patch :" << __GNUC_PATCHLEVEL__ << Qt::endl
|
||||||
|
#endif
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
<< " - MSC Short :" << _MSC_VER << Qt::endl
|
||||||
|
<< " - MSC Full :" << _MSC_FULL_VER << Qt::endl
|
||||||
|
#endif
|
||||||
|
#if defined(__clang__)
|
||||||
|
<< " - clang maj :" << __clang_major__ << Qt::endl
|
||||||
|
<< " - clang min :" << __clang_minor__ << Qt::endl
|
||||||
|
<< " - clang patch :" << __clang_patchlevel__ << Qt::endl
|
||||||
|
#endif
|
||||||
|
<< "<< End Of QDS Meta Info >>" << Qt::endl;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void registerAppInfo(const QString &appName)
|
||||||
|
{
|
||||||
|
QCoreApplication::setOrganizationName(Core::Constants::IDE_AUTHOR);
|
||||||
|
QCoreApplication::setOrganizationDomain("qt-project.org");
|
||||||
|
QCoreApplication::setApplicationName(appName);
|
||||||
|
QCoreApplication::setApplicationVersion(Core::Constants::IDE_VERSION_LONG);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace AppInfo
|
||||||
|
} // namespace QDSMeta
|
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define START_CRASHPAD
|
||||||
|
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
||||||
|
startCrashpad()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_QT_BREAKPAD
|
||||||
|
#include <qtsystemexceptionhandler.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
||||||
|
#define NOMINMAX
|
||||||
|
#include "client/crash_report_database.h"
|
||||||
|
#include "client/crashpad_client.h"
|
||||||
|
#include "client/settings.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
#if defined(ENABLE_CRASHPAD) && defined(Q_OS_WIN)
|
||||||
|
bool startCrashpad()
|
||||||
|
{
|
||||||
|
using namespace crashpad;
|
||||||
|
|
||||||
|
// Cache directory that will store crashpad information and minidumps
|
||||||
|
base::FilePath database(L"crashpad_reports");
|
||||||
|
base::FilePath handler(L"crashpad_handler.exe");
|
||||||
|
|
||||||
|
// URL used to submit minidumps to
|
||||||
|
std::string url(CRASHPAD_BACKEND_URL);
|
||||||
|
|
||||||
|
// Optional annotations passed via --annotations to the handler
|
||||||
|
std::map<std::string, std::string> annotations;
|
||||||
|
annotations["qt-version"] = QT_VERSION_STR;
|
||||||
|
|
||||||
|
// Optional arguments to pass to the handler
|
||||||
|
std::vector<std::string> arguments;
|
||||||
|
arguments.push_back("--no-rate-limit");
|
||||||
|
|
||||||
|
CrashpadClient *client = new CrashpadClient();
|
||||||
|
bool success = client->StartHandler(handler,
|
||||||
|
database,
|
||||||
|
database,
|
||||||
|
url,
|
||||||
|
annotations,
|
||||||
|
arguments,
|
||||||
|
/* restartable */ true,
|
||||||
|
/* asynchronous_start */ true);
|
||||||
|
// TODO: research using this method, should avoid creating a separate CrashpadClient for the
|
||||||
|
// puppet (needed only on windows according to docs).
|
||||||
|
// client->SetHandlerIPCPipe(L"\\\\.\\pipe\\qml2puppet");
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_QT_BREAKPAD
|
||||||
|
const QString libexecPath = QCoreApplication::applicationDirPath() + '/'
|
||||||
|
+ RELATIVE_LIBEXEC_PATH;
|
||||||
|
QtSystemExceptionHandler systemExceptionHandler(libexecPath);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
126
src/tools/qml2puppet/qml2puppet/runner/puppet/qmlpuppet.cpp
Normal file
126
src/tools/qml2puppet/qml2puppet/runner/puppet/qmlpuppet.cpp
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "qmlpuppet.h"
|
||||||
|
|
||||||
|
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
|
||||||
|
#include <sqlitelibraryinitializer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QQmlComponent>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
#include "qml2puppet/iconrenderer/iconrenderer.h"
|
||||||
|
#include "qml2puppet/import3d/import3d.h"
|
||||||
|
|
||||||
|
#include "configcrashpad.h"
|
||||||
|
|
||||||
|
#include <qt5nodeinstanceclientproxy.h>
|
||||||
|
|
||||||
|
void QmlPuppet::initCoreApp()
|
||||||
|
{
|
||||||
|
// Since we always render text into an FBO, we need to globally disable
|
||||||
|
// subpixel antialiasing and instead use gray.
|
||||||
|
qputenv("QSG_DISTANCEFIELD_ANTIALIASING", "gray");
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
qputenv("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM", "true");
|
||||||
|
#endif
|
||||||
|
#ifdef MULTILANGUAGE_TRANSLATIONPROVIDER
|
||||||
|
Sqlite::LibraryInitializer::initialize();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//If a style different from Desktop is set we have to use QGuiApplication
|
||||||
|
bool useGuiApplication = (!qEnvironmentVariableIsSet("QMLDESIGNER_FORCE_QAPPLICATION")
|
||||||
|
|| qgetenv("QMLDESIGNER_FORCE_QAPPLICATION") != "true")
|
||||||
|
&& qEnvironmentVariableIsSet("QT_QUICK_CONTROLS_STYLE")
|
||||||
|
&& qgetenv("QT_QUICK_CONTROLS_STYLE") != "Desktop";
|
||||||
|
#ifndef QT_GUI_LIB
|
||||||
|
createCoreApp<QCoreApplication>();
|
||||||
|
#else
|
||||||
|
#if defined QT_WIDGETS_LIB
|
||||||
|
if (!useGuiApplication)
|
||||||
|
createCoreApp<QApplication>();
|
||||||
|
else
|
||||||
|
#endif //QT_WIDGETS_LIB
|
||||||
|
createCoreApp<QGuiApplication>();
|
||||||
|
#endif //QT_GUI_LIB
|
||||||
|
}
|
||||||
|
|
||||||
|
int QmlPuppet::startTestMode()
|
||||||
|
{
|
||||||
|
QQmlEngine engine;
|
||||||
|
QQmlComponent component(&engine);
|
||||||
|
component.setData("import QtQuick 2.0\nItem {\n}\n", QUrl::fromLocalFile("test.qml"));
|
||||||
|
|
||||||
|
if (!QSharedPointer<QObject>(component.create())) {
|
||||||
|
qDebug() << "Basic QtQuick 2.0 not working...";
|
||||||
|
qDebug() << component.errorString();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Basic QtQuick 2.0 working...";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlPuppet::populateParser()
|
||||||
|
{
|
||||||
|
// we're not using the commandline parser but just populating the help text
|
||||||
|
m_argParser.addOptions(
|
||||||
|
{{"readcapturedstream", "Read captured stream.", "inputStream, [outputStream]"},
|
||||||
|
{"rendericon", "Renders icon.", "size, fileName, sourceQml"},
|
||||||
|
{"import3dAsset", "Import 3d asset.", "sourceAsset, outDir, importOptJson"}});
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlPuppet::initQmlRunner()
|
||||||
|
{
|
||||||
|
if (m_coreApp->arguments().count() < 2
|
||||||
|
|| (m_argParser.isSet("readcapturedstream") && m_coreApp->arguments().count() < 3)
|
||||||
|
|| (m_argParser.isSet("rendericon") && m_coreApp->arguments().count() < 5)
|
||||||
|
|| (m_argParser.isSet("import3dAsset") && m_coreApp->arguments().count() < 6)
|
||||||
|
|| (!m_argParser.isSet("readcapturedstream") && m_coreApp->arguments().count() < 4)) {
|
||||||
|
qDebug() << "Wrong argument count: " << m_coreApp->arguments().count();
|
||||||
|
m_argParser.showHelp(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_argParser.isSet("readcapturedstream") && m_coreApp->arguments().count() > 2) {
|
||||||
|
QString fileName = m_argParser.value("readcapturedstream");
|
||||||
|
if (!QFile::exists(fileName)) {
|
||||||
|
qDebug() << "Input stream does not exist:" << fileName;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_coreApp->arguments().count() > 3) {
|
||||||
|
fileName = m_coreApp->arguments().at(3);
|
||||||
|
if (!QFile::exists(fileName)) {
|
||||||
|
qDebug() << "Output stream does not exist:" << fileName;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_argParser.isSet("rendericon")) {
|
||||||
|
int size = m_coreApp->arguments().at(2).toInt();
|
||||||
|
QString iconFileName = m_coreApp->arguments().at(3);
|
||||||
|
QString iconSource = m_coreApp->arguments().at(4);
|
||||||
|
|
||||||
|
m_iconRenderer.reset(new IconRenderer(size, iconFileName, iconSource));
|
||||||
|
m_iconRenderer->setupRender();
|
||||||
|
} else if (m_argParser.isSet("import3dAsset")) {
|
||||||
|
QString sourceAsset = m_coreApp->arguments().at(2);
|
||||||
|
QString outDir = m_coreApp->arguments().at(3);
|
||||||
|
QString options = m_coreApp->arguments().at(4);
|
||||||
|
|
||||||
|
Import3D::import3D(sourceAsset, outDir, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
START_CRASHPAD;
|
||||||
|
new QmlDesigner::Qt5NodeInstanceClientProxy(m_coreApp.get());
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN) && defined(QT_NO_DEBUG)
|
||||||
|
SetErrorMode(SEM_NOGPFAULTERRORBOX); //We do not want to see any message boxes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m_argParser.isSet("readcapturedstream"))
|
||||||
|
exit(0);
|
||||||
|
}
|
21
src/tools/qml2puppet/qml2puppet/runner/puppet/qmlpuppet.h
Normal file
21
src/tools/qml2puppet/qml2puppet/runner/puppet/qmlpuppet.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../qmlbase.h"
|
||||||
|
|
||||||
|
class IconRenderer;
|
||||||
|
class QmlPuppet : public QmlBase
|
||||||
|
{
|
||||||
|
using QmlBase::QmlBase;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initCoreApp() override;
|
||||||
|
void populateParser() override;
|
||||||
|
int startTestMode() override;
|
||||||
|
void initQmlRunner() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSharedPointer<IconRenderer> m_iconRenderer;
|
||||||
|
};
|
111
src/tools/qml2puppet/qml2puppet/runner/qmlbase.h
Normal file
111
src/tools/qml2puppet/qml2puppet/runner/qmlbase.h
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH
|
||||||
|
// Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
#include <QQmlComponent>
|
||||||
|
#include <QQmlContext>
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QFileOpenEvent>
|
||||||
|
#include <QLibraryInfo>
|
||||||
|
#include <QSurfaceFormat>
|
||||||
|
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QTranslator>
|
||||||
|
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
#include "appmetadata.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
class QmlBase : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
struct AppArgs
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
};
|
||||||
|
|
||||||
|
QmlBase(int &argc, char **argv, QObject *parent = nullptr)
|
||||||
|
: QObject{parent}
|
||||||
|
, m_args({argc, argv})
|
||||||
|
{
|
||||||
|
m_argParser.setApplicationDescription("QML Runtime Provider for QDS");
|
||||||
|
m_argParser.addOptions(
|
||||||
|
{{"qml-puppet", "Run QML Puppet (default)"},
|
||||||
|
{"qml-runtime", "Run QML Runtime"},
|
||||||
|
{"appinfo", "Print build information"},
|
||||||
|
{"test", "Run test mode"}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int run()
|
||||||
|
{
|
||||||
|
populateParser();
|
||||||
|
initCoreApp();
|
||||||
|
initParser();
|
||||||
|
initQmlRunner();
|
||||||
|
return m_coreApp->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<QCoreApplication> coreApp() const { return m_coreApp; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void initCoreApp() = 0;
|
||||||
|
virtual void populateParser() = 0;
|
||||||
|
virtual void initQmlRunner() = 0;
|
||||||
|
|
||||||
|
virtual int startTestMode()
|
||||||
|
{
|
||||||
|
qDebug() << "Test mode is not implemented for this type of runner";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void createCoreApp()
|
||||||
|
{
|
||||||
|
m_coreApp.reset(new T(m_args.argc, m_args.argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<QCoreApplication> m_coreApp;
|
||||||
|
QCommandLineParser m_argParser;
|
||||||
|
QSharedPointer<QQmlApplicationEngine> m_qmlEngine;
|
||||||
|
|
||||||
|
AppArgs m_args;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initParser()
|
||||||
|
{
|
||||||
|
QCommandLineOption optHelp = m_argParser.addHelpOption();
|
||||||
|
QCommandLineOption optVers = m_argParser.addVersionOption();
|
||||||
|
|
||||||
|
if (!m_coreApp) {
|
||||||
|
qCritical() << "Cannot initialize coreapp!";
|
||||||
|
m_argParser.showHelp();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_argParser.parse(m_coreApp->arguments())) {
|
||||||
|
std::cout << "Error: " << m_argParser.errorText().toStdString() << std::endl
|
||||||
|
<< std::endl;
|
||||||
|
m_argParser.showHelp(1);
|
||||||
|
} else if (m_argParser.isSet(optVers)) {
|
||||||
|
m_argParser.showVersion();
|
||||||
|
} else if (m_argParser.isSet(optHelp)) {
|
||||||
|
m_argParser.showHelp(0);
|
||||||
|
} else if (m_argParser.isSet("appinfo")) {
|
||||||
|
QDSMeta::AppInfo::printAppInfo();
|
||||||
|
} else if (m_argParser.isSet("test")) {
|
||||||
|
exit(startTestMode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
97
src/tools/qml2puppet/qml2puppet/runner/runtime/loadwatcher.h
Normal file
97
src/tools/qml2puppet/qml2puppet/runner/runtime/loadwatcher.h
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qmlconfiguration.h"
|
||||||
|
|
||||||
|
#include "QtQml/qqmlcomponent.h"
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QQmlApplicationEngine>
|
||||||
|
|
||||||
|
//// 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, Config *conf)
|
||||||
|
: QObject(e)
|
||||||
|
, qae(e)
|
||||||
|
, conf(conf)
|
||||||
|
, expectedFileCount(expected)
|
||||||
|
{
|
||||||
|
connect(e, &QQmlApplicationEngine::objectCreated, this, &LoadWatcher::checkFinished);
|
||||||
|
// QQmlApplicationEngine also connects quit() to QCoreApplication::quit
|
||||||
|
// and exit() to QCoreApplication::exit but if called before exec()
|
||||||
|
// then QCoreApplication::quit or QCoreApplication::exit does nothing
|
||||||
|
connect(e, &QQmlEngine::quit, this, &LoadWatcher::quit);
|
||||||
|
connect(e, &QQmlEngine::exit, this, &LoadWatcher::exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
int returnCode = 0;
|
||||||
|
bool earlyExit = false;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void checkFinished(QObject *o, const QUrl &url)
|
||||||
|
{
|
||||||
|
Q_UNUSED(url);
|
||||||
|
if (o) {
|
||||||
|
checkForWindow(o);
|
||||||
|
if (conf && qae) {
|
||||||
|
for (PartialScene *ps : std::as_const(conf->completers)) {
|
||||||
|
if (o->inherits(ps->itemType().toUtf8().constData()))
|
||||||
|
contain(o, ps->container());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (haveWindow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!--expectedFileCount) {
|
||||||
|
printf("qml: Did not load any objects, exiting.\n");
|
||||||
|
exit(2);
|
||||||
|
QCoreApplication::exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit()
|
||||||
|
{
|
||||||
|
// Will be checked before calling exec()
|
||||||
|
earlyExit = true;
|
||||||
|
returnCode = 0;
|
||||||
|
}
|
||||||
|
void exit(int retCode)
|
||||||
|
{
|
||||||
|
earlyExit = true;
|
||||||
|
returnCode = retCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void contain(QObject *o, const QUrl &containPath)
|
||||||
|
{
|
||||||
|
QQmlComponent c(qae, containPath);
|
||||||
|
QObject *o2 = c.create();
|
||||||
|
if (!o2)
|
||||||
|
return;
|
||||||
|
o2->setParent(this);
|
||||||
|
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 checkForWindow(QObject *o)
|
||||||
|
{
|
||||||
|
if (o->isWindowType() && o->inherits("QQuickWindow"))
|
||||||
|
haveWindow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QQmlApplicationEngine *qae;
|
||||||
|
Config *conf;
|
||||||
|
|
||||||
|
bool haveWindow = false;
|
||||||
|
int expectedFileCount;
|
||||||
|
};
|
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QtQml/qqml.h>
|
||||||
|
|
||||||
|
class PartialScene : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QUrl container READ container WRITE setContainer NOTIFY containerChanged)
|
||||||
|
Q_PROPERTY(QString itemType READ itemType WRITE setItemType NOTIFY itemTypeChanged)
|
||||||
|
QML_ELEMENT
|
||||||
|
QML_ADDED_IN_VERSION(1, 0)
|
||||||
|
public:
|
||||||
|
PartialScene(QObject *parent = nullptr)
|
||||||
|
: QObject(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const QUrl container() const { return m_container; }
|
||||||
|
const QString itemType() const { return m_itemType; }
|
||||||
|
|
||||||
|
void setContainer(const QUrl &a)
|
||||||
|
{
|
||||||
|
if (a == m_container)
|
||||||
|
return;
|
||||||
|
m_container = a;
|
||||||
|
emit containerChanged();
|
||||||
|
}
|
||||||
|
void setItemType(const QString &a)
|
||||||
|
{
|
||||||
|
if (a == m_itemType)
|
||||||
|
return;
|
||||||
|
m_itemType = a;
|
||||||
|
emit itemTypeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void containerChanged();
|
||||||
|
void itemTypeChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QUrl m_container;
|
||||||
|
QString m_itemType;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Config : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(QQmlListProperty<PartialScene> sceneCompleters READ sceneCompleters)
|
||||||
|
Q_CLASSINFO("DefaultProperty", "sceneCompleters")
|
||||||
|
QML_NAMED_ELEMENT(Configuration)
|
||||||
|
QML_ADDED_IN_VERSION(1, 0)
|
||||||
|
public:
|
||||||
|
Config(QObject *parent = nullptr)
|
||||||
|
: QObject(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QQmlListProperty<PartialScene> sceneCompleters()
|
||||||
|
{
|
||||||
|
return QQmlListProperty<PartialScene>(this, &completers);
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<PartialScene *> completers;
|
||||||
|
};
|
348
src/tools/qml2puppet/qml2puppet/runner/runtime/qmlruntime.cpp
Normal file
348
src/tools/qml2puppet/qml2puppet/runner/runtime/qmlruntime.cpp
Normal file
@@ -0,0 +1,348 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
#include "loadwatcher.h"
|
||||||
|
#include "qmlruntime.h"
|
||||||
|
|
||||||
|
#include <private/qqmlimport_p.h>
|
||||||
|
#include <private/qtqmlglobal_p.h>
|
||||||
|
#if QT_CONFIG(qml_animation)
|
||||||
|
#include <private/qabstractanimation_p.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FILE_OPEN_EVENT_WAIT_TIME 3000 // ms
|
||||||
|
#define QSL QStringLiteral
|
||||||
|
|
||||||
|
void QmlRuntime::populateParser()
|
||||||
|
{
|
||||||
|
m_argParser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
||||||
|
m_argParser.setOptionsAfterPositionalArgumentsMode(
|
||||||
|
QCommandLineParser::ParseAsPositionalArguments);
|
||||||
|
|
||||||
|
m_argParser.addOptions(
|
||||||
|
{{QStringList() << QSL("a") << QSL("apptype"),
|
||||||
|
QSL("Select which application class to use. Default is gui."),
|
||||||
|
QSL("core|gui|widget")}, // just for translation
|
||||||
|
|
||||||
|
{QSL("I"), QSL("Prepend the given path to the import paths."), QSL("path")},
|
||||||
|
|
||||||
|
{QSL("f"), QSL("Load the given file as a QML file."), QSL("file")},
|
||||||
|
|
||||||
|
{QStringList() << QSL("c") << QSL("config"),
|
||||||
|
QSL("Load the given built-in configuration or configuration file."),
|
||||||
|
QSL("file")},
|
||||||
|
|
||||||
|
{QStringList() << QSL("list-conf"), QSL("List the built-in configurations.")},
|
||||||
|
|
||||||
|
{QSL("translation"), QSL("Load the given file as the translations file."), QSL("file")},
|
||||||
|
|
||||||
|
#ifdef QT_GUI_LIB
|
||||||
|
// OpenGL options
|
||||||
|
{QSL("desktop"), QSL("Force use of desktop OpenGL (AA_UseDesktopOpenGL).")},
|
||||||
|
|
||||||
|
{QSL("gles"), QSL("Force use of GLES (AA_UseOpenGLES).")},
|
||||||
|
|
||||||
|
{QSL("software"), QSL("Force use of software rendering (AA_UseSoftwareOpenGL).")},
|
||||||
|
|
||||||
|
{QSL("core-profile"), QSL("Force use of OpenGL Core Profile.")},
|
||||||
|
|
||||||
|
{QSL("disable-context-sharing"),
|
||||||
|
QSL("Disable the use of a shared GL context for QtQuick Windows")},
|
||||||
|
#endif // QT_GUI_LIB
|
||||||
|
|
||||||
|
// Debugging and verbosity options
|
||||||
|
{QSL("quiet"), QSL("Suppress all output.")},
|
||||||
|
|
||||||
|
{QSL("verbose"),
|
||||||
|
QSL("Print information about what qml is doing, like specific file URLs being loaded.")},
|
||||||
|
|
||||||
|
{QSL("slow-animations"), QSL("Run all animations in slow motion.")},
|
||||||
|
|
||||||
|
{QSL("fixed-animations"), QSL("Run animations off animation tick rather than wall time.")},
|
||||||
|
|
||||||
|
{QStringList() << QSL("r") << QSL("rhi"),
|
||||||
|
QSL("Set the backend for the Qt graphics abstraction (RHI). "
|
||||||
|
"Backend is one of: default, vulkan, metal, d3d11, gl"),
|
||||||
|
QSL("backend")},
|
||||||
|
|
||||||
|
{QSL("S"), QSL("Add selector to the list of QQmlFileSelectors."), QSL("selector")}});
|
||||||
|
|
||||||
|
// Positional arguments
|
||||||
|
m_argParser.addPositionalArgument(
|
||||||
|
"files",
|
||||||
|
QSL("Any number of QML files can be loaded. They will share the same engine."),
|
||||||
|
"[files...]");
|
||||||
|
m_argParser.addPositionalArgument("args",
|
||||||
|
QSL("Arguments after '--' are ignored, but passed through to "
|
||||||
|
"the application.arguments variable in QML."),
|
||||||
|
"[-- args...]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlRuntime::initCoreApp()
|
||||||
|
{
|
||||||
|
bool glShareContexts = true;
|
||||||
|
|
||||||
|
// these attributes must be set before the QCoreApp is initialized
|
||||||
|
for (int i = 0; i < m_args.argc; i++) {
|
||||||
|
if (!strcmp(m_args.argv[i], "-desktop") || !strcmp(m_args.argv[i], "--desktop")) {
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
|
||||||
|
} else if (!strcmp(m_args.argv[i], "-gles") || !strcmp(m_args.argv[i], "--gles")) {
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
|
||||||
|
} else if (!strcmp(m_args.argv[i], "-software") || !strcmp(m_args.argv[i], "--software")) {
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
|
||||||
|
} else if (!strcmp(m_args.argv[i], "-disable-context-sharing")
|
||||||
|
|| !strcmp(m_args.argv[i], "--disable-context-sharing")) {
|
||||||
|
glShareContexts = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glShareContexts)
|
||||||
|
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
|
||||||
|
|
||||||
|
// since we handled all attributes above, now we can initialize the core app
|
||||||
|
for (int i = 0; i < m_args.argc; i++) {
|
||||||
|
if (!strcmp(m_args.argv[i], "--apptype") || !strcmp(m_args.argv[i], "-a")
|
||||||
|
|| !strcmp(m_args.argv[i], "-apptype")) {
|
||||||
|
if (i + 1 < m_args.argc) {
|
||||||
|
++i;
|
||||||
|
if (!strcmp(m_args.argv[i], "core")) {
|
||||||
|
createCoreApp<QCoreApplication>();
|
||||||
|
}
|
||||||
|
else if (!strcmp(m_args.argv[i], "gui")) {
|
||||||
|
createCoreApp<QGuiApplication>();
|
||||||
|
}
|
||||||
|
#ifdef QT_WIDGETS_LIB
|
||||||
|
else if (!strcmp(m_args.argv[i], "widget")) {
|
||||||
|
createCoreApp<QApplication>();
|
||||||
|
static_cast<QApplication *>(m_coreApp.get())
|
||||||
|
->setWindowIcon(QIcon(m_iconResourcePath));
|
||||||
|
}
|
||||||
|
#endif // QT_WIDGETS_LIB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlRuntime::initQmlRunner()
|
||||||
|
{
|
||||||
|
m_qmlEngine.reset(new QQmlApplicationEngine());
|
||||||
|
|
||||||
|
QStringList files;
|
||||||
|
QString confFile;
|
||||||
|
QString translationFile;
|
||||||
|
|
||||||
|
if (!m_argParser.parse(QCoreApplication::arguments())) {
|
||||||
|
qWarning() << m_argParser.errorText();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: replace below logging modes with a proper logging category
|
||||||
|
m_verboseMode = m_argParser.isSet("verbose");
|
||||||
|
m_quietMode = (!m_verboseMode && m_argParser.isSet("quiet"));
|
||||||
|
// FIXME: need to re-evaluate. we have our own message handler.
|
||||||
|
// if (quietMode) {
|
||||||
|
// qInstallMessageHandler(quietMessageHandler);
|
||||||
|
// QLoggingCategory::setFilterRules(QStringLiteral("*=false"));
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (m_argParser.isSet("list-conf")) {
|
||||||
|
listConfFiles();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QT_CONFIG(qml_animation)
|
||||||
|
if (m_argParser.isSet("slow-animations"))
|
||||||
|
QUnifiedTimer::instance()->setSlowModeEnabled(true);
|
||||||
|
if (m_argParser.isSet("fixed-animations"))
|
||||||
|
QUnifiedTimer::instance()->setConsistentTiming(true);
|
||||||
|
#endif
|
||||||
|
const auto valsImportPath = m_argParser.values("I");
|
||||||
|
for (const QString &importPath : valsImportPath)
|
||||||
|
m_qmlEngine->addImportPath(importPath);
|
||||||
|
|
||||||
|
QStringList customSelectors;
|
||||||
|
|
||||||
|
const auto valsSelectors = m_argParser.values("S");
|
||||||
|
for (const QString &selector : valsSelectors)
|
||||||
|
customSelectors.append(selector);
|
||||||
|
|
||||||
|
if (!customSelectors.isEmpty())
|
||||||
|
m_qmlEngine->setExtraFileSelectors(customSelectors);
|
||||||
|
|
||||||
|
if (qEnvironmentVariableIsSet("QSG_CORE_PROFILE")
|
||||||
|
|| qEnvironmentVariableIsSet("QML_CORE_PROFILE") || m_argParser.isSet("core-profile")) {
|
||||||
|
QSurfaceFormat surfaceFormat;
|
||||||
|
surfaceFormat.setStencilBufferSize(8);
|
||||||
|
surfaceFormat.setDepthBufferSize(24);
|
||||||
|
surfaceFormat.setVersion(4, 1);
|
||||||
|
surfaceFormat.setProfile(QSurfaceFormat::CoreProfile);
|
||||||
|
QSurfaceFormat::setDefaultFormat(surfaceFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_argParser.isSet("config"))
|
||||||
|
confFile = m_argParser.value("config");
|
||||||
|
if (m_argParser.isSet("translation"))
|
||||||
|
translationFile = m_argParser.value("translation");
|
||||||
|
if (m_argParser.isSet("rhi")) {
|
||||||
|
const QString rhiBackend = m_argParser.value("rhi");
|
||||||
|
if (rhiBackend == QLatin1String("default"))
|
||||||
|
qunsetenv("QSG_RHI_BACKEND");
|
||||||
|
else
|
||||||
|
qputenv("QSG_RHI_BACKEND", rhiBackend.toLatin1());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto valsPosArgs = m_argParser.positionalArguments();
|
||||||
|
files << m_argParser.values("f");
|
||||||
|
for (const QString &posArg : valsPosArgs) {
|
||||||
|
if (posArg == QLatin1String("--"))
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
files << posArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QT_CONFIG(translation)
|
||||||
|
// Need to be installed before QQmlApplicationEngine's automatic translation loading
|
||||||
|
// (qt_ translations are loaded there)
|
||||||
|
if (!translationFile.isEmpty()) {
|
||||||
|
QTranslator translator;
|
||||||
|
|
||||||
|
if (translator.load(translationFile)) {
|
||||||
|
m_coreApp->installTranslator(&translator);
|
||||||
|
if (m_verboseMode)
|
||||||
|
qInfo() << "qml: Loaded translation file %s\n",
|
||||||
|
qPrintable(QDir::toNativeSeparators(translationFile));
|
||||||
|
} else {
|
||||||
|
if (!m_quietMode)
|
||||||
|
qInfo() << "qml: Could not load the translation file %s\n",
|
||||||
|
qPrintable(QDir::toNativeSeparators(translationFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!translationFile.isEmpty() && !quietMode)
|
||||||
|
qInfo() << "qml: Translation file specified, but Qt built without translation support.\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (files.size() <= 0) {
|
||||||
|
#if defined(Q_OS_DARWIN)
|
||||||
|
if (qobject_cast<QGuiApplication *>(m_coreApp.data())) {
|
||||||
|
m_exitTimerId = static_cast<QGuiApplication *>(m_coreApp.get())
|
||||||
|
->startTimer(FILE_OPEN_EVENT_WAIT_TIME);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (!m_quietMode)
|
||||||
|
qCritical() << "No files specified. Terminating.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadConf(confFile, !m_verboseMode);
|
||||||
|
|
||||||
|
// Load files
|
||||||
|
QScopedPointer<LoadWatcher> lw(new LoadWatcher(m_qmlEngine.data(), files.size(), m_conf.data()));
|
||||||
|
|
||||||
|
for (const QString &path : std::as_const(files)) {
|
||||||
|
QUrl url = QUrl::fromUserInput(path, QDir::currentPath(), QUrl::AssumeLocalFile);
|
||||||
|
if (m_verboseMode)
|
||||||
|
qInfo() << "qml: loading %s\n", qPrintable(url.toString());
|
||||||
|
m_qmlEngine->load(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lw->earlyExit)
|
||||||
|
exit(lw->returnCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlRuntime::loadConf(const QString &override, bool quiet) // Terminates app on failure
|
||||||
|
{
|
||||||
|
const QString defaultFileName = QLatin1String("default.qml");
|
||||||
|
QUrl settingsUrl;
|
||||||
|
bool builtIn = false; //just for keeping track of the warning
|
||||||
|
if (override.isEmpty()) {
|
||||||
|
QFileInfo fi;
|
||||||
|
fi.setFile(QStandardPaths::locate(QStandardPaths::AppDataLocation, defaultFileName));
|
||||||
|
if (fi.exists()) {
|
||||||
|
settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
|
||||||
|
} else {
|
||||||
|
// If different built-in configs are needed per-platform, just apply QFileSelector to the qrc conf.qml path
|
||||||
|
fi.setFile(m_confResourcePath + defaultFileName);
|
||||||
|
settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
|
||||||
|
builtIn = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QFileInfo fi;
|
||||||
|
fi.setFile(m_confResourcePath + override + QLatin1String(".qml"));
|
||||||
|
if (fi.exists()) {
|
||||||
|
settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
|
||||||
|
builtIn = true;
|
||||||
|
} else {
|
||||||
|
fi.setFile(QDir(QStandardPaths::locate(QStandardPaths::AppConfigLocation,
|
||||||
|
override,
|
||||||
|
QStandardPaths::LocateDirectory)),
|
||||||
|
m_confResourcePath);
|
||||||
|
if (fi.exists())
|
||||||
|
settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
|
||||||
|
else
|
||||||
|
fi.setFile(override);
|
||||||
|
if (!fi.exists()) {
|
||||||
|
qCritical() << "qml: Couldn't find required configuration file: %s\n",
|
||||||
|
qPrintable(QDir::toNativeSeparators(fi.absoluteFilePath()));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
settingsUrl = QQmlImports::urlFromLocalFileOrQrcOrUrl(fi.absoluteFilePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!quiet) {
|
||||||
|
qInfo() << "qml: %s\n", QLibraryInfo::build();
|
||||||
|
if (builtIn) {
|
||||||
|
qInfo() << "qml: Using built-in configuration: %s\n",
|
||||||
|
qPrintable(override.isEmpty() ? defaultFileName : override);
|
||||||
|
} else {
|
||||||
|
qInfo() << "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
|
||||||
|
QQmlEngine e2;
|
||||||
|
QQmlComponent c2(&e2, settingsUrl);
|
||||||
|
m_conf.reset(qobject_cast<Config *>(c2.create()));
|
||||||
|
|
||||||
|
if (!m_conf) {
|
||||||
|
qCritical() << "qml: Error loading configuration file: %s\n", qPrintable(c2.errorString());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlRuntime::listConfFiles()
|
||||||
|
{
|
||||||
|
const QDir confResourceDir(m_confResourcePath);
|
||||||
|
qInfo() << "%s\n", qPrintable(QCoreApplication::translate("main", "Built-in configurations:"));
|
||||||
|
for (const QFileInfo &fi : confResourceDir.entryInfoList(QDir::Files))
|
||||||
|
qInfo() << " %s\n", qPrintable(fi.baseName());
|
||||||
|
qInfo() << "%s\n", qPrintable(QCoreApplication::translate("main", "Other configurations:"));
|
||||||
|
bool foundOther = false;
|
||||||
|
const QStringList otherLocations = QStandardPaths::standardLocations(
|
||||||
|
QStandardPaths::AppConfigLocation);
|
||||||
|
for (const auto &confDirPath : otherLocations) {
|
||||||
|
const QDir confDir(confDirPath);
|
||||||
|
for (const QFileInfo &fi : confDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||||
|
foundOther = true;
|
||||||
|
if (m_verboseMode)
|
||||||
|
qInfo() << " %s\n", qPrintable(fi.absoluteFilePath());
|
||||||
|
else
|
||||||
|
qInfo() << " %s\n", qPrintable(fi.baseName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundOther)
|
||||||
|
qInfo() << " %s\n", qPrintable(QCoreApplication::translate("main", "none"));
|
||||||
|
if (m_verboseMode) {
|
||||||
|
qInfo() << "%s\n", qPrintable(QCoreApplication::translate("main", "Checked in:"));
|
||||||
|
for (const auto &confDirPath : otherLocations)
|
||||||
|
qInfo() << " %s\n", qPrintable(confDirPath);
|
||||||
|
}
|
||||||
|
}
|
30
src/tools/qml2puppet/qml2puppet/runner/runtime/qmlruntime.h
Normal file
30
src/tools/qml2puppet/qml2puppet/runner/runtime/qmlruntime.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../qmlbase.h"
|
||||||
|
#include "qmlconfiguration.h"
|
||||||
|
|
||||||
|
class QmlRuntime : public QmlBase
|
||||||
|
{
|
||||||
|
using QmlBase::QmlBase;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void initCoreApp() override;
|
||||||
|
void populateParser() override;
|
||||||
|
void initQmlRunner() override;
|
||||||
|
|
||||||
|
void listConfFiles();
|
||||||
|
void loadConf(const QString &override, bool quiet);
|
||||||
|
|
||||||
|
const QString m_iconResourcePath = QStringLiteral(":/qt-project.org/QmlRuntime/resources/qml-64.png");
|
||||||
|
const QString m_confResourcePath = QStringLiteral(":/runner/runnerconf/qmlruntime/");
|
||||||
|
|
||||||
|
|
||||||
|
QSharedPointer<Config> m_conf;
|
||||||
|
bool m_verboseMode = false;
|
||||||
|
bool m_quietMode = false;
|
||||||
|
int m_exitTimerId = -1;
|
||||||
|
};
|
||||||
|
|
@@ -12,4 +12,9 @@
|
|||||||
<file>mockfiles/ToolBarButton.qml</file>
|
<file>mockfiles/ToolBarButton.qml</file>
|
||||||
<file>mockfiles/ToggleButton.qml</file>
|
<file>mockfiles/ToggleButton.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
|
<qresource prefix="/runner">
|
||||||
|
<file>runnerconf/qmlruntime/default.qml</file>
|
||||||
|
<file>runnerconf/qmlruntime/content/resizeItemToWindow.qml</file>
|
||||||
|
<file>runnerconf/qmlruntime/content/resizeWindowToItem.qml</file>
|
||||||
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
import QtQuick.Window 2.0
|
||||||
|
import QtQuick 2.0
|
||||||
|
|
||||||
|
Window {
|
||||||
|
property Item containedObject: null
|
||||||
|
property bool __resizeGuard: false
|
||||||
|
onContainedObjectChanged: {
|
||||||
|
if (containedObject == undefined || containedObject == null) {
|
||||||
|
visible = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
__resizeGuard = true
|
||||||
|
width = containedObject.width
|
||||||
|
height = containedObject.height
|
||||||
|
containedObject.parent = contentItem
|
||||||
|
visible = true
|
||||||
|
__resizeGuard = false
|
||||||
|
}
|
||||||
|
onWidthChanged: if (!__resizeGuard && containedObject)
|
||||||
|
containedObject.width = width
|
||||||
|
onHeightChanged: if (!__resizeGuard && containedObject)
|
||||||
|
containedObject.height = height
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
import QtQuick.Window 2.0
|
||||||
|
import QtQuick 2.0
|
||||||
|
|
||||||
|
Window {
|
||||||
|
property Item containedObject: null
|
||||||
|
onContainedObjectChanged: {
|
||||||
|
if (containedObject == undefined || containedObject == null) {
|
||||||
|
visible = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
width = Qt.binding(function () {
|
||||||
|
return containedObject.width
|
||||||
|
})
|
||||||
|
height = Qt.binding(function () {
|
||||||
|
return containedObject.height
|
||||||
|
})
|
||||||
|
containedObject.parent = contentItem
|
||||||
|
visible = true
|
||||||
|
}
|
||||||
|
}
|
10
src/tools/qml2puppet/runnerconf/qmlruntime/default.qml
Normal file
10
src/tools/qml2puppet/runnerconf/qmlruntime/default.qml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||||
|
import QmlRuntime.QmlConfiguration 1.0
|
||||||
|
|
||||||
|
Configuration {
|
||||||
|
PartialScene {
|
||||||
|
itemType: "QQuickItem"
|
||||||
|
container: Qt.resolvedUrl("content/resizeItemToWindow.qml")
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user