diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 2ea13189fd..bdb4d1f9d4 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -30,7 +30,7 @@ if (SYNERGY_ENTERPRISE) endif () if (WIN32) - set (LEGACY_GUI_RC_FILES res/win/Synergy.rc src/ConfigWriter.cpp src/ConfigWriter.h) + set (LEGACY_GUI_RC_FILES res/win/Synergy.rc) endif() add_executable (synergy WIN32 diff --git a/src/gui/src/AppConfig.cpp b/src/gui/src/AppConfig.cpp index 28e365bb91..5bb33b93ea 100644 --- a/src/gui/src/AppConfig.cpp +++ b/src/gui/src/AppConfig.cpp @@ -25,6 +25,8 @@ #include #include +#include "ConfigWriter.h" + #if defined(Q_OS_WIN) const char AppConfig::m_SynergysName[] = "synergys.exe"; const char AppConfig::m_SynergycName[] = "synergyc.exe"; @@ -81,10 +83,7 @@ static const char* logLevelNames[] = "DEBUG2" }; -AppConfig::AppConfig(QSettings* userSettings, QSettings* systemSettings) : - m_pSettings(nullptr), - m_pUserSettings(userSettings), - m_pSystemSettings(systemSettings), +AppConfig::AppConfig() : m_ScreenName(), m_Port(24800), m_Interface(), @@ -98,20 +97,41 @@ AppConfig::AppConfig(QSettings* userSettings, QSettings* systemSettings) : m_LastExpiringWarningTime(0), m_AutoConfigServer(), m_MinimizeToTray(false), - m_SettingModified(false) + m_Edition(kUnregistered), + m_LogToFile(), + m_StartedBefore(), + m_ActivationHasRun(), + m_ServerGroupChecked(), + m_UseExternalConfig(), + m_UseInternalConfig(), + m_ClientGroupChecked(), + m_LoadFromSystemScope(), { - //If user setting don't exist but system ones do, load the system settings - if (!settingsExist(userSettings) && settingsExist(systemSettings)) + using GUI::Config::ConfigWriter; + + auto writer = ConfigWriter::make(); + + //Register this class to receive global load and saves + writer->registerClass(this); + + //User settings exist and the load from system scope variable is true + if (writer->hasSetting(settingName(LoadSystemSettings), ConfigWriter::kUser) && + writer->loadSetting(settingName(LoadSystemSettings), false,ConfigWriter::kUser).toBool()) { - m_pSettings = systemSettings; + writer->setScope(ConfigWriter::kSystem); + } + //If user setting don't exist but system ones do, load the system settings + else if (!writer->hasSetting(settingName(ScreenName), ConfigWriter::kUser) && + writer->hasSetting(settingName(ScreenName), ConfigWriter::kSystem)) + { + writer->setScope(ConfigWriter::kSystem); } else { // Otherwise just load to user scope - m_pSettings = userSettings; + writer->setScope(ConfigWriter::kUser); } - Q_ASSERT(m_pSettings); + //setScope triggers a global load so no need to call it again - loadSettings(); } AppConfig::~AppConfig() @@ -188,7 +208,7 @@ bool AppConfig::autoConfig() const { QString AppConfig::autoConfigServer() const { return m_AutoConfigServer; } -void AppConfig::loadSettings(bool ignoreSystem) +void AppConfig::loadSettings() { m_ScreenName = loadSetting(ScreenName, QHostInfo::localHostName()).toString(); m_Port = loadSetting(Port, 24800).toInt(); @@ -229,15 +249,7 @@ void AppConfig::loadSettings(bool ignoreSystem) m_ClientGroupChecked = loadSetting(GroupClientCheck, true).toBool(); m_ServerHostname = loadSetting(ServerHostname).toString(); - //If this is user scope and the user chose switch to global but ignoreSystem is not set. - if (settings().scope() == QSettings::UserScope && - m_LoadFromSystemScope && - !ignoreSystem) - { - //Switch to global scope and reload settings - switchToGlobal(); - loadSettings(); - } + } void AppConfig::saveSettings() @@ -273,8 +285,7 @@ void AppConfig::saveSettings() setSetting(GroupClientCheck, m_ClientGroupChecked); setSetting(ServerHostname, m_ServerHostname); - settings().sync(); - m_SettingModified = false; + m_unsavedChanges = false; } #ifndef SYNERGY_ENTERPRISE @@ -299,8 +310,6 @@ void AppConfig::setLastVersion(const QString& version) { setSettingModified(m_lastVersion, version); } -QSettings &AppConfig::settings() { return *m_pSettings; } - void AppConfig::setScreenName(const QString &s) { setSettingModified(m_ScreenName, s); } @@ -411,87 +420,44 @@ void AppConfig::setMinimizeToTray(bool newValue) { bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; } -bool AppConfig::settingsExist(QSettings* settings) { - //Use screen name as the test to see if the settings have been saved to this location - return settings->contains(settingName(ScreenName)); -} - QString AppConfig::settingName(AppConfig::Setting name) { return m_SynergySettingsName[name]; } template void AppConfig::setSetting(AppConfig::Setting name, T value) { - settings().setValue(settingName(name), value); + using GUI::Config::ConfigWriter; + ConfigWriter::make()->setSetting(settingName(name), value); } QVariant AppConfig::loadSetting(AppConfig::Setting name, const QVariant& defaultValue) { - return settings().value(settingName(name), defaultValue); + using GUI::Config::ConfigWriter; + return ConfigWriter::make()->loadSetting(settingName(name), defaultValue); } -AppConfig::SaveChoice AppConfig::checkGlobalSave() { - if (isSystemScoped()) { - - QMessageBox query; - query.setWindowTitle(tr("Save global settings.")); - query.setText(tr("This will overwrite the settings of anybody else that uses this computer.")); - - query.addButton(QMessageBox::Save); - const auto* pBtnCancel = query.addButton(QMessageBox::Cancel); - const auto* pBtnSaveLocal = query.addButton(tr("Save to user"), QMessageBox::ActionRole); - - query.setDefaultButton(QMessageBox::Cancel); - - query.exec(); - - if(query.clickedButton() == pBtnSaveLocal) - { - return SaveToUser; - } - else if(query.clickedButton() == pBtnCancel) - { - return Cancel; - } - } - return Save; -} - -void AppConfig::switchToGlobal(bool global) { - m_settings_lock.lock(); - if (global) - { - m_pSettings = m_pSystemSettings; - } - else - { - m_pSettings = m_pUserSettings; - } - m_settings_lock.unlock(); -} void AppConfig::setLoadFromSystemScope(bool value) { - if (value && !isSystemScoped()) + using GUI::Config::ConfigWriter; + + auto writer = ConfigWriter::make(); + + if (value && writer->getScope() != ConfigWriter::kSystem) { m_LoadFromSystemScope = value; - saveSettings(); //Save user prefs - switchToGlobal(); //Switch the the System Scope - loadSettings(); //Load the settings. + writer->globalSave(); //Save user prefs + writer->setScope(ConfigWriter::kSystem); //Switch the the System Scope and reload + } - else if (!value && isSystemScoped()) + else if (!value && writer->getScope() == ConfigWriter::kSystem) { - switchToGlobal(false); // Switch to UserScope - loadSettings(true); // Load user settings ignoring System scope setting + writer->setScope(ConfigWriter::kUser); // Switch to UserScope m_LoadFromSystemScope = value; // Set the user pref saveSettings(); // Save user prefs } } bool AppConfig::isSystemScoped() const { - return m_pSettings->scope() == QSettings::SystemScope; -} - -bool AppConfig::unsavedChanges() { - return m_SettingModified; + return GUI::Config::ConfigWriter::make()->getScope() == GUI::Config::ConfigWriter::kSystem; } bool AppConfig::getServerGroupChecked() const { @@ -547,7 +513,7 @@ void AppConfig::setSettingModified(T &variable, const T& newValue) { if (variable != newValue) { variable = newValue; - m_SettingModified = true; + m_unsavedChanges = true; } } diff --git a/src/gui/src/AppConfig.h b/src/gui/src/AppConfig.h index 9c7c372486..6635e4a9ac 100644 --- a/src/gui/src/AppConfig.h +++ b/src/gui/src/AppConfig.h @@ -26,6 +26,7 @@ #include "ElevateMode.h" #include #include +#include "ConfigBase.h" // this should be incremented each time a new page is added. this is // saved to settings when the user finishes running the wizard. if @@ -52,7 +53,7 @@ enum ProcessMode { Desktop }; -class AppConfig: public QObject +class AppConfig: public QObject, public GUI::Config::ConfigBase { Q_OBJECT @@ -61,19 +62,10 @@ class AppConfig: public QObject friend class SetupWizard; public: - AppConfig(QSettings* userSettings, QSettings* systemSettings); - ~AppConfig(); + AppConfig(); + ~AppConfig() override; public: - enum SaveChoice { - Save, - Cancel, - SaveToUser - }; - - /// @brief Gets the current settings. - /// @return The scoped setting currently selected - QSettings& settings(); bool isSystemScoped() const; @@ -108,7 +100,6 @@ class AppConfig: public QObject QString synergyProgramDir() const; QString synergyLogDir() const; - bool detectPath(const QString& name, QString& path); void persistLogDir(); ElevateMode elevateMode(); @@ -127,9 +118,6 @@ class AppConfig: public QObject /// False - This will load the UserScope then set the variable and save. void setLoadFromSystemScope(bool value); - /// @brief Returns true if the setting should be set to global scope. Only useful if current scope is UserScope - bool getLoadFromSystemScope() const; - bool getServerGroupChecked() const; bool getUseExternalConfig() const; @@ -150,27 +138,9 @@ class AppConfig: public QObject void setMinimizeToTray(bool b); bool getMinimizeToTray(); - void saveSettings(); + void saveSettings() override; void setLastVersion(const QString& version); - /// @brief settingsExist Checks ths settings to see if they exist in the QSettings location - /// @return bool True if there are unsaved changes - bool unsavedChanges(); - - /// @brief settingsExist Checks ths settings to see if they exist in the QSettings location - /// @param [in] settings The QSettings object to check - /// @return True if the setting was found. - static bool settingsExist(QSettings* settings); - - /// @brief If the scope is set to system, this function will query the user - /// if they want to continue saving to global scope or switch to user scope - /// if the scope is set to User the function will just return Save - /// @return SaveChoice The choice that was selected, or Save if the scope is user already - SaveChoice checkGlobalSave(); - - /// @brief This will switch the scope to or from global - /// @param [in] global bool Defaults to true to switch to global scope, False to set to User scope - void switchToGlobal(bool global = true); protected: /// @brief The enumeration to easily access the names of the setting inside m_SynergySettingsName @@ -219,23 +189,21 @@ protected: /// @brief loads the setting from the current scope /// @param ignoreSystem should the load feature ignore the globalScope setting that was saved - void loadSettings(bool ignoreSystem = false); + void loadSettings() override; static QString settingName(AppConfig::Setting name); private: - QSettings* m_pSettings; /// @brief Contain the current settings scope - QSettings* m_pUserSettings; /// @brief Contains the setting in UserScope - QSettings* m_pSystemSettings; /// @brief Contains the setting in SystemScope + QString m_ScreenName; int m_Port; QString m_Interface; int m_LogLevel; - bool m_LogToFile; + bool m_LogToFile{}; QString m_LogFilename; int m_WizardLastRun; ProcessMode m_ProcessMode; QString m_Language; - bool m_StartedBefore; + bool m_StartedBefore{}; bool m_AutoConfig; QString m_AutoConfigServer; ElevateMode m_ElevateMode; @@ -246,20 +214,19 @@ protected: QString m_Serialkey; QString m_lastVersion; int m_LastExpiringWarningTime; - bool m_ActivationHasRun; + bool m_ActivationHasRun{}; bool m_MinimizeToTray; - bool m_ServerGroupChecked; - bool m_UseExternalConfig; + bool m_ServerGroupChecked{}; + bool m_UseExternalConfig{}; QString m_ConfigFile; - bool m_UseInternalConfig; - bool m_ClientGroupChecked; + bool m_UseInternalConfig{}; + bool m_ClientGroupChecked{}; QString m_ServerHostname; - bool m_LoadFromSystemScope; /// @brief should the setting be loaded from SystemScope + bool m_LoadFromSystemScope{}; /// @brief should the setting be loaded from SystemScope /// If the user has settings but this is true then /// system settings will be loaded instead of the users - bool m_SettingModified; /// @brief Have the setting been changed since the last save static const char m_SynergysName[]; static const char m_SynergycName[]; diff --git a/src/gui/src/ConfigBase.h b/src/gui/src/ConfigBase.h new file mode 100644 index 0000000000..5ea7389ec9 --- /dev/null +++ b/src/gui/src/ConfigBase.h @@ -0,0 +1,48 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2020 - 2020 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SYNERGY_CORE_CONFIGBASE_H +#define SYNERGY_CORE_CONFIGBASE_H + +namespace GUI { + namespace Config { + + ///@brief This abstract class will be used by all classes that use the ConfigWriter + /// to allow global saving and loading + class ConfigBase { + public : + ConfigBase() = default; + + virtual ~ConfigBase() = default; + + /// @brief The function that is called when the settings need to be loaded from file + virtual void loadSettings() = 0; + + /// @brief The function that is called when the settings need to be saved to file + virtual void saveSettings() = 0; + + /// @brief Returns true if the class has marked itself with having unsaved changes + bool modified() const { return m_unsavedChanges; } + + protected: + /// @brief Does the class have unsaved changes in it. + bool m_unsavedChanges = false; + + }; + } +} +#endif //SYNERGY_CORE_CONFIGBASE_H diff --git a/src/gui/src/ConfigWriter.cpp b/src/gui/src/ConfigWriter.cpp index 165c0fc7f6..421ffc665b 100644 --- a/src/gui/src/ConfigWriter.cpp +++ b/src/gui/src/ConfigWriter.cpp @@ -2,72 +2,203 @@ // Created by jamie on 21/04/2020. // +#include +#include +#include + #include "ConfigWriter.h" +#include "ConfigBase.h" -ConfigWriter* ConfigWriter::s_pConfiguration = nullptr; +namespace GUI { + namespace Config { + //Assignment of static variable + ConfigWriter *ConfigWriter::s_pConfiguration = nullptr; -ConfigWriter *ConfigWriter::make() { - // Only one ConfigWriter can exist at any one time (Singolton) - if (!s_pConfiguration) { - s_pConfiguration = new ConfigWriter(); - } - return s_pConfiguration; -} - -ConfigWriter::ConfigWriter() { - -} - -void ConfigWriter::destroy() { - destroy(s_pConfiguration); -} - -ConfigWriter::~ConfigWriter() { - destroy(m_pSettingsCurrent); - destroy(m_pSettingsSystem); - destroy(m_pSettingsUser); -} - -template -void ConfigWriter::setSetting(const char *name, T value) { - -} - -QVariant ConfigWriter::loadSetting(const char *name, const QVariant &defaultValue) { - return QVariant(); -} - - -void ConfigWriter::setScope(ConfigWriter::Scope scope) { - if (m_CurrentScope != scope) - { - m_CurrentScope = scope; - switch (scope) - { - case User: - m_pSettingsCurrent = m_pSettingsUser; - break; - case System: - m_pSettingsCurrent = m_pSettingsSystem; - break; + ConfigWriter *ConfigWriter::make() { + // Only one ConfigWriter can exist at any one time (Singolton) + if (!s_pConfiguration) { + s_pConfiguration = new ConfigWriter(); + } + return s_pConfiguration; } + + + ConfigWriter::ConfigWriter() { + QSettings::setPath(QSettings::Format::IniFormat, + QSettings::Scope::SystemScope, + getSystemSettingPath()); + + //Config will default to User settings if they exist, + // otherwise it will load System setting and save them to User settings + m_pSettingsSystem = new QSettings(QSettings::Format::IniFormat, + QSettings::Scope::SystemScope, + QCoreApplication::organizationName(), + QCoreApplication::applicationName()); + + m_pSettingsUser = new QSettings(QSettings::Scope::UserScope, + QCoreApplication::organizationName(), + QCoreApplication::applicationName()); + + } + + + void ConfigWriter::destroy() { + destroy(s_pConfiguration); + } + + ConfigWriter::~ConfigWriter() { + while(!m_pCallerList.empty()) { + m_pCallerList.pop_back(); + } + m_pSettingsCurrent = nullptr; //this only references other pointers + destroy(m_pSettingsSystem); + destroy(m_pSettingsUser); + } + + + bool ConfigWriter::hasSetting(const QString &name, Scope scope) const { + switch (scope){ + case kUser: + return m_pSettingsUser->contains(name); + case kSystem: + return m_pSettingsSystem->contains(name); + default: + return m_pSettingsCurrent->contains(name); + } + } + + + + QVariant ConfigWriter::loadSetting(const QString& name, const QVariant &defaultValue, Scope scope) { + switch (scope){ + case kUser: + return m_pSettingsUser->value(name, defaultValue); + case kSystem: + return m_pSettingsSystem->value(name, defaultValue); + default: + return m_pSettingsCurrent->value(name, defaultValue); + } + } + + + void ConfigWriter::setScope(ConfigWriter::Scope scope) { + if (m_CurrentScope != scope) { + m_CurrentScope = scope; + switch (scope) { + case kUser: + m_pSettingsCurrent = m_pSettingsUser; + break; + case kSystem: + m_pSettingsCurrent = m_pSettingsSystem; + break; + default: + //setScope should never be kCurrent + assert(scope); + } + + //Notify registered classes to reload + globalLoad(); + } + } + + ConfigWriter::Scope ConfigWriter::getScope() const { + return m_CurrentScope; + } + + void ConfigWriter::globalLoad() { + for (auto &i : m_pCallerList) { + i->loadSettings(); + } + } + + void ConfigWriter::globalSave() { + + //Save if there are any unsaved changes otherwise skip + if (unsavedChanges()) { + auto choice = checkSystemSave(); + + switch (choice) { + case kSaveToUser: + //Switch to local and overrun into the save case without reloading + m_CurrentScope = kUser; + m_pSettingsCurrent = m_pSettingsUser; + case kSave: + for (auto &i : m_pCallerList) { + i->saveSettings(); + } + break; + default: + break; + } + } + } + + QSettings &ConfigWriter::settings() { + return *m_pSettingsCurrent; + } + + void ConfigWriter::registerClass(ConfigBase * receiver) { + m_pCallerList.push_back(receiver); + } + + QString ConfigWriter::getSystemSettingPath() { + const QString settingFilename("SystemConfig.ini"); + QString path; +#if defined(Q_OS_WIN) + // Program file + path = ""; +#elif defined(Q_OS_DARWIN) + //Global preferances dir + // Would be nice to use /library, but QT has no elevate system in place + path = "/usr/local/etc/symless/synergy/"; +#elif defined(Q_OS_LINUX) + // /usr/local/etc/synergy + path = "/usr/local/etc/symless/synergy/"; +#else + assert("OS not supported"); +#endif + return path + settingFilename; + } + + bool ConfigWriter::unsavedChanges() const { + for (const auto &i : m_pCallerList) { + if (i->modified()){ + //If any class returns true there is no point checking more + return true; + } + } + // If this line is reached no class has unsaved changes + return false; + } + + ConfigWriter::SaveChoice ConfigWriter::checkSystemSave() const { + if (m_CurrentScope == kSystem) { + + QMessageBox query; + query.setWindowTitle(tr("Save global settings.")); + query.setText(tr("This will overwrite the settings of anybody else that uses this computer.")); + + query.addButton(QMessageBox::Save); + const auto* pBtnCancel = query.addButton(QMessageBox::Cancel); + const auto* pBtnSaveLocal = query.addButton(tr("Save to user"), QMessageBox::ActionRole); + + query.setDefaultButton(QMessageBox::Cancel); + + query.exec(); + + if(query.clickedButton() == pBtnSaveLocal) + { + return kSaveToUser; + } + else if(query.clickedButton() == pBtnCancel) + { + return kCancel; + } + } + return kSave; + } + + } -} - -ConfigWriter::Scope ConfigWriter::getScope() const { - return m_CurrentScope; -} - -void ConfigWriter::gloablLoad() { - for(auto & i : m_pCallerList) { - i->loadSettings(); - } -} - -void ConfigWriter::globalSave() { - for(auto & i : m_pCallerList) { - i->saveSettings(); - } -} - +} \ No newline at end of file diff --git a/src/gui/src/ConfigWriter.h b/src/gui/src/ConfigWriter.h index bcf659b6b0..79ba87c024 100644 --- a/src/gui/src/ConfigWriter.h +++ b/src/gui/src/ConfigWriter.h @@ -17,88 +17,135 @@ #ifndef SYNERGY_CORE_CONFIGWRITER_H #define SYNERGY_CORE_CONFIGWRITER_H - #include #include -///@brief This abstract class will be used by all classes that use the ConfigWriter -/// to allow global saving and loading -class ConfigBase { -public : - ConfigBase() = default; - virtual ~ConfigBase() = default; +/// @brief Contains GUI code +namespace GUI { + /// @brief Contains Configuration code + namespace Config { - /// @brief The function that is called when the settings need to be loaded from file - virtual void loadSettings() = 0; + //Forward declare the class referenced by pointer + class ConfigBase; - /// @brief The function that is called when the settings need to be saved to file - virtual void saveSettings() = 0; -}; + class ConfigWriter: private QObject { -class ConfigWriter { + public: -public: + /// @brief the public way to construct the configuration calls + /// The pointer returned is owned by this class and should not be stored + /// by other classes. + static ConfigWriter* make(); - /// @brief the public way to construct the configuration calls - static ConfigWriter* make(); + /// @brief the public way to destroy the configuration class + static void destroy(); - /// @brief the public way to destroy the configuration class - static void destroy(); + ~ConfigWriter() override; - ~ConfigWriter(); + ///@brief An Enumeration of all the scopes available + enum Scope { kCurrent, kSystem, kUser}; - ///@brief An Enumeration of all the scopes available - enum Scope { System, User}; + /// @brief The choice selected when saving. + enum SaveChoice { kSave, kCancel, kSaveToUser}; - /// @brief Sets the value of a setting - /// @param [in] name The Setting to be saved - /// @param [in] value The Value to be saved - template - void setSetting(const char* name, T value); + /// @brief Checks if the setting exists + /// @param [in] name The name of the setting to check + /// @param [in] scope The scope to search in + /// @return bool True if the current scope has the named setting + bool hasSetting(const QString& name, Scope scope = kCurrent) const; - /// @brief Loads a setting - /// @param [in] name The setting to be loaded - /// @param [in] defaultValue The default value of the setting - QVariant loadSetting(const char* name, const QVariant& defaultValue = QVariant()); + /// @brief Sets the value of a setting + /// @param [in] name The Setting to be saved + /// @param [in] value The Value to be saved (Templated) + /// @param [in] scope The scope to get the value from, default is current scope + template + void setSetting(const QString& name, T value, Scope scope = kCurrent); - /// @brief Changes the setting save and load location between System and User scope - /// @param [in] scope The scope to set - void setScope(Scope scope = User); + /// @brief Loads a setting + /// @param [in] name The setting to be loaded + /// @param [in] defaultValue The default value of the setting + /// @param [in] scope The scope to get the value from, default is current scope + QVariant loadSetting(const QString& name, const QVariant& defaultValue = QVariant(), Scope scope = kCurrent); - /// @brief Get the current scope the settings are loading and save from. - /// @return Scope An enum defining the current scope - Scope getScope() const; + /// @brief Changes the setting save and load location between System and User scope + /// @param [in] scope The scope to set + void setScope(Scope scope = kUser); - /// @brief trigger a config load across all registered classes - void gloablLoad(); + /// @brief Get the current scope the settings are loading and save from. + /// @return Scope An enum defining the current scope + Scope getScope() const; - /// @brief trigger a config save across all registered classes - void globalSave(); + /// @brief trigger a config load across all registered classes + void globalLoad(); -protected: + /// @brief trigger a config save across all registered classes + void globalSave(); - Scope m_CurrentScope = User; /// @brief The current scope of the settings + /// @brief Returns the current scopes settings object + /// If more specialize control into the settings is needed this can provide + /// direct access to the settings file handler + /// @return QSettings The Settings object as a reference + QSettings& settings(); - QSettings* m_pSettingsCurrent = nullptr; /// @brief The currently active settings - QSettings* m_pSettingsUser = nullptr; /// @brief The user specific settings - QSettings* m_pSettingsSystem = nullptr; /// @brief The system wide settings + /// @brief Register a class to receives globalLoad and globalSave events + /// @param [in] ConfigBase The class that will receive the events + void registerClass(ConfigBase* receiver); -private: + /// @brief Checks if any registered class has any unsaved changes + /// @return bool True if any registered class has unsaved changes + bool unsavedChanges() const; - /// @brief Contains a list all all classes that hook into the writer. - /// This allows all classes that save settings to be called an updated - /// on a save and reload by any other class - std::list m_pCallerList; + /// @brief If the scope is set to system, this function will query the user + /// if they want to continue saving to global scope or switch to user scope + /// if the scope is set to User the function will just return Save + /// @return SaveChoice The choice that was selected, or Save if the scope is user already + SaveChoice checkSystemSave() const; - /// @brief The constructor, as this is a singolton we want to control who can call the constructor - ConfigWriter(); + protected: - /// @brief the pointer of the - static ConfigWriter* s_pConfiguration; + Scope m_CurrentScope = kUser; /// @brief The current scope of the settings - /// @brief deletes pointers and sets the value to null - template static inline void destroy(T*& p) { delete p; p = 0; } -}; + QSettings* m_pSettingsCurrent = nullptr; /// @brief The currently active settings + QSettings* m_pSettingsUser = nullptr; /// @brief The user specific settings + QSettings* m_pSettingsSystem = nullptr; /// @brief The system wide settings + + private: + + /// @brief Contains a list all all classes that hook into the writer. + /// This allows all classes that save settings to be called an updated + /// on a save and reload by any other class + std::list m_pCallerList; + + /// @brief The constructor, as this is a singolton we want to control who can call the constructor + ConfigWriter(); + + /// @brief the pointer of the ConfigWriter for singolton use + static ConfigWriter* s_pConfiguration; + + /// @brief Returns the OS specific settings ini file location + static QString getSystemSettingPath(); + /// @brief deletes pointers and sets the value to null + template static inline void destroy(T*& p) { delete p; p = 0; } + }; + + // Implementation of a template function needs to be visible to all calls thus is must be in the header + // Moved so its not bulking out the class definition + template + void ConfigWriter::setSetting(const QString& name, T value, Scope scope) { + switch (scope){ + case kUser: + m_pSettingsUser->setValue(name, value); + break; + case kSystem: + m_pSettingsSystem->setValue(name, value); + break; + default: + m_pSettingsCurrent->setValue(name, value); + break; + } + } + } +} #endif //SYNERGY_CORE_CONFIGWRITER_H diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index 772378fd0b..50b1ffcb2e 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -356,21 +356,9 @@ void MainWindow::saveSettings() appConfig().setServerHostname(m_pLineEditHostname->text()); - //Save if there are any unsaved changes otherwise skip - if (appConfig().unsavedChanges()) { - auto choice = appConfig().checkGlobalSave(); + //Save everything + GUI::Config::ConfigWriter::make()->globalSave(); - switch (choice) { - case AppConfig::SaveToUser: - //Switch to local and overrun into the save case - appConfig().switchToGlobal(false); - case AppConfig::Save: - appConfig().saveSettings(); - break; - default: - break; - } - } } void MainWindow::zeroConfToggled() { diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index ce545902a2..6b34253cb8 100644 --- a/src/gui/src/MainWindow.h +++ b/src/gui/src/MainWindow.h @@ -32,6 +32,7 @@ #include "IpcClient.h" #include "Ipc.h" #include "ActivationDialog.h" +#include "ConfigWriter.h" #include @@ -164,7 +165,8 @@ public slots: void zeroConfToggled(); protected: - QSettings& settings() { return appConfig().settings(); } + // TODO This should be properly using the ConfigWriter system. + QSettings& settings() { return GUI::Config::ConfigWriter::make()->settings(); } AppConfig& appConfig() { return *m_AppConfig; } QProcess* synergyProcess() { return m_pSynergy; } void setSynergyProcess(QProcess* p) { m_pSynergy = p; } diff --git a/src/gui/src/ServerConfig.cpp b/src/gui/src/ServerConfig.cpp index 11797181c6..72519f4d1e 100644 --- a/src/gui/src/ServerConfig.cpp +++ b/src/gui/src/ServerConfig.cpp @@ -432,5 +432,7 @@ size_t ServerConfig::setClipboardSharingSize(size_t size) { } QSettings &ServerConfig::settings() { - return m_pAppConfig->settings(); + using GUI::Config::ConfigWriter; + + return ConfigWriter::make()->settings(); } diff --git a/src/gui/src/main.cpp b/src/gui/src/main.cpp index d993160cf9..9738c9697a 100644 --- a/src/gui/src/main.cpp +++ b/src/gui/src/main.cpp @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -#define TRAY_RETRY_COUNT 10 +#define TRAY_RETRY_COUNT 1 #define TRAY_RETRY_WAIT 2000 #include "QSynergyApplication.h" @@ -90,22 +90,9 @@ int main(int argc, char* argv[]) QApplication::setQuitOnLastWindowClosed(false); #endif //S - QSettings::setPath(QSettings::Format::IniFormat, - QSettings::Scope::SystemScope, - getSystemSettingPath()); - //Config will default to User settings if they exist, - // otherwise it will load System setting and save them to User settings - QSettings systemSettings(QSettings::Format::IniFormat, - QSettings::Scope::SystemScope, - QCoreApplication::organizationName(), - QCoreApplication::applicationName()); - QSettings userSettings(QSettings::Scope::UserScope, - QCoreApplication::organizationName(), - QCoreApplication::applicationName()); - - AppConfig appConfig (&userSettings, &systemSettings); + AppConfig appConfig; qRegisterMetaType("Edition"); #ifndef SYNERGY_ENTERPRISE LicenseManager licenseManager (&appConfig); @@ -160,25 +147,7 @@ int waitForTray() return true; } -QString getSystemSettingPath() -{ - const QString settingFilename("SystemConfig.ini"); - QString path; -#if defined(Q_OS_WIN) - // Program file - path = ""; -#elif defined(Q_OS_DARWIN) - //Global preferances dir - // Would be nice to use /library, but QT has no elevate system in place - path = "/usr/local/etc/symless/synergy/"; -#elif defined(Q_OS_LINUX) - // /usr/local/etc/synergy - path = "/usr/local/etc/symless/synergy/"; -#else - assert("OS not supported"); -#endif - return path + settingFilename; -} + #if defined(Q_OS_MAC) bool checkMacAssistiveDevices()