[education/rkward] rkward: Convert (almost) all applicable settings to RKConfigValues, removing a lot of boilerplate code.

Thomas Friedrichsmeier null at kde.org
Sat Mar 12 23:15:38 GMT 2022


Git commit 42df8238687e02e4e4a53685bc442b4cde05aa16 by Thomas Friedrichsmeier.
Committed on 11/03/2022 at 23:02.
Pushed by tfry into branch 'master'.

Convert (almost) all applicable settings to RKConfigValues, removing a lot of boilerplate code.

Phew, that was a lot of settings...

M  +3    -3    rkward/settings/rksettings.cpp
M  +14   -3    rkward/settings/rksettingsmodule.h
M  +14   -33   rkward/settings/rksettingsmodulecommandeditor.cpp
M  +7    -10   rkward/settings/rksettingsmodulecommandeditor.h
M  +14   -32   rkward/settings/rksettingsmoduleconsole.cpp
M  +5    -7    rkward/settings/rksettingsmoduleconsole.h
M  +1    -12   rkward/settings/rksettingsmoduledebug.cpp
M  +2    -4    rkward/settings/rksettingsmoduledebug.h
M  +53   -64   rkward/settings/rksettingsmodulegeneral.cpp
M  +11   -13   rkward/settings/rksettingsmodulegeneral.h
M  +22   -43   rkward/settings/rksettingsmodulegraphics.cpp
M  +10   -11   rkward/settings/rksettingsmodulegraphics.h
M  +11   -21   rkward/settings/rksettingsmodulekateplugins.cpp
M  +3    -5    rkward/settings/rksettingsmodulekateplugins.h
M  +14   -33   rkward/settings/rksettingsmoduleobjectbrowser.cpp
M  +5    -8    rkward/settings/rksettingsmoduleobjectbrowser.h
M  +28   -61   rkward/settings/rksettingsmoduleoutput.cpp
M  +10   -12   rkward/settings/rksettingsmoduleoutput.h
M  +60   -67   rkward/settings/rksettingsmoduleplugins.cpp
M  +6    -7    rkward/settings/rksettingsmoduleplugins.h
M  +85   -120  rkward/settings/rksettingsmoduler.cpp [INFRASTRUCTURE]
M  +21   -25   rkward/settings/rksettingsmoduler.h
M  +12   -32   rkward/settings/rksettingsmodulewatch.cpp
M  +7    -8    rkward/settings/rksettingsmodulewatch.h
M  +0    -1    rkward/windows/rkworkplace.cpp

https://invent.kde.org/education/rkward/commit/42df8238687e02e4e4a53685bc442b4cde05aa16

