瀏覽代碼

Implemented checkForUpdates and download functions for each patchset

Ivan Arkhipov 5 年之前
父節點
當前提交
ff2d7886c1

+ 367 - 10
src/Legacy/models/patch/graphicspatch.cpp

@@ -2,39 +2,396 @@
 #include "LotroDat/LotroDat.h"
 #include "LotroDat/Database.h"
 #include "models/lotrodatmanagerobserver.h"
+#include "models/lotrodatmanager.h"
 
 #include <QUrlQuery>
 #include <QSet>
-#include <QThread>
 
 GraphicsPatch::GraphicsPatch(LotroDatManager *mgr, QObject *parent) : Patch("GraphicsPatch", mgr, parent)
 {
+    connect(lotro_mgr_, &LotroDatManager::operationStarted, this, &GraphicsPatch::onLotroDatManagerOperationStarted);
+    connect(lotro_mgr_, &LotroDatManager::operationFinished, this, &GraphicsPatch::onLotroDatManagerOperationFinished);
+    connect(lotro_mgr_->getObserver(), &LotroDatManagerObserver::statusChanged, this, &GraphicsPatch::onLotroDatManagerStatusChanged);
 }
 
 void GraphicsPatch::checkForUpdates()
 {
     emit operationStarted("checkForUpdates", this);
-    QThread::sleep(1);
-    emit operationFinished("checkForUpdates",  this, true);
+    QUrlQuery query; // query for building GET-request aka patch-version
+
+    foreach (QString db_name, databases_names) {
+        query.addQueryItem(db_name, "100");
+    }
+
+    QUrl target_url;
+    target_url.setUrl(Settings::getValue("Network/patch_updates_url").toString());
+    target_url.setQuery(query);
+
+    QByteArray target_array;
+    Downloader downloader;
+    downloader.setUrl(target_url);
+    downloader.targetBytearray = &target_array;
+    downloader.start();
+    downloader.waitForDownloaded();
+
+    if (target_array.isEmpty()) {
+        qDebug() << __FUNCTION__ << "Cannot download, target_array is empty!";
+        emit errorOccured("checkForUpdates", this, "QueryDownloadFailed");
+        emit operationFinished("checkForUpdates", this, false);
+        return;
+    }
+
+    QStringList patch_info = QString(target_array).split('|');
+    if (patch_info.size() != databases_names.size()) {
+        qDebug() << __FUNCTION__ << "Incorrect patches number! Data: " << patch_info;
+        emit errorOccured("checkForUpdates", this, "IncorrectQueryResult");
+        emit operationFinished("checkForUpdates", this, false);
+        return;
+    }
+
+    for (int i = 0; i < databases_names.size(); ++i) {
+        QStringList patch_data = patch_info[i].split(":::");
+        if (patch_data.size() != 3) {
+            qDebug() << __FUNCTION__ << "Incorrect patch entry size! Entry: " << patch_data;
+            emit errorOccured("checkForUpdates", this, "IncorrectDbInfo");
+            emit operationFinished("checkForUpdates", this, false);
+            return;
+        }
+
+        QString patch_filename = Settings::getValue("General/PatchDownloadDir").toString() + "/" + QUrl(patch_data[0]).fileName();
+
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/url", patch_data[0]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/hashsum", patch_data[1]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/datetime", patch_data[2]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/path", patch_filename);
+    }
+    emit operationFinished("checkForUpdates", this, true);
 }
 
 void GraphicsPatch::download()
 {
+    if (elapsed_patches_to_download_ != 0) {
+        qDebug() << "Trying to start download of patch set " << patch_name_ << " while download is still active!";
+        return;
+    }
+
     emit operationStarted("download", this);
-    QThread::sleep(5);
-    emit operationFinished("download", this, true);
+
+    bool download_started = false;
+
+    foreach (QString db_name, databases_names) {
+        QString settings_prefix = "PatchDatabases/" + db_name;
+
+        QString target_filename = QApplication::applicationDirPath() + "/" + Settings::getValue(settings_prefix + "/path").toString();
+        qDebug() << "GraphicsPatch: Checking if there's no need to download file " << target_filename;
+
+        if (FileSystem::fileHash(target_filename) == Settings::getValue(settings_prefix + "/hashsum").toString()) {
+            qDebug() << "GraphicsPatch: file " << target_filename << " is fresh, no need to download";
+            continue;
+        }
+
+        FileSystem::createFilePath(target_filename);
+        QFile* target_file = new QFile(target_filename);
+        if (!target_file->open(QIODevice::ReadWrite | QIODevice::Truncate)) {
+            emit errorOccured("download", this, "CantOpenDbFile");
+            continue;
+        }
+
+        qDebug() << "GraphicsPatch: beginning download of file " << target_filename;
+        download_started = true;
+
+        ++elapsed_patches_to_download_;
+        Downloader* downloader = new Downloader();
+        downloader->setUrl(Settings::getValue(settings_prefix + "/url").toUrl());
+        downloader->targetFile = target_file;
+        connect(downloader, &Downloader::progressChanged, this, &GraphicsPatch::onDownloaderProgressChanged);
+        connect(downloader, &Downloader::downloadFinished, this, &GraphicsPatch::onDownloaderFinished);
+        downloaders_.insert(downloader);
+        downloader->start();
+    }
+
+    if (!download_started) {
+        emit operationFinished("download", this, true);
+    } // otherwise will be emitted on the last onDownloaderFinished signal
 }
 
 void GraphicsPatch::install()
 {
+    if (elapsed_databases_to_install_ > 0) {
+        emit errorOccured("install", this, "Установка набора графических патчей ещё не закончена");
+        return;
+    }
+
     emit operationStarted("install", this);
-    QThread::sleep(5);
-    emit operationFinished("install", this, true);
+
+    status_.process = CurrentProcess::E_INSTALL;
+    status_.percent = 0;
+    status_.total_parts = 3;
+    status_.current_part = 0;
+
+    installLoadscreens();
+
+    status_.process = CurrentProcess::E_AWAITING_INSTALL;
+
+    foreach (QString db_name, QStringList({"image", "texture"})) {
+        ++elapsed_databases_to_install_;
+        QMetaObject::invokeMethod(lotro_mgr_,
+                                  "installPatch",
+                                  Qt::QueuedConnection,
+                                  Q_ARG(QString, "GraphicsPatch_" + db_name),
+                                  Q_ARG(QString, Settings::getValue("PatchDatabases/" + db_name + "/path").toString())
+                                  );
+    }
+
 }
 
 void GraphicsPatch::activate()
 {
-    emit operationStarted("activate", this);
-    QThread::sleep(5);
-    emit operationFinished("activate", this, true);
+    if (Settings::getValue("Components/loadscreens").toBool()) {
+        enableLoadscreens();
+    } else {
+        disableLoadscreens();
+    }
+
+    if (Settings::getValue("Components/maps").toBool()) {
+        QMetaObject::invokeMethod(lotro_mgr_,
+                                  "enableCategory",
+                                  Qt::QueuedConnection,
+                                  Q_ARG(QString, "GraphicsPatch_maps"),
+                                  Q_ARG(LotroDatManager::Category, LotroDatManager::Category::E_MAPS_COMMON)
+                                  );
+    } else {
+        QMetaObject::invokeMethod(lotro_mgr_,
+                                  "disableCategory",
+                                  Q_ARG(QString, "GraphicsPatch_maps"),
+                                  Q_ARG(LotroDatManager::Category, LotroDatManager::Category::E_MAPS_COMMON)
+                                  );
+    }
+
+    if (Settings::getValue("Components/textures").toBool()) {
+        QMetaObject::invokeMethod(lotro_mgr_,
+                                  "enableCategory",
+                                  Q_ARG(QString, "GraphicsPatch_maps"),
+                                  Q_ARG(LotroDatManager::Category, LotroDatManager::Category::E_TEXTURES_COMMON)
+                                  );
+    } else {
+        QMetaObject::invokeMethod(lotro_mgr_,
+                                  "disableCategory",
+                                  Q_ARG(QString, "GraphicsPatch_maps"),
+                                  Q_ARG(LotroDatManager::Category, LotroDatManager::Category::E_TEXTURES_COMMON)
+                                  );
+    }
+}
+
+void GraphicsPatch::onDownloaderProgressChanged(Downloader *, Downloader::Status)
+{
+    Downloader::Status all_downloads_status;
+    foreach (Downloader* downloader, downloaders_) {
+        all_downloads_status = all_downloads_status + downloader->getDownloadStatus();
+    }
+
+    emit downloadStatusChanged(this, all_downloads_status);
+}
+
+void GraphicsPatch::onDownloaderFinished(Downloader *ptr)
+{
+    Downloader::Status all_downloads_status;
+    foreach (Downloader* downloader, downloaders_) {
+        all_downloads_status = all_downloads_status + downloader->getDownloadStatus();
+    }
+
+    ptr->targetFile->close();
+    ptr->targetFile->deleteLater();
+
+    if (elapsed_patches_to_download_ == 1) {
+        foreach (Downloader* downloader, downloaders_) {
+            downloader->deleteLater();
+        }
+        downloaders_.clear();
+
+        emit downloadStatusChanged(this, all_downloads_status);
+        emit operationFinished("download", this, true);
+    }
+
+    --elapsed_patches_to_download_;
+}
+
+void GraphicsPatch::onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful)
+{
+    if (operation_name == "installPatch") {
+        if (!args[0].toString().contains("GraphicsPatch_")) {
+            return;
+        }
+
+        status_.process = CurrentProcess::E_AWAITING_INSTALL;
+        status_.percent = 100;
+        emit installStatusChanged(this, status_);
+
+        --elapsed_databases_to_install_;
+
+        if (!successful) {
+            emit errorOccured("install", this, "Database " + args[0].toString() + " (" + args[1].toString() + ") was not installed due to Legacy core error.");
+        }
+
+        if (elapsed_databases_to_install_ == 0) {
+            status_.process = CurrentProcess::E_FINISHED;
+            emit operationFinished("install", this, true);
+        }
+    }
+
+    if (operation_name == "enableCategory" || operation_name == "disableCategory") {
+        if (!args[0].toString().contains("GraphicsPatch_")) {
+            return;
+        }
+
+        status_.process = CurrentProcess::E_AWAITING_APPLY;
+        status_.percent = 100;
+        emit installStatusChanged(this, status_);
+
+        --elapsed_categories_to_activate_;
+        if (!successful) {
+            emit errorOccured("activate", this, "Error in patch " + args[0].toString() + ": activating category " + QString::number(args[1].toInt()) + " failed.");
+        }
+
+        if (elapsed_categories_to_activate_ == 0) {
+            status_.process = CurrentProcess::E_FINISHED;
+            emit operationFinished("activate", this, true);
+        }
+    }
+}
+
+void GraphicsPatch::onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args)
+{
+    if (operation_name == "installPatch") {
+        if (!args[0].toString().contains("GraphicsPatch_")) {
+            return;
+        }
+        status_.process = CurrentProcess::E_INSTALL;
+        status_.current_part++;
+        status_.percent = 0;
+        emit installStatusChanged(this, status_);
+    }
+
+    if (operation_name == "enableCategory" || operation_name == "disableCategory") {
+        if (!args[0].toString().contains("GraphicsPatch_")) {
+            return;
+        }
+        status_.process = CurrentProcess::E_APPLY;
+        status_.current_part++;
+        status_.percent = 0;
+        emit installStatusChanged(this, status_);
+    }
+}
+
+void GraphicsPatch::onLotroDatManagerStatusChanged(LotroDatManager::Status status)
+{
+    if (status_.process != CurrentProcess::E_INSTALL || status_.process != CurrentProcess::E_APPLY) {
+        return;
+    }
+
+    status_.percent = status.percent;
+    emit installStatusChanged(this, status_);
+}
+
+void GraphicsPatch::installLoadscreens()
+{
+    status_.current_part++;
+    status_.process = CurrentProcess::E_INSTALL;
+    status_.percent = 0;
+    emit installStatusChanged(this, status_);
+
+    QString locale_prefix = Settings::getValue("Lotro/original_locale").toString();
+
+    QStringList filenames = {
+        locale_prefix == "English" ? "lotro_ad_pregame.jpg" : "lotro_ad_pregame_" + locale_prefix + ".jpg",
+        "lotro_generic_teleport_screen_01.jpg",
+        "lotro_generic_teleport_screen_02.jpg",
+        "lotro_generic_teleport_screen_03.jpg",
+        "lotro_generic_teleport_screen_04.jpg",
+        "lotro_generic_teleport_screen_05.jpg",
+        "lotro_generic_teleport_screen_06.jpg",
+        "lotro_generic_teleport_screen_07.jpg",
+        "lotro_generic_teleport_screen_08.jpg",
+        "lotro_generic_teleport_screen_09.jpg",
+        "lotro_generic_teleport_screen_10.jpg"
+    };
+
+    LOTRO_DAT::Database database;
+    if (!database.InitDatabase(Settings::getValue("PatchDatabases/Loadscreen/path").toString().toStdString())) {
+        emit errorOccured("install", this, "installLoadscreensCannotInitDb");
+        return;
+    }
+
+    LOTRO_DAT::SubfileData data;
+
+    QString logo_path = Settings::getValue("Lotro/game_path").toString() + "/raw/" + (locale_prefix == "English" ? "en" : locale_prefix) + "/logo/";
+
+    for (size_t i = 0; i < qMin(size_t(filenames.size()), database.CountRows()); ++i) {
+        QFile::remove(logo_path + filenames[i] + "_ru");
+        if (!data.binary_data.WriteToFile((logo_path + filenames[i] + "_ru").toStdString())) {
+            emit errorOccured("install", this, "Не могу осуществить запись в файл " + logo_path + filenames[i]);
+        }
+        status_.percent = double(i) * 50.0 / (qMin(double(filenames.size()), double(database.CountRows())));
+        emit installStatusChanged(this, status_);
+    }
+
+
+    for (int i = 0; i < filenames.size(); ++i) {
+        QFile::copy(logo_path + filenames[i], logo_path + filenames[i] + "_orig");
+        status_.percent = 50 + double(i) * 50.0 / double(filenames.size());
+        emit installStatusChanged(this, status_);
+    }
+
+    status_.percent = 100;
+    emit installStatusChanged(this, status_);
+}
+
+void GraphicsPatch::enableLoadscreens()
+{
+    QString locale_prefix = Settings::getValue("Lotro/original_locale").toString();
+    QString logo_path = Settings::getValue("Lotro/game_path").toString() + "/raw/" + (locale_prefix == "English" ? "en" : locale_prefix) + "/logo/";
+
+    QStringList filenames = {
+        locale_prefix == "English" ? "lotro_ad_pregame.jpg" : "lotro_ad_pregame_" + locale_prefix + ".jpg",
+        "lotro_generic_teleport_screen_01.jpg",
+        "lotro_generic_teleport_screen_02.jpg",
+        "lotro_generic_teleport_screen_03.jpg",
+        "lotro_generic_teleport_screen_04.jpg",
+        "lotro_generic_teleport_screen_05.jpg",
+        "lotro_generic_teleport_screen_06.jpg",
+        "lotro_generic_teleport_screen_07.jpg",
+        "lotro_generic_teleport_screen_08.jpg",
+        "lotro_generic_teleport_screen_09.jpg",
+        "lotro_generic_teleport_screen_10.jpg"
+    };
+
+    for (int i = 0; i < filenames.size(); ++i) {
+        QFile::remove(logo_path + filenames[i]);
+        QFile::copy(logo_path + filenames[i] + "_ru", logo_path + filenames[i]);
+    }
+}
+
+void GraphicsPatch::disableLoadscreens()
+{
+    QString locale_prefix = Settings::getValue("Lotro/original_locale").toString();
+    QString logo_path = Settings::getValue("Lotro/game_path").toString() + "/raw/" + (locale_prefix == "English" ? "en" : locale_prefix) + "/logo/";
+
+    QStringList filenames = {
+        locale_prefix == "English" ? "lotro_ad_pregame.jpg" : "lotro_ad_pregame_" + locale_prefix + ".jpg",
+        "lotro_generic_teleport_screen_01.jpg",
+        "lotro_generic_teleport_screen_02.jpg",
+        "lotro_generic_teleport_screen_03.jpg",
+        "lotro_generic_teleport_screen_04.jpg",
+        "lotro_generic_teleport_screen_05.jpg",
+        "lotro_generic_teleport_screen_06.jpg",
+        "lotro_generic_teleport_screen_07.jpg",
+        "lotro_generic_teleport_screen_08.jpg",
+        "lotro_generic_teleport_screen_09.jpg",
+        "lotro_generic_teleport_screen_10.jpg"
+    };
+
+    for (int i = 0; i < filenames.size(); ++i) {
+        QFile::remove(logo_path + filenames[i]);
+        QFile::copy(logo_path + filenames[i] + "_orig", logo_path + filenames[i]);
+    }
 }

