From d5d61d18c89af3f6743b7c56774eebdfdcc87b2c Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Mon, 6 Jun 2022 22:03:57 +0200 Subject: Release 0.1.0 --- src/qt/CMakeLists.txt | 34 +++++ src/qt/assets.qrc | 15 ++ src/qt/assets/background.bmp | Bin 0 -> 2073738 bytes src/qt/assets/discord.png | Bin 0 -> 2412 bytes src/qt/assets/game.ico | Bin 0 -> 93062 bytes src/qt/assets/gear-solid.png | Bin 0 -> 2550 bytes src/qt/assets/globe.png | Bin 0 -> 2849 bytes src/qt/assets/logo.png | Bin 0 -> 21482 bytes src/qt/assets/tf2build.ttf | Bin 0 -> 57168 bytes src/qt/assets/version.rc.in | 21 +++ src/qt/main.cpp | 12 ++ src/qt/mainwindow.cpp | 249 ++++++++++++++++++++++++++++++ src/qt/mainwindow.hpp | 50 +++++++ src/qt/mainwindow.ui | 349 +++++++++++++++++++++++++++++++++++++++++++ src/qt/settings.cpp | 44 ++++++ src/qt/settings.hpp | 35 +++++ src/qt/settings.ui | 215 ++++++++++++++++++++++++++ src/qt/workers.cpp | 299 ++++++++++++++++++++++++++++++++++++ src/qt/workers.hpp | 94 ++++++++++++ 19 files changed, 1417 insertions(+) create mode 100644 src/qt/CMakeLists.txt create mode 100644 src/qt/assets.qrc create mode 100644 src/qt/assets/background.bmp create mode 100644 src/qt/assets/discord.png create mode 100644 src/qt/assets/game.ico create mode 100644 src/qt/assets/gear-solid.png create mode 100644 src/qt/assets/globe.png create mode 100644 src/qt/assets/logo.png create mode 100644 src/qt/assets/tf2build.ttf create mode 100644 src/qt/assets/version.rc.in create mode 100644 src/qt/main.cpp create mode 100644 src/qt/mainwindow.cpp create mode 100644 src/qt/mainwindow.hpp create mode 100644 src/qt/mainwindow.ui create mode 100644 src/qt/settings.cpp create mode 100644 src/qt/settings.hpp create mode 100644 src/qt/settings.ui create mode 100644 src/qt/workers.cpp create mode 100644 src/qt/workers.hpp (limited to 'src/qt') 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 @@ + + + assets/background.bmp + + + assets/globe.png + assets/logo.png + assets/gear-solid.png + assets/discord.png + assets/game.ico + + + assets/tf2build.ttf + + diff --git a/src/qt/assets/background.bmp b/src/qt/assets/background.bmp new file mode 100644 index 0000000..37156be Binary files /dev/null and b/src/qt/assets/background.bmp differ diff --git a/src/qt/assets/discord.png b/src/qt/assets/discord.png new file mode 100644 index 0000000..cc52539 Binary files /dev/null and b/src/qt/assets/discord.png differ diff --git a/src/qt/assets/game.ico b/src/qt/assets/game.ico new file mode 100644 index 0000000..7ebf98a Binary files /dev/null and b/src/qt/assets/game.ico differ diff --git a/src/qt/assets/gear-solid.png b/src/qt/assets/gear-solid.png new file mode 100644 index 0000000..8540b00 Binary files /dev/null and b/src/qt/assets/gear-solid.png differ diff --git a/src/qt/assets/globe.png b/src/qt/assets/globe.png new file mode 100644 index 0000000..98374e3 Binary files /dev/null and b/src/qt/assets/globe.png differ diff --git a/src/qt/assets/logo.png b/src/qt/assets/logo.png new file mode 100644 index 0000000..ad04eca Binary files /dev/null and b/src/qt/assets/logo.png differ diff --git a/src/qt/assets/tf2build.ttf b/src/qt/assets/tf2build.ttf new file mode 100644 index 0000000..d59eec9 Binary files /dev/null and b/src/qt/assets/tf2build.ttf differ 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 + +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 +#include +#include +#include +#include + +#include +#include + +#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("Task_t"); + qRegisterMetaType("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 +#include +#include + +#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 @@ + + + MainWindow + + + + 0 + 0 + 736 + 413 + + + + + 736 + 413 + + + + + 736 + 413 + + + + OFQT + + + + :/icon/assets/game.ico:/icon/assets/game.ico + + + + + + + + + + + + + + + + + QLabel { + margin: 10px; +} + + + <html><head/><body><p><img width="300" src=":/icon/assets/logo.png"/></p></body></html> + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 6 + + + 6 + + + 6 + + + + + + 0 + 0 + + + + + 45 + 45 + + + + QPushButton { + image: url(:/icon/assets/globe.png); + background-color: rgba(0, 0, 0, 0); + border: 0; +} + + + + + + + + + + + 0 + 0 + + + + + 45 + 45 + + + + QPushButton { + image: url(:/icon/assets/discord.png); + background-color: rgba(0, 0, 0, 0); + border: 0; +} + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + 0 + + + QLayout::SetMinimumSize + + + + + + + + + + 0 + 0 + + + + QLabel { + color: white; + margin-left: 5px; + margin-right: 5px; +} + + + STATUS + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + 0 + 0 + + + + QLabel { + color: white; + margin-left: 5px; + margin-right: 5px; +} + + + INFO + + + Qt::AlignBottom|Qt::AlignRight|Qt::AlignTrailing + + + + + + + + + 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; +} + + + 0 + + + -1 + + + Qt::AlignCenter + + + false + + + QProgressBar::TopToBottom + + + + + + + + + + 0 + 0 + + + + + 60 + 60 + + + + false + + + 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);*/ +} + + + + + + + + + + + + 0 + 0 + + + + + 175 + 60 + + + + 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)); +} + + + + MAIN_BUTTON + + + + + + + + + + mainButton + settingsButton + buttonDiscord + + + + + + 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 +#include + +#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 +#include + +#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 @@ + + + Settings + + + + 0 + 0 + 375 + 259 + + + + Settings + + + + + + 0 + + + + Server + + + + + + + + Server + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Info + + + + + + + + Current Revision + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + CURRENT_REVISION + + + + + + + + + + + Install Path + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + INSTALL_PATH + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Verify Files + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Verify + + + + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + false + + + + + + + + + buttonBox + rejected() + Settings + hide() + + + 187 + 235 + + + 187 + 129 + + + + + 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 +#include +#include + +#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 +#include + +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 -- cgit v1.2.3