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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Wed Oct 11 15:18:53 UTC 2006


Revision: 846
          http://svn.sourceforge.net/rkward/?rev=846&view=rev
Author:   tfry
Date:     2006-10-11 08:18:31 -0700 (Wed, 11 Oct 2006)

Log Message:
-----------
Intermediate commit (totally broken, use previous revision instead): Change storage mode of RKVariable

Modified Paths:
--------------
    trunk/rkward/ChangeLog
    trunk/rkward/TODO
    trunk/rkward/rkward/agents/rkloadagent.cpp
    trunk/rkward/rkward/agents/rkloadagent.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/dataeditor/editformatdialog.cpp
    trunk/rkward/rkward/dataeditor/twintablemetamember.cpp
    trunk/rkward/rkward/misc/rkobjectlistview.cpp
    trunk/rkward/rkward/plugin/rkcomponentproperties.cpp
    trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R

Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/ChangeLog	2006-10-11 15:18:31 UTC (rev 846)
@@ -1,3 +1,4 @@
+- storage mode for RKWard meta data was changed -> TODO
 - RMB option to search help on objects from packages in object browser
 - show tooltip information on objects in object browser
 - do not crash on call to "browser ()"

Modified: trunk/rkward/TODO
===================================================================
--- trunk/rkward/TODO	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/TODO	2006-10-11 15:18:31 UTC (rev 846)
@@ -74,6 +74,7 @@
 			- Invalid values are stored in a list in an attribute of the variable in question
 			- The corresponding "real" fields are set to NA
 			- Need to add a conversion script. See .rk.get.meta (). Both should be changed at the same time.
+				- Not really, it's already broken, currently, after save / reload
 	- maybe we can do stuff like auto-printing, (toplevel handlers: no, not those, they are not called in R_ReplDLLdo1 ()), syntax error information by using R_ReplDLLdo1 () for user/console commands. The command-text would be fed in via R_ReadConsole (would need to keep a buffer).
 			- How to differentiate readline calls to get new command data from readline calls to get user info?! The prompt may not be realiable enough. Is there other info?
 				- the hist parameter may be a hint, but is also set in do_browser
@@ -95,6 +96,7 @@
 				(object list remains the same, watch was not active, but symbol changed)
 				- will need to put an extra notification inside .rk.watch.globalenv ()? Will that get run?
 			- deal with data changes in edited objects
+			- object (list) updates should be run in a substack to ensure they are done in time
 	- RExpressionObject as an abstraction for R-Expressions (i.e. manually edited expressions).
 		- 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)

Modified: trunk/rkward/rkward/agents/rkloadagent.cpp
===================================================================
--- trunk/rkward/rkward/agents/rkloadagent.cpp	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/agents/rkloadagent.cpp	2006-10-11 15:18:31 UTC (rev 846)
@@ -54,12 +54,7 @@
 	command = new RCommand ("load (\"" + url.path () + "\")", RCommand::App | RCommand::ObjectListUpdate, QString::null, this, WORKSPACE_LOAD_COMMAND);
 	RKGlobals::rInterface ()->issueCommand (command);
 
-	connect (RObjectList::getObjectList (), SIGNAL (updateComplete ()), this, SLOT (listUpdateComplete ()));
-	
 	RObjectList::getObjectList ()->setWorkspaceURL (url);
-
-	RKWorkplace::mainWorkplace ()->restoreWorkplace ();
-	RKWorkplace::mainWorkplace ()->clearWorkplaceDescription ();
 }
 
 RKLoadAgent::~RKLoadAgent () {
@@ -74,16 +69,18 @@
 		if (command->failed ()) {
 			KMessageBox::error (0, i18n ("There has been an error opening file '%1':\n%2").arg (RObjectList::getObjectList ()->getWorkspaceURL ().path ()).arg (command->error ()), i18n ("Error loading workspace"));
 			RObjectList::getObjectList ()->setWorkspaceURL (QString::null);
+		} else {
+			RKWorkplace::mainWorkplace ()->restoreWorkplace ();
+			RKWorkplace::mainWorkplace ()->clearWorkplaceDescription ();
 		}
 		RKwardApp::getApp ()->slotSetStatusReady ();
 		RKwardApp::getApp ()->setCaption (QString::null);	// trigger update of caption
+
+		delete this;
+		return;
+	} else {
+		RK_ASSERT (false);
 	}
 }
 
-void RKLoadAgent::listUpdateComplete () {
-	RK_TRACE (APP);
-
-	delete this;
-}
-
 #include "rkloadagent.moc"

Modified: trunk/rkward/rkward/agents/rkloadagent.h
===================================================================
--- trunk/rkward/rkward/agents/rkloadagent.h	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/agents/rkloadagent.h	2006-10-11 15:18:31 UTC (rev 846)
@@ -33,8 +33,6 @@
 	RKLoadAgent (const KURL &url, bool merge=false);
 
 	~RKLoadAgent ();
-public slots:
-	void listUpdateComplete ();
 protected:
 	void rCommandDone (RCommand *command);
 private:

Modified: trunk/rkward/rkward/core/rkvariable.cpp
===================================================================
--- trunk/rkward/rkward/core/rkvariable.cpp	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/core/rkvariable.cpp	2006-10-11 15:18:31 UTC (rev 846)
@@ -27,9 +27,7 @@
 #include "../rkglobals.h"
 #include "rkmodificationtracker.h"
 