+ 11 - 11
src/Legacy/models/patch/graphicspatch.h

@@ -20,11 +20,11 @@ public slots:
     virtual void activate() override;
 
 private slots:
-//    void onDownloaderProgressChanged(Downloader* ptr, Downloader::Status status);
-//    void onDownloaderFinished(Downloader* ptr);
-//    void onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful);
-//    void onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args);
-//    void onLotroDatManagerStatusChanged(LotroDatManager::Status status);
+    void onDownloaderProgressChanged(Downloader* ptr, Downloader::Status status);
+    void onDownloaderFinished(Downloader* ptr);
+    void onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful);
+    void onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args);
+    void onLotroDatManagerStatusChanged(LotroDatManager::Status status);
 
 private:
     const QStringList databases_names = {
@@ -33,13 +33,13 @@ private:
         "loadscreen",
     };
 
-//    void installLoadscreens();
-//    void enableLoadscreens();
-//    void disableLoadscreens();
+    void installLoadscreens();
+    void enableLoadscreens();
+    void disableLoadscreens();
 
-//    quint8 elapsed_patches_to_download_ = 0; // for download process
-//    quint8 elapsed_databases_to_install_ = 0; // for install process
-//    quint8 elapsed_categories_to_activate_ = 0; // for activate/deactivate process
+    quint8 elapsed_patches_to_download_ = 0; // for download process
+    quint8 elapsed_databases_to_install_ = 0; // for install process
+    quint8 elapsed_categories_to_activate_ = 0; // for activate/deactivate process
 };
 
 #endif // IMAGESPATCH_H

