diff --git a/src/backend.cpp b/src/backend.cpp index 8a1fcca098dbcb4d6f3be9ac2f5756bc142d3359..08f88c52840954f067d934425596ae5be4f9340b 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -32,7 +32,7 @@ #include <QFileInfo> #include <QJsonArray> #include <QJsonObject> -#include <QMessageBox> + #include <QSettings> #include <QSslSocket> @@ -83,13 +83,6 @@ void Backend::initialize() qDebug("Initialization complete"); } -void Backend::showWarning(const QString &message) -{ - QMessageBox msg(QMessageBox::Warning, "Warning", message, QMessageBox::Ok); - msg.exec(); - qWarning() << message; -} - void Backend::updatePopup(const QString &text, bool indeterminate) { emit popupTextChanged(text); @@ -128,8 +121,9 @@ bool Backend::connectDesignStudio() const QString projectPath = m_projectManager.unpackProject(projectData); if (projectPath.isEmpty()) { - showWarning("Could not unpack project. Please check the logs for more " - "information."); + qCritical() + << "Could not unpack project. Please check the logs for more " + "information."; emit popupClose(); return; } @@ -138,15 +132,16 @@ bool Backend::connectDesignStudio() updatePopup("Running project..."); if (!m_projectManager.runProject(projectPath, "UntitledProject35")) { - showWarning("Could not run project. Please check the logs for more " - "information."); + qCritical() << "Could not run project. Please check the logs for more " + "information."; } else { m_projectManager.showAppWindow(); } emit popupClose(); }); if (!m_designStudioConnector->initialize()) { - showWarning("Could initialize server. Please check the logs for more information."); + qCritical() + << "Could initialize server. Please check the logs for more information."; m_designStudioConnector.reset(); } }, @@ -197,8 +192,8 @@ void Backend::runDemoProject(const QString &projectName) updatePopup("Caching demo project..."); if (!m_projectManager.cacheDemoProject(project, projectName)) { - showWarning( - "Could not cache demo project. Please check the logs for more information."); + qCritical() + << "Could not cache demo project. Please check the logs for more information."; emit popupClose(); return; } @@ -208,7 +203,7 @@ void Backend::runDemoProject(const QString &projectName) updatePopup("Running demo project..."); if (!m_projectManager.runDemoProject(projectName)) - showWarning("Could not run demo project. Please check the logs for more information."); + qCritical() << "Could not run demo project. Please check the logs for more information."; else m_projectManager.showAppWindow(); @@ -250,7 +245,7 @@ void Backend::runUserProject(const QString &url) updatePopup("Caching user project..."); if (!m_projectManager.cacheProject(projectData, projectInfo)) { - showWarning("Could not cache project. Please check the logs for more information."); + qCritical() << "Could not cache project. Please check the logs for more information."; emit popupClose(); return; } @@ -260,7 +255,7 @@ void Backend::runUserProject(const QString &url) updatePopup("Running cached project..."); if (!m_projectManager.runCachedProject(projectInfo)) - showWarning("Could not run project. Please check the logs for more information."); + qCritical() << "Could not run project. Please check the logs for more information."; else m_projectManager.showAppWindow(); diff --git a/src/backend.h b/src/backend.h index 9f3d7c65de49a292afec163984740d05fb4cb74e..8f17b7ffff9c12de721cbf86240f81ab0914c3dc 100644 --- a/src/backend.h +++ b/src/backend.h @@ -64,7 +64,6 @@ private: QThread m_dsConnectorThread; // member functions - void showWarning(const QString &message); void updateUserProjectList(); void updatePopup(const QString &text, bool indeterminate = true); diff --git a/src/main.cpp b/src/main.cpp index cf7a3b396c5f55898652a6dd13e7d29a29c11e5c..71747aeaa72daa3a8fd648417b2a6773cabe5dd9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,6 +25,7 @@ #include <android/log.h> #include <QApplication> +#include <QMessageBox> #include <QQmlContext> #include "backend.h" @@ -38,7 +39,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt const char *file = context.file ? context.file : ""; const char *function = context.function ? context.function : ""; QString logPrefix, logSuffix, newLog; - + QMessageBox msgBox(QMessageBox::Critical, "Critical:", msg, QMessageBox::Ok); switch (type) { case QtDebugMsg: @@ -52,12 +53,14 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt break; case QtCriticalMsg: logPrefix = QStringLiteral("Critical: "); + msgBox.exec(); break; case QtFatalMsg: logPrefix = QStringLiteral("Fatal: "); logSuffix = QStringLiteral(" (%1:%2, %3)").arg(file).arg(context.line).arg(function); break; } + newLog += logPrefix + localMsg + logSuffix + "\n"; __android_log_print(ANDROID_LOG_DEBUG, "Qt_UI_Viewer", "%s", qPrintable(newLog)); diff --git a/src/projectManager.cpp b/src/projectManager.cpp index f9c25f1cd28b966d2645f813eb1cd3c629338fec..bbece42f3fc897f4da2498e3070ac66966f1f976 100644 --- a/src/projectManager.cpp +++ b/src/projectManager.cpp @@ -120,187 +120,181 @@ QString ProjectManager::unpackProject(const QByteArray &project, bool extractZip QString ProjectManager::findFile(const QString &dir, const QString &filter) { - QDirIterator it(dir, {filter}, QDir::Files, QDirIterator::Subdirectories); + QDirIterator it(dir, {filter}, QDir::Files); return it.next(); } -void ProjectManager::parseQmlProjectFile(const QString &fileName, - QString *mainFile, - QStringList *importPaths) +QString ProjectManager::readQmlProjectFile(const QString &qmlProjectFilePath) { - /* 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); + QFile file(qmlProjectFilePath); if (!file.open(QIODevice::ReadOnly)) { - qCritical() << "Could not open Qml Project file! " << fileName + ": " << file.errorString(); - return; + qCritical() << "Could not open Qml Project file! " << file.fileName() + ": " + << file.errorString(); + return {}; } - const QString text = QString::fromUtf8(file.readAll()); + return QString::fromUtf8(file.readAll()); +} +QString ProjectManager::getMainQmlFile(const QString &projectPath, + const QString &qmlProjectFileContent) +{ const QRegularExpression mainFileRegExp("mainFile:\\s*\"(.*)\""); - const QRegularExpressionMatch mainFileMatch = mainFileRegExp.match(text); + const QRegularExpressionMatch mainFileMatch = mainFileRegExp.match(qmlProjectFileContent); if (!mainFileMatch.hasMatch()) { - qCritical() << "No main file found in " << fileName; - return; + qCritical() << "No main file found in " << qmlProjectFileContent; + return {}; } qDebug() << "Found main file: " << mainFileMatch.captured(1); - QString basePath = QFileInfo(fileName).path() + "/"; + return projectPath + "/" + mainFileMatch.captured(1); +} - *mainFile = basePath + mainFileMatch.captured(1); - if (mainFile->startsWith(QLatin1String(":/"))) - *mainFile = "qrc:" + mainFile->mid(1); +QStringList ProjectManager::getImportPaths(const QString &projectPath, + const QString &qmlProjectFileContent) +{ + const QRegularExpression importPathsRegExp("importPaths:\\s*\\[\\s*(.*)\\s*\\]"); + const QRegularExpressionMatch importPathsMatch = importPathsRegExp.match(qmlProjectFileContent); - const QRegularExpression qt6ProjectRegExp("qt6Project:\\s*true"); - const QRegularExpressionMatch qt6ProjectMatch = qt6ProjectRegExp.match(text); - if (!qt6ProjectMatch.hasMatch()) { - qWarning("This is not a Qt6 project.\nQt5 projects might work, but they are not " - "officially supported."); + if (!importPathsMatch.hasMatch()) { + qWarning() << "No import paths found in " << qmlProjectFileContent; + return {}; } - 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); - } + QStringList importPaths; + for (const QString &path : importPathsMatch.captured(1).split(",")) { + qDebug() << "verbose:: Found import path: " << path; + QString cleanedPath = path.trimmed(); + qDebug() << "verbose:: Cleaned import path: " << cleanedPath; + cleanedPath = projectPath + "/" + cleanedPath.mid(1, cleanedPath.length() - 2); + qDebug() << "verbose:: Cleaned import path: " << cleanedPath; + if (QFileInfo::exists(cleanedPath)) { + qDebug() << "verbose:: Adding import path: " << cleanedPath; + importPaths.append(cleanedPath); } } + + return importPaths; +} + +bool ProjectManager::isQt6Project(const QString &qmlProjectFileContent) +{ + const QRegularExpression qt6ProjectRegExp("qt6Project:\\s*true"); + const QRegularExpressionMatch qt6ProjectMatch = qt6ProjectRegExp.match(qmlProjectFileContent); + return qt6ProjectMatch.hasMatch(); } bool ProjectManager::runProject(const QString &projectPath, const QString &projectName) { - const QString newProjectName = QString(projectName).remove(".qmlrc").remove("#"); qDebug() << "Project location: " << projectPath; - qDebug() << "Project name: " << projectName; - qDebug() << "New project name: " << newProjectName; - QString mainQmlFilePath; - QStringList importPaths; + const QString qmlProjectFile = findFile(projectPath, "*.qmlproject"); + if (qmlProjectFile.isEmpty()) { + qCritical() << "No \"*.qmlproject\" found in \"" << projectPath << "\"."; + return false; + } - qDebug() << "Looking for qmlproject file in " << projectPath; - const QString qmlProjectFile = findFile(projectPath, newProjectName + "*.qmlproject"); - if (!qmlProjectFile.isEmpty()) { - qDebug() << "Found qmlproject file: " << qmlProjectFile; - parseQmlProjectFile(qmlProjectFile, &mainQmlFilePath, &importPaths); - } else { - qWarning("Not found: \"*.qmlproject\". Looking for main.qml.."); - mainQmlFilePath = findFile(projectPath, "main.qml"); + const QString qmlProjectFileContent = readQmlProjectFile(qmlProjectFile); + if (qmlProjectFileContent.isEmpty()) + return false; - if (mainQmlFilePath.isEmpty()) { - qWarning() << "Not found: \"main.qml\". Looking for \"" << newProjectName << ".qml\".."; - mainQmlFilePath = findFile(projectPath, newProjectName + ".qml"); - } + const QString mainQmlFilePath = getMainQmlFile(projectPath, qmlProjectFileContent); + if (mainQmlFilePath.isEmpty()) + return false; + + const QString qtquickcontrols2File = findFile(projectPath, "qtquickcontrols2.conf"); + if (!qtquickcontrols2File.isEmpty()) { + qputenv("QT_QUICK_CONTROLS_CONF", qtquickcontrols2File.toLatin1()); } - if (mainQmlFilePath.isEmpty()) { - qCritical() << "No \"*.qmlproject\", \"main.qml\" or \"" << newProjectName - << ".qml\" found in \"" << projectPath << "\"."; - return false; + const QStringList importPaths = getImportPaths(projectPath, qmlProjectFileContent); + if (isQt6Project(qmlProjectFileContent)) { + qWarning() << "This is not a Qt6 project.\nQt5 projects might work, but they are not " + "officially supported."; } - qDebug() << "Found mainQmlFile: " + mainQmlFilePath; + qDebug() << "Project is parsed successfully."; + qDebug() << "Qml Project File: " << qmlProjectFile; + qDebug() << "Main Qml File: " << mainQmlFilePath; + qDebug() << "Import Paths: " << importPaths; + qDebug() << "Qt Quick Controls 2 File: " << qtquickcontrols2File; QUrl mainQmlUrl = QUrl::fromUserInput(mainQmlFilePath); QFile file(mainQmlUrl.path()); if (!file.open(QIODevice::ReadOnly)) { - qWarning() << "Could not open mainQmlfile for reading! " << file.fileName() << ": " - << file.errorString(); - qWarning() << "Trying to open it as a resource file."; - file.setFileName(mainQmlUrl.path().prepend(":")); - if (!file.open(QIODevice::ReadOnly)) { - qCritical() << "Could not open mainQmlfile for reading! " << file.fileName() << ": " - << file.errorString(); - return false; - } + qCritical() << "Could not open mainQmlfile for reading! " << file.fileName() << ": " + << file.errorString(); + return false; } - qDebug() << "Looking for qtquickcontrols2File in " << projectPath; - const QString qtquickcontrols2File = findFile(projectPath, "qtquickcontrols2.conf"); + qDebug() << "Initializing the qmlEngine"; + m_qmlEngine.reset(new QQmlEngine); + m_qmlEngine->clearComponentCache(); - if (!qtquickcontrols2File.isEmpty()) { - qDebug() << "Found qtquickcontrols2File: " << qtquickcontrols2File; - qputenv("QT_QUICK_CONTROLS_CONF", qtquickcontrols2File.toLatin1()); - } + qDebug("Adding import paths"); + for (const QString &importPath : importPaths) { + qDebug() << "-- Import path: " << importPath; + m_qmlEngine->addImportPath(importPath); + } - qDebug() << "Initializing the qmlEngine"; - m_qmlEngine.reset(new QQmlEngine); - m_qmlEngine->clearComponentCache(); + QObject::connect(m_qmlEngine.data(), + &QQmlEngine::warnings, + this, + [&](const QList<QQmlError> &warnings) { + for (const auto &warning : warnings) { + qWarning() << warning.toString(); + } + }); + + emit projectStateChanged("Loading project..."); + QEventLoop().processEvents(QEventLoop::AllEvents, 1000); + + qDebug() << "Loading mainQmlUrl: " << mainQmlUrl.toString(); + m_qmlComponent.reset(new QQmlComponent(m_qmlEngine.data())); + m_qmlComponent->loadUrl(mainQmlUrl); + + qDebug() << "Waiting for qmlComponent to load"; + while (m_qmlComponent->isLoading()) + QCoreApplication::processEvents(); + + qDebug() << "Checking if m_qmlComponent is ready"; + if (!m_qmlComponent->isReady()) { + qCritical() << "m_qmlComponent is not ready. Reason:" << m_qmlComponent->errorString(); + return false; + } + qDebug() << "Creating top level object"; + QObject *topLevel = m_qmlComponent->create(); + if (!topLevel && m_qmlComponent->isError()) { + qCritical() << "Error while creating Qml m_qmlComponent:" << m_qmlComponent->errorString(); + return false; + } - qDebug("Adding import paths"); - for (const QString &importPath : importPaths) { - qDebug() << "-- Import path: " << importPath; - m_qmlEngine->addImportPath(importPath); - } + emit projectStateChanged("Setting up the quickWindow..."); + QEventLoop().processEvents(QEventLoop::AllEvents, 1000); - QObject::connect(m_qmlEngine.data(), - &QQmlEngine::warnings, - this, - [&](const QList<QQmlError> &warnings) { - for (const auto &warning : warnings) { - qWarning() << warning.toString(); - } - }); - - emit projectStateChanged("Loading project..."); - QEventLoop().processEvents(QEventLoop::AllEvents, 1000); - - qDebug() << "Loading mainQmlUrl: " << mainQmlUrl.toString(); - m_qmlComponent.reset(new QQmlComponent(m_qmlEngine.data())); - m_qmlComponent->loadUrl(mainQmlUrl); - - qDebug() << "Waiting for qmlComponent to load"; - while (m_qmlComponent->isLoading()) - QCoreApplication::processEvents(); - - qDebug() << "Checking if m_qmlComponent is ready"; - if (!m_qmlComponent->isReady()) { - qCritical() << "m_qmlComponent is not ready. Reason:" << m_qmlComponent->errorString(); - return false; - } - qDebug() << "Creating top level object"; - QObject *topLevel = m_qmlComponent->create(); - if (!topLevel && m_qmlComponent->isError()) { - qCritical() << "Error while creating Qml m_qmlComponent:" - << m_qmlComponent->errorString(); + qDebug() << "Setting up the quickWindow"; + m_quickWindow.reset(qobject_cast<QQuickWindow *>(topLevel)); + if (m_quickWindow) { + qDebug() << "Running with incubator controller"; + m_qmlEngine->setIncubationController(m_quickWindow->incubationController()); + } else { + qWarning() << "Top level object is not a QQuickWindow. Trying QQuickView..."; + + QQuickItem *contentItem = qobject_cast<QQuickItem *>(topLevel); + if (!contentItem) { + qCritical() << "Top level object cannot be casted to QQuickItem. Aborting."; return false; } - emit projectStateChanged("Setting up the quickWindow..."); - QEventLoop().processEvents(QEventLoop::AllEvents, 1000); - - qDebug() << "Setting up the quickWindow"; - m_quickWindow.reset(qobject_cast<QQuickWindow *>(topLevel)); - if (m_quickWindow) { - qDebug() << "Running with incubator controller"; - m_qmlEngine->setIncubationController(m_quickWindow->incubationController()); - } else { - qWarning() << "Top level object is not a QQuickWindow. Trying QQuickView..."; - - QQuickItem *contentItem = qobject_cast<QQuickItem *>(topLevel); - if (!contentItem) { - qCritical() << "Top level object cannot be casted to QQuickItem. Aborting."; - return false; - } - - qDebug() << "Initializing QQuickView"; - QQuickView *view = new QQuickView(m_qmlEngine.data(), nullptr); - m_quickWindow.reset(view); - view->setContent(mainQmlUrl, m_qmlComponent.data(), contentItem); - view->setResizeMode(QQuickView::SizeViewToRootObject); - m_quickWindow->setBaseSize(QSize(contentItem->width(), contentItem->height())); - } - return true; + qDebug() << "Initializing QQuickView"; + QQuickView *view = new QQuickView(m_qmlEngine.data(), nullptr); + m_quickWindow.reset(view); + view->setContent(mainQmlUrl, m_qmlComponent.data(), contentItem); + view->setResizeMode(QQuickView::SizeViewToRootObject); + m_quickWindow->setBaseSize(QSize(contentItem->width(), contentItem->height())); + } + return true; } bool ProjectManager::cacheProject(const QByteArray &projectData, const QJsonObject &projectInfo) diff --git a/src/projectManager.h b/src/projectManager.h index 3fc0759713970bab9e5af3613fe9167fb9e36b68..3a2cfdbf35a47726f36c327e1dfdc303788067ce 100644 --- a/src/projectManager.h +++ b/src/projectManager.h @@ -71,6 +71,10 @@ private: // Member functions QString findFile(const QString &dir, const QString &filter); + QString readQmlProjectFile(const QString &qmlProjectFilePath); + QString getMainQmlFile(const QString &projectPath, const QString &qmlProjectFileContent); + QStringList getImportPaths(const QString &projectPath, const QString &qmlProjectFileContent); + bool isQt6Project(const QString &qmlProjectFileContent); void parseQmlProjectFile(const QString &fileName, QString *mainFile, QStringList *importPaths); void cacheProject(const QString &projectName, const QString &projectPath);