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

tfry at users.sourceforge.net tfry at users.sourceforge.net
Wed Oct 11 17:32:31 UTC 2006


Revision: 847
          http://svn.sourceforge.net/rkward/?rev=847&view=rev
Author:   tfry
Date:     2006-10-11 10:32:19 -0700 (Wed, 11 Oct 2006)

Log Message:
-----------
New RKVariable data handling compiles now, but is *extremly* buggy, still

Modified Paths:
--------------
    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/dataeditor/twintabledatamember.cpp
    trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R

Modified: trunk/rkward/rkward/core/rkvariable.cpp
===================================================================
--- trunk/rkward/rkward/core/rkvariable.cpp	2006-10-11 15:18:31 UTC (rev 846)
+++ trunk/rkward/rkward/core/rkvariable.cpp	2006-10-11 17:32:19 UTC (rev 847)
@@ -63,7 +63,22 @@
 		for (int i=0; i < getLength (); ++i) {
 			list.append (getText (i));
 		}
+
 		setDataType (new_type);
+		if (new_type == RObject::DataCharacter) {
+			if (myData ()->cell_strings == 0) {
+				delete [] (myData ()->cell_doubles);
+				myData ()->cell_doubles = 0;
+				myData ()->cell_strings = new QString[getLength ()];
+			}
+		} else {
+			if (myData ()->cell_doubles == 0) {
+				delete [] (myData ()->cell_strings);
+				myData ()->cell_strings = 0;
+				myData ()->cell_doubles = new double[getLength ()];
+			}
+		}
+
 		int i = 0;
 		for (QStringList::const_iterator it = list.constBegin (); it != list.constEnd (); ++it) {
 			setText (i, *it);
@@ -92,48 +107,67 @@
 	
 	if (command->getFlags () == ROBJECT_UDPATE_STRUCTURE_COMMAND) {
 		RObject::rCommandDone (command);
-	} else if (command->getFlags () == GET_INVALID_FIELDS_COMMAND) {
-		#warning TODO
-
-		int command_type = RCommand::App | RCommand::Sync;
-		if (getDataType () == DataNumeric) {
-			command_type |= RCommand::GetRealVector;
-		} else if (getDataType () == DataFactor) {
-			#warning TODO
-		} else {
-			command_type |= RCommand::GetStringVector;
-		}
-		RKGlobals::rInterface ()->issueCommand (getFullName (), command_type, QString::null, this, GET_DATA_COMMAND);
 	} else if (command->getFlags () == GET_DATA_COMMAND) {
 		RK_ASSERT (myData ());
 		// prevent resyncing of data
 		setSyncing (false);
-		int len = command->getDataLength ();
-		RK_ASSERT (len == getLength ());
-		if (command->getDataType () == RData::RealVector) {
-			setNumeric (0, len - 1, command->getRealVector ());
-		} else if (command->getDataType () == RData::StringVector) {
-			setCharacter (0, len - 1, command->getStringVector ());
-		} else {
-			RK_ASSERT (false);
-		}
-		ChangeSet *set = new ChangeSet;
-		set->from_index = 0;
-		set->to_index = getLength ();
-		RKGlobals::tracker ()->objectDataChanged (this, set);
-		RKGlobals::tracker ()->objectMetaChanged (this);
-		setSyncing (true);
-	} else if (command->getFlags () == GET_FACTOR_LEVELS_COMMAND) {
-		RK_ASSERT (myData ());
-		// prevent resyncing of data
-		setSyncing (false);
-		RK_ASSERT (command->getDataLength ());
+
+		RK_ASSERT (command->getDataType () == RData::StructureVector);
+		RK_ASSERT (command->getDataLength () == 3);
+
+		RData *data = command->getStructureVector ()[0];
+		RData *levels = command->getStructureVector ()[1];
+		RData *invalids = command->getStructureVector ()[2];
+
+		// set factor levels first
+		RK_ASSERT (levels->getDataType () == RData::StringVector);
+		unsigned int levels_len = levels->getDataLength ();
+		RK_ASSERT (levels_len >= 1);
 		RK_ASSERT (!myData ()->value_labels);
 		myData ()->value_labels = new RObject::ValueLabels;
-		for (unsigned int i=0; i < command->getDataLength (); ++i) {
-			myData ()->value_labels->insert (QString::number (i+1), command->getStringVector ()[i]);
+		if ((levels_len == 1) && levels->getStringVector ()[0].isEmpty ()) {
+			// no levels
+		} else {
+			for (unsigned int i=0; i < levels_len; ++i) {
+				myData ()->value_labels->insert (QString::number (i+1), command->getStringVector ()[i]);
+			}
 		}
-		setSyncing (true);
+
+		// now set the data
+		RK_ASSERT (data->getDataLength () == (unsigned int) getLength ()); // not a problem due to the line below, I'd still like to know if / when this happens.
+		extendToLength (data->getDataLength ());
+		if (data->getDataType () == RData::StringVector) {
+			setCharacter (0, getLength () - 1, data->getStringVector ());
+		} else if (data->getDataType () == RData::RealVector) {
+			setNumeric (0, getLength () - 1, data->getRealVector ());
+		} else if (data->getDataType () == RData::IntVector) {
+			RK_ASSERT (false);		// not a problem, but I'd like to know if / when this happens
+			double *dd = new double[getLength ()];
+			unsigned int len = getLength ();
+			for (unsigned int i = 0; i < len; ++i) {
+				dd[i] = data->getIntVector ()[i];
+			}
+			setNumeric (0, getLength () - 1, dd);
+			delete [] dd;
+		}
+
+		// now set the invalid fields (only if they are still NAs in the R data)
+		RK_ASSERT (invalids->getDataType () == RData::StringVector);
+		if (invalids->getDataLength () == 1) {
+			// no invalids
+		} else {
+			unsigned int invalids_length = invalids->getDataLength ();
+			RK_ASSERT ((invalids_length % 2) == 0);
+			unsigned int invalids_count = invalids_length / 2;
+			for (unsigned int i=0; i < invalids_count; ++i) {
+				int row = invalids->getStringVector ()[i].toInt ();
+				if (myData ()->cell_states[row] & RKVarEditData::NA) {
+					setText (row, invalids->getStringVector ()[invalids_count + i]);
+				}
+			}
+		}
+	} else {
+		RK_ASSERT (false);
 	}
 }
 
@@ -158,7 +192,8 @@
 	RK_ASSERT (!myData ());
 	
 	data = new RKVarEditData;
-	myData ()->cell_data = 0;
+	myData ()->cell_strings = 0;
+	myData ()->cell_doubles = 0;
 	myData ()->cell_states = 0;
 	myData ()->allocated_length = 0;
 	myData ()->immediate_sync = true;
@@ -178,7 +213,7 @@
 	
 	if (to_empty) {
 		for (int row=0; row < getLength (); ++row) {
-			myData ()->cell_states[row] = Unknown;
+			myData ()->cell_states[row] = RKVarEditData::Unknown;
 		}
 	} else {
 		RKGlobals::rInterface ()->issueCommand (".rk.get.vector.data (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetStructuredData, QString::null, this, GET_DATA_COMMAND);
@@ -192,11 +227,14 @@
 
 	RK_ASSERT (myData ());
 
-	delete [] myData ()->cell_double_data;
-	for (int i = 0; i < myData ()->allocated_length; ++i) {
-		deleteStringData (i);
+	if (getDataType () == RObject::DataCharacter) {
+		delete [] myData ()->cell_strings;
+		RK_ASSERT (myData ()->cell_doubles == 0);
+	} else {
+		delete [] myData ()->cell_doubles;
+		RK_ASSERT (myData ()->cell_strings == 0);
 	}
-	delete [] myData ()->cell_string_data;
+	delete [] myData ()->cell_states;
 
 	RK_ASSERT (!(myData ()->changes));
 	delete myData ()->value_labels;
@@ -249,7 +287,7 @@
 	} 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);
+	myData ()->cell_states[row] -= (myData ()->cell_states[row] & RKVarEditData::UnsyncedInvalidState);
 }
 
 void RKVariable::writeData (int from_row, int to_row, RCommandChain *chain) {
@@ -259,7 +297,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);
+		if (myData ()->cell_states[from_row] & RKVarEditData::UnsyncedInvalidState) writeInvalidField (from_row, chain);
 	} else {
 		QString data_string = "c (";
 		for (int row = from_row; row <= to_row; ++row) {
@@ -268,7 +306,7 @@
 			if (row != to_row) {
 				data_string.append (", ");
 			}
-			if (myData ()->invalid_fields_not_synced[row] != 0) writeInvalidField (row, chain);
+			if (myData ()->cell_states[row] & RKVarEditData::UnsyncedInvalidState) 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);
@@ -317,23 +355,36 @@
 	while (target <= ilength) target = target * ALLOC_STEP;
 	RK_DO (qDebug ("resizing from %d to %d", myData ()->allocated_length, target), OBJECTS, DL_DEBUG);
 
-	QString **new_string_data = new QString*[target];
-	double *new_double_data = new double[target];
-	
-	if (myData ()->cell_string_data) {		// not starting from 0
-		qmemmove (new_string_data, myData ()->cell_string_data, myData ()->allocated_length * sizeof (QString*));
-		qmemmove (new_double_data, myData ()->cell_double_data, myData ()->allocated_length * sizeof (double));
-	
-		delete [] (myData ()->cell_string_data);
-		delete [] (myData ()->cell_double_data);
+	// allocate new memory and copy
+	if (getDataType () == RObject::DataCharacter) {
+		RK_ASSERT (myData ()->cell_doubles == 0);
+		QString *new_data = new QString[target];
+		if (myData ()->allocated_length) {		// if not yet allocated, don't mem-move
+			qmemmove (new_data, myData ()->cell_strings, myData ()->allocated_length * sizeof (QString));
+		}
+		delete [] (myData ()->cell_strings);
+		myData ()->cell_strings = new_data;
+	} else {
+		RK_ASSERT (myData ()->cell_strings == 0);
+		double *new_data = new double[target];
+		if (myData ()->allocated_length) {		// if not yet allocated, don't mem-move
+			qmemmove (new_data, myData ()->cell_doubles, myData ()->allocated_length * sizeof (double));
+		}
+		delete [] (myData ()->cell_doubles);
+		myData ()->cell_doubles = new_data;
 	}
+	int *new_states = new int[target];
+	if (myData ()->allocated_length) {		// if not yet allocated, don't mem-move
+		qmemmove (new_states, myData ()->cell_states, myData ()->allocated_length * sizeof (int));
+	}
+	delete [] (myData ()->cell_states);
+	myData ()->cell_states = new_states;
+
+	// set allocated but unused rows to Unknown
 	for (int i=myData ()->allocated_length; i < target; ++i) {
-		new_string_data[i] = unknown_char;
+		myData ()->cell_states[i] = RKVarEditData::Unknown;
 	}
 
-	myData ()->cell_string_data = new_string_data;
-	myData ()->cell_double_data = new_double_data;
-
 	myData ()->allocated_length = target;
 	dimensions[0] = length;
 }
@@ -343,32 +394,49 @@
 
 	// TODO: downsizing to values other than 0
 	if (getLength () <= 0) {
-		delete [] myData ()->cell_double_data;
-		myData ()->cell_double_data = 0;
-		for (int i = 0; i < myData ()->allocated_length; ++i) {
-#warning inefficient
-			deleteStringData (i);
-		}
-		delete [] myData ()->cell_string_data;
-		myData ()->cell_string_data = 0;
+		delete [] myData ()->cell_doubles;
+		myData ()->cell_doubles = 0;
+		delete [] myData ()->cell_strings;
+		myData ()->cell_strings = 0;
+		delete [] myData ()->cell_states;
+		myData ()->cell_states = 0;
 	}
 }
 
