Browse Source

Merge branch 'f/Legacy-0-set-up-settings-module' of LotRO_Legacy/Legacy_v2 into dev

Ivan Arkhipov 4 years ago
parent
commit
022c24d72b

+ 1 - 0
.gitignore

@@ -59,6 +59,7 @@ install_manifest.txt
 *.qbs.user.*
 *.moc
 moc_*.cpp
+*object_script*
 qrc_*.cpp
 ui_*.h
 Makefile*

+ 3 - 1
src/Legacy/Legacy.pro

@@ -38,7 +38,9 @@ SOURCES += \
     models/patch/textspatch.cpp \
     models/patch/graphicspatch.cpp \
     models/patchlist.cpp \
-    legacyapplication.cpp
+    legacyapplication.cpp \
+    models/settings.cpp \
+    models/filesystem.cpp
 
 HEADERS += \
     models/downloader.h \

+ 98 - 0
src/Legacy/models/filesystem.cpp

@@ -0,0 +1,98 @@
+#ifndef FILESYSTEM_H
+#define FILESYSTEM_H
+
+#include <QObject>
+#include <QFile>
+#include <QDir>
+#include <QFileInfo>
+#include <QCryptographicHash>
+#include <QDebug>
+#include <QSettings>
+
+#include "filesystem.h"
+
+namespace FileSystem {
+    bool fileExists(QString path) {
+        QFileInfo check_file(path);
+        return check_file.exists() && check_file.isFile();
+    }
+
+    bool folderExists(QString path) {
+        return QDir(path).exists();
+    }
+
+    bool createFilePath(QString file_path) { // Creates all necessary directories for file
+        QDir dir;
+        return dir.mkpath(QFileInfo(file_path).absoluteDir().absolutePath());
+    }
+
+    QString fileHash(const QString &fileName, QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Md5) {
+        QFile file(fileName);
+        if (file.open(QIODevice::ReadOnly)) {
+            QCryptographicHash hash(hashAlgorithm);
+            hash.addData(&file);
+            QByteArray hashData = hash.result();
+            return hashData.toHex();
+        }
+        return QByteArray();
+    }
+
+
+    void clearFolder(QDir &dir) {
+        //Получаем список файлов
+        QStringList lstFiles = dir.entryList(QDir::Files);
+
+        //Удаляем файлы
+        foreach (QString entry, lstFiles){
+            QString entryAbsPath = dir.absolutePath() + "/" + entry;
+            //QFile::setPermissions(entryAbsPath, QFile::ReadOwner | QFile::WriteOwner);
+            qDebug() << dir.absolutePath();
+            QFile::remove(entryAbsPath);
+        }
+    }
+
+
+    QStringList recognizeRegistryLotroPath() {
+        QStringList paths;
+
+        #ifdef _WIN32
+            // Windows 8, 10
+            QSettings n("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\12bbe590-c890-11d9-9669-0800200c9a66_is1", QSettings::NativeFormat);
+            foreach (QString key, n.allKeys()) {
+                qDebug() << key;
+                if(key.contains("InstallLocation") || key.contains("installlocation")){
+                    QString folder = n.value(key).toString()
+                            .replace("\\", "/")
+                            .replace("/TurbineLauncher.exe", "")
+                            .replace("/LotroLauncher.exe", "")
+                            .replace("\"", "");
+
+                    if(fileExists(folder + "/LotroLauncher.exe"))
+                        paths.append(folder);
+                }
+            }
+
+
+            // Windows 7
+            QSettings m("HKEY_CLASSES_ROOT\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache", QSettings::NativeFormat);
+            foreach (QString key, m.allKeys()) {
+              if((key.contains("TurbineLauncher.exe") || key.contains("LotroLauncher.exe")) && fileExists(key)){
+                  QString folder = n.value(key).toString()
+                          .replace("\\", "/")
+                          .replace("/TurbineLauncher.exe", "")
+                          .replace("/LotroLauncher.exe", "")
+                          .replace("\"", "");
+
+                  if(fileExists(folder + "/LotroLauncher.exe"))
+                      paths.append(folder);
+              }
+            }
+        #else
+            // Реализация под Linux
+        #endif
+
+        return paths;
+    }
+}
+
+#endif // FILESYSTEM_H

+ 6 - 76
src/Legacy/models/filesystem.h

@@ -10,87 +10,17 @@
 #include <QSettings>
 
 namespace FileSystem {
-    static bool fileExists(QString path) {
-        QFileInfo check_file(path);
-        return check_file.exists() && check_file.isFile();
-    }
+    extern bool fileExists(QString path);
 
-    static bool folderExists(QString path) {
-        return QDir(path).exists();
-    }
+    extern bool folderExists(QString path);
 
-    static bool createFilePath(QString file_path) { // Creates all necessary directories for file
-        QDir dir;
-        return dir.mkpath(QFileInfo(file_path).absoluteDir().absolutePath());
-    }
+    extern bool createFilePath(QString file_path);
 
-    static QString fileHash(const QString &fileName, QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Md5) {
-        QFile file(fileName);
-        if (file.open(QIODevice::ReadOnly)) {
-            QCryptographicHash hash(hashAlgorithm);
-            hash.addData(&file);
-            QByteArray hashData = hash.result();
-            return hashData.toHex();
-        }
-        return QByteArray();
-    }
+    extern QString fileHash(const QString &fileName, QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Md5);
 
+    extern void clearFolder(QDir &dir);
 
-    static void clearFolder(QDir &dir) {
-        //Получаем список файлов
-        QStringList lstFiles = dir.entryList(QDir::Files);
-
-        //Удаляем файлы
-        foreach (QString entry, lstFiles){
-            QString entryAbsPath = dir.absolutePath() + "/" + entry;
-            //QFile::setPermissions(entryAbsPath, QFile::ReadOwner | QFile::WriteOwner);
-            qDebug() << dir.absolutePath();
-            QFile::remove(entryAbsPath);
-        }
-    }
-
-
-    static QStringList recognizeRegistryLotroPath() {
-        QStringList paths;
-
-        #ifdef _WIN32
-            // Windows 8, 10
-            QSettings n("HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\12bbe590-c890-11d9-9669-0800200c9a66_is1", QSettings::NativeFormat);
-            foreach (QString key, n.allKeys()) {
-                qDebug() << key;
-                if(key.contains("InstallLocation") || key.contains("installlocation")){
-                    QString folder = n.value(key).toString()
-                            .replace("\\", "/")
-                            .replace("/TurbineLauncher.exe", "")
-                            .replace("/LotroLauncher.exe", "")
-                            .replace("\"", "");
-
-                    if(fileExists(folder + "/LotroLauncher.exe"))
-                        paths.append(folder);
-                }
-            }
-
-
-            // Windows 7
-            QSettings m("HKEY_CLASSES_ROOT\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache", QSettings::NativeFormat);
-            foreach (QString key, m.allKeys()) {
-              if((key.contains("TurbineLauncher.exe") || key.contains("LotroLauncher.exe")) && fileExists(key)){
-                  QString folder = n.value(key).toString()
-                          .replace("\\", "/")
-                          .replace("/TurbineLauncher.exe", "")
-                          .replace("/LotroLauncher.exe", "")
-                          .replace("\"", "");
-
-                  if(fileExists(folder + "/LotroLauncher.exe"))
-                      paths.append(folder);
-              }
-            }
-        #else
-            // Реализация под Linux
-        #endif
-
-        return paths;
-    }
+    extern QStringList recognizeRegistryLotroPath();
 }
 
 #endif // FILESYSTEM_H

+ 51 - 0
src/Legacy/models/patchlist.cpp

@@ -45,6 +45,9 @@ PatchList::PatchList(LotroDatManager *mgr, QObject *parent) : QObject(parent)
     graphics_patch_thread_->start();
     sounds_patch_thread_->start();
     videos_patch_thread_->start();
+
+    patch_update_timer.setInterval(5 * 60 * 1000); // Once in 5 minutes check for updates
+    connect(&patch_update_timer, &QTimer::timeout, this, &PatchList::update);
 }
 
 PatchList::~PatchList()
@@ -119,6 +122,12 @@ void PatchList::onLotroManagerOperationFinished(QString operation_name, QVector<
             qCritical() << "DatManager initialisation error!!!";
         }
     }
+    if (operation_name == "createBackup" || operation_name == "restoreFromBackup" || operation_name == "removeBackup") {
+        --active_operations_num_;
+        if (active_operations_num_ == 0) {
+            emit patchOperationsFinished();
+        }
+    }
 }
 
 void PatchList::startAutoUpdate()
@@ -127,12 +136,54 @@ void PatchList::startAutoUpdate()
     patch_update_timer.start();
 }
 
+void PatchList::stopAutoUpdate()
+{
+    patch_update_timer.stop();
+    auto_updates_enabled_ = false;
+}
+
 void PatchList::initialize() {
     ++active_operations_num_;
     emit patchOperationsStarted();
     QMetaObject::invokeMethod(lotro_mgr_, &LotroDatManager::initializeManager, Qt::QueuedConnection);
 }
 
