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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Mon Oct 2 17:25:04 UTC 2006


Revision: 789
          http://svn.sourceforge.net/rkward/?rev=789&view=rev
Author:   tfry
Date:     2006-10-02 10:24:35 -0700 (Mon, 02 Oct 2006)

Log Message:
-----------
Updating object list with RCommand::GetStructuredData (single command\!) is mostly working. Some cleanups still needed

Modified Paths:
--------------
    trunk/rkward/TODO
    trunk/rkward/rkward/core/rcontainerobject.cpp
    trunk/rkward/rkward/core/rcontainerobject.h
    trunk/rkward/rkward/core/rfunctionobject.cpp
    trunk/rkward/rkward/core/rfunctionobject.h
    trunk/rkward/rkward/core/rkmodificationtracker.cpp
    trunk/rkward/rkward/core/rkmodificationtracker.h
    trunk/rkward/rkward/core/rkvariable.cpp
    trunk/rkward/rkward/core/rkvariable.h
    trunk/rkward/rkward/core/robject.cpp
    trunk/rkward/rkward/core/robject.h
    trunk/rkward/rkward/core/robjectlist.cpp
    trunk/rkward/rkward/core/robjectlist.h
    trunk/rkward/rkward/misc/rkobjectlistview.cpp
    trunk/rkward/rkward/rbackend/rdata.cpp
    trunk/rkward/rkward/rbackend/rdata.h
    trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R

Modified: trunk/rkward/TODO
===================================================================
--- trunk/rkward/TODO	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/TODO	2006-10-02 17:24:35 UTC (rev 789)
@@ -11,6 +11,10 @@
 	- produce many readline calls (e.g. "for (i in 1:10) readline()") repeatedly and cancel all of them.
 		- Sometimes only the readine is interrupted, sometimes the whole command (might be R's fault? But works fine in plain R)
 		- Occasionally this seems to leave R in a bad (semi-crashed) state
+	- There is definitely a memory leak in handling output!
+		- Produce lots and lots of output -> watch mem usage grow
+		- Probably the RKConsole is to blame (run outside console -> no significant increase)
+			- Maybe the kate-part needs to be reset (syntax parse tree) every once in a while?
 
 Compilation / technical
 	- Incorporate FreeBSD patches http://www.freshports.org/math/rkward/files.php?message_id=200609172111.k8HLBiob081349@repoman.freebsd.org
@@ -87,9 +91,6 @@
 		- It will be possible to "store" these in the RObjectList and select them just like any other object
 		- RKVarslot will allow editing the selected value by hand (or just typing the name in)
 			- How to do this nicely UI wise?
-	- RFunctionObject for user defined functions. Maybe later it will be possible to use for functions from packages as well
-		- would be nice, if it also had some knowledge about function arguments
-		- ideally it would also know about the type of the return value, but this may not be realistic
 	- RKCancelDialog / RKErrorDialog:
 		- remove these classes. Port to use RKProgressControl instead
 	- instead of delete RObject, call RObject::deleteThis () and check for deleted in rCommandDone ()?
@@ -105,13 +106,12 @@
 		- well, on second thought, it might be better to rely more on RCommand::id () instead of pointers. Why? The id is unique (until integer overflow). The pointer may be reused after a delete -> potential problem when trying to cancel command which is actually already deleted (and potentially other cases)
 		- let's set this back for a while
 	- RKVariable:
-		- use QIntDict instead of string-map for value-labels / factor levels?
+		- use QIntDict instead of string-map for value-labels / factor levels? Qt4: QHash
 	- UNPROTECT_PTR
 	- give informative feedback on syntax errors (line numbers, etc.)!
 	- .rk.get.available.packages ()
 		- use external (file) storage for cache to save mem
 	- can the mutex be made non-recursive? I think so, but don't recall
-	- RCommand::GetStructure for retrieving simple lists in a single call. Create class RStructure with field string/int/double/structure data, make RCommand a subclass of this (or something similar)
 
 General code:
 	- use constBegin (), constEnd ()

Modified: trunk/rkward/rkward/core/rcontainerobject.cpp
===================================================================
--- trunk/rkward/rkward/core/rcontainerobject.cpp	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/rcontainerobject.cpp	2006-10-02 17:24:35 UTC (rev 789)
@@ -21,20 +21,15 @@
 #include "../rbackend/rinterface.h"
 #include "robjectlist.h"
 #include "rkvariable.h"
+#include "rfunctionobject.h"
 
 #include "../rkglobals.h"
 #include "rkmodificationtracker.h"
 
 #include "../debug.h"
 
-#define CLASSIFY_COMMAND 1
-#define UPDATE_CLASS_COMMAND 2
-#define UPDATE_CHILD_LIST_COMMAND 3
-#define GET_META_COMMAND 4
-
 RContainerObject::RContainerObject (RContainerObject *parent, const QString &name) : RObject (parent, name) {
 	RK_TRACE (OBJECTS);
-	num_children_updating = 0;
 	type = Container;
 }
 
@@ -47,93 +42,126 @@
 	}
 }
 
