[rkward-cvs] SF.net SVN: rkward:[3167] branches/2010_10_18_backend_restructuring_branch/ rkward

tfry at users.sourceforge.net tfry at users.sourceforge.net
Sun Oct 31 12:23:55 UTC 2010


Revision: 3167
          http://rkward.svn.sourceforge.net/rkward/?rev=3167&view=rev
Author:   tfry
Date:     2010-10-31 12:23:55 +0000 (Sun, 31 Oct 2010)

Log Message:
-----------
Move frontend dependent initialization code from RThread to RInterface

Modified Paths:
--------------
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h
    branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/settings/rksettingsmoduler.h
    branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandlog.cpp
    branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandlog.h

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h	2010-10-31 10:57:58 UTC (rev 3166)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rembedinternal.h	2010-10-31 12:23:55 UTC (rev 3167)
@@ -49,7 +49,6 @@
 		Started,
 		EvalRequest,
 		CallbackRequest,
-		StartupError,
 		HistoricalSubstackRequest,
 		OtherRequest		/**< Any other type of request. Note: which requests are in the enum, and which are not has mostly historical reasons. @see params */
 	};
@@ -149,17 +148,9 @@
 		OtherError=3		/**< Other error, usually a semantic error, e.g. object not found */
 	};
 
-/** An enum describing whether initialization of the embedded R-process went well, or what errors occurred. */
-	enum InitStatus {
-		Ok=0,					/**< No error */
-		LibLoadFail=1,		/**< Error while trying to load the rkward R package */
-		SinkFail=2,			/**< Error while redirecting R's stdout and stderr to files to be read from rkward */
-		OtherFail=4			/**< Other error while initializing the embedded R-process */
-	}; // TODO: make obsolete!
-
-/** initializes the R-backend. Returns an error-code that consists of a bit-wise or-conjunction of the RThread::InitStatus -enum, RThread::Ok on success.
+/** initializes the R-backend. Emits an RCallbackType::Started-request (with any error messages) when done.
 Note that you should call initialize only once in a application */
-	QString initialize ();
+	void initialize ();
 
 	void enterEventLoop ();
 protected:

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp	2010-10-31 10:57:58 UTC (rev 3166)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.cpp	2010-10-31 12:23:55 UTC (rev 3167)
@@ -22,6 +22,8 @@
 #include "../rkward.h"
 #include "../settings/rksettingsmoduler.h"
 #include "../settings/rksettingsmodulegeneral.h"
+#include "../settings/rksettingsmoduleoutput.h"
+#include "../settings/rksettingsmodulegraphics.h"
 #include "../core/robjectlist.h"
 #include "../core/renvironmentobject.h"
 #include "../core/rkmodificationtracker.h"
@@ -60,6 +62,11 @@
 // update output (for immediate output commands) at least this often (msecs):
 #define FLUSH_INTERVAL 100
 
+#define GET_LIB_PATHS 1
+#define GET_HELP_BASE 2
+#define SET_RUNTIME_OPTS 3
+#define STARTUP_PHASE2_COMPLETE 4
+
 RInterface::RInterface () {
 	RK_TRACE (RBACKEND);
 	
@@ -75,12 +82,13 @@
 	new RCommandStackModel (this);
 	RCommandStack::regular_stack = new RCommandStack (0);
 	running_command_canceled = 0;
+	startup_phase2_error = false;
 	command_logfile_mode = NotRecordingCommands;
 	previously_idle = false;
 	locked = 0;
 
 	// create a fake init command
-	RCommand *fake = new RCommand (i18n ("R Startup"), RCommand::App | RCommand::Sync | RCommand::ObjectListUpdate, i18n ("R Startup"));
+	RCommand *fake = new RCommand (i18n ("R Startup"), RCommand::App | RCommand::Sync | RCommand::ObjectListUpdate, i18n ("R Startup"), this, STARTUP_PHASE2_COMPLETE);
 	issueCommand (fake);
 
 	flush_timer = new QTimer (this);
@@ -268,6 +276,44 @@
 	QThread::yieldCurrentThread ();
 }
 