-QString RKVariable::getText (int row) {
+QString RKVariable::getText (int row, bool pretty) {
 	if (row >= getLength ()) {
 		RK_ASSERT (false);
 		return (*unknown_char);
 	}
+
+	if (myData ()->cell_states[row] & RKVarEditData::Invalid) {
+		RK_ASSERT (myData ()->invalid_fields[row] != 0);
+		return (*(myData ()->invalid_fields[row]));
+	}
+
+	if (myData ()->cell_states[row] & RKVarEditData::NA) {
+		return (*na_char);
+	}
+
+	if (pretty && (myData ()->value_labels)) {
+		QString otext = getText (row);
+		if (myData ()->value_labels->contains (otext)) {
+			return (*(myData ()->value_labels))[otext];
+		}
+	}
+
 	if (getDataType () == DataCharacter) {
-		return (*(myData ()->cell_string_data[row]));
+		RK_ASSERT (myData ()->cell_strings != 0);
+		return (myData ()->cell_strings[row]);
 	} else {
-		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);
+		RK_ASSERT (myData ()->cell_doubles != 0);
+		if (pretty && myData ()->formatting_options && (myData ()->formatting_options->precision_mode != FormattingOptions::PrecisionDefault)) {
+			if (myData ()->formatting_options->precision_mode == FormattingOptions::PrecisionRequired) {
+				return QString::number (myData ()->cell_doubles[row], 'g', MAX_PRECISION);
+			}
+			return QString::number (myData ()->cell_doubles[row], 'f', myData ()->formatting_options->precision);
 		}
+		return QString::number (myData ()->cell_doubles[row], 'g', MAX_PRECISION);
 	}
 }
 
