[rkward-cvs] SF.net SVN: rkward-code:[4700] trunk/rkward/rkward

tfry at users.sf.net tfry at users.sf.net
Tue Apr 16 08:08:00 UTC 2013


Revision: 4700
          http://sourceforge.net/p/rkward/code/4700
Author:   tfry
Date:     2013-04-16 08:07:58 +0000 (Tue, 16 Apr 2013)
Log Message:
-----------
Commands can have sub-commands. It's that simple.
Thus, remove the need to create "sub-stacks", and derive RCommand from RCommandChain, instead.
This allows for a lot of simplification..

Also, relax some assumptions on command ordering, in preparation for allow to add "priority" commands
(which will be run from R's event loop).

Modified Paths:
--------------
    trunk/rkward/rkward/rbackend/rcommand.cpp
    trunk/rkward/rkward/rbackend/rcommand.h
    trunk/rkward/rkward/rbackend/rcommandstack.cpp
    trunk/rkward/rkward/rbackend/rcommandstack.h
    trunk/rkward/rkward/rbackend/rinterface.cpp
    trunk/rkward/rkward/rbackend/rinterface.h
    trunk/rkward/rkward/settings/rksettingsmodulegraphics.cpp
    trunk/rkward/rkward/settings/rksettingsmoduleoutput.cpp
    trunk/rkward/rkward/settings/rksettingsmoduler.cpp
    trunk/rkward/rkward/windows/rcontrolwindow.cpp

Modified: trunk/rkward/rkward/rbackend/rcommand.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rcommand.cpp	2013-04-15 09:32:28 UTC (rev 4699)
+++ trunk/rkward/rkward/rbackend/rcommand.cpp	2013-04-16 08:07:58 UTC (rev 4700)
@@ -25,22 +25,11 @@
 #include "../debug.h"
 #include "../rkglobals.h"
 
-RCommandBase::RCommandBase (bool is_chain) {
-	is_command_chain = is_chain;
-	RCommandBase::parent = 0;
+RCommand* RCommandChain::toCommand() {
+	return (is_command ? static_cast<RCommand*> (this) : 0);
 }
 
-RCommand* RCommandBase::commandPointer () {
-	if (is_command_chain) return 0;
-	return static_cast<RCommand*> (this);
-}
 
-RCommandChain* RCommandBase::chainPointer () {
-	if (!is_command_chain) return 0;
-	return static_cast<RCommandChain*> (this);
-}
-
-
 RCommandNotifier::RCommandNotifier () : QObject () {
 	RK_TRACE (RBACKEND);
 }
@@ -51,7 +40,7 @@
 
 int RCommand::next_id = 0;
 
-RCommand::RCommand(const QString &command, int type, const QString &rk_equiv, RCommandReceiver *receiver, int flags) : RData (), RCommandBase (false) {
+RCommand::RCommand(const QString &command, int type, const QString &rk_equiv, RCommandReceiver *receiver, int flags) : RData (), RCommandChain (false) {
 	RK_TRACE (RBACKEND);
 	_id = next_id++;
 // if we ever submit enough commands to get a buffer overflow, use only positive numbers.

Modified: trunk/rkward/rkward/rbackend/rcommand.h
===================================================================
--- trunk/rkward/rkward/rbackend/rcommand.h	2013-04-15 09:32:28 UTC (rev 4699)
+++ trunk/rkward/rkward/rbackend/rcommand.h	2013-04-16 08:07:58 UTC (rev 4700)
@@ -2,7 +2,7 @@
                           rcommand.h  -  description
                              -------------------
     begin                : Mon Nov 11 2002
-    copyright            : (C) 2002, 2006, 2007, 2009, 2010 by Thomas Friedrichsmeier
+    copyright            : (C) 2002, 2006, 2007, 2009, 2010, 2013 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -29,38 +29,28 @@
 class RCommandReceiver;
 class RCommand;
 class RCommandProxy;
-class RCommandChain;
 
-/** Base class for RCommand and RCommandChain, to make it possible to store both in the same list */
-class RCommandBase {
-public:
-/** Returns the casted pointer, if this is a command, else 0 */
-	RCommand* commandPointer ();
-/** Returns the casted pointer, if this is a chain, else 0 */
-	RCommandChain* chainPointer ();
-protected:
-friend class RCommandStack;
-friend class RCommandStackModel;
-	RCommandBase (bool is_chain);
-	RCommandChain *parent;
-private:
-	bool is_command_chain;
-};
-
-/** this simple struct is used to ensure a sequence of RCommand s does not get interrupted by unrelated RCommands.
+/** R Commands can be arranged in a simple chain to make sure they are not interrupted by other commands.
+ *  Also, command may need to run sub-commands.
 @see \ref UsingTheInterfaceToR
 @see RInterface::startChain
 @see RInterface::closeChain */
-class RCommandChain : public RCommandBase {
+class RCommandChain {
 public:
 	bool isClosed () const { return closed; };
+/** @returns true, if there are no sub-commands or sub-chains waiting in this chain */
+	bool isEmpty () const { return sub_commands.isEmpty (); };
+	bool isCommand () const { return is_command; };
+	RCommandChain* parentChain () const { return parent; };
+	RCommand *toCommand ();
 protected:
 friend class RCommandStack;
 friend class RCommandStackModel;
-	RCommandChain () : RCommandBase (true) {};
-	QList<RCommandBase*> commands;
+	RCommandChain (bool is_chain=true) : closed (!is_chain), is_command (!is_chain) {};
+	QList<RCommandChain*> sub_commands;
 	bool closed;
-	bool isStack () { return (parent == 0); }
+	bool is_command;
+	RCommandChain *parent;
 };
 
 /** this struct is used to store the R output to an RCommand. The RCommand basically keeps a list of ROutputString (s). The difference to a normal
@@ -114,7 +104,7 @@
 	kept around very long, so they should not be a memory issue.
   *@author Thomas Friedrichsmeier
   */
-class RCommand : public RData, public RCommandBase {
+class RCommand : public RData, public RCommandChain {
 public:
 /** constructs an RCommand.
 @param command The command (string) to be run in the backend. This may include newlines and ";". The command should be a complete statement. If it is an incomplete statement, the backend will not wait for the rest of the command to come in, but rather the command will fail with RCommand::errorIncomplete.

Modified: trunk/rkward/rkward/rbackend/rcommandstack.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rcommandstack.cpp	2013-04-15 09:32:28 UTC (rev 4699)
+++ trunk/rkward/rkward/rbackend/rcommandstack.cpp	2013-04-16 08:07:58 UTC (rev 4700)
@@ -2,7 +2,7 @@
                           rcommandstack  -  description
                              -------------------
     begin                : Mon Sep 6 2004
-    copyright            : (C) 2004, 2007, 2010, 2011 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2013 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -28,58 +28,54 @@
 //static
 RCommandStack *RCommandStack::regular_stack;
 
-RCommandStack::RCommandStack (RCommand* parent_command) : RCommandChain () {
+RCommandStack::RCommandStack () : RCommandChain () {
 	RK_TRACE (RBACKEND);
-	closed = true;
-	current_chain = this;
-	sub_stack = 0;
-
-	RCommandStackModel::getModel ()->aboutToAdd (parent_command);
-	RCommandStack::parent_command = parent_command;
-	if (parent_command) {
-		RCommandStack* parent_stack = stackForCommand (parent_command);
-		RK_ASSERT (parent_stack);
-		parent_stack->sub_stack = this;
-	}
-	RCommandStackModel::getModel ()->addComplete ();
+	closed = false;
 }
 
 RCommandStack::~RCommandStack () {
 	RK_TRACE (RBACKEND);
-
-	RCommandStackModel::getModel ()->aboutToPop (parent_command);
-	if (parent_command) {
-		RCommandStack* parent_stack = stackForCommand (parent_command);
-		RK_ASSERT (parent_stack);
-		parent_stack->sub_stack = 0;
-	}
-	RCommandStackModel::getModel ()->popComplete ();
 }
 
 void RCommandStack::issueCommand (RCommand *command, RCommandChain *chain) {
 	RK_TRACE (RBACKEND);
 	if (!chain) chain = regular_stack;
+	issueCommandInternal (command, chain);
+}
 
-	RCommandStackModel::getModel ()->aboutToAdd (chain);
+void RCommandStack::issueCommandInternal (RCommandChain* child, RCommandChain* parent) {
+	RK_TRACE (RBACKEND);
+	RK_ASSERT (parent);
 
-	chain->commands.append (command);
-	command->parent = chain;
-
+	RCommandStackModel::getModel ()->aboutToAdd (parent, parent->sub_commands.size ());
+	parent->sub_commands.append (child);
+	child->parent = parent;
 	RCommandStackModel::getModel ()->addComplete ();
 }
 
+bool RCommandStack::removeFromParent (RCommandChain* child) {
+	RK_TRACE (RBACKEND);
+	RCommandChain* parent = child->parent;
+	RK_ASSERT (parent);
+
+	int index = parent->sub_commands.indexOf (child);
+	if (index < 0) return false;
+
+	RCommandStackModel::getModel ()->aboutToPop (parent, index);
+	parent->sub_commands.removeAt (index);
+	if (!child->is_command) delete child;
+//	else child->parent = 0;        // There is at least on point in the code, where we access the parent (chain) after the command was popped. This is rather unsafe in the first place, but...
+	RCommandStackModel::getModel ()->popComplete ();
+
+	return true;
+}
+
 RCommandChain *RCommandStack::startChain (RCommandChain *parent) {
 	RK_TRACE (RBACKEND);
 	if (!parent) parent = regular_stack;
 
 	RCommandChain *chain = new RCommandChain ();
-	RCommandStackModel::getModel ()->aboutToAdd (parent);
-	chain->closed = false;
-	chain->parent = parent;
-	parent->commands.append (chain);
-
-	RCommandStackModel::getModel ()->addComplete ();
-
+	issueCommandInternal (chain, parent);
 	return chain;
 }
 
@@ -89,6 +85,7 @@
 
 	chain->closed = true;
 	RCommandStackModel::getModel ()->itemChange (chain);
+	popIfCompleted (chain);
 }
 
 RCommand* RCommandStack::currentCommand () {
@@ -100,102 +97,57 @@
 		while (t.elapsed () < RK_Debug_CommandStep) {}
 	}
 
-	clearFinishedChains ();
-	RCommandBase *coc = current_chain;
-	while (coc->chainPointer ()) {
-		current_chain = coc->chainPointer ();
-		if (current_chain->commands.isEmpty ()) return 0;
-		coc = current_chain->commands.first ();
-	}
-	return coc->commandPointer ();
+	RCommandChain *dummy;
+	do {	// first pop any empty things in the way
+		dummy = activeSubItemOf (regular_stack);
+	} while (popIfCompleted (dummy));
+
+	RCommandChain *ret = activeSubItemOf (regular_stack);
+	if (ret) return ret->toCommand ();	// might still be 0, if it is not a command
+	return 0;
 }
 
-void RCommandStack::addChainCommandsToList (QList<RCommand*> *list, const RCommandChain *chain) const {
+RCommandChain* RCommandStack::activeSubItemOf (RCommandChain* item) {
 	RK_TRACE (RBACKEND);
 
-	foreach (RCommandBase* coc, chain->commands) {
-		if (coc->chainPointer ()) addChainCommandsToList (list, coc->chainPointer ());
-		else if (coc->commandPointer ()) list->append (coc->commandPointer ());
-		else RK_ASSERT (false);
-	}
+	if (item->sub_commands.isEmpty () && item->is_command && item->isClosed ()) return item;
+	if (item->sub_commands.isEmpty ()) return item;
+	return activeSubItemOf (item->sub_commands.first ());
 }
 
-QList<RCommand*> RCommandStack::allCommands () const {
+void RCommandStack::listCommandsRecursive (QList<RCommand*> *list, const RCommandChain *chain) {
 	RK_TRACE (RBACKEND);
 
-	QList<RCommand*> ret;
-	addChainCommandsToList (&ret, current_chain);
-	return ret;
-}
-
-bool RCommandStack::isEmpty () {
-//	RK_TRACE (RBACKEND);
-	return (commands.isEmpty ());
-}
-
-bool RCommandStack::isActive () {
-//	RK_TRACE (RBACKEND);
-
-	bool ret = !current_chain->commands.isEmpty ();
-	if (!ret) {
-		clearFinishedChains ();
+	if (chain->is_command) list->append (const_cast<RCommandChain*>(chain)->toCommand ());
+	foreach (const RCommandChain* coc, chain->sub_commands) {
+		listCommandsRecursive (list, coc);
 	}
-	return ret;
 }
 
-//static
-RCommandStack *RCommandStack::chainStack (RCommandChain *child) {
+QList<RCommand*> RCommandStack::allCommands () {
 	RK_TRACE (RBACKEND);
-	while (child->parent) {
-		child = child->parent;
-	}
-	return static_cast<RCommandStack *> (child);
-}
 
-//static
-RCommandStack *RCommandStack::stackForCommand (RCommand *child) {
-	RK_TRACE (RBACKEND);
-
-	RCommandBase *chain = child;
-	while (chain->parent) {
-		chain = chain->parent;
-	}
-	return static_cast<RCommandStack *> (chain);
+	QList<RCommand*> ret;
+	listCommandsRecursive (&ret, regular_stack);
+	return ret;
 }
 
-RCommandStack* RCommandStack::currentStack () {
+void RCommandStack::pop (RCommandChain *item) {
 	RK_TRACE (RBACKEND);
 
-	RCommandStack* stack = regular_stack;
-	while (stack->sub_stack) {
-		stack = stack->sub_stack;
-	}
-	return stack;
+	RCommandChain *parent = item->parent;
+	removeFromParent (item);
+	popIfCompleted (parent);
 }
 
-void RCommandStack::pop () {
+bool RCommandStack::popIfCompleted (RCommandChain* item) {
 	RK_TRACE (RBACKEND);
 
-	if (current_chain->commands.isEmpty ()) return;
-	RCommandBase* popped = current_chain->commands.first ();
-	RK_ASSERT (popped->commandPointer ());
-	RCommandStackModel::getModel ()->aboutToPop (popped->parent);
-	current_chain->commands.removeFirst ();
-	RCommandStackModel::getModel ()->popComplete ();
-}
-
-void RCommandStack::clearFinishedChains () {
-	// reached end of chain and chain is closed? walk up
-	while (current_chain->commands.isEmpty () && current_chain->closed && current_chain->parent) {
-		RK_TRACE (RBACKEND);	// trace in here. This is actually reach much *less* often
-
-		RCommandChain *prev_chain = current_chain;
-		RCommandStackModel::getModel ()->aboutToPop (current_chain->parent);
-		current_chain->parent->commands.removeFirst ();
-		current_chain = current_chain->parent;
-		delete prev_chain;
-		RCommandStackModel::getModel ()->popComplete ();
+	if (item->isClosed () && item->sub_commands.isEmpty () && item->parent && (!item->is_command)) {	// if the item has no parent, it is the main stack. If it is a command, it will be popped from the RInterface.
+		pop (item);
+		return true;
 	}
+	return false;
 }
 
 /////////////////////// RCommandStackModel ////////////////////
@@ -241,28 +193,19 @@
 	RK_ASSERT (listeners > 0);
 	RK_TRACE (RBACKEND);
 
-	RCommandBase* index_data = 0;
+	RCommandChain* index_data = 0;
 
 	if (!parent.isValid ()) {
 		index_data = RCommandStack::regular_stack;
 	} else {
-		RCommandBase* parent_index = static_cast<RCommandBase*> (parent.internalPointer ());
+		RCommandChain* parent_index = static_cast<RCommandChain*> (parent.internalPointer ());
 		RK_ASSERT (parent_index);
 
-		// parent is a command -> this must be a substack
-		if (parent_index->commandPointer ()) {
-			RK_ASSERT (parent.row () == 0);
-			index_data = RCommandStack::stackForCommand (parent_index->commandPointer ())->sub_stack;
-			RK_ASSERT (index_data);
-		} else {
-			// parent is a chain or stack
-			RCommandChain *chain = parent_index->chainPointer ();
-			if (chain->commands.size () <= row) {
-				RK_ASSERT (false);
-				return QModelIndex ();
-			}
-			index_data = chain->commands[row];
+		if (parent_index->sub_commands.size () <= row) {
+			RK_ASSERT (false);
+			return QModelIndex ();
 		}
+		index_data = parent_index->sub_commands[row];
 	}
 
 	return (createIndex (row, column, index_data));
@@ -272,24 +215,15 @@
 	RK_ASSERT (listeners);
 	RK_TRACE (RBACKEND);
 
-	RCommandBase* index_data;
-	if (!child.isValid()) {
-		return QModelIndex ();
-	} else {
-		RCommandBase* child_index = static_cast<RCommandBase*> (child.internalPointer ());
+	if (child.isValid ()) {
+		RCommandChain* child_index = static_cast<RCommandChain*> (child.internalPointer ());
 		RK_ASSERT (child_index);
 
-		if (child_index->chainPointer () && child_index->chainPointer ()->isStack ()) {
-			index_data = static_cast<RCommandStack*> (child_index->chainPointer ())->parent_command;
-			if (!index_data) {
-				return QModelIndex ();
-			}
-		} else {	// regular chains or commands
-			index_data = child_index->parent;
-		}
+		RCommandChain* index_data = child_index->parent;
+		if (index_data) return (createIndex (0, 0, index_data));
 	}
 
-	return (createIndex (0, 0, index_data));
+	return QModelIndex ();
 }
 
 int RCommandStackModel::rowCount (const QModelIndex& parent) const {
@@ -298,23 +232,9 @@
 
 	if (!parent.isValid ()) return 1;
 
-	RCommandBase* index_data = static_cast<RCommandBase*> (parent.internalPointer ());
+	RCommandChain* index_data = static_cast<RCommandChain*> (parent.internalPointer ());
 	RK_ASSERT (index_data);
-	if (index_data->commandPointer ()) {
-		RCommandStack *substack = RCommandStack::stackForCommand (index_data->commandPointer ())->sub_stack;
-		if (substack) {
-			if (substack->parent_command == index_data) {
-				RK_ASSERT (parent.row () == 0);
-				return 1;
-			}
-		}
-		return 0;
-	}
-	if (index_data->chainPointer ()) {
-		return (index_data->chainPointer ()->commands.size ());
-	}
-	RK_ASSERT (false);
-	return 0;
+	return (index_data->sub_commands.size ());
 }
 
 int RCommandStackModel::columnCount (const QModelIndex&) const {
@@ -331,10 +251,10 @@
 	if (!index.isValid ()) return QVariant ();
 	RK_ASSERT (index.model () == this);
 
-	RCommandBase* index_data = static_cast<RCommandBase*> (index.internalPointer ());
+	RCommandChain* index_data = static_cast<RCommandChain*> (index.internalPointer ());
 
-	if (index_data->commandPointer ()) {
-		RCommand *command = index_data->commandPointer ();
+	if (index_data->is_command) {
+		RCommand *command = index_data->toCommand ();
 		if ((index.column () == MAIN_COL) && (role == Qt::DisplayRole)) return (command->command ());
 		if ((index.column () == FLAGS_COL) && (role == Qt::DisplayRole)) {
 			QString ret;
@@ -352,24 +272,22 @@
 			if (command->status & RCommand::Running) ret += i18n ("Running");
 			if (command->status & RCommand::Canceled) {
 				if (!ret.isEmpty ()) ret += ", ";
-				ret += i18n ("Cancelled");
+				ret += i18n ("Canceled");
 			}
 			return (ret);
 		}
 		if ((index.column () == DESC_COL) && (role == Qt::DisplayRole)) {
 			return (command->rkEquivalent ());
 		}
-	}
-	if (index_data->chainPointer ()) {
-		RCommandChain* chain = index_data->chainPointer ();
-		if (chain->isStack ()) {
-			if ((index.column () == MAIN_COL) && (role == Qt::DisplayRole)) return (i18n ("Command Stack"));
-		} else {
+	} else {
+		if (index_data->parent) {
 			if ((index.column () == MAIN_COL) && (role == Qt::DisplayRole)) return (i18n ("Command Chain"));
 			if ((index.column () == STATUS_COL) && (role == Qt::DisplayRole)) {
-				if (chain->closed) return (i18n ("Closed"));
+				if (index_data->closed) return (i18n ("Closed"));
 				return (i18n ("Waiting"));
 			}
+		} else {
+			if ((index.column () == MAIN_COL) && (role == Qt::DisplayRole)) return (i18n ("Command Stack"));
 		}
 	}
 
@@ -383,10 +301,10 @@
 	if (!index.isValid ()) return 0;
 	RK_ASSERT (index.model () == this);
 
-	RCommandBase* index_data = static_cast<RCommandBase*> (index.internalPointer ());
+	RCommandChain* index_data = static_cast<RCommandChain*> (index.internalPointer ());
 	RK_ASSERT (index_data);
 
-	if (index_data->commandPointer ()) return (Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+	if (index_data->is_command) return (Qt::ItemIsSelectable | Qt::ItemIsEnabled);
 	return Qt::ItemIsEnabled;
 }
 
@@ -404,19 +322,18 @@
 	return QVariant ();
 }
 
-QModelIndex RCommandStackModel::indexFor (RCommandBase *item) {
+QModelIndex RCommandStackModel::indexFor (RCommandChain *item) {
 	RK_ASSERT (listeners);
 	RK_TRACE (RBACKEND);
 
 	if (!item) return (QModelIndex ());
 
-	if (item->chainPointer () && item->chainPointer ()->isStack ()) {
-		// stacks are always the first (and only) child of their parent
+	if (!item->parent) {
+		// stack is always the first (and only) child
 		return (createIndex (0, 0, item));
 	}
 
-	RK_ASSERT (item->parent);
-	int row = item->parent->commands.indexOf (item);
+	int row = item->parent->sub_commands.indexOf (item);
 	if (row < 0) {
 		RK_ASSERT (false);
 		return (QModelIndex ());
@@ -424,13 +341,12 @@
 	return (createIndex (row, 0, item));
 }
 
-void RCommandStackModel::aboutToPop (RCommandBase* parent) {
+void RCommandStackModel::aboutToPop (RCommandChain* parent, int index) {
 	if (!listeners) return;
 	RK_TRACE (RBACKEND);
 
 	QModelIndex parent_index = indexFor (parent);
-	// items are always removed at the front
-	beginRemoveRows (parent_index, 0, 0);
+	beginRemoveRows (parent_index, index, index);
 }
 
 void RCommandStackModel::popComplete () {
@@ -440,18 +356,12 @@
 	endRemoveRows ();
 }
 
-void RCommandStackModel::aboutToAdd (RCommandBase* parent) {
+void RCommandStackModel::aboutToAdd (RCommandChain* parent, int index) {
 	if (!listeners) return;
 	RK_TRACE (RBACKEND);
 
 	QModelIndex parent_index = indexFor (parent);
-	if ((!parent) || parent->commandPointer ()) {
-		beginInsertRows (parent_index, 0, 0);
-	} else {
-		// items are always added at the end
-		int row = parent->chainPointer ()->commands.size ();
-		beginInsertRows (parent_index, row, row);
-	}
+	beginInsertRows (parent_index, index, index);
 }
 
 void RCommandStackModel::addComplete () {
@@ -461,7 +371,7 @@
 	endInsertRows ();
 }
 
-void RCommandStackModel::itemChange (RCommandBase* item) {
+void RCommandStackModel::itemChange (RCommandChain* item) {
 	if (!listeners) return;
 	RK_TRACE (RBACKEND);
 

Modified: trunk/rkward/rkward/rbackend/rcommandstack.h
===================================================================
--- trunk/rkward/rkward/rbackend/rcommandstack.h	2013-04-15 09:32:28 UTC (rev 4699)
+++ trunk/rkward/rkward/rbackend/rcommandstack.h	2013-04-16 08:07:58 UTC (rev 4700)
@@ -2,7 +2,7 @@
                           rcommandstack  -  description
                              -------------------
     begin                : Mon Sep 6 2004
-    copyright            : (C) 2004, 2007, 2010, 2011 by Thomas Friedrichsmeier
+    copyright            : (C) 2004-2013 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -20,15 +20,17 @@
 #include "rcommand.h"
 
 /**
-This class represents a top-level RCommandChain. There are/will be two (types of) such chains: One for commands sent to the R-backend for "regular" evaluation, and one for commands sent in reply to a (modal) request from the R-backend via the RRequestHandler.
-The class provides convenience functions for determining the state of the Stack (empty/blocked/active) and inserting and fetching commands in the correct order.
-Remember to lock RInterface::mutex before accessing any of these functions!
-
- at author Thomas Friedrichsmeier
+* This class represents the top-level RCommandChain, which persists for the entire session.
+* Having a separate class for this (singleton!) is a bit of a historical left-over. However, it does make a bit of sense, as this essentially provides the API
+* for manipulation of RCommandChain s, which should be used by RInterface, only.
+* 
+* The main job of this class is to allow fetching commands in the correct order.
+* 
+* @author Thomas Friedrichsmeier
 */
 class RCommandStack : public RCommandChain {
 public:
-	RCommandStack (RCommand *parent_command);
+	RCommandStack ();
 	~RCommandStack ();
 
 /** add a command to the given chain (static, as it does no matter, which stack the chain belongs to) */
@@ -40,37 +42,22 @@
  (static, as it does no matter, which stack the chain belongs to). */
 	static void closeChain (RCommandChain *chain);
 
-/** @returns true, if there are no commands or open chains waiting in this stack */
-	bool isEmpty ();
-/** @returns true, if there are commands to be processed in the current chain */
-	bool isActive ();
+/** removes the given RCommand from the stack. */
+	static void pop (RCommandChain *item);
+	static bool popIfCompleted (RCommandChain *item);
+	static RCommandChain* activeSubItemOf (RCommandChain *item);
 
-/** removes the RCommand to be processed next from the stack and sets it as the currentCommand(). If there is no command to process right now, currentCommand() will be 0. Note: we can't just return the popped command for internal reasons. */
-	void pop ();
+/** returns a pointer to the current command to be processed. NOTE: This is really non-const. Chains which have been closed might be removed. */
+	static RCommand* currentCommand ();
+	static QList<RCommand*> allCommands ();
 
-/** see pop() */
-	RCommand* currentCommand ();
-	QList<RCommand*> allCommands () const;
-	RCommandChain* currentChain () { return current_chain; };
-
 /** the regular command stack, i.e. not a callback */
 	static RCommandStack *regular_stack;
-
-	static RCommandStack* currentStack ();
-
-/** return the parent RCommandStack of the given RCommandChain */
-	static RCommandStack *chainStack (RCommandChain *child);
-/** return the parent RCommandStack of the given RCommand */
-	static RCommandStack *stackForCommand (RCommand *child);
 private:
+	static void issueCommandInternal (RCommandChain *child, RCommandChain *parent);
+	static bool removeFromParent (RCommandChain *child);
 friend class RCommandStackModel;
-	RCommandChain *current_chain;
-/** super-ordinated command. 0 for the regular_stack */
-	RCommand *parent_command;
-/** pointer to any substack. Will only be non-zero, if the substack is active */
-	RCommandStack *sub_stack;
-	void clearFinishedChains ();
-	void addChainCommandsToList (QList<RCommand*> *list, const RCommandChain *chain) const;
+	static void listCommandsRecursive (QList<RCommand*> *list, const RCommandChain *chain);
 };
 
 #include <QAbstractItemModel>
@@ -115,24 +102,24 @@
 
 	/** call this, when you are about to remove an item from a command stack/chain, *before* you actually remove the item. When done, call popComplete().
 	@param parent The parent of the item to be removed */
-	void aboutToPop (RCommandBase* parent);
+	void aboutToPop (RCommandChain* parent, int index);
 	/** @see aboutToPop () */
 	void popComplete ();
 	/** call this, when you are about to add an item to a command stack/chain, *before* you actually add the item. When done, call addComplete().
 	@param parent The parent of the item to be removed */
-	void aboutToAdd (RCommandBase* parent);
+	void aboutToAdd (RCommandChain* parent, int index);
 	/** @see aboutToAdd () */
 	void addComplete ();
 	/** call this, when you have made changes to an item, that should be reflected in RControlWindow
 	@param item The item that was changed */
-	void itemChange (RCommandBase* item);
+	void itemChange (RCommandChain* item);
 private:
 	/** number of listeners. If there are no listeners, the model will do almost nothing at all */
 	int listeners;
 	static RCommandStackModel* static_model;
 
 	/** create a model index for the given item */
-	QModelIndex indexFor (RCommandBase *item);
+	QModelIndex indexFor (RCommandChain *item);
 };
 
 #endif

Modified: trunk/rkward/rkward/rbackend/rinterface.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.cpp	2013-04-15 09:32:28 UTC (rev 4699)
+++ trunk/rkward/rkward/rbackend/rinterface.cpp	2013-04-16 08:07:58 UTC (rev 4700)
@@ -93,7 +93,7 @@
 	}
 
 	new RCommandStackModel (this);
-	RCommandStack::regular_stack = new RCommandStack (0);
+	RCommandStack::regular_stack = new RCommandStack ();
 	startup_phase2_error = false;
 	command_logfile_mode = NotRecordingCommands;
 	previously_idle = false;
@@ -139,20 +139,23 @@
 	RK_TRACE (RBACKEND);
 
 	RK_ASSERT (!all_current_commands.isEmpty ());
-	RCommandStack::currentStack ()->pop ();
-	return all_current_commands.takeLast ();
+	RCommand *ret = all_current_commands.takeLast ();
+	RCommandStack::pop (ret);
+	return ret;
 }
 
 void RInterface::tryNextCommand () {
 	RK_TRACE (RBACKEND);
 	if (!currentCommandRequest ()) return;
 
-	RCommandStack *stack = RCommandStack::currentStack ();
-	bool main_stack = (stack == RCommandStack::regular_stack);
+	bool on_top_level = all_current_commands.isEmpty ();
+	if (!(on_top_level && locked)) {                                     // do not respect locks for sub-commands
+		RCommand *command = RCommandStack::currentCommand ();
+		if (!on_top_level && all_current_commands.contains (command)) {  // all sub-commands of the current command have finished
+			doNextCommand (0);
+			return;
+		}
 
-	if ((!(main_stack && locked)) && stack->isActive ()) {		// do not respect locks in substacks
-		RCommand *command = stack->currentCommand ();
-
 		if (command) {
 			all_current_commands.append (command);
 
@@ -175,11 +178,7 @@
 		}
 	}
 
-	if ((!stack->isActive ()) && stack->isEmpty () && !main_stack) {
-		// a substack was depleted
-		delete stack;
-		doNextCommand (0);
-	} else if (main_stack) {
+	if (on_top_level) {
 		if (!previously_idle) RKWardMainWindow::getMain ()->setRStatus (RKWardMainWindow::Idle);
 		previously_idle = true;
 	}
@@ -266,8 +265,7 @@
 		RK_ASSERT (command->getDataType () == RData::StringVector);
 		RKSettingsModuleRPackages::defaultliblocs += command->stringVector ();
 
-		RCommandStack *stack = RCommandStack::currentStack ();
-		RCommandChain *chain = stack->currentChain ();
+		RCommandChain *chain = command->parent;
 		RK_ASSERT (chain);
 		RK_ASSERT (!chain->isClosed ());
 
@@ -323,7 +321,7 @@
 	if (request->type == RBackendRequest::CommandOut) {
 		RCommandProxy *cproxy = request->takeCommand ();
 		RCommand *command = 0;
-
+#warning: when there are priority commands, the command to pop is NOT necessarily the one we last submitted!
 		// NOTE: the order of processing is: first try to submit the next command, then handle the old command.
 		// The reason for doing it this way, instead of the reverse, is that this allows the backend thread / process to continue working, concurrently
 		// NOTE: cproxy should only ever be 0 in the very first cycle
@@ -347,8 +345,7 @@
 		startup_errors = request->params["message"].toString ();
 
 		command_requests.append (request);
-		RCommandStack *stack = new RCommandStack (runningCommand ());
-		RCommandChain *chain = stack->startChain (stack);
+		RCommandChain *chain = RCommandStack::startChain (runningCommand ());
 
 		issueCommand ("paste (R.version[c (\"major\", \"minor\")], collapse=\".\")\n", RCommand::GetStringVector | RCommand::App | RCommand::Sync, QString (), this, GET_R_VERSION, chain);
 		// find out about standard library locations
@@ -454,9 +451,7 @@
 RCommandChain *RInterface::startChain (RCommandChain *parent) {
 	RK_TRACE (RBACKEND);
 
-	RCommandChain *ret;
-	ret = RCommandStack::startChain (parent);
-	return ret;
+	return RCommandStack::startChain (parent);
 };
 
 void RInterface::closeChain (RCommandChain *chain) {
@@ -636,7 +631,7 @@
 		current_command = new RCommand (QString (), RCommand::App | RCommand::EmptyCommand | RCommand::Sync);
 		issueCommand (current_command);
 	}
-	in_chain = startChain (new RCommandStack (current_command));
+	in_chain = startChain (current_command);
 
 	QString call = calllist.value (0);
 	if (call == "sync") {

Modified: trunk/rkward/rkward/rbackend/rinterface.h
===================================================================
--- trunk/rkward/rkward/rbackend/rinterface.h	2013-04-15 09:32:28 UTC (rev 4699)
+++ trunk/rkward/rkward/rbackend/rinterface.h	2013-04-16 08:07:58 UTC (rev 4700)
@@ -110,9 +110,9 @@
 		User=1		/**< locked on user request */
 	};
 
-/** Used for locking the backend, meaning not further commands will be given to the backend. This is used, when the currently running command is to be cancelled. It is used to make sure that the backend thread does not proceed with further commands, before the main thread takes notice. Also it is called, if the RThread is paused on User request. Further, the thread is initially locked so the main thread can check for some conditions before the backend thread may produce
-more errors/crashes. @see RInterface::cancelCommand @see RInterface::pauseProcessing
-May be an OR'ed combination of several LockType s */
+/** Used for locking the backend, meaning not further commands will be given to the backend. It is called, if the RThread is paused on User request.
+ * @see RInterface::pauseProcessing
+ * May be an OR'ed combination of several LockType s, but currently, there is only one LockType */
 	int locked;
 
 	QString startup_errors;

Modified: trunk/rkward/rkward/settings/rksettingsmodulegraphics.cpp
===================================================================
--- trunk/rkward/rkward/settings/rksettingsmodulegraphics.cpp	2013-04-15 09:32:28 UTC (rev 4699)
+++ trunk/rkward/rkward/settings/rksettingsmodulegraphics.cpp	2013-04-16 08:07:58 UTC (rev 4700)
@@ -148,6 +148,7 @@
 
 //static
 QStringList RKSettingsModuleGraphics::makeRRunTimeOptionCommands () {
+	RK_TRACE (SETTINGS);
 	QStringList list;
 
 #ifdef Q_WS_X11

Modified: trunk/rkward/rkward/settings/rksettingsmoduleoutput.cpp
===================================================================
--- trunk/rkward/rkward/settings/rksettingsmoduleoutput.cpp	2013-04-15 09:32:28 UTC (rev 4699)
+++ trunk/rkward/rkward/settings/rksettingsmoduleoutput.cpp	2013-04-16 08:07:58 UTC (rev 4700)
@@ -275,6 +275,7 @@
 
 //static
 QStringList RKSettingsModuleOutput::makeRRunTimeOptionCommands () {
+	RK_TRACE (SETTINGS);
 	QStringList list;
 
 // output format options

Modified: trunk/rkward/rkward/settings/rksettingsmoduler.cpp
===================================================================
--- trunk/rkward/rkward/settings/rksettingsmoduler.cpp	2013-04-15 09:32:28 UTC (rev 4699)
+++ trunk/rkward/rkward/settings/rksettingsmoduler.cpp	2013-04-16 08:07:58 UTC (rev 4700)
@@ -242,6 +242,7 @@
 
 //static
 QStringList RKSettingsModuleR::makeRRunTimeOptionCommands () {
+	RK_TRACE (SETTINGS);
 	QStringList list;
 
 	QString tf;

Modified: trunk/rkward/rkward/windows/rcontrolwindow.cpp
===================================================================
--- trunk/rkward/rkward/windows/rcontrolwindow.cpp	2013-04-15 09:32:28 UTC (rev 4699)
+++ trunk/rkward/rkward/windows/rcontrolwindow.cpp	2013-04-16 08:07:58 UTC (rev 4700)
@@ -117,9 +117,9 @@
 	// find out all the RCommands selected (not the chains)
 	for (QModelIndexList::const_iterator it = list.constBegin (); it != list.constEnd (); ++it) {
 		if ((*it).column ()) continue;		// only react once per row
-		RCommandBase* coc = static_cast<RCommandBase*> ((*it).internalPointer ());
+		RCommandChain* coc = static_cast<RCommandChain*> ((*it).internalPointer ());
 		RK_ASSERT (coc);
-		RCommand* command = coc->commandPointer ();
+		RCommand* command = coc->toCommand ();
 		if (command) {
 			if (!(command->type () & RCommand::Sync)) {
 				RKGlobals::rInterface ()->cancelCommand (command);





More information about the rkward-tracker mailing list