[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