-void RContainerObject::updateFromR () {
+RObject *RContainerObject::updateChildStructure (RObject *child, RData *new_data, bool just_created) {
 	RK_TRACE (OBJECTS);
+	RK_ASSERT (child);
+	RK_ASSERT (new_data);
 
-// TODO: move classification / type mismatch-checking to RObject
-	RCommand *command = new RCommand (".rk.classify (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetIntVector, QString::null, this, CLASSIFY_COMMAND);
-	RKGlobals::rInterface ()->issueCommand (command, RKGlobals::rObjectList()->getUpdateCommandChain ());
+	if (child->updateStructure (new_data)) {
+		return child;
+	} else {
+		if (just_created) {
+			delete child;
+			RK_ASSERT (false);
+			return 0;
+		} else {
+			RKGlobals::tracker ()->removeObject (child, 0, true);
+
+			RData *child_name_data = new_data->getStructureVector ()[0];
+			RK_ASSERT (child_name_data->getDataType () == RData::StringVector);
+			RK_ASSERT (child_name_data->getDataLength () >= 1);
+			QString child_name = child_name_data->getStringVector ()[0];
+
+			return (createChildFromStructure (new_data, child_name));
+		}
+	}
 }
 
-//virtual
-QString RContainerObject::listChildrenCommand () {
+bool RContainerObject::updateStructure (RData *new_data) {
 	RK_TRACE (OBJECTS);
+	unsigned int data_length = new_data->getDataLength (); 
+	RK_ASSERT (data_length >= 5);
+	RK_ASSERT (new_data->getDataType () == RData::StructureVector);
 
-	return ("names (" + getFullName () + ")");
+	if (!RObject::updateStructure (new_data)) return false;
+
+	if (data_length > 5) {
+		RK_ASSERT (data_length == 6);
+
+		RData *children_sub = new_data->getStructureVector ()[5];
+		RK_ASSERT (children_sub->getDataType () == RData::StructureVector);
+
+		updateChildren (children_sub);
+	}
+
+	return true;
 }
 
-void RContainerObject::rCommandDone (RCommand *command) {
+RObject *RContainerObject::createChildFromStructure (RData *child_data, const QString &child_name) {
 	RK_TRACE (OBJECTS);
+	RK_ASSERT (child_data->getDataType () == RData::StructureVector);
+	RK_ASSERT (childmap.find (child_name) == childmap.end ());
+	RK_ASSERT (child_data->getDataLength () >= 2);		// need to see at least the type at this point
 
-	bool properties_changed = false;
-	if (command->getFlags () == GET_META_COMMAND) {
-		handleGetMetaCommand (command);
-	} else if (command->getFlags () == CLASSIFY_COMMAND) {
-		if (!handleClassifyCommand (command, &properties_changed)) {
-			return; // will be deleted!
-		}
+	RData *type_data = child_data->getStructureVector ()[1];
+	RK_ASSERT (type_data->getDataType () == RData::IntVector);
+	RK_ASSERT (type_data->getDataLength () == 1);
+	qDebug ("t%d l%d", type_data->getDataType (), type_data->getDataLength ()); 
 
-		// classifiy command was successful. now get further information.
-		if (hasMetaObject ()) getMetaData (RKGlobals::rObjectList()->getUpdateCommandChain (), GET_META_COMMAND);
+	int child_type = type_data->getIntVector ()[0];
 
-		RCommand *command = new RCommand ("class (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetStringVector, QString::null, this, UPDATE_CLASS_COMMAND);
-		RKGlobals::rInterface ()->issueCommand (command, RKGlobals::rObjectList()->getUpdateCommandChain ());
+	RObject *child_object;
+	if (child_type & RObject::Container) {
+		child_object = new RContainerObject (this, child_name);
+	} else if (child_type & RObject::Function) {
+		child_object = new RFunctionObject (this, child_name);
+	} else {
+		child_object = new RKVariable (this, child_name);
+	}
+	RK_ASSERT (child_object);
+	RKGlobals::tracker ()->lockUpdates (true);	// object not yet added. prevent updates
+	child_object = updateChildStructure (child_object, child_data, true);
+	RKGlobals::tracker ()->lockUpdates (false);
+	RK_ASSERT (child_object);
 
-		command = new RCommand (listChildrenCommand (), RCommand::App | RCommand::Sync | RCommand::GetStringVector, QString::null, this, UPDATE_CHILD_LIST_COMMAND);
-		RKGlobals::rInterface ()->issueCommand (command, RKGlobals::rObjectList()->getUpdateCommandChain ());
+	if (child_object) RKGlobals::tracker ()->addObject (child_object, 0);
+	return child_object;
+}
 
-		if (properties_changed) RKGlobals::tracker ()->objectMetaChanged (this);
+void RContainerObject::updateChildren (RData *new_children) {
+	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_children->getDataType () == RData::StructureVector);
+	unsigned int new_child_count = new_children->getDataLength ();
 
-	} else if (command->getFlags () == UPDATE_CHILD_LIST_COMMAND) {
-		// first check, whether all known children still exist:
-		checkRemovedChildren (command->getStringVector (), command->getDataLength ());
-		
-		// next, update the existing and/or new children
-		num_children_updating = command->getDataLength ();
-		// empty object?
-		if (!num_children_updating) {
-			parent->childUpdateComplete ();
+// first find out, which children are now available, copy the old one, create the new ones
+	RObjectMap new_childmap;
+	for (unsigned int i = 0; i < new_child_count; ++i) {
+		RData *child_data = new_children->getStructureVector ()[i];
+		RK_ASSERT (child_data->getDataType () == RData::StructureVector);
+		RK_ASSERT (child_data->getDataLength () >= 1);
+		RData *child_name_data = child_data->getStructureVector ()[0];
+		RK_ASSERT (child_name_data->getDataType () == RData::StringVector);
+		RK_ASSERT (child_name_data->getDataLength () >= 1);
+		QString child_name = child_name_data->getStringVector ()[0];
+		qDebug (child_name.latin1 ());
+
+		RObject *child_object;
+		RObjectMap::const_iterator it = childmap.find (child_name);
+		if (it != childmap.end ()) {
+			child_object = updateChildStructure (it.data (), child_data);
+		} else {
+			child_object = createChildFromStructure (child_data, child_name);
 		}
-		for (unsigned int i = 0; i < command->getDataLength (); ++i) {
-			QString cname = command->getStringVector ()[i]; 	// for easier typing
-			if (childmap.find (cname) != childmap.end ()) {
-				RK_DO (qDebug ("updating existing child: %s", cname.latin1 ()), APP, DL_DEBUG);
-				childmap[cname]->updateFromR ();
-			} else {
-				RK_DO (qDebug ("creating new child: %s", cname.latin1 ()), APP, DL_DEBUG);
-				RKGlobals::rObjectList()->createFromR (this, cname);
-			}
-		}
-		
-	} else if (command->getFlags () == UPDATE_CLASS_COMMAND) {
-		if (handleUpdateClassCommand (command)) properties_changed = true;
-		if (properties_changed) RKGlobals::tracker ()->objectMetaChanged (this);
+		new_childmap.insert (child_name, child_object);
 	}
-}
 
-void RContainerObject::typeMismatch (RObject *child, QString childname) {
-	RK_TRACE (OBJECTS);
-	/* I no longer know, why I added the uncommented lines below. From what I can tell today, tracker->removeObject () will call removeChild ()
-	and the object will be deleted there. Will need to valgrind sonner or later to find out, if those lines did serve a purpose, after all. */
-	/* delete child;
-	childmap.remove (childname); */
-	
-	RKGlobals::tracker ()->removeObject (child, 0, true);
-	RKGlobals::rObjectList()->createFromR (this, childname);
-}
+// now find out, which old ones are missing
+	QValueList<RObject*> removed_list;
+	for (RObjectMap::const_iterator it = childmap.constBegin (); it != childmap.constEnd (); ++it) {
+		QString child_string = it.key ();
 
-void RContainerObject::childUpdateComplete () {
-	RK_TRACE (OBJECTS);
-	RK_ASSERT (num_children_updating);
-	if ((--num_children_updating) <= 0) parent->childUpdateComplete ();
-}
+		if (new_childmap.find (child_string) == new_childmap.end ()) {
+			removed_list.append (it.data ());
+		}
+	}
 
-void RContainerObject::addChild (RObject *child, QString childname) {
-	RK_TRACE (OBJECTS);
-	RK_ASSERT (child);
+// finally delete the missing old ones
+	for (QValueList<RObject*>::iterator it = removed_list.begin (); it != removed_list.end (); ++it) {
+		RK_DO (qDebug ("child no longer present: %s.", (*it)->getFullName ().latin1 ()), OBJECTS, DL_DEBUG);
+		RKGlobals::tracker ()->removeObject ((*it), 0, true);
+	}
 
-	childmap.insert (childname, child);
-	child->updateFromR ();
+	childmap = new_childmap;
 }
 
 int RContainerObject::numChildren () {
@@ -228,14 +256,17 @@
 void RContainerObject::removeChild (RObject *object, bool removed_in_workspace) {
 	RK_TRACE (OBJECTS);
 
-	RObjectMap::iterator it = childmap.find (object->getShortName ());
-	RK_ASSERT (it.data () == object);
-	
 	if (!removed_in_workspace) {
 		RCommand *command = new RCommand (object->getFullName () + " <- NULL", RCommand::App | RCommand::Sync);
 		RKGlobals::rInterface ()->issueCommand (command, 0);
 	}
 
+	RObjectMap::iterator it = childmap.find (object->getShortName ());
+	if (it == childmap.end ()) {
+		return;
+	}
+	RK_ASSERT (it.data () == object);
+
 	childmap.remove (it);
 	delete object;
 }
@@ -257,31 +288,6 @@
 	return false;
 }
 
-void RContainerObject::checkRemovedChildren (QString *current_children, int child_count) {
-	RK_TRACE (OBJECTS);
-	QValueList<RObject*> removed_list;
-
-// is there a more efficient algorithm for doing this?
-	for (RObjectMap::iterator it = childmap.begin (); it != childmap.end (); ++it) {
-		QString child_string = it.key ();
-		bool found = false;
-		for (int i = 0; i < child_count; ++i) {
-			if (child_string == current_children[i]) {
-				found = true;
-				break;
-			}
-		}
-		if (!found) {
-			removed_list.append (it.data ());
-		}
-	}
-
-	for (QValueList<RObject*>::iterator it = removed_list.begin (); it != removed_list.end (); ++it) {
-		RK_DO (qDebug ("child no longer present: %s.", (*it)->getFullName ().latin1 ()), OBJECTS, DL_DEBUG);
-		RKGlobals::tracker ()->removeObject ((*it), 0, true);
-	}
-}
-
 QString RContainerObject::validizeName (const QString &child_name) {
 	RK_TRACE (OBJECTS);
 	QString ret = child_name;
@@ -295,4 +301,3 @@
 	}
 	return (ret +postfix);
 }
-

Modified: trunk/rkward/rkward/core/rcontainerobject.h
===================================================================
--- trunk/rkward/rkward/core/rcontainerobject.h	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/rcontainerobject.h	2006-10-02 17:24:35 UTC (rev 789)
@@ -35,11 +35,14 @@
 	~RContainerObject ();
 
 	void writeChildMetaData (RCommandChain *chain);
-	
-	void updateFromR ();
 
-	virtual void childUpdateComplete ();
-	
+	/** update the given child with the given data. Since the child may be mismatching, and may need to be recreated, returns a pointer to the child (old or new) */
+	RObject *updateChildStructure (RObject *child, RData *new_data, bool just_created=false);
+	RObject *createChildFromStructure (RData *child_data, const QString &child_name);
+
+	/** reimplemented from RObject to also update children */
+	bool updateStructure (RData *new_data);
+
 	int numChildren ();
 	RObject **children ();
 
@@ -60,28 +63,14 @@
 
 	/** reimplemented from RObject to actually search for the object */
 	RObject *findObject (const QString &name, bool is_canonified=false);
-
-	virtual QString listChildrenCommand ();
-private:
-	friend class RObject;
-	friend class RKVariable;
-	void typeMismatch (RObject *child, QString childname);
 protected:
+	void updateChildren (RData *new_children);
 	RObjectMap childmap;
 	// why do I need this to make it compile?!
 	friend class RObjectList;
-	void addChild (RObject *child, QString childname);
+	friend class RObject;
 	virtual void renameChild (RObject *object, const QString &new_name);
 	virtual void removeChild (RObject *object, bool removed_in_workspace);
-/** given the current list of children (as returned by the "names"-command or similar in derived classes) find out, which children have been removed,
-and takes the appropriate measures */
-	void checkRemovedChildren (QString *current_children, int child_count);
-
-	int num_dimensions;
-	int *dimension;
-	int num_children_updating;
-
-	void rCommandDone (RCommand *command);
 };
 
 #endif

Modified: trunk/rkward/rkward/core/rfunctionobject.cpp
===================================================================
--- trunk/rkward/rkward/core/rfunctionobject.cpp	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/rfunctionobject.cpp	2006-10-02 17:24:35 UTC (rev 789)
@@ -17,51 +17,76 @@
 
 #include "rfunctionobject.h"
 
-#include "../rbackend/rinterface.h"
-#include "robjectlist.h"
+#include "../rbackend/rdata.h"
+#include "rkmodificationtracker.h"
 #include "../rkglobals.h"
 #include "../debug.h"
 
-#define CLASSIFY_COMMAND 1
-#define UPDATE_ARGS_COMMAND 2
-
 RFunctionObject::RFunctionObject (RContainerObject *parent, const QString &name) : RObject (parent, name) {
 	RK_TRACE (OBJECTS);
 	type = Function;
+
+	argcount = 0;
+	argnames = 0;
+	argvalues = 0;
 }
 
 RFunctionObject::~RFunctionObject () {
 	RK_TRACE (OBJECTS);
 }
 
-void RFunctionObject::updateFromR () {
+bool RFunctionObject::updateStructure (RData *new_data) {
 	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_data->getDataLength () >= 5);
+	RK_ASSERT (new_data->getDataType () == RData::StructureVector);
 
-// TODO: move classification / type mismatch-checking to RObject
-	RCommand *command = new RCommand (".rk.classify (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetIntVector, QString::null, this, CLASSIFY_COMMAND);
-	RKGlobals::rInterface ()->issueCommand (command, RKGlobals::rObjectList()->getUpdateCommandChain ());
+	if (!RObject::updateStructure (new_data)) return false;
+
+	if (updateArguments (new_data)) RKGlobals::tracker ()->objectMetaChanged (this);
+
+	return true;
 }
 
-void RFunctionObject::rCommandDone (RCommand *command) {
+bool RFunctionObject::updateArguments (RData *new_data) {
 	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_data->getDataLength () == 7);
+	RK_ASSERT (new_data->getDataType () == RData::StructureVector);
 
-	bool dummy;
-	if (command->getFlags () == CLASSIFY_COMMAND) {
-		if (!handleClassifyCommand (command, &dummy)) {
-			return; // will be deleted!
-		}
+	RData *argnames_data = new_data->getStructureVector ()[5];
+	RData *argvalues_data = new_data->getStructureVector ()[6];
 
-		RCommand *command = new RCommand ("c (as.character (names (formals (" + getFullName () +"))), as.character (formals (" +getFullName () + ")))", RCommand::App | RCommand::Sync | RCommand::GetStringVector, QString::null, this, UPDATE_ARGS_COMMAND);
-		RKGlobals::rInterface ()->issueCommand (command, RKGlobals::rObjectList()->getUpdateCommandChain ());
+	unsigned int new_arglen = argnames_data->getDataLength (); 
+	RK_ASSERT (argnames_data->getDataType () == argvalues_data->getDataType () == RData::StringVector);
+#warning Change this!
+return false;
+	RK_ASSERT (new_arglen == argvalues_data->getDataLength ());
+	QString *new_argnames = argnames_data->getStringVector ();
+	QString *new_argvalues = argvalues_data->getStringVector ();
+	argnames_data->detachData ();
+	argvalues_data->detachData ();
 
-	} else if (command->getFlags () == UPDATE_ARGS_COMMAND) {
-		RK_ASSERT (command->getDataLength () % 2 == 0);
+	bool changed = false;
+	if (new_arglen != argcount) {
+		changed = true;
+	} else {
+		for (unsigned int i = 0; i < new_arglen; ++i) {
+			if (argnames[i] != new_argnames[i]) {
+				changed = true;
+				break;
+			}
 
-		function_args.clear ();
-		for (unsigned int i = 0; i < command->getDataLength (); i += 2) {
-			function_args.append (new FunctionArg (command->getStringVector ()[i], command->getStringVector ()[i+1]));
+			if (argvalues[i] != new_argvalues[i]) {
+				changed = true;
+				break;
+			}
 		}
+	}
 
-		parent->childUpdateComplete ();
-	}
+	argcount = new_arglen;
+	delete [] argnames;
+	delete [] argvalues;
+	argnames = new_argnames;
+	argvalues = new_argvalues;
+
+	return changed;
 }

Modified: trunk/rkward/rkward/core/rfunctionobject.h
===================================================================
--- trunk/rkward/rkward/core/rfunctionobject.h	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/rfunctionobject.h	2006-10-02 17:24:35 UTC (rev 789)
@@ -35,13 +35,13 @@
 	RFunctionObject (RContainerObject *parent, const QString &name);
 	~RFunctionObject ();
 
-	void updateFromR ();
+/** reimplemented from RObject to handle function arguments */
+	bool updateStructure (RData *new_data);
 protected:
-	void rCommandDone (RCommand *command);
-
-	typedef QPair<QString, QString> FunctionArg;
-	typedef QValueList<FunctionArg *> FunctionArguments;
-	FunctionArguments function_args;
+	unsigned int argcount;
+	QString *argnames;
+	QString *argvalues;
+	bool updateArguments (RData *new_data);
 };
 
 #endif

Modified: trunk/rkward/rkward/core/rkmodificationtracker.cpp
===================================================================
--- trunk/rkward/rkward/core/rkmodificationtracker.cpp	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/rkmodificationtracker.cpp	2006-10-02 17:24:35 UTC (rev 789)
@@ -27,6 +27,8 @@
 
 RKModificationTracker::RKModificationTracker (QObject *parent) : QObject (parent) {
 	RK_TRACE (OBJECTS);
+
+	updates_locked = 0;
 }
 
 
@@ -62,7 +64,7 @@
 	}
 	
 	if (ed) ed->removeObject (object);
-	emit (objectRemoved (object));
+	if (updates_locked <= 0) emit (objectRemoved (object));
 	object->remove (removed_in_workspace);
 }
 
@@ -76,7 +78,7 @@
 
 // since we may end up with a different name that originally requested, we propagate the change also to the original editor
 	if (ed) ed->renameObject (object);
-	emit (objectPropertiesChanged (object));
+	if (updates_locked <= 0) emit (objectPropertiesChanged (object));
 }
 
 void RKModificationTracker::addObject (RObject *object, RKEditor *editor) {
@@ -91,7 +93,7 @@
 			ed->addObject (object);
 		}
 	}
-	emit (objectAdded (object));
+	if (updates_locked <= 0) emit (objectAdded (object));
 }
 
 void RKModificationTracker::objectMetaChanged (RObject *object) {
@@ -102,7 +104,7 @@
 	if (ed) {
 		ed->updateObjectMeta (object);
 	}
-	emit (objectPropertiesChanged (object));
+	if (updates_locked <= 0) emit (objectPropertiesChanged (object));
 }
 
 void RKModificationTracker::objectDataChanged (RObject *object, RObject::ChangeSet *changes) {

Modified: trunk/rkward/rkward/core/rkmodificationtracker.h
===================================================================
--- trunk/rkward/rkward/core/rkmodificationtracker.h	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/rkmodificationtracker.h	2006-10-02 17:24:35 UTC (rev 789)
@@ -47,6 +47,8 @@
 	void objectMetaChanged (RObject *object);
 /** the object's data was modified. Tells all editors and lists containing the object to update accordingly. The ChangeSet given tells which parts of the data have to be updated. The ChangeSet will get deleted by the RKModificationTracker, when done. */
 	void objectDataChanged (RObject *object, RObject::ChangeSet *changes);
+/** recursive! */
+	void lockUpdates (bool lock) { if (lock) ++updates_locked; else --updates_locked; };
 signals:
 /** classes which are not RKEditor(s) but need to know, when an object was removed, should connect to this signal */
 	void objectRemoved (RObject *object);
@@ -54,6 +56,8 @@
 	void objectPropertiesChanged (RObject *object);
 /** classes which are not RKEditor(s) but need to know, when an object was added, should connect to this signal */
 	void objectAdded (RObject *object);
+private:
+	int updates_locked;
 };
 
 #endif

