[education/rkward] rkward: Modernize settings code step 1: Automate the bureaucracy around boolean options.

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


Git commit e4772980dfaf761ec63894edd03e6231efa1979d by Thomas Friedrichsmeier.
Committed on 10/03/2022 at 22:06.
Pushed by tfry into branch 'master'.

Modernize settings code step 1: Automate the bureaucracy around boolean options.

Similar cleanup to follow for all other types of options

M  +1    -1    rkward/rkward.cpp
M  +7    -9    rkward/settings/rksettings.cpp
M  +28   -6    rkward/settings/rksettingsmodule.cpp
M  +32   -24   rkward/settings/rksettingsmodule.h
M  +17   -39   rkward/settings/rksettingsmodulecommandeditor.cpp
M  +2    -9    rkward/settings/rksettingsmodulecommandeditor.h
M  +17   -29   rkward/settings/rksettingsmoduleconsole.cpp
M  +4    -8    rkward/settings/rksettingsmoduleconsole.h
M  +1    -1    rkward/settings/rksettingsmoduledebug.cpp
M  +1    -1    rkward/settings/rksettingsmoduledebug.h
M  +9    -17   rkward/settings/rksettingsmodulegeneral.cpp
M  +3    -6    rkward/settings/rksettingsmodulegeneral.h
M  +4    -9    rkward/settings/rksettingsmodulegraphics.cpp
M  +2    -5    rkward/settings/rksettingsmodulegraphics.h
M  +32   -63   rkward/settings/rksettingsmoduleoutput.cpp
M  +9    -16   rkward/settings/rksettingsmoduleoutput.h
M  +1    -2    rkward/settings/rksettingsmoduleplugins.h
M  +20   -28   rkward/settings/rksettingsmoduler.cpp
M  +3    -6    rkward/settings/rksettingsmoduler.h

https://invent.kde.org/education/rkward/commit/e4772980dfaf761ec63894edd03e6231efa1979d

diff --git a/rkward/rkward.cpp b/rkward/rkward.cpp
index c826986f..2d24f9ff 100644
--- a/rkward/rkward.cpp
+++ b/rkward/rkward.cpp
@@ -426,7 +426,7 @@ void RKWardMainWindow::configureCarbonCopy () {
 	QDialog *dialog = new QDialog ();
 	dialog->setWindowTitle (i18n ("Carbon Copy Settings"));
 	QVBoxLayout *layout = new QVBoxLayout (dialog);
-	RKCarbonCopySettings *settings = new RKCarbonCopySettings (dialog);
+	RKCarbonCopySettings *settings = new RKCarbonCopySettings (dialog, nullptr);
 	layout->addWidget (settings);
 
 	RKDialogButtonBox *box = new RKDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel, dialog);
diff --git a/rkward/settings/rksettings.cpp b/rkward/settings/rksettings.cpp
index 7444e46c..3f2df298 100644
--- a/rkward/settings/rksettings.cpp
+++ b/rkward/settings/rksettings.cpp
@@ -210,19 +210,17 @@ void RKSettings::helpClicked () {
 	RKWorkplace::mainWorkplace ()->openHelpWindow (current_module->helpURL ());
 }
 