+ 2 - 2
src/Legacy/models/patch/patch.h

@@ -62,12 +62,12 @@ signals: // each signal brings with it pointer to this class
     void downloadStatusChanged(Patch* patch, Downloader::Status status);
     void installStatusChanged(Patch* patch, InstallationStatus status);
 
-private:
+protected:
     bool needDownloadDatabase(QString db_name);
 
     static bool isDatabaseDownloadEnabled(QString db_name); // Checks if this database needs to be downloaded (comparing with user parameters)
 
-private:
+protected:
     LotroDatManager* lotro_mgr_;
     QString patch_name_;
     QSet<Downloader*> downloaders_;

+ 242 - 8
src/Legacy/models/patch/soundspatch.cpp

@@ -9,32 +9,266 @@
 
 SoundsPatch::SoundsPatch(LotroDatManager *mgr, QObject *parent) : Patch("SoundsPatch", mgr, parent)
 {
+    connect(lotro_mgr_, &LotroDatManager::operationStarted, this, &SoundsPatch::onLotroDatManagerOperationStarted);
+    connect(lotro_mgr_, &LotroDatManager::operationFinished, this, &SoundsPatch::onLotroDatManagerOperationFinished);
+    connect(lotro_mgr_->getObserver(), &LotroDatManagerObserver::statusChanged, this, &SoundsPatch::onLotroDatManagerStatusChanged);
 }
 
 void SoundsPatch::checkForUpdates()
 {
     emit operationStarted("checkForUpdates", this);
-    QThread::sleep(1);
+    QUrlQuery query; // query for building GET-request aka patch-version
+
+    foreach (QString db_name, databases_names) {
+        query.addQueryItem(db_name, "100");
+    }
+
+    QUrl target_url;
+    target_url.setUrl(Settings::getValue("Network/patch_updates_url").toString());
+    target_url.setQuery(query);
+
+    QByteArray target_array;
+    Downloader downloader;
+    downloader.setUrl(target_url);
+    downloader.targetBytearray = &target_array;
+    downloader.start();
+    downloader.waitForDownloaded();
+
+    if (target_array.isEmpty()) {
+        qDebug() << __FUNCTION__ << "Cannot download, target_array is empty!";
+        emit errorOccured("checkForUpdates", this, "QueryDownloadFailed");
+        emit operationFinished("checkForUpdates", this, false);
+        return;
+    }
+
+    QStringList patch_info = QString(target_array).split("|");
+    if (patch_info.size() != databases_names.size()) {
+        qDebug() << __FUNCTION__ << "Incorrect patches number! Data: " << patch_info;
+        emit errorOccured("checkForUpdates", this, "IncorrectQueryResult");
+        emit operationFinished("checkForUpdates", this, false);
+        return;
+    }
+
+    for (int i = 0; i < databases_names.size(); ++i) {
+        QStringList patch_data = patch_info[i].split(":::");
+        if (patch_data.size() != 3) {
+            qDebug() << __FUNCTION__ << "Incorrect patch entry size! Entry: " << patch_data;
+            emit errorOccured("checkForUpdates", this, "IncorrectDbInfo");
+            emit operationFinished("checkForUpdates", this, false);
+            return;
+        }
+
+        QString patch_filename = Settings::getValue("General/PatchDownloadDir").toString() + "/" + QUrl(patch_data[0]).fileName();
+
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/url", patch_data[0]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/hashsum", patch_data[1]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/datetime", patch_data[2]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/path", patch_filename);
+    }
+
     emit operationFinished("checkForUpdates",  this, true);
 }
 
 void SoundsPatch::download()
 {
+    if (elapsed_patches_to_download_ != 0) {
+        qDebug() << "Trying to start download of patch set " << patch_name_ << " while download is still active!";
+        return;
+    }
+
     emit operationStarted("download", this);
-    QThread::sleep(5);
-    emit operationFinished("download", this, true);
+
+    bool download_started = false;
+
+    foreach (QString db_name, databases_names) {
+        QString settings_prefix = "PatchDatabases/" + db_name;
+
+        QString target_filename = QApplication::applicationDirPath() + "/" + Settings::getValue(settings_prefix + "/path").toString();
+        qDebug() << "SoundsPatch: Checking if there's no need to download file " << target_filename;
+
+        if (FileSystem::fileHash(target_filename) == Settings::getValue(settings_prefix + "/hashsum").toString()) {
+            qDebug() << "SoundsPatch: file " << target_filename << " is fresh, no need to download";
+            continue;
+        }
+
+        FileSystem::createFilePath(target_filename);
+        QFile* target_file = new QFile(target_filename);
+        if (!target_file->open(QIODevice::ReadWrite | QIODevice::Truncate)) {
+            emit errorOccured("download", this, "CantOpenDbFile");
+            continue;
+        }
+
+        qDebug() << "GraphicsPatch: beginning download of file " << target_filename;
+        download_started = true;
+
+        ++elapsed_patches_to_download_;
+        Downloader* downloader = new Downloader();
+        downloader->setUrl(Settings::getValue(settings_prefix + "/url").toUrl());
+        downloader->targetFile = target_file;
+        connect(downloader, &Downloader::progressChanged, this, &SoundsPatch::onDownloaderProgressChanged);
+        connect(downloader, &Downloader::downloadFinished, this, &SoundsPatch::onDownloaderFinished);
+        downloaders_.insert(downloader);
+        downloader->start();
+    }
+
+    if (!download_started) {
+        emit operationFinished("download", this, true);
+    } // otherwise will be emitted on the last onDownloaderFinished signal
 }
 
 void SoundsPatch::install()
 {
+    if (elapsed_databases_to_install_ > 0) {
+        emit errorOccured("install", this, "Установка набора графических патчей ещё не закончена");
+        return;
+    }
+
     emit operationStarted("install", this);
-    QThread::sleep(5);
-    emit operationFinished("install", this, true);
+
+    status_.process = CurrentProcess::E_AWAITING_INSTALL;
+    status_.percent = 0;
+    status_.total_parts = 1;
+    status_.current_part = 0;
+
+    emit installStatusChanged(this, status_);
+
+    foreach (QString db_name, QStringList({"sound"})) {
+        ++elapsed_databases_to_install_;
+        QMetaObject::invokeMethod(lotro_mgr_,
+                                  "installPatch",
+                                  Qt::QueuedConnection,
+                                  Q_ARG(QString, "SoundsPatch_" + db_name),
+                                  Q_ARG(QString, Settings::getValue("PatchDatabases/" + db_name + "/path").toString())
+                                  );
+    }
+
 }
 
 void SoundsPatch::activate()
 {
-    emit operationStarted("activate", this);
-    QThread::sleep(5);
-    emit operationFinished("activate", this, true);
+    if (Settings::getValue("Components/sounds").toBool()) {
+        QMetaObject::invokeMethod(lotro_mgr_,
+                                  "enableCategory",
+                                  Qt::QueuedConnection,
+                                  Q_ARG(QString, "SoundsPatch_sounds"),
+                                  Q_ARG(LotroDatManager::Category, LotroDatManager::Category::E_AUDIOS_COMMON)
+                                  );
+    } else {
+        QMetaObject::invokeMethod(lotro_mgr_,
+                                  "disableCategory",
+                                  Qt::QueuedConnection,
+                                  Q_ARG(QString, "SoundsPatch_sounds"),
+                                  Q_ARG(LotroDatManager::Category, LotroDatManager::Category::E_AUDIOS_COMMON)
+                                  );
+    }
+}
+
+void SoundsPatch::onDownloaderProgressChanged(Downloader *, Downloader::Status)
+{
+    Downloader::Status all_downloads_status;
+    foreach (Downloader* downloader, downloaders_) {
+        all_downloads_status = all_downloads_status + downloader->getDownloadStatus();
+    }
+
+    emit downloadStatusChanged(this, all_downloads_status);
+}
+
+void SoundsPatch::onDownloaderFinished(Downloader *ptr)
+{
+    Downloader::Status all_downloads_status;
+    foreach (Downloader* downloader, downloaders_) {
+        all_downloads_status = all_downloads_status + downloader->getDownloadStatus();
+    }
+
+    ptr->targetFile->close();
+    ptr->targetFile->deleteLater();
+
+    if (elapsed_patches_to_download_ == 1) {
+        foreach (Downloader* downloader, downloaders_) {
+            downloader->deleteLater();
+        }
+        downloaders_.clear();
+
+        emit downloadStatusChanged(this, all_downloads_status);
+        emit operationFinished("download", this, true);
+    }
+
+    --elapsed_patches_to_download_;
+}
+
+void SoundsPatch::onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful)
+{
+    if (operation_name == "installPatch") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+
+        status_.process = CurrentProcess::E_AWAITING_INSTALL;
+        status_.percent = 100;
+        emit installStatusChanged(this, status_);
+
+        --elapsed_databases_to_install_;
+
+        if (!successful) {
+            emit errorOccured("install", this, "Database " + args[0].toString() + " (" + args[1].toString() + ") was not installed due to Legacy core error.");
+        }
+
+        if (elapsed_databases_to_install_ == 0) {
+            status_.process = CurrentProcess::E_FINISHED;
+            emit operationFinished("install", this, true);
+        }
+    }
+
+    if (operation_name == "enableCategory" || operation_name == "disableCategory") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+
+        status_.process = CurrentProcess::E_AWAITING_APPLY;
+        status_.percent = 100;
+        emit installStatusChanged(this, status_);
+
+        --elapsed_categories_to_activate_;
+        if (!successful) {
+            emit errorOccured("activate", this, "Error in patch " + args[0].toString() + ": activating category " + QString::number(args[1].toInt()) + " failed.");
+        }
+
+        if (elapsed_categories_to_activate_ == 0) {
+            status_.process = CurrentProcess::E_FINISHED;
+            emit operationFinished("activate", this, true);
+        }
+    }
+}
+
+void SoundsPatch::onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args)
+{
+    if (operation_name == "installPatch") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+        status_.process = CurrentProcess::E_INSTALL;
+        status_.current_part++;
+        status_.percent = 0;
+        emit installStatusChanged(this, status_);
+    }
+
+    if (operation_name == "enableCategory" || operation_name == "disableCategory") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+        status_.process = CurrentProcess::E_APPLY;
+        status_.current_part++;
+        status_.percent = 0;
+        emit installStatusChanged(this, status_);
+    }
+}
+
+void SoundsPatch::onLotroDatManagerStatusChanged(LotroDatManager::Status status)
+{
+    if (status_.process != CurrentProcess::E_INSTALL || status_.process != CurrentProcess::E_APPLY) {
+        return;
+    }
+
+    status_.percent = status.percent;
+    emit installStatusChanged(this, status_);
 }

