Skip to content

Commit

Permalink
FEAT(client): profiles
Browse files Browse the repository at this point in the history
  • Loading branch information
Hartmnt committed Jan 3, 2025
1 parent e64f334 commit 2ac40ad
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 22 deletions.
2 changes: 1 addition & 1 deletion src/mumble/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1224,7 +1224,7 @@ void MainWindow::openUrl(const QUrl &url) {

try {
Settings newSettings;
newSettings.load(f.fileName());
newSettings.loadFile(f.fileName());

std::swap(newSettings, Global::get().s);

Expand Down
70 changes: 50 additions & 20 deletions src/mumble/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,19 @@ void Settings::save(const QString &path) const {
throw std::runtime_error("Expected settings file to have \".json\" extension");
}

nlohmann::json settingsJSON = *this;
nlohmann::json settingsJSON = nlohmann::json::object();
settingsJSON.push_back({ SettingsKeys::ACTIVE_PROFILE, activeProfileName });

nlohmann::json profilesJSON = nlohmann::json::object();
const QString &pname = activeProfileName;
if (loadedSettingsJSON.contains(SettingsKeys::PROFILES)) {
nlohmann::json oldProfiles = loadedSettingsJSON.at(SettingsKeys::PROFILES);
// oldProfiles.erase(pname);
profilesJSON.update(oldProfiles);
}
profilesJSON.push_back({ pname, *this });

settingsJSON.push_back({ SettingsKeys::PROFILES, profilesJSON });

QFile tmpFile(QString::fromLatin1("%1/mumble_settings.json.tmp")
.arg(QStandardPaths::writableLocation(QStandardPaths::TempLocation)));
Expand Down Expand Up @@ -216,7 +228,11 @@ void Settings::save() const {
}
}

void Settings::load(const QString &path) {
void Settings::loadProfile(const nlohmann::json &profileJSON) {
profileJSON.get_to(*this);
}

void Settings::loadFile(const QString &path) {
if (path.endsWith(QLatin1String(BACKUP_FILE_EXTENSION))) {
// Trim away the backup extension
settingsLocation = path.left(path.size() - static_cast< int >(std::strlen(BACKUP_FILE_EXTENSION)));
Expand All @@ -226,11 +242,22 @@ void Settings::load(const QString &path) {

std::ifstream stream(Mumble::QtUtils::qstring_to_path(path));

nlohmann::json settingsJSON;
try {
stream >> settingsJSON;
stream >> loadedSettingsJSON;
loadedSettingsJSON.get_to(*this);

if (loadedSettingsJSON.contains(activeProfileName)) {
loadProfile(loadedSettingsJSON.at(activeProfileName));
} else if (loadedSettingsJSON.contains("default")) {
loadProfile(loadedSettingsJSON.at("default"));
} else {
// The settings JSON does not contain the configure the requested
// profile and neither the "default" profile.
// We assume the JSON file does not contain any profiles, because it is
// old and we clean it to prevent writing junk when saving.
loadedSettingsJSON.clear();
}

settingsJSON.get_to(*this);

if (!mumbleQuitNormally) {
// These settings were saved without Mumble quitting normally afterwards. In order to prevent loading
Expand All @@ -254,7 +281,7 @@ void Settings::load(const QString &path) {
if (msgBox.exec() == QMessageBox::Yes) {
// Load the backup instead
qWarning() << "Loading backup settings from" << backupPath;
load(backupPath);
loadFile(backupPath);
}
}
} else {
Expand All @@ -274,12 +301,13 @@ void Settings::load(const QString &path) {
msgBox.exec();
}
}

} catch (const nlohmann::json::parse_error &e) {
qWarning() << "Failed to load settings from" << path << "due to invalid format: " << e.what();

if (!path.endsWith(QLatin1String(BACKUP_FILE_EXTENSION)) && QFileInfo(path + BACKUP_FILE_EXTENSION).exists()) {
qWarning() << "Falling back to backup" << path + BACKUP_FILE_EXTENSION;
load(path + BACKUP_FILE_EXTENSION);
loadFile(path + BACKUP_FILE_EXTENSION);
}
}

Expand All @@ -295,11 +323,11 @@ void Settings::load() {
if (foundExisting) {
// If we found a regular settings file, then use that and be done with it
qInfo() << "Loading settings from" << settingsPath;
load(settingsPath);
loadFile(settingsPath);
} else if (QFileInfo(settingsPath + BACKUP_FILE_EXTENSION).exists()) {
// Load backup settings instead
qInfo() << "Loading backup settings from" << settingsPath + BACKUP_FILE_EXTENSION;
load(settingsPath + BACKUP_FILE_EXTENSION);
loadFile(settingsPath + BACKUP_FILE_EXTENSION);
} else {
// Otherwise check for a legacy settings file and if that is found, load settings from there
QString legacySettingsPath = findSettingsLocation(true, &foundExisting);
Expand Down Expand Up @@ -1123,8 +1151,8 @@ void Settings::legacyLoad(const QString &path) {
settings_ptr->endGroup();


// This field previously populated Settings::uiUpdateCounter, which no longer exists. We require it though, in order
// to determine whether we have to perform some migration work.
// This field previously populated Settings::uiUpdateCounter, which no longer exists. We require it though, in
// order to determine whether we have to perform some migration work.
unsigned int configVersion = 0;
LOAD(configVersion, "lastupdate");
audioWizardShown = true;
Expand Down Expand Up @@ -1198,8 +1226,10 @@ QDataStream &operator>>(QDataStream &arch, PluginSetting &setting) {

return arch;
}
A

QDataStream &operator<<(QDataStream &arch, const PluginSetting &setting) {
QDataStream &
operator<<(QDataStream &arch, const PluginSetting &setting) {
arch << setting.enabled;
arch << setting.positionalDataEnabled;
arch << setting.allowKeyboardMonitoring;
Expand Down Expand Up @@ -1261,9 +1291,9 @@ void Settings::verifySettingsKeys() const {

QString Settings::findSettingsLocation(bool legacy, bool *foundExistingFile) const {
// In order to make sure we'll find (mostly legacy) settings files, even if they end up being in a slightly
// different dir than we currently expect, we construct a search path list that we'll traverse while searching for
// the settings file. In case we find a suitable settings file within the search path, then we'll continue to use
// this path instead of creating a new one (in the location that we currently think is best to use).
// different dir than we currently expect, we construct a search path list that we'll traverse while searching
// for the settings file. In case we find a suitable settings file within the search path, then we'll continue
// to use this path instead of creating a new one (in the location that we currently think is best to use).
QStringList paths;
paths << QCoreApplication::instance()->applicationDirPath();
paths << QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
Expand Down Expand Up @@ -1300,11 +1330,11 @@ QString Settings::findSettingsLocation(bool legacy, bool *foundExistingFile) con
chosenPath = QString::fromLatin1("%1/%2")
.arg(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation))
.arg(settingsFileNames[0]);
// Note: QStandardPaths::AppConfigLocation will return a directory of the style <root>/<org>/<application> where
// <root> is the path to the general config related directory on the respective OS, <org> is the name of our
// organization and <application> is our application's name. In our case (at the time of writing this) <org> =
// <application> = Mumble, leading to a doubly nested "Mumble" directory. This should only be a cosmetic issue
// though.
// Note: QStandardPaths::AppConfigLocation will return a directory of the style <root>/<org>/<application>
// where <root> is the path to the general config related directory on the respective OS, <org> is the name
// of our organization and <application> is our application's name. In our case (at the time of writing
// this) <org> = <application> = Mumble, leading to a doubly nested "Mumble" directory. This should only be
// a cosmetic issue though.
}

return chosenPath;
Expand Down
9 changes: 8 additions & 1 deletion src/mumble/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "SSL.h"
#include "SearchDialog.h"

#include <nlohmann/json.hpp>
#include <nlohmann/json_fwd.hpp>

#include <array>
Expand Down Expand Up @@ -558,6 +559,11 @@ struct Settings {
/// A flag used in order to determine whether or not to offer loading the setting's backup file instead
bool mumbleQuitNormally = false;

// Profile
QString activeProfileName = QStringLiteral("default");
nlohmann::json loadedSettingsJSON;


bool doEcho() const;
bool doPositionalAudio() const;

Expand All @@ -566,8 +572,9 @@ struct Settings {
void save(const QString &path) const;
void save() const;

void load(const QString &path);
void load();
void loadFile(const QString &path);
void loadProfile(const nlohmann::json &profileJSON);

void legacyLoad(const QString &path = {});

Expand Down
4 changes: 4 additions & 0 deletions src/mumble/SettingsKeys.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ namespace SettingsKeys {
* loading settings.
*/

// Meta
const SettingsKey ACTIVE_PROFILE = { "active_profile" };
const SettingsKey PROFILES = { "profiles" };

// Audio settings
const SettingsKey UNMUTE_ON_UNDEAF_KEY = { "unmute_on_undeaf" };
const SettingsKey MUTE_KEY = { "mute" };
Expand Down
5 changes: 5 additions & 0 deletions src/mumble/SettingsMacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

// Mappings between SettingsKey objects and the corresponding fields in the Settings struct

#define META_SETTINGS PROCESS(meta, ACTIVE_PROFILE, activeProfileName)

#define MISC_SETTINGS \
PROCESS(misc, DATABASE_LOCATION_KEY, qsDatabaseLocation) \
PROCESS(misc, IMAGE_DIRECTORY_KEY, qsImagePath) \
Expand Down Expand Up @@ -317,6 +319,7 @@


#define PROCESS_ALL_SETTINGS \
META_SETTINGS \
MISC_SETTINGS \
AUDIO_SETTINGS \
IDLE_SETTINGS \
Expand Down Expand Up @@ -344,6 +347,8 @@


#define PROCESS_ALL_SETTINGS_WITH_INTERMEDIATE_OPERATION \
META_SETTINGS \
INTERMEDIATE_OPERATION \
MISC_SETTINGS \
INTERMEDIATE_OPERATION \
AUDIO_SETTINGS \
Expand Down

0 comments on commit 2ac40ad

Please sign in to comment.