Modified: trunk/rkward/rkward/core/rkvariable.cpp
===================================================================
--- trunk/rkward/rkward/core/rkvariable.cpp	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/rkvariable.cpp	2006-10-02 17:24:35 UTC (rev 789)
@@ -27,9 +27,6 @@
 #include "../rkglobals.h"
 #include "rkmodificationtracker.h"
 
-#define CLASSIFY_COMMAND 1
-#define UPDATE_CLASS_COMMAND 3
-#define GET_META_COMMAND 4
 #define GET_STORAGE_MODE_COMMAND 10
 #define GET_DATA_COMMAND 11
 #define GET_FACTOR_LEVELS_COMMAND 12
@@ -98,40 +95,11 @@
 	RObject::writeMetaData (chain);
 }
 
-void RKVariable::updateFromR () {
-	RK_TRACE (OBJECTS);
-	
-	getMetaData (RKGlobals::rObjectList()->getUpdateCommandChain (), GET_META_COMMAND);
-
-// TODO: move classification / type mismatch-checking to RObject
-	RCommand *command = new RCommand (".rk.classify (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetIntVector, QString::null, this, CLASSIFY_COMMAND);
-	RKGlobals::rInterface ()->issueCommand (command, RKGlobals::rObjectList()->getUpdateCommandChain ());
-}
-
 void RKVariable::rCommandDone (RCommand *command) {
 	RK_TRACE (OBJECTS);
 	
-	bool properties_changed = false;
-
-	if (command->getFlags () == GET_META_COMMAND) {
-		handleGetMetaCommand (command);
-
-		// TODO: This is not quite good, yet, as it may result in two calls to objectMetaChanged.
-		QString dummy = getMetaProperty ("type");
-		int new_var_type = dummy.toInt ();
-		var_type = (RObject::VarType) new_var_type;
-		if (new_var_type != var_type) RKGlobals::tracker ()->objectMetaChanged (this);
-	} else if (command->getFlags () == CLASSIFY_COMMAND) {
-		if (!handleClassifyCommand (command, &properties_changed)) {
-			return; // will be deleted!
-		}
-
-		// classifiy command was successful. now get further information.
-		RCommand *ncommand = new RCommand ("class (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetStringVector, QString::null, this, UPDATE_CLASS_COMMAND);
-		RKGlobals::rInterface ()->issueCommand (ncommand, RKGlobals::rObjectList()->getUpdateCommandChain ());
-
-		if (properties_changed) RKGlobals::tracker ()->objectMetaChanged (this);
-
+	if (command->getFlags () == ROBJECT_UDPATE_STRUCTURE_COMMAND) {
+		RObject::rCommandDone (command);
 	} else if (command->getFlags () == GET_STORAGE_MODE_COMMAND) {
 		RK_ASSERT (command->getDataType () == RData::IntVector);
 		RK_ASSERT (command->getDataLength () == 2);
@@ -184,11 +152,6 @@
 			myData ()->value_labels->insert (QString::number (i+1), command->getStringVector ()[i]);
 		}
 		setSyncing (true);
-	} else if (command->getFlags () == UPDATE_CLASS_COMMAND) {
-		if (handleUpdateClassCommand (command)) properties_changed = true;
-		if (properties_changed) RKGlobals::tracker ()->objectMetaChanged (this);
-
-		parent->childUpdateComplete ();
 	}
 }
 
@@ -202,9 +165,9 @@
 void RKVariable::setLength (int len) {
 	RK_TRACE (OBJECTS);
 	RK_ASSERT (!getLength ());	// should only be called once
-	RK_ASSERT (dimension);
+	RK_ASSERT (dimensions);
 
-	dimension[0] = len;
+	dimensions[0] = len;
 }
 
 void RKVariable::restoreStorageInBackend () {
@@ -380,7 +343,7 @@
 
 	if (length <= 0) length = 1;
 	if (length < (myData ()->allocated_length - 1)) {
-		dimension[0] = length;
+		dimensions[0] = length;
 		return;
 	}
 
@@ -407,7 +370,7 @@
 	myData ()->cell_double_data = new_double_data;
 
 	myData ()->allocated_length = target;
-	dimension[0] = length;
+	dimensions[0] = length;
 }
 
 void RKVariable::downSize () {
@@ -675,7 +638,7 @@
 		myData ()->cell_double_data[myData ()->allocated_length - 1] = 0;
 	}
 
-	dimension[0] -= (to_row - from_row) + 1;	
+	dimensions[0] -= (to_row - from_row) + 1;	
 	downSize ();
 	RECHECK_VALID
 }

Modified: trunk/rkward/rkward/core/rkvariable.h
===================================================================
--- trunk/rkward/rkward/core/rkvariable.h	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/rkvariable.h	2006-10-02 17:24:35 UTC (rev 789)
@@ -47,9 +47,6 @@
 /** set the VarType. If sync, the change will be communicated to the backend immediately. See getVarType */
 	void setVarType (RObject::VarType, bool sync=true);
 
-/** reimplemented from RObject */
-	void updateFromR ();
-	
 /** reimplemented from RObject to also store value labels/factor levels (and in the future probably futher info) */
 	void writeMetaData (RCommandChain *chain);
 friend class RContainerObject;

Modified: trunk/rkward/rkward/core/robject.cpp
===================================================================
--- trunk/rkward/rkward/core/robject.cpp	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/robject.cpp	2006-10-02 17:24:35 UTC (rev 789)
@@ -24,6 +24,7 @@
 #include "../rbackend/rinterface.h"
 #include "../rkglobals.h"
 #include "rkmodificationtracker.h"
+#include "robjectlist.h"
 
 #include "../debug.h"
 
@@ -35,10 +36,9 @@
 	type = 0;
 	meta_map = 0;
 	data = 0;
+	classnames = 0;
 	num_classes = 0;
-	classname = 0;
-	dimension = new int [1];		// safe initialization
-	dimension[0] = 0;
+	dimensions = 0;
 	num_dimensions = 0;
 }
 