+void PatchList::createBackup()
+{
+    if (active_operations_num_ > 0) {
+        qWarning() << "Tried to start create backup operation, while others are still running!";
+        return;
+    }
+
+    ++active_operations_num_;
+    emit patchOperationsStarted();
+    QMetaObject::invokeMethod(lotro_mgr_, "createBackup", Qt::QueuedConnection);
+}
+
+void PatchList::restoreFromBackup()
+{
+    if (active_operations_num_ > 0) {
+        qWarning() << "Tried to start restore from backup operation, while others are still running!";
+        return;
+    }
+
+    ++active_operations_num_;
+    emit patchOperationsStarted();
+    QMetaObject::invokeMethod(lotro_mgr_, "restoreFromBackup", Qt::QueuedConnection);
+}
+
+void PatchList::removeBackup()
+{
+    if (active_operations_num_ > 0) {
+        qWarning() << "Tried to start remove backup operation, while others are still running!";
+        return;
+    }
+
+    ++active_operations_num_;
+    emit patchOperationsStarted();
+    QMetaObject::invokeMethod(lotro_mgr_, "removeBackup", Qt::QueuedConnection);
+}
+
 void PatchList::onPatchOperationStarted(Patch::Operation, Patch*)
 {
     if (active_operations_num_ == 0) {

+ 8 - 0
src/Legacy/models/patchlist.h

@@ -30,10 +30,18 @@ signals:
 public slots:
     void startAutoUpdate();
 
+    void stopAutoUpdate();
+
     void update();
 
     void initialize();
 
+    void createBackup();
+
+    void restoreFromBackup();
+
+    void removeBackup();
+
 private slots:
     void onPatchOperationStarted(Patch::Operation operation, Patch* patch);
     void onPatchOperationFinished(Patch::Operation operation, Patch* patch);

+ 143 - 0
src/Legacy/models/settings.cpp

@@ -0,0 +1,143 @@
+#include <QSettings>
+
+#include "settings.h"
+
+
+namespace Settings {
+
+QMap<QString, QVariant> defaults = {
+    // General info
+    {"General/UI_scale", 100},
+    {"General/CurrentInitStage", "0"},
+    {"General/MicroUpdates", false},
+    {"General/PatchDownloadDir", "data"},
+
+    // Lotro Manager
+    {"Lotro/game_path", "none"},
+    {"Lotro/original_locale", "English"},
+    {"Lotro/skip_raw_download", true},
+    {"Lotro/no_splash_screen", false},
+
+    // Backup
+    {"Backup/installed", false},
+    {"Backup/path", "/backup/"},
+    {"Backup/creation_time", "none"},
+
+    // Databases download settings
+    {"DatabaseDownload/text", false},          // TextsPatch
+    {"DatabaseDownload/font", false},          // TextsPatch
+    {"DatabaseDownload/image", false},         // GraphicsPatch
+    {"DatabaseDownload/loadscreen", false},    // GraphicsPatch
+    {"DatabaseDownload/texture", false},       // GraphicsPatch
+    {"DatabaseDownload/sound", false},         // SoundsPatch
+    {"DatabaseDownload/video", false},         // VideosPatch
+    {"DatabaseDownload/micro", false},         // MicroPatch
+
+    // Flags, meaning that database is fresh and needs to be installed
+
+    {"DatabaseUpdated/text", false},           // TextsPatch
+    {"DatabaseUpdated/font", false},           // TextsPatch
+    {"DatabaseUpdated/image", false},          // GraphicsPatch
+    {"DatabaseUpdated/loadscreen", false},     // GraphicsPatch
+    {"DatabaseUpdated/texture", false},        // GraphicsPatch
+    {"DatabaseUpdated/sound", false},          // SoundsPatch
+    {"DatabaseUpdated/video", false},          // VideosPatch
+    {"DatabaseUpdated/micro", false},          // MircoPatch
+
+    // Localisation components
+    {"Components/texts_main", false},          // TextsPatch
+    {"Components/texts_items", false},         // TextsPatch
+    {"Components/texts_emotes", false},        // TextsPatch
+    {"Components/maps", false},                // ImagesPatch
+    {"Components/loadscreens", false},         // ImagesPatch
+    {"Components/textures", false},            // ImagesPatch
+    {"Components/sounds", false},              // SoundsPatch
+    {"Components/videos", false},              // VideosPatch
+    {"Components/micropatch", false},          // PatchList
+
+    // Network
+    {"Network/site_url", "http://translate.lotros.ru/"},
+    {"Network/forum_url", "http://lotros.ru/"},
+    {"Network/discord_url", "https://discord.gg/j25MdKR"},
+    {"Network/add_report_url", "http://translate.lotros.ru/bugs/add"},
+    {"Network/donate_url", "http://translate.lotros.ru/donate"},
+    {"Network/game_servers_status", "http://translate.lotros.ru/servers.txt"},
+    {"Network/game_servers_message", "http://translate.lotros.ru/profmessage.txt"},
+    {"Network/weekly_code_url", "http://translate.lotros.ru/coupon.txt"},
+    {"Network/news_list_url", "http://translate.lotros.ru/groupware/launcher_news/30/1"},
+    {"Network/patch_updates_url", "http://translate.lotros.ru/groupware/check_updates"}
+};
+
+void setDefaultSettings()
+{
+    QSettings settings;
+    foreach (QString key, defaults.keys()) {
+        settings.setValue(key, defaults[key]);
+    }
+}
+
+QVariant getValue(QString key) {
+    QSettings settings;
+    return settings.value(key, defaults[key]);
+}
+
+void setValue(QString key, QVariant value) {
+    QSettings settings;
+    settings.setValue(key, value);
+}
+
+SettingsBackup createSettingsBackup() {
+    QSettings settings;
+    QMap<QString, QVariant> keysValuesPairs;
+    QStringList keys = settings.allKeys();
+    QStringListIterator it(keys);
+
+    while (it.hasNext()) {
+        QString currentKey = it.next();
+        keysValuesPairs.insert(currentKey, settings.value(currentKey));
+    }
+
+    return keysValuesPairs;
+}
+
+void restoreFromSettingsBackup(const SettingsBackup& backup) {
+    QSettings settings;
+    settings.clear();
+
+    for (auto i = backup.begin(); i != backup.end(); ++i) {
+        settings.setValue(i.key(), i.value());
+    }
+}
+
+void updatePatchComponentsDependencies() {
+    QSettings settings;
+
+    auto isComponentActive = [&settings](const QString& component) -> bool {
+        return settings.value("Components/" + component).toBool();
+    };
+
+    if (isComponentActive("texts_main") || isComponentActive("texts_items")
+            || isComponentActive("texts_emotes") || isComponentActive("videos")) {
+        // Videos also need text database, because it contains videos path references
+        settings.setValue("DatabaseDownload/text", true);
+    } else {
+        settings.setValue("DatabaseDownload/text", false);
+    }
+
+    if (isComponentActive("texts_main") || isComponentActive("texts_items")
+            || isComponentActive("texts_emotes")) {
+        settings.setValue("DatabaseDownload/font", true);
+    } else {
+        settings.setValue("DatabaseDownload/font", false);
+    }
+
+    settings.setValue("DatabaseDownload/image", isComponentActive("maps"));
+    settings.setValue("DatabaseDownload/loadscreen", isComponentActive("loadscreens"));
+    settings.setValue("DatabaseDownload/texture", isComponentActive("textures"));
+    settings.setValue("DatabaseDownload/sound", isComponentActive("sounds"));
+    settings.setValue("DatabaseDownload/video", isComponentActive("videos"));
+    settings.setValue("DatabaseDownload/micro", isComponentActive("micropatch"));
+}
+
+}  /* namespace Settings */
+

+ 8 - 70
src/Legacy/models/settings.h

@@ -5,83 +5,21 @@
 
 namespace Settings
 {
+    using SettingsBackup = QMap<QString, QVariant>;
 
-static QMap<QString, QVariant> defaults = {
-    // General info
-    {"General/UI_scale", "100"},
-    {"General/CurrentInitStage", "0"},
-    {"General/MicroUpdates", false},
-    {"General/PatchDownloadDir", "data"},
+    extern QMap<QString, QVariant> defaults;
 
-    // Lotro Manager
-    {"Lotro/game_path", "none"},
-    {"Lotro/original_locale", "English"},
-    {"Lotro/skip_raw_download", "True"},
-    {"Lotro/no_splash_screen", "True"},
+    void setDefaultSettings();
 
-    // Databases download settings
+    QVariant getValue(QString key);
 
-    {"DatabaseDownload/text", false},          // TextsPatch
-    {"DatabaseDownload/font", false},          // TextsPatch
-    {"DatabaseDownload/image", false},         // GraphicsPatch
-    {"DatabaseDownload/loadscreen", false},    // GraphicsPatch
-    {"DatabaseDownload/texture", false},       // GraphicsPatch
-    {"DatabaseDownload/sound", false},         // SoundsPatch
-    {"DatabaseDownload/video", false},         // VideosPatch
+    void setValue(QString key, QVariant value);
 
-    // Flags, meaning that database is fresh and needs to be installed
-
-    {"DatabaseUpdated/text", false},           // TextsPatch
-    {"DatabaseUpdated/font", false},           // TextsPatch
-    {"DatabaseUpdated/image", false},          // GraphicsPatch
-    {"DatabaseUpdated/loadscreen", false},     // GraphicsPatch
-    {"DatabaseUpdated/texture", false},        // GraphicsPatch
-    {"DatabaseUpdated/sound", false},          // SoundsPatch
-    {"DatabaseUpdated/video", false},          // VideosPatch
-
-    // Localisation components
-    {"Components/fonts", false},               // TextsPatch
-    {"Components/texts_main", false},          // TextsPatch
-    {"Components/texts_items", false},         // TextsPatch
-    {"Components/texts_emotes", false},        // TextsPatch
-    {"Components/maps", false},                // ImagesPatch
-    {"Components/loadscreens", false},         // ImagesPatch
-    {"Components/textures", false},            // ImagesPatch
-    {"Components/sounds", false},              // SoundsPatch
-    {"Components/videos", false},              // VideosPatch
-
-    // Network
-    {"Network/site_url", "http://translate.lotros.ru/"},
-    {"Network/forum_url", "http://lotros.ru/"},
-    {"Network/discord_url", "https://discord.gg/j25MdKR"},
-    {"Network/add_report_url", "http://translate.lotros.ru/bugs/add"},
-    {"Network/donate_url", "http://translate.lotros.ru/donate"},
-    {"Network/game_servers_status", "http://translate.lotros.ru/servers.txt"},
-    {"Network/game_servers_message", "http://translate.lotros.ru/profmessage.txt"},
-    {"Network/weekly_code_url", "http://translate.lotros.ru/coupon.txt"},
-    {"Network/news_list_url", "http://translate.lotros.ru/groupware/launcher_news/30/1"},
-    {"Network/patch_updates_url", "http://translate.lotros.ru/groupware/check_updates"}
-};
-
-static void setDefaultSettings()
-{
-    QSettings settings;
-    foreach (QString key, defaults.keys()) {
-        settings.setValue(key, defaults[key]);
-    }
-}
-
-static QVariant getValue(QString key) {
-    QSettings settings;
-    return settings.value(key, defaults[key]);
-}
-
-static void setValue(QString key, QVariant value) {
-    QSettings settings;
-    settings.setValue(key, value);
-}
+    SettingsBackup createSettingsBackup();
 
+    void restoreFromSettingsBackup(const SettingsBackup& backup);
 
+    void updatePatchComponentsDependencies();
 }
 
 #endif // SETTINGS_H

+ 0 - 52
src/Legacy/object_script.Legacy.Debug

@@ -1,52 +0,0 @@
-INPUT(
-./..\..\build\debug\Legacy\rcc\qrc_backgrounds.o
-./..\..\build\debug\Legacy\rcc\qrc_common.o
-./..\..\build\debug\Legacy\obj\main.o
-./..\..\build\debug\Legacy\obj\downloader.o
-./..\..\build\debug\Legacy\obj\lotrodatmanager.o
-./..\..\build\debug\Legacy\obj\selfupdater.o
-./..\..\build\debug\Legacy\obj\helpwidget.o
-./..\..\build\debug\Legacy\obj\mainwindow.o
-./..\..\build\debug\Legacy\obj\menuentry.o
-./..\..\build\debug\Legacy\obj\settingswidget.o
-./..\..\build\debug\Legacy\obj\aboutwidget.o
-./..\..\build\debug\Legacy\obj\statuswidget.o
-./..\..\build\debug\Legacy\obj\newslistwidget.o
-./..\..\build\debug\Legacy\obj\newspiece.o
-./..\..\build\debug\Legacy\obj\serverstatuswidget.o
-./..\..\build\debug\Legacy\obj\chooseversiondialog.o
-./..\..\build\debug\Legacy\obj\weeklycodewidget.o
-./..\..\build\debug\Legacy\obj\dialogwindow.o
-./..\..\build\debug\Legacy\obj\qsmoothscrollarea.o
-./..\..\build\debug\Legacy\obj\fonts.o
-./..\..\build\debug\Legacy\obj\patch.o
-./..\..\build\debug\Legacy\obj\soundspatch.o
-./..\..\build\debug\Legacy\obj\videospatch.o
-./..\..\build\debug\Legacy\obj\textspatch.o
-./..\..\build\debug\Legacy\obj\graphicspatch.o
-./..\..\build\debug\Legacy\obj\patchlist.o
-./..\..\build\debug\Legacy\obj\legacyapplication.o
-./..\..\build\debug\Legacy\obj\legacy_plugin_import.o
-./..\..\build\debug\Legacy\obj\moc_downloader.o
-./..\..\build\debug\Legacy\obj\moc_lotrodatmanager.o
-./..\..\build\debug\Legacy\obj\moc_selfupdater.o
-./..\..\build\debug\Legacy\obj\moc_helpwidget.o
-./..\..\build\debug\Legacy\obj\moc_mainwindow.o
-./..\..\build\debug\Legacy\obj\moc_menuentry.o
-./..\..\build\debug\Legacy\obj\moc_settingswidget.o
-./..\..\build\debug\Legacy\obj\moc_aboutwidget.o
-./..\..\build\debug\Legacy\obj\moc_statuswidget.o
-./..\..\build\debug\Legacy\obj\moc_newslistwidget.o
-./..\..\build\debug\Legacy\obj\moc_newspiece.o
-./..\..\build\debug\Legacy\obj\moc_serverstatuswidget.o
-./..\..\build\debug\Legacy\obj\moc_chooseversiondialog.o
-./..\..\build\debug\Legacy\obj\moc_weeklycodewidget.o
-./..\..\build\debug\Legacy\obj\moc_dialogwindow.o
-./..\..\build\debug\Legacy\obj\moc_qsmoothscrollarea.o
-./..\..\build\debug\Legacy\obj\moc_patch.o
-./..\..\build\debug\Legacy\obj\moc_soundspatch.o
-./..\..\build\debug\Legacy\obj\moc_videospatch.o
-./..\..\build\debug\Legacy\obj\moc_textspatch.o
-./..\..\build\debug\Legacy\obj\moc_graphicspatch.o
-./..\..\build\debug\Legacy\obj\moc_patchlist.o
-);

+ 0 - 50
src/Legacy/object_script.Legacy.Release

@@ -1,50 +0,0 @@
-INPUT(
-./..\..\build\release\Legacy\obj\main.o
-./..\..\build\release\Legacy\obj\downloader.o
-./..\..\build\release\Legacy\obj\lotrodatmanager.o
-./..\..\build\release\Legacy\obj\selfupdater.o
-./..\..\build\release\Legacy\obj\helpwidget.o
-./..\..\build\release\Legacy\obj\mainwindow.o
-./..\..\build\release\Legacy\obj\menuentry.o
-./..\..\build\release\Legacy\obj\settingswidget.o
-./..\..\build\release\Legacy\obj\aboutwidget.o
-./..\..\build\release\Legacy\obj\statuswidget.o
-./..\..\build\release\Legacy\obj\newslistwidget.o
-./..\..\build\release\Legacy\obj\newspiece.o
-./..\..\build\release\Legacy\obj\serverstatuswidget.o
-./..\..\build\release\Legacy\obj\chooseversiondialog.o
-./..\..\build\release\Legacy\obj\weeklycodewidget.o
-./..\..\build\release\Legacy\obj\dialogwindow.o
-./..\..\build\release\Legacy\obj\qsmoothscrollarea.o
-./..\..\build\release\Legacy\obj\fonts.o
-./..\..\build\release\Legacy\obj\patch.o
-./..\..\build\release\Legacy\obj\soundspatch.o
-./..\..\build\release\Legacy\obj\videospatch.o
-./..\..\build\release\Legacy\obj\textspatch.o
-./..\..\build\release\Legacy\obj\graphicspatch.o
-./..\..\build\release\Legacy\obj\patchlist.o
-./..\..\build\release\Legacy\obj\legacyapplication.o
-./..\..\build\release\Legacy\obj\legacy_plugin_import.o
-./..\..\build\release\Legacy\obj\moc_downloader.o
-./..\..\build\release\Legacy\obj\moc_lotrodatmanager.o
-./..\..\build\release\Legacy\obj\moc_selfupdater.o
-./..\..\build\release\Legacy\obj\moc_helpwidget.o
-./..\..\build\release\Legacy\obj\moc_mainwindow.o
-./..\..\build\release\Legacy\obj\moc_menuentry.o
-./..\..\build\release\Legacy\obj\moc_settingswidget.o
-./..\..\build\release\Legacy\obj\moc_aboutwidget.o
-./..\..\build\release\Legacy\obj\moc_statuswidget.o
-./..\..\build\release\Legacy\obj\moc_newslistwidget.o
-./..\..\build\release\Legacy\obj\moc_newspiece.o
-./..\..\build\release\Legacy\obj\moc_serverstatuswidget.o
-./..\..\build\release\Legacy\obj\moc_chooseversiondialog.o
-./..\..\build\release\Legacy\obj\moc_weeklycodewidget.o
-./..\..\build\release\Legacy\obj\moc_dialogwindow.o
-./..\..\build\release\Legacy\obj\moc_qsmoothscrollarea.o
-./..\..\build\release\Legacy\obj\moc_patch.o
-./..\..\build\release\Legacy\obj\moc_soundspatch.o
-./..\..\build\release\Legacy\obj\moc_videospatch.o
-./..\..\build\release\Legacy\obj\moc_textspatch.o
-./..\..\build\release\Legacy\obj\moc_graphicspatch.o
-./..\..\build\release\Legacy\obj\moc_patchlist.o
-);

+ 12 - 0
src/Legacy/widgets/mainwindow.cpp

@@ -58,6 +58,12 @@ MainWindow::MainWindow(PatchList *legacy_patches, QWidget *parent)
     ui->content_layout->addWidget(help_widget_);
     ui->content_layout->addWidget(about_widget_);
 
+    // Adding patch update triggers on settings state changes
+    connect(settings_widget_, &SettingsWidget::SettingsChanged, legacy_patches_, &PatchList::stopAutoUpdate);
+    connect(settings_widget_, &SettingsWidget::SettingsReset, legacy_patches_, &PatchList::startAutoUpdate);
+    connect(settings_widget_, &SettingsWidget::SettingsApplied, legacy_patches_, &PatchList::initialize);
+
+
     hideAllContentWidgets();
     status_widget_->show();
 
@@ -91,6 +97,12 @@ MainWindow::MainWindow(PatchList *legacy_patches, QWidget *parent)
     qDebug() << __FUNCTION__ << "Installing event filters to clickable objects";
     setEventFilterRecursive(this);
 
+    qDebug() << __FUNCTION__ << "Resizing window due to Settings value";
+    int window_scale_factor = Settings::getValue("General/UI_scale").toInt();;
+    window_width = default_window_width * window_scale_factor / 100;
+    window_height = default_window_height * window_scale_factor / 100;
+    resize(window_width, window_height);
+
     qDebug() << __FUNCTION__ << "Finished main frame initialisation";
     show();
 }

+ 372 - 58
src/Legacy/widgets/settingswidget.cpp

@@ -12,28 +12,40 @@
 #include <QScrollBar>
 #include <QFileDialog>
 #include <QMetaObject>
+#include <QMessageBox>
+
+using namespace SettingsWidgetPrivate;
 
 SettingsWidget::SettingsWidget(PatchList *legacy_patches, QWidget *parent)
     : QWidget(parent)
     , ui(new Ui::SettingsWidget)
     , legacy_patches_(legacy_patches)
 {
+    settings_changed_ = false;
+
     ui->setupUi(this);
-    for (int i = 1; i <= 4; ++i)
-        setStatusToBlock(i, E_ERROR);
-
-    combobox_scrolling_disabler = new SettingsWidgetPrivate::ComboboxScrollingDisabler();
-    scroller = new SettingsWidgetPrivate::SettingsTabsScroller({ui->sub_entry_1,
-                                                                ui->sub_entry_2,
-                                                                ui->sub_entry_3,
-                                                                ui->sub_entry_4
-                                                               },
-                                                                ui->content_scroll_area
-                                                               );
+
+    combobox_scrolling_disabler = new ComboboxScrollingDisabler();
+    scroller = new SettingsTabsScroller({ui->sub_entry_1,
+                                         ui->sub_entry_2,
+                                         ui->sub_entry_3,
+                                         ui->sub_entry_4
+                                        },
+                                        ui->content_scroll_area);
 
     ui->lotro_base_language_combobox->installEventFilter(combobox_scrolling_disabler);
     ui->interface_scale_combobox->installEventFilter(combobox_scrolling_disabler);
 //    ui->content_scroll_area->verticalScrollBar()->installEventFilter(scroller);
+
+    ui->patch_installing_label->hide();
+    connect(legacy_patches, &PatchList::patchOperationsStarted, this, &SettingsWidget::onPatchTotalOperationsStarted);
+    connect(legacy_patches, &PatchList::patchOperationsFinished, this, &SettingsWidget::onPatchTotalOperationsFinished);
+
+    ui->apply_changes_button->hide();
+    ui->apply_changes_label->hide();
+    ui->patch_installing_label->hide();
+    settings_backup_ = Settings::createSettingsBackup();
+    setActualParametersValues();
 }
 
 SettingsWidget::~SettingsWidget()
@@ -43,24 +55,88 @@ SettingsWidget::~SettingsWidget()
     delete ui;
 }
 
