diff options
Diffstat (limited to 'src/qt')
-rw-r--r-- | src/qt/CMakeLists.txt | 34 | ||||
-rw-r--r-- | src/qt/assets.qrc | 15 | ||||
-rw-r--r-- | src/qt/assets/background.bmp | bin | 0 -> 2073738 bytes | |||
-rw-r--r-- | src/qt/assets/discord.png | bin | 0 -> 2412 bytes | |||
-rw-r--r-- | src/qt/assets/game.ico | bin | 0 -> 93062 bytes | |||
-rw-r--r-- | src/qt/assets/gear-solid.png | bin | 0 -> 2550 bytes | |||
-rw-r--r-- | src/qt/assets/globe.png | bin | 0 -> 2849 bytes | |||
-rw-r--r-- | src/qt/assets/logo.png | bin | 0 -> 21482 bytes | |||
-rw-r--r-- | src/qt/assets/tf2build.ttf | bin | 0 -> 57168 bytes | |||
-rw-r--r-- | src/qt/assets/version.rc.in | 21 | ||||
-rw-r--r-- | src/qt/main.cpp | 12 | ||||
-rw-r--r-- | src/qt/mainwindow.cpp | 249 | ||||
-rw-r--r-- | src/qt/mainwindow.hpp | 50 | ||||
-rw-r--r-- | src/qt/mainwindow.ui | 349 | ||||
-rw-r--r-- | src/qt/settings.cpp | 44 | ||||
-rw-r--r-- | src/qt/settings.hpp | 35 | ||||
-rw-r--r-- | src/qt/settings.ui | 215 | ||||
-rw-r--r-- | src/qt/workers.cpp | 299 | ||||
-rw-r--r-- | src/qt/workers.hpp | 94 |
19 files changed, 1417 insertions, 0 deletions
diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt new file mode 100644 index 0000000..c0566d9 --- /dev/null +++ b/src/qt/CMakeLists.txt @@ -0,0 +1,34 @@ +SET(FRONTEND_NAME "OFQT") +enable_language(CXX) + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Gui REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Gui REQUIRED) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +list(APPEND + QT_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mainwindow.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mainwindow.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/settings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/settings.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/workers.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/workers.hpp + + ${CMAKE_CURRENT_SOURCE_DIR}/mainwindow.ui + ${CMAKE_CURRENT_SOURCE_DIR}/assets.qrc +) + +if(WIN32) + string(REPLACE "." "," CMAKE_PROJECT_COMMAVERSION ${CMAKE_PROJECT_VERSION}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/assets/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) + list(APPEND QT_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/version.rc) +endif() + +add_executable(${FRONTEND_NAME} WIN32 ${QT_SOURCES}) +target_link_libraries(${FRONTEND_NAME} PRIVATE libofqt) +target_link_libraries(${FRONTEND_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) +set_property(TARGET ${FRONTEND_NAME} PROPERTY CXX_STANDARD 11) diff --git a/src/qt/assets.qrc b/src/qt/assets.qrc new file mode 100644 index 0000000..10bca84 --- /dev/null +++ b/src/qt/assets.qrc @@ -0,0 +1,15 @@ +<RCC> + <qresource prefix="background"> + <file>assets/background.bmp</file> + </qresource> + <qresource prefix="icon"> + <file>assets/globe.png</file> + <file>assets/logo.png</file> + <file>assets/gear-solid.png</file> + <file>assets/discord.png</file> + <file>assets/game.ico</file> + </qresource> + <qresource prefix="font"> + <file>assets/tf2build.ttf</file> + </qresource> +</RCC> diff --git a/src/qt/assets/background.bmp b/src/qt/assets/background.bmp Binary files differnew file mode 100644 index 0000000..37156be --- /dev/null +++ b/src/qt/assets/background.bmp diff --git a/src/qt/assets/discord.png b/src/qt/assets/discord.png Binary files differnew file mode 100644 index 0000000..cc52539 --- /dev/null +++ b/src/qt/assets/discord.png diff --git a/src/qt/assets/game.ico b/src/qt/assets/game.ico Binary files differnew file mode 100644 index 0000000..7ebf98a --- /dev/null +++ b/src/qt/assets/game.ico diff --git a/src/qt/assets/gear-solid.png b/src/qt/assets/gear-solid.png Binary files differnew file mode 100644 index 0000000..8540b00 --- /dev/null +++ b/src/qt/assets/gear-solid.png diff --git a/src/qt/assets/globe.png b/src/qt/assets/globe.png Binary files differnew file mode 100644 index 0000000..98374e3 --- /dev/null +++ b/src/qt/assets/globe.png diff --git a/src/qt/assets/logo.png b/src/qt/assets/logo.png Binary files differnew file mode 100644 index 0000000..ad04eca --- /dev/null +++ b/src/qt/assets/logo.png diff --git a/src/qt/assets/tf2build.ttf b/src/qt/assets/tf2build.ttf Binary files differnew file mode 100644 index 0000000..d59eec9 --- /dev/null +++ b/src/qt/assets/tf2build.ttf diff --git a/src/qt/assets/version.rc.in b/src/qt/assets/version.rc.in new file mode 100644 index 0000000..06d3430 --- /dev/null +++ b/src/qt/assets/version.rc.in @@ -0,0 +1,21 @@ +IDI_ICON1 ICON DISCARDABLE "@CMAKE_CURRENT_SOURCE_DIR@/assets/game.ico" +1 VERSIONINFO +FILEVERSION @CMAKE_PROJECT_COMMAVERSION@ +PRODUCTVERSION @CMAKE_PROJECT_COMMAVERSION@ +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "FileVersion", "1.0" + VALUE "InternalName", "@CMAKE_PROJECT_NAME@" + VALUE "OriginalFilename", "@FRONTEND_NAME@.exe" + VALUE "ProductName", "@CMAKE_PROJECT_NAME@" + VALUE "ProductVersion", "@CMAKE_PROJECT_VERSION@" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END
\ No newline at end of file diff --git a/src/qt/main.cpp b/src/qt/main.cpp new file mode 100644 index 0000000..9cf530b --- /dev/null +++ b/src/qt/main.cpp @@ -0,0 +1,12 @@ +#include "mainwindow.hpp" + +#include <QApplication> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/src/qt/mainwindow.cpp b/src/qt/mainwindow.cpp new file mode 100644 index 0000000..35151ca --- /dev/null +++ b/src/qt/mainwindow.cpp @@ -0,0 +1,249 @@ +#include <QApplication> +#include <QMessageBox> +#include <QFontDatabase> +#include <QDesktopServices> +#include <QUrl> + +#include <limits.h> +#include <iostream> + +#include "steam.h" + +#include "mainwindow.hpp" +#include "./ui_mainwindow.h" +#include "workers.hpp" + + + +#define FONT "tf2build" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + centralWidget()->layout()->setContentsMargins(0, 0, 0, 0); + + qRegisterMetaType<Worker::Tasks_t>("Task_t"); + qRegisterMetaType<Worker::Results_t>("Results_t"); + + QFontDatabase::addApplicationFont (":/font/assets/" FONT ".ttf"); + QFont playFont(FONT, 20, QFont::Bold); + QFont progressFont(FONT, 10, QFont::Normal); + + ui->mainButton->setFont(playFont); + ui->progressBar->setFont(progressFont); + ui->statusLabel->setFont(progressFont); + ui->infoLabel->setFont(progressFont); + + QPixmap bkgnd(":/background/assets/background.bmp"); + bkgnd = bkgnd.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + + QPalette palette; + palette.setBrush(QPalette::Window, bkgnd); + this->setPalette(palette); + + worker = new Worker(); + worker->moveToThread(&thread); + + connect(&thread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &MainWindow::workerOperate, worker, &Worker::doWork); + connect(worker, &Worker::resultReady, this, &MainWindow::workerResult); + + thread.start(); + + //operateSVN(svnWorker::SVN_INSTALL); + + connect(ui->settingsButton, SIGNAL(clicked()), this, SLOT(settingsWindow())); + + settings = new Settings(worker, this); + settings->setModal(true); + //connect(settings, SIGNAL(visibleChanged()), this, SLOT(enable())); + + ui->mainButton->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(ui->mainButton, SIGNAL(clicked()), this, SLOT(updateButton())); + connect(ui->mainButton, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showButtonContext(const QPoint&))); + connect(ui->buttonDiscord, SIGNAL(clicked()), this, SLOT(openDiscordInvite())); + connect(ui->buttonWebsite, SIGNAL(clicked()), this, SLOT(openWebsite())); + + ui->mainButton->setText("..."); + ui->statusLabel->setText("..."); + ui->infoLabel->setText("..."); + + in_progress = false; + installed = false; + uptodate = false; + workerOperate(Worker::TASK_INIT); +} + +void MainWindow::workerResult(const enum Worker::Results_t& result) +{ + switch (result) + { + + case Worker::RESULT_UNINSTALL_COMPLETE: + case Worker::RESULT_UNINSTALL_FAILURE: + // TODO find better use for these + case Worker::RESULT_NONE: + resetProgress(); + break; + + case Worker::RESULT_EXIT: + QCoreApplication::quit(); + break; + + case Worker::RESULT_UPDATE_TEXT: + ui->progressBar->setValue(worker->progress); + ui->infoLabel->setText(worker->infoText); + break; + + case Worker::RESULT_IS_INSTALLED: + installed = true; + workerOperate(Worker::TASK_IS_UPTODATE); + break; + + case Worker::RESULT_IS_NOT_INSTALLED: + ui->mainButton->setText("Install"); + installed = false; + break; + + case Worker::RESULT_IS_UPTODATE: + uptodate = true; + ui->mainButton->setText("Play"); + ui->statusLabel->setText("Up to Date"); + break; + + case Worker::RESULT_IS_OUTDATED: + uptodate = false; + ui->mainButton->setText("Update"); + ui->statusLabel->setText(QString("Revision %1 is available").arg(worker->getRemoteRevision())); + break; + + case Worker::RESULT_INIT_COMPLETE: + ui->statusLabel->setText(""); + ui->infoLabel->setText(""); + workerOperate(Worker::TASK_IS_INSTALLED); + break; + + case Worker::RESULT_INIT_FAILURE: + QMessageBox::information(this, windowTitle(), "Could not find install location.\nIs Steam installed?"); + QCoreApplication::quit(); + break; + + case Worker::RESULT_INSTALL_COMPLETE: + resetProgress(); + ui->statusLabel->setText("Installed"); + workerOperate(Worker::TASK_IS_INSTALLED); + break; + + case Worker::RESULT_INSTALL_FAILURE: + ui->progressBar->setFormat("Install failed"); + break; + + case Worker::RESULT_UPDATE_COMPLETE: + resetProgress(); + ui->statusLabel->setText("Updated"); + workerOperate(Worker::TASK_IS_UPTODATE); + break; + + case Worker::RESULT_UPDATE_RUN: + ui->statusLabel->setText("Launching"); + workerOperate(Worker::TASK_RUN); + break; + + case Worker::RESULT_UPDATE_FAILURE: + ui->statusLabel->setText("Update failed"); + break; + + case Worker::RESULT_NO_STEAM: + resetProgress(); + QMessageBox::information(this, windowTitle(), "Steam is not running" ); + break; + + } + + in_progress = false; +} + +void MainWindow::settingsWindow() +{ + settings->refresh(); + settings->show(); + //this->setEnabled(false); +} + +void MainWindow::setupButton() +{ + workerOperate(Worker::TASK_IS_INSTALLED); +} + +void MainWindow::updateButton() +{ + if (in_progress) + return; + + if (installed) + { + if (!uptodate) + { + workerOperate(Worker::TASK_UPDATE); + ui->statusLabel->setText("Updating (may take a while)"); + } + else + { + workerOperate(Worker::TASK_RUN); + } + } + else + { + workerOperate(Worker::TASK_INSTALL); + ui->statusLabel->setText("Installing (may take a while)"); + } + + in_progress = true; +} + +void MainWindow::showButtonContext(const QPoint& pos) +{ + QPoint absPos = ui->mainButton->mapToGlobal(pos); + + QMenu ctxMenu; + ctxMenu.addAction("Run without Update"); + + QAction* selectedItem = ctxMenu.exec(absPos); + + if (selectedItem) + { + workerOperate(Worker::TASK_RUN); + } +} + + +void MainWindow::openDiscordInvite() +{ + QDesktopServices::openUrl(QUrl("https://discord.gg/mKjW2ACCrm", QUrl::TolerantMode)); +} + +void MainWindow::openWebsite() +{ + QDesktopServices::openUrl(QUrl("https://openfortress.fun/", QUrl::TolerantMode)); +} + +void MainWindow::resetProgress() +{ + ui->progressBar->setFormat(""); + ui->progressBar->setValue(-1); +} + +MainWindow::~MainWindow() +{ + delete ui; + delete settings; + + worker->stop_work(); + thread.quit(); + thread.wait(); +} + diff --git a/src/qt/mainwindow.hpp b/src/qt/mainwindow.hpp new file mode 100644 index 0000000..0d21efc --- /dev/null +++ b/src/qt/mainwindow.hpp @@ -0,0 +1,50 @@ +#ifndef MAINWINDOW_HPP +#define MAINWINDOW_HPP + +#include <QThread> +#include <QMainWindow> +#include <QMenu> + +#include "settings.hpp" +#include "workers.hpp" + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget* parent = nullptr); + ~MainWindow(); + +private: + Ui::MainWindow *ui; + Settings* settings; + QThread thread; + Worker* worker; + + bool in_progress; + bool installed; + bool uptodate; + + void setupButton(); + void resetProgress(); + +public slots: + void workerResult(const Worker::Results_t&); + +private slots: + void settingsWindow(); + void updateButton(); + void showButtonContext(const QPoint&); + void openDiscordInvite(); + void openWebsite(); + +signals: + void workerOperate(const Worker::Tasks_t&); + +}; +#endif // MAINWINDOW_HPP diff --git a/src/qt/mainwindow.ui b/src/qt/mainwindow.ui new file mode 100644 index 0000000..574129b --- /dev/null +++ b/src/qt/mainwindow.ui @@ -0,0 +1,349 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>736</width> + <height>413</height> + </rect> + </property> + <property name="minimumSize"> + <size> + <width>736</width> + <height>413</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>736</width> + <height>413</height> + </size> + </property> + <property name="windowTitle"> + <string>OFQT</string> + </property> + <property name="windowIcon"> + <iconset resource="assets.qrc"> + <normaloff>:/icon/assets/game.ico</normaloff>:/icon/assets/game.ico</iconset> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <widget class="QWidget" name="centralwidget"> + <property name="styleSheet"> + <string notr="true"/> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <layout class="QVBoxLayout" name="layoutLeft"> + <item> + <widget class="QLabel" name="logoOF"> + <property name="styleSheet"> + <string notr="true">QLabel { + margin: 10px; +}</string> + </property> + <property name="text"> + <string><html><head/><body><p><img width="300" src=":/icon/assets/logo.png"/></p></body></html></string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QVBoxLayout" name="layoutRight"> + <item> + <layout class="QHBoxLayout" name="layoutSocial"> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="topMargin"> + <number>6</number> + </property> + <property name="rightMargin"> + <number>6</number> + </property> + <item> + <widget class="QPushButton" name="buttonWebsite"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>45</width> + <height>45</height> + </size> + </property> + <property name="styleSheet"> + <string notr="true">QPushButton { + image: url(:/icon/assets/globe.png); + background-color: rgba(0, 0, 0, 0); + border: 0; +}</string> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="buttonDiscord"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>45</width> + <height>45</height> + </size> + </property> + <property name="styleSheet"> + <string notr="true">QPushButton { + image: url(:/icon/assets/discord.png); + background-color: rgba(0, 0, 0, 0); + border: 0; +}</string> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="sizeConstraint"> + <enum>QLayout::SetMinimumSize</enum> + </property> + <item> + <layout class="QVBoxLayout" name="statusLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QLabel" name="statusLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string notr="true">QLabel { + color: white; + margin-left: 5px; + margin-right: 5px; +}</string> + </property> + <property name="text"> + <string>STATUS</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="infoLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="styleSheet"> + <string notr="true">QLabel { + color: white; + margin-left: 5px; + margin-right: 5px; +}</string> + </property> + <property name="text"> + <string>INFO</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignRight|Qt::AlignTrailing</set> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QProgressBar" name="progressBar"> + <property name="styleSheet"> + <string notr="true">QProgressBar +{ + text-align: center; + border: none; + background-color: rgba(0, 0, 0, 140); + color: white; +} + +QProgressBar::chunk +{ + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, + stop:0 rgba(42, 28, 77, 255), + stop:1 rgba(73, 43, 133, 255)); + border: none; +}</string> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="value"> + <number>-1</number> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="invertedAppearance"> + <bool>false</bool> + </property> + <property name="textDirection"> + <enum>QProgressBar::TopToBottom</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QPushButton" name="settingsButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>60</width> + <height>60</height> + </size> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="styleSheet"> + <string notr="true">QPushButton { + padding: 10px; + image: url(:/icon/assets/gear-solid.png); + background-color: rgba(0, 0, 0, 140); + border: none; + color: white; +} + +QPushButton:pressed { + /*background-color: rgba(0, 0, 0, 200);*/ +} +</string> + </property> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="mainButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>175</width> + <height>60</height> + </size> + </property> + <property name="styleSheet"> + <string notr="true">QPushButton { + /*background-color: rgba(0, 0, 0, 140);*/ + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(38, 33, 76, 255), stop:0.0534188 rgba(38, 33, 76, 255), stop:0.0566239 rgba(0, 0, 0, 140)); + border: none; + color: white; +} + +QPushButton:pressed { + /*background-color: rgba(0, 0, 0, 200);*/ + background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(38, 33, 76, 255), stop:0.0534188 rgba(38, 33, 76, 255), stop:0.0566239 rgba(0, 0, 0, 200)); +} +</string> + </property> + <property name="text"> + <string>MAIN_BUTTON</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + <tabstops> + <tabstop>mainButton</tabstop> + <tabstop>settingsButton</tabstop> + <tabstop>buttonDiscord</tabstop> + </tabstops> + <resources> + <include location="assets.qrc"/> + </resources> + <connections/> +</ui> diff --git a/src/qt/settings.cpp b/src/qt/settings.cpp new file mode 100644 index 0000000..507e8c8 --- /dev/null +++ b/src/qt/settings.cpp @@ -0,0 +1,44 @@ +#include <QMessageBox> +#include <iostream> + +#include "workers.hpp" +#include "settings.hpp" +#include "./ui_settings.h" + +Settings::Settings(Worker* pworker, QWidget *parent) + : QDialog(parent) + , ui(new Ui::Settings) +{ + this->worker = pworker; + ui->setupUi(this); + + connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(applySettings())); + connect(ui->verifyButton, SIGNAL(clicked()), this, SLOT(verify())); + connect(this, &Settings::workerOperate, worker, &Worker::doWork); +} + +void Settings::refresh() +{ + ui->serverEdit->setText(this->worker->getRemote()); + + ui->revisionLabel->setText(QString("%1").arg(this->worker->getRevision())); + ui->installLabel->setText(this->worker->getOfDir()); +} + +void Settings::applySettings() +{ + worker->setRemote(ui->serverEdit->text()); + this->hide(); +} + +void Settings::verify() +{ + workerOperate(Worker::TASK_INSTALL); + QMessageBox::information(this, windowTitle(), "Verification Started" ); +} + +Settings::~Settings() +{ + delete ui; +} + diff --git a/src/qt/settings.hpp b/src/qt/settings.hpp new file mode 100644 index 0000000..3718f06 --- /dev/null +++ b/src/qt/settings.hpp @@ -0,0 +1,35 @@ +#ifndef SETTINGS_HPP +#define SETTINGS_HPP + +#include <QWidget> +#include <QDialog> + +#include "workers.hpp" + +QT_BEGIN_NAMESPACE +namespace Ui { class Settings; } +QT_END_NAMESPACE + +class Settings : public QDialog +{ + Q_OBJECT + +public: + Settings(Worker* pworker, QWidget *parent = nullptr); + ~Settings(); + + void refresh(); + +private: + Ui::Settings *ui; + Worker* worker; + +public slots: + void applySettings(); + void verify(); + +signals: + void workerOperate(const Worker::Tasks_t &); + +}; +#endif // SETTINGS_HPP diff --git a/src/qt/settings.ui b/src/qt/settings.ui new file mode 100644 index 0000000..4fde446 --- /dev/null +++ b/src/qt/settings.ui @@ -0,0 +1,215 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Settings</class> + <widget class="QWidget" name="Settings"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>375</width> + <height>259</height> + </rect> + </property> + <property name="windowTitle"> + <string>Settings</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="serverTab"> + <attribute name="title"> + <string>Server</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="serverLabel"> + <property name="text"> + <string>Server</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLineEdit" name="serverEdit"/> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="infoTab"> + <attribute name="title"> + <string>Info</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QHBoxLayout" name="revisionLayout"> + <item> + <widget class="QLabel" name="revisionText"> + <property name="text"> + <string>Current Revision</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="revisionLabel"> + <property name="text"> + <string>CURRENT_REVISION</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="installLayout"> + <item> + <widget class="QLabel" name="installText"> + <property name="text"> + <string>Install Path</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="installLabel"> + <property name="text"> + <string>INSTALL_PATH</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="verifyLabel"> + <property name="text"> + <string>Verify Files</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="verifyButton"> + <property name="text"> + <string>Verify</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + <property name="centerButtons"> + <bool>false</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>Settings</receiver> + <slot>hide()</slot> + <hints> + <hint type="sourcelabel"> + <x>187</x> + <y>235</y> + </hint> + <hint type="destinationlabel"> + <x>187</x> + <y>129</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/qt/workers.cpp b/src/qt/workers.cpp new file mode 100644 index 0000000..3fce706 --- /dev/null +++ b/src/qt/workers.cpp @@ -0,0 +1,299 @@ +#include <iostream> +#include <limits.h> +#include <pthread.h> + +#include "net.h" +#include "steam.h" +#include "toast.h" + +#include "./ui_mainwindow.h" +#include "workers.hpp" + +#define THREAD_COUNT 4 + +struct thread_object_info { + int working; + + QString* infoText; + char* of_dir; + char* remote; + struct revision_t* rev; + size_t index; +}; + +static void* thread_download(void* pinfo) +{ + struct thread_object_info* info = (struct thread_object_info*)pinfo; + if (info) + { + QString* infoText = info->infoText; + char* of_dir = info->of_dir; + char* remote = info->remote; + struct revision_t* rev = info->rev; + size_t i = info->index; + + struct file_info* file = &rev->files[i]; + if (file->type == TYPE_WRITE) + { + *info->infoText = QString("Verifying %1").arg(file->object); + if (verifyFileHash(of_dir, file)) + { + *infoText = QString("Downloading %1").arg(file->object); + downloadObject(of_dir, remote, file); + } + } + } + + info->working = 0; + pthread_exit(0); + + return NULL; +} + +Worker::Worker() +{ + net_init(); + of_dir = NULL; + remote = NULL; +} + +Worker::~Worker() +{ + net_deinit(); + + if (of_dir) + free(of_dir); + + if (remote) + free(remote); +} + +QString Worker::getOfDir() +{ + return QString(of_dir); +} + +QString Worker::getRemote() +{ + return QString(remote); +} + +void Worker::setRemote(QString remotestr) +{ + if (remote) + free(remote); + + remote = strdup(remotestr.toStdString().c_str()); + setLocalRemote(of_dir, remote); +} + +int Worker::getRevision() +{ + return getLocalRevision(of_dir); +} + +int Worker::getRemoteRevision() +{ + return getLatestRemoteRevision(remote); +} + +bool Worker::isOutdated() +{ + return getRemoteRevision() > getRevision(); +} + +void Worker::stop_work() +{ + do_work = false; +} + +int Worker::update_setup(int local_rev, int remote_rev) +{ + if (!of_dir) return 1; + + int retval = 0; + + + struct revision_t* rev = fastFowardRevisions(remote, local_rev, remote_rev); + + if (rev) + { + pthread_t download_threads[THREAD_COUNT] = {0}; + struct thread_object_info thread_info[THREAD_COUNT] = {0, NULL, NULL, NULL, NULL, 0}; + size_t tindex = 0; + QString infoStrings[THREAD_COUNT]; + + for (size_t i = 0; i < rev->file_count && do_work; ++i) + { + while (thread_info[tindex].working) + { + tindex = (tindex+1) % THREAD_COUNT; + } + + pthread_t* thread = &download_threads[tindex]; + struct thread_object_info* info = &thread_info[tindex]; + QString* threadString = &infoStrings[tindex]; + + if (!threadString->isEmpty()) + { + infoText = *threadString; + emit resultReady(RESULT_UPDATE_TEXT); + } + + info->working = 1; + info->infoText = threadString; + info->of_dir = of_dir; + info->remote = remote; + info->rev = rev; + info->index = i; + progress = (int)(((i * 100) + 1) / rev->file_count); + + emit resultReady(RESULT_UPDATE_TEXT); + pthread_create(thread, NULL, thread_download, info); + } + + for (size_t i = 0; i < THREAD_COUNT; ++i) + { + pthread_t* thread = &download_threads[i]; + if (*thread) + pthread_join(*thread, NULL); + } + + progress = 0; + infoText = QString("Processing"); + emit resultReady(RESULT_UPDATE_TEXT); + + for (size_t i = 0; i < rev->file_count && do_work; ++i) + { + struct file_info* file = &rev->files[i]; + if (file->type != TYPE_MKDIR) + continue; + + progress = (int)(((i * 100) + 1) / rev->file_count); + emit resultReady(RESULT_UPDATE_TEXT); + + size_t len = strlen(of_dir) + strlen(OS_PATH_SEP) + strlen(file->path) + 1; + char* buf = (char*)malloc(len); + snprintf(buf, len, "%s%s%s", of_dir, OS_PATH_SEP, file->path); + makeDir(buf); + free(buf); + } + + for (size_t i = 0; i < rev->file_count && do_work; ++i) + { + struct file_info* file = &rev->files[i]; + + progress = (int)(((i * 100) + 1) / rev->file_count); + emit resultReady(RESULT_UPDATE_TEXT); + + switch (file->type) + { + case TYPE_WRITE: + case TYPE_MKDIR: + { + retval += applyObject(of_dir, file); + } + break; + + case TYPE_DELETE: + { + size_t len = strlen(of_dir) + strlen(OS_PATH_SEP) + strlen(file->path) + 1; + char* buf = (char*)malloc(len); + snprintf(buf, len, "%s%s%s", of_dir, OS_PATH_SEP, file->path); + if (isFile(buf)) + retval += remove(buf); + free(buf); + } + break; + } + } + + if (do_work) + { + removeObjects(of_dir); + setLocalRemote(of_dir, remote); + setLocalRevision(of_dir, remote_rev); + } + + progress = 0; + infoText = QString(""); + emit resultReady(RESULT_UPDATE_TEXT); + + freeRevision(rev); + } + + return retval; +} + + +void Worker::doWork(const enum Worker::Tasks_t ¶meter) { + Results_t result = RESULT_NONE; + + + switch (parameter) + { + case TASK_INVALID: + break; + + case TASK_INIT: + result = RESULT_INIT_FAILURE; + of_dir = getOpenFortressDir(); + + if (of_dir) + { + of_dir_len = strlen(of_dir); + remote = getLocalRemote(of_dir); + + if (remote) + { + remote_len = strlen(remote); + result = RESULT_INIT_COMPLETE; + } + else + { + free(of_dir); + of_dir = NULL; + remote = NULL; + } + } + else + { + of_dir = NULL; + remote = NULL; + } + + break; + + case TASK_IS_INSTALLED: + result = getRevision() > -1 ? RESULT_IS_INSTALLED : RESULT_IS_NOT_INSTALLED; + break; + + case TASK_IS_UPTODATE: + result = isOutdated() ? RESULT_IS_OUTDATED : RESULT_IS_UPTODATE; + break; + + case TASK_UNINSTALL: + result = RESULT_UNINSTALL_FAILURE; + //if (direxists) result = svn_delete(mod) ? RESULT_UNINSTALL_FAILURE : RESULT_UNINSTALL_COMPLETE; + break; + + case TASK_INSTALL: + result = update_setup(0, getRemoteRevision()) > 0 ? RESULT_INSTALL_FAILURE : RESULT_INSTALL_COMPLETE; + break; + + case TASK_UPDATE: + result = update_setup(getRevision(), getRemoteRevision()) > 0 ? RESULT_UPDATE_FAILURE : RESULT_UPDATE_COMPLETE; + break; + + case TASK_UPDATE_RUN: + result = update_setup(getRevision(), getRemoteRevision()) > 0 ? RESULT_UPDATE_FAILURE : RESULT_UPDATE_COMPLETE; + break; + + case TASK_RUN: + result = getSteamPID() > -1 ? RESULT_EXIT : RESULT_NO_STEAM; + if (result == RESULT_EXIT) runOpenFortress(); + break; + } + + emit resultReady(result); +}
\ No newline at end of file diff --git a/src/qt/workers.hpp b/src/qt/workers.hpp new file mode 100644 index 0000000..a31d9eb --- /dev/null +++ b/src/qt/workers.hpp @@ -0,0 +1,94 @@ +#ifndef WORKERS_HPP +#define WORKERS_HPP + +#include <QObject> +#include <limits.h> + +QT_BEGIN_NAMESPACE +namespace Ui { class MainWindow; } +QT_END_NAMESPACE + +class Worker : public QObject +{ + Q_OBJECT + +private: + char* of_dir; + size_t of_dir_len; + + char* remote; + size_t remote_len; + + bool do_work = true; + +public: + int progress = -1; + QString infoText; + + Worker(); + ~Worker(); + + QString getOfDir(); + QString getRemote(); + void setRemote(QString); + + int getRevision(); + int getRemoteRevision(); + bool isOutdated(); + + void stop_work(); + + int update_setup(int, int); + + enum Tasks_t + { + TASK_INVALID, + + TASK_IS_INSTALLED, + TASK_IS_UPTODATE, + + TASK_INIT, + TASK_INSTALL, + TASK_UNINSTALL, + TASK_UPDATE, + TASK_UPDATE_RUN, + TASK_RUN, + }; + Q_ENUM(Tasks_t) + + enum Results_t + { + RESULT_NONE, + RESULT_EXIT, + + RESULT_UPDATE_TEXT, + + RESULT_IS_INSTALLED, + RESULT_IS_NOT_INSTALLED, + RESULT_IS_UPTODATE, + RESULT_IS_OUTDATED, + + RESULT_INIT_COMPLETE, + RESULT_INIT_FAILURE, + RESULT_INSTALL_COMPLETE, + RESULT_INSTALL_FAILURE, + RESULT_UNINSTALL_COMPLETE, + RESULT_UNINSTALL_FAILURE, + RESULT_UPDATE_COMPLETE, + RESULT_UPDATE_FAILURE, + RESULT_UPDATE_RUN, + + RESULT_NO_STEAM + }; + Q_ENUM(Results_t) + +public slots: + void doWork(const Tasks_t &); + +signals: + void resultReady(const Results_t &); + +}; + + +#endif
\ No newline at end of file |