@@ -384,7 +452,8 @@
 	} else if (getDataType () == DataCharacter) {
 		return (rQuote (getText (row)));
 	} else {
-		return (QString::number (myData ()->cell_double_data[row], 'g', MAX_PRECISION));
+		RK_ASSERT (myData ()->cell_doubles != 0);
+		return (QString::number (myData ()->cell_doubles[row], 'g', MAX_PRECISION));
 	}
 }
 
@@ -392,89 +461,66 @@
 	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 (myData ()->cell_states[row] & ValueInvalid) {
+		myData ()->cell_states[row] = RKVarEditData::UnsyncedInvalidState;
+		myData ()->invalid_fields.remove (row);
+	} else {
+		myData ()->cell_states[row] = 0;
+	}
 
-	if (getDataType () == DataCharacter) {
-		if (text.isNull ()) {
-			myData ()->cell_string_data[row] = na_char;
-		} else {
-			myData ()->cell_string_data[row] = new QString (text);
-		}
-	} 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_fields.replace (row, new QString (text));
-			myData ()->invalid_fields_not_synced.replace (row, (int *) 1);
-		}
+	qDebug ("%d, %s", row, text.latin1 ());
+
+	if (text.isNull ()) {
+		myData ()->cell_states[row] |= RKVarEditData::NA;
 	} else {
-		bool ok;
-		myData ()->cell_double_data[row] = text.toDouble (&ok);
-		if (!ok) {
+		if (getDataType () == DataCharacter) {
+			RK_ASSERT (myData ()->cell_strings != 0);
+			myData ()->cell_strings[row] = text;
+			myData ()->cell_states[row] |= RKVarEditData::Valid;
+		} else if (getDataType () == DataFactor) {
+			RK_ASSERT (myData ()->cell_doubles != 0);
 			if (text.isEmpty ()) {
-				myData ()->cell_string_data[row] = na_char;
+				myData ()->cell_states[row] |= RKVarEditData::NA;
+			} else if (myData ()->value_labels && myData ()->value_labels->contains (text)) {
+				myData ()->cell_doubles[row] = text.toInt ();
+				myData ()->cell_states[row] |= RKVarEditData::Valid;
 			} else {
 				myData ()->invalid_fields.replace (row, new QString (text));
-				myData ()->invalid_fields_not_synced.replace (row, (int *) 1);
+				myData ()->cell_states[row] |= RKVarEditData::Invalid | RKVarEditData::UnsyncedInvalidState;
 			}
-		}
-	}
-	cellChanged (row);
-}
-
-/** 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 RKVariable::getFormatted (int row) {
-	if (row >= getLength ()) {
-		RK_ASSERT (false);
-		return (*unknown_char);
-	}
-
-	if (myData ()->value_labels) {
-		if (myData ()->value_labels->contains (getText (row))) {
-			return (*(myData ()->value_labels))[getText (row)];
-		}
-	}
-
-	if (getDataType () == DataCharacter) {
-		return (*(myData ()->cell_string_data[row]));
-	} else {
-		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)) {
-				if (myData ()->formatting_options->precision_mode == FormattingOptions::PrecisionRequired) {
-					return QString::number (myData ()->cell_double_data[row], 'g', MAX_PRECISION);
+			qDebug ("1");
+			RK_ASSERT (myData ()->cell_doubles != 0);
+			bool ok;
+			myData ()->cell_doubles[row] = text.toDouble (&ok);
+			if (!ok) {
+				if (text.isEmpty ()) {
+					myData ()->cell_states[row] |= RKVarEditData::NA;
 				} else {
-					return QString::number (myData ()->cell_double_data[row], 'f', myData ()->formatting_options->precision);
+					myData ()->invalid_fields.replace (row, new QString (text));
+					myData ()->cell_states[row] |= RKVarEditData::Invalid | RKVarEditData::UnsyncedInvalidState;
 				}
 			} else {
-				// TODO: use global (configurable) defaults!
-				return QString::number (myData ()->cell_double_data[row], 'g', MAX_PRECISION);
+				qDebug ("here");
+				myData ()->cell_states[row] |= RKVarEditData::Valid;
 			}
 		}
 	}
 
-	return getText (row);
+	qDebug ("new cell state %d: %d", row, myData ()->cell_states[row]);
+	cellChanged (row);
 }
 
-/** tries to match a value-label to the value in the given cell. Returns the label, or - if there is no label - the original value in textual representation */
 QString RKVariable::getLabeled (int row) {
 	if (myData ()->value_labels) {
-		if (myData ()->value_labels->contains (getText (row))) {
-			return (*(myData ()->value_labels))[getText (row)];
+		QString otext = getText (row);
+		if (myData ()->value_labels->contains (otext)) {
+			return (*(myData ()->value_labels))[otext];
 		}
 	}
 	return getText (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! */
 double *RKVariable::getNumeric (int from_row, int to_row) {
 	if (to_row >= getLength ()) {
 		RK_ASSERT (false);
@@ -484,22 +530,17 @@
 
 	// TODO: no, this is not good. Return a _copy_!
 	// we simply return the whole array starting at the given offset for now. Change this, if the storage mechanism gets changed!
-	return &(myData ()->cell_double_data[from_row]);
+	return &(myData ()->cell_doubles[from_row]);
 }
 
 void RKVariable::setNumeric (int from_row, int to_row, double *data) {
 	RK_ASSERT (to_row < getLength ());
-	
-	for (int row=from_row; row <= to_row; ++row) {
-#warning inefficient
-		deleteStringData (row);
-	}
-	
+
 	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));
+			setText (row, QString::number (data[i++], 'g', MAX_PRECISION));
 		}
 	} else if (getDataType () == DataFactor) {
 		int i = 0;
@@ -509,8 +550,15 @@
 	} else {
 		int i = 0;
 		for (int row=from_row; row <= to_row; ++row) {
-			if (isnan (data[i])) myData ()->cell_string_data[row] = na_char;
-			myData ()->cell_double_data[row] = data[i++];
+			if (myData ()->cell_states[row] & RKVarEditData::Invalid) myData ()->cell_states[row] = RKVarEditData::UnsyncedInvalidState;
+			else myData ()->cell_states[row] = 0;
+
+			if (isnan (data[i])) {
+				myData ()->cell_states[row] |= RKVarEditData::NA;
+			} else {
+				myData ()->cell_states[row] |= RKVarEditData::Valid;
+				myData ()->cell_doubles[row] = data[i++];
+			}
 		}
 	}
 	cellsChanged (from_row, to_row);
@@ -540,9 +588,13 @@
 	if (getDataType () == DataCharacter) {
 		int i=0;
 		for (int row=from_row; row <= to_row; ++row) {
-#warning inefficient
-			deleteStringData (row);
-			myData ()->cell_string_data[row] = new QString (data[i++]);
+			if (myData ()->cell_states[row] & RKVarEditData::Invalid) myData ()->cell_states[row] = RKVarEditData::UnsyncedInvalidState;
+			else myData ()->cell_states[row] = 0;
+
+			if (data[i].isNull ()) myData ()->cell_states[row] |= RKVarEditData::NA;
+			else myData ()->cell_states[row] |= RKVarEditData::Valid;
+
+			myData ()->cell_strings[row] = QString (data[i++]);
 		}
 	} else {
 		int i=0;
@@ -561,43 +613,37 @@
 	if ((to_row < 0)) to_row = myData ()->allocated_length - 1;
 		
 	for (int row=from_row; row <= to_row; ++row) {
-#warning inefficient
-		deleteStringData (row);
-		myData ()->cell_string_data[row] = unknown_char;
+		myData ()->cell_strings[row] = RKVarEditData::Unknown;
 	}
 }
 
 RKVariable::Status RKVariable::cellStatus (int row) {
-	if (myData ()->cell_string_data[row] == na_char) {
-		return ValueUnused;
-	} else if (myData ()->cell_string_data[row] == unknown_char) {
-		return ValueUnknown;
-	} else if ((getDataType () != DataCharacter) && (myData ()->invalid_fields[row] != 0)) {
-		return ValueInvalid;
-	}
+	if (myData ()->cell_states[row] == RKVarEditData::Unknown) return ValueUnknown;
+	if (myData ()->cell_states[row] & RKVarEditData::NA) return ValueUnused;
+	if (myData ()->cell_states[row] & RKVarEditData::Invalid) return ValueInvalid;
 	return ValueValid;
 }
 
-/** entirely remove the given row (i.e. the cell). Will also take care of updating the state (are there any invalid cells left?), and syncing with the backend */
 void RKVariable::removeRow (int row) {
 	removeRows (row, row);
 }
 
-/** see removeRow (), but removes a range of rows (i.e. cells). Since data only needs to be copied once, this is more efficient than several single calls to removeRow () */
 void RKVariable::removeRows (int from_row, int to_row) {
 	for (int row = from_row; row <= to_row; ++row) {
-#warning inefficient
-		deleteStringData (row);
+		myData ()->invalid_fields.remove (row);
 	}
 
 	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));