+void SettingsWidget::setActualParametersValues()
+{
+    QString game_path = Settings::getValue("Lotro/game_path").toString();
+    if (game_path == "none") {
+        game_path = "Путь к файлам игры не выбран";
+    }
+    ui->game_folder_path->setText(game_path);
+
+
+    QString original_locale = Settings::getValue("Lotro/original_locale").toString();
+    int index = 0;
+
+    if (original_locale == "English")
+        index = 0;
+    if (original_locale == "DE")
+        index = 1;
+    if (original_locale == "FR")
+        index = 2;
+    ui->lotro_base_language_combobox->setCurrentIndex(index);
+
+    ui->skiprawdownload_checkbox->setChecked(Settings::getValue("Lotro/skip_raw_download").toBool());
+    ui->nosplashscreen_checkbox->setChecked(Settings::getValue("Lotro/no_splash_screen").toBool());
+
+    QString backup_status = Settings::getValue("Backup/installed").toBool() ? "Отсутствует" : "Активна";
+    ui->backup_status_value->setText(backup_status);
+    ui->backup_path_value->setText(QApplication::applicationDirPath() + Settings::getValue("Backup/path").toString());
+    QString backup_creation_time = Settings::getValue("Backup/creation_time").toString();
+    if (backup_creation_time == "none")
+        backup_creation_time = "-";
+    ui->backup_creation_time_value->setText(backup_creation_time);
+
+    ui->patch_texts_checkbox->setChecked(Settings::getValue("Components/texts_main").toBool());
+    ui->patch_items_checkbox->setChecked(Settings::getValue("Components/texts_items").toBool());
+    ui->patch_emotes_checkbox->setChecked(Settings::getValue("Components/texts_emotes").toBool());
+    ui->patch_maps_checkbox->setChecked(Settings::getValue("Components/maps").toBool());
+    ui->patch_loadscreens_checkbox->setChecked(Settings::getValue("Components/loadscreens").toBool());
+    ui->patch_textures_checkbox->setChecked(Settings::getValue("Components/textures").toBool());
+    ui->patch_sounds_checkbox->setChecked(Settings::getValue("Components/sounds").toBool());
+    ui->patch_video_checkbox->setChecked(Settings::getValue("Components/videos").toBool());
+    ui->micropatch_checkbox->setChecked(Settings::getValue("Components/micropatch").toBool());
+
+    int interface_scale = Settings::getValue("General/UI_scale").toInt();
+
+    int interface_scale_combobox_index = 0;
+    if (interface_scale == 50)
+        interface_scale_combobox_index = 0;
+    if (interface_scale == 75)
+        interface_scale_combobox_index = 1;
+    if (interface_scale == 100)
+        interface_scale_combobox_index = 2;
+    if (interface_scale == 125)
+        interface_scale_combobox_index = 3;
+    if (interface_scale == 150)
+        interface_scale_combobox_index = 4;
+    if (interface_scale == 175)
+        interface_scale_combobox_index = 5;
+    if (interface_scale == 200)
+        interface_scale_combobox_index = 6;
+
+    ui->interface_scale_combobox->setCurrentIndex(interface_scale_combobox_index);
+}
+
 void SettingsWidget::updateFontsSizes()
 {
     ui->frame_title->setFont(trajan_10pt);
     ui->group_label_1->setFont(trajan_9pt);
     ui->group_label_2->setFont(trajan_9pt);
     ui->group_label_3->setFont(trajan_9pt);
+    ui->group_label_4->setFont(trajan_9pt);
+
+    ui->patch_installing_label->setFont(crimson_12pt);
+    ui->apply_changes_button->setFont(trajan_10pt);
 
     ui->sub_entry_1_title->setFont(garamond_11pt);
     ui->sub_entry_2_title->setFont(garamond_11pt);
     ui->sub_entry_3_title->setFont(garamond_11pt);
+    ui->sub_entry_4_title->setFont(garamond_11pt);
 
     ui->backup_create_button->setFont(trajan_8pt);
     ui->backup_restore_button->setFont(trajan_8pt);
     ui->backup_remove_button->setFont(trajan_8pt);
 
-    ui->apply_button_entry_1->setFont(trajan_11pt);
-    ui->apply_button_entry_2->setFont(trajan_11pt);
-
     ui->game_folder_label->setFont(crimson_11pt);
     ui->game_folder_path->setFont(crimson_11pt);
     ui->lotro_base_language_label->setFont(crimson_11pt);
@@ -86,9 +162,9 @@ void SettingsWidget::updateFontsSizes()
     ui->patch_video_checkbox->setFont(crimson_11pt);
     ui->patch_texts_checkbox->setFont(crimson_11pt);
 
-    ui->micropatch_checkbox->setFont(crimson_12pt);
-    ui->interface_scale_label->setFont(crimson_12pt);
-    ui->interface_scale_combobox->setFont(crimson_12pt);
+    ui->micropatch_checkbox->setFont(crimson_11pt);
+    ui->interface_scale_label->setFont(crimson_11pt);
+    ui->interface_scale_combobox->setFont(crimson_11pt);
     ui->interface_scale_combobox->insertItem(ui->interface_scale_combobox->count(), "250%"); // is needed to invoke elements resize
     ui->interface_scale_combobox->removeItem(ui->interface_scale_combobox->count() - 1);
 
@@ -97,23 +173,7 @@ void SettingsWidget::updateFontsSizes()
     ui->sounds_block_label->setFont(crimson_12pt);
 }
 