diff --git a/rkward/settings/rksettings.cpp b/rkward/settings/rksettings.cpp
index 3f2df298..6b825dbd 100644
--- a/rkward/settings/rksettings.cpp
+++ b/rkward/settings/rksettings.cpp
@@ -216,7 +216,7 @@ void RKSettings::applyAll() {
 	for (auto it = modules.constBegin(); it != modules.constEnd(); ++it) {
 		if (it.value()->hasChanges()) {
 			it.value()->doApply();
-			it.value()->save (KSharedConfig::openConfig().data());
+			it.value()->save(KSharedConfig::openConfig().data());
 			tracker()->signalSettingsChange(it.key());
 		}
 	}
@@ -244,13 +244,13 @@ void RKSettings::enableApply () {
 void RKSettings::loadSettings (KConfig *config) {
 	RK_TRACE (SETTINGS);
 
-	FOREACH_SETTINGS_MODULE(loadSettings(config));
+	FOREACH_SETTINGS_MODULE(syncConfig(config, RKConfigBase::LoadConfig));
 }
 
 void RKSettings::saveSettings (KConfig *config) {
 	RK_TRACE (SETTINGS);
 
-	FOREACH_SETTINGS_MODULE(saveSettings(config));
+	FOREACH_SETTINGS_MODULE(syncConfig(config, RKConfigBase::SaveConfig));
 }
 
 #include <KAssistantDialog>
diff --git a/rkward/settings/rksettingsmodule.h b/rkward/settings/rksettingsmodule.h
index 1fb95620..40d5f7a0 100644
--- a/rkward/settings/rksettingsmodule.h
+++ b/rkward/settings/rksettingsmodule.h
@@ -37,6 +37,16 @@ class RKConfigBase {
 public:
 	virtual void loadConfig(KConfigGroup &cg) = 0;
 	virtual void saveConfig(KConfigGroup &cg) const = 0;
+	enum ConfigSyncAction {
+		SaveConfig,
+		LoadConfig
+	};
+	/** Save or load config value (a somewhat dirty trick that saves a lot of tying... */
+	void syncConfig(KConfigGroup &cg, ConfigSyncAction a) {
+		if (a == SaveConfig) saveConfig(cg);
+		else loadConfig(cg);
+	};
+	const char *key() { return name; }
 protected:
 	RKConfigBase(const char* name) : name(name) {};
 	virtual ~RKConfigBase() {};
@@ -46,19 +56,20 @@ protected:
 /** A single value stored in the RKWard config file.
  *
  *  The value set initially (in the constructor or via setDefaultValue() represents the default value. */
-template<typename T> class RKConfigValue : public RKConfigBase {
+template<typename T, typename STORAGE_T=T> class RKConfigValue : public RKConfigBase {
 public:
 	RKConfigValue(const char* name, const T &default_value) : RKConfigBase(name), value(default_value) {};
 	~RKConfigValue() {};
 
 	void loadConfig(KConfigGroup &cg) override {
-		value = cg.readEntry(name, value);
+		value = (T) cg.readEntry(name, (STORAGE_T) value);
 	}
 	void saveConfig(KConfigGroup &cg) const override {
-		cg.writeEntry(name, value);
+		cg.writeEntry(name, (STORAGE_T) value);
 	}
 	void setDefaultValue(const T& value) { RKConfigValue<T>::value = value; }
 	operator T() const { return(value); }
+	T& get() { return(value); }
 	RKConfigValue& operator= (const T v) { value = v; return *this; };
 
 /** Only for bool values: convenience function to create a fully connected checkbox for this option */
diff --git a/rkward/settings/rksettingsmodulecommandeditor.cpp b/rkward/settings/rksettingsmodulecommandeditor.cpp
index 7fc3666f..14b4686a 100644
--- a/rkward/settings/rksettingsmodulecommandeditor.cpp
+++ b/rkward/settings/rksettingsmodulecommandeditor.cpp
@@ -37,11 +37,11 @@
 
 // static members
 RKCodeCompletionSettings RKSettingsModuleCommandEditor::completion_settings;
-bool RKSettingsModuleCommandEditor::autosave_enabled;
+RKConfigValue<bool> RKSettingsModuleCommandEditor::autosave_enabled { "Autosave enabled", true };
 RKConfigValue<bool> RKSettingsModuleCommandEditor::autosave_keep { "Autosave keep saves", false };
-int RKSettingsModuleCommandEditor::autosave_interval;
-int RKSettingsModuleCommandEditor::num_recent_files;
-QString RKSettingsModuleCommandEditor::script_file_filter;
+RKConfigValue<int> RKSettingsModuleCommandEditor::autosave_interval {"Autosave interval", 5 };
+RKConfigValue<int> RKSettingsModuleCommandEditor::num_recent_files { "Max number of recent files", 10 };
+RKConfigValue<QString> RKSettingsModuleCommandEditor::script_file_filter { "Script file filter", "*.R *.S *.q *.Rhistory" };
 
 RKCodeCompletionSettingsWidget::RKCodeCompletionSettingsWidget(QWidget *parent, RKSettingsModule *module, RKCodeCompletionSettings *settings, bool show_common) : RKSettingsModuleWidget(parent, module), settings(settings), show_common(show_common) {
 	RK_TRACE (SETTINGS);
@@ -213,11 +213,6 @@ void RKSettingsModuleCommandEditor::applyChanges () {
 	script_file_filter = script_file_filter_box->text ();
 }
 
-void RKSettingsModuleCommandEditor::save (KConfig *config) {
-	RK_TRACE (SETTINGS);
-	saveSettings (config);
-}
-
 QString completionTypeToConfigKey (int cat) {
 	if (cat == RKCodeCompletionSettings::Calltip) return "Calltips";
 	if (cat == RKCodeCompletionSettings::Arghint) return "Argument completion";
@@ -228,39 +223,25 @@ QString completionTypeToConfigKey (int cat) {
 	return QString ();
 }
 
-void RKSettingsModuleCommandEditor::saveSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("Command Editor Windows");
-	completion_settings.saveSettings(cg);
-
-	cg.writeEntry ("Autosave enabled", autosave_enabled);
-	autosave_keep.saveConfig(cg);
-	cg.writeEntry ("Autosave interval", autosave_interval);
-
-	cg.writeEntry ("Max number of recent files", num_recent_files);
-	cg.writeEntry ("Script file filter", script_file_filter);
-}
-
-void RKSettingsModuleCommandEditor::loadSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
+void RKSettingsModuleCommandEditor::syncConfig(KConfig* config, RKConfigBase::ConfigSyncAction a) {
+	RK_TRACE(SETTINGS);
 
-	KConfigGroup cg = config->group ("Command Editor Windows");
-	completion_settings.loadSettings(cg);
+	KConfigGroup cg = config->group("Command Editor Windows");
+	completion_settings.syncConfig(cg, a);
 
-	autosave_enabled = cg.readEntry ("Autosave enabled", true);
-	autosave_keep.loadConfig(cg);
-	autosave_interval = cg.readEntry ("Autosave interval", 5);
+	autosave_enabled.syncConfig(cg, a);
+	autosave_keep.syncConfig(cg, a);
+	autosave_interval.syncConfig(cg, a);
 
-	num_recent_files = cg.readEntry ("Max number of recent files", 10);
-	script_file_filter = cg.readEntry ("Script file filter", "*.R *.S *.q *.Rhistory");
+	num_recent_files.syncConfig(cg, a);
+	script_file_filter.syncConfig(cg, a);
 }
 
 // static
 bool RKSettingsModuleCommandEditor::matchesScriptFileFilter (const QString &filename) {
 	RK_TRACE (SETTINGS);
 
-	const QStringList exts = script_file_filter.split (' ');
+	const QStringList exts = script_file_filter.get().split(' ');
 	foreach (const QString& ext, exts) {
 		QRegExp reg (ext, Qt::CaseInsensitive, QRegExp::Wildcard);
 		if (reg.exactMatch (filename)) return true;
diff --git a/rkward/settings/rksettingsmodulecommandeditor.h b/rkward/settings/rksettingsmodulecommandeditor.h
index 7b75ba98..319fe07a 100644
--- a/rkward/settings/rksettingsmodulecommandeditor.h
+++ b/rkward/settings/rksettingsmodulecommandeditor.h
@@ -32,8 +32,7 @@ public:
 	RKCodeCompletionSettings() {};
 	~RKCodeCompletionSettings() {};
 
-	void loadSettings(KConfigGroup &config) { group.loadConfig(config); };
-	void saveSettings(KConfigGroup &config) { group.saveConfig(config); };
+	void syncConfig(KConfigGroup &cg, RKConfigBase::ConfigSyncAction a) { group.syncConfig(cg, a); };
 
 	// NOTE: Don't insert values inbetween existing values, without also adjusting the sloppy config load/save/apply code
 	enum CompletionCategories {
@@ -102,10 +101,8 @@ public:
 	~RKSettingsModuleCommandEditor ();
 	
 	void applyChanges () override;
-	void save (KConfig *config) override;
-
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	void save (KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*) {};
 
 	QString caption () override;
@@ -122,9 +119,9 @@ public:
 	static bool matchesScriptFileFilter (const QString &filename);
 private:
 	static RKCodeCompletionSettings completion_settings;
-	static bool autosave_enabled;
+	static RKConfigValue<bool> autosave_enabled;
 	static RKConfigValue<bool> autosave_keep;
-	static int autosave_interval;
+	static RKConfigValue<int> autosave_interval;
 
 	RKCodeCompletionSettingsWidget *completion_settings_widget;
 	QGroupBox* autosave_enabled_box;
@@ -132,8 +129,8 @@ private:
 
 	RKSpinBox* num_recent_files_box;
 	QLineEdit* script_file_filter_box;
-	static int num_recent_files;
-	static QString script_file_filter;
+	static RKConfigValue<int> num_recent_files;
+	static RKConfigValue<QString> script_file_filter;
 };
 
 #endif
diff --git a/rkward/settings/rksettingsmoduleconsole.cpp b/rkward/settings/rksettingsmoduleconsole.cpp
index ce3dde13..f6100c0b 100644
--- a/rkward/settings/rksettingsmoduleconsole.cpp
+++ b/rkward/settings/rksettingsmoduleconsole.cpp
@@ -36,10 +36,10 @@
 
 RKCodeCompletionSettings RKSettingsModuleConsole::completion_settings;
 RKConfigValue<bool> RKSettingsModuleConsole::save_history {"save history", true};
-uint RKSettingsModuleConsole::max_history_length;
-uint RKSettingsModuleConsole::max_console_lines;
+RKConfigValue<uint> RKSettingsModuleConsole::max_history_length {"max history length", 100};
+RKConfigValue<uint> RKSettingsModuleConsole::max_console_lines {"max console lines", 500};
 RKConfigValue<bool> RKSettingsModuleConsole::pipe_user_commands_through_console {"pipe user commands through console", true};
-RKSettingsModuleConsole::PipedCommandsHistoryMode RKSettingsModuleConsole::add_piped_commands_to_history;
+RKConfigValue<RKSettingsModuleConsole::PipedCommandsHistoryMode, int> RKSettingsModuleConsole::add_piped_commands_to_history {"add piped commands to history", RKSettingsModuleConsole::AddSingleLine };
 RKConfigValue<bool> RKSettingsModuleConsole::context_sensitive_history_by_default {"command history defaults to context sensitive", false};
 
 RKSettingsModuleConsole::RKSettingsModuleConsole (RKSettings *gui, QWidget *parent) : RKSettingsModule (gui, parent) {
@@ -112,32 +112,20 @@ bool RKSettingsModuleConsole::shouldDoHistoryContextSensitive (Qt::KeyboardModif
 }
 
 //static
-void RKSettingsModuleConsole::saveSettings (KConfig *config) {
+void RKSettingsModuleConsole::syncConfig(KConfig* config, RKConfigBase::ConfigSyncAction a) {
 	RK_TRACE (SETTINGS);
 
 	KConfigGroup cg = config->group ("Console Settings");
-	save_history.saveConfig(cg);
-	cg.writeEntry ("max history length", max_history_length);
-	cg.writeEntry ("max console lines", max_console_lines);
-	pipe_user_commands_through_console.saveConfig(cg);
-	cg.writeEntry ("add piped commands to history", (int) add_piped_commands_to_history);
-	context_sensitive_history_by_default.saveConfig(cg);
-	completion_settings.saveSettings(cg);
-}
-
-//static
-void RKSettingsModuleConsole::loadSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("Console Settings");
-	save_history.loadConfig(cg);
-	max_history_length = cg.readEntry ("max history length", 100);
-	max_console_lines = cg.readEntry ("max console lines", 500);
-	pipe_user_commands_through_console.loadConfig(cg);
-	add_piped_commands_to_history = (PipedCommandsHistoryMode) cg.readEntry ("add piped commands to history", (int) AddSingleLine);
-	context_sensitive_history_by_default.loadConfig(cg);
-	completion_settings.tabkey_invokes_completion = true;
-	completion_settings.loadSettings(cg);
+	save_history.syncConfig(cg, a);
+	max_history_length.syncConfig(cg, a);
+	max_console_lines.syncConfig(cg, a);
+	pipe_user_commands_through_console.syncConfig(cg, a);
+	add_piped_commands_to_history.syncConfig(cg, a);
+	context_sensitive_history_by_default.syncConfig(cg, a);
+	if (a == RKConfigBase::LoadConfig) {
+		completion_settings.tabkey_invokes_completion = true;
+	}
+	completion_settings.syncConfig(cg, a);
 }
 
 //static
@@ -167,12 +155,6 @@ void RKSettingsModuleConsole::applyChanges () {
 	max_console_lines = max_console_lines_spinner->value ();
 	add_piped_commands_to_history = (PipedCommandsHistoryMode) add_piped_commands_to_history_box->currentIndex ();
 }
-
-void RKSettingsModuleConsole::save (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	saveSettings (config);
-}
 	
 QString RKSettingsModuleConsole::caption () {
 	RK_TRACE (SETTINGS);
diff --git a/rkward/settings/rksettingsmoduleconsole.h b/rkward/settings/rksettingsmoduleconsole.h
index cc1e79c7..ada18bc6 100644
--- a/rkward/settings/rksettingsmoduleconsole.h
+++ b/rkward/settings/rksettingsmoduleconsole.h
@@ -36,12 +36,10 @@ public:
 	RKSettingsModuleConsole (RKSettings *gui, QWidget *parent);
 	~RKSettingsModuleConsole ();
 
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*) {};
-
 	void applyChanges () override;
-	void save (KConfig *config) override;
 
 	static bool saveHistory () { return save_history; };
 	static uint maxHistoryLength () { return max_history_length; };
@@ -70,10 +68,10 @@ public slots:
 private:
 	static RKCodeCompletionSettings completion_settings;
 	static RKConfigValue<bool> save_history;
-	static uint max_history_length;
-	static uint max_console_lines;
+	static RKConfigValue<uint> max_history_length;
+	static RKConfigValue<uint> max_console_lines;
 	static RKConfigValue<bool> pipe_user_commands_through_console;
-	static PipedCommandsHistoryMode add_piped_commands_to_history;
+	static RKConfigValue<PipedCommandsHistoryMode, int> add_piped_commands_to_history;
 	static RKConfigValue<bool> context_sensitive_history_by_default;
 
 	RKCodeCompletionSettingsWidget *completion_settings_widget;
diff --git a/rkward/settings/rksettingsmoduledebug.cpp b/rkward/settings/rksettingsmoduledebug.cpp
index 359b4f60..03d625e1 100644
--- a/rkward/settings/rksettingsmoduledebug.cpp
+++ b/rkward/settings/rksettingsmoduledebug.cpp
@@ -121,18 +121,7 @@ void RKSettingsModuleDebug::applyChanges () {
 	RK_Debug::RK_Debug_Flags = flags;
 }
 
-void RKSettingsModuleDebug::save (KConfig *config) {
-	RK_TRACE (SETTINGS);
-	saveSettings (config);
-}
-
-void RKSettingsModuleDebug::saveSettings (KConfig *) {
-	RK_TRACE (SETTINGS);
-
-	// left empty on purpose
-}
-
-void RKSettingsModuleDebug::loadSettings (KConfig *) {
+void RKSettingsModuleDebug::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction) {
 	RK_TRACE (SETTINGS);
 
 	// left empty on purpose
diff --git a/rkward/settings/rksettingsmoduledebug.h b/rkward/settings/rksettingsmoduledebug.h
index 7a391571..377d2b18 100644
--- a/rkward/settings/rksettingsmoduledebug.h
+++ b/rkward/settings/rksettingsmoduledebug.h
@@ -35,10 +35,8 @@ public:
 	~RKSettingsModuleDebug ();
 
 	void applyChanges () override;
-	void save (KConfig *config) override;
-
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*) {};
 
 	QString caption () override;
diff --git a/rkward/settings/rksettingsmodulegeneral.cpp b/rkward/settings/rksettingsmodulegeneral.cpp
index 3bc7d39e..0d346cfa 100644
--- a/rkward/settings/rksettingsmodulegeneral.cpp
+++ b/rkward/settings/rksettingsmodulegeneral.cpp
@@ -39,17 +39,23 @@
 
 // static members
 QString RKSettingsModuleGeneral::files_path;
-QString RKSettingsModuleGeneral::new_files_path;
-StartupDialog::Result RKSettingsModuleGeneral::startup_action;
-RKSettingsModuleGeneral::WorkplaceSaveMode RKSettingsModuleGeneral::workplace_save_mode;
+RKConfigValue<QString> RKSettingsModuleGeneral::new_files_path { "logfile dir", QString() }; // NOTE: default initialized at runtime!
+RKConfigValue<StartupDialog::Result, int> RKSettingsModuleGeneral::startup_action { "startup action", StartupDialog::NoSavedSetting };
+RKConfigValue<RKSettingsModuleGeneral::WorkplaceSaveMode, int> RKSettingsModuleGeneral::workplace_save_mode { "save mode", SaveWorkplaceWithWorkspace };
 RKConfigValue<bool> RKSettingsModuleGeneral::cd_to_workspace_dir_on_load {"cd to workspace on load", true};
 RKConfigValue<bool> RKSettingsModuleGeneral::show_help_on_startup {"show help on startup", true};
-int RKSettingsModuleGeneral::warn_size_object_edit;
-RKSettingsModuleGeneral::RKMDIFocusPolicy RKSettingsModuleGeneral::mdi_focus_policy;
+RKConfigValue<int> RKSettingsModuleGeneral::warn_size_object_edit {"large object warning limit", 250000};
+RKConfigValue<RKSettingsModuleGeneral::RKMDIFocusPolicy, int> RKSettingsModuleGeneral::mdi_focus_policy {"focus policy", RKMDIClickFocus};
 RKSettingsModuleGeneral::RKWardConfigVersion RKSettingsModuleGeneral::stored_config_version;
 bool RKSettingsModuleGeneral::config_exists;
-RKSettingsModuleGeneral::InitialDirectory RKSettingsModuleGeneral::initial_dir;
-QString RKSettingsModuleGeneral::initial_dir_specification;
+RKConfigValue<RKSettingsModuleGeneral::InitialDirectory, int> RKSettingsModuleGeneral::initial_dir {"initial dir mode",
+#ifndef Q_OS_WIN
+	CurrentDirectory
+#else
+	RKWardDirectory
+#endif
+};
+RKConfigValue<QString> RKSettingsModuleGeneral::initial_dir_specification { "initial dir spec", QString() };
 bool RKSettingsModuleGeneral::rkward_version_changed;
 bool RKSettingsModuleGeneral::installation_moved = false;
 QString RKSettingsModuleGeneral::previous_rkward_data_dir;
@@ -77,7 +83,7 @@ RKSettingsModuleGeneral::RKSettingsModuleGeneral (RKSettings *gui, QWidget *pare
 	startup_action_choser->addItem (i18n ("Start with an empty table"), (int) StartupDialog::EmptyTable);
 	startup_action_choser->addItem (i18n ("Ask for a file to open"), (int) StartupDialog::ChoseFile);
 	startup_action_choser->addItem (i18n ("Show selection dialog (default)"), (int) StartupDialog::NoSavedSetting);
-	startup_action_choser->setCurrentIndex (startup_action_choser->findData (startup_action));
+	startup_action_choser->setCurrentIndex (startup_action_choser->findData (startup_action.get()));
 	connect (startup_action_choser, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &RKSettingsModuleGeneral::settingChanged);
 	main_vbox->addWidget (startup_action_choser);
 
@@ -209,76 +215,59 @@ void RKSettingsModuleGeneral::applyChanges () {
 	initial_dir_specification = initial_dir_custom_chooser->getLocation ();
 }
 
-void RKSettingsModuleGeneral::save (KConfig *config) {
+void RKSettingsModuleGeneral::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
 	RK_TRACE (SETTINGS);
-	saveSettings (config);
-}
 
-void RKSettingsModuleGeneral::saveSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
+	if (a == RKConfigBase::LoadConfig) {
+		config_exists = config->hasGroup("General");	// one of the very oldest groups in the config
+	}
 
 	KConfigGroup cg;
-	cg = config->group ("Logfiles");
-	cg.writeEntry ("logfile dir", new_files_path);
-
-	cg = config->group ("General");
-	cg.writeEntry ("startup action", (int) startup_action);
-	show_help_on_startup.saveConfig(cg);
-	cg.writeEntry ("initial dir mode", (int) initial_dir);
-	cg.writeEntry ("initial dir spec", (initial_dir == LastUsedDirectory) ? QDir::currentPath() : initial_dir_specification);
-	cg.writeEntry ("last known data dir", RKCommonFunctions::getRKWardDataDir ());
-
-	cg = config->group ("Workplace");
-	cg.writeEntry ("save mode", (int) workplace_save_mode);
-	cd_to_workspace_dir_on_load.saveConfig(cg);
-
-	cg = config->group ("Editor");
-	cg.writeEntry ("large object warning limit", warn_size_object_edit);
-
-	cg = config->group ("MDI");
-	cg.writeEntry ("focus policy", (int) mdi_focus_policy);
-
-	cg = config->group ("Internal");
-	cg.writeEntry ("config file version", (int) RKWardConfig_Latest);
-	cg.writeEntry ("previous runtime version", QString (RKWARD_VERSION));
-}
+	cg = config->group("Logfiles");
+	if (a == RKConfigBase::LoadConfig) {
+		// default not yet set, first time loading config
+		if (new_files_path.get().isNull()) new_files_path = QString(QDir().homePath() + "/.rkward/");
 
-void RKSettingsModuleGeneral::loadSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	config_exists = config->hasGroup ("General");	// one of the very oldest groups in the config
-
-	KConfigGroup cg;
-	cg = config->group ("General");
-	previous_rkward_data_dir = cg.readEntry ("last known data dir", RKCommonFunctions::getRKWardDataDir ());
-	installation_moved = (previous_rkward_data_dir != RKCommonFunctions::getRKWardDataDir ()) && !previous_rkward_data_dir.isEmpty ();
-	startup_action = (StartupDialog::Result) cg.readEntry ("startup action", (int) StartupDialog::NoSavedSetting);
-	show_help_on_startup.loadConfig(cg);
-	initial_dir = (InitialDirectory) cg.readEntry ("initial dir mode",
-#ifndef Q_OS_WIN
-		(int) CurrentDirectory
-#else
-		(int) RKWardDirectory
-#endif
-	);
-	initial_dir_specification = checkAdjustLoadedPath (cg.readEntry ("initial dir spec", QString ()));
+		new_files_path.loadConfig(cg);
+		files_path = new_files_path;
+	} else {
+		new_files_path.saveConfig(cg);
+	}
 
-	cg = config->group ("Logfiles");
-	files_path = new_files_path = checkAdjustLoadedPath (cg.readEntry ("logfile dir", QString (QDir ().homePath () + "/.rkward/")));
+	cg = config->group("General");
+	if (a == RKConfigBase::LoadConfig) {
+		previous_rkward_data_dir = cg.readEntry("last known data dir", RKCommonFunctions::getRKWardDataDir());
+		installation_moved = (previous_rkward_data_dir != RKCommonFunctions::getRKWardDataDir ()) && !previous_rkward_data_dir.isEmpty ();
+	} else {
+		cg.writeEntry("last known data dir", RKCommonFunctions::getRKWardDataDir());
+	}
+	startup_action.syncConfig(cg, a);
+	show_help_on_startup.syncConfig(cg, a);
+	initial_dir.syncConfig(cg, a);
+	if ((a == RKConfigBase::SaveConfig) && (initial_dir = LastUsedDirectory)) {
+		cg.writeEntry(initial_dir_specification.key(), QDir::currentPath());
+	} else {
+		initial_dir_specification.syncConfig(cg, a);
+	}
 
 	cg = config->group ("Workplace");
-	workplace_save_mode = (WorkplaceSaveMode) cg.readEntry ("save mode", (int) SaveWorkplaceWithWorkspace);
-	cd_to_workspace_dir_on_load.loadConfig(cg);
+	workplace_save_mode.syncConfig(cg, a);
+	cd_to_workspace_dir_on_load.syncConfig(cg, a);
 
 	cg = config->group ("Editor");
-	warn_size_object_edit = cg.readEntry ("large object warning limit", 250000);
+	warn_size_object_edit.syncConfig(cg, a);
 
 	cg = config->group ("MDI");
-	mdi_focus_policy = (RKMDIFocusPolicy) cg.readEntry ("focus policy", (int) RKMDIClickFocus);
+	mdi_focus_policy.syncConfig(cg, a);
 
 	cg = config->group ("Internal");
-	stored_config_version = (RKWardConfigVersion) cg.readEntry ("config file version", (int) RKWardConfig_Pre0_5_7);
-	rkward_version_changed = (cg.readEntry ("previous runtime version", QString ()) != RKWARD_VERSION);
+	if (a == RKConfigBase::LoadConfig) {
+		stored_config_version = (RKWardConfigVersion) cg.readEntry("config file version", (int) RKWardConfig_Pre0_5_7);
+		rkward_version_changed = (cg.readEntry("previous runtime version", QString()) != RKWARD_VERSION);
+	} else {
+		cg.writeEntry("config file version", (int) RKWardConfig_Latest);
+		cg.writeEntry("previous runtime version", QString(RKWARD_VERSION));
+	}
 }
 
 QString RKSettingsModuleGeneral::getSavedWorkplace (KConfig *config) {
diff --git a/rkward/settings/rksettingsmodulegeneral.h b/rkward/settings/rksettingsmodulegeneral.h
index 9a650bbd..188d8a32 100644
--- a/rkward/settings/rksettingsmodulegeneral.h
+++ b/rkward/settings/rksettingsmodulegeneral.h
@@ -54,10 +54,8 @@ public:
 	};
 
 	void applyChanges () override;
-	void save (KConfig *config) override;
-
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*) {};
 
 	QString caption () override;
@@ -120,21 +118,21 @@ private:
 	QComboBox *initial_dir_chooser;
 	GetFileNameWidget *initial_dir_custom_chooser;
 
-	static StartupDialog::Result startup_action;
+	static RKConfigValue<StartupDialog::Result, int> startup_action;
 	static QString files_path;
 /** since changing the files_path can not easily be done while in an active session, the setting should only take effect on the next start. This string stores a changed setting, while keeping the old one intact as long as RKWard is running */
-	static QString new_files_path;
-	static WorkplaceSaveMode workplace_save_mode;
+	static RKConfigValue<QString> new_files_path;
+	static RKConfigValue<WorkplaceSaveMode, int> workplace_save_mode;
 	static RKConfigValue<bool> cd_to_workspace_dir_on_load;
 	static RKConfigValue<bool> show_help_on_startup;
-	static int warn_size_object_edit;
-	static RKMDIFocusPolicy mdi_focus_policy;
+	static RKConfigValue<int> warn_size_object_edit;
+	static RKConfigValue<RKMDIFocusPolicy, int> mdi_focus_policy;
+	static RKConfigValue<InitialDirectory, int> initial_dir;
+	static RKConfigValue<QString> initial_dir_specification;
+	static QString previous_rkward_data_dir;
 	static RKWardConfigVersion stored_config_version;
-	static bool config_exists;
-	static InitialDirectory initial_dir;
-	static QString initial_dir_specification;
 	static bool rkward_version_changed;
-	static QString previous_rkward_data_dir;
+	static bool config_exists;
 	static bool installation_moved;
 	static QUrl generic_filedialog_start_url;
 };
diff --git a/rkward/settings/rksettingsmodulegraphics.cpp b/rkward/settings/rksettingsmodulegraphics.cpp
index af89302a..f5073b6e 100644
--- a/rkward/settings/rksettingsmodulegraphics.cpp
+++ b/rkward/settings/rksettingsmodulegraphics.cpp
@@ -2,7 +2,7 @@
                           rksettingsmodulegraphics  -  description
                              -------------------
     begin                : Mon Sep 13 2010
-    copyright            : (C) 2010, 2013 by Thomas Friedrichsmeier
+    copyright            : (C) 2010-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -38,15 +38,15 @@
 #include "../core/robject.h"
 
 // static members
-double RKSettingsModuleGraphics::graphics_width;
-double RKSettingsModuleGraphics::graphics_height;
-bool RKSettingsModuleGraphics::graphics_hist_enable;
-int RKSettingsModuleGraphics::graphics_hist_max_length;
-int RKSettingsModuleGraphics::graphics_hist_max_plotsize;
+RKConfigValue<double> RKSettingsModuleGraphics::graphics_width {"graphics_width", 7.0};
+RKConfigValue<double> RKSettingsModuleGraphics::graphics_height {"graphics_height", 7.0};
+RKConfigValue<bool> RKSettingsModuleGraphics::graphics_hist_enable {"graphics_hist_enable", true};
+RKConfigValue<int> RKSettingsModuleGraphics::graphics_hist_max_length {"graphics_hist_max_length", 20};
+RKConfigValue<int> RKSettingsModuleGraphics::graphics_hist_max_plotsize {"graphics_hist_max_plotsize", 4096};
 RKConfigValue<bool> RKSettingsModuleGraphics::options_kde_printing {"kde printing", true};
-RKSettingsModuleGraphics::DefaultDevice RKSettingsModuleGraphics::default_device;
-QString RKSettingsModuleGraphics::default_device_other;
-RKSettingsModuleGraphics::StandardDevicesMode RKSettingsModuleGraphics::replace_standard_devices;
+RKConfigValue<RKSettingsModuleGraphics::DefaultDevice, int> RKSettingsModuleGraphics::default_device {"default_device", RKDevice};
+RKConfigValue<QString> RKSettingsModuleGraphics::default_device_other {"default_device_custom", QString("cairoDevice")};
+RKConfigValue<RKSettingsModuleGraphics::StandardDevicesMode, int> RKSettingsModuleGraphics::replace_standard_devices {"replace_device", ReplaceDevice};
 
 RKSettingsModuleGraphics::RKSettingsModuleGraphics (RKSettings *gui, QWidget *parent) : RKSettingsModule(gui, parent) {
 	RK_TRACE (SETTINGS);
@@ -198,40 +198,19 @@ void RKSettingsModuleGraphics::applyChanges () {
 	}
 }
 
-void RKSettingsModuleGraphics::save (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	saveSettings (config);
-}
-
-void RKSettingsModuleGraphics::saveSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("Graphics Device Windows");
-	cg.writeEntry ("default_device", (int) default_device);
-	cg.writeEntry ("default_device_custom", default_device_other);
-	cg.writeEntry ("replace_device", (int) replace_standard_devices);
-	cg.writeEntry ("graphics_width", graphics_width);
-	cg.writeEntry ("graphics_height", graphics_height);
-	cg.writeEntry ("graphics_hist_enable", graphics_hist_enable);
-	cg.writeEntry ("graphics_hist_max_length", graphics_hist_max_length);
-	cg.writeEntry ("graphics_hist_max_plotsize", graphics_hist_max_plotsize);
-	options_kde_printing.saveConfig(cg);
-}
-
-void RKSettingsModuleGraphics::loadSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("Graphics Device Windows");
-	default_device = (DefaultDevice) cg.readEntry ("default_device", (int) RKDevice);
-	default_device_other = cg.readEntry ("default_device_custom", QString ("cairoDevice"));
-	replace_standard_devices = (StandardDevicesMode) cg.readEntry ("replace_device", (int) ReplaceDevice);
-	graphics_width = cg.readEntry ("graphics_width", 7.0);
-	graphics_height = cg.readEntry ("graphics_height", 7.0);
-	graphics_hist_enable = cg.readEntry ("graphics_hist_enable", true);
-	graphics_hist_max_length = cg.readEntry ("graphics_hist_max_length", 20);
-	graphics_hist_max_plotsize = cg.readEntry ("graphics_hist_max_plotsize", 4096);
-	options_kde_printing.loadConfig(cg);
+void RKSettingsModuleGraphics::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
+	RK_TRACE(SETTINGS);
+
+	KConfigGroup cg = config->group("Graphics Device Windows");
+	default_device.syncConfig(cg, a);
+	default_device_other.syncConfig(cg, a);
+	replace_standard_devices.syncConfig(cg, a);
+	graphics_width.syncConfig(cg, a);
+	graphics_height.syncConfig(cg, a);
+	graphics_hist_enable.syncConfig(cg, a);
+	graphics_hist_max_length.syncConfig(cg, a);
+	graphics_hist_max_plotsize.syncConfig(cg, a);
+	options_kde_printing.syncConfig(cg, a);
 }
 
 //static
diff --git a/rkward/settings/rksettingsmodulegraphics.h b/rkward/settings/rksettingsmodulegraphics.h
index 975611e1..396427a5 100644
--- a/rkward/settings/rksettingsmodulegraphics.h
+++ b/rkward/settings/rksettingsmodulegraphics.h
@@ -38,7 +38,6 @@ public:
 	~RKSettingsModuleGraphics ();
 	
 	void applyChanges () override;
-	void save (KConfig *config) override;
 
 /** generate the commands needed to set the R run time options */
 	static QStringList makeRRunTimeOptionCommands ();
@@ -46,8 +45,8 @@ public:
 /** Configured to (attempt to) use KDE printing dialog? */
 	static bool kdePrintingEnabled () { return options_kde_printing; };
 
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*) {};
 
 	QString caption () override;
@@ -81,16 +80,16 @@ private:
 	RKSpinBox *graphics_height_box;
 	RKSpinBox *graphics_width_box;
 
-	static DefaultDevice default_device;
-	static QString default_device_other;
-	static StandardDevicesMode replace_standard_devices;
+	static RKConfigValue<DefaultDevice, int> default_device;
+	static RKConfigValue<QString> default_device_other;
+	static RKConfigValue<StandardDevicesMode, int> replace_standard_devices;
 
-	static bool graphics_hist_enable;
-	static int graphics_hist_max_length;
-	static int graphics_hist_max_plotsize;
+	static RKConfigValue<bool> graphics_hist_enable;
+	static RKConfigValue<int> graphics_hist_max_length;
+	static RKConfigValue<int> graphics_hist_max_plotsize;
 
-	static double graphics_height;
-	static double graphics_width;
+	static RKConfigValue<double> graphics_height;
+	static RKConfigValue<double> graphics_width;
 
 	static RKConfigValue<bool> options_kde_printing;
 };
diff --git a/rkward/settings/rksettingsmodulekateplugins.cpp b/rkward/settings/rksettingsmodulekateplugins.cpp
index 1e6bda24..5a0e3d44 100644
--- a/rkward/settings/rksettingsmodulekateplugins.cpp
+++ b/rkward/settings/rksettingsmodulekateplugins.cpp
@@ -32,7 +32,7 @@
 
 #include "../debug.h"
 
-QStringList RKSettingsModuleKatePlugins::plugins_to_load;
+RKConfigValue<QStringList> RKSettingsModuleKatePlugins::plugins_to_load {"Plugins to load", QStringList() << "katesearchplugin" << "kateprojectplugin" << "katesnippetsplugin"};
 
 RKSettingsModuleKatePlugins::RKSettingsModuleKatePlugins(RKSettings *gui, QWidget *parent) : RKSettingsModule(gui, parent) {
 	RK_TRACE(SETTINGS);
@@ -58,7 +58,7 @@ RKSettingsModuleKatePlugins::RKSettingsModuleKatePlugins(RKSettings *gui, QWidge
 		item->setData(1, Qt::DecorationRole, QIcon::fromTheme(plugindata.iconName()));
 		item->setData(1, Qt::UserRole, key);
 		item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
-		item->setCheckState(0, plugins_to_load.contains(key) ? Qt::Checked : Qt::Unchecked);
+		item->setCheckState(0, plugins_to_load.get().contains(key) ? Qt::Checked : Qt::Unchecked);
 		plugin_table->addTopLevelItem(item);
 	}
 	plugin_table->resizeColumnToContents(0);
@@ -76,37 +76,27 @@ RKSettingsModuleKatePlugins::~RKSettingsModuleKatePlugins() {
 void RKSettingsModuleKatePlugins::applyChanges() {
 	RK_TRACE(SETTINGS);
 
-	plugins_to_load.clear();
+	QStringList p;
 	for (int i = plugin_table->topLevelItemCount() - 1; i >= 0; --i) {
 		QTreeWidgetItem *item = plugin_table->topLevelItem(i);
 		if (item->checkState(0) == Qt::Checked) {
-			plugins_to_load.append (item->data(1, Qt::UserRole).toString());
+			p.append (item->data(1, Qt::UserRole).toString());
 		}
 	}
+	plugins_to_load = p;
 	RKWardMainWindow::getMain()->katePluginIntegration()->loadPlugins(plugins_to_load);
 }
 
-void RKSettingsModuleKatePlugins::save(KConfig *config) {
+void RKSettingsModuleKatePlugins::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
 	RK_TRACE(SETTINGS);
 
-	saveSettings(config);
-}
-
-void RKSettingsModuleKatePlugins::saveSettings(KConfig *config) {
-	RK_TRACE(SETTINGS);
-
-	// if no kate plugins are known (installation problem), don't save any config
-	if (!RKWardMainWindow::getMain()->katePluginIntegration()->knownPluginCount()) return;
-
-	KConfigGroup cg = config->group("Kate Plugins");
-	cg.writeEntry("Plugins to load", plugins_to_load);
-}
-
-void RKSettingsModuleKatePlugins::loadSettings(KConfig *config) {
-	RK_TRACE(SETTINGS);
+	if (a == RKConfigBase::SaveConfig) {
+		// if no kate plugins are known (installation problem), don't save any config
+		if (!RKWardMainWindow::getMain()->katePluginIntegration()->knownPluginCount()) return;
+	}
 
 	KConfigGroup cg = config->group("Kate Plugins");
-	plugins_to_load = cg.readEntry("Plugins to load", QStringList() << "katesearchplugin" << "kateprojectplugin" << "katesnippetsplugin");
+	plugins_to_load.syncConfig(cg, a);
 }
 
 QString RKSettingsModuleKatePlugins::caption() {
diff --git a/rkward/settings/rksettingsmodulekateplugins.h b/rkward/settings/rksettingsmodulekateplugins.h
index 9e413833..e8609b97 100644
--- a/rkward/settings/rksettingsmodulekateplugins.h
+++ b/rkward/settings/rksettingsmodulekateplugins.h
@@ -32,10 +32,8 @@ public:
 	~RKSettingsModuleKatePlugins();
 
 	void applyChanges() override;
-	void save(KConfig *config) override;
-
-	static void saveSettings(KConfig *config);
-	static void loadSettings(KConfig *config);
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 	static void validateSettingsInteractive(QList<RKSetupWizardItem*>*) {};
 
 	QString caption() override;
@@ -44,7 +42,7 @@ public:
 private:
 	QTreeWidget *plugin_table;
 
-	static QStringList plugins_to_load;
+	static RKConfigValue<QStringList> plugins_to_load;
 };
 
 #endif
diff --git a/rkward/settings/rksettingsmoduleobjectbrowser.cpp b/rkward/settings/rksettingsmoduleobjectbrowser.cpp
index 4c175326..d8fbee94 100644
--- a/rkward/settings/rksettingsmoduleobjectbrowser.cpp
+++ b/rkward/settings/rksettingsmoduleobjectbrowser.cpp
@@ -34,9 +34,9 @@
 #include "../debug.h"
 
 // static
-bool RKSettingsModuleObjectBrowser::workspace_settings[RKObjectListViewSettings::SettingsCount];
-bool RKSettingsModuleObjectBrowser::varselector_settings[RKObjectListViewSettings::SettingsCount];
-QStringList RKSettingsModuleObjectBrowser::getstructure_blacklist;
+RKConfigValue<bool> RKSettingsModuleObjectBrowser::workspace_settings[RKObjectListViewSettings::SettingsCount] {{"show hidden vars", false},{"show type field", true},{"show class field", true},{"show label field", true}};
+RKConfigValue<bool> RKSettingsModuleObjectBrowser::varselector_settings[RKObjectListViewSettings::SettingsCount] { RKSettingsModuleObjectBrowser::workspace_settings[0],RKSettingsModuleObjectBrowser::workspace_settings[1],RKSettingsModuleObjectBrowser::workspace_settings[2],RKSettingsModuleObjectBrowser::workspace_settings[3]};
+RKConfigValue<QStringList> RKSettingsModuleObjectBrowser::getstructure_blacklist {"package blacklist", QStringList("GO")};
 
 RKSettingsModuleObjectBrowser::RKSettingsModuleObjectBrowser (RKSettings *gui, QWidget *parent) : RKSettingsModule (gui, parent) {
 	RK_TRACE (SETTINGS);
@@ -73,7 +73,7 @@ void RKSettingsModuleObjectBrowser::setDefaultForVarselector (RKObjectListViewSe
 //static
 bool RKSettingsModuleObjectBrowser::isPackageBlacklisted (const QString &package_name) {
 	RK_TRACE (SETTINGS);
-	return getstructure_blacklist.contains (package_name);
+	return getstructure_blacklist.get().contains (package_name);
 }
 
 void RKSettingsModuleObjectBrowser::addBlackList (QStringList *string_list) {
@@ -89,11 +89,6 @@ void RKSettingsModuleObjectBrowser::applyChanges () {
 	getstructure_blacklist = blacklist_choser->getValues();
 }
 
-void RKSettingsModuleObjectBrowser::save (KConfig *config) {
-	RK_TRACE (SETTINGS);
-	saveSettings (config);
-}
-
 QString RKSettingsModuleObjectBrowser::caption () {
 	RK_TRACE (SETTINGS);
 	return (i18n ("Workspace"));
@@ -106,35 +101,21 @@ void writeSettings (KConfigGroup &cg, bool *settings) {
 	cg.writeEntry ("show class field", settings[RKObjectListViewSettings::ShowFieldsClass]);
 }
 
-//static
-void RKSettingsModuleObjectBrowser::saveSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("Object Browser");
-	cg.writeEntry ("package blacklist", getstructure_blacklist);
-
-	KConfigGroup toolgroup = cg.group ("Tool window");
-	writeSettings (toolgroup, workspace_settings);
-	KConfigGroup varselgroup = cg.group ("Varselector");
-	writeSettings (varselgroup, varselector_settings);
-}
-
-void readSettings (const KConfigGroup &cg, bool *settings) {
-	settings[RKObjectListViewSettings::ShowObjectsHidden] = cg.readEntry ("show hidden vars", false);
-	settings[RKObjectListViewSettings::ShowFieldsLabel] = cg.readEntry ("show label field", true);
-	settings[RKObjectListViewSettings::ShowFieldsType] = cg.readEntry ("show type field", true);
-	settings[RKObjectListViewSettings::ShowFieldsClass] = cg.readEntry ("show class field", true);
+void syncSettings(KConfigGroup cg, RKConfigBase::ConfigSyncAction a, RKConfigValue<bool> *settings) {
+	for (int i = 0; i < RKObjectListViewSettings::SettingsCount; ++i) {
+		settings[i].syncConfig(cg, a);
+	}
 }
 
 //static
-void RKSettingsModuleObjectBrowser::loadSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
+void RKSettingsModuleObjectBrowser::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
+	RK_TRACE(SETTINGS);
 
-	KConfigGroup cg = config->group ("Object Browser");
-	getstructure_blacklist = cg.readEntry ("package blacklist", QStringList ("GO"));
+	KConfigGroup cg = config->group("Object Browser");
+	getstructure_blacklist.syncConfig(cg, a);
 
-	readSettings (cg.group ("Tool window"), workspace_settings);
-	readSettings (cg.group ("Varselector"), varselector_settings);
+	syncSettings (cg.group("Tool window"), a, workspace_settings);
+	syncSettings (cg.group("Varselector"), a, varselector_settings);
 }
 
 void RKSettingsModuleObjectBrowser::boxChanged (int) {
diff --git a/rkward/settings/rksettingsmoduleobjectbrowser.h b/rkward/settings/rksettingsmoduleobjectbrowser.h
index 90302cc8..c8bc4de4 100644
--- a/rkward/settings/rksettingsmoduleobjectbrowser.h
+++ b/rkward/settings/rksettingsmoduleobjectbrowser.h
@@ -37,15 +37,12 @@ public:
 
 /** applies current settings in this RKSettingsModule. This will only be called, if hasChanges () is true */
 	void applyChanges () override;
-/** saves current changes to the given KConfig
- at param config probably always RKGlobals::rkApp ()->config. But passing this as an argument is both more flexible and saves #including files.*/
-	void save (KConfig *config) override;
 
 /** @returns the caption ("Workspace Browser") */
 	QString caption () override;
 
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*) {};
 
 	static bool isDefaultForWorkspace (RKObjectListViewSettings::PersistentSettings setting) { return workspace_settings[setting]; };
@@ -63,10 +60,10 @@ public slots:
 	void addBlackList (QStringList *string_list);
 private:
 	MultiStringSelector *blacklist_choser;
-	static QStringList getstructure_blacklist;
+	static RKConfigValue<QStringList> getstructure_blacklist;
 
-	static bool workspace_settings[RKObjectListViewSettings::SettingsCount];
-	static bool varselector_settings[RKObjectListViewSettings::SettingsCount];
+	static RKConfigValue<bool> workspace_settings[RKObjectListViewSettings::SettingsCount];
+	static RKConfigValue<bool> varselector_settings[RKObjectListViewSettings::SettingsCount];
 };
 
 #endif
diff --git a/rkward/settings/rksettingsmoduleoutput.cpp b/rkward/settings/rksettingsmoduleoutput.cpp
index 912506fa..45597613 100644
--- a/rkward/settings/rksettingsmoduleoutput.cpp
+++ b/rkward/settings/rksettingsmoduleoutput.cpp
@@ -35,7 +35,7 @@
 #include "../debug.h"
 
 // static members
-bool RKCarbonCopySettings::cc_globally_enabled;
+RKConfigValue<bool> RKCarbonCopySettings::cc_globally_enabled {"CC enabled", false};
 RKConfigValue<bool> RKCarbonCopySettings::cc_console_commands {"CC console commands", true};
 RKConfigValue<bool> RKCarbonCopySettings::cc_script_commands {"CC script commands", false};
 RKConfigValue<bool> RKCarbonCopySettings::cc_app_plugin_commands {"CC app/plugin commands", false};
@@ -78,26 +78,15 @@ void RKCarbonCopySettings::update() {
 	cc_command_output_box->setChecked (cc_command_output);
 }
 
-void RKCarbonCopySettings::saveSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
+void RKCarbonCopySettings::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
+	RK_TRACE(SETTINGS);
 
-	KConfigGroup cg = config->group ("Carbon Copy Settings");
-	cg.writeEntry ("CC enabled", cc_globally_enabled);
-	cc_console_commands.saveConfig(cg);
-	cc_script_commands.saveConfig(cg);
-	cc_app_plugin_commands.saveConfig(cg);
-	cc_command_output.saveConfig(cg);
-}
-
-void RKCarbonCopySettings::loadSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("Carbon Copy Settings");
-	cc_globally_enabled = cg.readEntry ("CC enabled", false);
-	cc_console_commands.loadConfig(cg);
-	cc_script_commands.loadConfig(cg);
-	cc_app_plugin_commands.loadConfig(cg);
-	cc_command_output.loadConfig(cg);
+	KConfigGroup cg = config->group("Carbon Copy Settings");
+	cc_globally_enabled.syncConfig(cg, a);
+	cc_console_commands.syncConfig(cg, a);
+	cc_script_commands.syncConfig(cg, a);
+	cc_app_plugin_commands.syncConfig(cg, a);
+	cc_command_output.syncConfig(cg, a);
 }
 
 bool RKCarbonCopySettings::shouldCarbonCopyCommand (const RCommand *command) {
@@ -124,11 +113,11 @@ void RKCarbonCopySettings::applyChanges() {
 // static members
 RKConfigValue<bool> RKSettingsModuleOutput::auto_show {"auto_show", true};
 RKConfigValue<bool> RKSettingsModuleOutput::auto_raise {"auto_raise", true};
-QString RKSettingsModuleOutput::graphics_type;
-int RKSettingsModuleOutput::graphics_width;
-int RKSettingsModuleOutput::graphics_height;
-int RKSettingsModuleOutput::graphics_jpg_quality;
-QString RKSettingsModuleOutput::custom_css_file;
+RKConfigValue<QString> RKSettingsModuleOutput::graphics_type {"graphics_type", "NULL"};
+RKConfigValue<int> RKSettingsModuleOutput::graphics_width {"graphics_width", 480};
+RKConfigValue<int> RKSettingsModuleOutput::graphics_height {"graphics_height", 480};
+RKConfigValue<int> RKSettingsModuleOutput::graphics_jpg_quality {"graphics_jpg_quality", 75};
+RKConfigValue<QString> RKSettingsModuleOutput::custom_css_file {"custom css file", QString()};
 RKConfigValue<bool> RKSettingsModuleOutput::shared_default_output {"Shared default output", false};
 
 RKSettingsModuleOutput::RKSettingsModuleOutput (RKSettings *gui, QWidget *parent) : RKSettingsModule(gui, parent) {
@@ -164,7 +153,7 @@ RKSettingsModuleOutput::RKSettingsModuleOutput (RKSettings *gui, QWidget *parent
 	graphics_type_box->addItem (i18n ("PNG"), QString ("\"PNG\""));
 	graphics_type_box->addItem (i18n ("SVG"), QString ("\"SVG\""));
 	graphics_type_box->addItem (i18n ("JPG"), QString ("\"JPG\""));
-	graphics_type_box->setCurrentIndex (graphics_type_box->findData (graphics_type));
+	graphics_type_box->setCurrentIndex (graphics_type_box->findData (graphics_type.get()));
 	graphics_type_box->setEditable (false);
 	connect (graphics_type_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &RKSettingsModuleOutput::boxChanged);
 	h_layout->addSpacing (2*RKGlobals::spacingHint ());
@@ -238,42 +227,20 @@ void RKSettingsModuleOutput::applyChanges () {
 	cc_settings->applyChanges ();
 }
 
-void RKSettingsModuleOutput::save (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	saveSettings (config);
-}
-
-void RKSettingsModuleOutput::saveSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("Output Window");
-	auto_show.saveConfig(cg);
-	auto_raise.saveConfig(cg);
-	cg.writeEntry ("graphics_type", graphics_type);
-	cg.writeEntry ("graphics_width", graphics_width);
-	cg.writeEntry ("graphics_height", graphics_height);
-	cg.writeEntry ("graphics_jpg_quality", graphics_jpg_quality);
-	cg.writeEntry ("custom css file", custom_css_file);
-	shared_default_output.saveConfig(cg);
-
-	RKCarbonCopySettings::saveSettings (config);
-}
-
-void RKSettingsModuleOutput::loadSettings (KConfig *config) {
+void RKSettingsModuleOutput::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
 	RK_TRACE (SETTINGS);
 
 	KConfigGroup cg = config->group ("Output Window");
-	auto_show.loadConfig(cg);
-	auto_raise.loadConfig(cg);
-	graphics_type = cg.readEntry ("graphics_type", "NULL");
-	graphics_width = cg.readEntry ("graphics_width", 480);
-	graphics_height = cg.readEntry ("graphics_height", 480);
-	graphics_jpg_quality = cg.readEntry ("graphics_jpg_quality", 75);
-	custom_css_file = cg.readEntry ("custom css file", QString ());
-	shared_default_output.loadConfig(cg);
-
-	RKCarbonCopySettings::loadSettings (config);
+	auto_show.syncConfig(cg, a);
+	auto_raise.syncConfig(cg, a);
+	graphics_type.syncConfig(cg, a);
+	graphics_width.syncConfig(cg, a);
+	graphics_height.syncConfig(cg, a);
+	graphics_jpg_quality.syncConfig(cg, a);
+	custom_css_file.syncConfig(cg, a);
+	shared_default_output.syncConfig(cg, a);
+
+	RKCarbonCopySettings::syncConfig(config, a);
 }
 
 //static
@@ -282,11 +249,11 @@ QStringList RKSettingsModuleOutput::makeRRunTimeOptionCommands () {
 	QStringList list;
 
 // output format options
-	QString command = "options (\"rk.graphics.type\"=" + graphics_type;
+	QString command = "options (\"rk.graphics.type\"=" + graphics_type.get();
 	command.append (", \"rk.graphics.width\"=" + QString::number (graphics_width));
 	command.append (", \"rk.graphics.height\"=" + QString::number (graphics_height));
 	if (graphics_type == "\"JPG\"") command.append (", \"rk.graphics.jpg.quality\"=" + QString::number (graphics_jpg_quality));
-	command.append (", \"rk.output.css.file\"=\"" + (custom_css_file.isEmpty () ? RKCommonFunctions::getRKWardDataDir () + "pages/rkward_output.css" : custom_css_file) + '\"');
+	command.append (", \"rk.output.css.file\"=\"" + (custom_css_file.get().isEmpty () ? RKCommonFunctions::getRKWardDataDir () + "pages/rkward_output.css" : custom_css_file.get()) + '\"');
 	list.append (command + ")\n");
 
 	return (list);
diff --git a/rkward/settings/rksettingsmoduleoutput.h b/rkward/settings/rksettingsmoduleoutput.h
index 9dc6f0b6..0efb9e48 100644
--- a/rkward/settings/rksettingsmoduleoutput.h
+++ b/rkward/settings/rksettingsmoduleoutput.h
@@ -39,13 +39,12 @@ public:
 	explicit RKCarbonCopySettings (QWidget* parent, RKSettingsModule* module);
 	~RKCarbonCopySettings ();
 
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 
 	static bool shouldCarbonCopyCommand (const RCommand *command);
 	static bool includeOutputInCarbonCopy () { return (cc_globally_enabled && cc_command_output); };
 public slots:
-	void applyChanges ();
+	void applyChanges() override;
 private:
 	// There can be multiple instances of this widget, which need to be kept in sync.
 	static QList<RKCarbonCopySettings*> instances;
@@ -57,7 +56,7 @@ private:
 	QCheckBox *cc_app_plugin_commands_box;
 	QCheckBox *cc_command_output_box;
 
-	static bool cc_globally_enabled;
+	static RKConfigValue<bool> cc_globally_enabled;
 	static RKConfigValue<bool> cc_console_commands;
 	static RKConfigValue<bool> cc_script_commands;
 	static RKConfigValue<bool> cc_app_plugin_commands;
@@ -74,13 +73,12 @@ public:
 	~RKSettingsModuleOutput ();
 
 	void applyChanges () override;
-	void save (KConfig *config) override;
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 
 /** generate the commands needed to set the R run time options */
 	static QStringList makeRRunTimeOptionCommands ();
 
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*) {};
 
 	QString caption () override;
@@ -100,11 +98,11 @@ private:
 
 	static RKConfigValue<bool> auto_show;
 	static RKConfigValue<bool> auto_raise;
-	static QString graphics_type;
-	static int graphics_width;
-	static int graphics_height;
-	static int graphics_jpg_quality;
-	static QString custom_css_file;
+	static RKConfigValue<QString> graphics_type;
+	static RKConfigValue<int> graphics_width;
+	static RKConfigValue<int> graphics_height;
+	static RKConfigValue<int> graphics_jpg_quality;
+	static RKConfigValue<QString> custom_css_file;
 	static RKConfigValue<bool> shared_default_output;
 };
 
diff --git a/rkward/settings/rksettingsmoduleplugins.cpp b/rkward/settings/rksettingsmoduleplugins.cpp
index 4ebf5091..ece03306 100644
--- a/rkward/settings/rksettingsmoduleplugins.cpp
+++ b/rkward/settings/rksettingsmoduleplugins.cpp
@@ -45,10 +45,10 @@
 
 // static members
 QList<RKSettingsModulePlugins::PluginMapStoredInfo> RKSettingsModulePlugins::known_plugin_maps;
-RKSettingsModulePlugins::PluginPrefs RKSettingsModulePlugins::interface_pref;
-bool RKSettingsModulePlugins::show_code;
-int RKSettingsModulePlugins::code_size;
-int RKSettingsModulePlugins::side_preview_width;
+RKConfigValue<RKSettingsModulePlugins::PluginPrefs, int> RKSettingsModulePlugins::interface_pref {"Interface Preferences", RKSettingsModulePlugins::PreferRecommended};
+RKConfigValue<bool> RKSettingsModulePlugins::show_code {"Code display default", false};
+RKConfigValue<int> RKSettingsModulePlugins::code_size {"Code display size", 250};
+RKConfigValue<int> RKSettingsModulePlugins::side_preview_width {"Other preview size", 250};
 
 RKSettingsModulePlugins::RKSettingsModulePlugins (RKSettings *gui, QWidget *parent) : RKSettingsModule (gui, parent) {
 	RK_TRACE (SETTINGS);
@@ -123,82 +123,75 @@ void RKSettingsModulePlugins::configurePluginmaps () {
 	RKLoadLibsDialog::showPluginmapConfig (this, commandChain ());
 }
 
-void RKSettingsModulePlugins::save (KConfig *config) {
-	RK_TRACE (SETTINGS);
-	saveSettings (config);
-}
-
-void RKSettingsModulePlugins::saveSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
+void savePluginMaps(KConfigGroup &cg, const RKSettingsModulePlugins::PluginMapList &known_plugin_maps) {
+	RK_TRACE(SETTINGS);
 
-	KConfigGroup cg = config->group ("Plugin Settings");
-	cg.deleteGroup ("Known Plugin maps");	// always start from scratch to remove cruft from pluginmaps
-	KConfigGroup pmg = cg.group ("Known Plugin maps");
+	cg.deleteGroup("Known Plugin maps");	// always start from scratch to remove cruft from pluginmaps
+	KConfigGroup pmg = cg.group("Known Plugin maps");
 	QStringList all_known_maps;
 	for (int i = 0; i < known_plugin_maps.size (); ++i) {
-		const PluginMapStoredInfo &inf = known_plugin_maps[i];
+		const RKSettingsModulePlugins::PluginMapStoredInfo &inf = known_plugin_maps[i];
 		KConfigGroup ppmg = pmg.group (inf.filename);
-		ppmg.writeEntry ("Active", inf.active);
-		ppmg.writeEntry ("Broken", inf.broken_in_this_version);
-		ppmg.writeEntry ("Quirky", inf.quirky_in_this_version);
-		ppmg.writeEntry ("timestamp", inf.last_modified);
-		ppmg.writeEntry ("id", inf.id);
-		ppmg.writeEntry ("priority", inf.priority);
-		all_known_maps.append (inf.filename);
+		ppmg.writeEntry("Active", inf.active);
+		ppmg.writeEntry("Broken", inf.broken_in_this_version);
+		ppmg.writeEntry("Quirky", inf.quirky_in_this_version);
+		ppmg.writeEntry("timestamp", inf.last_modified);
+		ppmg.writeEntry("id", inf.id);
+		ppmg.writeEntry("priority", inf.priority);
+		all_known_maps.append(inf.filename);
 	}
 	// NOTE: The group list is always sorted alphabetically, which is why we need a separate list setting for saving info on order.
-	cg.writeEntry ("All known plugin maps", all_known_maps);
-
-	cg.writeEntry ("Interface Preferences", static_cast<int> (interface_pref));
-	cg.writeEntry ("Code display default", show_code);
-	cg.writeEntry ("Code display size", code_size);
-	cg.writeEntry ("Other preview size", side_preview_width);
+	cg.writeEntry("All known plugin maps", all_known_maps);
 }
 
-void RKSettingsModulePlugins::loadSettings (KConfig *config) {
+void RKSettingsModulePlugins::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
 	RK_TRACE (SETTINGS);
 
-	KConfigGroup cg = config->group ("Plugin Settings");
-	if (RKSettingsModuleGeneral::storedConfigVersion () < RKSettingsModuleGeneral::RKWardConfig_0_6_1) {
-		QStringList plugin_maps = cg.readEntry ("Plugin Maps", QStringList ());
-		QStringList kplugin_maps = cg.readEntry ("All known plugin maps", QStringList ());
-		for (int i = 0; i < kplugin_maps.size (); ++i) {
-			PluginMapStoredInfo inf (RKSettingsModuleGeneral::checkAdjustLoadedPath (kplugin_maps[i]));
-			inf.active = plugin_maps.contains (kplugin_maps[i]);	// comparing unadjusted path on purpose!
-			// state info will be properly initialized in fixPluginMapLists()
-			known_plugin_maps.append (inf);
-		}
+	KConfigGroup cg = config->group("Plugin Settings");
+	interface_pref.syncConfig(cg, a);
+	show_code.syncConfig(cg, a);
+	code_size.syncConfig(cg, a);
+	side_preview_width.syncConfig(cg, a);
+
+	if (a == RKConfigBase::SaveConfig) {
+		savePluginMaps(cg, known_plugin_maps);
 	} else {
-		KConfigGroup pmg = cg.group ("Known Plugin maps");
-		QStringList kplugin_maps = cg.readEntry ("All known plugin maps", QStringList ());
-		for (int i = 0; i < kplugin_maps.size (); ++i) {
-			KConfigGroup ppmg = pmg.group (kplugin_maps[i]);	// unadjusted path on purpose!
-			PluginMapStoredInfo inf (RKSettingsModuleGeneral::checkAdjustLoadedPath (kplugin_maps[i]));
-			inf.active = ppmg.readEntry ("Active", false);
-			// Pluginmaps which are broken with one version of RKWard may be alright with other versions. So reset flags, if version has changed.
-			inf.broken_in_this_version = ppmg.readEntry ("Broken", false) && !RKSettingsModuleGeneral::rkwardVersionChanged ();
-			inf.quirky_in_this_version = ppmg.readEntry ("Quirky", false) && !RKSettingsModuleGeneral::rkwardVersionChanged ();
-			inf.last_modified = ppmg.readEntry ("timestamp", QDateTime ());
-			inf.id = ppmg.readEntry ("id");
-			inf.priority = ppmg.readEntry ("priority", (int) PriorityMedium);
-			known_plugin_maps.append (inf);
+		if (RKSettingsModuleGeneral::storedConfigVersion () < RKSettingsModuleGeneral::RKWardConfig_0_6_1) {
+			QStringList plugin_maps = cg.readEntry ("Plugin Maps", QStringList ());
+			QStringList kplugin_maps = cg.readEntry ("All known plugin maps", QStringList ());
+			for (int i = 0; i < kplugin_maps.size (); ++i) {
+				PluginMapStoredInfo inf (RKSettingsModuleGeneral::checkAdjustLoadedPath (kplugin_maps[i]));
+				inf.active = plugin_maps.contains (kplugin_maps[i]);	// comparing unadjusted path on purpose!
+				// state info will be properly initialized in fixPluginMapLists()
+				known_plugin_maps.append (inf);
+			}
+		} else {
+			KConfigGroup pmg = cg.group ("Known Plugin maps");
+			QStringList kplugin_maps = cg.readEntry ("All known plugin maps", QStringList ());
+			for (int i = 0; i < kplugin_maps.size (); ++i) {
+				KConfigGroup ppmg = pmg.group (kplugin_maps[i]);	// unadjusted path on purpose!
+				PluginMapStoredInfo inf (RKSettingsModuleGeneral::checkAdjustLoadedPath (kplugin_maps[i]));
+				inf.active = ppmg.readEntry ("Active", false);
+				// Pluginmaps which are broken with one version of RKWard may be alright with other versions. So reset flags, if version has changed.
+				inf.broken_in_this_version = ppmg.readEntry ("Broken", false) && !RKSettingsModuleGeneral::rkwardVersionChanged ();
+				inf.quirky_in_this_version = ppmg.readEntry ("Quirky", false) && !RKSettingsModuleGeneral::rkwardVersionChanged ();
+				inf.last_modified = ppmg.readEntry ("timestamp", QDateTime ());
+				inf.id = ppmg.readEntry ("id");
+				inf.priority = ppmg.readEntry ("priority", (int) PriorityMedium);
+				known_plugin_maps.append (inf);
+			}
 		}
-	}
-	if (RKSettingsModuleGeneral::rkwardVersionChanged () || RKSettingsModuleGeneral::installationMoved ()) {
-		// if it is the first start this version or from a new path, scan the installation for new pluginmaps
-		// Note that in the case of installationMoved(), checkAdjustLoadedPath() has already kicked in, above, but rescanning is still useful
-		// e.g. if users have installed to a new location, because they had botched their previous installation
-		registerDefaultPluginMaps(AddIfNewAndDefault);
-	}
-	fixPluginMapLists ();	// removes any maps which don't exist any more
-
-	interface_pref = static_cast<PluginPrefs> (cg.readEntry ("Interface Preferences", static_cast<int> (PreferRecommended)));
-	show_code = cg.readEntry ("Code display default", false);
-	code_size = cg.readEntry ("Code display size", 250);
-	side_preview_width = cg.readEntry ("Other preview size", 250);
+		if (RKSettingsModuleGeneral::rkwardVersionChanged () || RKSettingsModuleGeneral::installationMoved ()) {
+			// if it is the first start this version or from a new path, scan the installation for new pluginmaps
+			// Note that in the case of installationMoved(), checkAdjustLoadedPath() has already kicked in, above, but rescanning is still useful
+			// e.g. if users have installed to a new location, because they had botched their previous installation
+			registerDefaultPluginMaps(AddIfNewAndDefault);
+		}
+		fixPluginMapLists ();	// removes any maps which don't exist any more
 
-	if (RKSettingsModuleGeneral::storedConfigVersion () <= RKSettingsModuleGeneral::RKWardConfig_Pre0_5_7) {
-		if (code_size == 40) code_size = 250;	// previous default untouched.
+		if (RKSettingsModuleGeneral::storedConfigVersion () <= RKSettingsModuleGeneral::RKWardConfig_Pre0_5_7) {
+			if (code_size == 40) code_size = 250;	// previous default untouched.
+		}
 	}
 }
 
diff --git a/rkward/settings/rksettingsmoduleplugins.h b/rkward/settings/rksettingsmoduleplugins.h
index 0ca7ea0b..98f2feeb 100644
--- a/rkward/settings/rksettingsmoduleplugins.h
+++ b/rkward/settings/rksettingsmoduleplugins.h
@@ -39,12 +39,11 @@ public:
 	~RKSettingsModulePlugins ();
 
 	void applyChanges () override;
-	void save (KConfig *config) override;
 
 	enum PluginPrefs { PreferDialog=0, PreferRecommended=1, PreferWizard=2 };
 
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*) {};
 
 	QString caption () override;
@@ -107,10 +106,10 @@ private:
 	/** plugin maps which are not necessarily active, but have been encountered, before. @see plugin_maps */
 	static PluginMapList known_plugin_maps;
 
-	static PluginPrefs interface_pref;
-	static bool show_code;
-	static int code_size;
-	static int side_preview_width;
+	static RKConfigValue<PluginPrefs,int> interface_pref;
+	static RKConfigValue<bool> show_code;
+	static RKConfigValue<int> code_size;
+	static RKConfigValue<int> side_preview_width;
 
 /* TODO: This one is currently unused (leftover of GHNS-based plugin installation), but might still be of interest */
 	static QStringList findPluginMapsRecursive (const QString &basedir);
diff --git a/rkward/settings/rksettingsmoduler.cpp b/rkward/settings/rksettingsmoduler.cpp
index b592c481..f2dd6ce0 100755
--- a/rkward/settings/rksettingsmoduler.cpp
+++ b/rkward/settings/rksettingsmoduler.cpp
@@ -44,25 +44,25 @@
 #include "../rkglobals.h"
 #include "../debug.h"
 
-// static members
-QString RKSettingsModuleR::options_outdec;
-int RKSettingsModuleR::options_width;
-int RKSettingsModuleR::options_warn;
-int RKSettingsModuleR::options_warningslength;
-int RKSettingsModuleR::options_maxprint;
-bool RKSettingsModuleR::options_keepsource;
-bool RKSettingsModuleR::options_keepsourcepkgs;
-int RKSettingsModuleR::options_expressions;
-int RKSettingsModuleR::options_digits;
-bool RKSettingsModuleR::options_checkbounds;
-QString RKSettingsModuleR::options_editor;
-QString RKSettingsModuleR::options_pager;
-QString RKSettingsModuleR::options_further;
-QStringList RKSettingsModuleR::options_addpaths;
 // static constants
 QString RKSettingsModuleR::builtin_editor = "<rkward>";
 // session constants
 QString RKSettingsModuleR::help_base_url;
+// static members
+RKConfigValue<QString> RKSettingsModuleR::options_outdec {"OutDec", "."};
+RKConfigValue<int> RKSettingsModuleR::options_width {"width", 80};
+RKConfigValue<int> RKSettingsModuleR::options_warn {"warn", 0};
+RKConfigValue<int> RKSettingsModuleR::options_warningslength {"warnings.length", 1000};
+RKConfigValue<int> RKSettingsModuleR::options_maxprint {"max.print", 99999};
+RKConfigValue<bool> RKSettingsModuleR::options_keepsource {"keep.source", true};
+RKConfigValue<bool> RKSettingsModuleR::options_keepsourcepkgs {"keep.source.pkgs", false};
+RKConfigValue<int> RKSettingsModuleR::options_expressions {"expressions", 5000};
+RKConfigValue<int> RKSettingsModuleR::options_digits {"digits", 7};
+RKConfigValue<bool> RKSettingsModuleR::options_checkbounds {"check.bounds", false};
+RKConfigValue<QString> RKSettingsModuleR::options_editor {"editor", builtin_editor};
+RKConfigValue<QString> RKSettingsModuleR::options_pager {"pager", builtin_editor};
+RKConfigValue<QString> RKSettingsModuleR::options_further {"further init commands", QString()};
+RKConfigValue<QStringList> RKSettingsModuleR::options_addpaths {"addsyspaths", QStringList()};
 
 RKSettingsModuleR::RKSettingsModuleR (RKSettings *gui, QWidget *parent) : RKSettingsModule(gui, parent) {
 	RK_TRACE (SETTINGS);
@@ -247,11 +247,12 @@ void RKSettingsModuleR::applyChanges () {
 	options_further = further_input->toPlainText ();
 	// normalize system paths before adding
 	QStringList paths = addpaths_selector->getValues ();
-	options_addpaths.clear ();
-	for (int i = 0; i < paths.count (); ++i) {
-		QString path = QDir::cleanPath (paths[i]);
-		if (!options_addpaths.contains (path)) options_addpaths.append (path);
+	QStringList cleanpaths;
+	for (int i = 0; i < paths.count(); ++i) {
+		QString path = QDir::cleanPath(paths[i]);
+		if (!cleanpaths.contains(path)) cleanpaths.append(path);
 	}
+	options_addpaths = cleanpaths;
 
 // apply run time options in R
 	QStringList commands = makeRRunTimeOptionCommands ();
@@ -289,7 +290,7 @@ QStringList RKSettingsModuleR::makeRRunTimeOptionCommands () {
 	QStringList list;
 
 	QString tf;
-	list.append ("options (OutDec=\"" + options_outdec.left (1) + "\")\n");
+	list.append ("options (OutDec=\"" + options_outdec.get().left (1) + "\")\n");
 	list.append ("options (width=" + QString::number (options_width) + ")\n");
 	list.append ("options (warn=" + QString::number (options_warn) + ")\n");
 	list.append ("options (max.print=" + QString::number (options_maxprint) + ")\n");
@@ -303,13 +304,13 @@ QStringList RKSettingsModuleR::makeRRunTimeOptionCommands () {
 	if (options_checkbounds) tf = "TRUE"; else tf = "FALSE";
 	list.append ("options (checkbounds=" + tf + ")\n");
 	if (options_editor == builtin_editor) list.append ("options (editor=rk.edit.files)\n");
-	else list.append ("options (editor=\"" + options_editor + "\")\n");
+	else list.append ("options (editor=\"" + options_editor.get() + "\")\n");
 	if (options_pager == builtin_editor) list.append ("options (pager=rk.show.files)\n");
-	else list.append ("options (pager=\"" + options_pager + "\")\n");
-	if (!options_further.isEmpty ()) list.append (options_further + '\n');
-	if (!options_addpaths.isEmpty ()) {
+	else list.append ("options (pager=\"" + options_pager.get() + "\")\n");
+	if (!options_further.get().isEmpty ()) list.append (options_further.get() + '\n');
+	if (!options_addpaths.get().isEmpty ()) {
 		QString command = "rk.adjust.system.path (add=c(";
-		foreach (const QString &p, options_addpaths) {
+		foreach (const QString &p, options_addpaths.get()) {
 			command.append (RObject::rQuote (p));
 		}
 		list.append (command + "))\n");
@@ -326,50 +327,24 @@ QStringList RKSettingsModuleR::makeRRunTimeOptionCommands () {
 	return list;
 }
 
-void RKSettingsModuleR::save (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	saveSettings (config);
-}
-
-void RKSettingsModuleR::saveSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("R Settings");
-	cg.writeEntry ("OutDec", options_outdec);
-	cg.writeEntry ("width", options_width);
-	cg.writeEntry ("warn", options_warn);
-	cg.writeEntry ("max.print", options_maxprint);
-	cg.writeEntry ("warnings.length", options_warningslength);
-	cg.writeEntry ("keep.source", options_keepsource);
-	cg.writeEntry ("keep.source.pkgs", options_keepsourcepkgs);
-	cg.writeEntry ("expressions", options_expressions);
-	cg.writeEntry ("digits", options_digits);
-	cg.writeEntry ("check.bounds", options_checkbounds);
-	cg.writeEntry ("editor", options_editor);
-	cg.writeEntry ("pager", options_pager);
-	cg.writeEntry ("further init commands", options_further);
-	cg.writeEntry ("addsyspaths", options_addpaths);
-}
-
-void RKSettingsModuleR::loadSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("R Settings");
-	options_outdec = cg.readEntry ("OutDec", ".");
-	options_width = cg.readEntry ("width", 80);
-	options_warn = cg.readEntry ("warn", 0);
-	options_maxprint = cg.readEntry ("max.print", 99999);
-	options_warningslength = cg.readEntry ("warnings.length", 1000);
-	options_keepsource = cg.readEntry ("keep.source", true);
-	options_keepsourcepkgs = cg.readEntry ("keep.source.pkgs", false);
-	options_expressions = cg.readEntry ("expressions", 5000);
-	options_digits = cg.readEntry ("digits", 7);
-	options_checkbounds = cg.readEntry ("check.bounds", false);
-	options_editor = cg.readEntry ("editor", builtin_editor);
-	options_pager = cg.readEntry ("pager", builtin_editor);
-	options_further = cg.readEntry ("further init commands", QString ());
-	options_addpaths = cg.readEntry ("addsyspaths", QStringList ());
+void RKSettingsModuleR::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
+	RK_TRACE(SETTINGS);
+
+	KConfigGroup cg = config->group("R Settings");
+	options_outdec.syncConfig(cg, a);
+	options_width.syncConfig(cg, a);
+	options_warn.syncConfig(cg, a);
+	options_maxprint.syncConfig(cg, a);
+	options_warningslength.syncConfig(cg, a);
+	options_keepsource.syncConfig(cg, a);
+	options_keepsourcepkgs.syncConfig(cg, a);
+	options_expressions.syncConfig(cg, a);
+	options_digits.syncConfig(cg, a);
+	options_checkbounds.syncConfig(cg, a);
+	options_editor.syncConfig(cg, a);
+	options_pager.syncConfig(cg, a);
+	options_further.syncConfig(cg, a);
+	options_addpaths.syncConfig(cg, a);
 }
 
 //#################################################
@@ -377,9 +352,7 @@ void RKSettingsModuleR::loadSettings (KConfig *config) {
 //#################################################
 
 // static members
-QStringList RKSettingsModuleRPackages::liblocs;
-QStringList RKSettingsModuleRPackages::defaultliblocs;
-QString RKSettingsModuleRPackages::r_libs_user;
+RKConfigValue<QStringList> RKSettingsModuleRPackages::liblocs {"LibraryLocations", QStringList()};
 RKConfigValue<bool> RKSettingsModuleRPackages::archive_packages {"archive packages", false};
 #if (defined Q_OS_WIN || defined Q_OS_MACOS)
 #	if (defined USE_BINARY_PACKAGES)
@@ -391,9 +364,12 @@ RKConfigValue<bool> RKSettingsModuleRPackages::archive_packages {"archive packag
 #	define USE_SOURCE_PACKAGES true
 #endif
 RKConfigValue<bool> RKSettingsModuleRPackages::source_packages {"source_packages", USE_SOURCE_PACKAGES};
-QStringList RKSettingsModuleRPackages::package_repositories;
+#define RKWARD_REPO "http://files.kde.org/rkward/R/"
+RKConfigValue<QStringList> RKSettingsModuleRPackages::package_repositories {"Repositories", QStringList(RKWARD_REPO)};
 QString RKSettingsModuleRPackages::essential_packages = QString ("base\nmethods\nutils\ngrDevices\ngraphics\nrkward");
-QString RKSettingsModuleRPackages::cran_mirror_url;
+RKConfigValue<QString> RKSettingsModuleRPackages::cran_mirror_url {"CRAN mirror url", "@CRAN@"};
+QStringList RKSettingsModuleRPackages::defaultliblocs;
+QString RKSettingsModuleRPackages::r_libs_user;
 
 RKSettingsModuleRPackages::RKSettingsModuleRPackages (RKSettings *gui, QWidget *parent) : RKSettingsModule(gui, parent), RCommandReceiver () {
 	RK_TRACE (SETTINGS);
@@ -450,7 +426,7 @@ RKSettingsModuleRPackages::~RKSettingsModuleRPackages () {
 void RKSettingsModuleRPackages::addLibraryLocation (const QString& new_loc, RCommandChain *chain) {
 	RK_TRACE (SETTINGS);
 
-	if (!libraryLocations ().contains (new_loc)) liblocs.prepend (new_loc);
+	if (!libraryLocations ().contains (new_loc)) liblocs.get().prepend (new_loc);
 
 	// update the backend in any case. User might have changed liblocs, there.
 	RKGlobals::rInterface ()->issueCommand (".libPaths (unique (c (" + RObject::rQuote (new_loc) + ", .libPaths ())))", RCommand::App | RCommand::Sync, QString (), 0, 0, chain);
@@ -554,7 +530,7 @@ QString RKSettingsModuleRPackages::libLocsCommand () {
 	// For additional library locations configured inside RKWard, try to create them, as needed.
 	// This is especially important for versioned dirs (which will not exist after upgrading R, for instance)
 	QString command;
-	if (!liblocs.isEmpty()) {
+	if (!liblocs.get().isEmpty()) {
 		bool first = true;
 		command = "local({\naddpaths <- unique (c(";
 		QStringList ll = expandLibLocs(liblocs);
@@ -609,7 +585,7 @@ QStringList RKSettingsModuleRPackages::makeRRunTimeOptionCommands () {
 
 // package repositories
 	QString command = "options (repos=c (CRAN=" + RObject::rQuote (cran_mirror_url);
-	for (QStringList::const_iterator it = package_repositories.begin (); it != package_repositories.end (); ++it) {
+	for (auto it = package_repositories.get().constBegin (); it != package_repositories.get().constEnd(); ++it) {
 		command.append (", " + RObject::rQuote (*it));
 	}
 	list.append (command + "))\n");
@@ -628,7 +604,7 @@ void RKSettingsModuleRPackages::applyChanges () {
 	RK_TRACE (SETTINGS);
 
 	cran_mirror_url = cran_mirror_input->text ();
-	if (cran_mirror_url.isEmpty ()) cran_mirror_url = "@CRAN@";
+	if (cran_mirror_url.get().isEmpty ()) cran_mirror_url = "@CRAN@";
 
 	package_repositories = repository_selector->getValues ();
 	liblocs = libloc_selector->getValues ();
@@ -640,45 +616,34 @@ void RKSettingsModuleRPackages::applyChanges () {
 	}
 }
 
-void RKSettingsModuleRPackages::save (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	saveSettings (config);
-}
-
-void RKSettingsModuleRPackages::saveSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("R Settings");
-	cg.writeEntry ("CRAN mirror url", cran_mirror_url);
-	archive_packages.saveConfig(cg);
-	source_packages.saveConfig(cg);
-	cg.writeEntry ("Repositories", package_repositories);
-	cg.writeEntry ("LibraryLocations", liblocs);
-}
-
-void RKSettingsModuleRPackages::loadSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("R Settings");
-
-	cran_mirror_url = cg.readEntry ("CRAN mirror url", "@CRAN@");
-	const QString rkward_repo ("http://files.kde.org/rkward/R/");
-	package_repositories = cg.readEntry ("Repositories", QStringList (rkward_repo));
-	if (RKSettingsModuleGeneral::storedConfigVersion () <= RKSettingsModuleGeneral::RKWardConfig_Pre0_5_7) {
-		package_repositories.removeAll ("@CRAN@");	// COMPAT: Cran mirror was part of this list before 0.5.3
-		if (package_repositories.isEmpty ()) package_repositories.append (rkward_repo);
-	} else if (RKSettingsModuleGeneral::storedConfigVersion () < RKSettingsModuleGeneral::RKWardConfig_0_6_3) {
-		package_repositories.removeAll ("http://rkward.sf.net/R");
-		package_repositories.append (rkward_repo);
-	}
+void RKSettingsModuleRPackages::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
+	RK_TRACE(SETTINGS);
+
+	KConfigGroup cg = config->group("R Settings");
+	cran_mirror_url.syncConfig(cg, a);
+	liblocs.syncConfig(cg, a);
+	archive_packages.syncConfig(cg, a);
+	source_packages.syncConfig(cg, a);  // NOTE: does not take effect on Linux, see pkgTypeOption
+	package_repositories.syncConfig(cg, a);
+
+	if (a == RKConfigBase::LoadConfig) {
+		const QString rkward_repo (RKWARD_REPO);
+		if (RKSettingsModuleGeneral::storedConfigVersion () <= RKSettingsModuleGeneral::RKWardConfig_Pre0_5_7) {
+			auto v = package_repositories.get();
+			v.removeAll ("@CRAN@");	// COMPAT: Cran mirror was part of this list before 0.5.3
+			if (v.isEmpty ()) v.append(rkward_repo);
+			package_repositories = v;
+		} else if (RKSettingsModuleGeneral::storedConfigVersion () < RKSettingsModuleGeneral::RKWardConfig_0_6_3) {
+			auto v = package_repositories.get();
+			v.removeAll("http://rkward.sf.net/R");
+			v.append(rkward_repo);
+			package_repositories = v;
+		}
 
-	liblocs = cg.readEntry ("LibraryLocations", QStringList ());
-	archive_packages.loadConfig(cg);
-	source_packages.loadConfig(cg);  // NOTE: does not take effect on Linux, see pkgTypeOption
-	if (USE_SOURCE_PACKAGES && (RKSettingsModuleGeneral::storedConfigVersion () < RKSettingsModuleGeneral::RKWardConfig_0_6_1)) {
-		// revert default on MacOSX, even if a previous stored setting exists
-		source_packages = true;
+		if (USE_SOURCE_PACKAGES && (RKSettingsModuleGeneral::storedConfigVersion () < RKSettingsModuleGeneral::RKWardConfig_0_6_1)) {
+			// revert default on MacOSX, even if a previous stored setting exists
+			source_packages = true;
+		}
 	}
 }
 
@@ -690,7 +655,7 @@ void RKSettingsModuleRPackages::validateSettingsInteractive (QList<RKSetupWizard
 
 	if (RKSettingsModuleGeneral::storedConfigVersion () < RKSettingsModuleGeneral::RKWardConfig_0_7_1) {
 		QString legacy_libloc = QDir (RKSettingsModuleGeneral::filesPath ()).absoluteFilePath ("library");
-		if (liblocs.contains (legacy_libloc)) {
+		if (liblocs.get().contains(legacy_libloc)) {
 			auto item = new RKSetupWizardItem(i18n("Unversioned library location"), i18n("The configured library locations (where R packages will be installed on this system) contains the directory '%1', "
 			                                  "which was suggested as a default library location in earlier versions of RKWard. Use of this directory is no longer "
 			                                  "recommended, as it is not accessible to R sessions outside of RKWard (unless configured, explicitly). Also due to the lack "
@@ -698,15 +663,15 @@ void RKSettingsModuleRPackages::validateSettingsInteractive (QList<RKSetupWizard
 			                                  "version of R.", legacy_libloc), RKSetupWizardItem::Warning);
 			item->addOption(i18nc("verb", "Rename"), i18n("Rename this location to include the version number of the currently running R. Packages will continue "
 			                                        "to work (if they are compatible with this version of R)."), [legacy_libloc](RKSetupWizard*) {
-									liblocs.removeAll(legacy_libloc);
+									liblocs.get().removeAll(legacy_libloc);
 									QString new_loc = legacy_libloc + '-' + RKSessionVars::RVersion (true);
 									RKGlobals::rInterface ()->issueCommand (QString ("file.rename(%1, %2)\n").arg (RObject::rQuote (legacy_libloc)).arg (RObject::rQuote (new_loc)), RCommand::App);
-									liblocs.prepend (legacy_libloc + QStringLiteral ("-%v"));
+									liblocs.get().prepend (legacy_libloc + QStringLiteral ("-%v"));
 									RKGlobals::rInterface ()->issueCommand (libLocsCommand(), RCommand::App);
 								});
 			item->addOption(i18nc("verb", "Remove"), i18n("Remove this location from the configuration (it will not be deleted on disk). You will have to "
 			                                        "re-install any packages that you want to keep."), [legacy_libloc](RKSetupWizard*) {
-									liblocs.removeAll(legacy_libloc);
+									liblocs.get().removeAll(legacy_libloc);
 									RKGlobals::rInterface ()->issueCommand (libLocsCommand(), RCommand::App);
 								});
 			item->addOption(i18nc("verb", "Keep"), i18n("Keep this location (do not change anything)"), [](RKSetupWizard*) {});
diff --git a/rkward/settings/rksettingsmoduler.h b/rkward/settings/rksettingsmoduler.h
index 4d98d7e1..62da874d 100644
--- a/rkward/settings/rksettingsmoduler.h
+++ b/rkward/settings/rksettingsmoduler.h
@@ -40,10 +40,8 @@ public:
 	~RKSettingsModuleR ();
 
 	void applyChanges () override;
-	void save (KConfig *config) override;
-
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*) {};
 
 	QString caption () override;
@@ -75,20 +73,20 @@ private:
 	QTextEdit *further_input;
 	MultiStringSelector *addpaths_selector;
 
-	static QString options_outdec;
-	static int options_width;
-	static int options_warn;
-	static int options_warningslength;
-	static int options_maxprint;
-	static bool options_keepsource;
-	static bool options_keepsourcepkgs;
-	static int options_expressions;
-	static int options_digits;
-	static bool options_checkbounds;
-	static QString options_editor;
-	static QString options_pager;
-	static QString options_further;
-	static QStringList options_addpaths;
+	static RKConfigValue<QString> options_outdec;
+	static RKConfigValue<int> options_width;
+	static RKConfigValue<int> options_warn;
+	static RKConfigValue<int> options_warningslength;
+	static RKConfigValue<int> options_maxprint;
+	static RKConfigValue<bool> options_keepsource;
+	static RKConfigValue<bool> options_keepsourcepkgs;
+	static RKConfigValue<int> options_expressions;
+	static RKConfigValue<int> options_digits;
+	static RKConfigValue<bool> options_checkbounds;
+	static RKConfigValue<QString> options_editor;
+	static RKConfigValue<QString> options_pager;
+	static RKConfigValue<QString> options_further;
+	static RKConfigValue<QStringList> options_addpaths;
 
 // constants
 	static QString builtin_editor;
@@ -112,10 +110,8 @@ public:
 	~RKSettingsModuleRPackages ();
 
 	void applyChanges () override;
-	void save (KConfig *config) override;
-
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*);
 
 /** generate the commands needed to set the R run time options */
@@ -147,11 +143,11 @@ private:
 	MultiStringSelector *repository_selector;
 	QLineEdit* cran_mirror_input;
 
-	static QString cran_mirror_url;
-	static QStringList liblocs;
+	static RKConfigValue<QString> cran_mirror_url;
+	static RKConfigValue<QStringList> liblocs;
 	static RKConfigValue<bool> archive_packages;
 	static RKConfigValue<bool> source_packages;
-	static QStringList package_repositories;
+	static RKConfigValue<QStringList> package_repositories;
 
 	friend class RInterface;
 	static QString r_libs_user;
diff --git a/rkward/settings/rksettingsmodulewatch.cpp b/rkward/settings/rksettingsmodulewatch.cpp
index 94277015..0965b1da 100644
--- a/rkward/settings/rksettingsmodulewatch.cpp
+++ b/rkward/settings/rksettingsmodulewatch.cpp
@@ -34,11 +34,11 @@
 #include "../debug.h"
 
 //static
-int RKSettingsModuleWatch::plugin_filter;
-int RKSettingsModuleWatch::app_filter;
-int RKSettingsModuleWatch::sync_filter;
-int RKSettingsModuleWatch::user_filter;
-uint RKSettingsModuleWatch::max_log_lines;
+RKConfigValue<int> RKSettingsModuleWatch::plugin_filter {"plugin command filter", ShowInput | ShowError};
+RKConfigValue<int> RKSettingsModuleWatch::app_filter {"app command filter", ShowInput | ShowError};
+RKConfigValue<int> RKSettingsModuleWatch::sync_filter {"sync command filter", ShowError};
+RKConfigValue<int> RKSettingsModuleWatch::user_filter {"user command filter", ShowInput | ShowOutput | ShowError | RaiseWindow};
+RKConfigValue<uint> RKSettingsModuleWatch::max_log_lines {"max log lines", 1000};
 
 //static
 bool RKSettingsModuleWatch::shouldShowInput (RCommand *command) {
@@ -227,29 +227,15 @@ void RKSettingsModuleWatch::validateGUI () {
 }
 
 //static
-void RKSettingsModuleWatch::saveSettings (KConfig *config) {
+void RKSettingsModuleWatch::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
 	RK_TRACE (SETTINGS);
 
-	KConfigGroup cg = config->group ("RInterface Watch Settings");
-	cg.writeEntry ("user command filter", user_filter);
-	cg.writeEntry ("plugin command filter", plugin_filter);
-	cg.writeEntry ("app command filter", app_filter);
-	cg.writeEntry ("sync command filter", sync_filter);
-
-	cg.writeEntry ("max log lines", max_log_lines);
-}
-
-//static
-void RKSettingsModuleWatch::loadSettings (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	KConfigGroup cg = config->group ("RInterface Watch Settings");
-	user_filter = cg.readEntry ("user command filter", static_cast<int> (ShowInput | ShowOutput | ShowError | RaiseWindow));
-	plugin_filter = cg.readEntry ("plugin command filter", static_cast<int> (ShowInput | ShowError));
-	app_filter = cg.readEntry ("app command filter", static_cast<int> (ShowInput | ShowError));
-	sync_filter = cg.readEntry ("sync command filter", static_cast<int> (ShowError));
-
-	max_log_lines = cg.readEntry ("max log lines", 1000);
+	KConfigGroup cg = config->group("RInterface Watch Settings");
+	user_filter.syncConfig(cg, a);
+	plugin_filter.syncConfig(cg, a);
+	app_filter.syncConfig(cg, a);
+	sync_filter.syncConfig(cg, a);
+	max_log_lines.syncConfig(cg, a);
 }
 
 void RKSettingsModuleWatch::applyChanges () {
@@ -262,12 +248,6 @@ void RKSettingsModuleWatch::applyChanges () {
 
 	max_log_lines = max_log_lines_spinner->value ();
 }
-
-void RKSettingsModuleWatch::save (KConfig *config) {
-	RK_TRACE (SETTINGS);
-
-	saveSettings (config);
-}
 	
 QString RKSettingsModuleWatch::caption () {
 	RK_TRACE (SETTINGS);
diff --git a/rkward/settings/rksettingsmodulewatch.h b/rkward/settings/rksettingsmodulewatch.h
index f0a28d43..1459df60 100644
--- a/rkward/settings/rksettingsmodulewatch.h
+++ b/rkward/settings/rksettingsmodulewatch.h
@@ -36,12 +36,11 @@ public:
 	RKSettingsModuleWatch (RKSettings *gui, QWidget *parent);
 	~RKSettingsModuleWatch ();
 
-	static void saveSettings (KConfig *config);
-	static void loadSettings (KConfig *config);
+	void save(KConfig *config) override { syncConfig(config, RKConfigBase::SaveConfig); };
+	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 	static void validateSettingsInteractive (QList<RKSetupWizardItem*>*) {};
 
 	void applyChanges () override;
-	void save (KConfig *config) override;
 	void validateGUI ();
 
 	static bool shouldShowInput (RCommand *command);
@@ -57,10 +56,10 @@ public slots:
 private:
 	enum FilterType { ShowInput=1, ShowOutput=2, ShowError=4, RaiseWindow=8 };
 
-	static int plugin_filter;
-	static int app_filter;
-	static int sync_filter;
-	static int user_filter;
+	static RKConfigValue<int> plugin_filter;
+	static RKConfigValue<int> app_filter;
+	static RKConfigValue<int> sync_filter;
+	static RKConfigValue<int> user_filter;
 	
 	struct FilterBoxes {
 		QCheckBox *input;
@@ -77,7 +76,7 @@ private:
 	int getFilterSettings (FilterBoxes *boxes);
 	FilterBoxes *addFilterSettings (QWidget *parent, QGridLayout *layout, int row, const QString &label, int state);
 
-	static uint max_log_lines;
+	static RKConfigValue<uint> max_log_lines;
 
 	QSpinBox *max_log_lines_spinner;
 };
diff --git a/rkward/windows/rkworkplace.cpp b/rkward/windows/rkworkplace.cpp
index 4c7788de..881d54a3 100644
--- a/rkward/windows/rkworkplace.cpp
+++ b/rkward/windows/rkworkplace.cpp
@@ -786,7 +786,6 @@ RKMDIWindow *RKWorkplace::activeWindow(RKMDIWindow::State state) const {
 }
 
 RKMDIWindow * RKWorkplace::windowForPart(KParts::Part* part) const {
-	RKMDIWindow *ret = 0;
 	for (auto it = windows.constBegin(); it != windows.constEnd(); ++it) {
 		if ((*it)->getPart() == part) {
 			return *it;



More information about the rkward-tracker mailing list