[education/rkward] rkward: Fix for some settings not getting applied; support creation of checkable groupbox in RKConfigValue

Thomas Friedrichsmeier null at kde.org
Mon Jul 22 22:34:28 BST 2024


Git commit 710843879370e28a712394768666c56493a5cfc9 by Thomas Friedrichsmeier.
Committed on 22/07/2024 at 21:34.
Pushed by tfry into branch 'master'.

Fix for some settings not getting applied; support creation of checkable groupbox in RKConfigValue

M  +3    -2    rkward/rkward.cpp
M  +12   -0    rkward/settings/rksettingsmodule.cpp
M  +8    -5    rkward/settings/rksettingsmodule.h
M  +62   -59   rkward/settings/rksettingsmodulecommandeditor.cpp
M  +3    -10   rkward/settings/rksettingsmodulecommandeditor.h
M  +2    -2    rkward/settings/rksettingsmoduleconsole.cpp
M  +3    -10   rkward/settings/rksettingsmodulegraphics.cpp
M  +22   -37   rkward/settings/rksettingsmoduleoutput.cpp
M  +2    -9    rkward/settings/rksettingsmoduleoutput.h

https://invent.kde.org/education/rkward/-/commit/710843879370e28a712394768666c56493a5cfc9

diff --git a/rkward/rkward.cpp b/rkward/rkward.cpp
index c15fcd8a4..a9976fb26 100644
--- a/rkward/rkward.cpp
+++ b/rkward/rkward.cpp
@@ -412,6 +412,7 @@ void RKWardMainWindow::slotCancelAllCommands () {
 void RKWardMainWindow::configureCarbonCopy () {
 	RK_TRACE (APP);
 
+	// TODO: This is currently known not to stay in sync with the main settings dialog, if both are active at the same time
 	QDialog *dialog = new QDialog ();
 	dialog->setWindowTitle (i18n ("Carbon Copy Settings"));
 	QVBoxLayout *layout = new QVBoxLayout (dialog);
@@ -420,8 +421,8 @@ void RKWardMainWindow::configureCarbonCopy () {
 
 	RKDialogButtonBox *box = new RKDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel, dialog);
 	dialog->setAttribute (Qt::WA_DeleteOnClose);
-	connect (dialog, &QDialog::accepted, settings, &RKCarbonCopySettings::applyChanges);
-	connect (box->button (QDialogButtonBox::Apply), &QPushButton::clicked, settings, &RKCarbonCopySettings::applyChanges);
+	connect(dialog, &QDialog::accepted, settings, &RKCarbonCopySettings::doApply);
+	connect(box->button(QDialogButtonBox::Apply), &QPushButton::clicked, settings, &RKCarbonCopySettings::doApply);
 	layout->addWidget (box);
 
 	dialog->show ();
diff --git a/rkward/settings/rksettingsmodule.cpp b/rkward/settings/rksettingsmodule.cpp
index 79b7d0aad..f7fdd6f92 100644
--- a/rkward/settings/rksettingsmodule.cpp
+++ b/rkward/settings/rksettingsmodule.cpp
@@ -12,6 +12,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
 #include "../misc/rkspinbox.h"
 
 #include <QCheckBox>
+#include <QGroupBox>
 #include <QComboBox>
 
 #include <functional>
@@ -52,6 +53,17 @@ QCheckBox* RKConfigValue<bool, bool>::makeCheckbox(const QString& label, RKSetti
 	return ret;
 }
 
+template<>
+QGroupBox* RKConfigValue<bool, bool>::makeCheckableGroupBox(const QString& label, RKSettingsModuleWidget* module) {
+	QGroupBox *ret = new QGroupBox(label);
+	ret->setCheckable(true);
+	ret->setChecked(value);
+	QObject::connect(ret, &QGroupBox::toggled, module, &RKSettingsModuleWidget::change);
+	QObject::connect(module, &RKSettingsModuleWidget::apply, module, [ret, this]() { this->value = ret->isChecked(); });
+	return ret;
+}
+
+
 template<>
 QAction* RKConfigValue<bool, bool>::makeAction(QObject *parent, const QString &label, std::function<void(bool)> handler) {
 	QAction *ret = new QAction(label, parent);
diff --git a/rkward/settings/rksettingsmodule.h b/rkward/settings/rksettingsmodule.h
index 29716022c..2228c57a9 100644
--- a/rkward/settings/rksettingsmodule.h
+++ b/rkward/settings/rksettingsmodule.h
@@ -18,6 +18,7 @@ class RKSettings;
 class RCommandChain;
 class QCheckBox;
 class QComboBox;
+class QGroupBox;
 class RKSettingsModule;
 class RKSettingsModuleWidget;
 class RKSetupWizardItem;
@@ -76,6 +77,8 @@ public:
 
 /** Only for bool values: convenience function to create a fully connected checkbox for this option */
 	QCheckBox* makeCheckbox(const QString& label, RKSettingsModuleWidget* module);
+/** Only for bool values: convenience function to create a fully connected checkable groupbox for this option */
+	QGroupBox* makeCheckableGroupBox(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) {
@@ -166,6 +169,11 @@ public:
 	bool hasChanges() const { return changed; };
 	virtual QString longCaption() const { return windowTitle(); };
 	RKSettingsModule* parentModule() const { return parent_module; };
+	void doApply() {
+		Q_EMIT apply();
+		applyChanges();
+		changed = false;
+	}
 Q_SIGNALS:
 	void settingsChanged();
 	void apply();
@@ -173,11 +181,6 @@ protected:
 	QUrl helpURL() { return help_url; };
 	bool changed;
 /** temporary indirection until applyChanges() has been obsolete, everywhere */
-	void doApply() {
-		Q_EMIT apply();
-		applyChanges();
-		changed = false;
-	}
 friend class RKSettings;
 	const RKSettingsModule::PageId pageid;
 	const RKSettingsModule::PageId superpageid;
diff --git a/rkward/settings/rksettingsmodulecommandeditor.cpp b/rkward/settings/rksettingsmodulecommandeditor.cpp
index 49bfc920a..0740b54b6 100644
--- a/rkward/settings/rksettingsmodulecommandeditor.cpp
+++ b/rkward/settings/rksettingsmodulecommandeditor.cpp
@@ -37,79 +37,88 @@ RKConfigValue<bool> RKSettingsModuleCommandEditor::autosave_keep { "Autosave kee
 RKConfigValue<int> RKSettingsModuleCommandEditor::autosave_interval {"Autosave interval", 5 };
 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, RKSettingsModule::no_page_id), settings(settings) {
-	RK_TRACE (SETTINGS);
-	QVBoxLayout* main_vbox = new QVBoxLayout (this);
-	main_vbox->setContentsMargins(0,0,0,0);
+RKCodeCompletionSettingsWidget::RKCodeCompletionSettingsWidget(RKSettingsModuleWidget* parent, RKCodeCompletionSettings* settings, bool show_common)
+    : QWidget(parent), settings(settings), parentwidget(parent) {
+	RK_TRACE(SETTINGS);
+
+	QVBoxLayout* main_vbox = new QVBoxLayout(this);
+	main_vbox->setContentsMargins(0, 0, 0, 0);
 
-	QGroupBox* group = new QGroupBox (i18n ("Code Completion / Code Hints"), this);
-	QVBoxLayout* box_layout = new QVBoxLayout (group);
+	QGroupBox* group = new QGroupBox(i18n("Code Completion / Code Hints"));
+	QVBoxLayout* box_layout = new QVBoxLayout(group);
 
-	QGridLayout *g_layout = new QGridLayout ();
-	box_layout->addLayout (g_layout);
-	makeCompletionTypeBoxes (QStringList () << i18n ("Function call tip") << i18n ("Function argument completion") << i18n ("Object name completion") << i18n ("Filename completion") << i18n ("Auto word completion") << i18n("Mouseover object info"), g_layout);
+	QGridLayout* g_layout = new QGridLayout();
+	box_layout->addLayout(g_layout);
+	makeCompletionTypeBoxes(QStringList{i18n("Function call tip"), i18n("Function argument completion"), i18n("Object name completion"),
+	                                    i18n("Filename completion"), i18n("Auto word completion"), i18n("Mouseover object info")},
+	                        g_layout);
 
-	auto_completion_enabled_box = new QGroupBox (i18n ("Start code completions/hints, automatically"), group);
-	auto_completion_enabled_box->setCheckable (true);
-	auto_completion_enabled_box->setChecked (settings->auto_completion_enabled);
-	connect (auto_completion_enabled_box, &QGroupBox::toggled, this, &RKCodeCompletionSettingsWidget::change);
-	box_layout->addWidget (auto_completion_enabled_box);
+	auto auto_completion_enabled_box = settings->auto_completion_enabled.makeCheckableGroupBox(i18n("Start code completions/hints, automatically"), parent);
+	box_layout->addWidget(auto_completion_enabled_box);
 
-	QFormLayout* form_layout = new QFormLayout (auto_completion_enabled_box);
-	auto auto_completion_min_chars_box = settings->auto_completion_min_chars.makeSpinBox(1, INT_MAX, this);
-	form_layout->addRow (i18n("Minimum number of characters"), auto_completion_min_chars_box);
+	QFormLayout* form_layout = new QFormLayout(auto_completion_enabled_box);
+	auto auto_completion_min_chars_box = settings->auto_completion_min_chars.makeSpinBox(1, INT_MAX, parent);
+	form_layout->addRow(i18n("Minimum number of characters"), auto_completion_min_chars_box);
 
-	auto auto_completion_timeout_box = settings->auto_completion_timeout.makeSpinBox(0, INT_MAX, this);
-	form_layout->addRow (i18n ("Timeout (milliseconds)"), auto_completion_timeout_box);
+	auto auto_completion_timeout_box = settings->auto_completion_timeout.makeSpinBox(0, INT_MAX, parent);
+	form_layout->addRow(i18n("Timeout (milliseconds)"), auto_completion_timeout_box);
 
-	form_layout->addRow(i18n("(Attempt to) start completion whenever the cursor position changes"), settings->auto_completion_cursor_activated.makeCheckbox(QString(), this));
+	form_layout->addRow(i18n("(Attempt to) start completion whenever the cursor position changes"),
+	                    settings->auto_completion_cursor_activated.makeCheckbox(QString(), parent));
 
-	form_layout = new QFormLayout ();
-	box_layout->addLayout (form_layout);
+	form_layout = new QFormLayout();
+	box_layout->addLayout(form_layout);
 
-	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);
+	auto tabkey_invokes_completion_box = settings->tabkey_invokes_completion.makeCheckbox(QString(), 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);
 
-	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);
-	form_layout->addRow (i18n ("Keyboard navigation of completion items"), cursor_navigates_completions_box);
+	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")}}), parent);
+	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);
+	form_layout->addRow(i18n("Keyboard navigation of completion items"), cursor_navigates_completions_box);
 
 	if (show_common) {
-		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);
-
-		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);
-
-		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);
-
-		auto completion_all_filetypes = settings->completion_all_filetypes.makeCheckbox(QString(), this);
+		auto completion_list_member_operator_box = settings->completion_options.makeDropDown(
+		    RKConfigBase::LabelList({{RObject::DollarExpansion, i18n("'$'-operator (list$member)")}, {0, i18n("'[['-operator (list[[\"member\"]])")}}), parent,
+		    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);
+
+		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))")}}),
+		    parent, 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);
+
+		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")}}),
+		    parent, RObject::IncludeEnvirIfNotGlobalEnv | RObject::IncludeEnvirForGlobalEnv | RObject::IncludeEnvirIfMasked);
+		form_layout->addRow(i18n("Include environment for objects on the search path:"), completion_object_qualification_box);
+
+		auto completion_all_filetypes = settings->completion_all_filetypes.makeCheckbox(QString(), parent);
 		form_layout->addRow(i18n("Offer completions in all file types (not just R scripts)"), completion_all_filetypes);
 	} 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>")));