-void SettingsWidget::setStatusToBlock(int block_id, SettingsWidget::E_STATUS status)
-{
-    QWidget* widget = ui->checkpoints_list->findChild<QWidget*>("group_status_icon_" + QString::number(block_id));
-    if (!widget)
-        return;
-
-    if (status == E_NONE)
-        widget->setStyleSheet("");
-    if (status == E_OK)
-        widget->setStyleSheet("border-image: url(:/status/ok_icon.png);");
-    if (status == E_WARNING)
-        widget->setStyleSheet("border-image: url(:/status/alert_icon.png);");
-    if (status == E_ERROR)
-        widget->setStyleSheet("border-image: url(:/status/error_icon.png);");
-}
-
-void SettingsWidget::resizeEvent(QResizeEvent *event)
+void SettingsWidget::resizeEvent(QResizeEvent *)
 {
     updateFontsSizes();
     double coefficient = window_width / default_window_width;
@@ -121,40 +181,36 @@ void SettingsWidget::resizeEvent(QResizeEvent *event)
     ui->frame_title->move(QPoint(45, 33) * coefficient);
     ui->frame_title->resize(QSize(201, 21) * coefficient);
     ui->checkpoints_list->move(QPoint(25, 70) * coefficient);
-    ui->checkpoints_list->resize(QSize(265, 321) * coefficient);
+    ui->checkpoints_list->resize(QSize(265, 451) * coefficient);
 
     ui->content_scroll_area->move(QPoint(310, 0) * coefficient);
     ui->content_scroll_area->resize(QSize(671, 521) * coefficient);
     ui->content_widget->setMinimumWidth(650 * coefficient);
 
-    ui->group_status_icon_1->setMinimumSize(QSize(25, 25) * coefficient);
-    ui->group_status_icon_2->setMinimumSize(QSize(25, 25) * coefficient);
-    ui->group_status_icon_3->setMinimumSize(QSize(25, 25) * coefficient);
-
     ui->change_folder_button->setMinimumSize(QSize(36, 32) * coefficient);
 
     ui->patch_texts_icon->setMinimumSize(QSize(80, 80) * coefficient);
     ui->patch_graphics_icon->setMinimumSize(QSize(80, 80) * coefficient);
     ui->patch_sounds_icon->setMinimumSize(QSize(80, 80) * coefficient);
-
-    ui->apply_button_entry_1->setMinimumHeight(double(55) * coefficient);
-    ui->apply_button_entry_2->setMinimumHeight(double(55) * coefficient);
+    ui->apply_changes_button->setMinimumSize(QSize(160, 60) * coefficient);
 }
 