+ 9 - 14
src/Legacy/models/patch/soundspatch.h

@@ -19,26 +19,21 @@ public slots:
     virtual void activate() override;
 
 private slots:
-//    void onDownloaderProgressChanged(Downloader* ptr, Downloader::Status status);
-//    void onDownloaderFinished(Downloader* ptr);
-//    void onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful);
-//    void onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args);
-//    void onLotroDatManagerStatusChanged(LotroDatManager::Status status);
+    void onDownloaderProgressChanged(Downloader* ptr, Downloader::Status status);
+    void onDownloaderFinished(Downloader* ptr);
+    void onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful);
+    void onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args);
+    void onLotroDatManagerStatusChanged(LotroDatManager::Status status);
 
 private:
     const QStringList databases_names = {
-        "image",
-        "texture",
-        "loadscreen",
+        "sound",
     };
 
-//    void installLoadscreens();
-//    void enableLoadscreens();
-//    void disableLoadscreens();
+    quint8 elapsed_patches_to_download_ = 0; // for download process
+    quint8 elapsed_databases_to_install_ = 0; // for install process
+    quint8 elapsed_categories_to_activate_ = 0; // for activate/deactivate process
 
-//    quint8 elapsed_patches_to_download_ = 0; // for download process
-//    quint8 elapsed_databases_to_install_ = 0; // for install process
-//    quint8 elapsed_categories_to_activate_ = 0; // for activate/deactivate process
 };
 
 #endif // SOUNDSPATCH_H

