Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEAT(client): Settings Profiles #6681

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
FEAT(client): Settings Profiles (backend)
TODO: Write commit message
Hartmnt committed Jan 5, 2025
commit 430c7fac289ca5266ae96540e3e3cffc6f051e88
1 change: 1 addition & 0 deletions src/mumble/Global.h
Original file line number Diff line number Diff line change
@@ -51,6 +51,7 @@ struct Global Q_DECL_FINAL {

MainWindow *mw;
Settings s;
Profiles profiles;
boost::shared_ptr< ServerHandler > sh;
boost::shared_ptr< AudioInput > ai;
boost::shared_ptr< AudioOutput > ao;
15 changes: 15 additions & 0 deletions src/mumble/JSONSerialization.cpp
Original file line number Diff line number Diff line change
@@ -242,6 +242,21 @@ void from_json(const nlohmann::json &j, OverlaySettings &settings) {
}


void to_json(nlohmann::json &j, const Profiles &settings) {
#define PROCESS(category, key, variable) save(j, SettingsKeys::key, settings.variable);

PROCESS_ALL_PROFILE_SETTINGS

#undef PROCESS
}

void from_json(const nlohmann::json &j, Profiles &settings) {
#define PROCESS(category, key, variable) load(j, SettingsKeys::key, settings.variable, settings.variable, true);

PROCESS_ALL_PROFILE_SETTINGS

#undef PROCESS
}

void to_json(nlohmann::json &j, const QString &string) {
j = string.toStdString();
2 changes: 2 additions & 0 deletions src/mumble/JSONSerialization.h
Original file line number Diff line number Diff line change
@@ -121,6 +121,8 @@ void to_json(nlohmann::json &j, const Settings &settings);
void from_json(const nlohmann::json &j, Settings &settings);
void to_json(nlohmann::json &j, const OverlaySettings &settings);
void from_json(const nlohmann::json &j, OverlaySettings &settings);
void to_json(nlohmann::json &j, const Profiles &settings);
void from_json(const nlohmann::json &j, Profiles &settings);

void to_json(nlohmann::json &j, const QString &string);
void from_json(const nlohmann::json &j, QString &string);
58 changes: 56 additions & 2 deletions src/mumble/Settings.cpp
Original file line number Diff line number Diff line change
@@ -151,7 +151,16 @@ void Settings::save(const QString &path) const {
throw std::runtime_error("Expected settings file to have \".json\" extension");
}

nlohmann::json settingsJSON = *this;
Profiles &profiles = Global::get().profiles;
nlohmann::json settingsJSON = profiles;
nlohmann::json &profilesJSON = settingsJSON.at(SettingsKeys::PROFILES);
nlohmann::json activeProfileJSON = *this;

qInfo("Saving settings profile '%s'", qUtf8Printable(profiles.activeProfileName));

// Replace the settings loaded from disk with the current (possibly modified) settings
profilesJSON.erase(profiles.activeProfileName.toStdString());
profilesJSON.push_back({ profiles.activeProfileName, activeProfileJSON });

QFile tmpFile(QString::fromLatin1("%1/mumble_settings.json.tmp")
.arg(QStandardPaths::writableLocation(QStandardPaths::TempLocation)));
@@ -216,6 +225,33 @@ void Settings::save() const {
}
}

void Settings::loadProfile(std::optional< QString > requestedProfile) {
Profiles &profiles = Global::get().profiles;

QString profileName;
if (!requestedProfile) {
profileName = profiles.activeProfileName;
} else {
profileName = requestedProfile.value();
}

if (!profiles.allProfiles.contains(profileName)) {
qWarning("Failed to load settings profile '%s'. Falling back to '%s'...", qUtf8Printable(profileName),
qUtf8Printable(Profiles::s_default_profile_name));
profileName = Profiles::s_default_profile_name;

if (!profiles.allProfiles.contains(profileName)) {
qWarning("Failed to load fallback settings profile '%s'", qUtf8Printable(Profiles::s_default_profile_name));
return;
}
}

qInfo("Loading settings profile '%s'", qUtf8Printable(profileName));

*this = profiles.allProfiles[profileName];
profiles.activeProfileName = profileName;
}

void Settings::load(const QString &path) {
if (path.endsWith(QLatin1String(BACKUP_FILE_EXTENSION))) {
// Trim away the backup extension
@@ -230,7 +266,16 @@ void Settings::load(const QString &path) {
try {
stream >> settingsJSON;

settingsJSON.get_to(*this);
if (settingsJSON.contains(SettingsKeys::ACTIVE_PROFILE)) {
settingsJSON.get_to(Global::get().profiles);
loadProfile();
} else {
// The file does not contain the key "SettingsKeys::ACTIVE_PROFILE"
// We assume the JSON file does not contain any profiles, because it is
// old. We load the file raw instead and convert it to the s_default_profile_name profile.
qWarning("Migrating settings file to 'default' profile");
settingsJSON.get_to(*this);
}

if (!mumbleQuitNormally) {
// These settings were saved without Mumble quitting normally afterwards. In order to prevent loading
@@ -401,6 +446,8 @@ std::size_t qHash(const ChannelTarget &target) {
return qHash(target.channelID);
}

const QString Profiles::s_default_profile_name = QLatin1String("default");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use std::string for this?


const QString Settings::cqsDefaultPushClickOn = QLatin1String(":/on.ogg");
const QString Settings::cqsDefaultPushClickOff = QLatin1String(":/off.ogg");

@@ -1222,6 +1269,7 @@ void Settings::verifySettingsKeys() const {
#define INTERMEDIATE_OPERATION categoryNames.push_back(currentCategoryName);
PROCESS_ALL_SETTINGS_WITH_INTERMEDIATE_OPERATION
PROCESS_ALL_OVERLAY_SETTINGS_WITH_INTERMEDIATE_OPERATION
PROCESS_ALL_PROFILE_SETTINGS_WITH_INTERMEDIATE_OPERATION

// Assert that all entries in categoryNames are unique
std::sort(categoryNames.begin(), categoryNames.end());
@@ -1241,6 +1289,7 @@ void Settings::verifySettingsKeys() const {
keyNames.clear();
PROCESS_ALL_SETTINGS_WITH_INTERMEDIATE_OPERATION
PROCESS_ALL_OVERLAY_SETTINGS_WITH_INTERMEDIATE_OPERATION
PROCESS_ALL_PROFILE_SETTINGS_WITH_INTERMEDIATE_OPERATION
#undef PROCESS
#undef INTERMEDIATE_OPERATION

@@ -1255,6 +1304,11 @@ void Settings::verifySettingsKeys() const {
PROCESS_ALL_OVERLAY_SETTINGS
std::sort(variableNames.begin(), variableNames.end());
assert(std::unique(variableNames.begin(), variableNames.end()) == variableNames.end());
variableNames.clear();

PROCESS_ALL_PROFILE_SETTINGS
std::sort(variableNames.begin(), variableNames.end());
assert(std::unique(variableNames.begin(), variableNames.end()) == variableNames.end());
#undef PROCESS
}

10 changes: 10 additions & 0 deletions src/mumble/Settings.h
Original file line number Diff line number Diff line change
@@ -32,9 +32,11 @@
#include <nlohmann/json_fwd.hpp>

#include <array>
#include <optional>

class QSettings;
struct MigratedPath;
struct Settings;

// Global helper classes to spread variables around across threads
// especially helpful to initialize things like the stored
@@ -184,6 +186,13 @@ struct OverlaySettings {
friend bool operator!=(const OverlaySettings &lhs, const OverlaySettings &rhs);
};

struct Profiles {
static const QString s_default_profile_name;

QString activeProfileName = s_default_profile_name;
QMap< QString, Settings > allProfiles = {};
Comment on lines +192 to +193
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where (reasonably) possible new code should prefer the use of std containers

};

struct Settings {
enum AudioTransmit { Continuous, VAD, PushToTalk };
enum VADSource { Amplitude, SignalToNoise };
@@ -566,6 +575,7 @@ struct Settings {
void save(const QString &path) const;
void save() const;

void loadProfile(std::optional< QString > requestedProfile = {});
void load(const QString &path);
void load();

4 changes: 4 additions & 0 deletions src/mumble/SettingsKeys.h
Original file line number Diff line number Diff line change
@@ -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" };
9 changes: 9 additions & 0 deletions src/mumble/SettingsMacros.h
Original file line number Diff line number Diff line change
@@ -11,6 +11,10 @@

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

#define PROFILE_SETTINGS \
PROCESS(profiles, ACTIVE_PROFILE, activeProfileName) \
PROCESS(profiles, PROFILES, allProfiles)

#define MISC_SETTINGS \
PROCESS(misc, DATABASE_LOCATION_KEY, qsDatabaseLocation) \
PROCESS(misc, IMAGE_DIRECTORY_KEY, qsImagePath) \
@@ -342,6 +346,7 @@

#define PROCESS_ALL_OVERLAY_SETTINGS OVERLAY_SETTINGS

#define PROCESS_ALL_PROFILE_SETTINGS PROFILE_SETTINGS

#define PROCESS_ALL_SETTINGS_WITH_INTERMEDIATE_OPERATION \
MISC_SETTINGS \
@@ -391,5 +396,9 @@
OVERLAY_SETTINGS \
INTERMEDIATE_OPERATION

#define PROCESS_ALL_PROFILE_SETTINGS_WITH_INTERMEDIATE_OPERATION \
PROFILE_SETTINGS \
INTERMEDIATE_OPERATION


#endif // MUMBLE_MUMBLE_SETTINGS_MACROS_H_