[education/rkward] rkward: Port RInterface away from RCommandReceiver.

Thomas Friedrichsmeier null at kde.org
Thu Jun 9 15:30:34 BST 2022


Git commit f411dcca24442bdb933e0f5b4bb769f2b1fd10c9 by Thomas Friedrichsmeier.
Committed on 09/06/2022 at 14:29.
Pushed by tfry into branch 'master'.

Port RInterface away from RCommandReceiver.

M  +1    -1    rkward/agents/rkeditobjectagent.cpp
M  +1    -1    rkward/agents/rkeditobjectagent.h
M  +0    -1    rkward/agents/rkquitagent.h
M  +0    -2    rkward/agents/rksaveagent.h
M  +1    -1    rkward/dialogs/rkloadlibsdialog.h
M  +0    -2    rkward/plugin/rkpreviewbox.h
M  +73   -74   rkward/rbackend/rkrinterface.cpp
M  +2    -3    rkward/rbackend/rkrinterface.h

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

diff --git a/rkward/agents/rkeditobjectagent.cpp b/rkward/agents/rkeditobjectagent.cpp
index 52bb873b..046f36f6 100644
--- a/rkward/agents/rkeditobjectagent.cpp
+++ b/rkward/agents/rkeditobjectagent.cpp
@@ -22,7 +22,7 @@ RKEditObjectAgent::RKEditObjectAgent (const QStringList &_object_names, RCommand
 	RKEditObjectAgent::object_names = _object_names;
 
 	// first issue an empty command to trigger an update of the object list
-	RInterface::issueCommand (new RCommand (QString (), RCommand::EmptyCommand | RCommand::ObjectListUpdate, QString (), this), chain);
+	RInterface::issueCommand (new RCommand (QString (), RCommand::EmptyCommand | RCommand::ObjectListUpdate), chain);
 
 	// now add another empty command to find out, when the update has completed
 	RInterface::whenAllFinished(this, [this]() {
diff --git a/rkward/agents/rkeditobjectagent.h b/rkward/agents/rkeditobjectagent.h
index 84514c3b..c44ece76 100644
--- a/rkward/agents/rkeditobjectagent.h
+++ b/rkward/agents/rkeditobjectagent.h
@@ -17,7 +17,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
 
 @author Thomas Friedrichsmeier
 */
-class RKEditObjectAgent : public QObject, public RCommandReceiver {
+class RKEditObjectAgent : public QObject {
 	Q_OBJECT
 public:
 	RKEditObjectAgent (const QStringList &object_names, RCommandChain *chain);
diff --git a/rkward/agents/rkquitagent.h b/rkward/agents/rkquitagent.h
index 72c56fa1..93f78d33 100644
--- a/rkward/agents/rkquitagent.h
+++ b/rkward/agents/rkquitagent.h
@@ -8,7 +8,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
 #define RKQUITAGENT_H
 
 #include <qobject.h>
-#include "../rbackend/rcommandreceiver.h"
 
 class RKProgressControl;
 
diff --git a/rkward/agents/rksaveagent.h b/rkward/agents/rksaveagent.h
index 24b11722..008d4b2c 100644
--- a/rkward/agents/rksaveagent.h
+++ b/rkward/agents/rksaveagent.h
@@ -7,8 +7,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
 #ifndef RKSAVEAGENT_H
 #define RKSAVEAGENT_H
 
-#include "../rbackend/rcommandreceiver.h"
-
 #include <QUrl>
 
 class RCommandChain;
diff --git a/rkward/dialogs/rkloadlibsdialog.h b/rkward/dialogs/rkloadlibsdialog.h
index b682d540..a973be5f 100644
--- a/rkward/dialogs/rkloadlibsdialog.h
+++ b/rkward/dialogs/rkloadlibsdialog.h
@@ -14,7 +14,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
 #include <QSortFilterProxyModel>
 
 #include "../settings/rksettingsmoduler.h"
-#include "../rbackend/rcommandreceiver.h"
+#include "../rbackend/rcommand.h"
 
 class QLineEdit;
 class QTreeView;
diff --git a/rkward/plugin/rkpreviewbox.h b/rkward/plugin/rkpreviewbox.h
index c020eb57..0a2003df 100644
--- a/rkward/plugin/rkpreviewbox.h
+++ b/rkward/plugin/rkpreviewbox.h
@@ -12,8 +12,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
 
 #include "rkcomponentproperties.h"
 
-#include "../rbackend/rcommandreceiver.h"
-
 class QCheckBox;
 class QDomElement;
 class QLabel;
diff --git a/rkward/rbackend/rkrinterface.cpp b/rkward/rbackend/rkrinterface.cpp
index ea33f897..ade15f95 100644
--- a/rkward/rbackend/rkrinterface.cpp
+++ b/rkward/rbackend/rkrinterface.cpp
@@ -56,11 +56,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
 // flush new pieces of output after this period of time:
 #define FLUSH_INTERVAL 100
 
-#define GET_LIB_PATHS 1
-#define GET_HELP_BASE 2
-#define SET_RUNTIME_OPTS 3
 #define STARTUP_PHASE2_COMPLETE 4
-#define GET_R_VERSION 5
 #define RSTARTUP_COMPLETE 6
 
 // statics
@@ -71,12 +67,13 @@ RInterface *RInterface::_instance = nullptr;
 void RInterface::create() {
 	RK_TRACE (RBACKEND);
 	RK_ASSERT(_instance == nullptr);
-	_instance = new RInterface();
+	new RInterface();
 }
 
 RInterface::RInterface () {
 	RK_TRACE (RBACKEND);
 
+	_instance = this;
 	new RCommandStackModel (this);
 	RCommandStack::regular_stack = new RCommandStack ();
 	startup_phase2_error = false;
@@ -88,8 +85,24 @@ RInterface::RInterface () {
 	dummy_command_on_stack = 0;
 
 	// create a fake init command
-	RCommand *fake = new RCommand (i18n ("R Startup"), RCommand::App | RCommand::Sync | RCommand::ObjectListUpdate, i18n ("R Startup"), this, STARTUP_PHASE2_COMPLETE);
-	_issueCommand(fake);
+	runStartupCommand(new RCommand(i18n("R Startup"), RCommand::App | RCommand::Sync | RCommand::ObjectListUpdate, i18n("R Startup")), nullptr, 
+	[this](RCommand *command) {
+		QString message = startup_errors;
+		if (startup_phase2_error) message.append (i18n ("<p>\t-An unspecified error occurred that is not yet handled by RKWard. Likely RKWard will not function properly. Please check your setup.</p>\n"));
+		if (!message.isEmpty ()) {
+			message.prepend (i18n ("<p>There was a problem starting the R backend. The following error(s) occurred:</p>\n"));
+
+			QString details = command->fullOutput().replace('<', "<").replace('\n', "<br>");
+			if (!details.isEmpty ()) {
+				// WORKAROUND for stupid KMessageBox behavior. (kdelibs 4.2.3)
+				// If length of details <= 512, it tries to show the details as a QLabel.
+				details = details.leftJustified (513);
+			}
+			KMessageBox::detailedError (0, message, details, i18n ("Error starting R"), KMessageBox::Notify | KMessageBox::AllowLink);
+		}
+
+		startup_errors.clear ();
+	});
 
 	new RKSessionVars (this);
 	new RKDebugHandler (this);
@@ -100,7 +113,7 @@ RInterface::RInterface () {
 	// NOTE: will receive the list as a call plain generic request from the backend ("updateInstalledPackagesList")
 	_issueCommand(new RCommand(".rk.get.installed.packages()", RCommand::App | RCommand::Sync));
 
-	_issueCommand(new RCommand(QString(), RCommand::App | RCommand::Sync | RCommand::EmptyCommand, QString(), this, RSTARTUP_COMPLETE));
+	whenAllFinished(this, []() { RKSettings::validateSettingsInteractive (); });
 }
 
 void RInterface::issueCommand (const QString &command, int type, const QString &rk_equiv, RCommandReceiver *receiver, int flags, RCommandChain *chain) {
@@ -293,70 +306,16 @@ void RInterface::doNextCommand (RCommand *command) {
 	}
 }
 
-void RInterface::rCommandDone (RCommand *command) {
-	RK_TRACE (RBACKEND);
-
-	if (command->failed ()) {
-		startup_phase2_error = true;
-		return;
-	}
-
-	if (command->getFlags () == GET_LIB_PATHS) {
-		RK_ASSERT (command->getDataType () == RData::StringVector);
-		RKSettingsModuleRPackages::r_libs_user = command->stringVector ().value (0);
-		RKSettingsModuleRPackages::defaultliblocs += command->stringVector ().mid (1);
-
-		RCommandChain *chain = command->parent;
-		RK_ASSERT (chain);
-		RK_ASSERT (!chain->isClosed ());
-
-		// apply user configurable run time options
-		QStringList commands = RKSettingsModuleR::makeRRunTimeOptionCommands () + RKSettingsModuleRPackages::makeRRunTimeOptionCommands () + RKSettingsModuleOutput::makeRRunTimeOptionCommands () + RKSettingsModuleGraphics::makeRRunTimeOptionCommands ();
-		for (QStringList::const_iterator it = commands.cbegin (); it != commands.cend (); ++it) {
-			issueCommand (*it, RCommand::App | RCommand::Sync, QString (), this, SET_RUNTIME_OPTS, chain);
-		}
-		// initialize output file
-		RKOutputDirectory::getCurrentOutput(chain);
-
-#ifdef Q_OS_MACOS
-		// On MacOS, the backend is started from inside R home to allow resolution of dynamic libs. Re-set to frontend wd, here.
-		issueCommand ("setwd (" + RKRSharedFunctionality::quote (QDir::currentPath ()) + ")\n", RCommand::App | RCommand::Sync, QString (), this, SET_RUNTIME_OPTS, chain);
-#endif
-		// Workaround for https://bugs.kde.org/show_bug.cgi?id=421958
-		if (RKSessionVars::compareRVersion("4.0.0") < 1 && RKSessionVars::compareRVersion("4.0.1") > 0) {
-			issueCommand ("if(compiler::enableJIT(-1) > 2) compiler::enableJIT(2)\n", RCommand::App | RCommand::Sync, QString (), this, SET_RUNTIME_OPTS, chain);
-		}
-
-		closeChain (chain);
-	} else if (command->getFlags () == GET_R_VERSION) {
-		RK_ASSERT (command->getDataType () == RData::StringVector);
-		RK_ASSERT (command->getDataLength () == 1);
-		RKSessionVars::setRVersion (command->stringVector ().value (0));
-	} else if (command->getFlags () == GET_HELP_BASE) {
-		RK_ASSERT (command->getDataType () == RData::StringVector);
-		RK_ASSERT (command->getDataLength () == 1);
-		RKSettingsModuleR::help_base_url = command->stringVector ().value (0);
-	} else if (command->getFlags () == SET_RUNTIME_OPTS) {
-		// no special handling. In case of failures, staturt_fail was set to true, above.
-	} else if (command->getFlags () == STARTUP_PHASE2_COMPLETE) {
-		QString message = startup_errors;
-		if (startup_phase2_error) message.append (i18n ("<p>\t-An unspecified error occurred that is not yet handled by RKWard. Likely RKWard will not function properly. Please check your setup.</p>\n"));
-		if (!message.isEmpty ()) {
-			message.prepend (i18n ("<p>There was a problem starting the R backend. The following error(s) occurred:</p>\n"));
-
-			QString details = command->fullOutput().replace('<', "<").replace('\n', "<br>");
-			if (!details.isEmpty ()) {
-				// WORKAROUND for stupid KMessageBox behavior. (kdelibs 4.2.3)
-				// If length of details <= 512, it tries to show the details as a QLabel.
-				details = details.leftJustified (513);
-			}
-			KMessageBox::detailedError (0, message, details, i18n ("Error starting R"), KMessageBox::Notify | KMessageBox::AllowLink);
+void RInterface::runStartupCommand(RCommand* command, RCommandChain *chain, std::function<void (RCommand *)> callback) {
+	command->whenFinished(this, [this, callback](RCommand* command) {
+		RK_TRACE(RBACKEND);
+		if (command->failed()) {
+			startup_phase2_error = true;
+		} else {
+			callback(command);
 		}
-
-		startup_errors.clear ();
-	} else if (command->getFlags () == RSTARTUP_COMPLETE) {
-		RKSettings::validateSettingsInteractive ();
-	}
+	});
+	_issueCommand(command, chain);
 }
 
 void RInterface::handleRequest (RBackendRequest* request) {
@@ -415,11 +374,51 @@ void RInterface::handleRequest (RBackendRequest* request) {
 		command_requests.append (request);
 		RCommandChain *chain = openSubcommandChain (runningCommand ());
 
-		issueCommand ("paste (R.version[c (\"major\", \"minor\")], collapse=\".\")\n", RCommand::GetStringVector | RCommand::App | RCommand::Sync, QString (), this, GET_R_VERSION, chain);
+		runStartupCommand(new RCommand("paste (R.version[c (\"major\", \"minor\")], collapse=\".\")\n", RCommand::GetStringVector | RCommand::App | RCommand::Sync), chain, 
+		[](RCommand *command) {
+			RK_ASSERT (command->getDataType () == RData::StringVector);
+			RK_ASSERT (command->getDataLength () == 1);
+			RKSessionVars::setRVersion (command->stringVector ().value (0));
+		});
 		// find out about standard library locations
-		issueCommand ("c(path.expand(Sys.getenv(\"R_LIBS_USER\")), .libPaths())\n", RCommand::GetStringVector | RCommand::App | RCommand::Sync, QString (), this, GET_LIB_PATHS, chain);
+		runStartupCommand(new RCommand("c(path.expand(Sys.getenv(\"R_LIBS_USER\")), .libPaths())\n", RCommand::GetStringVector | RCommand::App | RCommand::Sync), chain,
+		[this](RCommand *command) {
+			RK_ASSERT (command->getDataType () == RData::StringVector);
+			RKSettingsModuleRPackages::r_libs_user = command->stringVector ().value (0);
+			RKSettingsModuleRPackages::defaultliblocs += command->stringVector ().mid (1);
+
+			RCommandChain *chain = command->parent;
+			RK_ASSERT (chain);
+			RK_ASSERT (!chain->isClosed ());
+
+			// apply user configurable run time options
+			auto runtimeopt_callback = [](RCommand *) {}; // No special handling. Any failure will be recorded with runStartupCommand().
+			QStringList commands = RKSettingsModuleR::makeRRunTimeOptionCommands () + RKSettingsModuleRPackages::makeRRunTimeOptionCommands () + RKSettingsModuleOutput::makeRRunTimeOptionCommands () + RKSettingsModuleGraphics::makeRRunTimeOptionCommands ();
+			for (QStringList::const_iterator it = commands.cbegin (); it != commands.cend (); ++it) {
+				runStartupCommand(new RCommand(*it, RCommand::App | RCommand::Sync), chain, runtimeopt_callback);
+			}
+			// initialize output file
+			RKOutputDirectory::getCurrentOutput(chain);
+
+#ifdef Q_OS_MACOS
+			// On MacOS, the backend is started from inside R home to allow resolution of dynamic libs. Re-set to frontend wd, here.
+			runStartupCommand(new RCommand("setwd (" + RKRSharedFunctionality::quote(QDir::currentPath()) + ")\n", RCommand::App | RCommand::Sync), chain, runtimeopt_callback);
+#endif
+			// Workaround for https://bugs.kde.org/show_bug.cgi?id=421958
+			if (RKSessionVars::compareRVersion("4.0.0") < 1 && RKSessionVars::compareRVersion("4.0.1") > 0) {
+				runStartupCommand(new RCommand("if(compiler::enableJIT(-1) > 2) compiler::enableJIT(2)\n", RCommand::App | RCommand::Sync), chain, runtimeopt_callback);
+			}
+
+			closeChain (chain);
+		});
+
 		// start help server / determined help base url
-		issueCommand (".rk.getHelpBaseUrl ()\n", RCommand::GetStringVector | RCommand::App | RCommand::Sync, QString (), this, GET_HELP_BASE, chain);
+		runStartupCommand(new RCommand(".rk.getHelpBaseUrl ()\n", RCommand::GetStringVector | RCommand::App | RCommand::Sync), chain,
+		[](RCommand *command) {
+			RK_ASSERT (command->getDataType () == RData::StringVector);
+			RK_ASSERT (command->getDataLength () == 1);
+			RKSettingsModuleR::help_base_url = command->stringVector ().value (0);
+		});
 
 		// NOTE: more initialization commands get run *after* we have determined the standard library locations (see rCommandDone())
 	} else {
diff --git a/rkward/rbackend/rkrinterface.h b/rkward/rbackend/rkrinterface.h
index 36b7d1a2..fd587207 100644
--- a/rkward/rbackend/rkrinterface.h
+++ b/rkward/rbackend/rkrinterface.h
@@ -12,7 +12,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
 #include <QFile>
 
 #include "rcommand.h"
-#include "rcommandreceiver.h"
 
 class RCommand;
 class RKWardMainWindow;
@@ -31,7 +30,7 @@ class RBackendRequest;
 	*@author Thomas Friedrichsmeier
 */
 
-class RInterface : public QObject, public RCommandReceiver {
+class RInterface : public QObject {
 	Q_OBJECT
 public:
 	static void create();
@@ -131,6 +130,7 @@ private:
 
 	QString startup_errors;
 	bool startup_phase2_error;
+	void runStartupCommand(RCommand *command, RCommandChain* chain, std::function<void(RCommand*)> callback);
 	RCommand *dummy_command_on_stack;
 friend class RKRBackendProtocolFrontend;
 	bool backend_dead;
@@ -140,7 +140,6 @@ friend class RKWardMainWindow;
 friend class RCommand;
 protected:
 	void handleRequest (RBackendRequest *request);
-	void rCommandDone (RCommand *command) override;
 	static RInterface *_instance;
 	void _issueCommand(RCommand *command, RCommandChain *chain=0);
 /** constructor */



More information about the rkward-tracker mailing list