diff --git a/CMakeLists.txt b/CMakeLists.txt index 710cfb228e648c25f604c2c053b8b8c08ad3be74..77c666d6920b0ab3b9b3ab55d8ed2d6c989b3596 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.14) -project(qtdesignviewer-wasm LANGUAGES CXX) +project(qtdesignviewer LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -31,7 +31,7 @@ endif() qt_add_executable(${PROJECT_NAME} resources/importdummy_wasm.qml src/main.cpp - src/dv_wasm.cpp src/dv_wasm.h + src/designviewer.cpp src/designviewer.h ) target_link_libraries(${PROJECT_NAME} PRIVATE diff --git a/emsdk b/emsdk index 63a63e1664d4b656994606c6e334d1e11e4d9f10..517e02fac88b48c74da14b1cf7c6d51e489a5793 160000 --- a/emsdk +++ b/emsdk @@ -1 +1 @@ -Subproject commit 63a63e1664d4b656994606c6e334d1e11e4d9f10 +Subproject commit 517e02fac88b48c74da14b1cf7c6d51e489a5793 diff --git a/src/dv_wasm.cpp b/src/designviewer.cpp similarity index 78% rename from src/dv_wasm.cpp rename to src/designviewer.cpp index 21df42e231ceccc6e36623d808ce36912333c4bf..3c5c0308f48264641f540dd808c7e6cfe9b07546 100644 --- a/src/dv_wasm.cpp +++ b/src/designviewer.cpp @@ -23,7 +23,7 @@ ** ****************************************************************************/ -#include "dv_wasm.h" +#include "designviewer.h" #if defined(Q_OS_WASM) #include <emscripten.h> @@ -54,7 +54,16 @@ extern "C" EMSCRIPTEN_KEEPALIVE void qt_callSetFileData(char *content, g_setFileDataCallback = nullptr; } -void DvWasm::fetchProject(QByteArray *data, QString *fileName) +DesignViewer::DesignViewer() +{ + QString projectFileName; + QByteArray projectData; + fetchProject(&projectData, &projectFileName); + if (!runProject(projectData, projectFileName)) + printError("Failed to run project", projectFileName, 0); +} + +void DesignViewer::fetchProject(QByteArray *data, QString *fileName) { // Call qt_callSetFileData to make sure the emscripten linker does not // optimize it away, which may happen if the function is called from JavaScript @@ -63,10 +72,11 @@ void DvWasm::fetchProject(QByteArray *data, QString *fileName) ::qt_callSetFileData(nullptr, 0, nullptr); auto setFileDataCallback = - [data, fileName](char *content, size_t contentSize, char *projectFilename) { - data->setRawData(content, contentSize); - *fileName = QString::fromUtf8(projectFilename); - }; + [data, fileName](char *content, size_t contentSize, char *projectFilename) + { + data->setRawData(content, contentSize); + *fileName = QString::fromUtf8(projectFilename); + }; g_setFileDataCallback = setFileDataCallback; EM_ASM_({ @@ -92,15 +102,17 @@ void DvWasm::fetchProject(QByteArray *data, QString *fileName) // Call the C++ file data ready callback ccall("qt_callSetFileData", null, - ["number", "number", "string"], - [heapPointer, contentSize, projectfileName]); + [ "number", "number", "string" ], + [ heapPointer, contentSize, projectfileName ]); }); } -QString DvWasm::unpackProject(const QByteArray &project, bool extractZip) + +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); @@ -114,16 +126,18 @@ QString DvWasm::unpackProject(const QByteArray &project, bool extractZip) 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."); 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()) + { + printLog("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)) { + if (!QResource::unregisterResource(data, m_projectPath)) + { printErr("Cannot unregister the previous resource data."); } } @@ -135,11 +149,13 @@ QString DvWasm::unpackProject(const QByteArray &project, bool extractZip) const QString resourcePath{"/" + QString::number(QRandomGenerator::global()->generate())}; m_projectPath = resourcePath; - if (!QDir(resourcePath).removeRecursively()) { + if (!QDir(resourcePath).removeRecursively()) + { printLog("Could not remove resource path: " + resourcePath); } - if (!QResource::registerResource(data, resourcePath)) { + if (!QResource::registerResource(data, resourcePath)) + { printErr("Can not load the resource data."); return ""; } @@ -150,22 +166,23 @@ QString DvWasm::unpackProject(const QByteArray &project, bool extractZip) return projectLocation; } -QString DvWasm::findFile(const QString &dir, const QString &filter) +QString DesignViewer::findFile(const QString &dir, const QString &filter) { QDirIterator it(dir, {filter}, QDir::Files, QDirIterator::Subdirectories); return it.next(); } -void DvWasm::parseQmlprojectFile(const QString &fileName, - QString *mainFile, - QStringList *importPaths) +void DesignViewer::parseQmlprojectFile(const QString &fileName, + QString *mainFile, + QStringList *importPaths) { /* if filename comes from a resource, then qml need qrc:/ at the mainfile and importPaths. * But all other c++ call like QFileInfo::exists do not understand that, there we * need to keep the only ":" character at the beginning of the string */ QFile file(fileName); - if (!file.open(QIODevice::ReadOnly)) { + if (!file.open(QIODevice::ReadOnly)) + { printErr("Could not open Qml Project file! " + fileName + ": " + file.errorString()); return; } @@ -175,7 +192,8 @@ void DvWasm::parseQmlprojectFile(const QString &fileName, const QRegularExpression mainFileRegExp("mainFile:\\s*\"(.*)\""); const QRegularExpressionMatch mainFileMatch = mainFileRegExp.match(text); - if (!mainFileMatch.hasMatch()) { + if (!mainFileMatch.hasMatch()) + { printErr("No main file found in " + fileName); return; } @@ -189,7 +207,8 @@ void DvWasm::parseQmlprojectFile(const QString &fileName, const QRegularExpression qt6ProjectRegExp("qt6Project:\\s*true"); const QRegularExpressionMatch qt6ProjectMatch = qt6ProjectRegExp.match(text); - if (!qt6ProjectMatch.hasMatch()) { + if (!qt6ProjectMatch.hasMatch()) + { printWarn("This is not a Qt6 project.\nQt5 projects might work, but they are not " "officially supported."); } @@ -197,11 +216,14 @@ void DvWasm::parseQmlprojectFile(const QString &fileName, const QRegularExpression importPathsRegExp("importPaths:\\s*\\[\\s*(.*)\\s*\\]"); const QRegularExpressionMatch importPathsMatch = importPathsRegExp.match(text); - if (importPathsMatch.hasMatch()) { - for (const QString &path : importPathsMatch.captured(1).split(",")) { + if (importPathsMatch.hasMatch()) + { + 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); @@ -210,32 +232,39 @@ void DvWasm::parseQmlprojectFile(const QString &fileName, } } -bool DvWasm::runProject(const QByteArray &projectData, const QString &projectName) +bool DesignViewer::runProject(const QByteArray &projectData, const QString &projectName) { const QString projectLocation = unpackProject(projectData); + const QString newProjectName = QString(projectName).remove(".qmlrc"); printLog("Final project location: " + projectLocation); + printLog("Original project name: " + projectName); + printLog("New project name: " + newProjectName); QString mainQmlFilePath; QStringList importPaths; printLog("Looking for qmlproject file in " + projectLocation); - const QString qmlProjectFile = findFile(projectLocation, "*.qmlproject"); - if (!qmlProjectFile.isEmpty()) { + const QString qmlProjectFile = findFile(projectLocation, newProjectName + ".qmlproject"); + if (!qmlProjectFile.isEmpty()) + { printLog("Found qmlproject file: " + qmlProjectFile); parseQmlprojectFile(qmlProjectFile, &mainQmlFilePath, &importPaths); - } else { + } + else + { printWarn("Not found: \"*.qmlproject\". Looking for main.qml.."); mainQmlFilePath = findFile(projectLocation, "main.qml"); - if (mainQmlFilePath.isEmpty()) { - printWarn("Not found: \"main.qml\". Looking for \"" + projectName + ".qml\".."); - mainQmlFilePath = findFile(projectLocation, projectName + ".qml"); + if (mainQmlFilePath.isEmpty()) + { + printWarn("Not found: \"main.qml\". Looking for \"" + newProjectName + ".qml\".."); + mainQmlFilePath = findFile(projectLocation, newProjectName + ".qml"); } } - if (mainQmlFilePath.isEmpty()) { - printErr("No \"*.qmlproject\", \"main.qml\" or \"" + projectName + ".qml\" found in \"" - + projectLocation + "\"."); + if (mainQmlFilePath.isEmpty()) + { + printErr("No \"*.qmlproject\", \"main.qml\" or \"" + newProjectName + ".qml\" found in \"" + projectLocation + "\"."); return false; } @@ -243,22 +272,24 @@ bool DvWasm::runProject(const QByteArray &projectData, const QString &projectNam 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()); + if (!file.open(QIODevice::ReadOnly)) + { + printErr("Could not open mainQmlfile for reading! " + file.fileName() + ": " + file.errorString()); return false; } printLog("Looking for qtquickcontrols2File in " + projectLocation); const QString qtquickcontrols2File = findFile(projectLocation, "qtquickcontrols2.conf"); - if (!qtquickcontrols2File.isEmpty()) { + if (!qtquickcontrols2File.isEmpty()) + { printLog("Found qtquickcontrols2File: " + qtquickcontrols2File); qputenv("QT_QUICK_CONTROLS_CONF", qtquickcontrols2File.toLatin1()); } printLog("Adding import paths"); - for (const QString &importPath : importPaths) { + for (const QString &importPath : importPaths) + { printLog("-- Import path: " + importPath); m_qmlEngine.addImportPath(importPath); } @@ -266,8 +297,10 @@ bool DvWasm::runProject(const QByteArray &projectData, const QString &projectNam QObject::connect(&m_qmlEngine, &QQmlEngine::warnings, this, - [&](const QList<QQmlError> &warnings) { - for (const auto &warning : warnings) { + [&](const QList<QQmlError> &warnings) + { + for (const auto &warning : warnings) + { printWarn(warning.toString()); } }); @@ -280,27 +313,33 @@ bool DvWasm::runProject(const QByteArray &projectData, const QString &projectNam QCoreApplication::processEvents(); printLog("Checking if m_qmlComponent is ready"); - if (!m_qmlComponent.isReady()) { + if (!m_qmlComponent.isReady()) + { printErr("m_qmlComponent is not ready. Reason: " + m_qmlComponent.errorString()); return false; } printLog("Creating top level object"); QObject *topLevel = m_qmlComponent.create(); - if (!topLevel && m_qmlComponent.isError()) { + if (!topLevel && m_qmlComponent.isError()) + { printErr("Error while creating Qml m_qmlComponent:" + m_qmlComponent.errorString()); return false; } printLog("Setting up the quickWindow"); m_quickWindow.reset(qobject_cast<QQuickWindow *>(topLevel)); - if (m_quickWindow) { + if (m_quickWindow) + { printLog("Running with incubator controller"); m_qmlEngine.setIncubationController(m_quickWindow->incubationController()); - } else { + } + else + { printWarn("Top level object is not a QQuickWindow. Trying QQuickView..."); QQuickItem *contentItem = qobject_cast<QQuickItem *>(topLevel); - if (!contentItem) { + if (!contentItem) + { printErr("Top level object cannot be casted to QQuickItem. Aborting."); return false; } @@ -317,12 +356,12 @@ bool DvWasm::runProject(const QByteArray &projectData, const QString &projectNam return true; } -void DvWasm::printLog(const QString &message) +void DesignViewer::printLog(const QString &message) { fprintf(stdout, "%s\n", qPrintable(message)); } -void DvWasm::printWarn(const QString &message) +void DesignViewer::printWarn(const QString &message) { QString escaped = message; escaped.replace("'", "\'"); @@ -330,34 +369,20 @@ void DvWasm::printWarn(const QString &message) emscripten_run_script("alert('" + escaped.toUtf8() + "');"); } -void DvWasm::printError(const QString &message, const QString &fileName, int line) +void DesignViewer::printError(const QString &message, const QString &fileName, int line) { printWarn(message); emscripten_run_script("location.hash = ''; location.reload();"); } -void DvWasm::showAppWindow() +void DesignViewer::showAppWindow() { printLog("Resizing the QML app window"); const QSize size; - const QString command - = QString::fromLatin1("setScreenSize(%1, %2);").arg(size.width()).arg(size.height()); + const QString command = QString::fromLatin1("setScreenSize(%1, %2);").arg(size.width()).arg(size.height()); emscripten_run_script(command.toUtf8()); printLog("Showing the QML app window"); m_quickWindow->show(); } -bool DvWasm::initialize() -{ - QString projectFileName; - QByteArray projectData; - fetchProject(&projectData, &projectFileName); - if (!runProject(projectData, projectFileName)) { - printError("Failed to run project", projectFileName, 0); - return false; - } - - return true; -} - #endif // Q_OS_WASM diff --git a/src/dv_wasm.h b/src/designviewer.h similarity index 93% rename from src/dv_wasm.h rename to src/designviewer.h index 6e9787f81bab87e5b9d2dbe5193bbf76aabfa274..f7f28c9d8d80baaea3bbede7831f57590876569f 100644 --- a/src/dv_wasm.h +++ b/src/designviewer.h @@ -23,8 +23,8 @@ ** ****************************************************************************/ -#ifndef DV_WASM_H -#define DV_WASM_H +#ifndef DESIGN_VIEWER_H +#define DESIGN_VIEWER_H #include <QQmlComponent> #include <QQmlEngine> @@ -33,11 +33,11 @@ #include <QSize> #include <QString> -class DvWasm : public QObject +class DesignViewer : public QObject { Q_OBJECT public: - bool initialize(); + explicit DesignViewer(); private: QByteArray m_projectData; @@ -59,4 +59,4 @@ private: bool runProject(const QByteArray &projectData, const QString &projectName); }; -#endif +#endif // DESIGN_VIEWER_H diff --git a/src/main.cpp b/src/main.cpp index dfb622a20b340545d3ed053e6921199f654699c6..d75d7d04951712d3700179f2a1e8f8dcf30227a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,7 +28,7 @@ #include <QQmlContext> #include <QSurfaceFormat> -#include "dv_wasm.h" +#include "designviewer.h" int main(int argc, char *argv[]) { @@ -39,10 +39,8 @@ int main(int argc, char *argv[]) QSurfaceFormat::setDefaultFormat(format); QCoreApplication::setApplicationVersion(QString("Built on %1 %2").arg(__DATE__, __TIME__)); - QGuiApplication app(argc, argv); - - DvWasm dv; + DesignViewer dv; return app.exec(); }