#6538 Implemented a most of the new config system

This commit is contained in:
Jamie Newbon 2020-04-23 18:11:20 +01:00
parent 10f558d863
commit df2d31ecf8
10 changed files with 423 additions and 303 deletions

View file

@ -30,7 +30,7 @@ if (SYNERGY_ENTERPRISE)
endif () endif ()
if (WIN32) 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() endif()
add_executable (synergy WIN32 add_executable (synergy WIN32

View file

@ -25,6 +25,8 @@
#include <QtWidgets/QMessageBox> #include <QtWidgets/QMessageBox>
#include <QPushButton> #include <QPushButton>
#include "ConfigWriter.h"
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
const char AppConfig::m_SynergysName[] = "synergys.exe"; const char AppConfig::m_SynergysName[] = "synergys.exe";
const char AppConfig::m_SynergycName[] = "synergyc.exe"; const char AppConfig::m_SynergycName[] = "synergyc.exe";
@ -81,10 +83,7 @@ static const char* logLevelNames[] =
"DEBUG2" "DEBUG2"
}; };
AppConfig::AppConfig(QSettings* userSettings, QSettings* systemSettings) : AppConfig::AppConfig() :
m_pSettings(nullptr),
m_pUserSettings(userSettings),
m_pSystemSettings(systemSettings),
m_ScreenName(), m_ScreenName(),
m_Port(24800), m_Port(24800),
m_Interface(), m_Interface(),
@ -98,20 +97,41 @@ AppConfig::AppConfig(QSettings* userSettings, QSettings* systemSettings) :
m_LastExpiringWarningTime(0), m_LastExpiringWarningTime(0),
m_AutoConfigServer(), m_AutoConfigServer(),
m_MinimizeToTray(false), 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 using GUI::Config::ConfigWriter;
if (!settingsExist(userSettings) && settingsExist(systemSettings))
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 } 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() AppConfig::~AppConfig()
@ -188,7 +208,7 @@ bool AppConfig::autoConfig() const {
QString AppConfig::autoConfigServer() const { return m_AutoConfigServer; } QString AppConfig::autoConfigServer() const { return m_AutoConfigServer; }
void AppConfig::loadSettings(bool ignoreSystem) void AppConfig::loadSettings()
{ {
m_ScreenName = loadSetting(ScreenName, QHostInfo::localHostName()).toString(); m_ScreenName = loadSetting(ScreenName, QHostInfo::localHostName()).toString();
m_Port = loadSetting(Port, 24800).toInt(); m_Port = loadSetting(Port, 24800).toInt();
@ -229,15 +249,7 @@ void AppConfig::loadSettings(bool ignoreSystem)
m_ClientGroupChecked = loadSetting(GroupClientCheck, true).toBool(); m_ClientGroupChecked = loadSetting(GroupClientCheck, true).toBool();
m_ServerHostname = loadSetting(ServerHostname).toString(); 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() void AppConfig::saveSettings()
@ -273,8 +285,7 @@ void AppConfig::saveSettings()
setSetting(GroupClientCheck, m_ClientGroupChecked); setSetting(GroupClientCheck, m_ClientGroupChecked);
setSetting(ServerHostname, m_ServerHostname); setSetting(ServerHostname, m_ServerHostname);
settings().sync(); m_unsavedChanges = false;
m_SettingModified = false;
} }
#ifndef SYNERGY_ENTERPRISE #ifndef SYNERGY_ENTERPRISE
@ -299,8 +310,6 @@ void AppConfig::setLastVersion(const QString& version) {
setSettingModified(m_lastVersion, version); setSettingModified(m_lastVersion, version);
} }
QSettings &AppConfig::settings() { return *m_pSettings; }
void AppConfig::setScreenName(const QString &s) { void AppConfig::setScreenName(const QString &s) {
setSettingModified(m_ScreenName, s); setSettingModified(m_ScreenName, s);
} }
@ -411,87 +420,44 @@ void AppConfig::setMinimizeToTray(bool newValue) {
bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; } 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) { QString AppConfig::settingName(AppConfig::Setting name) {
return m_SynergySettingsName[name]; return m_SynergySettingsName[name];
} }
template<typename T> template<typename T>
void AppConfig::setSetting(AppConfig::Setting name, T value) { 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) { 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) { 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; m_LoadFromSystemScope = value;
saveSettings(); //Save user prefs writer->globalSave(); //Save user prefs
switchToGlobal(); //Switch the the System Scope writer->setScope(ConfigWriter::kSystem); //Switch the the System Scope and reload
loadSettings(); //Load the settings.
} }
else if (!value && isSystemScoped()) else if (!value && writer->getScope() == ConfigWriter::kSystem)
{ {
switchToGlobal(false); // Switch to UserScope writer->setScope(ConfigWriter::kUser); // Switch to UserScope
loadSettings(true); // Load user settings ignoring System scope setting
m_LoadFromSystemScope = value; // Set the user pref m_LoadFromSystemScope = value; // Set the user pref
saveSettings(); // Save user prefs saveSettings(); // Save user prefs
} }
} }
bool AppConfig::isSystemScoped() const { bool AppConfig::isSystemScoped() const {
return m_pSettings->scope() == QSettings::SystemScope; return GUI::Config::ConfigWriter::make()->getScope() == GUI::Config::ConfigWriter::kSystem;
}
bool AppConfig::unsavedChanges() {
return m_SettingModified;
} }
bool AppConfig::getServerGroupChecked() const { bool AppConfig::getServerGroupChecked() const {
@ -547,7 +513,7 @@ void AppConfig::setSettingModified(T &variable, const T& newValue) {
if (variable != newValue) if (variable != newValue)
{ {
variable = newValue; variable = newValue;
m_SettingModified = true; m_unsavedChanges = true;
} }
} }

View file

@ -26,6 +26,7 @@
#include "ElevateMode.h" #include "ElevateMode.h"
#include <shared/EditionType.h> #include <shared/EditionType.h>
#include <mutex> #include <mutex>
#include "ConfigBase.h"
// this should be incremented each time a new page is added. this is // this should be incremented each time a new page is added. this is
// saved to settings when the user finishes running the wizard. if // saved to settings when the user finishes running the wizard. if
@ -52,7 +53,7 @@ enum ProcessMode {
Desktop Desktop
}; };
class AppConfig: public QObject class AppConfig: public QObject, public GUI::Config::ConfigBase
{ {
Q_OBJECT Q_OBJECT
@ -61,19 +62,10 @@ class AppConfig: public QObject
friend class SetupWizard; friend class SetupWizard;
public: public:
AppConfig(QSettings* userSettings, QSettings* systemSettings); AppConfig();
~AppConfig(); ~AppConfig() override;
public: public:
enum SaveChoice {
Save,
Cancel,
SaveToUser
};
/// @brief Gets the current settings.
/// @return The scoped setting currently selected
QSettings& settings();
bool isSystemScoped() const; bool isSystemScoped() const;
@ -108,7 +100,6 @@ class AppConfig: public QObject
QString synergyProgramDir() const; QString synergyProgramDir() const;
QString synergyLogDir() const; QString synergyLogDir() const;
bool detectPath(const QString& name, QString& path);
void persistLogDir(); void persistLogDir();
ElevateMode elevateMode(); ElevateMode elevateMode();
@ -127,9 +118,6 @@ class AppConfig: public QObject
/// False - This will load the UserScope then set the variable and save. /// False - This will load the UserScope then set the variable and save.
void setLoadFromSystemScope(bool value); 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 getServerGroupChecked() const;
bool getUseExternalConfig() const; bool getUseExternalConfig() const;
@ -150,27 +138,9 @@ class AppConfig: public QObject
void setMinimizeToTray(bool b); void setMinimizeToTray(bool b);
bool getMinimizeToTray(); bool getMinimizeToTray();
void saveSettings(); void saveSettings() override;
void setLastVersion(const QString& version); 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: protected:
/// @brief The enumeration to easily access the names of the setting inside m_SynergySettingsName /// @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 /// @brief loads the setting from the current scope
/// @param ignoreSystem should the load feature ignore the globalScope setting that was saved /// @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); static QString settingName(AppConfig::Setting name);
private: 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; QString m_ScreenName;
int m_Port; int m_Port;
QString m_Interface; QString m_Interface;
int m_LogLevel; int m_LogLevel;
bool m_LogToFile; bool m_LogToFile{};
QString m_LogFilename; QString m_LogFilename;
int m_WizardLastRun; int m_WizardLastRun;
ProcessMode m_ProcessMode; ProcessMode m_ProcessMode;
QString m_Language; QString m_Language;
bool m_StartedBefore; bool m_StartedBefore{};
bool m_AutoConfig; bool m_AutoConfig;
QString m_AutoConfigServer; QString m_AutoConfigServer;
ElevateMode m_ElevateMode; ElevateMode m_ElevateMode;
@ -246,20 +214,19 @@ protected:
QString m_Serialkey; QString m_Serialkey;
QString m_lastVersion; QString m_lastVersion;
int m_LastExpiringWarningTime; int m_LastExpiringWarningTime;
bool m_ActivationHasRun; bool m_ActivationHasRun{};
bool m_MinimizeToTray; bool m_MinimizeToTray;
bool m_ServerGroupChecked; bool m_ServerGroupChecked{};
bool m_UseExternalConfig; bool m_UseExternalConfig{};
QString m_ConfigFile; QString m_ConfigFile;
bool m_UseInternalConfig; bool m_UseInternalConfig{};
bool m_ClientGroupChecked; bool m_ClientGroupChecked{};
QString m_ServerHostname; 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 /// If the user has settings but this is true then
/// system settings will be loaded instead of the users /// 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_SynergysName[];
static const char m_SynergycName[]; static const char m_SynergycName[];

48
src/gui/src/ConfigBase.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -2,72 +2,203 @@
// Created by jamie on 21/04/2020. // Created by jamie on 21/04/2020.
// //
#include <QCoreApplication>
#include <QMessageBox>
#include <QPushButton>
#include "ConfigWriter.h" #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() { ConfigWriter *ConfigWriter::make() {
// Only one ConfigWriter can exist at any one time (Singolton) // Only one ConfigWriter can exist at any one time (Singolton)
if (!s_pConfiguration) { if (!s_pConfiguration) {
s_pConfiguration = new ConfigWriter(); s_pConfiguration = new ConfigWriter();
} }
return s_pConfiguration; return s_pConfiguration;
}
ConfigWriter::ConfigWriter() {
}
void ConfigWriter::destroy() {
destroy(s_pConfiguration);
}
ConfigWriter::~ConfigWriter() {
destroy(m_pSettingsCurrent);
destroy(m_pSettingsSystem);
destroy(m_pSettingsUser);
}
template<typename T>
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() {
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();
}
}