+		if (myData ()->cell_strings) {
+			qmemmove (&(myData ()->cell_strings[from_row]), &(myData ()->cell_strings[to_row+1]), (myData ()->allocated_length - to_row - 1) * sizeof (QString));
+		} else {
+			qmemmove (&(myData ()->cell_doubles[from_row]), &(myData ()->cell_doubles[to_row+1]), (myData ()->allocated_length - to_row - 1) * sizeof (double));
+		}
+		qmemmove (&(myData ()->cell_states[from_row]), &(myData ()->cell_states[to_row+1]), (myData ()->allocated_length - to_row - 1) * sizeof (int));
 	}
 
 	for (int row = (myData ()->allocated_length - 1 - (to_row - from_row)); row < myData ()->allocated_length; ++row) {
-		myData ()->cell_string_data[myData ()->allocated_length - 1] = unknown_char;
-		myData ()->cell_double_data[myData ()->allocated_length - 1] = 0;
+		myData ()->cell_states[myData ()->allocated_length - 1] = RKVarEditData::Unknown;
 	}
 
 	dimensions[0] -= (to_row - from_row) + 1;	
@@ -609,25 +655,25 @@
 }
 
 void RKVariable::insertRows (int row, int count) {
-	int old_len = getLength ();
+//	int old_len = getLength ();
 	extendToLength (getLength () + count);
 
-	for (int i=old_len; i <= row+count; ++i) {
-		myData ()->cell_string_data[i] = na_char;
-		myData ()->cell_double_data[i] = 0;
-	}
+/*	for (int i=old_len; i <= row+count; ++i) {
+		myData ()->cell_states[i] = RKVarEditData::NA;
+	} */
 
 	if (row >= getLength () && (count == 1)) {		// important special case
-		myData ()->cell_string_data[row+count] = myData ()->cell_string_data[row];
-		myData ()->cell_double_data[row+count] = myData ()->cell_double_data[row];
-	} else { 
-		qmemmove (&(myData ()->cell_string_data[row+count]), &(myData ()->cell_string_data[row]), (myData ()->allocated_length - (row + count) - 1) * sizeof (QString*));
-		qmemmove (&(myData ()->cell_double_data[row+count]), &(myData ()->cell_double_data[row]), (myData ()->allocated_length - (row + count) - 1) * sizeof (double));
+		if (myData ()->cell_strings) myData ()->cell_strings[row+count] = myData ()->cell_strings[row];
+		if (myData ()->cell_doubles) myData ()->cell_doubles[row+count] = myData ()->cell_doubles[row];
+		myData ()->cell_states[row+count] = myData ()->cell_states[row];
+	} else {
+		if (myData ()->cell_strings) qmemmove (&(myData ()->cell_strings[row+count]), &(myData ()->cell_strings[row]), (myData ()->allocated_length - (row + count) - 1) * sizeof (QString));
+		if (myData ()->cell_doubles) qmemmove (&(myData ()->cell_doubles[row+count]), &(myData ()->cell_doubles[row]), (myData ()->allocated_length - (row + count) - 1) * sizeof (double));
+		qmemmove (&(myData ()->cell_states[row+count]), &(myData ()->cell_states[row]), (myData ()->allocated_length - (row + count) - 1) * sizeof (int));
 	}
 	
 	for (int i=row+count-1; i >= row; --i) {
-		myData ()->cell_string_data[i] = na_char;
-		myData ()->cell_double_data[i] = 0;
+		myData ()->cell_states[i] = RKVarEditData::NA;
 	}
 }
 

