deskflow/src/lib/gui/proxy/QSettingsProxy.cpp

209 lines
5.8 KiB
C++
Raw Normal View History

/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2024 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/>.
*/
#include "QSettingsProxy.h"
#include "common/constants.h"
#include "gui/Logger.h"
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QSettings>
#include <memory>
namespace synergy::gui::proxy {
const auto kLegacyOrgDomain = "http-symless-com";
const auto kLegacySystemConfigFilename = "SystemConfig.ini";
#if defined(Q_OS_UNIX)
const auto kUnixSystemConfigPath = "/usr/local/etc/";
#endif
//
// Free functions
//
/**
* @brief The base dir for the system settings file.
*
* Important: Qt will append the org name as a dir, and the app name as the
* settings filename, i.e.: `{base-dir}/Synergy/Synergy.ini`
*/
QString getSystemSettingsBaseDir() {
#if defined(Q_OS_WIN)
return QCoreApplication::applicationDirPath();
#elif defined(Q_OS_UNIX)
// Qt already adds application and filename to the end of the path.
// On macOS, it would be nice to use /Library dir, but qt has no elevate
// system.
return kUnixSystemConfigPath;
#else
#error "unsupported platform"
#endif
}
void migrateLegacySystemSettings(QSettings &settings) {
if (QFile(settings.fileName()).exists()) {
qDebug("system settings already exist, skipping migration");
return;
}
QSettings::setPath(
QSettings::IniFormat, QSettings::SystemScope,
kLegacySystemConfigFilename);
QSettings oldSystemSettings(
QSettings::IniFormat, QSettings::SystemScope,
QCoreApplication::organizationName(),
QCoreApplication::applicationName());
if (QFile(oldSystemSettings.fileName()).exists()) {
for (const auto &key : oldSystemSettings.allKeys()) {
settings.setValue(key, oldSystemSettings.value(key));
}
}
QSettings::setPath(
QSettings::IniFormat, QSettings::SystemScope, getSystemSettingsBaseDir());
}
void migrateLegacyUserSettings(QSettings &newSettings) {
QString newPath = newSettings.fileName();
QFile newFile(newPath);
if (newFile.exists()) {
qInfo("user settings already exist, skipping migration");
return;
}
QSettings oldSettings(kLegacyOrgDomain, kAppName);
QString oldPath = oldSettings.fileName();
if (oldPath.isEmpty()) {
qInfo("no legacy settings to migrate, filename empty");
return;
}
if (!QFile(oldPath).exists()) {
qInfo("no legacy settings to migrate, file does not exist");
return;
}
QFileInfo oldFileInfo(oldPath);
QFileInfo newFileInfo(newPath);
qDebug(
"migrating legacy settings: '%s' -> '%s'", //
qPrintable(oldFileInfo.fileName()), qPrintable(newFileInfo.fileName()));
QStringList keys = oldSettings.allKeys();
for (const QString &key : keys) {
QVariant oldValue = oldSettings.value(key);
newSettings.setValue(key, oldValue);
logVerbose(
QString("migrating setting '%1' = '%2'").arg(key, oldValue.toString()));
}
newSettings.sync();
}
//
// QSettingsProxy
//
void QSettingsProxy::loadUser() {
m_pSettings = std::make_unique<QSettings>();
#if defined(Q_OS_MAC)
// on mac, we used to save settings to "com.http-symless-com.Synergy.plist"
// because `setOrganizationName` was historically called using a url instead
// of an actual domain (e.g. symless.com).
migrateLegacyUserSettings(*m_pSettings);
#endif // Q_OS_MAC
}
void QSettingsProxy::loadSystem() {
auto orgName = QCoreApplication::organizationName();
if (orgName.isEmpty()) {
qFatal("unable to load config, organization name is empty");
return;
} else {
qDebug() << "org name for config:" << orgName;
}
auto appName = QCoreApplication::applicationName();
if (appName.isEmpty()) {
qFatal("unable to load config, application name is empty");
return;
} else {
qDebug() << "app name for config:" << appName;
}
QSettings::setPath(
QSettings::Format::IniFormat, QSettings::Scope::SystemScope,
getSystemSettingsBaseDir());
m_pSettings = std::make_unique<QSettings>(
QSettings::Format::IniFormat, QSettings::Scope::SystemScope, orgName,
appName);
#if defined(Q_OS_WIN)
migrateLegacySystemSettings(*m_pSettings);
#endif // Q_OS_WIN
}
int QSettingsProxy::beginReadArray(const QString &prefix) {
return m_pSettings->beginReadArray(prefix);
}
void QSettingsProxy::setArrayIndex(int i) { m_pSettings->setArrayIndex(i); }
QVariant QSettingsProxy::value(const QString &key) const {
return m_pSettings->value(key);
}
QVariant
QSettingsProxy::value(const QString &key, const QVariant &defaultValue) const {
return m_pSettings->value(key, defaultValue);
}
void QSettingsProxy::endArray() { m_pSettings->endArray(); }
void QSettingsProxy::beginWriteArray(const QString &prefix) {
m_pSettings->beginWriteArray(prefix);
}
void QSettingsProxy::setValue(const QString &key, const QVariant &value) {
m_pSettings->setValue(key, value);
}
void QSettingsProxy::beginGroup(const QString &prefix) {
m_pSettings->beginGroup(prefix);
}
void QSettingsProxy::remove(const QString &key) { m_pSettings->remove(key); }
void QSettingsProxy::endGroup() { m_pSettings->endGroup(); }
bool QSettingsProxy::isWritable() const { return m_pSettings->isWritable(); }
bool QSettingsProxy::contains(const QString &key) const {
return m_pSettings->contains(key);
}
} // namespace synergy::gui::proxy