+		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>")));
 	}
 
 	main_vbox->addWidget(group);
 }
 
-void RKCodeCompletionSettingsWidget::applyChanges() {
-	settings->auto_completion_enabled = auto_completion_enabled_box->isChecked ();
-}
-
 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) {
-		auto *box = settings->completion_type_enabled[i].makeCheckbox(labels[i], this);
+		auto* box = settings->completion_type_enabled[i].makeCheckbox(labels[i], parentwidget);
 		layout->addWidget(box, i / 2, i % 2);
 	}
 }
@@ -134,14 +143,11 @@ public:
 		main_vbox->addWidget(RKCommonFunctions::wordWrappedLabel(i18n("Settings marked with (*) do not take effect until you restart RKWard")));
 		main_vbox->addSpacing(2 * RKStyle::spacingHint());
 
-		main_vbox->addWidget(completion_settings_widget = new RKCodeCompletionSettingsWidget(this, parent_module, &parent_module->completion_settings, true));
+		main_vbox->addWidget(completion_settings_widget = new RKCodeCompletionSettingsWidget(this, &RKSettingsModuleCommandEditor::completion_settings, true));
 
 		main_vbox->addSpacing(2 * RKStyle::spacingHint());
 
-		QGroupBox *group = autosave_enabled_box = new QGroupBox(i18n("Autosaves"), this);
-		autosave_enabled_box->setCheckable(true);
-		autosave_enabled_box->setChecked(RKSettingsModuleCommandEditor::autosave_enabled);
-		connect(autosave_enabled_box, &QGroupBox::toggled, this, &RKSettingsPageCommandEditor::change);
+		QGroupBox *group = RKSettingsModuleCommandEditor::autosave_enabled.makeCheckableGroupBox(i18n("Autosaves"), this);
 		QFormLayout *form_layout = new QFormLayout(group);
 
 		form_layout->addRow(i18n("Autosave interval (minutes)"), RKSettingsModuleCommandEditor::autosave_interval.makeSpinBox(1, INT_MAX, this));