-void SettingsWidget::on_interface_scale_combobox_currentIndexChanged(const QString &arg1)
-{
-    MainWindow* window = qobject_cast<MainWindow*>(qApp->activeWindow());
-
-    if (!window) {
-        ui->interface_scale_combobox->setCurrentText(Settings::getValue("General/UI_scale").toString() + "%");
-        qDebug() << "CANNOT FIND MAIN WINDOW!!!";
-        return;
+void SettingsWidget::processParameterChange() {
+    if (!settings_changed_) {
+        settings_changed_ = true;
+        emit SettingsChanged();
+        ui->apply_changes_label->show();
+        ui->apply_changes_button->show();
     }
+}
 
-    int value = arg1.left(arg1.length() - 1).toInt();
-    window->resize(1000 * value / 100, 648 * value / 100);
-
-    Settings::setValue("General/UI_scale", value);
+void SettingsWidget::checkIfParametersWereReset() {
+    if (settings_changed_ && settings_backup_ == Settings::createSettingsBackup()) {
+        settings_changed_ = false;
+        emit SettingsReset();
+        ui->apply_changes_label->hide();
+        ui->apply_changes_button->hide();
+    }
 }
 
 void SettingsWidget::on_change_folder_button_clicked()
@@ -169,11 +225,14 @@ void SettingsWidget::on_change_folder_button_clicked()
 
     QString game_folder= str.replace("/LotroLauncher.exe", "").replace("\\", "/").replace("//", "/") + "/";
 
-    if (Settings::getValue("Lotro/game_path").toString() == game_folder)
+    if (settings_backup_["Lotro/game_path"].toString() == game_folder) {
         return;
+    }
 
-    Settings::setValue("Lotro/game_path", game_folder);
+    processParameterChange();
+    settings_backup_["Lotro/game_path"] = game_folder;
     ui->game_folder_path->setText(game_folder);
+    checkIfParametersWereReset();
 }
 
 void SettingsWidget::on_lotro_base_language_combobox_currentIndexChanged(int index)
@@ -187,8 +246,263 @@ void SettingsWidget::on_lotro_base_language_combobox_currentIndexChanged(int ind
     if (index == 2)
         value = "FR";
 
-    if (Settings::getValue("Lotro/original_locale").toString() == value)
+    if (settings_backup_["Lotro/original_locale"].toString() == value) {
+        return;
+    }
+
+    processParameterChange();
+    settings_backup_["Lotro/original_locale"] = value;
+    checkIfParametersWereReset();
+}
+
+void SettingsWidget::on_skiprawdownload_checkbox_stateChanged(int arg1) {
+    if (arg1 == Qt::Checked) {
+        Settings::setValue("Lotro/skip_raw_download", true);
+        settings_backup_["Lotro/skip_raw_download"] = true;
+    }
+    if (arg1 == Qt::Unchecked) {
+        Settings::setValue("Lotro/skip_raw_download", false);
+        settings_backup_["Lotro/skip_raw_download"] = false;
+    }
+}
+
+void SettingsWidget::on_nosplashscreen_checkbox_stateChanged(int arg1)
+{
+    if (arg1 == Qt::Checked) {
+        Settings::setValue("Lotro/no_splash_screen", true);
+        settings_backup_["Lotro/no_splash_screen"] = true;
+    }
+    if (arg1 == Qt::Unchecked) {
+        Settings::setValue("Lotro/no_splash_screen", false);
+        settings_backup_["Lotro/no_splash_screen"] = false;
+    }
+}
+
+void SettingsWidget::on_backup_create_button_clicked()
+{
+    if (settings_changed_) {
+        QMessageBox::warning(nullptr, "Невозможно выполнить действие!", "Некоторые настройки были изменены. Чтобы создать резервную копию, примените или отмените изменения!");
+        return;
+    }
+
+    if (Settings::getValue("Backup/installed").toBool()) {
+        int result = QMessageBox::question(nullptr, "Подтвердите действие", "Резервная копия уже существует. Вы хотите перезаписать существующую копию?", QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton);
+        if (result != QMessageBox::Yes) {
+            return;
+        }
+    }
+
+    QMetaObject::invokeMethod(legacy_patches_, "createBackup", Qt::QueuedConnection);
+}
+
+void SettingsWidget::on_backup_restore_button_clicked()
+{
+    if (!Settings::getValue("Backup/installed").toBool()) {
+        QMessageBox::warning(nullptr, "Невозможно выполнить действие.", "Резервная копия не найдена. Создайте резервную копию, чтобы иметь возможность восстановления данных.");
+        return;
+    }
+
+    if (settings_changed_) {
+        QMessageBox::warning(nullptr, "Невозможно выполнить действие.", "Некоторые настройки были изменены. Чтобы восстановить данные из резервной копии, примените или отмените изменения!");
+        return;
+    }
+
+    QMetaObject::invokeMethod(legacy_patches_, "restoreFromBackup", Qt::QueuedConnection);
+}
+
+void SettingsWidget::on_backup_remove_button_clicked()
+{
+    if (Settings::getValue("Backup/installed").toBool()) {
+        int result = QMessageBox::question(nullptr, "Подтвердите действие", "Вы уверены, что хотите удалить существующую резервную копию?", QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton);
+        if (result != QMessageBox::Yes) {
+            return;
+        }
+    } else {
+        QMessageBox::information(nullptr, "Невозможно выполнить действие.", "Удаление невозможно: резервной копии не существует.");
+        return;
+    }
+
+    QMetaObject::invokeMethod(legacy_patches_, "removeBackup", Qt::QueuedConnection);
+}
+
+void SettingsWidget::on_patch_texts_checkbox_clicked()
+{
+    processParameterChange();
+    if (ui->patch_texts_checkbox->isChecked()) {
+        settings_backup_["Components/texts_main"] = true;
+    } else {
+        settings_backup_["Components/texts_main"] = false;
+    }
+    checkIfParametersWereReset();
+}
+
+void SettingsWidget::on_patch_items_checkbox_clicked()
+{
+    processParameterChange();
+    if (ui->patch_items_checkbox->isChecked()) {
+        settings_backup_["Components/texts_items"] = true;
+    } else {
+        settings_backup_["Components/texts_items"] = false;
+    }
+    checkIfParametersWereReset();
+}
+
+void SettingsWidget::on_patch_emotes_checkbox_clicked()
+{
+    processParameterChange();
+    if (ui->patch_emotes_checkbox->isChecked()) {
+        settings_backup_["Components/texts_emotes"] = true;
+    } else {
+        settings_backup_["Components/texts_emotes"] = false;
+    }
+    checkIfParametersWereReset();
+}
+
+void SettingsWidget::on_patch_maps_checkbox_clicked()
+{
+    processParameterChange();
+    if (ui->patch_maps_checkbox->isChecked()) {
+        settings_backup_["Components/maps"] = true;
+    } else {
+        settings_backup_["Components/maps"] = false;
+    }
+    checkIfParametersWereReset();
+}
+
+void SettingsWidget::on_patch_textures_checkbox_clicked()
+{
+    processParameterChange();
+    if (ui->patch_textures_checkbox->isChecked()) {
+        settings_backup_["Components/textures"] = true;
+    } else {
+        settings_backup_["Components/textures"] = false;
+    }
+    checkIfParametersWereReset();
+}
+
+void SettingsWidget::on_patch_loadscreens_checkbox_clicked()
+{
+    processParameterChange();
+    if (ui->patch_loadscreens_checkbox->isChecked()) {
+        settings_backup_["Components/loadscreens"] = true;
+    } else {
+        settings_backup_["Components/loadscreens"] = false;
+    }
+    checkIfParametersWereReset();
+
+}
+
+void SettingsWidget::on_patch_sounds_checkbox_clicked()
+{
+    processParameterChange();
+    if (ui->patch_sounds_checkbox->isChecked()) {
+        settings_backup_["Components/sounds"] = true;
+    } else {
+        settings_backup_["Components/sounds"] = false;
+    }
+    checkIfParametersWereReset();
+}
+
+void SettingsWidget::on_patch_video_checkbox_clicked()
+{
+    processParameterChange();
+    if (ui->patch_video_checkbox->isChecked()) {
+        settings_backup_["Components/videos"] = true;
+    } else {
+        settings_backup_["Components/videos"] = false;
+    }
+    checkIfParametersWereReset();
+}
+
+void SettingsWidget::on_patch_force_apply_button_clicked()
+{
+ // TODO(endevir): Implement
+}
+
+void SettingsWidget::on_micropatch_checkbox_clicked()
+{
+    processParameterChange();
+    if (ui->micropatch_checkbox->isChecked()) {
+        settings_backup_["Components/micropatch"] = true;
+    } else {
+        settings_backup_["Components/micropatch"] = false;
+    }
+    checkIfParametersWereReset();
+}
+
+void SettingsWidget::on_interface_scale_combobox_currentIndexChanged(const QString &arg1)
+{
+    MainWindow* window = qobject_cast<MainWindow*>(qApp->activeWindow());
+
+    if (!window) {
+        ui->interface_scale_combobox->setCurrentText(Settings::getValue("General/UI_scale").toString() + "%");
+        qDebug() << "CANNOT FIND MAIN WINDOW!!!";
         return;
+    }
+
+    int value = arg1.left(arg1.length() - 1).toInt();
+    window->resize(default_window_width * value / 100, default_window_height * value / 100);
+
+    Settings::setValue("General/UI_scale", value);
+    settings_backup_["General/UI_scale"] = value;
+}
 
-    Settings::setValue("Lotro/original_locale", value);
+void SettingsWidget::onPatchTotalOperationsStarted()
+{
+    patch_operations_running_ = true;
+    ui->patch_installing_label->show();
+
+    ui->change_folder_button->setEnabled(false);
+    ui->lotro_base_language_combobox->setEnabled(false);
+
+    ui->backup_create_button->setEnabled(false);
+    ui->backup_restore_button->setEnabled(false);
+    ui->backup_remove_button->setEnabled(false);
+
+    ui->patch_texts_checkbox->setEnabled(false);
+    ui->patch_items_checkbox->setEnabled(false);
+    ui->patch_emotes_checkbox->setEnabled(false);
+    ui->patch_maps_checkbox->setEnabled(false);
+    ui->patch_textures_checkbox->setEnabled(false);
+    ui->patch_loadscreens_checkbox->setEnabled(false);
+    ui->patch_sounds_checkbox->setEnabled(false);
+    ui->patch_video_checkbox->setEnabled(false);
+    ui->patch_force_apply_button->setEnabled(false);
+    ui->micropatch_checkbox->setEnabled(false);
+}
+
+void SettingsWidget::onPatchTotalOperationsFinished()
+{
+    patch_operations_running_ = false;
+    ui->patch_installing_label->hide();
+    settings_backup_ = Settings::createSettingsBackup();
+
+    ui->change_folder_button->setEnabled(true);
+    ui->lotro_base_language_combobox->setEnabled(true);
+
+    ui->backup_create_button->setEnabled(true);
+    ui->backup_restore_button->setEnabled(true);
+    ui->backup_remove_button->setEnabled(true);
+
+    ui->patch_texts_checkbox->setEnabled(true);
+    ui->patch_items_checkbox->setEnabled(true);
+    ui->patch_emotes_checkbox->setEnabled(true);
+    ui->patch_maps_checkbox->setEnabled(true);
+    ui->patch_textures_checkbox->setEnabled(true);
+    ui->patch_loadscreens_checkbox->setEnabled(true);
+    ui->patch_sounds_checkbox->setEnabled(true);
+    ui->patch_video_checkbox->setEnabled(true);
+    ui->patch_force_apply_button->setEnabled(true);
+    ui->micropatch_checkbox->setEnabled(true);
 }
+
+void SettingsWidget::on_apply_changes_button_clicked()
+{
+    Settings::restoreFromSettingsBackup(settings_backup_);
+    Settings::updatePatchComponentsDependencies();
+    settings_changed_ = false;
+    ui->apply_changes_label->hide();
+    ui->apply_changes_button->hide();
+    emit SettingsApplied();
+}
+

+ 62 - 14
src/Legacy/widgets/settingswidget.h

@@ -12,6 +12,8 @@
 #include <QScrollBar>
 #include <QWheelEvent>
 
+#include "models/settings.h"
+
 namespace Ui {
 class SettingsWidget;
 }
@@ -47,7 +49,7 @@ public:
     }
 
 protected:
-    bool eventFilter(QObject *obj, QEvent *event) override {
+    bool eventFilter(QObject *, QEvent *event) override {
 //        if (obj != target_widget_) {
 //            return false;
 //        }
@@ -87,12 +89,11 @@ protected:
     }
 
 private:
-    int current_entry_id_;
     QScrollArea* target_widget_;
+    int current_entry_id_;
     QList<QWidget*> entries_;
     QPropertyAnimation* scroll_entries_animation_;
 };
-
 }
 
 class SettingsWidget : public QWidget
@@ -105,34 +106,81 @@ public:
 
     ~SettingsWidget();
 
-    enum E_STATUS {
-        E_NONE = 0,
-        E_ERROR = -2,
-        E_WARNING = -1,
-        E_OK = 1
-    };
+signals:
+    void SettingsChanged(); // Settings were changed so we should not do any actions until SettingsApplied() signal
+
+    void SettingsApplied(); // Need to re-initialise all environment and start updates check
+
+    void SettingsReset(); // Need to drop updates blockage, but do not re-initialize all environment
 
 public slots:
+    void setActualParametersValues();
+
     void updateFontsSizes();
-    void setStatusToBlock(int block_id, E_STATUS status);
 
 protected:
     void resizeEvent(QResizeEvent *event) override;
 
 private slots:
+    void processParameterChange();
+
+    void checkIfParametersWereReset();
+
     void on_interface_scale_combobox_currentIndexChanged(const QString &arg1);
 
     void on_change_folder_button_clicked();
 
     void on_lotro_base_language_combobox_currentIndexChanged(int index);
 
+    void onPatchTotalOperationsStarted();
+
+    void onPatchTotalOperationsFinished();
+
+    void on_skiprawdownload_checkbox_stateChanged(int arg1);
+
+    void on_nosplashscreen_checkbox_stateChanged(int arg1);
+
+    void on_backup_create_button_clicked();
+
+    void on_backup_restore_button_clicked();
+
+    void on_backup_remove_button_clicked();
+
+    void on_patch_texts_checkbox_clicked();
+
+    void on_patch_items_checkbox_clicked();
+
+    void on_patch_emotes_checkbox_clicked();
+
+    void on_patch_maps_checkbox_clicked();
+
+    void on_patch_textures_checkbox_clicked();
+
+    void on_patch_loadscreens_checkbox_clicked();
+
+    void on_patch_sounds_checkbox_clicked();
+
+    void on_patch_video_checkbox_clicked();
+
+    void on_patch_force_apply_button_clicked();
+
+    void on_micropatch_checkbox_clicked();
+
+    void on_apply_changes_button_clicked();
+
+
 private:
-    Ui::SettingsWidget *ui;
+    bool patch_operations_running_ = false;
+
+    Ui::SettingsWidget *ui = nullptr;
+
+    PatchList *legacy_patches_ = nullptr;
 
-    PatchList *legacy_patches_;
+    SettingsWidgetPrivate::ComboboxScrollingDisabler* combobox_scrolling_disabler = nullptr;
+    SettingsWidgetPrivate::SettingsTabsScroller* scroller = nullptr;
 
-    SettingsWidgetPrivate::ComboboxScrollingDisabler* combobox_scrolling_disabler;
-    SettingsWidgetPrivate::SettingsTabsScroller* scroller;
+    Settings::SettingsBackup settings_backup_;
+    bool settings_changed_ = false;
 };
 
 #endif // SettingsWidget_H

+ 307 - 322
src/Legacy/widgets/settingswidget.ui

@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>1000</width>
-    <height>538</height>
+    <height>530</height>
    </rect>
   </property>
   <property name="sizePolicy">
@@ -50,7 +50,7 @@
      <x>25</x>
      <y>70</y>
      <width>265</width>
-     <height>321</height>
+     <height>451</height>
     </rect>
    </property>
    <layout class="QGridLayout" name="gridLayout_6">
