diff --git a/src/gui/src/ActivationDialog.cpp b/src/gui/src/ActivationDialog.cpp index 88948958b..e8136107f 100644 --- a/src/gui/src/ActivationDialog.cpp +++ b/src/gui/src/ActivationDialog.cpp @@ -54,7 +54,6 @@ void ActivationDialog::reject() if (QDialog::Accepted == cancelActivationDialog.exec()) { m_LicenseManager->skipActivation(); m_appConfig->activationHasRun(true); - m_appConfig->saveSettings(); } else { return; } @@ -66,7 +65,6 @@ void ActivationDialog::accept() { QMessageBox message; m_appConfig->activationHasRun(true); - m_appConfig->saveSettings(); std::pair result; try { diff --git a/src/gui/src/AppConfig.cpp b/src/gui/src/AppConfig.cpp index dbd297c65..990405078 100644 --- a/src/gui/src/AppConfig.cpp +++ b/src/gui/src/AppConfig.cpp @@ -16,26 +16,65 @@ * along with this program. If not, see . */ +#include "QSynergyApplication.h" #include "AppConfig.h" #include "QUtility.h" #include #include +#include +#include + +#include "ConfigWriter.h" #if defined(Q_OS_WIN) const char AppConfig::m_SynergysName[] = "synergys.exe"; const char AppConfig::m_SynergycName[] = "synergyc.exe"; const char AppConfig::m_SynergyLogDir[] = "log/"; +const char AppConfig::synergyConfigName[] = "synergy.sgc"; #define DEFAULT_PROCESS_MODE Service #else const char AppConfig::m_SynergysName[] = "synergys"; const char AppConfig::m_SynergycName[] = "synergyc"; const char AppConfig::m_SynergyLogDir[] = "/var/log/"; +const char AppConfig::synergyConfigName[] = "synergy.conf"; #define DEFAULT_PROCESS_MODE Desktop #endif const ElevateMode defaultElevateMode = ElevateAsNeeded; +const char* AppConfig::m_SynergySettingsName[] = { + "screenName", + "port", + "interface", + "logLevel2", + "logToFile", + "logFilename", + "wizardLastRun", + "language", + "startedBefore", + "autoConfig", + "autoConfigServer", + "elevateMode", + "elevateModeEnum", + "edition", + "cryptoEnabled", + "autoHide", + "serialKey", + "lastVersion", + "lastExpiringWarningTime", + "activationHasRun", + "minimizeToTray", + "ActivateEmail", + "loadFromSystemScope", + "groupServerChecked", + "useExternalConfig", + "configFile", + "useInternalConfig", + "groupClientChecked", + "serverHostname", +}; + static const char* logLevelNames[] = { "INFO", @@ -44,8 +83,7 @@ static const char* logLevelNames[] = "DEBUG2" }; -AppConfig::AppConfig(QSettings* settings) : - m_pSettings(settings), +AppConfig::AppConfig() : m_ScreenName(), m_Port(24800), m_Interface(), @@ -58,11 +96,42 @@ AppConfig::AppConfig(QSettings* settings) : m_AutoHide(false), m_LastExpiringWarningTime(0), m_AutoConfigServer(), - m_MinimizeToTray(false) + m_MinimizeToTray(false), + m_Edition(kUnregistered), + m_LogToFile(), + m_StartedBefore(), + m_ActivationHasRun(), + m_ServerGroupChecked(), + m_UseExternalConfig(), + m_UseInternalConfig(), + m_ClientGroupChecked(), + m_LoadFromSystemScope() { - Q_ASSERT(m_pSettings); - loadSettings(); + 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(kLoadSystemSettings), ConfigWriter::kUser) && + writer->loadSetting(settingName(kLoadSystemSettings), false, ConfigWriter::kUser).toBool()) + { + writer->setScope(ConfigWriter::kSystem); + } + //If user setting don't exist but system ones do, load the system settings + else if (!writer->hasSetting(settingName(kScreenName), ConfigWriter::kUser) && + writer->hasSetting(settingName(kScreenName), ConfigWriter::kSystem)) + { + writer->setScope(ConfigWriter::kSystem); + } else { // Otherwise just load to user scope + writer->setScope(ConfigWriter::kUser); + } + + //Notify registered classes to reload + writer->globalLoad(); + } AppConfig::~AppConfig() @@ -141,60 +210,82 @@ QString AppConfig::autoConfigServer() const { return m_AutoConfigServer; } void AppConfig::loadSettings() { - m_ScreenName = settings().value("screenName", QHostInfo::localHostName()).toString(); - m_Port = settings().value("port", 24800).toInt(); - m_Interface = settings().value("interface").toString(); - m_LogLevel = settings().value("logLevel2", 0).toInt(); // level 0: INFO - m_LogToFile = settings().value("logToFile", false).toBool(); - m_LogFilename = settings().value("logFilename", synergyLogDir() + "synergy.log").toString(); - m_WizardLastRun = settings().value("wizardLastRun", 0).toInt(); - m_Language = settings().value("language", QLocale::system().name()).toString(); - m_StartedBefore = settings().value("startedBefore", false).toBool(); - m_AutoConfig = settings().value("autoConfig", false).toBool(); - m_AutoConfigServer = settings().value("autoConfigServer", "").toString(); - QVariant elevateMode = settings().value("elevateModeEnum"); - if (!elevateMode.isValid()) { - elevateMode = settings().value ("elevateMode", - QVariant(static_cast(defaultElevateMode))); + m_ScreenName = loadSetting(kScreenName, QHostInfo::localHostName()).toString(); + m_Port = loadSetting(kPort, 24800).toInt(); + m_Interface = loadSetting(kInterfaceSetting).toString(); + m_LogLevel = loadSetting(kLogLevel, 0).toInt(); + m_LogToFile = loadSetting(kLogToFile, false).toBool(); + m_LogFilename = loadSetting(kLogFilename, synergyLogDir() + "synergy.log").toString(); + m_WizardLastRun = loadSetting(kWizardLastRun, 0).toInt(); + m_Language = loadSetting(kLanguage, QLocale::system().name()).toString(); + m_StartedBefore = loadSetting(kStartedBefore, false).toBool(); + m_AutoConfig = loadSetting(kAutoConfig, false).toBool(); + m_AutoConfigServer = loadSetting(kAutoConfigServer, "").toString(); + + { //Scope related code together + // TODO Investigate why kElevateModeEnum isn't loaded fully + QVariant elevateMode = loadSetting(kElevateModeEnum); + if (!elevateMode.isValid()) { + elevateMode = loadSetting(kElevateModeSetting, + QVariant(static_cast(defaultElevateMode))); + } + m_ElevateMode = static_cast(elevateMode.toInt()); } - m_ElevateMode = static_cast(elevateMode.toInt()); - m_Edition = static_cast(settings().value("edition", kUnregistered).toInt()); - m_ActivateEmail = settings().value("activateEmail", "").toString(); - m_CryptoEnabled = settings().value("cryptoEnabled", true).toBool(); - m_AutoHide = settings().value("autoHide", false).toBool(); - m_Serialkey = settings().value("serialKey", "").toString().trimmed(); - m_lastVersion = settings().value("lastVersion", "Unknown").toString(); - m_LastExpiringWarningTime = settings().value("lastExpiringWarningTime", 0).toInt(); - m_ActivationHasRun = settings().value("activationHasRun", false).toBool(); - m_MinimizeToTray = settings().value("minimizeToTray", false).toBool(); + + m_Edition = static_cast(loadSetting(kEditionSetting, kUnregistered).toInt()); + m_ActivateEmail = loadSetting(kActivateEmail, "").toString(); + m_CryptoEnabled = loadSetting(kCryptoEnabled, true).toBool(); + m_AutoHide = loadSetting(kAutoHide, false).toBool(); + m_Serialkey = loadSetting(kSerialKey, "").toString().trimmed(); + m_lastVersion = loadSetting(kLastVersion, "Unknown").toString(); + m_LastExpiringWarningTime = loadSetting(kLastExpireWarningTime, 0).toInt(); + m_ActivationHasRun = loadSetting(kActivationHasRun, false).toBool(); + m_MinimizeToTray = loadSetting(kMinimizeToTray, false).toBool(); + m_LoadFromSystemScope = loadSetting(kLoadSystemSettings, false).toBool(); + m_ServerGroupChecked = loadSetting(kGroupServerCheck, false).toBool(); + m_UseExternalConfig = loadSetting(kUseExternalConfig, false).toBool(); + m_ConfigFile = loadSetting(kConfigFile, QDir::homePath() + "/" + synergyConfigName).toString(); + m_UseInternalConfig = loadSetting(kUseInternalConfig, false).toBool(); + m_ClientGroupChecked = loadSetting(kGroupClientCheck, true).toBool(); + m_ServerHostname = loadSetting(kServerHostname).toString(); + + } void AppConfig::saveSettings() { - settings().setValue("screenName", m_ScreenName); - settings().setValue("port", m_Port); - settings().setValue("interface", m_Interface); - settings().setValue("logLevel2", m_LogLevel); - settings().setValue("logToFile", m_LogToFile); - settings().setValue("logFilename", m_LogFilename); - settings().setValue("wizardLastRun", kWizardVersion); - settings().setValue("language", m_Language); - settings().setValue("startedBefore", m_StartedBefore); - settings().setValue("autoConfig", m_AutoConfig); - settings().setValue("autoConfigServer", m_AutoConfigServer); + setSetting(kScreenName, m_ScreenName); + setSetting(kPort, m_Port); + setSetting(kInterfaceSetting, m_Interface); + setSetting(kLogLevel, m_LogLevel); + setSetting(kLogToFile, m_LogToFile); + setSetting(kLogFilename, m_LogFilename); + setSetting(kWizardLastRun, kWizardVersion); + setSetting(kLanguage, m_Language); + setSetting(kStartedBefore, m_StartedBefore); + setSetting(kAutoConfig, m_AutoConfig); + setSetting(kAutoConfigServer, m_AutoConfigServer); // Refer to enum ElevateMode declaration for insight in to why this // flag is mapped this way - settings().setValue("elevateMode", m_ElevateMode == ElevateAlways); - settings().setValue("elevateModeEnum", static_cast(m_ElevateMode)); - settings().setValue("edition", m_Edition); - settings().setValue("cryptoEnabled", m_CryptoEnabled); - settings().setValue("autoHide", m_AutoHide); - settings().setValue("serialKey", m_Serialkey); - settings().setValue("lastVersion", m_lastVersion); - settings().setValue("lastExpiringWarningTime", m_LastExpiringWarningTime); - settings().setValue("activationHasRun", m_ActivationHasRun); - settings().setValue("minimizeToTray", m_MinimizeToTray); - settings().sync(); + setSetting(kElevateModeSetting, m_ElevateMode == ElevateAlways); + setSetting(kElevateModeEnum, static_cast(m_ElevateMode)); + setSetting(kEditionSetting, m_Edition); + setSetting(kCryptoEnabled, m_CryptoEnabled); + setSetting(kAutoHide, m_AutoHide); + setSetting(kSerialKey, m_Serialkey); + setSetting(kLastVersion, m_lastVersion); + setSetting(kLastExpireWarningTime, m_LastExpiringWarningTime); + setSetting(kActivationHasRun, m_ActivationHasRun); + setSetting(kMinimizeToTray, m_MinimizeToTray); + setSetting(kLoadSystemSettings, m_LoadFromSystemScope); + setSetting(kGroupServerCheck, m_ServerGroupChecked); + setSetting(kUseExternalConfig, m_UseExternalConfig); + setSetting(kConfigFile, m_ConfigFile); + setSetting(kUseInternalConfig, m_UseInternalConfig); + setSetting(kGroupClientCheck, m_ClientGroupChecked); + setSetting(kServerHostname, m_ServerHostname); + + m_unsavedChanges = false; } #ifndef SYNERGY_ENTERPRISE @@ -215,54 +306,70 @@ QString AppConfig::lastVersion() const return m_lastVersion; } -void AppConfig::setLastVersion(QString version) { - m_lastVersion = version; +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); +} -void AppConfig::setScreenName(const QString &s) { m_ScreenName = s; } +void AppConfig::setPort(int i) { + setSettingModified(m_Port, i); +} -void AppConfig::setPort(int i) { m_Port = i; } +void AppConfig::setNetworkInterface(const QString &s) { + setSettingModified(m_Interface, s); +} -void AppConfig::setNetworkInterface(const QString &s) { m_Interface = s; } +void AppConfig::setLogLevel(int i) { + setSettingModified(m_LogLevel, i); +} -void AppConfig::setLogLevel(int i) { m_LogLevel = i; } +void AppConfig::setLogToFile(bool b) { + setSettingModified(m_LogToFile, b); +} -void AppConfig::setLogToFile(bool b) { m_LogToFile = b; } +void AppConfig::setLogFilename(const QString &s) { + setSettingModified(m_LogFilename, s); +} -void AppConfig::setLogFilename(const QString &s) { m_LogFilename = s; } +void AppConfig::setWizardHasRun() { + setSettingModified(m_WizardLastRun, kWizardVersion); +} -void AppConfig::setWizardHasRun() { m_WizardLastRun = kWizardVersion; } +void AppConfig::setLanguage(const QString& language) { + setSettingModified(m_Language, language); +} -void AppConfig::setLanguage(const QString language) { m_Language = language; } +void AppConfig::setStartedBefore(bool b) { + setSettingModified(m_StartedBefore, b); +} -void AppConfig::setStartedBefore(bool b) { m_StartedBefore = b; } - -void AppConfig::setElevateMode(ElevateMode em) { m_ElevateMode = em; } +void AppConfig::setElevateMode(ElevateMode em) { + setSettingModified(m_ElevateMode, em); +} void AppConfig::setAutoConfig(bool autoConfig) { - m_AutoConfig = autoConfig; + setSettingModified(m_AutoConfig, autoConfig); emit zeroConfToggled(); } -void AppConfig::setAutoConfigServer(QString autoConfigServer) +void AppConfig::setAutoConfigServer(const QString& autoConfigServer) { - m_AutoConfigServer = autoConfigServer; + setSettingModified(m_AutoConfigServer, autoConfigServer); } #ifndef SYNERGY_ENTERPRISE void AppConfig::setEdition(Edition e) { - m_Edition = e; + setSettingModified(m_Edition, e); } Edition AppConfig::edition() const { return m_Edition; } -QString AppConfig::setSerialKey(QString serial) { - using std::swap; - swap (serial, m_Serialkey); - return serial; +void AppConfig::setSerialKey(const QString& serial) { + setSettingModified(m_Serialkey, serial); } void AppConfig::clearSerialKey() @@ -274,7 +381,9 @@ QString AppConfig::serialKey() { return m_Serialkey; } int AppConfig::lastExpiringWarningTime() const { return m_LastExpiringWarningTime; } -void AppConfig::setLastExpiringWarningTime(int t) { m_LastExpiringWarningTime = t; } +void AppConfig::setLastExpiringWarningTime(int newValue) { + setSettingModified(m_LastExpiringWarningTime, newValue); +} #endif QString AppConfig::synergysName() const { return m_SynergysName; } @@ -286,9 +395,9 @@ ElevateMode AppConfig::elevateMode() return m_ElevateMode; } -void AppConfig::setCryptoEnabled(bool e) { - m_CryptoEnabled = e; - emit sslToggled(e); +void AppConfig::setCryptoEnabled(bool newValue) { + setSettingModified(m_CryptoEnabled, newValue); + emit sslToggled(m_CryptoEnabled); } bool AppConfig::getCryptoEnabled() const { @@ -299,10 +408,122 @@ bool AppConfig::getCryptoEnabled() const { m_CryptoEnabled; } -void AppConfig::setAutoHide(bool b) { m_AutoHide = b; } +void AppConfig::setAutoHide(bool b) { + setSettingModified(m_MinimizeToTray, b); +} bool AppConfig::getAutoHide() { return m_AutoHide; } -void AppConfig::setMinimizeToTray(bool b) { m_MinimizeToTray = b; } +void AppConfig::setMinimizeToTray(bool newValue) { + setSettingModified(m_MinimizeToTray, newValue); +} bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; } + +QString AppConfig::settingName(AppConfig::Setting name) { + return m_SynergySettingsName[name]; +} + +template +void AppConfig::setSetting(AppConfig::Setting name, T value) { + using GUI::Config::ConfigWriter; + ConfigWriter::make()->setSetting(settingName(name), value); +} + +QVariant AppConfig::loadSetting(AppConfig::Setting name, const QVariant& defaultValue) { + using GUI::Config::ConfigWriter; + return ConfigWriter::make()->loadSetting(settingName(name), defaultValue); +} + + +void AppConfig::setLoadFromSystemScope(bool value) { + using GUI::Config::ConfigWriter; + + auto writer = ConfigWriter::make(); + + if (value && writer->getScope() != ConfigWriter::kSystem) + { + m_LoadFromSystemScope = value; + m_unsavedChanges = true; + writer->globalSave(); //Save user prefs + writer->setScope(ConfigWriter::kSystem); //Switch the the System Scope + //If the system scope has settings, trigger a global reload, otherwise keep the current users settings + if (writer->hasSetting(settingName(kScreenName), ConfigWriter::kUser)) { + // If the system already has settings, then load them up now. + writer->globalLoad(); + } + } + else if (!value && writer->getScope() == ConfigWriter::kSystem) + { + writer->setScope(ConfigWriter::kUser); // Switch to UserScope + if (writer->hasSetting(settingName(kScreenName), ConfigWriter::kUser)) { + // If the user already has settings, then load them up now. + writer->globalLoad(); + } + m_LoadFromSystemScope = value; + m_unsavedChanges = true; + writer->globalSave(); // Save user prefs + } +} + +bool AppConfig::isSystemScoped() const { + return GUI::Config::ConfigWriter::make()->getScope() == GUI::Config::ConfigWriter::kSystem; +} + +bool AppConfig::getServerGroupChecked() const { + return m_ServerGroupChecked; +} + +bool AppConfig::getUseExternalConfig() const { + return m_UseExternalConfig; +} + +QString AppConfig::getConfigFile() const { + return m_ConfigFile; +} + +bool AppConfig::getUseInternalConfig() const { + return m_UseInternalConfig; +} + +bool AppConfig::getClientGroupChecked() const { + return m_ClientGroupChecked; +} + +QString AppConfig::getServerHostname() const { + return m_ServerHostname; +} + +void AppConfig::setServerGroupChecked(bool newValue) { + setSettingModified(m_ServerGroupChecked, newValue); +} + +void AppConfig::setUseExternalConfig(bool newValue) { + setSettingModified(m_UseExternalConfig, newValue); +} + +void AppConfig::setConfigFile(const QString& newValue) { + setSettingModified(m_ConfigFile, newValue); +} + +void AppConfig::setUseInternalConfig(bool newValue) { + setSettingModified(m_UseInternalConfig, newValue); +} + +void AppConfig::setClientGroupChecked(bool newValue) { + setSettingModified(m_ClientGroupChecked, newValue); +} + +void AppConfig::setServerHostname(const QString& newValue) { + setSettingModified(m_ServerHostname, newValue); +} + +template +void AppConfig::setSettingModified(T &variable, const T& newValue) { + if (variable != newValue) + { + variable = newValue; + m_unsavedChanges = true; + } +} + diff --git a/src/gui/src/AppConfig.h b/src/gui/src/AppConfig.h index 5ca0b3648..452899484 100644 --- a/src/gui/src/AppConfig.h +++ b/src/gui/src/AppConfig.h @@ -22,8 +22,11 @@ #include #include +#include #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 @@ -50,7 +53,7 @@ enum ProcessMode { Desktop }; -class AppConfig: public QObject +class AppConfig: public QObject, public GUI::Config::ConfigBase { Q_OBJECT @@ -59,10 +62,13 @@ class AppConfig: public QObject friend class SetupWizard; public: - AppConfig(QSettings* settings); - ~AppConfig(); + AppConfig(); + ~AppConfig() override; public: + + bool isSystemScoped() const; + const QString& screenName() const; int port() const; const QString& networkInterface() const; @@ -78,11 +84,11 @@ class AppConfig: public QObject bool autoConfig() const; void setAutoConfig(bool autoConfig); QString autoConfigServer() const; - void setAutoConfigServer(QString autoConfigServer); + void setAutoConfigServer(const QString& autoConfigServer); #ifndef SYNERGY_ENTERPRISE void setEdition(Edition); Edition edition() const; - QString setSerialKey(QString serial); + void setSerialKey(const QString& serial); void clearSerialKey(); QString serialKey(); int lastExpiringWarningTime() const; @@ -94,7 +100,6 @@ class AppConfig: public QObject QString synergyProgramDir() const; QString synergyLogDir() const; - bool detectPath(const QString& name, QString& path); void persistLogDir(); ElevateMode elevateMode(); @@ -107,17 +112,70 @@ class AppConfig: public QObject bool activationHasRun() const; AppConfig& activationHasRun(bool value); #endif + /// @brief Sets the user preference to load from SystemScope. + /// @param [in] value + /// True - This will set the variable, and save the user settings before loading the global scope settings + /// False - This will load the UserScope then set the variable and save. + void setLoadFromSystemScope(bool value); + + + bool getServerGroupChecked() const; + bool getUseExternalConfig() const; + QString getConfigFile() const; + bool getUseInternalConfig() const; + bool getClientGroupChecked() const; + QString getServerHostname() const; + + void setServerGroupChecked(bool); + void setUseExternalConfig(bool) ; + void setConfigFile(const QString&); + void setUseInternalConfig(bool) ; + void setClientGroupChecked(bool) ; + void setServerHostname(const QString&); QString lastVersion() const; void setMinimizeToTray(bool b); bool getMinimizeToTray(); - void saveSettings(); - void setLastVersion(QString version); + void saveSettings() override; + void setLastVersion(const QString& version); + protected: - QSettings& settings(); + /// @brief The enumeration to easily access the names of the setting inside m_SynergySettingsName + enum Setting { + kScreenName, + kPort, + kInterfaceSetting, + kLogLevel, + kLogToFile, + kLogFilename, + kWizardLastRun, + kLanguage, + kStartedBefore, + kAutoConfig, + kAutoConfigServer, + kElevateModeSetting, + kElevateModeEnum, + kEditionSetting, + kCryptoEnabled, + kAutoHide, + kSerialKey, + kLastVersion, + kLastExpireWarningTime, + kActivationHasRun, + kMinimizeToTray, + kActivateEmail, + kLoadSystemSettings, + kGroupServerCheck, + kUseExternalConfig, + kConfigFile, + kUseInternalConfig, + kGroupClientCheck, + kServerHostname, + }; + void setScreenName(const QString& s); void setPort(int i); void setNetworkInterface(const QString& s); @@ -125,13 +183,17 @@ protected: void setLogToFile(bool b); void setLogFilename(const QString& s); void setWizardHasRun(); - void setLanguage(const QString language); + void setLanguage(const QString& language); void setStartedBefore(bool b); void setElevateMode(ElevateMode em); - void loadSettings(); + + /// @brief loads the setting from the current scope + /// @param ignoreSystem should the load feature ignore the globalScope setting that was saved + void loadSettings() override; + static QString settingName(AppConfig::Setting name); private: - QSettings* m_pSettings; + QString m_ScreenName; int m_Port; QString m_Interface; @@ -155,10 +217,50 @@ protected: bool m_ActivationHasRun; bool m_MinimizeToTray; + bool m_ServerGroupChecked; + bool m_UseExternalConfig; + QString m_ConfigFile; + bool m_UseInternalConfig; + bool m_ClientGroupChecked; + QString m_ServerHostname; + + 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 + static const char m_SynergysName[]; static const char m_SynergycName[]; static const char m_SynergyLogDir[]; + /// @brief Contains the string values of the settings names that will be saved + static const char* m_SynergySettingsName[]; + + /// @brief Contains the name of the default configuration filename + static const char synergyConfigName[]; + + /// @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(AppConfig::Setting name, T value); + + /// @brief Loads a setting + /// @param [in] name The setting to be loaded + /// @param [in] defaultValue The default value of the setting + QVariant loadSetting(AppConfig::Setting name, const QVariant& defaultValue = QVariant()); + + /// @brief As the settings will be accessible by multiple objects this lock will ensure that + /// it cant be modified by more that one object at a time if the setting is being switched + /// from system to user. + std::mutex m_settings_lock; + + /// @brief Sets the setting in the config checking if it has changed and flagging that settings + /// needs to be saved if the setting was different + /// @param [in] variable the setting that will be changed + /// @param [in] newValue The new value of the setting + template + void setSettingModified(T& variable,const T& newValue); + signals: void sslToggled(bool enabled); void zeroConfToggled(); diff --git a/src/gui/src/ConfigBase.h b/src/gui/src/ConfigBase.h new file mode 100644 index 000000000..5ea7389ec --- /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 new file mode 100644 index 000000000..0a98003da --- /dev/null +++ b/src/gui/src/ConfigWriter.cpp @@ -0,0 +1,231 @@ +/* + * 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 . + */ + +#include + +#include +#include +#include + +#include "ConfigWriter.h" +#include "ConfigBase.h" + +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 (Singleton) + 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()); + + //Set scope to user for initially + m_pSettingsCurrent = m_pSettingsUser; + } + + + 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); + } + } + } + + 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(); + } + save(); + 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/"; +#elif defined(Q_OS_LINUX) + // QT adds application and filename to the end of the path already on linux + path = "/usr/local/etc/symless/"; + return path; +#else + assert("OS not supported"); +#endif + return path + settingFilename; + } + + bool ConfigWriter::unsavedChanges() const { + if (m_unsavedChanges) { + return true; + } + + 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; + } + + void ConfigWriter::markUnsaved() { + m_unsavedChanges = true; + } + + 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; + } + + void ConfigWriter::save() { + m_pSettingsCurrent->sync(); + m_unsavedChanges = false; + } + } +} \ No newline at end of file diff --git a/src/gui/src/ConfigWriter.h b/src/gui/src/ConfigWriter.h new file mode 100644 index 000000000..f7817ef18 --- /dev/null +++ b/src/gui/src/ConfigWriter.h @@ -0,0 +1,161 @@ +/* + * 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_CONFIGWRITER_H +#define SYNERGY_CORE_CONFIGWRITER_H + +#include +#include + +/// @brief Contains GUI code +namespace GUI { + /// @brief Contains Configuration code + namespace Config { + + //Forward declare the class referenced by pointer + class ConfigBase; + + class ConfigWriter: private QObject { + + 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 destroy the configuration class + static void destroy(); + + ~ConfigWriter() override; + + ///@brief An Enumeration of all the scopes available + enum Scope { kCurrent, kSystem, kUser}; + + /// @brief The choice selected when saving. + enum SaveChoice { kSave, kCancel, kSaveToUser}; + + /// @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 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 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 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 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 load across all registered classes + void globalLoad(); + + /// @brief trigger a config save across all registered classes + void globalSave(); + + /// @brief Saves the settings to file + void save(); + + /// @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(); + + /// @brief This marks the settings as unsaved if the settings() was used to directly affect the config file + void markUnsaved(); + + /// @brief Register a class to receives globalLoad and globalSave events + /// @param [in] ConfigBase The class that will receive the events + void registerClass(ConfigBase* receiver); + + /// @brief Checks if any registered class has any unsaved changes + /// @return bool True if any registered class has unsaved changes + bool unsavedChanges() const; + + /// @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; + + protected: + + Scope m_CurrentScope = kUser; /// @brief The current scope of the 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 + + 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 if this class modified settings then set the flag + bool m_unsavedChanges = false; + + /// @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; + } + m_unsavedChanges = true; + } + } +} +#endif //SYNERGY_CORE_CONFIGWRITER_H diff --git a/src/gui/src/LicenseManager.cpp b/src/gui/src/LicenseManager.cpp index b756bbf80..f0f09c2f3 100644 --- a/src/gui/src/LicenseManager.cpp +++ b/src/gui/src/LicenseManager.cpp @@ -62,8 +62,6 @@ LicenseManager::setSerialKey(SerialKey serialKey, bool acceptExpired) emit beginTrial(m_serialKey.isExpiring(currentTime)); } } - - m_AppConfig->saveSettings(); } return ret; @@ -118,7 +116,6 @@ void LicenseManager::refresh() setSerialKey(serialKey, true); } catch (...) { m_AppConfig->clearSerialKey(); - m_AppConfig->saveSettings(); } } if (m_serialKey.isExpired(::time(0))) { diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index 3c687e4e9..9b4da2b5d 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -36,6 +36,7 @@ #include "ProcessorArch.h" #include "SslCertificate.h" #include "Zeroconf.h" +#include #if defined(Q_OS_MAC) #include "OSXHelpers.h" @@ -96,9 +97,9 @@ static const char* synergyDefaultIconFiles[] = }; #ifdef SYNERGY_ENTERPRISE -MainWindow::MainWindow (QSettings& settings, AppConfig& appConfig) +MainWindow::MainWindow (AppConfig& appConfig) #else -MainWindow::MainWindow (QSettings& settings, AppConfig& appConfig, +MainWindow::MainWindow (AppConfig& appConfig, LicenseManager& licenseManager) #endif : @@ -107,11 +108,10 @@ MainWindow::MainWindow (QSettings& settings, AppConfig& appConfig, m_ActivationDialogRunning(false), #endif m_pZeroconf(nullptr), - m_Settings(settings), m_AppConfig(&appConfig), m_pSynergy(NULL), m_SynergyState(synergyDisconnected), - m_ServerConfig(&m_Settings, 5, 3, m_AppConfig->screenName(), this), + m_ServerConfig(5, 3, m_AppConfig->screenName(), this), m_pTempConfigFile(NULL), m_pTrayIcon(NULL), m_pTrayIconMenu(NULL), @@ -195,7 +195,6 @@ MainWindow::MainWindow (QSettings& settings, AppConfig& appConfig, QString currentVersion = m_VersionChecker.getVersion(); if (lastVersion != currentVersion) { m_AppConfig->setLastVersion (currentVersion); - m_AppConfig->saveSettings(); #ifndef SYNERGY_ENTERPRISE m_LicenseManager->notifyUpdate (lastVersion, currentVersion); #endif @@ -326,13 +325,13 @@ void MainWindow::loadSettings() { // the next two must come BEFORE loading groupServerChecked and groupClientChecked or // disabling and/or enabling the right widgets won't automatically work - m_pRadioExternalConfig->setChecked(settings().value("useExternalConfig", false).toBool()); - m_pRadioInternalConfig->setChecked(settings().value("useInternalConfig", true).toBool()); + m_pRadioExternalConfig->setChecked(appConfig().getUseExternalConfig()); + m_pRadioInternalConfig->setChecked(appConfig().getUseInternalConfig()); - m_pGroupServer->setChecked(settings().value("groupServerChecked", false).toBool()); - m_pLineEditConfigFile->setText(settings().value("configFile", QDir::homePath() + "/" + synergyConfigName).toString()); - m_pGroupClient->setChecked(settings().value("groupClientChecked", true).toBool()); - m_pLineEditHostname->setText(settings().value("serverHostname").toString()); + m_pGroupServer->setChecked(appConfig().getServerGroupChecked()); + m_pLineEditConfigFile->setText(appConfig().getConfigFile()); + m_pGroupClient->setChecked(appConfig().getClientGroupChecked()); + m_pLineEditHostname->setText(appConfig().getServerHostname()); } void MainWindow::initConnections() @@ -348,14 +347,17 @@ void MainWindow::initConnections() void MainWindow::saveSettings() { // program settings - settings().setValue("groupServerChecked", m_pGroupServer->isChecked()); - settings().setValue("useExternalConfig", m_pRadioExternalConfig->isChecked()); - settings().setValue("configFile", m_pLineEditConfigFile->text()); - settings().setValue("useInternalConfig", m_pRadioInternalConfig->isChecked()); - settings().setValue("groupClientChecked", m_pGroupClient->isChecked()); - settings().setValue("serverHostname", m_pLineEditHostname->text()); + appConfig().setServerGroupChecked(m_pGroupServer->isChecked()); + appConfig().setClientGroupChecked(m_pGroupClient->isChecked()); + appConfig().setUseExternalConfig(m_pRadioExternalConfig->isChecked()); + appConfig().setUseInternalConfig(m_pRadioInternalConfig->isChecked()); + appConfig().setConfigFile(m_pLineEditConfigFile->text()); + appConfig().setServerHostname(m_pLineEditHostname->text()); + + + //Save everything + GUI::Config::ConfigWriter::make()->globalSave(); - settings().sync(); } void MainWindow::zeroConfToggled() { @@ -494,7 +496,6 @@ void MainWindow::checkConnected(const QString& line) "the background.")); appConfig().setStartedBefore(true); - appConfig().saveSettings(); } } else if (line.contains("started server")) @@ -1457,7 +1458,6 @@ void MainWindow::on_m_pLabelAutoConfig_linkActivated(const QString &) void MainWindow::on_m_pComboServerList_currentIndexChanged(const QString &server) { appConfig().setAutoConfigServer(server); - appConfig().saveSettings(); } void MainWindow::windowStateChanged() @@ -1465,3 +1465,9 @@ void MainWindow::windowStateChanged() if (windowState() == Qt::WindowMinimized && appConfig().getMinimizeToTray()) hide(); } + +void MainWindow::closeEvent(QCloseEvent *event) { + //If the main window is closing, trigger a save + GUI::Config::ConfigWriter::make()->globalSave(); + event->accept(); +} diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index 92d7d2abc..0dd60c80e 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 @@ -95,9 +96,9 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase public: #ifdef SYNERGY_ENTERPRISE - MainWindow(QSettings& settings, AppConfig& appConfig); + MainWindow(AppConfig& appConfig); #else - MainWindow(QSettings& settings, AppConfig& appConfig, + MainWindow(AppConfig& appConfig, LicenseManager& licenseManager); #endif ~MainWindow(); @@ -164,7 +165,8 @@ public slots: void zeroConfToggled(); protected: - QSettings& settings() { return m_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; } @@ -186,6 +188,8 @@ public slots: void stopDesktop(); void changeEvent(QEvent* event); void retranslateMenuBar(); + void closeEvent(QCloseEvent *event) override; + #if defined(Q_OS_WIN) bool isServiceRunning(QString name); #else @@ -216,7 +220,6 @@ public slots: QStringList m_PendingClientNames; #endif Zeroconf* m_pZeroconf; - QSettings& m_Settings; AppConfig* m_AppConfig; QProcess* m_pSynergy; int m_SynergyState; diff --git a/src/gui/src/ServerConfig.cpp b/src/gui/src/ServerConfig.cpp index fd821e5ad..3220a5a10 100644 --- a/src/gui/src/ServerConfig.cpp +++ b/src/gui/src/ServerConfig.cpp @@ -42,22 +42,21 @@ static const struct const int serverDefaultIndex = 7; -ServerConfig::ServerConfig(QSettings* settings, int numColumns, int numRows , +ServerConfig::ServerConfig(int numColumns, int numRows , QString serverName, MainWindow* mainWindow) : - m_pSettings(settings), - m_Screens(), - m_NumColumns(numColumns), - m_NumRows(numRows), - m_ServerName(serverName), - m_IgnoreAutoConfigClient(false), - m_EnableDragAndDrop(false), - m_DisableLockToScreen(false), - m_ClipboardSharing(true), - m_ClipboardSharingSize(defaultClipboardSharingSize()), - m_pMainWindow(mainWindow) -{ - Q_ASSERT(m_pSettings); + m_Screens(), + m_NumColumns(numColumns), + m_NumRows(numRows), + m_ServerName(serverName), + m_IgnoreAutoConfigClient(false), + m_EnableDragAndDrop(false), + m_DisableLockToScreen(false), + m_ClipboardSharing(true), + m_ClipboardSharingSize(defaultClipboardSharingSize()), + m_pMainWindow(mainWindow) +{ + GUI::Config::ConfigWriter::make()->registerClass(this); loadSettings(); } @@ -142,6 +141,9 @@ void ServerConfig::saveSettings() settings().endArray(); settings().endGroup(); + + //Tell the config writer there are changes + GUI::Config::ConfigWriter::make()->markUnsaved(); } void ServerConfig::loadSettings() @@ -430,3 +432,9 @@ size_t ServerConfig::setClipboardSharingSize(size_t size) { swap (size, m_ClipboardSharingSize); return size; } + +QSettings &ServerConfig::settings() { + using GUI::Config::ConfigWriter; + + return ConfigWriter::make()->settings(); +} diff --git a/src/gui/src/ServerConfig.h b/src/gui/src/ServerConfig.h index fb3284ce5..5b989e831 100644 --- a/src/gui/src/ServerConfig.h +++ b/src/gui/src/ServerConfig.h @@ -25,6 +25,7 @@ #include "Screen.h" #include "BaseConfig.h" #include "Hotkey.h" +#include "ConfigBase.h" class QTextStream; class QSettings; @@ -32,14 +33,15 @@ class QString; class QFile; class ServerConfigDialog; class MainWindow; +class AppConfig; -class ServerConfig : public BaseConfig +class ServerConfig : public BaseConfig, public GUI::Config::ConfigBase { friend class ServerConfigDialog; friend QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config); public: - ServerConfig(QSettings* settings, int numColumns, int numRows, + ServerConfig(int numColumns, int numRows, QString serverName, MainWindow* mainWindow); ~ServerConfig(); @@ -67,15 +69,15 @@ class ServerConfig : public BaseConfig size_t clipboardSharingSize() const { return m_ClipboardSharingSize; } static size_t defaultClipboardSharingSize(); - void saveSettings(); - void loadSettings(); + void saveSettings() override; + void loadSettings() override; bool save(const QString& fileName) const; void save(QFile& file) const; int numScreens() const; int autoAddScreen(const QString name); protected: - QSettings& settings() { return *m_pSettings; } + QSettings& settings(); ScreenList& screens() { return m_Screens; } void setScreens(const ScreenList& screens) { m_Screens = screens; } void addScreen(const Screen& screen) { m_Screens.append(screen); } @@ -110,7 +112,6 @@ class ServerConfig : public BaseConfig void addToFirstEmptyGrid(const QString& clientName); private: - QSettings* m_pSettings; ScreenList m_Screens; int m_NumColumns; int m_NumRows; diff --git a/src/gui/src/SettingsDialog.cpp b/src/gui/src/SettingsDialog.cpp index 8c512a414..b8c720ec0 100644 --- a/src/gui/src/SettingsDialog.cpp +++ b/src/gui/src/SettingsDialog.cpp @@ -49,53 +49,7 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) : m_Locale.fillLanguageComboBox(m_pComboLanguage); - m_pLineEditScreenName->setText(appConfig().screenName()); - m_pSpinBoxPort->setValue(appConfig().port()); - m_pLineEditInterface->setText(appConfig().networkInterface()); - m_pComboLogLevel->setCurrentIndex(appConfig().logLevel()); - m_pCheckBoxLogToFile->setChecked(appConfig().logToFile()); - m_pLineEditLogFilename->setText(appConfig().logFilename()); - setIndexFromItemData(m_pComboLanguage, appConfig().language()); - m_pCheckBoxAutoHide->setChecked(appConfig().getAutoHide()); - m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray()); - m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); - -#if defined(Q_OS_WIN) - m_pBonjourWindows = new BonjourWindows(this, m_pMainWindow, m_appConfig); - if (m_pBonjourWindows->isRunning()) { - allowAutoConfig(); - } - - m_pComboElevate->setCurrentIndex(static_cast(appConfig().elevateMode())); - -#else - // elevate checkbox is only useful on ms windows. - m_pLabelElevate->hide(); - m_pComboElevate->hide(); - - // for linux and mac, allow auto config by default - allowAutoConfig(); -#endif - - m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); - -#ifdef SYNERGY_ENTERPRISE - - m_pCheckBoxEnableCrypto->setEnabled(true); - m_pLabelProUpgrade->hide(); - - m_pCheckBoxAutoConfig->hide(); - m_pLabelInstallBonjour->hide(); - -#else - - bool isPro = m_appConfig.edition() == kPro; - m_pCheckBoxEnableCrypto->setEnabled(isPro); - m_pLabelProUpgrade->setVisible(!isPro); - - m_pCheckBoxAutoConfig->setChecked(appConfig().autoConfig()); - -#endif + loadFromConfig(); } void SettingsDialog::accept() @@ -111,7 +65,9 @@ void SettingsDialog::accept() appConfig().setAutoHide(m_pCheckBoxAutoHide->isChecked()); appConfig().setAutoConfig(m_pCheckBoxAutoConfig->isChecked()); appConfig().setMinimizeToTray(m_pCheckBoxMinimizeToTray->isChecked()); - appConfig().saveSettings(); + + //We only need to test the System scoped Radio as they are connected + appConfig().setLoadFromSystemScope(m_pRadioSystemScope->isChecked()); QDialog::accept(); } @@ -148,6 +104,65 @@ void SettingsDialog::changeEvent(QEvent* event) } } +void SettingsDialog::loadFromConfig() { + + m_pLineEditScreenName->setText(appConfig().screenName()); + m_pSpinBoxPort->setValue(appConfig().port()); + m_pLineEditInterface->setText(appConfig().networkInterface()); + m_pComboLogLevel->setCurrentIndex(appConfig().logLevel()); + m_pCheckBoxLogToFile->setChecked(appConfig().logToFile()); + m_pLineEditLogFilename->setText(appConfig().logFilename()); + setIndexFromItemData(m_pComboLanguage, appConfig().language()); + m_pCheckBoxAutoHide->setChecked(appConfig().getAutoHide()); + m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray()); + m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); + + if (m_appConfig.isSystemScoped()) { + m_pRadioSystemScope->setChecked(true); + } + else { + m_pRadioUserScope->setChecked(true); + } + +#if defined(Q_OS_WIN) + m_pBonjourWindows = new BonjourWindows(this, m_pMainWindow, m_appConfig); + if (m_pBonjourWindows->isRunning()) { + allowAutoConfig(); + } + + m_pComboElevate->setCurrentIndex(static_cast(appConfig().elevateMode())); + +#else + // elevate checkbox is only useful on ms windows. + m_pLabelElevate->hide(); + m_pComboElevate->hide(); + + // for linux and mac, allow auto config by default + allowAutoConfig(); +#endif + + m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); + +#ifdef SYNERGY_ENTERPRISE + + m_pCheckBoxEnableCrypto->setEnabled(true); + m_pLabelProUpgrade->hide(); + + m_pCheckBoxAutoConfig->hide(); + m_pLabelInstallBonjour->hide(); + +#else + + bool isPro = m_appConfig.edition() == kPro; + m_pCheckBoxEnableCrypto->setEnabled(isPro); + m_pLabelProUpgrade->setVisible(!isPro); + + m_pCheckBoxAutoConfig->setChecked(appConfig().autoConfig()); + +#endif +} + + void SettingsDialog::allowAutoConfig() { m_pLabelInstallBonjour->hide(); @@ -185,7 +200,6 @@ void SettingsDialog::on_m_pComboLanguage_currentIndexChanged(int index) void SettingsDialog::on_m_pCheckBoxEnableCrypto_toggled(bool checked) { m_appConfig.setCryptoEnabled(checked); - m_appConfig.saveSettings(); if (checked) { SslCertificate sslCertificate; sslCertificate.generateCertificate(); @@ -199,3 +213,9 @@ void SettingsDialog::on_m_pLabelInstallBonjour_linkActivated(const QString&) m_pBonjourWindows->downloadAndInstall(); #endif } + +void SettingsDialog::on_m_pRadioSystemScope_toggled(bool checked) +{ + appConfig().setLoadFromSystemScope(checked); + loadFromConfig(); +} diff --git a/src/gui/src/SettingsDialog.h b/src/gui/src/SettingsDialog.h index 738bb4578..64596dda5 100644 --- a/src/gui/src/SettingsDialog.h +++ b/src/gui/src/SettingsDialog.h @@ -45,6 +45,9 @@ class SettingsDialog : public QDialog, public Ui::SettingsDialogBase void changeEvent(QEvent* event); AppConfig& appConfig() { return m_appConfig; } + /// @brief Causes the dialog to load all the settings from m_appConfig + void loadFromConfig(); + private: MainWindow* m_pMainWindow; AppConfig& m_appConfig; @@ -58,6 +61,10 @@ class SettingsDialog : public QDialog, public Ui::SettingsDialogBase void on_m_pCheckBoxLogToFile_stateChanged(int ); void on_m_pButtonBrowseLog_clicked(); void on_m_pLabelInstallBonjour_linkActivated(const QString &link); + + /// @brief Handles the toggling of the system scoped radio button + /// As the user scope radio is connected this will fire for either radio button + void on_m_pRadioSystemScope_toggled(bool checked); }; #endif diff --git a/src/gui/src/SettingsDialogBase.ui b/src/gui/src/SettingsDialogBase.ui index 10bcc5891..ef7fcc806 100644 --- a/src/gui/src/SettingsDialogBase.ui +++ b/src/gui/src/SettingsDialogBase.ui @@ -13,7 +13,34 @@ Settings + + + + + &Settings Scope + + + + + + System + + + true + + + + + + + User + + + + + + diff --git a/src/gui/src/main.cpp b/src/gui/src/main.cpp index 5d8a5e899..cff969fd0 100644 --- a/src/gui/src/main.cpp +++ b/src/gui/src/main.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #if defined(Q_OS_MAC) @@ -48,6 +47,7 @@ public: }; int waitForTray(); +QString getSystemSettingPath(); #if defined(Q_OS_MAC) bool checkMacAssistiveDevices(); @@ -89,8 +89,7 @@ int main(int argc, char* argv[]) QApplication::setQuitOnLastWindowClosed(false); #endif - QSettings settings; - AppConfig appConfig (&settings); + AppConfig appConfig; qRegisterMetaType("Edition"); #ifndef SYNERGY_ENTERPRISE LicenseManager licenseManager (&appConfig); @@ -101,7 +100,7 @@ int main(int argc, char* argv[]) #ifdef SYNERGY_ENTERPRISE MainWindow mainWindow(settings, appConfig); #else - MainWindow mainWindow(settings, appConfig, licenseManager); + MainWindow mainWindow(appConfig, licenseManager); #endif QObject::connect(dynamic_cast(&app), SIGNAL(aboutToQuit()), @@ -145,6 +144,8 @@ int waitForTray() return true; } + + #if defined(Q_OS_MAC) bool checkMacAssistiveDevices() {