[education/rkward] rkward/settings: Automate creating of dropbown boxes in settings

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


Git commit 33be9e7c0b022b9cb84fa0d96e7ae464cfa10531 by Thomas Friedrichsmeier.
Committed on 12/03/2022 at 12:45.
Pushed by tfry into branch 'master'.

Automate creating of dropbown boxes in settings

M  +25   -0    rkward/settings/rksettingsmodule.cpp
M  +19   -0    rkward/settings/rksettingsmodule.h
M  +13   -35   rkward/settings/rksettingsmodulecommandeditor.cpp
M  +0    -4    rkward/settings/rksettingsmodulecommandeditor.h
M  +3    -7    rkward/settings/rksettingsmoduleconsole.cpp
M  +0    -1    rkward/settings/rksettingsmoduleconsole.h
M  +6    -30   rkward/settings/rksettingsmoduler.cpp
M  +0    -4    rkward/settings/rksettingsmoduler.h

https://invent.kde.org/education/rkward/commit/33be9e7c0b022b9cb84fa0d96e7ae464cfa10531

diff --git a/rkward/settings/rksettingsmodule.cpp b/rkward/settings/rksettingsmodule.cpp
index b615b23a..70808c94 100644
--- a/rkward/settings/rksettingsmodule.cpp
+++ b/rkward/settings/rksettingsmodule.cpp
@@ -17,9 +17,13 @@
 #include "rksettingsmodule.h"
 
 #include "../rkward.h"
+#include "../debug.h"
 #include "rksettings.h"
 
 #include <QCheckBox>
+#include <QComboBox>
+
+#include <functional>
 
 //static
 RCommandChain* RKSettingsModule::chain = 0;
@@ -53,6 +57,27 @@ template<typename TT, typename std::enable_if<std::is_same<TT, bool>::value>::ty
 	return ret;
 }
 
+QComboBox* RKConfigBase::makeDropDownHelper(const LabelList &entries, RKSettingsModuleWidget* module, int initial, std::function<void(int)> setter) {
+	RK_TRACE(SETTINGS);
+
+	QComboBox *ret = new QComboBox();
+	int index = -1;
+	for (int i = 0; i < entries.size(); ++i) {
+		auto key = entries[i].key;
+		auto label = entries[i].label;
+		ret->addItem(label, key);
+		if (key == initial) index = i;
+	}
+	RK_ASSERT(index >= 0);
+	ret->setCurrentIndex(index);
+	QObject::connect(ret, QOverload<int>::of(&QComboBox::currentIndexChanged), [ret, setter, module]() {
+		module->change();
+		setter(ret->currentData().toInt());
+	});
+
+	return ret;
+}
+
 void linkHelperDummy() {
 	RKConfigValue<bool>("", true).makeCheckbox(QString(), nullptr);
 }
diff --git a/rkward/settings/rksettingsmodule.h b/rkward/settings/rksettingsmodule.h
index 40d5f7a0..5052d4e7 100644
--- a/rkward/settings/rksettingsmodule.h
+++ b/rkward/settings/rksettingsmodule.h
@@ -26,6 +26,7 @@ class KConfig;
 class RKSettings;
 class RCommandChain;
 class QCheckBox;
+class QComboBox;
 class RKSettingsModule;
 class RKSettingsModuleWidget;
 class RKSetupWizardItem;
@@ -47,10 +48,18 @@ public:
 		else loadConfig(cg);
 	};
 	const char *key() { return name; }
+
+	struct ValueLabel {
+		int key;
+		QString label;
+	};
+	typedef QList<ValueLabel> LabelList;
 protected:
 	RKConfigBase(const char* name) : name(name) {};
 	virtual ~RKConfigBase() {};
 	const char* name;