+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);
+		for (unsigned int i = 0; i < command->getDataLength (); ++i) {
+			RKSettingsModuleRPackages::defaultliblocs.append (command->getStringVector ()[i]);
+		}
+	} else if (command->getFlags () == GET_HELP_BASE) {
+		RK_ASSERT (command->getDataType () == RData::StringVector);
+		RK_ASSERT (command->getDataLength () == 1);
+		RKSettingsModuleR::help_base_url = command->getStringVector ()[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 = runningCommand()->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 ();
+	}
+}
+
 void RInterface::customEvent (QEvent *e) {
 	RK_TRACE (RBACKEND);
 
@@ -292,21 +338,29 @@
 	} else if (request->type == RBackendRequest::HistoricalSubstackRequest) {
 		processHistoricalSubstackRequest (request);
 	} else if ((request->type == RBackendRequest::Started)) {
-		request->completed ();
-		RKWardMainWindow::discardStartupOptions ();
-	} else if ((request->type == RBackendRequest::StartupError)) {
-		QString message = i18n ("<p>There was a problem starting the R backend. The following error(s) occurred:</p>\n");
-		message.append (request->params["message"].toString ());
+		// The backend thread has finished basic initialization, but we still have more to do...
+		startup_errors = request->params["message"].toString ();
 
-		QString details = runningCommand()->fullOutput();
-		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.replace('<', "<").replace('\n', "<br>").leftJustified (513);
+		command_requests.append (request);
+		RCommandStack *stack = new RCommandStack (runningCommand ());
+		RCommandChain *chain = stack->startChain (stack);
+
+		// find out about standard library locations
+		issueCommand (".libPaths ()\n", RCommand::GetStringVector | RCommand::App | RCommand::Sync, QString (), this, GET_LIB_PATHS, chain);
+		// start help server / determined help base url
+		issueCommand (".rk.getHelpBaseUrl ()\n", RCommand::GetStringVector | RCommand::App | RCommand::Sync, QString (), this, GET_HELP_BASE, chain);
+
+		// apply user configurable run time options
+		QStringList commands = RKSettingsModuleR::makeRRunTimeOptionCommands () + RKSettingsModuleRPackages::makeRRunTimeOptionCommands () + RKSettingsModuleOutput::makeRRunTimeOptionCommands () + RKSettingsModuleGraphics::makeRRunTimeOptionCommands ();
+		for (QStringList::const_iterator it = commands.begin (); it != commands.end (); ++it) {
+			issueCommand (*it, RCommand::App | RCommand::Sync, QString (), this, SET_RUNTIME_OPTS, chain);
 		}
-		KMessageBox::detailedError (0, message, details, i18n ("Error starting R"), KMessageBox::Notify | KMessageBox::AllowLink);
+		// initialize output file
+		issueCommand ("rk.set.output.html.file (\"" + RKSettingsModuleGeneral::filesPath () + "/rk_out.html\")\n", RCommand::App | RCommand::Sync, QString (), this, SET_RUNTIME_OPTS, chain);
 
+		closeChain (chain);
 		request->completed ();
+		RKWardMainWindow::discardStartupOptions ();
 	} else {
 		processRBackendRequest (request);
 	}

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h	2010-10-31 10:57:58 UTC (rev 3166)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rinterface.h	2010-10-31 12:23:55 UTC (rev 3167)
@@ -23,12 +23,12 @@
 #include <QFile>
 
 #include "rcommand.h"
+#include "rcommandreceiver.h"
 
 class RCommand;
 class RKWardMainWindow;
 class QTimer;
 class RThread;
-class RCommandReceiver;
 struct RKWardStartupOptions;
 struct RBackendRequest;
 
@@ -44,7 +44,7 @@
 	*@author Thomas Friedrichsmeier
 */
 