@@ -164,13 +170,10 @@ public:
 	void applyChanges() override {
 		RK_TRACE(SETTINGS);
 
-		completion_settings_widget->applyChanges();
-		RKSettingsModuleCommandEditor::autosave_enabled = autosave_enabled_box->isChecked();
 		RKSettingsModuleCommandEditor::script_file_filter = script_file_filter_box->text();
 	}
 private:
 	RKCodeCompletionSettingsWidget *completion_settings_widget;
-	QGroupBox* autosave_enabled_box;
 	QLineEdit* script_file_filter_box;
 };
 
diff --git a/rkward/settings/rksettingsmodulecommandeditor.h b/rkward/settings/rksettingsmodulecommandeditor.h
index a7e65d607..8917255ed 100644
--- a/rkward/settings/rksettingsmodulecommandeditor.h
+++ b/rkward/settings/rksettingsmodulecommandeditor.h
@@ -10,13 +10,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
 #include "rksettingsmodule.h"
 #include "../core/robject.h"
 
-class RKSpinBox;
-class QLineEdit;
-class QGroupBox;
-class QComboBox;
 class QGridLayout;
 namespace KTextEditor { class ConfigPage; }
-
 class RKCodeCompletionSettingsWidget;
 class RKCodeCompletionSettings {
 public:
@@ -63,17 +58,15 @@ friend class RKSettingsModuleConsole;
 	RKConfigGroup group {"Completion", { &dummyoptions, &auto_completion_enabled, &auto_completion_min_chars, &auto_completion_timeout, &auto_completion_cursor_activated, &tabkey_invokes_completion, &cursor_navigates_completions, &completion_options, &completion_all_filetypes }};
 };
 
