diff --git a/CMakeLists.txt b/CMakeLists.txt index 82acd636913c818503dbca06b479c1deaa7ca2e4..724bb5547caa46f54d2c6e9b13b48d3d383ccf83 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ find_package( REQUIRED ) -set(QT_MINIMUM_VERSION 6.3.0) +set(QT_MINIMUM_VERSION 6.6.0) if(QT_VERSION VERSION_LESS QT_MINIMUM_VERSION) message(FATAL_ERROR "Minimum supported Qt version: ${QT_MINIMUM_VERSION}") endif() @@ -40,8 +40,22 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Qml Qt6::GuiPrivate ) -set_property(TARGET ${PROJECT_NAME} - APPEND PROPERTY QT_WASM_INITIAL_MEMORY "50MB" +## FIXME: cannot enable exceptions in wasm +# target_compile_options(${PROJECT_NAME} PRIVATE + # -fwasm-exceptions +# ) + +target_link_options(${PROJECT_NAME} PRIVATE + # -fwasm-exceptions + # -sEXPORT_EXCEPTION_HANDLING_HELPERS=1 + # -sEXCEPTION_STACK_TRACES=1 + -sEXCEPTION_DEBUG=1 + -sFULL_ES3=1 + -sABORT_ON_WASM_EXCEPTIONS=0 +) + +set_target_properties(${PROJECT_NAME} PROPERTIES + QT_WASM_INITIAL_MEMORY 2048MB ) qt6_import_qml_plugins(${PROJECT_NAME}) @@ -59,7 +73,7 @@ install( DIRECTORY ${CMAKE_SOURCE_DIR}/www/ DESTINATION ${CMAKE_INSTALL_PREFIX} ) - +# END --install configuration execute_process(COMMAND git describe --always --tags OUTPUT_VARIABLE GIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process(COMMAND git -C ${CMAKE_SOURCE_DIR}/qtquickdesigner-components describe --always --tags OUTPUT_VARIABLE QT_QUICK_COMPONENTS_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -72,5 +86,6 @@ message(STATUS "QT_QUICK_COMPONENTS_VERSION: ${QT_QUICK_COMPONENTS_VERSION}") message(STATUS "EMSDK_VERSION: ${EMSDK_VERSION}") message(STATUS "QT_VERSION: ${QT_VERSION}") +add_definitions( -DCMAKE_VAR_GIT_VERSION="${GIT_VERSION}" ) + set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_INSTALL_PREFIX}) -# END --install configuration diff --git a/cicd/gitlab-ci.yml b/cicd/gitlab-ci.yml index 1299a52056a8d675fcaae1ad858d57e3277afd3b..64ce51a2090709dcfa3149c7b1cbc92a70725f7b 100644 --- a/cicd/gitlab-ci.yml +++ b/cicd/gitlab-ci.yml @@ -1,7 +1,8 @@ variables: - QDS_CI_QT_VERSION: - value: "6.6.1" - description: "Qt version for build" + # QT version and emsdk version must be compatible. + # See https://doc.qt.io/qt-6/wasm.html + QDS_CI_QT_VERSION: "6.6.1" + QDS_CI_EMSDK_VERSION: "3.1.37" QDS_CI_ARTIFACTS_PATH: "${CI_PROJECT_DIR}/artifacts" DEBIAN_FRONTEND: non-interactive GIT_SUBMODULE_STRATEGY: recursive diff --git a/cicd/stages/build.yml b/cicd/stages/build.yml index ba4b2313f617f30eecb4f45759c8ac077bbda3eb..d236bb84c05026b15dd9b13db9a80136dcd39a06 100644 --- a/cicd/stages/build.yml +++ b/cicd/stages/build.yml @@ -21,8 +21,8 @@ build-wasm: - mkdir -p ${QDS_CI_ARTIFACTS_PATH} - | cd emsdk - ./emsdk install 3.1.37 - ./emsdk activate 3.1.37 + ./emsdk install ${QDS_CI_EMSDK_VERSION} + ./emsdk activate ${QDS_CI_EMSDK_VERSION} source emsdk_env.sh cd .. - echo ${DOCKER_ENV_QT_PATH_WASM_SINGLETHREAD} diff --git a/src/designviewer.cpp b/src/designviewer.cpp index 7eb3fe6f8f9e474e9979874208ae9172b47e057a..228ed446042a8f48b9646ac6f4b944e4b7bb6586 100644 --- a/src/designviewer.cpp +++ b/src/designviewer.cpp @@ -46,8 +46,6 @@ #include <QtGui/private/qzipreader_p.h> #endif -#define printErr(x) printError(x, __FILE_NAME__, __LINE__) - std::function<void(char *, size_t, char *)> g_setFileDataCallback; extern "C" EMSCRIPTEN_KEEPALIVE void qt_callSetFileData(char *content, size_t contentSize, @@ -62,26 +60,26 @@ extern "C" EMSCRIPTEN_KEEPALIVE void qt_callSetFileData(char *content, DesignViewer::DesignViewer() { - printLog("DesignViewer constructor"); + qDebug() << "DesignViewer constructor"; QString projectFileName; QByteArray projectData; - printLog("Fetching project"); + qDebug() << "Fetching project"; fetchProject(&projectData, &projectFileName); - printLog("Running project"); + qDebug() << "Running project"; if (!runProject(projectData, projectFileName)) { - printErr("Failed to run project"); + qCritical() << "Failed to run project"; } - printLog("DesignViewer constructor done"); + qDebug() << "DesignViewer constructor done"; } void DesignViewer::fetchProject(QByteArray *data, QString *fileName) { - printLog("Init project data"); + qDebug() << "Init project data"; // Access global variables set by index.html emscripten::val jsData = emscripten::val::global("contentArray"); emscripten::val jsFileName = emscripten::val::global("projectfileName"); - printLog("Copying project data"); + qDebug() << "Copying project data"; // Copy project data to the C++ heap and convert string *data = QByteArray::fromEcmaUint8Array(jsData); *fileName = QString::fromStdString(jsFileName.as<std::string>()); @@ -91,8 +89,7 @@ QString DesignViewer::unpackProject(const QByteArray &project, bool extractZip) { QString projectLocation = "/home/web_user/"; - if (extractZip) - { + if (extractZip) { QDir().mkpath(projectLocation); QBuffer buffer; buffer.setData(project); @@ -101,42 +98,38 @@ QString DesignViewer::unpackProject(const QByteArray &project, bool extractZip) reader.extractAll(projectLocation); } - printLog("Initial project location: " + projectLocation); + qDebug() << "Initial project location: " + projectLocation; QDir projectLocationDir(projectLocation); // maybe it was not a zip file so try it as resource binary - if (projectLocationDir.isEmpty()) - { + if (projectLocationDir.isEmpty()) { if (extractZip) - printLog("File could not be extracted. Trying to open it as a resource file."); + qDebug() << "File could not be extracted. Trying to open it as a resource file."; const uchar *data; - if (m_projectData.size()) - { - printLog("Unregistering the previous data from QRC system. Path: " + m_projectPath + " Size: " + QString::number(m_projectData.size()) + " bytes."); + if (m_projectData.size()) { + qDebug() << "Unregistering the previous data from QRC system. Path: " + m_projectPath + + " Size: " + QString::number(m_projectData.size()) + " bytes."; data = reinterpret_cast<const uchar *>(m_projectData.data()); - if (!QResource::unregisterResource(data, m_projectPath)) - { - printErr("Cannot unregister the previous resource data."); + if (!QResource::unregisterResource(data, m_projectPath)) { + qCritical() << "Cannot unregister the previous resource data."; } } m_projectData = project; data = reinterpret_cast<const uchar *>(m_projectData.data()); - printLog("Registering resource data. Size: " + QString::number(m_projectData.size())); + qDebug() << "Registering resource data. Size: " + QString::number(m_projectData.size()); const QString resourcePath{"/" + QString::number(QRandomGenerator::global()->generate())}; m_projectPath = resourcePath; - if (!QDir(resourcePath).removeRecursively()) - { - printLog("Could not remove resource path: " + resourcePath); + if (!QDir(resourcePath).removeRecursively()) { + qDebug() << "Could not remove resource path: " + resourcePath; } - if (!QResource::registerResource(data, resourcePath)) - { - printErr("Can not load the resource data."); + if (!QResource::registerResource(data, resourcePath)) { + qCritical() << "Can not load the resource data."; return ""; } @@ -161,9 +154,8 @@ void DesignViewer::parseQmlprojectFile(const QString &fileName, * need to keep the only ":" character at the beginning of the string */ QFile file(fileName); - if (!file.open(QIODevice::ReadOnly)) - { - printErr("Could not open Qml Project file! " + fileName + ": " + file.errorString()); + if (!file.open(QIODevice::ReadOnly)) { + qCritical() << "Could not open Qml Project file! " + fileName + ": " + file.errorString(); return; } @@ -172,13 +164,12 @@ void DesignViewer::parseQmlprojectFile(const QString &fileName, const QRegularExpression mainFileRegExp("mainFile:\\s*\"(.*)\""); const QRegularExpressionMatch mainFileMatch = mainFileRegExp.match(text); - if (!mainFileMatch.hasMatch()) - { - printErr("No main file found in " + fileName); + if (!mainFileMatch.hasMatch()) { + qCritical() << "No main file found in " + fileName; return; } - printLog("Found main file: " + mainFileMatch.captured(1)); + qDebug() << "Found main file: " + mainFileMatch.captured(1); QString basePath = QFileInfo(fileName).path() + "/"; *mainFile = basePath + mainFileMatch.captured(1); @@ -189,8 +180,8 @@ void DesignViewer::parseQmlprojectFile(const QString &fileName, const QRegularExpressionMatch qt6ProjectMatch = qt6ProjectRegExp.match(text); if (!qt6ProjectMatch.hasMatch()) { - printWarn("This is not a Qt6 project.\nQt5 projects might work, but they are not " - "officially supported."); + qWarning() << "This is not a Qt6 project.\nQt5 projects might work, but they are not " + "officially supported."; } const QRegularExpression importPathsRegExp("importPaths:\\s*\\[\\s*(.*)\\s*\\]"); @@ -198,12 +189,10 @@ void DesignViewer::parseQmlprojectFile(const QString &fileName, if (importPathsMatch.hasMatch()) { - for (const QString &path : importPathsMatch.captured(1).split(",")) - { + for (const QString &path : importPathsMatch.captured(1).split(",")) { QString cleanedPath = path.trimmed(); cleanedPath = basePath + cleanedPath.mid(1, cleanedPath.length() - 2); - if (QFileInfo::exists(cleanedPath)) - { + if (QFileInfo::exists(cleanedPath)) { if (cleanedPath.startsWith(QLatin1String(":/"))) cleanedPath = "qrc:" + cleanedPath.mid(1); importPaths->append(cleanedPath); @@ -218,118 +207,107 @@ bool DesignViewer::runProject(const QByteArray &projectData, const QString &proj QString newProjectName = QString(projectName).remove(".qmlrc"); if (newProjectName.contains("/")) { - printLog("Project name contains a path. Removing it."); + qDebug() << "Project name contains a path. Removing it."; newProjectName = newProjectName.split("/").last(); } - printLog("Final project location: " + projectLocation); - printLog("Original project name: " + projectName); - printLog("New project name: " + newProjectName); + qDebug() << "Final project location: " + projectLocation; + qDebug() << "Original project name: " + projectName; + qDebug() << "New project name: " + newProjectName; QString mainQmlFilePath; QStringList importPaths; - printLog("Looking for qmlproject file in " + projectLocation); + qDebug() << "Looking for qmlproject file in " + projectLocation; const QString qmlProjectFile = findFile(projectLocation, newProjectName + ".qmlproject"); - if (!qmlProjectFile.isEmpty()) - { - printLog("Found qmlproject file: " + qmlProjectFile); + if (!qmlProjectFile.isEmpty()) { + qDebug() << "Found qmlproject file: " + qmlProjectFile; parseQmlprojectFile(qmlProjectFile, &mainQmlFilePath, &importPaths); - } - else - { - printWarn("Not found: \"*.qmlproject\". Looking for main.qml.."); + } else { + qWarning() << "Not found: \"*.qmlproject\". Looking for main.qml.."; mainQmlFilePath = findFile(projectLocation, "main.qml"); if (mainQmlFilePath.isEmpty()) { - printWarn("Not found: \"main.qml\". Looking for \"" + newProjectName + ".qml\".."); + qWarning() << "Not found: \"main.qml\". Looking for \"" + newProjectName + ".qml\".."; mainQmlFilePath = findFile(projectLocation, newProjectName + ".qml"); } } - if (mainQmlFilePath.isEmpty()) - { - printErr("No \"*.qmlproject\", \"main.qml\" or \"" + newProjectName + ".qml\" found in \"" + projectLocation + "\"."); + if (mainQmlFilePath.isEmpty()) { + qCritical() << "No \"*.qmlproject\", \"main.qml\" or \"" + newProjectName + + ".qml\" found in \"" + projectLocation + "\"."; return false; } - printLog("Found mainQmlFile: " + mainQmlFilePath); + qDebug() << "Found mainQmlFile: " + mainQmlFilePath; QUrl mainQmlUrl = QUrl::fromUserInput(mainQmlFilePath); QFile file(mainQmlUrl.path().prepend(":")); if (!file.open(QIODevice::ReadOnly)) { - printErr("Could not open mainQmlfile for reading! " + file.fileName() + ": " + file.errorString()); + qCritical() << "Could not open mainQmlfile for reading! " + file.fileName() + ": " + + file.errorString(); return false; } - printLog("Looking for qtquickcontrols2File in " + projectLocation); + qDebug() << "Looking for qtquickcontrols2File in " + projectLocation; const QString qtquickcontrols2File = findFile(projectLocation, "qtquickcontrols2.conf"); - if (!qtquickcontrols2File.isEmpty()) - { - printLog("Found qtquickcontrols2File: " + qtquickcontrols2File); + if (!qtquickcontrols2File.isEmpty()) { + qDebug() << "Found qtquickcontrols2File: " + qtquickcontrols2File; qputenv("QT_QUICK_CONTROLS_CONF", qtquickcontrols2File.toLatin1()); } - printLog("Adding import paths"); - for (const QString &importPath : importPaths) - { - printLog("-- Import path: " + importPath); + qDebug() << "Adding import paths"; + for (const QString &importPath : importPaths) { + qDebug() << "-- Import path: " + importPath; m_qmlEngine.addImportPath(importPath); } QObject::connect(&m_qmlEngine, &QQmlEngine::warnings, this, - [&](const QList<QQmlError> &warnings) - { - for (const auto &warning : warnings) - { - printWarn(warning.toString()); + [&](const QList<QQmlError> &warnings) { + for (const auto &warning : warnings) { + qWarning() << warning.toString(); } }); - printLog("Loading mainQmlUrl: " + mainQmlUrl.toString()); + qDebug() << "Loading mainQmlUrl: " + mainQmlUrl.toString(); m_qmlComponent.loadUrl(mainQmlUrl); - printLog("Waiting for qmlComponent to load"); + qDebug() << "Waiting for qmlComponent to load"; while (m_qmlComponent.isLoading()) QCoreApplication::processEvents(); - printLog("Checking if m_qmlComponent is ready"); - if (!m_qmlComponent.isReady()) - { - printErr("m_qmlComponent is not ready. Reason: " + m_qmlComponent.errorString()); + qDebug() << "Checking if m_qmlComponent is ready"; + if (!m_qmlComponent.isReady()) { + qCritical() << "m_qmlComponent is not ready. Reason: " + m_qmlComponent.errorString(); return false; } - printLog("Creating top level object"); + qDebug() << "Creating top level object"; QObject *topLevel = m_qmlComponent.create(); - if (!topLevel && m_qmlComponent.isError()) - { - printErr("Error while creating Qml m_qmlComponent:" + m_qmlComponent.errorString()); + if (!topLevel && m_qmlComponent.isError()) { + qCritical() << "Error while creating Qml m_qmlComponent:" + m_qmlComponent.errorString(); return false; } - printLog("Setting up the quickWindow"); + qDebug() << "Setting up the quickWindow"; m_quickWindow.reset(qobject_cast<QQuickWindow *>(topLevel)); - if (m_quickWindow) - { - printLog("Running with incubator controller"); + if (m_quickWindow) { + qDebug() << "Running with incubator controller"; m_qmlEngine.setIncubationController(m_quickWindow->incubationController()); - } - else - { - printWarn("Top level object is not a QQuickWindow. Trying QQuickView..."); + } else { + qWarning() << "Top level object is not a QQuickWindow. Trying QQuickView..."; QQuickItem *contentItem = qobject_cast<QQuickItem *>(topLevel); if (!contentItem) { - printErr("Top level object cannot be casted to QQuickItem. Aborting."); + qCritical() << "Top level object cannot be casted to QQuickItem. Aborting."; return false; } - printLog("Initializing QQuickView"); + qDebug() << "Initializing QQuickView"; QQuickView *view = new QQuickView(&m_qmlEngine, nullptr); m_quickWindow.reset(view); view->setContent(mainQmlUrl, &m_qmlComponent, contentItem); @@ -341,65 +319,44 @@ bool DesignViewer::runProject(const QByteArray &projectData, const QString &proj return true; } -void DesignViewer::printLog(const QString &message) -{ - fprintf(stdout, "%s\n", qPrintable(message)); -} - -void DesignViewer::printWarn(const QString &message) -{ - fprintf(stderr, "WARNING:%s\n", qPrintable(message)); -} - -void DesignViewer::printError(const QString &message, const QString &fileName, int line) -{ - fprintf(stderr, "ERROR:%s\n", qPrintable(message)); - QString escaped = message; - escaped.replace("'", "\'"); - escaped.replace("\n", "\\n"); - emscripten::val location = emscripten::val::global("window")["location"]; - location.set("hash", std::string()); - location.call<void>("reload"); -} - void DesignViewer::showAppWindow() { - printLog("Resizing the QML app window"); + qDebug() << "Resizing the QML app window"; const QSize size; - printLog("Getting the QML app window container"); + qDebug() << "Getting the QML app window container"; emscripten::val qtContainer = emscripten::val::global("qtcontainer"); // global from index.html - printLog("Getting the QML app window style"); + qDebug() << "Getting the QML app window style"; emscripten::val qtContainerStyle = qtContainer["style"]; - printLog("Setting the QML app window size"); + qDebug() << "Setting the QML app window size"; if (size.isEmpty()) { - printLog("Setting the QML app window size to 100%"); + qDebug() << "Setting the QML app window size to 100%"; qtContainerStyle.set("width", std::string("100%")); // qtContainerStyle.set("height", // std::string( // "100%")); // ### FIXME: 100% height gives 0px height for some reason } else { - printLog("Setting the QML app window size to " - + QString("%1x%2").arg(size.width()).arg(size.height())); + qDebug() << "Setting the QML app window size to " + + QString("%1x%2").arg(size.width()).arg(size.height()); qtContainerStyle.set("width", QString("%1px").arg(size.width()).toStdString()); qtContainerStyle.set("height", QString("%1px").arg(size.height()).toStdString()); } - printLog("Setting the QML app window position"); + qDebug() << "Setting the QML app window position"; // Make Qt pick up the new container size by calling the resizeCanvasElement() // qtloader API. This needs to be done on delay after initial setup to make // sure qtloader is initialized. // QTimer::singleShot(0, [&]() { - // emscripten::val instance = emscripten::val::global("instance"); + // emscripten::val instance = emscripten::val::global("instance"; // if (instance.isNull()) { - // printErr("instance is null"); + // qCritical()<<"instance is null"; // return; // } // instance.call<void>("qtResizeContainerElement", qtContainer); - // printLog("QML app window position set"); + // qDebug() << "QML app window position set"; // }); - printLog("Showing the QML app window"); + qDebug() << "Showing the QML app window"; m_quickWindow->show(); } diff --git a/src/designviewer.h b/src/designviewer.h index 1736277c4455a90f5ca59341cb9b68f8769285b5..2dea2c2462f0c654d589f58db46243cea9d90db3 100644 --- a/src/designviewer.h +++ b/src/designviewer.h @@ -49,9 +49,6 @@ private: QWidget *m_appWindow = nullptr; - void printLog(const QString &message); - void printWarn(const QString &message); - void printError(const QString &message, const QString &fileName, int line); void showAppWindow(); void fetchProject(QByteArray *data, QString *fileName); diff --git a/src/main.cpp b/src/main.cpp index d75d7d04951712d3700179f2a1e8f8dcf30227a6..541e4e20f3d89119f872876a005c957faf02e2ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,21 +24,59 @@ ****************************************************************************/ #include <QApplication> -#include <QDebug> -#include <QQmlContext> #include <QSurfaceFormat> +#include <QtQuick3D/QQuick3D> #include "designviewer.h" +void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + QString logPrefix, logSuffix, newLog; + FILE *logFile = stdout; + + QByteArray localMsg = msg.toLocal8Bit(); + const char *file = context.file ? context.file : ""; + const char *function = context.function ? context.function : ""; + + switch (type) { + case QtDebugMsg: + logPrefix = QStringLiteral("Debug: "); + break; + case QtInfoMsg: + logPrefix = QStringLiteral("Info: "); + break; + case QtWarningMsg: + logPrefix = QStringLiteral("Warning: "); + logFile = stderr; + break; + case QtCriticalMsg: + logPrefix = QStringLiteral("Critical: "); + logFile = stderr; + break; + case QtFatalMsg: + logPrefix = QStringLiteral("Fatal: "); + logSuffix = QStringLiteral(" (%1:%2, %3)").arg(file).arg(context.line).arg(function); + logFile = stderr; + break; + } + + newLog += "(WASM) " + logPrefix + localMsg + logSuffix + "\n"; + fprintf(logFile, "%s", newLog.toUtf8().constData()); +} + int main(int argc, char *argv[]) { - qDebug().noquote() << QString("Built on %1 %2\n").arg(__DATE__, __TIME__); + qInstallMessageHandler(messageHandler); + qDebug() << "Version: " << CMAKE_VAR_GIT_VERSION << ". Built on " << __DATE__ << __TIME__ + << "with Qt" << QT_VERSION_STR; QSurfaceFormat format = QSurfaceFormat::defaultFormat(); format.setVersion(3, 0); + format.setSamples(4); QSurfaceFormat::setDefaultFormat(format); + qDebug() << "Default format: " << format; - QCoreApplication::setApplicationVersion(QString("Built on %1 %2").arg(__DATE__, __TIME__)); + QCoreApplication::setApplicationVersion(QStringLiteral(CMAKE_VAR_GIT_VERSION)); QGuiApplication app(argc, argv); DesignViewer dv; diff --git a/www/index.html b/www/index.html index f1754b0c1a59d0d42587452250463223e4a609bd..87e83e18a9a4b8b0ebd4695790e4ce8f4de8b521 100644 --- a/www/index.html +++ b/www/index.html @@ -43,14 +43,14 @@ <body onload="init()" class="qt-design-system"> <figure style="overflow: visible" id="qtspinner"> <center style="line-height: 150%"> - <!-- <div class="c-box c-box--grey h-wysiwyg-html" data-scheme style="font-style: normal;"> + <!-- <div class="c-box c-box--grey h-wysiwyg-html" data-scheme style="font-style: normal;"> <p>Upcoming maintenance break on Tuesday 21st May</p> - <a class="c-link" target="_blank" rel="noopener noreferrer" + <a class="c-link" target="_blank" rel="noopener noreferrer" href="https://forum.qt.io/topic/156671/upcoming-maintenance-break-on-the-qt-design-viewer-tuesday-21-05-2024"> Learn more </a> </div> --> - + <img src="resources/images/qtdesignstudioviewer-128.png" srcset=" @@ -64,7 +64,7 @@ style="display: block" /> <div id="title">Qt Design Viewer</div> - <div id="subtitle" class="subtitleclass">Powered by WebAssembly</div> + <div id="subtitle" class="subtitleclass"></div> <div id="qtstatus"></div> <noscript >JavaScript is disabled. Please enable JavaScript to use this @@ -150,6 +150,9 @@ and remains locally in Your browser, nothing gets uploaded into the cloud. </p> + <p> + You can report bugs or give feedback on <a href="https://bugreports.qt.io/secure/CreateIssueDetails!init.jspa?pid=11740&issuetype=1&components=24729&versions=20809">Qt Bug Reports.</a> + </p> <p> <a href="https://git.qt.io/design-studio/design-viewer/design-viewer-wasm" >"Qt Design Viewer" sources</a diff --git a/www/scripts/script.js b/www/scripts/script.js index 21c438bdc1fb6dcae08d7d445c634853930dbc0f..5ebe8163fb5aef0ac7a92209e71b6b1084ad3c84 100644 --- a/www/scripts/script.js +++ b/www/scripts/script.js @@ -64,6 +64,14 @@ window.addEventListener( false ); +function logError(error) { + console.error(error); + console.error(error.stack); + const status = document.querySelector('#qtstatus'); + status.innerHTML = 'An error occurred while running the project.<br><br>Error Message:<br>' + error + ' <br><br>Please check the logs for more information.<br>Reloading in 10 seconds.'; + setTimeout(() => location.reload(), 10000); +} + function handleFileSelection(event) { reader = new FileReader(); var file = fileinput.files[0]; @@ -73,7 +81,12 @@ function handleFileSelection(event) { hideMainPage(); loadProjector(); }; - reader.readAsArrayBuffer(file); + + try { + reader.readAsArrayBuffer(file); + } catch (e) { + logError(e); + } } function loadFromServer(fileName, password) { @@ -220,30 +233,38 @@ async function loadProjector() { } try { - showUi(spinner); status.innerHTML = 'Loading...'; instance = await qtLoad({ qt: { onLoaded: () => { + launchstatus.style.display = "none"; setContainerSize(container, window.innerWidth, window.innerHeight); showUi(container); }, onExit: exitData => { - console.log("onExit"); + console.log("onExit: " + exitData.code + " " + exitData.text); status.innerHTML = 'Application exit'; - status.innerHTML += - exitData.code !== undefined ? ` with code ` : ''; - status.innerHTML += - exitData.text !== undefined ? ` ()` : ''; - showUi(spinner); + + if (exitData.code === 0) { + status.innerHTML += ' with success.'; + return; + } + + status.innerHTML += ' with an error.'; + status.innerHTML += '<br><br>Exit code:<br>' + exitData.code; + status.innerHTML += '<br><br>Exit message:<br>' + exitData.text; + + const reportLink = document.createElement('a'); + reportLink.href = 'https://bugreports.qt.io/secure/CreateIssueDetails!init.jspa?pid=11740&issuetype=1&components=24729&versions=20809&summary=Design+Viewer+Crash&description=' + encodeURIComponent('Exit code:\n' + exitData.code + '\n\nExit message:\n' + exitData.text); + + status.innerHTML += '<br><br>You can report this issue at <a href="' + reportLink.href + '">Qt Bug Reports.</a>'; }, entryFunction: window.createQtAppInstance, containerElements: [container] } }); } catch (e) { - console.error(e); - console.error(e.stack); + logError(e); } }