-#define GET_STORAGE_MODE_COMMAND 10
 #define GET_DATA_COMMAND 11
-#define GET_FACTOR_LEVELS_COMMAND 12
 
 #define MAX_PRECISION DBL_DIG
 
@@ -41,22 +39,16 @@
 RKVariable::RKVariable (RContainerObject *parent, const QString &name) : RObject (parent, name) {
 	RK_TRACE (OBJECTS);
 	type = Variable;
-	var_type = Unknown;
 }
 
 RKVariable::~RKVariable () {
 	RK_TRACE (OBJECTS);
 }
 
-QString RKVariable::getVarTypeString () {
+void RKVariable::setVarType (RObject::RDataType new_type, bool sync) {
 	RK_TRACE (OBJECTS);
-	return RObject::typeToText (var_type);
-}
 
-void RKVariable::setVarType (RObject::VarType new_type, bool sync) {
-	RK_TRACE (OBJECTS);
-
-	if (var_type == new_type) {
+	if (getDataType () == new_type) {
 		// of course this is not harmful in any way, but in order to catch this kind of use, we raise an assert here for now.
 		RK_ASSERT (false);
 		return;
@@ -71,7 +63,7 @@
 		for (int i=0; i < getLength (); ++i) {
 			list.append (getText (i));
 		}
-		var_type = new_type;
+		setDataType (new_type);
 		int i = 0;
 		for (QStringList::const_iterator it = list.constBegin (); it != list.constEnd (); ++it) {
 			setText (i, *it);
@@ -82,7 +74,7 @@
 		}
 		setSyncing (internal_sync);
 	} else {
-		var_type = new_type;
+		setDataType (new_type);
 	}
 
 	setMetaProperty ("type", QString ().setNum ((int) new_type), sync);
@@ -100,26 +92,16 @@
 	
 	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);
-		if (!(command->getIntVector ()[1])) {
-			RKGlobals::rInterface ()->issueCommand ("levels (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetStringVector, QString::null, this, GET_FACTOR_LEVELS_COMMAND);
-			if (getVarType () == Unknown) {
-				var_type = Factor;
-			}
-		}
+	} else if (command->getFlags () == GET_INVALID_FIELDS_COMMAND) {
+		#warning TODO
+
 		int command_type = RCommand::App | RCommand::Sync;
-		if (command->getIntVector ()[0]) {
+		if (getDataType () == DataNumeric) {
 			command_type |= RCommand::GetRealVector;
-			if (getVarType () == Unknown) {
-				var_type = Number;
-			}
+		} else if (getDataType () == DataFactor) {
+			#warning TODO
 		} else {
 			command_type |= RCommand::GetStringVector;
-			if (getVarType () == Unknown) {
-				var_type = String;
-			}
 		}
 		RKGlobals::rInterface ()->issueCommand (getFullName (), command_type, QString::null, this, GET_DATA_COMMAND);
 	} else if (command->getFlags () == GET_DATA_COMMAND) {
@@ -160,8 +142,6 @@
 #define ALLOC_STEP 2
 #define INITIAL_ALLOC 100
 
-#define RECHECK_VALID { if ((!myData ()->invalid_count) && (!myData ()->previously_valid)) restoreStorageInBackend (); }
-
 void RKVariable::setLength (int len) {
 	RK_TRACE (OBJECTS);
 	RK_ASSERT (!getLength ());	// should only be called once
@@ -170,29 +150,6 @@
 	dimensions[0] = len;
 }
 
-void RKVariable::restoreStorageInBackend () {
-	RK_TRACE (OBJECTS);
-	RK_ASSERT (myData ());
-	
-	if (getVarType () == Number) {
-		RKGlobals::rInterface ()->issueCommand ("mode (" + getFullName () + ") <- \"numeric\"", RCommand::App | RCommand::Sync);
-	} else if (getVarType () == Factor) {
-		RKGlobals::rInterface ()->issueCommand ("rk.restore.factor (" + getFullName () + ")", RCommand::App | RCommand::Sync);
-	}
-}
-
-void RKVariable::deleteStringData (int row) {
-	RK_ASSERT (myData ());
-
-	if (myData ()->cell_string_data[row] && (myData ()->cell_string_data[row] != na_char) && (myData ()->cell_string_data[row] != unknown_char)) {
-		delete myData ()->cell_string_data[row];
-		if (getVarType () != String) {
-			myData ()->invalid_count--;
-		}
-	}
-	myData ()->cell_string_data[row] = 0;
-}
-
 // virtual
 void RKVariable::allocateEditData () {
 	RK_TRACE (OBJECTS);
@@ -201,15 +158,15 @@
 	RK_ASSERT (!myData ());
 	
 	data = new RKVarEditData;
-	myData ()->cell_double_data = 0;
-	myData ()->cell_string_data = 0;
+	myData ()->cell_data = 0;
+	myData ()->cell_states = 0;
 	myData ()->allocated_length = 0;
 	myData ()->immediate_sync = true;
 	myData ()->changes = 0;
-	myData ()->invalid_count = 0;
 	myData ()->value_labels = 0;
 	myData ()->formatting_options = 0;
 	myData ()->previously_valid = true;
+	myData ()->invalid_fields.setAutoDelete (true);
 	
 	extendToLength (getLength ());
 }
@@ -221,11 +178,10 @@
 	
 	if (to_empty) {
 		for (int row=0; row < getLength (); ++row) {
-			myData ()->cell_string_data[row] = na_char;
-			myData ()->cell_double_data[row] = RKGlobals::na_double;
+			myData ()->cell_states[row] = Unknown;
 		}
 	} else {
-		RKGlobals::rInterface ()->issueCommand ("c (is.numeric (" + getFullName () + "), is.null (levels (" + getFullName () + ")))", RCommand::App | RCommand::Sync | RCommand::GetIntVector, QString::null, this, GET_STORAGE_MODE_COMMAND);
+		RKGlobals::rInterface ()->issueCommand (".rk.get.vector.data (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetStructuredData, QString::null, this, GET_DATA_COMMAND);
 		myData ()->formatting_options = parseFormattingOptionsString (getMetaProperty ("format"));
 	}
 }
@@ -283,9 +239,17 @@
 	writeData (0, getLength () - 1, chain);
 	delete myData ()->changes;
 	writeMetaData (chain);
-	if (getVarType () == Factor) {
-		RKGlobals::rInterface ()->issueCommand ("rk.restore.factor (" + getFullName () + ")", RCommand::App | RCommand::Sync, QString::null, 0, 0, chain);
+}
+
+void RKVariable::writeInvalidField (int row, RCommandChain *chain) {
+	RK_TRACE (OBJECTS);
+
+	if (myData ()->invalid_fields[row]) {
+		RKGlobals::rInterface ()->issueCommand (".rk.set.invalid.field (" + getFullName () + ", " + QString::number (row+1) + ", " + rQuote (*(myData ()->invalid_fields[row])) + ")", RCommand::App | RCommand::Sync, QString::null, 0,0, chain);
+	} else {
+		RKGlobals::rInterface ()->issueCommand (".rk.set.invalid.field (" + getFullName () + ", " + QString::number (row+1) + ", NULL)", RCommand::App | RCommand::Sync, QString::null, 0,0, chain);
 	}
+	myData ()->invalid_fields_not_synced.remove (row);
 }
 
 void RKVariable::writeData (int from_row, int to_row, RCommandChain *chain) {
@@ -295,6 +259,7 @@
 	// TODO: try to sync in correct storage mode
 	if (from_row == to_row) {
 		RKGlobals::rInterface ()->issueCommand (getFullName () + "[" + QString::number (from_row+1) + "] <- " + getRText (from_row), RCommand::App | RCommand::Sync, QString::null, 0,0, chain);
+		if (myData ()->invalid_fields_not_synced[from_row] != 0) writeInvalidField (from_row, chain);
 	} else {
 		QString data_string = "c (";
 		for (int row = from_row; row <= to_row; ++row) {
@@ -303,6 +268,7 @@
 			if (row != to_row) {
 				data_string.append (", ");
 			}
+			if (myData ()->invalid_fields_not_synced[row] != 0) writeInvalidField (row, chain);
 		}
 		data_string.append (")");
 		RKGlobals::rInterface ()->issueCommand (getFullName () + "[" + QString::number (from_row + 1) + ":" + QString::number (to_row + 1) + "] <- " + data_string, RCommand::App | RCommand::Sync, QString::null, 0,0, chain);
@@ -323,7 +289,6 @@
 		if ((myData ()->changes->from_index > row) || (myData ()->changes->from_index == -1)) myData ()->changes->from_index = row;
 		if (myData ()->changes->to_index < row) myData ()->changes->to_index = row;
 	}
-	RECHECK_VALID
 }
 
 void RKVariable::cellsChanged (int from_row, int to_row) {
@@ -335,7 +300,6 @@
 		if ((myData ()->changes->from_index > from_row) || (myData ()->changes->from_index == -1)) myData ()->changes->from_index = from_row;
 		if (myData ()->changes->to_index < to_row) myData ()->changes->to_index = to_row;
 	}
-	RECHECK_VALID
 }
 
 void RKVariable::extendToLength (int length) {
@@ -395,10 +359,12 @@
 		RK_ASSERT (false);
 		return (*unknown_char);
 	}
-	if (getVarType () == String) {
+	if (getDataType () == DataCharacter) {
 		return (*(myData ()->cell_string_data[row]));
 	} else {
-		if (myData ()->cell_string_data[row] != 0) {
+		if (myData ()->invalid_fields[row] != 0) {
+			return (*(myData ()->invalid_fields[row]));
+		} else if (myData ()->cell_string_data[row] != 0) {
 			return (*(myData ()->cell_string_data[row]));
 		} else {
 			return QString::number (myData ()->cell_double_data[row], 'g', MAX_PRECISION);
@@ -411,11 +377,11 @@
 	
 	Status cell_state = cellStatus (row);
 	
-	if (cell_state == ValueUnused) {
+	if ((cell_state == ValueUnused) || (cell_state == ValueInvalid)) {
 		return ("NA");
-	} else if (getVarType () == Factor) {
+	} else if (getDataType () == DataFactor) {
 		return (rQuote (getLabeled (row)));
-	} else if ((getVarType () == String) || (cell_state == ValueInvalid)) {
+	} else if (getDataType () == DataCharacter) {
 		return (rQuote (getText (row)));
 	} else {
 		return (QString::number (myData ()->cell_double_data[row], 'g', MAX_PRECISION));
@@ -425,24 +391,26 @@
 void RKVariable::setText (int row, const QString &text) {
 	RK_TRACE (OBJECTS);
 	RK_ASSERT (row < getLength ());
+
 	// delete previous string data, unless it's a special value
+	bool was_invalid = (myData ()->invalid_fields[row] != 0); 
 	deleteStringData (row);
+	if (was_invalid) myData ()->invalid_fields_not_synced.replace (row, (int *) 1);
 
-	if (getVarType () == String) {
+	if (getDataType () == DataCharacter) {
 		if (text.isNull ()) {
 			myData ()->cell_string_data[row] = na_char;
 		} else {
 			myData ()->cell_string_data[row] = new QString (text);
 		}
-	} else if (getVarType () == Factor) {
+	} else if (getDataType () == DataFactor) {
 		if (text.isEmpty ()) {
 			myData ()->cell_string_data[row] = na_char;
 		} else if (myData ()->value_labels && myData ()->value_labels->contains (text)) {
 			myData ()->cell_double_data[row] = text.toInt ();
 		} else {
-			myData ()->invalid_count++;
-			myData ()->previously_valid = false;
-			myData ()->cell_string_data[row] = new QString (text);
+			myData ()->invalid_fields.replace (row, new QString (text));
+			myData ()->invalid_fields_not_synced.replace (row, (int *) 1);
 		}
 	} else {
 		bool ok;
@@ -451,9 +419,8 @@
 			if (text.isEmpty ()) {
 				myData ()->cell_string_data[row] = na_char;
 			} else {
-				myData ()->invalid_count++;
-				myData ()->previously_valid = false;
-				myData ()->cell_string_data[row] = new QString (text);
+				myData ()->invalid_fields.replace (row, new QString (text));
+				myData ()->invalid_fields_not_synced.replace (row, (int *) 1);
 			}
 		}
 	}
@@ -473,10 +440,12 @@
 		}
 	}
 
-	if (getVarType () == String) {
+	if (getDataType () == DataCharacter) {
 		return (*(myData ()->cell_string_data[row]));
 	} else {
-		if (myData ()->cell_string_data[row] != 0) {
+		if (myData ()->invalid_fields[row] != 0) {
+			return (*(myData ()->invalid_fields[row]));
+		} else if (myData ()->cell_string_data[row] != 0) {
 			return (*(myData ()->cell_string_data[row]));
 		} else {
 			if (myData ()->formatting_options && (myData ()->formatting_options->precision_mode != FormattingOptions::PrecisionDefault)) {
@@ -526,13 +495,13 @@
 		deleteStringData (row);
 	}
 	
-	if (getVarType () == String) {
+	if (getDataType () == DataCharacter) {
 		RK_ASSERT (false);		// asserting false to catch cases of this use for now. it's not really a problem, though
 		int i = 0;
 		for (int row=from_row; row <= to_row; ++row) {
 			myData ()->cell_string_data[row] = new QString (QString::number (data[i++], 'g', MAX_PRECISION));
 		}
-	} else if (getVarType () == Factor) {
+	} else if (getDataType () == DataFactor) {
 		int i = 0;
 		for (int row=from_row; row <= to_row; ++row) {
 			setText (row, QString::number (data[i++], 'g', MAX_PRECISION));
@@ -558,11 +527,7 @@
 	
 	int i = 0;
 	for (int row = from_row; row <= to_row; ++row) {
-		if (myData ()->cell_string_data[row]) {
-			ret[i] = *(myData ()->cell_string_data[row]);
-		} else {
-			ret[i] = getText (row).local8Bit ();
-		}
+		ret[i] = getText (row);
 		i++;
 	}
 
@@ -572,7 +537,7 @@
 void RKVariable::setCharacter (int from_row, int to_row, QString *data) {
 	RK_ASSERT (to_row < getLength ());
 	
-	if (getVarType () == String) {
+	if (getDataType () == DataCharacter) {
 		int i=0;
 		for (int row=from_row; row <= to_row; ++row) {
 #warning inefficient
@@ -607,7 +572,7 @@
 		return ValueUnused;
 	} else if (myData ()->cell_string_data[row] == unknown_char) {
 		return ValueUnknown;
-	} else if ((getVarType () != String) && (myData ()->cell_string_data[row] != 0)) {
+	} else if ((getDataType () != DataCharacter) && (myData ()->invalid_fields[row] != 0)) {
 		return ValueInvalid;
 	}
 	return ValueValid;
@@ -625,10 +590,6 @@
 		deleteStringData (row);
 	}
 
-	for (int row=from_row; row <= to_row; ++row) {
-		if (cellStatus (row) == ValueInvalid) myData ()->invalid_count--;
-	}
-	
 	if (to_row < (myData ()->allocated_length - 1)) {	// not the last rows
 		qmemmove (&(myData ()->cell_string_data[from_row]), &(myData ()->cell_string_data[to_row+1]), (myData ()->allocated_length - to_row - 1) * sizeof (QString*));
 		qmemmove (&(myData ()->cell_double_data[from_row]), &(myData ()->cell_double_data[to_row+1]), (myData ()->allocated_length - to_row - 1) * sizeof (double));
@@ -641,7 +602,6 @@
 
 	dimensions[0] -= (to_row - from_row) + 1;	
 	downSize ();
-	RECHECK_VALID
 }
 
 void RKVariable::insertRow (int row) {
@@ -892,7 +852,7 @@
 		return AlignCellRight;
 	} else {
 	// TODO: use global (configurable) defaults, if not specified
-		if ((getVarType () == String) || (getVarType () == Factor)) {
+		if ((getDataType () == DataCharacter) || (getDataType () == DataFactor)) {
 			return AlignCellLeft;
 		} else {
 			return AlignCellRight;

Modified: trunk/rkward/rkward/core/rkvariable.h
===================================================================
--- trunk/rkward/rkward/core/rkvariable.h	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/core/rkvariable.h	2006-10-11 15:18:31 UTC (rev 846)
@@ -18,6 +18,7 @@
 #define RKVARIABLE_H
 
 #include <qstring.h>
+#include <qintdict.h>
 
 #include "robject.h"
 
@@ -39,19 +40,12 @@
 
 	~RKVariable ();
 
-/** The VarType in String representation */
-	QString getVarTypeString ();
-/** The VarType of this variable. Note: This is only the preferred VarType. In R the variable may be stored differently, if it contains illegal values (in that
-case it will be stored as a character vector */
-	RObject::VarType getVarType () { return var_type; };
-/** set the VarType. If sync, the change will be communicated to the backend immediately. See getVarType */
-	void setVarType (RObject::VarType, bool sync=true);
+/** set the VarType. If sync, the change will be communicated to the backend immediately. See RObject::RDataType */
+	void setVarType (RObject::RDataType, bool sync=true);
 
 /** reimplemented from RObject to also store value labels/factor levels (and in the future probably futher info) */
 	void writeMetaData (RCommandChain *chain);
 friend class RContainerObject;
-	RObject::VarType var_type;
-	
 	void rCommandDone (RCommand *command);
 public:
 ////////////// BEGIN: data handling ////////////////////////
@@ -80,11 +74,11 @@
 /** get the text in pretty form, e.g. rounding numbers to a certain number of digits, replacing numeric values with value labels if available, etc. Formatting is done according to the meta-information stored in the RObject and global user preferences */
 	QString getFormatted (int row);
 /** get a copy of the numeric values of rows starting from from_index, going to to_index. Do not use this before making sure that the rStorage () is really
-numeric! */
+numeric!  TODO: unused  */
 	double *getNumeric (int from_row, int to_row);
 /** set numeric values in the given range. Assumes you provide enough values for the range. If internalStorage is String, all values will be converted to strings, so you should use this function only, if you know you are dealing with a numeric object */
 	void setNumeric (int from_row, int to_row, double *data);
-/** like getNumeric, but returns values as an array of QString*s. */
+/** like getNumeric, but returns values as an array of QString*s. TODO: unused */
 	QString *getCharacter (int from_row, int to_row);
 /** like setNumeric, but sets chars. If internalStorage () is numeric, attempts to convert the given strings to numbers. I.e. the function behaves essentially like setText (), but operates on a range of cells. */
 	void setCharacter (int from_row, int to_row, QString *data);
@@ -150,25 +144,30 @@
 protected:
 /** Extended from RObject::EditData to actually contain data. */
 	struct RKVarEditData : public EditData {
-/// array of numeric data for the cells.
-		double *cell_double_data;
-/** array of string data for the cells.
-Why is this an array of Qstring* instead of just of QString? The reason is that we need to differentiate three special strings: 1) empty 2) NA 3) unknown / unused. QString.isNull () vs. QString.isEmpty () would buy us two, but that's not enough, unfortunately. */
-		QString **cell_string_data;
-/// the currently allocated length of cell_double_data of cell_string_data. Used to determine, when a re-allocation is required
+		void *cell_data;
+		enum CellState {
+			Unknown=0,
+			Invalid=1,
+			NA=2,
+			Valid=4,
+			UnsyncedInvalidState=4
+		};
+		CellState *cell_states;
+
+/// the currently allocated length of cell_data and cell_states. Used to determine, when a re-allocation is required
 		int allocated_length;
 /// see setSyncing
 		bool immediate_sync;
 /// stores changes if syncing is not immediate
 		ChangeSet *changes;
-/// number of invalid entries
-		int invalid_count;
 /// stores whether there were preivously invalid cells. If so, and there are no longer, now, we may change the mode in the backend.
 		bool previously_valid;
 /// the value-labels or factor levels assigned to this variable. 0 if no values/levels given
 		ValueLabels *value_labels;
 /// the formatting options set for this var (see FormattingOptions) */
 		FormattingOptions *formatting_options;
+/// storage for invalid fields
+		QIntDict<QString> invalid_fields;
 	};
 /** reimplemented from RObject */
 	void allocateEditData ();
@@ -189,10 +188,7 @@
 	void cellsChanged (int from_row, int to_row);
 /** writes the given range of cells to the backend (regardless of whether syncing should be immediate) */
 	void writeData (int from_row, int to_row, RCommandChain *chain=0);
-/** deletes the string data for the given cell */
-	void deleteStringData (int row);
-/** called if a variable was invalid (and therefore stored in a wrong mode in the R backend) and is now valid again. Restores the storage mode in the backend. */
-	void restoreStorageInBackend ();
+	void writeInvalidField (int row, RCommandChain *chain=0);
 /** writes the values labels to the backend */
 	void writeValueLabels (RCommandChain *chain);
 /** creates/parses formatting options from the stored meta-property string. See also: getFormattingOptions () */

Modified: trunk/rkward/rkward/core/robject.cpp
===================================================================
--- trunk/rkward/rkward/core/robject.cpp	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/core/robject.cpp	2006-10-11 15:18:31 UTC (rev 846)
@@ -221,17 +221,13 @@
 	}
 	
 	QString command_string = ".rk.set.meta (" + getFullName () + ", c (";
-	QString data_string = "), c (";
-	int i=meta_map->size ();
-	for (MetaMap::iterator it = meta_map->begin (); it != meta_map->end (); ++it) {
-		data_string.append (rQuote (it.data ()));
-		command_string.append (rQuote (it.key ()));
-		if (--i) {
-			data_string.append (", ");
+	for (MetaMap::const_iterator it = meta_map->constBegin (); it != meta_map->constEnd (); ++it) {
+		if (it != meta_map->constBegin ()) {
 			command_string.append (", ");
 		}
+		command_string.append (rQuote (it.key ()) + "=" + rQuote (it.data ()));
 	}
-	command_string.append (data_string + "))");
+	command_string.append ("))");
 	
 	RCommand *command = new RCommand (command_string, RCommand::App | RCommand::Sync);
 	RKGlobals::rInterface ()->issueCommand (command, chain);
@@ -452,32 +448,38 @@
 }
 
 //static
-QString RObject::typeToText (VarType var_type) {
-	if (var_type == Unknown) {
+QString RObject::typeToText (RDataType var_type) {
+	if (var_type == DataUnknown) {
 		return "Unknown";
-	} else if (var_type == Number) {
+	} else if (var_type == DataNumeric) {
 		return "Number";
-	} else if (var_type == String) {
+	} else if (var_type == DataCharacter) {
 		return "String";
-	} else if (var_type == Factor) {
+	} else if (var_type == DataFactor) {
 		return "Factor";
+	} else if (var_type == DataLogical) {
+		return "Logical";
 	} else {
+		RK_ASSERT (false);
 		return "Invalid";
 	}
 }
 
 //static 
-RObject::VarType RObject::textToType (const QString &text) {
+RObject::RDataType RObject::textToType (const QString &text) {
 	if (text == "Unknown") {
-		return Unknown;
+		return DataUnknown;
 	} else if (text == "Number") {
-		return Number;
+		return DataNumeric;
 	} else if (text == "String") {
-		return String;
+		return DataCharacter;
 	} else if (text == "Factor") {
-		return Factor;
+		return DataFactor;
+	} else if (text == "Logical") {
+		return DataLogical;
 	} else {
-		return Invalid;
+		RK_ASSERT (false);
+		return DataUnknown;
 	}
 }
 

Modified: trunk/rkward/rkward/core/robject.h
===================================================================
--- trunk/rkward/rkward/core/robject.h	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/core/robject.h	2006-10-11 15:18:31 UTC (rev 846)
@@ -57,20 +57,25 @@
 		ToplevelEnv=1024,
 		PackageEnv=2048,
 		HasMetaObject=4096,
-		Misplaced=8192		/** < the object is not in the namespace where it would be expected */
+		Misplaced=8192,		/** < the object is not in the namespace where it would be expected */
+		Numeric=1 << 14,
+		Factor=2 << 14,
+		Character=3 << 14,
+		Logical=4 << 14,
+		DataTypeMask=NumericA | FactorA | CharacterA | LogicalA
 	};
 
+	enum RDataType {
+		DataUnknown=0,
+		DataNumeric=1,
+		DataFactor=2,
+		DataCharacter=3,
+		DataLogical=4
+	};
+
 	#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
-	};
 	
 	QString getShortName ();
 	virtual QString getFullName ();
@@ -130,10 +135,15 @@
 /** array of child objects. Always 0, reimplemented in RContainerObject */
 	virtual RObject **children () { return 0; };
 
-/** returns a textual representation of the given VarType */
-	static QString typeToText (VarType var_type);
+	RDataType getDataType () { return ((RDataType) ((type & DataTypeMask) >> 14)); };
+	void setDataType (RDataType new_type) {
+		int n_type = type - (type & DataTypeMask);
+		type = n_type + (new_type << 14);
+	};
+/** returns a textual representation of the given RDataType */
+	static QString typeToText (RDataType);
 /** converts the given text to a VarType. Returns Invalid on failure */
-	static VarType textToType (const QString &text);
+	static RDataType textToType (const QString &text);
 /** Returns the given string in quotes, taking care of escaping quotation marks inside the string. */
 	static QString rQuote (const QString &string);
 /** Returns a pretty description of the object, and its most important properties. TODO should this be virtual or not? I suppose, it's a close call. For now, we do all work here with casts */

Modified: trunk/rkward/rkward/core/robjectlist.cpp
===================================================================
--- trunk/rkward/rkward/core/robjectlist.cpp	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/core/robjectlist.cpp	2006-10-11 15:18:31 UTC (rev 846)
@@ -189,7 +189,7 @@
 	QString remainder = canonified.section (QChar ('$'), 1);
 
 	for (unsigned int i = 0; i < num_toplevel_environments; ++i) {
-		RObject *found = toplevel_environments[i]->findChild (current_level);
+		RObject *found = toplevel_environments[i]->findObject (current_level, true);
 		if (found) {
 			if (remainder.isEmpty ()) return (found);
 			return (found->findObject (remainder, true));

Modified: trunk/rkward/rkward/dataeditor/editformatdialog.cpp
===================================================================
--- trunk/rkward/rkward/dataeditor/editformatdialog.cpp	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/dataeditor/editformatdialog.cpp	2006-10-11 15:18:31 UTC (rev 846)
@@ -46,7 +46,7 @@
 	alignment_group->layout()->setSpacing (RKGlobals::spacingHint ());
 	alignment_group->layout()->setMargin (RKGlobals::marginHint ());
 	QVBoxLayout *group_layout = new QVBoxLayout (alignment_group->layout());
-	group_layout->addWidget (new QRadioButton (i18n ("Default for type '%1'").arg (var->getVarTypeString ()), alignment_group));
+	group_layout->addWidget (new QRadioButton (i18n ("Default for type '%1'").arg (RObject::typeToText (var->getDataType ())), alignment_group));
 	group_layout->addWidget (new QRadioButton (i18n ("Left"), alignment_group));
 	group_layout->addWidget (new QRadioButton (i18n ("Right"), alignment_group));
 	alignment_group->setButton ((int) RKVariable::FormattingOptions::AlignDefault);

Modified: trunk/rkward/rkward/dataeditor/twintablemetamember.cpp
===================================================================
--- trunk/rkward/rkward/dataeditor/twintablemetamember.cpp	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/dataeditor/twintablemetamember.cpp	2006-10-11 15:18:31 UTC (rev 846)
@@ -33,9 +33,9 @@
 #include "../debug.h"
 
 TwinTableMetaMember::TwinTableMetaMember (QWidget *parent, TwinTable *table) : TwinTableMember (parent, table, 0, 1) {
-	type_values.insert (QString::number (RObject::Number), RObject::typeToText (RObject::Number));
-	type_values.insert (QString::number (RObject::Factor), RObject::typeToText (RObject::Factor));
-	type_values.insert (QString::number (RObject::String), RObject::typeToText (RObject::String));
+	type_values.insert (QString::number (RObject::DataNumeric), RObject::typeToText (RObject::DataNumeric));
+	type_values.insert (QString::number (RObject::DataFactor), RObject::typeToText (RObject::DataFactor));
+	type_values.insert (QString::number (RObject::DataCharacter), RObject::typeToText (RObject::DataCharacter));
 }
 
 TwinTableMetaMember::~TwinTableMetaMember () {
@@ -59,7 +59,7 @@
 	} else if (row == LABEL_ROW) {
 		var->setLabel (text, true);
 	} else if (row == TYPE_ROW) {
-		var->setVarType ((RObject::VarType) text.toInt ());
+		var->setVarType ((RObject::RDataType) text.toInt ());
 	} else if (row == FORMAT_ROW) {
 		return var->setFormattingOptionsString (text);
 	} else if (row == LEVELS_ROW) {
@@ -135,7 +135,7 @@
 	} else if (row == LABEL_ROW) {
 		return var->getLabel ();
 	} else if (row == TYPE_ROW) {
-		return QString::number (var->getVarType ());
+		return QString::number (var->getDataType ());
 	} else if (row == FORMAT_ROW) {
 		return var->getFormattingOptionsString ();
 	} else if (row == LEVELS_ROW) {
@@ -156,7 +156,7 @@
 	} else if (row == LABEL_ROW) {
 		return var->getLabel ();
 	} else if (row == TYPE_ROW) {
-		return var->getVarTypeString ();
+		return RObject::typeToText (var->getDataType ());
 	} else if (row == FORMAT_ROW) {
 		return var->getFormattingOptionsString ();
 	} else if (row == LEVELS_ROW) {

Modified: trunk/rkward/rkward/misc/rkobjectlistview.cpp
===================================================================
--- trunk/rkward/rkward/misc/rkobjectlistview.cpp	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/misc/rkobjectlistview.cpp	2006-10-11 15:18:31 UTC (rev 846)
@@ -201,7 +201,7 @@
 	// also take care of removing the children of the removed item!
 	// this can NOT be done by using QListViewItemIterator (item), as that is NOT constrained to the children!
 	RObject **children = object->children ();
-	for (unsigned int i = 0; i < object->numChildren (); ++i) {
+	for (int i = 0; i < object->numChildren (); ++i) {
 		objectRemoved (children[i]);
 	}
 
@@ -253,29 +253,31 @@
 	item->setText (0, object->getShortName ());
 	item->setText (1, object->getLabel ());
 	if (object->isVariable ()) {
-		item->setText (2, static_cast<RKVariable*> (object)->getVarTypeString ());
+		item->setText (2, RObject::typeToText (object->getDataType ()));
 	}
 	item->setText (3, object->makeClassString ("; "));
 
 	if (object->isDataFrame ()) {
 		item->setPixmap (0, SmallIcon("spreadsheet"));
 	} else if (object->isVariable()) {
-		switch(static_cast<RKVariable*> (object)->getVarType ()) {
-			case RObject::Number:
+		switch(object->getDataType ()) {
+			case RObject::DataNumeric:
 				item->setPixmap (0, SmallIcon("math_paren",12));
 				break;
-			case RObject::Factor:
+			case RObject::DataFactor:
 				item->setPixmap (0, SmallIcon("math_onetwomatrix",12));
 				break;
-			case RObject::String:
+			case RObject::DataCharacter:
 				item->setPixmap (0, SmallIcon("text",12));
 				break;
-			case RObject::Invalid:
+			case RObject::DataLogical:
+				#warning TODO icon for logical
+			case RObject::DataUnknown:
+				item->setPixmap (0, SmallIcon("help",12));
+				break;
+			default:
 				item->setPixmap (0, SmallIcon("no",12));
 				break;
-			case RObject::Unknown:
-				item->setPixmap (0, SmallIcon("help",12));
-				break;
 		}
 	} else if (object->isType (RObject::List)) {
 		item->setPixmap (0, *icon_list);

Modified: trunk/rkward/rkward/plugin/rkcomponentproperties.cpp
===================================================================
--- trunk/rkward/rkward/plugin/rkcomponentproperties.cpp	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/plugin/rkcomponentproperties.cpp	2006-10-11 15:18:31 UTC (rev 846)
@@ -740,7 +740,7 @@
 	if (!types.isEmpty ()) {
 		// TODO: this is not entirely correct, yet
 		if (object->isVariable ()) {
-			if (!types.contains (static_cast<RKVariable *> (object)->getVarTypeString ().lower ())) {
+			if (!types.contains (RObject::typeToText (object->getDataType ()).lower ())) {
 				return false;
 			}
 		} else {

Modified: trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R
===================================================================
--- trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R	2006-10-11 11:42:22 UTC (rev 845)
+++ trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R	2006-10-11 15:18:31 UTC (rev 846)
@@ -1,11 +1,19 @@
 ".rk.get.meta" <- function (x) {
-	c (row.names (attr (x, ".rk.meta")), as.vector (attr (x, ".rk.meta")[[1]]), recursive=TRUE)
+	y <- attr (x, ".rk.meta");
+	c (names (y), as.character (y))
 }
 
-".rk.set.meta" <- function (x, l, m) {
-	eval (substitute (attr (x, ".rk.meta") <<- data.frame (d=m, row.names=l)))
+".rk.set.meta" <- function (x, m) {
+	eval (substitute (attr (x, ".rk.meta") <<- m))
 }
 
+".rk.set.invalid.field" <- function (x, r, d) {
+	l <- attr (x, ".rk.invalid.fields");
+	if (is.null (l)) l <- list ();
+	l[[as.character(r)]] <- d;
+	eval (substitute (attr (x, ".rk.invalid.fields") <<- l))
+}
+
 ".rk.data.frame.insert.row" <- function (x, index=0) {
 	if ((index == 0) || (index > dim (x)[1])) {	# insert row at end
 		eval (substitute (x[dim(x)[1]+1,] <<- c (NA)))
@@ -246,6 +254,17 @@
 	}
 }
 
+".rk.get.vector.data" <- function (x) {
+	ret <- list ();
+	ret$data <- as.vector (x);
+	ret$levels <- levels (x)
+	if (is.null (ret$levels)) ret$levels <- ""
+	i <- attr (x, ".rk.invalid.fields");
+	ret$invalids <- as.character (c (names (i), i));
+	if (is.null (ret$invalids)) ret$invalid <- ""
+	ret
+}
+
 ".rk.get.structure" <- function (x, name, envlevel=0, namespacename=NULL, misplaced=FALSE) {
 	fun <- FALSE
 	cont <- FALSE
@@ -257,22 +276,28 @@
 	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 (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
+		type <- type + 16
 		cont <- TRUE
-	} else type = 32
-	if (is.function (x)) {
-		fun <- TRUE
-		type = 128
+	} else {
+		if (is.function (x)) {
+			fun <- TRUE
+			type <- 128
+		} else if (is.environment (x)) {
+			type <- 256
+			cont <- TRUE
+		} else {
+			type <- 32
+			if (is.facter (x)) type <- type + 32768			# 2 << 14
+			else if (is.logical (x)) type <- type + 65536		# 4 << 14
+			else if (is.numeric (x)) type <- type + 16384		# 1 << 14
+			else if (is.character (x)) type <- type + 49152		# 3 << 14
+		}
 	}
-	if (is.environment (x)) {
-		type = 256
-		cont <- TRUE
-	}
 	if (!is.null (attr (x, ".rk.meta"))) type = type + 4096
 	if (misplaced) type <- type + 8192
 	type <- as.integer (type)


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