mirror of
https://github.com/logos-storage/logos-storage-app-skeleton.git
synced 2026-06-13 20:09:28 +00:00
Move files for QML architecture
This commit is contained in:
parent
aca1eeed0b
commit
4df4f78694
@ -12,17 +12,15 @@
|
||||
"build": {
|
||||
"type": "cmake",
|
||||
"files": [
|
||||
"src/storage_ui_plugin.cpp",
|
||||
"src/storage_ui_plugin.h",
|
||||
"src/storagewindow.cpp",
|
||||
"src/storagewindow.h",
|
||||
"src/storagewidget.cpp",
|
||||
"src/storagewidget.h",
|
||||
"src/storage_ui_resources.qrc"
|
||||
"src/StorageUIPlugin.cpp",
|
||||
"src/StorageUIPlugin.h",
|
||||
"src/StorageBackend.cpp",
|
||||
"src/StorageBackend.h",
|
||||
"src/storage_resources.qrc"
|
||||
]
|
||||
},
|
||||
"capabilities": [
|
||||
"ui_components",
|
||||
"storage"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
#include "StorageUIPlugin.h"
|
||||
#include "src/StorageBackend.h"
|
||||
#include <QQuickWidget>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
#include <QDebug>
|
||||
#include <QFileInfo>
|
||||
#include <QFile>
|
||||
|
||||
QWidget* StorageUIPlugin::createWidget(LogosAPI* logosAPI) {
|
||||
qDebug() << "StorageUIPlugin::createWidget called";
|
||||
|
||||
QQuickWidget* quickWidget = new QQuickWidget();
|
||||
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
||||
|
||||
// Register StorageBackend type with QML engine to expose the enum
|
||||
qmlRegisterType<StorageBackend>("StorageBackend", 1, 0, "StorageBackend");
|
||||
|
||||
// Create backend instance
|
||||
StorageBackend* backend = new StorageBackend(logosAPI, quickWidget);
|
||||
|
||||
// Set backend as context property
|
||||
quickWidget->rootContext()->setContextProperty("backend", backend);
|
||||
|
||||
// For development: check environment variable, otherwise use qrc
|
||||
QString qmlPath = "qrc:/StorageView.qml";
|
||||
QString envPath = qgetenv("STORAGE_UI_QML_PATH");
|
||||
if (!envPath.isEmpty() && QFile::exists(envPath)) {
|
||||
qmlPath = QUrl::fromLocalFile(QFileInfo(envPath).absoluteFilePath()).toString();
|
||||
qDebug() << "Loading QML from file system:" << qmlPath;
|
||||
}
|
||||
|
||||
quickWidget->setSource(QUrl(qmlPath));
|
||||
|
||||
if (quickWidget->status() == QQuickWidget::Error) {
|
||||
qWarning() << "StorageUIPlugin: Failed to load QML:" << quickWidget->errors();
|
||||
}
|
||||
|
||||
return quickWidget;
|
||||
}
|
||||
|
||||
void StorageUIPlugin::destroyWidget(QWidget* widget) {
|
||||
delete widget;
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import StorageBackend
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 0
|
||||
anchors.rightMargin: 0
|
||||
anchors.topMargin: 0
|
||||
anchors.bottomMargin: 0
|
||||
color: "#202428"
|
||||
}
|
||||
|
||||
Text {
|
||||
text: qsTr("Storage UI")
|
||||
color: "black"
|
||||
anchors.centerIn: parent
|
||||
font.pointSize: 20
|
||||
}
|
||||
|
||||
Text {
|
||||
objectName: "status"
|
||||
text: "..."
|
||||
color: "white"
|
||||
font.pointSize: 20
|
||||
anchors.topMargin: 32
|
||||
}
|
||||
|
||||
Button {
|
||||
objectName: "startButton"
|
||||
anchors.leftMargin: 50
|
||||
text: "Stop"
|
||||
}
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
#include "StorageBackend.h"
|
||||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
#include <QLocale>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
StorageBackend::StorageBackend(LogosAPI* logosAPI, QObject* parent)
|
||||
: QObject(parent),
|
||||
m_status(NotStarted),
|
||||
m_logosAPI(nullptr),
|
||||
m_logos(nullptr)
|
||||
{
|
||||
qDebug() << "Initializing StorageBackend...";
|
||||
|
||||
if (logosAPI) {
|
||||
m_logosAPI = logosAPI;
|
||||
} else {
|
||||
m_logosAPI = new LogosAPI("core", this);
|
||||
}
|
||||
|
||||
m_logos = new LogosModules(m_logosAPI);
|
||||
}
|
||||
|
||||
StorageBackend::~StorageBackend()
|
||||
{
|
||||
stopStorage();
|
||||
}
|
||||
|
||||
void StorageBackend::setStatus(StorageStatus newStatus)
|
||||
{
|
||||
if (m_status != newStatus) {
|
||||
m_status = newStatus;
|
||||
emit statusChanged();
|
||||
qDebug() << "StorageBackend: Status changed to" << m_status;
|
||||
}
|
||||
}
|
||||
|
||||
void StorageBackend::startStorage()
|
||||
{
|
||||
setStatus(Starting);
|
||||
|
||||
auto& storageModule = m_logos->storage_module;
|
||||
|
||||
QString configStr = R"({
|
||||
|
||||
})";
|
||||
|
||||
if (!storageModule.initStorage(configStr)) {
|
||||
setStatus(Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Subscribe to connectedPeersResponse events
|
||||
// if (!storageModule.on("connectedPeersResponse", [this](const QVariantList& data) {
|
||||
// if (data.size() < 1) {
|
||||
// qWarning() << "StorageBackend: connectedPeersResponse payload missing fields";
|
||||
// return;
|
||||
// }
|
||||
// onConnectedPeersResponse(data);
|
||||
// })) {
|
||||
// qWarning() << "StorageBackend: failed to subscribe to connectedPeersResponse events";
|
||||
// }
|
||||
|
||||
if (!storageModule.startStorage()) {
|
||||
setStatus(Error);
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus(Running);
|
||||
|
||||
// Refresh peers and metrics after a delay to allow Storage to fully start
|
||||
// QTimer::singleShot(1000, this, [this]() {
|
||||
// refreshPeers();
|
||||
// refreshMetrics();
|
||||
// });
|
||||
}
|
||||
|
||||
void StorageBackend::stopStorage()
|
||||
{
|
||||
if (m_status != Running && m_status != Starting) {
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus(Stopping);
|
||||
|
||||
auto& storageModule = m_logos->storage_module;
|
||||
|
||||
if (!storageModule.stopStorage()) {
|
||||
qWarning() << "StorageBackend::stopStorage: stopStorage() returned false";
|
||||
setStatus(Error);
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus(Stopped);
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
#include "logos_api.h"
|
||||
#include "logos_api_client.h"
|
||||
#include "logos_sdk.h"
|
||||
|
||||
class StorageBackend : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum StorageStatus {
|
||||
NotStarted = 0,
|
||||
Starting,
|
||||
Running,
|
||||
Stopping,
|
||||
Stopped,
|
||||
Error
|
||||
};
|
||||
Q_ENUM(StorageStatus)
|
||||
|
||||
Q_PROPERTY(StorageStatus status READ status NOTIFY statusChanged)
|
||||
|
||||
explicit StorageBackend(LogosAPI* logosAPI = nullptr, QObject* parent = nullptr);
|
||||
~StorageBackend();
|
||||
|
||||
StorageStatus status() const { return m_status; }
|
||||
|
||||
public slots:
|
||||
Q_INVOKABLE void startStorage();
|
||||
Q_INVOKABLE void stopStorage();
|
||||
|
||||
signals:
|
||||
void statusChanged();
|
||||
|
||||
private slots:
|
||||
// void onConnectedPeersResponse(const QVariantList& data);
|
||||
|
||||
private:
|
||||
void setStatus(StorageStatus newStatus);
|
||||
|
||||
StorageStatus m_status;
|
||||
LogosAPI* m_logosAPI;
|
||||
LogosModules* m_logos;
|
||||
};
|
||||
@ -1,5 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>StorageView.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@ -1,42 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(qml VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Quick)
|
||||
|
||||
qt_standard_project_setup(REQUIRES 6.8)
|
||||
|
||||
qt_add_executable(appqml
|
||||
main.cpp
|
||||
)
|
||||
|
||||
qt_add_qml_module(appqml
|
||||
URI qml
|
||||
VERSION 1.0
|
||||
QML_FILES
|
||||
Main.qml
|
||||
)
|
||||
|
||||
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
|
||||
# If you are developing for iOS or macOS you should consider setting an
|
||||
# explicit, fixed bundle identifier manually though.
|
||||
set_target_properties(appqml PROPERTIES
|
||||
# MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appqml
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
MACOSX_BUNDLE TRUE
|
||||
WIN32_EXECUTABLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(appqml
|
||||
PRIVATE Qt6::Quick
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS appqml
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
@ -1,8 +0,0 @@
|
||||
import QtQuick
|
||||
|
||||
Window {
|
||||
width: 640
|
||||
height: 480
|
||||
visible: true
|
||||
title: qsTr("Hello World")
|
||||
}
|
||||
156
src/StorageBackend.cpp
Normal file
156
src/StorageBackend.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
#include "StorageBackend.h"
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLocale>
|
||||
|
||||
StorageBackend::StorageBackend(LogosAPI* logosAPI, QObject* parent)
|
||||
: QObject(parent), m_status(Destroyed), m_logosAPI(nullptr), m_logos(nullptr) {
|
||||
qDebug() << "Initializing StorageBackend...";
|
||||
|
||||
if (logosAPI) {
|
||||
m_logosAPI = logosAPI;
|
||||
} else {
|
||||
m_logosAPI = new LogosAPI("core", this);
|
||||
}
|
||||
|
||||
m_logos = new LogosModules(m_logosAPI);
|
||||
|
||||
initStorage();
|
||||
}
|
||||
|
||||
StorageBackend::~StorageBackend()
|
||||
{
|
||||
m_logosAPI = nullptr;
|
||||
m_logos = nullptr;
|
||||
}
|
||||
|
||||
void StorageBackend::initStorage() {
|
||||
qDebug() << "StorageBackend::initStorage called";
|
||||
|
||||
bool result = m_logos->storage_module.init("{}");
|
||||
|
||||
qDebug() << "StorageBackend::initStorage: init result =" << result;
|
||||
|
||||
if (!result) {
|
||||
qDebug() << "StorageBackend: Failed to initialise Storage module.";
|
||||
setStatus(Destroyed, "Failed to initialise Storage module.");
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus(Stopped, "Storage module ready.");
|
||||
|
||||
if (!m_logos->storage_module.on("storageStart", [this](const QVariantList& data) {
|
||||
int code = data[0].toInt();
|
||||
|
||||
if (code != RET_OK) {
|
||||
qDebug() << "StorageBackend: storageStart event failure with code" << code;
|
||||
setStatus(Stopped, "Failed to start Storage module.");
|
||||
} else {
|
||||
qDebug() << "StorageBackend: storageStart event success";
|
||||
setStatus(Running, "Storage module started.");
|
||||
}
|
||||
})) {
|
||||
qWarning() << "StorageWidget: failed to subscribe to storageStart events";
|
||||
}
|
||||
|
||||
if (!m_logos->storage_module.on("storageStop", [this](const QVariantList& data) {
|
||||
int code = data[0].toInt();
|
||||
|
||||
if (code != RET_OK) {
|
||||
qDebug() << "StorageBackend: storageStop event failure with code" << code;
|
||||
setStatus(Running, "Failed to stop Storage module.");
|
||||
} else {
|
||||
qDebug() << "StorageBackend: storageStop event success";
|
||||
setStatus(Stopped, "Storage module stopped.");
|
||||
emit stopped();
|
||||
}
|
||||
})) {
|
||||
qWarning() << "StorageWidget: failed to subscribe to storageStop events";
|
||||
}
|
||||
|
||||
startStop();
|
||||
}
|
||||
|
||||
void StorageBackend::setStatus(StorageStatus newStatus, QString statusText) {
|
||||
if (m_status != newStatus || m_statusText != statusText) {
|
||||
m_status = newStatus;
|
||||
m_statusText = statusText;
|
||||
emit statusChanged();
|
||||
qDebug() << "StorageBackend: Status changed to" << m_status;
|
||||
}
|
||||
}
|
||||
|
||||
void StorageBackend::startStop() {
|
||||
qDebug() << "StorageBackend: startStop method called";
|
||||
|
||||
if (m_status == Destroyed || m_status == Starting || m_status == Stopping) {
|
||||
qDebug() << "StorageBackend: Cannot start/stop Storage in current state:" << m_status;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_status != Running) {
|
||||
qDebug() << "StorageBackend: Starting Storage...";
|
||||
setStatus(Starting, "Starting Storage module...");
|
||||
|
||||
bool result = m_logos->storage_module.start();
|
||||
|
||||
if (!result) {
|
||||
qDebug() << "StorageBackend: Failed to start Storage.";
|
||||
setStatus(Stopped, "Failed to start Storage module.");
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "StorageBackend: start command sent, waiting for events.";
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void StorageBackend::stop() {
|
||||
qDebug() << "StorageBackend: Stopping Storage...";
|
||||
setStatus(Stopping, "Stopping Storage module...");
|
||||
|
||||
bool result = m_logos->storage_module.stop();
|
||||
|
||||
if (!result) {
|
||||
qDebug() << "StorageBackend: Failed to stop Storage.";
|
||||
setStatus(Running, "Failed to stop Storage module.");
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "StorageBackend: stop command sent, waiting for events.";
|
||||
}
|
||||
|
||||
void StorageBackend::destroy() {
|
||||
qDebug() << "StorageBackend: destroy method called";
|
||||
|
||||
StorageStatus status = m_status;
|
||||
int result = m_logos->storage_module.destroy();
|
||||
|
||||
if (!result) {
|
||||
qDebug() << "StorageBackend: Failed to destroy Storage module." << result;
|
||||
setStatus(status, "Failed to destroy Storage module.");
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "StorageBackend: Storage module destroyed.";
|
||||
}
|
||||
|
||||
QString StorageBackend::statusText() const { return m_statusText; }
|
||||
|
||||
QString StorageBackend::startStopText() const {
|
||||
if (m_status != Running) {
|
||||
return "Start";
|
||||
} else {
|
||||
return "Stop";
|
||||
}
|
||||
}
|
||||
|
||||
bool StorageBackend::canStartStop() const { return m_status == Running || m_status == Stopped; }
|
||||
|
||||
bool StorageBackend::isRunning() { return m_status == Running; }
|
||||
|
||||
bool StorageBackend::isInitialised() { return m_status != Destroyed; }
|
||||
54
src/StorageBackend.h
Normal file
54
src/StorageBackend.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include "logos_api.h"
|
||||
#include "logos_sdk.h"
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
#include <QtQml/qqml.h>
|
||||
|
||||
static const int RET_OK = 0;
|
||||
|
||||
class StorageBackend : public QObject {
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
public:
|
||||
enum StorageStatus { Stopped = 0, Starting, Running, Stopping, Destroyed };
|
||||
Q_ENUM(StorageStatus)
|
||||
|
||||
Q_PROPERTY(bool canStartStop READ canStartStop NOTIFY statusChanged)
|
||||
bool canStartStop() const;
|
||||
|
||||
Q_PROPERTY(QString startStopText READ startStopText NOTIFY statusChanged)
|
||||
QString startStopText() const;
|
||||
|
||||
Q_PROPERTY(QString statusText READ statusText NOTIFY statusChanged)
|
||||
QString statusText() const;
|
||||
|
||||
explicit StorageBackend(LogosAPI* logosAPI = nullptr, QObject* parent = nullptr);
|
||||
~StorageBackend();
|
||||
|
||||
public slots:
|
||||
void startStop();
|
||||
void destroy();
|
||||
bool isRunning();
|
||||
bool isInitialised();
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void statusChanged();
|
||||
void stopped();
|
||||
|
||||
private slots:
|
||||
|
||||
private:
|
||||
void setStatus(StorageStatus newStatus, QString statusText);
|
||||
void initStorage();
|
||||
|
||||
StorageStatus m_status;
|
||||
LogosAPI* m_logosAPI;
|
||||
LogosModules* m_logos;
|
||||
|
||||
QString m_statusText;
|
||||
};
|
||||
115
src/StorageUIPlugin.cpp
Normal file
115
src/StorageUIPlugin.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
#include "StorageUIPlugin.h"
|
||||
#include "StorageBackend.h"
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
#include <QQuickItem>
|
||||
#include <QQuickWidget>
|
||||
|
||||
QWidget* StorageUIPlugin::createWidget(LogosAPI* logosAPI) {
|
||||
qDebug() << "StorageUIPlugin::createWidget called";
|
||||
|
||||
QQuickWidget* quickWidget = new QQuickWidget();
|
||||
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
||||
|
||||
QString qmlPath = "qrc:/StorageView.qml";
|
||||
|
||||
quickWidget->setSource(QUrl(qmlPath));
|
||||
|
||||
if (quickWidget->status() == QQuickWidget::Error) {
|
||||
qWarning() << "StorageUIPlugin: Failed to load QML:" << quickWidget->errors();
|
||||
}
|
||||
|
||||
// Create backend instance
|
||||
StorageBackend* backend = new StorageBackend(logosAPI, quickWidget);
|
||||
|
||||
// Set backend as context property
|
||||
QQuickItem* root = quickWidget->rootObject();
|
||||
Q_ASSERT(root);
|
||||
|
||||
root->setProperty("backend", QVariant::fromValue(static_cast<QObject*>(backend)));
|
||||
|
||||
return quickWidget;
|
||||
}
|
||||
|
||||
// Destroy the widget and clean up the backend.
|
||||
// It will block the event loop up to 2 seconds to ensure proper cleanup.
|
||||
// It will try to stop the backend if it is running.`
|
||||
void StorageUIPlugin::destroyWidget(QWidget* widget) {
|
||||
qDebug() << "StorageUIPlugin: Destroy widget";
|
||||
|
||||
auto* quickWidget = qobject_cast<QQuickWidget*>(widget);
|
||||
if (!quickWidget) {
|
||||
delete widget;
|
||||
return;
|
||||
}
|
||||
|
||||
QQuickItem* root = quickWidget->rootObject();
|
||||
if (!root) {
|
||||
qWarning() << "StorageUIPlugin::destroyWidget: No rootObject, deleting widget";
|
||||
quickWidget->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable QML to ensure that not updated are pushed in the UI
|
||||
root->setEnabled(false);
|
||||
|
||||
// Retrieve the backend object from the root element
|
||||
// as it was set in createWidget
|
||||
QObject* value = root->property("backend").value<QObject*>();
|
||||
auto* backend = qobject_cast<StorageBackend*>(value);
|
||||
if (!backend) {
|
||||
qWarning() << "StorageUIPlugin::destroyWidget: No backend found on root property 'backend'.";
|
||||
quickWidget->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!backend->isInitialised()) {
|
||||
qDebug() << "StorageUIPlugin::destroyWidget: backend is not initialised so let's detroy it.";
|
||||
quickWidget->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!backend->isRunning()) {
|
||||
qDebug() << "StorageUIPlugin::destroyWidget: backend is not running so let's detroy it.";
|
||||
|
||||
backend->destroy();
|
||||
|
||||
quickWidget->deleteLater();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "StorageUIPlugin::destroyWidget: backend is running so let's stop it.";
|
||||
|
||||
// Here we create a QEventLoop to wait for the stopped signal
|
||||
QEventLoop loop;
|
||||
QTimer timeout;
|
||||
// Single shot means that the timer will only fire once.
|
||||
timeout.setSingleShot(true);
|
||||
|
||||
// Connect to timeout and unblock the event loop after 2 seconds
|
||||
QObject::connect(&timeout, &QTimer::timeout, &loop, [&]() {
|
||||
qWarning() << "StorageUIPlugin::destroyWidget: stop timeout";
|
||||
loop.quit();
|
||||
});
|
||||
|
||||
// Connect to stop signal
|
||||
QObject::connect(backend, &StorageBackend::stopped, &loop, [&]() { loop.quit(); }, Qt::QueuedConnection);
|
||||
|
||||
// Call the stop method asynchronously
|
||||
QMetaObject::invokeMethod(backend, "stop", Qt::QueuedConnection);
|
||||
|
||||
// Set the timeout to 2 sec
|
||||
timeout.start(2000);
|
||||
|
||||
// Block
|
||||
loop.exec();
|
||||
|
||||
// Try to cleanup, event if the stop method failed
|
||||
backend->destroy();
|
||||
|
||||
delete quickWidget;
|
||||
}
|
||||
@ -10,5 +10,5 @@ class StorageUIPlugin : public QObject, public IComponent {
|
||||
|
||||
public:
|
||||
Q_INVOKABLE QWidget* createWidget(LogosAPI* logosAPI = nullptr) override;
|
||||
void destroyWidget(QWidget* widget) override;
|
||||
};
|
||||
Q_INVOKABLE void destroyWidget(QWidget* widget) override;
|
||||
};
|
||||
17
src/main.cpp
17
src/main.cpp
@ -1,17 +0,0 @@
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include "StorageWindow.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
|
||||
qDebug() << "Starting Storage Qt Application";
|
||||
|
||||
// Create and show the main window
|
||||
StorageWindow mainWindow;
|
||||
mainWindow.setWindowTitle("Logos Storage App");
|
||||
mainWindow.resize(800, 600);
|
||||
mainWindow.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
147
src/qml/CMakeLists.txt
Normal file
147
src/qml/CMakeLists.txt
Normal file
@ -0,0 +1,147 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(qml VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
|
||||
########### DEPENDENCIES ###########
|
||||
|
||||
# This section locates the required dependencies in 3 different ways:
|
||||
# 1- With NIX, the root folders (LOGOS_LIBLOGOS_ROOT, LOGOS_CPP_SDK_ROO)
|
||||
# are defined and point to the correct locations in
|
||||
# the Nix store.
|
||||
# 2- If the root folders are fetched from source (basically using git) in the
|
||||
# parent folder, this is detected and used.
|
||||
# 3- If none of the above apply, the vendor folders inside this project are used,
|
||||
# meaning the dependencies need to be fetched using git submodules.
|
||||
|
||||
# Locate logos-cpp-sdk
|
||||
if(NOT DEFINED LOGOS_CPP_SDK_ROOT)
|
||||
set(_parent_cpp_sdk "${CMAKE_SOURCE_DIR}/../../../logos-cpp-sdk")
|
||||
set(_use_vendor ${LOGOS_STORAGE_UI_USE_VENDOR})
|
||||
|
||||
if(NOT _use_vendor)
|
||||
if(NOT EXISTS "${_parent_cpp_sdk}/cpp/logos_api.h")
|
||||
set(_use_vendor ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(_use_vendor)
|
||||
set(LOGOS_CPP_SDK_ROOT "${CMAKE_SOURCE_DIR}/../../vendor/logos-cpp-sdk")
|
||||
else()
|
||||
set(LOGOS_CPP_SDK_ROOT "${_parent_cpp_sdk}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Locate the logos_api header file.
|
||||
# If the file is found, the sdk is considered found.
|
||||
set(_cpp_sdk_found FALSE)
|
||||
if(EXISTS "${LOGOS_CPP_SDK_ROOT}/cpp/logos_api.h")
|
||||
set(_cpp_sdk_found TRUE)
|
||||
set(_cpp_sdk_is_source TRUE)
|
||||
elseif(EXISTS "${LOGOS_CPP_SDK_ROOT}/include/cpp/logos_api.h")
|
||||
set(_cpp_sdk_found TRUE)
|
||||
set(_cpp_sdk_is_source FALSE)
|
||||
endif()
|
||||
|
||||
# Fails if the SDK is not found.
|
||||
if(NOT _cpp_sdk_found)
|
||||
message(FATAL_ERROR
|
||||
"logos-cpp-sdk not found at ${LOGOS_CPP_SDK_ROOT}. "
|
||||
"Set LOGOS_CPP_SDK_ROOT or run git submodule update --init --recursive."
|
||||
)
|
||||
endif()
|
||||
|
||||
########### DEPENDENCIES END ###########
|
||||
|
||||
########### QML DEFINITION ###########
|
||||
|
||||
set(PLUGIN_UI_BUILD_DIR "../../build/generated_code")
|
||||
|
||||
list(APPEND SOURCES
|
||||
${PLUGIN_UI_BUILD_DIR}/logos_sdk.cpp
|
||||
)
|
||||
|
||||
# Create a library with the Logos SDK and generated sources to keep them separate
|
||||
add_library(storage_generated STATIC
|
||||
${PLUGIN_UI_BUILD_DIR}/logos_sdk.cpp
|
||||
${PLUGIN_UI_BUILD_DIR}/storage_module_api.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_client.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_provider.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/module_proxy.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/token_manager.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_consumer.cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/logos_api_provider.cpp
|
||||
)
|
||||
|
||||
# Define the dependencies needed for storage_generated
|
||||
target_link_libraries(storage_generated PUBLIC
|
||||
Qt6::Core
|
||||
Qt6::RemoteObjects
|
||||
)
|
||||
|
||||
# Discover the required dependencies
|
||||
find_package(Qt6 REQUIRED COMPONENTS Quick RemoteObjects)
|
||||
|
||||
# Standard project setup for Qt applications
|
||||
qt_standard_project_setup(REQUIRES 6.8)
|
||||
|
||||
# Add the Qt Quick application executable
|
||||
qt_add_executable(appqml
|
||||
main.cpp
|
||||
)
|
||||
|
||||
# Use these required dependencies.
|
||||
target_link_libraries(appqml PRIVATE
|
||||
Qt6::Quick
|
||||
Qt6::Qml
|
||||
storage_generated
|
||||
)
|
||||
|
||||
# Define the qml module and the StorageBackend sources.
|
||||
qt_add_qml_module(appqml
|
||||
URI StorageBackend
|
||||
VERSION 1.0
|
||||
SOURCES
|
||||
../src/StorageBackend.cpp
|
||||
../src/StorageBackend.h
|
||||
QML_FILES
|
||||
StorageView.qml
|
||||
)
|
||||
|
||||
########### QML DEFINITION END ###########
|
||||
|
||||
########### HEADERS ###########
|
||||
|
||||
target_include_directories(storage_generated PUBLIC
|
||||
"${PLUGIN_UI_BUILD_DIR}"
|
||||
"${PLUGIN_UI_BUILD_DIR}/include"
|
||||
)
|
||||
|
||||
# Include directories
|
||||
if(_cpp_sdk_is_source)
|
||||
target_include_directories(storage_generated PUBLIC
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/cpp/generated
|
||||
)
|
||||
else()
|
||||
target_include_directories(storage_generated PUBLIC
|
||||
${LOGOS_CPP_SDK_ROOT}/include
|
||||
${LOGOS_CPP_SDK_ROOT}/include/cpp
|
||||
${LOGOS_CPP_SDK_ROOT}/include/core
|
||||
${PLUGIN_UI_BUILD_DIR}/include
|
||||
)
|
||||
endif()
|
||||
|
||||
# Import the application headers.
|
||||
target_include_directories(appqml PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../src
|
||||
${PLUGINS_OUTPUT_DIR}
|
||||
)
|
||||
|
||||
########### HEADERS END ###########
|
||||
|
||||
message(STATUS "Qt Quick app configured successfully")
|
||||
63
src/qml/StorageView.qml
Normal file
63
src/qml/StorageView.qml
Normal file
@ -0,0 +1,63 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
//import QtQuick.Layouts
|
||||
Item {
|
||||
property var backend: mockBackend
|
||||
readonly property int stopped: 0
|
||||
readonly property int starting: 1
|
||||
readonly property int running: 2
|
||||
readonly property int stopping: 3
|
||||
readonly property int destroyed: 4
|
||||
|
||||
id: root
|
||||
width: 400
|
||||
height: 300
|
||||
|
||||
QtObject {
|
||||
id: mockBackend
|
||||
|
||||
property var status: root.stopped
|
||||
property var statusText: "Destroyed"
|
||||
property var startStopText: "Start"
|
||||
property var canStartStop: true
|
||||
|
||||
function startStop() {
|
||||
if (status == root.running) {
|
||||
status = root.stopped
|
||||
statusText = "Stopped"
|
||||
startStopText = "Start"
|
||||
} else {
|
||||
status = root.running
|
||||
statusText = "Started"
|
||||
startStopText = "Stop"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 0
|
||||
anchors.rightMargin: 0
|
||||
anchors.topMargin: 0
|
||||
anchors.bottomMargin: 0
|
||||
color: "#202428"
|
||||
}
|
||||
|
||||
Text {
|
||||
objectName: "status"
|
||||
text: root.backend.statusText
|
||||
color: "white"
|
||||
font.pointSize: 20
|
||||
anchors.centerIn: parent
|
||||
anchors.topMargin: 0
|
||||
}
|
||||
|
||||
Button {
|
||||
objectName: "startStopButton"
|
||||
anchors.leftMargin: 50
|
||||
text: root.backend.startStopText
|
||||
enabled: root.backend.canStartStop
|
||||
onClicked: root.backend.startStop()
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QtQml>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
QGuiApplication app(argc, argv);
|
||||
@ -8,7 +9,6 @@ int main(int argc, char* argv[]) {
|
||||
QObject::connect(
|
||||
&engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); },
|
||||
Qt::QueuedConnection);
|
||||
engine.loadFromModule("qml", "Main");
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
5
src/storage_resources.qrc
Normal file
5
src/storage_resources.qrc
Normal file
@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file alias="StorageView.qml">qml/StorageView.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
Loading…
x
Reference in New Issue
Block a user