Modified: trunk/rkward/rkward/core/rkvariable.h
===================================================================
--- trunk/rkward/rkward/core/rkvariable.h	2006-10-11 15:18:31 UTC (rev 846)
+++ trunk/rkward/rkward/core/rkvariable.h	2006-10-11 17:32:19 UTC (rev 847)
@@ -52,27 +52,20 @@
 /** the Status enum is used for both keeping track of the entire row and inidvidual cells. For single cells the meaning should be obvious. The entire row
 is set to Unused, if _no_ cell in the row is used, Valid if _all_ cells in the row are valid and Invalid if _one or more_ cells in the row are invalid, Unknown if _all_ cells in the row are unknown/updating. */
 	enum Status { ValueUnused=0, ValueValid=1, ValueInvalid=2, ValueUnknown=4 };
-/** The storage mode. For most vars this will be numeric. Note that if a single cell in a row is Invalid, the entire row will - in the R-backend - have to be stored as a string. */
-//	enum RStorage { StorageString=0, StorageNumeric=1 };
-/** See Storage enum. Returns how the row is actually saved in the R-backend. */
-//	RStorage rStorage ();
-/** changes the internal storage mode, and also - if possible/necessary - the storage mode in the backend. Warning: this is an expensive operation, as it may involve conversion, deletion, reallocation and copying of data */
-//	void changeStorageMode (RStorage new_mode);
 
 /** sets whether changed data should be synced immediately or not. Set this to off for large paste operations. Rember to call setSyncing (true) and syncDataToR () after the paste is complete */
 	void setSyncing (bool immediate);
 /** syncs pending data changes to the backend */
 	void syncDataToR ();
 	