@@ -60,29 +60,165 @@
     <property name="rightMargin">
      <number>11</number>
     </property>
+    <property name="bottomMargin">
+     <number>0</number>
+    </property>
     <property name="horizontalSpacing">
      <number>0</number>
     </property>
     <property name="verticalSpacing">
-     <number>20</number>
+     <number>15</number>
     </property>
-    <item row="0" column="0">
-     <widget class="QLabel" name="group_label_1">
+    <item row="7" column="0">
+     <widget class="QWidget" name="apply_changes_button_widget" native="true">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>0</height>
+       </size>
+      </property>
+      <layout class="QHBoxLayout" name="horizontalLayout_5">
+       <property name="spacing">
+        <number>0</number>
+       </property>
+       <property name="leftMargin">
+        <number>0</number>
+       </property>
+       <property name="topMargin">
+        <number>0</number>
+       </property>
+       <property name="rightMargin">
+        <number>0</number>
+       </property>
+       <property name="bottomMargin">
+        <number>0</number>
+       </property>
+       <item>
+        <spacer name="horizontalSpacer">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>34</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QPushButton" name="apply_changes_button">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="minimumSize">
+          <size>
+           <width>160</width>
+           <height>60</height>
+          </size>
+         </property>
+         <property name="font">
+          <font>
+           <family>Trajan Pro 3</family>
+           <pointsize>11</pointsize>
+           <weight>50</weight>
+           <bold>false</bold>
+           <kerning>false</kerning>
+          </font>
+         </property>
+         <property name="autoFillBackground">
+          <bool>false</bool>
+         </property>
+         <property name="styleSheet">
+          <string notr="true">QPushButton#apply_changes_button { 
+	color: white;
+	border-image: url(:/buttons/button_big_normal.png);
+}
+
+QPushButton#apply_changes_button:hover {
+	color: white;
+	border-image: url(:/buttons/button_big_over.png);
+}
+
+QPushButton#apply_changes_button:pressed {
+	color: white;
+	border-image: url(:/buttons/button_big_pressed.png);
+}
+
+QPushButton#apply_changes_button:disabled {
+	color: white;
+	border-image: url(:/buttons/button_big_disabled.png);
+}
+</string>
+         </property>
+         <property name="text">
+          <string notr="true">  Применить  </string>
+         </property>
+         <property name="iconSize">
+          <size>
+           <width>0</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="default">
+          <bool>false</bool>
+         </property>
+         <property name="flat">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer name="horizontalSpacer_3">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>34</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+      </layout>
+     </widget>
+    </item>
+    <item row="6" column="0">
+     <widget class="QLabel" name="patch_installing_label">
       <property name="font">
        <font>
         <family>Trajan Pro 3</family>
         <pointsize>10</pointsize>
        </font>
       </property>
+      <property name="styleSheet">
+       <string notr="true">color: red</string>
+      </property>
       <property name="text">
-       <string>I. Общие настройки</string>
+       <string>Выполняется установка русификации, изменение параметров недоступно</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignCenter</set>
       </property>
       <property name="wordWrap">
        <bool>true</bool>
       </property>
+      <property name="textInteractionFlags">
+       <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+      </property>
      </widget>
     </item>
-    <item row="3" column="0">
+    <item row="4" column="0">
      <spacer name="verticalSpacer">
       <property name="orientation">
        <enum>Qt::Vertical</enum>
@@ -95,8 +231,8 @@
       </property>
      </spacer>
     </item>
-    <item row="1" column="0">
-     <widget class="QLabel" name="group_label_2">
+    <item row="2" column="0">
+     <widget class="QLabel" name="group_label_3">
       <property name="font">
        <font>
         <family>Trajan Pro 3</family>
@@ -104,15 +240,15 @@
        </font>
       </property>
       <property name="text">
-       <string>II. Настройка резервной копии</string>
+       <string>III. Выбор компонентов русификации</string>
       </property>
       <property name="wordWrap">
        <bool>true</bool>
       </property>
      </widget>
     </item>
-    <item row="2" column="0">
-     <widget class="QLabel" name="group_label_3">
+    <item row="3" column="0">
+     <widget class="QLabel" name="group_label_4">
       <property name="font">
        <font>
         <family>Trajan Pro 3</family>
@@ -120,67 +256,67 @@
        </font>
       </property>
       <property name="text">
-       <string>III. Выбор компонентов</string>
+       <string>IV. Параметры Наследия</string>
       </property>
       <property name="wordWrap">
        <bool>true</bool>
       </property>
      </widget>
     </item>
-    <item row="0" column="1">
-     <widget class="QWidget" name="group_status_icon_1" native="true">
-      <property name="sizePolicy">
-       <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-        <horstretch>0</horstretch>
-        <verstretch>0</verstretch>
-       </sizepolicy>
+    <item row="0" column="0">
+     <widget class="QLabel" name="group_label_1">
+      <property name="font">
+       <font>
+        <family>Trajan Pro 3</family>
+        <pointsize>10</pointsize>
+       </font>
       </property>
-      <property name="minimumSize">
-       <size>
-        <width>25</width>
-        <height>25</height>
-       </size>
+      <property name="text">
+       <string>I. Параметры клиента игры</string>
       </property>
-      <property name="styleSheet">
-       <string notr="true">border-image: url(:/status/ok_icon.png);</string>
+      <property name="wordWrap">
+       <bool>true</bool>
       </property>
      </widget>
     </item>
-    <item row="2" column="1">
-     <widget class="QWidget" name="group_status_icon_3" native="true">
-      <property name="sizePolicy">
-       <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-        <horstretch>0</horstretch>
-        <verstretch>0</verstretch>
-       </sizepolicy>
+    <item row="1" column="0">
+     <widget class="QLabel" name="group_label_2">
+      <property name="font">
+       <font>
+        <family>Trajan Pro 3</family>
+        <pointsize>10</pointsize>
+       </font>
       </property>
-      <property name="minimumSize">
-       <size>
-        <width>25</width>
-        <height>25</height>
-       </size>
+      <property name="text">
+       <string>II. Параметры резервной копии</string>
       </property>
-      <property name="styleSheet">
-       <string notr="true">border-image: url(:/status/error_icon.png);</string>
+      <property name="wordWrap">
+       <bool>true</bool>
       </property>
      </widget>
     </item>
-    <item row="1" column="1">
-     <widget class="QWidget" name="group_status_icon_2" native="true">
-      <property name="sizePolicy">
-       <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-        <horstretch>0</horstretch>
-        <verstretch>0</verstretch>
-       </sizepolicy>
-      </property>
-      <property name="minimumSize">
-       <size>
-        <width>25</width>
-        <height>25</height>
-       </size>
+    <item row="5" column="0">
+     <widget class="QLabel" name="apply_changes_label">
+      <property name="font">
+       <font>
+        <family>Trajan Pro 3</family>
+        <pointsize>10</pointsize>
+       </font>
       </property>
       <property name="styleSheet">
-       <string notr="true">border-image: url(:/status/ok_icon.png);</string>
+       <string notr="true">color: red</string>
+      </property>
+      <property name="text">
+       <string>Нажмите на кнопку &quot;Применить&quot;, чтобы изменения вступили в силу!</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignCenter</set>
+      </property>
+      <property name="wordWrap">
+       <bool>true</bool>
+      </property>
+      <property name="textInteractionFlags">
+       <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
       </property>
      </widget>
     </item>