+ 207 - 3
src/Legacy/models/patch/textspatch.cpp

@@ -9,20 +9,111 @@
 
 TextsPatch::TextsPatch(LotroDatManager *mgr, QObject *parent) : Patch("TextsPatch", mgr, parent)
 {
+    connect(lotro_mgr_, &LotroDatManager::operationStarted, this, &TextsPatch::onLotroDatManagerOperationStarted);
+    connect(lotro_mgr_, &LotroDatManager::operationFinished, this, &TextsPatch::onLotroDatManagerOperationFinished);
+    connect(lotro_mgr_->getObserver(), &LotroDatManagerObserver::statusChanged, this, &TextsPatch::onLotroDatManagerStatusChanged);
 }
 
 void TextsPatch::checkForUpdates()
 {
     emit operationStarted("checkForUpdates", this);
-    QThread::sleep(1);
+    QUrlQuery query; // query for building GET-request aka patch-version
+
+    foreach (QString db_name, databases_names) {
+        query.addQueryItem(db_name, "100");
+    }
+
+    QUrl target_url;
+    target_url.setUrl(Settings::getValue("Network/patch_updates_url").toString());
+    target_url.setQuery(query);
+
+    QByteArray target_array;
+    Downloader downloader;
+    downloader.setUrl(target_url);
+    downloader.targetBytearray = &target_array;
+    downloader.start();
+    downloader.waitForDownloaded();
+
+    if (target_array.isEmpty()) {
+        qDebug() << __FUNCTION__ << "Cannot download, target_array is empty!";
+        emit errorOccured("checkForUpdates", this, "QueryDownloadFailed");
+        emit operationFinished("checkForUpdates", this, false);
+        return;
+    }
+
+    QStringList patch_info = QString(target_array).split("|");
+    if (patch_info.size() != databases_names.size()) {
+        qDebug() << __FUNCTION__ << "Incorrect patches number! Data: " << patch_info;
+        emit errorOccured("checkForUpdates", this, "IncorrectQueryResult");
+        emit operationFinished("checkForUpdates", this, false);
+        return;
+    }
+
+    for (int i = 0; i < databases_names.size(); ++i) {
+        QStringList patch_data = patch_info[i].split(":::");
+        if (patch_data.size() != 3) {
+            qDebug() << __FUNCTION__ << "Incorrect patch entry size! Entry: " << patch_data;
+            emit errorOccured("checkForUpdates", this, "IncorrectDbInfo");
+            emit operationFinished("checkForUpdates", this, false);
+            return;
+        }
+
+        QString patch_filename = Settings::getValue("General/PatchDownloadDir").toString() + "/" + QUrl(patch_data[0]).fileName();
+
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/url", patch_data[0]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/hashsum", patch_data[1]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/datetime", patch_data[2]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/path", patch_filename);
+    }
+
     emit operationFinished("checkForUpdates",  this, true);
 }
 
 void TextsPatch::download()
 {
+    if (elapsed_patches_to_download_ != 0) {
+        qDebug() << "Trying to start download of patch set " << patch_name_ << " while download is still active!";
+        return;
+    }
+
     emit operationStarted("download", this);
-    QThread::sleep(5);
-    emit operationFinished("download", this, true);
+
+    bool download_started = false;
+
+    foreach (QString db_name, databases_names) {
+        QString settings_prefix = "PatchDatabases/" + db_name;
+
+        QString target_filename = QApplication::applicationDirPath() + "/" + Settings::getValue(settings_prefix + "/path").toString();
+        qDebug() << "TextsPatch: Checking if there's no need to download file " << target_filename;
+
+        if (FileSystem::fileHash(target_filename) == Settings::getValue(settings_prefix + "/hashsum").toString()) {
+            qDebug() << "TextsPatch: file " << target_filename << " is fresh, no need to download";
+            continue;
+        }
+
+        FileSystem::createFilePath(target_filename);
+        QFile* target_file = new QFile(target_filename);
+        if (!target_file->open(QIODevice::ReadWrite | QIODevice::Truncate)) {
+            emit errorOccured("download", this, "CantOpenDbFile");
+            continue;
+        }
+
+        qDebug() << "TextsPatch: beginning download of file " << target_filename;
+        download_started = true;
+
+        ++elapsed_patches_to_download_;
+        Downloader* downloader = new Downloader();
+        downloader->setUrl(Settings::getValue(settings_prefix + "/url").toUrl());
+        downloader->targetFile = target_file;
+        connect(downloader, &Downloader::progressChanged, this, &TextsPatch::onDownloaderProgressChanged);
+        connect(downloader, &Downloader::downloadFinished, this, &TextsPatch::onDownloaderFinished);
+        downloaders_.insert(downloader);
+        downloader->start();
+    }
+
+    if (!download_started) {
+        emit operationFinished("download", this, true);
+    } // otherwise will be emitted on the last onDownloaderFinished signal
 }
 
 void TextsPatch::install()