-void RKSettings::applyAll () {
+void RKSettings::applyAll() {
 	RK_TRACE (SETTINGS);
 
-	ModuleMap::const_iterator it;
-	for (it = modules.constBegin (); it != modules.constEnd (); ++it) {
-		if (it.value ()->hasChanges ()) {
-			it.value ()->applyChanges ();
-			it.value ()->changed = false;
-			it.value ()->save (KSharedConfig::openConfig ().data ());
-			tracker ()->signalSettingsChange (it.key ());
+	for (auto it = modules.constBegin(); it != modules.constEnd(); ++it) {
+		if (it.value()->hasChanges()) {
+			it.value()->doApply();
+			it.value()->save (KSharedConfig::openConfig().data());
+			tracker()->signalSettingsChange(it.key());
 		}
 	}
-	button (QDialogButtonBox::Apply)->setEnabled (false);
+	button(QDialogButtonBox::Apply)->setEnabled(false);
 }
 
 void RKSettings::enableApply () {
diff --git a/rkward/settings/rksettingsmodule.cpp b/rkward/settings/rksettingsmodule.cpp
index 16efdf02..b615b23a 100644
--- a/rkward/settings/rksettingsmodule.cpp
+++ b/rkward/settings/rksettingsmodule.cpp
@@ -2,7 +2,7 @@
                           rksettingsmodule  -  description
                              -------------------
     begin                : Wed Jul 28 2004
-    copyright            : (C) 2004 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -19,18 +19,40 @@
 #include "../rkward.h"
 #include "rksettings.h"
 
+#include <QCheckBox>
+
 //static
 RCommandChain* RKSettingsModule::chain = 0;
 
-RKSettingsModule::RKSettingsModule(RKSettings *gui, QWidget *parent) : QWidget (parent) {
-	changed = false;
-	RKSettingsModule::gui = gui;
+RKSettingsModule::RKSettingsModule(RKSettings *gui, QWidget *parent) : RKSettingsModuleWidget (parent, nullptr) {
+	connect(this, &RKSettingsModule::settingsChanged, gui, &RKSettings::enableApply);
 }
 
 RKSettingsModule::~RKSettingsModule() {
 }
 
-void RKSettingsModule::change () {
+RKSettingsModuleWidget::RKSettingsModuleWidget(QWidget *parent, RKSettingsModule *parent_module) : QWidget(parent), changed(false) {
+	if (parent_module) {
+		connect(this, &RKSettingsModuleWidget::settingsChanged, parent_module, &RKSettingsModuleWidget::change);
+		connect(parent_module, &RKSettingsModule::apply, this, &RKSettingsModuleWidget::doApply);
+	}
+}
+
+void RKSettingsModuleWidget::change() {
 	changed = true;
-	gui->enableApply ();
+	settingsChanged();
+}
+
+
+template<>
+template<typename TT, typename std::enable_if<std::is_same<TT, bool>::value>::type* = nullptr> QCheckBox* RKConfigValue<bool>::makeCheckbox(const QString& label, RKSettingsModuleWidget* module) {
+	QCheckBox *ret = new QCheckBox(label);
+	ret->setChecked(value);
+	QObject::connect(ret, &QCheckBox::stateChanged, module, &RKSettingsModuleWidget::change);
+	QObject::connect(module, &RKSettingsModuleWidget::apply, [ret, this]() { this->value = ret->isChecked(); });
+	return ret;
+}
+
+void linkHelperDummy() {
+	RKConfigValue<bool>("", true).makeCheckbox(QString(), nullptr);
 }
diff --git a/rkward/settings/rksettingsmodule.h b/rkward/settings/rksettingsmodule.h
index 8b214dd9..1fb95620 100644
--- a/rkward/settings/rksettingsmodule.h
+++ b/rkward/settings/rksettingsmodule.h
@@ -2,7 +2,7 @@
                           rksettingsmodule  -  description
                              -------------------
     begin                : Wed Jul 28 2004
-    copyright            : (C) 2004-2018 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -25,6 +25,10 @@
 class KConfig;
 class RKSettings;
 class RCommandChain;
+class QCheckBox;
+class RKSettingsModule;
+class RKSettingsModuleWidget;
+class RKSetupWizardItem;
 
 /** Base class for RKWard config settings.
  *
@@ -56,6 +60,9 @@ public:
 	void setDefaultValue(const T& value) { RKConfigValue<T>::value = value; }
 	operator T() const { 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 */
+	template<typename TT = T, typename std::enable_if<std::is_same<TT, bool>::value>::type* = nullptr> QCheckBox* makeCheckbox(const QString& label, RKSettingsModuleWidget* module);
 private:
 	T value;
 };
@@ -90,18 +97,39 @@ private:
 	std::vector<RKConfigBase*> values;
 };
 
+/** Base class for UI widgets operating on an RKSettingsModule. For now this is used, only where similar settings are shared across modules (e.g. code completion). Eventually, this could be used to disentangle RKSettingsModule from QWidget. */
+class RKSettingsModuleWidget : public QWidget {
+	Q_OBJECT
+public:
+	RKSettingsModuleWidget(QWidget *parent, RKSettingsModule *parent_module);
+	~RKSettingsModuleWidget() {};
+	virtual void applyChanges() = 0;
+/** Mark this module as "changed" (propagates to parent module) */
+	void change ();
+	bool hasChanges () { return changed; };
+signals:
+	void settingsChanged();
+	void apply();
+protected:
+	bool changed;
+/** temporary indirection until applyChanges() has been obsolete, everywhere */
+	void doApply() {
+		applyChanges();
+		emit(apply());
+		changed = false;
+	}
+};
+
 /**
 Base class for settings modules. Provides some pure virtual calls.
 
 @author Thomas Friedrichsmeier
 */
-class RKSettingsModule : public QWidget {
+class RKSettingsModule : public RKSettingsModuleWidget {
 public:
 	RKSettingsModule (RKSettings *gui, QWidget *parent);
 	virtual ~RKSettingsModule ();
 
-	bool hasChanges () { return changed; };
-	virtual void applyChanges () = 0;
 	virtual void save (KConfig *config) = 0;
 	
 	virtual QString caption () = 0;
@@ -110,29 +138,9 @@ be inserted into this chain. It's safe to use this unconditionally, as if there
 	RCommandChain *commandChain () { return chain; };
 
 	virtual QUrl helpURL () { return QUrl (); };
-protected:
-friend class RKSettingsModuleWidget;
-	void change ();
-
-	bool changed;
 private:
-	RKSettings *gui;
 friend class RKSettings;
 	static RCommandChain *chain;
 };
 
-/** Base class for UI widgets operating on an RKSettingsModule. For now this is used, only where similar settings are shared across modules (e.g. code completion). Eventually, this could be used to disentangle RKSettingsModule from QWidget. */
-class RKSettingsModuleWidget : public QWidget {
-public:
-	RKSettingsModuleWidget(QWidget *parent, RKSettingsModule *_module) : QWidget(parent), module(_module) {};
-	~RKSettingsModuleWidget() {};
-	virtual void applyChanges() = 0;
-protected:
-	void change() { module->change(); }
-private:
-	RKSettingsModule *module;
-};
-
-class RKSetupWizardItem;
-
 #endif
diff --git a/rkward/settings/rksettingsmodulecommandeditor.cpp b/rkward/settings/rksettingsmodulecommandeditor.cpp
index ce197c16..7fc3666f 100644
--- a/rkward/settings/rksettingsmodulecommandeditor.cpp
+++ b/rkward/settings/rksettingsmodulecommandeditor.cpp
@@ -2,7 +2,7 @@
                           rksettingsmodulecommandeditor  -  description
                              -------------------
     begin                : Tue Oct 23 2007
-    copyright            : (C) 2007-2019 by Thomas Friedrichsmeier
+    copyright            : (C) 2007-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -38,7 +38,7 @@
 // static members
 RKCodeCompletionSettings RKSettingsModuleCommandEditor::completion_settings;
 bool RKSettingsModuleCommandEditor::autosave_enabled;
-bool RKSettingsModuleCommandEditor::autosave_keep;
+RKConfigValue<bool> RKSettingsModuleCommandEditor::autosave_keep { "Autosave keep saves", false };
 int RKSettingsModuleCommandEditor::autosave_interval;
 int RKSettingsModuleCommandEditor::num_recent_files;
 QString RKSettingsModuleCommandEditor::script_file_filter;
@@ -72,19 +72,14 @@ RKCodeCompletionSettingsWidget::RKCodeCompletionSettingsWidget(QWidget *parent,
 	connect (auto_completion_timeout_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RKCodeCompletionSettingsWidget::change);
 	form_layout->addRow (i18n ("Timeout (milliseconds)"), auto_completion_timeout_box);
 
-	auto_completion_cursor_activated_box = new QCheckBox (auto_completion_enabled_box);
-	auto_completion_cursor_activated_box->setChecked (settings->auto_completion_cursor_activated);
-	connect (auto_completion_cursor_activated_box, &QCheckBox::stateChanged, this, &RKCodeCompletionSettingsWidget::change);
-	form_layout->addRow (i18n ("(Attempt to) start completion whenever the cursor position changes"), auto_completion_cursor_activated_box);
+	form_layout->addRow(i18n("(Attempt to) start completion whenever the cursor position changes"), settings->auto_completion_cursor_activated.makeCheckbox(QString(), this));
 
 	form_layout = new QFormLayout ();
 	box_layout->addLayout (form_layout);
 
-	tabkey_invokes_completion_box = new QCheckBox(group);
-	tabkey_invokes_completion_box->setChecked(settings->tabkey_invokes_completion);
-	RKCommonFunctions::setTips (i18n ("Note: Further shortcuts can be assigned, and by default, Ctlr+Space invokes completions, in addition to this. Further, pressing the Tab key, while completions are shown, performs partial completion (if possible), independent of this setting."), tabkey_invokes_completion_box);
-	connect (tabkey_invokes_completion_box, &QCheckBox::stateChanged, this, &RKCodeCompletionSettingsWidget::change);
-	form_layout->addRow (i18n ("Tab key invokes code completion"), tabkey_invokes_completion_box);
+	auto tabkey_invokes_completion_box = settings->tabkey_invokes_completion.makeCheckbox(QString(), this);
+	RKCommonFunctions::setTips(i18n("Note: Further shortcuts can be assigned, and by default, Ctlr+Space invokes completions, in addition to this. Further, pressing the Tab key, while completions are shown, performs partial completion (if possible), independent of this setting."), tabkey_invokes_completion_box);
+	form_layout->addRow(i18n("Tab key invokes code completion"), tabkey_invokes_completion_box);
 
 	cursor_navigates_completions_box = new QComboBox(group);
 	cursor_navigates_completions_box->addItem(i18n("Up/down cursor keys"));
@@ -130,12 +125,7 @@ void RKCodeCompletionSettingsWidget::applyChanges() {
 	settings->auto_completion_enabled = auto_completion_enabled_box->isChecked ();
 	settings->auto_completion_min_chars = auto_completion_min_chars_box->intValue ();
 	settings->auto_completion_timeout = auto_completion_timeout_box->intValue ();
-	settings->auto_completion_cursor_activated = auto_completion_cursor_activated_box->isChecked ();
-	for (int i = 0; i < RKCodeCompletionSettings::N_COMPLETION_CATEGORIES; ++i) {
-		settings->completion_type_enabled[i] = completion_type_enabled_box[i]->isChecked ();
-	}
 	settings->cursor_navigates_completions = (cursor_navigates_completions_box->currentIndex() == 0);
-	settings->tabkey_invokes_completion = tabkey_invokes_completion_box->isChecked();
 
 	if (show_common) {
 		settings->completion_options = 0;
@@ -147,14 +137,11 @@ void RKCodeCompletionSettingsWidget::applyChanges() {
 	}
 }
 
-void RKCodeCompletionSettingsWidget::makeCompletionTypeBoxes (const QStringList& labels, QGridLayout* layout) {
-	RK_ASSERT (labels.count () == RKCodeCompletionSettings::N_COMPLETION_CATEGORIES);
+void RKCodeCompletionSettingsWidget::makeCompletionTypeBoxes(const QStringList& labels, QGridLayout* layout) {
+	RK_ASSERT(labels.count() == RKCodeCompletionSettings::N_COMPLETION_CATEGORIES);
 	for (int i = 0; i < RKCodeCompletionSettings::N_COMPLETION_CATEGORIES; ++i) {
-		QCheckBox *box = new QCheckBox(labels[i]);
-		box->setChecked (settings->completion_type_enabled[i]);
-		completion_type_enabled_box[i] = box;
-		layout->addWidget (completion_type_enabled_box[i], i / 2, i % 2);
-		connect (box, &QCheckBox::stateChanged, this, &RKCodeCompletionSettingsWidget::change);
+		auto *box = settings->completion_type_enabled[i].makeCheckbox(labels[i], this);
+		layout->addWidget(box, i / 2, i % 2);
 	}
 }
 
@@ -172,18 +159,15 @@ RKSettingsModuleCommandEditor::RKSettingsModuleCommandEditor (RKSettings *gui, Q
 	QGroupBox *group = autosave_enabled_box = new QGroupBox (i18n ("Autosaves"), this);
 	autosave_enabled_box->setCheckable (true);
 	autosave_enabled_box->setChecked (autosave_enabled);
-	connect (autosave_enabled_box, &QGroupBox::toggled, this, &RKSettingsModuleCommandEditor::settingChanged);
+	connect (autosave_enabled_box, &QGroupBox::toggled, this, &RKSettingsModule::change);
 	QFormLayout *form_layout = new QFormLayout (group);
 
 	autosave_interval_box = new RKSpinBox (group);
 	autosave_interval_box->setIntMode (1, INT_MAX, autosave_interval);
-	connect (autosave_interval_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RKSettingsModuleCommandEditor::settingChanged);
+	connect (autosave_interval_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RKSettingsModule::change);
 	form_layout->addRow (i18n ("Autosave interval (minutes)"), autosave_interval_box);
 
-	autosave_keep_box = new QCheckBox (i18n ("Keep autosave file after manual save"), group);
-	autosave_keep_box->setChecked (autosave_keep);
-	connect (autosave_keep_box, &QCheckBox::stateChanged, this, &RKSettingsModuleCommandEditor::settingChanged);
-	form_layout->addRow (autosave_keep_box);
+	form_layout->addRow(autosave_keep.makeCheckbox(i18n("Keep autosave file after manual save"), this));
 
 	main_vbox->addWidget (group);
 
@@ -194,13 +178,13 @@ RKSettingsModuleCommandEditor::RKSettingsModuleCommandEditor (RKSettings *gui, Q
 	num_recent_files_box = new RKSpinBox (group);
 	num_recent_files_box->setIntMode (1, INT_MAX, num_recent_files);
 	RKCommonFunctions::setTips (i18n ("<p>The number of recent files to remember (in the Open Recent R Script File menu).</p>") + RKCommonFunctions::noteSettingsTakesEffectAfterRestart (), num_recent_files_box, group);
-	connect (num_recent_files_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RKSettingsModuleCommandEditor::settingChanged);
+	connect (num_recent_files_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RKSettingsModule::change);
 	form_layout->addRow (i18n ("Number of scripts in recent file lists (*)"), num_recent_files_box);
 
 	script_file_filter_box = new QLineEdit (group);
 	script_file_filter_box->setText (script_file_filter);
 	RKCommonFunctions::setTips (i18n ("<p>A list of filters (file name extensions) that should be treated as R script files. Most importantly, files matching one of these filters will always be opened with R syntax highlighting.</p><p>Filters are case insensitive.</p>"), script_file_filter_box);
-	connect (script_file_filter_box, &QLineEdit::textChanged, this, &RKSettingsModuleCommandEditor::settingChanged);
+	connect (script_file_filter_box, &QLineEdit::textChanged, this, &RKSettingsModule::change);
 	form_layout->addRow (i18n ("R script file filters (separated by spaces)"), script_file_filter_box);
 
 	main_vbox->addWidget (group);
@@ -212,11 +196,6 @@ RKSettingsModuleCommandEditor::~RKSettingsModuleCommandEditor () {
 	RK_TRACE (SETTINGS);
 }
 
-void RKSettingsModuleCommandEditor::settingChanged () {
-	RK_TRACE (SETTINGS);
-	change ();
-}
-
 QString RKSettingsModuleCommandEditor::caption () {
 	RK_TRACE (SETTINGS);
 	return (i18n ("Script editor"));
@@ -228,7 +207,6 @@ void RKSettingsModuleCommandEditor::applyChanges () {
 	completion_settings_widget->applyChanges ();
 
 	autosave_enabled = autosave_enabled_box->isChecked ();
-	autosave_keep = autosave_keep_box->isChecked ();
 	autosave_interval = autosave_interval_box->intValue ();
 
 	num_recent_files = num_recent_files_box->intValue ();
@@ -257,7 +235,7 @@ void RKSettingsModuleCommandEditor::saveSettings (KConfig *config) {
 	completion_settings.saveSettings(cg);
 
 	cg.writeEntry ("Autosave enabled", autosave_enabled);
-	cg.writeEntry ("Autosave keep saves", autosave_keep);
+	autosave_keep.saveConfig(cg);
 	cg.writeEntry ("Autosave interval", autosave_interval);
 
 	cg.writeEntry ("Max number of recent files", num_recent_files);
@@ -271,7 +249,7 @@ void RKSettingsModuleCommandEditor::loadSettings (KConfig *config) {
 	completion_settings.loadSettings(cg);
 
 	autosave_enabled = cg.readEntry ("Autosave enabled", true);
-	autosave_keep = cg.readEntry ("Autosave keep saves", false);
+	autosave_keep.loadConfig(cg);
 	autosave_interval = cg.readEntry ("Autosave interval", 5);
 
 	num_recent_files = cg.readEntry ("Max number of recent files", 10);
diff --git a/rkward/settings/rksettingsmodulecommandeditor.h b/rkward/settings/rksettingsmodulecommandeditor.h
index cfaf7478..7b75ba98 100644
--- a/rkward/settings/rksettingsmodulecommandeditor.h
+++ b/rkward/settings/rksettingsmodulecommandeditor.h
@@ -2,7 +2,7 @@
                           rksettingsmodulecommandeditor  -  description
                              -------------------
     begin                : Tue Oct 23 2007
-    copyright            : (C) 2007-2020 by Thomas Friedrichsmeier
+    copyright            : (C) 2007-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -21,7 +21,6 @@
 #include "../core/robject.h"
 
 class RKSpinBox;
-class QCheckBox;
 class QLineEdit;
 class QGroupBox;
 class QComboBox;
@@ -82,9 +81,6 @@ private:
 	RKSpinBox* auto_completion_min_chars_box;
 	RKSpinBox* auto_completion_timeout_box;
 	QGroupBox* auto_completion_enabled_box;
-	QCheckBox* auto_completion_cursor_activated_box;
-	QCheckBox* tabkey_invokes_completion_box;
-	QCheckBox* completion_type_enabled_box[RKCodeCompletionSettings::N_COMPLETION_CATEGORIES];
 	QComboBox* cursor_navigates_completions_box;
 	QComboBox* completion_list_member_operator_box;
 	QComboBox* completion_slot_operator_box;
@@ -124,17 +120,14 @@ public:
 	static int maxNumRecentFiles () { return num_recent_files; };
 	static QString scriptFileFilter () { return script_file_filter; };
 	static bool matchesScriptFileFilter (const QString &filename);
-public slots:
-	void settingChanged ();
 private:
 	static RKCodeCompletionSettings completion_settings;
 	static bool autosave_enabled;
-	static bool autosave_keep;
+	static RKConfigValue<bool> autosave_keep;
 	static int autosave_interval;
 
 	RKCodeCompletionSettingsWidget *completion_settings_widget;
 	QGroupBox* autosave_enabled_box;
-	QCheckBox* autosave_keep_box;
 	RKSpinBox* autosave_interval_box;
 
 	RKSpinBox* num_recent_files_box;
diff --git a/rkward/settings/rksettingsmoduleconsole.cpp b/rkward/settings/rksettingsmoduleconsole.cpp
index 816a382a..ce3dde13 100644
--- a/rkward/settings/rksettingsmoduleconsole.cpp
+++ b/rkward/settings/rksettingsmoduleconsole.cpp
@@ -2,7 +2,7 @@
                           rksettingsmoduleconsole  -  description
                              -------------------
     begin                : Sun Oct 16 2005
-    copyright            : (C) 2005-2020 by Thomas Friedrichsmeier
+    copyright            : (C) 2005-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -21,7 +21,7 @@
 #include <KSharedConfig>
 
 #include <qlayout.h>
-#include <qcheckbox.h>
+#include <QCheckBox>
 #include <qlabel.h>
 #include <QVBoxLayout>
 #include <QComboBox>
@@ -35,12 +35,12 @@
 // static
 
 RKCodeCompletionSettings RKSettingsModuleConsole::completion_settings;
-bool RKSettingsModuleConsole::save_history;
+RKConfigValue<bool> RKSettingsModuleConsole::save_history {"save history", true};
 uint RKSettingsModuleConsole::max_history_length;
 uint RKSettingsModuleConsole::max_console_lines;
-bool RKSettingsModuleConsole::pipe_user_commands_through_console;
+RKConfigValue<bool> RKSettingsModuleConsole::pipe_user_commands_through_console {"pipe user commands through console", true};
 RKSettingsModuleConsole::PipedCommandsHistoryMode RKSettingsModuleConsole::add_piped_commands_to_history;
-bool RKSettingsModuleConsole::context_sensitive_history_by_default;
+RKConfigValue<bool> RKSettingsModuleConsole::context_sensitive_history_by_default {"command history defaults to context sensitive", false};
 
 RKSettingsModuleConsole::RKSettingsModuleConsole (RKSettings *gui, QWidget *parent) : RKSettingsModule (gui, parent) {
 	RK_TRACE (SETTINGS);
@@ -49,10 +49,7 @@ RKSettingsModuleConsole::RKSettingsModuleConsole (RKSettings *gui, QWidget *pare
 
 	vbox->addWidget (completion_settings_widget = new RKCodeCompletionSettingsWidget (this, this, &completion_settings, false));
 
-	save_history_box = new QCheckBox (i18n ("Load/Save command history"), this);
-	save_history_box->setChecked (save_history);
-	connect (save_history_box, &QCheckBox::stateChanged, this, &RKSettingsModuleConsole::changedSetting);
-	vbox->addWidget (save_history_box);
+	vbox->addWidget (save_history.makeCheckbox(i18n("Load/Save command history"), this));
 
 	vbox->addWidget (new QLabel (i18n ("Maximum length of command history"), this));
 	max_history_length_spinner = new QSpinBox(this);
@@ -76,10 +73,8 @@ RKSettingsModuleConsole::RKSettingsModuleConsole (RKSettings *gui, QWidget *pare
 
 	vbox->addSpacing (2*RKGlobals::spacingHint ());
 
-	pipe_user_commands_through_console_box = new QCheckBox (i18n ("Run commands from script editor through console"), this);
-	pipe_user_commands_through_console_box->setChecked (pipe_user_commands_through_console);
-	connect (pipe_user_commands_through_console_box, &QCheckBox::stateChanged, this, &RKSettingsModuleConsole::changedSetting);
-	vbox->addWidget (pipe_user_commands_through_console_box);
+	auto pipe_user_commands_through_console_box = pipe_user_commands_through_console.makeCheckbox(i18n("Run commands from script editor through console"), this);
+	vbox->addWidget(pipe_user_commands_through_console_box);
 
 	vbox->addWidget (new QLabel (i18n ("Also add those commands to console history"), this));
 	add_piped_commands_to_history_box = new QComboBox (this);
@@ -88,15 +83,13 @@ RKSettingsModuleConsole::RKSettingsModuleConsole (RKSettings *gui, QWidget *pare
 	add_piped_commands_to_history_box->insertItem ((int) AlwaysAdd, i18n ("Add all commands"));
 	add_piped_commands_to_history_box->setCurrentIndex ((int) add_piped_commands_to_history);
 	connect (add_piped_commands_to_history_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &RKSettingsModuleConsole::changedSetting);
-	add_piped_commands_to_history_box->setEnabled (pipe_user_commands_through_console_box->isChecked ());
+	add_piped_commands_to_history_box->setEnabled(pipe_user_commands_through_console_box->isChecked());
+	connect(pipe_user_commands_through_console_box, &QCheckBox::stateChanged, add_piped_commands_to_history_box, &QCheckBox::setEnabled);
 	vbox->addWidget (add_piped_commands_to_history_box);
 
 	vbox->addSpacing (2*RKGlobals::spacingHint ());
 
-	reverse_context_mode_box = new QCheckBox (i18n ("Command history is context sensitive by default"), this);
-	connect (reverse_context_mode_box, &QCheckBox::stateChanged, this, &RKSettingsModuleConsole::changedSetting);
-	reverse_context_mode_box->setChecked (context_sensitive_history_by_default);
-	vbox->addWidget (reverse_context_mode_box);
+	vbox->addWidget (context_sensitive_history_by_default.makeCheckbox(i18n("Command history is context sensitive by default"), this));
 
 	vbox->addStretch ();
 }
@@ -108,8 +101,6 @@ RKSettingsModuleConsole::~RKSettingsModuleConsole () {
 void RKSettingsModuleConsole::changedSetting (int) {
 	RK_TRACE (SETTINGS);
 	change ();
-
-	add_piped_commands_to_history_box->setEnabled (pipe_user_commands_through_console_box->isChecked ());
 }
 
 //static
@@ -125,12 +116,12 @@ void RKSettingsModuleConsole::saveSettings (KConfig *config) {
 	RK_TRACE (SETTINGS);
 
 	KConfigGroup cg = config->group ("Console Settings");
-	cg.writeEntry ("save history", save_history);
+	save_history.saveConfig(cg);
 	cg.writeEntry ("max history length", max_history_length);
 	cg.writeEntry ("max console lines", max_console_lines);
-	cg.writeEntry ("pipe user commands through console", pipe_user_commands_through_console);
+	pipe_user_commands_through_console.saveConfig(cg);
 	cg.writeEntry ("add piped commands to history", (int) add_piped_commands_to_history);
-	cg.writeEntry ("command history defaults to context sensitive", context_sensitive_history_by_default);
+	context_sensitive_history_by_default.saveConfig(cg);
 	completion_settings.saveSettings(cg);
 }
 
@@ -139,12 +130,12 @@ void RKSettingsModuleConsole::loadSettings (KConfig *config) {
 	RK_TRACE (SETTINGS);
 
 	KConfigGroup cg = config->group ("Console Settings");
-	save_history = cg.readEntry ("save history", true);
+	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 = cg.readEntry ("pipe user commands through console", true);
+	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 = cg.readEntry ("command history defaults to context sensitive", false);
+	context_sensitive_history_by_default.loadConfig(cg);
 	completion_settings.tabkey_invokes_completion = true;
 	completion_settings.loadSettings(cg);
 }
@@ -172,12 +163,9 @@ void RKSettingsModuleConsole::applyChanges () {
 	RK_TRACE (SETTINGS);
 
 	completion_settings_widget->applyChanges();
-	save_history = save_history_box->isChecked ();
 	max_history_length = max_history_length_spinner->value ();
 	max_console_lines = max_console_lines_spinner->value ();
-	pipe_user_commands_through_console = pipe_user_commands_through_console_box->isChecked ();
 	add_piped_commands_to_history = (PipedCommandsHistoryMode) add_piped_commands_to_history_box->currentIndex ();
-	context_sensitive_history_by_default = reverse_context_mode_box->isChecked ();
 }
 
 void RKSettingsModuleConsole::save (KConfig *config) {
diff --git a/rkward/settings/rksettingsmoduleconsole.h b/rkward/settings/rksettingsmoduleconsole.h
index 33988082..cc1e79c7 100644
--- a/rkward/settings/rksettingsmoduleconsole.h
+++ b/rkward/settings/rksettingsmoduleconsole.h
@@ -2,7 +2,7 @@
                           rksettingsmoduleconsole  -  description
                              -------------------
     begin                : Sun Oct 16 2005
-    copyright            : (C) 2005-2020 by Thomas Friedrichsmeier
+    copyright            : (C) 2005-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -22,7 +22,6 @@
 #include "rksettingsmodulecommandeditor.h"  // For RKCodeCompletionSettings
 #include <qnamespace.h>
 
-class QCheckBox;
 class QComboBox;
 class QSpinBox;
 
@@ -70,17 +69,14 @@ public slots:
 	void changedSetting (int);
 private:
 	static RKCodeCompletionSettings completion_settings;
-	static bool save_history;
+	static RKConfigValue<bool> save_history;
 	static uint max_history_length;
 	static uint max_console_lines;
-	static bool pipe_user_commands_through_console;
+	static RKConfigValue<bool> pipe_user_commands_through_console;
 	static PipedCommandsHistoryMode add_piped_commands_to_history;
-	static bool context_sensitive_history_by_default;
+	static RKConfigValue<bool> context_sensitive_history_by_default;
 
 	RKCodeCompletionSettingsWidget *completion_settings_widget;
-	QCheckBox *save_history_box;
-	QCheckBox *reverse_context_mode_box;
-	QCheckBox *pipe_user_commands_through_console_box;
 	QComboBox *add_piped_commands_to_history_box;
 	QSpinBox *max_history_length_spinner;
 	QSpinBox *max_console_lines_spinner;
diff --git a/rkward/settings/rksettingsmoduledebug.cpp b/rkward/settings/rksettingsmoduledebug.cpp
index b0260bd3..359b4f60 100644
--- a/rkward/settings/rksettingsmoduledebug.cpp
+++ b/rkward/settings/rksettingsmoduledebug.cpp
@@ -2,7 +2,7 @@
                           rksettingsmoduledebug  description
                              -------------------
     begin                : Tue Oct 23 2007
-    copyright            : (C) 2007, 2009 by Thomas Friedrichsmeier
+    copyright            : (C) 2007-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
diff --git a/rkward/settings/rksettingsmoduledebug.h b/rkward/settings/rksettingsmoduledebug.h
index d03208a6..7a391571 100644
--- a/rkward/settings/rksettingsmoduledebug.h
+++ b/rkward/settings/rksettingsmoduledebug.h
@@ -2,7 +2,7 @@
                           rksettingsmoduledebug -  description
                              -------------------
     begin                : Tue Oct 23 2007
-    copyright            : (C) 2007-2018 by Thomas Friedrichsmeier
+    copyright            : (C) 2007-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
diff --git a/rkward/settings/rksettingsmodulegeneral.cpp b/rkward/settings/rksettingsmodulegeneral.cpp
index 464239d6..3bc7d39e 100644
--- a/rkward/settings/rksettingsmodulegeneral.cpp
+++ b/rkward/settings/rksettingsmodulegeneral.cpp
@@ -2,7 +2,7 @@
                           rksettingsmodulegeneral  -  description
                              -------------------
     begin                : Fri Jul 30 2004
-    copyright            : (C) 2004-2014 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -42,8 +42,8 @@ QString RKSettingsModuleGeneral::files_path;
 QString RKSettingsModuleGeneral::new_files_path;
 StartupDialog::Result RKSettingsModuleGeneral::startup_action;
 RKSettingsModuleGeneral::WorkplaceSaveMode RKSettingsModuleGeneral::workplace_save_mode;
-bool RKSettingsModuleGeneral::cd_to_workspace_dir_on_load;
-bool RKSettingsModuleGeneral::show_help_on_startup;
+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;
 RKSettingsModuleGeneral::RKWardConfigVersion RKSettingsModuleGeneral::stored_config_version;
@@ -81,10 +81,7 @@ RKSettingsModuleGeneral::RKSettingsModuleGeneral (RKSettings *gui, QWidget *pare
 	connect (startup_action_choser, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &RKSettingsModuleGeneral::settingChanged);
 	main_vbox->addWidget (startup_action_choser);
 
-	show_help_on_startup_box = new QCheckBox (i18n ("Show RKWard Help on Startup"), this);
-	show_help_on_startup_box->setChecked (show_help_on_startup);
-	connect (show_help_on_startup_box, &QCheckBox::stateChanged, this, &RKSettingsModuleGeneral::settingChanged);
-	main_vbox->addWidget (show_help_on_startup_box);
+	main_vbox->addWidget(show_help_on_startup.makeCheckbox(i18n("Show RKWard Help on Startup"), this));
 
 	QGroupBox* group_box = new QGroupBox (i18n ("Initial working directory (*)"), this);
 	QHBoxLayout *hlayout = new QHBoxLayout (group_box);
@@ -129,10 +126,7 @@ RKSettingsModuleGeneral::RKSettingsModuleGeneral (RKSettings *gui, QWidget *pare
 
 	main_vbox->addSpacing (2*RKGlobals::spacingHint ());
 
-	cd_to_workspace_dir_on_load_box = new QCheckBox (i18n ("When loading a workspace, change to the corresponding directory."), this);
-	cd_to_workspace_dir_on_load_box->setChecked (cd_to_workspace_dir_on_load);
-	connect (cd_to_workspace_dir_on_load_box, &QCheckBox::stateChanged, this, &RKSettingsModuleGeneral::settingChanged);
-	main_vbox->addWidget (cd_to_workspace_dir_on_load_box);
+	main_vbox->addWidget(cd_to_workspace_dir_on_load.makeCheckbox(i18n("When loading a workspace, change to the corresponding directory."), this));
 
 	main_vbox->addSpacing (2*RKGlobals::spacingHint ());
 
@@ -208,9 +202,7 @@ void RKSettingsModuleGeneral::applyChanges () {
 	RK_TRACE (SETTINGS);
 	new_files_path = files_choser->getLocation ();
 	startup_action = static_cast<StartupDialog::Result> (startup_action_choser->itemData (startup_action_choser->currentIndex ()).toInt ());
-	show_help_on_startup = show_help_on_startup_box->isChecked ();
 	workplace_save_mode = static_cast<WorkplaceSaveMode> (workplace_save_chooser->checkedId ());
-	cd_to_workspace_dir_on_load = cd_to_workspace_dir_on_load_box->isChecked ();
 	warn_size_object_edit = warn_size_object_edit_box->intValue ();
 	mdi_focus_policy = static_cast<RKMDIFocusPolicy> (mdi_focus_policy_chooser->currentIndex ());
 	initial_dir = static_cast<InitialDirectory> (initial_dir_chooser->itemData (initial_dir_chooser->currentIndex ()).toInt ());
@@ -231,14 +223,14 @@ void RKSettingsModuleGeneral::saveSettings (KConfig *config) {
 
 	cg = config->group ("General");
 	cg.writeEntry ("startup action", (int) startup_action);
-	cg.writeEntry ("show help on startup", show_help_on_startup);
+	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);
-	cg.writeEntry ("cd to workspace on load", cd_to_workspace_dir_on_load);
+	cd_to_workspace_dir_on_load.saveConfig(cg);
 
 	cg = config->group ("Editor");
 	cg.writeEntry ("large object warning limit", warn_size_object_edit);
@@ -261,7 +253,7 @@ void RKSettingsModuleGeneral::loadSettings (KConfig *config) {
 	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 = cg.readEntry ("show help on startup", true);
+	show_help_on_startup.loadConfig(cg);
 	initial_dir = (InitialDirectory) cg.readEntry ("initial dir mode",
 #ifndef Q_OS_WIN
 		(int) CurrentDirectory
@@ -276,7 +268,7 @@ void RKSettingsModuleGeneral::loadSettings (KConfig *config) {
 
 	cg = config->group ("Workplace");
 	workplace_save_mode = (WorkplaceSaveMode) cg.readEntry ("save mode", (int) SaveWorkplaceWithWorkspace);
-	cd_to_workspace_dir_on_load = cg.readEntry ("cd to workspace on load", true);
+	cd_to_workspace_dir_on_load.loadConfig(cg);
 
 	cg = config->group ("Editor");
 	warn_size_object_edit = cg.readEntry ("large object warning limit", 250000);
diff --git a/rkward/settings/rksettingsmodulegeneral.h b/rkward/settings/rksettingsmodulegeneral.h
index 9ed16a32..9a650bbd 100644
--- a/rkward/settings/rksettingsmodulegeneral.h
+++ b/rkward/settings/rksettingsmodulegeneral.h
@@ -2,7 +2,7 @@
                           rksettingsmodulegeneral  -  description
                              -------------------
     begin                : Fri Jul 30 2004
-    copyright            : (C) 2004-2018 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -22,7 +22,6 @@
 
 class GetFileNameWidget;
 class QComboBox;
-class QCheckBox;
 class QButtonGroup;
 class RKSpinBox;
 
@@ -116,8 +115,6 @@ private:
 	GetFileNameWidget *files_choser;
 	QComboBox *startup_action_choser;
 	QButtonGroup *workplace_save_chooser;
-	QCheckBox *cd_to_workspace_dir_on_load_box;
-	QCheckBox *show_help_on_startup_box;
 	RKSpinBox *warn_size_object_edit_box;
 	QComboBox *mdi_focus_policy_chooser;
 	QComboBox *initial_dir_chooser;
@@ -128,8 +125,8 @@ private:
 /** 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 bool cd_to_workspace_dir_on_load;
-	static bool show_help_on_startup;
+	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 RKWardConfigVersion stored_config_version;
diff --git a/rkward/settings/rksettingsmodulegraphics.cpp b/rkward/settings/rksettingsmodulegraphics.cpp
index d2229f70..af89302a 100644
--- a/rkward/settings/rksettingsmodulegraphics.cpp
+++ b/rkward/settings/rksettingsmodulegraphics.cpp
@@ -43,7 +43,7 @@ double RKSettingsModuleGraphics::graphics_height;
 bool RKSettingsModuleGraphics::graphics_hist_enable;
 int RKSettingsModuleGraphics::graphics_hist_max_length;
 int RKSettingsModuleGraphics::graphics_hist_max_plotsize;
-bool RKSettingsModuleGraphics::options_kde_printing;
+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;
@@ -123,10 +123,7 @@ RKSettingsModuleGraphics::RKSettingsModuleGraphics (RKSettings *gui, QWidget *pa
 	connect (graphics_height_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RKSettingsModuleGraphics::boxChanged);
 	main_vbox->addWidget (group);
 
-	kde_printing_box = new QCheckBox (i18n ("Use KDE printer dialog for printing devices (if available)"), this);
-	kde_printing_box->setChecked (options_kde_printing);
-	connect (kde_printing_box, &QCheckBox::stateChanged, this, &RKSettingsModuleGraphics::boxChanged);
-	main_vbox->addWidget (kde_printing_box);
+	main_vbox->addWidget(options_kde_printing.makeCheckbox(i18n("Use KDE printer dialog for printing devices (if available)"), this));
 
 	graphics_hist_box = new QGroupBox (i18n ("Screen device history"), this);
 	graphics_hist_box->setCheckable (true);
@@ -195,8 +192,6 @@ void RKSettingsModuleGraphics::applyChanges () {
 	graphics_hist_max_length = graphics_hist_max_length_box->value ();
 	graphics_hist_max_plotsize = graphics_hist_max_plotsize_box->value ();
 
-	options_kde_printing = kde_printing_box->isChecked ();
-
 	QStringList commands = makeRRunTimeOptionCommands ();
 	for (QStringList::const_iterator it = commands.begin (); it != commands.end (); ++it) {
 		RKGlobals::rInterface ()->issueCommand (*it, RCommand::App, QString (), 0, 0, commandChain ());
@@ -221,7 +216,7 @@ void RKSettingsModuleGraphics::saveSettings (KConfig *config) {
 	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);
-	cg.writeEntry ("kde printing", options_kde_printing);
+	options_kde_printing.saveConfig(cg);
 }
 
 void RKSettingsModuleGraphics::loadSettings (KConfig *config) {
@@ -236,7 +231,7 @@ void RKSettingsModuleGraphics::loadSettings (KConfig *config) {
 	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 = cg.readEntry ("kde printing", true);
+	options_kde_printing.loadConfig(cg);
 }
 
 //static
diff --git a/rkward/settings/rksettingsmodulegraphics.h b/rkward/settings/rksettingsmodulegraphics.h
index 676b6169..975611e1 100644
--- a/rkward/settings/rksettingsmodulegraphics.h
+++ b/rkward/settings/rksettingsmodulegraphics.h
@@ -2,7 +2,7 @@
                           rksettingsmodulegraphics  -  description
                              -------------------
     begin                : Mon Sep 13 2010
-    copyright            : (C) 2010-2018 by Thomas Friedrichsmeier
+    copyright            : (C) 2010-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -25,7 +25,6 @@ class QLineEdit;
 class QGroupBox;
 class RKSpinBox;
 class QSpinBox;
-class QCheckBox;
 class QButtonGroup;
 class QRadioButton;
 
@@ -82,8 +81,6 @@ private:
 	RKSpinBox *graphics_height_box;
 	RKSpinBox *graphics_width_box;
 
-	QCheckBox *kde_printing_box;
-
 	static DefaultDevice default_device;
 	static QString default_device_other;
 	static StandardDevicesMode replace_standard_devices;
@@ -95,7 +92,7 @@ private:
 	static double graphics_height;
 	static double graphics_width;
 
-	static bool options_kde_printing;
+	static RKConfigValue<bool> options_kde_printing;
 };
 
 #endif
diff --git a/rkward/settings/rksettingsmoduleoutput.cpp b/rkward/settings/rksettingsmoduleoutput.cpp
index eea2b8ee..912506fa 100644
--- a/rkward/settings/rksettingsmoduleoutput.cpp
+++ b/rkward/settings/rksettingsmoduleoutput.cpp
@@ -2,7 +2,7 @@
                           rksettingsmoduleoutput  -  description
                              -------------------
     begin                : Fri Jul 30 2004
-    copyright            : (C) 2004, 2010, 2011 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -36,38 +36,27 @@
 
 // static members
 bool RKCarbonCopySettings::cc_globally_enabled;
-bool RKCarbonCopySettings::cc_console_commands;
-bool RKCarbonCopySettings::cc_script_commands;
-bool RKCarbonCopySettings::cc_app_plugin_commands;
-bool RKCarbonCopySettings::cc_command_output;
+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};
+RKConfigValue<bool> RKCarbonCopySettings::cc_command_output {"CC command output", true};
 QList<RKCarbonCopySettings*> RKCarbonCopySettings::instances;
 
-RKCarbonCopySettings::RKCarbonCopySettings (QWidget* parent) : QWidget (parent) {
+RKCarbonCopySettings::RKCarbonCopySettings(QWidget* parent, RKSettingsModule* module) : RKSettingsModuleWidget(parent, module) {
 	RK_TRACE (SETTINGS);
 
 	QVBoxLayout *main_vbox = new QVBoxLayout (this);
 	main_vbox->setContentsMargins (0, 0, 0, 0);
 	cc_globally_enabled_box = new QGroupBox (i18n ("Carbon copy commands to output"), this);
 	cc_globally_enabled_box->setCheckable (true);
-	connect (cc_globally_enabled_box, &QGroupBox::clicked, this, &RKCarbonCopySettings::settingChanged);
+	connect (cc_globally_enabled_box, &QGroupBox::clicked, this, &RKCarbonCopySettings::change);
 	main_vbox->addWidget (cc_globally_enabled_box);
 
 	QVBoxLayout *group_layout = new QVBoxLayout (cc_globally_enabled_box);
-	cc_console_commands_box = new QCheckBox (i18n ("Commands entered in the console"), cc_globally_enabled_box);
-	connect (cc_console_commands_box, &QCheckBox::clicked, this, &RKCarbonCopySettings::settingChanged);
-	group_layout->addWidget (cc_console_commands_box);
-
-	cc_script_commands_box = new QCheckBox (i18n ("Commands run via the 'Run' menu"), cc_globally_enabled_box);
-	connect (cc_script_commands_box, &QCheckBox::clicked, this, &RKCarbonCopySettings::settingChanged);
-	group_layout->addWidget (cc_script_commands_box);
-
-	cc_app_plugin_commands_box = new QCheckBox (i18n ("Commands originating from dialogs and plugins"), cc_globally_enabled_box);
-	connect (cc_app_plugin_commands_box, &QCheckBox::clicked, this, &RKCarbonCopySettings::settingChanged);
-	group_layout->addWidget (cc_app_plugin_commands_box);
-
-	cc_command_output_box = new QCheckBox (i18n ("Also carbon copy the command output"), cc_globally_enabled_box);
-	connect (cc_command_output_box, &QCheckBox::clicked, this, &RKCarbonCopySettings::settingChanged);
-	group_layout->addWidget (cc_command_output_box);
+	group_layout->addWidget(cc_console_commands_box = cc_console_commands.makeCheckbox(i18n("Commands entered in the console"), this));
+	group_layout->addWidget(cc_script_commands_box = cc_script_commands.makeCheckbox(i18n("Commands run via the 'Run' menu"), this));
+	group_layout->addWidget(cc_app_plugin_commands_box = cc_app_plugin_commands.makeCheckbox(i18n("Commands originating from dialogs and plugins"), this));
+	group_layout->addWidget(cc_command_output_box = cc_command_output.makeCheckbox(i18n("Also carbon copy the command output"), this));
 
 	update ();
 	instances.append (this);
@@ -94,10 +83,10 @@ void RKCarbonCopySettings::saveSettings (KConfig *config) {
 
 	KConfigGroup cg = config->group ("Carbon Copy Settings");
 	cg.writeEntry ("CC enabled", cc_globally_enabled);
-	cg.writeEntry ("CC console commands", cc_console_commands);
-	cg.writeEntry ("CC script commands", cc_script_commands);
-	cg.writeEntry ("CC app/plugin commands", cc_app_plugin_commands);
-	cg.writeEntry ("CC command output", cc_command_output);
+	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) {
@@ -105,10 +94,10 @@ void RKCarbonCopySettings::loadSettings (KConfig *config) {
 
 	KConfigGroup cg = config->group ("Carbon Copy Settings");
 	cc_globally_enabled = cg.readEntry ("CC enabled", false);
-	cc_console_commands = cg.readEntry ("CC console commands", true);
-	cc_script_commands = cg.readEntry ("CC script commands", false);
-	cc_app_plugin_commands = cg.readEntry ("CC app/plugin commands", false);
-	cc_command_output = cg.readEntry ("CC command output", true);
+	cc_console_commands.loadConfig(cg);
+	cc_script_commands.loadConfig(cg);
+	cc_app_plugin_commands.loadConfig(cg);
+	cc_command_output.loadConfig(cg);
 }
 
 bool RKCarbonCopySettings::shouldCarbonCopyCommand (const RCommand *command) {
@@ -122,20 +111,10 @@ bool RKCarbonCopySettings::shouldCarbonCopyCommand (const RCommand *command) {
 	return false;
 }
 
-void RKCarbonCopySettings::settingChanged () {
-	RK_TRACE (SETTINGS);
-
-	emit (changed ());
-}
-
 void RKCarbonCopySettings::applyChanges() {
 	RK_TRACE (SETTINGS);
 
 	cc_globally_enabled = cc_globally_enabled_box->isChecked ();
-	cc_console_commands = cc_console_commands_box->isChecked ();
-	cc_script_commands = cc_script_commands_box->isChecked ();
-	cc_app_plugin_commands = cc_app_plugin_commands_box->isChecked ();
-	cc_command_output = cc_command_output_box->isChecked ();
 
 	foreach (RKCarbonCopySettings *sibling, instances) {
 		if (sibling != this) sibling->update ();
@@ -143,8 +122,8 @@ void RKCarbonCopySettings::applyChanges() {
 }
 
 // static members
-bool RKSettingsModuleOutput::auto_show;
-bool RKSettingsModuleOutput::auto_raise;
+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;
@@ -159,20 +138,16 @@ RKSettingsModuleOutput::RKSettingsModuleOutput (RKSettings *gui, QWidget *parent
 	
 	QGroupBox *group = new QGroupBox (i18n ("Output Window options"), this);
 	QVBoxLayout* group_layout = new QVBoxLayout (group);
-	group_layout->addWidget (auto_show_box = new QCheckBox (i18n ("show window on new output"), group));
-	auto_show_box->setChecked (auto_show);
-	connect (auto_show_box, &QCheckBox::stateChanged, this, &RKSettingsModuleOutput::boxChanged);
-	group_layout->addWidget (auto_raise_box = new QCheckBox (i18n ("raise window on new output"), group));
-	auto_raise_box->setChecked (auto_raise);
+	auto auto_show_box = auto_show.makeCheckbox(i18n("show window on new output"), this);
+	group_layout->addWidget (auto_show_box);
+	auto auto_raise_box = auto_raise.makeCheckbox(i18n("raise window on new output"), this);
+	group_layout->addWidget (auto_raise_box);
 	auto_raise_box->setEnabled (auto_show);
-	connect (auto_raise_box, &QCheckBox::stateChanged, this, &RKSettingsModuleOutput::boxChanged);
+	connect(auto_show_box, &QCheckBox::stateChanged, auto_raise_box, &QWidget::setEnabled);
 
 	main_vbox->addWidget (group);
 
-	shared_default_output_box = new QCheckBox(i18n("Default output (used, while no other output has been set, explicitly) is shared across workspaces(*)."), this);
-	shared_default_output_box->setChecked(shared_default_output);
-	connect(shared_default_output_box, &QCheckBox::stateChanged, this, &RKSettingsModuleOutput::boxChanged);
-	main_vbox->addWidget(shared_default_output_box);
+	main_vbox->addWidget(shared_default_output.makeCheckbox(i18n("Default output (used, while no other output has been set, explicitly) is shared across workspaces(*)."), this));
 
 	custom_css_file_box = new GetFileNameWidget (this, GetFileNameWidget::ExistingFile, true, i18n ("CSS file to use for output (leave empty for default)"), i18n ("Select CSS file"), custom_css_file);
 	connect (custom_css_file_box, &GetFileNameWidget::locationChanged, this, &RKSettingsModuleOutput::boxChanged);
@@ -224,8 +199,7 @@ RKSettingsModuleOutput::RKSettingsModuleOutput (RKSettings *gui, QWidget *parent
 
 	main_vbox->addWidget (group);
 
-	cc_settings = new RKCarbonCopySettings (this);
-	connect (cc_settings, &RKCarbonCopySettings::changed, this, &RKSettingsModuleOutput::boxChanged);
+	cc_settings = new RKCarbonCopySettings(this, this);
 	main_vbox->addWidget (cc_settings);
 
 	main_vbox->addStretch ();
@@ -238,7 +212,6 @@ RKSettingsModuleOutput::~RKSettingsModuleOutput() {
 void RKSettingsModuleOutput::boxChanged () {
 	RK_TRACE (SETTINGS);
 	change ();
-	auto_raise_box->setEnabled (auto_show_box->isChecked ());
 	graphics_jpg_quality_box->setEnabled (graphics_type_box->itemData (graphics_type_box->currentIndex ()).toString () == "\"JPG\"");
 }
 
@@ -250,10 +223,6 @@ QString RKSettingsModuleOutput::caption () {
 void RKSettingsModuleOutput::applyChanges () {
 	RK_TRACE (SETTINGS);
 
-	auto_show = auto_show_box->isChecked ();
-	auto_raise = auto_raise_box->isChecked ();
-	shared_default_output = shared_default_output_box->isChecked();
-
 	custom_css_file = custom_css_file_box->getLocation ();
 
 	graphics_type = graphics_type_box->itemData (graphics_type_box->currentIndex ()).toString ();
@@ -279,8 +248,8 @@ void RKSettingsModuleOutput::saveSettings (KConfig *config) {
 	RK_TRACE (SETTINGS);
 
 	KConfigGroup cg = config->group ("Output Window");
-	cg.writeEntry ("auto_show", auto_show);
-	cg.writeEntry ("auto_raise", auto_raise);
+	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);
@@ -295,8 +264,8 @@ void RKSettingsModuleOutput::loadSettings (KConfig *config) {
 	RK_TRACE (SETTINGS);
 
 	KConfigGroup cg = config->group ("Output Window");
-	auto_show = cg.readEntry ("auto_show", true);
-	auto_raise = cg.readEntry ("auto_raise", true);
+	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);
diff --git a/rkward/settings/rksettingsmoduleoutput.h b/rkward/settings/rksettingsmoduleoutput.h
index 5a785138..9dc6f0b6 100644
--- a/rkward/settings/rksettingsmoduleoutput.h
+++ b/rkward/settings/rksettingsmoduleoutput.h
@@ -2,7 +2,7 @@
                           rksettingsmoduleoutput  -  description
                              -------------------
     begin                : Fri Jul 30 2004
-    copyright            : (C) 2004-2018 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -33,10 +33,10 @@ Allows to configure which types of commands should be "carbon copied" to the out
 and a widget to configure the settings.
 @author Thomas Friedrichsmeier
 */
-class RKCarbonCopySettings : public QWidget {
+class RKCarbonCopySettings : public RKSettingsModuleWidget {
 	Q_OBJECT
 public:
-	explicit RKCarbonCopySettings (QWidget* parent);
+	explicit RKCarbonCopySettings (QWidget* parent, RKSettingsModule* module);
 	~RKCarbonCopySettings ();
 
 	static void saveSettings (KConfig *config);
@@ -46,10 +46,6 @@ public:
 	static bool includeOutputInCarbonCopy () { return (cc_globally_enabled && cc_command_output); };
 public slots:
 	void applyChanges ();
-signals:
-	void changed ();
-private slots:
-	void settingChanged ();
 private:
 	// There can be multiple instances of this widget, which need to be kept in sync.
 	static QList<RKCarbonCopySettings*> instances;
@@ -62,10 +58,10 @@ private:
 	QCheckBox *cc_command_output_box;
 
 	static bool cc_globally_enabled;
-	static bool cc_console_commands;
-	static bool cc_script_commands;
-	static bool cc_app_plugin_commands;
-	static bool cc_command_output;
+	static RKConfigValue<bool> cc_console_commands;
+	static RKConfigValue<bool> cc_script_commands;
+	static RKConfigValue<bool> cc_app_plugin_commands;
+	static RKConfigValue<bool> cc_command_output;
 };
 
 /**
@@ -95,18 +91,15 @@ public:
 public slots:
 	void boxChanged ();
 private:
-	QCheckBox *auto_show_box;
-	QCheckBox *auto_raise_box;
 	QComboBox *graphics_type_box;
 	QSpinBox *graphics_width_box;
 	QSpinBox *graphics_height_box;
 	QSpinBox *graphics_jpg_quality_box;
 	RKCarbonCopySettings *cc_settings;
 	GetFileNameWidget *custom_css_file_box;
-	QCheckBox* shared_default_output_box;
 
-	static bool auto_show;
-	static bool auto_raise;
+	static RKConfigValue<bool> auto_show;
+	static RKConfigValue<bool> auto_raise;
 	static QString graphics_type;
 	static int graphics_width;
 	static int graphics_height;
diff --git a/rkward/settings/rksettingsmoduleplugins.h b/rkward/settings/rksettingsmoduleplugins.h
index ae8ecd59..0ca7ea0b 100644
--- a/rkward/settings/rksettingsmoduleplugins.h
+++ b/rkward/settings/rksettingsmoduleplugins.h
@@ -2,7 +2,7 @@
                           rksettingsmoduleplugins  -  description
                              -------------------
     begin                : Wed Jul 28 2004
-    copyright            : (C) 2004-2020 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -27,7 +27,6 @@
 class RKMultiStringSelectorV2;
 class RKSettingsModulePluginsModel;
 class QButtonGroup;
-class QCheckBox;
 class RKSpinBox;
 
 /** The settings-module for plugin specific settings
diff --git a/rkward/settings/rksettingsmoduler.cpp b/rkward/settings/rksettingsmoduler.cpp
index a42b0624..b592c481 100755
--- a/rkward/settings/rksettingsmoduler.cpp
+++ b/rkward/settings/rksettingsmoduler.cpp
@@ -2,7 +2,7 @@
                           rksettingsmoduler  -  description
                              -------------------
     begin                : Wed Jul 28 2004
-    copyright            : (C) 2004-2018 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -380,8 +380,17 @@ void RKSettingsModuleR::loadSettings (KConfig *config) {
 QStringList RKSettingsModuleRPackages::liblocs;
 QStringList RKSettingsModuleRPackages::defaultliblocs;
 QString RKSettingsModuleRPackages::r_libs_user;
-bool RKSettingsModuleRPackages::archive_packages;
-bool RKSettingsModuleRPackages::source_packages;
+RKConfigValue<bool> RKSettingsModuleRPackages::archive_packages {"archive packages", false};
+#if (defined Q_OS_WIN || defined Q_OS_MACOS)
+#	if (defined USE_BINARY_PACKAGES)
+#		define USE_SOURCE_PACKAGES false
+#	else
+#		define USE_SOURCE_PACKAGES true
+#	endif
+#else
+#	define USE_SOURCE_PACKAGES true
+#endif
+RKConfigValue<bool> RKSettingsModuleRPackages::source_packages {"source_packages", USE_SOURCE_PACKAGES};
 QStringList RKSettingsModuleRPackages::package_repositories;
 QString RKSettingsModuleRPackages::essential_packages = QString ("base\nmethods\nutils\ngrDevices\ngraphics\nrkward");
 QString RKSettingsModuleRPackages::cran_mirror_url;
@@ -410,21 +419,15 @@ RKSettingsModuleRPackages::RKSettingsModuleRPackages (RKSettings *gui, QWidget *
 	connect (repository_selector, &MultiStringSelector::getNewStrings, this, &RKSettingsModuleRPackages::addRepository);
 	main_vbox->addWidget (repository_selector);
 
-	archive_packages_box = new QCheckBox (i18n ("Archive downloaded packages"), this);
-	archive_packages_box->setChecked (archive_packages);
-	connect (archive_packages_box, &QCheckBox::stateChanged, this, &RKSettingsModuleRPackages::settingChanged);
-	main_vbox->addWidget (archive_packages_box);
+	main_vbox->addWidget(archive_packages.makeCheckbox(i18n("Archive downloaded packages"), this));
 
-#if defined Q_OS_WIN || defined Q_OS_MACOS
-	source_packages_box = new QCheckBox (i18n ("Build packages from source"), this);
-	source_packages_box->setChecked (source_packages);
-#else
-	source_packages_box = new QCheckBox (i18n ("Build packages from source (not configurable on this platform)"), this);
+	auto source_packages_box = source_packages.makeCheckbox(i18n ("Build packages from source"), this);
+#if !defined Q_OS_WIN || defined Q_OS_MACOS
+	source_packages_box->setText(i18n("Build packages from source (not configurable on this platform)"));
 	source_packages_box->setChecked (true);
 	source_packages_box->setEnabled (false);
 #endif
 	RKCommonFunctions::setTips (QString ("<p>%1</p>").arg (i18n ("Installing packages from pre-compiled binaries (if available) is generally faster, and does not require an installation of development tools and libraries. On the other hand, building packages from source provides best compatibility. On Mac OS X and Linux, building packages from source is currently recommended.")), source_packages_box);
-	connect (source_packages_box, &QCheckBox::stateChanged, this, &RKSettingsModuleRPackages::settingChanged);
 	main_vbox->addWidget (source_packages_box);
 
 	main_vbox->addStretch ();
@@ -627,8 +630,6 @@ void RKSettingsModuleRPackages::applyChanges () {
 	cran_mirror_url = cran_mirror_input->text ();
 	if (cran_mirror_url.isEmpty ()) cran_mirror_url = "@CRAN@";
 
-	archive_packages = archive_packages_box->isChecked ();
-	source_packages = source_packages_box->isChecked ();
 	package_repositories = repository_selector->getValues ();
 	liblocs = libloc_selector->getValues ();
 
@@ -650,8 +651,8 @@ void RKSettingsModuleRPackages::saveSettings (KConfig *config) {
 
 	KConfigGroup cg = config->group ("R Settings");
 	cg.writeEntry ("CRAN mirror url", cran_mirror_url);
-	cg.writeEntry ("archive packages", archive_packages);
-	cg.writeEntry ("source_packages", source_packages);
+	archive_packages.saveConfig(cg);
+	source_packages.saveConfig(cg);
 	cg.writeEntry ("Repositories", package_repositories);
 	cg.writeEntry ("LibraryLocations", liblocs);
 }
@@ -673,21 +674,12 @@ void RKSettingsModuleRPackages::loadSettings (KConfig *config) {
 	}
 
 	liblocs = cg.readEntry ("LibraryLocations", QStringList ());
-	archive_packages = cg.readEntry ("archive packages", false);
-#if defined Q_OS_WIN || defined Q_OS_MACOS
-#	if defined USE_BINARY_PACKAGES
-#		define USE_SOURCE_PACKAGES false
-#	else
-#		define USE_SOURCE_PACKAGES true
-#endif
-	source_packages = cg.readEntry ("source packages", USE_SOURCE_PACKAGES);
+	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;
 	}
-#else
-	source_packages = true;
-#endif
 }
 
 #include <QGroupBox>
diff --git a/rkward/settings/rksettingsmoduler.h b/rkward/settings/rksettingsmoduler.h
index 5d3aa20d..4d98d7e1 100644
--- a/rkward/settings/rksettingsmoduler.h
+++ b/rkward/settings/rksettingsmoduler.h
@@ -2,7 +2,7 @@
                           rksettingsmoduler  -  description
                              -------------------
     begin                : Wed Jul 28 2004
-    copyright            : (C) 2004-2018 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2022 by Thomas Friedrichsmeier
     email                : thomas.friedrichsmeier at kdemail.net
  ***************************************************************************/
 
@@ -22,7 +22,6 @@
 #include <qstring.h>
 #include <qstringlist.h>
 
-class QCheckBox;
 class QComboBox;
 class QLineEdit;
 class MultiStringSelector;
@@ -145,15 +144,13 @@ private:
 	static QString libLocsCommand ();
 
 	MultiStringSelector *libloc_selector;
-	QCheckBox *archive_packages_box;
-	QCheckBox *source_packages_box;
 	MultiStringSelector *repository_selector;
 	QLineEdit* cran_mirror_input;
 
 	static QString cran_mirror_url;
 	static QStringList liblocs;
-	static bool archive_packages;
-	static bool source_packages;
+	static RKConfigValue<bool> archive_packages;
+	static RKConfigValue<bool> source_packages;
 	static QStringList package_repositories;
 
 	friend class RInterface;



More information about the rkward-tracker mailing list