From b618cae4995653819e90f9528788b9152d904268 Mon Sep 17 00:00:00 2001
From: Burak Hancerli <burak.hancerli@qt.io>
Date: Sun, 1 Oct 2023 13:45:43 +0200
Subject: [PATCH] chore: remove android related stuff

---
 CMakeLists.txt     |   6 +-
 src/dv_android.cpp | 201 ----------------------------------
 src/dv_android.h   |  81 --------------
 src/dv_base.cpp    | 267 ---------------------------------------------
 src/dv_base.h      |  66 -----------
 src/dv_wasm.cpp    | 231 +++++++++++++++++++++++++++++++++++++++
 src/dv_wasm.h      |  31 ++++--
 src/main.cpp       |  18 +--
 8 files changed, 258 insertions(+), 643 deletions(-)
 delete mode 100644 src/dv_android.cpp
 delete mode 100644 src/dv_android.h
 delete mode 100644 src/dv_base.cpp
 delete mode 100644 src/dv_base.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 568ebc5..710cfb2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,9 +29,9 @@ if(QT_VERSION VERSION_LESS QT_MINIMUM_VERSION)
 endif()
 
 qt_add_executable(${PROJECT_NAME}
-    design-viewer/importdummy_wasm.qml
-    design-viewer/src/main.cpp
-    design-viewer/src/dv_wasm.cpp design-viewer/src/dv_wasm.h
+    resources/importdummy_wasm.qml
+    src/main.cpp
+    src/dv_wasm.cpp src/dv_wasm.h
 )
 
 target_link_libraries(${PROJECT_NAME} PRIVATE
diff --git a/src/dv_android.cpp b/src/dv_android.cpp
deleted file mode 100644
index 76a8679..0000000
--- a/src/dv_android.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2023 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "dv_android.h"
-
-#if !defined(Q_OS_WASM)
-
-#include <QEventLoop>
-#include <QFileInfo>
-#include <QGuiApplication>
-#include <QMessageBox>
-#include <QNetworkReply>
-#include <QScrollBar>
-#include <QSslSocket>
-
-#define QSTRN QString::number
-
-void DvAndroid::printLog(const QString &log)
-{
-    qDebug() << log;
-    m_logs += log + "\n";
-    emit logsChanged();
-}
-
-void DvAndroid::printWarn(const QString &warn)
-{
-    printLog("WARN: " + warn);
-}
-
-void DvAndroid::printError(const QString &error, const QString &fileName, int line)
-{
-    printLog(QString(error)
-                 .prepend("ERROR: ")
-                 .append(" (")
-                 .append(fileName)
-                 .append(":")
-                 .append(QSTRN(line))
-                 .append(")"));
-}
-
-void DvAndroid::showWarning(const QString &message)
-{
-    QMessageBox msg(QMessageBox::Warning, "Warning", message, QMessageBox::Ok);
-    msg.exec();
-}
-
-QSharedPointer<QNetworkReply> DvAndroid::fetchResource(const QString &url)
-{
-    printLog("Fetching resource from " + url);
-
-    QNetworkRequest request(url);
-    request.setRawHeader("Authorization", "test");
-    QSharedPointer<QNetworkReply> reply(m_nam.get(request));
-    QObject::connect(reply.data(),
-                     &QNetworkReply::sslErrors,
-                     this,
-                     [&](const QList<QSslError> &errors) {
-                         printErr(errors.first().errorString());
-                     });
-
-    QEventLoop loop;
-    QObject::connect(reply.data(), &QNetworkReply::finished, &loop, &QEventLoop::quit);
-    QObject::connect(reply.data(),
-                     &QNetworkReply::downloadProgress,
-                     this,
-                     [&](qint64 bytesReceived, qint64 bytesTotal) {
-                         float percentage = roundf((float) bytesReceived / (float) bytesTotal * 100);
-                         printLog("Download progress " + QSTRN(percentage) + "% - "
-                                  + QSTRN(bytesReceived) + "/" + QSTRN(bytesTotal));
-                     });
-    loop.exec();
-
-    if (reply->error() != QNetworkReply::NoError) {
-        printErr(reply->errorString());
-    } else {
-        printLog("Resource fetched successfully");
-    }
-
-    return reply;
-}
-
-void DvAndroid::printSysInfo()
-{
-    const QRect screenGeometry = QGuiApplication::primaryScreen()->geometry();
-
-    printLog("Qt Design Viewer");
-    printLog("System information:");
-    printLog("-- Qt version: " + QString(QT_VERSION_STR));
-    printLog("-- OpenSSL support: " + QVariant(QSslSocket::supportsSsl()).toString());
-    printLog("-- Screen height: " + QSTRN(screenGeometry.height()));
-    printLog("-- Screen width: " + QSTRN(screenGeometry.width()));
-}
-
-bool DvAndroid::initialize()
-{
-    printLog("Initializing Qt Design Viewer...");
-    printSysInfo();
-    m_buildInfo = QCoreApplication::applicationVersion() + "\n" + "Qt " + QString(QT_VERSION_STR)
-                  + "\n" + "OpenSSL support: " + QVariant(QSslSocket::supportsSsl()).toString();
-    emit buildInfoChanged();
-    printLog("Initialization complete");
-    return true;
-}
-
-void DvAndroid::downloadAndRun(const QString &url)
-{
-    printLog("=========================");
-    printLog("Fetching a new project...");
-
-    QString projectUrl = url;
-    if (projectUrl.startsWith("https://designviewer.qt.io/#")) {
-        projectUrl = projectUrl.split("#").at(1);
-        projectUrl.prepend("https://designviewer.qt.io/qmlprojects/");
-    }
-
-    auto reply = fetchResource(projectUrl);
-    if (reply->error() != QNetworkReply::NoError) {
-        printErr("Could not fetch project");
-        return;
-    }
-
-    if (!runProject(reply->readAll(), QFileInfo(url).baseName())) {
-        printErr("Could not run project");
-        return;
-    }
-}
-
-void DvAndroid::orientateWindow(Qt::ScreenOrientation orientation)
-{
-    QQuickItem *contentItem = m_quickWindow->contentItem();
-    QQuickItem *childItem{contentItem->childItems().at(0)};
-    const QRect screenGeometry = QGuiApplication::primaryScreen()->geometry();
-
-    printLog("Adapting orientation. Initial sizing:");
-    printLog("-- Screen size: " + QSTRN(screenGeometry.height()) + " x "
-             + QSTRN(screenGeometry.width()));
-    printLog("-- Quick window size: " + QSTRN(m_quickWindow->height()) + " x "
-             + QSTRN(m_quickWindow->width()));
-    printLog("-- Child size: " + QSTRN(childItem->height()) + " x " + QSTRN(childItem->width()));
-    printLog("-- Child pos: " + QSTRN(childItem->x()) + ", " + QSTRN(childItem->y()));
-    printLog("-- Child scale: " + QSTRN(childItem->scale()));
-
-    printLog("Calculating the new size and scale...");
-
-    const QSizeF newContentSize = childItem->size().scaled(screenGeometry.size().toSizeF(),
-                                                           Qt::AspectRatioMode::KeepAspectRatio);
-
-    const qreal newScale = newContentSize.height() / childItem->size().height();
-    const qreal newX = (childItem->width() - screenGeometry.width()) / -2.0f;
-    const qreal newY = (childItem->height() - screenGeometry.height()) / -2.0f;
-
-    childItem->setScale(newScale);
-    childItem->setPosition(QPointF(newX, newY));
-
-    printLog("-- Calculated item height: " + QSTRN(newContentSize.height()));
-    printLog("-- Calculated item width: " + QSTRN(newContentSize.width()));
-    printLog("-- Calculated item scale: " + QSTRN(newScale));
-    printLog("-- Calculated item pos..: " + QSTRN(newX) + "," + QSTRN(newY));
-
-    printLog("Final Sizing:");
-    printLog("-- Child height: " + QSTRN(childItem->height()));
-    printLog("-- Child width: " + QSTRN(childItem->width()));
-    printLog("-- Child scale: " + QSTRN(childItem->scale()));
-    printLog("-- Child pos-x: " + QSTRN(childItem->x()));
-    printLog("-- Child pos-y: " + QSTRN(childItem->y()));
-}
-
-void DvAndroid::showAppWindow()
-{
-    QScreen *screen = QGuiApplication::primaryScreen();
-    QObject::connect(screen, &QScreen::orientationChanged, this, &DvAndroid::orientateWindow);
-    orientateWindow(screen->orientation());
-
-    printLog("Initializing and showing the QML app window");
-
-    m_quickWindow->show();
-}
-
-#endif // !defined(Q_OS_WASM)
diff --git a/src/dv_android.h b/src/dv_android.h
deleted file mode 100644
index 4d7be49..0000000
--- a/src/dv_android.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2023 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#ifndef DV_ANDROID_H
-#define DV_ANDROID_H
-
-#include <QLabel>
-#include <QLineEdit>
-#include <QNetworkAccessManager>
-#include <QPushButton>
-#include <QScrollArea>
-#include <QStringList>
-#include <QVBoxLayout>
-#include <QWidget>
-
-#include "dv_base.h"
-
-class DvAndroid : public DvBase
-{
-    Q_OBJECT
-    Q_PROPERTY(QString logs READ logs NOTIFY logsChanged)
-    Q_PROPERTY(QString buildInfo READ buildInfo NOTIFY buildInfoChanged)
-
-public:
-    bool initialize() override;
-    QString logs() const { return m_logs; }
-    QString buildInfo() const { return m_buildInfo; }
-
-private:
-    // UI data
-    QString m_logs;
-    QString m_buildInfo;
-
-    // Other members
-    QNetworkAccessManager m_nam;
-
-    void printLog(const QString &message) override;
-    void printWarn(const QString &message) override;
-    void printError(const QString &message, const QString &fileName, int line) override;
-    void showAppWindow() override;
-
-    void showWarning(const QString &message);
-    void showFatalMessageAndDie(const QStringList &message);
-    QSharedPointer<QNetworkReply> fetchResource(const QString &url);
-
-    void printSysInfo();
-
-signals:
-    void logsChanged();
-    void buildInfoChanged();
-
-public slots:
-    void downloadAndRun(const QString &url);
-
-private slots:
-    void orientateWindow(Qt::ScreenOrientation orientation);
-};
-
-#endif // DV_ANDROID_H
diff --git a/src/dv_base.cpp b/src/dv_base.cpp
deleted file mode 100644
index 26f9361..0000000
--- a/src/dv_base.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2023 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#ifndef DV_UTILS_H
-#define DV_UTILS_H
-
-#include "dv_base.h"
-
-#include <QtGui/private/qzipreader_p.h>
-
-#include <QBuffer>
-#include <QCoreApplication>
-#include <QDirIterator>
-#include <QRandomGenerator>
-#include <QRegularExpression>
-#include <QResource>
-#include <QTemporaryDir>
-#include <QTemporaryFile>
-
-QString DvBase::unpackProject(const QByteArray &project, bool extractZip)
-{
-#if defined(Q_OS_WASM)
-    QString projectLocation = "/home/web_user/";
-#else
-    QTemporaryDir tempDir("qmlprojector");
-    QString projectLocation = tempDir.path();
-#endif
-
-    if (extractZip) {
-        QDir().mkpath(projectLocation);
-        QBuffer buffer;
-        buffer.setData(project);
-        buffer.open(QIODevice::ReadOnly);
-        QZipReader reader(&buffer);
-        reader.extractAll(projectLocation);
-    }
-
-    printLog("Initial project location: " + projectLocation);
-
-    QDir projectLocationDir(projectLocation);
-
-    // maybe it was not a zip file so try it as resource binary
-    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.");
-            data = reinterpret_cast<const uchar *>(m_projectData.data());
-            if (!QResource::unregisterResource(data, m_projectPath)) {
-                printErr("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()));
-
-        const QString resourcePath{"/" + QString::number(QRandomGenerator::global()->generate())};
-        m_projectPath = resourcePath;
-
-        if (!QDir(resourcePath).removeRecursively()) {
-            printLog("Could not remove resource path: " + resourcePath);
-        }
-
-        if (!QResource::registerResource(data, resourcePath)) {
-            printErr("Can not load the resource data.");
-            return "";
-        }
-
-        projectLocation = ":" + resourcePath;
-    }
-
-    return projectLocation;
-}
-
-QString DvBase::findFile(const QString &dir, const QString &filter)
-{
-    QDirIterator it(dir, {filter}, QDir::Files, QDirIterator::Subdirectories);
-    return it.next();
-}
-
-void DvBase::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)) {
-        printErr("Could not open Qml Project file! " + fileName + ": " + file.errorString());
-        return;
-    }
-
-    const QString text = QString::fromUtf8(file.readAll());
-
-    const QRegularExpression mainFileRegExp("mainFile:\\s*\"(.*)\"");
-    const QRegularExpressionMatch mainFileMatch = mainFileRegExp.match(text);
-
-    if (!mainFileMatch.hasMatch()) {
-        printErr("No main file found in " + fileName);
-        return;
-    }
-
-    printLog("Found main file: " + mainFileMatch.captured(1));
-    QString basePath = QFileInfo(fileName).path() + "/";
-
-    *mainFile = basePath + mainFileMatch.captured(1);
-    if (mainFile->startsWith(QLatin1String(":/")))
-        *mainFile = "qrc:" + mainFile->mid(1);
-
-    const QRegularExpression qt6ProjectRegExp("qt6Project:\\s*true");
-    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.");
-    }
-
-    const QRegularExpression importPathsRegExp("importPaths:\\s*\\[\\s*(.*)\\s*\\]");
-    const QRegularExpressionMatch importPathsMatch = importPathsRegExp.match(text);
-
-    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 (cleanedPath.startsWith(QLatin1String(":/")))
-                    cleanedPath = "qrc:" + cleanedPath.mid(1);
-                importPaths->append(cleanedPath);
-            }
-        }
-    }
-}
-
-bool DvBase::runProject(const QByteArray &projectData, const QString &projectName)
-{
-    const QString projectLocation = unpackProject(projectData);
-    printLog("Final project location: " + projectLocation);
-
-    QString mainQmlFilePath;
-    QStringList importPaths;
-
-    printLog("Looking for qmlproject file in " + projectLocation);
-    const QString qmlProjectFile = findFile(projectLocation, "*.qmlproject");
-    if (!qmlProjectFile.isEmpty()) {
-        printLog("Found qmlproject file: " + qmlProjectFile);
-        parseQmlprojectFile(qmlProjectFile, &mainQmlFilePath, &importPaths);
-    } 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()) {
-        printErr("No \"*.qmlproject\", \"main.qml\" or \"" + projectName + ".qml\" found in \""
-                 + projectLocation + "\".");
-        return false;
-    }
-
-    printLog("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());
-        return false;
-    }
-
-    printLog("Looking for qtquickcontrols2File in " + projectLocation);
-    const QString qtquickcontrols2File = findFile(projectLocation, "qtquickcontrols2.conf");
-
-    if (!qtquickcontrols2File.isEmpty()) {
-        printLog("Found qtquickcontrols2File: " + qtquickcontrols2File);
-        qputenv("QT_QUICK_CONTROLS_CONF", qtquickcontrols2File.toLatin1());
-    }
-
-    printLog("Adding import paths");
-    for (const QString &importPath : importPaths) {
-        printLog("-- 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());
-                         }
-                     });
-
-    printLog("Loading mainQmlUrl: " + mainQmlUrl.toString());
-    m_qmlComponent.loadUrl(mainQmlUrl);
-
-    printLog("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());
-        return false;
-    }
-    printLog("Creating top level object");
-    QObject *topLevel = m_qmlComponent.create();
-    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) {
-        printLog("Running with incubator controller");
-        m_qmlEngine.setIncubationController(m_quickWindow->incubationController());
-    } else {
-        printWarn("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.");
-            return false;
-        }
-
-        printLog("Initializing QQuickView");
-        QQuickView *view = new QQuickView(&m_qmlEngine, nullptr);
-        m_quickWindow.reset(view);
-        view->setContent(mainQmlUrl, &m_qmlComponent, contentItem);
-        view->setResizeMode(QQuickView::SizeViewToRootObject);
-        m_quickWindow->setBaseSize(QSize(contentItem->width(), contentItem->height()));
-    }
-
-    showAppWindow();
-    return true;
-}
-#endif // DV_UTILS_H
diff --git a/src/dv_base.h b/src/dv_base.h
deleted file mode 100644
index 4d9c9c4..0000000
--- a/src/dv_base.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2023 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Viewer of the Qt Toolkit.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#ifndef DV_BASE_H
-#define DV_BASE_H
-
-#include <QQmlComponent>
-#include <QQmlEngine>
-#include <QQuickItem>
-#include <QQuickView>
-#include <QSize>
-#include <QString>
-#include <QWidget>
-
-#define printErr(x) printError(x, __FILE_NAME__, __LINE__)
-
-class DvBase : public QObject
-{
-    Q_OBJECT
-public:
-    virtual bool initialize() = 0;
-
-protected:
-    QScopedPointer<QQuickWindow> m_quickWindow;
-
-    QQmlEngine m_qmlEngine;
-    QQmlComponent m_qmlComponent{&m_qmlEngine};
-
-    virtual void printLog(const QString &message) = 0;
-    virtual void printWarn(const QString &message) = 0;
-    virtual void printError(const QString &message, const QString &fileName, int line) = 0;
-    virtual void showAppWindow() = 0;
-
-    QString unpackProject(const QByteArray &project, bool extractZip = false);
-    QString findFile(const QString &dir, const QString &filter);
-    void parseQmlprojectFile(const QString &fileName, QString *mainFile, QStringList *importPaths);
-    bool runProject(const QByteArray &projectData, const QString &projectName);
-
-private:
-    QByteArray m_projectData;
-    QString m_projectPath;
-};
-
-#endif // DV_BASE_H
diff --git a/src/dv_wasm.cpp b/src/dv_wasm.cpp
index ca06b9a..21df42e 100644
--- a/src/dv_wasm.cpp
+++ b/src/dv_wasm.cpp
@@ -29,7 +29,18 @@
 #include <emscripten.h>
 #include <functional>
 