@@ -38,3 +129,116 @@ void TextsPatch::activate()
     QThread::sleep(5);
     emit operationFinished("activate", this, true);
 }
+
+
+void TextsPatch::onDownloaderProgressChanged(Downloader *, Downloader::Status)
+{
+    Downloader::Status all_downloads_status;
+    foreach (Downloader* downloader, downloaders_) {
+        all_downloads_status = all_downloads_status + downloader->getDownloadStatus();
+    }
+
+    emit downloadStatusChanged(this, all_downloads_status);
+}
+
+void TextsPatch::onDownloaderFinished(Downloader *ptr)
+{
+    Downloader::Status all_downloads_status;
+    foreach (Downloader* downloader, downloaders_) {
+        all_downloads_status = all_downloads_status + downloader->getDownloadStatus();
+    }
+
+    ptr->targetFile->close();
+    ptr->targetFile->deleteLater();
+
+    if (elapsed_patches_to_download_ == 1) {
+        foreach (Downloader* downloader, downloaders_) {
+            downloader->deleteLater();
+        }
+        downloaders_.clear();
+
+        emit downloadStatusChanged(this, all_downloads_status);
+        emit operationFinished("download", this, true);
+    }
+
+    --elapsed_patches_to_download_;
+}
+
+void TextsPatch::onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful)
+{
+    if (operation_name == "installPatch") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+
+        status_.process = CurrentProcess::E_AWAITING_INSTALL;
+        status_.percent = 100;
+        emit installStatusChanged(this, status_);
+
+        --elapsed_databases_to_install_;
+
+        if (!successful) {
+            emit errorOccured("install", this, "Database " + args[0].toString() + " (" + args[1].toString() + ") was not installed due to Legacy core error.");
+        }
+
+        if (elapsed_databases_to_install_ == 0) {
+            status_.process = CurrentProcess::E_FINISHED;
+            emit operationFinished("install", this, true);
+        }
+    }
+
+    if (operation_name == "enableCategory" || operation_name == "disableCategory") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+
+        status_.process = CurrentProcess::E_AWAITING_APPLY;
+        status_.percent = 100;
+        emit installStatusChanged(this, status_);
+
+        --elapsed_categories_to_activate_;
+        if (!successful) {
+            emit errorOccured("activate", this, "Error in patch " + args[0].toString() + ": activating category " + QString::number(args[1].toInt()) + " failed.");
+        }
+
+        if (elapsed_categories_to_activate_ == 0) {
+            status_.process = CurrentProcess::E_FINISHED;
+            emit operationFinished("activate", this, true);
+        }
+    }
+}
+
+void TextsPatch::onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args)
+{
+    if (operation_name == "installPatch") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+        status_.process = CurrentProcess::E_INSTALL;
+        status_.current_part++;
+        status_.percent = 0;
+        emit installStatusChanged(this, status_);
+    }
+
+    if (operation_name == "enableCategory" || operation_name == "disableCategory") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+        status_.process = CurrentProcess::E_APPLY;
+        status_.current_part++;
+        status_.percent = 0;
+        emit installStatusChanged(this, status_);
+    }
+}
+
+void TextsPatch::onLotroDatManagerStatusChanged(LotroDatManager::Status status)
+{
+    if (status_.process != CurrentProcess::E_INSTALL || status_.process != CurrentProcess::E_APPLY) {
+        return;
+    }
+
+    status_.percent = status.percent;
+    emit installStatusChanged(this, status_);
+}
+
+

+ 10 - 15
src/Legacy/models/patch/textspatch.h

@@ -19,25 +19,20 @@ public slots:
     virtual void activate() override;
 
 private slots:
-//    void onDownloaderProgressChanged(Downloader* ptr, Downloader::Status status);
-//    void onDownloaderFinished(Downloader* ptr);
-//    void onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful);
-//    void onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args);
-//    void onLotroDatManagerStatusChanged(LotroDatManager::Status status);
+    void onDownloaderProgressChanged(Downloader* ptr, Downloader::Status status);
+    void onDownloaderFinished(Downloader* ptr);
+    void onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful);
+    void onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args);
+    void onLotroDatManagerStatusChanged(LotroDatManager::Status status);
 
 private:
     const QStringList databases_names = {
-        "image",
-        "texture",
-        "loadscreen",
+        "text",
+        "font"
     };
 
-//    void installLoadscreens();
-//    void enableLoadscreens();
-//    void disableLoadscreens();
-
-//    quint8 elapsed_patches_to_download_ = 0; // for download process
-//    quint8 elapsed_databases_to_install_ = 0; // for install process
-//    quint8 elapsed_categories_to_activate_ = 0; // for activate/deactivate process
+    quint8 elapsed_patches_to_download_ = 0; // for download process
+    quint8 elapsed_databases_to_install_ = 0; // for install process
+    quint8 elapsed_categories_to_activate_ = 0; // for activate/deactivate process
 };
 #endif // TEXTPATCH_H

+ 204 - 4
src/Legacy/models/patch/videospatch.cpp

@@ -9,20 +9,110 @@
 
 VideosPatch::VideosPatch(LotroDatManager *mgr, QObject *parent) : Patch("VideosPatch", mgr, parent)
 {
+    connect(lotro_mgr_, &LotroDatManager::operationStarted, this, &VideosPatch::onLotroDatManagerOperationStarted);
+    connect(lotro_mgr_, &LotroDatManager::operationFinished, this, &VideosPatch::onLotroDatManagerOperationFinished);
+    connect(lotro_mgr_->getObserver(), &LotroDatManagerObserver::statusChanged, this, &VideosPatch::onLotroDatManagerStatusChanged);
 }
 
 void VideosPatch::checkForUpdates()
 {
     emit operationStarted("checkForUpdates", this);
-    QThread::sleep(1);
-    emit operationFinished("checkForUpdates",  this, true);
+    QUrlQuery query; // query for building GET-request aka patch-version
+
+    foreach (QString db_name, databases_names) {
+        query.addQueryItem(db_name, "100");
+    }
+
+    QUrl target_url;
+    target_url.setUrl(Settings::getValue("Network/patch_updates_url").toString());
+    target_url.setQuery(query);
+
+    QByteArray target_array;
+    Downloader downloader;
+    downloader.setUrl(target_url);
+    downloader.targetBytearray = &target_array;
+    downloader.start();
+    downloader.waitForDownloaded();
+
+    if (target_array.isEmpty()) {
+        qDebug() << __FUNCTION__ << "Cannot download, target_array is empty!";
+        emit errorOccured("checkForUpdates", this, "QueryDownloadFailed");
+        emit operationFinished("checkForUpdates", this, false);
+        return;
+    }
+
+    QStringList patch_info = QString(target_array).split('|');
+    if (patch_info.size() != databases_names.size()) {
+        qDebug() << __FUNCTION__ << "Incorrect patches number! Data: " << patch_info;
+        emit errorOccured("checkForUpdates", this, "IncorrectQueryResult");
+        emit operationFinished("checkForUpdates", this, false);
+        return;
+    }
+
+    for (int i = 0; i < databases_names.size(); ++i) {
+        QStringList patch_data = patch_info[i].split(":::");
+        if (patch_data.size() != 3) {
+            qDebug() << __FUNCTION__ << "Incorrect patch entry size! Entry: " << patch_data;
+            emit errorOccured("checkForUpdates", this, "IncorrectDbInfo");
+            emit operationFinished("checkForUpdates", this, false);
+            return;
+        }
+
+        QString patch_filename = Settings::getValue("General/PatchDownloadDir").toString() + "/" + QUrl(patch_data[0]).fileName();
+
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/url", patch_data[0]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/hashsum", patch_data[1]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/datetime", patch_data[2]);
+        Settings::setValue("PatchDatabases/" + databases_names[i] + "/path", patch_filename);
+    }
+    emit operationFinished("checkForUpdates", this, true);
 }
 
 void VideosPatch::download()
 {
+    if (elapsed_patches_to_download_ != 0) {
+        qDebug() << "Trying to start download of patch set " << patch_name_ << " while download is still active!";
+        return;
+    }
+
     emit operationStarted("download", this);
-    QThread::sleep(5);
-    emit operationFinished("download", this, true);
+
+    bool download_started = false;
+
+    foreach (QString db_name, databases_names) {
+        QString settings_prefix = "PatchDatabases/" + db_name;
+
+        QString target_filename = QApplication::applicationDirPath() + "/" + Settings::getValue(settings_prefix + "/path").toString();
+        qDebug() << "VideosPatch: Checking if there's no need to download file " << target_filename;
+
+        if (FileSystem::fileHash(target_filename) == Settings::getValue(settings_prefix + "/hashsum").toString()) {
+            qDebug() << "VideosPatch: file " << target_filename << " is fresh, no need to download";
+            continue;
+        }
+
+        FileSystem::createFilePath(target_filename);
+        QFile* target_file = new QFile(target_filename);
+        if (!target_file->open(QIODevice::ReadWrite | QIODevice::Truncate)) {
+            emit errorOccured("download", this, "CantOpenDbFile");
+            continue;
+        }
+
+        qDebug() << "VideosPatch: beginning download of file " << target_filename;
+        download_started = true;
+
+        ++elapsed_patches_to_download_;
+        Downloader* downloader = new Downloader();
+        downloader->setUrl(Settings::getValue(settings_prefix + "/url").toUrl());
+        downloader->targetFile = target_file;
+        connect(downloader, &Downloader::progressChanged, this, &VideosPatch::onDownloaderProgressChanged);
+        connect(downloader, &Downloader::downloadFinished, this, &VideosPatch::onDownloaderFinished);
+        downloaders_.insert(downloader);
+        downloader->start();
+    }
+
+    if (!download_started) {
+        emit operationFinished("download", this, true);
+    } // otherwise will be emitted on the last onDownloaderFinished signal
 }
 
 void VideosPatch::install()
@@ -38,3 +128,113 @@ void VideosPatch::activate()
     QThread::sleep(5);
     emit operationFinished("activate", this, true);
 }