-/** get the value at the given row in text-form - regardless of the storage mode. */
-	QString getText (int row);
+/** get the value at the given row in text-form - regardless of the storage mode.
+ at param pretty: 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 getText (int row, bool pretty=false);
 /** get the value at the given row in text-form suitable for submission to R. I.e. strings are quoted, numbers are not, empty values are returned as NA */
 	QString getRText (int row);
 /** set the value at the given row in text-form. Will try to convert the given string to the internal storage format if possible. */
 	void setText (int row, const QString &text);
 
-/** 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!  TODO: unused  */
 	double *getNumeric (int from_row, int to_row);
@@ -144,7 +137,8 @@
 protected:
 /** Extended from RObject::EditData to actually contain data. */
 	struct RKVarEditData : public EditData {
-		void *cell_data;
+		QString *cell_strings;
+		double *cell_doubles;
 		enum CellState {
 			Unknown=0,
 			Invalid=1,
@@ -152,7 +146,7 @@
 			Valid=4,
 			UnsyncedInvalidState=4
 		};
-		CellState *cell_states;
+		int *cell_states;
 
 /// the currently allocated length of cell_data and cell_states. Used to determine, when a re-allocation is required
 		int allocated_length;

Modified: trunk/rkward/rkward/core/robject.cpp
===================================================================
--- trunk/rkward/rkward/core/robject.cpp	2006-10-11 15:18:31 UTC (rev 846)
+++ trunk/rkward/rkward/core/robject.cpp	2006-10-11 17:32:19 UTC (rev 847)
@@ -124,7 +124,7 @@
 		ret.append (i18n ("List"));
 	} else if (isType (Variable)) {
 		ret.append (i18n ("Variable"));
-		ret.append ("<br><b>" + i18n ("Data Type:") + " </b>" + static_cast<RKVariable *> (this)->getVarTypeString ());
+		ret.append ("<br><b>" + i18n ("Data Type:") + " </b>" + typeToText (getDataType ()));
 	} else if (isType (Environment)) {
 		ret.append (i18n ("Environment"));
 	}