+#include <QBuffer>
+#include <QCoreApplication>
+#include <QDirIterator>
 #include <QFile>
+#include <QRandomGenerator>
+#include <QRegularExpression>
+#include <QResource>
+#include <QTemporaryDir>
+#include <QTemporaryFile>
+#include <QtGui/private/qzipreader_p.h>
+
+#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,
@@ -85,6 +96,226 @@ void DvWasm::fetchProject(QByteArray *data, QString *fileName)
               [heapPointer, contentSize, projectfileName]);
     });
 }
+QString DvWasm::unpackProject(const QByteArray &project, bool extractZip)
+{
+    QString projectLocation = "/home/web_user/";
+
+    if (extractZip) {
+        QDir().mkpath(projectLocation);
+        QBuffer buffer;
+        buffer.setData(project);
+        buffer.open(QIODevice::ReadOnly);
+        QZipReader reader(&buffer);
+        reader.extractAll(projectLocation);
+    }
+
+    printLog("Initial project location: " + projectLocation);
+
+    QDir projectLocationDir(projectLocation);
+
+    // maybe it was not a zip file so try it as resource binary
+    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.");
+            data = reinterpret_cast<const uchar *>(m_projectData.data());
+            if (!QResource::unregisterResource(data, m_projectPath)) {
+                printErr("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()));
+
+        const QString resourcePath{"/" + QString::number(QRandomGenerator::global()->generate())};
+        m_projectPath = resourcePath;
+
+        if (!QDir(resourcePath).removeRecursively()) {
+            printLog("Could not remove resource path: " + resourcePath);
+        }
+
+        if (!QResource::registerResource(data, resourcePath)) {
+            printErr("Can not load the resource data.");
+            return "";
+        }
+
+        projectLocation = ":" + resourcePath;
+    }
+
+    return projectLocation;
+}
+
+QString DvWasm::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)
+{
+    /* 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)) {
+        printErr("Could not open Qml Project file! " + fileName + ": " + file.errorString());
+        return;
+    }
+
+    const QString text = QString::fromUtf8(file.readAll());
+
+    const QRegularExpression mainFileRegExp("mainFile:\\s*\"(.*)\"");
+    const QRegularExpressionMatch mainFileMatch = mainFileRegExp.match(text);
+
+    if (!mainFileMatch.hasMatch()) {
+        printErr("No main file found in " + fileName);
+        return;
+    }
+
+    printLog("Found main file: " + mainFileMatch.captured(1));
+    QString basePath = QFileInfo(fileName).path() + "/";
+
+    *mainFile = basePath + mainFileMatch.captured(1);
+    if (mainFile->startsWith(QLatin1String(":/")))
+        *mainFile = "qrc:" + mainFile->mid(1);
+
+    const QRegularExpression qt6ProjectRegExp("qt6Project:\\s*true");
+    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.");
+    }
+
+    const QRegularExpression importPathsRegExp("importPaths:\\s*\\[\\s*(.*)\\s*\\]");
+    const QRegularExpressionMatch importPathsMatch = importPathsRegExp.match(text);
+
+    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 (cleanedPath.startsWith(QLatin1String(":/")))
+                    cleanedPath = "qrc:" + cleanedPath.mid(1);
+                importPaths->append(cleanedPath);
+            }
+        }
+    }
+}
+
+bool DvWasm::runProject(const QByteArray &projectData, const QString &projectName)
+{
+    const QString projectLocation = unpackProject(projectData);
+    printLog("Final project location: " + projectLocation);
+
+    QString mainQmlFilePath;
+    QStringList importPaths;
+
+    printLog("Looking for qmlproject file in " + projectLocation);
+    const QString qmlProjectFile = findFile(projectLocation, "*.qmlproject");
+    if (!qmlProjectFile.isEmpty()) {
+        printLog("Found qmlproject file: " + qmlProjectFile);
+        parseQmlprojectFile(qmlProjectFile, &mainQmlFilePath, &importPaths);
+    } 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()) {
+        printErr("No \"*.qmlproject\", \"main.qml\" or \"" + projectName + ".qml\" found in \""
+                 + projectLocation + "\".");
+        return false;
+    }
+
+    printLog("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());
+        return false;
+    }
+
+    printLog("Looking for qtquickcontrols2File in " + projectLocation);
+    const QString qtquickcontrols2File = findFile(projectLocation, "qtquickcontrols2.conf");
+
+    if (!qtquickcontrols2File.isEmpty()) {
+        printLog("Found qtquickcontrols2File: " + qtquickcontrols2File);
+        qputenv("QT_QUICK_CONTROLS_CONF", qtquickcontrols2File.toLatin1());
+    }
+
+    printLog("Adding import paths");
+    for (const QString &importPath : importPaths) {
+        printLog("-- 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());
+                         }
+                     });
+
+    printLog("Loading mainQmlUrl: " + mainQmlUrl.toString());
+    m_qmlComponent.loadUrl(mainQmlUrl);
+
+    printLog("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());
+        return false;
+    }
+    printLog("Creating top level object");
+    QObject *topLevel = m_qmlComponent.create();
+    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) {
+        printLog("Running with incubator controller");
+        m_qmlEngine.setIncubationController(m_quickWindow->incubationController());
+    } else {
+        printWarn("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.");
+            return false;
+        }
+
+        printLog("Initializing QQuickView");
+        QQuickView *view = new QQuickView(&m_qmlEngine, nullptr);
+        m_quickWindow.reset(view);
+        view->setContent(mainQmlUrl, &m_qmlComponent, contentItem);
+        view->setResizeMode(QQuickView::SizeViewToRootObject);
+        m_quickWindow->setBaseSize(QSize(contentItem->width(), contentItem->height()));
+    }
+
+    showAppWindow();
+    return true;
+}
 
 void DvWasm::printLog(const QString &message)
 {
diff --git a/src/dv_wasm.h b/src/dv_wasm.h
index b1c384d..6e9787f 100644
--- a/src/dv_wasm.h
+++ b/src/dv_wasm.h
@@ -26,22 +26,37 @@
 #ifndef DV_WASM_H
 #define DV_WASM_H
 
-#include "dv_base.h"
+#include <QQmlComponent>
+#include <QQmlEngine>
+#include <QQuickItem>
+#include <QQuickView>
+#include <QSize>
+#include <QString>
 
-class DvWasm : public DvBase
+class DvWasm : public QObject
 {
+    Q_OBJECT
 public:
-    bool initialize() override;
+    bool initialize();
 
 private:
-    QByteArray *m_projectData;
+    QByteArray m_projectData;
+    QString m_projectPath;
 
-    void printLog(const QString &message) override;
-    void printWarn(const QString &message) override;
-    void printError(const QString &message, const QString &fileName, int line) override;
-    void showAppWindow() override;
+    QScopedPointer<QQuickWindow> m_quickWindow;
+    QQmlEngine m_qmlEngine;
+    QQmlComponent m_qmlComponent{&m_qmlEngine};
+
+    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);
+    QString unpackProject(const QByteArray &project, bool extractZip = false);
+    QString findFile(const QString &dir, const QString &filter);
+    void parseQmlprojectFile(const QString &fileName, QString *mainFile, QStringList *importPaths);
+    bool runProject(const QByteArray &projectData, const QString &projectName);
 };
 
 #endif
diff --git a/src/main.cpp b/src/main.cpp
index 624ad99..dfb622a 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -28,7 +28,6 @@
 #include <QQmlContext>
 #include <QSurfaceFormat>
 
-#include "dv_android.h"
 #include "dv_wasm.h"
 
 int main(int argc, char *argv[])
@@ -38,27 +37,12 @@ int main(int argc, char *argv[])
     QSurfaceFormat format = QSurfaceFormat::defaultFormat();
     format.setVersion(3, 0);
     QSurfaceFormat::setDefaultFormat(format);
-    QScopedPointer<DvBase> dv;
 
     QCoreApplication::setApplicationVersion(QString("Built on %1 %2").arg(__DATE__, __TIME__));
 
-#ifdef Q_OS_WASM
     QGuiApplication app(argc, argv);
 
-    dv.reset(new DvWasm);
-#else
-    QApplication app(argc, argv);
-    QApplication::setApplicationName(QStringLiteral("Qt Design Viewer"));
-
-    dv.reset(new DvAndroid);
-    QQuickView view;
-    view.engine()->rootContext()->setContextProperty("backend", dv.data());
-    view.setSource(QUrl(QStringLiteral("qrc:/main.qml")));
-    view.show();
-#endif
-
-    if (!dv->initialize())
-        return -1;
+    DvWasm dv;
 
     return app.exec();
 }
-- 
GitLab