-class RKCodeCompletionSettingsWidget : public RKSettingsModuleWidget {
+class RKCodeCompletionSettingsWidget : public QWidget {
 public:
-	RKCodeCompletionSettingsWidget(QWidget *parent, RKSettingsModule *module, RKCodeCompletionSettings *settings, bool show_common);
+	RKCodeCompletionSettingsWidget(RKSettingsModuleWidget *parent, RKCodeCompletionSettings *settings, bool show_common);
 	~RKCodeCompletionSettingsWidget() {};
-	void applyChanges() override;
 private:
 	void makeCompletionTypeBoxes (const QStringList& labels, QGridLayout* layout);
 
-	QGroupBox* auto_completion_enabled_box;
-
 	RKCodeCompletionSettings *settings;
+	RKSettingsModuleWidget *parentwidget;
 };
 
 /**
diff --git a/rkward/settings/rksettingsmoduleconsole.cpp b/rkward/settings/rksettingsmoduleconsole.cpp
index 67adcd11d..e49f1cff7 100644
--- a/rkward/settings/rksettingsmoduleconsole.cpp
+++ b/rkward/settings/rksettingsmoduleconsole.cpp
@@ -47,7 +47,7 @@ public:
 
 		QVBoxLayout *vbox = new QVBoxLayout(this);
 
-		vbox->addWidget(completion_settings_widget = new RKCodeCompletionSettingsWidget(this, parentModule(), &RKSettingsModuleConsole::completion_settings, false));
+		vbox->addWidget(completion_settings_widget = new RKCodeCompletionSettingsWidget(this, &RKSettingsModuleConsole::completion_settings, false));
 
 		vbox->addWidget(RKSettingsModuleConsole::save_history.makeCheckbox(i18n("Load/Save command history"), this));
 
@@ -84,7 +84,7 @@ public:
 	}
 	void applyChanges() override {
 		RK_TRACE(SETTINGS);
-		completion_settings_widget->applyChanges();
+		// All settings are RKConfigValue-based
 	}
 private:
 	RKCodeCompletionSettingsWidget *completion_settings_widget;
diff --git a/rkward/settings/rksettingsmodulegraphics.cpp b/rkward/settings/rksettingsmodulegraphics.cpp
index 12498f875..1da409ca2 100644
--- a/rkward/settings/rksettingsmodulegraphics.cpp
+++ b/rkward/settings/rksettingsmodulegraphics.cpp
@@ -119,18 +119,15 @@ public:
 
 		main_vbox->addWidget(RKSettingsModuleGraphics::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);
-		graphics_hist_box->setChecked(RKSettingsModuleGraphics::graphics_hist_enable);
+		auto graphics_hist_box = RKSettingsModuleGraphics::graphics_hist_enable.makeCheckableGroupBox(i18n("Screen device history"), this);
 		group_layout = new QVBoxLayout(graphics_hist_box);
-		connect(graphics_hist_box, &QGroupBox::toggled, this, &RKSettingsPageGraphics::boxChanged);
 		h_layout = new QHBoxLayout();
 		group_layout->addLayout(h_layout);
-		h_layout->addWidget(new QLabel(i18n("Maximum number of recorded plots:"), graphics_hist_box));
+		h_layout->addWidget(new QLabel(i18n("Maximum number of recorded plots:")));
 		h_layout->addWidget(RKSettingsModuleGraphics::graphics_hist_max_length.makeSpinBox(1, 200, this));
 		h_layout = new QHBoxLayout();
 		group_layout->addLayout(h_layout);
-		h_layout->addWidget(new QLabel(i18n("Maximum size of a single recorded plot (in KB):"), graphics_hist_box));
+		h_layout->addWidget(new QLabel(i18n("Maximum size of a single recorded plot (in KB):")));
 		h_layout->addWidget(RKSettingsModuleGraphics::graphics_hist_max_plotsize.makeSpinBox(4, 50000, this));
 		main_vbox->addWidget(graphics_hist_box);
 
@@ -161,8 +158,6 @@ public:
 		RKSettingsModuleGraphics::default_device_other = default_device_other_edit->text();
 		RKSettingsModuleGraphics::replace_standard_devices = (RKSettingsModuleGraphics::StandardDevicesMode) replace_standard_devices_group->checkedId();
 
-		RKSettingsModuleGraphics::graphics_hist_enable = graphics_hist_box->isChecked();
-
 		QStringList commands = RKSettingsModuleGraphics::makeRRunTimeOptionCommands();
 		for (QStringList::const_iterator it = commands.cbegin(); it != commands.cend(); ++it) {
 			RInterface::issueCommand(new RCommand(*it, RCommand::App), parent_module->commandChain());
@@ -172,8 +167,6 @@ private:
 	QButtonGroup *default_device_group;
 	QLineEdit *default_device_other_edit;
 	QButtonGroup *replace_standard_devices_group;
-
-	QGroupBox *graphics_hist_box;
 };
 
 RKSettingsModuleGraphics::RKSettingsModuleGraphics(QObject *parent) : RKSettingsModule(parent) {
diff --git a/rkward/settings/rksettingsmoduleoutput.cpp b/rkward/settings/rksettingsmoduleoutput.cpp
index c5d135179..a1e68535d 100644
--- a/rkward/settings/rksettingsmoduleoutput.cpp
+++ b/rkward/settings/rksettingsmoduleoutput.cpp
@@ -32,42 +32,33 @@ RKConfigValue<bool> RKCarbonCopySettings::cc_console_commands {"CC console comma
 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, RKSettingsModule* module) : RKSettingsModuleWidget(parent, module, RKSettingsModule::no_page_id) {
-	RK_TRACE (SETTINGS);
+// TODO: Multiple instances of this are allowed to exist, simultaneously, and they are not kept in sync.
+//       Idea for a generic solution: RKSettingsModule could emit a signal, when changes got synced (form UI),
+//       and RKConfigValue-created controls could listen to that, and update if needed.
+RKCarbonCopySettings::RKCarbonCopySettings(QWidget* parent, RKSettingsModuleWidget* page)
+    : RKSettingsModuleWidget(parent, nullptr, RKSettingsModule::no_page_id) {
+	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::change);
-	main_vbox->addWidget (cc_globally_enabled_box);
-
-	QVBoxLayout *group_layout = new QVBoxLayout (cc_globally_enabled_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);
-}
+	QVBoxLayout* main_vbox = new QVBoxLayout(this);
+	main_vbox->setContentsMargins(0, 0, 0, 0);
+	auto cc_globally_enabled_box = cc_globally_enabled.makeCheckableGroupBox(i18n("Carbon copy commands to output"), this);
+	main_vbox->addWidget(cc_globally_enabled_box);
 
-RKCarbonCopySettings::~RKCarbonCopySettings () {
-	RK_TRACE (SETTINGS);
+	QVBoxLayout* group_layout = new QVBoxLayout(cc_globally_enabled_box);
+	group_layout->addWidget(cc_console_commands.makeCheckbox(i18n("Commands entered in the console"), this));
+	group_layout->addWidget(cc_script_commands.makeCheckbox(i18n("Commands run via the 'Run' menu"), this));
+	group_layout->addWidget(cc_app_plugin_commands.makeCheckbox(i18n("Commands originating from dialogs and plugins"), this));
+	group_layout->addWidget(cc_command_output.makeCheckbox(i18n("Also carbon copy the command output"), this));
 
-	instances.removeAll (this);
+	if (page) {
+		connect(page, &RKSettingsModuleWidget::apply, this, &RKSettingsModuleWidget::doApply);
+		connect(this, &RKSettingsModuleWidget::settingsChanged, page, &RKSettingsModuleWidget::change);
+	}
 }
 
-void RKCarbonCopySettings::update() {
+RKCarbonCopySettings::~RKCarbonCopySettings() {
 	RK_TRACE (SETTINGS);
-
-	cc_globally_enabled_box->setChecked (cc_globally_enabled);
-	cc_console_commands_box->setChecked (cc_console_commands);
-	cc_script_commands_box->setChecked (cc_script_commands);
-	cc_app_plugin_commands_box->setChecked (cc_app_plugin_commands);
-	cc_command_output_box->setChecked (cc_command_output);
 }
 
 void RKCarbonCopySettings::syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a) {
@@ -93,13 +84,7 @@ bool RKCarbonCopySettings::shouldCarbonCopyCommand (const RCommand *command) {
 }
 
 void RKCarbonCopySettings::applyChanges() {
-	RK_TRACE (SETTINGS);
-
-	cc_globally_enabled = cc_globally_enabled_box->isChecked ();
-
-	for (RKCarbonCopySettings *sibling : std::as_const(instances)) {
-		if (sibling != this) sibling->update ();
-	}
+	// All RKConfigValue-based
 }
 
 // static members
@@ -172,7 +157,7 @@ public:
 
 		main_vbox->addWidget(group);
 
-		cc_settings = new RKCarbonCopySettings(this, parent_module);
+		cc_settings = new RKCarbonCopySettings(this, this);
 		main_vbox->addWidget(cc_settings);
 
 		main_vbox->addStretch();
diff --git a/rkward/settings/rksettingsmoduleoutput.h b/rkward/settings/rksettingsmoduleoutput.h
index aecef3585..7af833ac1 100644
--- a/rkward/settings/rksettingsmoduleoutput.h
+++ b/rkward/settings/rksettingsmoduleoutput.h
@@ -26,8 +26,8 @@ and a widget to configure the settings.
 class RKCarbonCopySettings : public RKSettingsModuleWidget {
 	Q_OBJECT
 public:
-	explicit RKCarbonCopySettings (QWidget* parent, RKSettingsModule* module);
-	~RKCarbonCopySettings ();
+	explicit RKCarbonCopySettings(QWidget* parent, RKSettingsModuleWidget* page);
+	~RKCarbonCopySettings();
 
 	static void syncConfig(KConfig *config, RKConfigBase::ConfigSyncAction a);
 
@@ -38,13 +38,6 @@ public Q_SLOTS:
 private:
 	// There can be multiple instances of this widget, which need to be kept in sync.
 	static QList<RKCarbonCopySettings*> instances;
-	void update ();
-
-	QGroupBox *cc_globally_enabled_box;
-	QCheckBox *cc_console_commands_box;
-	QCheckBox *cc_script_commands_box;
-	QCheckBox *cc_app_plugin_commands_box;
-	QCheckBox *cc_command_output_box;
 
 	static RKConfigValue<bool> cc_globally_enabled;
 	static RKConfigValue<bool> cc_console_commands;



More information about the rkward-tracker mailing list