Modified: trunk/rkward/rkward/core/robject.h
===================================================================
--- trunk/rkward/rkward/core/robject.h	2006-10-11 15:18:31 UTC (rev 846)
+++ trunk/rkward/rkward/core/robject.h	2006-10-11 17:32:19 UTC (rev 847)
@@ -62,7 +62,7 @@
 		Factor=2 << 14,
 		Character=3 << 14,
 		Logical=4 << 14,
-		DataTypeMask=NumericA | FactorA | CharacterA | LogicalA
+		DataTypeMask=Numeric | Factor | Character | Logical
 	};
 
 	enum RDataType {

Modified: trunk/rkward/rkward/dataeditor/twintabledatamember.cpp
===================================================================
--- trunk/rkward/rkward/dataeditor/twintabledatamember.cpp	2006-10-11 15:18:31 UTC (rev 846)
+++ trunk/rkward/rkward/dataeditor/twintabledatamember.cpp	2006-10-11 17:32:19 UTC (rev 847)
@@ -84,7 +84,7 @@
 	QString text;
 	int align = 0;
 	if (var && (row < numTrueRows ())) {
-		text = var->getFormatted (row);
+		text = var->getText (row, true);
 		align = var->getAlignment ();
 	}
 	paintCellInternal (p, row, col, cr, selected, cg, brush_override, pen_override, text, align);
@@ -110,7 +110,7 @@
 	if (row >= numTrueRows ()) {
 		table->insertNewRow ();
 	}
-	
+
 	if (var->cellStatus (row) == RKVariable::ValueUnknown) return 0;
 
 	tted = new CellEditor (this, var->getText (row), 0, var->getValueLabels ());

Modified: trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R
===================================================================
--- trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R	2006-10-11 15:18:31 UTC (rev 846)
+++ trunk/rkward/rkward/rbackend/rpackages/rkward/R/internal.R	2006-10-11 17:32:19 UTC (rev 847)
@@ -292,7 +292,7 @@
 			cont <- TRUE
 		} else {
 			type <- 32
-			if (is.facter (x)) type <- type + 32768			# 2 << 14
+			if (is.factor (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


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