+
+	static QComboBox* makeDropDownHelper(const LabelList &entries, RKSettingsModuleWidget* module, int initial, std::function<void(int)> setter);
 };
 
 /** A single value stored in the RKWard config file.
@@ -74,6 +83,16 @@ public:
 
 /** 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);
+/** Currently only for boolean or int options: Make a dropdown selector (QComboBox). If bit_flag_mask is set, the selector operates on (part of) an OR-able set of flags, instead of
+ *  plain values. */
+	QComboBox* makeDropDown(const LabelList &entries, RKSettingsModuleWidget* _module, int bit_flag_mask = 0) {
+		static_assert(std::is_same<STORAGE_T, int>::value || std::is_same<STORAGE_T, bool>::value, "makeDropDown can only be used for int or bool");
+		if (bit_flag_mask) {
+			return makeDropDownHelper(entries, _module, value & bit_flag_mask, [this, bit_flag_mask](int val){this->value = (T) ((this->value & ~bit_flag_mask) + val);});
+		} else {
+			return makeDropDownHelper(entries, _module, (std::is_same<STORAGE_T, bool>::value && value) ? 1 : (int) value, [this](int val){this->value = (T) val;});
+		}
+	}
 private:
 	T value;
 };
diff --git a/rkward/settings/rksettingsmodulecommandeditor.cpp b/rkward/settings/rksettingsmodulecommandeditor.cpp
index 14b4686a..02d38286 100644
--- a/rkward/settings/rksettingsmodulecommandeditor.cpp
+++ b/rkward/settings/rksettingsmodulecommandeditor.cpp
@@ -65,7 +65,7 @@ RKCodeCompletionSettingsWidget::RKCodeCompletionSettingsWidget(QWidget *parent,
 	auto_completion_min_chars_box = new RKSpinBox (auto_completion_enabled_box);
 	auto_completion_min_chars_box->setIntMode (1, INT_MAX, settings->auto_completion_min_chars);
 	connect (auto_completion_min_chars_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &RKCodeCompletionSettingsWidget::change);
-	form_layout->addRow ("Minimum number of characters", auto_completion_min_chars_box);
+	form_layout->addRow (i18n("Minimum number of characters"), auto_completion_min_chars_box);
 
 	auto_completion_timeout_box = new RKSpinBox (auto_completion_enabled_box);
 	auto_completion_timeout_box->setIntMode (0, INT_MAX, settings->auto_completion_timeout);
@@ -81,38 +81,26 @@ RKCodeCompletionSettingsWidget::RKCodeCompletionSettingsWidget(QWidget *parent,
 	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"));
-	cursor_navigates_completions_box->addItem(i18n("Alt+Up/down cursor keys"));
-	cursor_navigates_completions_box->setCurrentIndex(settings->cursor_navigates_completions ? 0 : 1);
+	auto cursor_navigates_completions_box = settings->cursor_navigates_completions.makeDropDown(RKConfigBase::LabelList(
+		{{1, i18n("Up/down cursor keys")}, {0, i18n("Alt+Up/down cursor keys")}}
+	), this);
 	RKCommonFunctions::setTips (i18n ("If you wish to avoid ambiguity between navigation completion options and navigating the document, you can set the behavior such that completion items are navigate using Alt+up / Alt+down, instead of just the up/down cursor keys."), cursor_navigates_completions_box);
-	connect (cursor_navigates_completions_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &RKCodeCompletionSettingsWidget::change);
 	form_layout->addRow (i18n ("Keyboard navigation of completion items"), cursor_navigates_completions_box);
 
 	if (show_common) {
-		completion_list_member_operator_box = new QComboBox (group);
-		completion_list_member_operator_box->addItem (i18n ("'$'-operator (list$member)"));
-		completion_list_member_operator_box->addItem (i18n ("'[['-operator (list[[\"member\"]])"));
-		completion_list_member_operator_box->setCurrentIndex ((settings->completion_options & RObject::DollarExpansion) ? 0 : 1);
-		connect (completion_list_member_operator_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &RKCodeCompletionSettingsWidget::change);
+		auto completion_list_member_operator_box = settings->completion_options.makeDropDown(RKConfigBase::LabelList(
+			{{RObject::DollarExpansion, i18n("'$'-operator (list$member)")}, {0, i18n("'[['-operator (list[[\"member\"]])")}}
+		), this, RObject::DollarExpansion);
 		form_layout->addRow (i18nc ("Note: list() and data.frame() are programming terms in R, and should not be translated, here", "Operator for access to members of list() and data.frame() objects"), completion_list_member_operator_box);
 
-		completion_slot_operator_box = new QComboBox (group);
-		completion_slot_operator_box->addItem (i18n ("'@'-operator (object at smember)"));
-		completion_slot_operator_box->addItem (i18n ("'slot()'-function (slot(object, member))"));
-		completion_slot_operator_box->setCurrentIndex ((settings->completion_options & RObject::ExplicitSlotsExpansion) ? 1 : 0);
-		connect (completion_slot_operator_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &RKCodeCompletionSettingsWidget::change);
+		auto completion_slot_operator_box = settings->completion_options.makeDropDown(RKConfigBase::LabelList(
+			{{0, i18n("'@'-operator (object at member)")}, {RObject::ExplicitSlotsExpansion, i18n("'slot()'-function (slot(object, member))")}}
+		), this, RObject::ExplicitSlotsExpansion);
 		form_layout->addRow (i18nc ("Note: S4-slot() is a programming term in R, and should not be translated, here", "Operator for access to S4-slot()s"), completion_slot_operator_box);
 
-		completion_object_qualification_box = new QComboBox (group);
-		completion_object_qualification_box->addItem (i18n ("For masked objects, only"));
-		completion_object_qualification_box->addItem (i18n ("For objects outside of <i>.GlobalEnv</i>, only"));
-		completion_object_qualification_box->addItem (i18n ("Always"));
-		if (settings->completion_options & (RObject::IncludeEnvirIfNotGlobalEnv)) {
-			if (settings->completion_options & (RObject::IncludeEnvirIfNotGlobalEnv)) completion_object_qualification_box->setCurrentIndex (2);
-			else completion_object_qualification_box->setCurrentIndex (1);
-		}
-		connect (completion_object_qualification_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &RKCodeCompletionSettingsWidget::change);
+		auto completion_object_qualification_box = settings->completion_options.makeDropDown(RKConfigBase::LabelList(
+			{{RObject::IncludeEnvirIfMasked, i18n("For masked objects, only")}, {RObject::IncludeEnvirIfNotGlobalEnv, i18n("For objects outside of <i>.GlobalEnv</i>, only")}, {RObject::IncludeEnvirIfNotGlobalEnv | RObject::IncludeEnvirForGlobalEnv, i18n("Always")}}
+		), this, RObject::IncludeEnvirIfNotGlobalEnv | RObject::IncludeEnvirForGlobalEnv | RObject::IncludeEnvirIfMasked);
 		form_layout->addRow (i18n ("Include environment for objects on the search path:"), completion_object_qualification_box);
 	} else {
 		box_layout->addWidget(RKCommonFunctions::linkedWrappedLabel(i18n("<b>Note: </b>Additional (common) completion options are available at the <a href=\"rkward://settings/editor\">script editor settings</a>")));
@@ -125,16 +113,6 @@ 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->cursor_navigates_completions = (cursor_navigates_completions_box->currentIndex() == 0);
-
-	if (show_common) {
-		settings->completion_options = 0;
-		if (completion_list_member_operator_box->currentIndex () == 0) settings->completion_options = settings->completion_options + RObject::DollarExpansion;
-		if (completion_slot_operator_box->currentIndex () == 1) settings->completion_options = settings->completion_options + RObject::ExplicitSlotsExpansion;
-		if (completion_object_qualification_box->currentIndex () == 2) settings->completion_options = settings->completion_options + (RObject::IncludeEnvirForGlobalEnv | RObject::IncludeEnvirIfNotGlobalEnv);
-		else if (completion_object_qualification_box->currentIndex () == 1) settings->completion_options = settings->completion_options + RObject::IncludeEnvirIfNotGlobalEnv;
-		else settings->completion_options = settings->completion_options + RObject::IncludeEnvirIfMasked;
-	}
 }
 
 void RKCodeCompletionSettingsWidget::makeCompletionTypeBoxes(const QStringList& labels, QGridLayout* layout) {
diff --git a/rkward/settings/rksettingsmodulecommandeditor.h b/rkward/settings/rksettingsmodulecommandeditor.h
index 319fe07a..1dab15ac 100644
--- a/rkward/settings/rksettingsmodulecommandeditor.h
+++ b/rkward/settings/rksettingsmodulecommandeditor.h
@@ -80,10 +80,6 @@ private:
 	RKSpinBox* auto_completion_min_chars_box;
 	RKSpinBox* auto_completion_timeout_box;
 	QGroupBox* auto_completion_enabled_box;
-	QComboBox* cursor_navigates_completions_box;
-	QComboBox* completion_list_member_operator_box;
-	QComboBox* completion_slot_operator_box;
-	QComboBox* completion_object_qualification_box;
 
 	RKCodeCompletionSettings *settings;
 	bool show_common;
diff --git a/rkward/settings/rksettingsmoduleconsole.cpp b/rkward/settings/rksettingsmoduleconsole.cpp
index f6100c0b..bb24af33 100644
--- a/rkward/settings/rksettingsmoduleconsole.cpp
+++ b/rkward/settings/rksettingsmoduleconsole.cpp
@@ -77,12 +77,9 @@ RKSettingsModuleConsole::RKSettingsModuleConsole (RKSettings *gui, QWidget *pare
 	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);
-	add_piped_commands_to_history_box->insertItem ((int) DontAdd, i18n ("Do not add"));
-	add_piped_commands_to_history_box->insertItem ((int) AddSingleLine, i18n ("Add only if single line"));
-	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);
+	auto add_piped_commands_to_history_box = add_piped_commands_to_history.makeDropDown(RKConfigBase::LabelList(
+		{{(int) DontAdd, i18n("Do not add")}, {(int) AddSingleLine, i18n("Add only if single line")}, {(int) AlwaysAdd, i18n("Add all commands")}}
+	), this);
 	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);
@@ -153,7 +150,6 @@ void RKSettingsModuleConsole::applyChanges () {
 	completion_settings_widget->applyChanges();
 	max_history_length = max_history_length_spinner->value ();
 	max_console_lines = max_console_lines_spinner->value ();
-	add_piped_commands_to_history = (PipedCommandsHistoryMode) add_piped_commands_to_history_box->currentIndex ();
 }
 	
 QString RKSettingsModuleConsole::caption () {
diff --git a/rkward/settings/rksettingsmoduleconsole.h b/rkward/settings/rksettingsmoduleconsole.h
index ada18bc6..8b04d753 100644
--- a/rkward/settings/rksettingsmoduleconsole.h
+++ b/rkward/settings/rksettingsmoduleconsole.h
@@ -75,7 +75,6 @@ private:
 	static RKConfigValue<bool> context_sensitive_history_by_default;
 
 	RKCodeCompletionSettingsWidget *completion_settings_widget;
-	QComboBox *add_piped_commands_to_history_box;
 	QSpinBox *max_history_length_spinner;
 	QSpinBox *max_console_lines_spinner;
 };
diff --git a/rkward/settings/rksettingsmoduler.cpp b/rkward/settings/rksettingsmoduler.cpp
index f2dd6ce0..afa23d30 100755
--- a/rkward/settings/rksettingsmoduler.cpp
+++ b/rkward/settings/rksettingsmoduler.cpp
@@ -79,14 +79,9 @@ RKSettingsModuleR::RKSettingsModuleR (RKSettings *gui, QWidget *parent) : RKSett
 
 	// options (warn)
 	grid->addWidget (new QLabel (i18n ("Display warnings"), this), ++row, 0);
-	warn_input = new QComboBox (this);
-	warn_input->setEditable (false);
-	warn_input->insertItem (0, i18n ("Suppress warnings"));			// do not change the order of options! See also: applyChanges ()
-	warn_input->insertItem (1, i18n ("Print warnings later (default)"));
-	warn_input->insertItem (2, i18n ("Print warnings immediately"));
-	warn_input->insertItem (3, i18n ("Convert warnings to errors"));
-	warn_input->setCurrentIndex (options_warn + 1);
-	connect (warn_input, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &RKSettingsModuleR::settingChanged);
+	auto warn_input = options_warn.makeDropDown(RKConfigBase::LabelList(
+		{{-1, i18n("Suppress warnings")}, {0, i18n("Print warnings later (default)")}, {1, i18n("Print warnings immediately")}, {2, i18n ("Convert warnings to errors")}}
+	), this);
 	grid->addWidget (warn_input, row, 1);
 
 	// options (OutDec)
@@ -128,22 +123,12 @@ RKSettingsModuleR::RKSettingsModuleR (RKSettings *gui, QWidget *parent) : RKSett
 
 	// options (keep.source)
 	grid->addWidget (new QLabel (i18n ("Keep comments in functions"), this), ++row, 0);
-	keepsource_input = new QComboBox (this);
-	keepsource_input->setEditable (false);
-	keepsource_input->addItem (i18n ("TRUE (default)"), true);
-	keepsource_input->addItem (i18n ("FALSE"), false);
-	keepsource_input->setCurrentIndex (options_keepsource ? 0 : 1);
-	connect (keepsource_input, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &RKSettingsModuleR::settingChanged);
+	auto keepsource_input = options_keepsource.makeDropDown(RKConfigBase::LabelList({{1, i18n("TRUE (default)")}, {0, i18n("FALSE")}}), this);
 	grid->addWidget (keepsource_input, row, 1);
 
 	// options (keep.source.pkgs)
 	grid->addWidget (new QLabel (i18n ("Keep comments in packages"), this), ++row, 0);
-	keepsourcepkgs_input = new QComboBox (this);
-	keepsourcepkgs_input->setEditable (false);
-	keepsourcepkgs_input->addItem (i18n ("TRUE"), true);
-	keepsourcepkgs_input->addItem (i18n ("FALSE (default)"), false);
-	keepsourcepkgs_input->setCurrentIndex (options_keepsourcepkgs ? 0 : 1);
-	connect (keepsourcepkgs_input, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &RKSettingsModuleR::settingChanged);
+	auto keepsourcepkgs_input = options_keepsourcepkgs.makeDropDown(RKConfigBase::LabelList({{1, i18n("TRUE")}, {0, i18n("FALSE (default)")}}), this);
 	grid->addWidget (keepsourcepkgs_input, row, 1);
 
 	// options (expressions)
@@ -168,12 +153,7 @@ RKSettingsModuleR::RKSettingsModuleR (RKSettings *gui, QWidget *parent) : RKSett
 
 	// options (check.bounds)
 	grid->addWidget (new QLabel (i18n ("Check vector bounds (warn)"), this), ++row, 0);
-	checkbounds_input = new QComboBox (this);
-	checkbounds_input->setEditable (false);
-	checkbounds_input->addItem (i18n ("TRUE"), true);
-	checkbounds_input->addItem (i18n ("FALSE (default)"), false);
-	checkbounds_input->setCurrentIndex (options_checkbounds ? 0 : 1);
-	connect (checkbounds_input, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &RKSettingsModuleR::settingChanged);
+	auto checkbounds_input = options_checkbounds.makeDropDown(RKConfigBase::LabelList({{1, i18n("TRUE")}, {0, i18n("FALSE (default)")}}), this);
 	grid->addWidget (checkbounds_input, row, 1);
 
 	grid->addWidget (new QLabel (i18n ("Editor command"), this), ++row, 0);
@@ -234,14 +214,10 @@ void RKSettingsModuleR::applyChanges () {
 
 	options_outdec = outdec_input->text ();
 	options_width = width_input->value ();
-	options_warn = warn_input->currentIndex () - 1;
 	options_warningslength = warningslength_input->value ();
 	options_maxprint = maxprint_input->value ();
-	options_keepsource = keepsource_input->itemData (keepsource_input->currentIndex ()).toBool ();
-	options_keepsourcepkgs = keepsourcepkgs_input->itemData (keepsourcepkgs_input->currentIndex ()).toBool ();
 	options_expressions = expressions_input->value ();
 	options_digits = digits_input->value ();
-	options_checkbounds = checkbounds_input->itemData (checkbounds_input->currentIndex ()).toBool ();
 	options_editor = editor_input->currentText ();
 	options_pager = pager_input->currentText ();
 	options_further = further_input->toPlainText ();
diff --git a/rkward/settings/rksettingsmoduler.h b/rkward/settings/rksettingsmoduler.h
index 62da874d..c5ebf66a 100644
--- a/rkward/settings/rksettingsmoduler.h
+++ b/rkward/settings/rksettingsmoduler.h
@@ -60,14 +60,10 @@ private slots:
 private:
 	QLineEdit *outdec_input;
 	QSpinBox *width_input;
-	QComboBox *warn_input;
 	QSpinBox *warningslength_input;
 	QSpinBox *maxprint_input;
-	QComboBox *keepsource_input;
-	QComboBox *keepsourcepkgs_input;
 	QSpinBox *expressions_input;
 	QSpinBox *digits_input;
-	QComboBox *checkbounds_input;
 	QComboBox *editor_input;
 	QComboBox *pager_input;
 	QTextEdit *further_input;



More information about the rkward-tracker mailing list