+
+void VideosPatch::onDownloaderProgressChanged(Downloader *, Downloader::Status)
+{
+    Downloader::Status all_downloads_status;
+    foreach (Downloader* downloader, downloaders_) {
+        all_downloads_status = all_downloads_status + downloader->getDownloadStatus();
+    }
+
+    emit downloadStatusChanged(this, all_downloads_status);
+}
+
+void VideosPatch::onDownloaderFinished(Downloader *ptr)
+{
+    Downloader::Status all_downloads_status;
+    foreach (Downloader* downloader, downloaders_) {
+        all_downloads_status = all_downloads_status + downloader->getDownloadStatus();
+    }
+
+    ptr->targetFile->close();
+    ptr->targetFile->deleteLater();
+
+    if (elapsed_patches_to_download_ == 1) {
+        foreach (Downloader* downloader, downloaders_) {
+            downloader->deleteLater();
+        }
+        downloaders_.clear();
+
+        emit downloadStatusChanged(this, all_downloads_status);
+        emit operationFinished("download", this, true);
+    }
+
+    --elapsed_patches_to_download_;
+}
+
+void VideosPatch::onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful)
+{
+    if (operation_name == "installPatch") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+
+        status_.process = CurrentProcess::E_AWAITING_INSTALL;
+        status_.percent = 100;
+        emit installStatusChanged(this, status_);
+
+        --elapsed_databases_to_install_;
+
+        if (!successful) {
+            emit errorOccured("install", this, "Database " + args[0].toString() + " (" + args[1].toString() + ") was not installed due to Legacy core error.");
+        }
+
+        if (elapsed_databases_to_install_ == 0) {
+            status_.process = CurrentProcess::E_FINISHED;
+            emit operationFinished("install", this, true);
+        }
+    }
+
+    if (operation_name == "enableCategory" || operation_name == "disableCategory") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+
+        status_.process = CurrentProcess::E_AWAITING_APPLY;
+        status_.percent = 100;
+        emit installStatusChanged(this, status_);
+
+        --elapsed_categories_to_activate_;
+        if (!successful) {
+            emit errorOccured("activate", this, "Error in patch " + args[0].toString() + ": activating category " + QString::number(args[1].toInt()) + " failed.");
+        }
+
+        if (elapsed_categories_to_activate_ == 0) {
+            status_.process = CurrentProcess::E_FINISHED;
+            emit operationFinished("activate", this, true);
+        }
+    }
+}
+
+void VideosPatch::onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args)
+{
+    if (operation_name == "installPatch") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+        status_.process = CurrentProcess::E_INSTALL;
+        status_.current_part++;
+        status_.percent = 0;
+        emit installStatusChanged(this, status_);
+    }
+
+    if (operation_name == "enableCategory" || operation_name == "disableCategory") {
+        if (!args[0].toString().contains("SoundsPatch_")) {
+            return;
+        }
+        status_.process = CurrentProcess::E_APPLY;
+        status_.current_part++;
+        status_.percent = 0;
+        emit installStatusChanged(this, status_);
+    }
+}
+
+void VideosPatch::onLotroDatManagerStatusChanged(LotroDatManager::Status status)
+{
+    if (status_.process != CurrentProcess::E_INSTALL || status_.process != CurrentProcess::E_APPLY) {
+        return;
+    }
+
+    status_.percent = status.percent;
+    emit installStatusChanged(this, status_);
+}

+ 9 - 15
src/Legacy/models/patch/videospatch.h

@@ -19,26 +19,20 @@ public slots:
     virtual void activate() override;
 
 private slots:
-//    void onDownloaderProgressChanged(Downloader* ptr, Downloader::Status status);
-//    void onDownloaderFinished(Downloader* ptr);
-//    void onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful);
-//    void onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args);
-//    void onLotroDatManagerStatusChanged(LotroDatManager::Status status);
+    void onDownloaderProgressChanged(Downloader* ptr, Downloader::Status status);
+    void onDownloaderFinished(Downloader* ptr);
+    void onLotroDatManagerOperationFinished(QString operation_name, QVector<QVariant> args, bool successful);
+    void onLotroDatManagerOperationStarted(QString operation_name, QVector<QVariant> args);
+    void onLotroDatManagerStatusChanged(LotroDatManager::Status status);
 
 private:
     const QStringList databases_names = {
-        "image",
-        "texture",
-        "loadscreen",
+        "video"
     };
 
-//    void installLoadscreens();
-//    void enableLoadscreens();
-//    void disableLoadscreens();
-
-//    quint8 elapsed_patches_to_download_ = 0; // for download process
-//    quint8 elapsed_databases_to_install_ = 0; // for install process
-//    quint8 elapsed_categories_to_activate_ = 0; // for activate/deactivate process
+    quint8 elapsed_patches_to_download_ = 0; // for download process
+    quint8 elapsed_databases_to_install_ = 0; // for install process
+    quint8 elapsed_categories_to_activate_ = 0; // for activate/deactivate process
 };
 
 #endif // VIDEOSPATCH_H

+ 10 - 23
src/Legacy/models/patchlist.cpp

@@ -78,33 +78,20 @@ void PatchList::onPatchOperationFinished(QString operation_name, Patch *patch, b
     qDebug() << "Operation " << operation_name << " finished of patchset " << patch->getPatchName() << ", result = " << result;
     --active_operations_num_;
 
-    if (!result) {
-        if (active_operations_num_ == 0) {
-            if (auto_updates_enabled_) {
-                patch_update_timer.start();
-            }
-            qDebug() << __FUNCTION__ << "All patch operations successfully finished!";
-            emit patchOperationsFinished();
-        }
-
-        return; // Do not continue operations chain, if error occured
-    }
-
-    if (operation_name == "checkForUpdates") {
+    if (result && operation_name == "checkForUpdates") {
         QMetaObject::invokeMethod(patch, &Patch::download, Qt::QueuedConnection);
+        return;
     }
 
-    if (operation_name == "download") {
-        QMetaObject::invokeMethod(patch, &Patch::install, Qt::QueuedConnection);
-    }
-
-    if (operation_name == "install") {
-        QMetaObject::invokeMethod(patch, &Patch::activate, Qt::QueuedConnection);
-    }
+//    if (result && operation_name == "download") {
+//        QMetaObject::invokeMethod(patch, &Patch::install, Qt::QueuedConnection);
+//        return;
+//    }
 
-    if (operation_name == "activate" && active_operations_num_ == 0) {
-        emit patchOperationsFinished();
-    }
+//    if (result && operation_name == "install") {
+//        QMetaObject::invokeMethod(patch, &Patch::activate, Qt::QueuedConnection);
+//        return;
+//    }
 
     if (active_operations_num_ == 0) {
         if (auto_updates_enabled_) {