@@ -258,9 +394,9 @@ QScrollBar:vertical {
     <property name="geometry">
      <rect>
       <x>0</x>
-      <y>0</y>
+      <y>-455</y>
       <width>651</width>
-      <height>1060</height>
+      <height>976</height>
      </rect>
     </property>
     <property name="sizePolicy">
@@ -334,22 +470,6 @@ border-radius: 0px;
           </property>
          </widget>
         </item>
-        <item row="3" column="0">
-         <widget class="QCheckBox" name="skiprawdownload_checkbox">
-          <property name="font">
-           <font>
-            <family>Crimson Text</family>
-            <pointsize>11</pointsize>
-           </font>
-          </property>
-          <property name="text">
-           <string>Пропустить проверку видеороликов и экранов загрузки (ускоряет запуск игры)</string>
-          </property>
-          <property name="checked">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
         <item row="0" column="0">
          <widget class="QLabel" name="sub_entry_1_title">
           <property name="sizePolicy">
@@ -375,99 +495,20 @@ border-radius: 0px;
           </property>
          </widget>
         </item>
-        <item row="7" column="0">
-         <widget class="QWidget" name="apply_block_3" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_8">
-           <property name="spacing">
-            <number>0</number>
-           </property>
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <item>
-            <spacer name="horizontalSpacer_6">
-             <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="apply_button_entry_1">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="minimumSize">
-              <size>
-               <width>0</width>
-               <height>55</height>
-              </size>
-             </property>
-             <property name="font">
-              <font>
-               <family>Trajan Pro 3</family>
-               <pointsize>11</pointsize>
-               <weight>50</weight>
-               <bold>false</bold>
-               <kerning>false</kerning>
-              </font>
-             </property>
-             <property name="autoFillBackground">
-              <bool>false</bool>
-             </property>
-             <property name="styleSheet">
-              <string notr="true">QPushButton { 
-	color: white;
-	border-image: url(:/buttons/button_big_normal.png);
-}
-
-QPushButton:hover {
-	color: white;
-	border-image: url(:/buttons/button_big_over.png);
-}
-
-QPushButton:pressed {
-	color: white;
-	border-image: url(:/buttons/button_big_pressed.png);
-}
-
-</string>
-             </property>
-             <property name="text">
-              <string notr="true">    применить    </string>
-             </property>
-             <property name="iconSize">
-              <size>
-               <width>0</width>
-               <height>0</height>
-              </size>
-             </property>
-             <property name="default">
-              <bool>false</bool>
-             </property>
-             <property name="flat">
-              <bool>true</bool>
-             </property>
-            </widget>
-           </item>
-          </layout>
+        <item row="3" column="0">
+         <widget class="QCheckBox" name="skiprawdownload_checkbox">
+          <property name="font">
+           <font>
+            <family>Crimson Text</family>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+          <property name="text">
+           <string>Пропустить проверку видеороликов и экранов загрузки (ускоряет запуск игры)</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
          </widget>
         </item>
         <item row="2" column="0">
@@ -1125,99 +1166,23 @@ background-color: none;</string>
           </property>
          </widget>
         </item>
-        <item row="4" column="0" colspan="2">
-         <widget class="QWidget" name="apply_block" native="true">
-          <layout class="QHBoxLayout" name="horizontalLayout_6">
-           <property name="spacing">
-            <number>0</number>
-           </property>
-           <property name="leftMargin">
-            <number>0</number>
-           </property>
-           <property name="topMargin">
-            <number>0</number>
-           </property>
-           <property name="rightMargin">
-            <number>0</number>
-           </property>
-           <property name="bottomMargin">
-            <number>0</number>
-           </property>
-           <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="QPushButton" name="apply_button_entry_2">
-             <property name="sizePolicy">
-              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
-               <horstretch>0</horstretch>
-               <verstretch>0</verstretch>
-              </sizepolicy>
-             </property>
-             <property name="minimumSize">
-              <size>
-               <width>0</width>
-               <height>55</height>
-              </size>
-             </property>
-             <property name="font">
-              <font>
-               <family>Trajan Pro 3</family>
-               <pointsize>11</pointsize>
-               <weight>50</weight>
-               <bold>false</bold>
-               <kerning>false</kerning>
-              </font>
-             </property>
-             <property name="autoFillBackground">
-              <bool>false</bool>
-             </property>
-             <property name="styleSheet">
-              <string notr="true">QPushButton { 
-	color: white;
-	border-image: url(:/buttons/button_big_normal.png);
-}
-
-QPushButton:hover {
-	color: white;
-	border-image: url(:/buttons/button_big_over.png);
-}
-
-QPushButton:pressed {
-	color: white;
-	border-image: url(:/buttons/button_big_pressed.png);
-}
-
-</string>
-             </property>
-             <property name="text">
-              <string notr="true">    применить    </string>
-             </property>
-             <property name="iconSize">
-              <size>
-               <width>0</width>
-               <height>0</height>
-              </size>
-             </property>
-             <property name="default">
-              <bool>false</bool>
-             </property>
-             <property name="flat">
-              <bool>true</bool>
-             </property>
-            </widget>
-           </item>
-          </layout>
+        <item row="4" column="1">
+         <widget class="QWidget" name="patch_sounds_icon" native="true">
+          <property name="minimumSize">
+           <size>
+            <width>80</width>
+            <height>80</height>
+           </size>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>80</width>
+            <height>80</height>
+           </size>
+          </property>
+          <property name="styleSheet">
+           <string notr="true">border-image: url(:/patch_icons/zvuki-photo-normal.png);</string>
+          </property>
          </widget>
         </item>
         <item row="2" column="1">
@@ -1239,7 +1204,7 @@ QPushButton:pressed {
           </property>
          </widget>
         </item>
-        <item row="3" column="0">
+        <item row="4" column="0">
          <widget class="QWidget" name="sounds_block" native="true">
           <layout class="QVBoxLayout" name="verticalLayout_4">
            <property name="spacing">
@@ -1323,25 +1288,6 @@ QPushButton:pressed {
           </property>
          </widget>
         </item>
-        <item row="3" column="1">
-         <widget class="QWidget" name="patch_sounds_icon" native="true">
-          <property name="minimumSize">
-           <size>
-            <width>80</width>
-            <height>80</height>
-           </size>
-          </property>
-          <property name="maximumSize">
-           <size>
-            <width>80</width>
-            <height>80</height>
-           </size>
-          </property>
-          <property name="styleSheet">
-           <string notr="true">border-image: url(:/patch_icons/zvuki-photo-normal.png);</string>
-          </property>
-         </widget>
-        </item>
         <item row="1" column="0">
          <widget class="QWidget" name="texts_block" native="true">
           <layout class="QVBoxLayout" name="verticalLayout">
@@ -1511,49 +1457,7 @@ QPushButton:pressed {
         <property name="verticalSpacing">
          <number>10</number>
         </property>
-        <item row="0" column="0">
-         <widget class="QLabel" name="sub_entry_4_title">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="font">
-           <font>
-            <family>EB Garamond</family>
-            <pointsize>10</pointsize>
-           </font>
-          </property>
-          <property name="text">
-           <string>● ПАРАМЕТРЫ НАСЛЕДИЯ ●</string>
-          </property>
-          <property name="alignment">
-           <set>Qt::AlignCenter</set>
-          </property>
-          <property name="wordWrap">
-           <bool>false</bool>
-          </property>
-         </widget>
-        </item>
-        <item row="1" column="0">
-         <widget class="QCheckBox" name="micropatch_checkbox">
-          <property name="font">
-           <font>
-            <family>Crimson Text</family>
-            <pointsize>11</pointsize>
-           </font>
-          </property>
-          <property name="text">
-           <string>Устанавливать самые свежие переводы (раньше появляются, 
-но могут содержать больше ошибок)</string>
-          </property>
-          <property name="checked">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="0">
+        <item row="3" column="0">
          <widget class="QWidget" name="widget_4" native="true">
           <layout class="QHBoxLayout" name="horizontalLayout_3">
            <property name="leftMargin">
@@ -1677,6 +1581,87 @@ border-radius: 3px;</string>
           </layout>
          </widget>
         </item>
+        <item row="0" column="0">
+         <widget class="QLabel" name="sub_entry_4_title">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="font">
+           <font>
+            <family>EB Garamond</family>
+            <pointsize>10</pointsize>
+           </font>
+          </property>
+          <property name="text">
+           <string>● ПАРАМЕТРЫ НАСЛЕДИЯ ●</string>
+          </property>
+          <property name="alignment">
+           <set>Qt::AlignCenter</set>
+          </property>
+          <property name="wordWrap">
+           <bool>false</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QCheckBox" name="micropatch_checkbox">
+          <property name="font">
+           <font>
+            <family>Crimson Text</family>
+            <pointsize>11</pointsize>
+           </font>
+          </property>
+          <property name="text">
+           <string>Устанавливать самые свежие переводы (раньше появляются, 
+но могут содержать больше ошибок)</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QPushButton" name="patch_force_apply_button">
+          <property name="font">
+           <font>
+            <family>EB Garamond</family>
+            <pointsize>9</pointsize>
+           </font>
+          </property>
+          <property name="autoFillBackground">
+           <bool>false</bool>
+          </property>
+          <property name="styleSheet">
+           <string notr="true">QPushButton {
+	color: black;
+    border: 2px solid #8f8f91;
+    border-radius: 6px;
+    background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+                                      stop: 0 #f6f7fa, stop: 1 #dadbde);
+    min-width: 80px;
+}
+ 
+QPushButton:pressed {
+    background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+                                      stop: 0 #caccd3, stop: 1 #f6f7fa);
+}
+ 
+QPushButton:flat {
+    border: none; /* no border for a flat push button */
+}
+ 
+QPushButton:default {
+    border-color: navy; /* make the default button prominent */
+}</string>
+          </property>
+          <property name="text">
+           <string>Повторно применить все патчи Наследия</string>
+          </property>
+         </widget>
+        </item>
        </layout>
       </widget>
      </item>

+ 10 - 5
src/Legacy/widgets/statuswidget.ui

@@ -131,7 +131,7 @@ QScrollBar:vertical {
    <property name="geometry">
     <rect>
      <x>780</x>
-     <y>30</y>
+     <y>10</y>
      <width>201</width>
      <height>61</height>
     </rect>
@@ -147,9 +147,9 @@ QScrollBar:vertical {
    <property name="geometry">
     <rect>
      <x>310</x>
-     <y>36</y>
+     <y>16</y>
      <width>541</width>
-     <height>491</height>
+     <height>511</height>
     </rect>
    </property>
    <property name="styleSheet">
@@ -472,7 +472,7 @@ border-image: url(:/characters/galadriel_with_text.png);
     <property name="geometry">
      <rect>
       <x>0</x>
-      <y>400</y>
+      <y>420</y>
       <width>381</width>
       <height>90</height>
      </rect>
@@ -600,6 +600,11 @@ QPushButton#game_button:disabled {
    <container>1</container>
   </customwidget>
  </customwidgets>
- <resources/>
+ <resources>
+  <include location="../../../resources/backgrounds.qrc"/>
+  <include location="../../../resources/backgrounds_advanced.qrc"/>
+  <include location="../../../resources/common.qrc"/>
+  <include location="../../../resources/res.qrc"/>
+ </resources>
  <connections/>
 </ui>