View file

@ -17,88 +17,135 @@
#ifndef SYNERGY_CORE_CONFIGWRITER_H #ifndef SYNERGY_CORE_CONFIGWRITER_H
#define SYNERGY_CORE_CONFIGWRITER_H #define SYNERGY_CORE_CONFIGWRITER_H
#include <QVariant> #include <QVariant>
#include <QSettings> #include <QSettings>
///@brief This abstract class will be used by all classes that use the ConfigWriter /// @brief Contains GUI code
/// to allow global saving and loading namespace GUI {
class ConfigBase { /// @brief Contains Configuration code
public : namespace Config {
ConfigBase() = default;
virtual ~ConfigBase() = default;
/// @brief The function that is called when the settings need to be loaded from file //Forward declare the class referenced by pointer
virtual void loadSettings() = 0; class ConfigBase;
/// @brief The function that is called when the settings need to be saved to file class ConfigWriter: private QObject {
virtual void saveSettings() = 0;
};
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 /// @brief the public way to destroy the configuration class
static ConfigWriter* make(); static void destroy();
/// @brief the public way to destroy the configuration class ~ConfigWriter() override;
static void destroy();
~ConfigWriter(); ///@brief An Enumeration of all the scopes available
enum Scope { kCurrent, kSystem, kUser};
///@brief An Enumeration of all the scopes available /// @brief The choice selected when saving.
enum Scope { System, User}; enum SaveChoice { kSave, kCancel, kSaveToUser};
/// @brief Sets the value of a setting /// @brief Checks if the setting exists
/// @param [in] name The Setting to be saved /// @param [in] name The name of the setting to check
/// @param [in] value The Value to be saved /// @param [in] scope The scope to search in
template <typename T> /// @return bool True if the current scope has the named setting
void setSetting(const char* name, T value); bool hasSetting(const QString& name, Scope scope = kCurrent) const;
/// @brief Loads a setting /// @brief Sets the value of a setting
/// @param [in] name The setting to be loaded /// @param [in] name The Setting to be saved
/// @param [in] defaultValue The default value of the setting /// @param [in] value The Value to be saved (Templated)
QVariant loadSetting(const char* name, const QVariant& defaultValue = QVariant()); /// @param [in] scope The scope to get the value from, default is current scope
template <typename T>
void setSetting(const QString& name, T value, Scope scope = kCurrent);
/// @brief Changes the setting save and load location between System and User scope /// @brief Loads a setting
/// @param [in] scope The scope to set /// @param [in] name The setting to be loaded
void setScope(Scope scope = User); /// @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. /// @brief Changes the setting save and load location between System and User scope
/// @return Scope An enum defining the current scope /// @param [in] scope The scope to set
Scope getScope() const; void setScope(Scope scope = kUser);
/// @brief trigger a config load across all registered classes /// @brief Get the current scope the settings are loading and save from.
void gloablLoad(); /// @return Scope An enum defining the current scope
Scope getScope() const;
/// @brief trigger a config save across all registered classes /// @brief trigger a config load across all registered classes
void globalSave(); 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 /// @brief Register a class to receives globalLoad and globalSave events
QSettings* m_pSettingsUser = nullptr; /// @brief The user specific settings /// @param [in] ConfigBase The class that will receive the events
QSettings* m_pSettingsSystem = nullptr; /// @brief The system wide settings 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. /// @brief If the scope is set to system, this function will query the user
/// This allows all classes that save settings to be called an updated /// if they want to continue saving to global scope or switch to user scope
/// on a save and reload by any other class /// if the scope is set to User the function will just return Save
std::list<ConfigBase*> m_pCallerList; /// @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 protected:
ConfigWriter();
/// @brief the pointer of the Scope m_CurrentScope = kUser; /// @brief The current scope of the settings
static ConfigWriter* s_pConfiguration;
/// @brief deletes pointers and sets the value to null QSettings* m_pSettingsCurrent = nullptr; /// @brief The currently active settings
template<class T> static inline void destroy(T*& p) { delete p; p = 0; } 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<ConfigBase*> 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<class T> 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<typename T>
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 #endif //SYNERGY_CORE_CONFIGWRITER_H

View file

@ -356,21 +356,9 @@ void MainWindow::saveSettings()
appConfig().setServerHostname(m_pLineEditHostname->text()); appConfig().setServerHostname(m_pLineEditHostname->text());
//Save if there are any unsaved changes otherwise skip //Save everything
if (appConfig().unsavedChanges()) { GUI::Config::ConfigWriter::make()->globalSave();
auto choice = appConfig().checkGlobalSave();
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() { void MainWindow::zeroConfToggled() {

View file

@ -32,6 +32,7 @@
#include "IpcClient.h" #include "IpcClient.h"
#include "Ipc.h" #include "Ipc.h"
#include "ActivationDialog.h" #include "ActivationDialog.h"
#include "ConfigWriter.h"
#include <QMutex> #include <QMutex>
@ -164,7 +165,8 @@ public slots:
void zeroConfToggled(); void zeroConfToggled();
protected: 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; } AppConfig& appConfig() { return *m_AppConfig; }
QProcess* synergyProcess() { return m_pSynergy; } QProcess* synergyProcess() { return m_pSynergy; }
void setSynergyProcess(QProcess* p) { m_pSynergy = p; } void setSynergyProcess(QProcess* p) { m_pSynergy = p; }

View file

@ -432,5 +432,7 @@ size_t ServerConfig::setClipboardSharingSize(size_t size) {
} }
QSettings &ServerConfig::settings() { QSettings &ServerConfig::settings() {
return m_pAppConfig->settings(); using GUI::Config::ConfigWriter;
return ConfigWriter::make()->settings();
} }

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define TRAY_RETRY_COUNT 10 #define TRAY_RETRY_COUNT 1
#define TRAY_RETRY_WAIT 2000 #define TRAY_RETRY_WAIT 2000
#include "QSynergyApplication.h" #include "QSynergyApplication.h"
@ -90,22 +90,9 @@ int main(int argc, char* argv[])
QApplication::setQuitOnLastWindowClosed(false); QApplication::setQuitOnLastWindowClosed(false);
#endif #endif
//S //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, AppConfig appConfig;
QCoreApplication::organizationName(),
QCoreApplication::applicationName());
AppConfig appConfig (&userSettings, &systemSettings);
qRegisterMetaType<Edition>("Edition"); qRegisterMetaType<Edition>("Edition");
#ifndef SYNERGY_ENTERPRISE #ifndef SYNERGY_ENTERPRISE
LicenseManager licenseManager (&appConfig); LicenseManager licenseManager (&appConfig);
@ -160,25 +147,7 @@ int waitForTray()
return true; 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) #if defined(Q_OS_MAC)
bool checkMacAssistiveDevices() bool checkMacAssistiveDevices()