@@ -47,9 +47,8 @@
 
 	if (data) discardEditData ();
 
-	delete[] classname;
-
-	delete dimension;
+	delete [] dimensions;
+	delete [] classnames;
 }
 
 QString RObject::getShortName () {
@@ -131,11 +130,11 @@
 QString RObject::makeClassString (const QString &sep) {
 	RK_TRACE (OBJECTS);
 	QString ret;
-	for (int i=0; i < num_classes; ++i) {
-		ret.append (classname[i]);
-		if (i < (num_classes - 1)) {
-			ret.append (sep);
-		}
+	bool first = true;
+	for (unsigned int i=0; i < numClasses (); ++i) {
+		if (first) first = false;
+		else ret.append (sep);
+		ret.append (getClassName (i));
 	}
 	return ret;
 }
@@ -143,8 +142,8 @@
 bool RObject::inherits (const QString &class_name) {
 	RK_TRACE (OBJECTS);
 
-	for (int i=0; i < num_classes; ++i) {
-		if (classname[i] == class_name) {
+	for (unsigned int i=0; i < numClasses (); ++i) {
+		if (getClassName (i) == class_name) {
 			return true;
 		}
 	}
@@ -155,12 +154,6 @@
 	RK_TRACE (OBJECTS);
 	return (getFullName () + "[[" + rQuote (short_child_name) + "]]");
 }
-	
-void RObject::getMetaData (RCommandChain *chain, int flags) {
-	RK_TRACE (OBJECTS);
-	RCommand *command = new RCommand (".rk.get.meta (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetStringVector, QString::null, this, flags);
-	RKGlobals::rInterface ()->issueCommand (command, chain);
-}
 
 void RObject::writeMetaData (RCommandChain *chain) {
 	RK_TRACE (OBJECTS);
@@ -193,88 +186,198 @@
 	type |= HasMetaObject;
 }
 
-void RObject::handleGetMetaCommand (RCommand *command) {
+void RObject::updateFromR () {
 	RK_TRACE (OBJECTS);
 
-	if (command->getDataLength ()) {
-		if (!meta_map) meta_map = new MetaMap;
-		meta_map->clear ();
+	RCommand *command = new RCommand (".rk.get.structure (" + getFullName () + ", " + rQuote (getShortName ()) + ")", RCommand::App | RCommand::Sync | RCommand::GetStructuredData, QString::null, this, ROBJECT_UDPATE_STRUCTURE_COMMAND);
+	RKGlobals::rInterface ()->issueCommand (command, RKGlobals::rObjectList()->getUpdateCommandChain ());
+}
 
-		int len = command->getDataLength ();
-		RK_ASSERT (!(len % 2));
-		int cut = len/2;
-		for (int i=0; i < cut; ++i) {
-			meta_map->insert (command->getStringVector ()[i], command->getStringVector ()[i+cut]);
-		}
-		
-		type |= HasMetaObject;
-	} else {		// no meta data received
-		delete meta_map;
-		meta_map = 0;
-		
-		type -= (type & HasMetaObject);
+void RObject::rCommandDone (RCommand *command) {
+	RK_TRACE (OBJECTS);
+
+	if (command->getFlags () == ROBJECT_UDPATE_STRUCTURE_COMMAND) {
+		if (parent) parent->updateChildStructure (this, command);		// this may result in a delete, so nothing after this!
+		else updateStructure (command);		// if we have no parent, likely we're the RObjectList 
+		return;
+	} else {
+		RK_ASSERT (false);
 	}
-
-	// TODO: only signal change, if there really was a change!
-	RKGlobals::tracker ()->objectMetaChanged (this);
 }
 
-bool RObject::handleUpdateClassCommand (RCommand *command) {
+bool RObject::updateStructure (RData *new_data) {
 	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_data->getDataLength () >= 5);
+	RK_ASSERT (new_data->getDataType () == RData::StructureVector);
 
-	bool change = false;
+	if (!canAccommodateStructure (new_data)) return false;
 
-	int len = command->getDataLength ();
-	if (num_classes != len) {
-		num_classes = len;
-		delete[] classname;
-		classname = new QString [num_classes];
-		change = true;
-	}
-	for (int cn=0; cn < num_classes; ++cn) {
-		if (classname[cn] != command->getStringVector ()[cn]) change = true;
-		classname[cn] = command->getStringVector ()[cn];
-	}
+	bool properties_change = false;
 
-	return change;
+	properties_change = updateName (new_data->getStructureVector ()[0]);
+	properties_change = updateType (new_data->getStructureVector ()[1]);
+	properties_change = updateClasses (new_data->getStructureVector ()[2]);
+	properties_change = updateMeta (new_data->getStructureVector ()[3]);
+	properties_change = updateDimensions (new_data->getStructureVector ()[4]);
+
+	if (properties_change) RKGlobals::tracker ()->objectMetaChanged (this);
+
+	return true;
 }
 
-bool RObject::handleClassifyCommand (RCommand *command, bool *dims_changed) {
+bool RObject::canAccommodateStructure (RData *new_data) {
 	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_data->getDataLength () >= 5);
+	RK_ASSERT (new_data->getDataType () == RData::StructureVector);
 
-	if (!command->getDataLength ()) {
+	if (!isValidName (new_data->getStructureVector ()[0])) return false;
+	if (!isValidType (new_data->getStructureVector ()[1])) return false;
+	return true;
+}
+
+bool RObject::isValidName (RData *new_data) {
+	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_data->getDataLength () == 1);
+	RK_ASSERT (new_data->getDataType () == RData::StringVector);
+
+	if (name != new_data->getStringVector ()[0]) {
 		RK_ASSERT (false);
+		name = new_data->getStringVector ()[0];
 		return false;
 	}
-	int new_type = command->getIntVector ()[0];
+	return true;
+}
 
-	if (!isMatchingType (type, new_type)){
-		RK_DO (qDebug ("type-mismatch: name: %s, old_type: %d, new_type: %d", RObject::name.latin1 (), type, new_type), OBJECTS, DL_INFO);
-		RObject::parent->typeMismatch (this, RObject::name);
-		return false;	// will be deleted!
+bool RObject::updateName (RData *new_data) {
+	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_data->getDataLength () == 1);
+	RK_ASSERT (new_data->getDataType () == RData::StringVector);
+
+	bool changed = false;
+	if (name != new_data->getStringVector ()[0]) {
+		changed = true;
+		RK_ASSERT (false);
+		name = new_data->getStringVector ()[0];
 	}
-	if (new_type != type) {
-		*dims_changed = true;
+	new_data->discardData ();
+	return changed;
+}
+
+bool RObject::isValidType (RData *new_data) {
+	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_data->getDataLength () == 1);
+	RK_ASSERT (new_data->getDataType () == RData::IntVector);
+
+	int new_type = new_data->getIntVector ()[0];
+	if (!isMatchingType (type, new_type)) return false;
+
+	return true;
+}
+
+bool RObject::updateType (RData *new_data) {
+	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_data->getDataLength () == 1);
+	RK_ASSERT (new_data->getDataType () == RData::IntVector);
+
+	bool changed = false;
+	int new_type = new_data->getIntVector ()[0];
+	if (type != new_type) {
+		changed = true;
 		type = new_type;
 	}
+	new_data->discardData ();
+	return changed;
+}
 
-	// get dimensions
-	int len = command->getDataLength () - 1;
-	if (num_dimensions != len) {
-		num_dimensions = len;
-		*dims_changed = true;
-		delete dimension;
-		if (num_dimensions < 1) {
-			RK_ASSERT (false);
-			num_dimensions = 1;
+bool RObject::updateClasses (RData *new_data) {
+	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_data->getDataLength () >= 1);		// or can there be classless objects in R?
+	RK_ASSERT (new_data->getDataType () == RData::StringVector);
+
+	bool change = false;
+
+	unsigned int new_len = new_data->getDataLength ();
+	QString *new_classes = new_data->getStringVector ();
+	new_data->detachData ();
+
+	if (numClasses () != new_len) {
+		change = true;
+	} else {
+		for (unsigned int cn=0; cn < numClasses (); ++cn) {
+			if (classnames[cn] != new_classes[cn]) {
+				change = true;
+				break;
+			}
 		}
-		dimension = new int [num_dimensions];
 	}
-	for (int d=0; d < num_dimensions; ++d) {
-		if (dimension[d] != command->getIntVector ()[d+1]) *dims_changed = true;
-		dimension[d] = command->getIntVector ()[d+1];
+
+	num_classes = new_len;
+	delete [] classnames;
+	classnames = new_classes;
+
+	return change;
+}
+
+bool RObject::updateMeta (RData *new_data) {
+	RK_TRACE (OBJECTS);
+
+	RK_ASSERT (new_data->getDataType () == RData::StringVector);
+
+	unsigned int len = new_data->getDataLength ();
+	if (len == 1) len = 0;		// if it's a single element, it's just a dummy
+	bool change = false;
+	if (len) {
+		if (!meta_map) meta_map = new MetaMap;
+		meta_map->clear ();
+
+		RK_ASSERT (!(len % 2));
+		unsigned int cut = len/2;
+		for (unsigned int i=0; i < cut; ++i) {
+			meta_map->insert (new_data->getStringVector ()[i], new_data->getStringVector ()[i+cut]);
+		}
+
+		type |= HasMetaObject;
+		// TODO: only signal change, if there really was a change!
+		change = true;
+	} else {		// no meta data received
+		if (meta_map) {
+			delete meta_map;
+			meta_map = 0;
+			change = true;
+		}
+
+		type -= (type & HasMetaObject);
 	}
 
+	new_data->discardData ();
+	return change;
+}
+
+bool RObject::updateDimensions (RData *new_data) {
+	RK_TRACE (OBJECTS);
+	RK_ASSERT (new_data->getDataLength () >= 1);
+	RK_ASSERT (new_data->getDataType () == RData::IntVector);
+
+	bool changed = false;
+
+	unsigned int new_len = new_data->getDataLength ();
+	int *new_dimensions = new_data->getIntVector ();
+	new_data->detachData ();
+
+	if (num_dimensions != new_len) {
+		changed = true;
+	} else {
+		for (unsigned int d=0; d < num_dimensions; ++d) {
+			if (dimensions[d] != new_dimensions[d]) {
+				changed = true;
+				break;
+			}
+		}
+	}
+	delete [] dimensions;
+	num_dimensions = new_len;
+	dimensions = new_dimensions;
+
 	return true;
 }
 

Modified: trunk/rkward/rkward/core/robject.h
===================================================================
--- trunk/rkward/rkward/core/robject.h	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/robject.h	2006-10-02 17:24:35 UTC (rev 789)
@@ -27,7 +27,10 @@
 class RContainerObject;
 class RCommandChain;
 class RKEditor;
+class RData;
 
+#define ROBJECT_UDPATE_STRUCTURE_COMMAND 1
+
 /**
 Base class for representations of objects in the R-workspace. RObject is never used directly (contains pure virtual functions).
 
@@ -37,16 +40,35 @@
 class RObject : public RCommandReceiver {
 public:
 	RObject (RContainerObject *parent, const QString &name);
-
 	virtual ~RObject ();
 
 /** types of objects, RKWard knows about */
-	enum RObjectType { DataFrame=1, Matrix=2, Array=4, List=8, Container=16, Variable=32, Workspace=64, Function=128, Environment=256, GlobalEnv=512, EnvironmentVar=1024, HasMetaObject=2048 };
-	#define ROBJECT_TYPE_INTERNAL_MASK (RObject::Container | RObject::Variable | RObject::Workspace | RObject::Function)
+	enum RObjectType {
+		DataFrame=1,
+		Matrix=2,
+		Array=4,
+		List=8,
+		Container=16,
+		Variable=32,
+		Workspace=64,
+		Function=128,
+		Environment=256,
+		GlobalEnv=512,
+		EnvironmentVar=1024,
+		HasMetaObject=2048
+	};
+
+	#define ROBJECT_TYPE_INTERNAL_MASK (RObject::Container | RObject::Variable | RObject::Workspace | RObject::Environment | RObject::Function)
 /** @returns false if an object of the given old type cannot represent an object of the given new type (e.g. (new_type & RObjectType::Variable), but (old_type & RObjectType::Container)). */
 	static bool isMatchingType (int old_type, int new_type) { return ((old_type & ROBJECT_TYPE_INTERNAL_MASK) == (new_type & ROBJECT_TYPE_INTERNAL_MASK)); };
 /** types of variables, RKWard knows about. See \ref RKVariable */
-	enum VarType { Unknown=0, Number=1, Factor=2, String=3, Invalid=4 };
+	enum VarType {
+		Unknown=0,
+		Number=1,
+		Factor=2,
+		String=3,
+		Invalid=4
+	};
 	
 	QString getShortName ();
 	virtual QString getFullName ();
@@ -63,6 +85,9 @@
 	bool isType (int type) { return (RObject::type & type); };
 	bool hasMetaObject () { return (type & HasMetaObject); };
 
+/** trigger an update of this and all descendent objects */
+	virtual void updateFromR ();
+
 /* Is the object writable? Recurses upwards to find any locked environments/bindings TODO */
 //	virtual bool isWriteAble ();
 //	virtual bool isRemovable ();
@@ -75,19 +100,19 @@
 	void rename (const QString &new_short_name);
 	void remove (bool removed_in_workspace);
 
-	int numClasses () { return num_classes; };
-	QString getClassName (int index) { return classname[index]; };
+	unsigned int numClasses () { return num_classes; };
+	QString getClassName (int index) { return classnames[index]; };
 	QString makeClassString (const QString &sep);
 /** @param class_name the name of the class to check for
 @returns true, if the object has (among others) the given class, false otherwise */
 	bool inherits (const QString &class_name);
 
 /** get number of dimensions. For simplicity, In RKWard each object is considered to have at least one dimension (but that dimension may be 0 in length) */
-	int numDimensions () { return num_dimensions; };
+	unsigned int numDimensions () { return num_dimensions; };
 /** get the length of the given dimension. The object is guaranteed to have at least 1 dimension, so calling getDimension (0) is always safe */
-	int getDimension (int index) { return dimension[index]; };
+	int getDimension (int index) { return dimensions[index]; };
 /** short hand for getDimension (0). Meaningful for one-dimensional objects */
-	int getLength () { return dimension[0]; }
+	int getLength () { return dimensions[0]; };
 
 /** A map of objects accessible by their short name. Used in RContainerObject. Defined here for technical reasons. */
 	typedef QMap<QString, RObject*> RObjectMap;
@@ -95,8 +120,6 @@
 /** A map of values to labels. This is used both in regular objects, in which it just represents a map of named values, if any. The more important use is in factors, where it represents the factor levels. Here, the key is always a string representation of a positive integer. */
 	typedef QMap<QString, QString> ValueLabels;
 
-/** Get the data for this object from the backend. Implemented in derived classes. */
-	virtual void updateFromR () = 0;
 /** write the MetaData to the backend. Commands will be issued in the given chain */
 	virtual void writeMetaData (RCommandChain *chain);
 
@@ -141,32 +164,46 @@
 	RContainerObject *parent;
 	QString name;
 	int type;
-	int num_classes;
-	QString *classname;
-	int num_dimensions;
-	int *dimension;
+	int *dimensions;
+	unsigned int num_dimensions;
+	QString *classnames;
+	unsigned int num_classes;
 
-/** fetches the meta data from the backend. Sets of a command with the given flags. Be sure to catch this command in your rCommandDone-function and send it to handleGetMetaCommand ()! */
-	virtual void getMetaData (RCommandChain *chain, int flags);
 /** generates a (full) name for a child of this object with the given name. */
 	virtual QString makeChildName (const QString &short_child_name);
-	
+
+/** Update object to reflect the structure passed in the new_data argument. If the data is mismatching (i.e. can not be accommodated by this type of object) false is returned (calls canAccommodateStructure () internally). In this case you should delete the object, and create a new one.
+ at returns true if the changes could be done, false if this  */
+	virtual bool updateStructure (RData *new_data);
+
 	typedef QMap<QString, QString> MetaMap;
 	MetaMap *meta_map;
-	
-/** handles updating class names from an update class command given as argument (common functionality between RContainerObject and RKVariable
- at param command The command. Make sure it really is a command to update classes *before* calling this function!
- at returns true if the classes changed, false if no change resulted */
-	bool handleUpdateClassCommand (RCommand *command);
-/** handles updating the meta data from a get meta data command given as argument (common functionality between RContainerObject and RKVariable. Takes care of notifying modification tracker, if meta data has changed. Therefore no return value. Most likely you will call this function for the result of a command triggered by getMetaData ();
- at param command The command. Make sure it really is a get meta data command *before* calling this function! */
-	void handleGetMetaCommand (RCommand *command);
-/** check the type of this object, and update dimension information from a .rk.classify command given as argument. If a type mismatch is found, this returns false, and you *must* return immediately, as the object will be deleted shortly!
- at param command The command. Make sure it really is a  .rk.classify command *before* calling this function!
- at param dims_changed If the dimensions changed, this bool is set to true. If the dimensions did not change, it is left untouched (i.e. even if it already was true)
- at returns false if there was a type mismatch. In this case you *must* return! */
-	bool handleClassifyCommand (RCommand *command, bool *dims_changed);
 
+	virtual bool canAccommodateStructure (RData *new_data);
+	bool isValidName (RData *new_data);
+	bool isValidType (RData *new_data);
+
+/** handles updating the object name from the given data (common functionality between RContainerObject and RKVariable. This should really never return true, as the name should never change. Hence also raises an assert. Is still useful for it's side effect of detaching and deleting the data from the RData structure after checking it.
+ at param new_data The data. Make sure it really is the classes field of an .rk.get.structure-command to update classes *before* calling this function! WARNING: the new_data object may get changed during this call. Call canAccommodateStructure () before calling this function!
+ at returns whether this caused any changes */
+	bool updateName (RData *new_data);
+/** update type information from the given data.
+ at param new_data The command. Make sure it really is the classification field of an .rk.get.structure-command to update classes *before* calling this function! WARNING: the new_data object may get changed during this call. Call canAccommodateStructure () before calling this function!
+ at returns whether this caused any changes */
+	bool updateType (RData *new_data);
+/** handles updating class names from the given data (common functionality between RContainerObject and RKVariable
+ at param new_data The data. Make sure it really is the classes field of an .rk.get.structure-command to update classes *before* calling this function! WARNING: the new_data object may get changed during this call. Call canAccommodateStructure () before calling this function!
+ at returns whether this caused any changes */
+	bool updateClasses (RData *new_data);
+/** handles updating the meta data from the given data (common functionality between RContainerObject and RKVariable. WARNING: the new_data object may get changed during this call. Call canAccommodateStructure () before calling this function!
+ at param new_data The data. Make sure it really is the meta field of an .rk.get.structure-command to update classes *before* calling this function!
+ at returns whether this caused any changes */
+	bool updateMeta (RData *new_data);
+/** update dimension information from the given data.
+ at param new_data The command. Make sure it really is the dims field of an .rk.get.structure-command to update classes *before* calling this function! WARNING: the new_data object may get changed during this call. Call canAccommodateStructure () before calling this function!
+ at returns whether this caused any changes */
+	bool updateDimensions (RData *new_data);
+
 /** an instance of this struct is created, when the object is opened for editing. For one thing, it keeps track of which editor(s) are working on the object.
 In subclasses like RKVariable, the struct is extended to additionally hold the data of the object, etc. */
 	struct EditData {
@@ -180,6 +217,8 @@
 	virtual void initializeEditData (bool to_empty=false);
 /** see above */
 	virtual void discardEditData ();
+
+	void rCommandDone (RCommand *command);
 };
 
 typedef RObject* RObjectPtr;

Modified: trunk/rkward/rkward/core/robjectlist.cpp
===================================================================
--- trunk/rkward/rkward/core/robjectlist.cpp	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/robjectlist.cpp	2006-10-02 17:24:35 UTC (rev 789)
@@ -19,9 +19,7 @@
 #define AUTO_UPDATE_INTERVAL 10000
 #define UPDATE_DELAY_INTERVAL 500
 
-#define UPDATE_LIST_COMMAND 1
-#define CHILD_GET_TYPE_COMMAND 2
-#define LOAD_COMPLETE_COMMAND 3
+#define UPDATE_WORKSPACE_COMMAND 1
 
 #include <qtimer.h>
 #include <qstringlist.h>
@@ -51,114 +49,41 @@
 	update_chain = 0;
 }
 
-
 RObjectList::~RObjectList () {
 	RK_TRACE (OBJECTS);
 }
 
-void RObjectList::rCommandDone (RCommand *command) {
-	RK_TRACE (OBJECTS);
-
-	bool changed = false;
-
-	if (command->getFlags () == UPDATE_LIST_COMMAND) {
-		// first check, whether all known children still exist:
-		checkRemovedChildren (command->getStringVector (), command->getDataLength ());
-		
-		// next, update the existing and/or new children
-		num_children_updating = command->getDataLength ();		// TODO: is this correct? Some children might have been removed!
-		// empty workspace?
-		if (!num_children_updating) {
-			num_children_updating = 1;
-			childUpdateComplete ();
-			return;
-		}
-		for (unsigned int i = 0; i < command->getDataLength (); ++i) {
-			QString cname = command->getStringVector ()[i];		// for easier typing
-			/*if (cname == (".rk.meta")) {
-				childUpdateComplete ();
-				continue;
-			}*/
-			if (childmap.find (cname) != childmap.end ()) {
-				childmap[cname]->updateFromR ();
-			} else {
-				createFromR (this, cname);
-				changed = true;
-			}
-		}
-	} else if (command->getFlags () == CHILD_GET_TYPE_COMMAND) {
-		if (command->getDataLength () != 1) {
-			RK_ASSERT (false);
-		}
-
-		PendingObject *pobj = pending_objects[command];
-		RObject *robj;
-		// TODO: handle more special types!
-		if (command->getIntVector ()[0] == 1) {
-			robj = new RContainerObject (pobj->parent, pobj->name);
-		} else if (command->getIntVector ()[0] == 2) {
-			robj = new RFunctionObject (pobj->parent, pobj->name);
-		} else {
-			robj = new RKVariable (pobj->parent, pobj->name);
-		}
-		RK_ASSERT (robj);
-		pobj->parent->addChild (robj, pobj->name);
-		delete pobj;
-		pending_objects.remove (command);
-		RKGlobals::tracker ()->addObject (robj, 0);
-	}
-	
-	// TODO: signal change
-}
-
-QString RObjectList::listChildrenCommand () {
-	RK_TRACE (OBJECTS);
-
-	return ("ls (all.names=TRUE)");
-}
-
 void RObjectList::updateFromR () {
 	RK_TRACE (OBJECTS);
 	if (update_chain) {
 		// gee, looks like another update is still on the way. lets schedule one for later:
 		update_timer->start (UPDATE_DELAY_INTERVAL, true);
-		RK_DO (qDebug ("another object-list update is already running (%d children still updating). Rescheduling a further update for later", num_children_updating), OBJECTS, DL_DEBUG);
+		RK_DO (qDebug ("another object-list update is already running. Rescheduling a further update for later"), OBJECTS, DL_DEBUG);
 		return;
 	}
 
 	emit (updateStarted ());
 	update_chain = RKGlobals::rInterface ()->startChain (0);
 
-	RCommand *command = new RCommand (listChildrenCommand (), RCommand::App | RCommand::Sync | RCommand::GetStringVector, QString::null, this, UPDATE_LIST_COMMAND);
+	RCommand *command = new RCommand (".rk.get.environment.structure (as.environment (\".GlobalEnv\"))", RCommand::App | RCommand::Sync | RCommand::GetStructuredData, QString::null, this, ROBJECT_UDPATE_STRUCTURE_COMMAND);
 	RKGlobals::rInterface ()->issueCommand (command, update_chain);
 }
 
- void RObjectList::createFromR (RContainerObject *parent, const QString &cname) {
+bool RObjectList::updateStructure (RData *new_data) {
 	RK_TRACE (OBJECTS);
- 	PendingObject *obj = new PendingObject;
-	obj->name = cname;
-	obj->parent = parent;
-	
-	QString fullname = parent->makeChildName (cname);
+	RK_ASSERT (new_data->getDataType () == RData::StructureVector);
 
-	RCommand *command = new RCommand (".rk.get.type (" + fullname + ")", RCommand::App | RCommand::Sync | RCommand::GetIntVector, QString::null, this, CHILD_GET_TYPE_COMMAND);
-	pending_objects.insert (command, obj);
-	RKGlobals::rInterface ()->issueCommand (command, update_chain);
-}
+//	if (!RObject::updateStructure (new_data)) return false;		// this is the workspace object. nothing to update
+	updateChildren (new_data);		// children are directly in the structure
 
-void RObjectList::childUpdateComplete () {
-	RK_TRACE (OBJECTS);
-	RK_ASSERT (num_children_updating);
-	if ((--num_children_updating) <= 0) {
-		RK_TRACE (OBJECTS);
+	RK_ASSERT (update_chain);
+	RKGlobals::rInterface ()->closeChain (update_chain);
+	update_chain = 0;
 
-		RK_ASSERT (update_chain);
-		RKGlobals::rInterface ()->closeChain (update_chain);
-		update_chain = 0;
+	RK_DO (qDebug ("object list update complete"), OBJECTS, DL_DEBUG);
+	emit (updateComplete ());
 
-		RK_DO (qDebug ("object list update complete"), OBJECTS, DL_DEBUG);
-		emit (updateComplete ());
-	}
+	return true;
 }
 
 void RObjectList::timeout () {

Modified: trunk/rkward/rkward/core/robjectlist.h
===================================================================
--- trunk/rkward/rkward/core/robjectlist.h	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/core/robjectlist.h	2006-10-02 17:24:35 UTC (rev 789)
@@ -46,47 +46,35 @@
 
 	void updateFromR ();
 	
-	void createFromR (RContainerObject *parent, const QString &cname);
-	
 	QString getFullName () { return QString::null; };
 	QString makeChildName (const QString &short_child_name) { return short_child_name; };
 	/** reimplemented from RContainerObject: do nothing. The object-list has no meta data. */
 	void writeMetaData (RCommandChain *) {};
 	
 	RCommandChain *getUpdateCommandChain () { return update_chain; };
-	
-	void childUpdateComplete ();
-	QString listChildrenCommand ();
 
 	KURL getWorkspaceURL () { return current_url; };
 public slots:
 	void timeout ();
 signals:
-/// emitted when the list of objects is about to be updated
+/// emitted when the list of objects is about to be updated	// TODO: remove me
 	void updateStarted ();
-/// emitted when the list of objects has been updated
+/// emitted when the list of objects has been updated	// TODO: remove me
 	void updateComplete ();
 protected:
-	void rCommandDone (RCommand *command);
 /// reimplemented from RContainerObject to call "remove (objectname)" instead of "objectname <- NULL"
 	void renameChild (RObject *object, const QString &new_name);
 /// reimplemented from RContainerObject to call "remove (objectname)" instead of "objectname <- NULL"
 	void removeChild (RObject *object, bool removed_in_workspace);
 /// reimplemented from RContainerObject to emit a change signal
 	void objectsChanged ();
+	bool updateStructure (RData *new_data);
 private:
 	friend class RKLoadAgent;
 	friend class RKSaveAgent;
 	void setWorkspaceURL (const KURL &url) { current_url = url; };
 	QTimer *update_timer;
 	
-	struct PendingObject {
-		QString name;
-		RContainerObject *parent;
-	};
-	
-	QMap<RCommand*, PendingObject*> pending_objects;
-	
 	RCommandChain *update_chain;
 
 	KURL current_url;

Modified: trunk/rkward/rkward/misc/rkobjectlistview.cpp
===================================================================
--- trunk/rkward/rkward/misc/rkobjectlistview.cpp	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/misc/rkobjectlistview.cpp	2006-10-02 17:24:35 UTC (rev 789)
@@ -152,7 +152,7 @@
 
 	RKListViewItem *parent = findObjectItem (object->getContainer ());
 	RK_ASSERT (parent);
-	addObject (parent, object, false);
+	addObject (parent, object, true);
 	
 	if (update_in_progress) {
 		changes = true;
@@ -181,6 +181,7 @@
 
 	RKListViewItem *item = findObjectItem (object);
 	RK_ASSERT (item);
+	qDebug (object->getFullName ().latin1 ());
 	updateItem (item, object);
 
 	if (update_in_progress) {

Modified: trunk/rkward/rkward/rbackend/rdata.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rdata.cpp	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/rbackend/rdata.cpp	2006-10-02 17:24:35 UTC (rev 789)
@@ -31,6 +31,34 @@
 RData::~RData () {
 	RK_TRACE (RBACKEND);
 
+	discardData ();
+}
+
+double *RData::getRealVector () {
+	return (static_cast<double *> (data));
+}
+
+int *RData::getIntVector () {
+	return (static_cast<int *> (data));
+}
+
+QString *RData::getStringVector () {
+	return (static_cast<QString *> (data));
+}
+
+RData **RData::getStructureVector () {
+	return (static_cast<RData **> (data));
+}
+
+void RData::detachData () {
+	data = 0;
+	length = 0;
+	datatype = NoData;
+}
+
+void RData::discardData () {
+	RK_TRACE (RBACKEND);
+
 	if (datatype == StructureVector) {
 		RData **sdata = getStructureVector ();
 		for (int i=length-1; i >= 0; --i) {
@@ -49,42 +77,10 @@
 	} else {
 		RK_ASSERT (datatype == NoData);
 	}
-}
 
-double *RData::getRealVector () {
-	if (datatype == RealVector) return (static_cast<double *> (data));
-
-	RK_ASSERT (false);
-	return 0;
+	detachData ();
 }
 
-int *RData::getIntVector () {
-	if (datatype == IntVector) return (static_cast<int *> (data));
-
-	RK_ASSERT (false);
-	return 0;
-}
-
-QString *RData::getStringVector () {
-	if (datatype == StringVector) return (static_cast<QString *> (data));
-
-	RK_ASSERT (false);
-	return 0;
-}
-
-RData **RData::getStructureVector () {
-	if (datatype == StructureVector) return (static_cast<RData **> (data));
-
-	RK_ASSERT (false);
-	return 0;
-}
-
-void RData::detachData () {
-	data = 0;
-	length = 0;
-	datatype = NoData;
-}
-
 void RData::setData (RData *from) {
 	data = from->data;
 	length = from->length;

Modified: trunk/rkward/rkward/rbackend/rdata.h
===================================================================
--- trunk/rkward/rkward/rbackend/rdata.h	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/rbackend/rdata.h	2006-10-02 17:24:35 UTC (rev 789)
@@ -25,11 +25,11 @@
 	RData ();
 	~RData ();
 	enum RDataType {
-		StructureVector,
-		IntVector,
-		RealVector,
-		StringVector,
-		NoData
+		StructureVector=0,
+		IntVector=1,
+		RealVector=2,
+		StringVector=3,
+		NoData=4
 	};
 
 /** returns the type of data contained */
@@ -46,6 +46,7 @@
 	RData **getStructureVector ();
 /** The data contained in the RData structure is owned by RData, and will usually be deleted at the end of the lifetime of the RData object. If you want to keep the data, call detachData () to prevent this deletion. You will be responsible for deletion of the data yourself. */
 	void detachData ();
+	void discardData ();
 
 /** public for technical reasons only. Do not use! Copy data from the given RData, and discard it */
 	void setData (RData *from);

Modified: trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R
===================================================================
--- trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R	2006-10-01 23:00:23 UTC (rev 788)
+++ trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R	2006-10-02 17:24:35 UTC (rev 789)
@@ -14,7 +14,7 @@
 ".rk.editor.closed" <- function (x) {
 	if (exists (".rk.editing")) .rk.editing <<- .rk.editing[.rk.editing != deparse (substitute (x))]
 }
-
+#TODO: remove:
 ".rk.classify" <- function (x) {
 	type <- 0
 	if (is.data.frame (x)) type = type + 1
@@ -23,12 +23,13 @@
 	if (is.list (x)) type = type + 8
 	if (type != 0) type = type + 16 else type = 32
 	if (is.function (x)) type = 128
-	if (!is.null (attr (x, ".rk.meta"))) type = type + 256
+	if (is.environment (x)) type = 256
+	if (!is.null (attr (x, ".rk.meta"))) type = type + 2048
 	d <- dim (x)
 	if (length (d) < 1) d <- length (x);	# handling for objects that according to R do not have a dimension (such as vectors, functions, etc.)
 	c (type, d)
 }
-
+#TODO: remove:
 ".rk.get.type" <- function (x) {
 	if (is.data.frame (x) || is.matrix (x) || is.array (x) || is.list (x)) return (1)		# container
 	if (is.function (x)) return (2)		# function
@@ -269,3 +270,76 @@
 
 	invisible (TRUE)
 }
+
+".rk.get.structure" <- function (x, name) {
+	fun <- FALSE
+	cont <- FALSE
+	type <- 0
+
+# Do not change the order! Make sure all fields exist, even if empty
+	ret = list ()
+
+# 1: name should always be first
+	ret$name <- as.character (name)
+
+# 2: classification
+	if (is.data.frame (x)) type = type + 1
+	if (is.matrix (x)) type = type + 2
+	if (is.array (x)) type = type + 4
+	if (is.list (x)) type = type + 8
+	if (type != 0) {
+		type = type + 16
+		cont <- TRUE
+	} else type = 32
+	if (is.function (x)) {
+		fun <- TRUE
+		type = 128
+	}
+	if (is.environment (x)) type = 256
+	if (!is.null (attr (x, ".rk.meta"))) type = type + 2048
+	ret$type <- as.integer (type)
+
+# 3: classes
+	ret$classes <- class (x)
+	if (is.null (ret$classes)) ret$classes = ""
+
+# 4: meta info
+	ret$meta <- .rk.get.meta (x)
+	if (is.null (ret$meta)) ret$meta <- ""
+
+# 5: dimensionality
+	ret$dims <- dim(x)
+	if (is.null (ret$dims)) ret$dims <- length (x)	# handling for objects that - according to R - do not have a dimension (such as vectors, functions, etc.)
+	if (is.null (ret$dims)) ret$dims <- 0	# according to help ("length"), we need to play safe
+	ret$dims <- as.integer (ret$dims)
+
+# 6: Special info valid for some objects ony. This should always be last in the returned structure, as the number of fields may vary
+	if (cont) {		# a container
+		nms <- names (x)
+		if (!is.null (nms)) {
+			i <- 0
+			sub <- list ()
+			for (child in x) {
+				i <- i+1
+				sub[[nms[i]]] <- .rk.get.structure (child, nms[i])
+			}
+			ret$sub <- sub
+		}
+	} else if (fun) {	# a function
+		ret$argnames <- as.character (names (formals (x)))
+		ret$argvalues <- as.character (formals (x))
+	}
+
+	ret
+}
+
+".rk.get.environment.structure" <- function (x) {
+	ret <- list ()
+
+	lst <- ls (x, all.names=TRUE)
+	for (childname in lst) {
+		ret[[childname]] <- .rk.get.structure (get (childname, envir=x), childname)
+	}
+
+	ret
+}


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