-class RInterface : public QObject {
+class RInterface : public QObject, public RCommandReceiver {
 	Q_OBJECT
 public:
 /** constructor */
@@ -122,6 +122,9 @@
 more errors/crashes. @see RInterface::cancelCommand @see RInterface::pauseProcessing
 May be an OR'ed combination of several LockType s */
 	int locked;
+
+	QString startup_errors;
+	bool startup_phase2_error;
 friend class RKWardMainWindow;
 friend class RCommand;
 /** Used (once!) to start the RThread. Need to make this separate to avoid race conditions */
@@ -129,6 +132,7 @@
 protected:
 /** needed to handle the QCustomEvent s, the RThread is sending (notifications on what's happening in the backend thread) */
 	void customEvent (QEvent *e);
+	void rCommandDone (RCommand *command);
 };
 
 /**

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp	2010-10-31 10:57:58 UTC (rev 3166)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/rbackend/rthread.cpp	2010-10-31 12:23:55 UTC (rev 3167)
@@ -17,24 +17,14 @@
 #include "rembedinternal.h"
 
 #include "rinterface.h"
-#include "rcommandstack.h"
-#include "../settings/rksettingsmoduler.h"
-#include "../settings/rksettingsmoduleoutput.h"
-#include "../settings/rksettingsmodulegraphics.h"
-#include "../settings/rksettingsmodulegeneral.h"
 #include "../rkglobals.h"
 #include "../rkward.h"		// for startup options
 #include "../version.h"
 
 #include "../debug.h"
 
-#include <kapplication.h>
 #include <klocale.h>
 
-#include <qstring.h>
-#include <QList>
-#include <QFileInfo>
-
 #ifndef Q_WS_WIN
 #	include <signal.h>		// needed for pthread_kill
 #	include <pthread.h>		// seems to be needed at least on FreeBSD
@@ -58,25 +48,8 @@
 	killed = false;
 	previous_command = 0;
 
-	// in RInterface::RInterface() we have created a fake RCommand to capture all the output/errors during startup. Fetch it
-	repl_status.eval_depth++;
-	fetchNextCommand ();
+	initialize ();
 
-	QString err = initialize ();
-	if (!err.isEmpty ()) {
-		RBackendRequest req (true, RBackendRequest::StartupError);
-		req.params["message"] = err;
-		handleRequest (&req);
-	}
-
-	// wait until RKWard is set to go (esp, it has handled any errors during startup, etc.)
-	RBackendRequest* req = new RBackendRequest (true, RBackendRequest::Started);
-	handleRequest (req);
-	delete req;
-
-	commandFinished ();		// the fake startup command
-	repl_status.eval_depth--;
-
 	enterEventLoop ();
 }
 
@@ -213,9 +186,13 @@
 	handleRequest (&request);
 }                                                                        
 
-QString RThread::initialize () {
+void RThread::initialize () {
 	RK_TRACE (RBACKEND);
 
+	// in RInterface::RInterface() we have created a fake RCommand to capture all the output/errors during startup. Fetch it
+	repl_status.eval_depth++;
+	fetchNextCommand ();
+
 	int argc = 2;
 	char* argv[2] = { qstrdup ("--slave"), qstrdup ("--no-save") };
 	RKWardStartupOptions *options = RKWardMainWindow::getStartupOptions ();
@@ -225,56 +202,33 @@
 
 	connectCallbacks ();
 
-	int status = 0;
+	bool lib_load_fail = false;
+	bool sink_fail = false;
+	if (!runDirectCommand ("library (\"rkward\")\n")) lib_load_fail = true;
+	if (!runDirectCommand (QString ("stopifnot(.rk.app.version==\"%1\")\n").arg (VERSION))) lib_load_fail = true;
+	if (!runDirectCommand (".rk.fix.assignments ()\n")) sink_fail = true;
 
-	if (!runDirectCommand ("library (\"rkward\")\n")) status |= LibLoadFail;
-	if (!runDirectCommand (QString ("stopifnot(.rk.app.version==\"%1\")\n").arg (VERSION))) status |= LibLoadFail;
-	if (!runDirectCommand (".rk.fix.assignments ()\n")) status |= LibLoadFail;
-
-// find out about standard library locations
-	RCommandProxy *dummy = runDirectCommand (".libPaths ()\n", RCommand::GetStringVector);
-	if (dummy->status & RCommand::Failed) status |= OtherFail;
-	for (unsigned int i = 0; i < dummy->getDataLength (); ++i) {
-		RKSettingsModuleRPackages::defaultliblocs.append (dummy->getStringVector ()[i]);
-	}
-	delete dummy;
-
-// start help server / determined help base url
-	dummy = runDirectCommand (".rk.getHelpBaseUrl ()\n", RCommand::GetStringVector);
-	if (dummy->status & RCommand::Failed) status |= OtherFail;
-	else {
-		RK_ASSERT (dummy->getDataLength () == 1);
-		RKSettingsModuleR::help_base_url = dummy->getStringVector ()[0];
-	}
-	delete dummy;
-
-// apply user configurable run time options
-	QStringList commands = RKSettingsModuleR::makeRRunTimeOptionCommands () + RKSettingsModuleRPackages::makeRRunTimeOptionCommands () + RKSettingsModuleOutput::makeRRunTimeOptionCommands () + RKSettingsModuleGraphics::makeRRunTimeOptionCommands ();
-	for (QStringList::const_iterator it = commands.begin (); it != commands.end (); ++it) {
-		if (!runDirectCommand ((*it).toLocal8Bit ())) {
-			status |= OtherFail;
-			RK_DO (qDebug ("error in initialization call '%s'", (*it).toLatin1().data ()), RBACKEND, DL_ERROR);
-		}
-	}
-
 // error/output sink and help browser
-	if (!runDirectCommand ("options (error=quote (.rk.do.error ()))\n")) status |= SinkFail;
-	if (!runDirectCommand ("rk.set.output.html.file (\"" + RKSettingsModuleGeneral::filesPath () + "/rk_out.html\")\n")) status |= SinkFail;
+	if (!runDirectCommand ("options (error=quote (.rk.do.error ()))\n")) sink_fail = true;
 
 	QString error_messages;
-	if (status & LibLoadFail) {
+	if (lib_load_fail) {
 		error_messages.append (i18n ("</p>\t- The 'rkward' R-library either could not be loaded at all, or not in the correct version. This may lead to all sorts of errors, from single missing features to complete failure to function. The most likely cause is that the last installation did not place all files in the correct place. However, in some cases, left-overs from a previous installation that was not cleanly removed may be the cause.</p>\
 		<p><b>You should quit RKWard, now, and fix your installation</b>. For help with that, see <a href=\"http://p.sf.net/rkward/compiling\">http://p.sf.net/rkward/compiling</a>.</p>\n"));
 	}
-	if (status & SinkFail) {
-		error_messages.append (i18n ("<p>\t-There was a problem setting up the communication with R. Most likely this is due to an incorrect version of the 'rkward' R-library or failure to find that at all. This indicates a broken installation.</p>\
+	if (sink_fail) {
+		error_messages.append (i18n ("<p>\t-There was a problem setting up the communication with R. Most likely this indicates a broken installation.</p>\
 		<p><b>You should quit RKWard, now, and fix your installation</b>. For help with that, see <a href=\"http://p.sf.net/rkward/compiling\">http://p.sf.net/rkward/compiling</a>.</p></p>\n"));
 	}
-	if (status & OtherFail) {
-		error_messages.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"));
-	}
 
-	return error_messages;
+	RBackendRequest req (true, RBackendRequest::Started);
+	req.params["message"] = QVariant (error_messages);
+	// blocks until RKWard is set to go (esp, it has displayed startup error messages, etc.)
+	// in fact, a number of sub-commands are run while handling this request!
+	handleRequest (&req);
+
+	commandFinished ();		// the fake startup command
+	repl_status.eval_depth--;
 }
 
 void RThread::checkObjectUpdatesNeeded (bool check_list) {

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/settings/rksettingsmoduler.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/settings/rksettingsmoduler.h	2010-10-31 10:57:58 UTC (rev 3166)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/settings/rksettingsmoduler.h	2010-10-31 12:23:55 UTC (rev 3167)
@@ -93,7 +93,7 @@
 	static QString builtin_editor;
 
 // session constants
-	friend class RThread;
+	friend class RInterface;
 	static QString help_base_url;
 };
 
@@ -145,7 +145,7 @@
 	static bool archive_packages;
 	static QStringList package_repositories;
 
-	friend class RThread;
+	friend class RInterface;
 	static QStringList defaultliblocs;
 	static QString essential_packages;
 };

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandlog.cpp
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandlog.cpp	2010-10-31 10:57:58 UTC (rev 3166)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandlog.cpp	2010-10-31 12:23:55 UTC (rev 3167)
@@ -57,7 +57,6 @@
 	clearLog ();
 
 	last_raised_command = 0;
-	command_input_shown = 0;
 
 	RKCommandLogPart *part = new RKCommandLogPart (this);
 	setPart (part);
@@ -85,7 +84,7 @@
 
 void RKCommandLog::addInputNoCheck (RCommand *command) {
 	RK_TRACE (APP);
-	if (command->id () == command_input_shown) return;		// already shown
+	if (command_input_shown.contains (command)) return;		// already shown
 
 // TODO: make colors/styles configurable
 	if (command->type () & RCommand::User) {
@@ -105,7 +104,7 @@
 
 	log_view->setFontItalic (false);
 
-	command_input_shown = command->id ();
+	command_input_shown.append (command);
 }
 
 void RKCommandLog::addOutputNoCheck (RCommand *command, ROutput *output) {
@@ -192,6 +191,7 @@
 	}
 
 	if (RKSettingsModuleWatch::shouldShowOutput (command)) log_view->insertPlainText ("\n");
+	command_input_shown.removeAll (command);
 }
 
 void RKCommandLog::settingsChanged (RKSettings::SettingsPage page) {

Modified: branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandlog.h
===================================================================
--- branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandlog.h	2010-10-31 10:57:58 UTC (rev 3166)
+++ branches/2010_10_18_backend_restructuring_branch/rkward/windows/rkcommandlog.h	2010-10-31 12:23:55 UTC (rev 3167)
@@ -2,7 +2,7 @@
                           rkcommandlog  -  description
                              -------------------
     begin                : Sun Nov 3 2002
-    copyright            : (C) 2002, 2004, 2005, 2006, 2007, 2009 by Thomas Friedrichsmeier
+    copyright            : (C) 2002, 2004, 2005, 2006, 2007, 2009, 2010 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -64,8 +64,8 @@
 	void checkRaiseWindow (RCommand *command);
 /** internal helper function, called whenever a line/lines have been added. Check whether log is longer than maximum setting. Scroll to the bottom */
 	void linesAdded ();
-/** Id of last command the input (i.e. the command itself) was shown for. Used to keep track of whether a command's input should be shown or not */
-	int command_input_shown;
+/** Used to keep track, which commands "input" has already been shown */
+	QList<RCommand*> command_input_shown;
 /** On a given command, the log_view should not be raised more than once */
 	int last_raised_command;
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the rkward-tracker mailing list